diff --git a/config/services.yaml b/config/services.yaml
index 00085811..6af4a5d3 100644
--- a/config/services.yaml
+++ b/config/services.yaml
@@ -16,6 +16,7 @@ parameters:
android_app_version: "%env(ANDROID_APP_VERSION)%"
ios_app_version: "%env(IOS_APP_VERSION)%"
insurance_premiums_banner_url: "%env(INSURANCE_PREMIUMS_BANNER_URL)%"
+ enabled_hub_filters: "%env(ENABLED_HUB_FILTERS)%"
services:
# default configuration for services in *this* file
@@ -109,6 +110,12 @@ services:
arguments:
$callback_url: "%env(WARRANTY_SERIAL_CALLBACK_URL)%"
+ App\Command\ProcessLatePaymongoTransactionsCommand:
+ arguments:
+ $em: "@doctrine.orm.entity_manager"
+ $paymongo: "@App\\Service\\PayMongoConnector"
+ $webhook_id: "%env(PAYMONGO_WEBHOOK_ID)%"
+
# rider tracker service
App\Service\RiderTracker:
arguments:
@@ -316,3 +323,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/Command/ProcessLatePaymongoTransactionsCommand.php b/src/Command/ProcessLatePaymongoTransactionsCommand.php
new file mode 100644
index 00000000..8bdc66ca
--- /dev/null
+++ b/src/Command/ProcessLatePaymongoTransactionsCommand.php
@@ -0,0 +1,136 @@
+em = $em;
+ $this->paymongo = $paymongo;
+ $this->webhook_id = $webhook_id;
+
+ parent::__construct();
+ }
+
+ protected function configure()
+ {
+ $this->setName('paymongo:checkpending')
+ ->setDescription('Check for any late PayMongo transactions and process if needed.')
+ ->setHelp('Check for any late PayMongo transactions and process if needed.')
+ ->addOption('force', 'f', InputOption::VALUE_NONE, 'Ignore webhook status and process anyway.');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $force = $input->getOption('force');
+
+ // if we aren't forcing, check webhook status first
+ if (!$force) {
+ $output->writeln('Checking webhook status...');
+
+ // check if webhook is disabled
+ $webhook = $this->paymongo->getWebhook($this->webhook_id);
+
+ if ($webhook['success'] && $webhook['response']['data']['attributes']['status'] === 'enabled') {
+ $output->writeln('Webhook is enabled, no need to do anything.');
+
+ return 0;
+ } else {
+ $output->writeln('Webhook is disabled! Logging event and attempting to re-enable...');
+
+ // attempt re-enabling of webhook
+ $result = $this->paymongo->enableWebhook($this->webhook_id);
+ if ($result['success'] && $result['response']['data']['attributes']['status'] ?? null === 'enabled') {
+ $output->writeln('Webhook ' . $this->webhook_id . ' re-enabled!');
+
+ // log event
+ $this->paymongo->log('WEBHOOK RE-ENABLED', "[]", json_encode($result['response'], JSON_PRETTY_PRINT), 'webhook');
+ } else {
+ $output->writeln('Webhook ' . $this->webhook_id . ' could not be re-enabled.');
+
+ // log event
+ $this->paymongo->log('WEBHOOK FAILURE', "[]", json_encode($result['response'], JSON_PRETTY_PRINT), 'webhook');
+ }
+ }
+ }
+
+ $output->writeln('Fetching all late pending transactions...');
+
+ // set date threshold to 24 hours ago
+ $date_threshold = (new DateTime())->modify('-24 hours');
+
+ $transactions = $this->em->getRepository(GatewayTransaction::class)
+ ->createQueryBuilder('t')
+ ->select('t')
+ ->where('t.status = :status')
+ ->andWhere('t.date_create <= :date_threshold')
+ ->setParameter('status', TransactionStatus::PENDING)
+ ->setParameter('date_threshold', $date_threshold)
+ ->getQuery()
+ ->getResult();
+
+ $output->writeln('Found '. count($transactions) . ' rows matching criteria.');
+
+ $x = 0;
+
+ foreach ($transactions as $trans) {
+ // check paymongo status
+ $checkout = $this->paymongo->getCheckout($trans->getExtTransactionId());
+
+ if ($checkout['success']) {
+ // check if we have any payments made
+ $payments = $checkout['response']['data']['attributes']['payments'] ?? [];
+
+ if (!empty($payments)) {
+ $amount_paid = 0;
+
+ // for good measure, we get all successful payments and add them up
+ foreach ($payments as $payment) {
+ if ($payment['attributes']['status'] === TransactionStatus::PAID) {
+ $amount_paid = bcadd($amount_paid, $payment['attributes']['amount']);
+ }
+ }
+
+ // this transaction is fully paid, so we mark it as paid
+ if (bccomp($trans->getAmount(), $amount_paid) <= 0) {
+ $trans->setStatus(TransactionStatus::PAID);
+ $trans->setDatePay(new DateTime());
+ $this->em->flush();
+
+ $output->writeln('Marked transaction '. $trans->getID() . ' as paid.');
+ $x++;
+ } else {
+ $output->writeln('Insufficient payment amount (' . $amount_paid . '/' . $trans->getAmount() . ') for this transaction: ' . $trans->getID() . '');
+ }
+ } else {
+ $output->writeln('No payments found for transaction: ' . $trans->getID() . '');
+ }
+ } else {
+ $output->writeln('Checkout not found: ' . $checkout['error']['message'] . '');
+ }
+ }
+
+ $output->writeln('Done! Processed ' . $x . ' rows.');
+
+ return 0;
+ }
+}
diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php
index 694ffdd0..bb9c8546 100644
--- a/src/Controller/CAPI/RiderAppController.php
+++ b/src/Controller/CAPI/RiderAppController.php
@@ -413,7 +413,9 @@ class RiderAppController extends ApiController
return new APIResponse(false, $msg);
// check if JO can be modified first
- $this->checkJOProgressionAllowed($jo, $rider);
+ if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
+ return new APIResponse(false, 'Job order can no longer be modified.');
+ }
// TODO: refactor this into a jo handler class, so we don't have to repeat for control center
@@ -466,7 +468,9 @@ class RiderAppController extends ApiController
return new APIResponse(true, $msg);
// check if JO can be modified first
- $this->checkJOProgressionAllowed($jo, $rider);
+ if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
+ return new APIResponse(false, 'Job order can no longer be modified.');
+ }
// requeue it, instead of cancelling it
$jo->requeue();
@@ -527,7 +531,9 @@ class RiderAppController extends ApiController
$jo = $rider->getCurrentJobOrder();
// check if JO can be modified first
- $this->checkJOProgressionAllowed($jo, $rider);
+ if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
+ return new APIResponse(false, 'Job order can no longer be modified.');
+ }
// set delivery status
$jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB);
@@ -570,7 +576,9 @@ class RiderAppController extends ApiController
$jo = $rider->getCurrentJobOrder();
// check if JO can be modified first
- $this->checkJOProgressionAllowed($jo, $rider);
+ if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
+ return new APIResponse(false, 'Job order can no longer be modified.');
+ }
// set delivery status
$jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB_PRE_JO);
@@ -613,7 +621,9 @@ class RiderAppController extends ApiController
$jo = $rider->getCurrentJobOrder();
// check if JO can be modified first
- $this->checkJOProgressionAllowed($jo, $rider);
+ if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
+ return new APIResponse(false, 'Job order can no longer be modified.');
+ }
// set delivery status
$jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB_PRE_JO);
@@ -656,7 +666,9 @@ class RiderAppController extends ApiController
$jo = $rider->getCurrentJobOrder();
// check if JO can be modified first
- $this->checkJOProgressionAllowed($jo, $rider);
+ if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
+ return new APIResponse(false, 'Job order can no longer be modified.');
+ }
// set delivery status
$jo->setDeliveryStatus(DeliveryStatus::RIDER_START);
@@ -700,7 +712,9 @@ class RiderAppController extends ApiController
$jo->setStatus(JOStatus::IN_PROGRESS);
// check if JO can be modified first
- $this->checkJOProgressionAllowed($jo, $rider);
+ if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
+ return new APIResponse(false, 'Job order can no longer be modified.');
+ }
// set delivery status
$jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE);
@@ -761,7 +775,9 @@ class RiderAppController extends ApiController
$jo = $rider->getCurrentJobOrder();
// check if JO can be modified first
- $this->checkJOProgressionAllowed($jo, $rider);
+ if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
+ return new APIResponse(false, 'Job order can no longer be modified.');
+ }
// set delivery status
$jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB);
@@ -854,7 +870,9 @@ class RiderAppController extends ApiController
return new APIResponse(false, $msg);
// check if JO can be modified first
- $this->checkJOProgressionAllowed($jo, $rider);
+ if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
+ return new APIResponse(false, 'Job order can no longer be modified.');
+ }
// need to check if service type is battery sales
// if so, serial is a required parameter
@@ -1002,7 +1020,9 @@ class RiderAppController extends ApiController
$jo = $rider->getCurrentJobOrder();
// check if JO can be modified first
- $this->checkJOProgressionAllowed($jo, $rider);
+ if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
+ return new APIResponse(false, 'Job order can no longer be modified.');
+ }
// set delivery status
$jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB_POST_JO);
@@ -1046,7 +1066,9 @@ class RiderAppController extends ApiController
$jo = $rider->getCurrentJobOrder();
// check if JO can be modified first
- $this->checkJOProgressionAllowed($jo, $rider);
+ if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
+ return new APIResponse(false, 'Job order can no longer be modified.');
+ }
// set delivery status
$jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB_POST_JO);
@@ -1265,7 +1287,9 @@ class RiderAppController extends ApiController
$jo = $em->getRepository(JobOrder::class)->find($jo_id);
// check if JO can be modified first
- $this->checkJOProgressionAllowed($jo, $rider);
+ if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
+ return new APIResponse(false, 'Job order can no longer be modified.');
+ }
// check if we have trade in items
$ti_items = [];
@@ -1376,7 +1400,9 @@ class RiderAppController extends ApiController
return new APIResponse(false, $msg);
// check if JO can be modified first
- $this->checkJOProgressionAllowed($jo, $rider);
+ if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
+ return new APIResponse(false, 'Job order can no longer be modified.');
+ }
// check service type
$stype_id = $req->request->get('stype_id');
@@ -1740,22 +1766,40 @@ class RiderAppController extends ApiController
return $msg;
}
- protected function checkJOProgressionAllowed(JobOrder $jo, $rider)
+ protected function checkJOProgressionAllowed(EntityManagerInterface $em, JobOrder $jo, &$rider)
{
+ $allowed = true;
+
+ error_log("JO delivery status is " . $jo->getDeliveryStatus() . " (not allowed: " . DeliveryStatus::CANCELLED . ")");
+ error_log("JO status is " . $jo->getStatus() . " (not allowed: " . JOStatus::CANCELLED . ")");
+
// TODO: add more statuses to block if needed, hence. this is a failsafe in case MQTT is not working.
+ // check delivery status
+ switch ($jo->getDeliveryStatus())
+ {
+ case DeliveryStatus::CANCELLED:
+ $allowed = false;
+ break;
+ }
+
+ // check JO status as well
switch ($jo->getStatus())
{
case JOStatus::CANCELLED:
- // if this is the rider's current JO, set to null
- if ($rider->getCurrentJobOrder() === $jo) {
- $rider->setCurrentJobOrder();
- }
-
- return new APIResponse(false, 'Job order can no longer be modified.');
+ $allowed = false;
break;
- default:
- return true;
}
+
+ // if this is the rider's current JO, set to null
+ if (!$allowed) {
+ if ($rider->getCurrentJobOrder() === $jo) {
+ $rider->setCurrentJobOrder();
+ $em->persist($rider);
+ $em->flush();
+ }
+ }
+
+ return $allowed;
}
protected function debugRequest(Request $req)
diff --git a/src/Controller/CustomerAppAPI/JobOrderController.php b/src/Controller/CustomerAppAPI/JobOrderController.php
index fa5a9a85..4f5c95ae 100644
--- a/src/Controller/CustomerAppAPI/JobOrderController.php
+++ b/src/Controller/CustomerAppAPI/JobOrderController.php
@@ -488,6 +488,8 @@ class JobOrderController extends ApiController
JobOrderManager $jo_manager,
PriceTierManager $pt_manager
) {
+ //error_log("CREATING JOB ORDER WITH PARAMS " . print_r($req->request->all(), true));
+
// validate params
$validity = $this->validateRequest($req, [
'service_type',
@@ -575,6 +577,8 @@ class JobOrderController extends ApiController
$flag_advance_order = true;
// $flag_advance_order = $advance_order ? true : false;
+ //error_log("RUNNING QUERY NEXT");
+
$jo = new JobOrder();
$jo->setSource(TransactionOrigin::MOBILE_APP)
->setStatus(JOStatus::PENDING)
@@ -643,6 +647,8 @@ class JobOrderController extends ApiController
$icrit->addPromo($promo);
}
+ //error_log("CONTINUING QUERY BUILDING");
+
// check customer vehicle
$cv = $this->em->getRepository(CustomerVehicle::class)->find($req->request->get('cv_id'));
if ($cv == null) {
@@ -708,13 +714,30 @@ class JobOrderController extends ApiController
$invoice = $ic->generateInvoice($icrit);
$jo->setInvoice($invoice);
+ //error_log("GENERATED INVOICE");
+
+ // save here first so we have a JO ID which is required for the hub selector
+ $this->em->persist($invoice);
+ $this->em->persist($jo);
+ $this->em->flush();
+
// assign hub and rider
// check if hub is null
if ($hub == null) {
+ //error_log("NO HUB");
+
// TODO: need to factor out the setting of HubCriteria fields
$hub_criteria = new HubCriteria();
$hub_criteria->setPoint($jo->getCoordinates());
+ // set job order info
+ $hub_criteria->setJobOrderId($jo->getID())
+ ->setJoType($jo->getServiceType())
+ ->setJoOrigin($jo->getSource())
+ ->setCustomerClass($cust->getCustomerClassification())
+ ->setOrderDate($jo->getDateCreate())
+ ->setServiceType($jo->getServiceType());
+
// get distance limit for mobile from env
// get value of hub_filter_enable from env
$limit_distance = $_ENV['CUST_DISTANCE_LIMIT'];
@@ -752,6 +775,10 @@ class JobOrderController extends ApiController
$hub_criteria->setCustomerId($customer_id);
+ // set filter flags for inventory and available riders
+ $hub_criteria->setInventoryCheck();
+ $hub_criteria->setRidersCheck();
+
// find nearest hubs
$nearest_hubs = $hub_select->find($hub_criteria);
@@ -830,6 +857,8 @@ class JobOrderController extends ApiController
}
}
} else {
+ //error_log("HAS HUB: " . $hub->getID());
+
$jo->setHub($hub);
$jo->setStatus(JOStatus::RIDER_ASSIGN);
$jo->setStatusAutoAssign(AutoAssignStatus::HUB_ASSIGNED);
@@ -841,8 +870,10 @@ class JobOrderController extends ApiController
$hub_dist->incrementJoCountForHub($hub);
}
+ //error_log("DONE SELECTING HUB");
+
+ // save additional hub related changes
$this->em->persist($jo);
- $this->em->persist($invoice);
// add event log for JO
$event = new JOEvent();
@@ -953,6 +984,8 @@ class JobOrderController extends ApiController
}
}
+ //error_log("DONE CREATING JOB ORDER " . $jo->getID());
+
// response
return new ApiResponse(true, '', [
'jo_id' => $jo->getID(),
diff --git a/src/Controller/JobOrderController.php b/src/Controller/JobOrderController.php
index 17c62a45..29ef66d5 100644
--- a/src/Controller/JobOrderController.php
+++ b/src/Controller/JobOrderController.php
@@ -761,7 +761,7 @@ class JobOrderController extends Controller
$lat = $req->request->get('coord_lat', 0);
$price_tier = 0;
- if (($lng != 0) && ($lat != 0))
+ if (!empty($lng) && !empty($lat))
{
$coordinates = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat'));
$price_tier = $pt_manager->getPriceTier($coordinates);
diff --git a/src/Controller/PayMongoController.php b/src/Controller/PayMongoController.php
index 21cd864c..af698acd 100644
--- a/src/Controller/PayMongoController.php
+++ b/src/Controller/PayMongoController.php
@@ -11,6 +11,8 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use DateTime;
+
class PayMongoController extends Controller
{
protected $pm;
@@ -45,10 +47,8 @@ class PayMongoController extends Controller
switch ($event_name) {
case "payment.paid":
return $this->handlePaymentPaid($event);
- break;
case "payment.failed":
- return $this->handlePaymentPaid($event);
- break;
+ return $this->handlePaymentFailed($event);
case "payment.refunded": // TODO: handle refunds
case "payment.refund.updated":
case "checkout_session.payment.paid":
@@ -69,6 +69,7 @@ class PayMongoController extends Controller
if (!empty($obj)) {
// mark as paid
$obj->setStatus(TransactionStatus::PAID);
+ $obj->setDatePay(new DateTime());
$this->em->flush();
}
@@ -77,7 +78,7 @@ class PayMongoController extends Controller
]);
}
- protected function handlePaymentFailed(Request $req)
+ protected function handlePaymentFailed($event)
{
// TODO: do something about failed payments?
return $this->json([
diff --git a/src/Controller/ReportController.php b/src/Controller/ReportController.php
index 4f3ed31e..5d05b7f8 100644
--- a/src/Controller/ReportController.php
+++ b/src/Controller/ReportController.php
@@ -236,6 +236,10 @@ class ReportController extends Controller
$reason = $jor->getReason();
+ $dispatched_by = 'system';
+ if ($jor->getUser() != null)
+ $dispatched_by = $jor->getUser()->getFullName();
+
$res[] = [
$jo->getID(),
$jo->getDateSchedule()->format('m/d/Y H:i'),
@@ -244,7 +248,7 @@ class ReportController extends Controller
JORejectionReason::getName($jor->getReason()),
$jor->getContactPerson(),
$jor->getRemarks(),
- $jor->getUser()->getFullName(),
+ !empty($jor->getUser()) ? $jor->getUser()->getFullName() : "",
ServiceType::getName($jo->getServiceType()),
];
}
diff --git a/src/Controller/TAPI/JobOrderController.php b/src/Controller/TAPI/JobOrderController.php
index ae4d5a61..cedf0320 100644
--- a/src/Controller/TAPI/JobOrderController.php
+++ b/src/Controller/TAPI/JobOrderController.php
@@ -239,6 +239,10 @@ class JobOrderController extends ApiController
// find nearest hubs
$nearest_hubs = $hub_select->find($hub_criteria);
+ // set filter flags for inventory and available riders
+ $hub_criteria->setInventoryCheck();
+ $hub_criteria->setRidersCheck();
+
if (!empty($nearest_hubs))
{
// go through the hub list, find the nearest hub
diff --git a/src/Entity/Hub.php b/src/Entity/Hub.php
index da3a44b9..7fba62c4 100644
--- a/src/Entity/Hub.php
+++ b/src/Entity/Hub.php
@@ -114,7 +114,9 @@ class Hub
public function getAvailableRiders()
{
$crit = Criteria::create();
- $crit->where(Criteria::expr()->eq('flag_available', true));
+ $crit->where(Criteria::expr()->eq('flag_available', true))
+ ->where(Criteria::expr()->eq('flag_active', true))
+ ->where(Criteria::expr()->eq('current_job_order', null));
return $this->riders->matching($crit);
}
diff --git a/src/Entity/SupportedArea.php b/src/Entity/SupportedArea.php
index 0e176f6a..c9cd52bf 100644
--- a/src/Entity/SupportedArea.php
+++ b/src/Entity/SupportedArea.php
@@ -39,6 +39,12 @@ class SupportedArea
*/
protected $coverage_area;
+ // prevent certain hub filters from being used
+ /**
+ * @ORM\Column(type="json", nullable=true)
+ */
+ protected $hub_filter_exceptions;
+
/**
* @ORM\ManyToOne(targetEntity="PriceTier", inversedBy="supported_areas")
* @ORM\JoinColumn(name="price_tier_id", referencedColumnName="id", nullable=true)
@@ -50,6 +56,7 @@ class SupportedArea
$this->date_create = new DateTime();
$this->price_tier = null;
+ $this->hub_filter_exceptions = [];
}
public function getID()
@@ -65,7 +72,7 @@ class SupportedArea
public function getDateCreate()
{
- return $this->date_Create;
+ return $this->date_create;
}
public function setName($name)
@@ -101,5 +108,16 @@ class SupportedArea
{
return $this->price_tier;
}
+
+ public function setHubFilterExceptions($exceptions)
+ {
+ $this->hub_filter_exceptions = $exceptions;
+ return $this;
+ }
+
+ public function getHubFilterExceptions()
+ {
+ return $this->hub_filter_exceptions;
+ }
}
diff --git a/src/EntityListener/GatewayTransactionListener.php b/src/EntityListener/GatewayTransactionListener.php
index c9007aaf..530f0093 100644
--- a/src/EntityListener/GatewayTransactionListener.php
+++ b/src/EntityListener/GatewayTransactionListener.php
@@ -58,17 +58,20 @@ class GatewayTransactionListener
'gateway_transaction' => $gt_obj,
]);
- if (!empty($obj)) {
+ // make sure the object exists and has not been processed yet
+ if (!empty($obj) && $obj->getStatus() === InsuranceApplicationStatus::CREATED) {
// mark as paid
$obj->setDatePay(new DateTime());
$obj->setStatus(InsuranceApplicationStatus::PAID);
$this->em->flush();
- }
- // flag on api as paid
- $result = $this->ic->tagApplicationPaid($obj->getExtTransactionId());
- if (!$result['success'] || $result['response']['transaction_code'] !== 'GR004') {
- error_log("INSURANCE MARK AS PAID FAILED FOR " . $obj->getID() . ": " . $result['error']['message']);
+ // flag on api as paid
+ $result = $this->ic->tagApplicationPaid($obj->getExtTransactionId());
+
+ // something went wrong with insurance api
+ if (!$result['success'] || $result['response']['transaction_code'] !== 'GR004') {
+ error_log("INSURANCE MARK AS PAID FAILED FOR " . $obj->getID() . ": " . $result['error']['message']);
+ }
}
}
}
diff --git a/src/Ramcar/DeliveryStatus.php b/src/Ramcar/DeliveryStatus.php
index b4d06871..c567032f 100644
--- a/src/Ramcar/DeliveryStatus.php
+++ b/src/Ramcar/DeliveryStatus.php
@@ -23,8 +23,8 @@ class DeliveryStatus extends NameValue
const COLLECTION = [
'rider_assign' => 'Assigned Rider',
'requeue' => 'Requeue',
- 'accept' => 'Rider Accept',
- 'arrive' => 'Rider Arrive',
+ 'rider_accept' => 'Rider Accept',
+ 'rider_arrive' => 'Rider Arrive',
'rider_edit' => 'Rider Edit',
'rider_depart_hub' => 'Rider Depart Hub',
'rider_arrive_hub_pre_jo' => 'Rider Arrive Hub Pre JO',
diff --git a/src/Ramcar/HubCriteria.php b/src/Ramcar/HubCriteria.php
index 5a663551..3f7668d5 100644
--- a/src/Ramcar/HubCriteria.php
+++ b/src/Ramcar/HubCriteria.php
@@ -12,6 +12,7 @@ class HubCriteria
protected $limit_results; // number of results to return
protected $limit_distance; // distance limit for search in km
protected $flag_inventory_check; // flag if we need to check for inventory
+ protected $flag_riders_check; // flag if we need to check for riders available
protected $jo_type; // jo service needed
protected $date_time; // date and time to check if hub is open or not
protected $items; // array of items: items[sku] = quantity to check for
@@ -20,6 +21,10 @@ class HubCriteria
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
+ protected $customer_class; // customer class
+ protected $order_date; // date JO was created
+ protected $service_type; // service type of JO
+ protected $jo_origin; // origin of JO
public function __construct()
{
@@ -29,12 +34,17 @@ class HubCriteria
$this->jo_type = '';
$this->date_time = new DateTime();
$this->flag_inventory_check = false;
+ $this->flag_riders_check = false;
$this->items = [];
$this->payment_method = '';
- $flag_emergency = false;
- $flag_round_robin = false;
- $jo_id = null;
- $customer_id = null;
+ $this->flag_emergency = false;
+ $this->flag_round_robin = false;
+ $this->jo_id = null;
+ $this->customer_id = null;
+ $this->customer_class = null;
+ $this->order_date = new DateTime();
+ $this->service_type = null;
+ $this->jo_origin = null;
}
public function setPoint(Point $point)
@@ -81,6 +91,17 @@ class HubCriteria
return $this->flag_inventory_check;
}
+ public function setRidersCheck($flag_riders_check = true)
+ {
+ $this->flag_riders_check = $flag_riders_check;
+ return $this;
+ }
+
+ public function hasRidersCheck()
+ {
+ return $this->flag_riders_check;
+ }
+
public function setJoType($jo_type)
{
// TODO: validate the jo type
@@ -171,5 +192,48 @@ class HubCriteria
return $this->customer_id;
}
+ public function setCustomerClass($customer_class)
+ {
+ $this->customer_class = $customer_class;
+ return $this;
+ }
+
+ public function getCustomerClass()
+ {
+ return $this->customer_class;
+ }
+
+ public function setOrderDate($order_date)
+ {
+ $this->order_date = $order_date;
+ return $this;
+ }
+
+ public function getOrderDate()
+ {
+ return $this->order_date;
+ }
+
+ public function setServiceType($service_type)
+ {
+ $this->service_type = $service_type;
+ return $this;
+ }
+
+ public function getServiceType()
+ {
+ return $this->service_type;
+ }
+
+ public function setJoOrigin($jo_origin)
+ {
+ $this->jo_origin = $jo_origin;
+ return $this;
+ }
+
+ public function getJoOrigin()
+ {
+ return $this->jo_origin;
+ }
}
diff --git a/src/Ramcar/JORejectionReason.php b/src/Ramcar/JORejectionReason.php
index 9dee1217..37d30c44 100644
--- a/src/Ramcar/JORejectionReason.php
+++ b/src/Ramcar/JORejectionReason.php
@@ -4,17 +4,24 @@ namespace App\Ramcar;
class JORejectionReason extends NameValue
{
- const ADMINISTRATIVE = 'administrative';
- const NO_STOCK_SALES = 'no_stock_sales';
- const NO_STOCK_SERVICE = 'no_stock_service';
- const LINE_NO_ANSWER = 'line_no_answer';
- const LINE_BUSY = 'line_busy';
- const NO_RIDER_AVAILABLE = 'no_rider_available';
- const NO_RIDER_IN_TRANSIT = 'no_rider_in_transit';
- const REFUSAL = 'refusal';
- const STORE_CLOSED = 'store_closed';
- const NO_CREDIT_CARD = 'no_credit_card';
- const DISCOUNT = 'discount';
+ const ADMINISTRATIVE = 'administrative';
+ const NO_STOCK_SALES = 'no_stock_sales';
+ const NO_STOCK_SERVICE = 'no_stock_service';
+ const LINE_NO_ANSWER = 'line_no_answer';
+ const LINE_BUSY = 'line_busy';
+ const NO_RIDER_AVAILABLE = 'no_rider_available';
+ const NO_RIDER_IN_TRANSIT = 'no_rider_in_transit';
+ const REFUSAL = 'refusal';
+ const STORE_CLOSED = 'store_closed';
+ const NO_CREDIT_CARD = 'no_credit_card';
+ const DISCOUNT = 'discount';
+ const STORE_CLOSED_SCHEDULED = 'store_closed_scheduled';
+ const STORE_CLOSED_HALF_DAY = 'store_closed_half_day';
+ const STORE_CLOSED_NO_ADVISE = 'store_closed_no_advise';
+ const PRIORITY_HUB_WTY_CLAIM = 'priority_hub_wty_claim';
+ const PRIORITY_HUB_JUMPSTART = 'priority_hub_jumpstart';
+ const PRIORITY_HUB_RESQ_REQUEST = 'priority_hub_resq_req';
+ const CUSTOMER_REQUEST = 'customer_request';
const COLLECTION = [
'administrative' => 'ADMINISTRATIVE',
@@ -28,5 +35,16 @@ class JORejectionReason extends NameValue
'store_closed' => 'STORE CLOSED',
'no_credit_card' => 'NO CREDIT CARD PAYMENT / NO TERMINAL',
'discount' => 'DISCOUNT',
+ 'store_closed_scheduled' => 'STORE CLOSED (ON SCHEDULE)',
+ 'store_closed_half_day' => 'STORE CLOSED (HALF DAY)',
+ 'store_closed_no_advise' => 'STORE CLOSED (NO ADVISE)',
+ 'priority_hub_wty_claim' => 'PRIORITY HUB OUTLET FOR WARRANTY CLAIM',
+ 'priority_hub_jumpstart' => 'PRIORITY HUB OUTLET FOR JUMPSTART',
+ 'priority_hub_resq_req' => 'PRIORITY HUB OUTLET FOR RESQ-Q REQUEST',
+ 'customer_request' => 'CUSTOMER REQUEST',
+ ];
+
+ const BLACKLIST = [
+ self::ADMINISTRATIVE => true,
];
}
diff --git a/src/Ramcar/NameValue.php b/src/Ramcar/NameValue.php
index 58b6d75e..99366a8d 100644
--- a/src/Ramcar/NameValue.php
+++ b/src/Ramcar/NameValue.php
@@ -4,9 +4,21 @@ namespace App\Ramcar;
class NameValue
{
+ const BLACKLIST = [];
+
static public function getCollection()
{
- return static::COLLECTION;
+ $result = [];
+ $blacklist = static::getBlacklist();
+
+ // filter from blacklist
+ foreach(static::COLLECTION as $key => $row) {
+ if (!isset($blacklist[$key])) {
+ $result[$key] = $row;
+ }
+ }
+
+ return $result;
}
static public function validate($value)
@@ -24,4 +36,9 @@ class NameValue
return 'Unknown';
}
+
+ static public function getBlacklist()
+ {
+ return static::BLACKLIST ?? [];
+ }
}
diff --git a/src/Service/HubDistributor.php b/src/Service/HubDistributor.php
index 27a70f15..b1d20ad6 100644
--- a/src/Service/HubDistributor.php
+++ b/src/Service/HubDistributor.php
@@ -81,6 +81,7 @@ class HubDistributor
'distance' => $hub_data['distance'],
'duration' => $hub_data['duration'],
'jo_count' => $hub_jo_count,
+ 'inventory' => $hub_data['inventory'] ?? 0,
];
}
else
@@ -91,6 +92,7 @@ class HubDistributor
'distance' => $hub_data['distance'],
'duration' => $hub_data['duration'],
'jo_count' => 0,
+ 'inventory' => $hub_data['inventory'] ?? 0,
];
}
}
diff --git a/src/Service/HubFilter/BaseHubFilter.php b/src/Service/HubFilter/BaseHubFilter.php
new file mode 100644
index 00000000..81f75b7d
--- /dev/null
+++ b/src/Service/HubFilter/BaseHubFilter.php
@@ -0,0 +1,144 @@
+hub_filter_logger = $hub_filter_logger;
+ $this->em = $em;
+ $this->rt = $rt;
+ $this->trans = $trans;
+
+ error_log("-------------------");
+ error_log("HUB FILTER RUNNING: " . $this->getID());
+ error_log("-------------------");
+ }
+
+ 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());
+
+ // log to file
+ $filename = '/../../../var/log/hub_rejection.log';
+ $date = date("Y-m-d H:i:s");
+
+ // build log entry
+ $entry = implode("", [
+ "[JO: " . $this->getJOID() . "]",
+ "[" . $date . "]",
+ "[" . $this->getID() . "]",
+ " " . $hub->getName() . " (ID: " . $hub->getID() . ")",
+ "\r\n",
+ ]);
+
+ @file_put_contents(__DIR__ . $filename, $entry, FILE_APPEND);
+ }
+
+ protected function createRejectionEntry($hub, $reason, $remarks = ""): JORejection
+ {
+ $jo = $this->em->getRepository(JobOrder::class)->find($this->getJOID());
+
+ $robj = new JORejection();
+ $robj->setDateCreate(new DateTime())
+ ->setHub($hub)
+ ->setJobOrder($jo)
+ ->setReason($reason)
+ ->setRemarks(implode(" ", ["Automatically filtered by hub selector.", $remarks]));
+
+ $this->em->persist($robj);
+ $this->em->flush();
+
+ return $robj;
+ }
+
+ protected function sendSMSMessage($hub, $order_date, $service_type, $rejection, $reason = "", $remarks = ""): void
+ {
+ $jo_id = $this->getJOID();
+
+ // 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..67097320
--- /dev/null
+++ b/src/Service/HubFilter/Filters/DateAndTimeHubFilter.php
@@ -0,0 +1,58 @@
+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..d7526d0f
--- /dev/null
+++ b/src/Service/HubFilter/Filters/InventoryHubFilter.php
@@ -0,0 +1,164 @@
+im = $im;
+ }
+
+ public function getRequestedParams() : array
+ {
+ return [
+ 'flag_inventory_check',
+ 'customer_class',
+ 'jo_type',
+ 'jo_origin',
+ 'order_date',
+ 'service_type',
+ 'items',
+ ];
+ }
+
+ 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) ||
+ $params['jo_origin'] === TransactionOrigin::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 (!isset($params['items'][$branch['SapCode']]) || $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
+ $jo_id = $this->getJOID();
+
+ if (!empty($jo_id)) {
+ // create rejection report entry
+ $robj = $this->createRejectionEntry(
+ $hub,
+ JORejectionReason::NO_STOCK_SALES,
+ "SKU(s): " . $battery_string,
+ );
+
+ // build SMS message
+ $this->sendSMSMessage(
+ $hub,
+ $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..01ed733f
--- /dev/null
+++ b/src/Service/HubFilter/Filters/JoTypeHubFilter.php
@@ -0,0 +1,52 @@
+ $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..16c1b514
--- /dev/null
+++ b/src/Service/HubFilter/Filters/MaxResultsHubFilter.php
@@ -0,0 +1,35 @@
+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..8af6705b
--- /dev/null
+++ b/src/Service/HubFilter/Filters/PaymentMethodHubFilter.php
@@ -0,0 +1,63 @@
+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..d2697feb
--- /dev/null
+++ b/src/Service/HubFilter/Filters/RiderAvailabilityHubFilter.php
@@ -0,0 +1,75 @@
+getJOID() . ": VIP CLASS");
+ return $hubs;
+ }
+
+ $results = [];
+
+ foreach ($hubs as $hub_data) {
+ $hub = $hub_data['hub'];
+
+ $available_riders = count($hub->getAvailableRiders());
+ // check we have available riders
+ error_log("TOTAL RIDERS: " . $available_riders);
+ if ($available_riders === 0) {
+ // if we have a JO, create rejection record and notify
+ $jo_id = $this->getJOID();
+
+ if (!empty($jo_id)) {
+ // create rejection report entry
+ $robj = $this->createRejectionEntry($hub, JORejectionReason::NO_RIDER_AVAILABLE);
+
+ // build SMS message
+ $this->sendSMSMessage(
+ $hub,
+ $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..235293a9
--- /dev/null
+++ b/src/Service/HubFilter/Filters/RoundRobinHubFilter.php
@@ -0,0 +1,46 @@
+hub_distributor = $hub_distributor;
+ }
+
+ public function getRequestedParams() : array
+ {
+ return [
+ 'flag_round_robin',
+ ];
+ }
+
+ 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..f3b9d2ab
--- /dev/null
+++ b/src/Service/HubFilter/HubFilterInterface.php
@@ -0,0 +1,20 @@
+container = $container;
$this->em = $em;
$this->im = $im;
$this->hub_distributor = $hub_distributor;
@@ -39,6 +39,18 @@ class HubSelector
$this->rt = $rt;
}
+ protected function getActiveFilters(): array
+ {
+ $fnames = explode(",", $this->container->getParameter('enabled_hub_filters'));
+ $enabled_filters = [];
+
+ foreach ($fnames as $filter) {
+ $enabled_filters[] = 'App\\Service\\HubFilter\\Filters\\' . $filter;
+ }
+
+ return $enabled_filters;
+ }
+
public function find(HubCriteria $criteria)
{
$point = $criteria->getPoint();
@@ -46,15 +58,20 @@ class HubSelector
$limit_distance = $criteria->getLimitDistance();
$jo_type = $criteria->getJoType();
$flag_inventory_check = $criteria->hasInventoryCheck();
+ $flag_riders_check = $criteria->hasRidersCheck();
$items = $criteria->getItems();
$date_time = $criteria->getDateTime();
$payment_method = $criteria->getPaymentMethod();
$flag_emergency = $criteria->isEmergency();
$flag_round_robin = $criteria->isRoundRobin();
$jo_id = $criteria->getJobOrderId();
+ $jo_origin = $criteria->getJoOrigin();
$customer_id = $criteria->getCustomerId();
+ $customer_class = $criteria->getCustomerClass();
- $results = [];
+ // needed for JORejection records and SMS notifs
+ $order_date = $criteria->getOrderDate();
+ $service_type = $criteria->getServiceType();
// error_log('payment methods ' . $payment_method);
// error_log('distance limit ' . $limit_distance);
@@ -63,278 +80,52 @@ class HubSelector
// get all the hubs within distance
$filtered_hubs = $this->getClosestHubs($point, $limit_distance, $jo_id, $customer_id);
- // error_log('closest hubs ' . json_encode($filtered_hubs));
+ // build param list
+ $params = [
+ 'date_time' => $date_time,
+ 'flag_inventory_check' => $flag_inventory_check,
+ 'customer_class' => $customer_class,
+ 'jo_type' => $jo_type,
+ 'jo_origin' => $jo_origin,
+ 'order_date' => $order_date,
+ 'service_type' => $service_type,
+ 'items' => $items,
+ 'flag_emergency' => $flag_emergency,
+ 'limit_results' => $limit_results,
+ 'payment_method' => $payment_method,
+ 'flag_riders_check' => $flag_riders_check,
+ 'flag_round_robin' => $flag_round_robin,
+ ];
- // 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;
-
- // error_log('date_time hubs ' . json_encode($filtered_hubs));
-
- 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));
-
- // inventory filter
- $hubs_inventory = $this->filterHubsByInventory($filtered_hubs, $flag_inventory_check,
- $jo_type, $items, $jo_id, $customer_id);
- $filtered_hubs = $hubs_inventory;
-
- //error_log('inventory hubs ' . json_encode($filtered_hubs));
-
- // 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(json_encode($results));
-
- 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,
- ];
- 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,
- ];
- }
- $flag_found_pmethod = true;
- }
-
- if (!$flag_found_pmethod)
- $this->hub_filter_logger->logFilteredHub($hub, 'no_payment_method', $jo_id, $customer_id);
+ // loop through all enabled filters
+ foreach ($this->getActiveFilters() as $hub_filter) {
+ // no hubs left to filter
+ if (empty($filtered_hubs)) {
+ break;
}
- else
- $this->hub_filter_logger->logFilteredHub($hub, 'no_payment_method', $jo_id, $customer_id);
- }
- return $results;
- }
+ $f = $this->container->get($hub_filter);
- 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,
- ];
+ // check if supported area is exempted from this filter
+ if ($this->isExemptedByArea($f->getID(), $point)) {
+ continue;
}
- 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)
- {
- if (empty($hubs))
- return $hubs;
+ $f->setJOID($jo_id);
+ $f->setCustomerID($customer_id);
- if (!$flag_inventory_check)
- return $hubs;
+ // get requested params only
+ $req_params = array_intersect_key($params, array_flip($f->getRequestedParams()));
- $results = [];
- if ($flag_inventory_check)
- {
- foreach ($hubs as $hub_data)
- {
- $hub = $hub_data['hub'];
+ // filter hub list
+ $filtered_hubs = $f->filter($filtered_hubs, $req_params);
- 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);
- }
- }
- }
+ // error_log($f->getID() . ' hubs ' . json_encode($filtered_hubs));
}
- return $results;
+ // error_log('final hub list ' . json_encode($filtered_hubs));
+
+ return $filtered_hubs;
}
protected function getClosestHubs(Point $point, $limit_distance, $jo_id, $customer_id)
@@ -375,7 +166,11 @@ class HubSelector
'distance' => $dist,
'duration' => 0,
'jo_count' => 0,
+ 'inventory' => 0,
];
+
+ // log to file
+ $this->logClosestHubResult($jo_id, $row[0], $dist, $limit_distance);
}
else
{
@@ -386,45 +181,6 @@ class HubSelector
return $hubs_data;
}
- protected function checkInventory($items, $hub)
- {
- // check if hub has all items
- $skus = [];
- $branch_codes[] = $hub->getBranchCode();
- $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)
{
@@ -440,26 +196,50 @@ class HubSelector
return round(($miles * 1.609344), 1);
}
- protected function sendSMSMessage($hub, $items)
+ protected function isExemptedByArea(string $filter_id, Point $coordinates): bool
{
- // compose message
- // get the skus for the message
- $sku_text = '';
- foreach ($items as $key => $value)
- {
- $sku_text .= ' ' . $key;
- }
- $message = str_replace('item_display', trim($sku_text), $this->trans->trans('no_inventory_message'));
+ $long = $coordinates->getLongitude();
+ $lat = $coordinates->getLatitude();
- // get hub notification number
- $mobile_number = $hub->getNotifNumber();
+ // get supported area given a set of coordinates
+ $query = $this->em->createQuery('SELECT s from App\Entity\SupportedArea s where st_contains(s.coverage_area, point(:long, :lat)) = true');
+ $area = $query->setParameter('long', $long)
+ ->setParameter('lat', $lat)
+ ->setMaxResults(1)
+ ->getOneOrNullResult();
- if (!empty($mobile_number))
- {
- // send SMS message
- // error_log('sending sms to - ' . $mobile_number);
- $this->rt->sendSMS($mobile_number, $this->trans->trans('message.battery_brand_allcaps'), $message);
+ if ($area !== null) {
+ // get all exceptions
+ $exceptions = $area->getHubFilterExceptions();
+
+ if (isset($exceptions[$filter_id])) {
+ error_log("FILTER " . $filter_id . " DISABLED FOR AREA: " . $area->getName());
+
+ // disable this filter for this area
+ return true;
+ }
}
+
+ // filter is in place
+ return false;
+ }
+
+ protected function logClosestHubResult($jo_id, $hub, $distance, $limit_distance)
+ {
+ // log to file
+ $filename = '/../../var/log/closest_hubs_selected.log';
+ $date = date("Y-m-d H:i:s");
+
+ // build log entry
+ $entry = implode("", [
+ "[JO: " . $jo_id . "]",
+ "[" . $date . "]",
+ "[Distance: " . $distance . " vs " . $limit_distance . "]",
+ " " . $hub->getName() . " (ID: " . $hub->getID() . ")",
+ "\r\n",
+ ]);
+
+ @file_put_contents(__DIR__ . $filename, $entry, FILE_APPEND);
}
}
diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php
index 419c27c3..b2d6fd68 100644
--- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php
+++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php
@@ -95,7 +95,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
protected $hub_dist;
protected $hub_geofence;
protected $cust_distance_limit;
- protected $hub_filter_enable;
+ protected $hub_filter_enabled;
protected $jo_manager;
protected $pt_manager;
@@ -2551,10 +2551,20 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
->setDateTime($obj->getDateSchedule())
->setLimitResults(50);
+ // NOTE: set JO type regardless, for now
+ $hub_criteria->setJoType($obj->getServiceType())
+ ->setOrderDate($obj->getDateCreate())
+ ->setServiceType($obj->getServiceType());
+
+ // set customer class
+ $cust = $obj->getCustomer();
+ $hub_criteria->setCustomerClass($cust->getCustomerClassification());
+
// check if hub filter is enabled. If not, use default values
// for the rest of the HubCriteria fields
if ($this->hub_filter_enabled == 'true')
{
+ // TODO: allow this to be disabled via env or CRM. commenting out for now
// error_log('hub filter is enabled');
if ($this->hub_geofence->isCovered($long, $lat))
{
@@ -2562,7 +2572,6 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
// error_log('Area is covered by hub filtering');
$hub_criteria->setLimitDistance($this->cust_distance_limit)
->setPaymentMethod($obj->getModeOfPayment())
- ->setJoType($obj->getServiceType())
->setRoundRobin(true);
}
}
@@ -2573,15 +2582,22 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
{
// reset distance limit if emergency
//TODO: move to .env the emergency distance limit
- $hub_criteria->setLimitDistance(500);
- $hub_criteria->setEmergency(true);
+ $hub_criteria->setLimitDistance(500)
+ ->setEmergency(true)
+ ->setPaymentMethod(null)
+ ->setRoundRobin(false);
}
+ // set filter flags for inventory and available riders
+ $hub_criteria->setInventoryCheck();
+ $hub_criteria->setRidersCheck();
+
// get JO and customer id for logging purposes
$jo_id = $obj->getID();
$customer_id = $obj->getCustomer()->getID();
$hub_criteria->setJobOrderId($jo_id)
+ ->setJoOrigin($obj->getSource())
->setCustomerId($customer_id);
$hubs = $hub_selector->find($hub_criteria);
@@ -2646,7 +2662,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
// handle inventory data
$bcode = $hub['hub']->getBranchCode();
- $hub['inventory'] = 0;
+ //$hub['inventory'] = 0;
if ($bcode != '')
{
$branch_codes[] = $bcode;
@@ -2664,7 +2680,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
// get template to display
$params['template'] = $this->getTwigTemplate('jo_processing_form');
+ // NOTE: as we have included inventory now from the hub selector, we no longer have to redo it here
+
// get battery (if any)
+ /*
$skus = [];
$invoice = $obj->getInvoice();
$inv_items = $invoice->getItems();
@@ -2694,6 +2713,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
}
}
}
+ */
// error_log(print_r($mres, true));
@@ -2889,13 +2909,22 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
->setDateTime($obj->getDateSchedule())
->setLimitResults(50);
+ // NOTE: set JO type regardless, for now
+ $hub_criteria->setJoType($obj->getServiceType())
+ ->setOrderDate($obj->getDateCreate())
+ ->setServiceType($obj->getServiceType());
+
+ // set customer class
+ $cust = $obj->getCustomer();
+ $hub_criteria->setCustomerClass($cust->getCustomerClassification());
+
+ // TODO: allow this to be disabled via env or CRM. commenting out for now
if ($this->hub_geofence->isCovered($long, $lat))
{
// if true, set other values for HubCriteria
// error_log('Area is covered by hub');
$hub_criteria->setLimitDistance($this->cust_distance_limit)
->setPaymentMethod($obj->getModeOfPayment())
- ->setJoType($obj->getServiceType())
->setRoundRobin(true);
}
@@ -2904,15 +2933,22 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
if ($willing_to_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT)
{
//TODO: move to .env the emergency distance limit
- $hub_criteria->setLimitDistance(500);
- $hub_criteria->setEmergency(true);
+ $hub_criteria->setLimitDistance(500)
+ ->setEmergency(true)
+ ->setPaymentMethod(null)
+ ->setRoundRobin(false);
}
+ // set filter flags for inventory and available riders
+ $hub_criteria->setInventoryCheck();
+ $hub_criteria->setRidersCheck();
+
// get JO and customer id for logging purposes
$jo_id = $obj->getID();
- $customer_id = $obj->getCustomer()->getID();
+ $customer_id = $cust->getID();
$hub_criteria->setJobOrderId($jo_id)
+ ->setJoOrigin($obj->getSource())
->setCustomerId($customer_id);
$hubs = $hub_selector->find($hub_criteria);
@@ -2921,6 +2957,8 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
$params['hubs'] = [];
$branch_codes = [];
+ $inv_data = [];
+
// format duration and distance into friendly time
foreach ($hubs as $hub) {
// duration
@@ -2976,7 +3014,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
// handle inventory data
$bcode = $hub['hub']->getBranchCode();
- $hub['inventory'] = 0;
+ //$hub['inventory'] = 0;
if ($bcode != '')
{
$branch_codes[] = $bcode;
@@ -2990,39 +3028,65 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
$params['hubs'][$hub_id] = $hub;
}
- // get battery (if any)
- $skus = [];
- $invoice = $obj->getInvoice();
- $inv_items = $invoice->getItems();
- foreach ($inv_items as $inv_item)
- {
- $batt = $inv_item->getBattery();
- if ($batt == null)
- continue;
+ // NOTE: as we have included inventory now from the hub selector, we no longer have to redo it here
- $skus[] = $batt->getSapCode();
- }
+ //error_log("TOTAL HUBS FOUND WITH BRANCH CODE: " . count($inv_data));
- // get inventory
- $mres = $motiv->getInventory($branch_codes, $skus);
- foreach ($mres as $mres_item)
- {
- // check if we have a valid response from motiv, ignore otherwise
- if (isset($mres_item['BranchCode']))
+ // get all enabled filters
+ $enabled_filter_str = $_ENV['ENABLED_HUB_FILTERS'];
+ $enabled_filters = explode(",", $enabled_filter_str);
+
+ // if inventory filter is disabled, fetch inventory here
+ if (!in_array('InventoryHubFilter', $enabled_filters) || $this->skipInventoryCheck($obj->getCoordinates())) {
+ error_log("NO INVENTORY CHECKS, GETTING INVENTORY FOR JO " . $obj->getID());
+
+ // get battery (if any)
+ $skus = [];
+ $invoice = $obj->getInvoice();
+ $inv_items = $invoice->getItems();
+ foreach ($inv_items as $inv_item)
{
- $bcode = $mres_item['BranchCode'];
- $inv_count = $mres_item['Quantity'];
- if (isset($inv_data[$bcode]))
- {
- $hub_id = $inv_data[$bcode]['hub_id'];
+ $batt = $inv_item->getBattery();
+ if ($batt == null)
+ continue;
- $params['hubs'][$hub_id]['inventory'] = $inv_count;
+ $skus[] = $batt->getSapCode();
+ }
+
+ // get inventory
+ $mres = $motiv->getInventory($branch_codes, $skus);
+ $x = 0;
+
+ error_log("TOTAL RESULTS FROM MOTIV: " . count($mres) . " OUT OF " . count($branch_codes) . " BRANCH CODES AND " . count($skus) . " SKUS");
+
+ foreach ($mres as $mres_item)
+ {
+ // check if we have a valid response from motiv, ignore otherwise
+ if (isset($mres_item['BranchCode']))
+ {
+ $bcode = $mres_item['BranchCode'];
+ $inv_count = $mres_item['Quantity'];
+ if (isset($inv_data[$bcode]))
+ {
+ $hub_id = $inv_data[$bcode]['hub_id'];
+
+ $params['hubs'][$hub_id]['inventory'] = $inv_count;
+
+ error_log("SETTING HUB " . $hub_id . " INVENTORY TO " . $inv_count);
+ $x++;
+ } else {
+ error_log("CANNOT FIND BCODE FOR " . $bcode);
+ }
+ } else {
+ error_log("CANNOT FIND BCODE FOR RESULT: " . print_r($mres_item, true));
}
}
+
+ error_log("SET QUANTITY OF " . $x . " HUBS TO NON ZERO");
+
+ // error_log(print_r($mres, true));
}
-
- // error_log(print_r($mres, true));
-
+
$params['obj'] = $obj;
// get template to display
$params['template'] = $this->getTwigTemplate('jo_open_hub_form');
@@ -4298,4 +4362,28 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
$this->rt->sendSMS($phone_number, $this->translator->trans('message.battery_brand_allcaps'), $msg);
}
+ protected function skipInventoryCheck(Point $coordinates): bool
+ {
+ $long = $coordinates->getLongitude();
+ $lat = $coordinates->getLatitude();
+
+ // get supported area given a set of coordinates
+ $query = $this->em->createQuery('SELECT s from App\Entity\SupportedArea s where st_contains(s.coverage_area, point(:long, :lat)) = true');
+ $area = $query->setParameter('long', $long)
+ ->setParameter('lat', $lat)
+ ->setMaxResults(1)
+ ->getOneOrNullResult();
+
+ if ($area !== null) {
+ // get all exceptions
+ $exceptions = $area->getHubFilterExceptions();
+
+ if (isset($exceptions['no_inventory'])) {
+ return true;
+ }
+ }
+
+ // filter is in place
+ return false;
+ }
}
diff --git a/src/Service/PayMongoConnector.php b/src/Service/PayMongoConnector.php
index c34a94e7..3abafc22 100644
--- a/src/Service/PayMongoConnector.php
+++ b/src/Service/PayMongoConnector.php
@@ -74,6 +74,16 @@ class PayMongoConnector
return $this->doRequest('/v1/checkout_sessions/' . $checkout_id, 'GET');
}
+ public function getWebhook($id)
+ {
+ return $this->doRequest('/v1/webhooks/'. $id, 'GET');
+ }
+
+ public function enableWebhook($id)
+ {
+ return $this->doRequest('/v1/webhooks/' . $id . '/enable', 'POST');
+ }
+
protected function generateHash()
{
return base64_encode($this->secret_key);
diff --git a/translations/messages.en.yaml b/translations/messages.en.yaml
index 8387663e..5fbc11a9 100644
--- a/translations/messages.en.yaml
+++ b/translations/messages.en.yaml
@@ -13,7 +13,8 @@ add_cust_vehicle_battery_info: This vehicle is using a Motolite battery
jo_title_pdf: Motolite Res-Q Job Order
country_code_prefix: '+63'
delivery_instructions_label: Delivery Instructions
-no_inventory_message: No stock for [item_display]
+no_inventory_message: 'A Job Order was created but there is insufficient stock for the following SKU(s) on this branch: [item_display]'
+no_riders_message: A Job Order was created but there are no riders available for this branch.
# images
image_logo_login: /assets/images/logo-resq.png
diff --git a/utils/hub_filter_exceptions/hub_filter_exceptions.sql b/utils/hub_filter_exceptions/hub_filter_exceptions.sql
new file mode 100644
index 00000000..ef165614
--- /dev/null
+++ b/utils/hub_filter_exceptions/hub_filter_exceptions.sql
@@ -0,0 +1,2 @@
+update supported_area set hub_filter_exceptions = '{"no_inventory":true,"no_available_rider":true}' where id = 34;
+update supported_area set hub_filter_exceptions = '{"no_inventory":true,"no_available_rider":true}' where id = 35;
\ No newline at end of file