resq/src/Controller/WarrantyController.php

623 lines
21 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\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;
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)
{
$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'));
// set and save values
$obj->setSerial($req->request->get('serial'))
->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'));
if ($date_claim)
{
$obj->setDateClaim($date_claim);
}
if ($date_expire)
{
$obj->setDateExpire($date_expire);
}
// custom validation for battery model
$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);
// custom validation for battery size
$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);
// custom validation for 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);
// 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 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'));
// set and save values
$obj->setSerial($req->request->get('serial'))
->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'));
if ($date_claim)
{
$obj->setDateClaim($date_claim);
}
if ($date_expire)
{
$obj->setDateExpire($date_expire);
}
// custom validation for battery model
$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);
// custom validation for battery size
$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);
// custom validation for 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);
// 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, 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)
{
$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));
}
}