Merge branch '307-cmb-fix-customer-hard-coded-country-code' into '270-final-cmb-fixes'

Resolve "CMB fix customer hard-coded country code"

See merge request jankstudio/resq!345
This commit is contained in:
Kendrick Chan 2020-01-23 03:52:03 +00:00
commit 5ac6127e19
45 changed files with 3305 additions and 143 deletions

View file

@ -42,3 +42,14 @@ POLICY_MOBILE=insertmobilepolicyidhere
# OTP
OTP_MODE=settotestorrandom
# geofence
GEOFENCE_ENABLE=settotrueorfalse
# unknown manufacturer and vehicle ids
CVU_MFG_ID=insertmfgidforunknownvehicles
CVU_BRAND_ID=insertbrandidforunknownvehicles
# country code prefix
COUNTRY_CODE=+insertcountrycodehere

View file

@ -41,7 +41,6 @@ class TestAPICommand extends Command
// TODO: shift this out of the bundle, since it's project specific
// warranty register
$serial = 'AJ34LJADR12134LKJL5';
$plate_num = 'XEN918';
@ -54,16 +53,22 @@ class TestAPICommand extends Command
'date_expire' => '20191001',
'first_name' => 'First',
'last_name' => 'Last',
'mobile_number' => '12345678910',
'mobile_number' => '09231234567',
];
$api->post('/capi/warranties', $params);
//$api->post('/capi/warranties', $params);
// get all warranties
$api->get('/capi/warranties');
$params = [
'order' => 'DESC',
'limit' => '5',
'start' => '1',
];
$api->get('/capi/warranties', $params);
// warranty find
$api->get('/capi/warranties/' . $serial);
//$api->get('/capi/warranties/' . $serial);
// warranty update
$id = 86811;
@ -78,7 +83,7 @@ class TestAPICommand extends Command
'last_name' => 'Last',
'mobile_number' => '123456789111',
];
$api->post('/capi/warranties/'. $id, $params);
//$api->post('/capi/warranties/'. $id, $params);
// warranty set privacy policy
$id = 86811;
@ -86,7 +91,7 @@ class TestAPICommand extends Command
$params = [
'privacy_policy_id' => $policy_id,
];
$api->post('/capi/warranties/' . $id .'/privacypolicy', $params);
//$api->post('/capi/warranties/' . $id .'/privacypolicy', $params);
// warranty claim
$id = 86811;
@ -94,30 +99,44 @@ class TestAPICommand extends Command
$params = [
'serial' => $serial,
];
$api->post('/capi/warranties/' . $id . '/claim', $params);
//$api->post('/capi/warranties/' . $id . '/claim', $params);
// warranty cancel
$id = 86811;
$api->get('/capi/warranties/' . $id . '/cancel');
//$api->get('/capi/warranties/' . $id . '/cancel');
// plate warranty
$api->get('/capi/plates/' . $plate_num . '/warranties');
//$api->get('/capi/plates/' . $plate_num . '/warranties');
// warranty delete
$id = 86811;
$api->post('/capi/warranties/' . $id . '/delete');
//$api->post('/capi/warranties/' . $id . '/delete');
// battery
$api->get('/capi/battery_brands');
$api->get('/capi/battery_sizes');
$api->get('/capi/batteries');
//$api->get('/capi/battery_brands');
//$api->get('/capi/battery_sizes');
//$api->get('/capi/batteries');
// vehicle
$api->get('/capi/vehicle_manufacturers');
$api->get('/capi/vehicles');
//$api->get('/capi/vehicle_manufacturers');
//$api->get('/capi/vehicles');
// privacy policy
$privacy_policy_id = 2;
$api->get('/capi/privacy_policy/' . $privacy_policy_id );
// register new customer
$params = [
'first_name' => 'Krispups',
'last_name' =>'Porzindog',
'mobile_number' => '9221111111',
'v_make_id' => '22241',
'v_model_year' => '2018',
'v_plate_number' => 'KPP1234',
'v_color' => 'White',
'v_condition' => 'new',
'v_fuel_type' => 'gas',
];
$api->post('/capi/quick_registration', $params);
}
}

View file

@ -12,6 +12,7 @@
"catalyst/menu-bundle": "dev-master",
"creof/doctrine2-spatial": "^1.2",
"data-dog/audit-bundle": "^0.1.10",
"edwinhoksberg/php-fcm": "^1.0",
"guzzlehttp/guzzle": "^6.3",
"predis/predis": "^1.1",
"sensio/framework-extra-bundle": "^5.1",

53
composer.lock generated
View file

@ -1,10 +1,10 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "ef9a215401e1fec51336e1d6a9df52d9",
"content-hash": "4873ae3fd18db755bc9bf395bbbfb141",
"packages": [
{
"name": "catalyst/auth-bundle",
@ -1564,6 +1564,55 @@
],
"time": "2018-06-14T14:45:07+00:00"
},
{
"name": "edwinhoksberg/php-fcm",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/EdwinHoksberg/php-fcm.git",
"reference": "7be637139fe54ec23f37c8dba519bafa7543e336"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/EdwinHoksberg/php-fcm/zipball/7be637139fe54ec23f37c8dba519bafa7543e336",
"reference": "7be637139fe54ec23f37c8dba519bafa7543e336",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^6.3",
"php": ">= 7.0"
},
"require-dev": {
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^6.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Fcm\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Edwin Hoksberg",
"email": "mail@edwinhoksberg.nl"
}
],
"description": "A library for sending Firebase cloud messages and managing user topic subscriptions, device groups and devices.",
"homepage": "https://github.com/EdwinHoksberg/php-fcm",
"keywords": [
"FCM",
"Firebase Cloud Messaging",
"firebase",
"google",
"notifications"
],
"time": "2018-04-09T19:32:41+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "6.3.3",

View file

@ -256,6 +256,8 @@ access_keys:
label: Search
- id: warranty.search
label: Customer Battery Search
- id: warranty.upload
label: Warranty Upload
- id: ticket
label: Ticket Access
@ -298,6 +300,12 @@ access_keys:
label: Popapp Comparison Report
- id: report.meh.customer
label: RESQ MEH Customer Report
- id: report.warranty.class
label: Warranty Class Report
- id: report.vehicle.battery.compatibility
label: Vehicle Battery Compatibility Report
- id: report.warranty.details
label: Warranty Details Report
- id: service
label: Other Services
@ -364,3 +372,17 @@ access_keys:
label: Add
- id: warranty.update
label: Update
- id: staticcontent
label: Static Content
acls:
- id: static_content.menu
label: Menu
- id: static_content.list
label: List
- id: static_content.add
label: Add
- id: static_content.update
label: Update
- id: static_content.delete
label: Delete

View file

@ -50,3 +50,8 @@ access_keys:
acls:
- id: privacypolicy.find
label: Find Privacy Policy
- id: customer
label: Customer
acls:
- id: customer.register
label: Register Customer

View file

@ -155,6 +155,14 @@ main_menu:
acl: warranty.list
label: Warranty
parent: support
- id: warranty_upload
acl: warranty.upload
label: Warranty Upload
parent: support
- id: static_content_list
acl: static_content.list
label: Static Content
parent: support
- id: service
acl: service.menu

View file

@ -135,3 +135,11 @@ capi_privacy_policy:
path: /capi/privacy_policy/{id}
controller: App\Controller\CAPI\PrivacyPolicyController::getPrivacyPolicy
methods: [GET]
# customer
# register customer and customer vehicle
capi_customer_register:
path: /capi/quick_registration
controller: App\Controller\CAPI\CustomerController::register
methods: [POST]

View file

@ -47,3 +47,33 @@ rep_resq_meh_export_csv:
path: /report/meh_customer_export
controller: App\Controller\ReportController::mehCustomerExportCSV
methods: [POST]
rep_warranty_class_form:
path: /report/warranty_class_report
controller: App\Controller\ReportController::warrantyClassForm
methods: [GET]
rep_warranty_class_export_csv:
path: /report/warranty_class_report
controller: App\Controller\ReportController::warrantyClassExportCSV
methods: [POST]
rep_vehicle_battery_compatibility_form:
path: /report/vehicle_battery_compatibility_report
controller: App\Controller\ReportController::vehicleBatteryCompatibilityForm
methods: [GET]
rep_vehicle_battery_compatibility_export_csv:
path: /report/vehicle_battery_compatibility_report
controller: App\Controller\ReportController::vehicleBatteryCompatibilityExportCSV
methods: [POST]
rep_warranty_details_form:
path: /report/warranty_details_report
controller: App\Controller\ReportController::warrantyDetailsForm
methods: [GET]
rep_warranty_details_export_csv:
path: /report/warranty_details_report
controller: App\Controller\ReportController::warrantyDetailsExportCSV
methods: [POST]

View file

@ -0,0 +1,33 @@
static_content_list:
path: /static_content
controller: App\Controller\StaticContentController::index
static_content_rows:
path: /static_content/rows
controller: App\Controller\StaticContentController::rows
methods: [POST]
static_content_create:
path: /static_content/create
controller: App\Controller\StaticContentController::addForm
methods: [GET]
static_content_create_submit:
path: /static_content/create
controller: App\Controller\StaticContentController::addSubmit
methods: [POST]
static_content_update:
path: /static_content/{id}
controller: App\Controller\StaticContentController::updateForm
methods: [GET]
static_content_update_submit:
path: /static_content/{id}
controller: App\Controller\StaticContentController::updateSubmit
methods: [POST]
static_content_delete:
path: /static_content/{id}
controller: App\Controller\StaticContentController::destroy
methods: [DELETE]

View file

@ -28,3 +28,13 @@ warranty_update_submit:
path: /warranties/{id}
controller: App\Controller\WarrantyController::updateSubmit
methods: [POST]
warranty_upload:
path: /warranty/upload
controller: App\Controller\WarrantyController::uploadForm
methods: [GET]
warranty_upload_submit:
path: /warranty/upload
controller: App\Controller\WarrantyController::uploadSubmit
methods: [POST]

View file

@ -10,6 +10,7 @@ parameters:
api_access_key: 'api_access_keys'
app_acl_file: 'acl.yaml'
app_access_key: 'access_keys'
cvu_brand_id: "%env(CVU_BRAND_ID)%"
services:
# default configuration for services in *this* file
@ -87,6 +88,25 @@ services:
$password: "%env(REDIS_CLIENT_PASSWORD)%"
$env_flag: "dev"
App\Service\GeofenceTracker:
arguments:
$geofence_flag: "%env(GEOFENCE_ENABLE)%"
App\Service\WarrantyHandler:
arguments:
$em: "@doctrine.orm.entity_manager"
App\Command\SetCustomerPrivacyPolicyCommand:
arguments:
$policy_promo: "%env(POLICY_PROMO)%"
$policy_third_party: "%env(POLICY_THIRD_PARTY)%"
$policy_mobile: "%env(POLICY_MOBILE)%"
App\Command\CreateCustomerFromWarrantyCommand:
arguments:
$cvu_mfg_id: "%env(CVU_MFG_ID)%"
$cvu_brand_id: "%env(CVU_BRAND_ID)%"
# rider tracker service
App\Service\RiderTracker:
arguments:
@ -144,14 +164,18 @@ services:
App\Service\InvoiceGeneratorInterface: "@App\\Service\\InvoiceGenerator\\ResqInvoiceGenerator"
# job order generator
App\Service\JobOrderHandler\CMBJobOrderHandler: ~
App\Service\JobOrderHandler\ResqJobOrderHandler:
arguments:
$country_code: "%env(COUNTRY_CODE)%"
#job order generator interface
#App\Service\JobOrderHandlerInterface: "@App\\Service\\JobOrderHandler\\CMBJobOrderHandler"
App\Service\JobOrderHandlerInterface: "@App\\Service\\JobOrderHandler\\ResqJobOrderHandler"
# customer generator
App\Service\CustomerHandler\CMBCustomerHandler: ~
App\Service\CustomerHandler\ResqCustomerHandler:
arguments:
$country_code: "%env(COUNTRY_CODE)%"
# customer generator interface
#App\Service\CustomerHandlerInterface: "@App\\Service\\CustomerHandler\\CMBCustomerHandler"

View file

@ -0,0 +1,75 @@
<?php
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Doctrine\Common\Persistence\ObjectManager;
use App\Entity\Battery;
use App\Service\WarrantyHandler;
class ComputeWarrantyExpiryDateCommand extends Command
{
protected $em;
protected $wh;
public function __construct(ObjectManager $em, WarrantyHandler $wh)
{
$this->em = $em;
$this->wh = $wh;
parent::__construct();
}
protected function configure()
{
$this->setName('warranty:computeexpirydate')
->setDescription('Compute expiry date for existing warranties.')
->setHelp('Compute expiry date for existing warranties.');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$warr_q = $this->em->createQuery('select w from App\Entity\Warranty w where w.date_expire is null');
$warranties = $warr_q->iterate();
foreach($warranties as $row)
{
$warr = $row[0];
error_log('Processing warranty for ' . $warr->getID());
$date_purchase = $warr->getDatePurchase();
$batteries = $this->wh->getBatteriesForWarranty($warr);
if (!empty($batteries))
{
$warranty_class = $warr->getWarrantyClass();
$warr_period = $this->wh->getWarrantyPeriod($batteries, $warranty_class);
if ($warr_period != null)
{
$expiry_date = $this->wh->computeDateExpire($date_purchase, $warr_period);
}
else
{
$expiry_date = $date_purchase;
}
// save expiry date
$warr->setDateExpire($expiry_date);
$this->em->persist($warr);
$this->em->flush();
}
$this->em->clear();
}
}
}

View file

@ -0,0 +1,458 @@
<?php
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
use Doctrine\Common\Persistence\ObjectManager;
use App\Entity\Warranty;
use App\Entity\Customer;
use App\Entity\CustomerVehicle;
use App\Entity\VehicleManufacturer;
use App\Entity\Vehicle;
use App\Ramcar\FuelType;
use App\Ramcar\VehicleStatusCondition;
use DateTime;
class CreateCustomerFromWarrantyCommand extends Command
{
const CV_FOUND = 'Vehicle found';
const CV_NEW = 'New vehicle';
const CUST_NEW = 'New customer and vehicle.';
protected $em;
protected $cust_index;
protected $cvu_mfg_id;
protected $cvu_brand_id;
public function __construct(ObjectManager $em, $cvu_mfg_id, $cvu_brand_id)
{
$this->em = $em;
$this->cvu_mfg_id = $cvu_mfg_id;
$this->cvu_brand_id = $cvu_brand_id;
parent::__construct();
}
protected function configure()
{
$this->setName('customer:createfromwarranty')
->setDescription('Create customers from existing warranties.')
->setHelp('Creates customers from existing warranties.')
->addArgument('file', InputArgument::REQUIRED, 'Path to the output CSV file with the warranties.');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$csv_file = $input->getArgument('file');
// attempt to open file
try
{
$fh = fopen($csv_file, "w");
}
catch (Exception $e)
{
throw new Exception('The file "' . $csv_file . '" could be opened.');
}
// counters for warranties, customers, customer vehicles
$total_warr = 0;
$total_inv_warr = 0;
$total_cust_added = 0;
$total_cv_added = 0;
/*
// load all customers
$output->writeln('Loading customer data...');
$this->loadCustomers($output);
*/
// get all warranties
error_log('Getting warranties...');
$warr_q = $this->em->createQuery('select w from App\Entity\Warranty w where w.mobile_number is not null');
$warranties = $warr_q->iterate();
// $warranties = $warr_q->getResult();
// $warranties = $this->em->getRepository(Warranty::class)->findAll();
//$invalid_warranties = [];
// $warr_count = count($warranties);
$created_objs = [];
$output->writeln("Processing warranties... ");
foreach($warranties as $row)
{
$warr = $row[0];
$total_warr++;
// check if warranty mobile already exists in customer
$w_mobile = $warr->getMobileNumber();
if (empty($w_mobile))
{
// TODO: for now, if warranty mobile number is empty, add to list of invalid entries
//$invalid_warranties[] = $this->processInvalidEntries($warr);
continue;
}
// parse warranty mobile in case of multiple numbers
// check for spaces, slash, and forward slash
$w_mobile_array = [];
if (preg_match('/[\\\s\/]/', $w_mobile))
{
$w_mobile_array = preg_split('/[\\\s\/]/', $w_mobile);
}
else
{
// only one mobile number
$w_mobile_array[] = $w_mobile;
}
// set values for new customer vehicle
$w_plate_number = $this->cleanPlateNumber($warr->getPlateNumber());
$cust_found = false;
foreach ($w_mobile_array as $w_mobile_num)
{
$w_mobile_num = trim($w_mobile_num);
// empty mobile num
if (empty($w_mobile_num))
continue;
// does it fit our 09XXXXXXXXX pattern?
if (preg_match('/^09[0-9]{9}$/', $w_mobile_num))
{
// remove first '0'
$w_mobile_num = substr($w_mobile_num, 1);
error_log("CONVERTED TO $w_mobile_num");
}
// does it fit our 9XXXXXXXXX pattern?
if (!preg_match('/^9[0-9]{9}$/', $w_mobile_num))
continue;
/*
// min length 2
// TODO: we need to check proper phone number format
// format should be '9XXXXXXXXX'
// TODO: if format doesn't fit and there's a 0 or 63 prefix, we should be able to detect and convert
if (strlen($w_mobile_num <= 2))
continue;
*/
error_log('');
error_log("($total_warr) processing $w_mobile_num from warranty...");
$customers = $this->findCustomerByNumber($w_mobile_num);
if (!empty($customers))
{
error_log('found customer for ' . $w_mobile_num);
foreach ($customers as $customer)
{
// get customer vehicles for customer
$c_vehicles = $customer->getVehicles();
$cv_found = false;
if (!empty($c_vehicles))
{
// check if plate number of customer vehicle matches warranty plate number
foreach ($c_vehicles as $c_vehicle)
{
$clean_cv_plate = $this->cleanPlateNumber($c_vehicle->getPlateNumber());
// check if it's already there
if ($clean_cv_plate == $w_plate_number)
{
// customer and customer vehicle already exists
$cv_found = true;
break;
}
}
}
// if there was a customer vehicle matched
if ($cv_found)
{
// vehicle found, do nothing.
error_log('vehicle found - ' . $w_plate_number);
$created_objs[] = $this->createReportData($warr, self::CV_FOUND);
}
else
{
// customer exists but not customer vehicle
// add customer vehicle to existing customer with unknown manufacturer and make
error_log('new vehicle - ' . $w_plate_number);
$this->createCustomerVehicle($customer, $this->getDefaultVehicle(), $w_plate_number);
$created_objs[] = $this->createReportData($warr, self::CV_NEW);
$total_cv_added++;
}
}
}
// customer not found
else
{
error_log('NEW customer and vehicle - ' . $w_plate_number);
// customer not found, add customer and customer vehicle
// get warranty first name, last name
$w_first_name = $warr->getFirstName();
$w_last_name = $warr->getLastName();
//$output->writeln($w_first_name);
//$output->writeln($w_last_name);
//$output->writeln($w_plate_number);
$new_cust = new Customer();
$new_cust->setFirstName($w_first_name)
->setLastName($w_last_name)
->setPhoneMobile($w_mobile_num);
$this->em->persist($new_cust);
$this->createCustomerVehicle($new_cust, $this->getDefaultVehicle(), $w_plate_number);
$created_objs[] = $this->createReportData($warr, self::CUST_NEW);
// add latest customer to hash
//$this->cust_index[$w_mobile_num][] = $new_cust;
$total_cust_added++;
$total_cv_added++;
}
}
$this->em->flush();
$this->em->clear();
}
/*
// process invalid warranties, if any
if (count($invalid_warranties) > 0)
{
fputcsv($fh, [
'ID',
'Serial',
'Warranty Class',
'Last Name',
'First Name',
'Mobile Number',
'Plate Number',
'Battery Model',
'Battery Size',
'SAP Battery',
'Status',
'Date Created',
'Date Purchased',
'Expiry Date',
'Date Claimed',
'Claimed From',
'Privacy Policy',
]);
foreach($invalid_warranties as $row)
{
$total_inv_warr++;
fputcsv($fh, $row);
}
}
*/
// process the report data
if (count($created_objs) > 0)
{
fputcsv($fh, [
'ID',
'Mobile Number',
'Plate Number',
'Action Done',
]);
foreach($created_objs as $row)
{
fputcsv($fh, $row);
}
}
fclose($fh);
$output->writeln('');
$output->writeln('Total warranties: ' . $total_warr);
//$output->writeln('Total warranties with no mobile number: ' . $total_inv_warr);
$output->writeln('Total customers added: ' . $total_cust_added);
$output->writeln('Total customer vehicles added: ' . $total_cv_added);
}
protected function getDefaultVehicle()
{
// get default vehicle
$default_vehicle = $this->em->getRepository(Vehicle::class)->find($this->cvu_brand_id);
if ($default_vehicle == null)
{
$output->writeln("Need to add vehicle with default values.");
return null;
}
return $default_vehicle;
}
protected function findCustomerByNumber($number)
{
$customers = $this->em->getRepository(Customer::class)->findBy(['phone_mobile' => $number]);
return $customers;
}
protected function loadCustomers()
{
error_log('starting query...');
// get all customers
$customers = $this->em->getRepository(Customer::class)->findAll();
$cust_q = $this->em->createQuery('select c from App\Entity\Customer c');
$cust_iter = $q->iterate();
error_log('looping through query...');
$this->cust_index = [];
foreach ($cust_iter as $customer)
{
error_log('here');
$mobile = trim($customer->getPhoneMobile());
if (!empty($mobile))
{
$mobile_array = [];
// need to check if multiple numbers in mobile
if (preg_match('/[\\\s\/]/', $mobile))
{
$mobile_array = preg_split('/[\\\s\/]/', $mobile);
}
else
{
// only one mobile number
$mobile_array[] = $mobile;
}
foreach($mobile_array as $number)
{
if (!(empty($number)))
{
if (!isset($this->cust_index[$number]))
$this->cust_index[$number] = [];
$this->cust_index[$number][] = $customer;
}
}
}
}
}
protected function createCustomerVehicle(Customer $cust, $vehicle, $plate_number)
{
$new_cv = new CustomerVehicle();
$new_cv->setCustomer($cust)
->setPlateNumber($plate_number)
->setStatusCondition(VehicleStatusCondition::BRAND_NEW)
->setModelYear('')
->setColor('')
->setFuelType(FuelType::GAS)
->setHasMotoliteBattery(true)
->setVehicle($vehicle);
$this->em->persist($new_cv);
}
protected function createReportData($warr, $action)
{
$obj = [
'id' => $warr->getID(),
'mobile_number' => $warr->getMobileNumber(),
'plate_number' => $warr->getPlateNumber(),
'action_done' => $action,
];
return $obj;
}
protected function processInvalidEntries($warr)
{
$batt_model = '';
$batt_size = '';
$sap_batt = '';
$policy = '';
$date_purchased = '';
$date_expire = '';
$date_claim = '';
$create_date = $warr->getDateCreate();
$date_create = $create_date->format('d/M/y');
if ($warr->getDatePurchase() != null)
{
$p_date = $warr->getDatePurchase();
$date_purchased = $p_date->format('d/M/y');
}
if ($warr->getDateClaim() != null)
{
$c_date = $warr->getDateClaim();
$date_claim = $c_date->format('d/M/y');
}
if ($warr->getDateExpire() != null)
{
$e_date = $warr->getDateExpire();
$date_expire = $e_date->format('d/M/y');
}
if ($warr->getBatteryModel() != null)
{
$batt_model = $warr->getBatteryModel()->getName();
}
if ($warr->getBatterySize() != null)
{
$batt_size = $warr->getBatterySize()->getName();
}
if ($warr->getSAPBattery() != null)
{
$sap_batt = $warr->getSAPBattery()->getBrand()->getName();
}
if ($warr->getPrivacyPolicy() != null)
{
$policy = $warr->getPrivacyPolicy()->getName();
}
$invalid_warranty = [
'id' => $warr->getID(),
'serial' => $warr->getSerial(),
'warranty_class' => $warr->getWarrantyClass(),
'last_name' => $warr->getLastName(),
'first_name' => $warr->getFirstName(),
'mobile_number' => $warr->getMobileNumber(),
'plate_number' => $warr->getPlateNumber(),
'battery_model' => $batt_model,
'battery_size' => $batt_size,
'sap_battery' => $sap_batt,
'status' => $warr->getStatus(),
'date_create' => $date_create,
'date_purchase' => $date_purchased,
'date_expire' => $date_expire,
'date_claim' => $date_claim,
'claimed_from' => $warr->getClaimedFrom(),
'privacy_policy' => $policy,
];
return $invalid_warranty;
}
protected function cleanPlateNumber($plate)
{
// remove spaces and make upper case
return strtoupper(str_replace(' ', '', $plate));
}
}

View file

