From 70ee7fdd8972da0e400f3b36da6d1908478eee7b Mon Sep 17 00:00:00 2001 From: root Date: Fri, 19 Jan 2024 04:14:06 -0500 Subject: [PATCH 01/16] Add invoice rule for price tier. #782 --- src/InvoiceRule/PriceTier.php | 157 +++++++++++++++++++++++++++++++++ src/Ramcar/InvoiceCriteria.php | 12 +++ 2 files changed, 169 insertions(+) create mode 100644 src/InvoiceRule/PriceTier.php diff --git a/src/InvoiceRule/PriceTier.php b/src/InvoiceRule/PriceTier.php new file mode 100644 index 00000000..4db12b55 --- /dev/null +++ b/src/InvoiceRule/PriceTier.php @@ -0,0 +1,157 @@ +em = $em; + } + + public function getID() + { + return 'price_tier'; + } + + public function compute($criteria, &$total) + { + $pt_id = $criteria->getPriceTier(); + + // get the service type + $service_type = $criteria->getServiceType(); + + // get price tier + $pt = $em->getRepository(PTEntity::class)->find($pt_id); + + // price tier is default + if ($pt == null) + { + // check if service type is battery sales + if ($service_type == ServiceType::BATTERY_REPLACEMENT_NEW) + { + $items = $this->processBatteryEntries($criteria, $total); + } + } + else + { + // get items in price tier + $pt_items = $pt->getItemPrices(); + + foreach ($pt_items as $pt_item) + { + // make item price hash + $pt_prices[$pt_item->getItemID()] = $pt_item->getPrice(); + } + } + + return $items; + } + + public function validatePromo($criteria, $promo_id) + { + return false; + } + + 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) && + ($stype != ServiceType::BATTERY_REPLACEMENT_WARRANTY)) + 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) + { + $battery = $this->em->getRepository(Battery::class)->find($item['battery']); + + 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); + } + } + + return null; + } + + protected function processBatteryEntries($criteria, &$total) + { + $items = []; + + // get the entries + $entries = $criteria->getEntries(); + foreach($entries as $entry) + { + $batt = $entry['battery']; + $qty = $entry['qty']; + $trade_in = null; + + if (isset($entry['trade_in'])) + $trade_in = $entry['trade_in']; + + $size = $batt->getSize(); + + if ($trade_in == null) + { + // battery purchase + $price = $batt->getSellingPrice(); + + $items[] = [ + 'service_type' => $this->getID(), + 'battery' => $batt, + 'qty' => $qty, + 'title' => $this->getTitle($criteria->getServiceType(), $batt), + 'price' => $price, + ]; + + $qty_price = bcmul($price, $qty, 2); + + $total['sell_price'] = bcadd($total['sell_price'], $qty_price, 2); + $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); + } + } + + return $items; + } + + protected function getTitle($service_type, $battery) + { + $title =''; + + // TODO: check for service type + $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName(); + + return $title; + } + +} diff --git a/src/Ramcar/InvoiceCriteria.php b/src/Ramcar/InvoiceCriteria.php index b27395da..18ebd82a 100644 --- a/src/Ramcar/InvoiceCriteria.php +++ b/src/Ramcar/InvoiceCriteria.php @@ -17,6 +17,7 @@ class InvoiceCriteria protected $service_charges; protected $flag_taxable; protected $source; // use Ramcar's TransactionOrigin + protected $price_tier; // entries are battery and trade-in combos protected $entries; @@ -32,6 +33,7 @@ class InvoiceCriteria $this->service_charges = []; $this->flag_taxable = false; $this->source = ''; + $this->price_tier = 0; // set to default } public function setServiceType($stype) @@ -179,4 +181,14 @@ class InvoiceCriteria return $this->source; } + public function setPriceTier($price_tier) + { + $this->price_tier = $price_tier; + return $this; + } + + public function getPriceTier() + { + return $this->price_tier; + } } From 29ad8d57a44ad1990cfb0e33990b52895f305892 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Mon, 22 Jan 2024 04:24:41 -0500 Subject: [PATCH 02/16] Add processing of battery entries and invoice item titles. #782 --- src/InvoiceRule/PriceTier.php | 77 +++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/src/InvoiceRule/PriceTier.php b/src/InvoiceRule/PriceTier.php index 4db12b55..7db80ccc 100644 --- a/src/InvoiceRule/PriceTier.php +++ b/src/InvoiceRule/PriceTier.php @@ -38,11 +38,18 @@ class PriceTier implements InvoiceRuleInterface // price tier is default if ($pt == null) { - // check if service type is battery sales - if ($service_type == ServiceType::BATTERY_REPLACEMENT_NEW) + // check if service type is battery sales and battery warranty (sometimes they add a battery + // for battery warranty + if (($service_type == ServiceType::BATTERY_REPLACEMENT_NEW) || + ($service_type == ServiceType::BATTERY_REPLACEMENT_WARRANTY)) { $items = $this->processBatteryEntries($criteria, $total); } + else + { + // TODO: process the service fees + $items = $this->processServiceEntries($criteria, $total); + } } else { @@ -54,6 +61,8 @@ class PriceTier implements InvoiceRuleInterface // make item price hash $pt_prices[$pt_item->getItemID()] = $pt_item->getPrice(); } + + // TODO: finish this } return $items; @@ -123,14 +132,17 @@ class PriceTier implements InvoiceRuleInterface if ($trade_in == null) { - // battery purchase - $price = $batt->getSellingPrice(); + // check if battery purchase or battery replacement + if ($service_type == ServiceType::BATTERY_REPLACEMENT_NEW) + $price = $batt->getSellingPrice(); + else + $price = 0; $items[] = [ 'service_type' => $this->getID(), 'battery' => $batt, 'qty' => $qty, - 'title' => $this->getTitle($criteria->getServiceType(), $batt), + 'title' => $this->getItemTitle($criteria->getServiceType(), $batt), 'price' => $price, ]; @@ -144,12 +156,63 @@ class PriceTier implements InvoiceRuleInterface return $items; } - protected function getTitle($service_type, $battery) + protected function processServiceEntries($criteria, &$total) + { + } + + protected function getItemTitle($service_type, $battery) { $title =''; // TODO: check for service type - $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName(); + switch ($service_type) { + case (ServiceType::BATTERY_REPLACEMENT_NEW): + $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName(); + break; + case (ServiceType::BATTERY_REPLACEMENT_WARRANTY): + $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName() . ' - Service Unit'; + break; + default: + $title = ''; + break; + } + + return $title; + + protected function getServiceTitle($service_type, $fuel_type) + { + $title = ''; + + switch ($service_type) { + case (ServiceType::JUMPSTART_TROUBLESHOOT): + case (ServiceType::JUMPSTART_WARRANTY): + $title = 'Service - Troubleshooting fee'; + break; + case (ServiceType::OVERHEAT_ASSISTANCE): + $title = 'Service - ' . ServiceType::getName(ServiceType::OVERHEAT_ASSISTANCE); + break; + case (ServiceType::POST_RECHARGED): + $title = 'Recharge fee'; + break; + case (ServiceType::POST_REPLACEMENT): + $title = 'Battery replacement'; + break; + case (ServiceType::TIRE_REPAIR): + $title = 'Service - Flat Tire'; + break; + case (ServiceType::EMERGENCY_REFUEL): + $title = '4L - ' . ucfirst($fuel_type); + break; + default: + $title = ''; + } + + return $title; + } + + protected function getServiceCoolantTitle() + { + $title = '4L Coolant'; return $title; } From b6763bfd3e41452a48048407120fa187f7058fcd Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 24 Jan 2024 02:24:13 -0500 Subject: [PATCH 03/16] Add price tier checking for battery sales. #782 --- config/services.yaml | 5 ++ src/Controller/JobOrderController.php | 22 ++++++- src/InvoiceRule/BatterySales.php | 38 +++++++++++- .../InvoiceGenerator/CMBInvoiceGenerator.php | 2 +- .../InvoiceGenerator/ResqInvoiceGenerator.php | 2 +- src/Service/InvoiceGeneratorInterface.php | 3 +- src/Service/InvoiceManager.php | 12 ++-- .../JobOrderHandler/ResqJobOrderHandler.php | 9 ++- src/Service/PriceTierManager.php | 58 +++++++++++++++++++ templates/job-order/form.html.twig | 6 +- 10 files changed, 141 insertions(+), 16 deletions(-) create mode 100644 src/Service/PriceTierManager.php diff --git a/config/services.yaml b/config/services.yaml index b19ecabc..d20db360 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -310,3 +310,8 @@ services: arguments: $server_key: "%env(FCM_SERVER_KEY)%" $sender_id: "%env(FCM_SENDER_ID)%" + + # price tier manager + App\Service\PriceTierManager: + arguments: + $em: "@doctrine.orm.entity_manager" diff --git a/src/Controller/JobOrderController.php b/src/Controller/JobOrderController.php index 91921a0f..17c62a45 100644 --- a/src/Controller/JobOrderController.php +++ b/src/Controller/JobOrderController.php @@ -30,6 +30,7 @@ use App\Service\HubSelector; use App\Service\RiderTracker; use App\Service\MotivConnector; +use App\Service\PriceTierManager; use App\Service\GeofenceTracker; use Symfony\Component\HttpFoundation\Request; @@ -42,6 +43,8 @@ use Doctrine\ORM\EntityManagerInterface; use Catalyst\MenuBundle\Annotation\Menu; +use CrEOF\Spatial\PHP\Types\Geometry\Point; + class JobOrderController extends Controller { public function getJobOrders(Request $req, JobOrderHandlerInterface $jo_handler) @@ -741,7 +744,7 @@ class JobOrderController extends Controller } - public function generateInvoice(Request $req, InvoiceGeneratorInterface $ic) + public function generateInvoice(Request $req, InvoiceGeneratorInterface $ic, PriceTierManager $pt_manager) { // error_log('generating invoice...'); $error = false; @@ -752,6 +755,19 @@ class JobOrderController extends Controller $cvid = $req->request->get('cvid'); $service_charges = $req->request->get('service_charges', []); + // coordinates + // need to check if lng and lat are set + $lng = $req->request->get('coord_lng', 0); + $lat = $req->request->get('coord_lat', 0); + + $price_tier = 0; + if (($lng != 0) && ($lat != 0)) + { + $coordinates = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat')); + $price_tier = $pt_manager->getPriceTier($coordinates); + } + + $em = $this->getDoctrine()->getManager(); // get customer vehicle @@ -767,8 +783,8 @@ class JobOrderController extends Controller $criteria->setServiceType($stype) ->setCustomerVehicle($cv) ->setIsTaxable() - ->setSource(TransactionOrigin::CALL); - + ->setSource(TransactionOrigin::CALL) + ->setPriceTier($price_tier); /* // if it's a jumpstart or troubleshoot only, we know what to charge already diff --git a/src/InvoiceRule/BatterySales.php b/src/InvoiceRule/BatterySales.php index 45b060d1..3ff9a995 100644 --- a/src/InvoiceRule/BatterySales.php +++ b/src/InvoiceRule/BatterySales.php @@ -10,14 +10,19 @@ use App\Ramcar\TradeInType; use App\Ramcar\ServiceType; use App\Entity\Battery; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class BatterySales implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -28,6 +33,9 @@ class BatterySales implements InvoiceRuleInterface public function compute($criteria, &$total) { $stype = $criteria->getServiceType(); + $pt = $criteria->getPriceTier(); + + error_log('price tier ' . $pt); $items = []; if ($stype == $this->getID()) @@ -47,8 +55,13 @@ class BatterySales implements InvoiceRuleInterface if ($trade_in == null) { - // battery purchase - $price = $batt->getSellingPrice(); + // check if price tier has item price for battery + $pt_price = $this->getPriceTierItemPrice($pt, $batt); + + if ($pt_price == null) + $price = $batt->getSellingPrice(); + else + $price = $pt_price; $items[] = [ 'service_type' => $this->getID(), @@ -114,6 +127,25 @@ class BatterySales implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id, $batt) + { + // price tier is default + if ($pt_id == 0) + return null; + + // find the item type battery + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'battery']); + if ($item_type == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $batt->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getTitle($battery) { $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName(); diff --git a/src/Service/InvoiceGenerator/CMBInvoiceGenerator.php b/src/Service/InvoiceGenerator/CMBInvoiceGenerator.php index 5dc86f8d..c1f40509 100644 --- a/src/Service/InvoiceGenerator/CMBInvoiceGenerator.php +++ b/src/Service/InvoiceGenerator/CMBInvoiceGenerator.php @@ -134,7 +134,7 @@ class CMBInvoiceGenerator implements InvoiceGeneratorInterface } // generate invoice criteria - public function generateInvoiceCriteria($jo, $discount, $invoice_items, $source = null, &$error_array) + public function generateInvoiceCriteria($jo, $discount, $invoice_items, $price_tier = null, $source = null, &$error_array) { $em = $this->em; diff --git a/src/Service/InvoiceGenerator/ResqInvoiceGenerator.php b/src/Service/InvoiceGenerator/ResqInvoiceGenerator.php index 3809133b..efe0a9de 100644 --- a/src/Service/InvoiceGenerator/ResqInvoiceGenerator.php +++ b/src/Service/InvoiceGenerator/ResqInvoiceGenerator.php @@ -144,7 +144,7 @@ class ResqInvoiceGenerator implements InvoiceGeneratorInterface } // generate invoice criteria - public function generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source = null, &$error_array) + public function generateInvoiceCriteria($jo, $promo_id, $invoice_items, $price_tier = null, $source = null, &$error_array) { $em = $this->em; diff --git a/src/Service/InvoiceGeneratorInterface.php b/src/Service/InvoiceGeneratorInterface.php index e2cb2cc3..4c46c38f 100644 --- a/src/Service/InvoiceGeneratorInterface.php +++ b/src/Service/InvoiceGeneratorInterface.php @@ -4,6 +4,7 @@ namespace App\Service; use App\Entity\Invoice; use App\Entity\JobOrder; +use App\Entity\PriceTier; use App\Ramcar\InvoiceCriteria; @@ -13,7 +14,7 @@ interface InvoiceGeneratorInterface public function generateInvoice(InvoiceCriteria $criteria); // generate invoice criteria - public function generateInvoiceCriteria(JobOrder $jo, int $promo_id, array $invoice_items, $source, array &$error_array); + public function generateInvoiceCriteria(JobOrder $jo, int $promo_id, array $invoice_items, $source, PriceTier $price_tier, array &$error_array); // prepare draft for invoice public function generateDraftInvoice(InvoiceCriteria $criteria, int $promo_id, array $service_charges, array $items); diff --git a/src/Service/InvoiceManager.php b/src/Service/InvoiceManager.php index 65fc3a43..93d6bafd 100644 --- a/src/Service/InvoiceManager.php +++ b/src/Service/InvoiceManager.php @@ -10,6 +10,7 @@ use Doctrine\ORM\EntityManagerInterface; use App\InvoiceRule; use App\Service\InvoiceGeneratorInterface; +use App\Service\PriceTierManager; use App\Ramcar\InvoiceCriteria; use App\Ramcar\InvoiceStatus; @@ -28,12 +29,14 @@ class InvoiceManager implements InvoiceGeneratorInterface protected $em; protected $validator; protected $available_rules; + protected $pt_manager; - public function __construct(EntityManagerInterface $em, Security $security, ValidatorInterface $validator) + public function __construct(EntityManagerInterface $em, Security $security, ValidatorInterface $validator, PriceTierManager $pt_manager) { $this->em = $em; $this->security = $security; $this->validator = $validator; + $this->pt_manager = $pt_manager; $this->available_rules = $this->getAvailableRules(); } @@ -42,7 +45,7 @@ class InvoiceManager implements InvoiceGeneratorInterface { // TODO: get list of invoice rules from .env or a json file? return [ - new InvoiceRule\BatterySales($this->em), + new InvoiceRule\BatterySales($this->em, $this->pt_manager), new InvoiceRule\BatteryReplacementWarranty($this->em), new InvoiceRule\Jumpstart($this->em), new InvoiceRule\JumpstartWarranty($this->em), @@ -58,12 +61,13 @@ class InvoiceManager implements InvoiceGeneratorInterface } // this is called when JO is submitted - public function generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source, &$error_array) + public function generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source, $price_tier, &$error_array) { // instantiate the invoice criteria $criteria = new InvoiceCriteria(); $criteria->setServiceType($jo->getServiceType()) - ->setCustomerVehicle($jo->getCustomerVehicle()); + ->setCustomerVehicle($jo->getCustomerVehicle()) + ->setPriceTier($price_tier); // set if taxable // NOTE: ideally, this should be a parameter when calling generateInvoiceCriteria. But that diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index 361c0b22..28e9035d 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -69,6 +69,7 @@ use App\Service\HubSelector; use App\Service\HubDistributor; use App\Service\HubFilteringGeoChecker; use App\Service\JobOrderManager; +use App\Service\PriceTierManager; use CrEOF\Spatial\PHP\Types\Geometry\Point; @@ -96,6 +97,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface protected $cust_distance_limit; protected $hub_filter_enable; protected $jo_manager; + protected $pt_manager; protected $template_hash; @@ -104,7 +106,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface TranslatorInterface $translator, RiderAssignmentHandlerInterface $rah, string $country_code, WarrantyHandler $wh, RisingTideGateway $rt, PromoLogger $promo_logger, HubDistributor $hub_dist, HubFilteringGeoChecker $hub_geofence, - string $cust_distance_limit, string $hub_filter_enabled, JobOrderManager $jo_manager) + string $cust_distance_limit, string $hub_filter_enabled, JobOrderManager $jo_manager, PriceTierManager $pt_manager) { $this->em = $em; $this->ic = $ic; @@ -121,6 +123,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface $this->cust_distance_limit = $cust_distance_limit; $this->hub_filter_enabled = $hub_filter_enabled; $this->jo_manager = $jo_manager; + $this->pt_manager = $pt_manager; $this->loadTemplates(); } @@ -585,7 +588,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface { $source = $jo->getSource(); - $this->ic->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source, $error_array); + // TODO: set the price tier according to location. + $price_tier = $this->pt_manager->getPriceTier($jo->getCoordinates()); + $this->ic->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source, $price_tier, $error_array); } // validate diff --git a/src/Service/PriceTierManager.php b/src/Service/PriceTierManager.php new file mode 100644 index 00000000..e4174e78 --- /dev/null +++ b/src/Service/PriceTierManager.php @@ -0,0 +1,58 @@ +em = $em; + } + + public function getItemPrice($pt_id, $item_type_id, $item_id) + { + // find the item price, given the price tier, battery id, and item type (battery) + $db_conn = $this->em->getConnection(); + + $ip_sql = 'SELECT ip.price AS price + FROM item_price ip + WHERE ip.price_tier_id = :pt_id + AND ip.item_type_id = :it_id + AND ip.item_id = :item_id'; + + $ip_stmt = $db_conn->prepare($ip_sql); + $ip_stmt->bindValue('pt_id', $pt_id); + $ip_stmt->bindValue('it_id', $item_type_id); + $ip_stmt->bindValue('item_id', $item_id); + + $ip_result = $ip_stmt->executeQuery(); + + $actual_price = 0; + // go through rows + while ($row = $ip_result->fetchAssociative()) + { + // get the price + $price = $row['price']; + + // actual price + $actual_price = number_format($price / 100, 2, '.', ''); + } + + return $actual_price; + } + + public function getPriceTier(Point $point) + { + // TODO: get location's price tier, given a set of coordinates + // for now, hardcoded for testing purposes + return 1; + } +} diff --git a/templates/job-order/form.html.twig b/templates/job-order/form.html.twig index ca68e922..375e0353 100644 --- a/templates/job-order/form.html.twig +++ b/templates/job-order/form.html.twig @@ -1761,6 +1761,8 @@ $(function() { var table = $("#invoice-table tbody"); var stype = $("#service_type").val(); var cvid = $("#customer-vehicle").val(); + var lng = $("#map_lng").val(); + var lat = $("#map_lat").val(); console.log(JSON.stringify(invoiceItems)); @@ -1772,7 +1774,9 @@ $(function() { 'stype': stype, 'items': invoiceItems, 'promo': promo, - 'cvid': cvid + 'cvid': cvid, + 'coord_lng': lng, + 'coord_lat': lat, } }).done(function(response) { // mark as invoice changed From c5b395d720589b6296c58bc158a80e211d8a3e7d Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 24 Jan 2024 04:02:14 -0500 Subject: [PATCH 04/16] Add price tier for battery replacement warranty. #782 --- .../BatteryReplacementWarranty.php | 41 ++++++++++++++++++- src/InvoiceRule/BatterySales.php | 2 - src/Service/InvoiceManager.php | 2 +- src/Service/PriceTierManager.php | 4 +- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/InvoiceRule/BatteryReplacementWarranty.php b/src/InvoiceRule/BatteryReplacementWarranty.php index ee1497b5..8c2dafd4 100644 --- a/src/InvoiceRule/BatteryReplacementWarranty.php +++ b/src/InvoiceRule/BatteryReplacementWarranty.php @@ -11,14 +11,19 @@ use App\Ramcar\TradeInType; use App\Entity\Battery; use App\Entity\ServiceOffering; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class BatteryReplacementWarranty implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -29,6 +34,7 @@ class BatteryReplacementWarranty implements InvoiceRuleInterface public function compute($criteria, &$total) { $stype = $criteria->getServiceType(); + $pt_id = $criteria->getPriceTier(); $items = []; if ($stype == $this->getID()) @@ -40,7 +46,14 @@ class BatteryReplacementWarranty implements InvoiceRuleInterface { $batt = $entry['battery']; $qty = 1; - $price = $this->getServiceTypeFee(); + + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id); + + if ($pt_price == null) + $price = $this->getServiceTypeFee(); + else + $price = $pt_price; $items[] = [ 'service_type' => $this->getID(), @@ -117,6 +130,30 @@ class BatteryReplacementWarranty implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + $code = 'battery_replacement_warranty_fee'; + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + + protected function getTitle($battery) { $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName() . ' - Service Unit'; diff --git a/src/InvoiceRule/BatterySales.php b/src/InvoiceRule/BatterySales.php index 3ff9a995..645e545b 100644 --- a/src/InvoiceRule/BatterySales.php +++ b/src/InvoiceRule/BatterySales.php @@ -35,8 +35,6 @@ class BatterySales implements InvoiceRuleInterface $stype = $criteria->getServiceType(); $pt = $criteria->getPriceTier(); - error_log('price tier ' . $pt); - $items = []; if ($stype == $this->getID()) { diff --git a/src/Service/InvoiceManager.php b/src/Service/InvoiceManager.php index 93d6bafd..6e37a207 100644 --- a/src/Service/InvoiceManager.php +++ b/src/Service/InvoiceManager.php @@ -46,7 +46,7 @@ class InvoiceManager implements InvoiceGeneratorInterface // TODO: get list of invoice rules from .env or a json file? return [ new InvoiceRule\BatterySales($this->em, $this->pt_manager), - new InvoiceRule\BatteryReplacementWarranty($this->em), + new InvoiceRule\BatteryReplacementWarranty($this->em, $this->pt_manager), new InvoiceRule\Jumpstart($this->em), new InvoiceRule\JumpstartWarranty($this->em), new InvoiceRule\PostRecharged($this->em), diff --git a/src/Service/PriceTierManager.php b/src/Service/PriceTierManager.php index e4174e78..c572af76 100644 --- a/src/Service/PriceTierManager.php +++ b/src/Service/PriceTierManager.php @@ -35,7 +35,9 @@ class PriceTierManager $ip_result = $ip_stmt->executeQuery(); - $actual_price = 0; + // results found + $actual_price = null; + // go through rows while ($row = $ip_result->fetchAssociative()) { From bc6364ace52058a4e343c784c07016a55731bcea Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 25 Jan 2024 02:11:05 -0500 Subject: [PATCH 05/16] Add price tier to invoice rules. #782 --- .../BatteryReplacementWarranty.php | 4 + src/InvoiceRule/Fuel.php | 94 +++++++- src/InvoiceRule/Jumpstart.php | 60 ++++- src/InvoiceRule/JumpstartWarranty.php | 47 +++- src/InvoiceRule/Overheat.php | 55 ++++- src/InvoiceRule/PostRecharged.php | 47 +++- src/InvoiceRule/PostReplacement.php | 47 +++- src/InvoiceRule/PriceTier.php | 220 ------------------ src/InvoiceRule/TireRepair.php | 54 ++++- src/Service/InvoiceManager.php | 14 +- 10 files changed, 386 insertions(+), 256 deletions(-) delete mode 100644 src/InvoiceRule/PriceTier.php diff --git a/src/InvoiceRule/BatteryReplacementWarranty.php b/src/InvoiceRule/BatteryReplacementWarranty.php index 8c2dafd4..46ba5e8a 100644 --- a/src/InvoiceRule/BatteryReplacementWarranty.php +++ b/src/InvoiceRule/BatteryReplacementWarranty.php @@ -145,6 +145,10 @@ class BatteryReplacementWarranty implements InvoiceRuleInterface $code = 'battery_replacement_warranty_fee'; $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + // check if service is null. If null, return null + if ($service == null) + return null; + $item_type_id = $item_type->getID(); $item_id = $service->getID(); diff --git a/src/InvoiceRule/Fuel.php b/src/InvoiceRule/Fuel.php index f843e1c0..691a1ba2 100644 --- a/src/InvoiceRule/Fuel.php +++ b/src/InvoiceRule/Fuel.php @@ -11,14 +11,19 @@ use App\Ramcar\ServiceType; use App\Entity\ServiceOffering; use App\Entity\CustomerVehicle; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class Fuel implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -29,6 +34,7 @@ class Fuel implements InvoiceRuleInterface public function compute($criteria, &$total) { $stype = $criteria->getServiceType(); + $pt_id = $criteria->getPriceTier(); $items = []; @@ -36,7 +42,13 @@ class Fuel implements InvoiceRuleInterface { $cv = $criteria->getCustomerVehicle(); - $fee = $this->getServiceTypeFee($cv); + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id, $cv); + + if ($pt_price == null) + $service_price = $this->getServiceTypeFee($cv); + else + $service_price = $pt_price; $ftype = $cv->getFuelType(); @@ -46,10 +58,10 @@ class Fuel implements InvoiceRuleInterface 'service_type' => $this->getID(), 'qty' => $qty, 'title' => $this->getServiceTitle($ftype), - 'price' => $fee, + 'price' => $service_price, ]; - $qty_fee = bcmul($qty, $fee, 2); + $qty_fee = bcmul($qty, $service_price, 2); $total_price = $qty_fee; switch ($ftype) @@ -57,7 +69,15 @@ class Fuel implements InvoiceRuleInterface case FuelType::GAS: case FuelType::DIESEL: $qty = 1; - $price = $this->getFuelFee($ftype); + + // check if price tier has item price for fuel type + $pt_price = $this->getPriceTierFuelItemPrice($pt_id, $ftype); + + if ($pt_price == null) + $price = $this->getFuelFee($ftype); + else + $price = $pt_price; + $items[] = [ 'service_type' => $this->getID(), 'qty' => $qty, @@ -138,6 +158,70 @@ class Fuel implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + // check if customer vehicle has a motolite battery + // if yes, set the code to the motolite user service fee + if ($cv->hasMotoliteBattery()) + $code = 'motolite_user_service_fee'; + else + $code = 'fuel_service_fee'; + + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + + protected function getPriceTierFuelItemPrice($pt_id, $fuel_type) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + $code = ''; + if ($fuel_type == FuelType::GAS) + $code = 'fuel_gas_fee'; + if ($fuel_type == FuelType::DIESEL) + $code = 'fuel_diesel_fee'; + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getTitle($fuel_type) { $title = '4L - ' . ucfirst($fuel_type); diff --git a/src/InvoiceRule/Jumpstart.php b/src/InvoiceRule/Jumpstart.php index dce41d99..d2e89b0a 100644 --- a/src/InvoiceRule/Jumpstart.php +++ b/src/InvoiceRule/Jumpstart.php @@ -8,16 +8,21 @@ use App\InvoiceRuleInterface; use App\Entity\ServiceOffering; use App\Entity\CustomerVehicle; +use App\Entity\ItemType; use App\Ramcar\TransactionOrigin; +use App\Service\PriceTierManager; + class Jumpstart implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -29,13 +34,21 @@ class Jumpstart implements InvoiceRuleInterface { $stype = $criteria->getServiceType(); $source = $criteria->getSource(); + $pt_id = $criteria->getPriceTier(); $items = []; if ($stype == $this->getID()) { $cv = $criteria->getCustomerVehicle(); - $fee = $this->getServiceTypeFee($source, $cv); + + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id, $source, $cv); + + if ($pt_price == null) + $price = $this->getServiceTypeFee($source, $cv); + else + $price = $pt_price; // add the service fee to items $qty = 1; @@ -43,10 +56,10 @@ class Jumpstart implements InvoiceRuleInterface 'service_type' => $this->getID(), 'qty' => $qty, 'title' => $this->getServiceTitle(), - 'price' => $fee, + 'price' => $price, ]; - $qty_price = bcmul($fee, $qty, 2); + $qty_price = bcmul($price, $qty, 2); $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); } @@ -86,6 +99,45 @@ class Jumpstart implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id, $source, $cv) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + 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'; + + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getServiceTitle() { $title = 'Service - Troubleshooting fee'; diff --git a/src/InvoiceRule/JumpstartWarranty.php b/src/InvoiceRule/JumpstartWarranty.php index 9423da44..4c6ac387 100644 --- a/src/InvoiceRule/JumpstartWarranty.php +++ b/src/InvoiceRule/JumpstartWarranty.php @@ -7,14 +7,19 @@ use Doctrine\ORM\EntityManagerInterface; use App\InvoiceRuleInterface; use App\Entity\ServiceOffering; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class JumpstartWarranty implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -25,12 +30,19 @@ class JumpstartWarranty implements InvoiceRuleInterface public function compute($criteria, &$total) { $stype = $criteria->getServiceType(); + $pt_id = $criteria->getPriceTier(); $items = []; if ($stype == $this->getID()) { - $fee = $this->getServiceTypeFee(); + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id); + + if ($pt_price == null) + $price = $this->getServiceTypeFee(); + else + $price = $pt_price; // add the service fee to items $qty = 1; @@ -38,10 +50,10 @@ class JumpstartWarranty implements InvoiceRuleInterface 'service_type' => $this->getID(), 'qty' => $qty, 'title' => $this->getServiceTitle(), - 'price' => $fee, + 'price' => $price, ]; - $qty_price = bcmul($fee, $qty, 2); + $qty_price = bcmul($price, $qty, 2); $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); } @@ -72,6 +84,33 @@ class JumpstartWarranty implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + $code = 'jumpstart_warranty_fee'; + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getServiceTitle() { $title = 'Service - Troubleshooting fee'; diff --git a/src/InvoiceRule/Overheat.php b/src/InvoiceRule/Overheat.php index 4c06bddb..af0ce182 100644 --- a/src/InvoiceRule/Overheat.php +++ b/src/InvoiceRule/Overheat.php @@ -10,14 +10,19 @@ use App\Ramcar\ServiceType; use App\Entity\ServiceOffering; use App\Entity\CustomerVehicle; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class Overheat implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -29,13 +34,22 @@ class Overheat implements InvoiceRuleInterface { $stype = $criteria->getServiceType(); $has_coolant = $criteria->hasCoolant(); + $pt_id = $criteria->getPriceTier(); $items = []; if ($stype == $this->getID()) { $cv = $criteria->getCustomerVehicle(); - $fee = $this->getServiceTypeFee($cv); + + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id, $cv); + + if ($pt_price == null) + $price = $this->getServiceTypeFee($cv); + else + + $price = $pt_price; // add the service fee to items $qty = 1; @@ -43,10 +57,10 @@ class Overheat implements InvoiceRuleInterface 'service_type' => $this->getID(), 'qty' => $qty, 'title' => $this->getServiceTitle(), - 'price' => $fee, + 'price' => $price, ]; - $qty_fee = bcmul($qty, $fee, 2); + $qty_fee = bcmul($qty, $price, 2); $total_price = $qty_fee; if ($has_coolant) @@ -112,6 +126,39 @@ class Overheat implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id, CustomerVehicle $cv) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + $code = 'overheat_fee'; + + // check if customer vehicle has a motolite battery + // if yes, set the code to the motolite user service fee + if ($cv->hasMotoliteBattery()) + $code = 'motolite_user_service_fee'; + + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getServiceTitle() { $title = 'Service - ' . ServiceType::getName(ServiceType::OVERHEAT_ASSISTANCE); diff --git a/src/InvoiceRule/PostRecharged.php b/src/InvoiceRule/PostRecharged.php index 808f2340..b0b20995 100644 --- a/src/InvoiceRule/PostRecharged.php +++ b/src/InvoiceRule/PostRecharged.php @@ -7,14 +7,19 @@ use Doctrine\ORM\EntityManagerInterface; use App\InvoiceRuleInterface; use App\Entity\ServiceOffering; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class PostRecharged implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -25,22 +30,29 @@ class PostRecharged implements InvoiceRuleInterface public function compute($criteria, &$total) { $stype = $criteria->getServiceType(); + $pt_id = $criteria->getPriceTier(); $items = []; if ($stype == $this->getID()) { - $fee = $this->getServiceTypeFee(); + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id); + + if ($pt_price == null) + $price = $this->getServiceTypeFee(); + else + $price = $pt_price; $qty = 1; $items[] = [ 'service_type' => $this->getID(), 'qty' => $qty, 'title' => $this->getServiceTitle(), - 'price' => $fee, + 'price' => $price, ]; - $qty_price = bcmul($fee, $qty, 2); + $qty_price = bcmul($price, $qty, 2); $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); } @@ -72,6 +84,33 @@ class PostRecharged implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + $code = 'post_recharged_fee'; + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getServiceTitle() { $title = 'Recharge fee'; diff --git a/src/InvoiceRule/PostReplacement.php b/src/InvoiceRule/PostReplacement.php index aba6d9aa..774b61de 100644 --- a/src/InvoiceRule/PostReplacement.php +++ b/src/InvoiceRule/PostReplacement.php @@ -7,14 +7,19 @@ use Doctrine\ORM\EntityManagerInterface; use App\InvoiceRuleInterface; use App\Entity\ServiceOffering; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class PostReplacement implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -25,22 +30,29 @@ class PostReplacement implements InvoiceRuleInterface public function compute($criteria, &$total) { $stype = $criteria->getServiceType(); + $pt_id = $criteria->getPriceTier(); $items = []; if ($stype == $this->getID()) { - $fee = $this->getServiceTypeFee(); + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id); + + if ($pt_price == null) + $price = $this->getServiceTypeFee(); + else + $price = $pt_price; $qty = 1; $items[] = [ 'service_type' => $this->getID(), 'qty' => $qty, 'title' => $this->getServiceTitle(), - 'price' => $fee, + 'price' => $price, ]; - $qty_price = bcmul($fee, $qty, 2); + $qty_price = bcmul($price, $qty, 2); $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); } @@ -71,6 +83,33 @@ class PostReplacement implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + $code = 'post_replacement_fee'; + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getServiceTitle() { $title = 'Battery replacement'; diff --git a/src/InvoiceRule/PriceTier.php b/src/InvoiceRule/PriceTier.php deleted file mode 100644 index 7db80ccc..00000000 --- a/src/InvoiceRule/PriceTier.php +++ /dev/null @@ -1,220 +0,0 @@ -em = $em; - } - - public function getID() - { - return 'price_tier'; - } - - public function compute($criteria, &$total) - { - $pt_id = $criteria->getPriceTier(); - - // get the service type - $service_type = $criteria->getServiceType(); - - // get price tier - $pt = $em->getRepository(PTEntity::class)->find($pt_id); - - // price tier is default - if ($pt == null) - { - // check if service type is battery sales and battery warranty (sometimes they add a battery - // for battery warranty - if (($service_type == ServiceType::BATTERY_REPLACEMENT_NEW) || - ($service_type == ServiceType::BATTERY_REPLACEMENT_WARRANTY)) - { - $items = $this->processBatteryEntries($criteria, $total); - } - else - { - // TODO: process the service fees - $items = $this->processServiceEntries($criteria, $total); - } - } - else - { - // get items in price tier - $pt_items = $pt->getItemPrices(); - - foreach ($pt_items as $pt_item) - { - // make item price hash - $pt_prices[$pt_item->getItemID()] = $pt_item->getPrice(); - } - - // TODO: finish this - } - - return $items; - } - - public function validatePromo($criteria, $promo_id) - { - return false; - } - - 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) && - ($stype != ServiceType::BATTERY_REPLACEMENT_WARRANTY)) - 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) - { - $battery = $this->em->getRepository(Battery::class)->find($item['battery']); - - 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); - } - } - - return null; - } - - protected function processBatteryEntries($criteria, &$total) - { - $items = []; - - // get the entries - $entries = $criteria->getEntries(); - foreach($entries as $entry) - { - $batt = $entry['battery']; - $qty = $entry['qty']; - $trade_in = null; - - if (isset($entry['trade_in'])) - $trade_in = $entry['trade_in']; - - $size = $batt->getSize(); - - if ($trade_in == null) - { - // check if battery purchase or battery replacement - if ($service_type == ServiceType::BATTERY_REPLACEMENT_NEW) - $price = $batt->getSellingPrice(); - else - $price = 0; - - $items[] = [ - 'service_type' => $this->getID(), - 'battery' => $batt, - 'qty' => $qty, - 'title' => $this->getItemTitle($criteria->getServiceType(), $batt), - 'price' => $price, - ]; - - $qty_price = bcmul($price, $qty, 2); - - $total['sell_price'] = bcadd($total['sell_price'], $qty_price, 2); - $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); - } - } - - return $items; - } - - protected function processServiceEntries($criteria, &$total) - { - } - - protected function getItemTitle($service_type, $battery) - { - $title =''; - - // TODO: check for service type - switch ($service_type) { - case (ServiceType::BATTERY_REPLACEMENT_NEW): - $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName(); - break; - case (ServiceType::BATTERY_REPLACEMENT_WARRANTY): - $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName() . ' - Service Unit'; - break; - default: - $title = ''; - break; - } - - return $title; - - protected function getServiceTitle($service_type, $fuel_type) - { - $title = ''; - - switch ($service_type) { - case (ServiceType::JUMPSTART_TROUBLESHOOT): - case (ServiceType::JUMPSTART_WARRANTY): - $title = 'Service - Troubleshooting fee'; - break; - case (ServiceType::OVERHEAT_ASSISTANCE): - $title = 'Service - ' . ServiceType::getName(ServiceType::OVERHEAT_ASSISTANCE); - break; - case (ServiceType::POST_RECHARGED): - $title = 'Recharge fee'; - break; - case (ServiceType::POST_REPLACEMENT): - $title = 'Battery replacement'; - break; - case (ServiceType::TIRE_REPAIR): - $title = 'Service - Flat Tire'; - break; - case (ServiceType::EMERGENCY_REFUEL): - $title = '4L - ' . ucfirst($fuel_type); - break; - default: - $title = ''; - } - - return $title; - } - - protected function getServiceCoolantTitle() - { - $title = '4L Coolant'; - - return $title; - } - -} diff --git a/src/InvoiceRule/TireRepair.php b/src/InvoiceRule/TireRepair.php index 755c11bd..96d3c525 100644 --- a/src/InvoiceRule/TireRepair.php +++ b/src/InvoiceRule/TireRepair.php @@ -8,14 +8,19 @@ use App\InvoiceRuleInterface; use App\Entity\ServiceOffering; use App\Entity\CustomerVehicle; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class TireRepair implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -26,13 +31,21 @@ class TireRepair implements InvoiceRuleInterface public function compute($criteria, &$total) { $stype = $criteria->getServiceType(); + $pt_id = $criteria->getPriceTier(); $items = []; if ($stype == $this->getID()) { $cv = $criteria->getCustomerVehicle(); - $fee = $this->getServiceTypeFee($cv); + + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id, $cv); + + if ($pt_price == null) + $price = $this->getServiceTypeFee($cv); + else + $price = $pt_price; // add the service fee to items $qty = 1; @@ -40,10 +53,10 @@ class TireRepair implements InvoiceRuleInterface 'service_type' => $this->getID(), 'qty' => $qty, 'title' => $this->getServiceTitle(), - 'price' => $fee, + 'price' => $price, ]; - $qty_price = bcmul($fee, $qty, 2); + $qty_price = bcmul($price, $qty, 2); $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); } @@ -79,6 +92,39 @@ class TireRepair implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id, CustomerVehicle $cv) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + $code = 'tire_repair_fee'; + + // check if customer vehicle has a motolite battery + // if yes, set the code to the motolite user service fee + if ($cv->hasMotoliteBattery()) + $code = 'motolite_user_service_fee'; + + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getServiceTitle() { $title = 'Service - Flat Tire'; diff --git a/src/Service/InvoiceManager.php b/src/Service/InvoiceManager.php index 6e37a207..f46c95ab 100644 --- a/src/Service/InvoiceManager.php +++ b/src/Service/InvoiceManager.php @@ -47,13 +47,13 @@ class InvoiceManager implements InvoiceGeneratorInterface return [ new InvoiceRule\BatterySales($this->em, $this->pt_manager), new InvoiceRule\BatteryReplacementWarranty($this->em, $this->pt_manager), - new InvoiceRule\Jumpstart($this->em), - new InvoiceRule\JumpstartWarranty($this->em), - new InvoiceRule\PostRecharged($this->em), - new InvoiceRule\PostReplacement($this->em), - new InvoiceRule\Overheat($this->em), - new InvoiceRule\Fuel($this->em), - new InvoiceRule\TireRepair($this->em), + new InvoiceRule\Jumpstart($this->em, $this->pt_manager), + new InvoiceRule\JumpstartWarranty($this->em, $this->pt_manager), + new InvoiceRule\PostRecharged($this->em, $this->pt_manager), + new InvoiceRule\PostReplacement($this->em, $this->pt_manager), + new InvoiceRule\Overheat($this->em, $this->pt_manager), + 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\Tax($this->em), From 57fd7fe5ac1e3c49e7e608d6b5c71556f3a46c2c Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 25 Jan 2024 02:23:47 -0500 Subject: [PATCH 06/16] Fix issues found during testing. #782 --- src/InvoiceRule/Fuel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/InvoiceRule/Fuel.php b/src/InvoiceRule/Fuel.php index 691a1ba2..e4f365b9 100644 --- a/src/InvoiceRule/Fuel.php +++ b/src/InvoiceRule/Fuel.php @@ -158,7 +158,7 @@ class Fuel implements InvoiceRuleInterface return null; } - protected function getPriceTierItemPrice($pt_id) + protected function getPriceTierItemPrice($pt_id, CustomerVehicle $cv) { // price_tier is default if ($pt_id == 0) From c136b0666ba4f3601e9db88baa0441079cc72f3f Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 25 Jan 2024 03:08:00 -0500 Subject: [PATCH 07/16] Fix issues found during testing. #782 --- src/InvoiceRule/Tax.php | 35 +++++++++++++++++-- src/Service/InvoiceManager.php | 2 +- .../JobOrderHandler/ResqJobOrderHandler.php | 10 ++++-- src/Service/PriceTierManager.php | 25 ++++++++++--- 4 files changed, 62 insertions(+), 10 deletions(-) diff --git a/src/InvoiceRule/Tax.php b/src/InvoiceRule/Tax.php index b1e6a600..50834e44 100644 --- a/src/InvoiceRule/Tax.php +++ b/src/InvoiceRule/Tax.php @@ -9,14 +9,19 @@ use App\InvoiceRuleInterface; use App\Ramcar\ServiceType; use App\Entity\ServiceOffering; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class Tax implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -40,6 +45,7 @@ class Tax implements InvoiceRuleInterface // compute tax per item if service type is battery sales $stype = $criteria->getServiceType(); + $pt = $criteria->getPriceTier(); if ($stype == ServiceType::BATTERY_REPLACEMENT_NEW) { @@ -58,7 +64,13 @@ class Tax implements InvoiceRuleInterface $battery = $entry['battery']; $qty = $entry['qty']; - $price = $battery->getSellingPrice(); + // check if price tier has item price for battery + $pt_price = $this->getPriceTierItemPrice($pt, $battery); + + if ($pt_price == null) + $price = $battery->getSellingPrice(); + else + $price = $pt_price; $vat = $this->getTaxAmount($price, $tax_rate); @@ -96,6 +108,25 @@ class Tax implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id, $batt) + { + // price tier is default + if ($pt_id == 0) + return null; + + // find the item type battery + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'battery']); + if ($item_type == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $batt->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getTaxAmount($price, $tax_rate) { $vat_ex_price = $this->getTaxExclusivePrice($price, $tax_rate); diff --git a/src/Service/InvoiceManager.php b/src/Service/InvoiceManager.php index f46c95ab..8f655224 100644 --- a/src/Service/InvoiceManager.php +++ b/src/Service/InvoiceManager.php @@ -56,7 +56,7 @@ class InvoiceManager implements InvoiceGeneratorInterface new InvoiceRule\TireRepair($this->em, $this->pt_manager), new InvoiceRule\DiscountType($this->em), new InvoiceRule\TradeIn(), - new InvoiceRule\Tax($this->em), + new InvoiceRule\Tax($this->em, $this->pt_manager), ]; } diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index 28e9035d..c7c38100 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -588,7 +588,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface { $source = $jo->getSource(); - // TODO: set the price tier according to location. + // get the price tier according to location. $price_tier = $this->pt_manager->getPriceTier($jo->getCoordinates()); $this->ic->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source, $price_tier, $error_array); } @@ -822,7 +822,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface { $source = $obj->getSource(); - $this->ic->generateInvoiceCriteria($obj, $promo_id, $invoice_items, $source, $error_array); + // get the price tier according to location. + $price_tier = $this->pt_manager->getPriceTier($obj->getCoordinates()); + $this->ic->generateInvoiceCriteria($obj, $promo_id, $invoice_items, $source, $price_tier, $error_array); } // validate @@ -2170,7 +2172,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface // NOTE: this is CMB code but for compilation purposes we need to add this $source = $jo->getSource(); - $this->ic->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source, $error_array); + // get the price tier according to location. + $price_tier = $this->pt_manager->getPriceTier($jo->getCoordinates()); + $this->ic->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source, $price_tier, $error_array); } // validate diff --git a/src/Service/PriceTierManager.php b/src/Service/PriceTierManager.php index c572af76..1d8bb60c 100644 --- a/src/Service/PriceTierManager.php +++ b/src/Service/PriceTierManager.php @@ -51,10 +51,27 @@ class PriceTierManager return $actual_price; } - public function getPriceTier(Point $point) + public function getPriceTier(Point $coordinates) { - // TODO: get location's price tier, given a set of coordinates - // for now, hardcoded for testing purposes - return 1; + $price_tier_id = 0; + + $long = $coordinates->getLongitude(); + $lat = $coordinates->getLatitude(); + + // get location's price tier, 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) + { + $price_tier = $area->getPriceTier(); + if ($price_tier != null) + $price_tier_id = $price_tier->getID(); + } + + return $price_tier_id; } } From 213171f4b7e2bd07a65dd826cd0983d2a04b9ab4 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 26 Jan 2024 04:44:13 -0500 Subject: [PATCH 08/16] Add price tiering for Resq 2 App and TAPI. #782 --- src/Controller/APIController.php | 5 +++ src/Controller/CAPI/RiderAppController.php | 7 ++- .../CustomerAppAPI/InvoiceController.php | 45 ++++++++++++++++++- .../CustomerAppAPI/JobOrderController.php | 15 ++++++- src/Controller/TAPI/JobOrderController.php | 16 ++++++- src/Service/PriceTierManager.php | 31 +++++++------ 6 files changed, 99 insertions(+), 20 deletions(-) diff --git a/src/Controller/APIController.php b/src/Controller/APIController.php index 16a9cdf5..0eb148c5 100644 --- a/src/Controller/APIController.php +++ b/src/Controller/APIController.php @@ -50,6 +50,7 @@ use App\Service\HubFilterLogger; use App\Service\HubFilteringGeoChecker; use App\Service\HashGenerator; use App\Service\JobOrderManager; +use App\Service\PriceTierManager; use App\Entity\MobileSession; use App\Entity\Customer; @@ -2911,6 +2912,10 @@ class APIController extends Controller implements LoggedController // old app doesn't have separate jumpstart $icrit->setSource(TransactionOrigin::CALL); + // set price tier + $pt_id = $this->pt_manager->getPriceTier($jo->getCoordinates()); + $icrit->setPriceTier($pt_id); + // check promo $promo_id = $req->request->get('promo_id'); if (!empty($promo_id)) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index d29f6a04..6cce3745 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -34,6 +34,7 @@ use App\Service\JobOrderHandlerInterface; use App\Service\InvoiceGeneratorInterface; use App\Service\RisingTideGateway; use App\Service\RiderTracker; +use App\Service\PriceTierManager; use App\Ramcar\ServiceType; use App\Ramcar\TradeInType; @@ -1099,7 +1100,7 @@ class RiderAppController extends ApiController return new APIResponse(true, 'Batteries found.', $data); } - public function changeService(Request $req, EntityManagerInterface $em, InvoiceGeneratorInterface $ic) + public function changeService(Request $req, EntityManagerInterface $em, InvoiceGeneratorInterface $ic, PriceTierManager $pt_manager) { // $this->debugRequest($req); @@ -1203,6 +1204,10 @@ class RiderAppController extends ApiController $crit->setHasCoolant($jo->hasCoolant()); $crit->setIsTaxable(); + // set price tier + $pt_id = $pt_manager->getPriceTier($jo->getCoordinates()); + $icrit->setPriceTier($pt_id); + if ($promo != null) $crit->addPromo($promo); diff --git a/src/Controller/CustomerAppAPI/InvoiceController.php b/src/Controller/CustomerAppAPI/InvoiceController.php index a5c3a8b8..14f1a87e 100644 --- a/src/Controller/CustomerAppAPI/InvoiceController.php +++ b/src/Controller/CustomerAppAPI/InvoiceController.php @@ -4,18 +4,22 @@ namespace App\Controller\CustomerAppAPI; use Symfony\Component\HttpFoundation\Request; use Catalyst\ApiBundle\Component\Response as ApiResponse; +use CrEOF\Spatial\PHP\Types\Geometry\Point; use App\Service\InvoiceGeneratorInterface; +use App\Service\PriceTierManager; use App\Ramcar\InvoiceCriteria; use App\Ramcar\TradeInType; use App\Ramcar\TransactionOrigin; use App\Entity\CustomerVehicle; use App\Entity\Promo; use App\Entity\Battery; +use App\Entity\Customer; +use App\Entity\CustomerMetadata; class InvoiceController extends ApiController { - public function getEstimate(Request $req, InvoiceGeneratorInterface $ic) + public function getEstimate(Request $req, InvoiceGeneratorInterface $ic, PriceTierManager $pt_manager) { // $this->debugRequest($req); @@ -36,6 +40,9 @@ class InvoiceController extends ApiController return new ApiResponse(false, 'No customer information found.'); } + // get customer location from customer_metadata using customer id + $coordinates = $this->getCustomerMetadata($cust); + // make invoice criteria $icrit = new InvoiceCriteria(); $icrit->setServiceType($req->request->get('service_type')); @@ -113,6 +120,18 @@ class InvoiceController extends ApiController // set JO source $icrit->setSource(TransactionOrigin::MOBILE_APP); + // set price tier + $pt_id = 0; + if ($coordinates != null) + { + error_log('coordinates are not null'); + $pt_id = $pt_manager->getPriceTier($coordinates); + } + else + error_log('null?'); + + $icrit->setPriceTier($pt_id); + // send to invoice generator $invoice = $ic->generateInvoice($icrit); @@ -148,4 +167,28 @@ class InvoiceController extends ApiController // response return new ApiResponse(true, '', $data); } + + protected function getCustomerMetadata(Customer $cust) + { + $coordinates = null; + + // check if customer already has existing metadata + $c_meta = $this->em->getRepository(CustomerMetadata::class)->findOneBy(['customer' => $cust]); + if ($c_meta != null) + { + $meta_data = $c_meta->getAllMetaInfo(); + foreach ($meta_data as $m_info) + { + if ((isset($m_info['longitude'])) && (isset($m_info['latitude']))) + { + $lng = $m_info['longitude']; + $lat = $m_info['latitude']; + + $coordinates = new Point($lng, $lat); + } + } + } + + return $coordinates; + } } diff --git a/src/Controller/CustomerAppAPI/JobOrderController.php b/src/Controller/CustomerAppAPI/JobOrderController.php index 143f2a2e..fa5a9a85 100644 --- a/src/Controller/CustomerAppAPI/JobOrderController.php +++ b/src/Controller/CustomerAppAPI/JobOrderController.php @@ -21,6 +21,7 @@ use App\Service\HubDistributor; use App\Service\HubFilterLogger; use App\Service\HubFilteringGeoChecker; use App\Service\JobOrderManager; +use App\Service\PriceTierManager; use App\Ramcar\ServiceType; use App\Ramcar\APIRiderStatus; use App\Ramcar\InvoiceCriteria; @@ -484,7 +485,8 @@ class JobOrderController extends ApiController HubDistributor $hub_dist, HubFilterLogger $hub_filter_logger, HubFilteringGeoChecker $hub_geofence, - JobOrderManager $jo_manager + JobOrderManager $jo_manager, + PriceTierManager $pt_manager ) { // validate params $validity = $this->validateRequest($req, [ @@ -698,6 +700,10 @@ class JobOrderController extends ApiController // set JO source $icrit->setSource(TransactionOrigin::MOBILE_APP); + // set price tier + $pt_id = $pt_manager->getPriceTier($jo->getCoordinates()); + $icrit->setPriceTier($pt_id); + // send to invoice generator $invoice = $ic->generateInvoice($icrit); $jo->setInvoice($invoice); @@ -970,7 +976,8 @@ class JobOrderController extends ApiController HubDistributor $hub_dist, HubFilterLogger $hub_filter_logger, HubFilteringGeoChecker $hub_geofence, - JobOrderManager $jo_manager + JobOrderManager $jo_manager, + PriceTierManager $pt_manager ) { // validate params $validity = $this->validateRequest($req, [ @@ -1127,6 +1134,10 @@ class JobOrderController extends ApiController // set JO source $icrit->setSource(TransactionOrigin::MOBILE_APP); + // set price tier + $pt_id = $pt_manager->getPriceTier($jo->getCoordinates()); + $icrit->setPriceTier($pt_id); + // send to invoice generator $invoice = $ic->generateInvoice($icrit); $jo->setInvoice($invoice); diff --git a/src/Controller/TAPI/JobOrderController.php b/src/Controller/TAPI/JobOrderController.php index f7541b50..ae4d5a61 100644 --- a/src/Controller/TAPI/JobOrderController.php +++ b/src/Controller/TAPI/JobOrderController.php @@ -46,6 +46,7 @@ use App\Service\RiderTracker; use App\Service\PromoLogger; use App\Service\MapTools; use App\Service\JobOrderManager; +use App\Service\PriceTierManager; use App\Entity\JobOrder; use App\Entity\CustomerVehicle; @@ -79,7 +80,8 @@ class JobOrderController extends ApiController FCMSender $fcmclient, RiderAssignmentHandlerInterface $rah, PromoLogger $promo_logger, HubSelector $hub_select, HubDistributor $hub_dist, HubFilterLogger $hub_filter_logger, - HubFilteringGeoChecker $hub_geofence, EntityManagerInterface $em, JobOrderManager $jo_manager) + HubFilteringGeoChecker $hub_geofence, EntityManagerInterface $em, JobOrderManager $jo_manager, + PriceTierManager $pt_manager) { $this->denyAccessUnlessGranted('tapi_jo.request', null, 'No access.'); @@ -165,7 +167,17 @@ class JobOrderController extends ApiController // set JO source $icrit->setSource(TransactionOrigin::THIRD_PARTY); - $icrit->addEntry($data['batt'], $data['trade_in_type'], 1); + // set price tier + $pt_id = $pt_manager->getPriceTier($jo->getCoordinates()); + $icrit->setPriceTier($pt_id); + + // add the actual battery item first + $icrit->addEntry($data['batt'], null, 1); + + // if we have a trade in, add it as well, assuming trade in battery == battery purchased + if (!empty($data['trade_in_type'])) { + $icrit->addEntry($data['batt'], $data['trade_in_type'], 1); + } // send to invoice generator $invoice = $ic->generateInvoice($icrit); diff --git a/src/Service/PriceTierManager.php b/src/Service/PriceTierManager.php index 1d8bb60c..62d657f4 100644 --- a/src/Service/PriceTierManager.php +++ b/src/Service/PriceTierManager.php @@ -55,21 +55,24 @@ class PriceTierManager { $price_tier_id = 0; - $long = $coordinates->getLongitude(); - $lat = $coordinates->getLatitude(); - - // get location's price tier, 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) + if ($coordinates != null) { - $price_tier = $area->getPriceTier(); - if ($price_tier != null) - $price_tier_id = $price_tier->getID(); + $long = $coordinates->getLongitude(); + $lat = $coordinates->getLatitude(); + + // get location's price tier, 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) + { + $price_tier = $area->getPriceTier(); + if ($price_tier != null) + $price_tier_id = $price_tier->getID(); + } } return $price_tier_id; From 20f5bb08e02e16d26085d3a75856b1f0b1af0f22 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 26 Jan 2024 04:50:54 -0500 Subject: [PATCH 09/16] Add checking for longitude and latitude when calling getEstimate. #782 --- src/Controller/CustomerAppAPI/InvoiceController.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Controller/CustomerAppAPI/InvoiceController.php b/src/Controller/CustomerAppAPI/InvoiceController.php index 14f1a87e..2e9779eb 100644 --- a/src/Controller/CustomerAppAPI/InvoiceController.php +++ b/src/Controller/CustomerAppAPI/InvoiceController.php @@ -41,7 +41,16 @@ class InvoiceController extends ApiController } // get customer location from customer_metadata using customer id - $coordinates = $this->getCustomerMetadata($cust); + $lng = $req->request->get('longitude'); + $lat = $req->request->get('latitude'); + + if ((empty($lng)) || (empty($lat))) + { + // use customer metadata location as basis + $coordinates = $this->getCustomerMetadata($cust); + } + else + $coordinates = new Point($lng, $lat); // make invoice criteria $icrit = new InvoiceCriteria(); From d4eae00902393cd67cad6d5c1deab5d7970fe65d Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Sun, 28 Jan 2024 22:21:34 -0500 Subject: [PATCH 10/16] Add sql for item types. #782 --- utils/item_types/item_types.sql | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 utils/item_types/item_types.sql diff --git a/utils/item_types/item_types.sql b/utils/item_types/item_types.sql new file mode 100644 index 00000000..7c5aeeba --- /dev/null +++ b/utils/item_types/item_types.sql @@ -0,0 +1,53 @@ +-- 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 `item_type` +-- + +DROP TABLE IF EXISTS `item_type`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `item_type` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(80) NOT NULL, + `code` varchar(80) NOT NULL, + PRIMARY KEY (`id`), + KEY `item_type_idx` (`code`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `item_type` +-- + +LOCK TABLES `item_type` WRITE; +/*!40000 ALTER TABLE `item_type` DISABLE KEYS */; +INSERT INTO `item_type` VALUES (1,'Battery','battery'),(2,'Service Offering','service_offering'); +/*!40000 ALTER TABLE `item_type` 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-01-28 20:59:44 From 0e2afaa4001ae3e56866bbfc952a79143d8a5ef1 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 30 Jan 2024 01:30:09 -0500 Subject: [PATCH 11/16] Add new fields for transaction origin. #784 --- src/Ramcar/TransactionOrigin.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Ramcar/TransactionOrigin.php b/src/Ramcar/TransactionOrigin.php index a204b35f..2a742c0a 100644 --- a/src/Ramcar/TransactionOrigin.php +++ b/src/Ramcar/TransactionOrigin.php @@ -17,6 +17,10 @@ class TransactionOrigin extends NameValue const YOKOHAMA_TWITTER = 'yokohama_twitter'; const YOKOHAMA_INSTAGRAM = 'yokohama_instagram'; const YOKOHAMA_CAROUSELL = 'yokohama_carousell'; + const HOTLINE_MANILA = 'hotline_manila'; + const HOTLINE_CEBU = 'hotline_cebu'; + const FACEBOOK_MANILA = 'facebook_manila'; + const FACEBOOK_CEBU = 'facebook_cebu'; // TODO: for now, resq also gets the walk-in option // resq also gets new YOKOHAMA options @@ -34,5 +38,9 @@ class TransactionOrigin extends NameValue 'yokohama_twitter' => 'Yokohama Twitter', 'yokohama_instagram' => 'Yokohama Instagram', 'yokohama_carousell' => 'Yokohama Carousell', + 'hotline_manila' => 'Hotline Manila', + 'hotline_cebu' => 'Hotline Cebu', + 'facebook_manila' => 'Facebook Manila', + 'facebook_cebu' => 'Facebook Cebu' ]; } From 9b52d4578f13f46f25d07794b31610c9f039ffbb Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 30 Jan 2024 02:02:24 -0500 Subject: [PATCH 12/16] Add checking for discount rejection reason. #785 --- src/Service/JobOrderHandler/ResqJobOrderHandler.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index 361c0b22..38571fdd 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -4252,6 +4252,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface if ($rejection->getReason() == JORejectionReason::ADMINISTRATIVE) return null; + // check if reason is discount + if ($rejection->getReason() == JORejectionReason::DISCOUNT) + return null; + // sms content // Job Order # - can get from jo // Order Date and Time - get from jo From f7c8034538693fa1453754a78931628be5d861a2 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 30 Jan 2024 02:12:08 -0500 Subject: [PATCH 13/16] Comment out the geofence call for admin panel. #786 --- templates/job-order/form.html.twig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/templates/job-order/form.html.twig b/templates/job-order/form.html.twig index ca68e922..d0d7e834 100644 --- a/templates/job-order/form.html.twig +++ b/templates/job-order/form.html.twig @@ -1231,6 +1231,8 @@ $(function() { function selectPoint(lat, lng) { // check if point is in coverage area + // commenting out the geofence call for CRM + /* $.ajax({ method: "GET", url: "{{ url('jo_geofence') }}", @@ -1248,7 +1250,7 @@ $(function() { type: 'warning', }); } - }); + }); */ // clear markers markerLayerGroup.clearLayers(); From 5717eddaa04f17802f0982d18fd356417f11bf63 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 30 Jan 2024 02:24:08 -0500 Subject: [PATCH 14/16] Update geofence message in the app. #787 --- src/Controller/CustomerAppAPI/ApiController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controller/CustomerAppAPI/ApiController.php b/src/Controller/CustomerAppAPI/ApiController.php index 6a25eb80..fdc0ec59 100644 --- a/src/Controller/CustomerAppAPI/ApiController.php +++ b/src/Controller/CustomerAppAPI/ApiController.php @@ -162,6 +162,6 @@ class ApiController extends BaseApiController protected function getGeoErrorMessage() { - return 'Oops! Our service is limited to some areas in Metro Manila, Laguna, Cavite, Pampanga and Baguio only. We will update you as soon as we are able to cover your area'; + return 'Our services are currently limited to some areas in Metro Manila, Baguio, Batangas, Laguna, Cavite, Pampanga, and Palawan. We will update you as soon as we are available in your area. Thank you for understanding. Keep safe!'; } } From 33eaf9bbff1965ce6b65714bb332dae77f86b90a Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Wed, 31 Jan 2024 22:05:42 +0800 Subject: [PATCH 15/16] Fix transaction origin list to replace existing facebook and hotline with manila entries #784 --- src/Ramcar/TransactionOrigin.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Ramcar/TransactionOrigin.php b/src/Ramcar/TransactionOrigin.php index 2a742c0a..7f459e96 100644 --- a/src/Ramcar/TransactionOrigin.php +++ b/src/Ramcar/TransactionOrigin.php @@ -17,17 +17,17 @@ class TransactionOrigin extends NameValue const YOKOHAMA_TWITTER = 'yokohama_twitter'; const YOKOHAMA_INSTAGRAM = 'yokohama_instagram'; const YOKOHAMA_CAROUSELL = 'yokohama_carousell'; - const HOTLINE_MANILA = 'hotline_manila'; const HOTLINE_CEBU = 'hotline_cebu'; - const FACEBOOK_MANILA = 'facebook_manila'; const FACEBOOK_CEBU = 'facebook_cebu'; // TODO: for now, resq also gets the walk-in option // resq also gets new YOKOHAMA options const COLLECTION = [ - 'call' => 'Hotline', + 'call' => 'Hotline Manila', + 'hotline_cebu' => 'Hotline Cebu', 'online' => 'Online', - 'facebook' => 'Facebook', + 'facebook' => 'Facebook Manila', + 'facebook_cebu' => 'Facebook Cebu', 'vip' => 'VIP', 'mobile_app' => 'Mobile App', 'walk_in' => 'Walk-in', @@ -37,10 +37,6 @@ class TransactionOrigin extends NameValue 'yokohama_op_facebook' => 'Yokohama OP Facebook', 'yokohama_twitter' => 'Yokohama Twitter', 'yokohama_instagram' => 'Yokohama Instagram', - 'yokohama_carousell' => 'Yokohama Carousell', - 'hotline_manila' => 'Hotline Manila', - 'hotline_cebu' => 'Hotline Cebu', - 'facebook_manila' => 'Facebook Manila', - 'facebook_cebu' => 'Facebook Cebu' + 'yokohama_carousell' => 'Yokohama Carousell' ]; } From 0e5365a0151ed4d5c0506553b0dd878d2f287520 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 31 Jan 2024 20:13:41 -0500 Subject: [PATCH 16/16] Comment out geofence message when viewing JO. Initialize branch_codes array. #788 --- src/Service/JobOrderHandler/ResqJobOrderHandler.php | 1 + templates/job-order/form.view.html.twig | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index 38571fdd..ed10c764 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -2910,6 +2910,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface $params['status_cancelled'] = JOStatus::CANCELLED; $params['hubs'] = []; + $branch_codes = []; // format duration and distance into friendly time foreach ($hubs as $hub) { // duration diff --git a/templates/job-order/form.view.html.twig b/templates/job-order/form.view.html.twig index cc463f11..33d6fc5b 100644 --- a/templates/job-order/form.view.html.twig +++ b/templates/job-order/form.view.html.twig @@ -635,6 +635,8 @@ $(function() { function selectPoint(lat, lng) { // check if point is in coverage area + // commenting out the geofence call for CRM + /* $.ajax({ method: "GET", url: "{{ url('jo_geofence') }}", @@ -652,7 +654,7 @@ $(function() { type: 'warning', }); } - }); + }); */ // clear markers markerLayerGroup.clearLayers();