Merge branch '270-final-cmb-fixes' of gitlab.com:jankstudio/resq into 299-cmb-realtime-map
Conflicts: config/services.yaml
|
|
@ -242,6 +242,10 @@ access_keys:
|
||||||
label: Edit
|
label: Edit
|
||||||
- id: joborder.cancel
|
- id: joborder.cancel
|
||||||
label: Cancel
|
label: Cancel
|
||||||
|
- id: jo_onestep.form
|
||||||
|
label: One-step Process
|
||||||
|
- id: jo_onestep.edit
|
||||||
|
label: One-step Process Edit
|
||||||
|
|
||||||
- id: support
|
- id: support
|
||||||
label: Customer Support Access
|
label: Customer Support Access
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,10 @@ main_menu:
|
||||||
acl: joborder.menu
|
acl: joborder.menu
|
||||||
label: Job Order
|
label: Job Order
|
||||||
icon: flaticon-calendar-3
|
icon: flaticon-calendar-3
|
||||||
|
- id: jo_onestep_form
|
||||||
|
acl: jo_onestep.form
|
||||||
|
label: One-step Process
|
||||||
|
parent: joborder
|
||||||
- id: jo_in
|
- id: jo_in
|
||||||
acl: jo_in.list
|
acl: jo_in.list
|
||||||
label: Incoming
|
label: Incoming
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,3 @@
|
||||||
# controller: App\Controller\DefaultController::index
|
# controller: App\Controller\DefaultController::index
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
home:
|
|
||||||
path: /
|
|
||||||
controller: App\Controller\HomeController::index
|
|
||||||
|
|
||||||
|
|
|
||||||
8
config/routes/home.yaml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
home:
|
||||||
|
path: /
|
||||||
|
controller: App\Controller\HomeController::index
|
||||||
|
|
||||||
|
rider_locations:
|
||||||
|
path: /rider_locations
|
||||||
|
controller: App\Controller\HomeController::getRiderLocations
|
||||||
|
|
||||||
|
|
@ -34,3 +34,12 @@ hub_delete:
|
||||||
controller: App\Controller\HubController::destroy
|
controller: App\Controller\HubController::destroy
|
||||||
methods: [DELETE]
|
methods: [DELETE]
|
||||||
|
|
||||||
|
hub_nearest:
|
||||||
|
path: /ajax/nearest_hubs
|
||||||
|
controller: App\Controller\HubController::nearest
|
||||||
|
methods: [GET]
|
||||||
|
|
||||||
|
hub_riders:
|
||||||
|
path: /ajax/hubs/riders
|
||||||
|
controller: App\Controller\HubController::getHubRiders
|
||||||
|
methods: [GET]
|
||||||
|
|
|
||||||
|
|
@ -175,3 +175,23 @@ jo_reject_hub:
|
||||||
path: /job-order/{id}/reject-hub
|
path: /job-order/{id}/reject-hub
|
||||||
controller: App\Controller\JobOrderController::rejectHubSubmit
|
controller: App\Controller\JobOrderController::rejectHubSubmit
|
||||||
methods: [POST]
|
methods: [POST]
|
||||||
|
|
||||||
|
jo_onestep_form:
|
||||||
|
path: /job-order/onestep
|
||||||
|
controller: App\Controller\JobOrderController::oneStepForm
|
||||||
|
methods: [GET]
|
||||||
|
|
||||||
|
jo_onestep_submit:
|
||||||
|
path: /job-order/onestep
|
||||||
|
controller: App\Controller\JobOrderController::oneStepSubmit
|
||||||
|
methods: [POST]
|
||||||
|
|
||||||
|
jo_onestep_edit_form:
|
||||||
|
path: /job-order/onestep/{id}/edit
|
||||||
|
controller: App\Controller\JobOrderController::oneStepEditForm
|
||||||
|
methods: [GET]
|
||||||
|
|
||||||
|
jo_onestep_edit_submit:
|
||||||
|
path: /job-order/onestep/{id}/edit
|
||||||
|
controller: App\Controller\JobOrderController::oneStepEditSubmit
|
||||||
|
methods: [POST]
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,11 @@ services:
|
||||||
$cvu_mfg_id: "%env(CVU_MFG_ID)%"
|
$cvu_mfg_id: "%env(CVU_MFG_ID)%"
|
||||||
$cvu_brand_id: "%env(CVU_BRAND_ID)%"
|
$cvu_brand_id: "%env(CVU_BRAND_ID)%"
|
||||||
|
|
||||||
|
# rider tracker service
|
||||||
|
App\Service\RiderTracker:
|
||||||
|
arguments:
|
||||||
|
$redis_client: "@App\\Service\\RedisClientProvider"
|
||||||
|
|
||||||
Catalyst\APIBundle\Security\APIKeyUserProvider:
|
Catalyst\APIBundle\Security\APIKeyUserProvider:
|
||||||
arguments:
|
arguments:
|
||||||
$em: "@doctrine.orm.entity_manager"
|
$em: "@doctrine.orm.entity_manager"
|
||||||
|
|
@ -145,3 +150,40 @@ services:
|
||||||
$menu_name: "main_menu"
|
$menu_name: "main_menu"
|
||||||
tags:
|
tags:
|
||||||
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
|
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
|
||||||
|
|
||||||
|
# invoice generator
|
||||||
|
App\Service\InvoiceGenerator\CMBInvoiceGenerator: ~
|
||||||
|
|
||||||
|
# invoice generator interface
|
||||||
|
#App\Service\InvoiceGeneratorInterface: "@App\\Service\\InvoiceGenerator\\CMBInvoiceGenerator"
|
||||||
|
App\Service\InvoiceGeneratorInterface: "@App\\Service\\InvoiceGenerator\\ResqInvoiceGenerator"
|
||||||
|
|
||||||
|
# job order generator
|
||||||
|
App\Service\JobOrderHandler\CMBJobOrderHandler: ~
|
||||||
|
|
||||||
|
#job order generator interface
|
||||||
|
#App\Service\JobOrderHandlerInterface: "@App\\Service\\JobOrderHandler\\CMBJobOrderHandler"
|
||||||
|
App\Service\JobOrderHandlerInterface: "@App\\Service\\JobOrderHandler\\ResqJobOrderHandler"
|
||||||
|
|
||||||
|
# customer generator
|
||||||
|
App\Service\CustomerHandler\CMBCustomerHandler: ~
|
||||||
|
|
||||||
|
# customer generator interface
|
||||||
|
#App\Service\CustomerHandlerInterface: "@App\\Service\\CustomerHandler\\CMBCustomerHandler"
|
||||||
|
App\Service\CustomerHandlerInterface: "@App\\Service\\CustomerHandler\\ResqCustomerHandler"
|
||||||
|
|
||||||
|
# rider assignment
|
||||||
|
App\Service\RiderAssignmentHandler\CMBRiderAssignmentHandler: ~
|
||||||
|
|
||||||
|
# rider assignment interface
|
||||||
|
App\Service\RiderAssignmentHandlerInterface: "@App\\Service\\RiderAssignmentHandler\\CMBRiderAssignmentHandler"
|
||||||
|
|
||||||
|
# map manager
|
||||||
|
#App\Service\GISManager\Bing: ~
|
||||||
|
App\Service\GISManager\OpenStreet: ~
|
||||||
|
#App\Service\GISManager\Google: ~
|
||||||
|
|
||||||
|
#App\Service\GISManagerInterface: "@App\\Service\\GISManager\\Bing"
|
||||||
|
App\Service\GISManagerInterface: "@App\\Service\\GISManager\\OpenStreet"
|
||||||
|
#App\Service\GISManagerInterface: "@App\\Service\\GISManager\\Google"
|
||||||
|
|
||||||
|
|
|
||||||
8
migration/sql_delete_battery_vehicle_data.sql
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
DELETE FROM battery;
|
||||||
|
DELETE FROM battery_manufacturer;
|
||||||
|
DELETE FROM battery_manufacturer;
|
||||||
|
DELETE FROM battery_model;
|
||||||
|
DELETE FROM battery_size;
|
||||||
|
DELETE FROM vehicle;
|
||||||
|
DELETE FROM vehicle_manufacturer;
|
||||||
|
DELETE FROM battery_vehicle;
|
||||||
|
|
@ -295,3 +295,40 @@ span.has-danger,
|
||||||
.btn-icon {
|
.btn-icon {
|
||||||
margin-right: .5em;
|
margin-right: .5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.marker-pin {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 50% 50% 50% 0;
|
||||||
|
background: #c30b82;
|
||||||
|
position: absolute;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
margin: -15px 0 0 -15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.marker-pin::after {
|
||||||
|
content: '';
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
margin: 3px 0 0 3px;
|
||||||
|
background: #fff;
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-div-icon i {
|
||||||
|
position: absolute;
|
||||||
|
width: 22px;
|
||||||
|
font-size: 22px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin: 10px auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-div-icon i.awesome {
|
||||||
|
margin: 12px auto;
|
||||||
|
font-size: 17px;
|
||||||
|
|
||||||
|
|
|
||||||
BIN
public/assets/images/battery-assist-bm-logo-16x16.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
public/assets/images/battery-assist-bm-logo-32x32.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
public/assets/images/battery-assist-bm-logo-50x50.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
public/assets/images/battery-assist-bm-logo-edited.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
public/assets/images/battery-assist-bm-logo.png
Normal file
|
After Width: | Height: | Size: 5.2 MiB |
BIN
public/assets/images/black-text-logo-01-115x115.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
public/assets/images/black-text-logo-01-125x125.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
public/assets/images/black-text-logo-01-16x16.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
public/assets/images/black-text-logo-01-32x32.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
public/assets/images/black-text-logo-01.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
public/assets/images/century_logo.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
315
src/Command/ImportCMBBatteryDataCommand.php
Normal file
|
|
@ -0,0 +1,315 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
use Doctrine\Common\Persistence\ObjectManager;
|
||||||
|
|
||||||
|
use App\Entity\Battery;
|
||||||
|
use App\Entity\BatteryManufacturer;
|
||||||
|
use App\Entity\BatteryModel;
|
||||||
|
use App\Entity\BatterySize;
|
||||||
|
|
||||||
|
class ImportCMBBatteryDataCommand extends Command
|
||||||
|
{
|
||||||
|
const F_BATT_CODE = 1;
|
||||||
|
const F_BATT_DESC = 2;
|
||||||
|
const F_BATT_PRICE = 3;
|
||||||
|
|
||||||
|
protected $em;
|
||||||
|
|
||||||
|
protected $bmanu_hash;
|
||||||
|
protected $bmodel_hash;
|
||||||
|
protected $bsize_hash;
|
||||||
|
protected $batt_hash;
|
||||||
|
|
||||||
|
public function __construct(ObjectManager $om)
|
||||||
|
{
|
||||||
|
$this->em = $om;
|
||||||
|
|
||||||
|
// load existing batteries and sizes
|
||||||
|
$this->loadBatteryManufacturers();
|
||||||
|
$this->loadBatteryModels();
|
||||||
|
$this->loadBatteries();
|
||||||
|
$this->loadBatterySizes();
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('cmbbatterydata:import')
|
||||||
|
->setDescription('Import a CSV file with battery data.')
|
||||||
|
->setHelp('Adds the battery data based on imported CSV.')
|
||||||
|
->addArgument('file', InputArgument::REQUIRED, 'Path to the CSV file.');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$csv_file = $input->getArgument('file');
|
||||||
|
|
||||||
|
// attempt to open file
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$fh = fopen($csv_file, "r");
|
||||||
|
}
|
||||||
|
catch (Exception $e)
|
||||||
|
{
|
||||||
|
throw new Exception('The file "' . $csv_file . '" could be read.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// get entity manager
|
||||||
|
$em = $this->em;
|
||||||
|
|
||||||
|
// loop through the rows
|
||||||
|
$row_num = 0;
|
||||||
|
error_log('Processing battery csv file...');
|
||||||
|
while (($fields = fgetcsv($fh)) !== false)
|
||||||
|
{
|
||||||
|
// data starts at row 2
|
||||||
|
if ($row_num < 2)
|
||||||
|
{
|
||||||
|
$row_num++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// battery info
|
||||||
|
$code = trim($fields[self::F_BATT_CODE]);
|
||||||
|
$desc = trim($fields[self::F_BATT_DESC]);
|
||||||
|
$price = trim($fields[self::F_BATT_PRICE]);
|
||||||
|
|
||||||
|
$clean_price = trim($price, '$');
|
||||||
|
|
||||||
|
$battery_info = explode(' ', $desc);
|
||||||
|
|
||||||
|
// if battery_info has 3 elements, get the last two
|
||||||
|
// [0] = battery manufacturer
|
||||||
|
// [1] = battery model
|
||||||
|
// [2] = battery size
|
||||||
|
// if only 2, get both
|
||||||
|
// [0] = battery manufacturer and battery model
|
||||||
|
// [1] = battery size
|
||||||
|
// if 4,
|
||||||
|
// [0] = battery manufacturer
|
||||||
|
// concatenate [1] and [2] for the battery model
|
||||||
|
// [3] = battery size
|
||||||
|
$battery_manufacturer = '';
|
||||||
|
$battery_model = '';
|
||||||
|
$battery_size = '';
|
||||||
|
if (count($battery_info) == 3)
|
||||||
|
{
|
||||||
|
// sample: Century Marathoner 120-7L
|
||||||
|
$battery_manufacturer = trim($battery_info[0]);
|
||||||
|
$battery_model = trim($battery_info[1]);
|
||||||
|
$battery_size = trim($battery_info[2]);
|
||||||
|
}
|
||||||
|
if (count($battery_info) == 2)
|
||||||
|
{
|
||||||
|
// sample: Marshall DIN55R
|
||||||
|
$battery_manufacturer = trim($battery_info[0]);
|
||||||
|
$battery_model = trim($battery_info[0]);
|
||||||
|
$battery_size = trim($battery_info[1]);
|
||||||
|
}
|
||||||
|
if (count($battery_info) == 4)
|
||||||
|
{
|
||||||
|
// sample: Motolite Classic Wetcharged DIN100L
|
||||||
|
$battery_manufacturer = trim($battery_info[0]);
|
||||||
|
$battery_model = trim($battery_info[1]) . ' ' . trim($battery_info[2]);
|
||||||
|
$battery_size = trim($battery_info[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if battery size has ()
|
||||||
|
// if so, trim it to ignore the parenthesis and what's after (.
|
||||||
|
$pos = stripos($battery_size, '(');
|
||||||
|
if ($pos == true)
|
||||||
|
{
|
||||||
|
$sizes = explode('(', $battery_size);
|
||||||
|
$clean_size = trim($sizes[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$clean_size = $battery_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//error_log('battery manufacturer ' . $battery_manufacturer);
|
||||||
|
//error_log('battery model ' . $battery_model);
|
||||||
|
//error_log('battery size ' . $battery_size);
|
||||||
|
|
||||||
|
// normalize the manufacturer, model and size for the hash
|
||||||
|
// when we add to db for manufacturer, model, and size, we do not use the normalized versions
|
||||||
|
$normalized_manu = $this->normalizeName($battery_manufacturer);
|
||||||
|
$normalized_model = $this->normalizeName($battery_model);
|
||||||
|
$normalized_size = $this->normalizeName($clean_size);
|
||||||
|
|
||||||
|
// save battery manufacturer if not yet in system
|
||||||
|
if (!isset($this->bmanu_hash[$normalized_manu]))
|
||||||
|
{
|
||||||
|
$this->addBatteryManufacturer($battery_manufacturer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save battery model if not yet in system
|
||||||
|
if (!isset($this->bmodel_hash[$normalized_model]))
|
||||||
|
{
|
||||||
|
$this->addBatteryModel($battery_model);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save battery size if not yet in system
|
||||||
|
if (!isset($this->bsize_hash[$normalized_size]))
|
||||||
|
{
|
||||||
|
$this->addBatterySize($clean_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save battery if not yet in system
|
||||||
|
if (!isset($this->batt_hash[$normalized_manu][$normalized_model][$normalized_size]))
|
||||||
|
{
|
||||||
|
$this->addBattery($normalized_manu, $normalized_model, $normalized_size, $code, $clean_price);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addBatteryManufacturer($name)
|
||||||
|
{
|
||||||
|
$batt_manufacturer = new BatteryManufacturer();
|
||||||
|
|
||||||
|
$batt_manufacturer->setName($name);
|
||||||
|
|
||||||
|
$this->em->persist($batt_manufacturer);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
// add new manufacturer to hash
|
||||||
|
$normalized_name = $this->normalizeName($name);
|
||||||
|
$this->bmanu_hash[$normalized_name] = $batt_manufacturer;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addBatteryModel($name)
|
||||||
|
{
|
||||||
|
$batt_model = new BatteryModel();
|
||||||
|
|
||||||
|
$batt_model->setName($name);
|
||||||
|
|
||||||
|
$this->em->persist($batt_model);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
// add new model to hash
|
||||||
|
$normalized_name = $this->normalizeName($name);
|
||||||
|
$this->bmodel_hash[$normalized_name] = $batt_model;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addBatterySize($name)
|
||||||
|
{
|
||||||
|
if (!empty($name))
|
||||||
|
{
|
||||||
|
// save to db
|
||||||
|
$batt_size = new BatterySize();
|
||||||
|
|
||||||
|
$batt_size->setName($name);
|
||||||
|
|
||||||
|
$this->em->persist($batt_size);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
// add new size into hash
|
||||||
|
$normalized_name = $this->normalizeName($name);
|
||||||
|
$this->bsize_hash[$normalized_name] = $batt_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addBattery($manufacturer, $brand, $size, $code, $price)
|
||||||
|
{
|
||||||
|
// save to db
|
||||||
|
$bmanu = $this->bmanu_hash[$manufacturer];
|
||||||
|
$bmodel = $this->bmodel_hash[$brand];
|
||||||
|
$bsize = $this->bsize_hash[$size];
|
||||||
|
|
||||||
|
$battery = new Battery();
|
||||||
|
$battery->setManufacturer($bmanu)
|
||||||
|
->setModel($bmodel)
|
||||||
|
->setSize($bsize)
|
||||||
|
->setWarrantyPrivate(21)
|
||||||
|
->setWarrantyCommercial(6)
|
||||||
|
->setWarrantyTnv(12)
|
||||||
|
->setProductCode($code)
|
||||||
|
->setSAPCode($code)
|
||||||
|
->setSellingPrice($price);
|
||||||
|
|
||||||
|
$this->em->persist($battery);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
// insert into hash
|
||||||
|
$this->batt_hash[$brand][$brand][$size] = $battery;
|
||||||
|
|
||||||
|
// add battery into battery manufacturer, battery model, and battery size
|
||||||
|
$bmanu->addBattery($battery);
|
||||||
|
$bmodel->addBattery($battery);
|
||||||
|
$bsize->addBattery($battery);
|
||||||
|
|
||||||
|
$this->em->persist($bmanu);
|
||||||
|
$this->em->persist($bmodel);
|
||||||
|
$this->em->persist($bsize);
|
||||||
|
|
||||||
|
$this->em->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadBatteryManufacturers()
|
||||||
|
{
|
||||||
|
$this->bmanu_hash = [];
|
||||||
|
|
||||||
|
$batt_manufacturers = $this->em->getRepository(BatteryManufacturer::class)->findAll();
|
||||||
|
foreach ($batt_manufacturers as $batt_manu)
|
||||||
|
{
|
||||||
|
$name = $this->normalizeName($batt_manu->getName());
|
||||||
|
$this->bmanu_hash[$name] = $batt_manu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadBatteryModels()
|
||||||
|
{
|
||||||
|
$this->bmodel_hash = [];
|
||||||
|
|
||||||
|
$batt_models = $this->em->getRepository(BatteryModel::class)->findAll();
|
||||||
|
foreach ($batt_models as $batt_model)
|
||||||
|
{
|
||||||
|
$name = $this->normalizeName($batt_model->getName());
|
||||||
|
$this->bmodel_hash[$name] = $batt_model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadBatterySizes()
|
||||||
|
{
|
||||||
|
$this->bsize_hash = [];
|
||||||
|
|
||||||
|
$batt_sizes = $this->em->getRepository(BatterySize::class)->findAll();
|
||||||
|
foreach ($batt_sizes as $batt_size)
|
||||||
|
{
|
||||||
|
$name = $this->normalizeName($batt_size->getName());
|
||||||
|
$this->bsize_hash[$name] = $batt_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadBatteries()
|
||||||
|
{
|
||||||
|
$this->batt_hash = [];
|
||||||
|
|
||||||
|
$batts = $this->em->getRepository(Battery::class)->findAll();
|
||||||
|
foreach ($batts as $batt)
|
||||||
|
{
|
||||||
|
$brand = $this->normalizeName($batt->getManufacturer()->getName());
|
||||||
|
$model = $this->normalizeName($batt->getModel()->getName());
|
||||||
|
$size = $this->normalizeName($batt->getSize()->getName());
|
||||||
|
|
||||||
|
$this->batt_hash[$brand][$model][$size] = $batt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function normalizeName($name)
|
||||||
|
{
|
||||||
|
$normalized_key = trim(strtolower($name));
|
||||||
|
|
||||||
|
return $normalized_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
113
src/Command/ImportCMBBatteryTradeInPriceCommand.php
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
use Doctrine\Common\Persistence\ObjectManager;
|
||||||
|
|
||||||
|
use App\Entity\BatterySize;
|
||||||
|
|
||||||
|
class ImportCMBBatteryTradeInPriceCommand extends Command
|
||||||
|
{
|
||||||
|
const F_SIZE_DESC = 2;
|
||||||
|
const F_TRADEIN_PRICE = 3;
|
||||||
|
|
||||||
|
protected $em;
|
||||||
|
|
||||||
|
protected $bsize_hash;
|
||||||
|
|
||||||
|
public function __construct(ObjectManager $om)
|
||||||
|
{
|
||||||
|
$this->em = $om;
|
||||||
|
|
||||||
|
// load existing sizes
|
||||||
|
$this->loadBatterySizes();
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('cmbbatterydata:importtradeinprice')
|
||||||
|
->setDescription('Import a CSV file with trade in prices.')
|
||||||
|
->setHelp('Adds the battery tradein prices to existing batteries based on imported CSV.')
|
||||||
|
->addArgument('file', InputArgument::REQUIRED, 'Path to the CSV file.');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$csv_file = $input->getArgument('file');
|
||||||
|
|
||||||
|
// attempt to open file
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$fh = fopen($csv_file, "r");
|
||||||
|
}
|
||||||
|
catch (Exception $e)
|
||||||
|
{
|
||||||
|
throw new Exception('The file "' . $csv_file . '" could be read.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// get entity manager
|
||||||
|
$em = $this->em;
|
||||||
|
|
||||||
|
// loop through the rows
|
||||||
|
$row_num = 0;
|
||||||
|
error_log('Processing battery tradein price csv file...');
|
||||||
|
while (($fields = fgetcsv($fh)) !== false)
|
||||||
|
{
|
||||||
|
// data starts at row 2
|
||||||
|
if ($row_num < 2)
|
||||||
|
{
|
||||||
|
$row_num++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tradein price info
|
||||||
|
// battery price info
|
||||||
|
$desc = trim($fields[self::F_SIZE_DESC]);
|
||||||
|
$price = trim($fields[self::F_TRADEIN_PRICE]);
|
||||||
|
|
||||||
|
$clean_price = trim($price, '$');
|
||||||
|
|
||||||
|
$size_info = explode(' ', $desc);
|
||||||
|
|
||||||
|
$size = $size_info[1];
|
||||||
|
|
||||||
|
if (isset($this->bsize_hash[$size]))
|
||||||
|
{
|
||||||
|
$battery_size = $this->bsize_hash[$size];
|
||||||
|
|
||||||
|
// use TIPriceMotolite
|
||||||
|
$battery_size->setTIPriceMotolite($clean_price);
|
||||||
|
|
||||||
|
$this->em->persist($battery_size);
|
||||||
|
$this->em->flush();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error_log('Cannot find battery size ' . $size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadBatterySizes()
|
||||||
|
{
|
||||||
|
$this->bsize_hash = [];
|
||||||
|
|
||||||
|
$batt_sizes = $this->em->getRepository(BatterySize::class)->findAll();
|
||||||
|
foreach ($batt_sizes as $batt_size)
|
||||||
|
{
|
||||||
|
$name = $batt_size->getName();
|
||||||
|
$this->bsize_hash[$name] = $batt_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
447
src/Command/ImportCMBVehicleCompatibilityCommand.php
Normal file
|
|
@ -0,0 +1,447 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
use Doctrine\Common\Persistence\ObjectManager;
|
||||||
|
|
||||||
|
use App\Entity\BatteryManufacturer;
|
||||||
|
use App\Entity\BatteryModel;
|
||||||
|
use App\Entity\BatterySize;
|
||||||
|
use App\Entity\Battery;
|
||||||
|
use App\Entity\VehicleManufacturer;
|
||||||
|
use App\Entity\Vehicle;
|
||||||
|
|
||||||
|
class ImportCMBVehicleCompatibilityCommand extends Command
|
||||||
|
{
|
||||||
|
// field index in csv file
|
||||||
|
const F_VEHICLE_MANUFACTURER = 1;
|
||||||
|
const F_VEHICLE_MAKE = 2;
|
||||||
|
const F_VEHICLE_YEAR = 3;
|
||||||
|
const F_BATT_SDFC = 4;
|
||||||
|
const F_BATT_ULTRAMAX = 5;
|
||||||
|
const F_BATT_MOTOLITE = 6;
|
||||||
|
const F_BATT_MARATHONER = 7;
|
||||||
|
const F_BATT_EXCEL = 8;
|
||||||
|
|
||||||
|
const STR_CENTURY = 'Century';
|
||||||
|
const STR_MOTOLITE = 'Motolite';
|
||||||
|
const STR_MARSHALL = 'Marshall';
|
||||||
|
const STR_SDFC = 'SDFC';
|
||||||
|
const STR_MARATHONER = 'Marathoner';
|
||||||
|
const STR_WETCHARGED = 'Classic WetCharged';
|
||||||
|
const STR_ULTRAMAX = 'ULTRAMAX';
|
||||||
|
const STR_EXCEL = 'Excel';
|
||||||
|
const STR_PRESENT = 'Present';
|
||||||
|
const STR_M_42 = 'M-42';
|
||||||
|
const STR_M42 = 'M42';
|
||||||
|
|
||||||
|
protected $em;
|
||||||
|
|
||||||
|
protected $bmanu_hash;
|
||||||
|
protected $bmodel_hash;
|
||||||
|
protected $bsize_hash;
|
||||||
|
protected $batt_hash;
|
||||||
|
|
||||||
|
protected $vmanu_hash;
|
||||||
|
protected $vmake_hash;
|
||||||
|
|
||||||
|
public function __construct(ObjectManager $om)
|
||||||
|
{
|
||||||
|
$this->em = $om;
|
||||||
|
|
||||||
|
// load existing battery data
|
||||||
|
$this->loadBatteryManufacturers();
|
||||||
|
$this->loadBatteryModels();
|
||||||
|
$this->loadBatterySizes();
|
||||||
|
$this->loadBatteries();
|
||||||
|
|
||||||
|
// load existing vehicle data
|
||||||
|
$this->loadVehicleManufacturers();
|
||||||
|
$this->loadVehicleMakes();
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('cmbvehiclecompatibility:import')
|
||||||
|
->setDescription('Retrieve from a CSV file battery and vehicle information.')
|
||||||
|
->setHelp('Creates battery manufacturers, models, sizes, vehicle makes, and models based on data from imported CSV.')
|
||||||
|
->addArgument('file', InputArgument::REQUIRED, 'Path to the CSV file.');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$csv_file = $input->getArgument('file');
|
||||||
|
|
||||||
|
// attempt to open file
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$fh = fopen($csv_file, "r");
|
||||||
|
}
|
||||||
|
catch (Exception $e)
|
||||||
|
{
|
||||||
|
throw new Exception('The file "' . $csv_file . '" could be read.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// get entity manager
|
||||||
|
$em = $this->em;
|
||||||
|
|
||||||
|
$row_num = 0;
|
||||||
|
error_log('Processing vehicle compatibility csv file...');
|
||||||
|
while (($fields = fgetcsv($fh)) !== false)
|
||||||
|
{
|
||||||
|
$comp_batteries = [];
|
||||||
|
if ($row_num < 2)
|
||||||
|
{
|
||||||
|
$row_num++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize size battery array for cases where the battery size has '/'
|
||||||
|
$sdfc_sizes = [];
|
||||||
|
$ultramax_sizes = [];
|
||||||
|
$motolite_sizes = [];
|
||||||
|
$marathoner_sizes = [];
|
||||||
|
$excel_sizes = [];
|
||||||
|
|
||||||
|
// battery info
|
||||||
|
$sdfc_size = trim($fields[self::F_BATT_SDFC]);
|
||||||
|
$ultramax_size = trim($fields[self::F_BATT_ULTRAMAX]);
|
||||||
|
$motolite_size = trim($fields[self::F_BATT_MOTOLITE]);
|
||||||
|
$marathoner_size = trim($fields[self::F_BATT_MARATHONER]);
|
||||||
|
$excel_size = trim($fields[self::F_BATT_EXCEL]);
|
||||||
|
|
||||||
|
// check the sizes for '/'
|
||||||
|
$pos = stripos($sdfc_size, '/');
|
||||||
|
if ($pos == false)
|
||||||
|
{
|
||||||
|
// no '/' in size
|
||||||
|
$sdfc_sizes[] = $this->normalizeName($sdfc_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we have '/' in size so we have to explode
|
||||||
|
$sizes = explode('/', $sdfc_size);
|
||||||
|
foreach ($sizes as $size)
|
||||||
|
{
|
||||||
|
$sdfc_sizes[] = $this->normalizeName($size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$pos = stripos($motolite_size, '/');
|
||||||
|
if ($pos == false)
|
||||||
|
{
|
||||||
|
// no '/' in size
|
||||||
|
$motolite_sizes[] = $this->normalizeName($motolite_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we have '/' in size so we have to explode
|
||||||
|
$sizes = explode('/', $motolite_size);
|
||||||
|
foreach ($sizes as $size)
|
||||||
|
{
|
||||||
|
$motolite_sizes[] = $this->normalizeName($size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$pos = stripos($marathoner_size, '/');
|
||||||
|
if ($pos == false)
|
||||||
|
{
|
||||||
|
// no '/' in size
|
||||||
|
$marathoner_sizes[] = $this->normalizeName($marathoner_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we have '/' in size so we have to explode
|
||||||
|
$sizes = explode('/', $marathoner_size);
|
||||||
|
foreach ($sizes as $size)
|
||||||
|
{
|
||||||
|
$marathoner_sizes[] = $this->normalizeName($size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$pos = stripos($ultramax_size, '/');
|
||||||
|
if ($pos == false)
|
||||||
|
{
|
||||||
|
// no '/' in size
|
||||||
|
$ultramax_sizes[] = $this->normalizeName($ultramax_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we have '/' in size so we have to explode
|
||||||
|
$sizes = explode('/', $ultramax_size);
|
||||||
|
foreach ($sizes as $size)
|
||||||
|
{
|
||||||
|
$ultramax_sizes[] = $this->normalizeName($size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$pos = stripos($excel_size, '/');
|
||||||
|
if ($pos == false)
|
||||||
|
{
|
||||||
|
// no '/' in size
|
||||||
|
$excel_sizes[] = $this->normalizeName($excel_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we have '/' in size so we have to explode
|
||||||
|
$sizes = explode('/', $excel_size);
|
||||||
|
foreach ($sizes as $size)
|
||||||
|
{
|
||||||
|
$excel_sizes[] = $this->normalizeName($size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// normalize the battery manufacturers and battery models
|
||||||
|
$norm_century = $this->normalizeName(self::STR_CENTURY);
|
||||||
|
$norm_sdfc = $this->normalizeName(self::STR_SDFC);
|
||||||
|
$norm_motolite = $this->normalizeName(self::STR_MOTOLITE);
|
||||||
|
$norm_wetcharged = $this->normalizeName(self::STR_WETCHARGED);
|
||||||
|
$norm_marathoner = $this->normalizeName(self::STR_MARATHONER);
|
||||||
|
$norm_ultramax = $this->normalizeName(self::STR_ULTRAMAX);
|
||||||
|
$norm_excel = $this->normalizeName(self::STR_EXCEL);
|
||||||
|
|
||||||
|
//foreach($sdfc_sizes as $size)
|
||||||
|
//{
|
||||||
|
// error_log('sdfc size ' . $size);
|
||||||
|
//}
|
||||||
|
//foreach($motolite_sizes as $size)
|
||||||
|
//{
|
||||||
|
// error_log('motolite size ' . $size);
|
||||||
|
//}
|
||||||
|
//foreach($marathoner_sizes as $size)
|
||||||
|
//{
|
||||||
|
// error_log('marathoner size ' . $size);
|
||||||
|
//}
|
||||||
|
|
||||||
|
// vehicle info
|
||||||
|
$manufacturer = trim($fields[self::F_VEHICLE_MANUFACTURER]);
|
||||||
|
$make = trim($fields[self::F_VEHICLE_MAKE]);
|
||||||
|
$year = trim($fields[self::F_VEHICLE_YEAR]);
|
||||||
|
|
||||||
|
// vehicle data
|
||||||
|
// check if vehicle manufacturer has been added
|
||||||
|
if (!isset($this->vmanu_hash[$manufacturer]))
|
||||||
|
$this->addVehicleManufacturer($manufacturer);
|
||||||
|
|
||||||
|
// check if vehicle make has been added
|
||||||
|
if (!isset($this->vmake_hash[$manufacturer][$make]))
|
||||||
|
{
|
||||||
|
foreach($sdfc_sizes as $size)
|
||||||
|
{
|
||||||
|
if (!(empty($size)))
|
||||||
|
{
|
||||||
|
if (isset($this->batt_hash[$norm_century][$norm_sdfc][$size]))
|
||||||
|
$comp_batteries[] = $this->batt_hash[$norm_century][$norm_sdfc][$size];
|
||||||
|
else
|
||||||
|
error_log('Not in the system: ' . $norm_century . ' ' . $norm_sdfc . ' ' . $size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach($ultramax_sizes as $size)
|
||||||
|
{
|
||||||
|
if (!(empty($size)))
|
||||||
|
{
|
||||||
|
if (isset($this->batt_hash[$norm_ultramax][$norm_ultramax][$size]))
|
||||||
|
$comp_batteries[] = $this->batt_hash[$norm_ultramax][$norm_ultramax][$size];
|
||||||
|
else
|
||||||
|
error_log('Not in the system: ' . $norm_ultramax . ' ' . $norm_ultramax . ' ' . $size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach($motolite_sizes as $size)
|
||||||
|
{
|
||||||
|
if (!(empty($size)))
|
||||||
|
{
|
||||||
|
if (isset($this->batt_hash[$norm_motolite][$norm_wetcharged][$size]))
|
||||||
|
$comp_batteries[] = $this->batt_hash[$norm_motolite][$norm_wetcharged][$size];
|
||||||
|
else
|
||||||
|
error_log('Not in the system: ' . $norm_motolite . ' ' . $norm_wetcharged . ' ' . $size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach($marathoner_sizes as $size)
|
||||||
|
{
|
||||||
|
if (!(empty($size)))
|
||||||
|
{
|
||||||
|
if (isset($this->batt_hash[$norm_century][$norm_marathoner][$size]))
|
||||||
|
$comp_batteries[] = $this->batt_hash[$norm_century][$norm_marathoner][$size];
|
||||||
|
else
|
||||||
|
error_log('Not in the system: ' . $norm_century . ' ' . $norm_marathoner . ' ' . $size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach($excel_sizes as $size)
|
||||||
|
{
|
||||||
|
if (!(empty($size)))
|
||||||
|
{
|
||||||
|
if (isset($this->batt_hash[$norm_excel][$norm_excel][$size]))
|
||||||
|
$comp_batteries[] = $this->batt_hash[$norm_excel][$norm_excel][$size];
|
||||||
|
else
|
||||||
|
error_log('Not in the system: ' . $norm_excel . ' ' . $norm_excel . ' ' . $size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->addVehicleMake($manufacturer, $make, $year, $comp_batteries);
|
||||||
|
}
|
||||||
|
|
||||||
|
$row_num++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addVehicleManufacturer($name)
|
||||||
|
{
|
||||||
|
// save to db
|
||||||
|
$vehicle_manufacturer = new VehicleManufacturer();
|
||||||
|
|
||||||
|
$vehicle_manufacturer->setName($name);
|
||||||
|
|
||||||
|
$this->em->persist($vehicle_manufacturer);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
// add to hash
|
||||||
|
$this->vmanu_hash[$name] = $vehicle_manufacturer;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addVehicleMake($manufacturer, $make, $year, $batteries)
|
||||||
|
{
|
||||||
|
// save to db
|
||||||
|
$vehicle = new Vehicle();
|
||||||
|
|
||||||
|
$vmanu = $this->vmanu_hash[$manufacturer];
|
||||||
|
|
||||||
|
// parse year from and year to
|
||||||
|
$year_from = '';
|
||||||
|
$year_to = '';
|
||||||
|
|
||||||
|
if (!empty($year))
|
||||||
|
{
|
||||||
|
$model_years = explode('-', $year);
|
||||||
|
$year_from = $model_years[0];
|
||||||
|
if (!empty($year_to))
|
||||||
|
$year_to = $model_years[1];
|
||||||
|
|
||||||
|
// check if $year_to is the string "Present"
|
||||||
|
// if so, set to 0, for now
|
||||||
|
if ($year_to == self::STR_PRESENT)
|
||||||
|
$year_to = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$vehicle->setManufacturer($vmanu)
|
||||||
|
->setMake($make)
|
||||||
|
->setModelYearFrom($year_from)
|
||||||
|
->setModelYearTo($year_to);
|
||||||
|
|
||||||
|
// add vehicle to battery
|
||||||
|
foreach ($batteries as $battery)
|
||||||
|
{
|
||||||
|
$battery->addVehicle($vehicle);
|
||||||
|
$this->em->persist($battery);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add vehicle to manufacturer
|
||||||
|
$vmanu->addVehicle($vehicle);
|
||||||
|
|
||||||
|
$this->em->persist($vmanu);
|
||||||
|
$this->em->persist($vehicle);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
// add to hash
|
||||||
|
$this->vmake_hash[$manufacturer][$make] = $vehicle;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadBatteryManufacturers()
|
||||||
|
{
|
||||||
|
$this->bmanu_hash = [];
|
||||||
|
|
||||||
|
$batt_manufacturers = $this->em->getRepository(BatteryManufacturer::class)->findAll();
|
||||||
|
foreach ($batt_manufacturers as $batt_manu)
|
||||||
|
{
|
||||||
|
$name = $this->normalizeName($batt_manu->getName());
|
||||||
|
$this->bmanu_hash[$name] = $batt_manu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadBatteryModels()
|
||||||
|
{
|
||||||
|
$this->bmodel_hash = [];
|
||||||
|
|
||||||
|
$batt_models = $this->em->getRepository(BatteryModel::class)->findAll();
|
||||||
|
foreach ($batt_models as $batt_model)
|
||||||
|
{
|
||||||
|
$name = $this->normalizeName($batt_model->getName());
|
||||||
|
$this->bmodel_hash[$name] = $batt_model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadBatterySizes()
|
||||||
|
{
|
||||||
|
$this->bsize_hash = [];
|
||||||
|
|
||||||
|
$batt_sizes = $this->em->getRepository(BatterySize::class)->findAll();
|
||||||
|
foreach ($batt_sizes as $batt_size)
|
||||||
|
{
|
||||||
|
$name = $this->normalizeName($batt_size->getName());
|
||||||
|
$this->bsize_hash[$name] = $batt_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadBatteries()
|
||||||
|
{
|
||||||
|
$this->batt_hash = [];
|
||||||
|
|
||||||
|
$batts = $this->em->getRepository(Battery::class)->findAll();
|
||||||
|
foreach ($batts as $batt)
|
||||||
|
{
|
||||||
|
$brand = $this->normalizeName($batt->getManufacturer()->getName());
|
||||||
|
$model = $this->normalizeName($batt->getModel()->getName());
|
||||||
|
$size = $this->normalizeName($batt->getSize()->getName());
|
||||||
|
|
||||||
|
$this->batt_hash[$brand][$model][$size] = $batt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadVehicleManufacturers()
|
||||||
|
{
|
||||||
|
$this->vmanu_hash = [];
|
||||||
|
|
||||||
|
$vmanus = $this->em->getRepository(VehicleManufacturer::class)->findAll();
|
||||||
|
foreach ($vmanus as $vmanu)
|
||||||
|
{
|
||||||
|
$name = $vmanu->getName();
|
||||||
|
$this->vmanu_hash[$name] = $vmanu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadVehicleMakes()
|
||||||
|
{
|
||||||
|
$this->vmake_hash = [];
|
||||||
|
|
||||||
|
$vmakes = $this->em->getRepository(Vehicle::class)->findAll();
|
||||||
|
foreach ($vmakes as $vmake)
|
||||||
|
{
|
||||||
|
$manufacturer = $vmake->getManufacturer()->getName();
|
||||||
|
$make = $vmake->getMake();
|
||||||
|
|
||||||
|
$this->vmake_hash[$manufacturer][$make] = $vmake;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function normalizeName($name)
|
||||||
|
{
|
||||||
|
// check for M-42. Need to convert to M42
|
||||||
|
if (strcasecmp($name, self::STR_M_42) == 0)
|
||||||
|
{
|
||||||
|
$normalized_key = strtolower(self::STR_M42);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$normalized_key = trim(strtolower($name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $normalized_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
59
src/Command/SeedRiderSessionsCommand.php
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
use Doctrine\Common\Persistence\ObjectManager;
|
||||||
|
|
||||||
|
use App\Service\RedisClientProvider;
|
||||||
|
|
||||||
|
use App\Entity\RiderSession;
|
||||||
|
|
||||||
|
class SeedRiderSessionsCommand extends Command
|
||||||
|
{
|
||||||
|
protected $em;
|
||||||
|
protected $redis;
|
||||||
|
|
||||||
|
public function __construct(ObjectManager $om, RedisClientProvider $redis)
|
||||||
|
{
|
||||||
|
$this->em = $om;
|
||||||
|
$this->redis = $redis->getRedisClient();
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('rider:session:seed')
|
||||||
|
->setDescription('Seed current rider sessions')
|
||||||
|
->setHelp('Seed current rider sessions');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
// get all rider sessions
|
||||||
|
$r_sessions = $this->em->getRepository(RiderSession::class)->findAll();
|
||||||
|
foreach ($r_sessions as $session)
|
||||||
|
{
|
||||||
|
// get session id
|
||||||
|
$session_id = $session->getID();
|
||||||
|
|
||||||
|
// get rider id
|
||||||
|
if ($session->getRider() != null)
|
||||||
|
{
|
||||||
|
$rider_id = $session->getRider()->getID();
|
||||||
|
|
||||||
|
// key for redis
|
||||||
|
$redis_key = 'rider.id.' . $session_id;
|
||||||
|
//$output->writeln('key: ' . $redis_key);
|
||||||
|
|
||||||
|
// set to redis cache
|
||||||
|
$this->redis->set($redis_key, $rider_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,7 +24,7 @@ use App\Ramcar\TransactionOrigin;
|
||||||
use App\Ramcar\TradeInType;
|
use App\Ramcar\TradeInType;
|
||||||
use App\Ramcar\JOEventType;
|
use App\Ramcar\JOEventType;
|
||||||
|
|
||||||
use App\Service\InvoiceCreator;
|
use App\Service\InvoiceGeneratorInterface;
|
||||||
use App\Service\RisingTideGateway;
|
use App\Service\RisingTideGateway;
|
||||||
use App\Service\MQTTClient;
|
use App\Service\MQTTClient;
|
||||||
use App\Service\GeofenceTracker;
|
use App\Service\GeofenceTracker;
|
||||||
|
|
@ -817,7 +817,7 @@ class APIController extends Controller
|
||||||
return $res->getReturnResponse();
|
return $res->getReturnResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function requestJobOrder(Request $req, InvoiceCreator $ic, GeofenceTracker $geo)
|
public function requestJobOrder(Request $req, InvoiceGeneratorInterface $ic, GeofenceTracker $geo)
|
||||||
{
|
{
|
||||||
// check required parameters and api key
|
// check required parameters and api key
|
||||||
$required_params = [
|
$required_params = [
|
||||||
|
|
@ -979,7 +979,7 @@ class APIController extends Controller
|
||||||
$icrit->addEntry($batt, $trade_in, 1);
|
$icrit->addEntry($batt, $trade_in, 1);
|
||||||
|
|
||||||
// send to invoice generator
|
// send to invoice generator
|
||||||
$invoice = $ic->processCriteria($icrit);
|
$invoice = $ic->generateInvoice($icrit);
|
||||||
$jo->setInvoice($invoice);
|
$jo->setInvoice($invoice);
|
||||||
|
|
||||||
$em->persist($jo);
|
$em->persist($jo);
|
||||||
|
|
@ -1026,7 +1026,7 @@ class APIController extends Controller
|
||||||
return $res->getReturnResponse();
|
return $res->getReturnResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEstimate(Request $req, InvoiceCreator $ic)
|
public function getEstimate(Request $req, InvoiceGeneratorInterface $ic)
|
||||||
{
|
{
|
||||||
// $this->debugRequest($req);
|
// $this->debugRequest($req);
|
||||||
|
|
||||||
|
|
@ -1126,7 +1126,7 @@ class APIController extends Controller
|
||||||
$icrit->addEntry($batt, $trade_in, 1);
|
$icrit->addEntry($batt, $trade_in, 1);
|
||||||
|
|
||||||
// send to invoice generator
|
// send to invoice generator
|
||||||
$invoice = $ic->processCriteria($icrit);
|
$invoice = $ic->generateInvoice($icrit);
|
||||||
|
|
||||||
// make invoice json data
|
// make invoice json data
|
||||||
$data = [
|
$data = [
|
||||||
|
|
|
||||||
|
|
@ -2,134 +2,51 @@
|
||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
use App\Ramcar\CustomerClassification;
|
|
||||||
use App\Ramcar\FuelType;
|
|
||||||
use App\Ramcar\VehicleStatusCondition;
|
|
||||||
use App\Ramcar\CrudException;
|
use App\Ramcar\CrudException;
|
||||||
|
|
||||||
use App\Entity\Customer;
|
use App\Service\CustomerHandlerInterface;
|
||||||
use App\Entity\CustomerVehicle;
|
|
||||||
use App\Entity\MobileNumber;
|
|
||||||
use App\Entity\Vehicle;
|
|
||||||
use App\Entity\VehicleManufacturer;
|
|
||||||
use App\Entity\Battery;
|
|
||||||
use App\Entity\BatteryManufacturer;
|
|
||||||
|
|
||||||
use Doctrine\ORM\Query;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||||
|
|
||||||
use Catalyst\MenuBundle\Annotation\Menu;
|
use Catalyst\MenuBundle\Annotation\Menu;
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
|
|
||||||
class CustomerController extends Controller
|
class CustomerController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Menu(selected="customer_list")
|
* @Menu(selected="customer_list")
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index(CustomerHandlerInterface $cust_handler)
|
||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted('customer.list', null, 'No access.');
|
$this->denyAccessUnlessGranted('customer.list', null, 'No access.');
|
||||||
|
|
||||||
return $this->render('customer/list.html.twig');
|
$params = $cust_handler->initializeCustomerIndexForm();
|
||||||
|
|
||||||
|
$template = $params['template'];
|
||||||
|
|
||||||
|
return $this->render($template);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rows(Request $req)
|
public function rows(Request $req, CustomerHandlerInterface $cust_handler)
|
||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted('customer.list', null, 'No access.');
|
$this->denyAccessUnlessGranted('customer.list', null, 'No access.');
|
||||||
|
|
||||||
// build query
|
$params = $cust_handler->getCustomers($req);
|
||||||
$tqb = $this->getDoctrine()
|
|
||||||
->getRepository(Customer::class)
|
|
||||||
->createQueryBuilder('q');
|
|
||||||
|
|
||||||
$qb = $this->getDoctrine()
|
|
||||||
->getRepository(Customer::class)
|
|
||||||
->createQueryBuilder('q');
|
|
||||||
|
|
||||||
// get datatable params
|
|
||||||
$datatable = $req->request->get('datatable');
|
|
||||||
|
|
||||||
// count total records
|
|
||||||
$tquery = $tqb->select('COUNT(q)');
|
|
||||||
|
|
||||||
// add filters to count query
|
|
||||||
$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');
|
|
||||||
|
|
||||||
// add filters to query
|
|
||||||
$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.first_name', 'asc');
|
|
||||||
}
|
|
||||||
|
|
||||||
// get rows for this page
|
|
||||||
$obj_rows = $query->setFirstResult($offset)
|
|
||||||
->setMaxResults($perpage)
|
|
||||||
->getQuery()
|
|
||||||
->getResult();
|
|
||||||
|
|
||||||
|
$meta = $params['meta'];
|
||||||
|
$rows = $params['rows'];
|
||||||
|
|
||||||
// process rows
|
// process rows
|
||||||
$rows = [];
|
foreach ($rows as $key => $data) {
|
||||||
foreach ($obj_rows as $orow) {
|
|
||||||
// add row data
|
|
||||||
$row['id'] = $orow->getID();
|
|
||||||
$row['title'] = $orow->getTitle();
|
|
||||||
$row['first_name'] = $orow->getFirstName();
|
|
||||||
$row['last_name'] = $orow->getLastName();
|
|
||||||
$row['customer_classification'] = CustomerClassification::getName($orow->getCustomerClassification());
|
|
||||||
$row['flag_mobile_app'] = $orow->hasMobileApp();
|
|
||||||
$row['app_mobile_number'] = $orow->hasMobileApp() && !empty($orow->getMobileSessions()) ? $orow->getMobileSessions()[0]->getPhoneNumber() : '';
|
|
||||||
$row['flag_active'] = $orow->isActive();
|
|
||||||
$row['flag_csat'] = $orow->isCSAT();
|
|
||||||
|
|
||||||
// TODO: properly add mobile numbers and plate numbers as searchable/sortable fields, use doctrine events
|
|
||||||
$row['mobile_numbers'] = implode("<br>", $orow->getMobileNumberList());
|
|
||||||
$row['plate_numbers'] = implode("<br>", $orow->getPlateNumberList());
|
|
||||||
|
|
||||||
// add row metadata
|
|
||||||
$row['meta'] = [
|
|
||||||
'update_url' => '',
|
|
||||||
'delete_url' => ''
|
|
||||||
];
|
|
||||||
|
|
||||||
// add crud urls
|
// add crud urls
|
||||||
if ($this->isGranted('customer.update'))
|
$cust_id = $rows[$key]['id'];
|
||||||
$row['meta']['update_url'] = $this->generateUrl('customer_update', ['id' => $row['id']]);
|
|
||||||
if ($this->isGranted('customer.delete'))
|
|
||||||
$row['meta']['delete_url'] = $this->generateUrl('customer_delete', ['id' => $row['id']]);
|
|
||||||
|
|
||||||
$rows[] = $row;
|
if ($this->isGranted('customer.update'))
|
||||||
|
$rows[$key]['meta']['update_url'] = $this->generateUrl('customer_update', ['id' => $cust_id]);
|
||||||
|
if ($this->isGranted('customer.delete'))
|
||||||
|
$rows[$key]['meta']['delete_url'] = $this->generateUrl('customer_delete', ['id' => $cust_id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// response
|
// response
|
||||||
|
|
@ -139,347 +56,119 @@ class CustomerController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function fillDropdownParameters(&$params)
|
|
||||||
{
|
|
||||||
$em = $this->getDoctrine()->getManager();
|
|
||||||
|
|
||||||
$params['bmfgs'] = $em->getRepository(BatteryManufacturer::class)->findAll();
|
|
||||||
$params['vmfgs'] = $em->getRepository(VehicleManufacturer::class)->findAll();
|
|
||||||
|
|
||||||
$params['classifications'] = CustomerClassification::getCollection();
|
|
||||||
$params['fuel_types'] = FuelType::getCollection();
|
|
||||||
$params['status_conditions'] = VehicleStatusCondition::getCollection();
|
|
||||||
|
|
||||||
$params['years'] = $this->generateYearOptions();
|
|
||||||
$params['batteries'] = $em->getRepository(Battery::class)->findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Menu(selected="customer_list")
|
* @Menu(selected="customer_list")
|
||||||
*/
|
*/
|
||||||
public function addForm()
|
public function addForm(CustomerHandlerInterface $cust_handler)
|
||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted('customer.add', null, 'No access.');
|
$this->denyAccessUnlessGranted('customer.add', null, 'No access.');
|
||||||
|
|
||||||
$params['obj'] = new Customer();
|
$params = $cust_handler->initializeAddCustomerForm();
|
||||||
$params['mode'] = 'create';
|
|
||||||
|
|
||||||
// get dropdown parameters
|
$template = $params['template'];
|
||||||
$this->fillDropdownParameters($params);
|
|
||||||
|
|
||||||
// response
|
// response
|
||||||
return $this->render('customer/form.html.twig', $params);
|
return $this->render($template, $params);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function setObject($obj, $req)
|
public function addSubmit(Request $req, CustomerHandlerInterface $cust_handler)
|
||||||
{
|
|
||||||
// set and save values
|
|
||||||
$obj->setTitle($req->request->get('title'))
|
|
||||||
->setFirstName($req->request->get('first_name'))
|
|
||||||
->setLastName($req->request->get('last_name'))
|
|
||||||
->setCustomerClassification($req->request->get('customer_classification'))
|
|
||||||
->setCustomerNotes($req->request->get('customer_notes'))
|
|
||||||
->setEmail($req->request->get('email'))
|
|
||||||
->setIsCSAT($req->request->get('flag_csat') ? true : false)
|
|
||||||
->setActive($req->request->get('flag_active') ? true : false);
|
|
||||||
|
|
||||||
// phone numbers
|
|
||||||
$obj->setPhoneMobile($req->request->get('phone_mobile'))
|
|
||||||
->setPhoneLandline($req->request->get('phone_landline'))
|
|
||||||
->setPhoneOffice($req->request->get('phone_office'))
|
|
||||||
->setPhoneFax($req->request->get('phone_fax'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function addSubmit(Request $req, ValidatorInterface $validator)
|
|
||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted('customer.add', null, 'No access.');
|
$this->denyAccessUnlessGranted('customer.add', null, 'No access.');
|
||||||
|
|
||||||
// create new row
|
$result = $cust_handler->addCustomer($req);
|
||||||
$em = $this->getDoctrine()->getManager();
|
|
||||||
$row = new Customer();
|
|
||||||
|
|
||||||
$this->setObject($row, $req);
|
if (isset($result['id']))
|
||||||
|
{
|
||||||
// initialize error lists
|
$id = $result['id'];
|
||||||
$error_array = [];
|
|
||||||
$nerror_array = [];
|
|
||||||
$verror_array = [];
|
|
||||||
|
|
||||||
// error_log(print_r($req->request->all(), true));
|
|
||||||
|
|
||||||
// custom validation for vehicles
|
|
||||||
$vehicles = json_decode($req->request->get('vehicles'));
|
|
||||||
|
|
||||||
if (!empty($vehicles)) {
|
|
||||||
foreach ($vehicles as $vehicle) {
|
|
||||||
// check if vehicle exists
|
|
||||||
$vobj = $em->getRepository(Vehicle::class)->find($vehicle->vehicle);
|
|
||||||
|
|
||||||
if (empty($vobj)) {
|
|
||||||
$verror_array[$vehicle->index]['vehicle'] = 'Invalid vehicle specified.';
|
|
||||||
} else {
|
|
||||||
$cust_vehicle = new CustomerVehicle();
|
|
||||||
$cust_vehicle->setName($vehicle->name)
|
|
||||||
->setVehicle($vobj)
|
|
||||||
->setPlateNumber($vehicle->plate_number)
|
|
||||||
->setModelYear($vehicle->model_year)
|
|
||||||
->setColor($vehicle->color)
|
|
||||||
->setStatusCondition($vehicle->status_condition)
|
|
||||||
->setFuelType($vehicle->fuel_type)
|
|
||||||
->setActive($vehicle->flag_active)
|
|
||||||
->setCustomer($row);
|
|
||||||
|
|
||||||
// if specified, check if battery exists
|
|
||||||
if ($vehicle->battery) {
|
|
||||||
// check if battery exists
|
|
||||||
$bobj = $em->getRepository(Battery::class)->find($vehicle->battery);
|
|
||||||
|
|
||||||
if (empty($bobj)) {
|
|
||||||
$verror_array[$vehicle->index]['battery'] = 'Invalid battery specified.';
|
|
||||||
} else {
|
|
||||||
// check if warranty expiration was specified
|
|
||||||
$warr_ex = DateTime::createFromFormat("d M Y", $vehicle->warranty_expiration);
|
|
||||||
if (!$warr_ex)
|
|
||||||
$warr_ex = null;
|
|
||||||
|
|
||||||
$cust_vehicle->setHasMotoliteBattery(true)
|
|
||||||
->setCurrentBattery($bobj)
|
|
||||||
->setWarrantyCode($vehicle->warranty_code)
|
|
||||||
->setWarrantyExpiration($warr_ex);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$cust_vehicle->setHasMotoliteBattery(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
$verrors = $validator->validate($cust_vehicle);
|
|
||||||
|
|
||||||
// add errors to list
|
|
||||||
foreach ($verrors as $error) {
|
|
||||||
if (!isset($verror_array[$vehicle->index]))
|
|
||||||
$verror_array[$vehicle->index] = [];
|
|
||||||
|
|
||||||
$verror_array[$vehicle->index][$error->getPropertyPath()] = $error->getMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
// add to entity
|
|
||||||
if (!isset($verror_array[$vehicle->index])) {
|
|
||||||
$row->addVehicle($cust_vehicle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate
|
|
||||||
$errors = $validator->validate($row);
|
|
||||||
|
|
||||||
// add errors to list
|
|
||||||
foreach ($errors as $error) {
|
|
||||||
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if any errors were found
|
|
||||||
if (!empty($error_array) || !empty($nerror_array) || !empty($verror_array)) {
|
|
||||||
// return validation failure response
|
|
||||||
return $this->json([
|
|
||||||
'success' => false,
|
|
||||||
'errors' => $error_array,
|
|
||||||
'nerrors' => $nerror_array,
|
|
||||||
'verrors' => $verror_array
|
|
||||||
], 422);
|
|
||||||
} else {
|
|
||||||
// validated! save the entity
|
|
||||||
$em->persist($row);
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
// return successful response
|
// return successful response
|
||||||
return $this->json([
|
return $this->json([
|
||||||
'success' => 'Changes have been saved!',
|
'success' => 'Changes have been saved!',
|
||||||
'id' => $row->getID()
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Menu(selected="customer_list")
|
|
||||||
*/
|
|
||||||
public function updateForm($id)
|
|
||||||
{
|
|
||||||
$this->denyAccessUnlessGranted('customer.update', null, 'No access.');
|
|
||||||
|
|
||||||
$params['mode'] = 'update';
|
|
||||||
|
|
||||||
// get row data
|
|
||||||
$em = $this->getDoctrine()->getManager();
|
|
||||||
$row = $em->getRepository(Customer::class)->find($id);
|
|
||||||
|
|
||||||
// make sure this row exists
|
|
||||||
if (empty($row))
|
|
||||||
throw $this->createNotFoundException('The item does not exist');
|
|
||||||
|
|
||||||
// get dropdown parameters
|
|
||||||
$this->fillDropdownParameters($params);
|
|
||||||
|
|
||||||
$params['obj'] = $row;
|
|
||||||
|
|
||||||
// response
|
|
||||||
return $this->render('customer/form.html.twig', $params);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function updateVehicles($em, Customer $cust, $vehicles)
|
|
||||||
{
|
|
||||||
$vehicle_ids = [];
|
|
||||||
|
|
||||||
foreach ($vehicles as $vehicle)
|
|
||||||
{
|
|
||||||
// check if customer vehicle exists
|
|
||||||
if (!empty($vehicle->id))
|
|
||||||
{
|
|
||||||
$cust_vehicle = $em->getRepository(CustomerVehicle::class)->find($vehicle->id);
|
|
||||||
if ($cust_vehicle == null)
|
|
||||||
throw new CrudException("Could not find customer vehicle.");
|
|
||||||
|
|
||||||
}
|
|
||||||
// this is a new vehicle
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$cust_vehicle = new CustomerVehicle();
|
|
||||||
$cust_vehicle->setCustomer($cust);
|
|
||||||
$cust->addVehicle($cust_vehicle);
|
|
||||||
$em->persist($cust_vehicle);
|
|
||||||
}
|
|
||||||
|
|
||||||
// vehicle, because they could have changed vehicle type
|
|
||||||
$vobj = $em->getRepository(Vehicle::class)->find($vehicle->vehicle);
|
|
||||||
if ($vobj == null)
|
|
||||||
throw new CrudException("Could not find vehicle.");
|
|
||||||
|
|
||||||
// TODO: validate details
|
|
||||||
|
|
||||||
$cust_vehicle->setName($vehicle->name)
|
|
||||||
->setVehicle($vobj)
|
|
||||||
->setPlateNumber($vehicle->plate_number)
|
|
||||||
->setModelYear($vehicle->model_year)
|
|
||||||
->setColor($vehicle->color)
|
|
||||||
->setStatusCondition($vehicle->status_condition)
|
|
||||||
->setFuelType($vehicle->fuel_type)
|
|
||||||
->setActive($vehicle->flag_active);
|
|
||||||
|
|
||||||
// if specified, check if battery exists
|
|
||||||
if ($vehicle->battery)
|
|
||||||
{
|
|
||||||
// check if battery exists
|
|
||||||
$bobj = $em->getRepository(Battery::class)->find($vehicle->battery);
|
|
||||||
if ($bobj == null)
|
|
||||||
throw new CrudException("Could not find battery.");
|
|
||||||
|
|
||||||
// check if warranty expiration was specified
|
|
||||||
$warr_ex = DateTime::createFromFormat("d M Y", $vehicle->warranty_expiration);
|
|
||||||
if (!$warr_ex)
|
|
||||||
$warr_ex = null;
|
|
||||||
|
|
||||||
$cust_vehicle->setHasMotoliteBattery(true)
|
|
||||||
->setCurrentBattery($bobj)
|
|
||||||
->setWarrantyCode($vehicle->warranty_code)
|
|
||||||
->setWarrantyExpiration($warr_ex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$cust_vehicle->setHasMotoliteBattery(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// add to list of vehicles to keep
|
|
||||||
$vehicle_ids[$cust_vehicle->getID()] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleanup
|
|
||||||
// delete all vehicles not in list
|
|
||||||
$cvs = $cust->getVehicles();
|
|
||||||
foreach ($cvs as $cv)
|
|
||||||
{
|
|
||||||
if (!isset($vehicle_ids[$cv->getID()]))
|
|
||||||
{
|
|
||||||
$cust->removeVehicle($cv);
|
|
||||||
$em->remove($cv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updateSubmit(Request $req, ValidatorInterface $validator, $id)
|
|
||||||
{
|
|
||||||
$this->denyAccessUnlessGranted('customer.update', null, 'No access.');
|
|
||||||
|
|
||||||
// get row data
|
|
||||||
$em = $this->getDoctrine()->getManager();
|
|
||||||
$cust = $em->getRepository(Customer::class)->find($id);
|
|
||||||
|
|
||||||
// make sure this row exists
|
|
||||||
if (empty($cust))
|
|
||||||
throw $this->createNotFoundException('The item does not exist');
|
|
||||||
|
|
||||||
$this->setObject($cust, $req);
|
|
||||||
|
|
||||||
// initialize error lists
|
|
||||||
$error_array = [];
|
|
||||||
$nerror_array = [];
|
|
||||||
$verror_array = [];
|
|
||||||
|
|
||||||
// TODO: validate mobile numbers
|
|
||||||
// TODO: validate vehicles
|
|
||||||
|
|
||||||
// custom validation for vehicles
|
|
||||||
$vehicles = json_decode($req->request->get('vehicles'));
|
|
||||||
$this->updateVehicles($em, $cust, $vehicles);
|
|
||||||
|
|
||||||
// validate
|
|
||||||
$errors = $validator->validate($cust);
|
|
||||||
|
|
||||||
// add errors to list
|
|
||||||
foreach ($errors as $error)
|
|
||||||
{
|
|
||||||
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if any errors were found
|
|
||||||
if (!empty($error_array) || !empty($nerror_array) || !empty($verror_array))
|
|
||||||
{
|
|
||||||
// return validation failure response
|
|
||||||
return $this->json([
|
|
||||||
'success' => false,
|
|
||||||
'errors' => $error_array,
|
|
||||||
'nerrors' => $nerror_array,
|
|
||||||
'verrors' => $verror_array
|
|
||||||
], 422);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// validated! save the entity. do a persist anyway to save child entities
|
$error_array = $result['error_array'];
|
||||||
$em->persist($cust);
|
$nerror_array = $result['nerror_array'];
|
||||||
$em->flush();
|
$verror_array = $result['verror_array'];
|
||||||
|
|
||||||
|
// return validation failure response
|
||||||
|
return $this->json([
|
||||||
|
'success' => false,
|
||||||
|
'errors' => $error_array,
|
||||||
|
'nerrors' => $nerror_array,
|
||||||
|
'verrors' => $verror_array
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Menu(selected="customer_list")
|
||||||
|
*/
|
||||||
|
public function updateForm($id, CustomerHandlerInterface $cust_handler)
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted('customer.update', null, 'No access.');
|
||||||
|
|
||||||
|
$params = $cust_handler->initializeUpdateCustomerForm($id);
|
||||||
|
|
||||||
|
$template = $params['template'];
|
||||||
|
|
||||||
|
// response
|
||||||
|
return $this->render($template, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateSubmit(Request $req, CustomerHandlerInterface $cust_handler, $id)
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted('customer.update', null, 'No access.');
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$result = $cust_handler->updateCustomer($req, $id);
|
||||||
|
}
|
||||||
|
catch (CrudException $e)
|
||||||
|
{
|
||||||
|
throw new CrudException($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($result['id']))
|
||||||
|
{
|
||||||
|
$id = $result['id'];
|
||||||
|
|
||||||
// return successful response
|
// return successful response
|
||||||
return $this->json([
|
return $this->json([
|
||||||
'success' => 'Changes have been saved!',
|
'success' => 'Changes have been saved!',
|
||||||
'id' => $cust->getID()
|
'id' => $id
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$error_array = $result['error_array'];
|
||||||
|
$nerror_array = $result['nerror_array'];
|
||||||
|
$verror_array = $result['verror_array'];
|
||||||
|
|
||||||
|
// return validation failure response
|
||||||
|
return $this->json([
|
||||||
|
'success' => false,
|
||||||
|
'errors' => $error_array,
|
||||||
|
'nerrors' => $nerror_array,
|
||||||
|
'verrors' => $verror_array
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function destroy($id)
|
public function destroy($id, CustomerHandlerInterface $cust_handler)
|
||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted('customer.delete', null, 'No access.');
|
$this->denyAccessUnlessGranted('customer.delete', null, 'No access.');
|
||||||
|
|
||||||
// get row data
|
try
|
||||||
$em = $this->getDoctrine()->getManager();
|
{
|
||||||
$row = $em->getRepository(Customer::class)->find($id);
|
$cust_handler->deleteCustomer($id);
|
||||||
|
}
|
||||||
if (empty($row))
|
catch (NotFoundHttpException $e)
|
||||||
throw $this->createNotFoundException('The item does not exist');
|
{
|
||||||
|
throw $this->createNotFoundException($e->getMessage());
|
||||||
// delete this row
|
}
|
||||||
$em->remove($row);
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
// response
|
// response
|
||||||
$response = new Response();
|
$response = new Response();
|
||||||
|
|
@ -487,110 +176,17 @@ class CustomerController extends Controller
|
||||||
$response->send();
|
$response->send();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function generateYearOptions()
|
public function getCustomerVehicles(Request $req, CustomerHandlerInterface $cust_handler)
|
||||||
{
|
|
||||||
$start_year = 1950;
|
|
||||||
return range($start_year, date("Y") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCustomerVehicles(Request $req)
|
|
||||||
{
|
{
|
||||||
if (!$this->isGranted('jo_in.list')) {
|
if (!$this->isGranted('jo_in.list')) {
|
||||||
$exception = $this->createAccessDeniedException('No access.');
|
$exception = $this->createAccessDeniedException('No access.');
|
||||||
throw $exception;
|
throw $exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get search term
|
$results = $cust_handler->getCustomerVehicles($req);
|
||||||
$term = $req->query->get('search');
|
|
||||||
|
|
||||||
// get querybuilder
|
$vehicles = $results['vehicles'];
|
||||||
$qb = $this->getDoctrine()
|
$has_more_pages = $results['has_more_pages'];
|
||||||
->getRepository(CustomerVehicle::class)
|
|
||||||
->createQueryBuilder('q');
|
|
||||||
|
|
||||||
/*
|
|
||||||
// build expression now since we're reusing it
|
|
||||||
$vehicle_label = $qb->expr()->concat(
|
|
||||||
'q.plate_number',
|
|
||||||
$qb->expr()->literal(' - '),
|
|
||||||
'c.first_name',
|
|
||||||
$qb->expr()->literal(' '),
|
|
||||||
'c.last_name',
|
|
||||||
$qb->expr()->literal(' (+63'),
|
|
||||||
'c.phone_mobile',
|
|
||||||
$qb->expr()->literal(')')
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
|
|
||||||
// count total records
|
|
||||||
$tquery = $qb->select('COUNT(q)');
|
|
||||||
|
|
||||||
// add filters to count query
|
|
||||||
if (!empty($term)) {
|
|
||||||
$tquery->where('q.plate_number like :search')
|
|
||||||
->setParameter('search', $term . '%');
|
|
||||||
/*
|
|
||||||
$tquery->where('match_against (q.plate_number, :search \'in boolean mode\') > 0.1')
|
|
||||||
->setParameter('search', $term . '*');
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
$tquery->where('q.plate_number LIKE :filter')
|
|
||||||
->setParameter('filter', '%' . $term . '%');
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
$total = $tquery->getQuery()
|
|
||||||
->getSingleScalarResult();
|
|
||||||
|
|
||||||
// pagination vars
|
|
||||||
$page = $req->query->get('page') ?? 1;
|
|
||||||
$perpage = 20;
|
|
||||||
$offset = ($page - 1) * $perpage;
|
|
||||||
$pages = ceil($total / $perpage);
|
|
||||||
$has_more_pages = $page < $pages ? true : false;
|
|
||||||
|
|
||||||
// build main query
|
|
||||||
$query = $qb->select('q');
|
|
||||||
/*
|
|
||||||
->addSelect($vehicle_label . ' as vehicle_label')
|
|
||||||
->addSelect('c.first_name as cust_first_name')
|
|
||||||
->addSelect('c.last_name as cust_last_name');
|
|
||||||
*/
|
|
||||||
|
|
||||||
// add filters if needed
|
|
||||||
if (!empty($term)) {
|
|
||||||
$query->where('q.plate_number like :search')
|
|
||||||
->setParameter('search', $term . '%');
|
|
||||||
/*
|
|
||||||
$query->where('match_against (q.plate_number, :search \'in boolean mode\') > 0.1')
|
|
||||||
->setParameter('search', $term . '*');
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
$query->where('q.plate_number LIKE :filter')
|
|
||||||
->setParameter('filter', '%' . $term . '%');
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// get rows
|
|
||||||
$query_obj = $query->orderBy('q.plate_number', 'asc')
|
|
||||||
->setFirstResult($offset)
|
|
||||||
->setMaxResults($perpage)
|
|
||||||
->getQuery();
|
|
||||||
// error_log($query_obj->getSql());
|
|
||||||
|
|
||||||
$obj_rows = $query_obj->getResult();
|
|
||||||
|
|
||||||
// build vehicles array
|
|
||||||
$vehicles = [];
|
|
||||||
|
|
||||||
foreach ($obj_rows as $cv) {
|
|
||||||
$cust = $cv->getCustomer();
|
|
||||||
$vehicles[] = [
|
|
||||||
'id' => $cv->getID(),
|
|
||||||
'text' => $cv->getPlateNumber() . ' ' . $cust->getFirstName() . ' ' . $cust->getLastName() . ' (+63' . $cust->getPhoneMobile() . ')',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// response
|
// response
|
||||||
return $this->json([
|
return $this->json([
|
||||||
|
|
@ -602,85 +198,26 @@ class CustomerController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCustomerVehicleInfo(Request $req)
|
public function getCustomerVehicleInfo(Request $req, CustomerHandlerInterface $cust_handler)
|
||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted('jo_in.list', null, 'No access.');
|
$this->denyAccessUnlessGranted('jo_in.list', null, 'No access.');
|
||||||
|
|
||||||
// get id
|
$result = $cust_handler->getCustomerVehicleInfo($req);
|
||||||
$id = $req->query->get('id');
|
|
||||||
|
|
||||||
// get row data
|
if ($result == null)
|
||||||
$em = $this->getDoctrine()->getManager();
|
{
|
||||||
$obj = $em->getRepository(CustomerVehicle::class)->find($id);
|
|
||||||
|
|
||||||
// make sure this row exists
|
|
||||||
if (empty($obj)) {
|
|
||||||
return $this->json([
|
return $this->json([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
'error' => 'The item does not exist'
|
'error' => 'The item does not exist'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
$customer = $obj->getCustomer();
|
{
|
||||||
$vehicle = $obj->getVehicle();
|
// response
|
||||||
$battery = $obj->getCurrentBattery();
|
return $this->json([
|
||||||
|
'success' => true,
|
||||||
// build response
|
'data' => $result
|
||||||
$row = [
|
]);
|
||||||
'customer' => [
|
|
||||||
'id' => $customer->getID(),
|
|
||||||
'first_name' => $customer->getFirstName(),
|
|
||||||
'last_name' => $customer->getLastName(),
|
|
||||||
'customer_notes' => $customer->getCustomerNotes(),
|
|
||||||
'phone_mobile' => $customer->getPhoneMobile(),
|
|
||||||
'phone_landline' => $customer->getPhoneLandline(),
|
|
||||||
'phone_office' => $customer->getPhoneOffice(),
|
|
||||||
'phone_fax' => $customer->getPhoneFax(),
|
|
||||||
],
|
|
||||||
'vehicle' => [
|
|
||||||
'id' => $vehicle->getID(),
|
|
||||||
'mfg_name' => $vehicle->getManufacturer()->getName(),
|
|
||||||
'make' => $vehicle->getMake(),
|
|
||||||
'model_year_from' => $vehicle->getModelYearFrom(),
|
|
||||||
'model_year_to' => $vehicle->getModelYearTo(),
|
|
||||||
'model_year' => $obj->getModelYear(),
|
|
||||||
'color' => $obj->getColor(),
|
|
||||||
'plate_number' => $obj->getPlateNumber(),
|
|
||||||
//'fuel_type' => $obj->getFuelType(),
|
|
||||||
//'status_condition' => $obj->getStatusCondition(),
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
if (!empty($battery)) {
|
|
||||||
$row['battery'] = [
|
|
||||||
'id' => $battery->getID(),
|
|
||||||
'mfg_name' => $battery->getManufacturer()->getName(),
|
|
||||||
'model_name' => $battery->getModel()->getName(),
|
|
||||||
'size_name' => $battery->getSize()->getName(),
|
|
||||||
'prod_code' => $battery->getProductCode(),
|
|
||||||
'warranty_code' => $obj->getWarrantyCode(),
|
|
||||||
'warranty_expiration' => $obj->getWarrantyExpiration() ? $obj->getWarrantyExpiration()->format("d M Y") : "",
|
|
||||||
'has_motolite_battery' => $obj->hasMotoliteBattery(),
|
|
||||||
'is_active' => $obj->isActive()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// response
|
|
||||||
return $this->json([
|
|
||||||
'success' => true,
|
|
||||||
'data' => $row
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if datatable filter is present and append to query
|
|
||||||
protected function setQueryFilters($datatable, &$query) {
|
|
||||||
if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) {
|
|
||||||
$query->join('q.vehicles', 'cv')
|
|
||||||
->where('q.first_name LIKE :filter')
|
|
||||||
->orWhere('q.last_name LIKE :filter')
|
|
||||||
->orWhere('q.customer_classification LIKE :filter')
|
|
||||||
->orWhere('cv.plate_number LIKE :filter')
|
|
||||||
->setParameter('filter', $datatable['query']['data-rows-search'] . '%');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,84 @@ namespace App\Controller;
|
||||||
use Catalyst\MenuBundle\Annotation\Menu;
|
use Catalyst\MenuBundle\Annotation\Menu;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
use App\Service\RiderTracker;
|
||||||
|
use App\Service\GISManagerInterface;
|
||||||
|
|
||||||
|
use App\Entity\Rider;
|
||||||
|
|
||||||
|
|
||||||
class HomeController extends Controller
|
class HomeController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @Menu(selected="home")
|
* @Menu(selected="home")
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index(EntityManagerInterface $em, RiderTracker $rider_tracker,
|
||||||
|
GISManagerInterface $gis_manager)
|
||||||
{
|
{
|
||||||
return $this->render('home.html.twig');
|
// get map
|
||||||
|
$params['map_js_file'] = $gis_manager->getJSInitFile();
|
||||||
|
|
||||||
|
return $this->render('home.html.twig', $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRiderLocations(EntityManagerInterface $em, RiderTracker $rider_tracker)
|
||||||
|
{
|
||||||
|
// get all riders
|
||||||
|
$riders = $em->getRepository(Rider::class)->findAll();
|
||||||
|
|
||||||
|
$locations = [];
|
||||||
|
foreach ($riders as $rider)
|
||||||
|
{
|
||||||
|
// get location for each rider
|
||||||
|
$rider_id = $rider->getID();
|
||||||
|
$coordinates = $rider_tracker->getRiderLocation($rider_id);
|
||||||
|
|
||||||
|
$lat = $coordinates->getLatitude();
|
||||||
|
$long = $coordinates->getLongitude();
|
||||||
|
|
||||||
|
$jo = $rider->getActiveJobOrder();
|
||||||
|
if ($jo == null)
|
||||||
|
{
|
||||||
|
$has_jo = false;
|
||||||
|
$clat = 0;
|
||||||
|
$clong = 0;
|
||||||
|
$jo_data = [];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$has_jo = true;
|
||||||
|
$cust_loc = $jo->getCoordinates();
|
||||||
|
$clat = $cust_loc->getLatitude();
|
||||||
|
$clong = $cust_loc->getLongitude();
|
||||||
|
$jo_id = $jo->getID();
|
||||||
|
$jo_data = [
|
||||||
|
'id' => $jo_id,
|
||||||
|
'status' => $jo->getStatusText(),
|
||||||
|
'stype' => $jo->getServiceTypeName(),
|
||||||
|
'url' => $this->generateUrl('jo_all_form', ['id' => $jo_id]),
|
||||||
|
'plate' => $jo->getCustomerVehicle()->getPlateNumber(),
|
||||||
|
'cname' => $jo->getCustomer()->getNameDisplay(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// use rider map label as key
|
||||||
|
$rider_map_label = $rider->getMapLabel();
|
||||||
|
$locations[$rider_id] = [
|
||||||
|
'label' => $rider->getMapLabel(),
|
||||||
|
'loc' => [$lat, $long],
|
||||||
|
'has_jo' => $has_jo,
|
||||||
|
'cust_loc' => [$clat, $clong],
|
||||||
|
'jo' => $jo_data,
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json([
|
||||||
|
'riders' => $locations,
|
||||||
|
]);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@ use DateTime;
|
||||||
|
|
||||||
use Catalyst\MenuBundle\Annotation\Menu;
|
use Catalyst\MenuBundle\Annotation\Menu;
|
||||||
|
|
||||||
|
use App\Service\MapTools;
|
||||||
|
use App\Service\RiderTracker;
|
||||||
|
|
||||||
class HubController extends Controller
|
class HubController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
@ -287,4 +290,86 @@ class HubController extends Controller
|
||||||
$response->setStatusCode(Response::HTTP_OK);
|
$response->setStatusCode(Response::HTTP_OK);
|
||||||
$response->send();
|
$response->send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function nearest(MapTools $map_tools, Request $req)
|
||||||
|
{
|
||||||
|
// get lat / long
|
||||||
|
$lat = $req->query->get('lat');
|
||||||
|
$long = $req->query->get('long');
|
||||||
|
|
||||||
|
// get nearest hubs according to position
|
||||||
|
$point = new Point($long, $lat);
|
||||||
|
$result = $map_tools->getClosestHubs($point, 10, date("H:i:s"));
|
||||||
|
|
||||||
|
$hubs = [];
|
||||||
|
foreach ($result as $hub_res)
|
||||||
|
{
|
||||||
|
$hub = $hub_res['hub'];
|
||||||
|
$coords = $hub->getCoordinates();
|
||||||
|
$hubs[] = [
|
||||||
|
'id' => $hub->getID(),
|
||||||
|
'long' => $coords->getLongitude(),
|
||||||
|
'lat' => $coords->getLatitude(),
|
||||||
|
'label' => $hub->getFullName(),
|
||||||
|
'name' => $hub->getName(),
|
||||||
|
'branch' => $hub->getBranch(),
|
||||||
|
'cnum' => $hub->getContactNumbers(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json([
|
||||||
|
'hubs' => $hubs,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHubRiders(Request $req, RiderTracker $rider_tracker)
|
||||||
|
{
|
||||||
|
// get hub id
|
||||||
|
$hub_id = $req->query->get('id');
|
||||||
|
|
||||||
|
// get hub
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
$hub = $em->getRepository(Hub::class)->find($hub_id);
|
||||||
|
|
||||||
|
// make sure this row exists
|
||||||
|
if (empty($hub))
|
||||||
|
throw $this->createNotFoundException('The item does not exist');
|
||||||
|
|
||||||
|
//TODO: get available riders sort by proximity, show 10
|
||||||
|
$available_riders = $hub->getAvailableRiders();
|
||||||
|
|
||||||
|
$riders = [];
|
||||||
|
|
||||||
|
// TODO: remove this later when we don't get all available riders
|
||||||
|
$riders_limit = 5;
|
||||||
|
$num_riders = 0;
|
||||||
|
|
||||||
|
foreach ($available_riders as $rider)
|
||||||
|
{
|
||||||
|
if ($num_riders > $riders_limit)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// get location for each rider
|
||||||
|
$rider_id = $rider->getID();
|
||||||
|
$coordinates = $rider_tracker->getRiderLocation($rider_id);
|
||||||
|
|
||||||
|
$lat = $coordinates->getLatitude();
|
||||||
|
$long = $coordinates->getLongitude();
|
||||||
|
|
||||||
|
$riders[] = [
|
||||||
|
'id' => $rider->getID(),
|
||||||
|
'first_name' => $rider->getFirstName(),
|
||||||
|
'last_name' => $rider->getLastName(),
|
||||||
|
'contact_num' => $rider->getContactNumber(),
|
||||||
|
'plate_num' => $rider->getPlateNumber(),
|
||||||
|
'location' => [$lat, $long],
|
||||||
|
];
|
||||||
|
|
||||||
|
$num_riders++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json([
|
||||||
|
'riders' => $riders,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,17 +16,18 @@ use CrEOF\Spatial\PHP\Types\Geometry\Point;
|
||||||
use App\Ramcar\APIResult;
|
use App\Ramcar\APIResult;
|
||||||
use App\Ramcar\JOStatus;
|
use App\Ramcar\JOStatus;
|
||||||
use App\Ramcar\InvoiceCriteria;
|
use App\Ramcar\InvoiceCriteria;
|
||||||
use App\Ramcar\ServiceType;
|
use App\Ramcar\CMBServiceType;
|
||||||
use App\Ramcar\WarrantyClass;
|
use App\Ramcar\WarrantyClass;
|
||||||
use App\Ramcar\APIRiderStatus;
|
use App\Ramcar\APIRiderStatus;
|
||||||
use App\Ramcar\TransactionOrigin;
|
use App\Ramcar\TransactionOrigin;
|
||||||
use App\Ramcar\TradeInType;
|
use App\Ramcar\CMBTradeInType;
|
||||||
use App\Ramcar\InvoiceStatus;
|
use App\Ramcar\InvoiceStatus;
|
||||||
use App\Ramcar\ModeOfPayment;
|
use App\Ramcar\ModeOfPayment;
|
||||||
use App\Ramcar\JOEventType;
|
use App\Ramcar\JOEventType;
|
||||||
|
|
||||||
use App\Service\InvoiceCreator;
|
use App\Service\InvoiceGeneratorInterface;
|
||||||
use App\Service\MQTTClient;
|
use App\Service\MQTTClient;
|
||||||
|
use App\Service\RedisClientProvider;
|
||||||
|
|
||||||
use App\Entity\RiderSession;
|
use App\Entity\RiderSession;
|
||||||
use App\Entity\Customer;
|
use App\Entity\Customer;
|
||||||
|
|
@ -42,9 +43,10 @@ use App\Entity\RiderRating;
|
||||||
use App\Entity\Rider;
|
use App\Entity\Rider;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
use App\Entity\JOEvent;
|
use App\Entity\JOEvent;
|
||||||
|
use App\Entity\Warranty;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
|
use DateInterval;
|
||||||
|
|
||||||
// Rider API controller
|
// Rider API controller
|
||||||
class RAPIController extends Controller
|
class RAPIController extends Controller
|
||||||
|
|
@ -135,7 +137,7 @@ class RAPIController extends Controller
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function register(Request $req)
|
public function register(Request $req, RedisClientProvider $redis)
|
||||||
{
|
{
|
||||||
$res = new APIResult();
|
$res = new APIResult();
|
||||||
|
|
||||||
|
|
@ -178,6 +180,12 @@ class RAPIController extends Controller
|
||||||
// save
|
// save
|
||||||
$em->persist($sess);
|
$em->persist($sess);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
|
||||||
|
// create redis entry for the session
|
||||||
|
$redis_client = $redis->getRedisClient();
|
||||||
|
$redis_key = 'rider.id.' . $sess->getID();
|
||||||
|
error_log('redis_key: ' . $redis_key);
|
||||||
|
$redis_client->set($redis_key, '');
|
||||||
}
|
}
|
||||||
catch (DBALException $e)
|
catch (DBALException $e)
|
||||||
{
|
{
|
||||||
|
|
@ -201,7 +209,7 @@ class RAPIController extends Controller
|
||||||
return $res->getReturnResponse();
|
return $res->getReturnResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function login(Request $req, EncoderFactoryInterface $ef)
|
public function login(Request $req, EncoderFactoryInterface $ef, RedisClientProvider $redis)
|
||||||
{
|
{
|
||||||
$required_params = [
|
$required_params = [
|
||||||
'user',
|
'user',
|
||||||
|
|
@ -247,6 +255,13 @@ class RAPIController extends Controller
|
||||||
|
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
|
||||||
|
// update redis rider.id.<session id> with the rider id
|
||||||
|
$redis_client = $redis->getRedisClient();
|
||||||
|
$redis_key = 'rider.id.' . $this->session->getID();
|
||||||
|
$rider_id = $rider->getID();
|
||||||
|
|
||||||
|
$redis_client->set($redis_key, $rider_id);
|
||||||
|
|
||||||
$hub = $rider->getHub();
|
$hub = $rider->getHub();
|
||||||
if ($hub == null)
|
if ($hub == null)
|
||||||
$hub_data = null;
|
$hub_data = null;
|
||||||
|
|
@ -634,6 +649,12 @@ class RAPIController extends Controller
|
||||||
];
|
];
|
||||||
$mclient->sendEvent($jo, $payload);
|
$mclient->sendEvent($jo, $payload);
|
||||||
|
|
||||||
|
// create the warranty if new battery only
|
||||||
|
if ($jo->getServiceType () == CMBServiceType::BATTERY_REPLACEMENT_NEW)
|
||||||
|
{
|
||||||
|
$this->createWarranty($jo);
|
||||||
|
}
|
||||||
|
|
||||||
return $res->getReturnResponse();
|
return $res->getReturnResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -739,7 +760,7 @@ class RAPIController extends Controller
|
||||||
error_log(print_r($all, true));
|
error_log(print_r($all, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function changeService(Request $req, InvoiceCreator $ic)
|
public function changeService(Request $req, InvoiceGeneratorInterface $ic)
|
||||||
{
|
{
|
||||||
$this->debugRequest($req);
|
$this->debugRequest($req);
|
||||||
|
|
||||||
|
|
@ -752,7 +773,7 @@ class RAPIController extends Controller
|
||||||
|
|
||||||
// check service type
|
// check service type
|
||||||
$stype_id = $req->request->get('stype_id');
|
$stype_id = $req->request->get('stype_id');
|
||||||
if (!ServiceType::validate($stype_id))
|
if (!CMBServiceType::validate($stype_id))
|
||||||
{
|
{
|
||||||
$res->setError(true)
|
$res->setError(true)
|
||||||
->setErrorMessage('Invalid service type - ' . $stype_id);
|
->setErrorMessage('Invalid service type - ' . $stype_id);
|
||||||
|
|
@ -814,7 +835,7 @@ class RAPIController extends Controller
|
||||||
|
|
||||||
// check trade in
|
// check trade in
|
||||||
$trade_in = $req->request->get('trade_in');
|
$trade_in = $req->request->get('trade_in');
|
||||||
if (!TradeInType::validate($trade_in))
|
if (!CMBTradeInType::validate($trade_in))
|
||||||
$trade_in = null;
|
$trade_in = null;
|
||||||
|
|
||||||
// check mode of payment
|
// check mode of payment
|
||||||
|
|
@ -839,8 +860,7 @@ class RAPIController extends Controller
|
||||||
error_log('adding entry for battery - ' . $battery->getID());
|
error_log('adding entry for battery - ' . $battery->getID());
|
||||||
}
|
}
|
||||||
|
|
||||||
$invoice = $ic->processCriteria($crit);
|
$invoice = $ic->generateInvoice($crit);
|
||||||
$invoice->setStatus(InvoiceStatus::DRAFT);
|
|
||||||
|
|
||||||
// remove previous invoice
|
// remove previous invoice
|
||||||
$old_invoice = $jo->getInvoice();
|
$old_invoice = $jo->getInvoice();
|
||||||
|
|
@ -868,4 +888,80 @@ class RAPIController extends Controller
|
||||||
|
|
||||||
return $res->getReturnResponse();
|
return $res->getReturnResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function createWarranty($jo)
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
$warranty = new Warranty();
|
||||||
|
|
||||||
|
$warranty_class = $jo->getWarrantyClass();
|
||||||
|
$first_name = $jo->getCustomer()->getFirstName();
|
||||||
|
$last_name = $jo->getCustomer()->getLastName();
|
||||||
|
$mobile_number = $jo->getCustomer()->getPhoneMobile();
|
||||||
|
|
||||||
|
// check if date fulfilled is null
|
||||||
|
if ($jo->getDateFulfill() == null)
|
||||||
|
$date_create = $jo->getDateCreate();
|
||||||
|
else
|
||||||
|
$date_create = $jo->getDateFulfill();
|
||||||
|
|
||||||
|
// normalize the plate number
|
||||||
|
$plate_number = $this->normalizePlateNumber($jo->getCustomerVehicle()->getPlateNumber());
|
||||||
|
|
||||||
|
// get battery and its warranty periods
|
||||||
|
$warranty_period = 0;
|
||||||
|
$invoice_items = $jo->getInvoice()->getItems();
|
||||||
|
foreach ($invoice_items as $item)
|
||||||
|
{
|
||||||
|
if ($item->getBattery() != null)
|
||||||
|
{
|
||||||
|
$battery = $item->getBattery();
|
||||||
|
$warranty->setBatteryModel($battery->getModel());
|
||||||
|
$warranty->setBatterySize($battery->getSize());
|
||||||
|
|
||||||
|
if ($warranty_class == WarrantyClass::WTY_PRIVATE)
|
||||||
|
$warranty_period = $battery->getWarrantyPrivate();
|
||||||
|
else if ($warranty_class == WarrantyClass::WTY_COMMERCIAL)
|
||||||
|
$warranty_period = $battery->getWarrantyCommercial();
|
||||||
|
else if ($warranty_class == WarrantyClass::WTY_TNV)
|
||||||
|
$warranty_period = $battery->getWarrantyTnv();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute expiry date
|
||||||
|
$expiry_date = $this->computeDateExpire($date_create, $warranty_period);
|
||||||
|
|
||||||
|
$warranty->setWarrantyClass($warranty_class)
|
||||||
|
->setFirstName($first_name)
|
||||||
|
->setLastName($last_name)
|
||||||
|
->setMobileNumber($mobile_number)
|
||||||
|
->setDatePurchase($date_create)
|
||||||
|
->setDateExpire($expiry_date)
|
||||||
|
->setPlateNumber($plate_number);
|
||||||
|
|
||||||
|
$em->persist($warranty);
|
||||||
|
$em->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function normalizePlateNumber($plate_number)
|
||||||
|
{
|
||||||
|
// make it upper case
|
||||||
|
$plate_number = trim(strtoupper($plate_number));
|
||||||
|
|
||||||
|
// remove special characters and spaces
|
||||||
|
$plate_number = preg_replace('/[^A-Za-z0-9]/', '', $plate_number);
|
||||||
|
|
||||||
|
//error_log('plate number ' . $plate_number);
|
||||||
|
|
||||||
|
return $plate_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function computeDateExpire($date_create, $warranty_period)
|
||||||
|
{
|
||||||
|
$expire_date = clone $date_create;
|
||||||
|
$expire_date->add(new DateInterval('P'.$warranty_period.'M'));
|
||||||
|
return $expire_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,14 +60,13 @@ class Battery
|
||||||
|
|
||||||
// product code
|
// product code
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=80)
|
* @ORM\Column(type="string", length=80, nullable=true)
|
||||||
* @Assert\NotBlank()
|
|
||||||
*/
|
*/
|
||||||
protected $prod_code;
|
protected $prod_code;
|
||||||
|
|
||||||
// sap code
|
// sap code
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=80)
|
* @ORM\Column(type="string", length=80, nullable=true)
|
||||||
*/
|
*/
|
||||||
protected $sap_code;
|
protected $sap_code;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ use App\Ramcar\CustomerClassification;
|
||||||
*/
|
*/
|
||||||
class Customer
|
class Customer
|
||||||
{
|
{
|
||||||
|
// TODO: make this a setting somewhere
|
||||||
|
const COUNTRY_CODE_PREFIX = '+60';
|
||||||
|
|
||||||
// unique id
|
// unique id
|
||||||
/**
|
/**
|
||||||
* @ORM\Id
|
* @ORM\Id
|
||||||
|
|
@ -231,6 +234,11 @@ class Customer
|
||||||
return $this->last_name;
|
return $this->last_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getNameDisplay()
|
||||||
|
{
|
||||||
|
return $this->first_name . ' ' . $this->last_name;
|
||||||
|
}
|
||||||
|
|
||||||
public function setCustomerClassification($customer_classification)
|
public function setCustomerClassification($customer_classification)
|
||||||
{
|
{
|
||||||
$this->customer_classification = $customer_classification;
|
$this->customer_classification = $customer_classification;
|
||||||
|
|
@ -258,16 +266,16 @@ class Customer
|
||||||
$phones = [];
|
$phones = [];
|
||||||
|
|
||||||
if (!empty($this->phone_mobile))
|
if (!empty($this->phone_mobile))
|
||||||
$phones[] = '+63' . $this->phone_mobile;
|
$phones[] = self::COUNTRY_CODE_PREFIX . $this->phone_mobile;
|
||||||
|
|
||||||
if (!empty($this->phone_landline))
|
if (!empty($this->phone_landline))
|
||||||
$phones[] = '+63' . $this->phone_landline;
|
$phones[] = self::COUNTRY_CODE_PREFIX . $this->phone_landline;
|
||||||
|
|
||||||
if (!empty($this->phone_office))
|
if (!empty($this->phone_office))
|
||||||
$phones[] = '+63' . $this->phone_office;
|
$phones[] = self::COUNTRY_CODE_PREFIX . $this->phone_office;
|
||||||
|
|
||||||
if (!empty($this->phone_fax))
|
if (!empty($this->phone_fax))
|
||||||
$phones[] = '+63' . $this->phone_fax;
|
$phones[] = self::COUNTRY_CODE_PREFIX . $this->phone_fax;
|
||||||
|
|
||||||
return $phones;
|
return $phones;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,14 +67,12 @@ class CustomerVehicle
|
||||||
// vehicle status (new / second-hand)
|
// vehicle status (new / second-hand)
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=15)
|
* @ORM\Column(type="string", length=15)
|
||||||
* @Assert\NotBlank()
|
|
||||||
*/
|
*/
|
||||||
protected $status_condition;
|
protected $status_condition;
|
||||||
|
|
||||||
// fuel type - diesel, gas
|
// fuel type - diesel, gas
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=15)
|
* @ORM\Column(type="string", length=15)
|
||||||
* @Assert\NotBlank()
|
|
||||||
*/
|
*/
|
||||||
protected $fuel_type;
|
protected $fuel_type;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -319,4 +319,10 @@ class Rider
|
||||||
{
|
{
|
||||||
return $this->sessions;
|
return $this->sessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getMapLabel()
|
||||||
|
{
|
||||||
|
$map_label = $this->first_name .' ' . $this->last_name;
|
||||||
|
return $map_label;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
16
src/Ramcar/CMBModeOfPayment.php
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Ramcar;
|
||||||
|
|
||||||
|
class CMBModeOfPayment extends NameValue
|
||||||
|
{
|
||||||
|
const CASH = 'cash';
|
||||||
|
const CREDIT_CARD = 'credit_card';
|
||||||
|
const BANK_TRANSFER = 'bank_transfer';
|
||||||
|
|
||||||
|
const COLLECTION = [
|
||||||
|
'cash' => 'Cash',
|
||||||
|
'credit_card' => 'Credit Card',
|
||||||
|
'bank_transfer' => 'Bank Transfer',
|
||||||
|
];
|
||||||
|
}
|
||||||
16
src/Ramcar/CMBServiceType.php
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Ramcar;
|
||||||
|
|
||||||
|
class CMBServiceType extends NameValue
|
||||||
|
{
|
||||||
|
const BATTERY_REPLACEMENT_NEW = 'battery_new';
|
||||||
|
const BATTERY_REPLACEMENT_WARRANTY = 'battery_warranty';
|
||||||
|
const JUMPSTART = 'jumpstart';
|
||||||
|
|
||||||
|
const COLLECTION = [
|
||||||
|
'battery_new' => 'Battery Sales',
|
||||||
|
'battery_warranty' => 'Under Warranty',
|
||||||
|
'jumpstart' => 'Jumpstart',
|
||||||
|
];
|
||||||
|
}
|
||||||
13
src/Ramcar/CMBTradeInType.php
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Ramcar;
|
||||||
|
|
||||||
|
class CMBTradeInType extends NameValue
|
||||||
|
{
|
||||||
|
const YES = 'yes';
|
||||||
|
|
||||||
|
const COLLECTION = [
|
||||||
|
'yes' => 'Yes',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
15
src/Ramcar/CMBWarrantyClass.php
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Ramcar;
|
||||||
|
|
||||||
|
class CMBWarrantyClass extends NameValue
|
||||||
|
{
|
||||||
|
const WTY_PASSENGER = 'passenger';
|
||||||
|
const WTY_COMMERCIAL = 'commercial';
|
||||||
|
|
||||||
|
const COLLECTION = [
|
||||||
|
'passenger' => 'Passenger',
|
||||||
|
'commercial' => 'Commercial',
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
691
src/Service/CustomerHandler/CMBCustomerHandler.php
Normal file
|
|
@ -0,0 +1,691 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service\CustomerHandler;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
|
use App\Ramcar\CustomerClassification;
|
||||||
|
use App\Ramcar\CrudException;
|
||||||
|
|
||||||
|
use App\Service\CustomerHandlerInterface;
|
||||||
|
|
||||||
|
use App\Entity\Customer;
|
||||||
|
use App\Entity\CustomerVehicle;
|
||||||
|
use App\Entity\Vehicle;
|
||||||
|
use App\Entity\Battery;
|
||||||
|
use App\Entity\VehicleManufacturer;
|
||||||
|
use App\Entity\BatteryManufacturer;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
|
||||||
|
class CMBCustomerHandler implements CustomerHandlerInterface
|
||||||
|
{
|
||||||
|
const COUNTRY_CODE_PREFIX = '+60';
|
||||||
|
|
||||||
|
protected $em;
|
||||||
|
protected $validator;
|
||||||
|
|
||||||
|
protected $template_hash;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $em, ValidatorInterface $validator)
|
||||||
|
{
|
||||||
|
$this->em = $em;
|
||||||
|
$this->validator = $validator;
|
||||||
|
|
||||||
|
$this->loadTemplates();
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize form to display customer list
|
||||||
|
public function initializeCustomerIndexForm()
|
||||||
|
{
|
||||||
|
$params['template'] = $this->getTwigTemplate('cust_list');
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get customers
|
||||||
|
public function getCustomers(Request $req)
|
||||||
|
{
|
||||||
|
// build query
|
||||||
|
$tqb = $this->em->getRepository(Customer::class)
|
||||||
|
->createQueryBuilder('q');
|
||||||
|
|
||||||
|
$qb = $this->em->getRepository(Customer::class)
|
||||||
|
->createQueryBuilder('q');
|
||||||
|
|
||||||
|
// get datatable params
|
||||||
|
$datatable = $req->request->get('datatable');
|
||||||
|
|
||||||
|
// count total records
|
||||||
|
$tquery = $tqb->select('COUNT(q)');
|
||||||
|
|
||||||
|
// add filters to count query
|
||||||
|
$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');
|
||||||
|
|
||||||
|
// add filters to query
|
||||||
|
$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.first_name', '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['title'] = $orow->getTitle();
|
||||||
|
$row['first_name'] = $orow->getFirstName();
|
||||||
|
$row['last_name'] = $orow->getLastName();
|
||||||
|
$row['customer_classification'] = CustomerClassification::getName($orow->getCustomerClassification());
|
||||||
|
$row['flag_mobile_app'] = $orow->hasMobileApp();
|
||||||
|
$row['app_mobile_number'] = $orow->hasMobileApp() && !empty($orow->getMobileSessions()) ? $orow->getMobileSessions()[0]->getPhoneNumber() : '';
|
||||||
|
$row['flag_active'] = $orow->isActive();
|
||||||
|
$row['flag_csat'] = $orow->isCSAT();
|
||||||
|
|
||||||
|
// TODO: properly add mobile numbers and plate numbers as searchable/sortable fields, use doctrine events
|
||||||
|
$row['mobile_numbers'] = implode("<br>", $orow->getMobileNumberList());
|
||||||
|
$row['plate_numbers'] = implode("<br>", $orow->getPlateNumberList());
|
||||||
|
|
||||||
|
$rows[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
$params['meta'] = $meta;
|
||||||
|
$params['rows'] = $rows;
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize add customer form
|
||||||
|
public function initializeAddCustomerForm()
|
||||||
|
{
|
||||||
|
$params['obj'] = new Customer();
|
||||||
|
$params['mode'] = 'create';
|
||||||
|
|
||||||
|
// get dropdown parameters
|
||||||
|
$this->fillDropdownParameters($params);
|
||||||
|
|
||||||
|
// get template to display
|
||||||
|
$params['template'] = $this->getTwigTemplate('cust_add_form');
|
||||||
|
|
||||||
|
// return params
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add new customer and customer vehicle, if any
|
||||||
|
public function addCustomer(Request $req)
|
||||||
|
{
|
||||||
|
// create new row
|
||||||
|
$em = $this->em;
|
||||||
|
$row = new Customer();
|
||||||
|
|
||||||
|
$this->setObject($row, $req);
|
||||||
|
|
||||||
|
// initialize error lists
|
||||||
|
$error_array = [];
|
||||||
|
$nerror_array = [];
|
||||||
|
$verror_array = [];
|
||||||
|
|
||||||
|
// custom validation for vehicles
|
||||||
|
$vehicles = json_decode($req->request->get('vehicles'));
|
||||||
|
|
||||||
|
if (!empty($vehicles))
|
||||||
|
{
|
||||||
|
foreach ($vehicles as $vehicle)
|
||||||
|
{
|
||||||
|
// check if vehicle exists
|
||||||
|
$vobj = $em->getRepository(Vehicle::class)->find($vehicle->vehicle);
|
||||||
|
|
||||||
|
if (empty($vobj))
|
||||||
|
{
|
||||||
|
$verror_array[$vehicle->index]['vehicle'] = 'Invalid vehicle specified.';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$cust_vehicle = new CustomerVehicle();
|
||||||
|
$cust_vehicle->setName($vehicle->name)
|
||||||
|
->setVehicle($vobj)
|
||||||
|
->setPlateNumber($vehicle->plate_number)
|
||||||
|
->setModelYear($vehicle->model_year)
|
||||||
|
->setColor('')
|
||||||
|
->setStatusCondition('')
|
||||||
|
->setFuelType('')
|
||||||
|
->setActive($vehicle->flag_active)
|
||||||
|
->setCustomer($row);
|
||||||
|
|
||||||
|
// if specified, check if battery exists
|
||||||
|
if ($vehicle->battery)
|
||||||
|
{
|
||||||
|
// check if battery exists
|
||||||
|
$bobj = $em->getRepository(Battery::class)->find($vehicle->battery);
|
||||||
|
|
||||||
|
if (empty($bobj))
|
||||||
|
{
|
||||||
|
$verror_array[$vehicle->index]['battery'] = 'Invalid battery specified.';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// check if warranty expiration was specified
|
||||||
|
$warr_ex = DateTime::createFromFormat("d M Y", $vehicle->warranty_expiration);
|
||||||
|
if (!$warr_ex)
|
||||||
|
$warr_ex = null;
|
||||||
|
|
||||||
|
$cust_vehicle->setHasMotoliteBattery(true)
|
||||||
|
->setCurrentBattery($bobj)
|
||||||
|
->setWarrantyCode($vehicle->warranty_code)
|
||||||
|
->setWarrantyExpiration($warr_ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$cust_vehicle->setHasMotoliteBattery(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
$verrors = $this->validator->validate($cust_vehicle);
|
||||||
|
|
||||||
|
// add errors to list
|
||||||
|
foreach ($verrors as $error)
|
||||||
|
{
|
||||||
|
if (!isset($verror_array[$vehicle->index]))
|
||||||
|
$verror_array[$vehicle->index] = [];
|
||||||
|
|
||||||
|
$verror_array[$vehicle->index][$error->getPropertyPath()] = $error->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to entity
|
||||||
|
if (!isset($verror_array[$vehicle->index]))
|
||||||
|
{
|
||||||
|
$row->addVehicle($cust_vehicle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate
|
||||||
|
$errors = $this->validator->validate($row);
|
||||||
|
|
||||||
|
// add errors to list
|
||||||
|
foreach ($errors as $error)
|
||||||
|
{
|
||||||
|
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
// check if any errors were found
|
||||||
|
if (!empty($error_array) || !empty($nerror_array) || !empty($verror_array))
|
||||||
|
{
|
||||||
|
// return all error_arrays
|
||||||
|
$result = [
|
||||||
|
'error_array' => $error_array,
|
||||||
|
'nerror_array' => $nerror_array,
|
||||||
|
'verror_array' => $verror_array,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// validated! save the entity
|
||||||
|
$em->persist($row);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
$result = [
|
||||||
|
'id' => $row->getID(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize update customer form
|
||||||
|
public function initializeUpdateCustomerForm($id)
|
||||||
|
{
|
||||||
|
$params['mode'] = 'update';
|
||||||
|
|
||||||
|
// get row data
|
||||||
|
$em = $this->em;
|
||||||
|
$row = $em->getRepository(Customer::class)->find($id);
|
||||||
|
|
||||||
|
// make sure this row exists
|
||||||
|
if (empty($row))
|
||||||
|
throw new NotFoundHttpException('The item does not exist');
|
||||||
|
|
||||||
|
// get dropdown parameters
|
||||||
|
$this->fillDropdownParameters($params);
|
||||||
|
// get template to display
|
||||||
|
$params['template'] = $this->getTwigTemplate('cust_update_form');
|
||||||
|
|
||||||
|
$params['obj'] = $row;
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update customer and customer vehicle
|
||||||
|
public function updateCustomer(Request $req, $id)
|
||||||
|
{
|
||||||
|
// get row data
|
||||||
|
$em = $this->em;
|
||||||
|
$cust = $em->getRepository(Customer::class)->find($id);
|
||||||
|
|
||||||
|
// make sure this row exists
|
||||||
|
if (empty($cust))
|
||||||
|
throw $this->createNotFoundException('The item does not exist');
|
||||||
|
|
||||||
|
$this->setObject($cust, $req);
|
||||||
|
|
||||||
|
// initialize error lists
|
||||||
|
$error_array = [];
|
||||||
|
$nerror_array = [];
|
||||||
|
$verror_array = [];
|
||||||
|
|
||||||
|
// TODO: validate mobile numbers
|
||||||
|
// TODO: validate vehicles
|
||||||
|
|
||||||
|
// custom validation for vehicles
|
||||||
|
$vehicles = json_decode($req->request->get('vehicles'));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$this->updateVehicles($em, $cust, $vehicles);
|
||||||
|
}
|
||||||
|
catch (CrudException $e)
|
||||||
|
{
|
||||||
|
throw new CrudException($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate
|
||||||
|
$errors = $this->validator->validate($cust);
|
||||||
|
|
||||||
|
// add errors to list
|
||||||
|
foreach ($errors as $error)
|
||||||
|
{
|
||||||
|
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if any errors were found
|
||||||
|
$result = [];
|
||||||
|
if (!empty($error_array) || !empty($nerror_array) || !empty($verror_array))
|
||||||
|
{
|
||||||
|
// return all error_arrays
|
||||||
|
$result = [
|
||||||
|
'error_array' => $error_array,
|
||||||
|
'nerror_array' => $nerror_array,
|
||||||
|
'verror_array' => $verror_array,
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// validated! save the entity. do a persist anyway to save child entities
|
||||||
|
$em->persist($cust);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
$result = [
|
||||||
|
'id' => $cust->getID(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete customer
|
||||||
|
public function deleteCustomer(int $id)
|
||||||
|
{
|
||||||
|
// get row data
|
||||||
|
$em = $this->em;
|
||||||
|
$row = $em->getRepository(Customer::class)->find($id);
|
||||||
|
|
||||||
|
if (empty($row))
|
||||||
|
throw new NotFoundHttpException('The item does not exist');
|
||||||
|
|
||||||
|
// delete this row
|
||||||
|
$em->remove($row);
|
||||||
|
$em->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// get customer vehicles
|
||||||
|
public function getCustomerVehicles(Request $req)
|
||||||
|
{
|
||||||
|
// get search term
|
||||||
|
$term = $req->query->get('search');
|
||||||
|
|
||||||
|
// get querybuilder
|
||||||
|
$qb = $this->em
|
||||||
|
->getRepository(CustomerVehicle::class)
|
||||||
|
->createQueryBuilder('q');
|
||||||
|
|
||||||
|
/*
|
||||||
|
// build expression now since we're reusing it
|
||||||
|
$vehicle_label = $qb->expr()->concat(
|
||||||
|
'q.plate_number',
|
||||||
|
$qb->expr()->literal(' - '),
|
||||||
|
'c.first_name',
|
||||||
|
$qb->expr()->literal(' '),
|
||||||
|
'c.last_name',
|
||||||
|
$qb->expr()->literal(' (+63'),
|
||||||
|
'c.phone_mobile',
|
||||||
|
$qb->expr()->literal(')')
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// count total records
|
||||||
|
$tquery = $qb->select('COUNT(q)');
|
||||||
|
|
||||||
|
// add filters to count query
|
||||||
|
if (!empty($term)) {
|
||||||
|
$tquery->where('q.plate_number like :search')
|
||||||
|
->setParameter('search', $term . '%');
|
||||||
|
/*
|
||||||
|
$tquery->where('match_against (q.plate_number, :search \'in boolean mode\') > 0.1')
|
||||||
|
->setParameter('search', $term . '*');
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
$tquery->where('q.plate_number LIKE :filter')
|
||||||
|
->setParameter('filter', '%' . $term . '%');
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
$total = $tquery->getQuery()
|
||||||
|
->getSingleScalarResult();
|
||||||
|
|
||||||
|
// pagination vars
|
||||||
|
$page = $req->query->get('page') ?? 1;
|
||||||
|
$perpage = 20;
|
||||||
|
$offset = ($page - 1) * $perpage;
|
||||||
|
$pages = ceil($total / $perpage);
|
||||||
|
$has_more_pages = $page < $pages ? true : false;
|
||||||
|
|
||||||
|
// build main query
|
||||||
|
$query = $qb->select('q');
|
||||||
|
/*
|
||||||
|
->addSelect($vehicle_label . ' as vehicle_label')
|
||||||
|
->addSelect('c.first_name as cust_first_name')
|
||||||
|
->addSelect('c.last_name as cust_last_name');
|
||||||
|
*/
|
||||||
|
|
||||||
|
// add filters if needed
|
||||||
|
if (!empty($term)) {
|
||||||
|
$query->where('q.plate_number like :search')
|
||||||
|
->setParameter('search', $term . '%');
|
||||||
|
/*
|
||||||
|
$query->where('match_against (q.plate_number, :search \'in boolean mode\') > 0.1')
|
||||||
|
->setParameter('search', $term . '*');
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
$query->where('q.plate_number LIKE :filter')
|
||||||
|
->setParameter('filter', '%' . $term . '%');
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// get rows
|
||||||
|
$query_obj = $query->orderBy('q.plate_number', 'asc')
|
||||||
|
->setFirstResult($offset)
|
||||||
|
->setMaxResults($perpage)
|
||||||
|
->getQuery();
|
||||||
|
// error_log($query_obj->getSql());
|
||||||
|
|
||||||
|
$obj_rows = $query_obj->getResult();
|
||||||
|
|
||||||
|
// build vehicles array
|
||||||
|
$vehicles = [];
|
||||||
|
|
||||||
|
foreach ($obj_rows as $cv) {
|
||||||
|
$cust = $cv->getCustomer();
|
||||||
|
$vehicles[] = [
|
||||||
|
'id' => $cv->getID(),
|
||||||
|
'text' => $cv->getPlateNumber() . ' ' . $cust->getFirstName() . ' ' . $cust->getLastName() . ' ('. self::COUNTRY_CODE_PREFIX . $cust->getPhoneMobile() . ')',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = [
|
||||||
|
'vehicles' => $vehicles,
|
||||||
|
'has_more_pages' => $has_more_pages,
|
||||||
|
];
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get customer vehicle info
|
||||||
|
public function getCustomerVehicleInfo(Request $req)
|
||||||
|
{
|
||||||
|
// get id
|
||||||
|
$id = $req->query->get('id');
|
||||||
|
|
||||||
|
// get row data
|
||||||
|
$em = $this->em;
|
||||||
|
$obj = $em->getRepository(CustomerVehicle::class)->find($id);
|
||||||
|
|
||||||
|
// make sure this row exists
|
||||||
|
if (empty($obj)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$customer = $obj->getCustomer();
|
||||||
|
$vehicle = $obj->getVehicle();
|
||||||
|
$battery = $obj->getCurrentBattery();
|
||||||
|
|
||||||
|
// build response
|
||||||
|
$row = [
|
||||||
|
'customer' => [
|
||||||
|
'id' => $customer->getID(),
|
||||||
|
'first_name' => $customer->getFirstName(),
|
||||||
|
'last_name' => $customer->getLastName(),
|
||||||
|
'customer_notes' => $customer->getCustomerNotes(),
|
||||||
|
'phone_mobile' => $customer->getPhoneMobile(),
|
||||||
|
'phone_landline' => $customer->getPhoneLandline(),
|
||||||
|
'phone_office' => $customer->getPhoneOffice(),
|
||||||
|
'phone_fax' => $customer->getPhoneFax(),
|
||||||
|
],
|
||||||
|
'vehicle' => [
|
||||||
|
'id' => $vehicle->getID(),
|
||||||
|
'mfg_name' => $vehicle->getManufacturer()->getName(),
|
||||||
|
'make' => $vehicle->getMake(),
|
||||||
|
'model_year_from' => $vehicle->getModelYearFrom(),
|
||||||
|
'model_year_to' => $vehicle->getModelYearTo(),
|
||||||
|
'model_year' => $obj->getModelYear(),
|
||||||
|
'color' => $obj->getColor(),
|
||||||
|
'plate_number' => $obj->getPlateNumber(),
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!empty($battery)) {
|
||||||
|
$row['battery'] = [
|
||||||
|
'id' => $battery->getID(),
|
||||||
|
'mfg_name' => $battery->getManufacturer()->getName(),
|
||||||
|
'model_name' => $battery->getModel()->getName(),
|
||||||
|
'size_name' => $battery->getSize()->getName(),
|
||||||
|
'prod_code' => $battery->getProductCode(),
|
||||||
|
'warranty_code' => $obj->getWarrantyCode(),
|
||||||
|
'warranty_expiration' => $obj->getWarrantyExpiration() ? $obj->getWarrantyExpiration()->format("d M Y") : "",
|
||||||
|
'has_motolite_battery' => $obj->hasMotoliteBattery(),
|
||||||
|
'is_active' => $obj->isActive()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getTwigTemplate($id)
|
||||||
|
{
|
||||||
|
if (isset($this->template_hash[$id]))
|
||||||
|
{
|
||||||
|
return $this->template_hash[$id];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setObject($obj, $req)
|
||||||
|
{
|
||||||
|
// set and save values
|
||||||
|
$obj->setTitle($req->request->get('title'))
|
||||||
|
->setFirstName($req->request->get('first_name'))
|
||||||
|
->setLastName($req->request->get('last_name'))
|
||||||
|
->setCustomerClassification($req->request->get('customer_classification'))
|
||||||
|
->setCustomerNotes($req->request->get('customer_notes'))
|
||||||
|
->setEmail($req->request->get('email'))
|
||||||
|
->setIsCSAT($req->request->get('flag_csat') ? true : false)
|
||||||
|
->setActive($req->request->get('flag_active') ? true : false);
|
||||||
|
|
||||||
|
// phone numbers
|
||||||
|
$obj->setPhoneMobile($req->request->get('phone_mobile'))
|
||||||
|
->setPhoneLandline($req->request->get('phone_landline'))
|
||||||
|
->setPhoneOffice($req->request->get('phone_office'))
|
||||||
|
->setPhoneFax($req->request->get('phone_fax'));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function fillDropdownParameters(&$params)
|
||||||
|
{
|
||||||
|
$em = $this->em;
|
||||||
|
|
||||||
|
$params['bmfgs'] = $em->getRepository(BatteryManufacturer::class)->findAll();
|
||||||
|
$params['vmfgs'] = $em->getRepository(VehicleManufacturer::class)->findAll();
|
||||||
|
|
||||||
|
$params['classifications'] = CustomerClassification::getCollection();
|
||||||
|
|
||||||
|
$params['years'] = $this->generateYearOptions();
|
||||||
|
$params['batteries'] = $em->getRepository(Battery::class)->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function generateYearOptions()
|
||||||
|
{
|
||||||
|
$start_year = 1950;
|
||||||
|
return range($start_year, date("Y") + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function loadTemplates()
|
||||||
|
{
|
||||||
|
$this->template_hash = [];
|
||||||
|
|
||||||
|
// add all twig templates for customer to hash
|
||||||
|
$this->template_hash['cust_add_form'] = 'customer/cmb.form.html.twig';
|
||||||
|
$this->template_hash['cust_update_form'] = 'customer/cmb.form.html.twig';
|
||||||
|
$this->template_hash['cust_list'] = 'customer/list.html.twig';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function updateVehicles($em, Customer $cust, $vehicles)
|
||||||
|
{
|
||||||
|
$vehicle_ids = [];
|
||||||
|
|
||||||
|
foreach ($vehicles as $vehicle)
|
||||||
|
{
|
||||||
|
// check if customer vehicle exists
|
||||||
|
if (!empty($vehicle->id))
|
||||||
|
{
|
||||||
|
$cust_vehicle = $em->getRepository(CustomerVehicle::class)->find($vehicle->id);
|
||||||
|
if ($cust_vehicle == null)
|
||||||
|
throw new CrudException("Could not find customer vehicle.");
|
||||||
|
|
||||||
|
}
|
||||||
|
// this is a new vehicle
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$cust_vehicle = new CustomerVehicle();
|
||||||
|
$cust_vehicle->setCustomer($cust);
|
||||||
|
$cust->addVehicle($cust_vehicle);
|
||||||
|
$em->persist($cust_vehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// vehicle, because they could have changed vehicle type
|
||||||
|
$vobj = $em->getRepository(Vehicle::class)->find($vehicle->vehicle);
|
||||||
|
if ($vobj == null)
|
||||||
|
throw new CrudException("Could not find vehicle.");
|
||||||
|
|
||||||
|
// TODO: validate details
|
||||||
|
|
||||||
|
$cust_vehicle->setName($vehicle->name)
|
||||||
|
->setVehicle($vobj)
|
||||||
|
->setPlateNumber($vehicle->plate_number)
|
||||||
|
->setModelYear($vehicle->model_year)
|
||||||
|
->setColor('')
|
||||||
|
->setStatusCondition('')
|
||||||
|
->setFuelType('')
|
||||||
|
->setActive($vehicle->flag_active);
|
||||||
|
|
||||||
|
// if specified, check if battery exists
|
||||||
|
if ($vehicle->battery)
|
||||||
|
{
|
||||||
|
// check if battery exists
|
||||||
|
$bobj = $em->getRepository(Battery::class)->find($vehicle->battery);
|
||||||
|
if ($bobj == null)
|
||||||
|
throw new CrudException("Could not find battery.");
|
||||||
|
|
||||||
|
// check if warranty expiration was specified
|
||||||
|
$warr_ex = DateTime::createFromFormat("d M Y", $vehicle->warranty_expiration);
|
||||||
|
if (!$warr_ex)
|
||||||
|
$warr_ex = null;
|
||||||
|
|
||||||
|
$cust_vehicle->setHasMotoliteBattery(true)
|
||||||
|
->setCurrentBattery($bobj)
|
||||||
|
->setWarrantyCode($vehicle->warranty_code)
|
||||||
|
->setWarrantyExpiration($warr_ex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$cust_vehicle->setHasMotoliteBattery(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to list of vehicles to keep
|
||||||
|
$vehicle_ids[$cust_vehicle->getID()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
// delete all vehicles not in list
|
||||||
|
$cvs = $cust->getVehicles();
|
||||||
|
foreach ($cvs as $cv)
|
||||||
|
{
|
||||||
|
if (!isset($vehicle_ids[$cv->getID()]))
|
||||||
|
{
|
||||||
|
$cust->removeVehicle($cv);
|
||||||
|
$em->remove($cv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if datatable filter is present and append to query
|
||||||
|
protected function setQueryFilters($datatable, &$query) {
|
||||||
|
if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) {
|
||||||
|
$query->join('q.vehicles', 'cv')
|
||||||
|
->where('q.first_name LIKE :filter')
|
||||||
|
->orWhere('q.last_name LIKE :filter')
|
||||||
|
->orWhere('q.customer_classification LIKE :filter')
|
||||||
|
->orWhere('cv.plate_number LIKE :filter')
|
||||||
|
->setParameter('filter', $datatable['query']['data-rows-search'] . '%');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
693
src/Service/CustomerHandler/ResqCustomerHandler.php
Normal file
|
|
@ -0,0 +1,693 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service\CustomerHandler;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
|
use App\Service\CustomerHandlerInterface;
|
||||||
|
|
||||||
|
use App\Ramcar\CustomerClassification;
|
||||||
|
use App\Ramcar\FuelType;
|
||||||
|
use App\Ramcar\VehicleStatusCondition;
|
||||||
|
use App\Ramcar\CrudException;
|
||||||
|
|
||||||
|
use App\Entity\Customer;
|
||||||
|
use App\Entity\CustomerVehicle;
|
||||||
|
use App\Entity\Vehicle;
|
||||||
|
use App\Entity\Battery;
|
||||||
|
use App\Entity\VehicleManufacturer;
|
||||||
|
use App\Entity\BatteryManufacturer;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
|
||||||
|
class ResqCustomerHandler implements CustomerHandlerInterface
|
||||||
|
{
|
||||||
|
const COUNTRY_CODE_PREFIX = '+63';
|
||||||
|
|
||||||
|
protected $em;
|
||||||
|
protected $validator;
|
||||||
|
|
||||||
|
protected $template_hash;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $em, ValidatorInterface $validator)
|
||||||
|
{
|
||||||
|
$this->em = $em;
|
||||||
|
$this->validator = $validator;
|
||||||
|
|
||||||
|
$this->loadTemplates();
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize form to display customer list
|
||||||
|
public function initializeCustomerIndexForm()
|
||||||
|
{
|
||||||
|
$params['template'] = $this->getTwigTemplate('cust_list');
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get customers
|
||||||
|
public function getCustomers(Request $req)
|
||||||
|
{
|
||||||
|
// build query
|
||||||
|
$tqb = $this->em->getRepository(Customer::class)
|
||||||
|
->createQueryBuilder('q');
|
||||||
|
|
||||||
|
$qb = $this->em->getRepository(Customer::class)
|
||||||
|
->createQueryBuilder('q');
|
||||||
|
|
||||||
|
// get datatable params
|
||||||
|
$datatable = $req->request->get('datatable');
|
||||||
|
|
||||||
|
// count total records
|
||||||
|
$tquery = $tqb->select('COUNT(q)');
|
||||||
|
|
||||||
|
// add filters to count query
|
||||||
|
$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');
|
||||||
|
|
||||||
|
// add filters to query
|
||||||
|
$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.first_name', '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['title'] = $orow->getTitle();
|
||||||
|
$row['first_name'] = $orow->getFirstName();
|
||||||
|
$row['last_name'] = $orow->getLastName();
|
||||||
|
$row['customer_classification'] = CustomerClassification::getName($orow->getCustomerClassification());
|
||||||
|
$row['flag_mobile_app'] = $orow->hasMobileApp();
|
||||||
|
$row['app_mobile_number'] = $orow->hasMobileApp() && !empty($orow->getMobileSessions()) ? $orow->getMobileSessions()[0]->getPhoneNumber() : '';
|
||||||
|
$row['flag_active'] = $orow->isActive();
|
||||||
|
$row['flag_csat'] = $orow->isCSAT();
|
||||||
|
|
||||||
|
// TODO: properly add mobile numbers and plate numbers as searchable/sortable fields, use doctrine events
|
||||||
|
$row['mobile_numbers'] = implode("<br>", $orow->getMobileNumberList());
|
||||||
|
$row['plate_numbers'] = implode("<br>", $orow->getPlateNumberList());
|
||||||
|
|
||||||
|
$rows[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
$params['meta'] = $meta;
|
||||||
|
$params['rows'] = $rows;
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize add customer form
|
||||||
|
public function initializeAddCustomerForm()
|
||||||
|
{
|
||||||
|
$params['obj'] = new Customer();
|
||||||
|
$params['mode'] = 'create';
|
||||||
|
|
||||||
|
// get dropdown parameters
|
||||||
|
$this->fillDropdownParameters($params);
|
||||||
|
|
||||||
|
// get template to display
|
||||||
|
$params['template'] = $this->getTwigTemplate('cust_add_form');
|
||||||
|
|
||||||
|
// return params
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// add new customer and customer vehicle, if any
|
||||||
|
public function addCustomer(Request $req)
|
||||||
|
{
|
||||||
|
// create new row
|
||||||
|
$em = $this->em;
|
||||||
|
$row = new Customer();
|
||||||
|
|
||||||
|
$this->setObject($row, $req);
|
||||||
|
|
||||||
|
// initialize error lists
|
||||||
|
$error_array = [];
|
||||||
|
$nerror_array = [];
|
||||||
|
$verror_array = [];
|
||||||
|
|
||||||
|
// custom validation for vehicles
|
||||||
|
$vehicles = json_decode($req->request->get('vehicles'));
|
||||||
|
|
||||||
|
if (!empty($vehicles))
|
||||||
|
{
|
||||||
|
foreach ($vehicles as $vehicle)
|
||||||
|
{
|
||||||
|
// check if vehicle exists
|
||||||
|
$vobj = $em->getRepository(Vehicle::class)->find($vehicle->vehicle);
|
||||||
|
|
||||||
|
if (empty($vobj))
|
||||||
|
{
|
||||||
|
$verror_array[$vehicle->index]['vehicle'] = 'Invalid vehicle specified.';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$cust_vehicle = new CustomerVehicle();
|
||||||
|
$cust_vehicle->setName($vehicle->name)
|
||||||
|
->setVehicle($vobj)
|
||||||
|
->setPlateNumber($vehicle->plate_number)
|
||||||
|
->setModelYear($vehicle->model_year)
|
||||||
|
->setColor($vehicle->color)
|
||||||
|
->setStatusCondition($vehicle->status_condition)
|
||||||
|
->setFuelType($vehicle->fuel_type)
|
||||||
|
->setActive($vehicle->flag_active)
|
||||||
|
->setCustomer($row);
|
||||||
|
|
||||||
|
// if specified, check if battery exists
|
||||||
|
if ($vehicle->battery)
|
||||||
|
{
|
||||||
|
// check if battery exists
|
||||||
|
$bobj = $em->getRepository(Battery::class)->find($vehicle->battery);
|
||||||
|
|
||||||
|
if (empty($bobj))
|
||||||
|
{
|
||||||
|
$verror_array[$vehicle->index]['battery'] = 'Invalid battery specified.';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// check if warranty expiration was specified
|
||||||
|
$warr_ex = DateTime::createFromFormat("d M Y", $vehicle->warranty_expiration);
|
||||||
|
if (!$warr_ex)
|
||||||
|
$warr_ex = null;
|
||||||
|
|
||||||
|
$cust_vehicle->setHasMotoliteBattery(true)
|
||||||
|
->setCurrentBattery($bobj)
|
||||||
|
->setWarrantyCode($vehicle->warranty_code)
|
||||||
|
->setWarrantyExpiration($warr_ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$cust_vehicle->setHasMotoliteBattery(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
$verrors = $this->validator->validate($cust_vehicle);
|
||||||
|
|
||||||
|
// add errors to list
|
||||||
|
foreach ($verrors as $error)
|
||||||
|
{
|
||||||
|
if (!isset($verror_array[$vehicle->index]))
|
||||||
|
$verror_array[$vehicle->index] = [];
|
||||||
|
|
||||||
|
$verror_array[$vehicle->index][$error->getPropertyPath()] = $error->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to entity
|
||||||
|
if (!isset($verror_array[$vehicle->index]))
|
||||||
|
{
|
||||||
|
$row->addVehicle($cust_vehicle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate
|
||||||
|
$errors = $this->validator->validate($row);
|
||||||
|
|
||||||
|
// add errors to list
|
||||||
|
foreach ($errors as $error)
|
||||||
|
{
|
||||||
|
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if any errors were found
|
||||||
|
$result = [];
|
||||||
|
if (!empty($error_array) || !empty($nerror_array) || !empty($verror_array))
|
||||||
|
{
|
||||||
|
// return all error_arrays
|
||||||
|
$result = [
|
||||||
|
'error_array' => $error_array,
|
||||||
|
'nerror_array' => $nerror_array,
|
||||||
|
'verror_array' => $verror_array,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// validated! save the entity
|
||||||
|
$em->persist($row);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
$result = [
|
||||||
|
'id' => $row->getID(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize update customer form
|
||||||
|
public function initializeUpdateCustomerForm($id)
|
||||||
|
{
|
||||||
|
$params['mode'] = 'update';
|
||||||
|
|
||||||
|
// get row data
|
||||||
|
$em = $this->em;
|
||||||
|
$row = $em->getRepository(Customer::class)->find($id);
|
||||||
|
|
||||||
|
// make sure this row exists
|
||||||
|
if (empty($row))
|
||||||
|
throw new NotFoundHttpException('The item does not exist');
|
||||||
|
|
||||||
|
// get dropdown parameters
|
||||||
|
$this->fillDropdownParameters($params);
|
||||||
|
|
||||||
|
// get template to display
|
||||||
|
$params['template'] = $this->getTwigTemplate('cust_update_form');
|
||||||
|
|
||||||
|
$params['obj'] = $row;
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update customer and customer vehicle
|
||||||
|
public function updateCustomer(Request $req, $id)
|
||||||
|
{
|
||||||
|
// get row data
|
||||||
|
$em = $this->em;
|
||||||
|
$cust = $em->getRepository(Customer::class)->find($id);
|
||||||
|
|
||||||
|
// make sure this row exists
|
||||||
|
if (empty($cust))
|
||||||
|
throw $this->createNotFoundException('The item does not exist');
|
||||||
|
|
||||||
|
$this->setObject($cust, $req);
|
||||||
|
|
||||||
|
// initialize error lists
|
||||||
|
$error_array = [];
|
||||||
|
$nerror_array = [];
|
||||||
|
$verror_array = [];
|
||||||
|
|
||||||
|
// TODO: validate mobile numbers
|
||||||
|
// TODO: validate vehicles
|
||||||
|
|
||||||
|
// custom validation for vehicles
|
||||||
|
$vehicles = json_decode($req->request->get('vehicles'));
|
||||||
|
$this->updateVehicles($em, $cust, $vehicles);
|
||||||
|
|
||||||
|
// validate
|
||||||
|
$errors = $this->validator->validate($cust);
|
||||||
|
|
||||||
|
// add errors to list
|
||||||
|
foreach ($errors as $error)
|
||||||
|
{
|
||||||
|
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if any errors were found
|
||||||
|
$result = [];
|
||||||
|
if (!empty($error_array) || !empty($nerror_array) || !empty($verror_array))
|
||||||
|
{
|
||||||
|
// return all error_arrays
|
||||||
|
$result = [
|
||||||
|
'error_array' => $error_array,
|
||||||
|
'nerror_array' => $nerror_array,
|
||||||
|
'verror_array' => $verror_array,
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// validated! save the entity. do a persist anyway to save child entities
|
||||||
|
$em->persist($cust);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
$result = [
|
||||||
|
'id' => $cust->getID(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete customer
|
||||||
|
public function deleteCustomer(int $id)
|
||||||
|
{
|
||||||
|
// get row data
|
||||||
|
$em = $this->em;
|
||||||
|
$row = $em->getRepository(Customer::class)->find($id);
|
||||||
|
|
||||||
|
if (empty($row))
|
||||||
|
throw new NotFoundHttpException('The item does not exist');
|
||||||
|
|
||||||
|
// delete this row
|
||||||
|
$em->remove($row);
|
||||||
|
$em->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// get customer vehicles
|
||||||
|
public function getCustomerVehicles(Request $req)
|
||||||
|
{
|
||||||
|
// get search term
|
||||||
|
$term = $req->query->get('search');
|
||||||
|
|
||||||
|
// get querybuilder
|
||||||
|
$qb = $this->em
|
||||||
|
->getRepository(CustomerVehicle::class)
|
||||||
|
->createQueryBuilder('q');
|
||||||
|
|
||||||
|
/*
|
||||||
|
// build expression now since we're reusing it
|
||||||
|
$vehicle_label = $qb->expr()->concat(
|
||||||
|
'q.plate_number',
|
||||||
|
$qb->expr()->literal(' - '),
|
||||||
|
'c.first_name',
|
||||||
|
$qb->expr()->literal(' '),
|
||||||
|
'c.last_name',
|
||||||
|
$qb->expr()->literal(' (+63'),
|
||||||
|
'c.phone_mobile',
|
||||||
|
$qb->expr()->literal(')')
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// count total records
|
||||||
|
$tquery = $qb->select('COUNT(q)');
|
||||||
|
|
||||||
|
// add filters to count query
|
||||||
|
if (!empty($term)) {
|
||||||
|
$tquery->where('q.plate_number like :search')
|
||||||
|
->setParameter('search', $term . '%');
|
||||||
|
/*
|
||||||
|
$tquery->where('match_against (q.plate_number, :search \'in boolean mode\') > 0.1')
|
||||||
|
->setParameter('search', $term . '*');
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
$tquery->where('q.plate_number LIKE :filter')
|
||||||
|
->setParameter('filter', '%' . $term . '%');
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
$total = $tquery->getQuery()
|
||||||
|
->getSingleScalarResult();
|
||||||
|
|
||||||
|
// pagination vars
|
||||||
|
$page = $req->query->get('page') ?? 1;
|
||||||
|
$perpage = 20;
|
||||||
|
$offset = ($page - 1) * $perpage;
|
||||||
|
$pages = ceil($total / $perpage);
|
||||||
|
$has_more_pages = $page < $pages ? true : false;
|
||||||
|
|
||||||
|
// build main query
|
||||||
|
$query = $qb->select('q');
|
||||||
|
/*
|
||||||
|
->addSelect($vehicle_label . ' as vehicle_label')
|
||||||
|
->addSelect('c.first_name as cust_first_name')
|
||||||
|
->addSelect('c.last_name as cust_last_name');
|
||||||
|
*/
|
||||||
|
|
||||||
|
// add filters if needed
|
||||||
|
if (!empty($term)) {
|
||||||
|
$query->where('q.plate_number like :search')
|
||||||
|
->setParameter('search', $term . '%');
|
||||||
|
/*
|
||||||
|
$query->where('match_against (q.plate_number, :search \'in boolean mode\') > 0.1')
|
||||||
|
->setParameter('search', $term . '*');
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
$query->where('q.plate_number LIKE :filter')
|
||||||
|
->setParameter('filter', '%' . $term . '%');
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// get rows
|
||||||
|
$query_obj = $query->orderBy('q.plate_number', 'asc')
|
||||||
|
->setFirstResult($offset)
|
||||||
|
->setMaxResults($perpage)
|
||||||
|
->getQuery();
|
||||||
|
// error_log($query_obj->getSql());
|
||||||
|
|
||||||
|
$obj_rows = $query_obj->getResult();
|
||||||
|
|
||||||
|
// build vehicles array
|
||||||
|
$vehicles = [];
|
||||||
|
|
||||||
|
foreach ($obj_rows as $cv) {
|
||||||
|
$cust = $cv->getCustomer();
|
||||||
|
$vehicles[] = [
|
||||||
|
'id' => $cv->getID(),
|
||||||
|
'text' => $cv->getPlateNumber() . ' ' . $cust->getFirstName() . ' ' . $cust->getLastName() . ' ('. self::COUNTRY_CODE_PREFIX . $cust->getPhoneMobile() . ')',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = [
|
||||||
|
'vehicles' => $vehicles,
|
||||||
|
'has_more_pages' => $has_more_pages,
|
||||||
|
];
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get customer vehicle info
|
||||||
|
public function getCustomerVehicleInfo(Request $req)
|
||||||
|
{
|
||||||
|
// get id
|
||||||
|
$id = $req->query->get('id');
|
||||||
|
|
||||||
|
// get row data
|
||||||
|
$em = $this->em;
|
||||||
|
$obj = $em->getRepository(CustomerVehicle::class)->find($id);
|
||||||
|
|
||||||
|
// make sure this row exists
|
||||||
|
if (empty($obj)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$customer = $obj->getCustomer();
|
||||||
|
$vehicle = $obj->getVehicle();
|
||||||
|
$battery = $obj->getCurrentBattery();
|
||||||
|
|
||||||
|
// build response
|
||||||
|
$row = [
|
||||||
|
'customer' => [
|
||||||
|
'id' => $customer->getID(),
|
||||||
|
'first_name' => $customer->getFirstName(),
|
||||||
|
'last_name' => $customer->getLastName(),
|
||||||
|
'customer_notes' => $customer->getCustomerNotes(),
|
||||||
|
'phone_mobile' => $customer->getPhoneMobile(),
|
||||||
|
'phone_landline' => $customer->getPhoneLandline(),
|
||||||
|
'phone_office' => $customer->getPhoneOffice(),
|
||||||
|
'phone_fax' => $customer->getPhoneFax(),
|
||||||
|
],
|
||||||
|
'vehicle' => [
|
||||||
|
'id' => $vehicle->getID(),
|
||||||
|
'mfg_name' => $vehicle->getManufacturer()->getName(),
|
||||||
|
'make' => $vehicle->getMake(),
|
||||||
|
'model_year_from' => $vehicle->getModelYearFrom(),
|
||||||
|
'model_year_to' => $vehicle->getModelYearTo(),
|
||||||
|
'model_year' => $obj->getModelYear(),
|
||||||
|
'color' => $obj->getColor(),
|
||||||
|
'plate_number' => $obj->getPlateNumber(),
|
||||||
|
'fuel_type' => $obj->getFuelType(),
|
||||||
|
'status_condition' => $obj->getStatusCondition(),
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!empty($battery)) {
|
||||||
|
$row['battery'] = [
|
||||||
|
'id' => $battery->getID(),
|
||||||
|
'mfg_name' => $battery->getManufacturer()->getName(),
|
||||||
|
'model_name' => $battery->getModel()->getName(),
|
||||||
|
'size_name' => $battery->getSize()->getName(),
|
||||||
|
'prod_code' => $battery->getProductCode(),
|
||||||
|
'warranty_code' => $obj->getWarrantyCode(),
|
||||||
|
'warranty_expiration' => $obj->getWarrantyExpiration() ? $obj->getWarrantyExpiration()->format("d M Y") : "",
|
||||||
|
'has_motolite_battery' => $obj->hasMotoliteBattery(),
|
||||||
|
'is_active' => $obj->isActive()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getTwigTemplate($id)
|
||||||
|
{
|
||||||
|
if (isset($this->template_hash[$id]))
|
||||||
|
{
|
||||||
|
return $this->template_hash[$id];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setObject($obj, $req)
|
||||||
|
{
|
||||||
|
// set and save values
|
||||||
|
$obj->setTitle($req->request->get('title'))
|
||||||
|
->setFirstName($req->request->get('first_name'))
|
||||||
|
->setLastName($req->request->get('last_name'))
|
||||||
|
->setCustomerClassification($req->request->get('customer_classification'))
|
||||||
|
->setCustomerNotes($req->request->get('customer_notes'))
|
||||||
|
->setEmail($req->request->get('email'))
|
||||||
|
->setIsCSAT($req->request->get('flag_csat') ? true : false)
|
||||||
|
->setActive($req->request->get('flag_active') ? true : false);
|
||||||
|
|
||||||
|
// phone numbers
|
||||||
|
$obj->setPhoneMobile($req->request->get('phone_mobile'))
|
||||||
|
->setPhoneLandline($req->request->get('phone_landline'))
|
||||||
|
->setPhoneOffice($req->request->get('phone_office'))
|
||||||
|
->setPhoneFax($req->request->get('phone_fax'));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function fillDropdownParameters(&$params)
|
||||||
|
{
|
||||||
|
$em = $this->em;
|
||||||
|
|
||||||
|
$params['bmfgs'] = $em->getRepository(BatteryManufacturer::class)->findAll();
|
||||||
|
$params['vmfgs'] = $em->getRepository(VehicleManufacturer::class)->findAll();
|
||||||
|
|
||||||
|
$params['classifications'] = CustomerClassification::getCollection();
|
||||||
|
$params['fuel_types'] = FuelType::getCollection();
|
||||||
|
$params['status_conditions'] = VehicleStatusCondition::getCollection();
|
||||||
|
|
||||||
|
$params['years'] = $this->generateYearOptions();
|
||||||
|
$params['batteries'] = $em->getRepository(Battery::class)->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function generateYearOptions()
|
||||||
|
{
|
||||||
|
$start_year = 1950;
|
||||||
|
return range($start_year, date("Y") + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadTemplates()
|
||||||
|
{
|
||||||
|
$this->template_hash = [];
|
||||||
|
|
||||||
|
// add all twig templates for customer to hash
|
||||||
|
$this->template_hash['cust_add_form'] = 'customer/form.html.twig';
|
||||||
|
$this->template_hash['cust_update_form'] = 'customer/form.html.twig';
|
||||||
|
$this->template_hash['cust_list'] = 'customer/list.html.twig';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function updateVehicles($em, Customer $cust, $vehicles)
|
||||||
|
{
|
||||||
|
$vehicle_ids = [];
|
||||||
|
|
||||||
|
foreach ($vehicles as $vehicle)
|
||||||
|
{
|
||||||
|
// check if customer vehicle exists
|
||||||
|
if (!empty($vehicle->id))
|
||||||
|
{
|
||||||
|
$cust_vehicle = $em->getRepository(CustomerVehicle::class)->find($vehicle->id);
|
||||||
|
if ($cust_vehicle == null)
|
||||||
|
throw new CrudException("Could not find customer vehicle.");
|
||||||
|
|
||||||
|
}
|
||||||
|
// this is a new vehicle
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$cust_vehicle = new CustomerVehicle();
|
||||||
|
$cust_vehicle->setCustomer($cust);
|
||||||
|
$cust->addVehicle($cust_vehicle);
|
||||||
|
$em->persist($cust_vehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// vehicle, because they could have changed vehicle type
|
||||||
|
$vobj = $em->getRepository(Vehicle::class)->find($vehicle->vehicle);
|
||||||
|
if ($vobj == null)
|
||||||
|
throw new CrudException("Could not find vehicle.");
|
||||||
|
|
||||||
|
// TODO: validate details
|
||||||
|
|
||||||
|
$cust_vehicle->setName($vehicle->name)
|
||||||
|
->setVehicle($vobj)
|
||||||
|
->setPlateNumber($vehicle->plate_number)
|
||||||
|
->setModelYear($vehicle->model_year)
|
||||||
|
->setColor($vehicle->color)
|
||||||
|
->setStatusCondition($vehicle->status_condition)
|
||||||
|
->setFuelType($vehicle->fuel_type)
|
||||||
|
->setActive($vehicle->flag_active);
|
||||||
|
|
||||||
|
// if specified, check if battery exists
|
||||||
|
if ($vehicle->battery)
|
||||||
|
{
|
||||||
|
// check if battery exists
|
||||||
|
$bobj = $em->getRepository(Battery::class)->find($vehicle->battery);
|
||||||
|
if ($bobj == null)
|
||||||
|
throw new CrudException("Could not find battery.");
|
||||||
|
|
||||||
|
// check if warranty expiration was specified
|
||||||
|
$warr_ex = DateTime::createFromFormat("d M Y", $vehicle->warranty_expiration);
|
||||||
|
if (!$warr_ex)
|
||||||
|
$warr_ex = null;
|
||||||
|
|
||||||
|
$cust_vehicle->setHasMotoliteBattery(true)
|
||||||
|
->setCurrentBattery($bobj)
|
||||||
|
->setWarrantyCode($vehicle->warranty_code)
|
||||||
|
->setWarrantyExpiration($warr_ex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$cust_vehicle->setHasMotoliteBattery(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to list of vehicles to keep
|
||||||
|
$vehicle_ids[$cust_vehicle->getID()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
// delete all vehicles not in list
|
||||||
|
$cvs = $cust->getVehicles();
|
||||||
|
foreach ($cvs as $cv)
|
||||||
|
{
|
||||||
|
if (!isset($vehicle_ids[$cv->getID()]))
|
||||||
|
{
|
||||||
|
$cust->removeVehicle($cv);
|
||||||
|
$em->remove($cv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if datatable filter is present and append to query
|
||||||
|
protected function setQueryFilters($datatable, &$query) {
|
||||||
|
if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) {
|
||||||
|
$query->join('q.vehicles', 'cv')
|
||||||
|
->where('q.first_name LIKE :filter')
|
||||||
|
->orWhere('q.last_name LIKE :filter')
|
||||||
|
->orWhere('q.customer_classification LIKE :filter')
|
||||||
|
->orWhere('cv.plate_number LIKE :filter')
|
||||||
|
->setParameter('filter', $datatable['query']['data-rows-search'] . '%');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
35
src/Service/CustomerHandlerInterface.php
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
interface CustomerHandlerInterface
|
||||||
|
{
|
||||||
|
// initialize form to display customer list
|
||||||
|
public function initializeCustomerIndexForm();
|
||||||
|
|
||||||
|
// get customers
|
||||||
|
public function getCustomers(Request $req);
|
||||||
|
|
||||||
|
// initialize add customer form
|
||||||
|
public function initializeAddCustomerForm();
|
||||||
|
|
||||||
|
// add new customer and customer vehicle, if any
|
||||||
|
public function addCustomer(Request $req);
|
||||||
|
|
||||||
|
// initialize update customer form
|
||||||
|
public function initializeUpdateCustomerForm(int $id);
|
||||||
|
|
||||||
|
// update customer and customer vehicle
|
||||||
|
public function updateCustomer(Request $req, int $id);
|
||||||
|
|
||||||
|
// delete customer
|
||||||
|
public function deleteCustomer(int $id);
|
||||||
|
|
||||||
|
// get customer vehicles
|
||||||
|
public function getCustomerVehicles(Request $req);
|
||||||
|
|
||||||
|
// get customer vehicle info
|
||||||
|
public function getCustomerVehicleInfo(Request $req);
|
||||||
|
}
|
||||||
21
src/Service/GISManager/Bing.php
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service\GISManager;
|
||||||
|
|
||||||
|
use App\Service\GISManagerInterface;
|
||||||
|
|
||||||
|
class Bing implements GISManagerInterface
|
||||||
|
{
|
||||||
|
const JS_INIT_FILE = 'initBingMap.js';
|
||||||
|
|
||||||
|
public function getJSInitFile()
|
||||||
|
{
|
||||||
|
// return the bing map js file: initBingMap.js
|
||||||
|
return self::JS_INIT_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getJSJOFile()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
21
src/Service/GISManager/Google.php
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service\GISManager;
|
||||||
|
|
||||||
|
use App\Service\GISManagerInterface;
|
||||||
|
|
||||||
|
class Google implements GISManagerInterface
|
||||||
|
{
|
||||||
|
const JS_INIT_FILE = 'initGoogleMap.js';
|
||||||
|
|
||||||
|
public function getJSInitFile()
|
||||||
|
{
|
||||||
|
// return the google map js file: initGoogleMap.js
|
||||||
|
return self::JS_INIT_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getJSJOFile()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
23
src/Service/GISManager/OpenStreet.php
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service\GISManager;
|
||||||
|
|
||||||
|
use App\Service\GISManagerInterface;
|
||||||
|
|
||||||
|
class OpenStreet implements GISManagerInterface
|
||||||
|
{
|
||||||
|
const JS_INIT_FILE = 'initOpenStreetMap.js';
|
||||||
|
const JS_JO_FILE = 'joOpenStreetMap.js';
|
||||||
|
|
||||||
|
public function getJSInitFile()
|
||||||
|
{
|
||||||
|
// return the openstreet map js file: initOpenStreetMap.js
|
||||||
|
return self::JS_INIT_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getJSJOFile()
|
||||||
|
{
|
||||||
|
return self::JS_JO_FILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
13
src/Service/GISManagerInterface.php
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
interface GISManagerInterface
|
||||||
|
{
|
||||||
|
// returns the actual JS file
|
||||||
|
public function getJSInitFile();
|
||||||
|
|
||||||
|
// return the JS file for JO map
|
||||||
|
public function getJSJOFile();
|
||||||
|
}
|
||||||
|
|
||||||
632
src/Service/InvoiceGenerator/CMBInvoiceGenerator.php
Normal file
|
|
@ -0,0 +1,632 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service\InvoiceGenerator;
|
||||||
|
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
use App\Ramcar\InvoiceCriteria;
|
||||||
|
use App\Ramcar\InvoiceStatus;
|
||||||
|
use App\Ramcar\CMBTradeInType;
|
||||||
|
use App\Ramcar\DiscountApply;
|
||||||
|
use App\Ramcar\CMBServiceType;
|
||||||
|
use App\Ramcar\FuelType;
|
||||||
|
|
||||||
|
use App\Entity\Invoice;
|
||||||
|
use App\Entity\InvoiceItem;
|
||||||
|
use App\Entity\Battery;
|
||||||
|
use App\Entity\Promo;
|
||||||
|
use App\Entity\User;
|
||||||
|
|
||||||
|
use App\Service\InvoiceGeneratorInterface;
|
||||||
|
|
||||||
|
use Doctrine\Common\Util\Debug;
|
||||||
|
|
||||||
|
class CMBInvoiceGenerator implements InvoiceGeneratorInterface
|
||||||
|
{
|
||||||
|
const TAX_RATE = 0.00;
|
||||||
|
const SERVICE_FEE = 300;
|
||||||
|
const RECHARGE_FEE = 300;
|
||||||
|
const TROUBLESHOOTING_FEE = 150;
|
||||||
|
const BATT_REPLACEMENT_FEE = 0;
|
||||||
|
const WARRANTY_FEE = 0;
|
||||||
|
const OTHER_SERVICES_FEE = 200;
|
||||||
|
const COOLANT_FEE = 1600;
|
||||||
|
const REFUEL_FEE_GAS = 260;
|
||||||
|
const REFUEL_FEE_DIESEL = 220;
|
||||||
|
|
||||||
|
private $security;
|
||||||
|
protected $em;
|
||||||
|
protected $validator;
|
||||||
|
|
||||||
|
// creates invoice based on the criteria sent
|
||||||
|
public function __construct(Security $security, EntityManagerInterface $em,
|
||||||
|
ValidatorInterface $validator)
|
||||||
|
{
|
||||||
|
$this->security = $security;
|
||||||
|
$this->em = $em;
|
||||||
|
$this->validator = $validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateInvoice(InvoiceCriteria $criteria)
|
||||||
|
{
|
||||||
|
// initialize
|
||||||
|
$invoice = new Invoice();
|
||||||
|
$total = [
|
||||||
|
'sell_price' => 0.0,
|
||||||
|
'vat' => 0.0,
|
||||||
|
'vat_ex_price' => 0.0,
|
||||||
|
'ti_rate' => 0.0,
|
||||||
|
'total_price' => 0.0,
|
||||||
|
'discount' => 0.0,
|
||||||
|
];
|
||||||
|
|
||||||
|
$stype = $criteria->getServiceType();
|
||||||
|
$cv = $criteria->getCustomerVehicle();
|
||||||
|
$has_coolant = $criteria->hasCoolant();
|
||||||
|
switch ($stype)
|
||||||
|
{
|
||||||
|
case CMBServiceType::JUMPSTART:
|
||||||
|
$this->processJumpstart($total, $invoice);
|
||||||
|
break;
|
||||||
|
//case ServiceType::JUMPSTART_WARRANTY:
|
||||||
|
// $this->processJumpstartWarranty($total, $invoice);
|
||||||
|
|
||||||
|
case CMBServiceType::BATTERY_REPLACEMENT_NEW:
|
||||||
|
$this->processEntries($total, $criteria, $invoice);
|
||||||
|
/*
|
||||||
|
$this->processBatteries($total, $criteria, $invoice);
|
||||||
|
$this->processTradeIns($total, $criteria, $invoice);
|
||||||
|
*/
|
||||||
|
$this->processDiscount($total, $criteria, $invoice);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMBServiceType::BATTERY_REPLACEMENT_WARRANTY:
|
||||||
|
$this->processWarranty($total, $criteria, $invoice);
|
||||||
|
break;
|
||||||
|
//case ServiceType::POST_RECHARGED:
|
||||||
|
// $this->processRecharge($total, $invoice);
|
||||||
|
// break;
|
||||||
|
//case ServiceType::POST_REPLACEMENT:
|
||||||
|
// $this->processReplacement($total, $invoice);
|
||||||
|
// break;
|
||||||
|
//case ServiceType::TIRE_REPAIR:
|
||||||
|
// $this->processTireRepair($total, $invoice, $cv);
|
||||||
|
// $this->processOtherServices($total, $invoice, $stype);
|
||||||
|
// break;
|
||||||
|
//case ServiceType::OVERHEAT_ASSISTANCE:
|
||||||
|
// $this->processOverheat($total, $invoice, $cv, $has_coolant);
|
||||||
|
// break;
|
||||||
|
//case ServiceType::EMERGENCY_REFUEL:
|
||||||
|
// error_log('processing refuel');
|
||||||
|
// $ftype = $criteria->getCustomerVehicle()->getFuelType();
|
||||||
|
// $this->processRefuel($total, $invoice, $cv);
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check if any promo is applied
|
||||||
|
// apply discounts
|
||||||
|
$promos = $criteria->getPromos();
|
||||||
|
|
||||||
|
// get current user
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
if ($user != null)
|
||||||
|
{
|
||||||
|
$invoice->setCreatedBy($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoice->setTotalPrice($total['total_price'])
|
||||||
|
->setVATExclusivePrice($total['vat_ex_price'])
|
||||||
|
->setVAT($total['vat'])
|
||||||
|
->setDiscount($total['discount'])
|
||||||
|
->setTradeIn($total['ti_rate'])
|
||||||
|
->setStatus(InvoiceStatus::DRAFT);
|
||||||
|
|
||||||
|
// dump
|
||||||
|
//Debug::dump($invoice, 1);
|
||||||
|
|
||||||
|
return $invoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate invoice criteria
|
||||||
|
public function generateInvoiceCriteria($jo, $promo_id, $invoice_items, &$error_array)
|
||||||
|
{
|
||||||
|
$em = $this->em;
|
||||||
|
|
||||||
|
// instantiate the invoice criteria
|
||||||
|
$criteria = new InvoiceCriteria();
|
||||||
|
$criteria->setServiceType($jo->getServiceType())
|
||||||
|
->setCustomerVehicle($jo->getCustomerVehicle());
|
||||||
|
|
||||||
|
$ierror = $this->invoicePromo($criteria, $promo_id);
|
||||||
|
|
||||||
|
if (!$ierror && !empty($invoice_items))
|
||||||
|
{
|
||||||
|
// check for trade-in so we can mark it for mobile app
|
||||||
|
foreach ($invoice_items as $item)
|
||||||
|
{
|
||||||
|
// get first trade-in
|
||||||
|
if (!empty($item['trade_in']))
|
||||||
|
{
|
||||||
|
$jo->getTradeInType($item['trade_in']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ierror = $this->invoiceBatteries($criteria, $invoice_items);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ierror)
|
||||||
|
{
|
||||||
|
$error_array['invoice'] = $ierror;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// generate the invoice
|
||||||
|
$iobj = $this->generateInvoice($criteria);
|
||||||
|
|
||||||
|
// validate
|
||||||
|
$ierrors = $this->validator->validate($iobj);
|
||||||
|
|
||||||
|
// add errors to list
|
||||||
|
foreach ($ierrors as $error) {
|
||||||
|
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if invoice already exists for JO
|
||||||
|
$old_invoice = $jo->getInvoice();
|
||||||
|
if ($old_invoice != null)
|
||||||
|
{
|
||||||
|
// remove old invoice
|
||||||
|
$em->remove($old_invoice);
|
||||||
|
$em->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add invoice to JO
|
||||||
|
$jo->setInvoice($iobj);
|
||||||
|
|
||||||
|
$em->persist($iobj);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getTaxAmount($price)
|
||||||
|
{
|
||||||
|
$vat_ex_price = $this->getTaxExclusivePrice($price);
|
||||||
|
return $price - $vat_ex_price;
|
||||||
|
// return round($vat_ex_price * self::TAX_RATE, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getTaxExclusivePrice($price)
|
||||||
|
{
|
||||||
|
return round($price / (1 + self::TAX_RATE), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getTradeInRate($ti)
|
||||||
|
{
|
||||||
|
$size = $ti['size'];
|
||||||
|
$trade_in = $ti['trade_in'];
|
||||||
|
|
||||||
|
if ($trade_in == null)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch ($trade_in)
|
||||||
|
{
|
||||||
|
// TODO: for now, tradein uses getTIPriceMotolite.
|
||||||
|
// Might need to modify later
|
||||||
|
case CMBTradeInType::YES:
|
||||||
|
return $size->getTIPriceMotolite();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function invoicePromo(InvoiceCriteria $criteria, $promo_id)
|
||||||
|
{
|
||||||
|
// return error if there's a problem, false otherwise
|
||||||
|
// check service type
|
||||||
|
$stype = $criteria->getServiceType();
|
||||||
|
if ($stype != CMBServiceType::BATTERY_REPLACEMENT_NEW)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
|
||||||
|
if (empty($promo_id))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if this is a valid promo
|
||||||
|
$promo = $this->em->getRepository(Promo::class)->find($promo_id);
|
||||||
|
|
||||||
|
if (empty($promo))
|
||||||
|
return 'Invalid promo specified.';
|
||||||
|
|
||||||
|
$criteria->addPromo($promo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function invoiceBatteries(InvoiceCriteria $criteria, $items)
|
||||||
|
{
|
||||||
|
// check service type
|
||||||
|
$stype = $criteria->getServiceType();
|
||||||
|
if ($stype != CMBServiceType::BATTERY_REPLACEMENT_NEW && $stype != CMBServiceType::BATTERY_REPLACEMENT_WARRANTY)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// return error if there's a problem, false otherwise
|
||||||
|
if (!empty($items))
|
||||||
|
{
|
||||||
|
foreach ($items as $item)
|
||||||
|
{
|
||||||
|
// check if this is a valid battery
|
||||||
|
$battery = $this->em->getRepository(Battery::class)->find($item['battery']);
|
||||||
|
|
||||||
|
if (empty($battery))
|
||||||
|
{
|
||||||
|
$error = 'Invalid battery specified.';
|
||||||
|
return $error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// quantity
|
||||||
|
$qty = $item['quantity'];
|
||||||
|
if ($qty < 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
// add to criteria
|
||||||
|
$criteria->addBattery($battery, $qty);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// if this is a trade in, add trade in
|
||||||
|
if (!empty($item['trade_in']) && CMBTradeInType::validate($item['trade_in']))
|
||||||
|
$trade_in = $item['trade_in'];
|
||||||
|
else
|
||||||
|
$trade_in = null;
|
||||||
|
|
||||||
|
$criteria->addEntry($battery, $trade_in, $qty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function processEntries(&$total, InvoiceCriteria $criteria, Invoice $invoice)
|
||||||
|
{
|
||||||
|
// error_log('processing entries...');
|
||||||
|
$entries = $criteria->getEntries();
|
||||||
|
|
||||||
|
$con_batts = [];
|
||||||
|
$con_tis = [];
|
||||||
|
foreach ($entries as $entry)
|
||||||
|
{
|
||||||
|
$batt = $entry['battery'];
|
||||||
|
$qty = $entry['qty'];
|
||||||
|
$trade_in = $entry['trade_in'];
|
||||||
|
$size = $batt->getSize();
|
||||||
|
|
||||||
|
// consolidate batteries
|
||||||
|
$batt_id = $batt->getID();
|
||||||
|
if (!isset($con_batts[$batt_id]))
|
||||||
|
$con_batts[$batt->getID()] = [
|
||||||
|
'batt' => $batt,
|
||||||
|
'qty' => 0
|
||||||
|
];
|
||||||
|
$con_batts[$batt_id]['qty']++;
|
||||||
|
|
||||||
|
|
||||||
|
// no trade-in
|
||||||
|
if ($trade_in == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// consolidate trade-ins
|
||||||
|
$ti_key = $size->getID() . '|' . $trade_in;
|
||||||
|
if (!isset($con_tis[$ti_key]))
|
||||||
|
$con_tis[$ti_key] = [
|
||||||
|
'size' => $size,
|
||||||
|
'trade_in' => $trade_in,
|
||||||
|
'qty' => 0
|
||||||
|
];
|
||||||
|
$con_tis[$ti_key]['qty']++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->processBatteries($total, $con_batts, $invoice);
|
||||||
|
$this->processTradeIns($total, $con_tis, $invoice);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processBatteries(&$total, $con_batts, Invoice $invoice)
|
||||||
|
{
|
||||||
|
// process batteries
|
||||||
|
foreach ($con_batts as $con_data)
|
||||||
|
{
|
||||||
|
$batt = $con_data['batt'];
|
||||||
|
$qty = $con_data['qty'];
|
||||||
|
|
||||||
|
$sell_price = $batt->getSellingPrice();
|
||||||
|
$vat = $this->getTaxAmount($sell_price);
|
||||||
|
// $vat_ex_price = $this->getTaxExclusivePrice($sell_price);
|
||||||
|
|
||||||
|
$total['sell_price'] += $sell_price * $qty;
|
||||||
|
$total['vat'] += $vat * $qty;
|
||||||
|
$total['vat_ex_price'] += ($sell_price - $vat) * $qty;
|
||||||
|
|
||||||
|
$total['total_price'] += $sell_price * $qty;
|
||||||
|
|
||||||
|
// add item
|
||||||
|
$item = new InvoiceItem();
|
||||||
|
$item->setInvoice($invoice)
|
||||||
|
->setTitle($batt->getModel()->getName() . ' ' . $batt->getSize()->getName())
|
||||||
|
->setQuantity($qty)
|
||||||
|
->setPrice($sell_price)
|
||||||
|
->setBattery($batt);
|
||||||
|
|
||||||
|
$invoice->addItem($item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processTradeIns(&$total, $con_tis, Invoice $invoice)
|
||||||
|
{
|
||||||
|
foreach ($con_tis as $ti)
|
||||||
|
{
|
||||||
|
$qty = $ti['qty'];
|
||||||
|
$ti_rate = $this->getTradeInRate($ti);
|
||||||
|
|
||||||
|
$total['ti_rate'] += $ti_rate * $qty;
|
||||||
|
$total['total_price'] -= $ti_rate * $qty;
|
||||||
|
|
||||||
|
// add item
|
||||||
|
$item = new InvoiceItem();
|
||||||
|
$item->setInvoice($invoice)
|
||||||
|
->setTitle('Trade-in ' . CMBTradeInType::getName($ti['trade_in']) . ' ' . $ti['size']->getName() . ' battery')
|
||||||
|
->setQuantity($qty)
|
||||||
|
->setPrice($ti_rate * -1);
|
||||||
|
|
||||||
|
$invoice->addItem($item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processDiscount(&$total, InvoiceCriteria $criteria, Invoice $invoice)
|
||||||
|
{
|
||||||
|
$promos = $criteria->getPromos();
|
||||||
|
if (count($promos) < 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// NOTE: only get first promo because only one is applicable anyway
|
||||||
|
$promo = $promos[0];
|
||||||
|
|
||||||
|
$rate = $promo->getDiscountRate();
|
||||||
|
$apply_to = $promo->getDiscountApply();
|
||||||
|
|
||||||
|
switch ($apply_to)
|
||||||
|
{
|
||||||
|
case DiscountApply::SRP:
|
||||||
|
$discount = round($total['sell_price'] * $rate, 2);
|
||||||
|
break;
|
||||||
|
case DiscountApply::OPL:
|
||||||
|
// $discount = round($total['sell_price'] * 0.6 / 0.7 * $rate, 2);
|
||||||
|
$discount = round($total['sell_price'] * (1 - 1.5 / 0.7 * $rate), 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if discount is higher than 0, display in invoice
|
||||||
|
if ($discount > 0)
|
||||||
|
{
|
||||||
|
$item = new InvoiceItem();
|
||||||
|
$item->setInvoice($invoice)
|
||||||
|
->setTitle('Promo discount')
|
||||||
|
->setQuantity(1)
|
||||||
|
->setPrice(-1 * $discount);
|
||||||
|
$invoice->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
$total['discount'] = $discount;
|
||||||
|
$total['total_price'] -= $discount;
|
||||||
|
|
||||||
|
// process
|
||||||
|
$invoice->setPromo($promo);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processJumpstart(&$total, $invoice)
|
||||||
|
{
|
||||||
|
// add troubleshooting fee
|
||||||
|
$item = new InvoiceItem();
|
||||||
|
$item->setInvoice($invoice)
|
||||||
|
->setTitle('Troubleshooting fee')
|
||||||
|
->setQuantity(1)
|
||||||
|
->setPrice(self::TROUBLESHOOTING_FEE);
|
||||||
|
$invoice->addItem($item);
|
||||||
|
|
||||||
|
$total['sell_price'] = self::TROUBLESHOOTING_FEE;
|
||||||
|
$total['vat_ex_price'] = self::TROUBLESHOOTING_FEE;
|
||||||
|
$total['total_price'] = self::TROUBLESHOOTING_FEE;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processJumpstartWarranty(&$total, $invoice)
|
||||||
|
{
|
||||||
|
$item = new InvoiceItem();
|
||||||
|
$item->setInvoice($invoice)
|
||||||
|
->setTitle('Troubleshooting fee')
|
||||||
|
->setQuantity(1)
|
||||||
|
->setPrice(0.00);
|
||||||
|
$invoice->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processRecharge(&$total, $invoice)
|
||||||
|
{
|
||||||
|
// add recharge fee
|
||||||
|
$item = new InvoiceItem();
|
||||||
|
$item->setInvoice($invoice)
|
||||||
|
->setTitle('Recharge fee')
|
||||||
|
->setQuantity(1)
|
||||||
|
->setPrice(self::RECHARGE_FEE);
|
||||||
|
$invoice->addItem($item);
|
||||||
|
|
||||||
|
$total['sell_price'] = self::RECHARGE_FEE;
|
||||||
|
$total['vat_ex_price'] = self::RECHARGE_FEE;
|
||||||
|
$total['total_price'] = self::RECHARGE_FEE;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processReplacement(&$total, $invoice)
|
||||||
|
{
|
||||||
|
// add recharge fee
|
||||||
|
$item = new InvoiceItem();
|
||||||
|
$item->setInvoice($invoice)
|
||||||
|
->setTitle('Battery replacement')
|
||||||
|
->setQuantity(1)
|
||||||
|
->setPrice(self::BATT_REPLACEMENT_FEE);
|
||||||
|
$invoice->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processWarranty(&$total, InvoiceCriteria $criteria, $invoice)
|
||||||
|
{
|
||||||
|
// error_log('processing warranty');
|
||||||
|
$entries = $criteria->getEntries();
|
||||||
|
foreach ($entries as $entry)
|
||||||
|
{
|
||||||
|
$batt = $entry['battery'];
|
||||||
|
$item = new InvoiceItem();
|
||||||
|
$item->setInvoice($invoice)
|
||||||
|
->setTitle($batt->getModel()->getName() . ' ' . $batt->getSize()->getName() . ' - Service Unit')
|
||||||
|
->setQuantity(1)
|
||||||
|
->setPrice(self::WARRANTY_FEE)
|
||||||
|
->setBattery($batt);
|
||||||
|
$invoice->addItem($item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processOtherServices(&$total, $invoice, $stype)
|
||||||
|
{
|
||||||
|
$item = new InvoiceItem();
|
||||||
|
$item->setInvoice($invoice)
|
||||||
|
->setTitle('Service - ' . CMBServiceType::getName($stype))
|
||||||
|
->setQuantity(1)
|
||||||
|
->setPrice(self::OTHER_SERVICES_FEE);
|
||||||
|
$invoice->addItem($item);
|
||||||
|
|
||||||
|
$total['total_price'] = 200.00;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processOverheat(&$total, $invoice, $cv, $has_coolant)
|
||||||
|
{
|
||||||
|
// free if they have a motolite battery
|
||||||
|
if ($cv->hasMotoliteBattery())
|
||||||
|
$fee = 0;
|
||||||
|
else
|
||||||
|
$fee = self::SERVICE_FEE;
|
||||||
|
|
||||||
|
$item = new InvoiceItem();
|
||||||
|
$item->setInvoice($invoice)
|
||||||
|
->setTitle('Service - Overheat Assistance')
|
||||||
|
->setQuantity(1)
|
||||||
|
->setPrice($fee);
|
||||||
|
$invoice->addItem($item);
|
||||||
|
|
||||||
|
$total_price = $fee;
|
||||||
|
|
||||||
|
if ($has_coolant)
|
||||||
|
{
|
||||||
|
$coolant = new InvoiceItem();
|
||||||
|
$coolant->setInvoice($invoice)
|
||||||
|
->setTitle('4L Coolant')
|
||||||
|
->setQuantity(1)
|
||||||
|
->setPrice(self::COOLANT_FEE);
|
||||||
|
$invoice->addItem($coolant);
|
||||||
|
|
||||||
|
$total_price += self::COOLANT_FEE;
|
||||||
|
//$total_price += 1600;
|
||||||
|
}
|
||||||
|
|
||||||
|
$vat_ex_price = $this->getTaxExclusivePrice($total_price);
|
||||||
|
$vat = $total_price - $vat_ex_price;
|
||||||
|
$total['total_price'] = $total_price;
|
||||||
|
$total['vat_ex_price'] = $vat_ex_price;
|
||||||
|
$total['vat'] = $vat;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processTireRepair(&$total, $invoice, $cv)
|
||||||
|
{
|
||||||
|
// free if they have a motolite battery
|
||||||
|
if ($cv->hasMotoliteBattery())
|
||||||
|
$fee = 0;
|
||||||
|
else
|
||||||
|
$fee = self::SERVICE_FEE;
|
||||||
|
|
||||||
|
$item = new InvoiceItem();
|
||||||
|
$item->setInvoice($invoice)
|
||||||
|
->setTitle('Service - Flat Tire')
|
||||||
|
->setQuantity(1)
|
||||||
|
->setPrice($fee);
|
||||||
|
$invoice->addItem($item);
|
||||||
|
$total_price = $fee;
|
||||||
|
|
||||||
|
$vat_ex_price = $this->getTaxExclusivePrice($total_price);
|
||||||
|
$vat = $total_price - $vat_ex_price;
|
||||||
|
$total['total_price'] = $total_price;
|
||||||
|
$total['vat_ex_price'] = $vat_ex_price;
|
||||||
|
$total['vat'] = $vat;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processRefuel(&$total, $invoice, $cv)
|
||||||
|
{
|
||||||
|
// free if they have a motolite battery
|
||||||
|
if ($cv->hasMotoliteBattery())
|
||||||
|
$fee = 0;
|
||||||
|
else
|
||||||
|
$fee = self::SERVICE_FEE;
|
||||||
|
|
||||||
|
$ftype = $cv->getFuelType();
|
||||||
|
$item = new InvoiceItem();
|
||||||
|
|
||||||
|
// service charge
|
||||||
|
$item->setInvoice($invoice)
|
||||||
|
->setTitle('Service - ' . CMBServiceType::getName(CMBServiceType::EMERGENCY_REFUEL))
|
||||||
|
->setQuantity(1)
|
||||||
|
->setPrice($fee);
|
||||||
|
$invoice->addItem($item);
|
||||||
|
$total_price = $fee;
|
||||||
|
// $total['total_price'] = 200.00;
|
||||||
|
|
||||||
|
$gas_price = self::REFUEL_FEE_GAS;
|
||||||
|
$diesel_price = self::REFUEL_FEE_DIESEL;
|
||||||
|
|
||||||
|
$fuel = new InvoiceItem();
|
||||||
|
error_log('fuel type - ' . $ftype);
|
||||||
|
switch ($ftype)
|
||||||
|
{
|
||||||
|
case FuelType::GAS:
|
||||||
|
$fuel->setInvoice($invoice)
|
||||||
|
->setTitle('4L Fuel - Gas')
|
||||||
|
->setQuantity(1)
|
||||||
|
->setPrice($gas_price);
|
||||||
|
$invoice->addItem($fuel);
|
||||||
|
$total_price += $gas_price;
|
||||||
|
break;
|
||||||
|
case FuelType::DIESEL:
|
||||||
|
$fuel->setInvoice($invoice)
|
||||||
|
->setTitle('4L Fuel - Diesel')
|
||||||
|
->setQuantity(1)
|
||||||
|
->setPrice($diesel_price);
|
||||||
|
$total_price += $diesel_price;
|
||||||
|
$invoice->addItem($fuel);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// NOTE: should never get to this point
|
||||||
|
$fuel->setInvoice($invoice)
|
||||||
|
->setTitle('Fuel - Unknown')
|
||||||
|
->setQuantity(1)
|
||||||
|
->setPrice(0);
|
||||||
|
$total_price += 0.00;
|
||||||
|
$invoice->addItem($fuel);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$vat_ex_price = $this->getTaxExclusivePrice($total_price);
|
||||||
|
$vat = $total_price - $vat_ex_price;
|
||||||
|
$total['total_price'] = $total_price;
|
||||||
|
$total['vat_ex_price'] = $vat_ex_price;
|
||||||
|
$total['vat'] = $vat;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,14 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Service;
|
namespace App\Service\InvoiceGenerator;
|
||||||
|
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
use App\Ramcar\InvoiceCriteria;
|
use App\Ramcar\InvoiceCriteria;
|
||||||
|
use App\Ramcar\InvoiceStatus;
|
||||||
use App\Ramcar\TradeInType;
|
use App\Ramcar\TradeInType;
|
||||||
use App\Ramcar\DiscountApply;
|
use App\Ramcar\DiscountApply;
|
||||||
use App\Ramcar\ServiceType;
|
use App\Ramcar\ServiceType;
|
||||||
|
|
@ -11,32 +17,195 @@ use App\Ramcar\FuelType;
|
||||||
use App\Entity\Invoice;
|
use App\Entity\Invoice;
|
||||||
use App\Entity\InvoiceItem;
|
use App\Entity\InvoiceItem;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
|
use App\Entity\Battery;
|
||||||
|
|
||||||
|
use App\Service\InvoiceGeneratorInterface;
|
||||||
|
|
||||||
use Doctrine\Common\Util\Debug;
|
use Doctrine\Common\Util\Debug;
|
||||||
|
|
||||||
class InvoiceCreator
|
class ResqInvoiceGenerator implements InvoiceGeneratorInterface
|
||||||
{
|
{
|
||||||
const VAT_RATE = 0.12;
|
const TAX_RATE = 0.12;
|
||||||
const SERVICE_FEE = 300;
|
const SERVICE_FEE = 300;
|
||||||
|
const RECHARGE_FEE = 300;
|
||||||
|
const TROUBLESHOOTING_FEE = 150;
|
||||||
|
const BATT_REPLACEMENT_FEE = 0;
|
||||||
|
const WARRANTY_FEE = 0;
|
||||||
|
const OTHER_SERVICES_FEE = 200;
|
||||||
|
const COOLANT_FEE = 1600;
|
||||||
|
const REFUEL_FEE_GAS = 260;
|
||||||
|
const REFUEL_FEE_DIESEL = 220;
|
||||||
|
|
||||||
|
private $security;
|
||||||
|
protected $em;
|
||||||
|
protected $validator;
|
||||||
|
|
||||||
// creates invoice based on the criteria sent
|
// creates invoice based on the criteria sent
|
||||||
public function __construct()
|
public function __construct(Security $security, EntityManagerInterface $em,
|
||||||
|
ValidatorInterface $validator)
|
||||||
{
|
{
|
||||||
|
$this->security = $security;
|
||||||
|
$this->em = $em;
|
||||||
|
$this->validator = $validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getVATAmount($price)
|
public function generateInvoice(InvoiceCriteria $criteria)
|
||||||
{
|
{
|
||||||
$vat_ex_price = $this->getVATExclusivePrice($price);
|
// initialize
|
||||||
|
$invoice = new Invoice();
|
||||||
|
$total = [
|
||||||
|
'sell_price' => 0.0,
|
||||||
|
'vat' => 0.0,
|
||||||
|
'vat_ex_price' => 0.0,
|
||||||
|
'ti_rate' => 0.0,
|
||||||
|
'total_price' => 0.0,
|
||||||
|
'discount' => 0.0,
|
||||||
|
];
|
||||||
|
|
||||||
|
$stype = $criteria->getServiceType();
|
||||||
|
$cv = $criteria->getCustomerVehicle();
|
||||||
|
$has_coolant = $criteria->hasCoolant();
|
||||||
|
// error_log($stype);
|
||||||
|
switch ($stype)
|
||||||
|
{
|
||||||
|
case ServiceType::JUMPSTART_TROUBLESHOOT:
|
||||||
|
$this->processJumpstart($total, $invoice);
|
||||||
|
break;
|
||||||
|
case ServiceType::JUMPSTART_WARRANTY:
|
||||||
|
$this->processJumpstartWarranty($total, $invoice);
|
||||||
|
|
||||||
|
case ServiceType::BATTERY_REPLACEMENT_NEW:
|
||||||
|
$this->processEntries($total, $criteria, $invoice);
|
||||||
|
/*
|
||||||
|
$this->processBatteries($total, $criteria, $invoice);
|
||||||
|
$this->processTradeIns($total, $criteria, $invoice);
|
||||||
|
*/
|
||||||
|
$this->processDiscount($total, $criteria, $invoice);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ServiceType::BATTERY_REPLACEMENT_WARRANTY:
|
||||||
|
$this->processWarranty($total, $criteria, $invoice);
|
||||||
|
break;
|
||||||
|
case ServiceType::POST_RECHARGED:
|
||||||
|
$this->processRecharge($total, $invoice);
|
||||||
|
break;
|
||||||
|
case ServiceType::POST_REPLACEMENT:
|
||||||
|
$this->processReplacement($total, $invoice);
|
||||||
|
break;
|
||||||
|
case ServiceType::TIRE_REPAIR:
|
||||||
|
$this->processTireRepair($total, $invoice, $cv);
|
||||||
|
// $this->processOtherServices($total, $invoice, $stype);
|
||||||
|
break;
|
||||||
|
case ServiceType::OVERHEAT_ASSISTANCE:
|
||||||
|
$this->processOverheat($total, $invoice, $cv, $has_coolant);
|
||||||
|
break;
|
||||||
|
case ServiceType::EMERGENCY_REFUEL:
|
||||||
|
error_log('processing refuel');
|
||||||
|
$ftype = $criteria->getCustomerVehicle()->getFuelType();
|
||||||
|
$this->processRefuel($total, $invoice, $cv);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check if any promo is applied
|
||||||
|
// apply discounts
|
||||||
|
$promos = $criteria->getPromos();
|
||||||
|
|
||||||
|
// get current user
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
if ($user != null)
|
||||||
|
{
|
||||||
|
$invoice->setCreatedBy($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoice->setTotalPrice($total['total_price'])
|
||||||
|
->setVATExclusivePrice($total['vat_ex_price'])
|
||||||
|
->setVAT($total['vat'])
|
||||||
|
->setDiscount($total['discount'])
|
||||||
|
->setTradeIn($total['ti_rate'])
|
||||||
|
->setStatus(InvoiceStatus::DRAFT);
|
||||||
|
|
||||||
|
// dump
|
||||||
|
//Debug::dump($invoice, 1);
|
||||||
|
|
||||||
|
return $invoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate invoice criteria
|
||||||
|
public function generateInvoiceCriteria($jo, $promo_id, $invoice_items, &$error_array)
|
||||||
|
{
|
||||||
|
$em = $this->em;
|
||||||
|
|
||||||
|
// instantiate the invoice criteria
|
||||||
|
$criteria = new InvoiceCriteria();
|
||||||
|
$criteria->setServiceType($jo->getServiceType())
|
||||||
|
->setCustomerVehicle($jo->getCustomerVehicle());
|
||||||
|
|
||||||
|
$ierror = $this->invoicePromo($criteria, $promo_id);
|
||||||
|
|
||||||
|
if (!$ierror && !empty($invoice_items))
|
||||||
|
{
|
||||||
|
// check for trade-in so we can mark it for mobile app
|
||||||
|
foreach ($invoice_items as $item)
|
||||||
|
{
|
||||||
|
// get first trade-in
|
||||||
|
if (!empty($item['trade_in']))
|
||||||
|
{
|
||||||
|
$jo->getTradeInType($item['trade_in']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ierror = $this->invoiceBatteries($criteria, $invoice_items);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ierror)
|
||||||
|
{
|
||||||
|
$error_array['invoice'] = $ierror;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// generate the invoice
|
||||||
|
$iobj = $this->generateInvoice($criteria);
|
||||||
|
|
||||||
|
// validate
|
||||||
|
$ierrors = $this->validator->validate($iobj);
|
||||||
|
|
||||||
|
// add errors to list
|
||||||
|
foreach ($ierrors as $error) {
|
||||||
|
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if invoice already exists for JO
|
||||||
|
$old_invoice = $jo->getInvoice();
|
||||||
|
if ($old_invoice != null)
|
||||||
|
{
|
||||||
|
// remove old invoice
|
||||||
|
$em->remove($old_invoice);
|
||||||
|
$em->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add invoice to JO
|
||||||
|
$jo->setInvoice($iobj);
|
||||||
|
|
||||||
|
$em->persist($iobj);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getTaxAmount($price)
|
||||||
|
{
|
||||||
|
$vat_ex_price = $this->getTaxExclusivePrice($price);
|
||||||
return $price - $vat_ex_price;
|
return $price - $vat_ex_price;
|
||||||
// return round($vat_ex_price * self::VAT_RATE, 2);
|
// return round($vat_ex_price * self::TAX_RATE, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getVATExclusivePrice($price)
|
protected function getTaxExclusivePrice($price)
|
||||||
{
|
{
|
||||||
return round($price / (1 + self::VAT_RATE), 2);
|
return round($price / (1 + self::TAX_RATE), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTradeInRate($ti)
|
protected function getTradeInRate($ti)
|
||||||
{
|
{
|
||||||
$size = $ti['size'];
|
$size = $ti['size'];
|
||||||
$trade_in = $ti['trade_in'];
|
$trade_in = $ti['trade_in'];
|
||||||
|
|
@ -57,6 +226,75 @@ class InvoiceCreator
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function invoicePromo(InvoiceCriteria $criteria, $promo_id)
|
||||||
|
{
|
||||||
|
// return error if there's a problem, false otherwise
|
||||||
|
// check service type
|
||||||
|
$stype = $criteria->getServiceType();
|
||||||
|
if ($stype != ServiceType::BATTERY_REPLACEMENT_NEW)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
|
||||||
|
if (empty($promo_id))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if this is a valid promo
|
||||||
|
$promo = $this->em->getRepository(Promo::class)->find($promo_id);
|
||||||
|
|
||||||
|
if (empty($promo))
|
||||||
|
return 'Invalid promo specified.';
|
||||||
|
|
||||||
|
$criteria->addPromo($promo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function invoiceBatteries(InvoiceCriteria $criteria, $items)
|
||||||
|
{
|
||||||
|
// check service type
|
||||||
|
$stype = $criteria->getServiceType();
|
||||||
|
if ($stype != ServiceType::BATTERY_REPLACEMENT_NEW && $stype != ServiceType::BATTERY_REPLACEMENT_WARRANTY)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// return error if there's a problem, false otherwise
|
||||||
|
if (!empty($items))
|
||||||
|
{
|
||||||
|
foreach ($items as $item)
|
||||||
|
{
|
||||||
|
// check if this is a valid battery
|
||||||
|
$battery = $this->em->getRepository(Battery::class)->find($item['battery']);
|
||||||
|
|
||||||
|
if (empty($battery))
|
||||||
|
{
|
||||||
|
$error = 'Invalid battery specified.';
|
||||||
|
return $error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// quantity
|
||||||
|
$qty = $item['quantity'];
|
||||||
|
if ($qty < 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
// add to criteria
|
||||||
|
$criteria->addBattery($battery, $qty);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// if this is a trade in, add trade in
|
||||||
|
if (!empty($item['trade_in']) && TradeInType::validate($item['trade_in']))
|
||||||
|
$trade_in = $item['trade_in'];
|
||||||
|
else
|
||||||
|
$trade_in = null;
|
||||||
|
|
||||||
|
$criteria->addEntry($battery, $trade_in, $qty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function processEntries(&$total, InvoiceCriteria $criteria, Invoice $invoice)
|
protected function processEntries(&$total, InvoiceCriteria $criteria, Invoice $invoice)
|
||||||
{
|
{
|
||||||
// error_log('processing entries...');
|
// error_log('processing entries...');
|
||||||
|
|
@ -109,8 +347,8 @@ class InvoiceCreator
|
||||||
$qty = $con_data['qty'];
|
$qty = $con_data['qty'];
|
||||||
|
|
||||||
$sell_price = $batt->getSellingPrice();
|
$sell_price = $batt->getSellingPrice();
|
||||||
$vat = $this->getVATAmount($sell_price);
|
$vat = $this->getTaxAmount($sell_price);
|
||||||
// $vat_ex_price = $this->getVATExclusivePrice($sell_price);
|
// $vat_ex_price = $this->getTaxExclusivePrice($sell_price);
|
||||||
|
|
||||||
$total['sell_price'] += $sell_price * $qty;
|
$total['sell_price'] += $sell_price * $qty;
|
||||||
$total['vat'] += $vat * $qty;
|
$total['vat'] += $vat * $qty;
|
||||||
|
|
@ -192,22 +430,22 @@ class InvoiceCreator
|
||||||
$invoice->setPromo($promo);
|
$invoice->setPromo($promo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processJumpstart(&$total, $invoice)
|
protected function processJumpstart(&$total, $invoice)
|
||||||
{
|
{
|
||||||
// add troubleshooting fee
|
// add troubleshooting fee
|
||||||
$item = new InvoiceItem();
|
$item = new InvoiceItem();
|
||||||
$item->setInvoice($invoice)
|
$item->setInvoice($invoice)
|
||||||
->setTitle('Troubleshooting fee')
|
->setTitle('Troubleshooting fee')
|
||||||
->setQuantity(1)
|
->setQuantity(1)
|
||||||
->setPrice(150.00);
|
->setPrice(self::TROUBLESHOOTING_FEE);
|
||||||
$invoice->addItem($item);
|
$invoice->addItem($item);
|
||||||
|
|
||||||
$total['sell_price'] = 150.00;
|
$total['sell_price'] = self::TROUBLESHOOTING_FEE;
|
||||||
$total['vat_ex_price'] = 150.00;
|
$total['vat_ex_price'] = self::TROUBLESHOOTING_FEE;
|
||||||
$total['total_price'] = 150.00;
|
$total['total_price'] = self::TROUBLESHOOTING_FEE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processJumpstartWarranty(&$total, $invoice)
|
protected function processJumpstartWarranty(&$total, $invoice)
|
||||||
{
|
{
|
||||||
$item = new InvoiceItem();
|
$item = new InvoiceItem();
|
||||||
$item->setInvoice($invoice)
|
$item->setInvoice($invoice)
|
||||||
|
|
@ -217,33 +455,33 @@ class InvoiceCreator
|
||||||
$invoice->addItem($item);
|
$invoice->addItem($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processRecharge(&$total, $invoice)
|
protected function processRecharge(&$total, $invoice)
|
||||||
{
|
{
|
||||||
// add recharge fee
|
// add recharge fee
|
||||||
$item = new InvoiceItem();
|
$item = new InvoiceItem();
|
||||||
$item->setInvoice($invoice)
|
$item->setInvoice($invoice)
|
||||||
->setTitle('Recharge fee')
|
->setTitle('Recharge fee')
|
||||||
->setQuantity(1)
|
->setQuantity(1)
|
||||||
->setPrice(300.00);
|
->setPrice(self::RECHARGE_FEE);
|
||||||
$invoice->addItem($item);
|
$invoice->addItem($item);
|
||||||
|
|
||||||
$total['sell_price'] = 300.00;
|
$total['sell_price'] = self::RECHARGE_FEE;
|
||||||
$total['vat_ex_price'] = 300.00;
|
$total['vat_ex_price'] = self::RECHARGE_FEE;
|
||||||
$total['total_price'] = 300.00;
|
$total['total_price'] = self::RECHARGE_FEE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processReplacement(&$total, $invoice)
|
protected function processReplacement(&$total, $invoice)
|
||||||
{
|
{
|
||||||
// add recharge fee
|
// add recharge fee
|
||||||
$item = new InvoiceItem();
|
$item = new InvoiceItem();
|
||||||
$item->setInvoice($invoice)
|
$item->setInvoice($invoice)
|
||||||
->setTitle('Battery replacement')
|
->setTitle('Battery replacement')
|
||||||
->setQuantity(1)
|
->setQuantity(1)
|
||||||
->setPrice(0.00);
|
->setPrice(self::BATT_REPLACEMENT_FEE);
|
||||||
$invoice->addItem($item);
|
$invoice->addItem($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processWarranty(&$total, InvoiceCriteria $criteria, $invoice)
|
protected function processWarranty(&$total, InvoiceCriteria $criteria, $invoice)
|
||||||
{
|
{
|
||||||
// error_log('processing warranty');
|
// error_log('processing warranty');
|
||||||
$entries = $criteria->getEntries();
|
$entries = $criteria->getEntries();
|
||||||
|
|
@ -254,25 +492,25 @@ class InvoiceCreator
|
||||||
$item->setInvoice($invoice)
|
$item->setInvoice($invoice)
|
||||||
->setTitle($batt->getModel()->getName() . ' ' . $batt->getSize()->getName() . ' - Service Unit')
|
->setTitle($batt->getModel()->getName() . ' ' . $batt->getSize()->getName() . ' - Service Unit')
|
||||||
->setQuantity(1)
|
->setQuantity(1)
|
||||||
->setPrice(0.00)
|
->setPrice(self::WARRANTY_FEE)
|
||||||
->setBattery($batt);
|
->setBattery($batt);
|
||||||
$invoice->addItem($item);
|
$invoice->addItem($item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processOtherServices(&$total, $invoice, $stype)
|
protected function processOtherServices(&$total, $invoice, $stype)
|
||||||
{
|
{
|
||||||
$item = new InvoiceItem();
|
$item = new InvoiceItem();
|
||||||
$item->setInvoice($invoice)
|
$item->setInvoice($invoice)
|
||||||
->setTitle('Service - ' . ServiceType::getName($stype))
|
->setTitle('Service - ' . ServiceType::getName($stype))
|
||||||
->setQuantity(1)
|
->setQuantity(1)
|
||||||
->setPrice(200.00);
|
->setPrice(self::OTHER_SERVICES_FEE);
|
||||||
$invoice->addItem($item);
|
$invoice->addItem($item);
|
||||||
|
|
||||||
$total['total_price'] = 200.00;
|
$total['total_price'] = 200.00;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processOverheat(&$total, $invoice, $cv, $has_coolant)
|
protected function processOverheat(&$total, $invoice, $cv, $has_coolant)
|
||||||
{
|
{
|
||||||
// free if they have a motolite battery
|
// free if they have a motolite battery
|
||||||
if ($cv->hasMotoliteBattery())
|
if ($cv->hasMotoliteBattery())
|
||||||
|
|
@ -295,20 +533,21 @@ class InvoiceCreator
|
||||||
$coolant->setInvoice($invoice)
|
$coolant->setInvoice($invoice)
|
||||||
->setTitle('4L Coolant')
|
->setTitle('4L Coolant')
|
||||||
->setQuantity(1)
|
->setQuantity(1)
|
||||||
->setPrice(1600);
|
->setPrice(self::COOLANT_FEE);
|
||||||
$invoice->addItem($coolant);
|
$invoice->addItem($coolant);
|
||||||
|
|
||||||
$total_price += 1600;
|
$total_price += self::COOLANT_FEE;
|
||||||
|
//$total_price += 1600;
|
||||||
}
|
}
|
||||||
|
|
||||||
$vat_ex_price = $this->getVATExclusivePrice($total_price);
|
$vat_ex_price = $this->getTaxExclusivePrice($total_price);
|
||||||
$vat = $total_price - $vat_ex_price;
|
$vat = $total_price - $vat_ex_price;
|
||||||
$total['total_price'] = $total_price;
|
$total['total_price'] = $total_price;
|
||||||
$total['vat_ex_price'] = $vat_ex_price;
|
$total['vat_ex_price'] = $vat_ex_price;
|
||||||
$total['vat'] = $vat;
|
$total['vat'] = $vat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processTireRepair(&$total, $invoice, $cv)
|
protected function processTireRepair(&$total, $invoice, $cv)
|
||||||
{
|
{
|
||||||
// free if they have a motolite battery
|
// free if they have a motolite battery
|
||||||
if ($cv->hasMotoliteBattery())
|
if ($cv->hasMotoliteBattery())
|
||||||
|
|
@ -324,14 +563,14 @@ class InvoiceCreator
|
||||||
$invoice->addItem($item);
|
$invoice->addItem($item);
|
||||||
$total_price = $fee;
|
$total_price = $fee;
|
||||||
|
|
||||||
$vat_ex_price = $this->getVATExclusivePrice($total_price);
|
$vat_ex_price = $this->getTaxExclusivePrice($total_price);
|
||||||
$vat = $total_price - $vat_ex_price;
|
$vat = $total_price - $vat_ex_price;
|
||||||
$total['total_price'] = $total_price;
|
$total['total_price'] = $total_price;
|
||||||
$total['vat_ex_price'] = $vat_ex_price;
|
$total['vat_ex_price'] = $vat_ex_price;
|
||||||
$total['vat'] = $vat;
|
$total['vat'] = $vat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processRefuel(&$total, $invoice, $cv)
|
protected function processRefuel(&$total, $invoice, $cv)
|
||||||
{
|
{
|
||||||
// free if they have a motolite battery
|
// free if they have a motolite battery
|
||||||
if ($cv->hasMotoliteBattery())
|
if ($cv->hasMotoliteBattery())
|
||||||
|
|
@ -351,8 +590,8 @@ class InvoiceCreator
|
||||||
$total_price = $fee;
|
$total_price = $fee;
|
||||||
// $total['total_price'] = 200.00;
|
// $total['total_price'] = 200.00;
|
||||||
|
|
||||||
$gas_price = 260;
|
$gas_price = self::REFUEL_FEE_GAS;
|
||||||
$diesel_price = 220;
|
$diesel_price = self::REFUEL_FEE_DIESEL;
|
||||||
|
|
||||||
$fuel = new InvoiceItem();
|
$fuel = new InvoiceItem();
|
||||||
error_log('fuel type - ' . $ftype);
|
error_log('fuel type - ' . $ftype);
|
||||||
|
|
@ -385,84 +624,11 @@ class InvoiceCreator
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$vat_ex_price = $this->getVATExclusivePrice($total_price);
|
$vat_ex_price = $this->getTaxExclusivePrice($total_price);
|
||||||
$vat = $total_price - $vat_ex_price;
|
$vat = $total_price - $vat_ex_price;
|
||||||
$total['total_price'] = $total_price;
|
$total['total_price'] = $total_price;
|
||||||
$total['vat_ex_price'] = $vat_ex_price;
|
$total['vat_ex_price'] = $vat_ex_price;
|
||||||
$total['vat'] = $vat;
|
$total['vat'] = $vat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processCriteria(InvoiceCriteria $criteria)
|
|
||||||
{
|
|
||||||
// initialize
|
|
||||||
$invoice = new Invoice();
|
|
||||||
$total = [
|
|
||||||
'sell_price' => 0.0,
|
|
||||||
'vat' => 0.0,
|
|
||||||
'vat_ex_price' => 0.0,
|
|
||||||
'ti_rate' => 0.0,
|
|
||||||
'total_price' => 0.0,
|
|
||||||
'discount' => 0.0,
|
|
||||||
];
|
|
||||||
|
|
||||||
$stype = $criteria->getServiceType();
|
|
||||||
$cv = $criteria->getCustomerVehicle();
|
|
||||||
$has_coolant = $criteria->hasCoolant();
|
|
||||||
// error_log($stype);
|
|
||||||
switch ($stype)
|
|
||||||
{
|
|
||||||
case ServiceType::JUMPSTART_TROUBLESHOOT:
|
|
||||||
$this->processJumpstart($total, $invoice);
|
|
||||||
break;
|
|
||||||
case ServiceType::JUMPSTART_WARRANTY:
|
|
||||||
$this->processJumpstartWarranty($total, $invoice);
|
|
||||||
|
|
||||||
case ServiceType::BATTERY_REPLACEMENT_NEW:
|
|
||||||
$this->processEntries($total, $criteria, $invoice);
|
|
||||||
/*
|
|
||||||
$this->processBatteries($total, $criteria, $invoice);
|
|
||||||
$this->processTradeIns($total, $criteria, $invoice);
|
|
||||||
*/
|
|
||||||
$this->processDiscount($total, $criteria, $invoice);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ServiceType::BATTERY_REPLACEMENT_WARRANTY:
|
|
||||||
$this->processWarranty($total, $criteria, $invoice);
|
|
||||||
break;
|
|
||||||
case ServiceType::POST_RECHARGED:
|
|
||||||
$this->processRecharge($total, $invoice);
|
|
||||||
break;
|
|
||||||
case ServiceType::POST_REPLACEMENT:
|
|
||||||
$this->processReplacement($total, $invoice);
|
|
||||||
break;
|
|
||||||
case ServiceType::TIRE_REPAIR:
|
|
||||||
$this->processTireRepair($total, $invoice, $cv);
|
|
||||||
// $this->processOtherServices($total, $invoice, $stype);
|
|
||||||
break;
|
|
||||||
case ServiceType::OVERHEAT_ASSISTANCE:
|
|
||||||
$this->processOverheat($total, $invoice, $cv, $has_coolant);
|
|
||||||
break;
|
|
||||||
case ServiceType::EMERGENCY_REFUEL:
|
|
||||||
error_log('processing refuel');
|
|
||||||
$ftype = $criteria->getCustomerVehicle()->getFuelType();
|
|
||||||
$this->processRefuel($total, $invoice, $cv);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: check if any promo is applied
|
|
||||||
// apply discounts
|
|
||||||
$promos = $criteria->getPromos();
|
|
||||||
|
|
||||||
$invoice->setTotalPrice($total['total_price'])
|
|
||||||
->setVATExclusivePrice($total['vat_ex_price'])
|
|
||||||
->setVAT($total['vat'])
|
|
||||||
->setDiscount($total['discount'])
|
|
||||||
->setTradeIn($total['ti_rate']);
|
|
||||||
|
|
||||||
|
|
||||||
// dump
|
|
||||||
//Debug::dump($invoice, 1);
|
|
||||||
|
|
||||||
return $invoice;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
18
src/Service/InvoiceGeneratorInterface.php
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\Entity\Invoice;
|
||||||
|
use App\Entity\JobOrder;
|
||||||
|
|
||||||
|
use App\Ramcar\InvoiceCriteria;
|
||||||
|
|
||||||
|
interface InvoiceGeneratorInterface
|
||||||
|
{
|
||||||
|
// generate invoice using a criteria
|
||||||
|
public function generateInvoice(InvoiceCriteria $criteria);
|
||||||
|
|
||||||
|
// generate invoice criteria
|
||||||
|
public function generateInvoiceCriteria(JobOrder $jo, int $promo_id, array $invoice_items, array &$error_array);
|
||||||
|
|
||||||
|
}
|
||||||
2520
src/Service/JobOrderHandler/CMBJobOrderHandler.php
Normal file
2456
src/Service/JobOrderHandler/ResqJobOrderHandler.php
Normal file
93
src/Service/JobOrderHandlerInterface.php
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
use App\Service\MQTTClient;
|
||||||
|
use App\Service\APNSClient;
|
||||||
|
use App\Service\MapTools;
|
||||||
|
|
||||||
|
interface JobOrderHandlerInterface
|
||||||
|
{
|
||||||
|
// TODO: event sending has been moved to rider assignment handler for cmb. Might need
|
||||||
|
// to consider resq implementation for event sending for the other methods.
|
||||||
|
|
||||||
|
// get job order rows
|
||||||
|
public function getRows(Request $req, string $tier);
|
||||||
|
|
||||||
|
// get job orders
|
||||||
|
public function getJobOrders(Request $req);
|
||||||
|
|
||||||
|
// generate job order
|
||||||
|
public function generateJobOrder(Request $req, int $id);
|
||||||
|
|
||||||
|
// generate one step job order
|
||||||
|
public function generateOneStepJobOrder(Request $req, int $id);
|
||||||
|
|
||||||
|
// dispatch job order
|
||||||
|
public function dispatchJobOrder(Request $req, int $id, MQTTClient $mclient);
|
||||||
|
|
||||||
|
// assign job order
|
||||||
|
public function assignJobOrder(Request $req, int $id, MQTTCLient $mclient, APNSClient $aclient);
|
||||||
|
|
||||||
|
// fulfill job order
|
||||||
|
public function fulfillJobOrder(Request $req, int $id, MQTTClient $mclient);
|
||||||
|
|
||||||
|
// cancel job order
|
||||||
|
public function cancelJobOrder(Request $req, int $id, MQTTClient $mclient);
|
||||||
|
|
||||||
|
// set hub for job order
|
||||||
|
public function setHub(Request $req, int $id, MQTTClient $mclient);
|
||||||
|
|
||||||
|
// reject hub for job order
|
||||||
|
public function rejectHub(Request $req, int $id);
|
||||||
|
|
||||||
|
// set rider for job order
|
||||||
|
public function setRider(Request $req, int $id, MQTTClient $mclient);
|
||||||
|
|
||||||
|
// unlock processor
|
||||||
|
public function unlockProcessor(int $id);
|
||||||
|
|
||||||
|
// unlock assignor
|
||||||
|
public function unlockAssignor(int $id);
|
||||||
|
|
||||||
|
// initialize incoming job order form
|
||||||
|
public function initializeIncomingForm();
|
||||||
|
|
||||||
|
// initialize open edit job order form
|
||||||
|
public function initializeOpenEditForm(int $id);
|
||||||
|
|
||||||
|
// initialize incoming vehicle form
|
||||||
|
public function initializeIncomingVehicleForm(int $cvid);
|
||||||
|
|
||||||
|
// initialize all job orders form for a specific job order id
|
||||||
|
public function initializeAllForm(int $id);
|
||||||
|
|
||||||
|
// initialize dispatch/processing job order form
|
||||||
|
public function initializeProcessingForm(int $id, MapTools $map_tools);
|
||||||
|
|
||||||
|
// initialize assign job order form
|
||||||
|
public function initializeAssignForm(int $id);
|
||||||
|
|
||||||
|
// initialize fulflll job order form
|
||||||
|
public function initializeFulfillmentForm(int $id);
|
||||||
|
|
||||||
|
// initialize hub form
|
||||||
|
public function initializeHubForm(int $id, MapTools $map_tools);
|
||||||
|
|
||||||
|
// initialize rider form
|
||||||
|
public function initializeRiderForm(int $id);
|
||||||
|
|
||||||
|
// initialize one step form
|
||||||
|
public function initializeOneStepForm();
|
||||||
|
|
||||||
|
// initialize one step edit form
|
||||||
|
public function initializeOneStepEditForm(int $id, MapTools $map_tools);
|
||||||
|
|
||||||
|
// generate pdf form for job order
|
||||||
|
public function generatePDFForm(Request $req, int $id, string $proj_path);
|
||||||
|
|
||||||
|
// get template to display
|
||||||
|
public function getTwigTemplate(string $id);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service\RiderAssignmentHandler;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
use App\Service\RiderAssignmentHandlerInterface;
|
||||||
|
use App\Service\MQTTClient;
|
||||||
|
use App\Service\APNSClient;
|
||||||
|
|
||||||
|
use App\Entity\JobOrder;
|
||||||
|
use App\Entity\Rider;
|
||||||
|
|
||||||
|
use App\Ramcar\JOStatus;
|
||||||
|
|
||||||
|
class CMBRiderAssignmentHandler implements RiderAssignmentHandlerInterface
|
||||||
|
{
|
||||||
|
protected $em;
|
||||||
|
protected $aclient;
|
||||||
|
protected $mclient;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $em, MQTTClient $mclient,
|
||||||
|
APNSClient $aclient)
|
||||||
|
{
|
||||||
|
$this->em = $em;
|
||||||
|
$this->mclient = $mclient;
|
||||||
|
$this->aclient = $aclient;
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign job order to rider
|
||||||
|
public function assignJobOrder(JobOrder $obj, Rider $rider)
|
||||||
|
{
|
||||||
|
// create the payload
|
||||||
|
$payload = [
|
||||||
|
'event' => 'driver_assigned'
|
||||||
|
];
|
||||||
|
|
||||||
|
// send event
|
||||||
|
$this->mclient->sendEvent($obj, $payload);
|
||||||
|
|
||||||
|
// check if rider is available
|
||||||
|
if ($rider->isAvailable())
|
||||||
|
{
|
||||||
|
error_log('set rider availability to false');
|
||||||
|
// set rider to unavailable
|
||||||
|
$rider->setAvailable(false);
|
||||||
|
|
||||||
|
// send event to rider
|
||||||
|
$this->mclient->sendRiderEvent($obj, $payload);
|
||||||
|
|
||||||
|
// send push notification
|
||||||
|
$this->aclient->sendPush($obj, "A RESQ rider is on his way to you.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// complete job order
|
||||||
|
public function fulfillJobOrder(JobOrder $obj, string $image_url, Rider $rider)
|
||||||
|
{
|
||||||
|
// send to mqtt
|
||||||
|
$payload = [
|
||||||
|
'event' => 'fulfilled',
|
||||||
|
'jo_id' => $obj->getID(),
|
||||||
|
'driver_image' => $image_url,
|
||||||
|
'driver_name' => $rider->getFullName(),
|
||||||
|
'driver_id' => $rider->getID(),
|
||||||
|
];
|
||||||
|
$this->mclient->sendEvent($obj, $payload);
|
||||||
|
|
||||||
|
// send fulfill/complete event to rider
|
||||||
|
$this->mclient->sendRiderEvent($obj, $payload);
|
||||||
|
|
||||||
|
// search for the JO assigned to rider with JOStatus::ASSIGNED and sort by assign date
|
||||||
|
$jo_results = $this->em->getRepository(JobOrder::class)->findBy(['status' => JOStatus::ASSIGNED, 'rider' => $rider->getID()],
|
||||||
|
['date_assign' => 'ASC']);
|
||||||
|
|
||||||
|
// check if jo_results is empty
|
||||||
|
if (!empty($jo_results))
|
||||||
|
{
|
||||||
|
error_log('rider has another JO in queue');
|
||||||
|
// get first entry
|
||||||
|
$jo = current($jo_results);
|
||||||
|
|
||||||
|
// form the payload for the next job order
|
||||||
|
$jo_payload = [
|
||||||
|
'event' => 'driver_assigned'
|
||||||
|
];
|
||||||
|
|
||||||
|
// set rider to unavailable
|
||||||
|
$rider->setAvailable(false);
|
||||||
|
|
||||||
|
// send event to rider
|
||||||
|
$this->mclient->sendRiderEvent($jo, $jo_payload);
|
||||||
|
|
||||||
|
// send push notification
|
||||||
|
$this->aclient->sendPush($obj, "A RESQ rider is on his way to you.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/Service/RiderAssignmentHandlerInterface.php
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\Entity\JobOrder;
|
||||||
|
use App\Entity\Rider;
|
||||||
|
|
||||||
|
interface RiderAssignmentHandlerInterface
|
||||||
|
{
|
||||||
|
// assign job order to rider
|
||||||
|
public function assignJobOrder(JobOrder $obj, Rider $rider);
|
||||||
|
|
||||||
|
// complete job order
|
||||||
|
public function fulfillJobOrder(JobOrder $obj, string $image_url, Rider $rider);
|
||||||
|
}
|
||||||
|
|
@ -38,15 +38,18 @@ class RiderTracker
|
||||||
$long = $this->redis->hget($key, 'longitude');
|
$long = $this->redis->hget($key, 'longitude');
|
||||||
$lat = $this->redis->hget($key, 'latitude');
|
$lat = $this->redis->hget($key, 'latitude');
|
||||||
|
|
||||||
$coordinates = new Point($long, $lat);
|
return new Point($long, $lat);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$rider = $this->em->getRepository(Rider::class)->find($rider_id);
|
|
||||||
$coordinates = $rider->getHub()->getCoordinates();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $coordinates;
|
// not in cache, get hub
|
||||||
|
$rider = $this->em->getRepository(Rider::class)->find($rider_id);
|
||||||
|
$hub = $rider->getHub();
|
||||||
|
|
||||||
|
// no hub
|
||||||
|
// TODO: return valid coordinate
|
||||||
|
if ($hub == null)
|
||||||
|
return new Point(0, 0);
|
||||||
|
|
||||||
|
return $hub->getCoordinates();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,12 +35,16 @@
|
||||||
<meta name="theme-color" content="#ffffff">
|
<meta name="theme-color" content="#ffffff">
|
||||||
|
|
||||||
<!--begin::Extra Styles -->
|
<!--begin::Extra Styles -->
|
||||||
{% block stylesheets %}{% endblock %}
|
{% block stylesheets %}
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
|
||||||
|
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
|
||||||
|
crossorigin=""/>
|
||||||
|
{% endblock %}
|
||||||
<!--end::Extra Styles -->
|
<!--end::Extra Styles -->
|
||||||
</head>
|
</head>
|
||||||
<!-- end::Head -->
|
<!-- end::Head -->
|
||||||
<!-- end::Body -->
|
<!-- end::Body -->
|
||||||
<body class="m-page--fluid m--skin- m-content--skin-light2 m-header--fixed m-header--fixed-mobile m-aside-left--enabled m-aside-left--skin-dark m-aside-left--offcanvas m-footer--push m-aside--offcanvas-default">
|
<body class="m-page--fluid m--skin- m-content--skin-light2 m-header--fixed m-header--fixed-mobile m-aside-left--enabled m-aside-left--skin-dark m-aside-left--offcanvas m-aside--offcanvas-default">
|
||||||
<!-- begin:: Page -->
|
<!-- begin:: Page -->
|
||||||
<div class="m-grid m-grid--hor m-grid--root m-page">
|
<div class="m-grid m-grid--hor m-grid--root m-page">
|
||||||
<!-- BEGIN: Header -->
|
<!-- BEGIN: Header -->
|
||||||
|
|
@ -695,30 +699,6 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- end:: Body -->
|
<!-- end:: Body -->
|
||||||
<!-- begin::Footer -->
|
<!-- begin::Footer -->
|
||||||
<footer class="m-grid__item m-footer">
|
|
||||||
<div class="m-container m-container--fluid m-container--full-height m-page__container">
|
|
||||||
<div class="m-stack m-stack--flex-tablet-and-mobile m-stack--ver m-stack--desktop">
|
|
||||||
<div class="m-stack__item m-stack__item--left m-stack__item--middle m-stack__item--last">
|
|
||||||
<span class="m-footer__copyright">
|
|
||||||
{{ "now"|date("Y") }} © {% trans %}copyright{% endtrans %}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="m-stack__item m-stack__item--right m-stack__item--middle m-stack__item--first">
|
|
||||||
<ul class="m-footer__nav m-nav m-nav--inline m--pull-right">
|
|
||||||
<!--
|
|
||||||
<li class="m-nav__item">
|
|
||||||
<a href="#" class="m-nav__link">
|
|
||||||
<span class="m-nav__link-text">
|
|
||||||
About
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
-->
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
<!-- end::Footer -->
|
<!-- end::Footer -->
|
||||||
</div>
|
</div>
|
||||||
<!-- end:: Page -->
|
<!-- end:: Page -->
|
||||||
|
|
|
||||||
1127
templates/customer/cmb.form.html.twig
Normal file
|
|
@ -96,7 +96,10 @@ initMap();
|
||||||
function initMap() {
|
function initMap() {
|
||||||
var map = new google.maps.Map(document.getElementById('m_gmap'),
|
var map = new google.maps.Map(document.getElementById('m_gmap'),
|
||||||
{
|
{
|
||||||
center: {lat: 14.6091, lng: 121.0223},
|
center: {
|
||||||
|
lat: {% trans %}default_lat{% endtrans %},
|
||||||
|
lng: {% trans %}default_long{% endtrans %},
|
||||||
|
},
|
||||||
mapTypeId: 'roadmap',
|
mapTypeId: 'roadmap',
|
||||||
zoom: 13
|
zoom: 13
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,30 @@
|
||||||
{% extends 'base.html.twig' %}
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
{% block body %}
|
{% block stylesheets %}
|
||||||
<!-- BEGIN: Subheader -->
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/>
|
||||||
<div class="m-subheader">
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<div class="mr-auto">
|
|
||||||
<h3 class="m-subheader__title">
|
|
||||||
Dashboard
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="m-subheader__daterange" id="m_dashboard_daterangepicker">
|
|
||||||
<span class="m-subheader__daterange-label">
|
|
||||||
<span class="m-subheader__daterange-title"></span>
|
|
||||||
<span class="m-subheader__daterange-date m--font-brand"></span>
|
|
||||||
</span>
|
|
||||||
<a href="#" class="btn btn-sm btn-brand m-btn m-btn--icon m-btn--icon-only m-btn--custom m-btn--pill">
|
|
||||||
<i class="la la-angle-down"></i>
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- END: Subheader -->
|
|
||||||
<div class="m-content">
|
|
||||||
<!--Begin::Section-->
|
|
||||||
<!--End::Section-->
|
|
||||||
<!--Begin::Section-->
|
|
||||||
<!--End::Section-->
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div id="dashboard_map" style="height:100%;"></div>
|
||||||
|
<!-- BEGIN: Subheader -->
|
||||||
|
<!-- END: Subheader -->
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
{{ include('map/' ~ map_js_file) }}
|
||||||
|
<script>
|
||||||
|
|
||||||
|
{% if 'OpenStreet' in map_js_file %}
|
||||||
|
initMap();
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
function initMap() {
|
||||||
|
var default_lat = {% trans %}default_lat{% endtrans %};
|
||||||
|
var default_lng = {% trans %}default_long{% endtrans %};
|
||||||
|
|
||||||
|
var map = mapCreate('dashboard_map', default_lat, default_lng, 'road', 13);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -164,12 +164,34 @@
|
||||||
|
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src="//maps.google.com/maps/api/js?key={{ gmaps_api_key }}" type="text/javascript"></script>
|
<script src="//maps.google.com/maps/api/js?key={{ gmaps_api_key }}&libraries=places" type="text/javascript"></script>
|
||||||
<script src="/assets/vendors/custom/gmaps/gmaps.js" type="text/javascript"></script>
|
<script src="/assets/vendors/custom/gmaps/gmaps.js" type="text/javascript"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
// BEGIN google maps stuff
|
// BEGIN google maps stuff
|
||||||
|
// location search autocomplete
|
||||||
|
var input = document.getElementById('m_gmap_address');
|
||||||
|
|
||||||
|
var autocomplete = new google.maps.places.Autocomplete(input);
|
||||||
|
autocomplete.setComponentRestrictions({'country': ['{% trans %}default_region{% endtrans %}']});
|
||||||
|
autocomplete.addListener('place_changed', function() {
|
||||||
|
var place = autocomplete.getPlace();
|
||||||
|
|
||||||
|
if (!place.geometry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = {
|
||||||
|
'action': 'map.search',
|
||||||
|
'params': {
|
||||||
|
'lat': place.geometry.location.lat(),
|
||||||
|
'lng': place.geometry.location.lng()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(message);
|
||||||
|
});
|
||||||
|
|
||||||
function selectPoint(map, latlng) {
|
function selectPoint(map, latlng) {
|
||||||
var lat = latlng.lat();
|
var lat = latlng.lat();
|
||||||
var lng = latlng.lng();
|
var lng = latlng.lng();
|
||||||
|
|
@ -189,8 +211,8 @@ function selectPoint(map, latlng) {
|
||||||
|
|
||||||
var map = new GMaps({
|
var map = new GMaps({
|
||||||
div: '#m_gmap',
|
div: '#m_gmap',
|
||||||
lat: 14.6091,
|
lat: {% trans %}default_lat{% endtrans %},
|
||||||
lng: 121.0223,
|
lng: {% trans %}default_long{% endtrans %},
|
||||||
click: function(e) {
|
click: function(e) {
|
||||||
// handle click in map
|
// handle click in map
|
||||||
selectPoint(map, e.latLng);
|
selectPoint(map, e.latLng);
|
||||||
|
|
|
||||||
1717
templates/job-order/cmb.form.html.twig
Normal file
1431
templates/job-order/cmb.form.onestep.html.twig
Normal file
1421
templates/job-order/form.onestep.html.twig
Normal file
|
|
@ -89,7 +89,7 @@
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<label data-field="customer_phone_mobile">Mobile Phone</label>
|
<label data-field="customer_phone_mobile">Mobile Phone</label>
|
||||||
<div class="input-group m-input-group">
|
<div class="input-group m-input-group">
|
||||||
<span class="input-group-addon">+63</span>
|
<span class="input-group-addon">{% trans %}country_code_prefix{% endtrans %}</span>
|
||||||
<input type="text" name="customer_phone_mobile" id="customer-phone-mobile" class="form-control m-input" value="{{ obj.getCustomer.getPhoneMobile|default('') }}" data-vehicle-field="1" disabled>
|
<input type="text" name="customer_phone_mobile" id="customer-phone-mobile" class="form-control m-input" value="{{ obj.getCustomer.getPhoneMobile|default('') }}" data-vehicle-field="1" disabled>
|
||||||
<div class="form-control-feedback hide" data-field="customer_phone_mobile"></div>
|
<div class="form-control-feedback hide" data-field="customer_phone_mobile"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -97,7 +97,7 @@
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<label data-field="customer_phone_landline">Landline</label>
|
<label data-field="customer_phone_landline">Landline</label>
|
||||||
<div class="input-group m-input-group">
|
<div class="input-group m-input-group">
|
||||||
<span class="input-group-addon">+63</span>
|
<span class="input-group-addon">{% trans %}country_code_prefix{% endtrans %}</span>
|
||||||
<input type="text" name="customer_phone_landline" id="customer-phone-landline" class="form-control m-input" value="{{ obj.getCustomer.getPhoneLandline|default('') }}" data-vehicle-field="1" disabled>
|
<input type="text" name="customer_phone_landline" id="customer-phone-landline" class="form-control m-input" value="{{ obj.getCustomer.getPhoneLandline|default('') }}" data-vehicle-field="1" disabled>
|
||||||
<div class="form-control-feedback hide" data-field="customer_phone_landline"></div>
|
<div class="form-control-feedback hide" data-field="customer_phone_landline"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -221,7 +221,7 @@
|
||||||
<div class="form-group m-form__group row">
|
<div class="form-group m-form__group row">
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<div class="col-lg-12 form-group-inner">
|
<div class="col-lg-12 form-group-inner">
|
||||||
<label data-field="delivery_instructions">Delivery Instructions</label>
|
<label data-field="delivery_instructions">{% trans %}delivery_instructions_label{% endtrans %}</label>
|
||||||
<textarea name="delivery_instructions" class="form-control m-input" rows="4">{{ obj.getDeliveryInstructions }}</textarea>
|
<textarea name="delivery_instructions" class="form-control m-input" rows="4">{{ obj.getDeliveryInstructions }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -651,8 +651,8 @@ $(function() {
|
||||||
|
|
||||||
var map = new GMaps({
|
var map = new GMaps({
|
||||||
div: '#m_gmap',
|
div: '#m_gmap',
|
||||||
lat: 14.6091,
|
lat: {% trans %}default_lat{% endtrans %},
|
||||||
lng: 121.0223,
|
lng: {% trans %}default_long{% endtrans %},
|
||||||
click: function(e) {
|
click: function(e) {
|
||||||
// handle click in map
|
// handle click in map
|
||||||
selectPoint(map, e.latLng);
|
selectPoint(map, e.latLng);
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@
|
||||||
sortable: false,
|
sortable: false,
|
||||||
overflow: 'visible',
|
overflow: 'visible',
|
||||||
template: function (row, index, datatable) {
|
template: function (row, index, datatable) {
|
||||||
var 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" title="View / Edit"><i class="la la-edit"></i></a>';
|
var 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" title="View / Edit"><i class="la la-edit"></i></a>' + '<a href="' + row.meta.onestep_edit_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" title="One Step Edit"><i class="la la-edit"></i></a>';
|
||||||
|
|
||||||
return actions;
|
return actions;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,9 @@
|
||||||
{% if is_granted('jo_open.edit') %}
|
{% if is_granted('jo_open.edit') %}
|
||||||
actions += '<a href="' + row.meta.edit_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-reassign-hub" title="Edit"><i class="fa fa-file"></i></a>';
|
actions += '<a href="' + row.meta.edit_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-reassign-hub" title="Edit"><i class="fa fa-file"></i></a>';
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if is_granted('jo_onestep.edit') %}
|
||||||
|
actions += '<a href="' + row.meta.onestep_edit_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-reassign-hub" title="One Step Edit"><i class="fa fa-file"></i></a>';
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
return actions;
|
return actions;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
36
templates/map/initBingMap.js
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
<script type='text/javascript' src='https://www.bing.com/api/maps/mapcontrol?callback=initMap&key={{ bingmaps_api_key|raw }}' async defer></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function mapCreate(div_id, center_lat, center_lng, map_type, zoom) {
|
||||||
|
var map_type_id = Microsoft.Maps.MapTypeId.road;
|
||||||
|
switch (map_type) {
|
||||||
|
case 'road':
|
||||||
|
map_type_id = Microsoft.Maps.MapTypeId.road;
|
||||||
|
break;
|
||||||
|
case 'aerial':
|
||||||
|
map_type_id = Microsoft.Maps.MapTypeId.aerial;
|
||||||
|
break;
|
||||||
|
case 'dark':
|
||||||
|
map_type_id = Microsoft.Maps.MapTypeId.canvasDark;
|
||||||
|
break;
|
||||||
|
case 'light':
|
||||||
|
map_type_id = Microsoft.Maps.MapTypeId.canvasLight;
|
||||||
|
break;
|
||||||
|
case 'grayscale':
|
||||||
|
map_type_id = Microsoft.Maps.MapTypeId.grayscale;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
map_type_id = Microsoft.Maps.MapTypeId.road;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var map = new Microsoft.Maps.Map('#' + div_id, {
|
||||||
|
center: new Microsoft.Maps.Location(center_lat, center_lng),
|
||||||
|
mapTypeId: map_type_id,
|
||||||
|
zoom: zoom
|
||||||
|
});
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
22
templates/map/initGoogleMap.js
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<script src="//maps.google.com/maps/api/js?key={{ gmaps_api_key|raw }}&callback=initMap" type="text/javascript" async defer></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function mapCreate(div_id, center_lat, center_lng, map_type, zoom) {
|
||||||
|
var map_type_id = 'roadmap';
|
||||||
|
switch (map_type) {
|
||||||
|
case 'road':
|
||||||
|
map_type_id = 'roadmap';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
map_type_id = 'roadmap';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var map = new google.maps.Map(document.getElementById(div_id),
|
||||||
|
{
|
||||||
|
center: {lat: center_lat, lng: center_lng},
|
||||||
|
mapTypeId: map_type_id,
|
||||||
|
zoom: zoom
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
123
templates/map/initOpenStreetMap.js
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
|
||||||
|
integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
|
||||||
|
crossorigin="">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function mapCreate(div_id, center_lat, center_lng, map_type, zoom) {
|
||||||
|
var map = L.map(div_id).setView(
|
||||||
|
[center_lat, center_lng],
|
||||||
|
zoom
|
||||||
|
);
|
||||||
|
|
||||||
|
// add tile layer
|
||||||
|
// TODO: put access token in .env
|
||||||
|
var streets = L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
|
||||||
|
attribution: 'Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
|
||||||
|
maxZoom: 18,
|
||||||
|
id: 'mapbox/streets-v11',
|
||||||
|
accessToken: 'pk.eyJ1Ijoia2NvcmRlcm8iLCJhIjoiY2szbzA3ZHdsMDZxdTNsbGl4ZGNnN2VxaSJ9.LRzAe3RlV8sIP1N1x0chdw'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
// layer groups
|
||||||
|
// .addTo(map) --> this will display your riders by default
|
||||||
|
var lg_avail_rider = L.layerGroup().addTo(map);
|
||||||
|
var lg_jo_rider = L.layerGroup().addTo(map);
|
||||||
|
var lg_cust = L.layerGroup().addTo(map);
|
||||||
|
|
||||||
|
// this little snippet will not display your riders by default.
|
||||||
|
// Instead, a toggle button will display in the map, with a checkbox with text Riders.
|
||||||
|
// Check that to display the riders
|
||||||
|
//var ridersLayerGroup = L.layerGroup();
|
||||||
|
|
||||||
|
// create icons
|
||||||
|
var icon_rider_active_jo = L.divIcon({
|
||||||
|
className: 'map-div-icon',
|
||||||
|
html: "<div style='background-color:#FF0000;' class='marker-pin'></div><i class='fa fa-bolt awesome'>",
|
||||||
|
iconSize: [39, 42],
|
||||||
|
iconAnchor: [15, 42]
|
||||||
|
});
|
||||||
|
var icon_rider_available = L.divIcon({
|
||||||
|
className: 'map-div-icon',
|
||||||
|
html: "<div style='background-color:#00FF00;' class='marker-pin'></div><i class='fa fa-bolt awesome'>",
|
||||||
|
iconSize: [39, 42],
|
||||||
|
iconAnchor: [15, 42]
|
||||||
|
});
|
||||||
|
var icon_customer = L.divIcon({
|
||||||
|
className: 'map-div-icon',
|
||||||
|
html: "<div style='background-color:#0055FF;' class='marker-pin'></div><i class='fa fa-user awesome'>",
|
||||||
|
iconSize: [39, 42],
|
||||||
|
iconAnchor: [15, 42]
|
||||||
|
});
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '{{ path('rider_locations') }}',
|
||||||
|
}).done(function(response) {
|
||||||
|
// clear all markers
|
||||||
|
lg_avail_rider.clearLayers();
|
||||||
|
lg_jo_rider.clearLayers();
|
||||||
|
lg_cust.clearLayers();
|
||||||
|
|
||||||
|
// get riders and mark
|
||||||
|
var riders = response.riders;
|
||||||
|
|
||||||
|
$.each(riders, function(rider_id, rider_data) {
|
||||||
|
// rider location
|
||||||
|
var point = rider_data['loc'];
|
||||||
|
var lat = point[0];
|
||||||
|
var long = point[1];
|
||||||
|
|
||||||
|
// customer location
|
||||||
|
var cloc = rider_data['cust_loc'];
|
||||||
|
var clat = cloc[0];
|
||||||
|
var clong = cloc[1];
|
||||||
|
|
||||||
|
// rider popup content
|
||||||
|
rider_popup = '<strong>' + rider_data['label'] + '</strong>';
|
||||||
|
|
||||||
|
// create rider markers
|
||||||
|
if (rider_data['has_jo']) {
|
||||||
|
var jo_data = rider_data['jo'];
|
||||||
|
rider_popup += '<br>';
|
||||||
|
rider_popup += '<a href="' + jo_data['url'] + '">Job Order #' + jo_data['id'] + '</a><br>';
|
||||||
|
rider_popup += jo_data['stype'] + '<br>';
|
||||||
|
rider_popup += jo_data['status'] + '<br><br>';
|
||||||
|
rider_popup += jo_data['cname'] + '<br>';
|
||||||
|
rider_popup += jo_data['plate'];
|
||||||
|
|
||||||
|
var cust_popup = '<strong>' + jo_data['cname'] + '</strong><br>';
|
||||||
|
cust_popup += jo_data['plate'] + '<br>';
|
||||||
|
cust_popup += '<a href="' + jo_data['url'] + '">Job Order #' + jo_data['id'] + '</a><br>';
|
||||||
|
cust_popup += jo_data['stype'] + '<br>';
|
||||||
|
cust_popup += jo_data['status'];
|
||||||
|
|
||||||
|
var rider_marker = L.marker([lat, long], { icon: icon_rider_active_jo }).bindPopup(rider_popup);
|
||||||
|
var cust_marker = L.marker([clat, clong], { icon: icon_customer }).bindPopup(cust_popup);
|
||||||
|
lg_cust.addLayer(cust_marker);
|
||||||
|
lg_jo_rider.addLayer(rider_marker);
|
||||||
|
} else {
|
||||||
|
var rider_marker = L.marker([lat, long], { icon: icon_rider_available }).bindPopup(rider_popup);
|
||||||
|
lg_avail_rider.addLayer(rider_marker);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// base layer
|
||||||
|
var baseMaps = {
|
||||||
|
'Streets': streets
|
||||||
|
};
|
||||||
|
|
||||||
|
// overlay layer
|
||||||
|
var overlayMaps = {
|
||||||
|
'Available Riders' : lg_avail_rider,
|
||||||
|
'JO Riders' : lg_jo_rider,
|
||||||
|
'Customers' : lg_cust
|
||||||
|
}
|
||||||
|
|
||||||
|
L.control.layers(baseMaps, overlayMaps).addTo(map);
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
26
templates/map/joOpenStreetMap.js
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
|
||||||
|
integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
|
||||||
|
crossorigin="">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function mapCreate(div_id, center_lat, center_lng, map_type, zoom) {
|
||||||
|
var map = L.map(div_id).setView(
|
||||||
|
[center_lat, center_lng],
|
||||||
|
zoom
|
||||||
|
);
|
||||||
|
|
||||||
|
//TODO: put access token in .env
|
||||||
|
// add tile layer
|
||||||
|
var streets = L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
|
||||||
|
attribution: 'Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
|
||||||
|
maxZoom: 18,
|
||||||
|
id: 'mapbox/streets-v11',
|
||||||
|
accessToken: 'pk.eyJ1Ijoia2NvcmRlcm8iLCJhIjoiY2szbzA3ZHdsMDZxdTNsbGl4ZGNnN2VxaSJ9.LRzAe3RlV8sIP1N1x0chdw'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
@ -143,12 +143,34 @@
|
||||||
|
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src="//maps.google.com/maps/api/js?key={{ gmaps_api_key }}" type="text/javascript"></script>
|
<script src="//maps.google.com/maps/api/js?key={{ gmaps_api_key }}&libraries=places" type="text/javascript"></script>
|
||||||
<script src="/assets/vendors/custom/gmaps/gmaps.js" type="text/javascript"></script>
|
<script src="/assets/vendors/custom/gmaps/gmaps.js" type="text/javascript"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
// BEGIN google maps stuff
|
// BEGIN google maps stuff
|
||||||
|
// location search autocomplete
|
||||||
|
var input = document.getElementById('m_gmap_address');
|
||||||
|
|
||||||
|
var autocomplete = new google.maps.places.Autocomplete(input);
|
||||||
|
autocomplete.setComponentRestrictions({'country': ['{% trans %}default_region{% endtrans %}']});
|
||||||
|
autocomplete.addListener('place_changed', function() {
|
||||||
|
var place = autocomplete.getPlace();
|
||||||
|
|
||||||
|
if (!place.geometry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = {
|
||||||
|
'action': 'map.search',
|
||||||
|
'params': {
|
||||||
|
'lat': place.geometry.location.lat(),
|
||||||
|
'lng': place.geometry.location.lng()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(message);
|
||||||
|
});
|
||||||
|
|
||||||
function selectPoint(map, latlng) {
|
function selectPoint(map, latlng) {
|
||||||
var lat = latlng.lat();
|
var lat = latlng.lat();
|
||||||
var lng = latlng.lng();
|
var lng = latlng.lng();
|
||||||
|
|
@ -168,8 +190,8 @@ function selectPoint(map, latlng) {
|
||||||
|
|
||||||
var map = new GMaps({
|
var map = new GMaps({
|
||||||
div: '#m_gmap',
|
div: '#m_gmap',
|
||||||
lat: 14.6091,
|
lat: {% trans %}default_lat{% endtrans %},
|
||||||
lng: 121.0223,
|
lng: {% trans %}default_long{% endtrans %},
|
||||||
click: function(e) {
|
click: function(e) {
|
||||||
// handle click in map
|
// handle click in map
|
||||||
selectPoint(map, e.latLng);
|
selectPoint(map, e.latLng);
|
||||||
|
|
|
||||||
|
|
@ -174,12 +174,34 @@
|
||||||
|
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src="//maps.google.com/maps/api/js?key={{ gmaps_api_key }}" type="text/javascript"></script>
|
<script src="//maps.google.com/maps/api/js?key={{ gmaps_api_key }}&libraries=places" type="text/javascript"></script>
|
||||||
<script src="/assets/vendors/custom/gmaps/gmaps.js" type="text/javascript"></script>
|
<script src="/assets/vendors/custom/gmaps/gmaps.js" type="text/javascript"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
// BEGIN google maps stuff
|
// BEGIN google maps stuff
|
||||||
|
// location search autocomplete
|
||||||
|
var input = document.getElementById('m_gmap_address');
|
||||||
|
|
||||||
|
var autocomplete = new google.maps.places.Autocomplete(input);
|
||||||
|
autocomplete.setComponentRestrictions({'country': ['{% trans %}default_region{% endtrans %}']});
|
||||||
|
autocomplete.addListener('place_changed', function() {
|
||||||
|
var place = autocomplete.getPlace();
|
||||||
|
|
||||||
|
if (!place.geometry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = {
|
||||||
|
'action': 'map.search',
|
||||||
|
'params': {
|
||||||
|
'lat': place.geometry.location.lat(),
|
||||||
|
'lng': place.geometry.location.lng()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(message);
|
||||||
|
});
|
||||||
|
|
||||||
function selectPoint(map, latlng) {
|
function selectPoint(map, latlng) {
|
||||||
var lat = latlng.lat();
|
var lat = latlng.lat();
|
||||||
var lng = latlng.lng();
|
var lng = latlng.lng();
|
||||||
|
|
@ -199,8 +221,8 @@ function selectPoint(map, latlng) {
|
||||||
|
|
||||||
var map = new GMaps({
|
var map = new GMaps({
|
||||||
div: '#m_gmap',
|
div: '#m_gmap',
|
||||||
lat: 14.6091,
|
lat: {% trans %}default_lat{% endtrans %},
|
||||||
lng: 121.0223,
|
lng: {% trans %}default_long{% endtrans %},
|
||||||
click: function(e) {
|
click: function(e) {
|
||||||
// handle click in map
|
// handle click in map
|
||||||
selectPoint(map, e.latLng);
|
selectPoint(map, e.latLng);
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<label data-field="customer_phone_mobile">Mobile Phone</label>
|
<label data-field="customer_phone_mobile">Mobile Phone</label>
|
||||||
<div class="input-group m-input-group">
|
<div class="input-group m-input-group">
|
||||||
<span class="input-group-addon">+63</span>
|
<span class="input-group-addon">{% trans %}country_code_prefix{% endtrans %}</span>
|
||||||
<input type="text" name="customer_phone_mobile" id="customer-phone-mobile" class="form-control m-input" value="{{ data.getCustMobile|default('') }}" data-vehicle-field="1" disabled>
|
<input type="text" name="customer_phone_mobile" id="customer-phone-mobile" class="form-control m-input" value="{{ data.getCustMobile|default('') }}" data-vehicle-field="1" disabled>
|
||||||
<div class="form-control-feedback hide" data-field="customer_phone_mobile"></div>
|
<div class="form-control-feedback hide" data-field="customer_phone_mobile"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -61,7 +61,7 @@
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<label data-field="customer_phone_landline">Landline</label>
|
<label data-field="customer_phone_landline">Landline</label>
|
||||||
<div class="input-group m-input-group">
|
<div class="input-group m-input-group">
|
||||||
<span class="input-group-addon">+63</span>
|
<span class="input-group-addon">{% trans %}country_code_prefix{% endtrans %}</span>
|
||||||
<input type="text" name="customer_phone_landline" id="customer-phone-landline" class="form-control m-input" value="{{ data.getCustLandline|default('') }}" data-vehicle-field="1" disabled>
|
<input type="text" name="customer_phone_landline" id="customer-phone-landline" class="form-control m-input" value="{{ data.getCustLandline|default('') }}" data-vehicle-field="1" disabled>
|
||||||
<div class="form-control-feedback hide" data-field="customer_phone_landline"></div>
|
<div class="form-control-feedback hide" data-field="customer_phone_landline"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -71,7 +71,7 @@
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<label data-field="customer_contact">Contact</label>
|
<label data-field="customer_contact">Contact</label>
|
||||||
<div class="input-group m-input-group">
|
<div class="input-group m-input-group">
|
||||||
<span class="input-group-addon">+63</span>
|
<span class="input-group-addon">{% trans %}country_code_prefix{% endtrans %}</span>
|
||||||
<input type="text" name="customer_contact" id="customer-contact" class="form-control m-input" value="{{ data.getCustContact|default('') }}" data-vehicle-field="1" disabled>
|
<input type="text" name="customer_contact" id="customer-contact" class="form-control m-input" value="{{ data.getCustContact|default('') }}" data-vehicle-field="1" disabled>
|
||||||
<div class="form-control-feedback hide" data-field="customer_contact"></div>
|
<div class="form-control-feedback hide" data-field="customer_contact"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@
|
||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
<label data-field="contact_num">Contact Number</label>
|
<label data-field="contact_num">Contact Number</label>
|
||||||
<div class="input-group m-input-group">
|
<div class="input-group m-input-group">
|
||||||
<span class="input-group-addon">+63</span>
|
<span class="input-group-addon">{% trans %}country_code_prefix{% endtrans %}</span>
|
||||||
<input type="text" name="contact_num" class="form-control m-input" value="{{ customer and mode == 'create' and customer.getPhoneMobile is not empty ? customer.getPhoneMobile : obj.getContactNumber }}"{{ customer ? ' disabled' }}>
|
<input type="text" name="contact_num" class="form-control m-input" value="{{ customer and mode == 'create' and customer.getPhoneMobile is not empty ? customer.getPhoneMobile : obj.getContactNumber }}"{{ customer ? ' disabled' }}>
|
||||||
<div class="form-control-feedback hide" data-field="contact_num"></div>
|
<div class="form-control-feedback hide" data-field="contact_num"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@
|
||||||
Mobile Phone
|
Mobile Phone
|
||||||
</label>
|
</label>
|
||||||
<div class="input-group m-input-group">
|
<div class="input-group m-input-group">
|
||||||
<span class="input-group-addon">+63</span>
|
<span class="input-group-addon">{% trans %}country_code_prefix{% endtrans %}</span>
|
||||||
<input type="text" name="mobile_number" class="form-control m-input" value="{{ obj.getMobileNumber|default('') }}" data-name="mobile_number">
|
<input type="text" name="mobile_number" class="form-control m-input" value="{{ obj.getMobileNumber|default('') }}" data-name="mobile_number">
|
||||||
<div class="form-control-feedback hide" data-field="mobile_number"></div>
|
<div class="form-control-feedback hide" data-field="mobile_number"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
27
translations/cmb.messages.en.yaml
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# text
|
||||||
|
title_login: Res-Q for CMB | Login
|
||||||
|
block_title: Res-Q for CMB
|
||||||
|
control_panel_sign_in: Sign-in to Control Panel
|
||||||
|
alt_image_logo_login: Res-Q for CMB
|
||||||
|
alt_image_dashboard: Res-Q for CMB
|
||||||
|
copyright: Res-Q for CMB
|
||||||
|
battery_size_tradein_brand: Trade-in Motolite
|
||||||
|
battery_size_tradein_premium: Trade-in Premium
|
||||||
|
battery_size_tradein_other: Trade-in Other
|
||||||
|
add_cust_vehicle_battery_info: This vehicle is using a Motolite battery
|
||||||
|
jo_title_pdf: Res-Q for CMB Job Order
|
||||||
|
country_code_prefix: '+60'
|
||||||
|
delivery_instructions_label: 'Delivery Instructions - CarFix Job Order No.'
|
||||||
|
|
||||||
|
# images
|
||||||
|
image_logo_login: /assets/images/black-text-logo-01.png
|
||||||
|
icon_login: /assets/images/battery-assist-bm-logo-32x32.png
|
||||||
|
icon_base_32x32: /assets/images/black-text-logo-01-32x32.png
|
||||||
|
icon_base_16x16: /assets/images/black-text-logo-01-16x16.png
|
||||||
|
image_dashboard: /assets/images/century_logo.png
|
||||||
|
image_jo_pdf: /public/assets/images/black-text-logo-01-115x115.png
|
||||||
|
|
||||||
|
# default point for maps
|
||||||
|
default_lat: 3.084216
|
||||||
|
default_long: 101.6129996
|
||||||
|
default_region: my
|
||||||
|
|
@ -10,11 +10,18 @@ battery_size_tradein_premium: Trade-in Premium
|
||||||
battery_size_tradein_other: Trade-in Other
|
battery_size_tradein_other: Trade-in Other
|
||||||
add_cust_vehicle_battery_info: This vehicle is using a Motolite battery
|
add_cust_vehicle_battery_info: This vehicle is using a Motolite battery
|
||||||
jo_title_pdf: Motolite Res-Q Job Order
|
jo_title_pdf: Motolite Res-Q Job Order
|
||||||
|
country_code_prefix: '+63'
|
||||||
|
delivery_instructions_label: Delivery Instructions
|
||||||
|
|
||||||
# # images
|
# images
|
||||||
image_logo_login: /assets/images/logo-resq.png
|
image_logo_login: /assets/images/logo-resq.png
|
||||||
icon_login: /assets/demo/default/media/img/logo/favicon.ico
|
icon_login: /assets/demo/default/media/img/logo/favicon.ico
|
||||||
icon_base_32x32: /assets/images/favicon/favicon-32x32.png
|
icon_base_32x32: /assets/images/favicon/favicon-32x32.png
|
||||||
icon_base_16x16: /assets/images/favicon/favicon-16x16.png
|
icon_base_16x16: /assets/images/favicon/favicon-16x16.png
|
||||||
image_dashboard: /assets/images/logo-motolite.png
|
image_dashboard: /assets/images/logo-motolite.png
|
||||||
image_jo_pdf: /public/assets/images/logo-resq.png
|
image_jo_pdf: /public/assets/images/logo-resq.png
|
||||||
|
|
||||||
|
# default point for maps
|
||||||
|
default_lat: 14.6091
|
||||||
|
default_long: 121.0223
|
||||||
|
default_region: ph
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ battery_size_tradein_premium: Trade-in Premium
|
||||||
battery_size_tradein_other: Trade-in Other
|
battery_size_tradein_other: Trade-in Other
|
||||||
add_cust_vehicle_battery_info: This vehicle is using a Motolite battery
|
add_cust_vehicle_battery_info: This vehicle is using a Motolite battery
|
||||||
jo_title_pdf: Motolite Res-Q Job Order
|
jo_title_pdf: Motolite Res-Q Job Order
|
||||||
|
country_code_prefix: '+63'
|
||||||
|
delivery_instructions_label: Delivery Instructions
|
||||||
|
|
||||||
# images
|
# images
|
||||||
image_logo_login: /assets/images/logo-resq.png
|
image_logo_login: /assets/images/logo-resq.png
|
||||||
|
|
@ -18,3 +20,8 @@ icon_base_32x32: /assets/images/favicon/favicon-32x32.png
|
||||||
icon_base_16x16: /assets/images/favicon/favicon-16x16.png
|
icon_base_16x16: /assets/images/favicon/favicon-16x16.png
|
||||||
image_dashboard: /assets/images/logo-motolite.png
|
image_dashboard: /assets/images/logo-motolite.png
|
||||||
image_jo_pdf: /public/assets/images/logo-resq.png
|
image_jo_pdf: /public/assets/images/logo-resq.png
|
||||||
|
|
||||||
|
# default point for maps
|
||||||
|
default_lat: 14.6091
|
||||||
|
default_long: 121.0223
|
||||||
|
default_region: ph
|
||||||
|
|
|
||||||