1020 lines
34 KiB
PHP
1020 lines
34 KiB
PHP
<?php
|
|
|
|
class Crunchbutton_Support extends Cana_Table_Trackchange {
|
|
|
|
const TYPE_SMS = 'SMS';
|
|
const TYPE_BOX_NEED_HELP = 'BOX_NEED_HELP';
|
|
const TYPE_WARNING = 'WARNING';
|
|
const TYPE_TICKET = 'TICKET';
|
|
const TYPE_COCKPIT_CHAT = 'COCKPIT_CHAT';
|
|
|
|
const CONFIG_AUTO_REPLY_KEY = 'auto-reply-text';
|
|
|
|
const STATUS_OPEN = 'open';
|
|
const STATUS_CLOSED = 'closed';
|
|
|
|
const CUSTOM_SERVICE_GROUP_NAME_KEY = 'custom-service-group-name';
|
|
|
|
public function __construct($id = null) {
|
|
parent::__construct();
|
|
$this
|
|
->table('support')
|
|
->idVar('id_support')
|
|
->load($id);
|
|
if(!$id) {
|
|
date_default_timezone_set('UTC'); // always save in utc
|
|
$this->datetime = date('Y-m-d H:i:s e');
|
|
$this->status = 'open';
|
|
}
|
|
}
|
|
|
|
public function getFirstCustomerMessage(){
|
|
if( $this->id_support ){
|
|
$first_cs_reply = Crunchbutton_Support_Message::q( 'SELECT MIN( id_support_message ) AS id_support_message FROM support_message WHERE id_support = ' . $this->id_support . ' AND ( `from` = "' . Crunchbutton_Support_Message::TYPE_FROM_REP . '" OR `from` = "' . Crunchbutton_Support_Message::TYPE_FROM_SYSTEM . '" )' );
|
|
$where = '';
|
|
if( $first_cs_reply->id_support_message ){
|
|
$where = ' AND id_support_message < "' . $first_cs_reply->id_support_message . '"';
|
|
}
|
|
$query = 'SELECT * FROM support_message WHERE id_support = "' . $this->id_support . '" AND `from` = "' . Crunchbutton_Support_Message::TYPE_FROM_CLIENT . '" ' . $where . ' ORDER BY id_support_message ASC ';
|
|
$messages = Crunchbutton_Support_Message::q( $query );
|
|
$text = '';
|
|
foreach( $messages as $message ){
|
|
$text .= $message->body;
|
|
}
|
|
return $text;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public function tellCustomerService( $message ){
|
|
|
|
Crunchbutton_Message_Sms::send([
|
|
'to' => Crunchbutton_Support::getUsers(),
|
|
'from' => 'customer',
|
|
'message' => $message,
|
|
'reason' => Crunchbutton_Message_Sms::REASON_SUPPORT
|
|
]);
|
|
|
|
|
|
Log::debug( [ 'to' => Crunchbutton_Support::getUsers(), 'message' => $message, 'type' => 'support-tell-cs' ] );
|
|
|
|
}
|
|
|
|
// @todo: remove the getusers function in favor of getsupport
|
|
public static function getSupport() {
|
|
return Admin::q('
|
|
select a.* FROM admin a
|
|
left join admin_group ag using(id_admin)
|
|
left join `group` g using(id_group)
|
|
where g.name="'.Config::getVal( Crunchbutton_Support::CUSTOM_SERVICE_GROUP_NAME_KEY ).'"
|
|
');
|
|
}
|
|
|
|
public function getUsers( $forceAll = false ){
|
|
$support = array();
|
|
$group = Crunchbutton_Group::byName( Config::getVal( Crunchbutton_Support::CUSTOM_SERVICE_GROUP_NAME_KEY ) );
|
|
if( $group->id_group ){
|
|
$users = Crunchbutton_Admin::q( "SELECT a.* FROM admin a INNER JOIN admin_group ag ON ag.id_admin = a.id_admin AND ag.id_group = {$group->id_group}" );
|
|
if ( $users->count() > 0 ) {
|
|
foreach ( $users as $user ) {
|
|
// Check all the places where we send text message to CS and send it just to drivers that are current working.
|
|
if( $user->name && $user->txt ){
|
|
if( $forceAll || $user->isWorking() ){
|
|
$support[ $user->name ] = $user->txt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// no users, return a empty array
|
|
return $support;
|
|
}
|
|
|
|
public function lastReplyFrom(){
|
|
return $this->lastMessage()->from;
|
|
}
|
|
|
|
public function firstMessage(){
|
|
return Crunchbutton_Support_Message::q( 'SELECT * FROM support_message WHERE id_support = ' . $this->id_support . ' ORDER BY date ASC, id_support_message ASC LIMIT 1 ' );
|
|
}
|
|
|
|
public function lastMessage(){
|
|
return Crunchbutton_Support_Message::q( 'SELECT * FROM support_message WHERE id_support = ' . $this->id_support . ' ORDER BY date DESC, id_support_message DESC LIMIT 1 ' );
|
|
}
|
|
|
|
public function lastAdminSysMessage(){
|
|
return Crunchbutton_Support_Message::q( 'SELECT * FROM support_message WHERE id_support = ' . $this->id_support . ' AND ( `from` = "' . Crunchbutton_Support_Message::TYPE_FROM_REP . '" OR `from` = "' . Crunchbutton_Support_Message::TYPE_FROM_SYSTEM . '" ) ORDER BY date DESC, id_support_message DESC LIMIT 1 ' );
|
|
}
|
|
|
|
public function lastAdminMessage(){
|
|
return Crunchbutton_Support_Message::q( 'SELECT * FROM support_message WHERE id_support = ' . $this->id_support . ' AND `from` = "' . Crunchbutton_Support_Message::TYPE_FROM_REP . '" ORDER BY date DESC, id_support_message DESC LIMIT 1 ' );
|
|
}
|
|
|
|
public function lastValidOpenMessage(){
|
|
return Crunchbutton_Support_Message::q( 'SELECT * FROM support_message WHERE id_support = ' . $this->id_support . ' AND ( ( `from` = "' . Crunchbutton_Support_Message::TYPE_FROM_CLIENT . '" ) OR `from` = "' . Crunchbutton_Support_Message::TYPE_FROM_SYSTEM . '" AND type = "' . Crunchbutton_Support_Message::TYPE_NOTE . '" AND visibility = "' . Crunchbutton_Support_Message::TYPE_VISIBILITY_INTERNAL . '" ) ORDER BY date DESC, id_support_message DESC LIMIT 1 ' );
|
|
}
|
|
|
|
public function lastCustomerMessage(){
|
|
return Crunchbutton_Support_Message::q( 'SELECT * FROM support_message WHERE id_support = ' . $this->id_support . ' AND `from` = "' . Crunchbutton_Support_Message::TYPE_FROM_CLIENT . '" ORDER BY date DESC, id_support_message DESC LIMIT 1 ' );
|
|
}
|
|
|
|
public function addCustomerNameByPhone( $phone, $name ){
|
|
if( trim( $name ) != '' ){
|
|
$id_support = false;
|
|
$messages = Crunchbutton_Support_Message::byPhone( $phone );
|
|
foreach( $messages as $message ){
|
|
$message->name = $name;
|
|
$message->save();
|
|
$id_support = $message->id_support;
|
|
}
|
|
}
|
|
$support = Crunchbutton_Support::o( $id_support );
|
|
$support->addSystemMessage( c::admin()->name . ' changed the customer name to ' . $name );
|
|
return true;
|
|
}
|
|
|
|
public function name(){
|
|
$user = User::o( $this->id_user );
|
|
if( $user->name ){
|
|
return $user->name;
|
|
}
|
|
$message = $this->firstMessage();
|
|
if( $message->name ){
|
|
return $message->name;
|
|
}
|
|
return '<i>No name</i>';
|
|
}
|
|
|
|
public function message(){
|
|
$message = $this->firstMessage();
|
|
return $message->body;
|
|
}
|
|
|
|
public function clearPhone( $phone ){
|
|
$phone = str_replace( ' ' , '', $phone );
|
|
$phone = str_replace( '-' , '', $phone );
|
|
$phone = str_replace( '(' , '', $phone );
|
|
$phone = str_replace( ')' , '', $phone );
|
|
return $phone;
|
|
}
|
|
public function phone(){
|
|
$phone = $this->phone;
|
|
$phone = preg_replace('/[^\d]*/i','',$phone);
|
|
$phone = preg_replace('/(\d{3})(\d{3})(.*)/', '\\1-\\2-\\3', $phone);
|
|
return $phone;
|
|
}
|
|
|
|
public function createNewChat( $params ){
|
|
// try to get an existing session
|
|
$twilio_session = Session_Twilio::sessionByPhone( $params[ 'From' ] );
|
|
|
|
$phone = Crunchbutton_Support::clearPhone( $params[ 'From' ] );
|
|
|
|
if( !$twilio_session->id_session_twilio ){
|
|
|
|
// Create new session
|
|
$session = new Crunchbutton_Session_Adapter();
|
|
$fakeSessionId = substr( str_replace( '.' , '', uniqid( rand(), true ) ), 0, 32 );
|
|
$session->write( $fakeSessionId );
|
|
$session->save();
|
|
|
|
// Create a new session twilio
|
|
$twilio_session = new Crunchbutton_Session_Twilio;
|
|
$twilio_session->id_session = $session->id_session;
|
|
$twilio_session->data = json_encode( $params );
|
|
$twilio_session->phone = $phone;
|
|
$twilio_session->save();
|
|
}
|
|
|
|
// Get the current support ticket
|
|
$support = Support::getByTwilioSessionId( $twilio_session->id_session_twilio );
|
|
$createNewTicket = false;
|
|
// if a user send a new message a day later, make sure it creates a new issue - #2453
|
|
if( $support->id_support ){
|
|
$now = new DateTime( 'now', new DateTimeZone( c::config()->timezone ) );
|
|
$support_date = $support->date()->get(0);
|
|
if( $support_date ){
|
|
$interval = $now->diff( $support_date );
|
|
$seconds = ( $interval->s ) + ( $interval->i * 60 ) + ( $interval->h * 60 * 60 ) + ( $interval->d * 60 * 60 * 24 ) + ( $interval->m * 60 * 60 * 24 * 30 ) + ( $interval->y * 60 * 60 * 24 * 365 );
|
|
// This ticket is too old - create a new one
|
|
if( $seconds >= 86400 ){
|
|
$createNewTicket = true;
|
|
}
|
|
} else {
|
|
$createNewTicket = true;
|
|
}
|
|
} else {
|
|
$createNewTicket = true;
|
|
}
|
|
|
|
if( $createNewTicket ) {
|
|
// Create a new sms ticket
|
|
$support = Crunchbutton_Support::createNewSMSTicket( [ 'phone' => $phone,
|
|
'name' => $params[ 'Name' ],
|
|
'body' => '(Ticket created at cockpit)',
|
|
'id_session_twilio' => $twilio_session->id_session_twilio ] );
|
|
} else {
|
|
if( $support->status == Crunchbutton_Support::STATUS_CLOSED ){
|
|
$support->status = Crunchbutton_Support::STATUS_OPEN;
|
|
$support->addSystemMessage( 'Ticket reopened at cockpit' );
|
|
} else {
|
|
$support->addSystemMessage( 'Chat started by fake sms' );
|
|
}
|
|
}
|
|
$support->addAdminReply( $params[ 'Body' ] );
|
|
return $support;
|
|
}
|
|
|
|
public function createNewSMSTicket( $params = [] ){
|
|
$messageParams = [];
|
|
$support = new Crunchbutton_Support();
|
|
$support->type = Crunchbutton_Support::TYPE_SMS;
|
|
$support->phone = $params[ 'phone' ];
|
|
$support->status = Crunchbutton_Support::STATUS_OPEN;
|
|
$support->ip = $_SERVER[ 'REMOTE_ADDR' ];
|
|
$support->id_session_twilio = $params[ 'id_session_twilio' ];
|
|
$support->date = date( 'Y-m-d H:i:s' );
|
|
if( $params[ 'id_order' ] ) {
|
|
$order = Order::o( $params[ 'id_order' ] );
|
|
$support->id_order = $order->id_order;
|
|
$support->id_restaurant = $order->id_restaurant;
|
|
$support->id_user = $order->id_user;
|
|
$messageParams[ 'name' ] = $order->name;
|
|
}
|
|
if( trim( $messageParams[ 'name' ] ) == '' && trim( $params[ 'name' ] ) != '' ){
|
|
$messageParams[ 'name' ] = $params[ 'name' ];
|
|
}
|
|
$support->save();
|
|
// Params to create the new Support message
|
|
$messageParams[ 'phone' ] = $params[ 'phone' ];
|
|
$messageParams[ 'body' ] = $params[ 'body' ];
|
|
$messageParams['media'] = $params['media'];
|
|
$support->addCustomerMessage( $messageParams );
|
|
return Crunchbutton_Support::o( $support->id_support );
|
|
}
|
|
|
|
public function createNewBoxTicket( $params = [] ){
|
|
$messageParams = [];
|
|
$support = new Crunchbutton_Support();
|
|
$support->type = Crunchbutton_Support::TYPE_BOX_NEED_HELP;
|
|
$support->phone = $params[ 'phone' ];
|
|
$support->status = Crunchbutton_Support::STATUS_OPEN;
|
|
$support->ip = $_SERVER[ 'REMOTE_ADDR' ];
|
|
$support->id_session_twilio = $params[ 'id_session_twilio' ];
|
|
$support->date = date( 'Y-m-d H:i:s' );
|
|
if( c::user()->id_user ){
|
|
$support->id_user = c::user()->id_user;
|
|
}
|
|
$support->save();
|
|
// Params to create the new Support message
|
|
$messageParams[ 'name' ] = $params[ 'name' ];
|
|
$messageParams[ 'phone' ] = $params[ 'phone' ];
|
|
$messageParams[ 'body' ] = $params[ 'body' ];
|
|
$support->addCustomerMessage( $messageParams );
|
|
return Crunchbutton_Support::o( $support->id_support );
|
|
}
|
|
|
|
public function createNewTicket( $params = [] ){
|
|
$support = new Crunchbutton_Support();
|
|
$support->type = Crunchbutton_Support::TYPE_TICKET;
|
|
$support->status = Crunchbutton_Support::STATUS_OPEN;
|
|
$support->id_session_twilio = null;
|
|
$support->id_admin = c::admin()->id_admin;
|
|
$support->date = date( 'Y-m-d H:i:s' );
|
|
if( $params[ 'id_order' ] ) {
|
|
$order = Order::o( $params[ 'id_order' ] );
|
|
$support->id_order = $order->id_order;
|
|
$support->id_restaurant = $order->id_restaurant;
|
|
$support->id_user = $order->id_user;
|
|
$support->phone = $order->phone;
|
|
}
|
|
$support->save();
|
|
|
|
if( $params[ 'id_order' ] ) {
|
|
$order = Order::o( $params[ 'id_order' ] );
|
|
$messageParams[ 'name' ] = $order->name;
|
|
$messageParams[ 'phone' ] = $order->phone;
|
|
$messageParams[ 'body' ] = $params[ 'body' ];
|
|
$support->addCustomerMessage( $messageParams );
|
|
}
|
|
|
|
$support->addSystemMessage( $params[ 'body' ] );
|
|
return Crunchbutton_Support::o( $support->id_support );
|
|
}
|
|
|
|
public function createNewWarning( $params = [] ){
|
|
$support = false;
|
|
if( $params[ 'id_order' ] ){
|
|
$support = Crunchbutton_Support::q( 'SELECT * FROM support WHERE id_order = ' . $params[ 'id_order' ] . ' AND type = "' . Crunchbutton_Support::TYPE_WARNING . '" ORDER BY id_support DESC LIMIT 1' );
|
|
}
|
|
|
|
if( !$support->id_support && $params[ 'phone' ] ){
|
|
$support = Crunchbutton_Support::q( 'SELECT * FROM support WHERE phone = "' . $params[ 'phone' ] . '" ORDER BY id_support DESC LIMIT 1' );
|
|
}
|
|
|
|
if( $support && $support->id_support ){
|
|
$open = isset( $params[ 'dont_open_ticket' ] ) ? false : true;
|
|
if( $open ){
|
|
$support->status = Crunchbutton_Support::STATUS_OPEN;
|
|
}
|
|
} else {
|
|
$support = new Crunchbutton_Support();
|
|
$support->type = Crunchbutton_Support::TYPE_WARNING;
|
|
$support->status = Crunchbutton_Support::STATUS_OPEN;
|
|
$support->ip = $_SERVER[ 'REMOTE_ADDR' ];
|
|
$support->id_session_twilio = null;
|
|
$support->date = date( 'Y-m-d H:i:s' );
|
|
if( $params[ 'id_order' ] ) {
|
|
$order = Order::o( $params[ 'id_order' ] );
|
|
$support->id_order = $order->id_order;
|
|
$support->id_restaurant = $order->id_restaurant;
|
|
$support->id_user = $order->id_user;
|
|
$support->phone = $order->phone;
|
|
} else {
|
|
if( $params[ 'phone' ] ){
|
|
$support->phone = $params[ 'phone' ];
|
|
}
|
|
}
|
|
}
|
|
$support->save();
|
|
$support->addSystemMessage( $params[ 'body' ] );
|
|
return Crunchbutton_Support::o( $support->id_support );
|
|
}
|
|
|
|
public function addCustomerMessage( $params = [] ){
|
|
|
|
$messageParams[ 'id_admin' ] = NULL;
|
|
$messageParams[ 'type' ] = Crunchbutton_Support_Message::TYPE_SMS;
|
|
$messageParams[ 'from' ] = Crunchbutton_Support_Message::TYPE_FROM_CLIENT;
|
|
$messageParams[ 'visibility' ] = Crunchbutton_Support_Message::TYPE_VISIBILITY_EXTERNAL;
|
|
$messageParams[ 'name' ] = $params[ 'name' ];
|
|
$messageParams[ 'phone' ] = $params[ 'phone' ];
|
|
$messageParams[ 'body' ] = $params[ 'body' ];
|
|
$messageParams[ 'media' ] = $params[ 'media' ];
|
|
|
|
$this->addMessage( $messageParams );
|
|
|
|
// CS Auto-Reply #5042
|
|
$support = $this;
|
|
c::timeout( function() use( $support ) {
|
|
$support->autoReply();
|
|
}, 10 * 1000 );
|
|
}
|
|
|
|
public function autoReply(){
|
|
|
|
$support = Crunchbutton_Support::o( $this->id_support );
|
|
|
|
$body = $support->autoReplyMessage();
|
|
|
|
if( $support->shoudAutoReply() && $body ){
|
|
|
|
$messageParams[ 'type' ] = Crunchbutton_Support_Message::TYPE_AUTO_REPLY;
|
|
$messageParams[ 'from' ] = Crunchbutton_Support_Message::TYPE_FROM_SYSTEM;
|
|
$messageParams[ 'visibility' ] = Crunchbutton_Support_Message::TYPE_VISIBILITY_EXTERNAL;
|
|
$messageParams[ 'phone' ] = $support->phone;
|
|
$messageParams[ 'body' ] = $body;
|
|
|
|
$message = $support->addMessage( $messageParams );
|
|
|
|
Crunchbutton_Message_Sms::send([
|
|
'to' => $message->phone,
|
|
'message' => $message->body,
|
|
'reason' => Crunchbutton_Message_Sms::REASON_AUTO_REPLY
|
|
] );
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public function autoReplyMessage(){
|
|
$message = Crunchbutton_Config::q( 'SELECT * FROM config WHERE `key` = "' . Crunchbutton_Support::CONFIG_AUTO_REPLY_KEY . '" ORDER BY RAND() LIMIT 1' );
|
|
if( $message->value ){
|
|
return $message->value;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public function lastAutoReplyByPhone( $phone ){
|
|
$query = 'SELECT sm.* FROM support s
|
|
INNER JOIN support_message sm ON sm.id_support = s.id_support
|
|
WHERE s.phone = "' . $phone . '"
|
|
AND sm.type = "' . Crunchbutton_Support_Message::TYPE_AUTO_REPLY . '"
|
|
ORDER BY id_support_message DESC LIMIT 1';
|
|
$support_message = Crunchbutton_Support_Message::q( $query )->get( 0 );
|
|
if( $support_message->id_support_message ){
|
|
return $support_message;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public function shoudAutoReply(){
|
|
$last = $this->lastAutoReplyByPhone( $this->phone );
|
|
if( !$last ){
|
|
return true;
|
|
} else {
|
|
$now = new DateTime( 'now', new DateTimeZone( c::config()->timezone ) );
|
|
if( Crunchbutton_Util::intervalMoreThan24Hours( $now->diff( $last->date() ) ) ){
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public function addAdminReply($body, $guid = null){
|
|
$body = trim($body);
|
|
if ($body) {
|
|
$admin = Crunchbutton_Admin::o( c::admin()->id_admin );
|
|
$message = $this->addAdminMessage([
|
|
'body' => $body,
|
|
'phone' => $admin->phone,
|
|
'id_admin' => c::admin()->id_admin,
|
|
'guid' => $guid
|
|
]);
|
|
if( $message->id_support_message ){
|
|
$message->notify();
|
|
}
|
|
return $message;
|
|
}
|
|
}
|
|
|
|
public function byPhone( $phone ){
|
|
$clean_phone = str_replace( '-', '', $phone );
|
|
return Crunchbutton_Support::q( "SELECT * FROM support s WHERE s.phone = '{$phone}' OR REPLACE( REPLACE( s.phone, ' ', '' ), '-', '' ) = '{$clean_phone}' ORDER BY id_support ASC " );
|
|
}
|
|
|
|
public function addAdminMessage( $params = [] ){
|
|
$hasAdmin = false;
|
|
if( $params[ 'id_admin' ] ){
|
|
$admin = Crunchbutton_Admin::o( $params[ 'id_admin' ] );
|
|
if( $admin->id_admin ){
|
|
$hasAdmin = true;
|
|
}
|
|
}
|
|
if( !$hasAdmin ){
|
|
$admin = Crunchbutton_Admin::getByPhone( $params[ 'phone' ] );
|
|
}
|
|
if( $admin->id_admin ){
|
|
$messageParams[ 'id_admin' ] = $admin->id_admin;
|
|
$messageParams[ 'type' ] = Crunchbutton_Support_Message::TYPE_SMS;
|
|
$messageParams[ 'from' ] = Crunchbutton_Support_Message::TYPE_FROM_REP;
|
|
$messageParams[ 'visibility' ] = Crunchbutton_Support_Message::TYPE_VISIBILITY_EXTERNAL;
|
|
$messageParams[ 'name' ] = $admin->firstName();
|
|
$messageParams[ 'phone' ] = $params[ 'phone' ];
|
|
$messageParams[ 'body' ] = $params[ 'body' ];
|
|
$messageParams[ 'guid' ] = $params[ 'guid' ];
|
|
$messageParams[ 'media' ] = $params[ 'media' ];
|
|
return $this->addMessage( $messageParams );
|
|
}
|
|
}
|
|
|
|
public function pendingSupport(){
|
|
Crunchbutton_Support::closeTicketsOlderThanADay();
|
|
return Crunchbutton_Support::q("SELECT s.* FROM support s
|
|
INNER JOIN ( SELECT MAX( id_support_message ), id_support, `from` FROM support_message GROUP BY id_support ORDER BY id_support DESC ) sm ON s.id_support = sm.id_support
|
|
AND s.status = '" . Crunchbutton_Support::STATUS_OPEN . "' AND sm.from = '" . Crunchbutton_Support_Message::TYPE_FROM_CLIENT . "'");
|
|
}
|
|
|
|
// close all support issues that are older than a day #2487
|
|
public function closeTicketsOlderThanADay(){
|
|
$supports = Crunchbutton_Support::q( 'SELECT s.* FROM support s WHERE s.status = "' . Crunchbutton_Support::STATUS_OPEN . '" ORDER BY id_support ASC' );
|
|
$now = new DateTime( 'now', new DateTimeZone( c::config()->timezone ) );
|
|
foreach ( $supports as $support ) {
|
|
$lastCustomerMessage = $support->lastValidOpenMessage();
|
|
$close = false;
|
|
if( $lastCustomerMessage->id_support_message ){
|
|
$support_date = $lastCustomerMessage->date()->get(0);
|
|
if( $support_date ){
|
|
$interval = $now->diff( $support_date );
|
|
$seconds = ( $interval->s ) + ( $interval->i * 60 ) + ( $interval->h * 60 * 60 ) + ( $interval->d * 60 * 60 * 24 ) + ( $interval->m * 60 * 60 * 24 * 30 ) + ( $interval->y * 60 * 60 * 24 * 365 );
|
|
if( $seconds >= 86400 ){
|
|
$close = true;
|
|
}
|
|
} else {
|
|
$close = true;
|
|
}
|
|
} else {
|
|
$support_date = $support->date();
|
|
if( $support_date ){
|
|
$interval = $now->diff( $support_date );
|
|
$seconds = ( $interval->s ) + ( $interval->i * 60 ) + ( $interval->h * 60 * 60 ) + ( $interval->d * 60 * 60 * 24 ) + ( $interval->m * 60 * 60 * 24 * 30 ) + ( $interval->y * 60 * 60 * 24 * 365 );
|
|
if( $seconds >= 86400 ){
|
|
$close = true;
|
|
}
|
|
} else {
|
|
$close = true;
|
|
}
|
|
}
|
|
if( $close ){
|
|
$support->status = Crunchbutton_Support::STATUS_CLOSED;
|
|
$support->save();
|
|
$support->addSystemMessage( 'Automatically close support ticket older than a day' );
|
|
}
|
|
}
|
|
}
|
|
|
|
public function addSystemMessage( $body ) {
|
|
$messageParams[ 'id_admin' ] = null;
|
|
$messageParams[ 'type' ] = Crunchbutton_Support_Message::TYPE_NOTE;
|
|
$messageParams[ 'from' ] = Crunchbutton_Support_Message::TYPE_FROM_SYSTEM;
|
|
$messageParams[ 'visibility' ] = Crunchbutton_Support_Message::TYPE_VISIBILITY_INTERNAL;
|
|
$messageParams[ 'body' ] = $body;
|
|
$this->addMessage( $messageParams );
|
|
}
|
|
|
|
public function addNote( $body ){
|
|
if( trim( $body ) != '' ){
|
|
$admin = Crunchbutton_Admin::o( c::admin()->id_admin );
|
|
$messageParams[ 'id_admin' ] = $admin->id_admin;
|
|
$messageParams[ 'type' ] = Crunchbutton_Support_Message::TYPE_NOTE;
|
|
$messageParams[ 'from' ] = Crunchbutton_Support_Message::TYPE_FROM_REP;
|
|
$messageParams[ 'visibility' ] = Crunchbutton_Support_Message::TYPE_VISIBILITY_INTERNAL;
|
|
$messageParams[ 'name' ] = $admin->firstName();
|
|
$messageParams[ 'phone' ] = $params[ 'phone' ];
|
|
$messageParams[ 'body' ] = $body;
|
|
$message = $this->addMessage( $messageParams );
|
|
return $message;
|
|
}
|
|
}
|
|
|
|
public function addMessage( $params = [] ){
|
|
$message = new Crunchbutton_Support_Message();
|
|
$message->id_support = $this->id_support;
|
|
$message->id_admin = $params[ 'id_admin' ];
|
|
$message->from = $params[ 'from' ];
|
|
$message->type = $params[ 'type' ];
|
|
$message->visibility = $params[ 'visibility' ];
|
|
$message->phone = $params[ 'phone' ];
|
|
$message->guid = $params[ 'guid' ];
|
|
$message->name = $params[ 'name' ];
|
|
$message->body = $params[ 'body' ];
|
|
$message->media = $params[ 'media' ];
|
|
$today = new DateTime( 'now', new DateTimeZone( c::config()->timezone ) );
|
|
$message->date = $today->format( 'Y-m-d H:i:s' );
|
|
$message->save();
|
|
|
|
// Relate the admin with the message
|
|
if( $message->id_admin ){
|
|
$this->id_admin = $message->id_admin;
|
|
$this->save();
|
|
}
|
|
|
|
return $message;
|
|
}
|
|
|
|
public function queNotify() {
|
|
$support = $this;
|
|
c::timeout(function() use($support) {
|
|
$support->notify();
|
|
});
|
|
}
|
|
|
|
public function messages(){
|
|
return Crunchbutton_Support_Message::q( "SELECT * FROM support_message WHERE id_support = {$this->id_support} ORDER BY date ASC, id_support_message ASC" );
|
|
}
|
|
|
|
public function getByTwilioSessionId( $id_session_twilio ){
|
|
return Crunchbutton_Support::q( 'SELECT * FROM support WHERE id_session_twilio = ' . $id_session_twilio . ' ORDER BY id_support DESC LIMIT 1' );
|
|
}
|
|
|
|
public function sameTwilioSession(){
|
|
return $this->getAllByTwilioSessionId( $this->id_session_twilio, $this->id_support );
|
|
}
|
|
|
|
public function getAllByTwilioSessionId( $id_session_twilio, $id_support = false ){
|
|
$where = '';
|
|
if( $id_support ){
|
|
$where = ' AND id_support != ' . $id_support;
|
|
}
|
|
return Crunchbutton_Support::q( 'SELECT * FROM support WHERE id_session_twilio = ' . $id_session_twilio . $where . ' ORDER BY id_support DESC' );
|
|
}
|
|
|
|
public function notify() {
|
|
|
|
$support = $this;
|
|
|
|
$env = c::getEnv();
|
|
$message = $this->firstMessage();
|
|
|
|
$message = "(support-" . $env . "): ".
|
|
$support->name.
|
|
"\n\n".
|
|
"phone: ".
|
|
$support->phone.
|
|
"\n\n".
|
|
$message->body;
|
|
|
|
// Log
|
|
$message = '@'.$this->id_session_twilio.' : ' . $message;
|
|
|
|
Crunchbutton_Message_Sms::send([
|
|
'to' => Crunchbutton_Support::getUsers(),
|
|
'message' => $message,
|
|
'reason' => Crunchbutton_Message_Sms::REASON_SUPPORT
|
|
]);
|
|
|
|
$this->makeACall();
|
|
|
|
}
|
|
|
|
public static function find($search = []) {
|
|
$query = 'SELECT `support`.* FROM `support` WHERE id_support IS NOT NULL ';
|
|
|
|
if ($search['type']) {
|
|
$query .= " and type='".$search['type']."' ";
|
|
}
|
|
|
|
if ($search['status']) {
|
|
$query .= " and status='".$search['status']."' ";
|
|
}
|
|
|
|
if ($search['start']) {
|
|
$s = new DateTime($search['start']);
|
|
$query .= " and DATE(`date`)>='".$s->format('Y-m-d')."' ";
|
|
}
|
|
|
|
if ($search['end']) {
|
|
$s = new DateTime($search['end']);
|
|
$query .= " and DATE(`date`)<='".$s->format('Y-m-d')."' ";
|
|
}
|
|
|
|
if ($search['search']) {
|
|
$qn = '';
|
|
$q = '';
|
|
$searches = explode(' ',$search['search']);
|
|
foreach ($searches as $word) {
|
|
if ($word{0} == '-') {
|
|
$qn .= ' and `support`.name not like "%'.substr($word,1).'%" ';
|
|
$qn .= ' and `support`.message not like "%'.substr($word,1).'%" ';
|
|
} else {
|
|
$q .= '
|
|
and (`support`.name like "%'.$word.'%"
|
|
or `support`.message like "%'.$word.'%")
|
|
';
|
|
}
|
|
}
|
|
$query .= $q.$qn;
|
|
}
|
|
|
|
$query .= 'ORDER BY `date` DESC';
|
|
|
|
if ($search['limit']) {
|
|
$query .= ' limit '.$search['limit'].' ';
|
|
}
|
|
|
|
$supports = self::q($query);
|
|
return $supports;
|
|
}
|
|
|
|
public function user() {
|
|
return User::o($this->id_user);
|
|
}
|
|
|
|
public function date() {
|
|
if (!isset($this->_date)) {
|
|
$this->_date = new DateTime($this->datetime, new DateTimeZone( 'UTC' ));
|
|
$this->_date->setTimezone( new DateTimeZone( c::config()->timezone ) );
|
|
}
|
|
return $this->_date;
|
|
}
|
|
|
|
public function relativeTime() {
|
|
return Crunchbutton_Util::relativeTime($this->datetime);
|
|
}
|
|
|
|
public function rep() {
|
|
return Crunchbutton_Admin::o($this->id_admin);
|
|
}
|
|
|
|
public function save() {
|
|
$initial_save = false;
|
|
if(!Support::o($this->id_support)->id_support) {
|
|
$initial_save = true;
|
|
}
|
|
|
|
$this->phone = Phone::clean($this->phone);
|
|
|
|
parent::save();
|
|
if($initial_save) {
|
|
// Crunchbutton_Hipchat_Notification::NewSupport($this);
|
|
}
|
|
}
|
|
|
|
public function makeACall(){
|
|
|
|
$dateTime = new DateTime( 'now', new DateTimeZone('America/Los_Angeles'));
|
|
$hour = $dateTime->format( 'H' );
|
|
|
|
// Issue #1100 - Call David if CB receives a support after 1AM
|
|
if( $hour >= 1 && $hour <= 7 ){
|
|
|
|
$env = c::getEnv();
|
|
|
|
$twilio = new Services_Twilio(c::config()->twilio->{$env}->sid, c::config()->twilio->{$env}->token);
|
|
|
|
$id_support = $this->id_support;
|
|
|
|
$url = 'http://' . c::config()->host_callback . '/api/support/say/' . $id_support;
|
|
|
|
Log::debug( [ 'action' => 'Need to call', 'id_support' => $id_support, 'url' => $url, 'hour' => $hour, 'type' => 'sms' ] );
|
|
|
|
$nums = c::config()->site->config('support-phone-afterhours')->val();
|
|
if (!is_array($nums)) {
|
|
$nums = [$nums];
|
|
}
|
|
|
|
foreach ($nums as $supportName => $supportPhone ) {
|
|
$num = $supportPhone;
|
|
$name = $supportName;
|
|
$urlWithName = $url . '/' . $name;
|
|
$call = $twilio->account->calls->create(
|
|
c::config()->twilio->{$env}->outgoingRestaurant,
|
|
'+1'.$num,
|
|
$urlWithName
|
|
);
|
|
Log::debug( [ 'action' => 'Calling', 'num' => $num, 'url' => $urlWithName, 'type' => 'sms' ] );
|
|
}
|
|
}
|
|
|
|
Log::debug( [ 'action' => 'Not need to call', 'id_support' => $id_support, 'hour' => $hour, 'type' => 'sms' ] );
|
|
|
|
}
|
|
|
|
public function setOrderId($id_order) {
|
|
$order = Order::o($id_order);
|
|
$this->id_order = $order->id_order;
|
|
$this->id_restaurant = $order->id_restaurant;
|
|
$this->id_user = $order->id_user;
|
|
$this->name = $order->name;
|
|
}
|
|
|
|
public static function getSupportForOrder($id_order) {
|
|
$s = self::q('SELECT * FROM `support` WHERE `id_order`="'.$id_order.'" ORDER BY `id_support` DESC LIMIT 1')->get(0);
|
|
return $s->id ? $s : false;
|
|
}
|
|
|
|
public function repTime() {
|
|
$date = $this->date();
|
|
$date->setTimezone(c::admin()->timezone());
|
|
return $date;
|
|
}
|
|
|
|
public function restaurant() {
|
|
if (!isset($this->_restaurant)) {
|
|
$this->_restaurant = $this->id_restaurant ? Restaurant::o($this->id_restaurant) : $this->order()->restaurant();
|
|
}
|
|
return $this->_restaurant;
|
|
}
|
|
|
|
public function order() {
|
|
if (!isset($this->_order)) {
|
|
$this->_order = Order::o($this->id_order);
|
|
}
|
|
return $this->_order;
|
|
}
|
|
|
|
public function permissionToEdit(){
|
|
if( $this->id_restaurant ){
|
|
$userHasPermission = c::admin()->permission()->check( ['global', 'support-all', 'support-crud' ] );
|
|
if( !$userHasPermission ){
|
|
$restaurants = c::admin()->getRestaurantsUserHasPermissionToSeeTheirTickets();
|
|
foreach ( $restaurants as $id_restaurant ) {
|
|
if( $id_restaurant == $this->id_restaurant ){
|
|
$userHasPermission = true;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
$userHasPermission = c::admin()->permission()->check( ['global', 'support-all', 'support-crud', 'support-create' ] );
|
|
}
|
|
return $userHasPermission;
|
|
}
|
|
|
|
public function restaurantsUserHasPermissionToSeeTheirTickets(){
|
|
$restaurants_ids = [];
|
|
$_permissions = new Crunchbutton_Admin_Permission();
|
|
$all = $_permissions->all();
|
|
// Get all restaurants permissions
|
|
$restaurant_permissions = $all[ 'support' ][ 'permissions' ];
|
|
$permissions = c::admin()->getAllPermissionsName();
|
|
$restaurants_id = array();
|
|
foreach ( $permissions as $permission ) {
|
|
$permission = $permission->permission;
|
|
$info = $_permissions->getPermissionInfo( $permission );
|
|
$name = $info[ 'permission' ];
|
|
foreach( $restaurant_permissions as $restaurant_permission_name => $meta ){
|
|
if( $restaurant_permission_name == $name ){
|
|
if( strstr( $name, 'ID' ) ){
|
|
$regex = str_replace( 'ID' , '((.)*)', $name );
|
|
$regex = '/' . $regex . '/';
|
|
preg_match( $regex, $permission, $matches );
|
|
if( count( $matches ) > 0 ){
|
|
$restaurants_ids[] = $matches[ 1 ];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return array_unique( $restaurants_ids );
|
|
}
|
|
|
|
public function adminHasCreatePermission(){
|
|
$hasCreatePermission = c::admin()->permission()->check( ['global', 'support-all', 'support-crud', 'support-create' ] );
|
|
if( !$hasCreatePermission ){
|
|
$pattern = '/' . str_replace( 'ID' , '.*', 'support-crud-ID' ) . '/';
|
|
$hasCreatePermission = c::admin()->hasPermission( $pattern, true );
|
|
if( !$hasCreatePermission ){
|
|
$groups = c::admin()->groups();
|
|
if( $groups->count() ){
|
|
foreach ( $groups as $group ) {
|
|
if( $group->hasPermission( $pattern, true ) ){
|
|
$hasCreatePermission = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return $hasCreatePermission;
|
|
}
|
|
|
|
public function exports() {
|
|
|
|
$out = [];
|
|
|
|
|
|
$out = $this->properties();
|
|
$out['user'] = $this->user()->id_user ? $this->user()->exports() : null;
|
|
$out['driver'] = ($this->order()->id_order && $this->order()->driver()->id_admin) ? $this->order()->driver()->exports() : null;
|
|
$out['restaurant'] = $this->restaurant()->id_restaurant ? $this->restaurant()->exports() : null;
|
|
$out['order'] = $this->order()->id_order ? $this->order()->exports() : null;
|
|
|
|
// Export the comments
|
|
$out[ 'comments' ] = [];
|
|
$comments = $this->comments();
|
|
foreach( $comments as $comment ){
|
|
$out[ 'comments' ][] = $comment->exportsNote();
|
|
}
|
|
|
|
// Check if the ticket belongs to a driver with pexcard #3990
|
|
$admin = Admin::getByPhone( $this->clearPhone( $this->phone ) );
|
|
if( $admin->id_admin && $admin->isDriver() ){
|
|
$pexcard = $admin->pexcard();
|
|
if( $pexcard->id_admin_pexcard ){
|
|
$out[ 'pexcard' ] = $pexcard->exports();
|
|
$out[ 'pexcard' ][ 'name' ] = $admin->name;
|
|
}
|
|
}
|
|
|
|
$messages = Crunchbutton_Support_Message::byPhone( $this->phone, $this->id_support );
|
|
|
|
foreach ( $messages as $message ) {
|
|
$out['messages'][] = $message->exports();
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
public function comments(){
|
|
return Crunchbutton_Support_Message::q( 'SELECT * FROM support_message sm WHERE sm.id_support = "' . $this->id_support . '" AND sm.type = "' . Crunchbutton_Support_Message::TYPE_NOTE . '" AND `from` != "' . Crunchbutton_Support_Message::TYPE_FROM_SYSTEM . '" ORDER BY sm.date DESC' );
|
|
}
|
|
|
|
public function findsTheSendersName( $phone = null ){
|
|
if( !$phone ){
|
|
$phone = $this->phone;
|
|
}
|
|
|
|
// look at the users
|
|
$user = Crunchbutton_User::q( 'SELECT * FROM user WHERE phone = "' . $phone . '" LIMIT 1' );
|
|
if( count( $user ) && $user->get( 0 ) && $user->get( 0 )->name ){
|
|
return $user->get( 0 )->name;
|
|
}
|
|
// look at the orders
|
|
$order = Crunchbutton_User::q( 'SELECT * FROM `order` WHERE phone = "' . $phone . '" LIMIT 1' );
|
|
if( count( $order ) && $order->get( 0 ) && $order->get( 0 )->name ){
|
|
return $order->get( 0 )->name;
|
|
}
|
|
// look at the admins
|
|
$admin = Crunchbutton_User::q( 'SELECT * FROM admin WHERE phone = "' . $phone . '" LIMIT 1' );
|
|
if( count( $admin ) && $admin->get( 0 ) && $admin->get( 0 )->name ){
|
|
return $admin->get( 0 )->name;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public function findsTheSendersType( $phone = null ){
|
|
if( !$phone ){
|
|
$phone = $this->phone;
|
|
}
|
|
// look at the admins
|
|
$admin = Crunchbutton_User::q( 'SELECT * FROM admin WHERE phone = "' . $phone . '" LIMIT 1' );
|
|
if( count( $admin ) && $admin->get( 0 ) && $admin->get( 0 )->id_admin ){
|
|
return 'Driver: ';
|
|
}
|
|
// look at the users
|
|
$user = Crunchbutton_User::q( 'SELECT * FROM user WHERE phone = "' . $phone . '" LIMIT 1' );
|
|
if( count( $user ) && $user->get( 0 ) && $user->get( 0 )->id_user ){
|
|
return 'Customer: ';
|
|
}
|
|
// look at the orders
|
|
$order = Crunchbutton_User::q( 'SELECT * FROM `order` WHERE phone = "' . $phone . '" LIMIT 1' );
|
|
if( count( $order ) && $order->get( 0 ) && $order->get( 0 )->id_order ){
|
|
return 'Customer: ';
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public function dailyDigest( $days = 1 ){
|
|
|
|
$query = 'SELECT DISTINCT( sm.id_support ) AS id, s.* FROM support_message sm
|
|
INNER JOIN support s ON s.id_support = sm.id_support
|
|
WHERE sm.date > DATE_SUB( NOW(), interval ' . $days . ' day ) AND s.type != "' . Crunchbutton_Support::TYPE_WARNING . '"
|
|
ORDER BY sm.date ASC';
|
|
|
|
$tickets = Crunchbutton_Support::q( $query );
|
|
$out = [ 'open' => [], 'closed' => [] ];
|
|
foreach( $tickets as $ticket ){
|
|
$data = [];
|
|
$data[ 'id_support' ] = $ticket->id_support;
|
|
$data[ 'phone' ] = Crunchbutton_Util::format_phone( $ticket->firstMessage()->phone );
|
|
$_name = $ticket->firstMessage()->name;
|
|
if( !$_name ){
|
|
$_name = $ticket->findsTheSendersName();
|
|
}
|
|
if( !$_name ){
|
|
$_name = '<i>Unknown</i>';
|
|
}
|
|
$type = $ticket->findsTheSendersType();
|
|
$data[ 'name' ] = $type . $_name;
|
|
$messages = Crunchbutton_Support_Message::q( 'SELECT * FROM support_message sm WHERE id_support = "' . $ticket->id_support . '" AND sm.date > DATE_SUB( NOW(), interval ' . $days . ' day )' );
|
|
$count = 0;
|
|
$prev_type = null;
|
|
$prev_from = null;
|
|
$prev_body = null;
|
|
$_firstMessageDate = null;
|
|
$_secondMessageDate = null;
|
|
foreach( $messages as $message ){
|
|
if( $message->from == Crunchbutton_Support_Message::TYPE_FROM_SYSTEM ||
|
|
$message->body == '(Ticket created at cockpit)' ){
|
|
continue;
|
|
}
|
|
$date = $message->date()->format( 'g:i a' );
|
|
if( !$data[ 'date' ] ){
|
|
$data[ 'date' ] = $message->date()->format( 'M jS g:i a' );
|
|
}
|
|
|
|
if( $_firstMessageDate && !$_secondMessageDate ){
|
|
$_secondMessageDate = $message->date();
|
|
}
|
|
|
|
if( !$_firstMessageDate ){
|
|
$_firstMessageDate = $message->date();
|
|
}
|
|
|
|
if( $message->from == Crunchbutton_Support_Message::TYPE_FROM_CLIENT ){
|
|
$name = ( $_name ? $_name : '<i>Unknown</i>' );
|
|
} else {
|
|
if( $message->from == Crunchbutton_Support_Message::TYPE_FROM_REP ){
|
|
if( $message->name ){
|
|
$name = $message->name;
|
|
} else {
|
|
$admin = Admin::o( $message->id_admin );
|
|
$name = $admin->name;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( $prev_from == $message->from && $prev_type == $message->type ){
|
|
$join = ( ctype_upper( substr( $message->body, 0 ) ) ) ? '' : '<br>';
|
|
$data[ 'messages' ][ $count ][ 'body' ] .= $join . $message->body;
|
|
} else {
|
|
$count++;
|
|
$data[ 'messages' ][ $count ] = [ 'type' => $message->from , 'body' => $message->body, 'name' => $name, 'date' => $date ];
|
|
}
|
|
$prev_type = $message->type;
|
|
$prev_from = $message->from;
|
|
$prev_body = $message->body;
|
|
}
|
|
if( count( $data[ 'messages' ] ) ){
|
|
|
|
if( $_firstMessageDate && $_secondMessageDate ){
|
|
$seconds = Crunchbutton_Util::intervalToSeconds( $_firstMessageDate->diff( $_secondMessageDate ) );
|
|
if( $seconds >= ( 60 * 5 ) ){
|
|
$data[ 'more_5_min' ] = true;
|
|
}
|
|
}
|
|
|
|
if( $ticket->status == Crunchbutton_Support::STATUS_OPEN ){
|
|
$data[ 'status' ] = 'Opened';
|
|
$out[ 'open' ][] = $data;
|
|
} else {
|
|
$data[ 'status' ] = 'Closed';
|
|
$out[ 'closed' ][] = $data;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
|
|
}
|