resq/src/Controller/WarrantyController.php

763 lines
27 KiB
PHP

<?php
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\Entity\Customer;
use App\Ramcar\WarrantyClass;
use App\Ramcar\WarrantyStatus;
use App\Ramcar\WarrantySource;
use App\Service\WarrantyAPILogger;
use App\Service\WarrantyBulkUploader;
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;
use DateTime;
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")
*/
public function index()
{
$this->denyAccessUnlessGranted('warranty.list', null, 'No access.');
return $this->render('warranty/list.html.twig');
}
public function rows(Request $req)
{
$this->denyAccessUnlessGranted('warranty.list', null, 'No access.');
// get query builder
$qb = $this->getDoctrine()
->getRepository(Warranty::class)
->createQueryBuilder('q');
// get datatable params
$datatable = $req->request->get('datatable');
// count total records
$tquery = $qb->select('COUNT(q)');
// add filters to count query
$this->setQueryFilters($datatable, $tquery);
$total = $tquery->getQuery()
->getSingleScalarResult();
// get current page number
$page = $datatable['pagination']['page'] ?? 1;
$perpage = $datatable['pagination']['perpage'];
$offset = ($page - 1) * $perpage;
// add metadata
$meta = [
'page' => $page,
'perpage' => $perpage,
'pages' => ceil($total / $perpage),
'total' => $total,
'sort' => 'asc',
'field' => 'id'
];
// build query
$query = $qb->select('q');
// add filters to query
$this->setQueryFilters($datatable, $query);
// check if sorting is present, otherwise use default
if (isset($datatable['sort']['field']) && !empty($datatable['sort']['field'])) {
$order = $datatable['sort']['sort'] ?? 'asc';
$query->orderBy('q.' . $datatable['sort']['field'], $order);
} else {
$query->orderBy('q.id', 'asc');
}
// get rows for this page
$obj_rows = $query->setFirstResult($offset)
->setMaxResults($perpage)
->getQuery()
->getResult();
// process rows
$rows = [];
foreach ($obj_rows as $orow) {
// add row data
$row['id'] = $orow->getID();
$row['serial'] = $orow->getSerial();
$row['plate_number'] = $orow->getPlateNumber();
$row['warranty_class'] = $orow->getWarrantyClass();
$row['status'] = $orow->getStatus();
$row['is_activated'] = $orow->isActivated();
// add row metadata
$row['meta'] = [
'update_url' => '',
];
// add crud urls
if ($this->isGranted('warranty.update'))
$row['meta']['update_url'] = $this->generateUrl('warranty_update', ['id' => $row['id']]);
$rows[] = $row;
}
// response
return $this->json([
'meta' => $meta,
'data' => $rows
]);
}
/**
* @Menu(selected="warranty_list")
*/
public function addForm()
{
$this->denyAccessUnlessGranted('warranty.add', null, 'No access.');
$params['obj'] = new Warranty();
$params['mode'] = 'create';
// get dropdown parameters
$this->fillDropdownParameters($params);
// response
return $this->render('warranty/form.html.twig', $params);
}
public function addSubmit(Request $req, ValidatorInterface $validator, WarrantyAPILogger $logger)
{
$this->denyAccessUnlessGranted('warranty.add', null, 'No access.');
// create new row
$em = $this->getDoctrine()->getManager();
$obj = new Warranty();
$date_purchase = DateTime::createFromFormat('d M Y', $req->request->get('date_purchase'));
$date_claim = DateTime::createFromFormat('d M Y', $req->request->get('date_claim'));
$date_expire = DateTime::createFromFormat('d M Y', $req->request->get('date_expire'));
// get serial. Set to null if empty
if (empty(trim($req->request->get('serial'))))
$obj->setSerial();
else
$obj->setSerial($req->request->get('serial'));
// get outlet info, sender info
$req->request->get('outlet_name', '');
// set and save values
$obj->setWarrantyClass($req->request->get('warranty_class'))
->setFirstName($req->request->get('first_name'))
->setLastName($req->request->get('last_name'))
->setMobileNumber($req->request->get('mobile_number'))
->setDatePurchase($date_purchase)
->setClaimedFrom($req->request->get('claim_from'))
->setStatus($req->request->get('status'))
->setCreateSource(WarrantySource::ADMIN_PANEL)
->setOutletName($req->request->get('outlet_name', ''))
->setOutletContactNumber($req->request->get('outlet_contact_number', ''))
->setSenderName($req->request->get('sender_name', ''))
->setSenderContactNumber($req->request->get('sender_contact_number', ''))
->setOutletAddress($req->request->get('outlet_address', ''))
->setSalesInvoiceNumber($req->request->get('sales_invoice_number', ''));
if ($date_claim)
{
$obj->setDateClaim($date_claim);
}
if ($date_expire)
{
$obj->setDateExpire($date_expire);
}
// custom validation for battery model
// check if battery model is blank
$bmodel = $req->request->get('battery_model');
if (!empty($bmodel))
{
$model = $em->getRepository(BatteryModel::class)
->find($req->request->get('battery_model'));
if (empty($model))
$error_array['battery_model'] = 'Invalid model selected.';
else
$obj->setBatteryModel($model);
}
else
$obj->setBatteryModel(NULL);
// custom validation for battery size
// check if battery size is blank
$bsize = $req->request->get('battery_size');
if (!empty($bsize))
{
$size = $em->getRepository(BatterySize::class)
->find($req->request->get('battery_size'));
if (empty($size))
$error_array['battery_size'] = 'Invalid size selected.';
else
$obj->setBatterySize($size);
}
else
$obj->setBatterySize(NULL);
// custom validation for SAP battery
// check if sap battery is blank
$sap_battery = $req->request->get('sap_battery');
if (!empty($sap_battery))
{
$sap = $em->getRepository(SAPBattery::class)
->find($req->request->get('sap_battery'));
if (empty($sap))
$error_array['sap_battery'] = 'Invalid SAP battery selected.';
else
$obj->setSAPBattery($sap);
}
else
$obj->setSAPBattery(NULL);
// validate
$errors = $validator->validate($obj);
$cleaned_plate_number = Warranty::cleanPlateNumber($req->request->get('plate_number'));
if (!$cleaned_plate_number)
{
$error_array['plate_number'] = 'Invalid plate number specified.';
}
$obj->setPlateNumber($cleaned_plate_number);
// 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($obj);
$em->flush();
// log warranty creation
$action = 'create';
$user_id = $this->getUser()->getUsername();
$source = WarrantySource::ADMIN_PANEL;
$log_data = [
'serial' => $req->request->get('serial'),
'warranty_class' => $req->request->get('warranty_class'),
'first_name' => $req->request->get('first_name'),
'last_name' => $req->request->get('last_name'),
'mobile_number' => $req->request->get('mobile_number'),
'date_purchase' => $req->request->get('date_purchase'),
'claim_from' => $req->request->get('claim_from'),
'status' => $req->request->get('status'),
'date_claim' => $req->request->get('date_claim'),
'date_expire' => $req->request->get('date_expire'),
'battery_model' => $req->request->get('battery_model'),
'battery_size' => $req->request->get('battery_size'),
'sap_battery' => $req->request->get('sap_battery'),
'plate_number' => $req->request->get('plate_number'),
'outlet_name' => $req->request->get('outlet_name', ''),
'outlet_contact_number' => $req->request->get('outlet_contact_number', ''),
'sender_name' => $req->request->get('sender_name', ''),
'sender_contact_number' => $req->request->get('sender_contact_number', ''),
'outlet_address' => $req->request->get('outlet_address', ''),
'sales_invoice_number' => $req->request->get('sales_invoice_number', ''),
];
$logger->logWarrantyInfo($log_data, '', $user_id, $action, $source);
// return successful response
return $this->json([
'success' => 'Changes have been saved!'
]);
}
}
/**
* @Menu(selected="warranty_list")
*/
public function updateForm($id)
{
$this->denyAccessUnlessGranted('warranty.update', null, 'No access.');
$params['mode'] = 'update';
// get row data
$em = $this->getDoctrine()->getManager();
$obj = $em->getRepository(Warranty::class)->find($id);
// make sure this row exists
if (empty($obj))
throw $this->createNotFoundException('The item does not exist');
$params['obj'] = $obj;
// get dropdown parameters
$this->fillDropdownParameters($params);
// response
return $this->render('warranty/form.html.twig', $params);
}
public function updateSubmit(Request $req, ValidatorInterface $validator, $id)
{
$this->denyAccessUnlessGranted('warranty.update', null, 'No access.');
// get row data
$em = $this->getDoctrine()->getManager();
$obj = $em->getRepository(Warranty::class)->find($id);
// make sure this row exists
if (empty($obj))
throw $this->createNotFoundException('The item does not exist');
$date_purchase = DateTime::createFromFormat('d M Y', $req->request->get('date_purchase'));
$date_claim = DateTime::createFromFormat('d M Y', $req->request->get('date_claim'));
$date_expire = DateTime::createFromFormat('d M Y', $req->request->get('date_expire'));
// get serial. Set to null if empty
if (empty(trim($req->request->get('serial'))))
$obj->setSerial();
else
$obj->setSerial($req->request->get('serial'));
// set and save values
$obj->setWarrantyClass($req->request->get('warranty_class'))
->setFirstName($req->request->get('first_name'))
->setLastName($req->request->get('last_name'))
->setMobileNumber($req->request->get('mobile_number'))
->setDatePurchase($date_purchase)
->setClaimedFrom($req->request->get('claim_from'))
->setStatus($req->request->get('status'))
->setOutletName($req->request->get('outlet_name', ''))
->setOutletContactNumber($req->request->get('outlet_contact_number', ''))
->setSenderName($req->request->get('sender_name', ''))
->setSenderContactNumber($req->request->get('sender_contact_number', ''))
->setOutletAddress($req->request->get('outlet_address', ''))
->setSalesInvoiceNumber($req->request->get('sales_invoice_number', ''));
if ($date_claim)
{
$obj->setDateClaim($date_claim);
}
if ($date_expire)
{
$obj->setDateExpire($date_expire);
}
// custom validation for battery model
// check if battery model is blank
$bmodel = $req->request->get('battery_model');
if (!empty($bmodel))
{
$model = $em->getRepository(BatteryModel::class)
->find($req->request->get('battery_model'));
if (empty($model))
$error_array['battery_model'] = 'Invalid model selected.';
else
$obj->setBatteryModel($model);
}
else
$obj->setBatteryModel(NULL);
// custom validation for battery size
// check if battery size is blank
$bsize = $req->request->get('battery_size');
if (!empty($bsize))
{
$size = $em->getRepository(BatterySize::class)
->find($req->request->get('battery_size'));
if (empty($size))
$error_array['battery_size'] = 'Invalid size selected.';
else
$obj->setBatterySize($size);
}
else
$obj->setBatterySize(NULL);
// custom validation for SAP battery
// check if sap battery is blank
$sap_battery = $req->request->get('sap_battery');
if (!empty($sap_battery))
{
$sap = $em->getRepository(SAPBattery::class)
->find($req->request->get('sap_battery'));
if (empty($sap))
$error_array['sap_battery'] = 'Invalid SAP battery selected.';
else
$obj->setSAPBattery($sap);
}
else
$obj->setSAPBattery(NULL);
// validate
$errors = $validator->validate($obj);
$cleaned_plate_number = Warranty::cleanPlateNumber($req->request->get('plate_number'));
if (!$cleaned_plate_number)
{
$error_array['plate_number'] = 'Invalid plate number specified.';
}
$obj->setPlateNumber($cleaned_plate_number);
// 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($obj);
$em->flush();
// return successful response
return $this->json([
'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, WarrantyBulkUploader $warr_uploader)
{
// retrieve temporary info for file
$file = $req->files->get('csv_file');
// process the csv file. Call the WarrantyBulkUploader service
$entries = $warr_uploader->warrantyUpload($file);
$resp = new StreamedResponse();
$resp->setCallback(function() use($entries) {
// csv output
$csv_handle = fopen('php://output', 'w+');
fputcsv($csv_handle, [
'Row Num',
'Encoded By',
'Date of Encoded',
'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',
'Status',
'Reason Warranty Not Added',
]);
foreach ($entries as $row)
{
fputcsv($csv_handle, $row);
}
fclose($csv_handle);
});
$filename = 'upload_warranty_results' . '.csv';
$resp->headers->set('Content-Type', 'text/csv; charset=utf-8');
$resp->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"');
$resp->setStatusCode(200);
return $resp;
}
// NOTE: this is not being called anymore. We are now using the WarrantyBulkUploader service.
// Do we delete this?
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();
}
}
}
// find customer vehicle using plate number
$vehicle = null;
//$customer_vehicle = $em->getRepository(CustomerVehicle::class)->findOneBy(['plate_number' => $plate_number]);
$cv_query = $em->createQuery('SELECT cv FROM App\Entity\CustomerVehicle cv WHERE cv.plate_number = :plate_number');
$customer_vehicle = $cv_query->setParameters([
'plate_number' => $plate_number,
])
->setMaxResults(1)
->getOneOrNullResult();
if ($customer_vehicle != null)
$vehicle = $customer_vehicle->getVehicle();
// find customer using mobile number
$customer = null;
//$customer_results = $em->getRepository(Customer::class)->findBy(['phone_mobile' => $mobile_number]);
$cust_query = $em->createQuery('SELECT c FROM App\Entity\Customer c where c.phone_mobile = :mobile_number');
$customer_results = $cust_query->setParameters([
'mobile_number' => $mobile_number
])
->getResult();
foreach ($customer_results as $cust)
{
if ($customer_vehicle != null)
{
if ($cust->getID() == $customer_vehicle->getCustomer()->getID())
break;
}
}
if ($customer_vehicle != null)
{
// set customer to associated customer of customer vehicle
$customer = $customer_vehicle->getCustomer();
}
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);
$user_id = $this->getUser()->getUsername();
$source = WarrantySource::BULK_UPLOAD;
$wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class,
$user_id, $source, $customer, $vehicle);
}
}
$em->clear();
$row_num++;
}
return $invalid_entries;
}
protected function fillDropdownParameters(&$params)
{
$em = $this->getDoctrine()->getManager();
$params['batt_models'] = $em->getRepository(BatteryModel::class)->findAll();
$params['batt_sizes'] = $em->getRepository(BatterySize::class)->findAll();
$params['sap_batts'] = $em->getRepository(SAPBattery::class)->findAll();
$params['warranty_classes'] = WarrantyClass::getCollection();
$params['warranty_statuses'] = WarrantyStatus::getCollection();
}
// check if datatable filter is present and append to query
protected function setQueryFilters($datatable, &$query) {
if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) {
$query->where('q.serial LIKE :filter')
->orWhere('q.plate_number LIKE :filter')
->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%');
}
}
protected function cleanPlateNumber($plate)
{
// remove spaces and make upper case
return strtoupper(str_replace(' ', '', $plate));
}
}