diff --git a/config/acl.yaml b/config/acl.yaml index b9b42afb..fb623290 100644 --- a/config/acl.yaml +++ b/config/acl.yaml @@ -344,6 +344,8 @@ access_keys: label: Advance Order Job Order Report - id: report.customer.source label: Customer Source Report + - id: report.hub.filter + label: Hub Filter Report - id: service label: Other Services diff --git a/config/routes/report.yaml b/config/routes/report.yaml index 02f12f41..bb9096b9 100644 --- a/config/routes/report.yaml +++ b/config/routes/report.yaml @@ -137,3 +137,13 @@ rep_customer_source_submit: path: /report/customer_source_report controller: App\Controller\ReportController::customerSourceSubmit methods: [POST] + +rep_hub_filter_form: + path: /report/hub_filter_report + controller: App\Controller\ReportController::hubFilterForm + methods: [GET] + +rep_hub_filter_submit: + path: /report/hub_filter_report + controller: App\Controller\ReportController::hubFilterSubmit + methods: [POST] diff --git a/src/Controller/APIController.php b/src/Controller/APIController.php index eba37122..0568aeb0 100644 --- a/src/Controller/APIController.php +++ b/src/Controller/APIController.php @@ -1043,6 +1043,11 @@ class APIController extends Controller implements LoggedController if (!empty($sku)) $hub_criteria->addItem($batt->getSAPCode(), 1); + // get customer id. No JO id at this point + $customer_id = $cust->getID(); + + $hub_criteria->setCustomerId($customer_id); + // find nearest hubs $nearest_hubs = $hub_select->find($hub_criteria); @@ -2769,6 +2774,11 @@ class APIController extends Controller implements LoggedController if (!empty($sku)) $hub_criteria->addItem($batt->getSAPCode(), 1); + // get customer id. No JO id at this point + $customer_id = $cust->getID(); + + $hub_criteria->setCustomerId($customer_id); + // find nearest hubs $nearest_hubs = $hub_select->find($hub_criteria); diff --git a/src/Controller/ReportController.php b/src/Controller/ReportController.php index f259619a..464259df 100644 --- a/src/Controller/ReportController.php +++ b/src/Controller/ReportController.php @@ -20,6 +20,7 @@ use App\Entity\Customer; use App\Entity\BatteryModel; use App\Entity\BatterySize; use App\Entity\SMSMessage; +use App\Entity\HubFilterLog; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; @@ -1123,6 +1124,62 @@ class ReportController extends Controller return $resp; } + /** + * @Menu(selected="outlet_list") + */ + public function hubFilterForm() + { + $this->denyAccessUnlessGranted('report.hub.filter', null, 'No access.'); + + return $this->render('report/hub-filter/form.html.twig'); + } + + public function hubFilterSubmit(Request $req, EntityManagerInterface $em) + { + // get dates + $raw_date_start = $req->request->get('date_start'); + $raw_date_end = $req->request->get('date_end'); + + $date_start = DateTime::createFromFormat('m/d/Y', $raw_date_start); + $date_end = DateTime::createFromFormat('m/d/Y', $raw_date_end); + + $data = $this->getHubFilterData($req, $em, $raw_date_start, $raw_date_end); + + $resp = new StreamedResponse(); + $resp->setCallback(function() use ($data) { + // csv output + $csv_handle = fopen('php://output', 'w+'); + fputcsv($csv_handle, [ + 'Filtered Hub ID', + 'Hub Name', + 'Job Order ID', + 'Customer ID', + 'Customer Last Name', + 'Customer First Name', + 'Customer Mobile Number', + 'Date Created', + 'Reason', + 'Date of Rejection', + ]); + + foreach ($data as $row) + { + fputcsv($csv_handle, $row); + } + + fclose($csv_handle); + }); + + $filename = 'hub_filter_' . $date_start->format('Ymd') . '_' . $date_end->format('Ymd') . '.csv'; + + $resp->setStatusCode(200); + $resp->headers->set('Content-Type', 'text/csv; charset=utf-8'); + $resp->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"'); + + return $resp; + + } + protected function processPopappFile(UploadedFile $csv_file, EntityManagerInterface $em) { // attempt to open file @@ -2261,6 +2318,47 @@ class ReportController extends Controller return $result; } + protected function getHubFilterData($req, $em, $raw_date_start, $raw_date_end) + { + $date_start = DateTime::createFromFormat('m/d/Y', $raw_date_start); + $date_end = DateTime::createFromFormat('m/d/Y', $raw_date_end); + + // change to this format: Y-m-d H:i:s + $new_date_start = $date_start->format('Y-m-d H:i:s'); + $new_date_end = $date_end->format('Y-m-d H:i:s'); + + // pdo connection. Table gets big very fast. + $db = $em->getConnection(); + + // get hub filter logs + $sql = 'SELECT hf.hub_filtered_id, h.name, hf.jo_id, hf.customer_id, c.last_name, c.first_name, c.phone_mobile, hf.date_create, hf.filter_type_id FROM hub_filter_log hf, hub h, customer c WHERE hf.hub_filtered_id=h.id AND c.id=hf.customer_id AND hf.date_create >= :date_start AND hf.date_create <= :date_end ORDER BY hf.date_create'; + $stmt = $db->prepare($sql); + $stmt->execute([ + 'date_start' => $new_date_start, + 'date_end' => $new_date_end, + ]); + + $result = []; + // go through rows + while ($row = $stmt->fetch(PDO::FETCH_NUM)) + { + $result[] = [ + $row[0], // filtered hub id + $row[1], // hub name + $row[2], // job order id + $row[3], // customer id + $row[4], // customer last name + $row[5], // customer first name + $row[6], // customer mobile + $row[7], // date create + $row[8], // filter type id + $row[7], // date of rejection + ]; + } + + return $result; + } + protected function getRESQCustomerIDs(EntityManagerInterface $em) { // pdo connection diff --git a/src/Entity/HubFilterLog.php b/src/Entity/HubFilterLog.php index 2c4d8584..c1633684 100644 --- a/src/Entity/HubFilterLog.php +++ b/src/Entity/HubFilterLog.php @@ -44,9 +44,23 @@ class HubFilterLog */ protected $filter_type_id; + // jo id that made request + /** + * @ORM\Column(type="integer", nullable=true) + */ + protected $jo_id; + + // customer id that made request + /** + * @ORM\Column(type="integer", nullable=true) + */ + protected $customer_id; + public function __construct() { $this->date_create = new DateTime(); + $this->jo_id = null; + $this->customer_id = null; } public function getID() @@ -80,5 +94,28 @@ class HubFilterLog { return $this->filter_type_id; } + + public function setJobOrderId($jo_id) + { + $this->jo_id = $jo_id; + return $this; + } + + public function getJobOrderId() + { + return $this->jo_id; + } + + public function setCustomerId($customer_id) + { + $this->customer_id = $customer_id; + return $this; + } + + public function getCustomerId() + { + return $this->customer_id; + } + } diff --git a/src/Ramcar/HubCriteria.php b/src/Ramcar/HubCriteria.php index 76f00eb6..61ffcbaa 100644 --- a/src/Ramcar/HubCriteria.php +++ b/src/Ramcar/HubCriteria.php @@ -18,6 +18,8 @@ class HubCriteria protected $payment_method; // payment method of JO protected $flag_emergency; // flag if emergency or not protected $flag_round_robin; // flag if we use round robin or not + protected $jo_id; // JO id. This is null if called from mobile API + protected $customer_id; // customer id public function __construct() { @@ -31,6 +33,8 @@ class HubCriteria $this->payment_method = ''; $flag_emergency = false; $flag_round_robin = false; + $jo_id = null; + $customer_id = null; } public function setPoint(Point $point) @@ -145,5 +149,27 @@ class HubCriteria return $this->flag_round_robin; } + public function setJobOrderId($jo_id) + { + $this->jo_id = $jo_id; + return $this; + } + + public function getJobOrderId() + { + return $this->jo_id; + } + + public function setCustomerId($customer_id) + { + $this->customer_id = $customer_id; + return $this; + } + + public function getCustomerId() + { + return $this->customer_id; + } + } diff --git a/src/Service/HubFilterLogger.php b/src/Service/HubFilterLogger.php index 74744a39..e25c6adb 100644 --- a/src/Service/HubFilterLogger.php +++ b/src/Service/HubFilterLogger.php @@ -16,12 +16,14 @@ class HubFilterLogger $this->em = $em; } - public function logFilteredHub(Hub $hub, $filter_type) + public function logFilteredHub(Hub $hub, $filter_type, $jo_id, $customer_id) { $hub_filter_log = new HubFilterLog(); $hub_filter_log->setHub($hub) - ->setFilterTypeId($filter_type); + ->setFilterTypeId($filter_type) + ->setJobOrderId($jo_id) + ->setCustomerId($customer_id); $this->em->persist($hub_filter_log); $this->em->flush(); diff --git a/src/Service/HubSelector.php b/src/Service/HubSelector.php index a0f78213..ab810c20 100644 --- a/src/Service/HubSelector.php +++ b/src/Service/HubSelector.php @@ -51,37 +51,39 @@ class HubSelector $payment_method = $criteria->getPaymentMethod(); $flag_emergency = $criteria->isEmergency(); $flag_round_robin = $criteria->isRoundRobin(); + $jo_id = $criteria->getJobOrderId(); + $customer_id = $criteria->getCustomerId(); $results = []; // get all the hubs within distance - $filtered_hubs = $this->getClosestHubs($point, $limit_distance); + $filtered_hubs = $this->getClosestHubs($point, $limit_distance, $jo_id, $customer_id); error_log('closest hubs ' . json_encode($filtered_hubs)); if (!$flag_emergency) { // filter the first hub results for date and opening times - $hubs_date_time = $this->filterHubsByDateAndTime($filtered_hubs, $date_time); + $hubs_date_time = $this->filterHubsByDateAndTime($filtered_hubs, $date_time, $jo_id, $customer_id); $filtered_hubs = $hubs_date_time; //error_log('date_time hubs ' . json_encode($filtered_hubs)); // filter jo types - $hubs_jo_type = $this->filterHubsByJoType($filtered_hubs, $jo_type); + $hubs_jo_type = $this->filterHubsByJoType($filtered_hubs, $jo_type, $jo_id, $customer_id); $filtered_hubs = $hubs_jo_type; //error_log('jo_type hubs ' . json_encode($filtered_hubs)); // filter hubs by payment methods - $hubs_payment_method = $this->filterHubsByPaymentMethod($filtered_hubs, $payment_method); + $hubs_payment_method = $this->filterHubsByPaymentMethod($filtered_hubs, $payment_method, $jo_id, $customer_id); $filtered_hubs = $hubs_payment_method; //error_log('payment hubs ' . json_encode($filtered_hubs)); // inventory filter $hubs_inventory = $this->filterHubsByInventory($filtered_hubs, $flag_inventory_check, - $jo_type, $items); + $jo_type, $items, $jo_id, $customer_id); $filtered_hubs = $hubs_inventory; //error_log('inventory hubs ' . json_encode($filtered_hubs)); @@ -93,7 +95,7 @@ class HubSelector //error_log('round robin hubs ' . json_encode($filtered_hubs)); // max results filter - $hubs_max_result = $this->filterHubsByMaxResults($filtered_hubs, $limit_results); + $hubs_max_result = $this->filterHubsByMaxResults($filtered_hubs, $limit_results, $jo_id, $customer_id); $filtered_hubs = $hubs_max_result; } @@ -120,7 +122,7 @@ class HubSelector } - protected function filterHubsByMaxResults($hubs, $limit_result) + protected function filterHubsByMaxResults($hubs, $limit_result, $jo_id, $customer_id) { if (empty($hubs)) return $hubs; @@ -133,13 +135,13 @@ class HubSelector if ($i < $limit_result) $results[] = $hubs[$i]; else - $this->hub_filter_logger->logFilteredHub($hubs[$i]['hub'], 'max_results'); + $this->hub_filter_logger->logFilteredHub($hubs[$i]['hub'], 'max_results', $jo_id, $customer_id); } return $results; } - protected function filterHubsByJoType($hubs, $jo_type) + protected function filterHubsByJoType($hubs, $jo_type, $jo_id, $customer_id) { if (empty($hubs)) return $hubs; @@ -163,13 +165,13 @@ class HubSelector 'duration' => $hub_data['duration'], ]; else - $this->hub_filter_logger->logFilteredHub($hub, 'job_order_type'); + $this->hub_filter_logger->logFilteredHub($hub, 'job_order_type', $jo_id, $customer_id); } return $results; } - protected function filterHubsByPaymentMethod($hubs, $payment_method) + protected function filterHubsByPaymentMethod($hubs, $payment_method, $jo_id, $customer_id) { if (empty($hubs)) return $hubs; @@ -201,16 +203,16 @@ class HubSelector } if (!$flag_found_pmethod) - $this->hub_filter_logger->logFilteredHub($hub, 'no_payment_method'); + $this->hub_filter_logger->logFilteredHub($hub, 'no_payment_method', $jo_id, $customer_id); } else - $this->hub_filter_logger->logFilteredHub($hub, 'no_payment_method'); + $this->hub_filter_logger->logFilteredHub($hub, 'no_payment_method', $jo_id, $customer_id); } return $results; } - protected function filterHubsByDateAndTime($hubs, $date_time) + protected function filterHubsByDateAndTime($hubs, $date_time, $jo_id, $customer_id) { if (empty($hubs)) return $hubs; @@ -245,13 +247,13 @@ class HubSelector ]; } else - $this->hub_filter_logger->logFilteredHub($hub, 'date_and_time'); + $this->hub_filter_logger->logFilteredHub($hub, 'date_and_time', $jo_id, $customer_id); } return $results; } - protected function filterHubsByInventory($hubs, $flag_inventory_check, $jo_type, $items) + protected function filterHubsByInventory($hubs, $flag_inventory_check, $jo_type, $items, $jo_id, $customer_id) { if (empty($hubs)) return $hubs; @@ -290,7 +292,7 @@ class HubSelector error_log($message); $this->sendSMSMessage($hub, $items); - $this->hub_filter_logger->logFilteredHub($hub, 'no_inventory'); + $this->hub_filter_logger->logFilteredHub($hub, 'no_inventory', $jo_id, $customer_id); } } if ($jo_type == ServiceType::BATTERY_REPLACEMENT_WARRANTY) @@ -317,7 +319,7 @@ class HubSelector error_log($message); $this->sendSMSMessage($hub, $items); - $this->hub_filter_logger->logFilteredHub($hub, 'no_inventory'); + $this->hub_filter_logger->logFilteredHub($hub, 'no_inventory', $jo_id, $customer_id); } } } @@ -326,7 +328,7 @@ class HubSelector return $results; } - protected function getClosestHubs(Point $point, $limit_distance) + protected function getClosestHubs(Point $point, $limit_distance, $jo_id, $customer_id) { // get closest hubs based on st_distance function from db $query_string = 'SELECT h, st_distance(h.coordinates, point(:lng, :lat)) as dist FROM App\Entity\Hub h WHERE h.status_open = true ORDER BY dist'; @@ -367,7 +369,7 @@ class HubSelector } else { - $this->hub_filter_logger->logFilteredHub($row[0], 'distance'); + $this->hub_filter_logger->logFilteredHub($row[0], 'not_within_distance', $jo_id, $customer_id); } } diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index 3637e4a1..971f6903 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -1996,6 +1996,13 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface if ($willing_to_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) $hub_criteria->setEmergency(true); + // get JO and customer id for logging purposes + $jo_id = $obj->getID(); + $customer_id = $obj->getCustomer()->getID(); + + $hub_criteria->setJobOrderId($jo_id) + ->setCustomerId($customer_id); + $hubs = $hub_selector->find($hub_criteria); $params['hubs'] = []; @@ -2293,6 +2300,13 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface if ($willing_to_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) $hub_criteria->setEmergency(true); + // get JO and customer id for logging purposes + $jo_id = $obj->getID(); + $customer_id = $obj->getCustomer()->getID(); + + $hub_criteria->setJobOrderId($jo_id) + ->setCustomerId($customer_id); + $hubs = $hub_selector->find($hub_criteria); $params['status_cancelled'] = JOStatus::CANCELLED; diff --git a/templates/base.html.twig b/templates/base.html.twig index 3316aa32..ab5dfb77 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -249,6 +249,14 @@ Customer Source Report + + + + + + diff --git a/templates/report/hub-filter/form.html.twig b/templates/report/hub-filter/form.html.twig new file mode 100644 index 00000000..c41e9712 --- /dev/null +++ b/templates/report/hub-filter/form.html.twig @@ -0,0 +1,82 @@ +{% extends 'base.html.twig' %} + +{% block body %} + +