added new sms routing classes

partial #3752
This commit is contained in:
Devin Smith 2014-11-26 10:41:39 -08:00
parent 295f9dad86
commit 73f7e54965
7 changed files with 357 additions and 187 deletions

View File

@ -1,188 +1,6 @@
<?php
class Controller_api_twilio_driver extends Crunchbutton_Controller_Rest {
const ACTION_ACCEPT = 'accept';
const ACTION_PICKEDUP = 'picked';
const ACTION_DELIVERED = 'delivered';
const ACTION_DETAILS = 'details';
const ACTION_HELP = 'help';
const ACTION_NONE = 'none';
public function init() {
$phone = str_replace( '+1', '', $_REQUEST[ 'From' ] );
$body = trim( $_REQUEST[ 'Body' ] );
if( trim( $phone ) == '' ){
$this->adminError();
$this->log( [ 'action' => 'admin not found', 'phone' => $phone, 'body' => $body ] );
exit();
}
$admin = Admin::getByPhone( $phone );
if( !$admin->id_admin ){
$this->adminError();
$this->log( [ 'action' => 'admin not found', 'phone' => $phone, 'body' => $body ] );
exit();
}
$this->log( [ 'action' => 'message received', 'id_admin' => $admin->id_admin, 'name' => $admin->name, 'phone' => $phone, 'body' => $body ] );
$action = $this->parseVerb( $body );
$id_order = $this->parseOrder( $body );
$order = Order::o( $id_order );
if( $order->id_order ){
switch ( $action ) {
case Controller_api_twilio_driver::ACTION_ACCEPT:
$this->accept($order->setStatus(Crunchbutton_Order_Action::DELIVERY_ACCEPTED, true), $id_order );
break;
case Controller_api_twilio_driver::ACTION_PICKEDUP:
$this->picked($order->setStatus(Crunchbutton_Order_Action::DELIVERY_PICKEDUP), $id_order );
break;
case Controller_api_twilio_driver::ACTION_DELIVERED:
$this->delivered($order->setStatus(Crunchbutton_Order_Action::DELIVERY_DELIVERED), $id_order );
break;
case Controller_api_twilio_driver::ACTION_DETAILS:
$this->details( $order );
break;
case Controller_api_twilio_driver::ACTION_HELP:
$this->help();
break;
case Controller_api_twilio_driver::ACTION_NONE:
default:
$this->help();
break;
}
} else {
if( $action == Controller_api_twilio_driver::ACTION_HELP ){
$this->help();
} else {
$this->help( true );
}
}
}
public function adminError(){
echo $this->response( false );
}
public function help( $invalidOrder = false ){
if( $invalidOrder ){
echo $this->response( 'Invalid order.' );
} else {
echo $this->response( 'You should use "order command".' . "\n" . 'Accepted commands: accept (or a), picked (or p), delivered (or d) or details. ' . "\n" . 'eg. 123 p' );
}
$this->log( [ 'action' => 'help requested', 'invalidOrder' => $invalidOrder ] );
}
public function accept( $success, $id_order ){
if( $success ){
echo $this->response( 'Order #' . $id_order . ' accepted' );
$this->log( [ 'action' => 'order accepted', 'id_order' => $id_order ] );
} else {
echo $this->response( 'Error accepting the order #' . $id_order );
$this->log( [ 'action' => 'accept error', 'id_order' => $id_order ] );
}
}
public function picked( $success, $id_order ){
if( $success ){
echo $this->response( 'Changed order #' . $id_order . ' status to picked up' );
$this->log( [ 'action' => 'order picked up', 'id_order' => $id_order ] );
} else {
echo $this->response( 'Error changing order #' . $id_order . ' status to picked up' );
$this->log( [ 'action' => 'picked up error', 'id_order' => $id_order ] );
}
}
public function delivered( $success, $id_order ){
if( $success ){
echo $this->response( 'Changed order #' . $id_order . ' status to delivered' );
$this->log( [ 'action' => 'order delivered', 'id_order' => $id_order ] );
} else {
echo $this->response( 'Error changing order #' . $id_order . ' status to delivered' );
$this->log( [ 'action' => 'delivered error', 'id_order' => $id_order ] );
}
}
public function details( $order ){
echo $this->response( $order->message( 'sms-driver' ) );
$this->log( [ 'action' => 'details requested', 'id_order' => $order->id_order ] );
}
public function response( $content ){
header( 'Content-type: text/xml' );
if( $content ){
$content = '<SMS>' . $content . '</SMS>';
} else {
$content = '';
}
return '<?xml version="1.0" encoding="UTF-8"?>'."\n" .'<Response>' . $content . '</Response>';
}
public function parseOrder( $words ){
$words = explode( ' ', $words );
foreach( $words as $word ){
$word = trim( $word );
if( is_numeric( $word ) ){
return intval( $word );
}
}
return false;
}
public function parseVerb( $words ){
$accept = [ 'accept', 'acept', 'a' ];
$picked = [ 'picked up', 'picked', 'got', 'up', 'p' ];
$delivered = [ 'delivered', 'd' ];
$details = [ 'details' ];
$help = [ 'help', 'h' ];
$words = explode( ' ', $words );
foreach( $words as $word ){
$word = trim( $word );
if( is_numeric( $word ) ){
continue;
}
$word = strtolower( $word );
// accept
if( in_array( $word, $accept ) ){
return Controller_api_twilio_driver::ACTION_ACCEPT;
}
// picked up
if( in_array( $word, $picked ) ){
return Controller_api_twilio_driver::ACTION_PICKEDUP;
}
// delivered
if( in_array( $word, $delivered ) ){
return Controller_api_twilio_driver::ACTION_DELIVERED;
}
// details
if( in_array( $word, $details ) ){
return Controller_api_twilio_driver::ACTION_DETAILS;
}
// help
if( in_array( $word, $help ) ){
return Controller_api_twilio_driver::ACTION_HELP;
}
}
return Controller_api_twilio_driver::ACTION_NONE;
}
public function log( $content ){
Log::debug( array_merge ( $content, [ 'type' => 'driver-sms' ] ) );
}
}
Message_Incoming_Sms::route($this->request());
}
}