@ -34,7 +34,7 @@ class ImportPartnersCommand extends Command
protected $em;
public function __construct(Objectmanager $om)
public function __construct(ObjectManager $om)
{
$this->em = $om;

View file

@ -7,7 +7,6 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Dotenv\Dotenv;
use Doctrine\Common\Persistence\ObjectManager;
@ -19,10 +18,19 @@ class SetCustomerPrivacyPolicyCommand extends Command
{
private $em;
public function __construct(ObjectManager $om)
private $policy_promo_id;
private $policy_third_party_id;
private $policy_mobile_id;
public function __construct(ObjectManager $om, $policy_promo,
$policy_third_party, $policy_mobile)
{
$this->em = $om;
$this->policy_promo_id = $policy_promo;
$this->policy_third_party_id = $policy_third_party;
$this->policy_mobile_id = $policy_mobile;
parent::__construct();
}
@ -35,16 +43,8 @@ class SetCustomerPrivacyPolicyCommand extends Command
protected function execute(InputInterface $input, OutputInterface $output)
{
// get the policy ids from .env
$dotenv = new Dotenv();
$dotenv->loadEnv(__DIR__.'/../../.env');
$policy_promo_id = $_ENV['POLICY_PROMO'];
$policy_third_party_id = $_ENV['POLICY_THIRD_PARTY'];
$policy_mobile_id = $_ENV['POLICY_MOBILE'];
// get third party policy
$third_party_policy = $this->em->getRepository(PrivacyPolicy::class)->find($policy_third_party_id);
$third_party_policy = $this->em->getRepository(PrivacyPolicy::class)->find($this->policy_third_party_id);
// get customers on third party
$third_party_customers = $this->em->getRepository(Customer::class)->findBy(['priv_third_party' => true]);
@ -54,7 +54,7 @@ class SetCustomerPrivacyPolicyCommand extends Command
}
// get promo policy
$promo_policy = $this->em->getRepository(PrivacyPolicy::class)->find($policy_promo_id);
$promo_policy = $this->em->getRepository(PrivacyPolicy::class)->find($this->policy_promo_id);
// get customers on promo
$promo_customers = $this->em->getRepository(Customer::class)->findBy(['priv_promo' => true]);
@ -66,7 +66,7 @@ class SetCustomerPrivacyPolicyCommand extends Command
$this->em->flush();
// get mobile policy
$mobile_policy = $this->em->getRepository(PrivacyPolicy::class)->find($policy_mobile_id);
$mobile_policy = $this->em->getRepository(PrivacyPolicy::class)->find($this->policy_mobile_id);
// get mobile sessions
$mobile_sessions = $this->em->getRepository(MobileSession::class)->findAll();

View file

@ -0,0 +1,98 @@
<?php
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Doctrine\Common\Persistence\ObjectManager;
use App\Entity\Warranty;
use App\Entity\CustomerVehicle;
use App\Service\WarrantyHandler;
class UpdateCustomerVehicleWarrantyCommand extends Command
{
protected $em;
protected $wh;
public function __construct(ObjectManager $em, WarrantyHandler $wh)
{
$this->em = $em;
$this->wh = $wh;
parent::__construct();
}
protected function configure()
{
$this->setName('customervehicle:updatewarrantyinfo')
->setDescription('Update customer vehicle warranty.')
->setHelp('Update customer vehicle warranty.');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
// get all warranties
// since it's possible that the same plate number will have multiple warranties, order them from earliest to latest
$warr_q = $this->em->createQuery('select w from App\Entity\Warranty w where w.plate_number is not null order by w.date_purchase asc');
$warranties = $warr_q->iterate();
foreach ($warranties as $row)
{
$warr = $row[0];
// clean plate number
$plate_number = $this->wh->cleanPlateNumber($warr->getPlateNumber());
// get other warranty information
$serial = $warr->getSerial();
$expiry_date = $warr->getDateExpire();
// TODO: check length of serial for now. Should not exceed 20.
// there is a warranty with 2 serial codes in live
// for now, ignore the warranty
if (strlen($serial) > 20)
{
continue;
}
// find battery
$batteries = $this->wh->getBatteriesForWarranty($warr);
// find customer vehicle using plate number
/*
error_log('Finding customer vehicle with plate number ' . $plate_number);
$cust_vehicles = $this->em->getRepository(CustomerVehicle::class)->findBy(['plate_number' => $plate_number]);
if (!empty($cust_vehicles))
{
if (!empty($batteries))
{
// set current battery to the first battery in list.
// there are cases where multiple batteries linked to an SAP code.
$battery = $batteries[0];
$battery_id = $battery->getID();
}
$q = $this->em->createQuery('update App\Entity\CustomerVehicle cv
set cv.curr_battery = :batt_id,
cv.warranty_code = :serial,
cv.warranty_expiration = :expiry_date
where cv.plate_number = :plate_number')
->setParameters([
'batt_id' => $battery_id,
'serial' => $serial,
'expiry_date' => $expiry_date,
'plate_number' => $plate_number]);
$q->execute();
} */
$this->wh->updateCustomerVehicle($serial, $batteries, $plate_number, $expiry_date);
$this->em->detach($row[0]);
}
}
}

View file

@ -341,6 +341,15 @@ class APIController extends Controller
$this->session->setCustomer($dupe_cust);
}
// TODO: check if mobile matches mobile of customer
$customer = $this->findCustomerByNumber($this->session->getPhoneNumber());
if ($customer != null)
{
// TODO: if there is a dupe_sess, do we need to check if
// dupe_cust is the same as the customer we found?
$this->session->setCustomer($customer);
}
$em->flush();
// response
@ -839,18 +848,15 @@ class APIController extends Controller
$long = $req->request->get('long');
$lat = $req->request->get('lat');
/*
// geofence
$is_covered = $geo->isCovered($long, $lat);
if (!$is_covered)
{
// TODO: put geofence error message in config file somewhere
$res->setError(true)
->setErrorMessage('Oops! Our service is limited to Metro Manila only. We will update you as soon as we are able to cover your area');
->setErrorMessage('Oops! Our service is limited to some areas in Metro Manila, Laguna, and Baguio only. We will update you as soon as we are able to cover your area');
return $res->getReturnResponse();
}
*/
$jo = new JobOrder();
$jo->setSource(TransactionOrigin::MOBILE_APP)
@ -2182,4 +2188,29 @@ class APIController extends Controller
return $res->getReturnResponse();
}
protected function findCustomerByNumber($number)
{
$em = $this->getDoctrine()->getManager();
$customers = $em->getRepository(Customer::class)->findBy(['phone_mobile' => $number]);
// find the customer with the most number of cars
$car_count = 0;
$cust = null;
foreach($customers as $customer)
{
$vehicles = $customer->getVehicles();
if (count($vehicles) > $car_count)
{
$car_count = count($vehicles);
// "save" customer object
$cust = $customer;
}
}
return $cust;
}
}

View file

@ -0,0 +1,204 @@
<?php
namespace App\Controller\CAPI;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\ORM\Query;
use Doctrine\ORM\EntityManagerInterface;
use Catalyst\APIBundle\Controller\APIController;
use Catalyst\APIBundle\Response\APIResponse;
use App\Entity\Customer;
use App\Entity\CustomerVehicle;
use App\Entity\Vehicle;
use Catalyst\APIBundle\Access\Generator as ACLGenerator;
class CustomerController extends APIController
{
protected $acl_gen;
public function __construct(ACLGenerator $acl_gen)
{
$this->acl_gen = $acl_gen;
}
public function register(Request $req, EntityManagerInterface $em)
{
$this->denyAccessUnlessGranted('customer.register', null, 'No access.');
// required parameters
$params = [
'first_name',
'last_name',
'mobile_number',
'v_make_id',
'v_model_year',
'v_plate_number',
'v_color',
'v_condition',
'v_fuel_type',
];
$msg = $this->checkRequiredParameters($req, $params);
error_log('msg - ' . $msg);
if ($msg)
return new APIResponse(false, $msg);
$first_name = $req->request->get('first_name');
$last_name = $req->request->get('last_name');
$mobile_number = $req->request->get('mobile_number');
$make_id = $req->request->get('v_make_id');
$model_year = $req->request->get('v_model_year');
$plate_number = $this->cleanPlateNumber($req->request->get('v_plate_number'));
$color = $req->request->get('v_color');
$condition = $req->request->get('v_condition');
$fuel_type = $req->request->get('v_fuel_type');
// check if vehicle exists
$vehicle = $em->getRepository(Vehicle::class)->find($make_id);
if ($vehicle == null)
return new APIResponse(false, 'Invalid vehicle make.');
// clean up mobile number
// does it fit our 09XXXXXXXXX pattern?
if (preg_match('/^09[0-9]{9}$/', $mobile_number))
{
// remove first '0'
$mobile_number = substr($mobile_number, 1);
error_log("CONVERTED TO $mobile_number");
}
// does it fit our 9XXXXXXXXX pattern?
if (!preg_match('/^9[0-9]{9}$/', $mobile_number))
return new APIResponse(false, 'Invalid mobile number.');
/*
// min length 2
// TODO: we need to check proper phone number format
// format should be '9XXXXXXXXX'
// TODO: if format doesn't fit and there's a 0 or 63 prefix, we should be able to detect and convert
if (strlen($mobile_number <= 2))
continue;
*/
$data = [];
$message = '';
// check if customer already exists
$customers = $em->getRepository(Customer::class)->findBy(['phone_mobile' => $mobile_number]);
if (!empty($customers))
{
foreach($customers as $customer)
{
// get customer vehicles for customer
$c_vehicles = $customer->getVehicles();
$cv_found = false;
if (!empty($c_vehicles))
{
// check if plate number of customer vehicle matches plate number
foreach($c_vehicles as $c_vehicle)
{
$clean_cv_plate = $this->cleanPlateNumber($c_vehicle->getPlateNumber());
// check if it's already there
if ($clean_cv_plate == $plate_number)
{
// customer and customer vehicle already exists
$cv_found = true;
break;
}
}
}
// if there is a customer vehicle matched
if ($cv_found)
{
// vehicle found, do nothing
$message = 'Customer found.';
}
else
{
// customer already exists but not customer vehicle
// add customer vehicle
$new_cv = new CustomerVehicle();
$new_cv->setCustomer($customer)
->setPlateNumber($plate_number)
->setStatusCondition($condition)
->setModelYear($model_year)
->setColor($color)
->setFuelType($fuel_type)
->setHasMotoliteBattery(true)
->setVehicle($vehicle);
$em->persist($new_cv);
$message = 'Vehicle added.';
$data[] = [
'make_id' => $make_id,
'model_year' => $model_year,
'plate_number' => $plate_number,
'color' => $color,
'condition' => $condition,
'fuel_type' => $fuel_type,
];
}
}
}
else
{
// customer not found
$new_cust = new Customer();
$new_cust->setFirstName($first_name)
->setLastName($last_name)
->setPhoneMobile($mobile_number);
$em->persist($new_cust);
// add customer vehicle
$new_cv = new CustomerVehicle();
$new_cv->setCustomer($new_cust)
->setPlateNumber($plate_number)
->setStatusCondition($condition)
->setModelYear($model_year)
->setColor($color)
->setFuelType($fuel_type)
->setHasMotoliteBattery(true)
->setVehicle($vehicle);
$em->persist($new_cv);
$message = 'Customer and vehicle added.';
$data[] = [
'first_name' => $first_name,
'last_name' => $last_name,
'mobile_number' => $mobile_number,
'make_id' => $make_id,
'model_year' => $model_year,
'plate_number' => $plate_number,
'color' => $color,
'condition' => $condition,
'fuel_type' => $fuel_type,
];
}
$em->flush();
$em->clear();
return new APIResponse(true, $message, $data);
}
protected function cleanPlateNumber($plate)
{
// remove spaces and make upper case
return strtoupper(str_replace(' ', '', $plate));
}
}

View file

@ -17,10 +17,16 @@ use App\Entity\SAPBattery;
use App\Entity\SAPBatterySize;
use App\Entity\SAPBatteryBrand;
use App\Entity\PrivacyPolicy;
use App\Entity\Customer;
use App\Entity\CustomerVehicle;
use App\Entity\Vehicle;
use App\Ramcar\NameValue;
use App\Ramcar\WarrantyClass;
use App\Ramcar\WarrantyStatus;
use App\Ramcar\FuelType;
use App\Ramcar\VehicleStatusCondition;
use DateTime;
use Catalyst\APIBundle\Access\Generator as ACLGenerator;
@ -226,6 +232,9 @@ class WarrantyController extends APIController
try
{
$em->persist($warr);
$this->getCustomerFromMobile($em, $warr);
$em->flush();
}
catch (UniqueConstraintViolationException $e)
@ -488,9 +497,156 @@ class WarrantyController extends APIController
}
$em->persist($warr);
$em->flush();
return new APIResponse(true, 'Privacy policy for warranty set successfully.');
}
protected function getCustomerFromMobile($em, $warranty)
{
$w_mobile = $warranty->getMobileNumber();
if (empty($w_mobile))
{
return null;
}
// set values for new customer vehicle
$w_plate_number = $this->cleanPlateNumber($warranty->getPlateNumber());
$cust_found = false;
$w_mobile_num = trim($w_mobile);
// does it fit our 09XXXXXXXXX pattern?
if (preg_match('/^09[0-9]{9}$/', $w_mobile_num))
{
// remove first '0'
$w_mobile_num = substr($w_mobile_num, 1);
error_log("CONVERTED TO $w_mobile_num");
}
// does it fit our 9XXXXXXXXX pattern?
if (!preg_match('/^9[0-9]{9}$/', $w_mobile_num))
return null;
/*
// min length 2
// TODO: we need to check proper phone number format
// format should be '9XXXXXXXXX'
// TODO: if format doesn't fit and there's a 0 or 63 prefix, we should be able to detect and convert
if (strlen($w_mobile_num <= 2))
continue;
*/
$customers = $this->findCustomerByNumber($em, $w_mobile_num);
if (!empty($customers))
{
error_log('found customer for ' . $w_mobile_num);
foreach ($customers as $customer)
{
// get customer vehicles for customer
$c_vehicles = $customer->getVehicles();
$cv_found = false;
if (!empty($c_vehicles))
{
// check if plate number of customer vehicle matches warranty plate number
foreach ($c_vehicles as $c_vehicle)
{
$clean_cv_plate = $this->cleanPlateNumber($c_vehicle->getPlateNumber());
// check if it's already there
if ($clean_cv_plate == $w_plate_number)
{
// customer and customer vehicle already exists
$cv_found = true;
break;
}
}
}
// if there was a customer vehicle matched
if ($cv_found)
{
// vehicle found, do nothing.
error_log('vehicle found - ' . $w_plate_number);
}
else
{
// customer exists but not customer vehicle
// add customer vehicle to existing customer with unknown manufacturer and make
error_log('new vehicle - ' . $w_plate_number);
$this->createCustomerVehicle($em, $customer, $this->getDefaultVehicle($em), $w_plate_number);
}
}
}
// customer not found
else
{
error_log('NEW customer and vehicle - ' . $w_plate_number);
// customer not found, add customer and customer vehicle
// get warranty first name, last name
$w_first_name = $warranty->getFirstName();
$w_last_name = $warranty->getLastName();
$new_cust = new Customer();
$new_cust->setFirstName($w_first_name)
->setLastName($w_last_name)
->setPhoneMobile($w_mobile_num);
$em->persist($new_cust);
$this->createCustomerVehicle($em, $new_cust, $this->getDefaultVehicle($em), $w_plate_number);
}
$em->flush();
$em->clear();
}
protected function getDefaultVehicle($em)
{
// get default vehicle
$cvu_brand_id = $this->getParameter('cvu_brand_id');
$default_vehicle = $em->getRepository(Vehicle::class)->find($cvu_brand_id);
if ($default_vehicle == null)
{
$output->writeln("Need to add vehicle with default values.");
return null;
}
return $default_vehicle;
}
protected function cleanPlateNumber($plate)
{
// remove spaces and make upper case
return strtoupper(str_replace(' ', '', $plate));
}
protected function createCustomerVehicle($em, Customer $cust, $vehicle, $plate_number)
{
$new_cv = new CustomerVehicle();
$new_cv->setCustomer($cust)
->setPlateNumber($plate_number)
->setStatusCondition(VehicleStatusCondition::BRAND_NEW)
->setModelYear('')
->setColor('')
->setFuelType(FuelType::GAS)
->setHasMotoliteBattery(true)
->setVehicle($vehicle);
$em->persist($new_cv);
}
protected function findCustomerByNumber($em, $number)
{
$customers = $em->getRepository(Customer::class)->findBy(['phone_mobile' => $number]);
return $customers;
}
}

