1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 05:02:36 +01:00

Working on the bot

This commit is contained in:
Hillel Coren 2016-08-10 15:57:34 +03:00
parent d374843e50
commit 815c3991a6
18 changed files with 397 additions and 88 deletions

View File

@ -2,8 +2,9 @@
namespace App\Http\Controllers;
use App\Libraries\CurlUtils;
use Exception;
use App\Libraries\Skype\SkypeResponse;
use App\Libraries\CurlUtils;
use App\Ninja\Intents\BaseIntent;
class BotController extends Controller
@ -11,13 +12,15 @@ class BotController extends Controller
public function handleMessage($platform)
{
$to = '29:1C-OsU7OWBEDOYJhQUsDkYHmycOwOq9QOg5FVTwRX9ts';
//$message = 'create a new invoice for Mr. Gino ';
$message = 'add 1 item';
//$message = 'set the cost to 20';
//$message = 'new invoice for john for 2 items due tomorrow';
//$message = 'create a new invoice for john smith for 2 tickets, set the invoice date to today, the due date to tomorrow, the deposit to 5 and the discount set to 10 percent';
//$message = 'create a new invoice for john smith with a due date of September 7th';
//$message = 'create a new invoice for john';
$message = 'add 2 tickets and set the due date to yesterday';
//$message = 'set the po number to 0004';
//$message = 'set the quantity to 20';
//$message = 'send the invoice';
//$message = view('bots.skype.message', ['message' => $message])->render();
//return $this->sendResponse($to, $message);
//$message = 'show me my products';
echo "Message: $message <p>";
$token = $this->authenticate();
@ -33,9 +36,7 @@ class BotController extends Controller
$this->saveState($token, $state);
/*
} catch (Exception $exception) {
$message = view('bots.skype.message', [
'message' => $exception->getMessage()
])->render();
SkypeResponse::message($exception->getMessage());
}
*/
@ -86,7 +87,6 @@ class BotController extends Controller
private function saveState($token, $data)
{
$url = sprintf('%s/botstate/skype/conversations/%s', MSBOT_STATE_URL, '29:1C-OsU7OWBEDOYJhQUsDkYHmycOwOq9QOg5FVTwRX9ts');
var_dump($url);
$headers = [
'Authorization: Bearer ' . $token,
@ -94,11 +94,8 @@ class BotController extends Controller
];
$data = '{ eTag: "*", data: "' . addslashes(json_encode($data)) . '" }';
//$data = '{ eTag: "*", data: "" }';
var_dump($data);
$response = CurlUtils::post($url, $data, $headers);
var_dump($response);
CurlUtils::post($url, $data, $headers);
}
private function sendResponse($token, $to, $message)
@ -111,7 +108,7 @@ class BotController extends Controller
$response = CurlUtils::post($url, $message, $headers);
var_dump($message);
echo "<pre>" . htmlentities(json_encode(json_decode($message), JSON_PRETTY_PRINT)) . "</pre>";
var_dump($response);
}

View File

@ -0,0 +1,11 @@
<?php namespace App\Libraries\Skype;
class ButtonCard
{
public function __construct($type, $title, $value)
{
$this->type = $type;
$this->title = $title;
$this->value = $value;
}
}

View File

@ -0,0 +1,26 @@
<?php namespace App\Libraries\Skype;
class HeroCard
{
public function __construct()
{
$this->contentType = 'application/vnd.microsoft.card.hero';
$this->content = new stdClass;
$this->content->buttons = [];
}
public function setTitle($title)
{
$this->content->title = $title;
}
public function setSubitle($subtitle)
{
$this->content->subtitle = $subtitle;
}
public function addButton($button)
{
$this->content->buttons[] = $button;
}
}

View File

@ -0,0 +1,75 @@
<?php namespace App\Libraries\Skype;
use HTML;
use stdClass;
class InvoiceCard
{
public function __construct($invoice)
{
$this->contentType = 'application/vnd.microsoft.card.receipt';
$this->content = new stdClass;
$this->content->facts = [];
$this->content->items = [];
$this->content->buttons = [];
$this->setTitle('test');
$this->setTitle(trans('texts.invoice_for_client', [
'invoice' => link_to($invoice->getRoute(), $invoice->invoice_number),
'client' => link_to($invoice->client->getRoute(), $invoice->client->getDisplayName())
]));
$this->addFact(trans('texts.email'), HTML::mailto($invoice->client->contacts[0]->email)->toHtml());
if ($invoice->due_date) {
$this->addFact($invoice->present()->dueDateLabel, $invoice->present()->due_date);
}
if ($invoice->po_number) {
$this->addFact(trans('texts.po_number'), $invoice->po_number);
}
if ($invoice->discount) {
$this->addFact(trans('texts.discount'), $invoice->present()->discount);
}
foreach ($invoice->invoice_items as $item) {
$this->addItem($item, $invoice->account);
}
$this->setTotal($invoice->present()->requestedAmount);
$this->addButton('imBack', trans('texts.send_email'), 'send_email');
$this->addButton('imBack', trans('texts.download_pdf'), 'download_pdf');
}
public function setTitle($title)
{
$this->content->title = $title;
}
public function setTotal($value)
{
$this->content->total = $value;
}
public function addFact($key, $value)
{
$fact = new stdClass;
$fact->key = $key;
$fact->value = $value;
$this->content->facts[] = $fact;
}
public function addItem($item, $account)
{
$this->content->items[] = new InvoiceItemCard($item, $account);
}
public function addButton($type, $title, $value)
{
$this->content->buttons[] = new ButtonCard($type, $title, $value);
}
}

