diff --git a/config/acl.yaml b/config/acl.yaml index ea81ada5..513fd650 100644 --- a/config/acl.yaml +++ b/config/acl.yaml @@ -274,8 +274,12 @@ access_keys: label: View Behind Schedule - id: jo_advance_order.form label: New Advance Order + - id: jo_advance_order.edit + label: New Advance Order Edit - id: jo_assign_advance_order.form label: Assign Advance Order + - id: jo_assign_advance_order.edit + label: Assign Advance Order Edit - id: support label: Customer Support Access diff --git a/config/menu.yaml b/config/menu.yaml index c216839b..248fb3b8 100644 --- a/config/menu.yaml +++ b/config/menu.yaml @@ -110,7 +110,7 @@ main_menu: acl: jo_advance_order.form label: New Advance Order parent: joborder - - id: jo_advance_order_assign_form + - id: jo_assign_advance_order_form acl: jo_assign_advance_order.form label: Assign Advance Order parent: joborder diff --git a/config/routes/job_order.yaml b/config/routes/job_order.yaml index 45623b22..eb296cfc 100644 --- a/config/routes/job_order.yaml +++ b/config/routes/job_order.yaml @@ -281,7 +281,7 @@ jo_advance_order_edit_form: methods: [GET] jo_advance_order_edit_submit: - path: /job-order/onestep/{id}/edit + path: /job-order/advance-order/{id}/edit controller: App\Controller\JobOrderController::advanceOrderEditSubmit methods: [POST] diff --git a/src/Controller/JobOrderController.php b/src/Controller/JobOrderController.php index d8ff3b06..3b4887a6 100644 --- a/src/Controller/JobOrderController.php +++ b/src/Controller/JobOrderController.php @@ -228,7 +228,7 @@ class JobOrderController extends Controller } /** - * @Menu(selected="jo_all") + * @Menu(selected="jo_/viewall") */ public function listAll(JobOrderHandlerInterface $jo_handler) { @@ -284,18 +284,18 @@ class JobOrderController extends Controller $rows[$key]['meta']['reassign_rider_url'] = $this->generateUrl('jo_open_rider_form', ['id' => $jo_id]); // $rows[$key]['meta']['edit_url'] = $this->generateUrl('jo_open_edit_form', ['id' => $jo_id]); $rows[$key]['meta']['edit_url'] = $this->generateUrl($jo_handler->getEditRoute($jo_id, $tier_params['edit_route']), ['id' => $jo_id]); - $rows[$key]['meta']['onestep_edit_url'] = $this->generateUrl('jo_onestep_edit_form', ['id' => $jo_id]); + //$rows[$key]['meta']['onestep_edit_url'] = $this->generateUrl('jo_onestep_edit_form', ['id' => $jo_id]); } else if ($tier == 'behind_schedule') { $rows[$key]['meta']['edit_url'] = $this->generateUrl($jo_handler->getEditRoute($jo_id, $tier_params['edit_route']), ['id' => $jo_id]); - $rows[$key]['meta']['onestep_edit_url'] = $this->generateUrl('jo_onestep_edit_form', ['id' => $jo_id]); + //$rows[$key]['meta']['onestep_edit_url'] = $this->generateUrl('jo_onestep_edit_form', ['id' => $jo_id]); } else { // $rows[$key]['meta']['update_url'] = $this->generateUrl($tier_params['edit_route'], ['id' => $jo_id]); - $rows[$key]['meta']['update_url'] = $this->generateUrl($jo_handler->getEditRoute($jo_id, $tier_params['edit_route']), ['id' => $jo_id]); - $rows[$key]['meta']['onestep_edit_url'] = $this->generateUrl('jo_onestep_edit_form', ['id' => $jo_id]); + $rows[$key]['meta']['edit_url'] = $this->generateUrl($jo_handler->getEditRoute($jo_id, $tier_params['edit_route']), ['id' => $jo_id]); + //$rows[$key]['meta']['onestep_edit_url'] = $this->generateUrl('jo_onestep_edit_form', ['id' => $jo_id]); $rows[$key]['meta']['pdf_url'] = $this->generateUrl('jo_pdf_form', ['id' => $jo_id]); } @@ -1095,6 +1095,77 @@ class JobOrderController extends Controller return $this->render($template, $params); } + public function advanceOrderSubmit(Request $req, JobOrderHandlerInterface $jo_handler, MQTTClient $mclient) + { + $this->denyAccessUnlessGranted('jo_advance_order.form', null, 'No access.'); + + // initialize error list + $error_array = []; + $id = -1; + $error_array = $jo_handler->processAdvanceOrderJobOrder($req, $id, $mclient); + + // 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_advance_order_edit_form") + */ + public function advanceOrderEditForm($id, EntityManagerInterface $em, JobOrderHandlerInterface $jo_handler, + GISManagerInterface $gis, MapTools $map_tools) + { + $this->denyAccessUnlessGranted('jo_advance_order.edit', null, 'No access.'); + + $params = $jo_handler->initializeAdvanceOrderEditForm($id, $map_tools); + $params['submit_url'] = $this->generateUrl('jo_advance_order_edit_submit', ['id' => $id]); + $params['return_url'] = $this->generateUrl('jo_open'); + $params['map_js_file'] = $gis->getJSJOFile(); + $params['vmfgs'] = $em->getRepository(VehicleManufacturer::class)->findAll(); + $params['vmakes'] = $em->getRepository(Vehicle::class)->findAll(); + + $template = $params['template']; + + // response + return $this->render($template, $params); + } + + public function advanceOrderEditSubmit(Request $req, JobOrderHandlerInterface $jo_handler, $id, MQTTClient $mclient) + { + $this->denyAccessUnlessGranted('jo_advance_order.edit', null, 'No access.'); + + $error_array = []; + $error_array = $jo_handler->processAdvanceOrderJobOrder($req, $id, $mclient); + + // 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_hub_view") */ diff --git a/src/Service/JobOrderHandler/CMBJobOrderHandler.php b/src/Service/JobOrderHandler/CMBJobOrderHandler.php index 998bc41b..3bc46ef2 100644 --- a/src/Service/JobOrderHandler/CMBJobOrderHandler.php +++ b/src/Service/JobOrderHandler/CMBJobOrderHandler.php @@ -2907,6 +2907,358 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface return $params; } + public function processAdvanceOrderJobOrder(Request $req, $id, MQTTClient $mclient) + { + // initialize error list + $error_array = []; + + $em = $this->em; + + $jo = $em->getRepository(JobOrder::class)->find($id); + $event_type = CMBJOEventType::OPEN_EDIT; + if (empty($jo)) + { + // new job order + $jo = new JobOrder(); + $event_type = CMBJOEventType::CREATE; + } + + // 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 responsible party is present + if (empty($req->request->get('responsible_party'))) + $error_array['responsible_party'] = 'Responsible party is required.'; + + // check if new customer + if ($req->request->get('new_customer', false)) + { + // validate mobile phone + $valid_mobile = $this->cust_handler->validateMobileNumber($req->request->get('phone_mobile')); + if (!($valid_mobile)) + $error_array['phone_mobile'] = 'Invalid mobile phone number.'; + + // check if plate number is in request + if (empty(trim($req->request->get('plate_number')))) + $error_array['plate_number'] = 'Plate number is required.'; + + // 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('last_name')) + ->setFirstName($req->request->get('first_name')) + ->setPhoneMobile($req->request->get('phone_mobile')) + ->setPhoneLandline($req->request->get('phone_landline')) + ->setPhoneOffice($req->request->get('phone_office')) + ->setCustomerNotes($req->request->get('customer_notes')); + + $new_cv->setCustomer($new_cust) + ->setVehicle($new_vehicle) + ->setPlateNumber(trim($req->request->get('plate_number'))) + ->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.'; + } + + // delivery address + if (empty($req->request->get('delivery_address'))) + $error_array['delivery_address'] = 'Delivery address is required.'; + + // get discount and set to meta + $discount = $req->request->get('invoice_discount'); + + if (($discount > 60) || ($discount < 0)) + { + $error_array['invoice_discount'] = 'Invalid discount specified'; + } + + // get list of service charges + $service_charges = $req->request->get('service_charges', []); + + if (empty($error_array)) + { + // get current user + $user = $this->security->getUser(); + + // coordinates + $point = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat')); + + $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'))) + ->setCoordinates($point) + ->setAdvanceOrder($req->request->get('flag_advance') ?? false) + ->setServiceType($stype) + ->setWarrantyClass($req->request->get('warranty_class')) + ->setSource($req->request->get('source')) + ->setDeliveryInstructions($req->request->get('delivery_instructions')) + ->setDeliveryAddress($req->request->get('delivery_address')) + ->setORName($req->request->get('or_name')) + ->setPromoDetail($req->request->get('promo_detail', '')) + ->setModeOfPayment($req->request->get('mode_of_payment')) + ->setLandmark($req->request->get('landmark')) + ->setHub($hub) + ->setResponsibleParty($req->request->get('responsible_party', '')) + ->setStatus(JOStatus::RIDER_ASSIGN); + + $jo->addMeta('discount', $discount); + $jo->addMeta('service_charges', $service_charges); + + // 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 invoice + $invoice_items = $req->request->get('invoice_items', []); + $discount = $req->request->get('invoice_discount'); + $invoice_change = $req->request->get('invoice_change', 0); + + // check if invoice changed + if ($invoice_change) + { + $this->ic->generateInvoiceCriteria($jo, $discount, $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($event_type) + ->setJobOrder($jo); + + if ($user != null) + { + $event->setUser($user); + } + + $em->persist($event); + $em->flush(); + } + } + + return $error_array; + } + + public function initializeAdvanceOrderEditForm($id, $map_tools) + { + $em = $this->em; + $obj = $em->getRepository(JobOrder::class)->find($id); + + $params['obj'] = $obj; + $params['mode'] = 'advanceorder-edit'; + $params['cvid'] = $obj->getCustomerVehicle()->getID(); + $params['vid'] = $obj->getCustomerVehicle()->getVehicle()->getID(); + $params['current_date'] = new DateTime(); + + // get service charges + $sc_array = []; + $jo_service_charges = $obj->getMeta('service_charges'); + if (!(empty($jo_service_charges))) + { + foreach ($jo_service_charges as $jo_sc_id) + { + // find service charge + $sc_obj = $em->getRepository(ServiceCharge::class)->find($jo_sc_id); + + $sc_array[] = $sc_obj; + } + } + + $params['jo_service_charges'] = $sc_array; + + // get odometer + $odometer = $obj->getMeta('odometer'); + + $params['odometer'] = $odometer; + + // get customer email used in JO + $email = $obj->getMeta('customer_email'); + + $params['email'] = $email; + + // get images if any + $jo_extra = $obj->getJOExtra(); + $pic_array = []; + $params['signature'] = null; + if ($jo_extra != null) + { + $img_1 = $jo_extra->getImage1Filename(); + $img_2 = $jo_extra->getImage2Filename(); + $img_3 = $jo_extra->getImage3Filename(); + $img_4 = $jo_extra->getImage4Filename(); + + $other_images = $jo_extra->getOtherImages(); + + $cust_signature = $jo_extra->getCustomerSignature(); + + if ($img_1 != null) + $pic_array['image_1'] = $img_1; + if ($img_2 != null) + $pic_array['image_2'] = $img_2; + if ($img_3 != null) + $pic_array['image_3'] = $img_3; + if ($img_4 != null) + $pic_array['image_4'] = $img_4; + + if ($other_images != null) + { + foreach ($other_images as $img) + { + $pic_array['other_images'][] = $img; + } + } + + $params['signature'] = $cust_signature; + } + + $params['jo_pictures'] = $pic_array; + + $this->fillDropdownParameters($params); + $this->fillFormTags($params); + + // get the hubs + // TODO: move this snippet to a function + $hubs = $map_tools->getClosestHubs($obj->getCoordinates(), 50, 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; + } + + // counters + $hub['rider_count'] = count($hub['hub']->getAvailableRiders()); + $hub['jo_count'] = count($hub['hub']->getForAssignmentJobOrders()); + + // check for rejection + $hub['flag_rejected'] = false; + $hub_id = $hub['hub']->getID(); + + $params['hubs'][] = $hub; + } + + // get template to display + $params['template'] = $this->getTwigTemplate('jo_advanceorder_edit_form'); + + return $params; + } + protected function fillDropdownParameters(&$params) { $em = $this->em; @@ -3006,6 +3358,11 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface $params['ftags']['ticket_table'] = false; $params['ftags']['cancel_button'] = false; break; + case 'advanceorder-edit': + $params['ftags']['invoice_edit'] = true; + $params['ftags']['preset_vehicle'] = true; + break; + } } @@ -3031,6 +3388,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface $this->template_hash['jo_popup'] = 'job-order/cmb.popup.html.twig'; $this->template_hash['jo_behind_schedule'] = 'job-order/cmb.list.behindschedule.html.twig'; $this->template_hash['jo_advanceorder_form'] = 'job-order/cmb.form.advanceorder.html.twig'; + $this->template_hash['jo_advanceorder_edit_form'] = 'job-order/cmb.form.advanceorder.html.twig'; } protected function checkTier($tier) @@ -3286,11 +3644,20 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface if (empty($jo)) throw new NotFoundHttpException('The item does not exist'); + $edit_route = ''; // check transaction origin if ($jo->getSource() == CMBTransactionOrigin::WALK_IN) - return 'jo_walkin_edit_form'; + $edit_route = 'jo_walkin_edit_form'; else - return 'jo_onestep_edit_form'; + { + // need to check if onestep or not + if ($jo->getStatus() == JOStatus::ASSIGNED) + $edit_route = 'jo_onestep_edit_form'; + else + $edit_route = 'jo_advance_order_edit_form'; + } + + return $edit_route; } protected function generateDiscountOptions() diff --git a/templates/job-order/cmb.list.all.html.twig b/templates/job-order/cmb.list.all.html.twig index 17c7be16..49d04ae2 100644 --- a/templates/job-order/cmb.list.all.html.twig +++ b/templates/job-order/cmb.list.all.html.twig @@ -115,7 +115,7 @@ sortable: false, overflow: 'visible', template: function (row, index, datatable) { - var actions = ''; + var actions = ''; actions += ''; return actions; diff --git a/templates/job-order/cmb.list.behindschedule.html.twig b/templates/job-order/cmb.list.behindschedule.html.twig index 2ed1bbeb..5f9a9c57 100644 --- a/templates/job-order/cmb.list.behindschedule.html.twig +++ b/templates/job-order/cmb.list.behindschedule.html.twig @@ -103,8 +103,8 @@ sortable: false, overflow: 'visible', template: function (row, index, datatable) { - {% if is_granted('jo_onestep.edit') %} - var actions = ''; + {% if is_granted('jo_onestep.edit') or is_granted('jo_advance_order.edit') or is_granted('jo_assign_advance_order.edit') %} + var actions = ''; {% endif %} return actions; diff --git a/templates/job-order/cmb.list.open.html.twig b/templates/job-order/cmb.list.open.html.twig index aac00d65..21669275 100644 --- a/templates/job-order/cmb.list.open.html.twig +++ b/templates/job-order/cmb.list.open.html.twig @@ -114,8 +114,8 @@ sortable: false, overflow: 'visible', template: function (row, index, datatable) { - {% if is_granted('jo_onestep.edit') %} - var actions = ''; + {% if is_granted('jo_onestep.edit') or is_granted('jo_advance_order.edit') or is_granted('jo_assign_advance_order.edit') %} + var actions = ''; {% endif %} return actions;