View file

@ -14,6 +14,8 @@ use App\Entity\Warranty;
use App\Entity\CustomerVehicle;
use App\Entity\MobileSession;
use App\Entity\Customer;
use App\Entity\BatteryModel;
use App\Entity\BatterySize;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
@ -27,7 +29,6 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Dotenv\Dotenv;
use Catalyst\MenuBundle\Annotation\Menu;
@ -36,6 +37,8 @@ use DateTime;
class ReportController extends Controller
{
const PREREGISTER_PREFIX = '9';
/**
* @Menu(selected="outlet_list")
*/
@ -474,6 +477,7 @@ class ReportController extends Controller
'Plate Number',
'Warranty Create Date',
'Activation Status',
'Warranty Class',
'Has Mobile App?',
'Date Mobile App Downloaded',
'Mobile Number Using Mobile App',
@ -546,6 +550,181 @@ class ReportController extends Controller
return $resp;
}
/**
* @Menu(selected="outlet_list")
*/
public function warrantyClassForm()
{
$this->denyAccessUnlessGranted('report.warranty.class', null, 'No access.');
$params['mode'] = 'form';
return $this->render('report/warranty-class/form.html.twig', $params);
}
/**
* @Menu(selected="outlet_list")
*/
public function warrantyClassExportCSV(Request $req, EntityManagerInterface $em)
{
$data = $this->getWarrantyClassData($em);
$resp = new StreamedResponse();
$resp->setCallback(function() use ($data) {
// csv output
$csv_handle = fopen('php://output', 'w+');
fputcsv($csv_handle, [
'Customer Last Name',
'Customer First Name',
'Vehicle Manufacturer',
'Vehicle Make',
'Model Year',
'Vehicle Color',
'Warranty Serial',
'Warranty Class',
'Plate Number',
'Warranty Last Name',
'Warranty First Name',
'Warranty Mobile Number',
'Warranty Battery Model',
'Warranty Battery Size',
'Warranty SAP Battery',
'Warranty Status',
'Warranty Created',
'Warranty Purchased',
'Warranty Expiry Date',
'Warranty Claim Date',
'Warranty Claimed From',
'Warranty Privacy Policy',
'Is Warranty Activated?',
]);
foreach ($data as $row)
{
fputcsv($csv_handle, $row);
}
fclose($csv_handle);
});
$filename = 'warranty_class_report' . '.csv';
$resp->setStatusCode(200);
$resp->headers->set('Content-Type', 'text/csv; charset=utf-8');
$resp->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"');
return $resp;
}
/**
* @Menu(selected="outlet_list")
*/
public function vehicleBatteryCompatibilityForm()
{
$this->denyAccessUnlessGranted('report.vehicle.battery.compatibility', null, 'No access.');
$params['mode'] = 'form';
return $this->render('report/vehicle-battery-compatibility/form.html.twig', $params);
}
/**
* @Menu(selected="outlet_list")
*/
public function vehicleBatteryCompatibilityExportCSV(Request $req, EntityManagerInterface $em)
{
$data = $this->getVehicleBatteryCompatibilityData($em);
$resp = new StreamedResponse();
$resp->setCallback(function() use ($data) {
// csv output
$csv_handle = fopen('php://output', 'w+');
fputcsv($csv_handle, [
'Vehicle Manufacturer',
'Vehicle Make',
'Vehicle Model Year From',
'Vehicle Model Year To',
'Battery Manufacturer',
'Battery Model',
'Battery Size',
'Battery SAP Code',
]);
foreach ($data as $row)
{
fputcsv($csv_handle, $row);
}
fclose($csv_handle);
});
$filename = 'vehicle_battery_compatibility_report' . '.csv';
$resp->setStatusCode(200);
$resp->headers->set('Content-Type', 'text/csv; charset=utf-8');
$resp->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"');
return $resp;
}
/**
* @Menu(selected="outlet_list")
*/
public function warrantyDetailsForm()
{
$this->denyAccessUnlessGranted('report.warranty.details', null, 'No access.');
$params['mode'] = 'form';
return $this->render('report/warranty-details/form.html.twig', $params);
}
/**
* @Menu(selected="outlet_list")
*/
public function warrantyDetailsExportCSV(Request $resq, EntityManagerInterface $em)
{
$data = $this->getWarrantyDetailsData($em);
$resp = new StreamedResponse();
$resp->setCallback(function() use ($data) {
// csv output
$csv_handle = fopen('php://output', 'w+');
fputcsv($csv_handle, [
'Warranty ID',
'Serial',
'Battery Model',
'Battery Size',
'Warranty Class',
'Plate Number',
'Status',
'Date Created',
'Date Purchased',
'Expiry Date',
'Date Claimed',
'SAP Battery ID',
'Claim ID',
'Last Name',
'First Name',
'Mobile Number',
'Privacy Policy Number',
'Activated?',
]);
foreach ($data as $row)
{
fputcsv($csv_handle, $row);
}
fclose($csv_handle);
});
$filename = 'warranty_details_report' . '.csv';
$resp->setStatusCode(200);
$resp->headers->set('Content-Type', 'text/csv; charset=utf-8');
$resp->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"');
return $resp;
}
protected function processPopappFile(UploadedFile $csv_file, EntityManagerInterface $em)
{
// attempt to open file
@ -588,6 +767,7 @@ class ReportController extends Controller
'plate_num' => '',
'warr_date_create' => '',
'warr_activation_status' => '',
'warr_class' => '',
'has_mobile' => '',
'date_mobile' => '',
'mobile_number' => '',
@ -605,66 +785,68 @@ class ReportController extends Controller
if (!empty($serial))
{
// get the warranty for serial
$warr_qb = $this->getDoctrine()
->getRepository(Warranty::class)
->createQueryBuilder('q');
$warranty_query = $warr_qb->select('q')
->where('q.serial = :serial')
->setParameter('serial', $serial);
$warranty = $warranty_query->getQuery()->getOneOrNullResult();
$warranties = $em->getRepository(Warranty::class)->findBy(['serial' => $serial]);
if ($warranty != null)
if (!empty($warranties))
{
$isValid = InvalidPlateNumber::isInvalid($warranty->getPlateNumber());
if ($isValid)
foreach ($warranties as $warranty)
{
// get customer vehicles using plate number
$customer_vehicles = $em->getRepository(CustomerVehicle::class)->findBy(['plate_number' => $warranty->getPlateNumber()]);
// check if customer vehicle is empty
if (count($customer_vehicles) != 0)
//error_log('found warranty for serial ' . $serial);
$plate_number = $warranty->getPlateNumber();
$isValid = InvalidPlateNumber::isInvalid($plate_number);
if ($isValid)
{
$has_mobile = false;
$mobile_date = '';
$mobile_number = '';
// get the first customer vehicle, store as best_cv until we find one with a mobile session
$best_cv = current($customer_vehicles);
foreach($customer_vehicles as $cv)
// get customer vehicles using plate number
$customer_vehicles = $em->getRepository(CustomerVehicle::class)->findBy(['plate_number' => $plate_number]);
// check if customer vehicle is empty
if (count($customer_vehicles) != 0)
{
// get mobile session of customer
//error_log($cv->getCustomer()->getLastName() . ' ' . $cv->getCustomer()->getFirstName());
$mobile_session = $em->getRepository(MobileSession::class)
->findOneBy(['customer' => $cv->getCustomer()->getID()], ['date_generated' => 'ASC']);
if ($mobile_session != null)
//error_log('found customer vehicle for plate number ' . $plate_number);
$has_mobile = false;
$mobile_date = '';
$mobile_number = '';
// get the first customer vehicle, store as best_cv until we find one with a mobile session
$best_cv = current($customer_vehicles);
foreach($customer_vehicles as $cv)
{
// get mobile data
$has_mobile = true;
$mobile_date = $mobile_session->getDateGenerated()->format("d M Y");
$mobile_number = $mobile_session->getPhoneNumber();
// get mobile session of customer
//error_log($cv->getCustomer()->getLastName() . ' ' . $cv->getCustomer()->getFirstName());
$cust_id = $cv->getCustomer()->getID();
$mobile_session = $em->getRepository(MobileSession::class)
->findOneBy(['customer' => $cust_id], ['date_generated' => 'ASC']);
if ($mobile_session != null)
{
// get mobile data
//error_log('found mobile session for customer id ' . $cv->getCustomer()->getID());
$has_mobile = true;
$mobile_date = $mobile_session->getDateGenerated()->format("d M Y");
$mobile_number = $mobile_session->getPhoneNumber();
// set best_cv to this customer vehicle with mobile session
$best_cv = $cv;
// set best_cv to this customer vehicle with mobile session
$best_cv = $cv;
}
}
// set the customer data in results
$results[$key]['cust_id'] = $best_cv->getCustomer()->getID();
$results[$key]['cust_lastname'] = $best_cv->getCustomer()->getLastName();
$results[$key]['cust_firstname'] = $best_cv->getCustomer()->getFirstName();
$results[$key]['cust_mobile_number'] = $best_cv->getCustomer()->getPhoneMobile();
$results[$key]['plate_num'] = $best_cv->getPlateNumber();
$results[$key]['has_mobile'] = ($has_mobile ? 'Yes' : 'No');
$results[$key]['date_mobile'] = $mobile_date;
$results[$key]['mobile_number'] = $mobile_number;
}
// set the customer data in results
$results[$key]['cust_id'] = $best_cv->getCustomer()->getID();
$results[$key]['cust_lastname'] = $best_cv->getCustomer()->getLastName();
$results[$key]['cust_firstname'] = $best_cv->getCustomer()->getFirstName();
$results[$key]['cust_mobile_number'] = $best_cv->getCustomer()->getPhoneMobile();
$results[$key]['plate_num'] = $best_cv->getPlateNumber();
$results[$key]['has_mobile'] = ($has_mobile ? 'Yes' : 'No');
$results[$key]['date_mobile'] = $mobile_date;
$results[$key]['mobile_number'] = $mobile_number;
}
// set the warranty data in results
$results[$key]['warr_lastname'] = $warranty->getLastName();
$results[$key]['warr_firstname'] = $warranty->getFirstName();
$results[$key]['warr_date_create'] = $warranty->getDateCreate()->format("d M Y");
$results[$key]['warr_activation_status'] = ($warranty->isActivated() ? 'Active' : 'Inactive');
$results[$key]['warr_class'] = $warranty->getWarrantyClass();
}
// set the warranty data in results
$results[$key]['warr_lastname'] = $warranty->getLastName();
$results[$key]['warr_firstname'] = $warranty->getFirstName();
$results[$key]['warr_date_create'] = $warranty->getDateCreate()->format("d M Y");
$results[$key]['warr_activation_status'] = ($warranty->isActivated() ? 'Active' : 'Inactive');
}
}
}
@ -719,6 +901,265 @@ class ReportController extends Controller
}
return $results;
}
protected function getWarrantyClassData(EntityManagerInterface $em)
{
$results = [];
// query preregistered ustomers using search term '%9'
$cust_query = $em->createQuery('select c from App\Entity\Customer c where c.phone_mobile like :search_mobile')
->setParameter('search_mobile', "%" . self::PREREGISTER_PREFIX);
$customers = $cust_query->iterate();
foreach($customers as $crow)
{
$cust = $crow[0];
//error_log('Processing customer ' . $cust->getID());
// get list of customer vehicles
$c_vehicles = $cust->getVehicles();
foreach($c_vehicles as $cv)
{
if (!empty($c_vehicles))
{
// find warranty for plate number
$clean_cv_plate = $this->cleanPlateNumber($cv->getPlateNumber());
$warranties = $em->getRepository(Warranty::class)->findBy(['plate_number' => $clean_cv_plate]);
foreach ($warranties as $warr)
{
//error_log('Found warranty for plate number ' . $warr->getPlateNumber());
// form the result row
$results[] = $this->formWarrantyClassResult($cust, $cv, $warr);
}
}
}
$em->clear();
}
return $results;
}
protected function cleanPlateNumber($plate)
{
// remove spaces and make upper case
return strtoupper(str_replace(' ', '', $plate));
}
protected function formWarrantyClassResult($cust, $cv, $warr)
{
$batt_model = '';
$batt_size = '';
$sap_batt = '';
$policy = '';
$date_purchased = '';
$date_expire = '';
$date_claim = '';
$create_date = $warr->getDateCreate();
$date_create = $create_date->format('d/M/y');
if ($warr->getDatePurchase() != null)
{
$p_date = $warr->getDatePurchase();
$date_purchased = $p_date->format('d/M/y');
}
if ($warr->getDateClaim() != null)
{
$c_date = $warr->getDateClaim();
$date_claim = $c_date->format('d/M/y');
}
if ($warr->getDateExpire() != null)
{
$e_date = $warr->getDateExpire();
$date_expire = $e_date->format('d/M/y');
}
if ($warr->getBatteryModel() != null)
{
$batt_model = $warr->getBatteryModel()->getName();
}
if ($warr->getBatterySize() != null)
{
$batt_size = $warr->getBatterySize()->getName();
}
if ($warr->getSAPBattery() != null)
{
$sap_batt = $warr->getSAPBattery()->getBrand()->getName();
}
if ($warr->getPrivacyPolicy() != null)
{
$policy = $warr->getPrivacyPolicy()->getName();
}
$data = [
'c_last_name' => $cust->getLastName(),
'c_first_name' => $cust->getFirstName(),
'manufacturer' => $cv->getVehicle()->getManufacturer()->getName(),
'make' => $cv->getVehicle()->getMake(),
'model_year' => $cv->getModelYear(),
'color' => $cv->getColor(),
'serial' => $warr->getSerial(),
'class' => $warr->getWarrantyClass(),
'plate_number' => $warr->getPlateNumber(),
'w_last_name' => $warr->getLastName(),
'w_first_name' => $warr->getFirstName(),
'w_mobile_num' => $warr->getMobileNumber(),
'w_batt_model' => $batt_model,
'w_batt_size' => $batt_size,
'w_sap_batt' => $sap_batt,
'w_status' => $warr->getStatus(),
'w_date_create' => $date_create,
'w_date_purchase' => $date_purchased,
'w_date_expire' => $date_expire,
'w_date_claim' => $date_claim,
'w_claimed_from' => $warr->getClaimedFrom(),
'w_privacy_policy' => $policy,
'w_activated' => ($warr->isActivated() ? 'Active' : 'Inactive'),
];
return $data;
}
protected function getVehicleBatteryCompatibilityData(EntityManagerInterface $em)
{
$results = [];
$conn = $em->getConnection();
$sql = 'SELECT vm.name AS vm_name, v.make,
v.model_year_from, v.model_year_to,
bm.name AS bm_name, bmodel.name AS bmodel_name,
bsize.name AS bsize_name,
b.sap_code
FROM vehicle_manufacturer vm, vehicle v, battery_vehicle bv,
battery b, battery_manufacturer bm, battery_model bmodel,
battery_size bsize
WHERE vm.id = v.manufacturer_id
AND v.id = bv.vehicle_id
AND bv.battery_id = b.id
AND b.manufacturer_id = bm.id
AND b.model_id = bmodel.id
AND b.size_id = bsize.id
ORDER BY vm.name, v.make';
$stmt = $conn->prepare($sql);
$stmt->execute();
$query_results = $stmt->fetchAll();
foreach($query_results as $row)
{
$results[] = [
'vehicle_manufacturer' => $row['vm_name'],
'vehicle_make' => $row['make'],
'vehicle_model_year_from' => $row['model_year_from'],
'vehicle_model_year_to' => $row['model_year_to'],
'battery_manufacturer' => $row['bm_name'],
'battery_model' => $row['bmodel_name'],
'battery_size' => $row['bsize_name'],
'battery_sap_code' => $row['sap_code'],
];
}
return $results;
}
protected function getWarrantyDetailsData(EntityManagerInterface $em)
{
$bm_hash = $this->loadBatteryModels($em);
$bs_hash = $this->loadBatterySizes($em);
$results = [];
$conn = $em->getConnection();
$sql = 'SELECT w.id, w.serial, w.warranty_class, w.plate_number,
w.status, w.date_create, w.date_purchase, w.date_expire,
w.date_claim, w.sap_bty_id, w.claim_id, w.first_name,
w.last_name, w.mobile_number, w.flag_activated,
w.warranty_privacy_policy, w.bty_model_id, w.bty_size_id
FROM warranty w';
$stmt = $conn->prepare($sql);
$stmt->execute();
$query_results = $stmt->fetchAll();
foreach ($query_results as $row)
{
// get battery model and size names
$bmodel_name = '';
$bm_id = $row['bty_model_id'];
if (!empty($bm_id))
{
if (isset($bm_hash[$bm_id]))
$bmodel_name = $bm_hash[$bm_id];
}
$bsize_name = '';
$bs_id = $row['bty_size_id'];
if (!empty($bs_id))
{
if (isset($bs_hash[$bs_id]))
$bsize_name = $bs_hash[$bs_id];
}
$results[] = [
'id' => $row['id'],
'serial' => $row['serial'],
'battery_model' => $bmodel_name,
'battery_size' => $bsize_name,
'warranty_class' => $row['warranty_class'],
'plate_number' => $row['plate_number'],
'status' => $row['status'],
'date_create' => $row['date_create'],
'date_purchase' => $row['date_purchase'],
'date_expire' => $row['date_expire'],
'date_claim' => $row['date_claim'],
'sap_bty_id' => $row['sap_bty_id'],
'claim_id' => $row['claim_id'],
'last_name' => $row['last_name'],
'first_name' => $row['first_name'],
'mobile_number' => $row['mobile_number'],
'privacy_policy' => $row['warranty_privacy_policy'],
'flag_activated' => (boolean) $row['flag_activated'],
];
}
return $results;
}
protected function loadBatteryModels(EntityManagerInterface $em)
{
$bmodel_hash = [];
$models = $em->getRepository(BatteryModel::class)->findAll();
foreach ($models as $model)
{
$bmodel_id = $model->getID();
$bmodel_hash[$bmodel_id] = $model->getName();
}
return $bmodel_hash;
}
protected function loadBatterySizes(EntityManagerInterface $em)
{
$bsize_hash = [];
$sizes = $em->getRepository(BatterySize::class)->findAll();
foreach ($sizes as $size)
{
$bsize_id = $size->getID();
$bsize_hash[$bsize_id] = $size->getName();
}
return $bsize_hash;
}
}