View File

@ -0,0 +1,12 @@
<?php namespace App\Libraries\Skype;
class InvoiceItemCard
{
public function __construct($invoiceItem, $account)
{
$this->title = $invoiceItem->product_key;
$this->subtitle = $invoiceItem->notes;
$this->quantity = $invoiceItem->qty;
$this->price = $account->formatMoney($invoiceItem->cost);
}
}

View File

@ -0,0 +1,28 @@
<?php namespace App\Libraries\Skype;
class SkypeResponse
{
public function __construct($type)
{
$this->type = $type;
$this->attachments = [];
}
public static function message($message)
{
$instance = new self('message/text');
$instance->setText($message);
return json_encode($instance);
}
public function setText($text)
{
$this->text = $text;
}
public function addAttachment($attachment)
{
$this->attachments[] = $attachment;
}
}

View File

@ -3,6 +3,7 @@
use stdClass;
use Exception;
use App\Libraries\CurlUtils;
use App\Libraries\Skype\SkypeResponse;
class BaseIntent
{
@ -26,7 +27,7 @@ class BaseIntent
$this->state = $state;
$this->data = $data;
var_dump($state);
//var_dump($state);
}
public static function createIntent($state, $data)
@ -38,9 +39,23 @@ class BaseIntent
$intent = $data->intents[0]->intent;
$entityType = false;
echo "Intent: $intent<p>";
foreach ($data->entities as $entity) {
if ($entity->type === 'EntityType') {
$entityType = $entity->entity;
break;
}
}
if ( ! $entityType) {
$entityType = $state->current->entityType;
}
$entityType = ucwords(strtolower($entityType));
$intent = str_replace('Entity', $entityType, $intent);
$className = "App\\Ninja\\Intents\\{$intent}Intent";
echo "Intent: $intent<p>";
if ( ! class_exists($className)) {
throw new Exception(trans('texts.intent_not_supported'));
}
@ -109,11 +124,10 @@ class BaseIntent
protected function parseClient()
{
$clientRepo = app('App\Ninja\Repositories\ClientRepository');
$client = false;
foreach ($this->data->entities as $param) {
if ($param->type == 'Client') {
if ($param->type == 'Name') {
$client = $clientRepo->findPhonetically($param->entity);
}
}
@ -125,6 +139,10 @@ class BaseIntent
{
$data = [];
if ( ! isset($this->data->compositeEntities)) {
return [];
}
foreach ($this->data->compositeEntities as $compositeEntity) {
if ($compositeEntity->parentType != 'FieldValuePair') {
continue;
@ -178,4 +196,22 @@ class BaseIntent
return $value;
}
protected function createResponse($type, $content)
{
$response = new SkypeResponse($type);
if (is_string($content)) {
$response->setText($content);
} else {
if ( ! is_array($content)) {
$content = [$content];
}
foreach ($content as $item) {
$response->addAttachment($item);
}
}
return json_encode($response);
}
}

View File

@ -11,17 +11,16 @@ class CreateInvoiceIntent extends InvoiceIntent
$invoiceItems = $this->parseInvoiceItems();
if ( ! $client) {
return view('bots.skype.message', [
'message' => trans('texts.client_not_found')
])->render();
throw new Exception(trans('texts.client_not_found'));
}
$data = [
$data = array_merge($this->parseFields(), [
'client_id' => $client->id,
'invoice_items' => $invoiceItems,
];
]);
var_dump($data);
$valid = EntityModel::validate($data, ENTITY_INVOICE);
if ($valid !== true) {
@ -29,6 +28,7 @@ class CreateInvoiceIntent extends InvoiceIntent
}
$invoice = $this->invoiceRepo->save($data);
$invoiceItemIds = array_map(function($item) {
return $item['public_id'];
}, $invoice->invoice_items->toArray());
@ -38,8 +38,6 @@ class CreateInvoiceIntent extends InvoiceIntent
$this->setEntities(ENTITY_INVOICE, $invoice->public_id);
$this->setEntities(ENTITY_INVOICE_ITEM, $invoiceItemIds);
return view('bots.skype.invoice', [
'invoice' => $invoice
])->render();
return $this->createResponse('message/card.receipt', $invoice->present()->skypeBot);
}
}

View File

@ -1,39 +0,0 @@
<?php namespace App\Ninja\Intents;
use Exception;
use App\Models\EntityModel;
use App\Models\Invoice;
class CreateInvoiceItemsIntent extends InvoiceIntent
{
public function process()
{
$invoice = $this->invoice();
$invoiceItems = $this->parseInvoiceItems();
$data = [
'public_id' => $invoice->public_id,
'invoice_items' => array_merge($invoice->invoice_items->toArray(), $invoiceItems),
];
var_dump($data);
$valid = EntityModel::validate($data, ENTITY_INVOICE, $invoice);
if ($valid !== true) {
throw new Exception($valid);
}
$invoice = $this->invoiceRepo->save($data, $invoice);
$invoiceItems = array_slice($invoice->invoice_items->toArray(), count($invoiceItems) * -1);
$invoiceItemIds = array_map(function($item) {
return $item['public_id'];
}, $invoiceItems);
$this->setEntities(ENTITY_INVOICE_ITEM, $invoiceItemIds);
return view('bots.skype.invoice', [
'invoice' => $invoice->load('invoice_items')
])->render();
}
}

View File

@ -1,8 +1,9 @@
<?php namespace App\Ninja\Intents;
use Auth;
use App\Models\EntityModel;
use App\Models\Invoice;
use Auth;
use App\Libraries\Skype\SkypeResponse;
class DownloadInvoiceIntent extends InvoiceIntent
{
@ -13,8 +14,6 @@ class DownloadInvoiceIntent extends InvoiceIntent
$message = trans('texts.' . $invoice->getEntityType()) . ' ' . $invoice->invoice_number;
$message = link_to('/download/' . $invoice->invitations[0]->invitation_key, $message);
return view('bots.skype.message', [
'message' => $message
])->render();
return SkypeResponse::message($message);
}
}

