Resolve "Regional pricing" #1703
10 changed files with 141 additions and 16 deletions
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
58
src/Service/PriceTierManager.php
Normal file
58
src/Service/PriceTierManager.php
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use CrEOF\Spatial\PHP\Types\Geometry\Point;
|
||||
|
||||
use App\Entity\PriceTier;
|
||||
|
||||
class PriceTierManager
|
||||
{
|
||||
protected $em;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue