diff --git a/.env.dist b/.env.dist index bd82f980..9fc0a002 100644 --- a/.env.dist +++ b/.env.dist @@ -74,3 +74,6 @@ MAPTILER_API_KEY=map_tiler_api_key # API version API_VERSION=insert_api_version_here + +#SSL_ENABLE for websockets +SSL_ENABLE=set_to_true_or_false diff --git a/config/acl.yaml b/config/acl.yaml index abd73118..81b49726 100644 --- a/config/acl.yaml +++ b/config/acl.yaml @@ -270,6 +270,8 @@ access_keys: label: Autoassign Test - id: jo_hub.list label: Hub View + - id: jo_cancel.fulfill + label: Fulfill Cancelled JO - id: support label: Customer Support Access diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml index 1c848030..ade96bcc 100644 --- a/config/packages/twig.yaml +++ b/config/packages/twig.yaml @@ -8,3 +8,4 @@ twig: mqtt_host: "%env(MQTT_WS_HOST)%" mqtt_port: "%env(MQTT_WS_PORT)%" dashboard_enable: "%env(DASHBOARD_ENABLE)%" + ssl_enable: "%env(SSL_ENABLE)%" diff --git a/config/routes/job_order.yaml b/config/routes/job_order.yaml index 586ed81f..6ea3a3c5 100644 --- a/config/routes/job_order.yaml +++ b/config/routes/job_order.yaml @@ -253,3 +253,17 @@ jo_hub_view_form: controller: App\Controller\JobOrderController::hubViewForm methods: [GET] +jo_fulfill_cancel_submit: + path: /job-order/fulfillcancel/{id} + controller: App\Controller\JobOrderController::fulfillCancelSubmit + methods: [POST] + +jo_cancel_reasons: + path: /ajax/jo_cancel_reasons + controller: App\Controller\JobOrderController::cancelReasons + methods: [GET] + +jo_geofence: + path: /ajax/job-order/geofence + controller: App\Controller\JobOrderController::checkGeofence + methods: [GET] diff --git a/initial_sql/sql_update_customer_date_create.sql b/initial_sql/sql_update_customer_date_create.sql new file mode 100644 index 00000000..50102db3 --- /dev/null +++ b/initial_sql/sql_update_customer_date_create.sql @@ -0,0 +1,2 @@ +UPDATE customer SET date_create=NOW() WHERE date_create="0000-00-00 00:00:00"; + diff --git a/public/assets/js/map_mqtt.js b/public/assets/js/map_mqtt.js index 0e6bdb31..250e00c6 100644 --- a/public/assets/js/map_mqtt.js +++ b/public/assets/js/map_mqtt.js @@ -1,7 +1,8 @@ class MapEventHandler { - constructor(options, dashmap) { + constructor(options, dashmap, ssl) { this.options = options; this.dashmap = dashmap; + this.ssl = ssl; } connect(user_id, host, port) { @@ -11,7 +12,7 @@ class MapEventHandler { this.mqtt = new Paho.MQTT.Client(host, port, client_id); var options = { - // useSSL: true, + useSSL: this.ssl, timeout: 3, invocationContext: this, onSuccess: this.onConnect.bind(this), diff --git a/src/Command/ImportSAPDeltaCommand.php b/src/Command/ImportSAPDeltaCommand.php new file mode 100644 index 00000000..aeea6366 --- /dev/null +++ b/src/Command/ImportSAPDeltaCommand.php @@ -0,0 +1,331 @@ +em = $em; + $this->initSAPBatteryHash(); + $this->initSAPBatterySizeHash(); + $this->initSAPBatteryBrandHash(); + + parent::__construct(); + } + + protected function configure() + { + $this->setName('sap_battery:delta') + ->setDescription('Update SAP battery table with new SAP battery data.') + ->setHelp('Creates SAP battery data entries from CSV file.') + ->addArgument('file', InputArgument::REQUIRED, 'Path to the CSV file.') + ->addArgument('output_file', InputArgument::REQUIRED, 'Path to the output CSV file.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $csv_file = $input->getArgument('file'); + $report_file = $input->getArgument('output_file'); + + // CSV column order: + // 0 - brand + // 1 - sku + // 2 - size + + // attempt to open file + try + { + $fh = fopen($csv_file, "r"); + } + catch (Exception $e) + { + throw new Exception('The file "' . $csv_file . '" could not be read.'); + } + + // get entity manager + $em = $this->em; + + // loop through the rows + $row_num = 0; + error_log('Processing sap battery csv file...'); + $existing_brands = []; + $existing_sizes = []; + $existing_batteries = []; + $added_brands = []; + $added_sizes = []; + $added_batteries = []; + $total_processed = 0; + while (($fields = fgetcsv($fh)) !== false) + { + // data starts at row 2 + if ($row_num < 2) + { + $row_num++; + continue; + } + + // check if blank row + if (strlen(trim($fields[0])) == 0) + continue; + + // clean up fields + $clean_brand = $this->normalizeName(trim($fields[0])); + $clean_sku = $this->normalizeName(trim($fields[1])); + $clean_size = $this->normalizeName(trim($fields[2])); + + // check if sap battery code already exists + if (!isset($this->sap_battery_hash[$clean_sku])) + { + // check if brand in system + $sap_brand = null; + if (!isset($this->sap_battery_brand_hash[$clean_brand])) + { + // add brand + $sap_brand = new SAPBatteryBrand(); + $sap_brand->setName($clean_brand); + + $em->persist($sap_brand); + + // add to list of added brands + $added_brands[$clean_brand] = $clean_brand; + + //$output->writeln('Adding brand: ' . $clean_brand); + + // add to hash + $this->sap_battery_brand_hash[$clean_brand] = $sap_brand; + } + else + { + // get the brand + $sap_brand = $this->sap_battery_brand_hash[$clean_brand]; + + // need to check if this is in added_brands because the hash contains + // existing + added. What we need is the list of existing only + if (!isset($added_brands[$clean_brand])) + { + // add to list of existing brands + //$output->writeln('Brand already in db ' . $clean_brand); + $existing_brands[$clean_brand] = $clean_brand; + } + } + + // check if size in system + $sap_size = null; + if (!isset($this->sap_battery_size_hash[$clean_size])) + { + // add size + $sap_size = new SAPBatterySize(); + $sap_size->setName($clean_size); + + $em->persist($sap_size); + + // add to list of added sizes + $added_sizes[$clean_size] = $clean_size; + + //$output->writeln('Adding size: ' . $clean_size); + + // add to hash + $this->sap_battery_size_hash[$clean_size] = $sap_size; + } + else + { + // get the size + $sap_size = $this->sap_battery_size_hash[$clean_size]; + + // need to check if this is in added_sizes because the hash contains + // existing + added. What we need is the list of existing only + if (!isset($added_sizes[$clean_size])) + { + // add to list of existing sizes + //$output->writeln('Size already in db ' . $clean_size); + $existing_sizes[$clean_size] = $clean_size; + } + } + + // add the sap_battery + // create sap battery entry + $sap_battery = new SAPBattery(); + $sap_battery->setID($clean_sku) + ->setSize($sap_size) + ->setBrand($sap_brand); + + $em->persist($sap_battery); + + // add to list of added batteries + $added_batteries[$clean_sku] = $clean_sku; + + //$output->writeln('Adding battery: ' . $clean_sku); + + // add to hash + $this->sap_battery_hash[$clean_sku] = $sap_battery; + } + else + { + // TODO: for now, assume that the brand and size in system == brand and size in csv file + // need to check if this is in added_batteries because the hash contains + // existing + added. What we need is the list of existing only + if (!isset($added_batteries[$clean_sku])) + { + // add to list of existing batteries + //$output->writeln('Battery already in db ' . $clean_sku); + $existing_batteries[$clean_sku] = $this->sap_battery_hash[$clean_sku]; + if (!isset($existing_brands[$clean_brand])) + $existing_brands[$clean_brand] = $clean_brand; + if (!isset($existing_sizes[$clean_size])) + $existing_sizes[$clean_size] = $clean_size; + } + } + + $total_processed++; + $row_num++; + + } + + $em->flush(); + + // need to output the list of added and not added data + $this->writeOutputFile($report_file, $added_brands, $added_sizes, $added_batteries, + $existing_brands, $existing_sizes, $existing_batteries, $total_processed); + + return 0; + } + + protected function initSAPBatteryHash() + { + $this->sap_battery_hash = []; + + $batts = $this->em->getRepository(SAPBattery::class)->findAll(); + foreach ($batts as $batt) + { + $id = $this->normalizeName($batt->getID()); + $this->sap_battery_hash[$id] = $batt; + } + } + + protected function initSAPBatterySizeHash() + { + $this->sap_battery_size_hash = []; + + $sizes = $this->em->getRepository(SAPBatterySize::class)->findAll(); + foreach ($sizes as $size) + { + $name = $this->normalizeName($size->getName()); + $this->sap_battery_size_hash[$name] = $size; + } + } + + protected function initSAPBatteryBrandHash() + { + $this->sap_battery_brand_hash = []; + + $brands = $this->em->getRepository(SAPBatteryBrand::class)->findAll(); + foreach ($brands as $brand) + { + $name = $this->normalizeName($brand->getName()); + $this->sap_battery_brand_hash[$name] = $brand; + } + } + + protected function writeOutputFile($report_file, $added_brands, $added_sizes, $added_batteries, + $existing_brands, $existing_sizes, $existing_batteries, $total_processed) + { + try + { + $fh = fopen($report_file, "w"); + } + catch (Exception $e) + { + throw new Exception('The file "' . $report_file . '" could be opened.'); + } + + fputs($fh, 'Total entries processed: ' . $total_processed . "\n"); + + fputs($fh, 'Total brands added: ' . count($added_brands) . "\n"); + fputs($fh, 'Total sizes added: ' . count($added_sizes) . "\n"); + fputs($fh, 'Total batteries added: ' . count($added_batteries) . "\n"); + + fputs($fh, 'Total number of brands in csv file that are in the system: ' . count($existing_brands) . "\n"); + fputs($fh, 'Total number of sizes in csv file that are in the system: ' . count($existing_sizes) . "\n"); + fputs($fh, 'Total number of batteries in csv file that are in the system: ' . count($existing_batteries) . "\n"); + + // write the added batteries + // check the existing brands array for the added ones + $not_added_batteries = []; + fputs($fh, 'Added Batteries: ' . "\n"); + foreach($added_batteries as $added_battery) + { + fputs($fh, $added_battery, strlen($added_battery)); + fputs($fh, "\n"); + } + + // write the added brands + // check the existing arrays for the added ones + $not_added_brands = []; + fputs($fh, 'Added Brands: ' . "\n"); + foreach ($added_brands as $added_brand) + { + fputs($fh, $added_brand, strlen($added_brand)); + fputs($fh, "\n"); + } + + // write the added sizes + // check the existing array for the added ones + $not_added_sizes = []; + fputs($fh, 'Added Sizes: ' . "\n"); + foreach ($added_sizes as $added_size) + { + fputs($fh, $added_size, strlen($added_size)); + fputs($fh, "\n"); + } + + // write the not added batteries + fputs($fh, 'Batteries already in system: ' . "\n"); + foreach($existing_batteries as $not_added_battery) + { + fputs($fh, $not_added_battery->getID(), strlen($not_added_battery->getID())); + fputs($fh, "\n"); + } + + // write the not added brands + fputs($fh, 'Brands already in system: ' . "\n"); + foreach($existing_brands as $not_added_brand) + { + fputs($fh, $not_added_brand, strlen($not_added_brand)); + fputs($fh, "\n"); + } + + // write the not added sizes + fputs($fh, 'Sizes already in system: ' . "\n"); + foreach($existing_sizes as $not_added_size) + { + fputs($fh, $not_added_size, strlen($not_added_size)); + fputs($fh, "\n"); + } + + fclose($fh); + } + + protected function normalizeName($name) + { + $normalized_key = trim(strtoupper($name)); + + return $normalized_key; + } +} diff --git a/src/Command/ImportSAPMasterCommand.php b/src/Command/ImportSAPMasterCommand.php new file mode 100644 index 00000000..9e266c2b --- /dev/null +++ b/src/Command/ImportSAPMasterCommand.php @@ -0,0 +1,256 @@ +em = $em; + $this->initSAPBatteryHash(); + $this->initSAPBatterySizeHash(); + $this->initSAPBatteryBrandHash(); + + parent::__construct(); + } + + protected function configure() + { + $this->setName('sap_battery:master') + ->setDescription('Import SAP battery master list.') + ->setHelp('Creates SAP battery, SAP battery brands, and SAP battery sizes from CSV file.') + ->addArgument('file', InputArgument::REQUIRED, 'Path to the CSV file.') + ->addArgument('output_file', InputArgument::REQUIRED, 'Path to the output CSV file.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $csv_file = $input->getArgument('file'); + $report_file = $input->getArgument('output_file'); + + // CSV column order: + // 0 - brand + // 1 - sku + // 2 - size + + // attempt to open file + try + { + $fh = fopen($csv_file, "r"); + } + catch (Exception $e) + { + throw new Exception('The file "' . $csv_file . '" could not be read.'); + } + + // get entity manager + $em = $this->em; + // loop through the rows + $row_num = 0; + error_log('Processing sap battery csv file...'); + $added_brands = []; + $added_sizes = []; + $added_batteries = []; + $repeat_brands = []; + $repeat_sizes = []; + $repeat_batteries = []; + $total_processed = 0; + while (($fields = fgetcsv($fh)) !== false) + { + // data starts at row 2 + if ($row_num < 2) + { + $row_num++; + continue; + } + + // check if blank row + if (strlen(trim($fields[0])) == 0) + continue; + + // clean up fields + $clean_brand = $this->normalizeName(trim($fields[0])); + $clean_sku = $this->normalizeName(trim($fields[1])); + $clean_size = $this->normalizeName(trim($fields[2])); + + // check if brand in system + $sap_brand = null; + if (!isset($this->sap_battery_brand_hash[$clean_brand])) + { + // add brand + $sap_brand = new SAPBatteryBrand(); + $sap_brand->setName($clean_brand); + + $em->persist($sap_brand); + + // add to list of added brands + $added_brands[$clean_brand] = $clean_brand; + + //$output->writeln('Adding brand: ' . $clean_brand); + + // add to hash + $this->sap_battery_brand_hash[$clean_brand] = $sap_brand; + } + else + { + // get the brand + $sap_brand = $this->sap_battery_brand_hash[$clean_brand]; + + // repeat brand so no need to add but still need to count + $repeat_brands[] = $clean_brand; + } + + // check if size in system + $sap_size = null; + if (!isset($this->sap_battery_size_hash[$clean_size])) + { + // add size + $sap_size = new SAPBatterySize(); + $sap_size->setName($clean_size); + + $em->persist($sap_size); + + // add to list of added sizes + $added_sizes[$clean_size] = $clean_size; + + //$output->writeln('Adding size: ' . $clean_size); + + // add to hash + $this->sap_battery_size_hash[$clean_size] = $sap_size; + } + else + { + // get the size + $sap_size = $this->sap_battery_size_hash[$clean_size]; + + // repeat size so no need to add to system but still need to count + $repeat_sizes[] = $clean_size; + } + + // check if sap battery code already exists + if (!isset($this->sap_battery_hash[$clean_sku])) + { + // add the sap_battery + // create sap battery entry + $sap_battery = new SAPBattery(); + $sap_battery->setID($clean_sku) + ->setSize($sap_size) + ->setBrand($sap_brand); + + $em->persist($sap_battery); + + // add to list of added batteries + $added_batteries[$clean_sku] = $clean_sku; + + //$output->writeln('Adding battery: ' . $clean_sku); + + // add to hash + $this->sap_battery_hash[$clean_sku] = $sap_battery; + } + else + { + $repeat_batteries[] = $clean_sku; + } + + $total_processed++; + $row_num++; + } + + $em->flush(); + + // need to output the list of added and not added data + $this->writeOutputFile($report_file, $added_brands, $added_sizes, $added_batteries, $total_processed, + $repeat_brands, $repeat_sizes, $repeat_batteries); + + return 0; + } + + protected function initSAPBatteryHash() + { + $this->sap_battery_hash = []; + + $batts = $this->em->getRepository(SAPBattery::class)->findAll(); + foreach ($batts as $batt) + { + $id = $this->normalizeName($batt->getID()); + $this->sap_battery_hash[$id] = $batt; + } + } + + protected function initSAPBatterySizeHash() + { + $this->sap_battery_size_hash = []; + + $sizes = $this->em->getRepository(SAPBatterySize::class)->findAll(); + foreach ($sizes as $size) + { + $name = $this->normalizeName($size->getName()); + $this->sap_battery_size_hash[$name] = $size; + } + } + + protected function initSAPBatteryBrandHash() + { + $this->sap_battery_brand_hash = []; + + $brands = $this->em->getRepository(SAPBatteryBrand::class)->findAll(); + foreach ($brands as $brand) + { + $name = $this->normalizeName($brand->getName()); + $this->sap_battery_brand_hash[$name] = $brand; + } + } + + protected function writeOutputFile($report_file, $added_brands, $added_sizes, $added_batteries, $total_processed, + $repeat_brands, $repeat_sizes, $repeat_batteries) + { + try + { + $fh = fopen($report_file, "w"); + } + catch (Exception $e) + { + throw new Exception('The file "' . $report_file . '" could be opened.'); + } + + fputs($fh, 'Total entries processed: ' . $total_processed . "\n"); + + fputs($fh, 'Total brands added: ' . count($added_brands) . "\n"); + fputs($fh, 'Total sizes added: ' . count($added_sizes) . "\n"); + fputs($fh, 'Total batteries added: ' . count($added_batteries) . "\n"); + + fputs($fh, 'Repeat brands: ' . count($repeat_brands) . "\n"); + fputs($fh, 'Repeat sizes: ' . count($repeat_sizes) . "\n"); + fputs($fh, 'Repeat batteries: ' . count($repeat_batteries) . "\n"); + + foreach ($repeat_batteries as $repeat_battery) + { + fputs($fh, 'Duplicate SKU: ' . $repeat_battery . "\n"); + } + + } + + protected function normalizeName($name) + { + $normalized_key = trim(strtoupper($name)); + + return $normalized_key; + } + +} diff --git a/src/Controller/JobOrderController.php b/src/Controller/JobOrderController.php index 1549f48a..11c7edf0 100644 --- a/src/Controller/JobOrderController.php +++ b/src/Controller/JobOrderController.php @@ -6,6 +6,7 @@ use App\Ramcar\JOStatus; use App\Ramcar\InvoiceCriteria; use App\Ramcar\CMBServiceType; use App\Ramcar\ServiceType; +use App\Ramcar\JOCancelReasons; use App\Entity\CustomerVehicle; use App\Entity\Promo; @@ -22,9 +23,13 @@ use App\Service\MapTools; use App\Service\MQTTClient; use App\Service\APNSClient; use App\Service\InventoryManager; + use App\Service\RiderTracker; use App\Service\MotivConnector; +use App\Service\GeofenceTracker; + + use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Bundle\FrameworkBundle\Controller\Controller; @@ -632,7 +637,6 @@ class JobOrderController extends Controller $params['vmfgs'] = $em->getRepository(VehicleManufacturer::class)->findAll(); $params['vmakes'] = $em->getRepository(Vehicle::class)->findAll(); $params['return_url'] = $this->generateUrl('jo_all'); - $params['submit_url'] = ''; $params['map_js_file'] = $gis->getJSJOFile(); $template = $params['template']; @@ -1154,6 +1158,51 @@ class JobOrderController extends Controller return $this->render($template, $params); } + public function fulfillCancelSubmit(Request $req, JobOrderHandlerInterface $jo_handler, $id) + { + $this->denyAccessUnlessGranted('jo_cancel.fulfill', null, 'No access.'); + + // TODO: make the service function to fulfill the cancelled JO + $error_array = []; + $result = $jo_handler->fulfillCancelledJobOrder($req, $id); + + $error_array = $result['error_array']; + + // check if any errors were found + if (!empty($error_array)) { + // return validation failure response + return $this->json([ + 'success' => false, + 'errors' => $error_array + ], 422); + } + + // return successful response + return $this->json([ + 'success' => 'Changes have been saved!' + ]); + } + + // ajax call + public function cancelReasons() + { + return $this->json([ + 'cancel_reasons' => JOCancelReasons::getCollection(), + ]); + } + + // ajax call + public function checkGeofence(Request $req, GeofenceTracker $geo) + { + $lat = $req->query->get('lat'); + $lng = $req->query->get('lng'); + + $is_covered = $geo->isCovered($lng, $lat); + + return $this->json([ + 'is_covered' => $is_covered + ]); + } /** * @Menu(selected="jo_autoassign") diff --git a/src/Controller/WarrantyController.php b/src/Controller/WarrantyController.php index ae6da43f..b1f2442e 100644 --- a/src/Controller/WarrantyController.php +++ b/src/Controller/WarrantyController.php @@ -386,43 +386,58 @@ class WarrantyController extends Controller $inv_entries = $this->processWarrantyFile($file, $em, $wh); $resp = new StreamedResponse(); - $resp->setCallback(function() use($inv_entries) { - // csv output - $csv_handle = fopen('php://output', 'w+'); - fputcsv($csv_handle, [ - 'Owner First Name', - 'Owner Last Name', - 'Owner Email', - 'Owner Address', - 'Owner Mobile', - 'Owner Telephone', - 'Vehicle Make', - 'Vehicle Model', - 'Vehicle Year', - 'Vehicle Plate Number', - 'Battery Serial Number', - 'Battery Sales Invoice', - 'Battery Date of Purchase', - 'Distributor Name', - 'Distributor Address', - 'Application Type ID', - 'Battery ID', - 'Ownership Type', - 'Reason Warranty Not Added', - ]); - foreach ($inv_entries as $row) - { - fputcsv($csv_handle, $row); - } - fclose($csv_handle); - }); + if (count($inv_entries) > 0) + { + $resp->setCallback(function() use($inv_entries) { + // csv output + $csv_handle = fopen('php://output', 'w+'); + fputcsv($csv_handle, [ + 'Owner First Name', + 'Owner Last Name', + 'Owner Email', + 'Owner Address', + 'Owner Mobile', + 'Owner Telephone', + 'Vehicle Make', + 'Vehicle Model', + 'Vehicle Year', + 'Vehicle Plate Number', + 'Battery Serial Number', + 'Battery Sales Invoice', + 'Battery Date of Purchase', + 'Distributor Name', + 'Distributor Address', + 'Application Type ID', + 'Battery ID', + 'Ownership Type', + 'Reason Warranty Not Added', + ]); + foreach ($inv_entries as $row) + { + fputcsv($csv_handle, $row); + } + + fclose($csv_handle); + }); + + } + else + { + $resp->setCallback(function() { + // csv output + $csv_handle = fopen('php://output', 'w+'); + fputcsv($csv_handle, ['No Invalid Warranties']); + + fclose($csv_handle); + }); + } $filename = 'invalid_warranties' . '.csv'; - $resp->setStatusCode(200); $resp->headers->set('Content-Type', 'text/csv; charset=utf-8'); $resp->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"'); + $resp->setStatusCode(200); return $resp; } diff --git a/src/Entity/Customer.php b/src/Entity/Customer.php index 9ba043c9..281c9fa9 100644 --- a/src/Entity/Customer.php +++ b/src/Entity/Customer.php @@ -6,6 +6,8 @@ use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\ArrayCollection; use Symfony\Component\Validator\Constraints as Assert; +use DateTime; + use App\Ramcar\CustomerClassification; /** @@ -184,6 +186,12 @@ class Customer */ protected $flag_dpa_consent; + // date customer was created + /** + * @ORM\Column(type="datetime") + */ + protected $date_create; + public function __construct() { $this->numbers = new ArrayCollection(); @@ -214,6 +222,8 @@ class Customer $this->flag_promo_email = false; $this->flag_promo_sms = false; $this->flag_dpa_consent = false; + + $this->date_create = new DateTime(); } public function getID() diff --git a/src/Entity/JobOrder.php b/src/Entity/JobOrder.php index 8bcdbb77..9fdc2424 100644 --- a/src/Entity/JobOrder.php +++ b/src/Entity/JobOrder.php @@ -12,6 +12,7 @@ use DateTime; use App\Ramcar\ModeOfPayment; use App\Ramcar\JOStatus; use App\Ramcar\ServiceType; +use App\Ramcar\WillingToWaitContent; /** * @ORM\Entity @@ -334,6 +335,30 @@ class JobOrder */ protected $phone_mobile; + // customer is willing to wait or not + /** + * @ORM\Column(type="string", length=30) + */ + protected $will_wait; + + // reason for not willing to wait + /** + * @ORM\Column(type="string", length=80, nullable=true) + */ + protected $reason_not_waiting; + + // more notes on why not willing to wait + /** + * @ORM\Column(type="text", nullable=true) + */ + protected $not_waiting_notes; + + // reason for not trading in battery + /** + * @ORM\Column(type="string", length=80, nullable=true) + */ + protected $no_trade_in_reason; + public function __construct() { $this->date_create = new DateTime(); @@ -356,6 +381,8 @@ class JobOrder $this->meta = []; $this->phone_mobile = ''; + + $this->will_wait = WillingToWaitContent::WILLING_TO_WAIT; } public function getID() @@ -962,5 +989,47 @@ class JobOrder return $this->phone_mobile; } + public function setWillWait($will_wait) + { + $this->will_wait = $will_wait; + return $this; + } + public function getWillWait() + { + return $this->will_wait; + } + + public function setReasonNotWait($reason) + { + $this->reason_not_waiting = $reason; + return $this; + } + + public function getReasonNotWait() + { + return $this->reason_not_waiting; + } + + public function setNotWaitingNotes($notes) + { + $this->not_waiting_notes = $notes; + return $this; + } + + public function getNotWaitingNotes() + { + return $this->not_waiting_notes; + } + + public function setNoTradeInReason($reason) + { + $this->no_trade_in_reason = $reason; + return $this; + } + + public function getNoTradeInReason() + { + return $this->no_trade_in_reason; + } } diff --git a/src/Ramcar/CustomerNotWaitReason.php b/src/Ramcar/CustomerNotWaitReason.php new file mode 100644 index 00000000..0fef4385 --- /dev/null +++ b/src/Ramcar/CustomerNotWaitReason.php @@ -0,0 +1,22 @@ + 'Emergency', + 'use_vehicle_now' => 'Need to Use Vehicle Now', + 'with_appointment' => 'With Appointment', + 'post_replacement' => 'Post Replacement', + 'post_recharge' => 'Post Recharge', + 'normal_request_not_urgent' => 'Normal Request not Urgent (Rush below TAT)', + ]; +} diff --git a/src/Ramcar/JOCancelReasons.php b/src/Ramcar/JOCancelReasons.php new file mode 100644 index 00000000..4386482b --- /dev/null +++ b/src/Ramcar/JOCancelReasons.php @@ -0,0 +1,32 @@ + 'Wrong Battery', + 'customer_no_show' => 'Customer No Show', + 'reschedule' => 'Reschedule', + 'location_change' => 'Change Location', + 'battery_working' => 'Battery is Already Working', + 'late_delivery' => 'Late Delivery', + 'customer_bought_new_battery' => 'Customer Already Bought New Battery from Nearby Outlet', + 'battery_no_stock' => 'No Stock of Battery', + 'system_problem' => 'System Problem', + 'wrong_price_provided' => 'Wrong Price Provided', + 'wrong_payment_mode' => 'Wrong Mode of Payment', + ]; +} diff --git a/src/Ramcar/NoTradeInReason.php b/src/Ramcar/NoTradeInReason.php new file mode 100644 index 00000000..aeea695b --- /dev/null +++ b/src/Ramcar/NoTradeInReason.php @@ -0,0 +1,20 @@ + 'No existing battery', + 'sell_other_shop' => 'Sell to other shop', + 'used_as_spare_battery' => 'Used as spare battery', + 'return_battery_company' => 'Need to return battery to company', + 'low_trade_in_value' => 'Trade in value is low', + ]; +} diff --git a/src/Ramcar/TransactionOrigin.php b/src/Ramcar/TransactionOrigin.php index c4d69ad2..8d4c12aa 100644 --- a/src/Ramcar/TransactionOrigin.php +++ b/src/Ramcar/TransactionOrigin.php @@ -10,6 +10,7 @@ class TransactionOrigin extends NameValue const VIP = 'vip'; const MOBILE_APP = 'mobile_app'; const WALK_IN = 'walk_in'; + const LAZADA = 'lazada'; // TODO: for now, resq also gets the walk-in option const COLLECTION = [ @@ -19,5 +20,6 @@ class TransactionOrigin extends NameValue 'vip' => 'VIP', 'mobile_app' => 'Mobile App', 'walk_in' => 'Walk-in', + 'lazada' => 'Lazada', ]; } diff --git a/src/Ramcar/WillingToWaitContent.php b/src/Ramcar/WillingToWaitContent.php new file mode 100644 index 00000000..2ac47e7b --- /dev/null +++ b/src/Ramcar/WillingToWaitContent.php @@ -0,0 +1,14 @@ + 'Willing to Wait', + 'not_willing_to_wait' => 'Not Willing to Wait', + ]; +} diff --git a/src/Service/CustomerHandler/ResqCustomerHandler.php b/src/Service/CustomerHandler/ResqCustomerHandler.php index eec2e2fb..5f3653dd 100644 --- a/src/Service/CustomerHandler/ResqCustomerHandler.php +++ b/src/Service/CustomerHandler/ResqCustomerHandler.php @@ -6,8 +6,8 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Validator\Validator\ValidatorInterface; - use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\Security\Core\Security; use App\Service\CustomerHandlerInterface; @@ -30,14 +30,16 @@ class ResqCustomerHandler implements CustomerHandlerInterface protected $em; protected $validator; protected $country_code; + protected $security; protected $template_hash; public function __construct(EntityManagerInterface $em, ValidatorInterface $validator, - string $country_code) + string $country_code, Security $security) { $this->em = $em; $this->validator = $validator; $this->country_code = $country_code; + $this->security = $security; $this->loadTemplates(); } @@ -172,14 +174,6 @@ class ResqCustomerHandler implements CustomerHandlerInterface $em = $this->em; $row = new Customer(); - // NOTE: commenting the dpa changes for now - // check if dpa consent is unticked - /* - $is_dpa_checked = $req->request->get('flag_dpa_consent'); - if (!$is_dpa_checked) - $error_array['flag_dpa_consent'] = 'DPA consent should be checked.'; - */ - // check if email marketing promo is checked $is_email_promo_checked = $req->request->get('flag_promo_email'); if ($is_email_promo_checked) @@ -342,14 +336,6 @@ class ResqCustomerHandler implements CustomerHandlerInterface $nerror_array = []; $verror_array = []; - // NOTE: commenting out the dpa changes for now - // check if dpa consent is unticked - /* - $is_dpa_checked = $req->request->get('flag_dpa_consent'); - if (!$is_dpa_checked) - $error_array['flag_dpa_consent'] = 'DPA consent should be checked.'; - */ - // check if email marketing promo is checked $is_email_promo_checked = $req->request->get('flag_promo_email'); if ($is_email_promo_checked) @@ -597,6 +583,11 @@ class ResqCustomerHandler implements CustomerHandlerInterface protected function setObject($obj, $req) { + // check for dpa access + $is_dpa_checked = true; + if ($this->security->isGranted('customer.dpa')) + $is_dpa_checked = $req->request->get('flag_dpa_consent', false); + // set and save values $obj->setTitle($req->request->get('title')) ->setFirstName($req->request->get('first_name')) @@ -608,7 +599,7 @@ class ResqCustomerHandler implements CustomerHandlerInterface ->setActive($req->request->get('flag_active') ? true : false) ->setPromoSms($req->request->get('flag_promo_sms', false)) ->setPromoEmail($req->request->get('flag_promo_email', false)) - ->setDpaConsent($req->request->get('flag_dpa_consent', false)); + ->setDpaConsent($is_dpa_checked); // phone numbers $obj->setPhoneMobile($req->request->get('phone_mobile')) diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index 9694a2ba..70cac92d 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -37,6 +37,9 @@ use App\Ramcar\ModeOfPayment; use App\Ramcar\TransactionOrigin; use App\Ramcar\FacilitatedType; use App\Ramcar\JORejectionReason; +use App\Ramcar\CustomerNotWaitReason; +use App\Ramcar\NoTradeInReason; +use App\Ramcar\WillingToWaitContent; use App\Service\InvoiceGeneratorInterface; use App\Service\JobOrderHandlerInterface; @@ -45,6 +48,7 @@ use App\Service\WarrantyHandler; use App\Service\MQTTClient; use App\Service\APNSClient; use App\Service\MapTools; +use App\Service\RisingTideGateway; use CrEOF\Spatial\PHP\Types\Geometry\Point; @@ -65,13 +69,14 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface protected $rah; protected $country_code; protected $wh; + protected $rt; protected $template_hash; public function __construct(Security $security, EntityManagerInterface $em, InvoiceGeneratorInterface $ic, ValidatorInterface $validator, TranslatorInterface $translator, RiderAssignmentHandlerInterface $rah, - string $country_code, WarrantyHandler $wh) + string $country_code, WarrantyHandler $wh, RisingTideGateway $rt) { $this->em = $em; $this->ic = $ic; @@ -81,6 +86,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface $this->rah = $rah; $this->country_code = $country_code; $this->wh = $wh; + $this->rt = $rt; $this->loadTemplates(); } @@ -183,6 +189,12 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface else $row['assignor'] = $orow->getAssignedBy()->getFullName(); + $hub_facilitated = $orow->getFacilitatedBy(); + if ($hub_facilitated == null) + $row['hub_facilitated'] = ''; + else + $row['hub_facilitated'] = $orow->getFacilitatedBy()->getName(); + $rows[] = $row; } @@ -291,10 +303,24 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface else { // get email, dpa_consent, promo_sms, and promo_email, if set + // check for dpa access + $is_dpa_checked = true; + if ($this->security->isGranted('customer.dpa')) + $is_dpa_checked = $req->request->get('flag_dpa_consent', false); + + // check if email marketing promo is checked + $is_email_promo_checked = $req->request->get('flag_promo_email'); + if ($is_email_promo_checked) + { + // check email field + if (empty($req->request->get('customer_email'))) + $error_array['customer_email'] = 'Email address required.'; + } + $customer->setEmail($req->request->get('customer_email')) ->setPromoSms($req->request->get('flag_promo_sms', false)) ->setPromoEmail($req->request->get('flag_promo_email', false)) - ->setDpaConsent($req->request->get('flag_dpa_consent', false)); + ->setDpaConsent($is_dpa_checked); } // check if lat and lng are provided @@ -314,6 +340,37 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } } + // check if landmark is set + if (empty($req->request->get('landmark'))) + $error_array['landmark'] = 'Landmark is required.'; + + // check if customer is not willing to wait + $will_wait = $req->request->get('flag_willing_to_wait'); + $reason = ''; + $more_reason = ''; + if ($will_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) + { + // get the reason and text + $reason = $req->request->get('no_wait_reason'); + $more_reason = $req->request->get('not_wait_notes'); + } + + // check if service is battery sales + $stype = $req->request->get('service_type'); + $no_trade_in_reason = ''; + if ($stype == ServiceType::BATTERY_REPLACEMENT_NEW) + { + // check if trade in + $is_trade_in = $req->request->get('invoice_trade_in_type'); + if (empty($is_trade_in)) + { + $no_trade_in_reason = $req->request->get('no_trade_in_reason'); + + if (empty($no_trade_in_reason)) + $error_array['no_trade_in_reason'] = 'No trade in reason required.'; + } + } + // TODO: check status before saving since JO might already // have a status that needs to be retained @@ -324,8 +381,6 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface // coordinates $point = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat')); - $stype = $req->request->get('service_type'); - // set and save values $jo->setDateSchedule(DateTime::createFromFormat("d M Y h:i A", $req->request->get('date_schedule_date') . " " . $req->request->get('date_schedule_time'))) ->setCoordinates($point) @@ -343,7 +398,11 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface ->setORName($req->request->get('or_name')) ->setPromoDetail($req->request->get('promo_detail')) ->setModeOfPayment($req->request->get('mode_of_payment')) - ->setLandmark($req->request->get('landmark')); + ->setLandmark($req->request->get('landmark')) + ->setWillWait($req->request->get('flag_willing_to_wait')) + ->setReasonNotWait($reason) + ->setNotWaitingNotes($more_reason) + ->setNoTradeInReason($no_trade_in_reason); // check if user is null, meaning call to create came from API if ($user != null) @@ -434,6 +493,37 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface $error_array['coordinates'] = 'No map coordinates provided. Please click on a location on the map.'; } + // check if landmark is set + if (empty($req->request->get('landmark'))) + $error_array['landmark'] = 'Landmark is required.'; + + // check if customer is not willing to wait + $will_wait = $req->request->get('flag_willing_to_wait'); + $reason = ''; + $more_reason = ''; + if ($will_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) + { + // get the reason and text + $reason = $req->request->get('no_wait_reason'); + $more_reason = $req->request->get('not_wait_notes'); + } + + // check if service type is battery sales + $stype = $req->request->get('service_type'); + $no_trade_in_reason = ''; + if ($stype == ServiceType::BATTERY_REPLACEMENT_NEW) + { + // check if trade in + $is_trade_in = $req->request->get('invoice_trade_in_type'); + if (empty($is_trade_in)) + { + $no_trade_in_reason = $req->request->get('no_trade_in_reason'); + + if (empty($no_trade_in_reason)) + $error_array['no_trade_in_reason'] = 'No trade in reason required.'; + } + } + if (empty($error_array)) { // get current user @@ -442,8 +532,6 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface // coordinates $point = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat')); - $stype = $req->request->get('service_type'); - // set and save values $obj->setDateSchedule(DateTime::createFromFormat("d M Y h:i A", $req->request->get('date_schedule_date') . " " . $req->request->get('date_schedule_time'))) ->setCoordinates($point) @@ -458,7 +546,11 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface ->setORName($req->request->get('or_name')) ->setPromoDetail($req->request->get('promo_detail')) ->setModeOfPayment($req->request->get('mode_of_payment')) - ->setLandmark($req->request->get('landmark')); + ->setLandmark($req->request->get('landmark')) + ->setWillWait($req->request->get('flag_willing_to_wait')) + ->setReasonNotWait($reason) + ->setNotWaitingNotes($more_reason) + ->setNoTradeInReason($no_trade_in_reason); // did they change invoice? $invoice_items = $req->request->get('invoice_items', []); @@ -492,6 +584,8 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface ->setTypeID(JOEventType::OPEN_EDIT) ->setJobOrder($obj); + error_log('open edit?'); + if ($user != null) { $event->setUser($user); @@ -587,6 +681,21 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface $fac_by = null; } + // check if landmark is set + if (empty($req->request->get('landmark'))) + $error_array['landmark'] = 'Landmark is required.'; + + // check if customer is not willing to wait + $will_wait = $req->request->get('flag_willing_to_wait'); + $reason = ''; + $more_reason = ''; + if ($will_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) + { + // get the reason and text + $reason = $req->request->get('no_wait_reason'); + $more_reason = $req->request->get('not_wait_notes'); + } + if (empty($error_array)) { // coordinates @@ -606,7 +715,11 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface ->setDeliveryAddress($req->request->get('delivery_address')) ->setFacilitatedType($fac_type) ->setFacilitatedBy($fac_by) - ->setHub($hub); + ->setHub($hub) + ->setLandmark($req->request->get('landmark')) + ->setWillWait($req->request->get('flag_willing_to_wait')) + ->setReasonNotWait($reason) + ->setNotWaitingNotes($more_reason); // validate $errors = $this->validator->validate($obj); @@ -680,6 +793,21 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } } + // check if landmark is set + if (empty($req->request->get('landmark'))) + $error_array['landmark'] = 'Landmark is required.'; + + // check if customer is not willing to wait + $will_wait = $req->request->get('flag_willing_to_wait'); + $reason = ''; + $more_reason = ''; + if ($will_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) + { + // get the reason and text + $reason = $req->request->get('no_wait_reason'); + $more_reason = $req->request->get('not_wait_notes'); + } + // get current user $user = $this->security->getUser(); @@ -700,7 +828,11 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface ->setTier2Notes($req->request->get('tier2_notes')) ->setDeliveryAddress($req->request->get('delivery_address')) ->setDateAssign(new DateTime()) - ->setRider($rider); + ->setRider($rider) + ->setLandmark($req->request->get('landmark')) + ->setWillWait($req->request->get('flag_willing_to_wait')) + ->setReasonNotWait($reason) + ->setNotWaitingNotes($more_reason); if ($user != null) { @@ -763,6 +895,21 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface $error_array['coordinates'] = 'No map coordinates provided. Please click on a location on the map.'; } + // check if landmark is set + if (empty($req->request->get('landmark'))) + $error_array['landmark'] = 'Landmark is required.'; + + // check if customer is not willing to wait + $will_wait = $req->request->get('flag_willing_to_wait'); + $reason = ''; + $more_reason = ''; + if ($will_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) + { + // get the reason and text + $reason = $req->request->get('no_wait_reason'); + $more_reason = $req->request->get('not_wait_notes'); + } + if (empty($error_array)) { // coordinates $point = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat')); @@ -777,7 +924,11 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface ->setDeliveryInstructions($req->request->get('delivery_instructions')) ->setTier1Notes($req->request->get('tier1_notes')) ->setTier2Notes($req->request->get('tier2_notes')) - ->setDeliveryAddress($req->request->get('delivery_address')); + ->setDeliveryAddress($req->request->get('delivery_address')) + ->setLandmark($req->request->get('landmark')) + ->setWillWait($req->request->get('flag_willing_to_wait')) + ->setReasonNotWait($reason) + ->setNotWaitingNotes($more_reason); // validate $errors = $this->validator->validate($obj); @@ -868,6 +1019,12 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface else error_log('Invalid plate number for warranty. Plate number = ' . $obj->getCustomerVehicle()->getPlateNumber()); } + + // send SMS to customer + // prepend country code to number + $phone_number = $this->country_code . $obj->getCustomer()->getPhoneMobile(); + if (!empty($phone_number)) + $this->sendSMSToCustomer($phone_number); } } @@ -883,6 +1040,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface throw new NotFoundHttpException('The item does not exist'); $cancel_reason = $req->request->get('cancel_reason'); + error_log($cancel_reason); $obj->cancel($cancel_reason); // the event @@ -947,6 +1105,23 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } } + // check if landmark is set + if (empty($req->request->get('landmark'))) + $error_array['landmark'] = 'Landmark is required.'; + + error_log($req->request->get('landmark')); + + // check if customer is not willing to wait + $will_wait = $req->request->get('flag_willing_to_wait'); + $reason = ''; + $more_reason = ''; + if ($will_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) + { + // get the reason and text + $reason = $req->request->get('no_wait_reason'); + $more_reason = $req->request->get('not_wait_notes'); + } + if (empty($error_array)) { // rider mqtt event @@ -974,6 +1149,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface ->setTier2Notes($req->request->get('tier2_notes')) ->setDeliveryAddress($req->request->get('delivery_address')) ->setHub($hub) + ->setLandmark($req->request->get('landmark')) + ->setWillWait($req->request->get('flag_willing_to_wait')) + ->setReasonNotWait($reason) + ->setNotWaitingNotes($more_reason) ->clearRider(); if ($user != null) @@ -1148,6 +1327,21 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } } + // check if landmark is set + if (empty($req->request->get('landmark'))) + $error_array['landmark'] = 'Landmark is required.'; + + // check if customer is not willing to wait + $will_wait = $req->request->get('flag_willing_to_wait'); + $reason = ''; + $more_reason = ''; + if ($will_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) + { + // get the reason and text + $reason = $req->request->get('no_wait_reason'); + $more_reason = $req->request->get('not_wait_notes'); + } + if (empty($error_array)) { // rider mqtt event // NOTE: need to send this before saving because rider will be cleared @@ -1174,7 +1368,11 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface ->setTier2Notes($req->request->get('tier2_notes')) ->setDeliveryAddress($req->request->get('delivery_address')) ->setDateAssign(new DateTime()) - ->setRider($rider); + ->setRider($rider) + ->setLandmark($req->request->get('landmark')) + ->setWillWait($req->request->get('flag_willing_to_wait')) + ->setReasonNotWait($reason) + ->setNotWaitingNotes($more_reason); if ($user != null) { @@ -1562,6 +1760,18 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface $this->fillDropdownParameters($params); $this->fillFormTags($params); + // check JO status to determine the mode and submit_url to return + if ($obj->getStatus() == JOStatus::CANCELLED) + { + $params['mode'] = 'fulfill-cancel'; + $params['submit_url'] = 'jo_fulfill_cancel_submit'; + } + else + { + $params['mode'] = 'update-all'; + $params['submit_url'] = ''; + } + // get template to display $params['template'] = $this->getTwigTemplate('jo_all_form'); @@ -2479,6 +2689,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface $params['facilitated_types'] = FacilitatedType::getCollection(); $params['facilitated_hubs'] = $fac_hubs; $params['sources'] = TransactionOrigin::getCollection(); + $params['willing_to_wait_content'] = WillingToWaitContent::getCollection(); + $params['no_wait_reasons'] = CustomerNotWaitReason::getCollection(); + $params['no_trade_in_reasons'] = NoTradeInReason::getCollection(); } protected function initFormTags(&$params) @@ -2810,20 +3023,35 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface ->andWhere('h.flag_hub_view = :flag_hub_view') ->setParameter('flag_hub_view', true); } + if (isset($datatable['query']['schedule_date'])) + { + $start = $datatable['query']['schedule_date'][0] . ' ' . '00:00:00'; + $end = $datatable['query']['schedule_date'][1] . ' ' . '23:59:00'; + + $date_start = DateTime::createFromFormat('m/d/Y H:i:s', $start); + $date_end = DateTime::createFromFormat('m/d/Y H:i:s', $end); + + $query->andWhere('q.date_schedule >= :date_start') + ->andWhere('q.date_schedule <= :date_end') + ->setParameter('date_start', $date_start) + ->setParameter('date_end', $date_end); + } + else + { + $c_date = new DateTime(); + $start_curr_date = $c_date->format('Y-m-d') . ' ' . '00:00:00'; + $end_curr_date = $c_date->format('Y-m-d') . ' ' . '23:59:00'; - $c_date = new DateTime(); - $start_curr_date = $c_date->format('Y-m-d') . ' ' . '00:00:00'; - $end_curr_date = $c_date->format('Y-m-d') . ' ' . '23:59:00'; + $start_current_date = DateTime::createFromFormat('Y-m-d H:i:s', $start_curr_date); + $end_current_date = DateTime::createFromFormat('Y-m-d H:i:s', $end_curr_date); - $start_current_date = DateTime::createFromFormat('Y-m-d H:i:s', $start_curr_date); - $end_current_date = DateTime::createFromFormat('Y-m-d H:i:s', $end_curr_date); - - $query->andWhere('q.date_schedule >= :start_current_date') - ->andWhere('q.date_schedule <= :end_current_date') - ->andWhere('q.status IN (:statuses)') - ->setParameter('start_current_date', $start_current_date) - ->setParameter('end_current_date', $end_current_date) - ->setParameter('statuses', $status, Connection::PARAM_STR_ARRAY); + $query->andWhere('q.date_schedule >= :start_current_date') + ->andWhere('q.date_schedule <= :end_current_date') + ->andWhere('q.status IN (:statuses)') + ->setParameter('start_current_date', $start_current_date) + ->setParameter('end_current_date', $end_current_date) + ->setParameter('statuses', $status, Connection::PARAM_STR_ARRAY); + } break; default: $query->where('q.status = :status') @@ -2999,4 +3227,44 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface return $params; } + public function fulfillCancelledJobOrder(Request $req, $id) + { + // initialize error list + $error_array = []; + + // get object data + $em = $this->em; + $obj = $em->getRepository(JobOrder::class)->find($id); + + // make sure this object exists + if (empty($obj)) + throw new NotFoundHttpException('The item does not exist'); + + $obj->fulfill(); + + // the event + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::FULFILL) + ->setJobOrder($obj); + + // get current user + $user = $this->security->getUser(); + if ($user != null) + { + $event->setUser($user); + } + + $event->setUser($user); + $em->persist($event); + $em->flush(); + } + + public function sendSMSToCustomer($phone_number) + { + // TODO: put this in config file or somewhere + $message = "Your Resq job order has been completed."; + $this->rt->sendSMS($phone_number, 'MOTOLITE', $message); + } + } diff --git a/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php b/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php index 138b7989..4a86ceba 100644 --- a/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php +++ b/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php @@ -21,6 +21,7 @@ use App\Service\MQTTClient; use App\Service\WarrantyHandler; use App\Service\JobOrderHandlerInterface; use App\Service\InvoiceGeneratorInterface; +use App\Service\RisingTideGateway; use App\Entity\RiderSession; use App\Entity\Rider; @@ -45,12 +46,13 @@ class ResqRiderAPIHandler implements RiderAPIHandlerInterface protected $jo_handler; protected $ic; protected $session; + protected $rt; public function __construct(EntityManagerInterface $em, RedisClientProvider $redis, EncoderFactoryInterface $ef, RiderCache $rcache, string $country_code, MQTTClient $mclient, WarrantyHandler $wh, JobOrderHandlerInterface $jo_handler, - InvoiceGeneratorInterface $ic) + InvoiceGeneratorInterface $ic, RisingTideGateway $rt) { $this->em = $em; $this->redis = $redis; @@ -61,6 +63,7 @@ class ResqRiderAPIHandler implements RiderAPIHandlerInterface $this->wh = $wh; $this->jo_handler = $jo_handler; $this->ic = $ic; + $this->rt = $rt; // one device = one session, since we have control over the devices // when a rider logs in, we just change the rider assigned to the device @@ -523,6 +526,15 @@ class ResqRiderAPIHandler implements RiderAPIHandlerInterface // save to customer vehicle battery record $this->jo_handler->updateVehicleBattery($jo); + // send SMS to customer + $phone_number = $jo->getCustomer()->getPhoneMobile(); + if (!empty($phone_number)) + { + // TODO: put this in config file or somewhere + $message = "Your Resq job order has been completed."; + $this->rt->sendSMS($phone_number, 'MOTOLITE', $message); + } + $this->em->flush(); // create warranty diff --git a/templates/customer/form.html.twig b/templates/customer/form.html.twig index d91ce316..97b80884 100644 --- a/templates/customer/form.html.twig +++ b/templates/customer/form.html.twig @@ -123,12 +123,11 @@