Merge branch '783-rider-app-trade-in-support' into 'master'
Resolve "Rider app trade-in support" Closes #783 See merge request jankstudio/resq!912
This commit is contained in:
commit
b19d9c203a
68 changed files with 4218 additions and 141 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -12,3 +12,6 @@
|
|||
|
||||
*.swp
|
||||
/public/warranty_uploads/*
|
||||
.vscode
|
||||
*__pycache__
|
||||
/public/assets/images/insurance-premiums.png
|
||||
|
|
@ -634,6 +634,45 @@ catalyst_auth:
|
|||
- id: service_offering.delete
|
||||
label: Delete
|
||||
|
||||
- id: price_tier
|
||||
label: Price Tier
|
||||
acls:
|
||||
- id: price_tier.menu
|
||||
label: Menu
|
||||
- id: price_tier.list
|
||||
label: List
|
||||
- id: price_tier.add
|
||||
label: Add
|
||||
- id: price_tier.update
|
||||
label: Update
|
||||
- id: price_tier.delete
|
||||
label: Delete
|
||||
|
||||
- id: item_type
|
||||
label: Item Type
|
||||
acls:
|
||||
- id: item_type.menu
|
||||
label: Menu
|
||||
- id: item_type.list
|
||||
label: List
|
||||
- id: item_type.add
|
||||
label: Add
|
||||
- id: item_type.update
|
||||
label: Update
|
||||
- id: item_type.delete
|
||||
label: Delete
|
||||
|
||||
- id: item
|
||||
label: Item
|
||||
acls:
|
||||
- id: item.menu
|
||||
label: Menu
|
||||
- id: item_pricing
|
||||
label: Item Pricing
|
||||
acls:
|
||||
- id: item_pricing.update
|
||||
label: Update
|
||||
|
||||
api:
|
||||
user_entity: "App\\Entity\\ApiUser"
|
||||
acl_data:
|
||||
|
|
@ -712,6 +751,16 @@ catalyst_auth:
|
|||
acls:
|
||||
- id: warrantyserial.upload
|
||||
label: Upload
|
||||
- id: hub
|
||||
label: Hub Access
|
||||
acls:
|
||||
- id: hub.list
|
||||
label: List
|
||||
- id: joborder
|
||||
label: Job Order Access
|
||||
acls:
|
||||
- id: joborder.find
|
||||
label: Find Job Order
|
||||
|
||||
- id: tapi_vmanufacturer
|
||||
label: Third Party Vehicle Manufacturer Access
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ catalyst_menu:
|
|||
acl: support.menu
|
||||
label: '[menu.support]'
|
||||
icon: flaticon-support
|
||||
order: 10
|
||||
order: 11
|
||||
- id: customer_list
|
||||
acl: customer.list
|
||||
label: '[menu.support.customers]'
|
||||
|
|
@ -223,7 +223,7 @@ catalyst_menu:
|
|||
acl: service.menu
|
||||
label: '[menu.service]'
|
||||
icon: flaticon-squares
|
||||
order: 11
|
||||
order: 12
|
||||
- id: service_list
|
||||
acl: service.list
|
||||
label: '[menu.service.services]'
|
||||
|
|
@ -233,7 +233,7 @@ catalyst_menu:
|
|||
acl: partner.menu
|
||||
label: '[menu.partner]'
|
||||
icon: flaticon-network
|
||||
order: 12
|
||||
order: 13
|
||||
- id: partner_list
|
||||
acl: partner.list
|
||||
label: '[menu.partner.partners]'
|
||||
|
|
@ -247,7 +247,7 @@ catalyst_menu:
|
|||
acl: motolite_event.menu
|
||||
label: '[menu.motolite_event]'
|
||||
icon: flaticon-event-calendar-symbol
|
||||
order: 13
|
||||
order: 14
|
||||
- id: motolite_event_list
|
||||
acl: motolite_event.list
|
||||
label: '[menu.motolite_event.events]'
|
||||
|
|
@ -257,7 +257,7 @@ catalyst_menu:
|
|||
acl: analytics.menu
|
||||
label: '[menu.analytics]'
|
||||
icon: flaticon-graphic
|
||||
order: 14
|
||||
order: 15
|
||||
- id: analytics_forecast_form
|
||||
acl: analytics.forecast
|
||||
label: '[menu.analytics.forecasting]'
|
||||
|
|
@ -267,7 +267,7 @@ catalyst_menu:
|
|||
acl: database.menu
|
||||
label: '[menu.database]'
|
||||
icon: fa fa-database
|
||||
order: 15
|
||||
order: 16
|
||||
- id: ticket_type_list
|
||||
acl: ticket_type.menu
|
||||
label: '[menu.database.tickettypes]'
|
||||
|
|
@ -288,3 +288,21 @@ catalyst_menu:
|
|||
acl: service_offering.menu
|
||||
label: '[menu.database.serviceofferings]'
|
||||
parent: database
|
||||
- id: item_type_list
|
||||
acl: item_type.menu
|
||||
label: '[menu.database.itemtypes]'
|
||||
parent: database
|
||||
|
||||
- id: item
|
||||
acl: item.menu
|
||||
label: Item Management
|
||||
icon: fa fa-boxes
|
||||
order: 10
|
||||
- id: price_tier_list
|
||||
acl: price_tier.list
|
||||
label: Price Tiers
|
||||
parent: item
|
||||
- id: item_pricing
|
||||
acl: item_pricing.update
|
||||
label: Item Pricing
|
||||
parent: item
|
||||
|
|
|
|||
|
|
@ -303,3 +303,13 @@ apiv2_insurance_application_create:
|
|||
path: /apiv2/insurance/application
|
||||
controller: App\Controller\CustomerAppAPI\InsuranceController::createApplication
|
||||
methods: [POST]
|
||||
|
||||
apiv2_insurance_premiums_banner:
|
||||
path: /apiv2/insurance/premiums_banner
|
||||
controller: App\Controller\CustomerAppAPI\InsuranceController::getPremiumsBanner
|
||||
methods: [GET]
|
||||
|
||||
apiv2_insurance_body_types:
|
||||
path: /apiv2/insurance/body_types
|
||||
controller: App\Controller\CustomerAppAPI\InsuranceController::getBodyTypes
|
||||
methods: [GET]
|
||||
|
|
@ -194,3 +194,16 @@ capi_warranty_serial_upload:
|
|||
path: /capi/warranty_serial/upload
|
||||
controller: App\Controller\CAPI\WarrantySerialController::uploadWarrantySerialFile
|
||||
methods: [POST]
|
||||
|
||||
# pullout form system
|
||||
# hub
|
||||
capi_hub_list:
|
||||
path: /capi/hubs
|
||||
controller: App\Controller\CAPI\HubController::getAll
|
||||
methods: [GET]
|
||||
|
||||
# job order details
|
||||
capi_job_order:
|
||||
path: /capi/job_order/{id}
|
||||
controller: App\Controller\CAPI\JobOrderController::getJobOrder
|
||||
methods: [GET]
|
||||
|
|
|
|||
|
|
@ -94,3 +94,24 @@ capi_rider_jo_start:
|
|||
path: /rider_api/start
|
||||
controller: App\Controller\CAPI\RiderAppController::startJobOrder
|
||||
methods: [POST]
|
||||
|
||||
# trade-ins
|
||||
capi_rider_battery_sizes:
|
||||
path: /rider_api/battery_sizes
|
||||
controller: App\Controller\CAPI\RiderAppController::getBatterySizes
|
||||
methods: [GET]
|
||||
|
||||
capi_rider_trade_in_types:
|
||||
path: /rider_api/trade_in_types
|
||||
controller: App\Controller\CAPI\RiderAppController::getTradeInTypes
|
||||
methods: [GET]
|
||||
|
||||
capi_rider_battery_info:
|
||||
path: /rider_api/battery/{serial}
|
||||
controller: App\Controller\CAPI\RiderAppController::getBatteryInfo
|
||||
methods: [GET]
|
||||
|
||||
capi_rider_update_jo:
|
||||
path: /rider_api/job_order/update
|
||||
controller: App\Controller\CAPI\RiderAppController::updateJobOrder
|
||||
methods: [POST]
|
||||
|
|
|
|||
14
config/routes/item_pricing.yaml
Normal file
14
config/routes/item_pricing.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
item_pricing:
|
||||
path: /item-pricing
|
||||
controller: App\Controller\ItemPricingController::index
|
||||
methods: [GET]
|
||||
|
||||
item_pricing_update:
|
||||
path: /item-pricing
|
||||
controller: App\Controller\ItemPricingController::formSubmit
|
||||
methods: [POST]
|
||||
|
||||
item_pricing_prices:
|
||||
path: /item-pricing/{pt_id}/{it_id}/prices
|
||||
controller: App\Controller\ItemPricingController::itemPrices
|
||||
methods: [GET]
|
||||
34
config/routes/item_type.yaml
Normal file
34
config/routes/item_type.yaml
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
item_type_list:
|
||||
path: /item-types
|
||||
controller: App\Controller\ItemTypeController::index
|
||||
methods: [GET]
|
||||
|
||||
item_type_rows:
|
||||
path: /item-types/rowdata
|
||||
controller: App\Controller\ItemTypeController::datatableRows
|
||||
methods: [POST]
|
||||
|
||||
item_type_add_form:
|
||||
path: /item-types/newform
|
||||
controller: App\Controller\ItemTypeController::addForm
|
||||
methods: [GET]
|
||||
|
||||
item_type_add_submit:
|
||||
path: /item-types
|
||||
controller: App\Controller\ItemTypeController::addSubmit
|
||||
methods: [POST]
|
||||
|
||||
item_type_update_form:
|
||||
path: /item-types/{id}
|
||||
controller: App\Controller\ItemTypeController::updateForm
|
||||
methods: [GET]
|
||||
|
||||
item_type_update_submit:
|
||||
path: /item-types/{id}
|
||||
controller: App\Controller\ItemTypeController::updateSubmit
|
||||
methods: [POST]
|
||||
|
||||
item_type_delete:
|
||||
path: /item-types/{id}
|
||||
controller: App\Controller\ItemTypeController::deleteSubmit
|
||||
methods: [DELETE]
|
||||
34
config/routes/price_tier.yaml
Normal file
34
config/routes/price_tier.yaml
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
price_tier_list:
|
||||
path: /price-tiers
|
||||
controller: App\Controller\PriceTierController::index
|
||||
methods: [GET]
|
||||
|
||||
price_tier_rows:
|
||||
path: /price-tiers/rows
|
||||
controller: App\Controller\PriceTierController::datatableRows
|
||||
methods: [POST]
|
||||
|
||||
price_tier_add_form:
|
||||
path: /price-tiers/newform
|
||||
controller: App\Controller\PriceTierController::addForm
|
||||
methods: [GET]
|
||||
|
||||
price_tier_add_submit:
|
||||
path: /price-tiers
|
||||
controller: App\Controller\PriceTierController::addSubmit
|
||||
methods: [POST]
|
||||
|
||||
price_tier_update_form:
|
||||
path: /price-tiers/{id}
|
||||
controller: App\Controller\PriceTierController::updateForm
|
||||
methods: [GET]
|
||||
|
||||
price_tier_update_submit:
|
||||
path: /price-tiers/{id}
|
||||
controller: App\Controller\PriceTierController::updateSubmit
|
||||
methods: [POST]
|
||||
|
||||
price_tier_delete:
|
||||
path: /price-tiers/{id}
|
||||
controller: App\Controller\PriceTierController::deleteSubmit
|
||||
methods: [DELETE]
|
||||
|
|
@ -51,7 +51,7 @@ tapi_vehicle_make_list:
|
|||
tapi_battery_list:
|
||||
path: /tapi/vehicles/{vid}/compatible_batteries
|
||||
controller: App\Controller\TAPI\BatteryController::getCompatibleBatteries
|
||||
methods: [GET]
|
||||
methods: [POST]
|
||||
|
||||
# promos
|
||||
tapi_promo_list:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ parameters:
|
|||
api_version: "%env(API_VERSION)%"
|
||||
android_app_version: "%env(ANDROID_APP_VERSION)%"
|
||||
ios_app_version: "%env(IOS_APP_VERSION)%"
|
||||
insurance_premiums_banner_url: "%env(INSURANCE_PREMIUMS_BANNER_URL)%"
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
|
|
@ -310,3 +311,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"
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ class APIRoleController extends Controller
|
|||
protected function padAPIACLHierarchy(&$params)
|
||||
{
|
||||
// get acl keys hierarchy
|
||||
$api_acl_data = $this->api_acl_gen->getACL();
|
||||
$api_acl_data = $this->api_acl_gen->getACL('api');
|
||||
$params['api_acl_hierarchy'] = $api_acl_data['hierarchy'];
|
||||
}
|
||||
|
||||
|
|
|
|||
53
src/Controller/CAPI/HubController.php
Normal file
53
src/Controller/CAPI/HubController.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller\CAPI;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Catalyst\ApiBundle\Controller\ApiController;
|
||||
use Catalyst\ApiBundle\Component\Response as APIResponse;
|
||||
|
||||
use App\Entity\Hub;
|
||||
|
||||
use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator;
|
||||
|
||||
class HubController extends ApiController
|
||||
{
|
||||
protected $acl_gen;
|
||||
|
||||
public function __construct(ACLGenerator $acl_gen)
|
||||
{
|
||||
$this->acl_gen = $acl_gen;
|
||||
}
|
||||
|
||||
public function getAll(EntityManagerInterface $em)
|
||||
{
|
||||
// get all hub data order by name
|
||||
$this->denyAccessUnlessGranted('hub.list', null, 'No access.');
|
||||
|
||||
$results = $em->getRepository(Hub::class)->findBy([], ['name' => 'ASC']);
|
||||
|
||||
$hubs = [];
|
||||
foreach($results as $res)
|
||||
{
|
||||
$hub_id = $res->getId();
|
||||
$hub_name = $res->getName();
|
||||
$hub_address = $res->getAddress();
|
||||
$hub_branch_code = $res->getBranchCode();
|
||||
|
||||
$hubs[$hub_id] = [
|
||||
'id' => $hub_id,
|
||||
'name' => $hub_name,
|
||||
'address' => $hub_address,
|
||||
'branch_code' => $hub_branch_code,
|
||||
];
|
||||
}
|
||||
|
||||
$data = [
|
||||
'hubs' => $hubs,
|
||||
];
|
||||
return new APIResponse(true, 'Hubs loaded.', $data);
|
||||
}
|
||||
}
|
||||
139
src/Controller/CAPI/JobOrderController.php
Normal file
139
src/Controller/CAPI/JobOrderController.php
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller\CAPI;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Catalyst\ApiBundle\Controller\ApiController;
|
||||
use Catalyst\ApiBundle\Component\Response as APIResponse;
|
||||
|
||||
use App\Entity\JobOrder;
|
||||
use App\Entity\Warranty;
|
||||
|
||||
use App\Ramcar\JOStatus;
|
||||
|
||||
use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator;
|
||||
|
||||
class JobOrderController extends ApiController
|
||||
{
|
||||
protected $acl_gen;
|
||||
|
||||
public function __construct(ACLGenerator $acl_gen)
|
||||
{
|
||||
$this->acl_gen = $acl_gen;
|
||||
}
|
||||
|
||||
public function getJobOrder($id, EntityManagerInterface $em)
|
||||
{
|
||||
$this->denyAccessUnlessGranted('joborder.find', null, 'No access.');
|
||||
|
||||
$jo = $em->getRepository(JobOrder::class)->find($id);
|
||||
|
||||
if ($jo == null)
|
||||
return new APIResponse(false, 'No job order found with that number.', null, 404);
|
||||
|
||||
$data = $this->generateJobOrderData($jo, $em);
|
||||
|
||||
return new APIResponse(true, 'Job order found.', $data);
|
||||
}
|
||||
|
||||
protected function generateJobOrderData($jo, EntityManagerInterface $em)
|
||||
{
|
||||
// customer vehicle
|
||||
$cv = $jo->getCustomerVehicle();
|
||||
|
||||
// customer information
|
||||
$customer = $jo->getCustomer();
|
||||
|
||||
// hub
|
||||
$hub_name = '';
|
||||
$hub = $jo->getHub();
|
||||
if ($hub != null)
|
||||
$hub_name = $hub->getName();
|
||||
|
||||
// check if JO is fulfilled, if not, we leave date_purchase blank
|
||||
$date_purchase = '';
|
||||
$serial = '';
|
||||
$status = $jo->getStatus();
|
||||
if ($status == JOStatus::FULFILLED)
|
||||
{
|
||||
if ($jo->getDateFulfill() != null)
|
||||
$date_purchase = $jo->getDateFulfill()->format('M d, Y H:i');
|
||||
|
||||
// find warranty to get the serial using plate number
|
||||
$serial = $this->getSerialFromWarranty($cv->getPlateNumber(), $em);
|
||||
}
|
||||
|
||||
$jo_data = [
|
||||
'id' => $jo->getID(),
|
||||
'first_name' => $customer->getFirstName(),
|
||||
'last_name' => $customer->getLastName(),
|
||||
'mobile_number' => $customer->getPhoneMobile(),
|
||||
'email' => $customer->getEmail(),
|
||||
'plate_number' => $cv->getPlateNumber(),
|
||||
'date_purchase' => $date_purchase,
|
||||
'address' => $jo->getDeliveryAddress(),
|
||||
'hub' => $hub_name,
|
||||
'serial' => $serial,
|
||||
];
|
||||
|
||||
// invoice items
|
||||
$items = [];
|
||||
$jo_items = $jo->getInvoice()->getItems();
|
||||
$non_battery_item_titles = ['Promo discount', 'Trade-in', 'Service'];
|
||||
foreach ($jo_items as $item)
|
||||
{
|
||||
$item_title = $item->getTitle();
|
||||
|
||||
// check if title has Promo discount, Trade-in, or Service
|
||||
$flag_battery = $this->checkIfBatteryInvoiceItem($item_title, $non_battery_item_titles);
|
||||
if ($flag_battery == true)
|
||||
{
|
||||
$items[] = [
|
||||
'title' => $item->getTitle(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$jo_data['items'] = $items;
|
||||
|
||||
return $jo_data;
|
||||
}
|
||||
|
||||
protected function checkIfBatteryInvoiceItem($item_title, $non_battery_item_titles)
|
||||
{
|
||||
foreach ($non_battery_item_titles as $nb_item_title)
|
||||
{
|
||||
$pos_result = stripos($item_title, $nb_item_title);
|
||||
|
||||
// if found, invoice item is not a battery item
|
||||
if ($pos_result !== false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getSerialFromWarranty($plate_number, EntityManagerInterface $em)
|
||||
{
|
||||
// NOTE: Modify the search for the latest warranty. This seems hacky.
|
||||
// get latest warranty using plate number
|
||||
$warranty_results = $em->getRepository(Warranty::class)->findBy(
|
||||
['plate_number' => $plate_number],
|
||||
['date_create' => 'desc']
|
||||
);
|
||||
|
||||
$serial = '';
|
||||
if (!empty($warranty_results))
|
||||
{
|
||||
// get first entry
|
||||
$warranty = current($warranty_results);
|
||||
|
||||
$serial = $warranty->getSerial();
|
||||
}
|
||||
|
||||
return $serial;
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,9 @@ use App\Entity\BatterySize;
|
|||
use App\Entity\RiderAPISession;
|
||||
use App\Entity\User;
|
||||
use App\Entity\ApiUser as APIUser;
|
||||
|
||||
use App\Entity\JobOrder;
|
||||
use App\Entity\SAPBattery;
|
||||
use App\Entity\WarrantySerial;
|
||||
use App\Service\RedisClientProvider;
|
||||
use App\Service\RiderCache;
|
||||
use App\Service\MQTTClient;
|
||||
|
|
@ -34,6 +36,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;
|
||||
|
|
@ -286,8 +289,9 @@ class RiderAppController extends ApiController
|
|||
|
||||
// do we have a job order?
|
||||
// $jo = $rider->getActiveJobOrder();
|
||||
// NOTE: we do not include job orders that have been cancelled
|
||||
$jo = $rider->getCurrentJobOrder();
|
||||
if ($jo == null)
|
||||
if ($jo == null || $jo->getStatus() == JOStatus::CANCELLED)
|
||||
{
|
||||
$data = [
|
||||
'job_order' => null
|
||||
|
|
@ -408,6 +412,9 @@ class RiderAppController extends ApiController
|
|||
if (!empty($msg))
|
||||
return new APIResponse(false, $msg);
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
|
||||
// TODO: refactor this into a jo handler class, so we don't have to repeat for control center
|
||||
|
||||
// set jo status to in transit
|
||||
|
|
@ -458,6 +465,9 @@ class RiderAppController extends ApiController
|
|||
// TODO: this is a workaround for requeue, because rider app gets stuck in accept / decline screen
|
||||
return new APIResponse(true, $msg);
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
|
||||
// requeue it, instead of cancelling it
|
||||
$jo->requeue();
|
||||
|
||||
|
|
@ -516,6 +526,9 @@ class RiderAppController extends ApiController
|
|||
// get rider's current job order
|
||||
$jo = $rider->getCurrentJobOrder();
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB);
|
||||
|
||||
|
|
@ -556,6 +569,9 @@ class RiderAppController extends ApiController
|
|||
// get rider's current job order
|
||||
$jo = $rider->getCurrentJobOrder();
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB_PRE_JO);
|
||||
|
||||
|
|
@ -596,6 +612,9 @@ class RiderAppController extends ApiController
|
|||
// get rider's current job order
|
||||
$jo = $rider->getCurrentJobOrder();
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB_PRE_JO);
|
||||
|
||||
|
|
@ -636,6 +655,9 @@ class RiderAppController extends ApiController
|
|||
// get rider's current job order
|
||||
$jo = $rider->getCurrentJobOrder();
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_START);
|
||||
|
||||
|
|
@ -677,6 +699,9 @@ class RiderAppController extends ApiController
|
|||
// set jo status to in progress
|
||||
$jo->setStatus(JOStatus::IN_PROGRESS);
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE);
|
||||
|
||||
|
|
@ -735,6 +760,9 @@ class RiderAppController extends ApiController
|
|||
// get rider's current job order
|
||||
$jo = $rider->getCurrentJobOrder();
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB);
|
||||
|
||||
|
|
@ -758,6 +786,54 @@ class RiderAppController extends ApiController
|
|||
return new APIResponse(true, 'Rider arrive at hub.', $data);
|
||||
}
|
||||
|
||||
public function getBatterySizes(Request $req, EntityManagerInterface $em)
|
||||
{
|
||||
// get capi user
|
||||
$capi_user = $this->getUser();
|
||||
if ($capi_user == null)
|
||||
return new APIResponse(false, 'User not found.');
|
||||
|
||||
// get rider id from capi user metadata
|
||||
$rider = $this->getRiderFromCAPI($capi_user, $em);
|
||||
if ($rider == null)
|
||||
return new APIResponse(false, 'No rider found.');
|
||||
|
||||
// get sizes
|
||||
$qb = $em->getRepository(BatterySize::class)
|
||||
->createQueryBuilder('bs');
|
||||
|
||||
$sizes = $qb->select('bs.id, bs.name')
|
||||
->orderBy('bs.name', 'asc')
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
// response
|
||||
return new APIResponse(true, '', [
|
||||
'sizes' => $sizes,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getTradeInTypes(Request $req, EntityManagerInterface $em)
|
||||
{
|
||||
// get capi user
|
||||
$capi_user = $this->getUser();
|
||||
if ($capi_user == null)
|
||||
return new APIResponse(false, 'User not found.');
|
||||
|
||||
// get rider id from capi user metadata
|
||||
$rider = $this->getRiderFromCAPI($capi_user, $em);
|
||||
if ($rider == null)
|
||||
return new APIResponse(false, 'No rider found.');
|
||||
|
||||
// get trade-in types
|
||||
$types = TradeInType::getCollection();
|
||||
|
||||
// response
|
||||
return new APIResponse(true, '', [
|
||||
'types' => $types,
|
||||
]);
|
||||
}
|
||||
|
||||
public function payment(Request $req, EntityManagerInterface $em, JobOrderHandlerInterface $jo_handler,
|
||||
RisingTideGateway $rt, WarrantyHandler $wh, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient, TranslatorInterface $translator)
|
||||
{
|
||||
|
|
@ -777,6 +853,20 @@ class RiderAppController extends ApiController
|
|||
if (!empty($msg))
|
||||
return new APIResponse(false, $msg);
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
|
||||
// need to check if service type is battery sales
|
||||
// if so, serial is a required parameter
|
||||
$serial = $req->request->get('serial', '');
|
||||
if ($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW)
|
||||
{
|
||||
/*
|
||||
if (empty($serial))
|
||||
return new APIResponse(false, 'Missing parameter(s): serial');
|
||||
*/
|
||||
}
|
||||
|
||||
// set invoice to paid
|
||||
$jo->getInvoice()->setStatus(InvoiceStatus::PAID);
|
||||
|
||||
|
|
@ -828,7 +918,6 @@ class RiderAppController extends ApiController
|
|||
// create warranty
|
||||
if($jo_handler->checkIfNewBattery($jo))
|
||||
{
|
||||
$serial = null;
|
||||
$warranty_class = $jo->getWarrantyClass();
|
||||
$first_name = $jo->getCustomer()->getFirstName();
|
||||
$last_name = $jo->getCustomer()->getLastName();
|
||||
|
|
@ -912,6 +1001,9 @@ class RiderAppController extends ApiController
|
|||
// get rider's current job order
|
||||
$jo = $rider->getCurrentJobOrder();
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB_POST_JO);
|
||||
|
||||
|
|
@ -953,6 +1045,9 @@ class RiderAppController extends ApiController
|
|||
// get rider's current job order
|
||||
$jo = $rider->getCurrentJobOrder();
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB_POST_JO);
|
||||
|
||||
|
|
@ -1099,7 +1194,167 @@ class RiderAppController extends ApiController
|
|||
return new APIResponse(true, 'Batteries found.', $data);
|
||||
}
|
||||
|
||||
public function changeService(Request $req, EntityManagerInterface $em, InvoiceGeneratorInterface $ic)
|
||||
public function getBatteryInfo(Request $req, $serial, EntityManagerInterface $em)
|
||||
{
|
||||
if (empty($serial))
|
||||
{
|
||||
return new APIResponse(false, 'Missing parameter(s): serial');
|
||||
}
|
||||
|
||||
// get capi user
|
||||
$capi_user = $this->getUser();
|
||||
if ($capi_user == null)
|
||||
return new APIResponse(false, 'User not found.');
|
||||
|
||||
// get rider id from capi user metadata
|
||||
$rider = $this->getRiderFromCAPI($capi_user, $em);
|
||||
if ($rider == null)
|
||||
return new APIResponse(false, 'No rider found.');
|
||||
|
||||
// find battery given serial/sap_code and flag_active is true
|
||||
$serial = $em->getRepository(WarrantySerial::class)->find($serial);
|
||||
|
||||
if (empty($serial)) {
|
||||
return new APIResponse(false, 'Warranty serial number not found.');
|
||||
}
|
||||
|
||||
$sap_battery = $em->getRepository(SAPBattery::class)->find($serial->getSKU());
|
||||
|
||||
if (empty($sap_battery)) {
|
||||
return new APIResponse(false, 'No battery info found.');
|
||||
}
|
||||
|
||||
$battery = [
|
||||
'id' => $sap_battery->getID(),
|
||||
'brand' => $sap_battery->getBrand()->getName(),
|
||||
'size' => $sap_battery->getSize()->getName(),
|
||||
'size_id' => $sap_battery->getSize()->getID(),
|
||||
'trade_in_type' => TradeInType::MOTOLITE,
|
||||
'container_size' => $sap_battery->getContainerSize()->getName(),
|
||||
];
|
||||
|
||||
return new APIResponse(true, 'Battery info found.', [
|
||||
'battery' => $battery,
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateJobOrder(Request $req, EntityManagerInterface $em, InvoiceGeneratorInterface $ic, PriceTierManager $pt_manager)
|
||||
{
|
||||
$items = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
// get job order id
|
||||
if (!isset($items['jo_id']))
|
||||
return new APIResponse(false, 'Missing parameter(s): jo_id');
|
||||
|
||||
// validate jo_id
|
||||
$jo_id = $items['jo_id'];
|
||||
if (empty($jo_id) || $jo_id == null)
|
||||
return new APIResponse(false, 'Missing parameter(s): jo_id');
|
||||
|
||||
// get capi user
|
||||
$capi_user = $this->getUser();
|
||||
if ($capi_user == null)
|
||||
return new APIResponse(false, 'User not found.');
|
||||
|
||||
// get rider id from capi user metadata
|
||||
$rider = $this->getRiderFromCAPI($capi_user, $em);
|
||||
if ($rider == null)
|
||||
return new APIResponse(false, 'No rider found.');
|
||||
|
||||
// get the job order
|
||||
$jo = $em->getRepository(JobOrder::class)->find($jo_id);
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
|
||||
// check if we have trade in items
|
||||
$ti_items = [];
|
||||
if (isset($items['trade_in_items']))
|
||||
{
|
||||
// validate the trade in items first
|
||||
$ti_items = $items['trade_in_items'];
|
||||
$msg = $this->validateTradeInItems($em, $ti_items);
|
||||
if (!empty($msg))
|
||||
return new APIResponse(false, $msg);
|
||||
}
|
||||
|
||||
// get the service type
|
||||
if (!isset($items['stype_id']))
|
||||
return new APIResponse(false, 'Missing parameter(s): stype_id');
|
||||
|
||||
// validate service type
|
||||
$stype_id = $items['stype_id'];
|
||||
if (!ServiceType::validate($stype_id))
|
||||
return new APIResponse(false, 'Invalid service type - ' . $stype_id);
|
||||
|
||||
// save service type
|
||||
$jo->setServiceType($stype_id);
|
||||
|
||||
// validate promo if any. Promo not required
|
||||
$promo = null;
|
||||
if (isset($items['promo_id']))
|
||||
{
|
||||
$promo_id = $items['promo_id'];
|
||||
$promo = $em->getRepository(Promo::class)->find($promo_id);
|
||||
if ($promo == null)
|
||||
return new APIResponse(false, 'Invalid promo id - ' . $promo_id);
|
||||
}
|
||||
|
||||
// get other parameters, if any: has motolite battery, has warranty doc, with coolant, payment method
|
||||
if (isset($items['flag_motolite_battery']))
|
||||
{
|
||||
// get customer vehicle from jo
|
||||
$cv = $jo->getCustomerVehicle();
|
||||
$has_motolite = $items['flag_motolite_battery'];
|
||||
if ($has_motolite == 'true')
|
||||
$cv->setHasMotoliteBattery(true);
|
||||
else
|
||||
$cv->setHasMotoliteBattery(false);
|
||||
|
||||
$em->persist($cv);
|
||||
|
||||
}
|
||||
if (isset($items['flag_warranty_doc']))
|
||||
{
|
||||
// TODO: what do we do?
|
||||
}
|
||||
if (isset($items['flag_coolant']))
|
||||
{
|
||||
$has_coolant = $items['flag_coolant'];
|
||||
if ($has_coolant == 'true')
|
||||
$jo->setHasCoolant(true);
|
||||
else
|
||||
$jo->setHasCoolant(false);
|
||||
|
||||
}
|
||||
if (isset($items['mode_of_payment']))
|
||||
{
|
||||
$payment_method = $items['payment_method'];
|
||||
if (!ModeOfPayment::validate($payment_method))
|
||||
$payment_method = ModeOfPayment::CASH;
|
||||
$jo->setModeOfPayment($payment_method);
|
||||
}
|
||||
|
||||
// get capi user
|
||||
$capi_user = $this->getUser();
|
||||
if ($capi_user == null)
|
||||
return new APIResponse(false, 'User not found.');
|
||||
|
||||
// get rider id from capi user metadata
|
||||
$rider = $this->getRiderFromCAPI($capi_user, $em);
|
||||
if ($rider == null)
|
||||
return new APIResponse(false, 'No rider found.');
|
||||
|
||||
// need to get the existing invoice items using jo id and invoice id
|
||||
$existing_ii = $this->getInvoiceItems($em, $jo);
|
||||
|
||||
$this->generateUpdatedInvoice($em, $ic, $jo, $existing_ii, $ti_items, $promo, $pt_manager);
|
||||
|
||||
$data = [];
|
||||
return new APIResponse(true, 'Job order updated.', $data);
|
||||
}
|
||||
|
||||
public function changeService(Request $req, EntityManagerInterface $em, InvoiceGeneratorInterface $ic, PriceTierManager $pt_manager)
|
||||
{
|
||||
// $this->debugRequest($req);
|
||||
|
||||
|
|
@ -1120,6 +1375,9 @@ class RiderAppController extends ApiController
|
|||
if (!empty($msg))
|
||||
return new APIResponse(false, $msg);
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
|
||||
// check service type
|
||||
$stype_id = $req->request->get('stype_id');
|
||||
if (!ServiceType::validate($stype_id))
|
||||
|
|
@ -1203,6 +1461,10 @@ class RiderAppController extends ApiController
|
|||
$crit->setHasCoolant($jo->hasCoolant());
|
||||
$crit->setIsTaxable();
|
||||
|
||||
// set price tier
|
||||
$pt_id = $pt_manager->getPriceTier($jo->getCoordinates());
|
||||
$crit->setPriceTier($pt_id);
|
||||
|
||||
if ($promo != null)
|
||||
$crit->addPromo($promo);
|
||||
|
||||
|
|
@ -1241,6 +1503,164 @@ class RiderAppController extends ApiController
|
|||
return new APIResponse(true, 'Job order service changed.', $data);
|
||||
}
|
||||
|
||||
protected function generateUpdatedInvoice(EntityManagerInterface $em, InvoiceGeneratorInterface $ic, JobOrder $jo, $existing_ii, $trade_in_items, $promo, PriceTierManager $pt_manager)
|
||||
{
|
||||
// get the service type
|
||||
$stype = $jo->getServiceType();
|
||||
|
||||
// get the source
|
||||
$source = $jo->getSource();
|
||||
|
||||
// get the customer vehicle
|
||||
$cv = $jo->getCustomerVehicle();
|
||||
|
||||
// get coolant if any
|
||||
$flag_coolant = $jo->hasCoolant();
|
||||
|
||||
// check if new promo is null
|
||||
if ($promo == null)
|
||||
{
|
||||
// promo not updated from app so check existing invoice
|
||||
// get the promo id from existing invoice item
|
||||
$promo_id = $existing_ii['promo_id'];
|
||||
if ($promo_id == null)
|
||||
$promo = null;
|
||||
else
|
||||
$promo = $em->getRepository(Promo::class)->find($promo_id);
|
||||
}
|
||||
|
||||
// populate Invoice Criteria
|
||||
$icrit = new InvoiceCriteria();
|
||||
$icrit->setServiceType($stype)
|
||||
->setCustomerVehicle($cv)
|
||||
->setSource($source)
|
||||
->setHasCoolant($flag_coolant)
|
||||
->setIsTaxable();
|
||||
|
||||
// set price tier
|
||||
$pt_id = $pt_manager->getPriceTier($jo->getCoordinates());
|
||||
$icrit->setPriceTier($pt_id);
|
||||
|
||||
// at this point, all information should be valid
|
||||
// assuming JO information is already valid since this
|
||||
// is in the system already
|
||||
// add promo if any to criteria
|
||||
if ($promo != null)
|
||||
$icrit->addPromo($promo);
|
||||
|
||||
// get the battery purchased from existing invoice items
|
||||
// add the batteries ordered to criteria
|
||||
$ii_items = $existing_ii['invoice_items'];
|
||||
foreach ($ii_items as $ii_item)
|
||||
{
|
||||
$batt_id = $ii_item['batt_id'];
|
||||
$qty = $ii_item['qty'];
|
||||
|
||||
$battery = $em->getRepository(Battery::class)->find($batt_id);
|
||||
|
||||
$icrit->addEntry($battery, null, $qty);
|
||||
}
|
||||
|
||||
// add the trade in items to the criteria
|
||||
foreach ($trade_in_items as $ti_item)
|
||||
{
|
||||
$batt_size_id = $ti_item['battery_size_id'];
|
||||
$qty = $ti_item['qty'];
|
||||
$trade_in_type = $ti_item['trade_in_type'];
|
||||
|
||||
$batt_size = $em->getRepository(BatterySize::class)->find($batt_size_id);
|
||||
|
||||
$icrit->addTradeInEntry($batt_size, $trade_in_type, $qty);
|
||||
}
|
||||
|
||||
// call generateInvoice
|
||||
$invoice = $ic->generateInvoice($icrit);
|
||||
|
||||
// remove previous invoice
|
||||
$old_invoice = $jo->getInvoice();
|
||||
$em->remove($old_invoice);
|
||||
$em->flush();
|
||||
|
||||
// save new invoice
|
||||
$jo->setInvoice($invoice);
|
||||
$em->persist($invoice);
|
||||
|
||||
// log event?
|
||||
$event = new JOEvent();
|
||||
$event->setDateHappen(new DateTime())
|
||||
->setTypeID(JOEventType::RIDER_EDIT)
|
||||
->setJobOrder($jo)
|
||||
->setRider($jo->getRider());
|
||||
$em->persist($event);
|
||||
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
protected function getInvoiceItems(EntityManagerInterface $em, JobOrder $jo)
|
||||
{
|
||||
$jo_id = $jo->getID();
|
||||
$conn = $em->getConnection();
|
||||
|
||||
// need to get the ordered battery id and quantity from invoice item
|
||||
// and the promo from invoice
|
||||
$query_sql = 'SELECT ii.battery_id AS battery_id, ii.qty AS qty, i.promo_id AS promo_id
|
||||
FROM invoice_item ii, invoice i
|
||||
WHERE ii.invoice_id = i.id
|
||||
AND i.job_order_id = :jo_id
|
||||
AND ii.battery_id IS NOT NULL';
|
||||
|
||||
$query_stmt = $conn->prepare($query_sql);
|
||||
$query_stmt->bindValue('jo_id', $jo_id);
|
||||
|
||||
$results = $query_stmt->executeQuery();
|
||||
|
||||
$promo_id = null;
|
||||
$invoice_items = [];
|
||||
while ($row = $results->fetchAssociative())
|
||||
{
|
||||
$promo_id = $row['promo_id'];
|
||||
$invoice_items[] = [
|
||||
'batt_id' => $row['battery_id'],
|
||||
'qty' => $row['qty'],
|
||||
'trade_in' => ''
|
||||
];
|
||||
}
|
||||
|
||||
$data = [
|
||||
'promo_id' => $promo_id,
|
||||
'invoice_items' => $invoice_items
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function validateTradeInItems(EntityManagerInterface $em, $ti_items)
|
||||
{
|
||||
$msg = '';
|
||||
foreach ($ti_items as $ti_item)
|
||||
{
|
||||
$bs_id = $ti_item['battery_size_id'];
|
||||
$ti_type = $ti_item['trade_in_type'];
|
||||
|
||||
// validate the battery size id
|
||||
$batt_size = $em->getRepository(BatterySize::class)->find($bs_id);
|
||||
if ($batt_size == null)
|
||||
{
|
||||
$msg = 'Invalid battery size for trade in: ' . $bs_id;
|
||||
return $msg;
|
||||
}
|
||||
|
||||
// validate the trade in type
|
||||
if (!TradeInType::validate($ti_type))
|
||||
{
|
||||
$msg = 'Invalid trade in type: ' . $ti_type;
|
||||
return $msg;
|
||||
}
|
||||
}
|
||||
|
||||
return $msg;
|
||||
}
|
||||
|
||||
protected function getCAPIUser($id, EntityManagerInterface $em)
|
||||
{
|
||||
$capi_user = $em->getRepository(APIUser::class)->find($id);
|
||||
|
|
@ -1320,6 +1740,24 @@ class RiderAppController extends ApiController
|
|||
return $msg;
|
||||
}
|
||||
|
||||
protected function checkJOProgressionAllowed(JobOrder $jo, $rider)
|
||||
{
|
||||
// TODO: add more statuses to block if needed, hence. this is a failsafe in case MQTT is not working.
|
||||
switch ($jo->getStatus())
|
||||
{
|
||||
case JOStatus::CANCELLED:
|
||||
// if this is the rider's current JO, set to null
|
||||
if ($rider->getCurrentJobOrder() === $jo) {
|
||||
$rider->setCurrentJobOrder();
|
||||
}
|
||||
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected function debugRequest(Request $req)
|
||||
{
|
||||
$all = $req->request->all();
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use App\Ramcar\InsuranceApplicationStatus;
|
|||
use App\Ramcar\InsuranceMVType;
|
||||
use App\Ramcar\InsuranceClientType;
|
||||
use App\Ramcar\TransactionStatus;
|
||||
use App\Ramcar\InsuranceBodyType;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
|
||||
use DateTime;
|
||||
|
|
@ -293,6 +294,45 @@ class InsuranceController extends ApiController
|
|||
]);
|
||||
}
|
||||
|
||||
public function getPremiumsBanner(Request $req)
|
||||
{
|
||||
// validate params
|
||||
$validity = $this->validateRequest($req);
|
||||
|
||||
if (!$validity['is_valid']) {
|
||||
return new ApiResponse(false, $validity['error']);
|
||||
}
|
||||
|
||||
return new ApiResponse(true, '', [
|
||||
'url' => $this->getParameter('insurance_premiums_banner_url'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getBodyTypes(Request $req)
|
||||
{
|
||||
// validate params
|
||||
$validity = $this->validateRequest($req);
|
||||
|
||||
if (!$validity['is_valid']) {
|
||||
return new ApiResponse(false, $validity['error']);
|
||||
}
|
||||
|
||||
$bt_collection = InsuranceBodyType::getCollection();
|
||||
$body_types = [];
|
||||
|
||||
// NOTE: formatting it this way to match how insurance third party API returns their own stuff, so it's all handled one way on the app
|
||||
foreach ($bt_collection as $bt_key => $bt_name) {
|
||||
$body_types[] = [
|
||||
'id' => $bt_key,
|
||||
'name' => $bt_name,
|
||||
];
|
||||
}
|
||||
|
||||
return new ApiResponse(true, '', [
|
||||
'body_types' => $body_types,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getLineType($mv_type_id, $vehicle_use_type, $is_public = false)
|
||||
{
|
||||
$line = '';
|
||||
|
|
|
|||
|
|
@ -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,18 @@ class InvoiceController extends ApiController
|
|||
return new ApiResponse(false, 'No customer information found.');
|
||||
}
|
||||
|
||||
// get customer location from customer_metadata using customer id
|
||||
$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();
|
||||
$icrit->setServiceType($req->request->get('service_type'));
|
||||
|
|
@ -113,6 +129,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 +176,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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -4,16 +4,19 @@ 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\Entity\CustomerVehicle;
|
||||
use App\Entity\JobOrder;
|
||||
use App\Entity\VehicleManufacturer;
|
||||
use App\Entity\Vehicle;
|
||||
use App\Entity\ItemType;
|
||||
use App\Ramcar\JOStatus;
|
||||
use App\Ramcar\ServiceType;
|
||||
use App\Ramcar\TradeInType;
|
||||
use App\Ramcar\InsuranceApplicationStatus;
|
||||
use App\Service\PayMongoConnector;
|
||||
use App\Service\PriceTierManager;
|
||||
use DateTime;
|
||||
|
||||
class VehicleController extends ApiController
|
||||
|
|
@ -237,7 +240,7 @@ class VehicleController extends ApiController
|
|||
]);
|
||||
}
|
||||
|
||||
public function getCompatibleBatteries(Request $req, $vid)
|
||||
public function getCompatibleBatteries(Request $req, $vid, PriceTierManager $pt_manager)
|
||||
{
|
||||
// validate params
|
||||
$validity = $this->validateRequest($req);
|
||||
|
|
@ -252,11 +255,43 @@ class VehicleController extends ApiController
|
|||
return new ApiResponse(false, 'Invalid vehicle.');
|
||||
}
|
||||
|
||||
// get location from request
|
||||
$lng = $req->query->get('longitude', '');
|
||||
$lat = $req->query->get('latitude', '');
|
||||
|
||||
$batts = $vehicle->getActiveBatteries();
|
||||
$pt_id = 0;
|
||||
if ((!(empty($lng))) && (!(empty($lat))))
|
||||
{
|
||||
// get the price tier
|
||||
$coordinates = new Point($lng, $lat);
|
||||
|
||||
$pt_id = $pt_manager->getPriceTier($coordinates);
|
||||
}
|
||||
|
||||
// batteries
|
||||
$batt_list = [];
|
||||
$batts = $vehicle->getActiveBatteries();
|
||||
foreach ($batts as $batt) {
|
||||
// TODO: Add warranty_tnv to battery information
|
||||
// check if customer location is in a price tier location
|
||||
if ($pt_id == 0)
|
||||
$price = $batt->getSellingPrice();
|
||||
else
|
||||
{
|
||||
// get item type for battery
|
||||
$item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'battery']);
|
||||
if ($item_type == null)
|
||||
$price = $batt->getSellingPrice();
|
||||
else
|
||||
{
|
||||
$item_type_id = $item_type->getID();
|
||||
$batt_id = $batt->getID();
|
||||
|
||||
// find the item price given price tier id and battery id
|
||||
$price = $pt_manager->getItemPrice($pt_id, $item_type_id, $batt_id);
|
||||
}
|
||||
}
|
||||
|
||||
$batt_list[] = [
|
||||
'id' => $batt->getID(),
|
||||
'mfg_id' => $batt->getManufacturer()->getID(),
|
||||
|
|
@ -265,7 +300,7 @@ class VehicleController extends ApiController
|
|||
'model_name' => $batt->getModel()->getName(),
|
||||
'size_id' => $batt->getSize()->getID(),
|
||||
'size_name' => $batt->getSize()->getName(),
|
||||
'price' => $batt->getSellingPrice(),
|
||||
'price' => $price,
|
||||
'wty_private' => $batt->getWarrantyPrivate(),
|
||||
'wty_commercial' => $batt->getWarrantyCommercial(),
|
||||
'image_url' => $this->getBatteryImageURL($req, $batt),
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace App\Controller;
|
|||
|
||||
use App\Ramcar\InsuranceApplicationStatus;
|
||||
use App\Service\FCMSender;
|
||||
use App\Service\InsuranceConnector;
|
||||
use App\Entity\InsuranceApplication;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
|
|
@ -15,11 +16,13 @@ use DateTime;
|
|||
|
||||
class InsuranceController extends Controller
|
||||
{
|
||||
protected $ic;
|
||||
protected $em;
|
||||
protected $fcmclient;
|
||||
|
||||
public function __construct(EntityManagerInterface $em, FCMSender $fcmclient)
|
||||
public function __construct(InsuranceConnector $ic, EntityManagerInterface $em, FCMSender $fcmclient)
|
||||
{
|
||||
$this->ic = $ic;
|
||||
$this->em = $em;
|
||||
$this->fcmclient = $fcmclient;
|
||||
}
|
||||
|
|
@ -28,17 +31,8 @@ class InsuranceController extends Controller
|
|||
{
|
||||
$payload = $req->request->all();
|
||||
|
||||
// DEBUG
|
||||
@file_put_contents(__DIR__ . '/../../var/log/insurance.log', print_r($payload, true) . "\r\n----------------------------------------\r\n\r\n", FILE_APPEND);
|
||||
error_log(print_r($payload, true));
|
||||
|
||||
/*
|
||||
return $this->json([
|
||||
'success' => true,
|
||||
]);
|
||||
*/
|
||||
|
||||
// END DEBUG
|
||||
// log this callback
|
||||
$this->ic->log('CALLBACK', "[]", json_encode($payload), 'callback');
|
||||
|
||||
// if no transaction code given, silently fail
|
||||
if (empty($payload['transaction_code'])) {
|
||||
|
|
|
|||
269
src/Controller/ItemPricingController.php
Normal file
269
src/Controller/ItemPricingController.php
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
|
||||
|
||||
use Catalyst\MenuBundle\Annotation\Menu;
|
||||
|
||||
use App\Entity\PriceTier;
|
||||
use App\Entity\Battery;
|
||||
use App\Entity\ServiceOffering;
|
||||
use App\Entity\ItemType;
|
||||
use App\Entity\ItemPrice;
|
||||
|
||||
class ItemPricingController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Menu(selected="item_pricing")
|
||||
* @IsGranted("item_pricing.update")
|
||||
*/
|
||||
public function index (EntityManagerInterface $em)
|
||||
{
|
||||
// get all the price tiers
|
||||
$price_tiers = $em->getRepository(PriceTier::class)->findAll();
|
||||
|
||||
// get all item types
|
||||
$item_types = $em->getRepository(ItemType::class)->findBy([], ['name' => 'asc']);
|
||||
|
||||
// get all the items/batteries
|
||||
// load only batteries upon initial loading
|
||||
$items = $this->getBatteries($em);
|
||||
|
||||
// set the default item type to battery
|
||||
$default_it = $em->getRepository(ItemType::class)->findOneBy(['code' => 'battery']);
|
||||
|
||||
$params = [
|
||||
'sets' => [
|
||||
'price_tiers' => $price_tiers,
|
||||
'item_types' => $item_types,
|
||||
],
|
||||
'items' => $items,
|
||||
'default_item_type_id' => $default_it->getID(),
|
||||
];
|
||||
|
||||
return $this->render('item-pricing/form.html.twig', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Menu(selected="item_pricing")
|
||||
* @IsGranted("item_pricing.update")
|
||||
*/
|
||||
public function formSubmit(Request $req, EntityManagerInterface $em)
|
||||
{
|
||||
$pt_id = $req->request->get('price_tier_id');
|
||||
$it_id = $req->request->get('item_type_id');
|
||||
$prices = $req->request->get('price');
|
||||
|
||||
// get the item type
|
||||
$item_type = $em->getRepository(ItemType::class)->find($it_id);
|
||||
|
||||
if ($item_type->getCode() == 'battery')
|
||||
{
|
||||
// get batteries
|
||||
$items = $em->getRepository(Battery::class)->findBy(['flag_active' => true], ['id' => 'asc']);
|
||||
}
|
||||
else
|
||||
{
|
||||
// get service offerings
|
||||
$items = $em->getRepository(ServiceOffering::class)->findBy([], ['id' => 'asc']);
|
||||
}
|
||||
|
||||
// on default price tier
|
||||
if ($pt_id == 0)
|
||||
{
|
||||
// default price tier, update battery or service offering, depending on item type
|
||||
// NOTE: battery and service offering prices or fees are stored as decimal.
|
||||
foreach ($items as $item)
|
||||
{
|
||||
$item_id = $item->getID();
|
||||
if (isset($prices[$item_id]))
|
||||
{
|
||||
// check item type
|
||||
if ($item_type->getCode() == 'battery')
|
||||
$item->setSellingPrice($prices[$item_id]);
|
||||
else
|
||||
$item->setFee($prices[$item_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the price tier
|
||||
$price_tier = $em->getRepository(PriceTier::class)->find($pt_id);
|
||||
|
||||
$item_prices = $price_tier->getItemPrices();
|
||||
|
||||
// clear the tier's item prices for the specific item type
|
||||
foreach ($item_prices as $ip)
|
||||
{
|
||||
if ($ip->getItemType() == $item_type)
|
||||
$em->remove($ip);
|
||||
}
|
||||
|
||||
// update the tier's item prices
|
||||
foreach ($items as $item)
|
||||
{
|
||||
$item_id = $item->getID();
|
||||
|
||||
$item_price = new ItemPrice();
|
||||
|
||||
$item_price->setItemType($item_type)
|
||||
->setPriceTier($price_tier)
|
||||
->setItemID($item_id);
|
||||
|
||||
if (isset($prices[$item_id]))
|
||||
{
|
||||
$item_price->setPrice($prices[$item_id] * 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
$item_price->setPrice($item->getPrice() * 100);
|
||||
}
|
||||
|
||||
// save
|
||||
$em->persist($item_price);
|
||||
}
|
||||
}
|
||||
|
||||
$em->flush();
|
||||
|
||||
return $this->redirectToRoute('item_pricing');
|
||||
}
|
||||
|
||||
/**
|
||||
* @IsGranted("item_pricing.update")
|
||||
*/
|
||||
public function itemPrices(EntityManagerInterface $em, $pt_id, $it_id)
|
||||
{
|
||||
$pt_prices = [];
|
||||
|
||||
// get the item type
|
||||
$it = $em->getRepository(ItemType::class)->find($it_id);
|
||||
|
||||
// check if default prices are needed
|
||||
if ($pt_id != 0)
|
||||
{
|
||||
// get the price tier
|
||||
$pt = $em->getRepository(PriceTier::class)->find($pt_id);
|
||||
|
||||
// get the items under the price tier
|
||||
$pt_items = $pt->getItemPrices();
|
||||
|
||||
foreach ($pt_items as $pt_item)
|
||||
{
|
||||
// make item price hash
|
||||
$pt_prices[$pt_item->getItemID()] = $pt_item->getPrice();
|
||||
}
|
||||
}
|
||||
|
||||
// get the prices from battery or service offering, depending on item type
|
||||
if ($it->getCode() == 'battery')
|
||||
{
|
||||
// get batteries
|
||||
$items = $em->getRepository(Battery::class)->findBy(['flag_active' => true], ['id' => 'asc']);
|
||||
}
|
||||
else
|
||||
{
|
||||
// get service offerings
|
||||
$items = $em->getRepository(ServiceOffering::class)->findBy([], ['id' => 'asc']);
|
||||
}
|
||||
|
||||
$data_items = [];
|
||||
foreach ($items as $item)
|
||||
{
|
||||
$item_id = $item->getID();
|
||||
|
||||
// get default price
|
||||
if ($it->getCode() == 'battery')
|
||||
{
|
||||
$price = $item->getSellingPrice();
|
||||
$name = $item->getModel()->getName() . ' ' . $item->getSize()->getName();
|
||||
}
|
||||
else
|
||||
{
|
||||
$price = $item->getFee();
|
||||
$name = $item->getName();
|
||||
}
|
||||
|
||||
// check if tier has price for item
|
||||
if (isset($pt_prices[$item_id]))
|
||||
{
|
||||
$pt_price = $pt_prices[$item_id];
|
||||
|
||||
// actual price
|
||||
$price = number_format($pt_price / 100, 2, '.', '');
|
||||
}
|
||||
|
||||
$actual_price = $price;
|
||||
|
||||
$data_items[] = [
|
||||
'id' => $item_id,
|
||||
'name' => $name,
|
||||
'item_type_id' => $it->getID(),
|
||||
'item_type' => $it->getName(),
|
||||
'price' => $actual_price,
|
||||
];
|
||||
}
|
||||
|
||||
// response
|
||||
return new JsonResponse([
|
||||
'items' => $data_items,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getBatteries(EntityManagerInterface $em)
|
||||
{
|
||||
// get the item type for battery
|
||||
$batt_item_type = $em->getRepository(ItemType::class)->findOneBy(['code' => 'battery']);
|
||||
|
||||
// get all active batteries
|
||||
$batts = $em->getRepository(Battery::class)->findBy(['flag_active' => true], ['id' => 'asc']);
|
||||
foreach ($batts as $batt)
|
||||
{
|
||||
$batt_set[$batt->getID()] = [
|
||||
'name' => $batt->getModel()->getName() . ' ' . $batt->getSize()->getName(),
|
||||
'item_type_id' => $batt_item_type->getID(),
|
||||
'item_type' => $batt_item_type->getName(),
|
||||
'price' => $batt->getSellingPrice(),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'items' => $batt_set,
|
||||
];
|
||||
}
|
||||
|
||||
protected function getServiceOfferings(EntityeManagerInterface $em)
|
||||
{
|
||||
// get the item type for service offering
|
||||
$service_item_type = $em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']);
|
||||
|
||||
// get all service offerings
|
||||
$services = $em->getRepository(ServiceOffering::class)->findBy([], ['id' => 'asc']);
|
||||
$service_set = [];
|
||||
foreach ($services as $service)
|
||||
{
|
||||
$service_set[$service->getID()] = [
|
||||
'name' => $service->getName(),
|
||||
'item_type_id' => $service_item_type->getID(),
|
||||
'item_type' => $service_item_type->getName(),
|
||||
'price' => $service->getFee(),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'items' => $service_set,
|
||||
];
|
||||
}
|
||||
}
|
||||
251
src/Controller/ItemTypeController.php
Normal file
251
src/Controller/ItemTypeController.php
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
|
||||
|
||||
use App\Entity\ItemType;
|
||||
|
||||
use Catalyst\MenuBundle\Annotation\Menu;
|
||||
|
||||
class ItemTypeController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Menu(selected="item_type_list")
|
||||
* @IsGranted("item_type.list")
|
||||
*/
|
||||
public function index ()
|
||||
{
|
||||
return $this->render('item-type/list.html.twig');
|
||||
}
|
||||
|
||||
/**
|
||||
* @IsGranted("item_type.list")
|
||||
*/
|
||||
public function datatableRows(Request $req)
|
||||
{
|
||||
// get query builder
|
||||
$qb = $this->getDoctrine()
|
||||
->getRepository(ItemType::class)
|
||||
->createQueryBuilder('q');
|
||||
|
||||
// get datatable params
|
||||
$datatable = $req->request->get('datatable');
|
||||
|
||||
// count total records
|
||||
$tquery = $qb->select('COUNT(q)');
|
||||
$this->setQueryFilters($datatable, $tquery);
|
||||
$total = $tquery->getQuery()
|
||||
->getSingleScalarResult();
|
||||
|
||||
// get current page number
|
||||
$page = $datatable['pagination']['page'] ?? 1;
|
||||
|
||||
$perpage = $datatable['pagination']['perpage'];
|
||||
$offset = ($page - 1) * $perpage;
|
||||
|
||||
// add metadata
|
||||
$meta = [
|
||||
'page' => $page,
|
||||
'perpage' => $perpage,
|
||||
'pages' => ceil($total / $perpage),
|
||||
'total' => $total,
|
||||
'sort' => 'asc',
|
||||
'field' => 'id'
|
||||
];
|
||||
|
||||
// build query
|
||||
$query = $qb->select('q');
|
||||
$this->setQueryFilters($datatable, $query);
|
||||
|
||||
// check if sorting is present, otherwise use default
|
||||
if (isset($datatable['sort']['field']) && !empty($datatable['sort']['field'])) {
|
||||
$order = $datatable['sort']['sort'] ?? 'asc';
|
||||
$query->orderBy('q.' . $datatable['sort']['field'], $order);
|
||||
} else {
|
||||
$query->orderBy('q.id', 'asc');
|
||||
}
|
||||
|
||||
// get rows for this page
|
||||
$obj_rows = $query->setFirstResult($offset)
|
||||
->setMaxResults($perpage)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
// process rows
|
||||
$rows = [];
|
||||
foreach ($obj_rows as $orow) {
|
||||
// add row data
|
||||
$row['id'] = $orow->getID();
|
||||
$row['name'] = $orow->getName();
|
||||
|
||||
// add row metadata
|
||||
$row['meta'] = [
|
||||
'update_url' => '',
|
||||
'delete_url' => ''
|
||||
];
|
||||
|
||||
// add crud urls
|
||||
if ($this->isGranted('item_type.update'))
|
||||
$row['meta']['update_url'] = $this->generateUrl('item_type_update_form', ['id' => $row['id']]);
|
||||
if ($this->isGranted('item_type.delete'))
|
||||
$row['meta']['delete_url'] = $this->generateUrl('item_type_delete', ['id' => $row['id']]);
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
// response
|
||||
return $this->json([
|
||||
'meta' => $meta,
|
||||
'data' => $rows
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Menu(selected="item_type.list")
|
||||
* @IsGranted("item_type.add")
|
||||
*/
|
||||
public function addForm()
|
||||
{
|
||||
$item_type = new ItemType();
|
||||
$params = [
|
||||
'obj' => $item_type,
|
||||
'mode' => 'create',
|
||||
];
|
||||
|
||||
// response
|
||||
return $this->render('item-type/form.html.twig', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @IsGranted("item_type.add")
|
||||
*/
|
||||
public function addSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator)
|
||||
{
|
||||
$item_type = new ItemType();
|
||||
|
||||
$this->setObject($item_type, $req);
|
||||
|
||||
// validate
|
||||
$errors = $validator->validate($item_type);
|
||||
|
||||
// initialize error list
|
||||
$error_array = [];
|
||||
|
||||
// add errors to list
|
||||
foreach ($errors as $error) {
|
||||
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
||||
}
|
||||
|
||||
// check if any errors were found
|
||||
if (!empty($error_array)) {
|
||||
// return validation failure response
|
||||
return $this->json([
|
||||
'success' => false,
|
||||
'errors' => $error_array
|
||||
], 422);
|
||||
}
|
||||
|
||||
// validated! save the entity
|
||||
$em->persist($item_type);
|
||||
$em->flush();
|
||||
|
||||
// return successful response
|
||||
return $this->json([
|
||||
'success' => 'Changes have been saved!'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Menu(selected="item_type_list")
|
||||
* @ParamConverter("item_type", class="App\Entity\ItemType")
|
||||
* @IsGranted("item_type.update")
|
||||
*/
|
||||
public function updateForm($id, EntityManagerInterface $em, ItemType $item_type)
|
||||
{
|
||||
$params = [];
|
||||
$params['obj'] = $item_type;
|
||||
$params['mode'] = 'update';
|
||||
|
||||
// response
|
||||
return $this->render('item-type/form.html.twig', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ParamConverter("item_type", class="App\Entity\ItemType")
|
||||
* @IsGranted("item_type.update")
|
||||
*/
|
||||
public function updateSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator, ItemType $item_type)
|
||||
{
|
||||
$this->setObject($item_type, $req);
|
||||
|
||||
// validate
|
||||
$errors = $validator->validate($item_type);
|
||||
|
||||
// initialize error list
|
||||
$error_array = [];
|
||||
|
||||
// add errors to list
|
||||
foreach ($errors as $error) {
|
||||
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
||||
}
|
||||
|
||||
// check if any errors were found
|
||||
if (!empty($error_array)) {
|
||||
// return validation failure response
|
||||
return $this->json([
|
||||
'success' => false,
|
||||
'errors' => $error_array
|
||||
], 422);
|
||||
}
|
||||
|
||||
// validated! save the entity
|
||||
$em->flush();
|
||||
|
||||
// return successful response
|
||||
return $this->json([
|
||||
'success' => 'Changes have been saved!'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ParamConverter("item_type", class="App\Entity\ItemType")
|
||||
* @IsGranted("item_type.delete")
|
||||
*/
|
||||
public function deleteSubmit(EntityManagerInterface $em, ItemType $item_type)
|
||||
{
|
||||
// delete this object
|
||||
$em->remove($item_type);
|
||||
$em->flush();
|
||||
|
||||
// response
|
||||
$response = new Response();
|
||||
$response->setStatusCode(Response::HTTP_OK);
|
||||
$response->send();
|
||||
}
|
||||
|
||||
|
||||
protected function setObject(ItemType $obj, Request $req)
|
||||
{
|
||||
// set and save values
|
||||
$obj->setName($req->request->get('name'))
|
||||
->setCode($req->request->get('code'));
|
||||
}
|
||||
|
||||
protected function setQueryFilters($datatable, QueryBuilder $query)
|
||||
{
|
||||
if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) {
|
||||
$query->where('q.name LIKE :filter')
|
||||
->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace App\Controller;
|
|||
|
||||
use App\Entity\GatewayTransaction;
|
||||
use App\Ramcar\TransactionStatus;
|
||||
use App\Service\PayMongoConnector;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
|
@ -12,10 +13,12 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
|||
|
||||
class PayMongoController extends Controller
|
||||
{
|
||||
protected $pm;
|
||||
protected $em;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
public function __construct(PayMongoConnector $pm, EntityManagerInterface $em)
|
||||
{
|
||||
$this->pm = $pm;
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
|
|
@ -23,16 +26,8 @@ class PayMongoController extends Controller
|
|||
{
|
||||
$payload = json_decode($req->getContent(), true);
|
||||
|
||||
// DEBUG
|
||||
@file_put_contents(__DIR__ . '/../../var/log/paymongo.log', print_r($payload, true) . "\r\n----------------------------------------\r\n\r\n", FILE_APPEND);
|
||||
|
||||
/*
|
||||
return $this->json([
|
||||
'success' => true,
|
||||
]);
|
||||
*/
|
||||
|
||||
// END DEBUG
|
||||
// log this callback
|
||||
$this->pm->log('CALLBACK', "[]", $req->getContent(), 'callback');
|
||||
|
||||
// if no event type given, silently fail
|
||||
if (empty($payload['data'])) {
|
||||
|
|
|
|||
355
src/Controller/PriceTierController.php
Normal file
355
src/Controller/PriceTierController.php
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
|
||||
|
||||
use Catalyst\MenuBundle\Annotation\Menu;
|
||||
|
||||
use App\Entity\PriceTier;
|
||||
use App\Entity\SupportedArea;
|
||||
|
||||
class PriceTierController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Menu(selected="price_tier_list")
|
||||
* @IsGranted("price_tier.list")
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return $this->render('price-tier/list.html.twig');
|
||||
}
|
||||
|
||||
/**
|
||||
* @IsGranted("price_tier.list")
|
||||
*/
|
||||
public function datatableRows(Request $req)
|
||||
{
|
||||
// get query builder
|
||||
$qb = $this->getDoctrine()
|
||||
->getRepository(PriceTier::class)
|
||||
->createQueryBuilder('q');
|
||||
|
||||
// get datatable params
|
||||
$datatable = $req->request->get('datatable');
|
||||
|
||||
// count total records
|
||||
$tquery = $qb->select('COUNT(q)');
|
||||
$this->setQueryFilters($datatable, $tquery);
|
||||
$total = $tquery->getQuery()
|
||||
->getSingleScalarResult();
|
||||
|
||||
// get current page number
|
||||
$page = $datatable['pagination']['page'] ?? 1;
|
||||
|
||||
$perpage = $datatable['pagination']['perpage'];
|
||||
$offset = ($page - 1) * $perpage;
|
||||
|
||||
// add metadata
|
||||
$meta = [
|
||||
'page' => $page,
|
||||
'perpage' => $perpage,
|
||||
'pages' => ceil($total / $perpage),
|
||||
'total' => $total,
|
||||
'sort' => 'asc',
|
||||
'field' => 'id'
|
||||
];
|
||||
|
||||
// build query
|
||||
$query = $qb->select('q');
|
||||
$this->setQueryFilters($datatable, $query);
|
||||
|
||||
// check if sorting is present, otherwise use default
|
||||
if (isset($datatable['sort']['field']) && !empty($datatable['sort']['field'])) {
|
||||
$order = $datatable['sort']['sort'] ?? 'asc';
|
||||
$query->orderBy('q.' . $datatable['sort']['field'], $order);
|
||||
} else {
|
||||
$query->orderBy('q.id', 'asc');
|
||||
}
|
||||
|
||||
// get rows for this page
|
||||
$obj_rows = $query->setFirstResult($offset)
|
||||
->setMaxResults($perpage)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
// process rows
|
||||
$rows = [];
|
||||
foreach ($obj_rows as $orow) {
|
||||
// add row data
|
||||
$row['id'] = $orow->getID();
|
||||
$row['name'] = $orow->getName();
|
||||
|
||||
// add row metadata
|
||||
$row['meta'] = [
|
||||
'update_url' => '',
|
||||
'delete_url' => ''
|
||||
];
|
||||
|
||||
// add crud urls
|
||||
if ($this->isGranted('price_tier.update'))
|
||||
$row['meta']['update_url'] = $this->generateUrl('price_tier_update_form', ['id' => $row['id']]);
|
||||
if ($this->isGranted('service_offering.delete'))
|
||||
$row['meta']['delete_url'] = $this->generateUrl('price_tier_delete', ['id' => $row['id']]);
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
// response
|
||||
return $this->json([
|
||||
'meta' => $meta,
|
||||
'data' => $rows
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Menu(selected="price_tier.list")
|
||||
* @IsGranted("price_tier.add")
|
||||
*/
|
||||
public function addForm(EntityManagerInterface $em)
|
||||
{
|
||||
$pt = new PriceTier();
|
||||
|
||||
// get the supported areas
|
||||
$sets = $this->generateFormSets($em);
|
||||
|
||||
$params = [
|
||||
'obj' => $pt,
|
||||
'sets' => $sets,
|
||||
'mode' => 'create',
|
||||
];
|
||||
|
||||
// response
|
||||
return $this->render('price-tier/form.html.twig', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @IsGranted("price_tier.add")
|
||||
*/
|
||||
public function addSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator)
|
||||
{
|
||||
// initialize error list
|
||||
$error_array = [];
|
||||
|
||||
$pt = new PriceTier();
|
||||
|
||||
$error_array = $this->validateRequest($em, $req);
|
||||
|
||||
$this->setObject($pt, $req);
|
||||
|
||||
// validate
|
||||
$errors = $validator->validate($pt);
|
||||
|
||||
// add errors to list
|
||||
foreach ($errors as $error) {
|
||||
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
||||
}
|
||||
|
||||
// check if any errors were found
|
||||
if (!empty($error_array)) {
|
||||
// return validation failure response
|
||||
return $this->json([
|
||||
'success' => false,
|
||||
'errors' => $error_array
|
||||
], 422);
|
||||
}
|
||||
|
||||
// validated! save the entity
|
||||
$em->persist($pt);
|
||||
|
||||
// set the price tier id for the selected supported areas
|
||||
$this->updateSupportedAreas($em, $pt, $req);
|
||||
|
||||
$em->flush();
|
||||
|
||||
// return successful response
|
||||
return $this->json([
|
||||
'success' => 'Changes have been saved!'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Menu(selected="price_tier_list")
|
||||
* @ParamConverter("pt", class="App\Entity\PriceTier")
|
||||
* @IsGranted("price_tier.update")
|
||||
*/
|
||||
public function updateForm($id, EntityManagerInterface $em, PriceTier $pt)
|
||||
{
|
||||
// get the supported areas
|
||||
$sets = $this->generateFormSets($em, $pt);
|
||||
|
||||
$params = [
|
||||
'obj' => $pt,
|
||||
'sets' => $sets,
|
||||
'mode' => 'update',
|
||||
];
|
||||
|
||||
// response
|
||||
return $this->render('price-tier/form.html.twig', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ParamConverter("pt", class="App\Entity\PriceTier")
|
||||
* @IsGranted("price_tier.update")
|
||||
*/
|
||||
public function updateSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator, PriceTier $pt)
|
||||
{
|
||||
// initialize error list
|
||||
$error_array = [];
|
||||
|
||||
// clear supported areas of price tier
|
||||
$this->clearPriceTierSupportedAreas($em, $pt);
|
||||
|
||||
$error_array = $this->validateRequest($em, $req);
|
||||
$this->setObject($pt, $req);
|
||||
|
||||
// validate
|
||||
$errors = $validator->validate($pt);
|
||||
|
||||
// add errors to list
|
||||
foreach ($errors as $error) {
|
||||
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
||||
}
|
||||
|
||||
// check if any errors were found
|
||||
if (!empty($error_array)) {
|
||||
// return validation failure response
|
||||
return $this->json([
|
||||
'success' => false,
|
||||
'errors' => $error_array
|
||||
], 422);
|
||||
}
|
||||
|
||||
// set the price tier id for the selected supported areas
|
||||
$this->updateSupportedAreas($em, $pt, $req);
|
||||
|
||||
// validated! save the entity
|
||||
$em->flush();
|
||||
|
||||
// return successful response
|
||||
return $this->json([
|
||||
'success' => 'Changes have been saved!'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ParamConverter("pt", class="App\Entity\PriceTier")
|
||||
* @IsGranted("price_tier.delete")
|
||||
*/
|
||||
public function deleteSubmit(EntityManagerInterface $em, PriceTier $pt)
|
||||
{
|
||||
// clear supported areas of price tier
|
||||
$this->clearPriceTierSupportedAreas($em, $pt);
|
||||
|
||||
// delete this object
|
||||
$em->remove($pt);
|
||||
$em->flush();
|
||||
|
||||
// response
|
||||
$response = new Response();
|
||||
$response->setStatusCode(Response::HTTP_OK);
|
||||
$response->send();
|
||||
}
|
||||
|
||||
protected function validateRequest(EntityManagerInterface $em, Request $req)
|
||||
{
|
||||
// get areas
|
||||
$areas = $req->request->get('areas');
|
||||
|
||||
// check if no areas selected aka empty
|
||||
if (!empty($areas))
|
||||
{
|
||||
foreach ($areas as $area_id)
|
||||
{
|
||||
$supported_area = $em->getRepository(SupportedArea::class)->find($area_id);
|
||||
|
||||
if ($supported_area == null)
|
||||
return ['areas' => 'Invalid area'];
|
||||
|
||||
// check if supported area already belongs to a price tier
|
||||
if ($supported_area->getPriceTier() != null)
|
||||
return ['areas' => 'Area already belongs to a price tier.'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function setObject(PriceTier $obj, Request $req)
|
||||
{
|
||||
// clear supported areas first
|
||||
$obj->clearSupportedAreas();
|
||||
|
||||
$obj->setName($req->request->get('name'));
|
||||
}
|
||||
|
||||
protected function clearPriceTierSupportedAreas(EntityManagerInterface $em, PriceTier $obj)
|
||||
{
|
||||
// find the supported areas set with the price tier
|
||||
$areas = $em->getRepository(SupportedArea::class)->findBy(['price_tier' => $obj]);
|
||||
|
||||
if (!empty($areas))
|
||||
{
|
||||
// set the price tier id for the supported areas to null
|
||||
foreach ($areas as $area)
|
||||
{
|
||||
$area->setPriceTier(null);
|
||||
}
|
||||
|
||||
$em->flush();
|
||||
}
|
||||
}
|
||||
|
||||
protected function updateSupportedAreas(EntityManagerInterface $em, PriceTier $obj, Request $req)
|
||||
{
|
||||
// get the selected areas
|
||||
$areas = $req->request->get('areas');
|
||||
|
||||
// check if no areas selected aka empty
|
||||
if (!empty($areas))
|
||||
{
|
||||
foreach ($areas as $area_id)
|
||||
{
|
||||
// get supported area
|
||||
$supported_area = $em->getRepository(SupportedArea::class)->find($area_id);
|
||||
|
||||
if ($supported_area != null)
|
||||
$supported_area->setPriceTier($obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function generateFormSets(EntityManagerInterface $em, PriceTier $pt = null)
|
||||
{
|
||||
// get the supported areas with no price tier id or price tier id is set to the one that is being updated
|
||||
$areas = $em->getRepository(SupportedArea::class)->findBy(['price_tier' => array(null, $pt)]);
|
||||
$areas_set = [];
|
||||
foreach ($areas as $area)
|
||||
{
|
||||
$areas_set[$area->getID()] = $area->getName();
|
||||
}
|
||||
|
||||
return [
|
||||
'areas' => $areas_set
|
||||
];
|
||||
}
|
||||
|
||||
protected function setQueryFilters($datatable, QueryBuilder $query)
|
||||
{
|
||||
if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) {
|
||||
$query->where('q.name LIKE :filter')
|
||||
->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ use App\Ramcar\JOStatus;
|
|||
use App\Ramcar\ServiceType;
|
||||
use App\Ramcar\WillingToWaitContent;
|
||||
use App\Ramcar\CustomerClassification;
|
||||
use App\Ramcar\CustomerNotWaitReason;
|
||||
|
||||
use DateTime;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@ use Catalyst\ApiBundle\Component\Response as APIResponse;
|
|||
use App\Ramcar\APIResult;
|
||||
|
||||
use App\Entity\Vehicle;
|
||||
use App\Entity\ItemType;
|
||||
|
||||
use App\Service\PriceTierManager;
|
||||
|
||||
use CrEOF\Spatial\PHP\Types\Geometry\Point;
|
||||
|
||||
use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator;
|
||||
|
||||
|
|
@ -25,7 +30,7 @@ class BatteryController extends ApiController
|
|||
$this->acl_gen = $acl_gen;
|
||||
}
|
||||
|
||||
public function getCompatibleBatteries(Request $req, $vid, EntityManagerInterface $em)
|
||||
public function getCompatibleBatteries(Request $req, $vid, EntityManagerInterface $em, PriceTierManager $pt_manager)
|
||||
{
|
||||
$this->denyAccessUnlessGranted('tapi_battery_compatible.list', null, 'No access.');
|
||||
|
||||
|
|
@ -43,13 +48,44 @@ class BatteryController extends ApiController
|
|||
return new APIResponse(false, $message);
|
||||
}
|
||||
|
||||
// get location from request
|
||||
$lng = $req->request->get('longitude', '');
|
||||
$lat = $req->request->get('latitude', '');
|
||||
|
||||
$batts = $vehicle->getActiveBatteries();
|
||||
$pt_id = 0;
|
||||
if ((!(empty($lng))) && (!(empty($lat))))
|
||||
{
|
||||
// get the price tier
|
||||
$coordinates = new Point($lng, $lat);
|
||||
|
||||
$pt_id = $pt_manager->getPriceTier($coordinates);
|
||||
}
|
||||
|
||||
// batteries
|
||||
$batt_list = [];
|
||||
// $batts = $vehicle->getBatteries();
|
||||
$batts = $vehicle->getActiveBatteries();
|
||||
foreach ($batts as $batt)
|
||||
{
|
||||
// TODO: Add warranty_tnv to battery information
|
||||
// check if customer location is in a price tier location
|
||||
if ($pt_id == 0)
|
||||
$price = $batt->getSellingPrice();
|
||||
else
|
||||
{
|
||||
// get item type for battery
|
||||
$item_type = $em->getRepository(ItemType::class)->findOneBy(['code' => 'battery']);
|
||||
if ($item_type == null)
|
||||
$price = $batt->getSellingPrice();
|
||||
else
|
||||
{
|
||||
$item_type_id = $item_type->getID();
|
||||
$batt_id = $batt->getID();
|
||||
|
||||
// find the item price given price tier id and battery id
|
||||
$price = $pt_manager->getItemPrice($pt_id, $item_type_id, $batt_id);
|
||||
}
|
||||
}
|
||||
|
||||
$batt_list[] = [
|
||||
'id' => $batt->getID(),
|
||||
'mfg_id' => $batt->getManufacturer()->getID(),
|
||||
|
|
@ -58,7 +94,7 @@ class BatteryController extends ApiController
|
|||
'model_name' => $batt->getModel()->getName(),
|
||||
'size_id' => $batt->getSize()->getID(),
|
||||
'size_name' => $batt->getSize()->getName(),
|
||||
'price' => $batt->getSellingPrice(),
|
||||
'price' => $price,
|
||||
'wty_private' => $batt->getWarrantyPrivate(),
|
||||
'wty_commercial' => $batt->getWarrantyCommercial(),
|
||||
'image_url' => $this->getBatteryImageURL($req, $batt),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
97
src/Entity/ItemPrice.php
Normal file
97
src/Entity/ItemPrice.php
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="item_price")
|
||||
*/
|
||||
|
||||
class ItemPrice
|
||||
{
|
||||
// unique id
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="PriceTier", inversedBy="item_prices")
|
||||
* @ORM\JoinColumn(name="price_tier_id", referencedColumnName="id")
|
||||
*/
|
||||
protected $price_tier;
|
||||
|
||||
// item type
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="ItemType", inversedBy="items")
|
||||
* @ORM\JoinColumn(name="item_type_id", referencedColumnName="id")
|
||||
*/
|
||||
protected $item_type;
|
||||
|
||||
// could be battery id or service offering id, loosely coupled
|
||||
/**
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
protected $item_id;
|
||||
|
||||
// current price
|
||||
// NOTE: we need to move the decimal point two places to the left to get actual value
|
||||
// we want to avoid floating point problems
|
||||
/**
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
protected $price;
|
||||
|
||||
public function getID()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setPriceTier(PriceTier $price_tier)
|
||||
{
|
||||
$this->price_tier = $price_tier;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPriceTier()
|
||||
{
|
||||
return $this->price_tier;
|
||||
}
|
||||
|
||||
public function setItemType(ItemType $item_type)
|
||||
{
|
||||
$this->item_type = $item_type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getItemType()
|
||||
{
|
||||
return $this->item_type;
|
||||
}
|
||||
|
||||
public function setItemID($item_id)
|
||||
{
|
||||
$this->item_id = $item_id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getItemID()
|
||||
{
|
||||
return $this->item_id;
|
||||
}
|
||||
|
||||
public function setPrice($price)
|
||||
{
|
||||
$this->price = $price;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPrice()
|
||||
{
|
||||
return $this->price;
|
||||
}
|
||||
}
|
||||
80
src/Entity/ItemType.php
Normal file
80
src/Entity/ItemType.php
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="item_type", indexes={
|
||||
* @ORM\Index(name="item_type_idx", columns={"code"})
|
||||
* })
|
||||
*/
|
||||
|
||||
class ItemType
|
||||
{
|
||||
// unique id
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=80)
|
||||
* @Assert\NotBlank()
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=80)
|
||||
* @Assert\NotBlank()
|
||||
*/
|
||||
protected $code;
|
||||
|
||||
// items under an item type
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity="ItemPrice", mappedBy="item_type")
|
||||
*/
|
||||
protected $items;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->code = '';
|
||||
}
|
||||
|
||||
public function getID()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setCode($code)
|
||||
{
|
||||
$this->code = $code;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCode()
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
public function getItems()
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
}
|
||||
88
src/Entity/PriceTier.php
Normal file
88
src/Entity/PriceTier.php
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="price_tier")
|
||||
*/
|
||||
|
||||
class PriceTier
|
||||
{
|
||||
// unique id
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
// name of price tier
|
||||
/**
|
||||
* @ORM\Column(type="string", length=80)
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
// supported areas under price tier
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity="SupportedArea", mappedBy="price_tier");
|
||||
*/
|
||||
protected $supported_areas;
|
||||
|
||||
// items under a price tier
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity="ItemPrice", mappedBy="price_tier")
|
||||
*/
|
||||
protected $item_prices;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->supported_areas = new ArrayCollection();
|
||||
$this->items = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getID()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getSupportedAreaObjects()
|
||||
{
|
||||
return $this->supported_areas;
|
||||
}
|
||||
|
||||
public function getSupportedAreas()
|
||||
{
|
||||
$str_supported_areas = [];
|
||||
foreach ($this->supported_areas as $supported_area)
|
||||
$str_supported_areas[] = $supported_area->getID();
|
||||
|
||||
return $str_supported_areas;
|
||||
}
|
||||
|
||||
public function clearSupportedAreas()
|
||||
{
|
||||
$this->supported_areas->clear();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getItemPrices()
|
||||
{
|
||||
return $this->item_prices;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -39,9 +39,17 @@ class SupportedArea
|
|||
*/
|
||||
protected $coverage_area;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="PriceTier", inversedBy="supported_areas")
|
||||
* @ORM\JoinColumn(name="price_tier_id", referencedColumnName="id", nullable=true)
|
||||
*/
|
||||
protected $price_tier;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->date_create = new DateTime();
|
||||
|
||||
$this->price_tier = null;
|
||||
}
|
||||
|
||||
public function getID()
|
||||
|
|
@ -82,5 +90,16 @@ class SupportedArea
|
|||
{
|
||||
return $this->coverage_area;
|
||||
}
|
||||
|
||||
public function setPriceTier(PriceTier $price_tier = null)
|
||||
{
|
||||
$this->price_tier = $price_tier;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPriceTier()
|
||||
{
|
||||
return $this->price_tier;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class GatewayTransactionListener
|
|||
}
|
||||
|
||||
// flag on api as paid
|
||||
$result = $this->ic->tagApplicationPaid($obj->getID());
|
||||
$result = $this->ic->tagApplicationPaid($obj->getExtTransactionId());
|
||||
if (!$result['success'] || $result['response']['transaction_code'] !== 'GR004') {
|
||||
error_log("INSURANCE MARK AS PAID FAILED FOR " . $obj->getID() . ": " . $result['error']['message']);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,34 @@ 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]);
|
||||
|
||||
// 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($battery)
|
||||
{
|
||||
$title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName() . ' - Service Unit';
|
||||
|
|
|
|||
|
|
@ -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,7 @@ class BatterySales implements InvoiceRuleInterface
|
|||
public function compute($criteria, &$total)
|
||||
{
|
||||
$stype = $criteria->getServiceType();
|
||||
$pt = $criteria->getPriceTier();
|
||||
|
||||
$items = [];
|
||||
if ($stype == $this->getID())
|
||||
|
|
@ -36,19 +42,28 @@ class BatterySales implements InvoiceRuleInterface
|
|||
$entries = $criteria->getEntries();
|
||||
foreach($entries as $entry)
|
||||
{
|
||||
$batt = $entry['battery'];
|
||||
$qty = $entry['qty'];
|
||||
$trade_in = null;
|
||||
|
||||
// check if entry is for trade in
|
||||
if (isset($entry['trade_in']))
|
||||
$trade_in = $entry['trade_in'];
|
||||
|
||||
$size = $batt->getSize();
|
||||
|
||||
// entry is a battery purchase
|
||||
if ($trade_in == null)
|
||||
{
|
||||
// battery purchase
|
||||
$price = $batt->getSellingPrice();
|
||||
// safe to get entry with battery key since CRM and apps
|
||||
// will set this for a battery purchase and trade_in will
|
||||
// will not be set
|
||||
$batt = $entry['battery'];
|
||||
|
||||
// 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 +129,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();
|
||||
|
|
|
|||
|
|
@ -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, 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
|
||||
// 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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -55,18 +68,8 @@ class Jumpstart implements InvoiceRuleInterface
|
|||
|
||||
public function getServiceTypeFee($source, CustomerVehicle $cv)
|
||||
{
|
||||
// check the source of JO
|
||||
// (1) if from app, service fee is 0 if motolite user. jumpstart fee for app if non-motolite user.
|
||||
// (2) any other source, jumpstart fees are charged whether motolite user or not
|
||||
if ($source == TransactionOrigin::MOBILE_APP)
|
||||
{
|
||||
if ($cv->hasMotoliteBattery())
|
||||
$code = 'motolite_user_service_fee';
|
||||
else
|
||||
$code = 'jumpstart_fee_mobile_app';
|
||||
}
|
||||
else
|
||||
$code = 'jumpstart_fee';
|
||||
// get the service fee code, depending on the JO source and if customer vehicle has a motolite battery
|
||||
$code = $this->getServiceFeeCode($cv, $source);
|
||||
|
||||
$fee = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]);
|
||||
|
||||
|
|
@ -86,10 +89,68 @@ 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;
|
||||
|
||||
// get the service fee code, depending on the JO source and if customer vehicle has a motolite battery
|
||||
$code = $this->getServiceFeeCode($cv, $source);
|
||||
|
||||
// find the service offering
|
||||
$service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]);
|
||||
|
||||
// check if service is null. If null, return null
|
||||
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';
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
protected function getServiceFeeCode(CustomerVehicle $cv, $source)
|
||||
{
|
||||
// check the source of JO
|
||||
// (1) if from app, service fee is 0 if motolite user. jumpstart fee for app if non-motolite user.
|
||||
// (2) any other source, jumpstart fees are charged whether motolite user or not. Service fees for non-motolite
|
||||
// and motolite users are now different (used to be the same)
|
||||
if ($source == TransactionOrigin::MOBILE_APP)
|
||||
{
|
||||
if ($cv->hasMotoliteBattery())
|
||||
$code = 'motolite_user_service_fee';
|
||||
else
|
||||
$code = 'jumpstart_fee_mobile_app';
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log('hotline');
|
||||
if ($cv->hasMotoliteBattery())
|
||||
{
|
||||
error_log('has motolite battery');
|
||||
$code = 'motolite_user_jumpstart_fee';
|
||||
}
|
||||
else
|
||||
$code = 'jumpstart_fee';
|
||||
}
|
||||
|
||||
return $code;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,14 +7,20 @@ use Doctrine\ORM\EntityManagerInterface;
|
|||
use App\InvoiceRuleInterface;
|
||||
|
||||
use App\Entity\ServiceOffering;
|
||||
use App\Entity\ItemType;
|
||||
use App\Entity\CustomerVehicle;
|
||||
|
||||
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 +31,21 @@ class JumpstartWarranty implements InvoiceRuleInterface
|
|||
public function compute($criteria, &$total)
|
||||
{
|
||||
$stype = $criteria->getServiceType();
|
||||
$pt_id = $criteria->getPriceTier();
|
||||
|
||||
$items = [];
|
||||
|
||||
if ($stype == $this->getID())
|
||||
{
|
||||
$fee = $this->getServiceTypeFee();
|
||||
$cv = $criteria->getCustomerVehicle();
|
||||
|
||||
// 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;
|
||||
|
|
@ -38,19 +53,24 @@ 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);
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
public function getServiceTypeFee()
|
||||
public function getServiceTypeFee(CustomerVehicle $cv)
|
||||
{
|
||||
$code = 'jumpstart_warranty_fee';
|
||||
// check if user has motolite battery.
|
||||
// Motolite users now have a service fee for jumpstart warranty
|
||||
if ($cv->hasMotoliteBattery())
|
||||
$code = 'motolite_user_jumpstart_warranty_fee';
|
||||
else
|
||||
$code = 'jumpstart_warranty_fee';
|
||||
|
||||
// find the service fee using the code
|
||||
// if we can't find the fee, return 0
|
||||
|
|
@ -72,6 +92,39 @@ class JumpstartWarranty 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
|
||||
// check if user has motolite battery.
|
||||
// Motolite users now have a service fee for jumpstart warranty
|
||||
if ($cv->hasMotoliteBattery())
|
||||
$code = 'motolite_user_jumpstart_warranty_fee';
|
||||
else
|
||||
$code = 'jumpstart_warranty_fee';
|
||||
|
||||
$service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]);
|
||||
|
||||
// check if service is null. If null, return null
|
||||
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';
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -94,7 +108,7 @@ class Overheat implements InvoiceRuleInterface
|
|||
|
||||
// find the service fee using the code
|
||||
// if we can't find the fee, return 0
|
||||
$fee = $this->em->getRepository(ServiceOffering::class)->findOneBy($code);
|
||||
$fee = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]);
|
||||
|
||||
if ($fee == null)
|
||||
return 0;
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ class TradeIn implements InvoiceRuleInterface
|
|||
$entries = $criteria->getEntries();
|
||||
foreach($entries as $entry)
|
||||
{
|
||||
$batt = $entry['battery'];
|
||||
$qty = $entry['qty'];
|
||||
$trade_in_type = null;
|
||||
|
||||
|
|
@ -30,7 +29,18 @@ class TradeIn implements InvoiceRuleInterface
|
|||
|
||||
if ($trade_in_type != null)
|
||||
{
|
||||
$ti_rate = $this->getTradeInRate($batt, $trade_in_type);
|
||||
// at this point, entry is a trade in
|
||||
// need to check if battery (coming from CRM) is set
|
||||
// or battery_size is set (coming from rider app)
|
||||
if (isset($entry['battery']))
|
||||
{
|
||||
$battery = $entry['battery'];
|
||||
$batt_size = $battery->getSize();
|
||||
}
|
||||
else
|
||||
$batt_size = $entry['battery_size'];
|
||||
|
||||
$ti_rate = $this->getTradeInRate($batt_size, $trade_in_type);
|
||||
|
||||
$qty_ti = bcmul($ti_rate, $qty, 2);
|
||||
|
||||
|
|
@ -41,7 +51,7 @@ class TradeIn implements InvoiceRuleInterface
|
|||
|
||||
$items[] = [
|
||||
'qty' => $qty,
|
||||
'title' => $this->getTitle($batt, $trade_in_type),
|
||||
'title' => $this->getTitle($batt_size, $trade_in_type),
|
||||
'price' => $price,
|
||||
];
|
||||
}
|
||||
|
|
@ -60,10 +70,8 @@ class TradeIn implements InvoiceRuleInterface
|
|||
return null;
|
||||
}
|
||||
|
||||
protected function getTradeInRate($battery, $trade_in_type)
|
||||
protected function getTradeInRate($size, $trade_in_type)
|
||||
{
|
||||
$size = $battery->getSize();
|
||||
|
||||
switch ($trade_in_type)
|
||||
{
|
||||
case TradeInType::MOTOLITE:
|
||||
|
|
@ -77,9 +85,9 @@ class TradeIn implements InvoiceRuleInterface
|
|||
return 0;
|
||||
}
|
||||
|
||||
protected function getTitle($battery, $trade_in_type)
|
||||
protected function getTitle($battery_size, $trade_in_type)
|
||||
{
|
||||
$title = 'Trade-in ' . TradeInType::getName($trade_in_type) . ' ' . $battery->getSize()->getName() . ' battery';
|
||||
$title = 'Trade-in ' . TradeInType::getName($trade_in_type) . ' ' . $battery_size->getName() . ' battery';
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
|
|
|||
18
src/Ramcar/InsuranceBodyType.php
Normal file
18
src/Ramcar/InsuranceBodyType.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace App\Ramcar;
|
||||
|
||||
class InsuranceBodyType extends NameValue
|
||||
{
|
||||
const SEDAN = 'sedan';
|
||||
const SUV = 'suv';
|
||||
const TRUCK = 'truck';
|
||||
const MOTORCYCLE = 'motorcycle';
|
||||
|
||||
const COLLECTION = [
|
||||
'SEDAN' => 'Sedan',
|
||||
'SUV' => 'SUV',
|
||||
'TRUCK' => 'Truck',
|
||||
'MOTORCYCLE' => 'Motorcycle',
|
||||
];
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -108,6 +110,17 @@ class InvoiceCriteria
|
|||
$this->entries[] = $entry;
|
||||
}
|
||||
|
||||
public function addTradeInEntry($battery_size, $trade_in, $qty)
|
||||
{
|
||||
$entry = [
|
||||
'battery_size' => $battery_size,
|
||||
'trade_in' => $trade_in,
|
||||
'qty' => $qty
|
||||
];
|
||||
|
||||
$this->entries[] = $entry;
|
||||
}
|
||||
|
||||
public function getEntries()
|
||||
{
|
||||
return $this->entries;
|
||||
|
|
@ -179,4 +192,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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ class InsuranceConnector
|
|||
return base64_encode($this->username . ":" . $this->password);
|
||||
}
|
||||
|
||||
protected function doRequest($url, $method, $body = [])
|
||||
protected function doRequest($url, $method, $request_body = [])
|
||||
{
|
||||
$client = new Client();
|
||||
$headers = [
|
||||
|
|
@ -102,7 +102,7 @@ class InsuranceConnector
|
|||
|
||||
try {
|
||||
$response = $client->request($method, $this->base_url . '/' . $url, [
|
||||
'json' => $body,
|
||||
'json' => $request_body,
|
||||
'headers' => $headers,
|
||||
]);
|
||||
} catch (RequestException $e) {
|
||||
|
|
@ -111,6 +111,11 @@ class InsuranceConnector
|
|||
error_log("Insurance API Error: " . $error['message']);
|
||||
error_log(Psr7\Message::toString($e->getRequest()));
|
||||
error_log($e->getResponse()->getBody()->getContents());
|
||||
error_log("Insurance Creds: " . $this->username . ", " . $this->password);
|
||||
error_log("Insurance Hash: " . $this->generateHash());
|
||||
|
||||
// log this error
|
||||
$this->log($url, Psr7\Message::toString($e->getRequest()), Psr7\Message::toString($e->getResponse()), 'error');
|
||||
|
||||
if ($e->hasResponse()) {
|
||||
$error['response'] = Psr7\Message::toString($e->getResponse());
|
||||
|
|
@ -122,11 +127,32 @@ class InsuranceConnector
|
|||
];
|
||||
}
|
||||
|
||||
error_log(print_r(json_decode($response->getBody(), true), true));
|
||||
$result_body = $response->getBody();
|
||||
|
||||
// log response
|
||||
$this->log($url, json_encode($request_body), $result_body);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'response' => json_decode($response->getBody(), true)
|
||||
'response' => json_decode($result_body, true),
|
||||
];
|
||||
}
|
||||
|
||||
// TODO: make this more elegant
|
||||
public function log($title, $request_body = "[]", $result_body = "[]", $type = 'api')
|
||||
{
|
||||
$filename = '/../../var/log/insurance_' . $type . '.log';
|
||||
$date = date("Y-m-d H:i:s");
|
||||
|
||||
// build log entry
|
||||
$entry = implode("\r\n", [
|
||||
$date,
|
||||
$title,
|
||||
"REQUEST:\r\n" . $request_body,
|
||||
"RESPONSE:\r\n" . $result_body,
|
||||
"\r\n----------------------------------------\r\n\r\n",
|
||||
]);
|
||||
|
||||
@file_put_contents(__DIR__ . $filename, $entry, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,28 +45,29 @@ class InvoiceManager implements InvoiceGeneratorInterface
|
|||
{
|
||||
// TODO: get list of invoice rules from .env or a json file?
|
||||
return [
|
||||
new InvoiceRule\BatterySales($this->em),
|
||||
new InvoiceRule\BatteryReplacementWarranty($this->em),
|
||||
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\BatterySales($this->em, $this->pt_manager),
|
||||
new InvoiceRule\BatteryReplacementWarranty($this->em, $this->pt_manager),
|
||||
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),
|
||||
new InvoiceRule\Tax($this->em, $this->pt_manager),
|
||||
];
|
||||
}
|
||||
|
||||
// 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);
|
||||
// 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
|
||||
|
|
@ -817,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
|
||||
|
|
@ -2014,6 +2021,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
|
||||
// NOTE: for resq2 app
|
||||
$mclientv2->sendEvent($obj, $payload);
|
||||
$mclientv2->sendRiderEvent($obj, $payload);
|
||||
$fcmclient->sendJoEvent($obj, "jo_fcm_title_driver_assigned", "jo_fcm_body_driver_assigned");
|
||||
}
|
||||
|
||||
|
|
@ -2165,7 +2173,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
|
||||
|
|
|
|||
|
|
@ -68,4 +68,31 @@ class MQTTClientApiv2
|
|||
// error_log('sent to ' . $channel);
|
||||
}
|
||||
}
|
||||
|
||||
public function sendRiderEvent(JobOrder $job_order, $payload)
|
||||
{
|
||||
// check if a rider is available
|
||||
$rider = $job_order->getRider();
|
||||
if ($rider == null)
|
||||
return;
|
||||
|
||||
/*
|
||||
// NOTE: this is for the old rider app
|
||||
// check if rider has sessions
|
||||
$sessions = $rider->getSessions();
|
||||
if (count($sessions) == 0)
|
||||
return;
|
||||
|
||||
// send to every rider session
|
||||
foreach ($sessions as $sess)
|
||||
{
|
||||
$sess_id = $sess->getID();
|
||||
$channel = self::RIDER_PREFIX . $sess_id;
|
||||
$this->publish($channel, json_encode($payload));
|
||||
}
|
||||
*/
|
||||
|
||||
// NOTE: this is for the new rider app
|
||||
$this->publish('rider/' . $rider->getID() . '/delivery', json_encode($payload));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ class PayMongoConnector
|
|||
return base64_encode($this->secret_key);
|
||||
}
|
||||
|
||||
protected function doRequest($url, $method, $body = [])
|
||||
protected function doRequest($url, $method, $request_body = [])
|
||||
{
|
||||
$client = new Client();
|
||||
$headers = [
|
||||
|
|
@ -90,14 +90,14 @@ class PayMongoConnector
|
|||
|
||||
try {
|
||||
$response = $client->request($method, $this->base_url . '/' . $url, [
|
||||
'json' => $body,
|
||||
'json' => $request_body,
|
||||
'headers' => $headers,
|
||||
]);
|
||||
} catch (RequestException $e) {
|
||||
$error = ['message' => $e->getMessage()];
|
||||
|
||||
ob_start();
|
||||
var_dump($body);
|
||||
//var_dump($request_body);
|
||||
$varres = ob_get_clean();
|
||||
error_log($varres);
|
||||
|
||||
|
|
@ -107,6 +107,9 @@ class PayMongoConnector
|
|||
error_log("PayMongo API Error: " . $error['message']);
|
||||
error_log(Psr7\Message::toString($e->getRequest()));
|
||||
|
||||
// log this error
|
||||
$this->log($url, Psr7\Message::toString($e->getRequest()), Psr7\Message::toString($e->getResponse()), 'error');
|
||||
|
||||
if ($e->hasResponse()) {
|
||||
$error['response'] = Psr7\Message::toString($e->getResponse());
|
||||
}
|
||||
|
|
@ -117,9 +120,32 @@ class PayMongoConnector
|
|||
];
|
||||
}
|
||||
|
||||
$result_body = $response->getBody();
|
||||
|
||||
// log response
|
||||
$this->log($url, json_encode($request_body), $result_body);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'response' => json_decode($response->getBody(), true)
|
||||
];
|
||||
}
|
||||
|
||||
// TODO: make this more elegant
|
||||
public function log($title, $request_body = "[]", $result_body = "[]", $type = 'api')
|
||||
{
|
||||
$filename = '/../../var/log/paymongo_' . $type . '.log';
|
||||
$date = date("Y-m-d H:i:s");
|
||||
|
||||
// build log entry
|
||||
$entry = implode("\r\n", [
|
||||
$date,
|
||||
$title,
|
||||
"REQUEST:\r\n" . $request_body,
|
||||
"RESPONSE:\r\n" . $result_body,
|
||||
"\r\n----------------------------------------\r\n\r\n",
|
||||
]);
|
||||
|
||||
@file_put_contents(__DIR__ . $filename, $entry, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
80
src/Service/PriceTierManager.php
Normal file
80
src/Service/PriceTierManager.php
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
<?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();
|
||||
|
||||
// results found
|
||||
$actual_price = null;
|
||||
|
||||
// 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 $coordinates)
|
||||
{
|
||||
$price_tier_id = 0;
|
||||
|
||||
if ($coordinates != null)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
}
|
||||
164
templates/item-pricing/form.html.twig
Normal file
164
templates/item-pricing/form.html.twig
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block body %}
|
||||
<!-- BEGIN: Subheader -->
|
||||
<div class="m-subheader">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="mr-auto">
|
||||
<h3 class="m-subheader__title">Item Pricing</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END: Subheader -->
|
||||
<div class="m-content">
|
||||
<div class="row">
|
||||
<div class="col-xl-12">
|
||||
<div class="m-portlet m-portlet--mobile">
|
||||
<div class="m-portlet__body">
|
||||
<div class="m-form m-form--label-align-right m--margin-top-20 m--margin-bottom-30">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-xl-12">
|
||||
<div class="form-group m-form__group row align-items-center">
|
||||
<div class="col-md-2">
|
||||
<label>Item Prices for </label>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="m-input-icon m-input-icon--left">
|
||||
<div class="input-group">
|
||||
<select class="form-control m-input" id="price-tier-select" name="price_tier_list">
|
||||
<option value="0">Default Price Tier</option>
|
||||
{% for price_tier in sets.price_tiers %}
|
||||
<option value="{{ price_tier.getID }}">{{ price_tier.getName }} </option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="m-input-icon m-input-icon--left">
|
||||
<div class="input-group">
|
||||
<select class="form-control m-input" id="item-type-select" name="item_type_list">
|
||||
{% for item_type in sets.item_types %}
|
||||
<option value="{{ item_type.getID }}">{{ item_type.getName }} </option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="row-form" class="m-form m-form--fit m-form--label-align-right" method="post" action="{{ url('item_pricing_update') }}">
|
||||
<input id="price-tier-id" type="hidden" name="price_tier_id" value="0">
|
||||
<input id="item-type-id" type="hidden" name="item_type_id" value="{{ default_item_type_id }}">
|
||||
<div style="padding-left: 25px; padding-right: 25px;">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 100px">ID</th>
|
||||
<th>Name</th>
|
||||
<th hidden> Item Type ID </th>
|
||||
<th>Item Type</th>
|
||||
<th style="width: 180px">Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="table-body">
|
||||
{% for id, item in items.items %}
|
||||
<tr>
|
||||
<td>{{ id }}</td>
|
||||
<td>{{ item.name }} </td>
|
||||
<td hidden> {{ item.item_type_id }} </td>
|
||||
<td>{{ item.item_type }} </td>
|
||||
<td class="py-1">
|
||||
<input name="price[{{ id }}]" class="form-control ca-filter" type="number" value="{{ item.price }}" step="0.01">
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="">
|
||||
<input type="submit" class="btn btn-primary" value="Update Price">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
|
||||
initialize();
|
||||
|
||||
function initialize() {
|
||||
init_price_tier_dropdown();
|
||||
init_item_type_dropdown();
|
||||
}
|
||||
|
||||
function init_price_tier_dropdown() {
|
||||
var pt_dropdown = document.getElementById('price-tier-select');
|
||||
var it_dropdown = document.getElementById('item-type-select');
|
||||
pt_dropdown.addEventListener('change', function(e) {
|
||||
var it_type = it_dropdown.value;
|
||||
load_prices(e.target.value, it_type);
|
||||
});
|
||||
}
|
||||
|
||||
function init_item_type_dropdown() {
|
||||
var it_dropdown = document.getElementById('item-type-select');
|
||||
var pt_dropdown = document.getElementById('price-tier-select');
|
||||
it_dropdown.addEventListener('change', function(e) {
|
||||
var pt_type = pt_dropdown.value;
|
||||
load_prices(pt_type, e.target.value);
|
||||
});
|
||||
}
|
||||
|
||||
function load_prices(price_tier_id, item_type_id) {
|
||||
var req = new XMLHttpRequest();
|
||||
req.onreadystatechange = function() {
|
||||
// process response
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
// update form
|
||||
update_table(JSON.parse(req.responseText));
|
||||
var pt_field = document.getElementById('price-tier-id');
|
||||
pt_field.value = price_tier_id;
|
||||
var it_field = document.getElementById('item-type-id');
|
||||
it_field.value = item_type_id;
|
||||
} else {
|
||||
// console.log('could not load tier prices');
|
||||
}
|
||||
}
|
||||
var url_pattern = '{{ url('item_pricing_prices', {'pt_id': '--id--', 'it_id': '--it-id--'}) }}';
|
||||
var url = url_pattern.replace('--id--', price_tier_id).replace('--it-id--', item_type_id);
|
||||
console.log(url);
|
||||
req.open('GET', url, true);
|
||||
req.send();
|
||||
}
|
||||
|
||||
function update_table(data) {
|
||||
console.log(data);
|
||||
var item_html = '';
|
||||
for (var i in data.items) {
|
||||
var item = data.items[i];
|
||||
// console.log(item);
|
||||
item_html += '<tr>';
|
||||
item_html += '<td>' + item.id + '</td>';
|
||||
item_html += '<td>' + item.name + '</td>';
|
||||
item_html += '<td hidden>' + item.item_type_id + '</td>';
|
||||
item_html += '<td>' + item.item_type + '</td>';
|
||||
item_html += '<td class="py-1">';
|
||||
item_html += '<input name="price[' + item.id + ']" class="form-control ca-filter" type="number" value="' + item.price + '" step="0.01">';
|
||||
item_html += '</td>';
|
||||
item_html += '</tr>';
|
||||
}
|
||||
|
||||
var table_body = document.getElementById('table-body');
|
||||
table_body.innerHTML = item_html;
|
||||
}
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
142
templates/item-type/form.html.twig
Normal file
142
templates/item-type/form.html.twig
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block body %}
|
||||
<!-- BEGIN: Subheader -->
|
||||
<div class="m-subheader">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="mr-auto">
|
||||
<h3 class="m-subheader__title">Item Types</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END: Subheader -->
|
||||
<div class="m-content">
|
||||
<!--Begin::Section-->
|
||||
<div class="row">
|
||||
<div class="col-xl-6">
|
||||
<div class="m-portlet m-portlet--mobile">
|
||||
<div class="m-portlet__head">
|
||||
<div class="m-portlet__head-caption">
|
||||
<div class="m-portlet__head-title">
|
||||
<span class="m-portlet__head-icon">
|
||||
<i class="la la-industry"></i>
|
||||
</span>
|
||||
<h3 class="m-portlet__head-text">
|
||||
{% if mode == 'update' %}
|
||||
Edit Item Type
|
||||
<small>{{ obj.getName() }}</small>
|
||||
{% else %}
|
||||
New Item Type
|
||||
{% endif %}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="row-form" class="m-form m-form--fit m-form--label-align-right m-form--group-seperator-dashed" method="post" action="{{ mode == 'update' ? url('item_type_update_submit', {'id': obj.getId()}) : url('item_type_add_submit') }}">
|
||||
<div class="m-portlet__body">
|
||||
<div class="form-group m-form__group row no-border">
|
||||
<label class="col-lg-3 col-form-label" data-field="name">
|
||||
Name:
|
||||
</label>
|
||||
<div class="col-lg-9">
|
||||
<input type="text" name="name" class="form-control m-input" value="{{ obj.getName() }}">
|
||||
<div class="form-control-feedback hide" data-field="name"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group m-form__group row no-border">
|
||||
<label class="col-lg-3 col-form-label" data-field="code">
|
||||
Code:
|
||||
</label>
|
||||
<div class="col-lg-9">
|
||||
<input type="text" name="code" class="form-control m-input" value="{{ obj.getCode() }}">
|
||||
<div class="form-control-feedback hide" data-field="code"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m-portlet__foot m-portlet__foot--fit">
|
||||
<div class="m-form__actions m-form__actions--solid m-form__actions--right">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<button type="submit" class="btn btn-success">Submit</button>
|
||||
<a href="{{ url('item_type_list') }}" class="btn btn-secondary">Back</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
$(function() {
|
||||
$("#row-form").submit(function(e) {
|
||||
var form = $(this);
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: form.prop('action'),
|
||||
data: form.serialize()
|
||||
}).done(function(response) {
|
||||
// remove all error classes
|
||||
removeErrors();
|
||||
swal({
|
||||
title: 'Done!',
|
||||
text: 'Your changes have been saved!',
|
||||
type: 'success',
|
||||
onClose: function() {
|
||||
window.location.href = "{{ url('item_type_list') }}";
|
||||
}
|
||||
});
|
||||
}).fail(function(response) {
|
||||
if (response.status == 422) {
|
||||
var errors = response.responseJSON.errors;
|
||||
var firstfield = false;
|
||||
|
||||
// remove all error classes first
|
||||
removeErrors();
|
||||
|
||||
// display errors contextually
|
||||
$.each(errors, function(field, msg) {
|
||||
var formfield = $("[name='" + field + "']");
|
||||
var label = $("label[data-field='" + field + "']");
|
||||
var msgbox = $(".form-control-feedback[data-field='" + field + "']");
|
||||
|
||||
// add error classes to bad fields
|
||||
formfield.addClass('form-control-danger');
|
||||
label.addClass('has-danger');
|
||||
msgbox.html(msg).addClass('has-danger').removeClass('hide');
|
||||
|
||||
// check if this field comes first in DOM
|
||||
var domfield = formfield.get(0);
|
||||
|
||||
if (!firstfield || (firstfield && firstfield.compareDocumentPosition(domfield) === 2)) {
|
||||
firstfield = domfield;
|
||||
}
|
||||
});
|
||||
|
||||
// focus on first bad field
|
||||
firstfield.focus();
|
||||
|
||||
// scroll to above that field to make it visible
|
||||
$('html, body').animate({
|
||||
scrollTop: $(firstfield).offset().top - 200
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// remove all error classes
|
||||
function removeErrors() {
|
||||
$(".form-control-danger").removeClass('form-control-danger');
|
||||
$("[data-field]").removeClass('has-danger');
|
||||
$(".form-control-feedback[data-field]").addClass('hide');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
146
templates/item-type/list.html.twig
Normal file
146
templates/item-type/list.html.twig
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block body %}
|
||||
<!-- BEGIN: Subheader -->
|
||||
<div class="m-subheader">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="mr-auto">
|
||||
<h3 class="m-subheader__title">
|
||||
Item Types
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END: Subheader -->
|
||||
<div class="m-content">
|
||||
<!--Begin::Section-->
|
||||
<div class="row">
|
||||
<div class="col-xl-12">
|
||||
<div class="m-portlet m-portlet--mobile">
|
||||
<div class="m-portlet__body">
|
||||
<div class="m-form m-form--label-align-right m--margin-top-20 m--margin-bottom-30">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-xl-8 order-2 order-xl-1">
|
||||
<div class="form-group m-form__group row align-items-center">
|
||||
<div class="col-md-4">
|
||||
<div class="m-input-icon m-input-icon--left">
|
||||
<input type="text" class="form-control m-input m-input--solid" placeholder="Search..." id="data-rows-search">
|
||||
<span class="m-input-icon__icon m-input-icon__icon--left">
|
||||
<span><i class="la la-search"></i></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-4 order-1 order-xl-2 m--align-right">
|
||||
<a href="{{ url('item_type_add_form') }}" class="btn btn-focus m-btn m-btn--custom m-btn--icon m-btn--air m-btn--pill">
|
||||
<span>
|
||||
<i class="la la-industry"></i>
|
||||
<span>New Item Type</span>
|
||||
</span>
|
||||
</a>
|
||||
<div class="m-separator m-separator--dashed d-xl-none"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--begin: Datatable -->
|
||||
<div id="data-rows"></div>
|
||||
<!--end: Datatable -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
$(function() {
|
||||
var options = {
|
||||
data: {
|
||||
type: 'remote',
|
||||
source: {
|
||||
read: {
|
||||
url: '{{ url("item_type_rows") }}',
|
||||
method: 'POST'
|
||||
}
|
||||
},
|
||||
saveState: {
|
||||
cookie: false,
|
||||
webstorage: false
|
||||
},
|
||||
pageSize: 10,
|
||||
serverPaging: true,
|
||||
serverFiltering: true,
|
||||
serverSorting: true
|
||||
},
|
||||
layout: {
|
||||
scroll: true
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'ID',
|
||||
width: 30
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Name'
|
||||
},
|
||||
{
|
||||
field: 'Actions',
|
||||
width: 110,
|
||||
title: 'Actions',
|
||||
sortable: false,
|
||||
overflow: 'visible',
|
||||
template: function (row, index, datatable) {
|
||||
var actions = '';
|
||||
|
||||
if (row.meta.update_url != '') {
|
||||
actions += '<a href="' + row.meta.update_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-edit" data-id="' + row.name + '" title="Edit"><i class="la la-edit"></i></a>';
|
||||
}
|
||||
|
||||
if (row.meta.delete_url != '') {
|
||||
actions += '<a href="' + row.meta.delete_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-danger m-btn--icon m-btn--icon-only m-btn--pill btn-delete" data-id="' + row.name + '" title="Delete"><i class="la la-trash"></i></a>';
|
||||
}
|
||||
|
||||
return actions;
|
||||
},
|
||||
}
|
||||
],
|
||||
search: {
|
||||
onEnter: false,
|
||||
input: $('#data-rows-search'),
|
||||
delay: 400
|
||||
}
|
||||
};
|
||||
|
||||
var table = $("#data-rows").mDatatable(options);
|
||||
|
||||
$(document).on('click', '.btn-delete', function(e) {
|
||||
var url = $(this).prop('href');
|
||||
var id = $(this).data('id');
|
||||
var btn = $(this);
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
swal({
|
||||
title: 'Confirmation',
|
||||
html: 'Are you sure you want to delete <strong>' + id + '</strong>?',
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
$.ajax({
|
||||
method: "DELETE",
|
||||
url: url
|
||||
}).done(function(response) {
|
||||
table.row(btn.parents('tr')).remove();
|
||||
table.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
177
templates/item/form.html.twig
Normal file
177
templates/item/form.html.twig
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block body %}
|
||||
<!-- BEGIN: Subheader -->
|
||||
<div class="m-subheader">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="mr-auto">
|
||||
<h3 class="m-subheader__title">Items</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END: Subheader -->
|
||||
<div class="m-content">
|
||||
<!--Begin::Section-->
|
||||
<div class="row">
|
||||
<div class="col-xl-6">
|
||||
<div class="m-portlet m-portlet--mobile">
|
||||
<div class="m-portlet__head">
|
||||
<div class="m-portlet__head-caption">
|
||||
<div class="m-portlet__head-title">
|
||||
<span class="m-portlet__head-icon">
|
||||
<i class="la la-industry"></i>
|
||||
</span>
|
||||
<h3 class="m-portlet__head-text">
|
||||
{% if mode == 'update' %}
|
||||
Edit Item
|
||||
<small>{{ obj.getName() }}</small>
|
||||
{% else %}
|
||||
New Item
|
||||
{% endif %}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="row-form" class="m-form m-form--fit m-form--label-align-right m-form--group-seperator-dashed" method="post" action="{{ mode == 'update' ? url('item_type_update_submit', {'id': obj.getId()}) : url('item_add_submit') }}">
|
||||
<div class="m-portlet__body">
|
||||
<div class="form-group m-form__group row no-border">
|
||||
<label class="col-lg-3 col-form-label" data-field="item_type">
|
||||
Item Type:
|
||||
</label>
|
||||
<div class="col-lg-9">
|
||||
<select class="form-control m-input" id="item-type" name="item_type">
|
||||
{% for id, label in sets.item_types %}
|
||||
{% if obj.getItemType %}
|
||||
<option value="{{ id }}"{{ obj.getItemType.getID == id ? ' selected' }}>{{ label }}</option>
|
||||
{% else %}
|
||||
<option value="{{ id }}">{{ label }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="form-control-feedback hide" data-field="item_type"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group m-form__group row no-border
|
||||
{% if obj.getItemType %}
|
||||
{% if obj.getItemType.getCode is not same as ('battery') %}
|
||||
hide
|
||||
{% endif %}
|
||||
{% else %}
|
||||
hide
|
||||
{% endif %}
|
||||
" id="battery-row">
|
||||
<label class="col-lg-3 col-form-label" data-field="battery">
|
||||
Battery:
|
||||
</label>
|
||||
<div class="col-lg-9">
|
||||
<select class="form-control m-input" id="item-type" name="battery">
|
||||
{% for id, label in sets.batteries %}
|
||||
<option value="{{ id }}"{{ obj.getItemID == id ? ' selected' }}>{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="form-control-feedback hide" data-field="battery"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m-portlet__foot m-portlet__foot--fit">
|
||||
<div class="m-form__actions m-form__actions--solid m-form__actions--right">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<button type="submit" class="btn btn-success">Submit</button>
|
||||
<a href="{{ url('item_list') }}" class="btn btn-secondary">Back</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
$(function() {
|
||||
$("#row-form").submit(function(e) {
|
||||
var form = $(this);
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: form.prop('action'),
|
||||
data: form.serialize()
|
||||
}).done(function(response) {
|
||||
// remove all error classes
|
||||
removeErrors();
|
||||
swal({
|
||||
title: 'Done!',
|
||||
text: 'Your changes have been saved!',
|
||||
type: 'success',
|
||||
onClose: function() {
|
||||
window.location.href = "{{ url('item_list') }}";
|
||||
}
|
||||
});
|
||||
}).fail(function(response) {
|
||||
if (response.status == 422) {
|
||||
var errors = response.responseJSON.errors;
|
||||
var firstfield = false;
|
||||
|
||||
// remove all error classes first
|
||||
removeErrors();
|
||||
|
||||
// display errors contextually
|
||||
$.each(errors, function(field, msg) {
|
||||
var formfield = $("[name='" + field + "']");
|
||||
var label = $("label[data-field='" + field + "']");
|
||||
var msgbox = $(".form-control-feedback[data-field='" + field + "']");
|
||||
|
||||
// add error classes to bad fields
|
||||
formfield.addClass('form-control-danger');
|
||||
label.addClass('has-danger');
|
||||
msgbox.html(msg).addClass('has-danger').removeClass('hide');
|
||||
|
||||
// check if this field comes first in DOM
|
||||
var domfield = formfield.get(0);
|
||||
|
||||
if (!firstfield || (firstfield && firstfield.compareDocumentPosition(domfield) === 2)) {
|
||||
firstfield = domfield;
|
||||
}
|
||||
});
|
||||
|
||||
// focus on first bad field
|
||||
firstfield.focus();
|
||||
|
||||
// scroll to above that field to make it visible
|
||||
$('html, body').animate({
|
||||
scrollTop: $(firstfield).offset().top - 200
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// remove all error classes
|
||||
function removeErrors() {
|
||||
$(".form-control-danger").removeClass('form-control-danger');
|
||||
$("[data-field]").removeClass('has-danger');
|
||||
$(".form-control-feedback[data-field]").addClass('hide');
|
||||
}
|
||||
});
|
||||
|
||||
$('#item-type').change(function(e) {
|
||||
console.log('item type change ' + e.target.value);
|
||||
if (e.target.value === '1') {
|
||||
// display battery row
|
||||
$('#battery-row').removeClass("hide");
|
||||
|
||||
// hide service offering rows
|
||||
} else {
|
||||
// display service offering row
|
||||
|
||||
// hide battery row
|
||||
$('#battery-row').addClass("hide");
|
||||
}
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
146
templates/item/list.html.twig
Normal file
146
templates/item/list.html.twig
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block body %}
|
||||
<!-- BEGIN: Subheader -->
|
||||
<div class="m-subheader">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="mr-auto">
|
||||
<h3 class="m-subheader__title">
|
||||
Items
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END: Subheader -->
|
||||
<div class="m-content">
|
||||
<!--Begin::Section-->
|
||||
<div class="row">
|
||||
<div class="col-xl-12">
|
||||
<div class="m-portlet m-portlet--mobile">
|
||||
<div class="m-portlet__body">
|
||||
<div class="m-form m-form--label-align-right m--margin-top-20 m--margin-bottom-30">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-xl-8 order-2 order-xl-1">
|
||||
<div class="form-group m-form__group row align-items-center">
|
||||
<div class="col-md-4">
|
||||
<div class="m-input-icon m-input-icon--left">
|
||||
<input type="text" class="form-control m-input m-input--solid" placeholder="Search..." id="data-rows-search">
|
||||
<span class="m-input-icon__icon m-input-icon__icon--left">
|
||||
<span><i class="la la-search"></i></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-4 order-1 order-xl-2 m--align-right">
|
||||
<a href="{{ url('item_add_form') }}" class="btn btn-focus m-btn m-btn--custom m-btn--icon m-btn--air m-btn--pill">
|
||||
<span>
|
||||
<i class="la la-industry"></i>
|
||||
<span>New Item</span>
|
||||
</span>
|
||||
</a>
|
||||
<div class="m-separator m-separator--dashed d-xl-none"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--begin: Datatable -->
|
||||
<div id="data-rows"></div>
|
||||
<!--end: Datatable -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
$(function() {
|
||||
var options = {
|
||||
data: {
|
||||
type: 'remote',
|
||||
source: {
|
||||
read: {
|
||||
url: '{{ url("item_rows") }}',
|
||||
method: 'POST'
|
||||
}
|
||||
},
|
||||
saveState: {
|
||||
cookie: false,
|
||||
webstorage: false
|
||||
},
|
||||
pageSize: 10,
|
||||
serverPaging: true,
|
||||
serverFiltering: true,
|
||||
serverSorting: true
|
||||
},
|
||||
layout: {
|
||||
scroll: true
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'ID',
|
||||
width: 30
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Name'
|
||||
},
|
||||
{
|
||||
field: 'Actions',
|
||||
width: 110,
|
||||
title: 'Actions',
|
||||
sortable: false,
|
||||
overflow: 'visible',
|
||||
template: function (row, index, datatable) {
|
||||
var actions = '';
|
||||
|
||||
if (row.meta.update_url != '') {
|
||||
actions += '<a href="' + row.meta.update_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-edit" data-id="' + row.name + '" title="Edit"><i class="la la-edit"></i></a>';
|
||||
}
|
||||
|
||||
if (row.meta.delete_url != '') {
|
||||
actions += '<a href="' + row.meta.delete_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-danger m-btn--icon m-btn--icon-only m-btn--pill btn-delete" data-id="' + row.name + '" title="Delete"><i class="la la-trash"></i></a>';
|
||||
}
|
||||
|
||||
return actions;
|
||||
},
|
||||
}
|
||||
],
|
||||
search: {
|
||||
onEnter: false,
|
||||
input: $('#data-rows-search'),
|
||||
delay: 400
|
||||
}
|
||||
};
|
||||
|
||||
var table = $("#data-rows").mDatatable(options);
|
||||
|
||||
$(document).on('click', '.btn-delete', function(e) {
|
||||
var url = $(this).prop('href');
|
||||
var id = $(this).data('id');
|
||||
var btn = $(this);
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
swal({
|
||||
title: 'Confirmation',
|
||||
html: 'Are you sure you want to delete <strong>' + id + '</strong>?',
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
$.ajax({
|
||||
method: "DELETE",
|
||||
url: url
|
||||
}).done(function(response) {
|
||||
table.row(btn.parents('tr')).remove();
|
||||
table.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -1266,6 +1266,9 @@ $(function() {
|
|||
$('#map_lat').val(lat);
|
||||
$('#map_lng').val(lng);
|
||||
|
||||
// regenerate invoice
|
||||
generateInvoice();
|
||||
|
||||
}
|
||||
|
||||
osm_map.on('click', function(e) {
|
||||
|
|
@ -1763,6 +1766,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));
|
||||
|
||||
|
|
@ -1774,7 +1779,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
|
||||
|
|
|
|||
154
templates/price-tier/form.html.twig
Normal file
154
templates/price-tier/form.html.twig
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block body %}
|
||||
<!-- BEGIN: Subheader -->
|
||||
<div class="m-subheader">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="mr-auto">
|
||||
<h3 class="m-subheader__title">Price Tiers</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END: Subheader -->
|
||||
<div class="m-content">
|
||||
<!--Begin::Section-->
|
||||
<div class="row">
|
||||
<div class="col-xl-6">
|
||||
<div class="m-portlet m-portlet--mobile">
|
||||
<div class="m-portlet__head">
|
||||
<div class="m-portlet__head-caption">
|
||||
<div class="m-portlet__head-title">
|
||||
<span class="m-portlet__head-icon">
|
||||
<i class="la la-industry"></i>
|
||||
</span>
|
||||
<h3 class="m-portlet__head-text">
|
||||
{% if mode == 'update' %}
|
||||
Edit Price Tier
|
||||
<small>{{ obj.getName() }}</small>
|
||||
{% else %}
|
||||
New Price Tier
|
||||
{% endif %}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="row-form" class="m-form m-form--fit m-form--label-align-right m-form--group-seperator-dashed" method="post" action="{{ mode == 'update' ? url('price_tier_update_submit', {'id': obj.getId()}) : url('price_tier_add_submit') }}">
|
||||
<div class="m-portlet__body">
|
||||
<div class="form-group m-form__group row no-border">
|
||||
<label class="col-lg-3 col-form-label" data-field="name">
|
||||
Name:
|
||||
</label>
|
||||
<div class="col-lg-9">
|
||||
<input type="text" name="name" class="form-control m-input" value="{{ obj.getName() }}">
|
||||
<div class="form-control-feedback hide" data-field="name"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group m-form__group row no-border">
|
||||
<label class="col-lg-3 col-form-label" data-field="areas">
|
||||
Coverage Area:
|
||||
</label>
|
||||
<div class="col-lg-9">
|
||||
{% if sets.areas is empty %}
|
||||
No available supported areas.
|
||||
{% else %}
|
||||
<div class="m-checkbox-list">
|
||||
{% for id, label in sets.areas %}
|
||||
<label class="m-checkbox">
|
||||
<input type="checkbox" name="areas[]" value="{{ id }}"{{ id in obj.getSupportedAreas() ? ' checked' : '' }}>
|
||||
{{ label }}
|
||||
<span></span>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="form-control-feedback hide" data-field="areas"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m-portlet__foot m-portlet__foot--fit">
|
||||
<div class="m-form__actions m-form__actions--solid m-form__actions--right">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<button type="submit" class="btn btn-success">Submit</button>
|
||||
<a href="{{ url('price_tier_list') }}" class="btn btn-secondary">Back</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
$(function() {
|
||||
$("#row-form").submit(function(e) {
|
||||
var form = $(this);
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: form.prop('action'),
|
||||
data: form.serialize()
|
||||
}).done(function(response) {
|
||||
// remove all error classes
|
||||
removeErrors();
|
||||
swal({
|
||||
title: 'Done!',
|
||||
text: 'Your changes have been saved!',
|
||||
type: 'success',
|
||||
onClose: function() {
|
||||
window.location.href = "{{ url('price_tier_list') }}";
|
||||
}
|
||||
});
|
||||
}).fail(function(response) {
|
||||
if (response.status == 422) {
|
||||
var errors = response.responseJSON.errors;
|
||||
var firstfield = false;
|
||||
|
||||
// remove all error classes first
|
||||
removeErrors();
|
||||
|
||||
// display errors contextually
|
||||
$.each(errors, function(field, msg) {
|
||||
var formfield = $("[name='" + field + "']");
|
||||
var label = $("label[data-field='" + field + "']");
|
||||
var msgbox = $(".form-control-feedback[data-field='" + field + "']");
|
||||
|
||||
// add error classes to bad fields
|
||||
formfield.addClass('form-control-danger');
|
||||
label.addClass('has-danger');
|
||||
msgbox.html(msg).addClass('has-danger').removeClass('hide');
|
||||
|
||||
// check if this field comes first in DOM
|
||||
var domfield = formfield.get(0);
|
||||
|
||||
if (!firstfield || (firstfield && firstfield.compareDocumentPosition(domfield) === 2)) {
|
||||
firstfield = domfield;
|
||||
}
|
||||
});
|
||||
|
||||
// focus on first bad field
|
||||
firstfield.focus();
|
||||
|
||||
// scroll to above that field to make it visible
|
||||
$('html, body').animate({
|
||||
scrollTop: $(firstfield).offset().top - 200
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// remove all error classes
|
||||
function removeErrors() {
|
||||
$(".form-control-danger").removeClass('form-control-danger');
|
||||
$("[data-field]").removeClass('has-danger');
|
||||
$(".form-control-feedback[data-field]").addClass('hide');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
146
templates/price-tier/list.html.twig
Normal file
146
templates/price-tier/list.html.twig
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block body %}
|
||||
<!-- BEGIN: Subheader -->
|
||||
<div class="m-subheader">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="mr-auto">
|
||||
<h3 class="m-subheader__title">
|
||||
Price Tiers
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END: Subheader -->
|
||||
<div class="m-content">
|
||||
<!--Begin::Section-->
|
||||
<div class="row">
|
||||
<div class="col-xl-12">
|
||||
<div class="m-portlet m-portlet--mobile">
|
||||
<div class="m-portlet__body">
|
||||
<div class="m-form m-form--label-align-right m--margin-top-20 m--margin-bottom-30">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-xl-8 order-2 order-xl-1">
|
||||
<div class="form-group m-form__group row align-items-center">
|
||||
<div class="col-md-4">
|
||||
<div class="m-input-icon m-input-icon--left">
|
||||
<input type="text" class="form-control m-input m-input--solid" placeholder="Search..." id="data-rows-search">
|
||||
<span class="m-input-icon__icon m-input-icon__icon--left">
|
||||
<span><i class="la la-search"></i></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-4 order-1 order-xl-2 m--align-right">
|
||||
<a href="{{ url('price_tier_add_form') }}" class="btn btn-focus m-btn m-btn--custom m-btn--icon m-btn--air m-btn--pill">
|
||||
<span>
|
||||
<i class="la la-industry"></i>
|
||||
<span>New Price Tier</span>
|
||||
</span>
|
||||
</a>
|
||||
<div class="m-separator m-separator--dashed d-xl-none"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--begin: Datatable -->
|
||||
<div id="data-rows"></div>
|
||||
<!--end: Datatable -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
$(function() {
|
||||
var options = {
|
||||
data: {
|
||||
type: 'remote',
|
||||
source: {
|
||||
read: {
|
||||
url: '{{ url("price_tier_rows") }}',
|
||||
method: 'POST'
|
||||
}
|
||||
},
|
||||
saveState: {
|
||||
cookie: false,
|
||||
webstorage: false
|
||||
},
|
||||
pageSize: 10,
|
||||
serverPaging: true,
|
||||
serverFiltering: true,
|
||||
serverSorting: true
|
||||
},
|
||||
layout: {
|
||||
scroll: true
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'ID',
|
||||
width: 30
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Name'
|
||||
},
|
||||
{
|
||||
field: 'Actions',
|
||||
width: 110,
|
||||
title: 'Actions',
|
||||
sortable: false,
|
||||
overflow: 'visible',
|
||||
template: function (row, index, datatable) {
|
||||
var actions = '';
|
||||
|
||||
if (row.meta.update_url != '') {
|
||||
actions += '<a href="' + row.meta.update_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-edit" data-id="' + row.name + '" title="Edit"><i class="la la-edit"></i></a>';
|
||||
}
|
||||
|
||||
if (row.meta.delete_url != '') {
|
||||
actions += '<a href="' + row.meta.delete_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-danger m-btn--icon m-btn--icon-only m-btn--pill btn-delete" data-id="' + row.name + '" title="Delete"><i class="la la-trash"></i></a>';
|
||||
}
|
||||
|
||||
return actions;
|
||||
},
|
||||
}
|
||||
],
|
||||
search: {
|
||||
onEnter: false,
|
||||
input: $('#data-rows-search'),
|
||||
delay: 400
|
||||
}
|
||||
};
|
||||
|
||||
var table = $("#data-rows").mDatatable(options);
|
||||
|
||||
$(document).on('click', '.btn-delete', function(e) {
|
||||
var url = $(this).prop('href');
|
||||
var id = $(this).data('id');
|
||||
var btn = $(this);
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
swal({
|
||||
title: 'Confirmation',
|
||||
html: 'Are you sure you want to delete <strong>' + id + '</strong>?',
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
$.ajax({
|
||||
method: "DELETE",
|
||||
url: url
|
||||
}).done(function(response) {
|
||||
table.row(btn.parents('tr')).remove();
|
||||
table.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -159,6 +159,7 @@ menu.database.subtickettypes: 'Sub Ticket Types'
|
|||
menu.database.emergencytypes: 'Emergency Types'
|
||||
menu.database.ownershiptypes: 'Ownership Types'
|
||||
menu.database.serviceofferings: 'Service Offerings'
|
||||
menu.database.itemtypes: 'Item Types'
|
||||
|
||||
# fcm jo status updates
|
||||
jo_fcm_title_outlet_assign: 'Looking for riders'
|
||||
|
|
|
|||
53
utils/item_types/item_types.sql
Normal file
53
utils/item_types/item_types.sql
Normal file
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
INSERT INTO service_offering (name, code, fee) VALUES ('Motolite User Jumpstart Warranty Fee', 'motolite_user_jumpstart_warranty_fee', 200.00);
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
-- MySQL dump 10.19 Distrib 10.3.39-MariaDB, for Linux (x86_64)
|
||||
--
|
||||
-- Host: localhost Database: resq
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 10.3.39-MariaDB
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8mb4 */;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `service_offering`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `service_offering`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `service_offering` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(80) NOT NULL,
|
||||
`code` varchar(80) NOT NULL,
|
||||
`fee` decimal(9,2) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `service_offering_idx` (`code`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `service_offering`
|
||||
--
|
||||
|
||||
LOCK TABLES `service_offering` WRITE;
|
||||
/*!40000 ALTER TABLE `service_offering` DISABLE KEYS */;
|
||||
INSERT INTO `service_offering` VALUES (1,'Tax','tax',0.12),(2,'Motolite User Service Fee','motolite_user_service_fee',0.00),(3,'Battery Replacement Warranty Fee','battery_replacement_warranty_fee',0.00),(4,'Fuel Service Fee','fuel_service_fee',300.00),(5,'Fuel Gas Fee','fuel_gas_fee',340.00),(6,'Fuel Diesel Fee','fuel_diesel_fee',320.00),(7,'Jumpstart Fee','jumpstart_fee',300.00),(8,'Jumpstart Fee Mobile App','jumpstart_fee_mobile_app',300.00),(9,'Jumpstart Warranty Fee','jumpstart_warranty_fee',300.00),(10,'Overheat Fee','overheat_fee',300.00),(11,'Coolant Fee','coolant_fee',1600.00),(12,'Post Recharged Fee','post_recharged_fee',300.00),(13,'Post Replacement Fee','post_replacement_fee',0.00),(14,'Tire Repair Fee','tire_repair_fee',300.00),(17,'Motolite User Jumpstart Warranty Fee','motolite_user_jumpstart_warranty_fee',200.00),(18,'Motolite User Jumpstart Fee','motolite_user_jumpstart_fee',200.00);
|
||||
/*!40000 ALTER TABLE `service_offering` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2024-04-02 1:17:40
|
||||
Loading…
Reference in a new issue