1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-08 20:22:42 +01:00

Working on the bot

This commit is contained in:
Hillel Coren 2016-08-07 22:42:32 +03:00
parent 325aaa3272
commit f8fda5f241
10 changed files with 254 additions and 158 deletions

File diff suppressed because one or more lines are too long

View File

@ -627,9 +627,11 @@ if (!defined('CONTACT_EMAIL')) {
define('EMAIL_MARKUP_URL', env('EMAIL_MARKUP_URL', 'https://developers.google.com/gmail/markup')); define('EMAIL_MARKUP_URL', env('EMAIL_MARKUP_URL', 'https://developers.google.com/gmail/markup'));
define('OFX_HOME_URL', env('OFX_HOME_URL', 'http://www.ofxhome.com/index.php/home/directory/all')); define('OFX_HOME_URL', env('OFX_HOME_URL', 'http://www.ofxhome.com/index.php/home/directory/all'));
define('GOOGLE_ANALYITCS_URL', env('GOOGLE_ANALYITCS_URL', 'https://www.google-analytics.com/collect')); define('GOOGLE_ANALYITCS_URL', env('GOOGLE_ANALYITCS_URL', 'https://www.google-analytics.com/collect'));
define('MSBOT_LOGIN_URL', 'https://login.microsoftonline.com/common/oauth2/v2.0/token'); define('MSBOT_LOGIN_URL', 'https://login.microsoftonline.com/common/oauth2/v2.0/token');
define('MSBOT_LUIS_URL', 'https://api.projectoxford.ai/luis/v1/application'); define('MSBOT_LUIS_URL', 'https://api.projectoxford.ai/luis/v1/application');
define('SKYPE_API_URL', 'https://apis.skype.com/v3'); define('SKYPE_API_URL', 'https://apis.skype.com/v3');
define('MSBOT_STATE_URL', 'https://state.botframework.com/v3');
define('BLANK_IMAGE', 'data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='); define('BLANK_IMAGE', 'data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=');

View File

@ -0,0 +1,36 @@
<?php namespace App\Libraries;
class CurlUtils
{
public static function post($url, $data, $headers = false)
{
return self::exec('POST', $url, $data, $headers);
}
public static function get($url, $headers = false)
{
return self::exec('GET', $url, null, $headers);
}
public static function exec($method, $url, $data, $headers = false)
{
$curl = curl_init();
$opts = [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => $method,
CURLOPT_HTTPHEADER => $headers ?: [],
];
if ($data) {
$opts[CURLOPT_POSTFIELDS] = $data;
}
curl_setopt_array($curl, $opts);
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
}

View File

@ -3,6 +3,7 @@
use Auth; use Auth;
use Eloquent; use Eloquent;
use Utils; use Utils;
use Validator;
/** /**
* Class EntityModel * Class EntityModel
@ -86,6 +87,11 @@ class EntityModel extends Eloquent
return '[' . $this->getEntityType().':'.$this->public_id.':'.$this->getDisplayName() . ']'; return '[' . $this->getEntityType().':'.$this->public_id.':'.$this->getDisplayName() . ']';
} }
public function entityKey()
{
return $this->public_id . ':' . $this->getEntityType();
}
/* /*
public function getEntityType() public function getEntityType()
{ {
@ -190,4 +196,35 @@ class EntityModel extends Eloquent
$name = $parts[count($parts)-1]; $name = $parts[count($parts)-1];
return strtolower($name) . '_id'; return strtolower($name) . '_id';
} }
/**
* @param $data
* @param $entityType
* @return bool|string
*/
public static function validate($data, $entityType, $action = 'create')
{
// Use the API request if it exists
$requestClass = sprintf('App\\Http\\Requests\\%s%sAPIRequest', ucwords($action), ucwords($entityType));
if ( ! class_exists($requestClass)) {
$requestClass = sprintf('App\\Http\\Requests\\%s%sRequest', ucwords($action), ucwords($entityType));
}
$request = new $requestClass();
$request->setUserResolver(function() { return Auth::user(); });
$request->replace($data);
if ( ! $request->authorize()) {
return trans('texts.not_allowed');
}
$validator = Validator::make($data, $request->rules());
if ($validator->fails()) {
return $validator->messages()->first();
} else {
return true;
}
}
} }

View File