View File

@ -4,6 +4,7 @@ use Auth;
use Exception;
use App\Models\EntityModel;
use App\Models\Invoice;
use App\Libraries\Skype\SkypeResponse;
class EmailInvoiceIntent extends InvoiceIntent
{
@ -20,8 +21,6 @@ class EmailInvoiceIntent extends InvoiceIntent
$message = trans('texts.bot_emailed_' . $invoice->getEntityType());
return view('bots.skype.message', [
'message' => $message
])->render();
return SkypeResponse::message($message);
}
}

View File

@ -6,6 +6,9 @@ use App\Models\Invoice;
class InvoiceIntent extends BaseIntent
{
private $_invoice;
private $_invoiceItem;
public function __construct($state, $data)
{
$this->invoiceRepo = app('App\Ninja\Repositories\InvoiceRepository');
@ -15,6 +18,10 @@ class InvoiceIntent extends BaseIntent
protected function invoice()
{
if ($this->_invoice) {
return $this->_invoice;
}
$invoiceId = $this->entity(ENTITY_INVOICE);
if ( ! $invoiceId) {
@ -34,6 +41,19 @@ class InvoiceIntent extends BaseIntent
return $invoice;
}
protected function invoiceItem()
{
if ($this->_invoiceItem) {
return $this->_invoiceItem;
}
$invoiceItemId = $this->entity(ENTITY_INVOICE_ITEM);
if ( ! $invoiceItemId) {
$invoice = $this->invoice();
}
}
protected function parseInvoiceItems()
{
$productRepo = app('App\Ninja\Repositories\ProductRepository');
@ -58,6 +78,7 @@ class InvoiceIntent extends BaseIntent
$item = $product->toArray();
$item['qty'] = $qty;
$invoiceItems[] = $item;
}
}
@ -65,4 +86,10 @@ class InvoiceIntent extends BaseIntent
return $invoiceItems;
}
protected function parseFields()
{
$data = parent::parseFields();
return $data;
}
}

View File

@ -0,0 +1,19 @@
<?php namespace App\Ninja\Intents;
use Auth;
use Exception;
use App\Models\Product;
class ListProductsIntent extends ProductIntent
{
public function process()
{
$products = Product::scope()->get();
return view('bots.skype.list', [
'items' => $products
])->render();
}
}

View File

@ -0,0 +1,15 @@
<?php namespace App\Ninja\Intents;
use Auth;
use Exception;
class ProductIntent extends BaseIntent
{
public function __construct($state, $data)
{
$this->productRepo = app('App\Ninja\Repositories\ProductRepository');
parent::__construct($state, $data);
}
}

