1580 lines
54 KiB
PHP
1580 lines
54 KiB
PHP
<?php
|
|
|
|
namespace App\Controller;
|
|
|
|
use App\Ramcar\BaseController;
|
|
use App\Ramcar\ServiceType;
|
|
use App\Ramcar\JOStatus;
|
|
use App\Ramcar\WarrantyClass;
|
|
use App\Ramcar\DiscountApply;
|
|
use App\Ramcar\TradeInType;
|
|
use App\Ramcar\InvoiceCriteria;
|
|
use App\Ramcar\InvoiceStatus;
|
|
use App\Ramcar\ModeOfPayment;
|
|
use App\Ramcar\TransactionOrigin;
|
|
|
|
use App\Entity\JobOrder;
|
|
use App\Entity\BatteryManufacturer;
|
|
use App\Entity\Customer;
|
|
use App\Entity\CustomerVehicle;
|
|
//use App\Entity\Outlet;
|
|
use App\Entity\Hub;
|
|
use App\Entity\Promo;
|
|
use App\Entity\Rider;
|
|
use App\Entity\Battery;
|
|
|
|
use App\Service\InvoiceCreator;
|
|
use App\Service\MapTools;
|
|
|
|
use Doctrine\ORM\Query;
|
|
use Doctrine\DBAL\Connection;
|
|
use Doctrine\DBAL\LockMode;
|
|
use Doctrine\ORM\PessimisticLockException;
|
|
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
|
|
|
use CrEOF\Spatial\PHP\Types\Geometry\Point;
|
|
|
|
use Mosquitto\Client as MosquittoClient;
|
|
use DateTime;
|
|
|
|
class JobOrderController extends BaseController
|
|
{
|
|
public function getJobOrders(Request $req)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_in.list', null, 'No access.');
|
|
|
|
// get search term
|
|
$term = $req->query->get('search');
|
|
|
|
// get querybuilder
|
|
$qb = $this->getDoctrine()
|
|
->getRepository(JobOrder::class)
|
|
->createQueryBuilder('q');
|
|
|
|
// build expression now since we're reusing it
|
|
$jo_label = $qb->expr()->concat($qb->expr()->literal('#'), 'q.id', $qb->expr()->literal(' - '), 'c.first_name', $qb->expr()->literal(' '), 'c.last_name', $qb->expr()->literal(' (Plate No: '), 'v.plate_number', $qb->expr()->literal(')'));
|
|
|
|
// count total records
|
|
$tquery = $qb->select('COUNT(q)')
|
|
->join('q.customer', 'c')
|
|
->join('q.cus_vehicle', 'v');
|
|
|
|
// add filters to count query
|
|
if (!empty($term)) {
|
|
$tquery->where($jo_label . ' LIKE :filter')
|
|
->setParameter('filter', '%' . $term . '%');
|
|
}
|
|
|
|
$total = $tquery->getQuery()
|
|
->getSingleScalarResult();
|
|
|
|
// pagination vars
|
|
$page = $req->query->get('page') ?? 1;
|
|
$perpage = 20;
|
|
$offset = ($page - 1) * $perpage;
|
|
$pages = ceil($total / $perpage);
|
|
$has_more_pages = $page < $pages ? true : false;
|
|
|
|
// build main query
|
|
$query = $qb->select('q')
|
|
->addSelect($jo_label . ' as jo_label')
|
|
->addSelect('c.first_name as cust_first_name')
|
|
->addSelect('c.last_name as cust_last_name')
|
|
->addSelect('v.plate_number as vehicle_plate_number');
|
|
|
|
// add filters if needed
|
|
if (!empty($term)) {
|
|
$query->where($jo_label . ' LIKE :filter')
|
|
->setParameter('filter', '%' . $term . '%');
|
|
}
|
|
|
|
// get rows
|
|
$obj_rows = $query->orderBy('q.id', 'asc')
|
|
->setFirstResult($offset)
|
|
->setMaxResults($perpage)
|
|
->getQuery()
|
|
->getResult();
|
|
|
|
// build job order array
|
|
$job_orders = [];
|
|
|
|
foreach ($obj_rows as $jo) {
|
|
$service_type = ServiceType::getName($jo[0]->getServiceType());
|
|
|
|
$job_orders[] = [
|
|
'id' => $jo[0]->getID(),
|
|
'text' => $jo['jo_label'] . ' - ' . $service_type
|
|
];
|
|
}
|
|
|
|
// response
|
|
return $this->json([
|
|
'success' => true,
|
|
'results' => $job_orders,
|
|
'pagination' => [
|
|
'more' => $has_more_pages
|
|
]
|
|
]);
|
|
}
|
|
|
|
protected function fillDropdownParameters(&$params)
|
|
{
|
|
$em = $this->getDoctrine()->getManager();
|
|
|
|
// db loaded
|
|
$params['bmfgs'] = $em->getRepository(BatteryManufacturer::class)->findAll();
|
|
$params['customers'] = $em->getRepository(Customer::class)->findAll();
|
|
$params['promos'] = $em->getRepository(Promo::class)->findAll();
|
|
|
|
// name values
|
|
$params['service_types'] = ServiceType::getCollection();
|
|
$params['warranty_classes'] = WarrantyClass::getCollection();
|
|
$params['modes_of_payment'] = ModeOfPayment::getCollection();
|
|
$params['statuses'] = JOStatus::getCollection();
|
|
$params['discount_apply'] = DiscountApply::getCollection();
|
|
$params['trade_in_types'] = TradeInType::getCollection();
|
|
$params['sources'] = TransactionOrigin::getCollection();
|
|
}
|
|
|
|
public function incomingForm()
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_in.list', null, 'No access.');
|
|
|
|
$params = $this->initParameters('jo_in');
|
|
$params['obj'] = new JobOrder();
|
|
$params['mode'] = 'create';
|
|
$params['submit_url'] = $this->generateUrl('jo_in_submit');
|
|
$params['return_url'] = $this->generateUrl('jo_in');
|
|
|
|
$em = $this->getDoctrine()->getManager();
|
|
|
|
$this->fillDropdownParameters($params);
|
|
|
|
// response
|
|
return $this->render('job-order/form.html.twig', $params);
|
|
}
|
|
|
|
public function incomingSubmit(Request $req, ValidatorInterface $validator, InvoiceCreator $ic)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_in.list', null, 'No access.');
|
|
|
|
// initialize error list
|
|
$error_array = [];
|
|
|
|
// create new row
|
|
$em = $this->getDoctrine()->getManager();
|
|
$obj = new JobOrder();
|
|
|
|
// check if lat and lng are provided
|
|
if (empty($req->request->get('coord_lng')) || empty($req->request->get('coord_lat'))) {
|
|
$error_array['coordinates'] = 'No map coordinates provided. Please click on a location on the map.';
|
|
}
|
|
|
|
// check if customer vehicle is set
|
|
if (empty($req->request->get('customer_vehicle'))) {
|
|
$error_array['customer_vehicle'] = 'No vehicle selected.';
|
|
} else {
|
|
// get customer vehicle
|
|
$cust_vehicle = $em->getRepository(CustomerVehicle::class)->find($req->request->get('customer_vehicle'));
|
|
|
|
if (empty($cust_vehicle)) {
|
|
$error_array['customer_vehicle'] = 'Invalid vehicle specified.';
|
|
}
|
|
}
|
|
|
|
if (empty($error_array)) {
|
|
// coordinates
|
|
$point = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat'));
|
|
|
|
$stype = $req->request->get('service_type');
|
|
|
|
// set and save values
|
|
$obj->setDateSchedule(DateTime::createFromFormat("d M Y h:i A", $req->request->get('date_schedule_date') . " " . $req->request->get('date_schedule_time')))
|
|
->setCoordinates($point)
|
|
->setAdvanceOrder($req->request->get('flag_advance') ?? false)
|
|
->setCreatedBy($this->getUser())
|
|
->setServiceType($stype)
|
|
->setWarrantyClass($req->request->get('warranty_class'))
|
|
->setCustomer($cust_vehicle->getCustomer())
|
|
->setCustomerVehicle($cust_vehicle)
|
|
->setSource($req->request->get('source'))
|
|
->setStatus(JOStatus::PENDING)
|
|
->setDeliveryInstructions($req->request->get('delivery_instructions'))
|
|
->setTier1Notes($req->request->get('tier1_notes'))
|
|
->setTier2Notes($req->request->get('tier2_notes'))
|
|
->setDeliveryAddress($req->request->get('delivery_address'))
|
|
->setORName($req->request->get('or_name'))
|
|
->setLandmark($req->request->get('landmark'));
|
|
|
|
// check if reference JO is set and validate
|
|
if (!empty($req->request->get('ref_jo'))) {
|
|
// get reference JO
|
|
$ref_jo = $em->getRepository(JobOrder::class)->find($req->request->get('ref_jo'));
|
|
|
|
if (empty($ref_jo)) {
|
|
$error_array['ref_jo'] = 'Invalid reference job order specified.';
|
|
} else {
|
|
$obj->setReferenceJO($ref_jo);
|
|
}
|
|
}
|
|
|
|
// instantiate invoice criteria
|
|
$criteria = new InvoiceCriteria();
|
|
$criteria->setServiceType($stype);
|
|
|
|
$ierror = $this->invoicePromo($em, $criteria, $req->request->get('invoice_promo'));
|
|
$invoice_items = $req->request->get('invoice_items');
|
|
|
|
if (!$ierror && !empty($invoice_items))
|
|
$ierror = $this->invoiceBatteries($em, $criteria, $invoice_items);
|
|
|
|
if ($ierror)
|
|
{
|
|
$error_array['invoice'] = $ierror;
|
|
}
|
|
else
|
|
{
|
|
// generate the invoice
|
|
$iobj = $ic->processCriteria($criteria);
|
|
$iobj->setStatus(InvoiceStatus::DRAFT)
|
|
->setCreatedBy($this->getUser());
|
|
|
|
// validate
|
|
$ierrors = $validator->validate($iobj);
|
|
|
|
// add errors to list
|
|
foreach ($ierrors as $error) {
|
|
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
|
}
|
|
|
|
// add invoice to JO
|
|
$obj->setInvoice($iobj);
|
|
|
|
// save
|
|
$em->persist($iobj);
|
|
}
|
|
|
|
// validate
|
|
$errors = $validator->validate($obj);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// validated! save the entity
|
|
$em->persist($obj);
|
|
$em->flush();
|
|
|
|
// return successful response
|
|
return $this->json([
|
|
'success' => 'Changes have been saved!'
|
|
]);
|
|
}
|
|
|
|
protected function checkTier($tier)
|
|
{
|
|
// check specified tier
|
|
switch ($tier) {
|
|
case 'proc':
|
|
$tier_key = 'jo_proc';
|
|
$tier_name = 'Dispatch';
|
|
$rows_route = 'jo_proc_rows';
|
|
$edit_route = 'jo_proc_form';
|
|
$unlock_route = 'jo_proc_unlock';
|
|
$jo_status = JOStatus::PENDING;
|
|
break;
|
|
case 'assign':
|
|
$tier_key = 'jo_assign';
|
|
$tier_name = 'Assigning';
|
|
$rows_route = 'jo_assign_rows';
|
|
$edit_route = 'jo_assign_form';
|
|
$unlock_route = 'jo_assign_unlock';
|
|
$jo_status = JOStatus::RIDER_ASSIGN;
|
|
break;
|
|
case 'fulfill':
|
|
$tier_key = 'jo_fulfill';
|
|
$tier_name = 'Fullfillment';
|
|
$rows_route = 'jo_fulfill_rows';
|
|
$edit_route = 'jo_fulfill_form';
|
|
$unlock_route = '';
|
|
$jo_status = [
|
|
JOStatus::ASSIGNED,
|
|
JOStatus::IN_PROGRESS
|
|
];
|
|
break;
|
|
case 'open':
|
|
$tier_key = 'jo_open';
|
|
$tier_name = 'Open';
|
|
$rows_route = 'jo_open_rows';
|
|
$edit_route = '';
|
|
$unlock_route = '';
|
|
$jo_status = [
|
|
JOStatus::PENDING,
|
|
JOStatus::RIDER_ASSIGN,
|
|
JOStatus::ASSIGNED,
|
|
JOStatus::IN_PROGRESS
|
|
];
|
|
break;
|
|
case 'all':
|
|
$tier_key = 'jo_open';
|
|
$tier_name = 'Open';
|
|
$rows_route = 'jo_open_rows';
|
|
$edit_route = 'jo_all_form';
|
|
$unlock_route = '';
|
|
$jo_status = '';
|
|
break;
|
|
default:
|
|
$exception = $this->createAccessDeniedException('No access.');
|
|
throw $exception;
|
|
}
|
|
|
|
// check acl
|
|
$this->denyAccessUnlessGranted($tier_key . '.list', null, 'No access.');
|
|
|
|
// return params if allowed access
|
|
return [
|
|
'key' => $tier_key,
|
|
'name' => $tier_name,
|
|
'rows_route' => $rows_route,
|
|
'edit_route' => $edit_route,
|
|
'unlock_route' => $unlock_route,
|
|
'jo_status' => $jo_status
|
|
];
|
|
}
|
|
|
|
public function listAssigning()
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_assign.list', null, 'No access.');
|
|
|
|
$params = $this->initParameters('jo_assign');
|
|
|
|
$params['table_refresh_rate'] = $this->container->getParameter('job_order_refresh_interval');
|
|
|
|
return $this->render('job-order/list.assigning.html.twig', $params);
|
|
}
|
|
|
|
public function listFulfillment()
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_fulfill.list', null, 'No access.');
|
|
|
|
$params = $this->initParameters('jo_fulfill');
|
|
|
|
$params['table_refresh_rate'] = $this->container->getParameter('job_order_refresh_interval');
|
|
|
|
return $this->render('job-order/list.fulfillment.html.twig', $params);
|
|
}
|
|
|
|
public function listOpen()
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_open.list', null, 'No access.');
|
|
|
|
$params = $this->initParameters('jo_open');
|
|
|
|
$params['table_refresh_rate'] = $this->container->getParameter('job_order_refresh_interval');
|
|
$params['statuses'] = JOStatus::getCollection();
|
|
|
|
return $this->render('job-order/list.open.html.twig', $params);
|
|
}
|
|
|
|
public function listAll()
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_all.list', null, 'No access.');
|
|
|
|
$params = $this->initParameters('jo_all');
|
|
|
|
$params['table_refresh_rate'] = $this->container->getParameter('job_order_refresh_interval');
|
|
|
|
return $this->render('job-order/list.all.html.twig', $params);
|
|
}
|
|
|
|
public function listRows($tier)
|
|
{
|
|
// check which job order tier is being called for and confirm access
|
|
$tier_params = $this->checkTier($tier);
|
|
|
|
$params = $this->initParameters($tier_params['key']);
|
|
|
|
$params['tier_name'] = $tier_params['name'];
|
|
$params['rows_route'] = $tier_params['rows_route'];
|
|
$params['table_refresh_rate'] = $this->container->getParameter('job_order_refresh_interval');
|
|
|
|
// response
|
|
return $this->render('job-order/list.html.twig', $params);
|
|
}
|
|
|
|
public function getRows(Request $req, $tier)
|
|
{
|
|
// check which job order tier is being called for and confirm access
|
|
$tier_params = $this->checkTier($tier);
|
|
|
|
// get current user
|
|
$user = $this->getUser();
|
|
$hubs = $user->getHubs();
|
|
|
|
// get query builder
|
|
$qb = $this->getDoctrine()
|
|
->getRepository(JobOrder::class)
|
|
->createQueryBuilder('q');
|
|
|
|
// get datatable params
|
|
$datatable = $req->request->get('datatable');
|
|
|
|
// count total records
|
|
$tquery = $qb->select('COUNT(q)');
|
|
|
|
$this->setQueryFilters($datatable, $tquery, $qb, $hubs, $tier, $tier_params['jo_status']);
|
|
|
|
$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');
|
|
|
|
$this->setQueryFilters($datatable, $query, $qb, $hubs, $tier, $tier_params['jo_status']);
|
|
|
|
// 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.date_schedule', 'asc');
|
|
}
|
|
|
|
// get rows for this page
|
|
$obj_rows = $query->setFirstResult($offset)
|
|
->setMaxResults($perpage)
|
|
->getQuery()
|
|
->getResult();
|
|
|
|
$statuses = JOStatus::getCollection();
|
|
$service_types = ServiceType::getCollection();
|
|
|
|
// process rows
|
|
$rows = [];
|
|
foreach ($obj_rows as $orow) {
|
|
// add row data
|
|
$row['id'] = $orow->getID();
|
|
$row['delivery_address'] = $orow->getDeliveryAddress();
|
|
$row['date_schedule'] = $orow->isAdvanceOrder() ? $orow->getDateSchedule()->format("d M Y g:i A") : 'Immediate';
|
|
$row['service_type'] = $service_types[$orow->getServiceType()];
|
|
$row['status'] = $statuses[$orow->getStatus()];
|
|
$row['flag_advance'] = $orow->isAdvanceOrder();
|
|
|
|
$processor = $orow->getProcessedBy();
|
|
if ($processor == null)
|
|
$row['processor'] = '';
|
|
else
|
|
$row['processor'] = $orow->getProcessedBy()->getFullName();
|
|
|
|
$assignor = $orow->getAssignedBy();
|
|
if ($assignor == null)
|
|
$row['assignor'] = '';
|
|
else
|
|
$row['assignor'] = $orow->getAssignedBy()->getFullName();
|
|
|
|
// add crud urls
|
|
if ($tier == 'open')
|
|
{
|
|
$row['meta']['reassign_hub_url'] = $this->generateUrl('jo_open_hub_form', ['id' => $row['id']]);
|
|
$row['meta']['reassign_rider_url'] = $this->generateUrl('jo_open_rider_form', ['id' => $row['id']]);
|
|
}
|
|
else
|
|
{
|
|
$row['meta']['update_url'] = $this->generateUrl($tier_params['edit_route'], ['id' => $row['id']]);
|
|
}
|
|
|
|
if ($tier_params['unlock_route'] != '')
|
|
$row['meta']['unlock_url'] = $this->generateUrl($tier_params['unlock_route'], ['id' => $row['id']]);
|
|
|
|
$rows[] = $row;
|
|
}
|
|
|
|
// response
|
|
return $this->json([
|
|
'meta' => $meta,
|
|
'data' => $rows
|
|
]);
|
|
}
|
|
|
|
public function processingForm(MapTools $map_tools, $id)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_proc.list', null, 'No access.');
|
|
|
|
$em = $this->getDoctrine()->getManager();
|
|
|
|
// manual transaction since we're locking
|
|
$em->getConnection()->beginTransaction();
|
|
|
|
try
|
|
{
|
|
|
|
// lock and get data
|
|
$obj = $em->getRepository(JobOrder::class)->find($id, LockMode::PESSIMISTIC_READ);
|
|
|
|
// make sure this job order exists
|
|
if (empty($obj))
|
|
{
|
|
$em->getConnection()->rollback();
|
|
throw $this->createNotFoundException('The job order does not exist');
|
|
}
|
|
|
|
// check status
|
|
if ($obj->getStatus() != JOStatus::PENDING)
|
|
{
|
|
$em->getConnection()->rollback();
|
|
throw $this->createNotFoundException('The job order does not have a pending status');
|
|
}
|
|
|
|
// check if we are the processor
|
|
$processor = $obj->getProcessedBy();
|
|
$user = $this->getUser();
|
|
// TODO: go back to list page and display alert / flash that says they cannot access it because they
|
|
// are not the processor
|
|
if ($processor != null && $processor->getID() != $user->getID())
|
|
{
|
|
$em->getConnection()->rollback();
|
|
throw $this->createAccessDeniedException('Not the processor');
|
|
}
|
|
|
|
// make this user be the processor
|
|
$obj->setProcessedBy($user);
|
|
$em->flush();
|
|
|
|
$em->getConnection()->commit();
|
|
}
|
|
catch(PessimisticLockException $e)
|
|
{
|
|
throw $this->createAccessDeniedException('Not the processor');
|
|
}
|
|
|
|
// NOTE: we are able to lock, everything should be fine now
|
|
|
|
$params = $this->initParameters('jo_proc');
|
|
$params['mode'] = 'update-processing';
|
|
$params['status_cancelled'] = JOStatus::CANCELLED;
|
|
|
|
$this->fillDropdownParameters($params);
|
|
|
|
// get closest hubs
|
|
$hubs = $map_tools->getClosestHubs($obj->getCoordinates(), 10, date("H:i:s"));
|
|
|
|
$params['hubs'] = [];
|
|
|
|
// format duration and distance into friendly time
|
|
foreach ($hubs as $hub) {
|
|
// duration
|
|
$seconds = $hub['duration'];
|
|
|
|
if (!empty($seconds) && $seconds > 0) {
|
|
$hours = floor($seconds / 3600);
|
|
$minutes = ceil(($seconds / 60) % 60);
|
|
|
|
$hub['duration'] = ($hours > 0 ? number_format($hours) . " hr" . ($hours > 1 ? "s" : '') . ($minutes > 0 ? ", " : '') : '') . ($minutes > 0 ? number_format($minutes) . " min" . ($minutes > 1 ? "s" : '') : '');
|
|
} else {
|
|
$hub['duration'] = false;
|
|
}
|
|
|
|
// distance
|
|
$meters = $hub['distance'];
|
|
|
|
if (!empty($meters) && $meters > 0) {
|
|
$hub['distance'] = round($meters / 1000) . " km";
|
|
} else {
|
|
$hub['distance'] = false;
|
|
}
|
|
|
|
$params['hubs'][] = $hub;
|
|
}
|
|
|
|
$params['obj'] = $obj;
|
|
$params['submit_url'] = $this->generateUrl('jo_proc_submit', ['id' => $obj->getID()]);
|
|
$params['return_url'] = $this->generateUrl('jo_proc');
|
|
|
|
// response
|
|
return $this->render('job-order/form.html.twig', $params);
|
|
}
|
|
|
|
public function processingSubmit(Request $req, ValidatorInterface $validator, $id)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_proc.list', null, 'No access.');
|
|
|
|
// get object data
|
|
$em = $this->getDoctrine()->getManager();
|
|
$obj = $em->getRepository(JobOrder::class)->find($id);
|
|
$processor = $obj->getProcessedBy();
|
|
$user = $this->getUser();
|
|
|
|
// check if we're the one processing, return error otherwise
|
|
if ($processor == null)
|
|
throw $this->createAccessDeniedException('Not the processor');
|
|
|
|
if ($processor != null && $processor->getID() != $user->getID())
|
|
throw $this->createAccessDeniedException('Not the processor');
|
|
|
|
// initialize error list
|
|
$error_array = [];
|
|
|
|
|
|
// make sure this object exists
|
|
if (empty($obj))
|
|
throw $this->createNotFoundException('The item does not exist');
|
|
|
|
// check if lat and lng are provided
|
|
if (empty($req->request->get('coord_lng')) || empty($req->request->get('coord_lat'))) {
|
|
$error_array['coordinates'] = 'No map coordinates provided. Please click on a location on the map.';
|
|
}
|
|
|
|
// check if hub is set
|
|
if (empty($req->request->get('hub'))) {
|
|
$error_array['hub'] = 'No hub selected.';
|
|
} else {
|
|
// get hub
|
|
$hub = $em->getRepository(Hub::class)->find($req->request->get('hub'));
|
|
|
|
if (empty($hub)) {
|
|
$error_array['hub'] = 'Invalid hub specified.';
|
|
}
|
|
}
|
|
|
|
if (empty($error_array)) {
|
|
// coordinates
|
|
$point = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat'));
|
|
|
|
// set and save values
|
|
$obj->setDateSchedule(DateTime::createFromFormat("d M Y h:i A", $req->request->get('date_schedule_date') . " " . $req->request->get('date_schedule_time')))
|
|
->setCoordinates($point)
|
|
->setAdvanceOrder($req->request->get('flag_advance') ?? false)
|
|
->setServiceType($req->request->get('service_type'))
|
|
->setWarrantyClass($req->request->get('warranty_class'))
|
|
->setSource($req->request->get('source'))
|
|
->setStatus(JOStatus::RIDER_ASSIGN)
|
|
->setDeliveryInstructions($req->request->get('delivery_instructions'))
|
|
->setTier1Notes($req->request->get('tier1_notes'))
|
|
->setTier2Notes($req->request->get('tier2_notes'))
|
|
->setDeliveryAddress($req->request->get('delivery_address'))
|
|
->setHub($hub);
|
|
|
|
// validate
|
|
$errors = $validator->validate($obj);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// validated! save the entity
|
|
$em->flush();
|
|
|
|
// return successful response
|
|
return $this->json([
|
|
'success' => 'Changes have been saved!'
|
|
]);
|
|
}
|
|
|
|
public function assigningForm(MapTools $map_tools, $id)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_assign.list', null, 'No access.');
|
|
|
|
$em = $this->getDoctrine()->getManager();
|
|
|
|
// manual transaction since we're locking
|
|
$em->getConnection()->beginTransaction();
|
|
|
|
$params = $this->initParameters('jo_assign');
|
|
$params['mode'] = 'update-assigning';
|
|
|
|
try
|
|
{
|
|
// get row data
|
|
$obj = $em->getRepository(JobOrder::class)->find($id);
|
|
|
|
// make sure this row exists
|
|
if (empty($obj))
|
|
{
|
|
$em->getConnection()->rollback();
|
|
throw $this->createNotFoundException('The job order does not exist');
|
|
}
|
|
|
|
// check status
|
|
if ($obj->getStatus() != JOStatus::RIDER_ASSIGN)
|
|
{
|
|
$em->getConnection()->rollback();
|
|
throw $this->createNotFoundException('The job order does not have an assigning status');
|
|
}
|
|
|
|
// check if hub is assigned to current user
|
|
$user_hubs = $this->getUser()->getHubs();
|
|
if (!in_array($obj->getHub()->getID(), $user_hubs))
|
|
{
|
|
$em->getConnection()->rollback();
|
|
throw $this->createNotFoundException('The job order is not on a hub assigned to this user');
|
|
}
|
|
|
|
// check if we are the assignor
|
|
$assignor = $obj->getAssignedBy();
|
|
$user = $this->getUser();
|
|
|
|
if ($assignor != null && $assignor->getID() != $user->getID())
|
|
{
|
|
$em->getConnection()->rollback();
|
|
throw $this->createAccessDeniedException('Not the assignor');
|
|
}
|
|
|
|
// make this user be the assignor
|
|
$obj->setAssignedBy($user);
|
|
$em->flush();
|
|
|
|
$em->getConnection()->commit();
|
|
}
|
|
catch (PessimisticLockException $e)
|
|
{
|
|
throw $this->createAccessDeniedException('Not the assignor');
|
|
}
|
|
|
|
$this->fillDropdownParameters($params);
|
|
|
|
$params['obj'] = $obj;
|
|
$params['status_cancelled'] = JOStatus::CANCELLED;
|
|
$params['submit_url'] = $this->generateUrl('jo_assign_submit', ['id' => $obj->getID()]);
|
|
$params['return_url'] = $this->generateUrl('jo_assign');
|
|
|
|
// response
|
|
return $this->render('job-order/form.html.twig', $params);
|
|
}
|
|
|
|
public function assigningSubmit(Request $req, ValidatorInterface $validator, $id)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_assign.list', null, 'No access.');
|
|
|
|
// initialize error list
|
|
$error_array = [];
|
|
|
|
// get object data
|
|
$em = $this->getDoctrine()->getManager();
|
|
$obj = $em->getRepository(JobOrder::class)->find($id);
|
|
|
|
// make sure this object exists
|
|
if (empty($obj))
|
|
throw $this->createNotFoundException('The item does not exist');
|
|
|
|
// check if lat and lng are provided
|
|
if (empty($req->request->get('coord_lng')) || empty($req->request->get('coord_lat'))) {
|
|
$error_array['coordinates'] = 'No map coordinates provided. Please click on a location on the map.';
|
|
}
|
|
|
|
// check if rider is set
|
|
if (empty($req->request->get('rider'))) {
|
|
$error_array['rider'] = 'No rider selected.';
|
|
} else {
|
|
// get rider
|
|
$rider = $em->getRepository(Rider::class)->find($req->request->get('rider'));
|
|
|
|
if (empty($rider)) {
|
|
$error_array['rider'] = 'Invalid rider specified.';
|
|
}
|
|
}
|
|
|
|
if (empty($error_array)) {
|
|
// coordinates
|
|
$point = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat'));
|
|
|
|
// set and save values
|
|
$obj->setDateSchedule(DateTime::createFromFormat("d M Y h:i A", $req->request->get('date_schedule_date') . " " . $req->request->get('date_schedule_time')))
|
|
->setCoordinates($point)
|
|
->setAdvanceOrder($req->request->get('flag_advance') ?? false)
|
|
->setServiceType($req->request->get('service_type'))
|
|
->setWarrantyClass($req->request->get('warranty_class'))
|
|
->setSource($req->request->get('source'))
|
|
->setStatus(JOStatus::ASSIGNED)
|
|
->setDeliveryInstructions($req->request->get('delivery_instructions'))
|
|
->setTier1Notes($req->request->get('tier1_notes'))
|
|
->setTier2Notes($req->request->get('tier2_notes'))
|
|
->setDeliveryAddress($req->request->get('delivery_address'))
|
|
->setAssignedBy($this->getUser())
|
|
->setDateAssign(new DateTime())
|
|
->setRider($rider);
|
|
|
|
// validate
|
|
$errors = $validator->validate($obj);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// validated! save the entity
|
|
$em->flush();
|
|
|
|
// send event to mobile app
|
|
$payload = [
|
|
'event' => 'driver_assigned'
|
|
];
|
|
$this->sendEvent($obj, $payload);
|
|
|
|
// return successful response
|
|
return $this->json([
|
|
'success' => 'Changes have been saved!'
|
|
]);
|
|
}
|
|
|
|
public function fulfillmentForm(MapTools $map_tools, $id)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_fulfill.list', null, 'No access.');
|
|
|
|
$em = $this->getDoctrine()->getManager();
|
|
|
|
$params = $this->initParameters('jo_fulfill');
|
|
$params['mode'] = 'update-fulfillment';
|
|
|
|
// get row data
|
|
$obj = $em->getRepository(JobOrder::class)->find($id);
|
|
|
|
// make sure this row exists
|
|
if (empty($obj))
|
|
{
|
|
throw $this->createNotFoundException('The job order does not exist');
|
|
}
|
|
|
|
// check status
|
|
if (!in_array($obj->getStatus(), [JOStatus::ASSIGNED, JOStatus::IN_PROGRESS]))
|
|
{
|
|
throw $this->createNotFoundException('The job order does not have a fulfillment status');
|
|
}
|
|
|
|
// check if hub is assigned to current user
|
|
$user_hubs = $this->getUser()->getHubs();
|
|
if (!in_array($obj->getHub()->getID(), $user_hubs))
|
|
{
|
|
throw $this->createNotFoundException('The job order is not on a hub assigned to this user');
|
|
}
|
|
|
|
$this->fillDropdownParameters($params);
|
|
|
|
$params['obj'] = $obj;
|
|
$params['status_cancelled'] = JOStatus::CANCELLED;
|
|
$params['submit_url'] = $this->generateUrl('jo_fulfill_submit', ['id' => $obj->getID()]);
|
|
$params['return_url'] = $this->generateUrl('jo_fulfill');
|
|
|
|
// response
|
|
return $this->render('job-order/form.html.twig', $params);
|
|
}
|
|
|
|
public function fulfillmentSubmit(Request $req, ValidatorInterface $validator, $id)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_fulfill.list', null, 'No access.');
|
|
|
|
// initialize error list
|
|
$error_array = [];
|
|
|
|
// get object data
|
|
$em = $this->getDoctrine()->getManager();
|
|
$obj = $em->getRepository(JobOrder::class)->find($id);
|
|
|
|
// make sure this object exists
|
|
if (empty($obj))
|
|
throw $this->createNotFoundException('The item does not exist');
|
|
|
|
// check if lat and lng are provided
|
|
if (empty($req->request->get('coord_lng')) || empty($req->request->get('coord_lat'))) {
|
|
$error_array['coordinates'] = 'No map coordinates provided. Please click on a location on the map.';
|
|
}
|
|
|
|
if (empty($error_array)) {
|
|
// coordinates
|
|
$point = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat'));
|
|
|
|
// set and save values
|
|
$obj->setDateSchedule(DateTime::createFromFormat("d M Y h:i A", $req->request->get('date_schedule_date') . " " . $req->request->get('date_schedule_time')))
|
|
->setCoordinates($point)
|
|
->setAdvanceOrder($req->request->get('flag_advance') ?? false)
|
|
->setServiceType($req->request->get('service_type'))
|
|
->setWarrantyClass($req->request->get('warranty_class'))
|
|
->setSource($req->request->get('source'))
|
|
->setStatus(JOStatus::FULFILLED)
|
|
->setDeliveryInstructions($req->request->get('delivery_instructions'))
|
|
->setTier1Notes($req->request->get('tier1_notes'))
|
|
->setTier2Notes($req->request->get('tier2_notes'))
|
|
->setDeliveryAddress($req->request->get('delivery_address'));
|
|
|
|
// validate
|
|
$errors = $validator->validate($obj);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// validated! save the entity
|
|
$em->flush();
|
|
|
|
// get rider
|
|
$rider = $obj->getRider();
|
|
|
|
$image_url = $req->getScheme() . '://' . $req->getHttpHost() . $req->getBasePath() . '/assets/images/user.gif';
|
|
if ($rider->getImageFile() != null)
|
|
$image_url = $req->getScheme() . '://' . $req->getHttpHost() . $req->getBasePath() . '/uploads/' . $rider->getImageFile();
|
|
|
|
// send to mqtt
|
|
$payload = [
|
|
'event' => 'fulfilled',
|
|
'jo_id' => $obj->getID(),
|
|
'driver_image' => $image_url,
|
|
'driver_name' => $rider->getFullName(),
|
|
'driver_id' => $rider->getID(),
|
|
];
|
|
$this->sendEvent($obj, $payload);
|
|
|
|
// return successful response
|
|
return $this->json([
|
|
'success' => 'Changes have been saved!'
|
|
]);
|
|
}
|
|
|
|
protected function sendEvent(JobOrder $job_order, $payload)
|
|
{
|
|
$session = $job_order->getCustomer()->getMobileSessions();
|
|
if (count($session) == 0)
|
|
return;
|
|
|
|
$phone_num = $session[0]->getPhoneNumber();
|
|
$channel = 'motolite.control.' . $phone_num;
|
|
$client = new MosquittoClient();
|
|
$client->connect('localhost', 1883);
|
|
$client->publish($channel, json_encode($payload));
|
|
$client->disconnect();
|
|
}
|
|
|
|
public function openHubForm(MapTools $map_tools, $id)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_open.list', null, 'No access.');
|
|
|
|
$em = $this->getDoctrine()->getManager();
|
|
|
|
$params = $this->initParameters('jo_open');
|
|
$params['mode'] = 'update-reassign-hub';
|
|
|
|
// get row data
|
|
$obj = $em->getRepository(JobOrder::class)->find($id);
|
|
|
|
// make sure this row exists
|
|
if (empty($obj))
|
|
{
|
|
throw $this->createNotFoundException('The job order does not exist');
|
|
}
|
|
|
|
$this->fillDropdownParameters($params);
|
|
|
|
// get closest hubs
|
|
$hubs = $map_tools->getClosestHubs($obj->getCoordinates(), 10, date("H:i:s"));
|
|
|
|
$params['status_cancelled'] = JOStatus::CANCELLED;
|
|
$params['hubs'] = [];
|
|
|
|
// format duration and distance into friendly time
|
|
foreach ($hubs as $hub) {
|
|
// duration
|
|
$seconds = $hub['duration'];
|
|
|
|
if (!empty($seconds) && $seconds > 0) {
|
|
$hours = floor($seconds / 3600);
|
|
$minutes = ceil(($seconds / 60) % 60);
|
|
|
|
$hub['duration'] = ($hours > 0 ? number_format($hours) . " hr" . ($hours > 1 ? "s" : '') . ($minutes > 0 ? ", " : '') : '') . ($minutes > 0 ? number_format($minutes) . " min" . ($minutes > 1 ? "s" : '') : '');
|
|
} else {
|
|
$hub['duration'] = false;
|
|
}
|
|
|
|
// distance
|
|
$meters = $hub['distance'];
|
|
|
|
if (!empty($meters) && $meters > 0) {
|
|
$hub['distance'] = round($meters / 1000) . " km";
|
|
} else {
|
|
$hub['distance'] = false;
|
|
}
|
|
|
|
$params['hubs'][] = $hub;
|
|
}
|
|
|
|
$params['obj'] = $obj;
|
|
$params['submit_url'] = $this->generateUrl('jo_open_hub_submit', ['id' => $obj->getID()]);
|
|
$params['return_url'] = $this->generateUrl('jo_open');
|
|
|
|
// response
|
|
return $this->render('job-order/form.html.twig', $params);
|
|
}
|
|
|
|
public function openHubSubmit(Request $req, ValidatorInterface $validator, $id)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_open.list', null, 'No access.');
|
|
|
|
// get object data
|
|
$em = $this->getDoctrine()->getManager();
|
|
$obj = $em->getRepository(JobOrder::class)->find($id);
|
|
$user = $this->getUser();
|
|
|
|
// initialize error list
|
|
$error_array = [];
|
|
|
|
// make sure this object exists
|
|
if (empty($obj))
|
|
throw $this->createNotFoundException('The item does not exist');
|
|
|
|
// check if lat and lng are provided
|
|
if (empty($req->request->get('coord_lng')) || empty($req->request->get('coord_lat'))) {
|
|
$error_array['coordinates'] = 'No map coordinates provided. Please click on a location on the map.';
|
|
}
|
|
|
|
// check if hub is set
|
|
if (empty($req->request->get('hub'))) {
|
|
$error_array['hub'] = 'No hub selected.';
|
|
} else {
|
|
// get hub
|
|
$hub = $em->getRepository(Hub::class)->find($req->request->get('hub'));
|
|
|
|
if (empty($hub)) {
|
|
$error_array['hub'] = 'Invalid hub specified.';
|
|
}
|
|
}
|
|
|
|
if (empty($error_array)) {
|
|
// coordinates
|
|
$point = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat'));
|
|
|
|
// set and save values
|
|
$obj->setDateSchedule(DateTime::createFromFormat("d M Y h:i A", $req->request->get('date_schedule_date') . " " . $req->request->get('date_schedule_time')))
|
|
->setCoordinates($point)
|
|
->setAdvanceOrder($req->request->get('flag_advance') ?? false)
|
|
->setServiceType($req->request->get('service_type'))
|
|
->setWarrantyClass($req->request->get('warranty_class'))
|
|
->setSource($req->request->get('source'))
|
|
->setStatus(JOStatus::RIDER_ASSIGN)
|
|
->setDeliveryInstructions($req->request->get('delivery_instructions'))
|
|
->setTier1Notes($req->request->get('tier1_notes'))
|
|
->setTier2Notes($req->request->get('tier2_notes'))
|
|
->setDeliveryAddress($req->request->get('delivery_address'))
|
|
->setHub($hub)
|
|
->clearRider();
|
|
|
|
// validate
|
|
$errors = $validator->validate($obj);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// validated! save the entity
|
|
$em->flush();
|
|
|
|
// return successful response
|
|
return $this->json([
|
|
'success' => 'Changes have been saved!'
|
|
]);
|
|
}
|
|
|
|
public function openRiderForm($id)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_open.list', null, 'No access.');
|
|
|
|
$em = $this->getDoctrine()->getManager();
|
|
|
|
$params = $this->initParameters('jo_open');
|
|
$params['mode'] = 'update-reassign-rider';
|
|
|
|
// get row data
|
|
$obj = $em->getRepository(JobOrder::class)->find($id);
|
|
|
|
// make sure this row exists
|
|
if (empty($obj))
|
|
{
|
|
$em->getConnection()->rollback();
|
|
throw $this->createNotFoundException('The job order does not exist');
|
|
}
|
|
|
|
// check status
|
|
if ($obj->getStatus() == JOStatus::PENDING)
|
|
{
|
|
$em->getConnection()->rollback();
|
|
throw $this->createNotFoundException('The job order does not have an assigned hub');
|
|
}
|
|
|
|
$this->fillDropdownParameters($params);
|
|
|
|
$params['obj'] = $obj;
|
|
$params['status_cancelled'] = JOStatus::CANCELLED;
|
|
$params['submit_url'] = $this->generateUrl('jo_open_rider_submit', ['id' => $obj->getID()]);
|
|
$params['return_url'] = $this->generateUrl('jo_open');
|
|
|
|
// response
|
|
return $this->render('job-order/form.html.twig', $params);
|
|
}
|
|
|
|
public function openRiderSubmit(Request $req, ValidatorInterface $validator, $id)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_open.list', null, 'No access.');
|
|
|
|
// initialize error list
|
|
$error_array = [];
|
|
|
|
// get object data
|
|
$em = $this->getDoctrine()->getManager();
|
|
$obj = $em->getRepository(JobOrder::class)->find($id);
|
|
|
|
// make sure this object exists
|
|
if (empty($obj))
|
|
throw $this->createNotFoundException('The item does not exist');
|
|
|
|
// check if lat and lng are provided
|
|
if (empty($req->request->get('coord_lng')) || empty($req->request->get('coord_lat'))) {
|
|
$error_array['coordinates'] = 'No map coordinates provided. Please click on a location on the map.';
|
|
}
|
|
|
|
// check if rider is set
|
|
if (empty($req->request->get('rider'))) {
|
|
$error_array['rider'] = 'No rider selected.';
|
|
} else {
|
|
// get rider
|
|
$rider = $em->getRepository(Rider::class)->find($req->request->get('rider'));
|
|
|
|
if (empty($rider)) {
|
|
$error_array['rider'] = 'Invalid rider specified.';
|
|
}
|
|
}
|
|
|
|
if (empty($error_array)) {
|
|
// coordinates
|
|
$point = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat'));
|
|
|
|
// set and save values
|
|
$obj->setDateSchedule(DateTime::createFromFormat("d M Y h:i A", $req->request->get('date_schedule_date') . " " . $req->request->get('date_schedule_time')))
|
|
->setCoordinates($point)
|
|
->setAdvanceOrder($req->request->get('flag_advance') ?? false)
|
|
->setServiceType($req->request->get('service_type'))
|
|
->setWarrantyClass($req->request->get('warranty_class'))
|
|
->setSource($req->request->get('source'))
|
|
->setStatus(JOStatus::ASSIGNED)
|
|
->setDeliveryInstructions($req->request->get('delivery_instructions'))
|
|
->setTier1Notes($req->request->get('tier1_notes'))
|
|
->setTier2Notes($req->request->get('tier2_notes'))
|
|
->setDeliveryAddress($req->request->get('delivery_address'))
|
|
->setAssignedBy($this->getUser())
|
|
->setDateAssign(new DateTime())
|
|
->setRider($rider);
|
|
|
|
// validate
|
|
$errors = $validator->validate($obj);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// validated! save the entity
|
|
$em->flush();
|
|
|
|
// return successful response
|
|
return $this->json([
|
|
'success' => 'Changes have been saved!'
|
|
]);
|
|
}
|
|
|
|
public function allForm($id)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_all.list', null, 'No access.');
|
|
|
|
$em = $this->getDoctrine()->getManager();
|
|
|
|
$params = $this->initParameters('jo_all');
|
|
$params['mode'] = 'update-all';
|
|
|
|
// get row data
|
|
$obj = $em->getRepository(JobOrder::class)->find($id);
|
|
|
|
// make sure this row exists
|
|
if (empty($obj))
|
|
throw $this->createNotFoundException('The job order does not exist');
|
|
|
|
$this->fillDropdownParameters($params);
|
|
|
|
$params['obj'] = $obj;
|
|
$params['status_cancelled'] = JOStatus::CANCELLED;
|
|
$params['return_url'] = $this->generateUrl('jo_all');
|
|
$params['submit_url'] = '';
|
|
|
|
// timeline stuff (descending by time)
|
|
$params['timeline'] = [
|
|
[
|
|
'date' => date("M j"),
|
|
'time' => date("g:i A"),
|
|
'event' => "Event 4",
|
|
'color' => "#f4516c"
|
|
],
|
|
[
|
|
'date' => date("M j"),
|
|
'time' => date("g:i A"),
|
|
'event' => "Event 3",
|
|
'color' => "#34bfa3"
|
|
],
|
|
[
|
|
'date' => date("M j"),
|
|
'time' => date("g:i A"),
|
|
'event' => "Event 2",
|
|
'color' => "#716aca"
|
|
],
|
|
[
|
|
'date' => date("M j"),
|
|
'time' => date("g:i A"),
|
|
'event' => "Event 1",
|
|
'color' => "#ffb822"
|
|
],
|
|
];
|
|
|
|
// response
|
|
return $this->render('job-order/form.html.twig', $params);
|
|
}
|
|
|
|
public function cancelJobOrder(Request $req, $id)
|
|
{
|
|
$this->denyAccessUnlessGranted('joborder.cancel', null, 'No access.');
|
|
|
|
$cancel_reason = $req->request->get('cancel_reason');
|
|
|
|
if (empty($cancel_reason))
|
|
{
|
|
// something happened
|
|
return $this->json([
|
|
'success' => false,
|
|
'error' => 'Reason for cancellation is required.'
|
|
], 422);
|
|
}
|
|
|
|
// get object data
|
|
$em = $this->getDoctrine()->getManager();
|
|
$obj = $em->getRepository(JobOrder::class)->find($id);
|
|
|
|
// make sure this object exists
|
|
if (empty($obj))
|
|
throw $this->createNotFoundException('The item does not exist');
|
|
|
|
// cancel job order
|
|
$obj->setStatus(JOStatus::CANCELLED)
|
|
->setCancelReason($cancel_reason);
|
|
|
|
// save
|
|
$em->flush();
|
|
|
|
// return successful response
|
|
return $this->json([
|
|
'success' => 'Job order has been cancelled!'
|
|
]);
|
|
}
|
|
|
|
// TODO: re-enable search, figure out how to group the orWhere filters into one, so can execute that plus the pending filter
|
|
// check if datatable filter is present and append to query
|
|
protected function setQueryFilters($datatable, &$query, $qb, $hubs, $tier, $status)
|
|
{
|
|
switch ($tier)
|
|
{
|
|
case 'fulfill':
|
|
$query->where('q.status IN (:statuses)')
|
|
->andWhere('q.hub IN (:hubs)')
|
|
->setParameter('statuses', $status, Connection::PARAM_STR_ARRAY)
|
|
->setParameter('hubs', $hubs, Connection::PARAM_STR_ARRAY);
|
|
break;
|
|
case 'assign':
|
|
$query->where('q.status = :status')
|
|
->andWhere('q.hub IN (:hubs)')
|
|
->setParameter('status', $status)
|
|
->setParameter('hubs', $hubs, Connection::PARAM_STR_ARRAY);
|
|
break;
|
|
case 'open':
|
|
$query->where('q.status IN (:statuses)')
|
|
->setParameter('statuses', $status, Connection::PARAM_STR_ARRAY);
|
|
break;
|
|
case 'all':
|
|
break;
|
|
default:
|
|
$query->where('q.status = :status')
|
|
->setParameter('status', $status);
|
|
}
|
|
|
|
// get only pending rows
|
|
/*
|
|
$query->where($qb->expr()->orX(
|
|
$qb->expr()where('q.status', 'pending');
|
|
));
|
|
|
|
|
|
// apply filters
|
|
if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) {
|
|
$query->where('q.delivery_address LIKE :filter')
|
|
->orWhere($qb->expr()->concat('c.first_name', $qb->expr()->literal(' '), 'c.last_name') . ' LIKE :filter')
|
|
->orWhere('cv.plate_number LIKE :filter')
|
|
->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%');
|
|
}
|
|
*/
|
|
}
|
|
|
|
protected function invoicePromo($em, InvoiceCriteria $criteria, $promo_id)
|
|
{
|
|
// return error if there's a problem, false otherwise
|
|
|
|
// check service type
|
|
$stype = $criteria->getServiceType();
|
|
if ($stype != ServiceType::BATTERY_REPLACEMENT_NEW)
|
|
return null;
|
|
|
|
|
|
if (empty($promo_id))
|
|
return false;
|
|
|
|
// check if this is a valid promo
|
|
$promo = $em->getRepository(Promo::class)->find($promo_id);
|
|
|
|
if (empty($promo))
|
|
return 'Invalid promo specified.';
|
|
|
|
$criteria->addPromo($promo);
|
|
return false;
|
|
}
|
|
|
|
protected function invoiceBatteries($em, InvoiceCriteria $criteria, $items)
|
|
{
|
|
// check service type
|
|
$stype = $criteria->getServiceType();
|
|
if ($stype != ServiceType::BATTERY_REPLACEMENT_NEW && $stype != ServiceType::BATTERY_REPLACEMENT_WARRANTY)
|
|
return null;
|
|
|
|
// return error if there's a problem, false otherwise
|
|
if (!empty($items))
|
|
{
|
|
foreach ($items as $item)
|
|
{
|
|
// check if this is a valid battery
|
|
$battery = $em->getRepository(Battery::class)->find($item['battery']);
|
|
|
|
if (empty($battery))
|
|
{
|
|
$error = 'Invalid battery specified.';
|
|
return $error;
|
|
}
|
|
|
|
// quantity
|
|
$qty = $item['quantity'];
|
|
if ($qty < 1)
|
|
continue;
|
|
|
|
// add to criteria
|
|
$criteria->addBattery($battery, $qty);
|
|
|
|
// if this is a trade in, add trade in
|
|
if (!empty($item['trade_in']) && TradeInType::validate($item['trade_in']))
|
|
$criteria->addTradeIn($item['trade_in'] == 'motolite', $qty);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function generateInvoice(Request $req, InvoiceCreator $ic)
|
|
{
|
|
error_log('generating invoice...');
|
|
$error = false;
|
|
|
|
$stype = $req->request->get('stype');
|
|
$items = $req->request->get('items');
|
|
$promo_id = $req->request->get('promo');
|
|
|
|
// instantiate invoice criteria
|
|
$criteria = new InvoiceCriteria();
|
|
$criteria->setServiceType($stype);
|
|
|
|
$em = $this->getDoctrine()->getManager();
|
|
|
|
/*
|
|
// if it's a jumpstart or troubleshoot only, we know what to charge already
|
|
if ($stype == ServiceType::JUMPSTART_TROUBLESHOOT)
|
|
{
|
|
$invoice = [
|
|
'price' => 150.00,
|
|
'discount' => 0,
|
|
'trade_in' => 0,
|
|
'vat' => 0,
|
|
'total_price' => 150.00,
|
|
'items' => []
|
|
];
|
|
$invoice['items'][] = [
|
|
'title' => 'Troubleshooting fee',
|
|
'quantity' => 1,
|
|
'unit_price' => 150.00,
|
|
'amount' => 150.00
|
|
];
|
|
|
|
return $this->json([
|
|
'success' => true,
|
|
'invoice' => $invoice
|
|
]);
|
|
}
|
|
*/
|
|
|
|
|
|
$error = $this->invoicePromo($em, $criteria, $promo_id);
|
|
|
|
if (!$error)
|
|
$error = $this->invoiceBatteries($em, $criteria, $items);
|
|
|
|
if ($error)
|
|
{
|
|
// something happened
|
|
return $this->json([
|
|
'success' => false,
|
|
'error' => $error
|
|
], 422);
|
|
}
|
|
|
|
// generate the invoice
|
|
$iobj = $ic->processCriteria($criteria);
|
|
|
|
// use invoice object values in a json friendly array
|
|
$invoice = [
|
|
'discount' => number_format($iobj->getDiscount(), 2),
|
|
'trade_in' => number_format($iobj->getTradeIn(), 2), // TODO: computations not done yet for this on invoice creator
|
|
'price' => number_format($iobj->getVATExclusivePrice(), 2),
|
|
'vat' => number_format($iobj->getVAT(), 2),
|
|
'total_price' => number_format($iobj->getTotalPrice(), 2),
|
|
'items' => []
|
|
];
|
|
|
|
foreach ($iobj->getItems() as $item)
|
|
{
|
|
$invoice['items'][] = [
|
|
'title' => $item->getTitle(),
|
|
'quantity' => number_format($item->getQuantity()), // TODO: quantities are always 1, hardcoded into InvoiceCreator. no way of accepting quantities on InvoiceCriteria
|
|
'unit_price' => number_format($item->getPrice(), 2),
|
|
'amount' => number_format($item->getPrice() * $item->getQuantity(), 2) // TODO: should this calculation should be a saved value on InvoiceItem instead?
|
|
];
|
|
}
|
|
|
|
// return
|
|
return $this->json([
|
|
'success' => true,
|
|
'invoice' => $invoice
|
|
]);
|
|
}
|
|
|
|
public function unlockProcessor($id)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_proc.unlock', null, 'No access.');
|
|
|
|
// clear lock
|
|
$em = $this->getDoctrine()->getManager();
|
|
$jo = $em->getRepository(JobOrder::class)->find($id);
|
|
if ($jo == null)
|
|
return $this->redirectToRoute('jo_proc');
|
|
|
|
$jo->setProcessedBy(null);
|
|
|
|
$em->flush();
|
|
|
|
// redirect to list
|
|
return $this->redirectToRoute('jo_proc');
|
|
}
|
|
|
|
public function unlockAssignor($id)
|
|
{
|
|
$this->denyAccessUnlessGranted('jo_assign.unlock', null, 'No access.');
|
|
|
|
// clear lock
|
|
$em = $this->getDoctrine()->getManager();
|
|
$jo = $em->getRepository(JobOrder::class)->find($id);
|
|
if ($jo == null)
|
|
return $this->redirectToRoute('jo_assign');
|
|
|
|
$jo->setAssignedBy(null);
|
|
$em->flush();
|
|
|
|
// redirect to list
|
|
return $this->redirectToRoute('jo_assign');
|
|
}
|
|
}
|