@ -1,17 +1,21 @@
<?php namespace App\Ninja\Intents; <?php namespace App\Ninja\Intents;
use stdClass;
use Exception; use Exception;
use App\Libraries\CurlUtils;
class BaseIntent class BaseIntent
{ {
protected $state;
protected $parameters; protected $parameters;
public function __construct($data) public function __construct($state, $data)
{ {
$this->state = $state ?: new stdClass;
$this->data = $data; $this->data = $data;
} }
public static function createIntent($data) public static function createIntent($state, $data)
{ {
if ( ! count($data->intents)) { if ( ! count($data->intents)) {
throw new Exception(trans('texts.intent_not_found')); throw new Exception(trans('texts.intent_not_found'));
@ -19,14 +23,14 @@ class BaseIntent
$intent = $data->intents[0]; $intent = $data->intents[0];
$intentType = $intent->intent; $intentType = $intent->intent;
$className = "App\\Ninja\\Intents\\{$intentType}Intent"; $className = "App\\Ninja\\Intents\\{$intentType}Intent";
if ( ! class_exists($className)) { if ( ! class_exists($className)) {
throw new Exception(trans('texts.intent_not_supported')); throw new Exception(trans('texts.intent_not_supported'));
} }
return (new $className($data)); return (new $className($state, $data));
} }
public function process() public function process()
@ -34,4 +38,62 @@ class BaseIntent
// do nothing by default // do nothing by default
} }
public function addState($entities)
{
var_dump($this->state);
if (isset($this->state->current)) {
$this->state->previous = $this->state->current;
}
$this->state->current = $entities;
}
public function getState()
{
return $this->state;
}
protected function parseClient()
{
$clientRepo = app('App\Ninja\Repositories\ClientRepository');
$client = false;
foreach ($this->data->entities as $param) {
if ($param->type == 'Client') {
$client = $clientRepo->findPhonetically($param->entity);
}
}
return $client;
}
protected function parseInvoiceItems()
{
$productRepo = app('App\Ninja\Repositories\ProductRepository');
$invoiceItems = [];
foreach ($this->data->compositeEntities as $entity) {
if ($entity->parentType == 'InvoiceItem') {
$product = false;
$qty = 1;
foreach ($entity->children as $child) {
if ($child->type == 'Product') {
$product = $productRepo->findPhonetically($child->value);
} else {
$qty = $child->value;
}
}
$item = $product->toArray();
$item['qty'] = $qty;
$invoiceItems[] = $item;
}
}
return $invoiceItems;
}
} }

View File

@ -1,5 +1,7 @@
<?php namespace App\Ninja\Intents; <?php namespace App\Ninja\Intents;
use App\Models\EntityModel;
class CreateInvoiceIntent extends BaseIntent class CreateInvoiceIntent extends BaseIntent
{ {
public function process() public function process()
@ -9,64 +11,31 @@ class CreateInvoiceIntent extends BaseIntent
$client = $this->parseClient(); $client = $this->parseClient();
$invoiceItems = $this->parseInvoiceItems(); $invoiceItems = $this->parseInvoiceItems();
if ($client) { if ( ! $client) {
$data = [
'client_id' => $client->id,
'invoice_items' => $invoiceItems,
];
$invoice = $invoiceRepo->save($data);
return view('bots.skype.invoice', [
'invoice' => $invoice
])->render();
} else {
return view('bots.skype.message', [ return view('bots.skype.message', [
'message' => trans('texts.client_not_found') 'message' => trans('texts.client_not_found')
])->render(); ])->render();
} }
}
private function parseClient() $data = [
{ 'client_id' => $client->id,
$clientRepo = app('App\Ninja\Repositories\ClientRepository'); 'invoice_items' => $invoiceItems,
];
$client = false; $valid = EntityModel::validate($data, ENTITY_INVOICE);
foreach ($this->data->entities as $param) { if ($valid !== true) {
if ($param->type == 'Client') { return view('bots.skype.message', [
$client = $clientRepo->findPhonetically($param->entity); 'message' => $valid
} ])->render();
} }
return $client; $invoice = $invoiceRepo->save($data);
$this->addState([$invoice->entityKey()]);
return view('bots.skype.invoice', [
'invoice' => $invoice
])->render();
} }
private function parseInvoiceItems()
{
$productRepo = app('App\Ninja\Repositories\ProductRepository');
$invoiceItems = [];
foreach ($this->data->compositeEntities as $entity) {
if ($entity->parentType == 'InvoiceItem') {
$product = false;
$qty = 1;
foreach ($entity->children as $child) {
if ($child->type == 'Product') {
$product = $productRepo->findPhonetically($child->value);
} else {
$qty = $child->value;
}
}
$item = $product->toArray();
$item['qty'] = $qty;
$invoiceItems[] = $item;
}
}
return $invoiceItems;
}
} }

View File