View file

@ -0,0 +1,289 @@
<?php
namespace App\Controller;
use App\Entity\StaticContent;
use Doctrine\ORM\Query;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Catalyst\MenuBundle\Annotation\Menu;
class StaticContentController extends Controller
{
/**
* @Menu(selected="static_content_list")
*/
public function index()
{
$this->denyAccessUnlessGranted('static_content.list', null, 'No access.');
return $this->render('static-content/list.html.twig');
}
public function rows(Request $req)
{
$this->denyAccessUnlessGranted('static_content.list', null, 'No access.');
// build query
$qb = $this->getDoctrine()
->getRepository(StaticContent::class)
->createQueryBuilder('q');
// get datatable params
$datatable = $req->request->get('datatable');
// count total records
$tquery = $qb->select('COUNT(q)');
// add fitlers 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.id', 'asc');
}
// get rows for this page
$obj_rows = $query->setFirstResult($offset)
->setMaxResults($perpage)
->getQuery()
->getResult();
// process rows
$rows = [];
foreach ($obj_rows as $orow) {
// add row data
$row['id'] = $orow->getID();
// add row metadata
$row['meta'] = [
'update_url' => '',
'delete_url' => ''
];
// add crud urls
if ($this->isGranted('static_content.update'))
$row['meta']['update_url'] = $this->generateUrl('static_content_update', ['id' => $row['id']]);
if ($this->isGranted('static_content.delete'))
$row['meta']['delete_url'] = $this->generateUrl('static_content_delete', ['id' => $row['id']]);
$rows[] = $row;
}
// response
return $this->json([
'meta' => $meta,
'data' => $rows
]);
}
/**
* @Menu(selected="static_content_list")
*/
public function addForm()
{
$this->denyAccessUnlessGranted('static_content.add', null, 'No access.');
$params = [];
$params['obj'] = new StaticContent();
$params['mode'] = 'create';
// response
return $this->render('static-content/form.html.twig', $params);
}
public function addSubmit(Request $req, ValidatorInterface $validator)
{
$this->denyAccessUnlessGranted('static_content.add', null, 'No access.');
// create new object
$em = $this->getDoctrine()->getManager();
$row = new StaticContent();
// set and save values
$id = $req->request->get('id');
$row->setID($id);
$row->setContent($req->request->get('content'));
// validate
$errors = $validator->validate($row);
// initialize error list
$error_array = [];
// check for duplicate ID
$result = $em->getRepository(StaticContent::class)->find($id);
if ($result != null)
{
error_log($id);
$error_array['id'] = 'Duplicate ID exists.';
}
// add errors to list
foreach ($errors as $error) {
$error_array[$error->getPropertyPath()] = $error->getMessage();
}
// check if any errors were found
if (!empty($error_array)) {
// return validation failure response
return $this->json([
'success' => false,
'errors' => $error_array
], 422);
} else {
// validated! save the entity
$em->persist($row);
$em->flush();
// return successful response
return $this->json([
'success' => 'Changes have been saved!'
]);
}
}
/**
* @Menu(selected="static_content_list")
*/
public function updateForm($id)
{
$this->denyAccessUnlessGranted('static_content.update', null, 'No access.');
$params = [];
$params['mode'] = 'update';
// get row data
$em = $this->getDoctrine()->getManager();
$row = $em->getRepository(StaticContent::class)->find($id);
// make sure this row exists
if (empty($row))
throw $this->createNotFoundException('The item does not exist');
$params['obj'] = $row;
// response
return $this->render('static-content/form.html.twig', $params);
}
public function updateSubmit(Request $req, ValidatorInterface $validator, $id)
{
$this->denyAccessUnlessGranted('static_content.update', null, 'No access.');
// get row data
$em = $this->getDoctrine()->getManager();
$row = $em->getRepository(StaticContent::class)->find($id);
// make sure this row exists
if (empty($row))
throw $this->createNotFoundException('The item does not exist');
// set and save values
$row->setID($req->request->get('id'))
->setContent($req->request->get('content'));
// validate
$errors = $validator->validate($row);
// initialize error list
$error_array = [];
// check for duplicate ID
$result = $em->getRepository(StaticContent::class)->find($id);
if ($result != null)
{
error_log($id);
$error_array['id'] = 'Duplicate ID exists.';
}
// add errors to list
foreach ($errors as $error) {
$error_array[$error->getPropertyPath()] = $error->getMessage();
}
// check if any errors were found
if (!empty($error_array)) {
// return validation failure response
return $this->json([
'success' => false,
'errors' => $error_array
], 422);
} else {
// validated! save the entity
$em->flush();
// return successful response
return $this->json([
'success' => 'Changes have been saved!'
]);
}
}
/**
* @Menu(selected="static_content_list")
*/
public function destroy($id)
{
$this->denyAccessUnlessGranted('static_content.delete', null, 'No access.');
$params = [];
// get row data
$em = $this->getDoctrine()->getManager();
$row = $em->getRepository(StaticContent::class)->find($id);
if (empty($row))
throw $this->createNotFoundException('The item does not exist');
// delete this row
$em->remove($row);
$em->flush();
// response
$response = new Response();
$response->setStatusCode(Response::HTTP_OK);
$response->send();
}
protected function setQueryFilters($datatable, &$query)
{
if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) {
$query->where('q.name LIKE :filter')
->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%');
}
}
}

View file

