diff --git a/config/services.yaml b/config/services.yaml index 12c32894..2bb23c98 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -322,3 +322,36 @@ services: App\Service\PriceTierManager: arguments: $em: "@doctrine.orm.entity_manager" + + # hub filters + App\Service\HubFilter\BaseHubFilter: + arguments: + $hub_filter_logger: "@App\\Service\\HubFilterLogger" + $em: "@doctrine.orm.entity_manager" + $rt: "@App\\Service\\RisingTideGateway" + $trans: "@Symfony\\Contracts\\Translation\\TranslatorInterface" + + App\Service\HubFilter\Filters\DateAndTimeHubFilter: + public: true + + App\Service\HubFilter\Filters\JoTypeHubFilter: + public: true + + App\Service\HubFilter\Filters\MaxResultsHubFilter: + public: true + + App\Service\HubFilter\Filters\PaymentMethodHubFilter: + public: true + + App\Service\HubFilter\Filters\RiderAvailabilityHubFilter: + public: true + + App\Service\HubFilter\Filters\InventoryHubFilter: + public: true + arguments: + $im: "@App\\Service\\InventoryManager" + + App\Service\HubFilter\Filters\RoundRobinHubFilter: + public: true + arguments: + $hub_distributor: "@App\\Service\\HubDistributor" diff --git a/src/Service/HubFilter/BaseHubFilter.php b/src/Service/HubFilter/BaseHubFilter.php new file mode 100644 index 00000000..36b72363 --- /dev/null +++ b/src/Service/HubFilter/BaseHubFilter.php @@ -0,0 +1,123 @@ +hub_filter_logger = $hub_filter_logger; + $this->em = $em; + $this->rt = $rt; + $this->trans = $trans; + } + + public function getID(): string + { + return $this->id; + } + + public function setJOID(int $jo_id) + { + $this->jo_id = $jo_id; + return $this; + } + + public function getJOID(): int + { + return $this->jo_id; + } + + public function setCustomerID(int $customer_id) + { + $this->customer_id = $customer_id; + return $this; + } + + public function getCustomerID(): int + { + return $this->customer_id; + } + + public function log(Hub $hub): void + { + $this->hub_filter_logger->logFilteredHub($hub, $this->getID(), $this->getJOID(), $this->getCustomerID()); + } + + protected function createRejectionEntry($jo_id, $hub, $remarks = ""): JORejection + { + $jo = $this->em->getRepository(JobOrder::class)->find($jo_id); + + $robj = new JORejection(); + $robj->setDateCreate(new DateTime()) + ->setHub($hub) + ->setJobOrder($jo) + ->setReason(JORejectionReason::NO_STOCK_SALES) + ->setRemarks(implode(" ", ["Automatically filtered by hub selector.", $remarks])); + + $this->em->persist($robj); + $this->em->flush(); + + return $robj; + } + + protected function sendSMSMessage($hub, $jo_id, $order_date, $service_type, $rejection, $reason = "", $remarks = ""): void + { + // check if we already have a rejection record for this hub and JO. this also means an SMS was already sent + $rejection_count = $this->em->createQueryBuilder() + ->select('count(r)') + ->from(JORejection::class, 'r') + ->where('r.job_order = :jo_id') + ->andWhere('r.hub = :hub_id') + ->andWhere('r.id != :rejection_id') + ->setParameter('jo_id', $jo_id) + ->setParameter('hub_id', $hub->getID()) + ->setParameter('rejection_id', $rejection->getID()) + ->getQuery() + ->getSingleScalarResult(); + + // if we already have a rejection record for this hub and JO, do not send another SMS + if ($rejection_count >= 1) { + error_log("ALREADY SENT REJECTION SMS TO HUB " . $hub->getID() . " FOR JO " . $jo_id); + return; + } + + $message = 'Job Order #: ' . $jo_id . "\n" . + 'Order Date and Time: ' . $order_date->format('d M Y g:i A') . "\n" . + 'Date and Time Rejected: ' . $rejection->getDateCreate()->format('d M Y g:i A') . "\n" . + 'Enrollee Name: ' . implode(" - ", [$hub->getName(), $hub->getBranch()]) . "\n" . + 'Reason of Rejection: ' . $reason . "\n" . + 'Remarks: ' . $remarks . "\n" . + 'Type of Service: ' . ServiceType::getName($service_type); + + error_log("SENDING SMS MESsAGE:\r\n" . $message); + + // send SMS message to hub + $this->rt->sendSMS( + $hub->getNotifNumber(), + $this->trans->trans('message.battery_brand_allcaps'), + $message + ); + } +} \ No newline at end of file diff --git a/src/Service/HubFilter/Filters/DateAndTimeHubFilter.php b/src/Service/HubFilter/Filters/DateAndTimeHubFilter.php new file mode 100644 index 00000000..0b25096a --- /dev/null +++ b/src/Service/HubFilter/Filters/DateAndTimeHubFilter.php @@ -0,0 +1,51 @@ +getTimeOpen()->format("H:i:s"); + $time_close = $hub->getTimeClose()->format("H:i:s"); + + $filter_time = $params['date_time']->format("H:i:s"); + + if (($filter_time >= $time_open) && + ($filter_time <= $time_close)) + { + $results[] = [ + 'hub' => $hub, + 'db_distance' => $hub_data['db_distance'], + 'distance' => $hub_data['distance'], + 'duration' => $hub_data['duration'], + 'jo_count' => 0, + 'inventory' => $hub_data['inventory'], + ]; + } + else + $this->log($hub); + } + + return $results; + } +} \ No newline at end of file diff --git a/src/Service/HubFilter/Filters/InventoryHubFilter.php b/src/Service/HubFilter/Filters/InventoryHubFilter.php new file mode 100644 index 00000000..82be87c5 --- /dev/null +++ b/src/Service/HubFilter/Filters/InventoryHubFilter.php @@ -0,0 +1,148 @@ +im = $im; + } + + public function filter(array $hubs, array $params = []) : array + { + // check if this is enabled + if (!$params['flag_inventory_check']) { + error_log("INVENTORY CHECK " . $this->getJOID() . ": DISABLED"); + return $hubs; + } + + // check customer class + if (!empty($params['customer_class']) && $params['customer_class'] == CustomerClassification::VIP) { + error_log("INVENTORY CHECK " . $this->getJOID() . ": VIP CLASS"); + return $hubs; + } + + // check item list is not empty + if (empty($params['items'])) { + error_log("INVENTORY CHECK " . $this->getJOID() . ": NO ITEMS"); + return $hubs; + } + + // check this is a battery item related JO + if ($params['jo_type'] != ServiceType::BATTERY_REPLACEMENT_NEW && + $params['jo_type'] != ServiceType::BATTERY_REPLACEMENT_WARRANTY + ) { + error_log("INVENTORY CHECK " . $this->getJOID() . ": INVALID SERVICE TYPE: " . $params['jo_type']); + return $hubs; + } + + // get a list of all hubs with branch codes + $branch_codes = []; + foreach ($hubs as $hub_data) { + $branch_code = $hub_data['hub']->getBranchCode(); + if (!empty($branch_code)) { + $branch_codes[] = $branch_code; + } + }; + + $hubs_to_filter = []; + $results = []; + $qtys = []; + + // call inventory manager for all hubs for selected SKUs + $skus = array_keys($params['items']); + + error_log("CHECKING INVENTORY FOR " . count($skus) . " ITEM(S) ON HUBS " . count($branch_codes) . "..."); + + $branches = $this->im->getBranchesInventory($branch_codes, $skus); + + error_log("REQUEST COMPLETE, RESULT COUNT: " . count($branches)); + + // check each result to see if sufficient quantity exists to meet request + foreach ($branches as $branch) { + if (isset($branch['BranchCode'])) { + // filter out branch if it does not have sufficient inventory + if ($branch['Quantity'] < $params['items'][$branch['SapCode']] && + !isset($hubs_to_filter[$branch['BranchCode']]) + ) { + error_log("FILTERING BRANCH WITH NO INVENTORY: " . $branch['BranchCode']); + $hubs_to_filter[$branch['BranchCode']] = true; + } else { + // save inventory count so we don't have to recheck later + $qtys[$branch['BranchCode']] = $branch['Quantity']; + } + } + } + + // get battery models for each requested SKU + $batteries = []; + foreach ($skus as $sku) { + $bobj = $this->em->getRepository(Battery::class)->findOneBy(['sap_code' => $sku]); + $batteries[] = implode(" ", [$bobj->getModel()->getName(), $bobj->getSize()->getName()]); + } + $battery_string = implode(", ", $batteries); + + // remove filtered hubs from list + foreach ($hubs as $hub_data) { + $hub = $hub_data['hub']; + $branch_code = $hub_data['hub']->getBranchCode(); + + // check if we are filtering this hub + if (isset($hubs_to_filter[$branch_code]) || empty($branch_code) || !isset($qtys[$branch_code])) { + // if we have a JO, create rejection record and notify + if (!empty($jo_id)) { + // create rejection report entry + $robj = $this->createRejectionEntry( + $jo_id, + $hub, + "SKU(s): " . $battery_string + ); + + // build SMS message + $this->sendSMSMessage( + $hub, + $jo_id, + $params['order_date'], + $params['service_type'], + $robj, + JORejectionReason::getName(JORejectionReason::NO_STOCK_SALES), + "Requested SKU(s) - " . $battery_string + ); + } + + // log this filter + $this->log($hub); + + error_log("FILTERED HUB " . $hub->getID() . " (no_inventory)"); + } else { + // include inventory in hub data + $hub_data['inventory'] = $qtys[$branch_code]; + + // we only include branches with branch codes and quantities + $results[] = $hub_data; + } + } + + // return filtered hubs + return $results; + } +} \ No newline at end of file diff --git a/src/Service/HubFilter/Filters/JoTypeHubFilter.php b/src/Service/HubFilter/Filters/JoTypeHubFilter.php new file mode 100644 index 00000000..15ba2952 --- /dev/null +++ b/src/Service/HubFilter/Filters/JoTypeHubFilter.php @@ -0,0 +1,44 @@ + $hub, + 'db_distance' => $hub_data['db_distance'], + 'distance' => $hub_data['distance'], + 'duration' => $hub_data['duration'], + 'jo_count' => 0, + 'inventory' => $hub_data['inventory'], + ]; + else + $this->log($hub); + } + + return $results; + } +} \ No newline at end of file diff --git a/src/Service/HubFilter/Filters/MaxResultsHubFilter.php b/src/Service/HubFilter/Filters/MaxResultsHubFilter.php new file mode 100644 index 00000000..027ab2cd --- /dev/null +++ b/src/Service/HubFilter/Filters/MaxResultsHubFilter.php @@ -0,0 +1,28 @@ +log($hubs[$i]['hub']); + } + + return $results; + } +} \ No newline at end of file diff --git a/src/Service/HubFilter/Filters/PaymentMethodHubFilter.php b/src/Service/HubFilter/Filters/PaymentMethodHubFilter.php new file mode 100644 index 00000000..bade7e65 --- /dev/null +++ b/src/Service/HubFilter/Filters/PaymentMethodHubFilter.php @@ -0,0 +1,55 @@ +getPaymentMethods(); + if ($payment_methods != null) + { + $flag_found_pmethod = false; + foreach ($payment_methods as $pmethod) + { + if ($pmethod == $params['payment_method']) + { + $results[] = [ + 'hub' => $hub, + 'db_distance' => $hub_data['db_distance'], + 'distance' => $hub_data['distance'], + 'duration' => $hub_data['duration'], + 'jo_count' => 0, + 'inventory' => $hub_data['inventory'], + ]; + } + $flag_found_pmethod = true; + } + + if (!$flag_found_pmethod) + $this->log($hub); + } + else + $this->log($hub); + } + + return $results; + } +} \ No newline at end of file diff --git a/src/Service/HubFilter/Filters/RiderAvailabilityHubFilter.php b/src/Service/HubFilter/Filters/RiderAvailabilityHubFilter.php new file mode 100644 index 00000000..8166a226 --- /dev/null +++ b/src/Service/HubFilter/Filters/RiderAvailabilityHubFilter.php @@ -0,0 +1,62 @@ +getJOID() . ": VIP CLASS"); + return $hubs; + } + + $results = []; + + foreach ($hubs as $hub_data) { + $hub = $hub_data['hub']; + + // check we have available riders + if ($hub->getAvailableRiders() === 0) { + // if we have a JO, create rejection record and notify + if (!empty($jo_id)) { + // create rejection report entry + $robj = $this->createRejectionEntry($jo_id, $hub); + + // build SMS message + $this->sendSMSMessage( + $hub, + $jo_id, + $params['order_date'], + $params['service_type'], + $robj, + JORejectionReason::getName(JORejectionReason::NO_RIDER_AVAILABLE), + ); + } + + // log this filter + $this->log($hub); + + error_log("FILTERED HUB " . $hub->getID() . " (no_available_rider)"); + } else { + $results[] = $hub_data; + } + } + + return $results; + } +} \ No newline at end of file diff --git a/src/Service/HubFilter/Filters/RoundRobinHubFilter.php b/src/Service/HubFilter/Filters/RoundRobinHubFilter.php new file mode 100644 index 00000000..ae0012f4 --- /dev/null +++ b/src/Service/HubFilter/Filters/RoundRobinHubFilter.php @@ -0,0 +1,39 @@ +hub_distributor = $hub_distributor; + } + + public function filter(array $hubs, array $params = []) : array + { + if (!$params['flag_round_robin']) + return $hubs; + + $results = []; + + // call hub distributor service + $arranged_hubs = $this->hub_distributor->arrangeHubs($hubs); + $results = $arranged_hubs; + + return $results; + } +} \ No newline at end of file diff --git a/src/Service/HubFilter/HubFilterInterface.php b/src/Service/HubFilter/HubFilterInterface.php new file mode 100644 index 00000000..fb9dea51 --- /dev/null +++ b/src/Service/HubFilter/HubFilterInterface.php @@ -0,0 +1,18 @@ +container = $container; $this->em = $em; $this->im = $im; $this->hub_distributor = $hub_distributor; @@ -45,6 +39,20 @@ class HubSelector $this->rt = $rt; } + // TODO: move this to env or something so we can enable and disable filters without code changes + protected function getActiveFilters(): array + { + return [ + 'App\Service\HubFilter\Filters\DateAndTimeHubFilter', + 'App\Service\HubFilter\Filters\JoTypeHubFilter', + 'App\Service\HubFilter\Filters\PaymentMethodHubFilter', + 'App\Service\HubFilter\Filters\RiderAvailabilityHubFilter', + 'App\Service\HubFilter\Filters\InventoryHubFilter', + 'App\Service\HubFilter\Filters\RoundRobinHubFilter', + 'App\Service\HubFilter\Filters\MaxResultsHubFilter', + ]; + } + public function find(HubCriteria $criteria) { $point = $criteria->getPoint(); @@ -66,461 +74,63 @@ class HubSelector $order_date = $criteria->getOrderDate(); $service_type = $criteria->getServiceType(); - $results = []; - // error_log('payment methods ' . $payment_method); // error_log('distance limit ' . $limit_distance); // error_log('emergency flag ' . $flag_emergency); // get all the hubs within distance $filtered_hubs = $this->getClosestHubs($point, $limit_distance, $jo_id, $customer_id); + + // gather all params in one array + // TODO: figure out a better way to do this where we don't have to specify the filter names here + $params = [ + 'date_and_time' => [ + 'date_time' => $date_time, + ], + 'no_inventory' => [ + 'flag_inventory_check' => $flag_inventory_check, + 'customer_class' => $customer_class, + 'jo_type' => $jo_type, + 'order_date' => $order_date, + 'service_type' => $service_type, + 'items' => $items, + ], + 'job_order_type' => [ + 'flag_emergency' => $flag_emergency, + 'jo_type' => $jo_type, + ], + 'max_results' => [ + 'limit_results' => $limit_results, + ], + 'no_payment_method' => [ + 'flag_emergency' => $flag_emergency, + 'payment_method' => $payment_method, + ], + 'no_available_rider' => [ + 'flag_riders_check' => $flag_riders_check, + 'customer_class' => $customer_class, + 'order_date' => $order_date, + 'service_type' => $service_type, + ], + 'round_robin' => [ + 'flag_round_robin' => $flag_round_robin, + ], + ]; - // error_log('closest hubs ' . json_encode($filtered_hubs)); + // loop through all enabled filters + foreach ($this->getActiveFilters() as $hub_filter) { + $f = $this->container->get($hub_filter); + $f->setJOID($jo_id); + $f->setCustomerID($customer_id); - // filter the first hub results for date and opening times - $hubs_date_time = $this->filterHubsByDateAndTime($filtered_hubs, $date_time, $jo_id, $customer_id); - $filtered_hubs = $hubs_date_time; + $filtered_hubs = $f->filter($filtered_hubs, $params[$f->getID()]); - // error_log('date_time hubs ' . json_encode($filtered_hubs)); - - // TODO: allow toggling of each filter individually for specific conditions (e.g. customer class, emergency) - - if (!$flag_emergency) - { - // filter jo types - $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, $jo_id, $customer_id); - $filtered_hubs = $hubs_payment_method; - - // error_log('payment hubs ' . json_encode($filtered_hubs)); + // error_log($f->getID() . ' hubs ' . json_encode($filtered_hubs)); } - // only enable rider and inventory checks if not VIP - if (!empty($customer_class) && $customer_class !== CustomerClassification::VIP) { - // available riders filter - $hubs_riders = $this->filterHubsByRiderAvailability($filtered_hubs, $flag_riders_check, $jo_id, $customer_id, $order_date, $service_type); - $filtered_hubs = $hubs_riders; - - // error_log('available riders hubs ' . json_encode($filtered_hubs)); - - // inventory filter - $hubs_inventory = $this->filterHubsByInventory($filtered_hubs, $flag_inventory_check, $jo_type, $items, $jo_id, $customer_id, $order_date, $service_type); - $filtered_hubs = $hubs_inventory; - - // error_log('inventory hubs ' . json_encode($filtered_hubs)); - } - - if (!$flag_emergency) { - // round robin filter - $hubs_round_robin = $this->filterHubsByRoundRobin($filtered_hubs, $flag_round_robin); - $filtered_hubs = $hubs_round_robin; - - // error_log('round robin hubs ' . json_encode($filtered_hubs)); - - // max results filter - $hubs_max_result = $this->filterHubsByMaxResults($filtered_hubs, $limit_results, $jo_id, $customer_id); - $filtered_hubs = $hubs_max_result; - } - - $results = $filtered_hubs; - // error_log('final hub list ' . json_encode($filtered_hubs)); - return $results; - } - - protected function filterHubsByRoundRobin($hubs, $flag_round_robin) - { - if (empty($hubs)) - return $hubs; - if (!$flag_round_robin) - return $hubs; - - $results = []; - // call hub distributor service - $arranged_hubs = $this->hub_distributor->arrangeHubs($hubs); - $results = $arranged_hubs; - - return $results; - - } - - protected function filterHubsByMaxResults($hubs, $limit_result, $jo_id, $customer_id) - { - if (empty($hubs)) - return $hubs; - if (empty($limit_result)) - return $hubs; - - $results = []; - for ($i = 0; $i < count($hubs); $i++) - { - if ($i < $limit_result) - $results[] = $hubs[$i]; - else - $this->hub_filter_logger->logFilteredHub($hubs[$i]['hub'], 'max_results', $jo_id, $customer_id); - } - - return $results; - } - - protected function filterHubsByJoType($hubs, $jo_type, $jo_id, $customer_id) - { - if (empty($hubs)) - return $hubs; - if (empty($jo_type)) - return $hubs; - - $results = []; - foreach ($hubs as $hub_data) - { - $hub = $hub_data['hub']; - - // TODO: for now, have this return true - $has_jo_type = true; - // check if hub offers the jo_type - // TODO: add service to hub - if ($has_jo_type) - $results[] = [ - 'hub' => $hub, - 'db_distance' => $hub_data['db_distance'], - 'distance' => $hub_data['distance'], - 'duration' => $hub_data['duration'], - 'jo_count' => 0, - 'inventory' => $hub_data['inventory'], - ]; - else - $this->hub_filter_logger->logFilteredHub($hub, 'job_order_type', $jo_id, $customer_id); - } - - return $results; - } - - protected function filterHubsByPaymentMethod($hubs, $payment_method, $jo_id, $customer_id) - { - if (empty($hubs)) - return $hubs; - if (empty($payment_method)) - return $hubs; - - $results = []; - foreach ($hubs as $hub_data) - { - $hub = $hub_data['hub']; - - // name of payment method is what is saved - $payment_methods = $hub->getPaymentMethods(); - if ($payment_methods != null) - { - $flag_found_pmethod = false; - foreach ($payment_methods as $pmethod) - { - if ($pmethod == $payment_method) - { - $results[] = [ - 'hub' => $hub, - 'db_distance' => $hub_data['db_distance'], - 'distance' => $hub_data['distance'], - 'duration' => $hub_data['duration'], - 'jo_count' => 0, - 'inventory' => $hub_data['inventory'], - ]; - } - $flag_found_pmethod = true; - } - - if (!$flag_found_pmethod) - $this->hub_filter_logger->logFilteredHub($hub, 'no_payment_method', $jo_id, $customer_id); - } - else - $this->hub_filter_logger->logFilteredHub($hub, 'no_payment_method', $jo_id, $customer_id); - } - - return $results; - } - - protected function filterHubsByDateAndTime($hubs, $date_time, $jo_id, $customer_id) - { - if (empty($hubs)) - return $hubs; - - if ($date_time == null) - return $hubs; - - $results = []; - - foreach ($hubs as $hub_data) - { - // go through each hub's opening times to check if hub is open - // for the specified time - // get hub opening and closing times - // TODO: maybe in the future, might also have to check if hub - // is open/available on date/day - $hub = $hub_data['hub']; - - $time_open = $hub->getTimeOpen()->format("H:i:s"); - $time_close = $hub->getTimeClose()->format("H:i:s"); - - $filter_time = $date_time->format("H:i:s"); - - if (($filter_time >= $time_open) && - ($filter_time <= $time_close)) - { - $results[] = [ - 'hub' => $hub, - 'db_distance' => $hub_data['db_distance'], - 'distance' => $hub_data['distance'], - 'duration' => $hub_data['duration'], - 'jo_count' => 0, - 'inventory' => $hub_data['inventory'], - ]; - } - else - $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, $jo_id, $customer_id, $order_date, $service_type) - { - // check if this is enabled - if (!$flag_inventory_check) { - error_log("INVENTORY CHECK " . $jo_id . ": DISABLED"); - return $hubs; - } - - // check hub list is not empty - if (empty($hubs)) { - error_log("INVENTORY CHECK " . $jo_id . ": NO HUBS"); - return $hubs; - } - - // check item list is not empty - if (empty($items)) { - error_log("INVENTORY CHECK " . $jo_id . ": NO ITEMS"); - return $hubs; - } - - // check this is a battery item related JO - if ($jo_type != ServiceType::BATTERY_REPLACEMENT_NEW && - $jo_type != ServiceType::BATTERY_REPLACEMENT_WARRANTY - ) { - error_log("INVENTORY CHECK " . $jo_id . ": INVALID SERVICE TYPE: " . $jo_type); - return $hubs; - } - - // get a list of all hubs with branch codes - $branch_codes = []; - foreach ($hubs as $hub_data) { - $branch_code = $hub_data['hub']->getBranchCode(); - if (!empty($branch_code)) { - $branch_codes[] = $branch_code; - } - }; - - $hubs_to_filter = []; - $results = []; - $qtys = []; - - // call inventory manager for all hubs for selected SKUs - $skus = array_keys($items); - - error_log("CHECKING INVENTORY FOR " . count($skus) . " ITEM(S) ON HUBS " . count($branch_codes) . "..."); - - $branches = $this->im->getBranchesInventory($branch_codes, $skus); - - error_log("REQUEST COMPLETE, RESULT COUNT: " . count($branches)); - - // check each result to see if sufficient quantity exists to meet request - foreach ($branches as $branch) { - if (isset($branch['BranchCode'])) { - // filter out branch if it does not have sufficient inventory - if ($branch['Quantity'] < $items[$branch['SapCode']] && - !isset($hubs_to_filter[$branch['BranchCode']]) - ) { - error_log("FILTERING BRANCH WITH NO INVENTORY: " . $branch['BranchCode']); - $hubs_to_filter[$branch['BranchCode']] = true; - } else { - // save inventory count so we don't have to recheck later - $qtys[$branch['BranchCode']] = $branch['Quantity']; - } - } - } - - // get battery models for each requested SKU - $batteries = []; - foreach ($skus as $sku) { - $bobj = $this->em->getRepository(Battery::class)->findOneBy(['sap_code' => $sku]); - $batteries[] = implode(" ", [$bobj->getModel()->getName(), $bobj->getSize()->getName()]); - } - $battery_string = implode(", ", $batteries); - - // remove filtered hubs from list - foreach ($hubs as $hub_data) { - $hub_obj = $hub_data['hub']; - $branch_code = $hub_data['hub']->getBranchCode(); - - // check if we are filtering this hub - if (isset($hubs_to_filter[$branch_code])) { - // if we have a JO, create rejection record and notify - if (!empty($jo_id)) { - // create rejection report entry - $robj = $this->createRejectionEntry( - $jo_id, - $hub_obj, - "SKU(s): " . $battery_string - ); - - // build SMS message - $this->sendSMSMessage( - $hub_obj, - $jo_id, - $order_date, - $service_type, - $robj, - JORejectionReason::getName(JORejectionReason::NO_STOCK_SALES), - "Requested SKU(s) - " . $battery_string - ); - } - - // log this filter - $this->hub_filter_logger->logFilteredHub($hub_obj, 'no_inventory', $jo_id, $customer_id); - - error_log("FILTERED HUB " . $hub_obj->getID() . " (no_inventory)"); - } else if (!empty($branch_code) && isset($qtys[$branch_code])) { - // include inventory in hub data - $hub_data['inventory'] = $qtys[$branch_code]; - - // we only include branches with branch codes and quantities - $results[] = $hub_data; - } - } - - // return filtered hubs - return $results; - - // NOTE: leaving the old code here for posterity, for now - /* - if ($flag_inventory_check) - { - foreach ($hubs as $hub_data) - { - $hub = $hub_data['hub']; - - if ($jo_type == ServiceType::BATTERY_REPLACEMENT_NEW) - { - // call inventory - $has_items = $this->checkInventory($items, $hub); - if ($has_items) - $results[] = [ - 'hub' => $hub, - 'db_distance' => $hub_data['db_distance'], - 'distance' => $hub_data['distance'], - 'duration' => $hub_data['duration'], - 'jo_count' => 0, - ]; - else - { - // get the skus for the message - $sku_text = ''; - foreach ($items as $key => $value) - { - $sku_text .= ' ' . $key; - } - // send SMS to hub - $message = str_replace('item_display', trim($sku_text), $this->trans->trans('no_inventory_message')); - // error_log($message); - $this->sendSMSMessage($hub, $items); - - $this->hub_filter_logger->logFilteredHub($hub, 'no_inventory', $jo_id, $customer_id); - } - } - if ($jo_type == ServiceType::BATTERY_REPLACEMENT_WARRANTY) - { - // call inventory - $has_items = $this->checkInventory($items, $hub); - if ($has_items) - $results[] = [ - 'hub' => $hub, - 'db_distance' => $hub_data['db_distance'], - 'distance' => $hub_data['distance'], - 'duration' => $hub_data['duration'], - 'jo_count' => 0, - ]; - else - { - // get the skus for the message - $sku_text = ''; - foreach ($items as $key => $value) - { - $sku_text .= ' ' . $key; - } - // send SMS to hub - $message = str_replace('item_display', trim($sku_text), $this->trans->trans('no_inventory_message')); - // error_log($message); - $this->sendSMSMessage($hub, $items); - - $this->hub_filter_logger->logFilteredHub($hub, 'no_inventory', $jo_id, $customer_id); - } - } - } - } - - return $results; - */ - } - - protected function filterHubsByRiderAvailability($hubs, $flag_riders_check, $jo_id, $customer_id, $order_date, $service_type) - { - // check if this is enabled - if (!$flag_riders_check) { - return $hubs; - } - - // check hub list is not empty - if (empty($hubs)) { - return $hubs; - } - - $results = []; - - foreach ($hubs as $hub_data) { - $hub_obj = $hub_data['hub']; - - // check we have available riders - if ($hub_obj->getAvailableRiders() === 0) { - // if we have a JO, create rejection record and notify - if (!empty($jo_id)) { - // create rejection report entry - $robj = $this->createRejectionEntry($jo_id, $hub_obj); - - // build SMS message - $this->sendSMSMessage( - $hub_obj, - $jo_id, - $order_date, - $service_type, - $robj, - JORejectionReason::getName(JORejectionReason::NO_RIDER_AVAILABLE), - ); - } - - // log this filter - $this->hub_filter_logger->logFilteredHub($hub_obj, 'no_available_rider', $jo_id, $customer_id); - - error_log("FILTERED HUB " . $hub_obj->getID() . " (no_available_rider)"); - } else { - $results[] = $hub_data; - } - } - - return $results; + return $filtered_hubs; } protected function getClosestHubs(Point $point, $limit_distance, $jo_id, $customer_id) @@ -573,44 +183,6 @@ class HubSelector return $hubs_data; } - protected function checkInventory($items, $branch_codes) - { - // check if hub has all items - $skus = []; - $result = false; - - foreach ($items as $key => $value) - { - // add sap code of item/battery into array since - // getBranchesInventory takes in an array of hubs/branches - // and an array of skus - // $items as format: $items[sku] = quantity - $skus[] = $key; - } - - // call InventoryManager's getBranchesInventory to check if hub has all items - $branches_with_items = $this->im->getBranchesInventory($branch_codes, $skus); - - if (!empty($branches_with_items)) - { - // check if branch has enough quantity for item - foreach ($branches_with_items as $branch) - { - // get quantity from call - $qty_available = $branch['Quantity']; - - // get the quantity request - $sku_requested = $branch['SapCode']; - $qty_requested = $items[$sku_requested]; - if ($qty_available >= $qty_requested) - $result = true; - } - } - - // return true or false - return $result; - } - // convert db distance to kilometers protected function distance($lat1, $lon1, $lat2, $lon2) { @@ -625,61 +197,5 @@ class HubSelector return round(($miles * 1.609344), 1); } - - protected function createRejectionEntry($jo_id, $hub, $remarks = ""): JORejection - { - $jo = $this->em->getRepository(JobOrder::class)->find($jo_id); - - $robj = new JORejection(); - $robj->setDateCreate(new DateTime()) - ->setHub($hub) - ->setJobOrder($jo) - ->setReason(JORejectionReason::NO_STOCK_SALES) - ->setRemarks(implode(" ", ["Automatically filtered by hub selector.", $remarks])); - - $this->em->persist($robj); - $this->em->flush(); - - return $robj; - } - - protected function sendSMSMessage($hub, $jo_id, $order_date, $service_type, $rejection, $reason = "", $remarks = ""): void - { - // check if we already have a rejection record for this hub and JO. this also means an SMS was already sent - $rejection_count = $this->em->createQueryBuilder() - ->select('count(r)') - ->from(JORejection::class, 'r') - ->where('r.job_order = :jo_id') - ->andWhere('r.hub = :hub_id') - ->andWhere('r.id != :rejection_id') - ->setParameter('jo_id', $jo_id) - ->setParameter('hub_id', $hub->getID()) - ->setParameter('rejection_id', $rejection->getID()) - ->getQuery() - ->getSingleScalarResult(); - - // if we already have a rejection record for this hub and JO, do not send another SMS - if ($rejection_count >= 1) { - error_log("ALREADY SENT REJECTION SMS TO HUB " . $hub->getID() . " FOR JO " . $jo_id); - return; - } - - $message = 'Job Order #: ' . $jo_id . "\n" . - 'Order Date and Time: ' . $order_date->format('d M Y g:i A') . "\n" . - 'Date and Time Rejected: ' . $rejection->getDateCreate()->format('d M Y g:i A') . "\n" . - 'Enrollee Name: ' . implode(" - ", [$hub->getName(), $hub->getBranch()]) . "\n" . - 'Reason of Rejection: ' . $reason . "\n" . - 'Remarks: ' . $remarks . "\n" . - 'Type of Service: ' . ServiceType::getName($service_type); - - error_log("SENDING SMS MESsAGE:\r\n" . $message); - - // send SMS message to hub - $this->rt->sendSMS( - $hub->getNotifNumber(), - $this->trans->trans('message.battery_brand_allcaps'), - $message - ); - } }