@ -8,6 +8,22 @@ class ClientPresenter extends EntityPresenter {
return $this->entity->country ? $this->entity->country->name : ''; return $this->entity->country ? $this->entity->country->name : '';
} }
public function balance()
{
$client = $this->entity;
$account = $client->account;
return $account->formatMoney($client->balance, $client);
}
public function paid_to_date()
{
$client = $this->entity;
$account = $client->account;
return $account->formatMoney($client->paid_to_date, $client);
}
public function status() public function status()
{ {
$class = $text = ''; $class = $text = '';

View File

@ -9,7 +9,6 @@ use Auth;
use Utils; use Utils;
use parsecsv; use parsecsv;
use Session; use Session;
use Validator;
use League\Fractal\Manager; use League\Fractal\Manager;
use App\Ninja\Repositories\ContactRepository; use App\Ninja\Repositories\ContactRepository;
use App\Ninja\Repositories\ClientRepository; use App\Ninja\Repositories\ClientRepository;
@ -141,7 +140,7 @@ class ImportService
foreach ($json['clients'] as $jsonClient) { foreach ($json['clients'] as $jsonClient) {
if ($this->validate($jsonClient, ENTITY_CLIENT) === true) { if (EntityModel::validate($jsonClient, ENTITY_CLIENT) === true) {
$client = $this->clientRepo->save($jsonClient); $client = $this->clientRepo->save($jsonClient);
$this->addSuccess($client); $this->addSuccess($client);
} else { } else {
@ -151,7 +150,7 @@ class ImportService
foreach ($jsonClient['invoices'] as $jsonInvoice) { foreach ($jsonClient['invoices'] as $jsonInvoice) {
$jsonInvoice['client_id'] = $client->id; $jsonInvoice['client_id'] = $client->id;
if ($this->validate($jsonInvoice, ENTITY_INVOICE) === true) { if (EntityModel::validate($jsonInvoice, ENTITY_INVOICE) === true) {
$invoice = $this->invoiceRepo->save($jsonInvoice); $invoice = $this->invoiceRepo->save($jsonInvoice);
$this->addSuccess($invoice); $this->addSuccess($invoice);
} else { } else {
@ -162,7 +161,7 @@ class ImportService
foreach ($jsonInvoice['payments'] as $jsonPayment) { foreach ($jsonInvoice['payments'] as $jsonPayment) {
$jsonPayment['client_id'] = $jsonPayment['client'] = $client->id; // TODO: change to client_id once views are updated $jsonPayment['client_id'] = $jsonPayment['client'] = $client->id; // TODO: change to client_id once views are updated
$jsonPayment['invoice_id'] = $jsonPayment['invoice'] = $invoice->id; // TODO: change to invoice_id once views are updated $jsonPayment['invoice_id'] = $jsonPayment['invoice'] = $invoice->id; // TODO: change to invoice_id once views are updated
if ($this->validate($jsonPayment, ENTITY_PAYMENT) === true) { if (EntityModel::validate($jsonPayment, ENTITY_PAYMENT) === true) {
$payment = $this->paymentRepo->save($jsonPayment); $payment = $this->paymentRepo->save($jsonPayment);
$this->addSuccess($payment); $this->addSuccess($payment);
} else { } else {
@ -280,7 +279,7 @@ class ImportService
$data['invoice_number'] = $account->getNextInvoiceNumber($invoice); $data['invoice_number'] = $account->getNextInvoiceNumber($invoice);
} }
if ($this->validate($data, $entityType) !== true) { if (EntityModel::validate($data, $entityType) !== true) {
return false; return false;
} }
@ -396,26 +395,6 @@ class ImportService
} }
} }
/**
* @param $data
* @param $entityType
* @return bool|string
*/
private function validate($data, $entityType)
{
$requestClass = 'App\\Http\\Requests\\Create' . ucwords($entityType) . 'Request';
$request = new $requestClass();
$request->setUserResolver(function() { return Auth::user(); });
$request->replace($data);
$validator = Validator::make($data, $request->rules());
if ($validator->fails()) {
return $validator->messages()->first();
} else {
return true;
}
}
/** /**
* @param array $files * @param array $files

View File

@ -2055,6 +2055,7 @@ $LANG = array(
'intent_not_found' => 'Sorry, I\'m not sure what you\'re asking.', 'intent_not_found' => 'Sorry, I\'m not sure what you\'re asking.',
'intent_not_supported' => 'Sorry, I\'m not able to do that.', 'intent_not_supported' => 'Sorry, I\'m not able to do that.',
'client_not_found' => 'We weren\'t able to find the client', 'client_not_found' => 'We weren\'t able to find the client',
'not_allowed' => 'Sorry, you don\'t have the needed permissions',
); );

View File

@ -8,6 +8,20 @@
'invoice' => link_to($invoice->getRoute(), $invoice->invoice_number), 'invoice' => link_to($invoice->getRoute(), $invoice->invoice_number),
'client' => link_to($invoice->client->getRoute(), $invoice->client->getDisplayName()) 'client' => link_to($invoice->client->getRoute(), $invoice->client->getDisplayName())
]) !!}', ]) !!}',
"facts": [
{
"key": "{{ trans('texts.email') }}:",
"value": "{!! addslashes(HTML::mailto($invoice->client->contacts[0]->email)->toHtml()) !!}"
},
{
"key": "{{ trans('texts.paid_to_date') }}:",
"value": "{{ $invoice->client->present()->paid_to_date }}"
},
{
"key": "{{ trans('texts.balance') }}:",
"value": "{{ $invoice->client->present()->balance }}"
}
],
"items":[ "items":[
@foreach ($invoice->invoice_items as $item) @foreach ($invoice->invoice_items as $item)
@if ($invoice->invoice_items[0] != $item) @if ($invoice->invoice_items[0] != $item)