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('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('MSBOT_LOGIN_URL', 'https://login.microsoftonline.com/common/oauth2/v2.0/token');
define('MSBOT_LUIS_URL', 'https://api.projectoxford.ai/luis/v1/application');
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=');

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 Eloquent;
use Utils;
use Validator;
/**
* Class EntityModel
@ -86,6 +87,11 @@ class EntityModel extends Eloquent
return '[' . $this->getEntityType().':'.$this->public_id.':'.$this->getDisplayName() . ']';
}
public function entityKey()
{
return $this->public_id . ':' . $this->getEntityType();
}
/*
public function getEntityType()
{
@ -190,4 +196,35 @@ class EntityModel extends Eloquent
$name = $parts[count($parts)-1];
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;
use stdClass;
use Exception;
use App\Libraries\CurlUtils;
class BaseIntent
{
protected $state;
protected $parameters;
public function __construct($data)
public function __construct($state, $data)
{
$this->state = $state ?: new stdClass;
$this->data = $data;
}
public static function createIntent($data)
public static function createIntent($state, $data)
{
if ( ! count($data->intents)) {
throw new Exception(trans('texts.intent_not_found'));
@ -26,7 +30,7 @@ class BaseIntent
throw new Exception(trans('texts.intent_not_supported'));
}
return (new $className($data));
return (new $className($state, $data));
}
public function process()
@ -34,4 +38,62 @@ class BaseIntent
// 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;
use App\Models\EntityModel;
class CreateInvoiceIntent extends BaseIntent
{
public function process()
@ -9,64 +11,31 @@ class CreateInvoiceIntent extends BaseIntent
$client = $this->parseClient();
$invoiceItems = $this->parseInvoiceItems();
if ($client) {
$data = [
'client_id' => $client->id,
'invoice_items' => $invoiceItems,
];
$invoice = $invoiceRepo->save($data);
return view('bots.skype.invoice', [
'invoice' => $invoice
])->render();
} else {
if ( ! $client) {
return view('bots.skype.message', [
'message' => trans('texts.client_not_found')
])->render();
}
}
private function parseClient()
{
$clientRepo = app('App\Ninja\Repositories\ClientRepository');
$data = [
'client_id' => $client->id,
'invoice_items' => $invoiceItems,
];
$client = false;
$valid = EntityModel::validate($data, ENTITY_INVOICE);
foreach ($this->data->entities as $param) {
if ($param->type == 'Client') {
$client = $clientRepo->findPhonetically($param->entity);
}
if ($valid !== true) {
return view('bots.skype.message', [
'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 : '';
}
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()
{
$class = $text = '';

View File

@ -9,7 +9,6 @@ use Auth;
use Utils;
use parsecsv;
use Session;
use Validator;
use League\Fractal\Manager;
use App\Ninja\Repositories\ContactRepository;
use App\Ninja\Repositories\ClientRepository;
@ -141,7 +140,7 @@ class ImportService
foreach ($json['clients'] as $jsonClient) {
if ($this->validate($jsonClient, ENTITY_CLIENT) === true) {
if (EntityModel::validate($jsonClient, ENTITY_CLIENT) === true) {
$client = $this->clientRepo->save($jsonClient);
$this->addSuccess($client);
} else {
@ -151,7 +150,7 @@ class ImportService
foreach ($jsonClient['invoices'] as $jsonInvoice) {
$jsonInvoice['client_id'] = $client->id;
if ($this->validate($jsonInvoice, ENTITY_INVOICE) === true) {
if (EntityModel::validate($jsonInvoice, ENTITY_INVOICE) === true) {
$invoice = $this->invoiceRepo->save($jsonInvoice);
$this->addSuccess($invoice);
} else {
@ -162,7 +161,7 @@ class ImportService
foreach ($jsonInvoice['payments'] as $jsonPayment) {
$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
if ($this->validate($jsonPayment, ENTITY_PAYMENT) === true) {
if (EntityModel::validate($jsonPayment, ENTITY_PAYMENT) === true) {
$payment = $this->paymentRepo->save($jsonPayment);
$this->addSuccess($payment);
} else {
@ -280,7 +279,7 @@ class ImportService
$data['invoice_number'] = $account->getNextInvoiceNumber($invoice);
}
if ($this->validate($data, $entityType) !== true) {
if (EntityModel::validate($data, $entityType) !== true) {
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

View File

@ -2055,6 +2055,7 @@ $LANG = array(
'intent_not_found' => 'Sorry, I\'m not sure what you\'re asking.',
'intent_not_supported' => 'Sorry, I\'m not able to do that.',
'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),
'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":[
@foreach ($invoice->invoice_items as $item)
@if ($invoice->invoice_items[0] != $item)