@ -4,15 +4,23 @@ namespace App\Controller;
use App\Entity\Warranty;
use App\Entity\SAPBattery;
use App\Entity\Battery;
use App\Entity\BatteryModel;
use App\Entity\BatterySize;
use App\Entity\Invoice;
use App\Entity\CustomerVehicle;
use App\Ramcar\WarrantyClass;
use App\Ramcar\WarrantyStatus;
use App\Service\WarrantyHandler;
use Doctrine\ORM\Query;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
@ -22,6 +30,11 @@ use Catalyst\MenuBundle\Annotation\Menu;
class WarrantyController extends Controller
{
const PURCHASE_DATE_EMPTY = 'Purchase date missing.';
const PLATE_NUM_EMPTY = 'Plate number missing.';
const SERIAL_EMPTY = 'Serial number missing.';
const PURCHASE_DATE_INVALID = 'Invalid purchase date.';
/**
* @Menu(selected="warranty_list")
*/
@ -348,9 +361,239 @@ class WarrantyController extends Controller
'success' => 'Changes have been saved!'
]);
}
}
/**
* @Menu(selected="warranty_list")
*/
public function uploadForm()
{
$this->denyAccessUnlessGranted('warranty.upload', null, 'No access.');
return $this->render('warranty/upload.form.html.twig');
}
/**
* @Menu(selected="warranty_list")
*/
public function uploadSubmit(Request $req, EntityManagerInterface $em,
WarrantyHandler $wh)
{
// retrieve temporary info for file
$file = $req->files->get('csv_file');
// process the csv file
$inv_entries = $this->processWarrantyFile($file, $em, $wh);
$resp = new StreamedResponse();
$resp->setCallback(function() use($inv_entries) {
// csv output
$csv_handle = fopen('php://output', 'w+');
fputcsv($csv_handle, [
'Owner First Name',
'Owner Last Name',
'Owner Email',
'Owner Address',
'Owner Mobile',
'Owner Telephone',
'Vehicle Make',
'Vehicle Model',
'Vehicle Year',
'Vehicle Plate Number',
'Battery Serial Number',
'Battery Sales Invoice',
'Battery Date of Purchase',
'Distributor Name',
'Distributor Address',
'Application Type ID',
'Battery ID',
'Ownership Type',
'Reason Warranty Not Added',
]);
foreach ($inv_entries as $row)
{
fputcsv($csv_handle, $row);
}
fclose($csv_handle);
});
$filename = 'invalid_warranties' . '.csv';
$resp->setStatusCode(200);
$resp->headers->set('Content-Type', 'text/csv; charset=utf-8');
$resp->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"');
return $resp;
}
protected function processWarrantyFile(UploadedFile $csv_file, EntityManagerInterface $em,
WarrantyHandler $wh)
{
// attempt to open file
try
{
$fh = fopen($csv_file, "r");
}
catch (Exception $e)
{
throw new Exception('The file "' . $csv_file . '" could be read.');
}
// loop through the rows
// 0 - Owner First Name
// 1 - Owner Last Name
// 2 - Owner Email
// 3 - Owner Address
// 4 - Owner Mobile
// 5 - Owner Telephone
// 6 - Vehicle Make
// 7 - Vehicle Model
// 8 - Vehicle Year
// 9 - Vehicle Plate Number
// 10 - Battery Serial Number
// 11 - Battery Sales Invoice
// 12 - Battery Date of Purchase
// 13 - Distributor Name
// 14 - Distributor Address
// 15 - Application Type ID
// 16 - Battery ID
// 17 - Ownership Type
$row_num = 0;
$invalid_entries = [];
while (($fields = fgetcsv($fh)) !== false)
{
// start processing at row 1, not 0
if ($row_num < 1)
{
$row_num++;
continue;
}
// get the data
$first_name = trim($fields[0]);
$last_name = trim($fields[1]);
$mobile_number = trim($fields[4]);
$plate = trim($fields[9]);
$serial = trim($fields[10]);
$purchase_date = trim($fields[12]);
$battery_id = trim($fields[16]);
$batt_invoice = trim($fields[11]);
$plate_number = $wh->cleanPlateNumber($plate);
// check if purchase_date or plate_number or serial is empty or if
// purchase date is valid
$date_purchase = DateTime::createFromFormat('d-M-y', $purchase_date);
if (empty($purchase_date) ||
empty($plate_number) ||
empty($serial) ||
($date_purchase == false))
{
$reason = '';
if (empty($plate_number))
$reason = $reason . self::PLATE_NUM_EMPTY . ' ';
if (empty($serial))
$reason = $reason . self::SERIAL_EMPTY . ' ';
if (empty($purchase_date))
$reason = $reason . self::PURCHASE_DATE_EMPTY . ' ';
else
{
if ($date_purchase == false)
$reason = $reason . self::PURCHASE_DATE_INVALID . ' ';
}
// add to invalid_entries
$invalid_entries[] = [
'owner_first_name' => $first_name,
'owner_last_name' => $last_name,
'owner_email' => trim($fields[2]),
'owner_address' => trim($fields[3]),
'owner_mobile' => $mobile_number,
'owner_telephone' => trim($fields[5]),
'vehicle_make' => trim($fields[6]),
'vehicle_model' => trim($fields[7]),
'vehicle_year' => trim($fields[8]),
'vehicle_plate_number' => $plate_number,
'battery_serial_number' => $serial,
'battery_sales_invoice' => $batt_invoice,
'battery_date_purchase' => $purchase_date,
'distributor_name' => trim($fields[13]),
'distributor_address' => trim($fields[14]),
'application_type_id' => trim($fields[15]),
'battery_id' => $battery_id,
'ownership_type' => trim($fields[17]),
'reason' => $reason,
];
}
else
{
// additional validation
// check if serial number and plate number already exists
$warr_results = $em->getRepository(Warranty::class)->findBy(['serial' => $serial, 'plate_number' => $plate_number]);
// get battery via the invoice because battery_id doesn't match what's in the live data
// get job order via invoice to get the warranty class
$warranty_class = '';
$batt_list = array();
// find invoice
$invoice = $em->getRepository(Invoice::class)->find($batt_invoice);
if (!empty($invoice))
{
// get job order
$jo = $invoice->getJobOrder();
// get warranty class
$warranty_class = $jo->getWarrantyClass();
// get battery
$invoice_items = $invoice->getItems();
foreach ($invoice_items as $item)
{
$battery = $item->getBattery();
if ($battery != null)
{
$batt_list[] = $item->getBattery();
}
}
}
if (!empty($warr_results))
{
foreach($warr_results as $warr)
{
// call service to check if warranty details is incomplete and then update warranty
// using details from csv file
error_log('Updating warranty for ' . $warr->getID());
$wh->updateWarranty($warr, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase);
}
}
else
{
// TODO: what if serial exists but plate number is different?
// check if just the serial exists
// if warranty exists, ignore for now
$w_results = $em->getRepository(Warranty::class)->findBy(['serial' => $serial]);
if (!empty($w_results))
{
continue;
}
error_log('Creating warranty for serial ' . $serial . ' and plate number ' . $plate_number);
$wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class);
}
}
$em->clear();
$row_num++;
}
return $invalid_entries;
}
protected function fillDropdownParameters(&$params)
{
@ -371,4 +614,10 @@ class WarrantyController extends Controller
->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%');
}
}
protected function cleanPlateNumber($plate)
{
// remove spaces and make upper case
return strtoupper(str_replace(' ', '', $plate));
}
}

View file

@ -68,6 +68,7 @@ class BatteryModel
public function getBatteries()
{
// TODO: fix this to be a proper getter function
// has to return set of strings because symfony is trying to move away from role objects
$str_batteries = [];
foreach ($this->batteries as $battery)

View file

@ -89,6 +89,7 @@ class BatterySize
public function getBatteries()
{
// TODO: fix this to be a proper getter function
// has to return set of strings because symfony is trying to move away from role objects
$str_batteries = [];
foreach ($this->batteries as $battery)

View file

@ -10,13 +10,10 @@ use App\Ramcar\CustomerClassification;
/**
* @ORM\Entity
* @ORM\Table(name="customer")
* @ORM\Table(name="customer", indexes={@ORM\Index(name="phone_mobile_idx", columns={"phone_mobile"})})
*/
class Customer
{
// TODO: make this a setting somewhere
const COUNTRY_CODE_PREFIX = '+60';
// unique id
/**
* @ORM\Id
@ -266,16 +263,16 @@ class Customer
$phones = [];
if (!empty($this->phone_mobile))
$phones[] = self::COUNTRY_CODE_PREFIX . $this->phone_mobile;
$phones[] = $this->phone_mobile;
if (!empty($this->phone_landline))
$phones[] = self::COUNTRY_CODE_PREFIX . $this->phone_landline;
$phones[] = $this->phone_landline;
if (!empty($this->phone_office))
$phones[] = self::COUNTRY_CODE_PREFIX . $this->phone_office;
$phones[] = $this->phone_office;
if (!empty($this->phone_fax))
$phones[] = self::COUNTRY_CODE_PREFIX . $this->phone_fax;
$phones[] = $this->phone_fax;
return $phones;
}

View file

@ -10,7 +10,8 @@ use DateTime;
/**
* @ORM\Entity
* @ORM\Table(name="customer_vehicle", indexes={@ORM\Index(columns={"plate_number"}, flags={"fulltext"})})
* @ORM\Table(name="customer_vehicle", indexes={@ORM\Index(columns={"plate_number"}, flags={"fulltext"}),
@ORM\Index(name="plate_number_idx", columns={"plate_number"})})
*/
class CustomerVehicle
{
@ -54,7 +55,6 @@ class CustomerVehicle
// model year
/**
* @ORM\Column(type="smallint")
* @Assert\NotBlank()
*/
protected $model_year;

View file

@ -0,0 +1,54 @@
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity
* @ORM\Table(name="static_content")
*/
class StaticContent
{
// unique id
/**
* @ORM\Id
* @ORM\Column(type="string", length=50)
* @Assert\NotBlank()
*/
protected $id;
// content
/**
* @ORM\Column(type="text")
*/
protected $content;
public function __construct()
{
}
public function setID($id)
{
$this->id = $id;
return $this;
}
public function getID()
{
return $this->id;
}
public function setContent($content)
{
$this->content = $content;
return $this;
}
public function getContent()
{
return $this->content;
}
}

View file

@ -14,7 +14,8 @@ use Exception;
* name="warranty",
* uniqueConstraints={
* @ORM\UniqueConstraint(columns={"serial"})
* }
* },
* indexes={@ORM\Index(name="plate_number_idx", columns={"plate_number"})})
* )
*/
class Warranty

View file

@ -25,17 +25,17 @@ use DateTime;
class CMBCustomerHandler implements CustomerHandlerInterface
{
const COUNTRY_CODE_PREFIX = '+60';
protected $em;
protected $validator;
protected $country_code;
protected $template_hash;
public function __construct(EntityManagerInterface $em, ValidatorInterface $validator)
public function __construct(EntityManagerInterface $em, ValidatorInterface $validator,
string $country_code)
{
$this->em = $em;
$this->validator = $validator;
$this->country_code = $country_code;
$this->loadTemplates();
}
@ -121,7 +121,14 @@ class CMBCustomerHandler implements CustomerHandlerInterface
$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());
// prepend the country code before each mobile number
$mobile_number_list = [];
$mobile_numbers = $orow->getMobileNumberList();
foreach ($mobile_numbers as $mobile_number)
{
$mobile_number_list[] = $this->country_code . $mobile_number;
}
$row['mobile_numbers'] = implode("<br>", $mobile_number_list);
$row['plate_numbers'] = implode("<br>", $orow->getPlateNumberList());
$rows[] = $row;
@ -467,7 +474,7 @@ class CMBCustomerHandler implements CustomerHandlerInterface
$cust = $cv->getCustomer();
$vehicles[] = [
'id' => $cv->getID(),
'text' => $cv->getPlateNumber() . ' ' . $cust->getFirstName() . ' ' . $cust->getLastName() . ' ('. self::COUNTRY_CODE_PREFIX . $cust->getPhoneMobile() . ')',
'text' => $cv->getPlateNumber() . ' ' . $cust->getFirstName() . ' ' . $cust->getLastName() . ' ('. $this->country_code . $cust->getPhoneMobile() . ')',
];
}

View file

@ -27,17 +27,17 @@ use DateTime;
class ResqCustomerHandler implements CustomerHandlerInterface
{
const COUNTRY_CODE_PREFIX = '+63';
protected $em;
protected $validator;
protected $country_code;
protected $template_hash;
public function __construct(EntityManagerInterface $em, ValidatorInterface $validator)
public function __construct(EntityManagerInterface $em, ValidatorInterface $validator,
string $country_code)
{
$this->em = $em;
$this->validator = $validator;
$this->country_code = $country_code;
$this->loadTemplates();
}
@ -124,7 +124,14 @@ class ResqCustomerHandler implements CustomerHandlerInterface
$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());
// prepend the country code before each mobile number
$mobile_number_list = [];
$mobile_numbers = $orow->getMobileNumberList();
foreach ($mobile_numbers as $mobile_number)
{
$mobile_number_list[] = $this->country_code . $mobile_number;
}
$row['mobile_numbers'] = implode("<br>", $mobile_number_list);
$row['plate_numbers'] = implode("<br>", $orow->getPlateNumberList());
$rows[] = $row;
@ -465,7 +472,7 @@ class ResqCustomerHandler implements CustomerHandlerInterface
$cust = $cv->getCustomer();
$vehicles[] = [
'id' => $cv->getID(),
'text' => $cv->getPlateNumber() . ' ' . $cust->getFirstName() . ' ' . $cust->getLastName() . ' ('. self::COUNTRY_CODE_PREFIX . $cust->getPhoneMobile() . ')',
'text' => $cv->getPlateNumber() . ' ' . $cust->getFirstName() . ' ' . $cust->getLastName() . ' ('. $this->country_code . $cust->getPhoneMobile() . ')',
];
}

View file

@ -11,25 +11,33 @@ use CrEOF\Spatial\PHP\Types\Geometry\Point;
class GeofenceTracker
{
protected $em;
protected $geofence_flag;
public function __construct(EntityManagerInterface $em)
public function __construct(EntityManagerInterface $em, $geofence_flag)
{
$this->em = $em;
$this->geofence_flag = $geofence_flag;
}
public function isCovered($long, $lat)
{
// see if the point is in any of the polygons
$query = $this->em->createQuery('SELECT count(s) from App\Entity\SupportedArea s where st_contains(s.coverage_area, point(:long, :lat)) = true')
->setParameter('long', $long)
->setParameter('lat', $lat);
// check if geofence is enabled
if ($this->geofence_flag == 'true')
{
// see if the point is in any of the polygons
$query = $this->em->createQuery('SELECT count(s) from App\Entity\SupportedArea s where st_contains(s.coverage_area, point(:long, :lat)) = true')
->setParameter('long', $long)
->setParameter('lat', $lat);
// number of polygons that contain the point
$count = $query->getSingleScalarResult();
// number of polygons that contain the point
$count = $query->getSingleScalarResult();
if ($count > 0)
return true;
if ($count > 0)
return true;
return false;
return false;
}
return true;
}
}

View file

@ -55,20 +55,20 @@ use FPDF;
class CMBJobOrderHandler implements JobOrderHandlerInterface
{
const COUNTRY_CODE_PREFIX = '+60';
protected $em;
protected $ic;
protected $security;
protected $validator;
protected $translator;
protected $rah;
protected $country_code;
protected $template_hash;
public function __construct(Security $security, EntityManagerInterface $em,
InvoiceGeneratorInterface $ic, ValidatorInterface $validator,
TranslatorInterface $translator, RiderAssignmentHandlerInterface $rah)
TranslatorInterface $translator, RiderAssignmentHandlerInterface $rah,
string $country_code)
{
$this->em = $em;
$this->ic = $ic;
@ -76,6 +76,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
$this->validator = $validator;
$this->translator = $translator;
$this->rah = $rah;
$this->country_code = $country_code;
$this->loadTemplates();
}
@ -1860,7 +1861,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
$pdf->SetXY($col2_x, $y);
$pdf->Cell($label_width, $line_height, 'Mobile Phone:');
$pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneMobile() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneMobile() : '', 0, 'L');
$pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneMobile() ? $this->country_code . $customer->getPhoneMobile() : '', 0, 'L');
// get Y after right cell
$y2 = $pdf->GetY();
@ -1877,7 +1878,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
$pdf->SetXY($col2_x, $y);
$pdf->Cell($label_width, $line_height, 'Landline:');
$pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneLandline() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneLandline() : '', 0, 'L');
$pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneLandline() ? $this->country_code . $customer->getPhoneLandline() : '', 0, 'L');
// get Y after right cell
$y2 = $pdf->GetY();
@ -1887,11 +1888,11 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
$pdf->SetXY($col2_x, $y);
$pdf->Cell($label_width, $line_height, 'Office Phone:');
$pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneOffice() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneOffice() : '', 0, 'L');
$pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneOffice() ? $this->country_code . $customer->getPhoneOffice() : '', 0, 'L');
$pdf->SetX($col2_x);
$pdf->Cell($label_width, $line_height, 'Fax:');
$pdf->MultiCell($val_width, $line_height, $customer && $customer->getPhoneFax() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneFax() : '', 0, 'L');
$pdf->MultiCell($val_width, $line_height, $customer && $customer->getPhoneFax() ? $this->country_code . $customer->getPhoneFax() : '', 0, 'L');
// insert vehicle info
$cv = $obj->getCustomerVehicle();