View File

@ -129,8 +129,10 @@ class Crunchbutton_Admin extends Cana_Table {
return $login;
}
public function getByPhone( $phone ){
return Crunchbutton_Admin::q( "SELECT * FROM admin a WHERE REPLACE( REPLACE( a.txt, ' ', '' ), '-', '' ) = '{$phone}' OR REPLACE( REPLACE( a.phone, ' ', '' ), '-', '' ) = '{$phone}' ORDER BY id_admin DESC LIMIT 1 " );
public function getByPhone( $phone, $activeOnly = false){
return Crunchbutton_Admin::q(
"SELECT * FROM admin a WHERE ".($activeOnly ? 'active=1 AND' : '')." (REPLACE( REPLACE( a.txt, ' ', '' ), '-', '' ) = '{$phone}' OR REPLACE( REPLACE( a.phone, ' ', '' ), '-', '' ) = '{$phone}') ORDER BY id_admin DESC LIMIT 1 "
);
}
public function getByPhoneSetup( $phone ){

View File

@ -0,0 +1,139 @@
<?php
class Crunchbutton_Message_Incoming_Driver extends Cana_Model {
const ACTION_ACCEPT = 'accept';
const ACTION_PICKEDUP = 'picked';
const ACTION_DELIVERED = 'delivered';
const ACTION_DETAILS = 'details';
const ACTION_HELP = 'help';
public function __construct($params) {
$parsed = $this->parseBody($params->body);
$action = $parsed['verb'];
$order = Order::o(intval($parsed['order']));
$response = [];
if ($order->id_order) {
switch ($action) {
case self::ACTION_ACCEPT:
$response = ['msg' => $this->accept($order->setStatus(Crunchbutton_Order_Action::DELIVERY_ACCEPTED, true, $params->admin), $order), 'stop' => true];
break;
case self::ACTION_PICKEDUP:
$response = ['msg' => $this->pickedup($order->setStatus(Crunchbutton_Order_Action::DELIVERY_PICKEDUP, false, $params->admin), $order), 'stop' => true];
break;
case self::ACTION_DELIVERED:
$response = ['msg' => $this->delivered($order->setStatus(Crunchbutton_Order_Action::DELIVERY_DELIVERED, false, $params->admin), $order), 'stop' => true];
break;
case self::ACTION_DETAILS:
$response = ['msg' => $this->details($order), 'stop' => true];
break;
case self::ACTION_HELP:
$response = ['msg' => $this->help($order), 'stop' => false];
break;
}
} elseif ($action == self::ACTION_HELP) {
$response = ['msg' => $this->help(), 'stop' => false];
}
$this->response = (object)$response;
}
public function help($order = null) {
$response =
"Driver command usage: \"".($order ? $order->id_order : 'order')." command\"\n".
"Commands: \n".
" accept (or a)\n".
" picked (or p)\n".
" delivered (or d)\n".
" details\n".
"Ex: ".($order ? $order->id_order : '123')." p";
$this->log( [ 'action' => 'help requested', 'invalidOrder' => $invalidOrder ] );
return $response;
}
public function accept($success, $order) {
if ($success) {
$response = 'Order #' . $order->id_order . ' accepted';
$this->log( [ 'action' => 'order accepted', 'id_order' => $order->id_order ] );
} else {
$response = 'Error accepting order #' . $order->id_order;
$this->log( [ 'action' => 'accept error', 'id_order' => $order->id_order ] );
}
return $response;
}
public function pickedup($success, $order) {
if ($success) {
$response = 'Changed order #' . $order->id_order . ' status to picked up';
$this->log( [ 'action' => 'order picked up', 'id_order' => $order->id_order ] );
} else {
$response = 'Error changing order #' . $order->id_order . ' status to picked up';
$this->log( [ 'action' => 'picked up error', 'id_order' => $order->id_order ] );
}
return $response;
}
public function delivered($success, $order) {
if ($success) {
$response = 'Changed order #' . $order->id_order . ' status to delivered';
$this->log( [ 'action' => 'order delivered', 'id_order' => $order->id_order ] );
} else {
$response = 'Error changing order #' . $order->id_order . ' status to delivered';
$this->log( [ 'action' => 'delivered error', 'id_order' => $order->id_order ] );
}
return $response;
}
public function details($order){
$response = $order->message('sms-driver');
$this->log( [ 'action' => 'details requested', 'id_order' => $order->id_order ] );
return $response;
}
public function parseBody($body) {
$body = strtolower($body);
$verbs = [
self::ACTION_ACCEPT => [ 'accept', 'acept', 'a' ],
self::ACTION_PICKEDUP => [ 'picked up', 'picked', 'pick', 'got', 'up', 'p' ],
self::ACTION_DELIVERED => [ 'delivered', 'd' ],
self::ACTION_DETAILS => [ 'details', 'deets', 'det' ],
self::ACTION_HELP => [ 'help', 'h' ]
];
if (preg_match('/^help|h$/',$body)) {
return ['verb' => self::ACTION_HELP, 'order' => null];
}
foreach ($verbs as $verb => $verbList) {
foreach ($verbList as $v) {
if (preg_match('/^((#)?([0-9]+) ('.$v.'))|(('.$v.') (#)?([0-9]+))$/', $body, $matches)) {
if ($matches[5]) {
return ['verb' => $verb, 'order' => $matches[8]];
} elseif ($matches[1]) {
return ['verb' => $verb, 'order' => $matches[3]];
}
return false;
}
}
}
return false;
}
public function log($content) {
Log::debug( array_merge ( $content, [ 'type' => 'driver-sms' ] ) );
}
}

View File

@ -0,0 +1,17 @@
<?php
class Crunchbutton_Message_Incoming_Response extends Cana_Model {
public static function twilioSms($response) {
//header('Content-type: text/xml');
if ($response) {
foreach ($response as $res) {
if ($res->msg) {
$sms .= '<SMS>' . $res->msg . '</SMS>';
}
}
}
echo '<?xml version="1.0" encoding="UTF-8"?>'."\n" .'<Response>' . $sms . '</Response>';
}
}

View File

@ -0,0 +1,59 @@
<?php
class Crunchbutton_Message_Incoming_Sms extends Cana_Model {
public static function route($request) {
$phone = str_replace('+1', '', $request['From']);
$body = trim($request['Body']);
$admin = Admin::getByPhone($phone, true);
if (!$phone || !$body) {
// error
header('HTTP/1.0 400 Bad Request');
exit;
}
// routing for drivers and support
if ($admin->id_admin) {
Log::debug([
'type' => 'driver-sms',
'action' => 'message received',
'id_admin' => $admin->id_admin,
'name' => $admin->name,
'phone' => $phone,
'body' => $body
]);
$params = (object)[
'body' => $body,
'phone' => $phone,
'admin' => $admin
];
if ($admin->isDriver()) {
$msg[] = (new Message_Incoming_Driver($params))->response;
}
/*
if (!$msg[0]->stop && $admin->isSupport()) {
$msg[] = (new Message_Incoming_Support($params))->response;
}
*/
if ($msg) {
Message_Incoming_Response::twilioSms($msg);
exit;
}
}
/*
// routing for incoming support messges
$params = (object)[
'body' => $body,
'phone' => $phone
];
$msg[] = (new Message_Incoming_Customer($params))->response;
if ($msg) {
Message_Incoming_Response::twilioSms($msg);
exit;
}
*/
}
}

View File

@ -0,0 +1,135 @@
<?php
class Crunchbutton_Message_Incoming_Support extends Cana_model {
const ACTION_ACCEPT = 'accept';
const ACTION_PICKEDUP = 'picked';
const ACTION_DELIVERED = 'delivered';
const ACTION_DETAILS = 'details';
const ACTION_HELP = 'help';
public function __construct($params) {
$parsed = $this->parseBody($params->body);
$action = $parsed['verb'];
$order = Order::o(intval($parsed['order']));
$response = [];
if ($order->id_order) {
switch ($action) {
case self::ACTION_ACCEPT:
$response = ['msg' => $this->accept($order->setStatus(Crunchbutton_Order_Action::DELIVERY_ACCEPTED, true), $order), 'stop' => true];
break;
case self::ACTION_PICKEDUP:
$response = ['msg' => $this->pickedup($order->setStatus(Crunchbutton_Order_Action::DELIVERY_PICKEDUP), $order), 'stop' => true];
break;
case self::ACTION_DELIVERED:
$response = ['msg' => $this->delivered($order->setStatus(Crunchbutton_Order_Action::DELIVERY_DELIVERED), $order), 'stop' => true];
break;
case self::ACTION_DETAILS:
$response = ['msg' => $this->details($order), 'stop' => true];
break;
case self::ACTION_HELP:
$response = ['msg' => $this->help($order), 'stop' => false];
break;
}
} elseif ($action == self::ACTION_HELP) {
$response = ['msg' => $this->help(), 'stop' => false];
}
$this->response = (object)$response;
}
public function help($order = null) {
$response =
"Driver command usage: \"".($order ? $order->id_order : 'order')." command\"\n".
"Commands: \n".
" accept (or a)\n".
" picked (or p)\n".
" delivered (or d)\n".
" details\n";
"Ex: ".($order ? $order->id_order : '123')." p";
$this->log( [ 'action' => 'help requested', 'invalidOrder' => $invalidOrder ] );
$this->response($response);
}
public function accept($success, $order) {
if ($success) {
$response = 'Order #' . $order->id_order . ' accepted';
$this->log( [ 'action' => 'order accepted', 'id_order' => $order->id_order ] );
} else {
$response = 'Error accepting order #' . $order->id_order;
$this->log( [ 'action' => 'accept error', 'id_order' => $order->id_order ] );
}
return $response;
}
public function pickedup($success, $order) {
if ($success) {
$response = 'Changed order #' . $order->id_order . ' status to picked up';
$this->log( [ 'action' => 'order picked up', 'id_order' => $order->id_order ] );
} else {
$response = 'Error changing order #' . $order->id_order . ' status to picked up';
$this->log( [ 'action' => 'picked up error', 'id_order' => $order->id_order ] );
}
return $response;
}
public function delivered($success, $order) {
if ($success) {
$response = 'Changed order #' . $order->id_order . ' status to delivered';
$this->log( [ 'action' => 'order delivered', 'id_order' => $order->id_order ] );
} else {
$response = 'Error changing order #' . $order->id_order . ' status to delivered';
$this->log( [ 'action' => 'delivered error', 'id_order' => $order->id_order ] );
}
return $response;
}
public function details($order){
$response = $order->message('sms-driver');
$this->log( [ 'action' => 'details requested', 'id_order' => $order->id_order ] );
return $response;
}
public function parseBody($body) {
$body = strtolower($body);
$verbs = [
self::ACTION_ACCEPT => [ 'accept', 'acept', 'a' ],
self::ACTION_PICKEDUP => [ 'picked up', 'picked', 'pick', 'got', 'up', 'p' ],
self::ACTION_DELIVERED => [ 'delivered', 'd' ],
self::ACTION_DETAILS => [ 'details', 'deets', 'det' ],
self::ACTION_HELP => [ 'help', 'h' ]
];
foreach ($verbs as $verb => $verbList) {
foreach ($verbList as $v) {
if (preg_match('/^((#)?([0-9]+) ('.$v.'))|(('.$v.') (#)?([0-9]+))$/', $body, $matches)) {
if ($matches[5]) {
return ['verb' => $verb, 'order' => $matches[8]];
} elseif ($matches[1]) {
return ['verb' => $verb, 'order' => $matches[3]];
}
return false;
}
}
}
return false;
}
public function log($content) {
Log::debug( array_merge ( $content, [ 'type' => 'driver-sms' ] ) );
}
}