resq/src/Controller/WarrantyController.php
2019-12-13 09:38:26 +00:00

690 lines
24 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\Ramcar\WarrantyClass;
use App\Ramcar\WarrantyStatus;
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)
{
// retrieve temporary info for file
$file = $req->files->get('csv_file');
// process the csv file
$inv_entries = $this->processWarrantyFile($file, $em);
$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)
{
// 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]);
$plate_number = $this->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' => trim($fields[11]),
'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]);
if (!empty($warr_results))
{
foreach($warr_results as $warr)
{
// 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 (!empty($battery_id))
{
// find battery
$battery = $em->getRepository(Battery::class)->find($battery_id);
if (!empty($battery))
{
// get the battery model and battery size
$model_id = $battery->getModel()->getID();
$size_id = $battery->getSize()->getID();
$bty_model = $em->getRepository(BatteryModel::class)->find($model_id);
$bty_size = $em->getRepository(BatterySize::class)->find($size_id);
if ($bty_model != null)
{
$warr->setBatteryModel($bty_model);
}
if ($bty_size != null)
{
$warr->setBatterySize($bty_size);
}
$sap_code = $battery->getSAPCode();
if (!empty($sap_code))
{
// find sap battery
$sap_batt = $em->getRepository(SAPBattery::class)->find($sap_code);
if (!empty($sap_batt))
{
$warr->setSAPBattery($sap_batt);
}
}
}
}
}
if (empty($warr->getDatePurchase()))
{
if (!empty($date_purchase))
{
$warr->setDatePurchase($date_purchase);
}
}
// TODO: compute expiry date
$em->persist($warr);
$em->flush();
}
}
else
{
// new warranty
$warranty = new Warranty();
// get the battery purchased
// check battery first. If not found, check sap_battery
$battery = $em->getRepository(Battery::class)->find($battery_id);
if ($battery != null)
{
// get the battery model and battery size
$model_id = $battery->getModel()->getID();
$size_id = $battery->getSize()->getID();
$bty_model = $em->getRepository(BatteryModel::class)->find($model_id);
$bty_size = $em->getRepository(BatterySize::class)->find($size_id);
if ($bty_model != null)
{
$warranty->setBatteryModel($bty_model);
}
if ($bty_size != null)
{
$warranty->setBatterySize($bty_size);
}
}
else
{
// find battery in sap_battery
$battery = $em->getRepository(SAPBattery::class)->find($battery_id);
if ($battery != null)
{
// battery is SAPBattery
$warranty->setSAPBattery($battery);
}
}
// TODO: compute expiry date
// set and save values
$warranty->setSerial($serial)
->setPlateNumber($plate_number)
->setFirstName($first_name)
->setLastName($last_name)
->setMobileNumber($mobile_number)
->setDatePurchase($date_purchase);
$em->persist($warranty);
$em->flush();
}
}
$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));
}
}