View file

@ -53,25 +53,25 @@ use FPDF;
class ResqJobOrderHandler implements JobOrderHandlerInterface
{
const COUNTRY_CODE_PREFIX = '+60';
protected $em;
protected $ic;
protected $security;
protected $validator;
protected $translator;
protected $country_code;
protected $template_hash;
public function __construct(Security $security, EntityManagerInterface $em,
InvoiceGeneratorInterface $ic, ValidatorInterface $validator,
TranslatorInterface $translator)
TranslatorInterface $translator, string $country_code)
{
$this->em = $em;
$this->ic = $ic;
$this->security = $security;
$this->validator = $validator;
$this->translator = $translator;
$this->country_code = $country_code;
$this->loadTemplates();
}
@ -1868,7 +1868,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
$pdf->SetXY($col2_x, $y);
$pdf->Cell($label_width, $line_height, 'Mobile Phone:');
$pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneMobile() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneMobile() : '', 0, 'L');
$pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneMobile() ? $this->country_code . $customer->getPhoneMobile() : '', 0, 'L');
// get Y after right cell
$y2 = $pdf->GetY();
@ -1885,7 +1885,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
$pdf->SetXY($col2_x, $y);
$pdf->Cell($label_width, $line_height, 'Landline:');
$pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneLandline() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneLandline() : '', 0, 'L');
$pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneLandline() ? $this->country_code . $customer->getPhoneLandline() : '', 0, 'L');
// get Y after right cell
$y2 = $pdf->GetY();
@ -1895,11 +1895,11 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
$pdf->SetXY($col2_x, $y);
$pdf->Cell($label_width, $line_height, 'Office Phone:');
$pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneOffice() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneOffice() : '', 0, 'L');
$pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneOffice() ? $this->country_code . $customer->getPhoneOffice() : '', 0, 'L');
$pdf->SetX($col2_x);
$pdf->Cell($label_width, $line_height, 'Fax:');
$pdf->MultiCell($val_width, $line_height, $customer && $customer->getPhoneFax() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneFax() : '', 0, 'L');
$pdf->MultiCell($val_width, $line_height, $customer && $customer->getPhoneFax() ? $this->country_code . $customer->getPhoneFax() : '', 0, 'L');
// insert vehicle info
$cv = $obj->getCustomerVehicle();

View file

@ -0,0 +1,332 @@
<?php
namespace App\Service;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Warranty;
use App\Entity\Battery;
use App\Entity\BatterySize;
use App\Entity\SAPBattery;
use App\Entity\BatteryModel;
use App\Entity\CustomerVehicle;
use App\Ramcar\WarrantyClass;
use DateTime;
use DateInterval;
class WarrantyHandler
{
protected $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number,
$batt_list, DateTime $date_purchase, $warranty_class)
{
// new warranty
$warranty = new Warranty();
foreach ($batt_list as $battery)
{
// get the battery model and battery size
$model_id = $battery->getModel()->getID();
$size_id = $battery->getSize()->getID();
$bty_model = $this->em->getRepository(BatteryModel::class)->find($model_id);
$bty_size = $this->em->getRepository(BatterySize::class)->find($size_id);
if ($bty_model != null)
{
$warranty->setBatteryModel($bty_model);
}
if ($bty_size != null)
{
$warranty->setBatterySize($bty_size);
}
$sap_code = $battery->getSAPCode();
if (!empty($sap_code))
{
// find sap battery
$sap_battery = $this->em->getRepository(SAPBattery::class)->find($sap_code);
if ($sap_battery != null)
{
$warranty->setSAPBattery($sap_battery);
}
}
}
// compute expiry date
$date_expire = null;
if ((!empty($warranty_class)) &&
(count($batt_list) != 0))
{
$period = $this->getWarrantyPeriod($batt_list, $warranty_class);
$date_expire = $this->computeDateExpire($date_purchase, $period);
$warranty->setDateExpire($date_expire);
}
// set and save values
$warranty->setSerial($serial)
->setPlateNumber($plate_number)
->setFirstName($first_name)
->setLastName($last_name)
->setMobileNumber($mobile_number)
->setDatePurchase($date_purchase);
$this->em->persist($warranty);
$this->em->flush();
// update customer vehicle with warranty info
$this->updateCustomerVehicle($serial, $batt_list, $plate_number, $date_expire);
$this->em->clear();
}
public function updateCustomerVehicle($serial, $batteries, $plate_number, $date_expire)
{
// find customer vehicle using plate number
error_log('Finding customer vehicle with plate number ' . $plate_number);
$cv_q = $this->em->createQuery('select count(cv) from App\Entity\CustomerVehicle cv where cv.plate_number = :plate_number')
->setParameter('plate_number', $plate_number);
$cv_result = $cv_q->getSingleScalarResult();
$battery_id = null;
if ($cv_result != 0)
{
if (!empty($batteries))
{
// set current battery to the first battery in list.
// there are cases where multiple batteries linked to an SAP code.
$battery = $batteries[0];
$battery_id = $battery->getID();
}
//error_log('Serial/Warranty Code = ' . $serial);
$q = $this->em->createQuery('update App\Entity\CustomerVehicle cv
set cv.curr_battery = :batt_id,
cv.warranty_code = :serial,
cv.warranty_expiration = :expiry_date
where cv.plate_number = :plate_number')
->setParameters([
'batt_id' => $battery_id,
'serial' => $serial,
'expiry_date' => $date_expire,
'plate_number' => $plate_number]);
$q->execute();
}
}
public function updateWarranty(Warranty $warr, $first_name, $last_name, $mobile_number, $batt_list, DateTime $date_purchase)
{
// TODO: add serial and plate number to update
// TODO: check if data from existing warranty matches the new data
// check if details are complete
if (empty($warr->getFirstName()))
{
if (!empty($first_name))
{
$warr->setFirstName($first_name);
}
}
if (empty($warr->getLastName()))
{
if (!empty($last_name))
{
$warr->setLastName($last_name);
}
}
if (empty($warr->getMobileNumber()))
{
if (!empty($mobile_number))
{
$warr->setMobileNumber($mobile_number);
}
}
if ((empty($warr->getBatteryModel())) ||
(empty($warr->getBatterySize())))
{
if (count($batt_list) != 0)
{
foreach ($batt_list as $battery)
{
// get the battery model and battery size
$model_id = $battery->getModel()->getID();
$size_id = $battery->getSize()->getID();
$bty_model = $this->em->getRepository(BatteryModel::class)->find($model_id);
$bty_size = $this->em->getRepository(BatterySize::class)->find($size_id);
if ($bty_model != null)
{
$warranty->setBatteryModel($bty_model);
}
if ($bty_size != null)
{
$warranty->setBatterySize($bty_size);
}
$sap_code = $battery->getSAPCode();
if (!empty($sap_code))
{
// find sap battery
$sap_battery = $this->em->getRepository(SAPBattery::class)->find($sap_code);
if ($sap_battery != null)
{
$warranty->setSAPBattery($sap_battery);
}
}
}
}
}
$purchase_date = $warr->getDatePurchase();
if (empty($purchase_date))
{
if (!empty($date_purchase))
{
$warr->setDatePurchase($date_purchase);
}
$purchase_date = $date_purchase;
}
if (empty($warr->getDateExpire()))
{
$batteries = [];
if (count($batt_list) == 0)
{
$batteries = $this->getBatteriesForWarranty($warr);
}
else
{
$batteries = $batt_list;
}
if (!empty($batteries))
{
$period = $this->getWarrantyPeriod($batteries, $warr->getWarrantyClass());
if (!empty($purchase_date))
{
$expire_date = $this->computeDateExpire($purchase_date, $period);
$warr->setDateExpire($expire_date);
}
}
}
$this->em->persist($warr);
$this->em->flush();
$this->em->clear();
}
public function computeDateExpire($date_create, $warranty_period)
{
$expire_date = clone $date_create;
$expire_date->add(new DateInterval('P'.$warranty_period.'M'));
return $expire_date;
}
public function getWarrantyPeriod($batteries, $warranty_class)
{
// set to -1 to show that we haven't set a warranty period yet
// cannot set initial value to 0 because warranty tnv can be 0
$least_warranty = -1;
$warr_period = 0;
foreach ($batteries as $battery)
{
// if multiple batteries, get the smallest warranty period
// check warranty class to get warranty period
if ($warranty_class == WarrantyClass::WTY_PRIVATE)
{
$warr_period = $battery->getWarrantyPrivate();
//error_log('Warranty Period for Private: ' . $warr_period);
}
if ($warranty_class == WarrantyClass::WTY_COMMERCIAL)
{
$warr_period = $battery->getWarrantyCommercial();
//error_log('Warranty Period for Commercial: ' . $warr_period);
}
if ($warranty_class == WarrantyClass::WTY_TNV)
{
$warr_period = $battery->getWarrantyTnv();
//error_log('Warranty Period for TNV: ' . $warr_period);
}
if ($least_warranty < 0)
{
// set least warranty to the first obtained warranty period
$least_warranty = $warr_period;
}
if ($least_warranty > $warr_period)
{
$least_warranty = $warr_period;
}
}
$warranty_period = $least_warranty;
return $warranty_period;
}
public function getBatteriesForWarranty($warr)
{
// find battery via sku/sap battery first
// if sku is null, use battery model and battery size to find battery
// if all three are null, do nothing
$batteries = null;
$sap_battery = $warr->getSAPBattery();
$batt_model = $warr->getBatteryModel();
$batt_size = $warr->getBatterySize();
$warranty_class = $warr->getWarrantyClass();
if (empty($warranty_class))
{
error_log('Warranty class is empty for warranty id ' . $warr->getID());
return null;
}
if ($sap_battery != null)
{
// get the battery linked to SAP Battery using sap_battery id
$batteries = $this->em->getRepository(Battery::class)->findBy(['sap_code' => $sap_battery->getID()]);
}
else
{
if ($batt_model == null)
{
error_log('Battery model is null for warranty id ' . $warr->getID());
return null;
}
if ($batt_size == null)
{
error_log('Battery size is null for warranty id ' . $warr->getID());
return null;
}
// find battery using battery model and battery size
$batteries = $this->em->getRepository(Battery::class)->findBy(['model' => $batt_model, 'size' => $batt_size]);
}
if (empty($batteries))
{
error_log('Battery not found for warranty id ' . $warr->getID());
return null;
}
return $batteries;
}
public function cleanPlateNumber($plate)
{
// remove spaces and make upper case
return strtoupper(str_replace(' ', '', $plate));
}
}

View file

@ -98,6 +98,9 @@
"doctrine/reflection": {
"version": "v1.0.0"
},
"edwinhoksberg/php-fcm": {
"version": "1.0.0"
},
"guzzlehttp/guzzle": {
"version": "6.3.0"
},

View file

@ -153,7 +153,7 @@
</h3>
<ul class="m-menu__inner">
<li class="m-menu__item " data-redirect="true" aria-haspopup="true">
<a href="{{ url('rep_popapp_comp_form') }}" class="m-menu__link">
<a href="{{ url('rep_popapp_comp_form') }}" class="m-menu__link">
<i class="m-menu__link-bullet m-menu__link-bullet--dot">
<span></span>
</i>
@ -161,7 +161,7 @@
Popapp Comparison Report
</span>
</a>
<a href="{{ url('rep_resq_meh_form') }}" class="m-menu__link">
<a href="{{ url('rep_resq_meh_form') }}" class="m-menu__link">
<i class="m-menu__link-bullet m-menu__link-bullet--dot">
<span></span>
</i>
@ -169,6 +169,30 @@
RESQ MEH Customer Report
</span>
</a>
<a href="{{ url('rep_warranty_class_form') }}" class="m-menu__link">
<i class="m-menu__link-bullet m-menu__link-bullet--dot">
<span></span>
</i>
<span class="m-menu__link-text">
Warranty Class Report
</span>
</a>
<a href="{{ url('rep_vehicle_battery_compatibility_form') }}" class="m-menu__link">
<i class="m-menu__link-bullet m-menu__link-bullet--dot">
<span></span>
</i>
<span class="m-menu__link-text">
Vehicle Battery Compatibility Report
</span>
</a>
<a href="{{ url('rep_warranty_details_form') }}" class="m-menu__link">
<i class="m-menu__link-bullet m-menu__link-bullet--dot">
<span></span>
</i>
<span class="m-menu__link-text">
Warranty Details Report
</span>
</a>
</li>
</ul>
</li>

View file