View File

@ -9,13 +9,46 @@ class UpdateInvoiceIntent extends InvoiceIntent
public function process()
{
$invoice = $this->invoice();
$invoiceItems = $this->parseInvoiceItems();
$data = $this->parseFields();
$data = array_merge($this->parseFields(), [
'public_id' => $invoice->public_id,
'invoice_items' => array_merge($invoice->invoice_items->toArray(), $invoiceItems),
]);
dd($data);
// map the cost and qty fields to the invoice items
if (isset($data['cost']) || isset($data['quantity'])) {
foreach ($data['invoice_items'] as $key => $item) {
// if it's new or we recently created it
if (empty($item['public_id']) || in_array($item['public_id'], $this->entities(ENTITY_INVOICE_ITEM))) {
$data['invoice_items'][$key]['cost'] = isset($data['cost']) ? $data['cost'] : $item['cost'];
$data['invoice_items'][$key]['qty'] = isset($data['quantity']) ? $data['quantity'] : $item['qty'];
}
}
}
return view('bots.skype.invoice', [
'invoice' => $invoice
])->render();
var_dump($data);
$valid = EntityModel::validate($data, ENTITY_INVOICE, $invoice);
if ($valid !== true) {
throw new Exception($valid);
}
$invoice = $this->invoiceRepo->save($data, $invoice);
$invoiceItems = array_slice($invoice->invoice_items->toArray(), count($invoiceItems) * -1);
$invoiceItemIds = array_map(function($item) {
return $item['public_id'];
}, $invoiceItems);
$this->setEntities(ENTITY_INVOICE_ITEM, $invoiceItemIds);
$response = $invoice
->load('invoice_items')
->present()
->skypeBot;
return $this->createResponse('message/card.receipt', $response);
}
}

View File

@ -1,6 +1,7 @@
<?php namespace App\Ninja\Presenters;
use Utils;
use App\Libraries\Skype\InvoiceCard;
class InvoicePresenter extends EntityPresenter {
@ -22,6 +23,14 @@ class InvoicePresenter extends EntityPresenter {
return $account->formatMoney($invoice->amount, $invoice->client);
}
public function requestedAmount()
{
$invoice = $this->entity;
$account = $invoice->account;
return $account->formatMoney($invoice->getRequestedAmount(), $invoice->client);
}
public function balanceDueLabel()
{
if ($this->entity->partial > 0) {
@ -33,6 +42,26 @@ class InvoicePresenter extends EntityPresenter {
}
}
public function dueDateLabel()
{
if ($this->entity->isType(INVOICE_TYPE_STANDARD)) {
return trans('texts.due_date');
} else {
return trans('texts.valid_until');
}
}
public function discount()
{
$invoice = $this->entity;
if ($invoice->is_amount_discount) {
return $invoice->account->formatMoney($invoice->discount);
} else {
return $invoice->discount . '%';
}
}
// https://schema.org/PaymentStatusType
public function paymentStatus()
{
@ -107,4 +136,9 @@ class InvoicePresenter extends EntityPresenter {
return trans('texts.auto_bill_notification', $data);
}
public function skypeBot()
{
return new InvoiceCard($this->entity);
}
}

View File

@ -12,15 +12,25 @@
{
"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 }}"
}
@if ($invoice->due_date)
, {
"key": "{{ $invoice->present()->dueDateLabel }}:",
"value": "{{ $invoice->present()->due_date }}"
}
@endif
@if ($invoice->po_number)
, {
"key": "{{ trans('texts.po_number') }}:",
"value": "{{ $invoice->po_number }}"
}
@endif
@if ($invoice->discount)
, {
"key": "{{ trans('texts.discount') }}:",
"value": "{{ $invoice->present()->discount }}"
}
@endif
],
"items":[
@foreach ($invoice->invoice_items as $item)
@ -38,7 +48,7 @@
@if (false)
"tax":"0.00",
@endif
"total":"{{ $invoice->present()->amount }}",
"total":"{{ $invoice->present()->requestedAmount }}",
"buttons":[
{
"type":"imBack",

View File

@ -0,0 +1,29 @@
{
"type":"message/card.carousel",
"attachments":[
@foreach ($items as $item)
@if ($items[0] != $item)
,
@endif
{
"contentType": "application/vnd.microsoft.card.hero",
"content": {
"title": "{{ $item['title'] }}",
"subtitle": "{{ $item['subtitle'] }}",
"buttons": [
@foreach($item['buttons'] as $button)
@if ($items['buttons'][0] != $button)
,
@endif
{
"type": "{{ $button['type'] }}",
"title": "{{ $button['title'] }}",
"value": "https://en.wikipedia.org/wiki/{cardContent.Key}"
}
@endforeach
]
}
}
@endforeach
]
}