diff --git a/config/acl.yaml b/config/acl.yaml index 90b2f06d..21f09775 100644 --- a/config/acl.yaml +++ b/config/acl.yaml @@ -246,6 +246,10 @@ access_keys: label: One-step Process - id: jo_onestep.edit label: One-step Process Edit + - id: jo_walkin.form + label: Walk-in + - id: jo_walkin.edit + label: Walk-in Edit - id: support label: Customer Support Access diff --git a/config/menu.yaml b/config/menu.yaml index a64dd8b4..1f90e314 100644 --- a/config/menu.yaml +++ b/config/menu.yaml @@ -102,6 +102,10 @@ main_menu: acl: jo_onestep.form label: One-step Process parent: joborder + - id: jo_walkin_form + acl: jo_walkin.form + label: Walk-in + parent: joborder - id: jo_in acl: jo_in.list label: Incoming diff --git a/config/routes/job_order.yaml b/config/routes/job_order.yaml index bfd41df9..d5cd8dfc 100644 --- a/config/routes/job_order.yaml +++ b/config/routes/job_order.yaml @@ -206,3 +206,23 @@ jo_tracker: controller: App\Controller\JobOrderController::tracker methods: [GET] +jo_walkin_form: + path: /job-order/walk-in + controller: App\Controller\JobOrderController::walkInForm + methods: [GET] + +jo_walkin_submit: + path: /job-order/walk-in + controller: App\Controller\JobOrderController::walkInSubmit + methods: [POST] + +jo_walkin_edit_form: + path: /job-order/walk-in/{id} + controller: App\Controller\JobOrderController::walkInEditForm + methods: [GET] + +jo_walkin_edit_submit: + path: /job-order/walk-in/{id} + controller: App\Controller\JobOrderController::walkInEditSubmit + methods: [POST] + diff --git a/src/Controller/JobOrderController.php b/src/Controller/JobOrderController.php index f70d5484..15d44e1d 100644 --- a/src/Controller/JobOrderController.php +++ b/src/Controller/JobOrderController.php @@ -12,6 +12,7 @@ use App\Entity\Battery; use App\Entity\JobOrder; use App\Entity\VehicleManufacturer; use App\Entity\Vehicle; +use App\Entity\Hub; use App\Service\InvoiceGeneratorInterface; use App\Service\JobOrderHandlerInterface; @@ -880,7 +881,6 @@ class JobOrderController extends Controller return $this->json([ 'success' => 'Changes have been saved!' ]); - } /** @@ -962,4 +962,93 @@ class JobOrderController extends Controller return $this->render('job-order/tracker.html.twig', $params); } + + /** + * @Menu(selected="jo_walkin_form") + */ + public function walkInForm(EntityManagerInterface $em, JobOrderHandlerInterface $jo_handler) + { + $this->denyAccessUnlessGranted('jo_walkin.form', null, 'No access.'); + + $params = $jo_handler->initializeWalkinForm(); + $params['submit_url'] = $this->generateUrl('jo_walkin_submit'); + $params['return_url'] = $this->generateUrl('jo_walkin_form'); + $params['vmfgs'] = $em->getRepository(VehicleManufacturer::class)->findAll(); + $params['vmakes'] = $em->getRepository(Vehicle::class)->findAll(); + $params['hubs'] = $em->getRepository(Hub::class)->findAll(); + + $template = $params['template']; + + // response + return $this->render($template, $params); + } + + public function walkInSubmit(Request $req, JobOrderHandlerInterface $jo_handler) + { + $this->denyAccessUnlessGranted('jo_walkin.form', null, 'No access.'); + + // initialize error list + $error_array = []; + $id = -1; + $error_array = $jo_handler->processWalkinJobOrder($req, $id); + + // check if any errors were found + if (!empty($error_array)) { + // return validation failure response + return $this->json([ + 'success' => false, + 'errors' => $error_array + ], 422); + } + + // return successful response + return $this->json([ + 'success' => 'Changes have been saved!' + ]); + } + + /** + * @Menu(selected="jo_walkin_edit_form") + */ + public function walkInEditForm($id, EntityManagerInterface $em, JobOrderHandlerInterface $jo_handler) + { + $this->denyAccessUnlessGranted('jo_walkin.edit', null, 'No access.'); + + $params = $jo_handler->initializeWalkinEditForm($id); + $params['submit_url'] = $this->generateUrl('jo_walkin_edit_submit', ['id' => $id]); + $params['return_url'] = $this->generateUrl('jo_open'); + $params['vmfgs'] = $em->getRepository(VehicleManufacturer::class)->findAll(); + $params['vmakes'] = $em->getRepository(Vehicle::class)->findAll(); + $params['hubs'] = $em->getRepository(Hub::class)->findAll(); + + $template = $params['template']; + + // response + return $this->render($template, $params); + } + + public function walkInEditSubmit(Request $req, JobOrderHandlerInterface $jo_handler) + { + $this->denyAccessUnlessGranted('jo_walkin.edit', null, 'No access.'); + + $error_array = []; + $error_array = $jo_handler->processOneStepJobOrder($req, $id); + + // check if any errors were found + if (!empty($error_array)) { + // return validation failure response + return $this->json([ + 'success' => false, + 'errors' => $error_array + ], 422); + } + + + // return successful response + return $this->json([ + 'success' => 'Changes have been saved!' + ]); + } + + } diff --git a/src/Ramcar/TransactionOrigin.php b/src/Ramcar/TransactionOrigin.php index baf412f1..c4d69ad2 100644 --- a/src/Ramcar/TransactionOrigin.php +++ b/src/Ramcar/TransactionOrigin.php @@ -9,12 +9,15 @@ class TransactionOrigin extends NameValue const FACEBOOK = 'facebook'; const VIP = 'vip'; const MOBILE_APP = 'mobile_app'; + const WALK_IN = 'walk_in'; + // TODO: for now, resq also gets the walk-in option const COLLECTION = [ 'call' => 'Hotline', 'online' => 'Online', 'facebook' => 'Facebook', 'vip' => 'VIP', 'mobile_app' => 'Mobile App', + 'walk_in' => 'Walk-in', ]; } diff --git a/src/Service/CustomerHandler/CMBCustomerHandler.php b/src/Service/CustomerHandler/CMBCustomerHandler.php index f66a8e30..371f674b 100644 --- a/src/Service/CustomerHandler/CMBCustomerHandler.php +++ b/src/Service/CustomerHandler/CMBCustomerHandler.php @@ -687,7 +687,7 @@ class CMBCustomerHandler implements CustomerHandlerInterface } } - protected function validateMobileNumber($mobile_number) + public function validateMobileNumber($mobile_number) { if (empty($mobile_number)) return true; diff --git a/src/Service/JobOrderHandler/CMBJobOrderHandler.php b/src/Service/JobOrderHandler/CMBJobOrderHandler.php index 40f428ee..a2727fea 100644 --- a/src/Service/JobOrderHandler/CMBJobOrderHandler.php +++ b/src/Service/JobOrderHandler/CMBJobOrderHandler.php @@ -42,6 +42,7 @@ use App\Ramcar\JORejectionReason; use App\Service\InvoiceGeneratorInterface; use App\Service\JobOrderHandlerInterface; use App\Service\RiderAssignmentHandlerInterface; +use App\Service\CustomerHandlerInterface; use App\Service\WarrantyHandler; use App\Service\MQTTClient; use App\Service\APNSClient; @@ -66,13 +67,15 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface protected $rah; protected $country_code; protected $wh; + protected $cust_handler; protected $template_hash; public function __construct(Security $security, EntityManagerInterface $em, InvoiceGeneratorInterface $ic, ValidatorInterface $validator, TranslatorInterface $translator, RiderAssignmentHandlerInterface $rah, - string $country_code, WarrantyHandler $wh) + string $country_code, WarrantyHandler $wh, + CustomerHandlerInterface $cust_handler) { $this->em = $em; $this->ic = $ic; @@ -82,6 +85,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface $this->rah = $rah; $this->country_code = $country_code; $this->wh = $wh; + $this->cust_handler = $cust_handler; $this->loadTemplates(); } @@ -416,8 +420,10 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface $error_array['customer_customer_notes'] = 'Customer notes cannot be null.'; } - $new_cust = new Customer(); - $new_cv = new CustomerVehicle(); + // validate mobile phone + $valid_mobile = $this->cust_handler->validateMobileNumber($req->request->get('customer_phone_mobile')); + if (!($valid_mobile)) + $error_array['customer_phone_mobile'] = 'Invalid mobile phone number.'; // find the vehicle using vid $new_vehicle = $em->getRepository(Vehicle::class)->find($req->request->get('vid')); @@ -426,8 +432,10 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface $error_array['cv_mfg'] = 'Invalid manufacturer specified.'; $error_array['cv_make'] = 'Invalid make specified.'; } - else + if (empty($error_array)) { + $new_cust = new Customer(); + $new_cv = new CustomerVehicle(); $new_cust->setLastName($req->request->get('customer_last_name')) ->setFirstName($req->request->get('customer_first_name')) @@ -918,7 +926,11 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface // create the warranty if new battery only if ($this->checkIfNewBattery($obj)) { - $serial = $req->request->get('warranty_code') ; + if (empty($req->request->get('warranty_code'))) + $serial = null; + else + $serial = $req->request->get('warranty_code'); + $warranty_class = $obj->getWarrantyClass(); $first_name = $obj->getCustomer()->getFirstName(); $last_name = $obj->getCustomer()->getLastName(); @@ -2345,6 +2357,298 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface return false; } + public function initializeWalkinForm() + { + $params['obj'] = new JobOrder(); + $params['mode'] = 'walk-in'; + + $this->fillDropdownParameters($params); + $this->fillFormTags($params); + + // get template to display + $params['template'] = $this->getTwigTemplate('jo_walkin'); + + // return params + return $params; + } + + public function processWalkinJobOrder(Request $req, $id) + { + // initialize error list + $error_array = []; + + $em = $this->em; + + $jo = $em->getRepository(JobOrder::class)->find($id); + if (empty($jo)) + { + // new job order + $jo = new JobOrder(); + } + + // check if new customer + if ($req->request->get('new_customer')) + { + if (empty($req->request->get('customer_customer_notes'))) + { + $error_array['customer_customer_notes'] = 'Customer notes cannot be null.'; + } + + // validate mobile phone + $valid_mobile = $this->cust_handler->validateMobileNumber($req->request->get('customer_phone_mobile')); + if (!($valid_mobile)) + $error_array['customer_phone_mobile'] = 'Invalid mobile phone number.'; + + // find the vehicle using vid + $new_vehicle = $em->getRepository(Vehicle::class)->find($req->request->get('vid')); + if (empty($new_vehicle)) + { + $error_array['cv_mfg'] = 'Invalid manufacturer specified.'; + $error_array['cv_make'] = 'Invalid make specified.'; + } + + if (empty($error_array)) + { + $new_cust = new Customer(); + $new_cv = new CustomerVehicle(); + + $new_cust->setLastName($req->request->get('customer_last_name')) + ->setFirstName($req->request->get('customer_first_name')) + ->setPhoneMobile($req->request->get('customer_phone_mobile')) + ->setPhoneLandline($req->request->get('customer_phone_landline')) + ->setPhoneOffice($req->request->get('customer_phone_office')) + ->setPhoneFax($req->request->get('customer_phone_fax')) + ->setCustomerNotes($req->request->get('customer_customer_notes')); + + $new_cv->setCustomer($new_cust) + ->setVehicle($new_vehicle) + ->setPlateNumber($req->request->get('cv_plate')) + ->setModelYear($req->request->get('cv_year')) + ->setColor('') + ->setStatusCondition('') + ->setFuelType('') + ->setActive() + ->setWarrantyCode($req->request->get('warranty_code')); + + if (($req->request->get('service_type')) == CMBServiceType::BATTERY_REPLACEMENT_NEW) + { + $new_cv->setHasMotoliteBattery(true); + } + else + { + $new_cv->setHasMotoliteBattery(false); + } + + // link JO to new customer + $jo->setCustomer($new_cust); + $jo->setCustomerVehicle($new_cv); + + $em->persist($new_cust); + $em->persist($new_cv); + } + } + else + { + // 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.'; + } + else + { + $jo->setCustomerVehicle($cust_vehicle); + $jo->setCustomer($cust_vehicle->getCustomer()); + + // save serial into cv + $cust_vehicle->setWarrantyCode($req->request->get('warranty_code')); + + $em->persist($cust_vehicle); + } + } + } + + // check if hub is selected + if (empty($req->request->get('hub_id'))) + $error_array['hub'] = 'No hub selected.'; + else + { + // get hub + $hub = $em->getRepository(Hub::class)->find($req->request->get('hub_id')); + + if (empty($hub)) + $error_array['hub'] = 'Invalid hub specified.'; + + // get hub coordinates + $hub_coordinates = $hub->getCoordinates(); + } + + if (empty($error_array)) + { + // get current user + $user = $this->security->getUser(); + + $stype = $req->request->get('service_type'); + + // set and save values + $jo->setDateSchedule(DateTime::createFromFormat("d M Y h:i A", $req->request->get('date_schedule_date') . " " . $req->request->get('date_schedule_time'))) + ->setAdvanceOrder($req->request->get('flag_advance') ?? false) + ->setServiceType($stype) + ->setWarrantyClass($req->request->get('warranty_class')) + ->setSource($req->request->get('source')) + ->setStatus(JOStatus::FULFILLED) + ->setTier1Notes($req->request->get('tier1_notes')) + ->setTier2Notes($req->request->get('tier2_notes')) + ->setORName($req->request->get('or_name')) + ->setPromoDetail($req->request->get('promo_detail')) + ->setModeOfPayment($req->request->get('mode_of_payment')) + ->setLandmark($req->request->get('landmark')) + ->setDeliveryAddress('Walk-in') + ->setLandmark('Walk-in') + ->setCoordinates($hub_coordinates) + ->setHub($hub); + + // check if user is null, meaning call to create came from API + if ($user != null) + { + $jo->setCreatedBy($user); + } + + // 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 { + $jo->setReferenceJO($ref_jo); + } + } + + // call service to generate job order and invoice + $invoice_items = $req->request->get('invoice_items', []); + $promo_id = $req->request->get('invoice_promo'); + $invoice_change = $req->request->get('invoice_change', 0); + + // check if invoice changed + if ($invoice_change) + { + $this->ic->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $error_array); + } + + // validate + $errors = $this->validator->validate($jo); + + // add errors to list + foreach ($errors as $error) { + $error_array[$error->getPropertyPath()] = $error->getMessage(); + } + + // check if errors are found + if (empty($error_array)) + { + // validated, no error. save the job order + $em->persist($jo); + + // the event + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::CREATE) + ->setJobOrder($jo); + + if ($user != null) + { + $event->setUser($user); + } + + $em->persist($event); + + // save to customer vehicle battery record + $this->updateVehicleBattery($jo); + + // save serial to customer vehicle + $cust_vehicle = $jo->getCustomerVehicle(); + $cust_vehicle->setWarrantyCode($req->request->get('warranty_code')); + + $em->persist($cust_vehicle); + + // create the warranty if new battery only + if ($this->checkIfNewBattery($jo)) + { + if (empty($req->request->get('warranty_code'))) + $serial = null; + else + $serial = $req->request->get('warranty_code'); + + $warranty_class = $jo->getWarrantyClass(); + $first_name = $jo->getCustomer()->getFirstName(); + $last_name = $jo->getCustomer()->getLastName(); + $mobile_number = $jo->getCustomer()->getPhoneMobile(); + + // check if date fulfilled is null + if ($jo->getDateFulfill() == null) + $date_purchase = $jo->getDateCreate(); + else + $date_purchase = $jo->getDateFulfill(); + + // validate plate number + // $plate_number = $this->wh->cleanPlateNumber($jo->getCustomerVehicle()->getPlateNumber()); + $plate_number = Warranty::cleanPlateNumber($jo->getCustomerVehicle()->getPlateNumber()); + if ($plate_number != false) + { + $batt_list = array(); + $invoice = $jo->getInvoice(); + if (!empty($invoice)) + { + // get battery + $invoice_items = $invoice->getItems(); + foreach ($invoice_items as $item) + { + $battery = $item->getBattery(); + if ($battery != null) + { + $batt_list[] = $item->getBattery(); + } + } + } + + $this->wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class); + } + } + + $em->flush(); + } + } + + return $error_array; + } + + public function initializeWalkinEditForm($id) + { + $em = $this->em; + $obj = $em->getRepository(JobOrder::class)->find($id); + + $params['obj'] = $obj; + $params['mode'] = 'walk-in-edit'; + $params['cvid'] = $obj->getCustomerVehicle()->getID(); + $params['vid'] = $obj->getCustomerVehicle()->getVehicle()->getID(); + + $this->fillDropdownParameters($params); + $this->fillFormTags($params); + + // get template to display + $params['template'] = $this->getTwigTemplate('jo_walkin_edit'); + + // return params + return $params; + } + protected function fillDropdownParameters(&$params) { $em = $this->em; @@ -2422,6 +2726,18 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface $params['ftags']['invoice_edit'] = true; $params['ftags']['preset_vehicle'] = true; break; + case 'walk-in': + $params['ftags']['vehicle_dropdown'] = true; + $params['ftags']['set_map_coordinate'] = false; + $params['ftags']['invoice_edit'] = true; + $params['ftags']['ticket_table'] = false; + $params['ftags']['cancel_button'] = false; + break; + case 'walk-in-edit': + $params['ftags']['invoice_edit'] = true; + $params['ftags']['preset_vehicle'] = true; + break; + } } @@ -2450,6 +2766,8 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface $this->template_hash['jo_list_all'] = 'job-order/list.all.html.twig'; $this->template_hash['jo_onestep'] = 'job-order/cmb.form.onestep.html.twig'; $this->template_hash['jo_onestep_edit_form'] = 'job-order/cmb.form.onestep.html.twig'; + $this->template_hash['jo_walkin'] = 'job-order/cmb.form.walkin.html.twig'; + $this->template_hash['jo_walkin_edit'] = 'job-order/cmb.form.walkin.html.twig'; } protected function checkTier($tier) diff --git a/templates/job-order/cmb.form.walkin.html.twig b/templates/job-order/cmb.form.walkin.html.twig new file mode 100644 index 00000000..1e3d8f9b --- /dev/null +++ b/templates/job-order/cmb.form.walkin.html.twig @@ -0,0 +1,1082 @@ +{% extends 'base.html.twig' %} + +{% block body %} + + + +
+ +
+
+
+
+
+
+ + + +

+ Walk-in Job Order +

+
+
+
+
+ + +
+ {%if ftags.vehicle_dropdown %} +
+
+
+ + + +
+ +
+
+
+
+
+ + + +
+
+
+ {% else %} + + {% endif %} + {% if obj.getReferenceJO %} +
+
+
+ + + +
+
+
+ {% endif %} + +
+
+

+ Customer Details +

+ + + +
+
+
+ + + +
+
+ + + +
+
+
+
+ +
+ {% trans %}country_code_prefix{% endtrans %} + + +
+
+
+ +
+ {% trans %}country_code_prefix{% endtrans %} + + +
+
+
+
+
+ +
+ {% trans %}country_code_prefix{% endtrans %} + + +
+
+
+ +
+ {% trans %}country_code_prefix{% endtrans %} + + +
+
+
+
+
+ + + +
+
+
+
+
+

+ Vehicle Details +

+
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+
+ + + +
+ +
+
+
+
+

+ Battery Details +

+
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+
+
+
+

+ Transaction Details +

+ + + +
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+
+ + + +
+
+ +
+ + + + +
+ +
+
+ +
+ + + + +
+ +
+
+
+
+ + + +
+
+ + + +
+
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+
+
+
+
+

+ Hubs +

+
+
+
+ + + +
+ + + + + + + + + + + + {% for hub in hubs %} + + + + + + + {% endfor %} + +
HubBranchContact NumbersDistance in KMAction
{{ hub.getName }}{{ hub.getBranch }}{{ hub.getContactNumbers }}
+
+
+
+
+
+
+
+

+ Invoice +

+
+
+
+ + + +
+
+ + + +
+
+
+
+ + {% if ftags.invoice_edit %} + + + {% else %} + + {% endif %} +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + + + + + + + + + + {% if not obj.getInvoice or (obj.getInvoice and obj.getInvoice.getItems|length == 0) %} + + + + {% else %} + {% for item in obj.getInvoice.getItems %} + + + + + + + {% endfor %} + {% endif %} + +
ItemQuantityUnit PriceAmount
+ No items to display. +
{{ item.getTitle }}{{ item.getQuantity|number_format }}{{ item.getPrice|number_format(2) }}{{ (item.getPrice * item.getQuantity)|number_format(2) }}
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + + +
+
+
+
+
+
+
+
+ + {% if ftags.set_map_coordinate and is_granted('joborder.cancel') and not obj.isCancelled %} + Cancel Job Order + {% endif %} + Back +
+
+
+
+ +
+
+
+
+{% endblock %} + +{% block scripts %} + +{% endblock %} +