@ -131,7 +131,7 @@
Mobile Phone
</label>
<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="phone_mobile" class="form-control m-input" value="{{ obj.getPhoneMobile|default('') }}" data-name="phone_mobile">
<div class="form-control-feedback hide" data-field="phone_mobile"></div>
</div>
@ -141,7 +141,7 @@
Landline
</label>
<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="phone_landline" class="form-control m-input" value="{{ obj.getPhoneLandline|default('') }}" data-name="phone_landline">
<div class="form-control-feedback hide" data-field="phone_landline"></div>
</div>
@ -153,7 +153,7 @@
Office Phone
</label>
<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="phone_office" class="form-control m-input" value="{{ obj.getPhoneOffice|default('') }}" data-name="phone_office">
<div class="form-control-feedback hide" data-field="phone_office"></div>
</div>
@ -163,7 +163,7 @@
Fax
</label>
<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="phone_fax" class="form-control m-input" value="{{ obj.getPhoneFax|default('') }}" data-name="phone_fax">
<div class="form-control-feedback hide" data-field="phone_fax"></div>
</div>

View file

@ -0,0 +1,50 @@
{% extends 'base.html.twig' %}
{% block body %}
<!-- BEGIN: Subheader -->
<div class="m-subheader">
<div class="d-flex align-items-center">
<div class="mr-auto">
<h3 class="m-subheader__title">
Vehicle Battery Compatibility Report
</h3>
</div>
</div>
</div>
<!-- END: Subheader -->
<div class="m-content">
<!--Begin::Section-->
<div class="row">
<div class="col-xl-6">
<div class="m-portlet m-portlet--mobile">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title">
<span class="m-portlet__head-icon">
<i class="fa fa-upload"></i>
</span>
<h3 class="m-portlet__head-text">
Generate Vehicle Battery Compatibility CSV File
</h3>
</div>
</div>
</div>
<form id="upload_form" class="m-form m-form--fit m-form--label-align-right m-form--group-seperator-dashed" method="post" action="{{ url('rep_vehicle_battery_compatibility_export_csv') }}" enctype="multipart/form-data">
<div class="m-portlet__body">
<div class="m-portlet__foot m-portlet__foot--fit">
<div class="m-form__actions m-form__actions--solid m-form__actions--right">
<div class="row">
<div class="col-lg-12">
<button type="submit" class="btn btn-success">Export to CSV</button>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,50 @@
{% extends 'base.html.twig' %}
{% block body %}
<!-- BEGIN: Subheader -->
<div class="m-subheader">
<div class="d-flex align-items-center">
<div class="mr-auto">
<h3 class="m-subheader__title">
Warranty Class Report
</h3>
</div>
</div>
</div>
<!-- END: Subheader -->
<div class="m-content">
<!--Begin::Section-->
<div class="row">
<div class="col-xl-6">
<div class="m-portlet m-portlet--mobile">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title">
<span class="m-portlet__head-icon">
<i class="fa fa-upload"></i>
</span>
<h3 class="m-portlet__head-text">
Generate Warranty Class CSV File
</h3>
</div>
</div>
</div>
<form id="upload_form" class="m-form m-form--fit m-form--label-align-right m-form--group-seperator-dashed" method="post" action="{{ url('rep_warranty_class_export_csv') }}" enctype="multipart/form-data">
<div class="m-portlet__body">
<div class="m-portlet__foot m-portlet__foot--fit">
<div class="m-form__actions m-form__actions--solid m-form__actions--right">
<div class="row">
<div class="col-lg-12">
<button type="submit" class="btn btn-success">Export to CSV</button>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,50 @@
{% extends 'base.html.twig' %}
{% block body %}
<!-- BEGIN: Subheader -->
<div class="m-subheader">
<div class="d-flex align-items-center">
<div class="mr-auto">
<h3 class="m-subheader__title">
Warranty Details Report
</h3>
</div>
</div>
</div>
<!-- END: Subheader -->
<div class="m-content">
<!--Begin::Section-->
<div class="row">
<div class="col-xl-6">
<div class="m-portlet m-portlet--mobile">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title">
<span class="m-portlet__head-icon">
<i class="fa fa-upload"></i>
</span>
<h3 class="m-portlet__head-text">
Generate Warranty Details CSV File
</h3>
</div>
</div>
</div>
<form id="upload_form" class="m-form m-form--fit m-form--label-align-right m-form--group-seperator-dashed" method="post" action="{{ url('rep_warranty_details_export_csv') }}" enctype="multipart/form-data">
<div class="m-portlet__body">
<div class="m-portlet__foot m-portlet__foot--fit">
<div class="m-form__actions m-form__actions--solid m-form__actions--right">
<div class="row">
<div class="col-lg-12">
<button type="submit" class="btn btn-success">Export to CSV</button>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,142 @@
{% extends 'base.html.twig' %}
{% block body %}
<!-- BEGIN: Subheader -->
<div class="m-subheader">
<div class="d-flex align-items-center">
<div class="mr-auto">
<h3 class="m-subheader__title">Static Content</h3>
</div>
</div>
</div>
<!-- END: Subheader -->
<div class="m-content">
<!--Begin::Section -->
<div class="row">
<div class="col-xl-8">
<div class="m-portlet m-portlet--mobile">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title">
<span class="m-portlet__head-icon">
<i class="la la-key"></i>
</span>
<h3 class="m-portlet__head-text">
{% if mode == 'update' %}
Edit Static Content
<small>{{ obj.getID() }}</small>
{% else %}
New Static Content
{% endif %}
</h3>
</div>
</div>
</div>
<form id="row-form" class="m-form m-form--fit m-form--label-align-right m-form--group-seperator-dashed" method="post" action="{{ mode == 'update' ? url('static_content_update_submit', {'id': obj.getID()}) : url('static_content_create_submit') }}">
<div class="m-portlet__body">
<div class="form-group m-form__group row no-border">
<div class="col-lg-12">
<label data-field="id">
ID:
</label>
<input type="text" name="id" class="form-control m-input" value="{{ obj.getID() }}">
<div class="form-control-feedback hide" data-field="id"></div>
</div>
</div>
<div class="form-group m-form__group row no-border">
<div class="col-lg-12">
<label data-field="content">
Content
</label>
<textarea name="content" class="form-control m-input" data-name="content" rows="50">{{ obj.getContent() }}</textarea>
<div class="form-control-feedback hide" data-field="content"></div>
</div>
</div>
</div>
<div class="m-portlet__foot m-portlet__foot--fit">
<div class="m-form__actions m-form__actions--solid m-form__actions--right">
<div class="row">
<div class="col-lg-12">
<button type="submit" class="btn btn-success">Submit</button>
<a href="{{ url('static_content_list') }}" class="btn btn-secondary">Back</a>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
$(function() {
$("#row-form").submit(function(e) {
var form = $(this);
e.preventDefault();
$.ajax({
method: "POST",
url: form.prop('action'),
data: form.serialize()
}).done(function(response) {
// remove all error classes
removeErrors();
swal({
title: 'Done!',
text: 'Your changes have been saved!',
type: 'success',
onClose: function() {
window.location.href = "{{ url('static_content_list') }}";
}
});
}).fail(function(response) {
if (response.status == 422 || response.status == 403) {
var errors = response.responseJSON.errors;
var firstfield = false;
// remove all error classes first
removeErrors();
// display errors contextually
$.each(errors, function(field, msg) {
var formfield = $("[name='" + field + "']");
var label = $("label[data-field='" + field + "']");
var msgbox = $(".form-control-feedback[data-field='" + field + "']");
// add error classes to bad fields
formfield.addClass('form-control-danger');
label.addClass('has-danger');
msgbox.html(msg).addClass('has-danger').removeClass('hide');
// check if this field comes first in DOM
var domfield = formfield.get(0);
if (!firstfield || (firstfield && firstfield.compareDocumentPosition(domfield) === 2)) {
firstfield = domfield;
}
});
// focus on first bad field
firstfield.focus();
// scroll to above that field to make it visible
$('html, body').animate({
scrollTop: $(firstfield).offset().top - 200
}, 100);
}
});
});
// remove all error classes
function removeErrors() {
$(".form-control-danger").removeClass('form-control-danger');
$("[data-field]").removeClass('has-danger');
$(".form-control-feedback[data-field]").addClass('hide');
}
});
</script>
{% endblock %}

View file

@ -0,0 +1,138 @@
{% extends 'base.html.twig' %}
{% block body %}
<!-- BEGIN: Subheader -->
<div class="m-subheader">
<div class="d-flex align-items-center">
<div class="mr-auto">
<h3 class="m-subheader__title">
Static Content
</h3>
</div>
</div>
</div>
<!-- END: Subheader -->
<div class="m-content">
<!--Begin::Section-->
<div class="row">
<div class="col-xl-12">
<div class="m-portlet m-portlet--mobile">
<div class="m-portlet__body">
<div class="m-form m-form--label-align-right m--margin-top-20 m--margin-bottom-30">
<div class="row align-items-center">
<div class="col-xl-8 order-2 order-xl-1">
<div class="form-group m-form__group row align-items-center">
<div class="col-md-4">
<div class="m-input-icon m-input-icon--left">
<input type="text" class="form-control m-input m-input--solid" placeholder="Search..." id="data-rows-search">
<span class="m-input-icon__icon m-input-icon__icon--left">
<span><i class="la la-search"></i></span>
</span>
</div>
</div>
</div>
</div>
<div class="col-xl-4 order-1 order-xl-2 m--align-right">
<a href="{{ url('static_content_create') }}" class="btn btn-focus m-btn m-btn--custom m-btn--icon m-btn--air m-btn--pill">
<span>
<i class="la la-key"></i>
<span>New Static Content</span>
</span>
</a>
<div class="m-separator m-separator--dashed d-xl-none"></div>
</div>
</div>
</div>
<!--begin: Datatable -->
<div id="data-rows"></div>
<!--end: Datatable -->
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
$(function() {
var options = {
data: {
type: 'remote',
source: {
read: {
url: '{{ url("static_content_rows") }}',
method: 'POST'
}
},
saveState: {
cookie: false,
webstorage: false
},
pageSize: 10,
serverPaging: true,
serverFiltering: true,
serverSorting: true
},
columns: [
{
field: 'id',
title: 'ID'
},
{
field: 'Actions',
width: 110,
title: 'Actions',
sortable: false,
overflow: 'visible',
template: function (row, index, datatable) {
var actions = '';
if (row.meta.update_url != '') {
actions += '<a href="' + row.meta.update_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-edit" data-id="' + row.name + '" title="Edit"><i class="la la-edit"></i></a>';
}
if (row.meta.delete_url != '') {
actions += '<a href="' + row.meta.delete_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-danger m-btn--icon m-btn--icon-only m-btn--pill btn-delete" data-id="' + row.id + '" title="Delete"><i class="la la-trash"></i></a>';
}
return actions;
},
}
],
search: {
onEnter: false,
input: $('#data-rows-search'),
delay: 400
}
};
var table = $("#data-rows").mDatatable(options);
$(document).on('click', '.btn-delete', function(e) {
var url = $(this).prop('href');
var id = $(this).data('id');
var btn = $(this);
e.preventDefault();
swal({
title: 'Confirmation',
html: 'Are you sure you want to delete <strong>' + id + '</strong>?',
type: 'warning',
showCancelButton: true
}).then((result) => {
if (result.value) {
$.ajax({
method: "DELETE",
url: url
}).done(function(response) {
table.row(btn.parents('tr')).remove();
table.reload();
});
}
});
});
});
</script>
{% endblock %}

View file

@ -0,0 +1,52 @@
{% extends 'base.html.twig' %}
{% block body %}
<!-- BEGIN: Subheader -->
<div class="m-subheader">
<div class="d-flex align-items-center">
<div class="mr-auto">
<h3 class="m-subheader__title">
Warranty Upload
</h3>
</div>
</div>
</div>
<!-- END: Subheader -->
<div class="m-content">
<!--Begin::Section-->
<div class="row">
<div class="col-xl-6">
<div class="m-portlet m-portlet--mobile">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title">
<span class="m-portlet__head-icon">
<i class="fa fa-upload"></i>
</span>
<h3 class="m-portlet__head-text">
Upload Warranty CSV File
</h3>
</div>
</div>
</div>
<form id="upload_form" class="m-form m-form--fit m-form--label-align-right m-form--group-seperator-dashed" method="post" action="{{ url('warranty_upload_submit') }}" enctype="multipart/form-data">
<div class="m-portlet__body">
<div class="form-group m-form__group row">
<input type="file" id="csv_file" name="csv_file" >
</div>
<div class="m-portlet__foot m-portlet__foot--fit">
<div class="m-form__actions m-form__actions--solid m-form__actions--right">
<div class="row">
<div class="col-lg-12">
<button type="submit" class="btn btn-success">Upload</button>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,23 @@
<?php
require __DIR__ . '/../../vendor/autoload.php';
use Fcm\FcmClient;
use Fcm\Push\Notification;
$api_token = 'AAAArpsiQbQ:APA91bHQVXxkUxNp3i2kviEmRDAnXKUyP0-Z5HZD15gV5V4TgidjmEiVVHilPnLffTW4u9txWkA_PPthTv7Baq8_wx99hr9Bx62q4JWrPsrfnNMeEw9w5ojPPu0eCOGOKHn_l1HoY_SJBS1n6DTt7IC0L14Kn33kmw';
$sender_id = 'AIzaSyD5gUUkXwaKarWYIigJGLLTzf9KQwoJ2wM';
// Instantiate the client with the project api_token and sender_id.
$client = new FcmClient($api_token, $sender_id);
// Instantiate the push notification request object.
$notification = new Notification();
// Enhance the notification object with our custom options.
$notification->addRecipient($device_id)
->setTitle('Motolite RES-Q')
->setBody('Test notification sending')
// Send the notification to the Firebase servers for further handling.
$client->send($notification);