Compare commits
93 commits
764-aggreg
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
630796df85 | ||
| dedfb58a28 | |||
| 1b24e68f6b | |||
|
|
dc4d5f90a7 | ||
|
|
0179a1b87e | ||
|
|
f1609b2273 | ||
| 22215ff9f6 | |||
|
|
6994d69020 | ||
|
|
83bdb5c626 | ||
|
|
5a5113b166 | ||
|
|
629cc2afa1 | ||
|
|
ad946247ba | ||
|
|
63902e5838 | ||
|
|
511aa5ec9b | ||
|
|
2df53674c4 | ||
|
|
4ab6b0659d | ||
|
|
a66d16a58b | ||
|
|
5f2ed34d8c | ||
|
|
e7d8af516e | ||
|
|
8da5381a1c | ||
|
|
f8d90cbdcd | ||
|
|
6139e649fb | ||
|
|
e1103cf108 | ||
|
|
a10f58e425 | ||
|
|
23d814d1e9 | ||
|
|
9b63139957 | ||
|
|
a335f84a13 | ||
|
|
8992fdeec0 | ||
|
|
57b4227da9 | ||
|
|
bff1f7ff73 | ||
|
|
e8b14ff379 | ||
|
|
44b3753ece | ||
|
|
a21ed66490 | ||
| 3fc04cd733 | |||
|
|
3b287236ec | ||
|
|
204c039fba | ||
|
|
b4057de938 | ||
| 2a30787dba | |||
| acee5f8f55 | |||
| 90628f0b54 | |||
| 4ccdd29ae6 | |||
| 2f9ee4ec67 | |||
| 4b5ad97225 | |||
|
|
e83de164c1 | ||
| 8c886c4dbf | |||
|
|
10c44fbe64 | ||
|
|
b5f169c14e | ||
|
|
cec648f894 | ||
|
|
c4b0513386 | ||
|
|
90838b004a | ||
|
|
c60a39c13e | ||
|
|
792db080a1 | ||
|
|
08084f682c | ||
|
|
3846ad5a43 | ||
|
|
191a02f4c4 | ||
|
|
e97cebd2b2 | ||
|
|
952122a39e | ||
|
|
ad841a7e25 | ||
|
|
75b2ada03f | ||
|
|
4b19cff996 | ||
|
|
2ebb6e040a | ||
|
|
404401d854 | ||
|
|
6dfaeee799 | ||
|
|
aae4aaa390 | ||
|
|
b53aacb840 | ||
|
|
22683e1edf | ||
|
|
4be9134090 | ||
|
|
21c97df677 | ||
|
|
5cf2c3619f | ||
|
|
7b6afbb099 | ||
|
|
190ac88153 | ||
|
|
aed31f2a33 | ||
|
|
76496ed6fe | ||
|
|
89e5dd799f | ||
|
|
0bd6a89840 | ||
|
|
be0e69db89 | ||
|
|
d52402a2ef | ||
|
|
a45c3dd65c | ||
|
|
b19d9c203a | ||
|
|
a64557ffcd | ||
|
|
d7909f7941 | ||
|
|
8e383fd23f | ||
|
|
86889b3147 | ||
| 6a804c11df | |||
| c8e2c02be1 | |||
|
|
06dc8eae7b | ||
|
|
f97f287f5b | ||
| 6f2fca292e | |||
| b80ece9084 | |||
| 90aada4bf3 | |||
| 93c313f111 | |||
| bf0d1f664b | |||
| 5ddebcd95f |
54 changed files with 2141 additions and 559 deletions
|
|
@ -751,6 +751,16 @@ catalyst_auth:
|
|||
acls:
|
||||
- id: warrantyserial.upload
|
||||
label: Upload
|
||||
- id: hub
|
||||
label: Hub Access
|
||||
acls:
|
||||
- id: hub.list
|
||||
label: List
|
||||
- id: joborder
|
||||
label: Job Order Access
|
||||
acls:
|
||||
- id: joborder.find
|
||||
label: Find Job Order
|
||||
|
||||
- id: tapi_vmanufacturer
|
||||
label: Third Party Vehicle Manufacturer Access
|
||||
|
|
|
|||
|
|
@ -194,3 +194,16 @@ capi_warranty_serial_upload:
|
|||
path: /capi/warranty_serial/upload
|
||||
controller: App\Controller\CAPI\WarrantySerialController::uploadWarrantySerialFile
|
||||
methods: [POST]
|
||||
|
||||
# pullout form system
|
||||
# hub
|
||||
capi_hub_list:
|
||||
path: /capi/hubs
|
||||
controller: App\Controller\CAPI\HubController::getAll
|
||||
methods: [GET]
|
||||
|
||||
# job order details
|
||||
capi_job_order:
|
||||
path: /capi/job_order/{id}
|
||||
controller: App\Controller\CAPI\JobOrderController::getJobOrder
|
||||
methods: [GET]
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
136
src/Command/ProcessLatePaymongoTransactionsCommand.php
Normal file
136
src/Command/ProcessLatePaymongoTransactionsCommand.php
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use App\Ramcar\TransactionStatus;
|
||||
use App\Entity\GatewayTransaction;
|
||||
use App\Service\PayMongoConnector;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class ProcessLatePaymongoTransactionsCommand extends Command
|
||||
{
|
||||
protected $em;
|
||||
protected $paymongo;
|
||||
|
||||
protected $webhook_id;
|
||||
|
||||
public function __construct(EntityManagerInterface $em, PayMongoConnector $paymongo, $webhook_id)
|
||||
{
|
||||
$this->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('<info>Webhook is enabled, no need to do anything.</info>');
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
$output->writeln('<comment>Webhook is disabled! Logging event and attempting to re-enable...</comment>');
|
||||
|
||||
// attempt re-enabling of webhook
|
||||
$result = $this->paymongo->enableWebhook($this->webhook_id);
|
||||
if ($result['success'] && $result['response']['data']['attributes']['status'] ?? null === 'enabled') {
|
||||
$output->writeln('<info>Webhook ' . $this->webhook_id . ' re-enabled!</info>');
|
||||
|
||||
// log event
|
||||
$this->paymongo->log('WEBHOOK RE-ENABLED', "[]", json_encode($result['response'], JSON_PRETTY_PRINT), 'webhook');
|
||||
} else {
|
||||
$output->writeln('<comment>Webhook ' . $this->webhook_id . ' could not be re-enabled.</comment>');
|
||||
|
||||
// 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('<comment>Insufficient payment amount (' . $amount_paid . '/' . $trans->getAmount() . ') for this transaction: ' . $trans->getID() . '</comment>');
|
||||
}
|
||||
} else {
|
||||
$output->writeln('<comment>No payments found for transaction: ' . $trans->getID() . '</comment>');
|
||||
}
|
||||
} else {
|
||||
$output->writeln('<comment>Checkout not found: ' . $checkout['error']['message'] . '</comment>');
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln('<info>Done! Processed ' . $x . ' rows.</info>');
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -326,7 +326,7 @@ class APIRoleController extends Controller
|
|||
protected function padAPIACLHierarchy(&$params)
|
||||
{
|
||||
// get acl keys hierarchy
|
||||
$api_acl_data = $this->api_acl_gen->getACL();
|
||||
$api_acl_data = $this->api_acl_gen->getACL('api');
|
||||
$params['api_acl_hierarchy'] = $api_acl_data['hierarchy'];
|
||||
}
|
||||
|
||||
|
|
|
|||
53
src/Controller/CAPI/HubController.php
Normal file
53
src/Controller/CAPI/HubController.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller\CAPI;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Catalyst\ApiBundle\Controller\ApiController;
|
||||
use Catalyst\ApiBundle\Component\Response as APIResponse;
|
||||
|
||||
use App\Entity\Hub;
|
||||
|
||||
use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator;
|
||||
|
||||
class HubController extends ApiController
|
||||
{
|
||||
protected $acl_gen;
|
||||
|
||||
public function __construct(ACLGenerator $acl_gen)
|
||||
{
|
||||
$this->acl_gen = $acl_gen;
|
||||
}
|
||||
|
||||
public function getAll(EntityManagerInterface $em)
|
||||
{
|
||||
// get all hub data order by name
|
||||
$this->denyAccessUnlessGranted('hub.list', null, 'No access.');
|
||||
|
||||
$results = $em->getRepository(Hub::class)->findBy([], ['name' => 'ASC']);
|
||||
|
||||
$hubs = [];
|
||||
foreach($results as $res)
|
||||
{
|
||||
$hub_id = $res->getId();
|
||||
$hub_name = $res->getName();
|
||||
$hub_address = $res->getAddress();
|
||||
$hub_branch_code = $res->getBranchCode();
|
||||
|
||||
$hubs[$hub_id] = [
|
||||
'id' => $hub_id,
|
||||
'name' => $hub_name,
|
||||
'address' => $hub_address,
|
||||
'branch_code' => $hub_branch_code,
|
||||
];
|
||||
}
|
||||
|
||||
$data = [
|
||||
'hubs' => $hubs,
|
||||
];
|
||||
return new APIResponse(true, 'Hubs loaded.', $data);
|
||||
}
|
||||
}
|
||||
139
src/Controller/CAPI/JobOrderController.php
Normal file
139
src/Controller/CAPI/JobOrderController.php
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller\CAPI;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Catalyst\ApiBundle\Controller\ApiController;
|
||||
use Catalyst\ApiBundle\Component\Response as APIResponse;
|
||||
|
||||
use App\Entity\JobOrder;
|
||||
use App\Entity\Warranty;
|
||||
|
||||
use App\Ramcar\JOStatus;
|
||||
|
||||
use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator;
|
||||
|
||||
class JobOrderController extends ApiController
|
||||
{
|
||||
protected $acl_gen;
|
||||
|
||||
public function __construct(ACLGenerator $acl_gen)
|
||||
{
|
||||
$this->acl_gen = $acl_gen;
|
||||
}
|
||||
|
||||
public function getJobOrder($id, EntityManagerInterface $em)
|
||||
{
|
||||
$this->denyAccessUnlessGranted('joborder.find', null, 'No access.');
|
||||
|
||||
$jo = $em->getRepository(JobOrder::class)->find($id);
|
||||
|
||||
if ($jo == null)
|
||||
return new APIResponse(false, 'No job order found with that number.', null, 404);
|
||||
|
||||
$data = $this->generateJobOrderData($jo, $em);
|
||||
|
||||
return new APIResponse(true, 'Job order found.', $data);
|
||||
}
|
||||
|
||||
protected function generateJobOrderData($jo, EntityManagerInterface $em)
|
||||
{
|
||||
// customer vehicle
|
||||
$cv = $jo->getCustomerVehicle();
|
||||
|
||||
// customer information
|
||||
$customer = $jo->getCustomer();
|
||||
|
||||
// hub
|
||||
$hub_name = '';
|
||||
$hub = $jo->getHub();
|
||||
if ($hub != null)
|
||||
$hub_name = $hub->getName();
|
||||
|
||||
// check if JO is fulfilled, if not, we leave date_purchase blank
|
||||
$date_purchase = '';
|
||||
$serial = '';
|
||||
$status = $jo->getStatus();
|
||||
if ($status == JOStatus::FULFILLED)
|
||||
{
|
||||
if ($jo->getDateFulfill() != null)
|
||||
$date_purchase = $jo->getDateFulfill()->format('M d, Y H:i');
|
||||
|
||||
// find warranty to get the serial using plate number
|
||||
$serial = $this->getSerialFromWarranty($cv->getPlateNumber(), $em);
|
||||
}
|
||||
|
||||
$jo_data = [
|
||||
'id' => $jo->getID(),
|
||||
'first_name' => $customer->getFirstName(),
|
||||
'last_name' => $customer->getLastName(),
|
||||
'mobile_number' => $customer->getPhoneMobile(),
|
||||
'email' => $customer->getEmail(),
|
||||
'plate_number' => $cv->getPlateNumber(),
|
||||
'date_purchase' => $date_purchase,
|
||||
'address' => $jo->getDeliveryAddress(),
|
||||
'hub' => $hub_name,
|
||||
'serial' => $serial,
|
||||
];
|
||||
|
||||
// invoice items
|
||||
$items = [];
|
||||
$jo_items = $jo->getInvoice()->getItems();
|
||||
$non_battery_item_titles = ['Promo discount', 'Trade-in', 'Service'];
|
||||
foreach ($jo_items as $item)
|
||||
{
|
||||
$item_title = $item->getTitle();
|
||||
|
||||
// check if title has Promo discount, Trade-in, or Service
|
||||
$flag_battery = $this->checkIfBatteryInvoiceItem($item_title, $non_battery_item_titles);
|
||||
if ($flag_battery == true)
|
||||
{
|
||||
$items[] = [
|
||||
'title' => $item->getTitle(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$jo_data['items'] = $items;
|
||||
|
||||
return $jo_data;
|
||||
}
|
||||
|
||||
protected function checkIfBatteryInvoiceItem($item_title, $non_battery_item_titles)
|
||||
{
|
||||
foreach ($non_battery_item_titles as $nb_item_title)
|
||||
{
|
||||
$pos_result = stripos($item_title, $nb_item_title);
|
||||
|
||||
// if found, invoice item is not a battery item
|
||||
if ($pos_result !== false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getSerialFromWarranty($plate_number, EntityManagerInterface $em)
|
||||
{
|
||||
// NOTE: Modify the search for the latest warranty. This seems hacky.
|
||||
// get latest warranty using plate number
|
||||
$warranty_results = $em->getRepository(Warranty::class)->findBy(
|
||||
['plate_number' => $plate_number],
|
||||
['date_create' => 'desc']
|
||||
);
|
||||
|
||||
$serial = '';
|
||||
if (!empty($warranty_results))
|
||||
{
|
||||
// get first entry
|
||||
$warranty = current($warranty_results);
|
||||
|
||||
$serial = $warranty->getSerial();
|
||||
}
|
||||
|
||||
return $serial;
|
||||
}
|
||||
}
|
||||
|
|
@ -386,6 +386,7 @@ class RiderAppController extends ApiController
|
|||
'flag_coolant' => $jo->hasCoolant(),
|
||||
'has_motolite' => $cv->hasMotoliteBattery(),
|
||||
'delivery_status' => $jo->getDeliveryStatus(),
|
||||
'flag_sealant' => $jo->hasSealant(),
|
||||
]
|
||||
];
|
||||
}
|
||||
|
|
@ -413,7 +414,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 +469,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 +532,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 +577,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 +622,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 +667,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 +713,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 +776,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 +871,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 +1021,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 +1067,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 +1288,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 = [];
|
||||
|
|
@ -1300,7 +1325,7 @@ class RiderAppController extends ApiController
|
|||
return new APIResponse(false, 'Invalid promo id - ' . $promo_id);
|
||||
}
|
||||
|
||||
// get other parameters, if any: has motolite battery, has warranty doc, with coolant, payment method
|
||||
// get other parameters, if any: has motolite battery, has warranty doc, with coolant, payment method, with sealant
|
||||
if (isset($items['flag_motolite_battery']))
|
||||
{
|
||||
// get customer vehicle from jo
|
||||
|
|
@ -1335,6 +1360,15 @@ class RiderAppController extends ApiController
|
|||
$jo->setModeOfPayment($payment_method);
|
||||
}
|
||||
|
||||
if (isset($items['flag_sealant']))
|
||||
{
|
||||
$has_sealant = $items['flag_sealant'];
|
||||
if ($has_sealant == 'true')
|
||||
$jo->setHasSealant(true);
|
||||
else
|
||||
$jo->setHasSealant(false);
|
||||
}
|
||||
|
||||
// get capi user
|
||||
$capi_user = $this->getUser();
|
||||
if ($capi_user == null)
|
||||
|
|
@ -1376,7 +1410,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');
|
||||
|
|
@ -1417,6 +1453,13 @@ class RiderAppController extends ApiController
|
|||
else
|
||||
$jo->setHasCoolant(false);
|
||||
|
||||
// sealant
|
||||
$flag_sealant = $req->request->get('flag_sealant', 'false');
|
||||
if ($flag_sealant == 'true')
|
||||
$jo->setHasSealant(true);
|
||||
else
|
||||
$jo->setHasSealant(false);
|
||||
|
||||
// has motolite battery
|
||||
$cv = $jo->getCustomerVehicle();
|
||||
$has_motolite = $req->request->get('has_motolite', 'false');
|
||||
|
|
@ -1517,6 +1560,9 @@ class RiderAppController extends ApiController
|
|||
// get coolant if any
|
||||
$flag_coolant = $jo->hasCoolant();
|
||||
|
||||
// get sealant if any
|
||||
$flag_sealant = $jo->hasSealant();
|
||||
|
||||
// check if new promo is null
|
||||
if ($promo == null)
|
||||
{
|
||||
|
|
@ -1535,6 +1581,7 @@ class RiderAppController extends ApiController
|
|||
->setCustomerVehicle($cv)
|
||||
->setSource($source)
|
||||
->setHasCoolant($flag_coolant)
|
||||
->setHasSealant($flag_sealant)
|
||||
->setIsTaxable();
|
||||
|
||||
// set price tier
|
||||
|
|
@ -1740,22 +1787,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)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use App\Ramcar\TransactionOrigin;
|
|||
use App\Entity\CustomerVehicle;
|
||||
use App\Entity\Promo;
|
||||
use App\Entity\Battery;
|
||||
use App\Entity\BatterySize;
|
||||
use App\Entity\Customer;
|
||||
use App\Entity\CustomerMetadata;
|
||||
|
||||
|
|
@ -119,7 +120,8 @@ class InvoiceController extends ApiController
|
|||
if (!empty($trade_in_type) && !empty($trade_in_batt)) {
|
||||
$ti_batt_obj = $this->em->getRepository(Battery::class)->find($trade_in_batt);
|
||||
if (!empty($ti_batt_obj)) {
|
||||
$icrit->addEntry($ti_batt_obj, $trade_in_type, 1);
|
||||
$ti_batt_size_obj = $ti_batt_obj->getSize();
|
||||
$icrit->addTradeInEntry($ti_batt_size_obj, $trade_in_type, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ use App\Ramcar\WarrantyClass;
|
|||
use App\Ramcar\HubCriteria;
|
||||
use App\Ramcar\DeliveryStatus;
|
||||
use App\Entity\Battery;
|
||||
use App\Entity\BatterySize;
|
||||
use App\Entity\Hub;
|
||||
use App\Entity\Promo;
|
||||
use App\Entity\JOEvent;
|
||||
|
|
@ -488,6 +489,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 +578,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 +648,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) {
|
||||
|
|
@ -690,7 +697,8 @@ class JobOrderController extends ApiController
|
|||
if (!empty($trade_in_type) && !empty($trade_in_batt)) {
|
||||
$ti_batt_obj = $this->em->getRepository(Battery::class)->find($trade_in_batt);
|
||||
if (!empty($ti_batt_obj)) {
|
||||
$icrit->addEntry($ti_batt_obj, $trade_in_type, 1);
|
||||
$ti_batt_size_obj = $ti_batt_obj->getSize();
|
||||
$icrit->addTradeInEntry($ti_batt_size_obj, $trade_in_type, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -708,13 +716,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 +777,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 +859,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 +872,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 +986,8 @@ class JobOrderController extends ApiController
|
|||
}
|
||||
}
|
||||
|
||||
//error_log("DONE CREATING JOB ORDER " . $jo->getID());
|
||||
|
||||
// response
|
||||
return new ApiResponse(true, '', [
|
||||
'jo_id' => $jo->getID(),
|
||||
|
|
@ -1124,7 +1159,8 @@ class JobOrderController extends ApiController
|
|||
if (!empty($trade_in_type) && !empty($trade_in_batt)) {
|
||||
$ti_batt_obj = $this->em->getRepository(Battery::class)->find($trade_in_batt);
|
||||
if (!empty($ti_batt_obj)) {
|
||||
$icrit->addEntry($ti_batt_obj, $trade_in_type, 1);
|
||||
$battery_size = $ti_batt_obj->getSize();
|
||||
$icrit->addTradeInEntry($battery_size, $trade_in_type, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -754,6 +754,8 @@ class JobOrderController extends Controller
|
|||
$promo_id = $req->request->get('promo');
|
||||
$cvid = $req->request->get('cvid');
|
||||
$service_charges = $req->request->get('service_charges', []);
|
||||
$flag_coolant = $req->request->get('flag_coolant', false);
|
||||
$flag_sealant = $req->request->get('flag_sealant', false);
|
||||
|
||||
// coordinates
|
||||
// need to check if lng and lat are set
|
||||
|
|
@ -761,7 +763,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);
|
||||
|
|
@ -784,7 +786,9 @@ class JobOrderController extends Controller
|
|||
->setCustomerVehicle($cv)
|
||||
->setIsTaxable()
|
||||
->setSource(TransactionOrigin::CALL)
|
||||
->setPriceTier($price_tier);
|
||||
->setPriceTier($price_tier)
|
||||
->setHasCoolant($flag_coolant)
|
||||
->setHasSealant($flag_sealant);
|
||||
|
||||
/*
|
||||
// if it's a jumpstart or troubleshoot only, we know what to charge already
|
||||
|
|
|
|||
|
|
@ -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([
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ use App\Ramcar\JOStatus;
|
|||
use App\Ramcar\ServiceType;
|
||||
use App\Ramcar\WillingToWaitContent;
|
||||
use App\Ramcar\CustomerClassification;
|
||||
use App\Ramcar\CustomerNotWaitReason;
|
||||
|
||||
use DateTime;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,10 +50,24 @@ class InvoiceItem
|
|||
*/
|
||||
protected $battery;
|
||||
|
||||
// battery size for trade in items
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="BatterySize")
|
||||
* @ORM\JoinColumn(name="battery_size_id", referencedColumnName="id")
|
||||
*/
|
||||
protected $battery_size;
|
||||
|
||||
// trade in type
|
||||
/**
|
||||
* @ORM\Column(type="string", length=20)
|
||||
*/
|
||||
protected $trade_in_type;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->title = '';
|
||||
$this->price = 0.0;
|
||||
$this->trade_in_type = '';
|
||||
}
|
||||
|
||||
public function getID()
|
||||
|
|
@ -115,4 +129,26 @@ class InvoiceItem
|
|||
{
|
||||
return $this->battery;
|
||||
}
|
||||
|
||||
public function setBatterySize(BatterySize $battery_size)
|
||||
{
|
||||
$this->battery_size = $battery_size;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBatterySize()
|
||||
{
|
||||
return $this->battery_size;
|
||||
}
|
||||
|
||||
public function setTradeInType(string $trade_in_type)
|
||||
{
|
||||
$this->trade_in_type = $trade_in_type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTradeInType()
|
||||
{
|
||||
return $this->trade_in_type;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -441,6 +441,12 @@ class JobOrder
|
|||
*/
|
||||
protected $flag_cust_new;
|
||||
|
||||
// only for tire service, if it requires sealant or not
|
||||
/**
|
||||
* @ORM\Column(type="boolean")
|
||||
*/
|
||||
protected $flag_sealant;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->date_create = new DateTime();
|
||||
|
|
@ -458,6 +464,7 @@ class JobOrder
|
|||
$this->trade_in_type = null;
|
||||
$this->flag_rider_rating = false;
|
||||
$this->flag_coolant = false;
|
||||
$this->flag_sealant = false;
|
||||
|
||||
$this->priority = 0;
|
||||
$this->meta = [];
|
||||
|
|
@ -1256,4 +1263,15 @@ class JobOrder
|
|||
return $this->flag_cust_new;
|
||||
}
|
||||
|
||||
public function setHasSealant($flag = true)
|
||||
{
|
||||
$this->flag_sealant = $flag;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasSealant()
|
||||
{
|
||||
return $this->flag_sealant;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use Catalyst\AuthBundle\Entity\Role as BaseRole;
|
|||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
|
||||
/**
|
||||
|
|
@ -16,6 +17,19 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
*/
|
||||
class Role extends BaseRole
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="string", length=80)
|
||||
* @Assert\NotBlank()
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=80)
|
||||
* @Assert\NotBlank()
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity="User", mappedBy="roles", fetch="EXTRA_LAZY")
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,14 +116,12 @@ class BatteryReplacementWarranty implements InvoiceRuleInterface
|
|||
$qty = $item['quantity'];
|
||||
if ($qty < 1)
|
||||
continue;
|
||||
|
||||
// if this is a trade in, add trade in
|
||||
if (!empty($item['trade_in']) && TradeInType::validate($item['trade_in']))
|
||||
$trade_in = $item['trade_in'];
|
||||
else
|
||||
|
||||
if (empty($item['trade_in']))
|
||||
{
|
||||
$trade_in = null;
|
||||
|
||||
$criteria->addEntry($battery, $trade_in, $qty);
|
||||
$criteria->addEntry($battery, $trade_in, $qty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -103,26 +103,24 @@ class BatterySales implements InvoiceRuleInterface
|
|||
// check if this is a valid battery
|
||||
foreach ($invoice_items as $item)
|
||||
{
|
||||
$battery = $this->em->getRepository(Battery::class)->find($item['battery']);
|
||||
|
||||
if (empty($battery))
|
||||
if (isset($item['battery']))
|
||||
{
|
||||
$error = 'Invalid battery specified.';
|
||||
return $error;
|
||||
}
|
||||
$battery = $this->em->getRepository(Battery::class)->find($item['battery']);
|
||||
|
||||
// quantity
|
||||
$qty = $item['quantity'];
|
||||
if ($qty < 1)
|
||||
continue;
|
||||
if (empty($battery))
|
||||
{
|
||||
$error = 'Invalid battery specified.';
|
||||
return $error;
|
||||
}
|
||||
|
||||
// quantity
|
||||
$qty = $item['quantity'];
|
||||
if ($qty < 1)
|
||||
continue;
|
||||
|
||||
// if this is a trade in, add trade in
|
||||
if (!empty($item['trade_in']) && TradeInType::validate($item['trade_in']))
|
||||
$trade_in = $item['trade_in'];
|
||||
else
|
||||
$trade_in = null;
|
||||
|
||||
$criteria->addEntry($battery, $trade_in, $qty);
|
||||
$criteria->addEntry($battery, $trade_in, $qty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,18 +68,8 @@ class Jumpstart implements InvoiceRuleInterface
|
|||
|
||||
public function getServiceTypeFee($source, CustomerVehicle $cv)
|
||||
{
|
||||
// check the source of JO
|
||||
// (1) if from app, service fee is 0 if motolite user. jumpstart fee for app if non-motolite user.
|
||||
// (2) any other source, jumpstart fees are charged whether motolite user or not
|
||||
if ($source == TransactionOrigin::MOBILE_APP)
|
||||
{
|
||||
if ($cv->hasMotoliteBattery())
|
||||
$code = 'motolite_user_service_fee';
|
||||
else
|
||||
$code = 'jumpstart_fee_mobile_app';
|
||||
}
|
||||
else
|
||||
$code = 'jumpstart_fee';
|
||||
// get the service fee code, depending on the JO source and if customer vehicle has a motolite battery
|
||||
$code = $this->getServiceFeeCode($cv, $source);
|
||||
|
||||
$fee = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]);
|
||||
|
||||
|
|
@ -110,20 +100,10 @@ class Jumpstart implements InvoiceRuleInterface
|
|||
if ($item_type == null)
|
||||
return null;
|
||||
|
||||
// find the service offering
|
||||
// check the source of JO
|
||||
// (1) if from app, service fee is 0 if motolite user. jumpstart fee for app if non-motolite user.
|
||||
// (2) any other source, jumpstart fees are charged whether motolite user or not
|
||||
if ($source == TransactionOrigin::MOBILE_APP)
|
||||
{
|
||||
if ($cv->hasMotoliteBattery())
|
||||
$code = 'motolite_user_service_fee';
|
||||
else
|
||||
$code = 'jumpstart_fee_mobile_app';
|
||||
}
|
||||
else
|
||||
$code = 'jumpstart_fee';
|
||||
// get the service fee code, depending on the JO source and if customer vehicle has a motolite battery
|
||||
$code = $this->getServiceFeeCode($cv, $source);
|
||||
|
||||
// find the service offering
|
||||
$service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]);
|
||||
|
||||
// check if service is null. If null, return null
|
||||
|
|
@ -144,4 +124,33 @@ class Jumpstart implements InvoiceRuleInterface
|
|||
|
||||
return $title;
|
||||
}
|
||||
|
||||
protected function getServiceFeeCode(CustomerVehicle $cv, $source)
|
||||
{
|
||||
// check the source of JO
|
||||
// (1) if from app, service fee is 0 if motolite user. jumpstart fee for app if non-motolite user.
|
||||
// (2) any other source, jumpstart fees are charged whether motolite user or not. Service fees for non-motolite
|
||||
// and motolite users are now different (used to be the same)
|
||||
if ($source == TransactionOrigin::MOBILE_APP)
|
||||
{
|
||||
if ($cv->hasMotoliteBattery())
|
||||
$code = 'motolite_user_service_fee';
|
||||
else
|
||||
$code = 'jumpstart_fee_mobile_app';
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log('hotline');
|
||||
if ($cv->hasMotoliteBattery())
|
||||
{
|
||||
error_log('has motolite battery');
|
||||
$code = 'motolite_user_jumpstart_fee';
|
||||
}
|
||||
else
|
||||
$code = 'jumpstart_fee';
|
||||
}
|
||||
|
||||
return $code;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use App\InvoiceRuleInterface;
|
|||
|
||||
use App\Entity\ServiceOffering;
|
||||
use App\Entity\ItemType;
|
||||
use App\Entity\CustomerVehicle;
|
||||
|
||||
use App\Service\PriceTierManager;
|
||||
|
||||
|
|
@ -36,11 +37,13 @@ class JumpstartWarranty implements InvoiceRuleInterface
|
|||
|
||||
if ($stype == $this->getID())
|
||||
{
|
||||
$cv = $criteria->getCustomerVehicle();
|
||||
|
||||
// check if price tier has item price
|
||||
$pt_price = $this->getPriceTierItemPrice($pt_id);
|
||||
$pt_price = $this->getPriceTierItemPrice($pt_id, $cv);
|
||||
|
||||
if ($pt_price == null)
|
||||
$price = $this->getServiceTypeFee();
|
||||
$price = $this->getServiceTypeFee($cv);
|
||||
else
|
||||
$price = $pt_price;
|
||||
|
||||
|
|
@ -60,9 +63,14 @@ class JumpstartWarranty implements InvoiceRuleInterface
|
|||
return $items;
|
||||
}
|
||||
|
||||
public function getServiceTypeFee()
|
||||
public function getServiceTypeFee(CustomerVehicle $cv)
|
||||
{
|
||||
$code = 'jumpstart_warranty_fee';
|
||||
// check if user has motolite battery.
|
||||
// Motolite users now have a service fee for jumpstart warranty
|
||||
if ($cv->hasMotoliteBattery())
|
||||
$code = 'motolite_user_jumpstart_warranty_fee';
|
||||
else
|
||||
$code = 'jumpstart_warranty_fee';
|
||||
|
||||
// find the service fee using the code
|
||||
// if we can't find the fee, return 0
|
||||
|
|
@ -84,7 +92,7 @@ class JumpstartWarranty implements InvoiceRuleInterface
|
|||
return null;
|
||||
}
|
||||
|
||||
protected function getPriceTierItemPrice($pt_id)
|
||||
protected function getPriceTierItemPrice($pt_id, CustomerVehicle $cv)
|
||||
{
|
||||
// price_tier is default
|
||||
if ($pt_id == 0)
|
||||
|
|
@ -96,7 +104,13 @@ class JumpstartWarranty implements InvoiceRuleInterface
|
|||
return null;
|
||||
|
||||
// find the service offering
|
||||
$code = 'jumpstart_warranty_fee';
|
||||
// check if user has motolite battery.
|
||||
// Motolite users now have a service fee for jumpstart warranty
|
||||
if ($cv->hasMotoliteBattery())
|
||||
$code = 'motolite_user_jumpstart_warranty_fee';
|
||||
else
|
||||
$code = 'jumpstart_warranty_fee';
|
||||
|
||||
$service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]);
|
||||
|
||||
// check if service is null. If null, return null
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ class TireRepair implements InvoiceRuleInterface
|
|||
public function compute($criteria, &$total)
|
||||
{
|
||||
$stype = $criteria->getServiceType();
|
||||
$has_sealant = $criteria->hasSealant();
|
||||
$pt_id = $criteria->getPriceTier();
|
||||
|
||||
$items = [];
|
||||
|
|
@ -56,8 +57,28 @@ class TireRepair implements InvoiceRuleInterface
|
|||
'price' => $price,
|
||||
];
|
||||
|
||||
$qty_price = bcmul($price, $qty, 2);
|
||||
$total['total_price'] = bcadd($total['total_price'], $qty_price, 2);
|
||||
$qty_fee = bcmul($qty, $price, 2);
|
||||
$total_price = $qty_fee;
|
||||
|
||||
if ($has_sealant)
|
||||
{
|
||||
$sealant_fee_data = $this->getSealantFeeData();
|
||||
|
||||
$sealant_fee = $sealant_fee_data['fee'];
|
||||
$sealant_title = $sealant_fee_data['title'];
|
||||
|
||||
$items[] = [
|
||||
'service_type' => $this->getID(),
|
||||
'qty' => $qty,
|
||||
'title' => $sealant_title,
|
||||
'price' => $sealant_fee,
|
||||
];
|
||||
|
||||
$qty_price = bcmul($sealant_fee, $qty, 2);
|
||||
$total_price = bcadd($total_price, $qty_price, 2);
|
||||
}
|
||||
|
||||
$total['total_price'] = bcadd($total['total_price'], $total_price, 2);
|
||||
}
|
||||
|
||||
return $items;
|
||||
|
|
@ -131,4 +152,28 @@ class TireRepair implements InvoiceRuleInterface
|
|||
|
||||
return $title;
|
||||
}
|
||||
|
||||
public function getSealantFeeData()
|
||||
{
|
||||
$data = [
|
||||
'fee' => 0.00,
|
||||
'title' => '',
|
||||
];
|
||||
|
||||
$code = 'tire_sealant_fee';
|
||||
|
||||
// find the service fee using the code
|
||||
// if we can't find the fee, return 0
|
||||
$fee = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]);
|
||||
|
||||
if ($fee != null)
|
||||
{
|
||||
$data = [
|
||||
'fee' => $fee->getFee(),
|
||||
'title' => $fee->getName(),
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,24 @@
|
|||
|
||||
namespace App\InvoiceRule;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use App\InvoiceRuleInterface;
|
||||
|
||||
use App\Ramcar\TradeInType;
|
||||
use App\Ramcar\ServiceType;
|
||||
|
||||
use App\Entity\BatterySize;
|
||||
|
||||
class TradeIn implements InvoiceRuleInterface
|
||||
{
|
||||
protected $em;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
public function getID()
|
||||
{
|
||||
return 'trade-in';
|
||||
|
|
@ -29,16 +41,7 @@ class TradeIn implements InvoiceRuleInterface
|
|||
|
||||
if ($trade_in_type != null)
|
||||
{
|
||||
// at this point, entry is a trade in
|
||||
// need to check if battery (coming from CRM) is set
|
||||
// or battery_size is set (coming from rider app)
|
||||
if (isset($entry['battery']))
|
||||
{
|
||||
$battery = $entry['battery'];
|
||||
$batt_size = $battery->getSize();
|
||||
}
|
||||
else
|
||||
$batt_size = $entry['battery_size'];
|
||||
$batt_size = $entry['battery_size'];
|
||||
|
||||
$ti_rate = $this->getTradeInRate($batt_size, $trade_in_type);
|
||||
|
||||
|
|
@ -50,6 +53,8 @@ class TradeIn implements InvoiceRuleInterface
|
|||
$price = bcmul($ti_rate, -1, 2);
|
||||
|
||||
$items[] = [
|
||||
'battery_size' => $batt_size,
|
||||
'trade_in_type' => $trade_in_type,
|
||||
'qty' => $qty,
|
||||
'title' => $this->getTitle($batt_size, $trade_in_type),
|
||||
'price' => $price,
|
||||
|
|
@ -67,6 +72,42 @@ class TradeIn implements InvoiceRuleInterface
|
|||
|
||||
public function validateInvoiceItems($criteria, $invoice_items)
|
||||
{
|
||||
// check service type. Only battery sales and battery warranty should have invoice items.
|
||||
$stype = $criteria->getServiceType();
|
||||
if ($stype != ServiceType::BATTERY_REPLACEMENT_NEW)
|
||||
return null;
|
||||
|
||||
// return error if there's a problem, false otherwise
|
||||
if (!empty($invoice_items))
|
||||
{
|
||||
// check if this is a valid battery
|
||||
foreach ($invoice_items as $item)
|
||||
{
|
||||
if (isset($item['battery_size']))
|
||||
{
|
||||
$battery_size = $this->em->getRepository(BatterySize::class)->find($item['battery_size']);
|
||||
|
||||
if (empty($battery_size))
|
||||
{
|
||||
$error = 'Invalid battery size specified.';
|
||||
return $error;
|
||||
}
|
||||
|
||||
// quantity
|
||||
$qty = $item['quantity'];
|
||||
if ($qty < 1)
|
||||
continue;
|
||||
|
||||
// check if trade in is set and if trade in type if valid
|
||||
if (!empty($item['trade_in']) && TradeInType::validate($item['trade_in']))
|
||||
{
|
||||
$trade_in = $item['trade_in'];
|
||||
$criteria->addTradeInEntry($battery_size, $trade_in, $qty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class InvoiceCriteria
|
|||
protected $flag_taxable;
|
||||
protected $source; // use Ramcar's TransactionOrigin
|
||||
protected $price_tier;
|
||||
protected $flag_sealant;
|
||||
|
||||
// entries are battery and trade-in combos
|
||||
protected $entries;
|
||||
|
|
@ -34,6 +35,7 @@ class InvoiceCriteria
|
|||
$this->flag_taxable = false;
|
||||
$this->source = '';
|
||||
$this->price_tier = 0; // set to default
|
||||
$this->flag_sealant = false;
|
||||
}
|
||||
|
||||
public function setServiceType($stype)
|
||||
|
|
@ -202,4 +204,15 @@ class InvoiceCriteria
|
|||
{
|
||||
return $this->price_tier;
|
||||
}
|
||||
|
||||
public function setHasSealant($flag = true)
|
||||
{
|
||||
$this->flag_sealant = $flag;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasSealant()
|
||||
{
|
||||
return $this->flag_sealant;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ?? [];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
144
src/Service/HubFilter/BaseHubFilter.php
Normal file
144
src/Service/HubFilter/BaseHubFilter.php
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service\HubFilter;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
use App\Service\HubFilterLogger;
|
||||
use App\Entity\Hub;
|
||||
use App\Entity\JobOrder;
|
||||
use App\Entity\JORejection;
|
||||
use App\Ramcar\ServiceType;
|
||||
use App\Ramcar\JORejectionReason;
|
||||
use App\Service\RisingTideGateway;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class BaseHubFilter
|
||||
{
|
||||
protected $id;
|
||||
protected $jo_id;
|
||||
protected $customer_id;
|
||||
protected $hub_filter_logger;
|
||||
protected $em;
|
||||
protected $rt;
|
||||
protected $trans;
|
||||
|
||||
public function __construct(HubFilterLogger $hub_filter_logger, EntityManagerInterface $em, RisingTideGateway $rt, TranslatorInterface $trans)
|
||||
{
|
||||
$this->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
|
||||
);
|
||||
}
|
||||
}
|
||||
58
src/Service/HubFilter/Filters/DateAndTimeHubFilter.php
Normal file
58
src/Service/HubFilter/Filters/DateAndTimeHubFilter.php
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service\HubFilter\Filters;
|
||||
|
||||
use App\Service\HubFilter\BaseHubFilter;
|
||||
use App\Service\HubFilter\HubFilterInterface;
|
||||
|
||||
class DateAndTimeHubFilter extends BaseHubFilter implements HubFilterInterface
|
||||
{
|
||||
protected $id = 'date_and_time';
|
||||
|
||||
public function getRequestedParams() : array
|
||||
{
|
||||
return [
|
||||
'date_time',
|
||||
];
|
||||
}
|
||||
|
||||
public function filter(array $hubs, array $params = []) : array
|
||||
{
|
||||
if ($params['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 = $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;
|
||||
}
|
||||
}
|
||||
164
src/Service/HubFilter/Filters/InventoryHubFilter.php
Normal file
164
src/Service/HubFilter/Filters/InventoryHubFilter.php
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service\HubFilter\Filters;
|
||||
|
||||
use App\Service\HubFilter\BaseHubFilter;
|
||||
use App\Service\HubFilter\HubFilterInterface;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
use App\Ramcar\JORejectionReason;
|
||||
use App\Ramcar\ServiceType;
|
||||
use App\Ramcar\CustomerClassification;
|
||||
use App\Service\InventoryManager;
|
||||
use App\Service\HubFilterLogger;
|
||||
use App\Service\RisingTideGateway;
|
||||
use App\Entity\Battery;
|
||||
use App\Ramcar\TransactionOrigin;
|
||||
|
||||
class InventoryHubFilter extends BaseHubFilter implements HubFilterInterface
|
||||
{
|
||||
protected $id = 'no_inventory';
|
||||
protected $im;
|
||||
|
||||
public function __construct(HubFilterLogger $hub_filter_logger, EntityManagerInterface $em, RisingTideGateway $rt, TranslatorInterface $trans, InventoryManager $im)
|
||||
{
|
||||
parent::__construct($hub_filter_logger, $em, $rt, $trans);
|
||||
$this->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;
|
||||
}
|
||||
}
|
||||
52
src/Service/HubFilter/Filters/JoTypeHubFilter.php
Normal file
52
src/Service/HubFilter/Filters/JoTypeHubFilter.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service\HubFilter\Filters;
|
||||
|
||||
use App\Service\HubFilter\BaseHubFilter;
|
||||
use App\Service\HubFilter\HubFilterInterface;
|
||||
|
||||
class JoTypeHubFilter extends BaseHubFilter implements HubFilterInterface
|
||||
{
|
||||
protected $id = 'job_order_type';
|
||||
|
||||
public function getRequestedParams() : array
|
||||
{
|
||||
return [
|
||||
'flag_emergency',
|
||||
'jo_type',
|
||||
];
|
||||
}
|
||||
|
||||
public function filter(array $hubs, array $params = []) : array
|
||||
{
|
||||
if ($params['flag_emergency'])
|
||||
return $hubs;
|
||||
|
||||
if (empty($params['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->log($hub);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
35
src/Service/HubFilter/Filters/MaxResultsHubFilter.php
Normal file
35
src/Service/HubFilter/Filters/MaxResultsHubFilter.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service\HubFilter\Filters;
|
||||
|
||||
use App\Service\HubFilter\BaseHubFilter;
|
||||
use App\Service\HubFilter\HubFilterInterface;
|
||||
|
||||
class MaxResultsHubFilter extends BaseHubFilter implements HubFilterInterface
|
||||
{
|
||||
protected $id = 'max_results';
|
||||
|
||||
public function getRequestedParams() : array
|
||||
{
|
||||
return [
|
||||
'limit_results',
|
||||
];
|
||||
}
|
||||
|
||||
public function filter(array $hubs, array $params = []) : array
|
||||
{
|
||||
if (empty($params['limit_results']))
|
||||
return $hubs;
|
||||
|
||||
$results = [];
|
||||
for ($i = 0; $i < count($hubs); $i++)
|
||||
{
|
||||
if ($i < $params['limit_results'])
|
||||
$results[] = $hubs[$i];
|
||||
else
|
||||
$this->log($hubs[$i]['hub']);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
63
src/Service/HubFilter/Filters/PaymentMethodHubFilter.php
Normal file
63
src/Service/HubFilter/Filters/PaymentMethodHubFilter.php
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service\HubFilter\Filters;
|
||||
|
||||
use App\Service\HubFilter\BaseHubFilter;
|
||||
use App\Service\HubFilter\HubFilterInterface;
|
||||
|
||||
class PaymentMethodHubFilter extends BaseHubFilter implements HubFilterInterface
|
||||
{
|
||||
protected $id = 'no_payment_method';
|
||||
|
||||
public function getRequestedParams() : array
|
||||
{
|
||||
return [
|
||||
'flag_emergency',
|
||||
'payment_method',
|
||||
];
|
||||
}
|
||||
|
||||
public function filter(array $hubs, array $params = []) : array
|
||||
{
|
||||
if ($params['flag_emergency'])
|
||||
return $hubs;
|
||||
|
||||
if (empty($params['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 == $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;
|
||||
}
|
||||
}
|
||||
75
src/Service/HubFilter/Filters/RiderAvailabilityHubFilter.php
Normal file
75
src/Service/HubFilter/Filters/RiderAvailabilityHubFilter.php
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service\HubFilter\Filters;
|
||||
|
||||
use App\Service\HubFilter\BaseHubFilter;
|
||||
use App\Service\HubFilter\HubFilterInterface;
|
||||
|
||||
use App\Ramcar\JORejectionReason;
|
||||
use App\Ramcar\CustomerClassification;
|
||||
|
||||
class RiderAvailabilityHubFilter extends BaseHubFilter implements HubFilterInterface
|
||||
{
|
||||
protected $id = 'no_available_rider';
|
||||
|
||||
public function getRequestedParams() : array
|
||||
{
|
||||
return [
|
||||
'flag_riders_check',
|
||||
'customer_class',
|
||||
'order_date',
|
||||
'service_type',
|
||||
];
|
||||
}
|
||||
|
||||
public function filter(array $hubs, array $params = []) : array
|
||||
{
|
||||
// check if this is enabled
|
||||
if (!$params['flag_riders_check']) {
|
||||
return $hubs;
|
||||
}
|
||||
|
||||
// check customer class
|
||||
if (!empty($params['customer_class']) && $params['customer_class'] == CustomerClassification::VIP) {
|
||||
error_log("RIDER CHECK " . $this->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;
|
||||
}
|
||||
}
|
||||
46
src/Service/HubFilter/Filters/RoundRobinHubFilter.php
Normal file
46
src/Service/HubFilter/Filters/RoundRobinHubFilter.php
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service\HubFilter\Filters;
|
||||
|
||||
use App\Service\HubFilter\BaseHubFilter;
|
||||
use App\Service\HubFilter\HubFilterInterface;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
use App\Service\HubDistributor;
|
||||
use App\Service\HubFilterLogger;
|
||||
use App\Service\RisingTideGateway;
|
||||
|
||||
class RoundRobinHubFilter extends BaseHubFilter implements HubFilterInterface
|
||||
{
|
||||
protected $id = 'round_robin';
|
||||
protected $hub_distributor;
|
||||
|
||||
public function __construct(HubFilterLogger $hub_filter_logger, EntityManagerInterface $em, RisingTideGateway $rt, TranslatorInterface $trans, HubDistributor $hub_distributor)
|
||||
{
|
||||
parent::__construct($hub_filter_logger, $em, $rt, $trans);
|
||||
$this->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;
|
||||
}
|
||||
}
|
||||
20
src/Service/HubFilter/HubFilterInterface.php
Normal file
20
src/Service/HubFilter/HubFilterInterface.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service\HubFilter;
|
||||
|
||||
interface HubFilterInterface
|
||||
{
|
||||
public function getID() : string;
|
||||
|
||||
public function filter(array $hubs, array $params = []) : array;
|
||||
|
||||
public function setJOID(int $jo_id);
|
||||
|
||||
public function getJOID() : int;
|
||||
|
||||
public function setCustomerID(int $customer_id);
|
||||
|
||||
public function getCustomerID() : int;
|
||||
|
||||
public function getRequestedParams() : array;
|
||||
}
|
||||
|
|
@ -5,21 +5,20 @@ namespace App\Service;
|
|||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
use CrEOF\Spatial\PHP\Types\Geometry\Point;
|
||||
|
||||
use App\Entity\Hub;
|
||||
|
||||
use App\Service\HubDistributor;
|
||||
use App\Service\InventoryManager;
|
||||
use App\Service\HubFilterLogger;
|
||||
use App\Service\RisingTideGateway;
|
||||
|
||||
use App\Ramcar\HubCriteria;
|
||||
use App\Ramcar\ServiceType;
|
||||
|
||||
class HubSelector
|
||||
{
|
||||
protected $container;
|
||||
protected $em;
|
||||
protected $im;
|
||||
protected $hub_distributor;
|
||||
|
|
@ -27,10 +26,11 @@ class HubSelector
|
|||
protected $trans;
|
||||
protected $rt;
|
||||
|
||||
public function __construct(EntityManagerInterface $em, InventoryManager $im,
|
||||
public function __construct(ContainerInterface $container, EntityManagerInterface $em, InventoryManager $im,
|
||||
HubDistributor $hub_distributor, HubFilterLogger $hub_filter_logger,
|
||||
TranslatorInterface $trans, RisingTideGateway $rt)
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class InvoiceManager implements InvoiceGeneratorInterface
|
|||
new InvoiceRule\Fuel($this->em, $this->pt_manager),
|
||||
new InvoiceRule\TireRepair($this->em, $this->pt_manager),
|
||||
new InvoiceRule\DiscountType($this->em),
|
||||
new InvoiceRule\TradeIn(),
|
||||
new InvoiceRule\TradeIn($this->em),
|
||||
new InvoiceRule\Tax($this->em, $this->pt_manager),
|
||||
];
|
||||
}
|
||||
|
|
@ -69,6 +69,14 @@ class InvoiceManager implements InvoiceGeneratorInterface
|
|||
->setCustomerVehicle($jo->getCustomerVehicle())
|
||||
->setPriceTier($price_tier);
|
||||
|
||||
if (($jo->getServiceType() == ServiceType::OVERHEAT_ASSISTANCE) &&
|
||||
($jo->hasCoolant()))
|
||||
$criteria->setHasCoolant(true);
|
||||
|
||||
if (($jo->getServiceType() == ServiceType::TIRE_REPAIR) &&
|
||||
($jo->hasSealant()))
|
||||
$criteria->setHasSealant(true);
|
||||
|
||||
// set if taxable
|
||||
// NOTE: ideally, this should be a parameter when calling generateInvoiceCriteria. But that
|
||||
// would mean adding it as a parameter to the call, impacting all calls
|
||||
|
|
@ -166,6 +174,7 @@ class InvoiceManager implements InvoiceGeneratorInterface
|
|||
// (3) generateInvoiceCriteria
|
||||
// (4) RiderAPIHandler's changeService
|
||||
// (5) TAPI's JobOrderController
|
||||
// (6) CAPI's RiderAppController
|
||||
public function generateInvoice($criteria)
|
||||
{
|
||||
// no need to validate since generateDraftInvoice was called before this was called
|
||||
|
|
@ -214,17 +223,27 @@ class InvoiceManager implements InvoiceGeneratorInterface
|
|||
$price = $item['price'];
|
||||
|
||||
$battery = null;
|
||||
$battery_size = null;
|
||||
$trade_in_type = '';
|
||||
if (isset($item['battery']))
|
||||
$battery = $item['battery'];
|
||||
|
||||
if (isset($item['promo']))
|
||||
$promo = $item['promo'];
|
||||
|
||||
if (isset($item['battery_size']))
|
||||
$battery_size = $item['battery_size'];
|
||||
|
||||
if (isset($item['trade_in_type']))
|
||||
$trade_in_type = $item['trade_in_type'];
|
||||
|
||||
$invoice_items[] = [
|
||||
'title' => $title,
|
||||
'quantity' => $quantity,
|
||||
'price' => $price,
|
||||
'battery' => $battery,
|
||||
'battery_size' => $battery_size,
|
||||
'trade_in_type' => $trade_in_type,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -273,11 +292,15 @@ class InvoiceManager implements InvoiceGeneratorInterface
|
|||
$invoice_item->setInvoice($invoice)
|
||||
->setTitle($item['title'])
|
||||
->setQuantity($item['quantity'])
|
||||
->setPrice((float)$item['price']);
|
||||
->setPrice((float)$item['price'])
|
||||
->setTradeInType($item['trade_in_type']);
|
||||
|
||||
if ($item['battery'] != null)
|
||||
$invoice_item->setBattery($item['battery']);
|
||||
|
||||
if ($item['battery_size'] != null)
|
||||
$invoice_item->setBatterySize($item['battery_size']);
|
||||
|
||||
$invoice->addItem($invoice_item);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ use App\Entity\EmergencyType;
|
|||
use App\Entity\OwnershipType;
|
||||
use App\Entity\CustomerLocation;
|
||||
use App\Entity\Battery;
|
||||
use App\Entity\BatterySize;
|
||||
|
||||
use App\Ramcar\ServiceType;
|
||||
use App\Ramcar\TradeInType;
|
||||
|
|
@ -95,7 +96,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;
|
||||
|
||||
|
|
@ -1611,6 +1612,26 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
$error_array['cust_location'] = 'Invalid customer location';
|
||||
}
|
||||
|
||||
// check facilitated type
|
||||
$fac_type = $req->request->get('facilitated_type');
|
||||
if (!empty($fac_type))
|
||||
{
|
||||
if (!FacilitatedType::validate($fac_type))
|
||||
$fac_type = null;
|
||||
}
|
||||
else
|
||||
$fac_type = null;
|
||||
|
||||
// check facilitated by
|
||||
$fac_by_id = $req->request->get('facilitated_by');
|
||||
$fac_by = null;
|
||||
if (!empty($fac_by_id))
|
||||
{
|
||||
$fac_by = $em->getRepository(Hub::class)->find($fac_by_id);
|
||||
if (empty($fac_by))
|
||||
$fac_by = null;
|
||||
}
|
||||
|
||||
// get previously assigned hub, if any
|
||||
$old_hub = $obj->getHub();
|
||||
|
||||
|
|
@ -1671,6 +1692,8 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
->setOwnershipType($owner_type)
|
||||
->setCustomerLocation($cust_location)
|
||||
->setInventoryCount($req->request->get('hub_inv_count', 0))
|
||||
->setFacilitatedType($fac_type)
|
||||
->setFacilitatedBy($fac_by)
|
||||
->clearRider();
|
||||
|
||||
if ($user != null)
|
||||
|
|
@ -2312,6 +2335,13 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
$em = $this->em;
|
||||
$jo = $em->getRepository(JobOrder::class)->find($id);
|
||||
|
||||
// get the job order's invoice items
|
||||
$invoice = $jo->getInvoice();
|
||||
$invoice_items = [];
|
||||
if ($invoice != null)
|
||||
$invoice_items = $invoice->getItems();
|
||||
|
||||
$params['invoice_items'] = $invoice_items;
|
||||
$params['obj'] = $jo;
|
||||
$params['mode'] = 'open_edit';
|
||||
$params['cvid'] = $jo->getCustomerVehicle()->getID();
|
||||
|
|
@ -2551,10 +2581,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 +2602,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 +2612,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 +2692,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
|
||||
// handle inventory data
|
||||
$bcode = $hub['hub']->getBranchCode();
|
||||
$hub['inventory'] = 0;
|
||||
//$hub['inventory'] = 0;
|
||||
if ($bcode != '')
|
||||
{
|
||||
$branch_codes[] = $bcode;
|
||||
|
|
@ -2660,43 +2706,65 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
$params['hubs'][$hub_id] = $hub;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
$batt = $inv_item->getBattery();
|
||||
if ($batt == null)
|
||||
continue;
|
||||
|
||||
$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));
|
||||
}
|
||||
|
||||
$params['obj'] = $obj;
|
||||
// get template to display
|
||||
$params['template'] = $this->getTwigTemplate('jo_processing_form');
|
||||
|
||||
// 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;
|
||||
|
||||
$skus[] = $batt->getSapCode();
|
||||
}
|
||||
|
||||
// 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']))
|
||||
{
|
||||
$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(print_r($mres, true));
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
|
|
@ -2889,13 +2957,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 +2981,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 +3005,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 +3062,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
|
||||
// handle inventory data
|
||||
$bcode = $hub['hub']->getBranchCode();
|
||||
$hub['inventory'] = 0;
|
||||
//$hub['inventory'] = 0;
|
||||
if ($bcode != '')
|
||||
{
|
||||
$branch_codes[] = $bcode;
|
||||
|
|
@ -2989,40 +3075,62 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
|
||||
$params['hubs'][$hub_id] = $hub;
|
||||
}
|
||||
|
||||
// get all enabled filters
|
||||
$enabled_filter_str = $_ENV['ENABLED_HUB_FILTERS'];
|
||||
$enabled_filters = explode(",", $enabled_filter_str);
|
||||
|
||||
// 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;
|
||||
// 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());
|
||||
|
||||
$skus[] = $batt->getSapCode();
|
||||
}
|
||||
|
||||
// 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 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');
|
||||
|
|
@ -3553,15 +3661,15 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
$params['trade_in_bmfgs'] = $em->getRepository(BatteryManufacturer::class)->findAll();
|
||||
$params['promos'] = $em->getRepository(Promo::class)->findAll();
|
||||
|
||||
// list of batteries for trade-in
|
||||
$ti_batteries = $em->getRepository(Battery::class)->findAll();
|
||||
$trade_in_batteries = [];
|
||||
foreach ($ti_batteries as $ti_battery)
|
||||
// list of battery sizes for trade-in
|
||||
$ti_batt_sizes = $em->getRepository(BatterySize::class)->findAll();
|
||||
$trade_in_batt_sizes = [];
|
||||
foreach ($ti_batt_sizes as $ti_batt_size)
|
||||
{
|
||||
$battery_name = $ti_battery->getModel()->getName() . ' ' . $ti_battery->getSize()->getName();
|
||||
$trade_in_batteries[$ti_battery->getID()] = $battery_name;
|
||||
$batt_size_name = $ti_batt_size->getName();
|
||||
$trade_in_batt_sizes[$ti_batt_size->getID()] = $batt_size_name;
|
||||
}
|
||||
$params['trade_in_batteries'] = $trade_in_batteries;
|
||||
$params['trade_in_batt_sizes'] = $trade_in_batt_sizes;
|
||||
|
||||
// list of emergency types
|
||||
$e_types = $em->getRepository(EmergencyType::class)->findBy([], ['name' => 'ASC']);
|
||||
|
|
@ -4259,12 +4367,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
|
||||
$phone_number = $this->country_code . $notif_number;
|
||||
|
||||
// check if reason is administrative
|
||||
if ($rejection->getReason() == JORejectionReason::ADMINISTRATIVE)
|
||||
return null;
|
||||
// check if reason is in the list of rejection reason
|
||||
$flag_send_sms = $this->checkRejectionReason($rejection->getReason());
|
||||
|
||||
// check if reason is discount
|
||||
if ($rejection->getReason() == JORejectionReason::DISCOUNT)
|
||||
if (!$flag_send_sms)
|
||||
return null;
|
||||
|
||||
// sms content
|
||||
|
|
@ -4298,4 +4404,65 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
$this->rt->sendSMS($phone_number, $this->translator->trans('message.battery_brand_allcaps'), $msg);
|
||||
}
|
||||
|
||||
protected function checkRejectionReason($reason): bool
|
||||
{
|
||||
// reason is administrative
|
||||
if ($reason == JORejectionReason::ADMINISTRATIVE)
|
||||
return false;
|
||||
|
||||
// reason is discount
|
||||
if ($reason == JORejectionReason::DISCOUNT)
|
||||
return false;
|
||||
|
||||
// reason is store closed on schedule
|
||||
if ($reason == JORejectionReason::STORE_CLOSED_SCHEDULED)
|
||||
return false;
|
||||
|
||||
// store closed half day
|
||||
if ($reason == JORejectionReason::STORE_CLOSED_HALF_DAY)
|
||||
return false;
|
||||
|
||||
// prio hub for warranty claim
|
||||
if ($reason == JORejectionReason::PRIORITY_HUB_WTY_CLAIM)
|
||||
return false;
|
||||
|
||||
// prio hub for jumpstart
|
||||
if ($reason == JORejectionReason::PRIORITY_HUB_JUMPSTART)
|
||||
return false;
|
||||
|
||||
// prio hub for RES-Q request
|
||||
if ($reason == JORejectionReason::PRIORITY_HUB_RESQ_REQUEST)
|
||||
return false;
|
||||
|
||||
// customer request
|
||||
if ($reason == JORejectionReason::CUSTOMER_REQUEST)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
</select>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<label for="invoice-trade-in-battery">Battery For Trade In</label>
|
||||
<select class="form-control m-input" id="invoice-trade-in-battery" data-value="">
|
||||
<label for="invoice-trade-in-battery-size">Battery Size For Trade In</label>
|
||||
<select class="form-control m-input" id="invoice-trade-in-battery-size" data-value="">
|
||||
<option value=""></option>
|
||||
{% for id, battery_name in trade_in_batteries %}
|
||||
<option value="{{ id }}">{{ battery_name }}</option>
|
||||
{% for id, batt_size_name in trade_in_batt_sizes %}
|
||||
<option value="{{ id }}">{{ batt_size_name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
// add trade in battery to invoice
|
||||
$('#btn-add-trade-in-to-invoice').click(function() {
|
||||
var bmfg = $("#invoice-trade-in-bmfg").val();
|
||||
var battery = $("#invoice-trade-in-battery").val();
|
||||
var battery_size = $("#invoice-trade-in-battery-size").val();
|
||||
var tradeIn = $("#invoice-trade-in-type").val();
|
||||
var qty = $("#invoice-trade-in-quantity").val();
|
||||
|
||||
// add to invoice array
|
||||
invoiceItems.push({
|
||||
battery: battery,
|
||||
battery_size: battery_size,
|
||||
quantity: qty,
|
||||
trade_in: tradeIn,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -630,20 +630,24 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group m-form__group row">
|
||||
<div class="col-lg-6">
|
||||
<label>Discount Type</label>
|
||||
{% if ftags.invoice_edit %}
|
||||
<select class="form-control m-input" id="invoice-promo" name="invoice_promo">
|
||||
<option value="">None</option>
|
||||
{% for promo in promos %}
|
||||
<option value="{{ promo.getID() }}">{{ promo.getName() ~ ' (' ~ promo.getDiscountRate * 100 ~ '% applied to ' ~ discount_apply[promo.getDiscountApply] ~ ')' }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="form-control-feedback hide" data-field="invoice_promo"></div>
|
||||
{% else %}
|
||||
<input type="text" id="invoice-promo" class="form-control m-input" value="{{ obj.getInvoice.getPromo.getName|default('None') }}" disabled>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<label>Discount Type</label>
|
||||
{% if ftags.invoice_edit %}
|
||||
<select class="form-control m-input" id="invoice-promo" name="invoice_promo">
|
||||
<option value="">None</option>
|
||||
{% for promo in promos %}
|
||||
{% if obj.getInvoice and obj.getInvoice.getPromo %}
|
||||
<option value="{{ promo.getID() }}" {{ obj.getInvoice.getPromo.getID == promo.getID ? ' selected'}}>{{ promo.getName() ~ ' (' ~ promo.getDiscountRate * 100 ~ '% applied to ' ~ discount_apply[promo.getDiscountApply] ~ ')' }}</option>
|
||||
{% else %}
|
||||
<option value="{{ promo.getID() }}">{{ promo.getName() ~ ' (' ~ promo.getDiscountRate * 100 ~ '% applied to ' ~ discount_apply[promo.getDiscountApply] ~ ')' }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="form-control-feedback hide" data-field="invoice_promo"></div>
|
||||
{% else %}
|
||||
<input type="text" id="invoice-promo" class="form-control m-input" value="{{ obj.getInvoice.getPromo.getName|default('None') }}" disabled>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<label>Promo Discount</label>
|
||||
<input type="text" id="invoice-promo-discount" class="form-control m-input text-right" value="{{ obj.getInvoice ? obj.getInvoice.getDiscount|number_format(2) : '0.00' }}" disabled>
|
||||
|
|
@ -827,20 +831,28 @@
|
|||
<div class="m-form__section">
|
||||
<div class="form-group m-form__group row">
|
||||
<div class="col-lg-2">
|
||||
<label for="faciliateted-type">Battery Facilitated By</label>
|
||||
<label for="facilitated-type">Battery Facilitated By</label>
|
||||
<select name="facilitated_type" class="form-control m-input" id="facilitated-type">
|
||||
<option value="">None</option>
|
||||
{% for key, type in facilitated_types %}
|
||||
<option value="{{ key }}">{{ type }}</option>
|
||||
{% if obj.getFacilitatedType %}
|
||||
<option value="{{ key }}"{{ obj.getFacilitatedType == key ? ' selected' }}>{{ type }}</option>
|
||||
{% else %}
|
||||
<option value="{{ key }}">{{ type }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-lg-8">
|
||||
<label for="faciliateted-by"> </label>
|
||||
<label for="facilitated-by"> </label>
|
||||
<select name="facilitated_by" class="form-control m-input" id="facilitated-by">
|
||||
<option value="">None</option>
|
||||
{% for key, name in facilitated_hubs %}
|
||||
<option value="{{ key }}">{{ name }}</option>
|
||||
{% if obj.getFacilitatedBy %}
|
||||
<option value="{{ key }}"{{ obj.getFacilitatedBy.getID == key ? ' selected' }}>{{ name }}</option>
|
||||
{% else %}
|
||||
<option value="{{ key }}">{{ name }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
|
@ -1194,6 +1206,10 @@
|
|||
<script src="/assets/vendors/custom/gmaps/gmaps.js" type="text/javascript"></script>
|
||||
|
||||
<script>
|
||||
var invoiceItems = [];
|
||||
var hasCoolant = 0;
|
||||
var hasSealant = 0;
|
||||
|
||||
// location search autocomplete
|
||||
var input = document.getElementById('m_gmap_address');
|
||||
|
||||
|
|
@ -1218,6 +1234,7 @@ autocomplete.addListener('place_changed', function() {
|
|||
|
||||
$(function() {
|
||||
var form_in_process = false;
|
||||
var invoiceItems = [];
|
||||
|
||||
// openstreet maps stuff
|
||||
// TODO: move this to a service
|
||||
|
|
@ -1228,6 +1245,49 @@ $(function() {
|
|||
|
||||
var markerLayerGroup = L.layerGroup().addTo(osm_map);
|
||||
|
||||
function populateInvoiceItems()
|
||||
{
|
||||
{% if invoice_items is defined %}
|
||||
{% for item in invoice_items %}
|
||||
var qty = {{ item.getQuantity }};
|
||||
{% if item.getBattery is not null %}
|
||||
var battery_id = {{ item.getBattery.getID }};
|
||||
|
||||
invoiceItems.push({
|
||||
battery: battery_id,
|
||||
quantity: qty,
|
||||
trade_in: '',
|
||||
});
|
||||
{% else %}
|
||||
{% if item.getBatterySize is not null %}
|
||||
var battery_size = {{ item.getBatterySize.GetID }};
|
||||
var trade_in_type = '{{ item.getTradeInType }}';
|
||||
|
||||
// add to invoice array
|
||||
invoiceItems.push({
|
||||
battery_size: battery_size,
|
||||
quantity: qty,
|
||||
trade_in: trade_in_type,
|
||||
});
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
// need to check if jo has coolant or sealant
|
||||
{% if obj.getServiceType == 'overheat' %}
|
||||
{% if obj.hasCoolant == 1 %}
|
||||
hasCoolant = 1;
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if obj.getServiceType == 'tire' %}
|
||||
{% if obj.hasSealant == 1 %}
|
||||
hasSealant = 1;
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
function selectPoint(lat, lng)
|
||||
{
|
||||
// check if point is in coverage area
|
||||
|
|
@ -1266,6 +1326,9 @@ $(function() {
|
|||
$('#map_lat').val(lat);
|
||||
$('#map_lng').val(lng);
|
||||
|
||||
// regenerate invoice
|
||||
generateInvoice();
|
||||
|
||||
}
|
||||
|
||||
osm_map.on('click', function(e) {
|
||||
|
|
@ -1309,6 +1372,11 @@ $(function() {
|
|||
// OSM code
|
||||
var lat = {{ obj.getCoordinates.getLatitude }};
|
||||
var lng = {{ obj.getCoordinates.getLongitude }};
|
||||
|
||||
var promo = $("#invoice-promo").val();
|
||||
|
||||
populateInvoiceItems();
|
||||
|
||||
selectPoint(lat, lng);
|
||||
|
||||
// remove placeholder text
|
||||
|
|
@ -1692,8 +1760,6 @@ $(function() {
|
|||
placeholder: ""
|
||||
});
|
||||
|
||||
var invoiceItems = [];
|
||||
|
||||
{% include 'invoice/trade_in.js.twig' %}
|
||||
|
||||
// add to invoice
|
||||
|
|
@ -1779,6 +1845,8 @@ $(function() {
|
|||
'cvid': cvid,
|
||||
'coord_lng': lng,
|
||||
'coord_lat': lat,
|
||||
'flag_coolant': hasCoolant,
|
||||
'flag_sealant': hasSealant,
|
||||
}
|
||||
}).done(function(response) {
|
||||
// mark as invoice changed
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
2
utils/hub_filter_exceptions/hub_filter_exceptions.sql
Normal file
2
utils/hub_filter_exceptions/hub_filter_exceptions.sql
Normal file
|
|
@ -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;
|
||||
|
|
@ -0,0 +1 @@
|
|||
INSERT INTO service_offering (name, code, fee) VALUES ('Motolite User Jumpstart Warranty Fee', 'motolite_user_jumpstart_warranty_fee', 200.00);
|
||||
1
utils/service_offering/insert_sealant_fee.sql
Normal file
1
utils/service_offering/insert_sealant_fee.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
INSERT INTO service_offering (name, code, fee) VALUES ('Tire Sealant Fee', 'tire_sealant_fee', '200.00');
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
-- MySQL dump 10.19 Distrib 10.3.39-MariaDB, for Linux (x86_64)
|
||||
--
|
||||
-- Host: localhost Database: resq
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 10.3.39-MariaDB
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8mb4 */;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `service_offering`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `service_offering`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `service_offering` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(80) NOT NULL,
|
||||
`code` varchar(80) NOT NULL,
|
||||
`fee` decimal(9,2) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `service_offering_idx` (`code`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `service_offering`
|
||||
--
|
||||
|
||||
LOCK TABLES `service_offering` WRITE;
|
||||
/*!40000 ALTER TABLE `service_offering` DISABLE KEYS */;
|
||||
INSERT INTO `service_offering` VALUES (1,'Tax','tax',0.12),(2,'Motolite User Service Fee','motolite_user_service_fee',0.00),(3,'Battery Replacement Warranty Fee','battery_replacement_warranty_fee',0.00),(4,'Fuel Service Fee','fuel_service_fee',300.00),(5,'Fuel Gas Fee','fuel_gas_fee',340.00),(6,'Fuel Diesel Fee','fuel_diesel_fee',320.00),(7,'Jumpstart Fee','jumpstart_fee',300.00),(8,'Jumpstart Fee Mobile App','jumpstart_fee_mobile_app',300.00),(9,'Jumpstart Warranty Fee','jumpstart_warranty_fee',300.00),(10,'Overheat Fee','overheat_fee',300.00),(11,'Coolant Fee','coolant_fee',1600.00),(12,'Post Recharged Fee','post_recharged_fee',300.00),(13,'Post Replacement Fee','post_replacement_fee',0.00),(14,'Tire Repair Fee','tire_repair_fee',300.00),(17,'Motolite User Jumpstart Warranty Fee','motolite_user_jumpstart_warranty_fee',200.00),(18,'Motolite User Jumpstart Fee','motolite_user_jumpstart_fee',200.00);
|
||||
/*!40000 ALTER TABLE `service_offering` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2024-04-02 1:17:40
|
||||
Loading…
Reference in a new issue