em = $em; $this->ic = $ic; $this->security = $security; $this->validator = $validator; $this->translator = $translator; $this->rah = $rah; $this->country_code = $country_code; $this->wh = $wh; $this->rt = $rt; $this->promo_logger = $promo_logger; $this->hub_dist = $hub_dist; $this->hub_geofence = $hub_geofence; $this->cust_distance_limit = $cust_distance_limit; $this->hub_filter_enabled = $hub_filter_enabled; $this->loadTemplates(); } // get job order rows 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->security->getUser(); if ($user == null) throw new AccessDeniedHttpException('No access.'); $hubs = $user->getHubs(); // get query builder $qb = $this->em->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 $qb = $this->em->getRepository(JobOrder::class) ->createQueryBuilder('q'); $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 $query_obj = $query->setFirstResult($offset) ->setMaxResults($perpage) ->getQuery(); // error_log($query_obj->getSQL()); $obj_rows = $query_obj->getResult(); $statuses = JOStatus::getCollection(); $service_types = ServiceType::getCollection(); // process rows $rows = []; foreach ($obj_rows as $orow) { $is_vip = false; $is_emergency = false; // check if customer is vip $cust_class = $orow->getCustomer()->getCustomerClassification(); if ($cust_class == CustomerClassification::VIP) $is_vip = true; // check if customer is not willing to wait $will_not_wait = $orow->getWillWait(); if ($will_not_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) $is_emergency = true; // add row data $row['id'] = $orow->getID(); $row['customer_name'] = $orow->getCustomer()->getFirstName() . ' ' . $orow->getCustomer()->getLastName(); $row['delivery_address'] = $orow->getDeliveryAddress(); $row['date_schedule'] = $orow->getDateSchedule()->format("d M Y g:i A"); $row['type'] = $orow->isAdvanceOrder() ? 'Advanced Order' : 'Immediate'; $row['service_type'] = $service_types[$orow->getServiceType()]; $row['status'] = $statuses[$orow->getStatus()]; $row['flag_advance'] = $orow->isAdvanceOrder(); $row['plate_number'] = $orow->getCustomerVehicle()->getPlateNumber(); $row['is_mobile'] = $orow->getSource() == TransactionOrigin::MOBILE_APP; $row['is_vip'] = $is_vip; $row['is_emergency'] = $is_emergency; $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(); $hub_facilitated = $orow->getFacilitatedBy(); if ($hub_facilitated == null) $row['hub_facilitated'] = ''; else $row['hub_facilitated'] = $orow->getFacilitatedBy()->getName(); $rows[] = $row; } $params['meta'] = $meta; $params['rows'] = $rows; $params['tier_params'] = $tier_params; return $params; } // get job orders public function getJobOrders(Request $req) { // get search term $term = $req->query->get('search'); // get querybuilder $qb = $this->em->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 ]; } $params['job_orders'] = $job_orders; $params['has_more_pages'] = $has_more_pages; return $params; } // creates job order public function generateJobOrder(Request $req, $id) { // initialize error list $error_array = []; $em = $this->em; $jo = $em->getRepository(JobOrder::class)->find($id); // flag for new job order for the customer tags $flag_new_jo = false; if (empty($jo)) { // new job order $jo = new JobOrder(); $flag_new_jo = true; } // find customer $cust_id = $req->request->get('cid'); $customer = $em->getRepository(Customer::class)->find($cust_id); if (empty($customer)) { $error_array['customer_vehicle'] = 'Invalid customer specified.'; } else { // get email, dpa_consent, promo_sms, and promo_email, if set // check for dpa access $is_dpa_checked = true; if ($this->security->isGranted('customer.dpa')) $is_dpa_checked = $req->request->get('flag_dpa_consent', false); // check if email marketing promo is checked $is_email_promo_checked = $req->request->get('flag_promo_email'); if ($is_email_promo_checked) { // check email field if (empty($req->request->get('customer_email'))) $error_array['customer_email'] = 'Email address required.'; } $customer->setEmail($req->request->get('customer_email')) ->setPromoSms($req->request->get('flag_promo_sms', false)) ->setPromoEmail($req->request->get('flag_promo_email', false)) ->setResearchSms($req->request->get('flag_research_sms', false)) ->setResearchEmail($req->request->get('flag_research_email', false)) ->setDpaConsent($is_dpa_checked); } // 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.'; } } // check if landmark is set if (empty($req->request->get('landmark'))) $error_array['landmark'] = 'Landmark is required.'; // check if customer is not willing to wait $will_wait = $req->request->get('flag_willing_to_wait'); $reason = ''; $more_reason = ''; if ($will_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) { // get the reason and text $reason = $req->request->get('no_wait_reason'); $more_reason = $req->request->get('not_wait_notes'); } // check if service is battery sales $stype = $req->request->get('service_type'); $no_trade_in_reason = ''; if ($stype == ServiceType::BATTERY_REPLACEMENT_NEW) { // check if trade in $is_trade_in = $req->request->get('invoice_trade_in_type'); if (empty($is_trade_in)) { $no_trade_in_reason = $req->request->get('no_trade_in_reason'); if (empty($no_trade_in_reason)) $error_array['no_trade_in_reason'] = 'No trade in reason required.'; } } // get source of awareness if any $soa_type = $req->request->get('source_of_awareness', ''); // get remarks $remarks = $req->request->get('remarks', ''); // get initial concern if any $initial_concern = $req->request->get('initial_concern', ''); // get initial concern notes if any $initial_concern_notes = $req->request->get('initial_concern_notes', ''); // get gender if any $gender = $req->request->get('gender', ''); // get caller classification if any $caller_class = $req->request->get('caller_class',''); // TODO: check status before saving since JO might already // have a status that needs to be retained 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')); // 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')) ->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')) ->setPromoDetail($req->request->get('promo_detail')) ->setModeOfPayment($req->request->get('mode_of_payment')) ->setLandmark($req->request->get('landmark')) ->setWillWait($req->request->get('flag_willing_to_wait')) ->setReasonNotWait($reason) ->setNotWaitingNotes($more_reason) ->setNoTradeInReason($no_trade_in_reason) ->setSourceOfAwareness($soa_type) ->setRemarks($remarks) ->setInitialConcern($initial_concern) ->setInitialConcernNotes($initial_concern_notes) ->setCallerClassification($caller_class) ->setGender($gender); // 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); } } // check service type if new battery // check if new JO if (($stype == ServiceType::BATTERY_REPLACEMENT_NEW) && ($flag_new_jo)) { // check if customer has customer tag promo if (($customer->getCustomerTag('TAG_CAR_CLUB_OFFICER_PROMO')) || ($customer->getCustomerTag('TAG_CAR_CLUB_MEMBER_PROMO'))) { // if has customer tag, customer has not availed of promo, get the hub where customer is pre-registered $car_club_hub = $customer->getCarClubCustomerHub(); if ($car_club_hub != null) { // assign hub, change the jo status $hub = $car_club_hub->getHub(); $jo->setHub($hub) ->setStatus(JOStatus::RIDER_ASSIGN); } } } // 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 and customer $em->persist($jo); $em->persist($customer); // the event $event = new JOEvent(); $event->setDateHappen(new DateTime()) ->setTypeID(JOEventType::CREATE) ->setJobOrder($jo); if ($user != null) { $event->setUser($user); } $em->persist($event); // check if JOStatus is rider assign if ($jo->getStatus() == JOStatus::RIDER_ASSIGN) { $rider_assign_event = new JOEvent(); $rider_assign_event->setDateHappen(new DateTime()) ->setTypeID(JOEventType::HUB_ASSIGN) ->setJobOrder($jo); if ($user != null) { $rider_assign_event->setUser($user); } $em->persist($rider_assign_event); } $em->flush(); } } $data['error_array'] = $error_array; if ($jo != null) { $data['job_order'] = $jo; // need to get the customer tags but only if new JO if ($flag_new_jo) { // check service type if ($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW) { $customer = $cust_vehicle->getCustomer(); $customer_tags = $customer->getCustomerTagObjects(); if (!empty($customer_tags)) { foreach ($customer_tags as $customer_tag) { if ($customer_tag->getID() == $jo->getInvoice()->getUsedCustomerTagId()) { // remove associated entity $customer->removeCustomerTag($customer_tag); // log the availment of promo from customer $created_by = $jo->getCreatedBy()->getUsername(); $cust_id = $jo->getCustomer()->getID(); $cust_fname = $jo->getCustomer()->getFirstName(); $cust_lname = $jo->getCustomer()->getLastName(); $jo_id = $jo->getID(); $invoice_id = $jo->getInvoice()->getID(); // TODO: check if we store total price of invoice or just the discounted amount $amount = $jo->getInvoice()->getTotalPrice(); $this->promo_logger->logPromoInfo($created_by, $cust_id, $cust_fname, $cust_lname, $jo_id, $invoice_id, $amount); } } } } } } return $data; } // updates job order public function openEditJobOrder(Request $req, $id) { $em = $this->em; $obj = $em->getRepository(JobOrder::class)->find($id); // 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 landmark is set if (empty($req->request->get('landmark'))) $error_array['landmark'] = 'Landmark is required.'; // check if customer is not willing to wait $will_wait = $req->request->get('flag_willing_to_wait'); $reason = ''; $more_reason = ''; if ($will_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) { // get the reason and text $reason = $req->request->get('no_wait_reason'); $more_reason = $req->request->get('not_wait_notes'); } // check if service type is battery sales $stype = $req->request->get('service_type'); $no_trade_in_reason = ''; if ($stype == ServiceType::BATTERY_REPLACEMENT_NEW) { // check if trade in $is_trade_in = $req->request->get('invoice_trade_in_type'); if (empty($is_trade_in)) { $no_trade_in_reason = $req->request->get('no_trade_in_reason'); if (empty($no_trade_in_reason)) $error_array['no_trade_in_reason'] = 'No trade in reason required.'; } } // get source of awareness if any $soa_type = $req->request->get('source_of_awareness', ''); // get remarks $remarks = $req->request->get('remarks', ''); // get initial concern if any $initial_concern = $req->request->get('initial_concern', ''); // get initial concern notes if any $initial_concern_notes = $req->request->get('initial_concern_notes', ''); // get gender if any $gender = $req->request->get('gender', ''); // get caller classification if any $caller_class = $req->request->get('caller_class', ''); 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')); // 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($stype) ->setWarrantyClass($req->request->get('warranty_class')) ->setSource($req->request->get('source')) ->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')) ->setPromoDetail($req->request->get('promo_detail')) ->setModeOfPayment($req->request->get('mode_of_payment')) ->setLandmark($req->request->get('landmark')) ->setWillWait($req->request->get('flag_willing_to_wait')) ->setReasonNotWait($reason) ->setNotWaitingNotes($more_reason) ->setNoTradeInReason($no_trade_in_reason) ->setSourceOfAwareness($soa_type) ->setRemarks($remarks) ->setInitialConcern($initial_concern) ->setInitialConcernNotes($initial_concern_notes) ->setCallerClassification($caller_class) ->setGender($gender); // did they change invoice? $invoice_items = $req->request->get('invoice_items', []); $promo_id = $req->request->get('invoice_promo'); $invoice_change = $req->request->get('invoice_change', 0); if ($invoice_change) { $this->ic->generateInvoiceCriteria($obj, $promo_id, $invoice_items, $error_array); } // validate $errors = $this->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); } // the event $event = new JOEvent(); $event->setDateHappen(new DateTime()) ->setTypeID(JOEventType::OPEN_EDIT) ->setJobOrder($obj); error_log('open edit?'); if ($user != null) { $event->setUser($user); } $em->persist($event); // validated! save the entity $em->flush(); } $data['error_array'] = $error_array; if ($obj != null) { $data['job_order'] = $obj; } return $data; } // dispatch job order public function dispatchJobOrder(Request $req, int $id, MQTTClient $mclient) { // get object data $em = $this->em; $obj = $em->getRepository(JobOrder::class)->find($id); $processor = $obj->getProcessedBy(); $user = $this->security->getUser();; // check if we're the one processing, return error otherwise if ($processor == null) throw new AccessDeniedHttpException('Not the processor'); if ($processor != null && $processor->getID() != $user->getID()) throw new AccessDeniedHttpException('Not the processor'); // initialize error list $error_array = []; // make sure this object exists if (empty($obj)) throw new NotFoundHttpException('The item does not exist'); // check if cancelled already if (!$obj->canDispatch()) { throw new NotFoundHttpException('Could not dispatch. Job Order is not pending.'); // TODO: have this handled better, so UI shows the error // $error_array['dispatch'] = 'Could not dispatch. Job Order is not pending.'; } // 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.'; } } // check facilitated type $fac_type = $req->request->get('facilitated_type'); if (!empty($fac_type)) { if (!FacilitatedType::validate($fac_type)) $fac_type = null; } else $fac_type = null; // check facilitated by $fac_by_id = $req->request->get('facilitated_by'); $fac_by = null; if (!empty($fac_by_id)) { $fac_by = $em->getRepository(Hub::class)->find($fac_by_id); if (empty($fac_by)) $fac_by = null; } // check if landmark is set if (empty($req->request->get('landmark'))) $error_array['landmark'] = 'Landmark is required.'; // check if customer is not willing to wait $will_wait = $req->request->get('flag_willing_to_wait'); $reason = ''; $more_reason = ''; if ($will_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) { // get the reason and text $reason = $req->request->get('no_wait_reason'); $more_reason = $req->request->get('not_wait_notes'); } // get source of awareness if any $soa_type = $req->request->get('source_of_awareness', ''); // get remarks $remarks = $req->request->get('remarks', ''); // get initial concern if any $initial_concern = $req->request->get('initial_concern', ''); // get initial concern notes if any $initial_concern_notes = $req->request->get('initial_concern_notes', ''); // get gender if any $gender = $req->request->get('gender', ''); // get caller classification if any $caller_class = $req->request->get('caller_class', ''); 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')) ->setFacilitatedType($fac_type) ->setFacilitatedBy($fac_by) ->setHub($hub) ->setLandmark($req->request->get('landmark')) ->setWillWait($req->request->get('flag_willing_to_wait')) ->setReasonNotWait($reason) ->setNotWaitingNotes($more_reason) ->setSourceOfAwareness($soa_type) ->setRemarks($remarks) ->setInitialConcern($initial_concern) ->setInitialConcernNotes($initial_concern_notes) ->setGender($gender) ->setCallerClassification($caller_class); // validate $errors = $this->validator->validate($obj); // add errors to list foreach ($errors as $error) { $error_array[$error->getPropertyPath()] = $error->getMessage(); } } if (empty($error_array)) { // the event $event = new JOEvent(); $event->setDateHappen(new DateTime()) ->setTypeID(JOEventType::HUB_ASSIGN) ->setJobOrder($obj); if ($user != null) { $event->setUser($user); } $em->persist($event); // validated! save the entity $em->flush(); // send event to mobile app $payload = [ 'event' => 'outlet_assign' ]; $mclient->sendEvent($obj, $payload); // update redis hub jo count $this->hub_dist->incrementJoCountForHub($hub); } return $error_array; } // assign job order public function assignJobOrder(Request $req, $id) { // get object data $em = $this->em; $obj = $em->getRepository(JobOrder::class)->find($id); // initialize error list $error_array = []; // make sure this object exists if (empty($obj)) throw new NotFoundHttpException('The item does not exist'); // check if we can assign if (!$obj->canAssign()) throw new NotFoundHttpException('Cannot assign rider to this job order.'); // 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.'; } } // check if landmark is set if (empty($req->request->get('landmark'))) $error_array['landmark'] = 'Landmark is required.'; // check if customer is not willing to wait $will_wait = $req->request->get('flag_willing_to_wait'); $reason = ''; $more_reason = ''; if ($will_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) { // get the reason and text $reason = $req->request->get('no_wait_reason'); $more_reason = $req->request->get('not_wait_notes'); } // get source of awareness if any $soa_type = $req->request->get('source_of_awareness', ''); // get remarks $remarks = $req->request->get('remarks', ''); // get initial concern if any $initial_concern = $req->request->get('initial_concern', ''); // get initial concern notes if any $initial_concern_notes = $req->request->get('initial_concern_notes', ''); // get gender if any $gender = $req->request->get('gender', ''); // get caller classification if any $caller_class = $req->request->get('caller_class', ''); // get current user $user = $this->security->getUser(); 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')) ->setDateAssign(new DateTime()) ->setRider($rider) ->setLandmark($req->request->get('landmark')) ->setWillWait($req->request->get('flag_willing_to_wait')) ->setReasonNotWait($reason) ->setNotWaitingNotes($more_reason) ->setDeliveryStatus(DeliveryStatus::RIDER_ASSIGN) ->setSourceOfAwareness($soa_type) ->setRemarks($remarks) ->setInitialConcern($initial_concern) ->setInitialConcernNotes($initial_concern_notes) ->setCallerClassification($caller_class) ->setGender($gender); if ($user != null) { $obj->setAssignedBy($user); } // validate $errors = $this->validator->validate($obj); // add errors to list foreach ($errors as $error) { $error_array[$error->getPropertyPath()] = $error->getMessage(); } } if (empty($error_array)) { // set rider unavailable // $rider->setAvailable(false); // set rider's current job order $rider->setCurrentJobOrder($obj); // the event $event = new JOEvent(); $event->setDateHappen(new DateTime()) ->setTypeID(JOEventType::RIDER_ASSIGN) ->setJobOrder($obj); if ($user != null) { $event->setUser($user); } $em->persist($event); // validated! save the entity $em->flush(); // call rider assignment handler's assignJobOrder $this->rah->assignJobOrder($obj, $rider); } return $error_array; } // fulfill job order public function fulfillJobOrder(Request $req, $id) { // initialize error list $error_array = []; // get object data $em = $this->em; $obj = $em->getRepository(JobOrder::class)->find($id); // make sure this object exists if (empty($obj)) throw new NotFoundHttpException('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 landmark is set if (empty($req->request->get('landmark'))) $error_array['landmark'] = 'Landmark is required.'; // check if customer is not willing to wait $will_wait = $req->request->get('flag_willing_to_wait'); $reason = ''; $more_reason = ''; if ($will_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) { // get the reason and text $reason = $req->request->get('no_wait_reason'); $more_reason = $req->request->get('not_wait_notes'); } // get source of awareness if any $soa_type = $req->request->get('source_of_awareness', ''); // get remarks $remarks = $req->request->get('remarks', ''); // get initial concern if any $initial_concern = $req->request->get('initial_concern', ''); // get initial concern notes if any $initial_concern_notes = $req->request->get('initial_concern_notes', ''); // get gender if any $gender = $req->request->get('gender', ''); // get caller classification if any $caller_class = $req->request->get('caller_class', ''); 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')) ->setDeliveryInstructions($req->request->get('delivery_instructions')) ->setTier1Notes($req->request->get('tier1_notes')) ->setTier2Notes($req->request->get('tier2_notes')) ->setDeliveryAddress($req->request->get('delivery_address')) ->setLandmark($req->request->get('landmark')) ->setWillWait($req->request->get('flag_willing_to_wait')) ->setReasonNotWait($reason) ->setNotWaitingNotes($more_reason) ->setDeliveryStatus(DeliveryStatus::FULFILLED) ->setSourceOfAwareness($soa_type) ->setRemarks($remarks) ->setInitialConcern($initial_concern) ->setInitialConcernNotes($initial_concern_notes) ->setGender($gender) ->setCallerClassification($caller_class); // validate $errors = $this->validator->validate($obj); // add errors to list foreach ($errors as $error) { $error_array[$error->getPropertyPath()] = $error->getMessage(); } } if (empty($error_array)) { $obj->fulfill(); // the event $event = new JOEvent(); $event->setDateHappen(new DateTime()) ->setTypeID(JOEventType::FULFILL) ->setJobOrder($obj); // get current user $user = $this->security->getUser(); if ($user != null) { $event->setUser($user); } $event->setUser($user); $em->persist($event); // save to customer vehicle battery record $this->updateVehicleBattery($obj); // 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(); // call rider assignment handler's fulfillJobOrder $this->rah->fulfillJobOrder($obj, $image_url, $rider); // create the warranty if new battery only if ($this->checkIfNewBattery($obj)) { $serial = null; $warranty_class = $obj->getWarrantyClass(); $first_name = $obj->getCustomer()->getFirstName(); $last_name = $obj->getCustomer()->getLastName(); $mobile_number = $obj->getCustomer()->getPhoneMobile(); // check if date fulfilled is null //if ($obj->getDateFulfill() == null) // $date_purchase = $obj->getDateCreate(); //else // $date_purchase = $obj->getDateFulfill(); // use date_schedule for warranty expiration computation $date_purchase = $obj->getDateSchedule(); // validate plate number // $plate_number = $this->wh->cleanPlateNumber($jo->getCustomerVehicle()->getPlateNumber()); $plate_number = Warranty::cleanPlateNumber($obj->getCustomerVehicle()->getPlateNumber()); if ($plate_number != false) { $batt_list = array(); $invoice = $obj->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(); } } } $user_id = $user->getUsername(); $source = WarrantySource::ADMIN_PANEL; $this->wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class, $user_id, $source, $obj->getCustomer(), $obj->getCustomerVehicle()->getVehicle()); } else error_log('Invalid plate number for warranty. Plate number = ' . $obj->getCustomerVehicle()->getPlateNumber()); } // send SMS to customer // prepend country code to number $phone_number = $this->country_code . $obj->getCustomer()->getPhoneMobile(); if (!empty($phone_number)) $this->sendSMSToCustomer($phone_number); } return $error_array; } // cancel job order public function cancelJobOrder(Request $req, int $id, MQTTClient $mclient) { // get object data $em = $this->em; $obj = $em->getRepository(JobOrder::class)->find($id); // make sure this object exists if (empty($obj)) throw new NotFoundHttpException('The item does not exist'); $cancel_reason = $req->request->get('cancel_reason'); //error_log('cancel_reason ' . $cancel_reason); $obj->setDeliveryStatus(DeliveryStatus::CANCELLED); $obj->cancel($cancel_reason); // the event $event = new JOEvent(); $event->setDateHappen(new DateTime()) ->setTypeID(JOEventType::CANCEL) ->setJobOrder($obj); // get current user $user = $this->security->getUser(); if ($user != null) { $event->setUser($user); } $event->setUser($user); $em->persist($event); // save $em->flush(); // send mobile app event $payload = [ 'event' => 'cancelled', 'reason' => $cancel_reason, 'jo_id' => $obj->getID(), ]; $mclient->sendEvent($obj, $payload); $mclient->sendRiderEvent($obj, $payload); } // set hub for job order public function setHub($req, $id, $mclient) { // get object data $em = $this->em; $obj = $em->getRepository(JobOrder::class)->find($id); $user = $this->security->getUser(); // initialize error list $error_array = []; // make sure this object exists if (empty($obj)) throw new NotFoundHttpException('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.'; } } // check if landmark is set if (empty($req->request->get('landmark'))) $error_array['landmark'] = 'Landmark is required.'; error_log($req->request->get('landmark')); // check if customer is not willing to wait $will_wait = $req->request->get('flag_willing_to_wait'); $reason = ''; $more_reason = ''; if ($will_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) { // get the reason and text $reason = $req->request->get('no_wait_reason'); $more_reason = $req->request->get('not_wait_notes'); } // get source of awareness if any $soa_type = $req->request->get('source_of_awareness', ''); // get remarks $remarks = $req->request->get('remarks', ''); // get initial concern if any $initial_concern = $req->request->get('initial_concern', ''); // get initial concern notes if any $initial_concern_notes = $req->request->get('initial_concern_notes', ''); // get gender if any $gender = $req->request->get('gender', ''); // get caller classification if any $caller_class = $req->request->get('caller_class', ''); // get previously assigned hub, if any $old_hub = $obj->getHub(); // get previously assigned rider, if any $old_rider = $obj->getRider(); if (empty($error_array)) { // rider mqtt event // NOTE: need to send this before saving because rider will be cleared $rider_payload = [ 'event' => 'cancelled', 'reason' => 'Reassigned', 'jo_id' => $obj->getID(), ]; $mclient->sendRiderEvent($obj, $rider_payload); // need to unset first rider's current job order $old_rider = $obj->getRider(); if ($old_rider != null) { if (($old_rider->getCurrentJobOrder() != null) && ($old_rider->getCurrentJobOrder()->getID() == $obj->getID())) { $old_rider->setCurrentJobOrder(); // set available flag for first rider $old_rider->setAvailable(true); } } // 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) ->setLandmark($req->request->get('landmark')) ->setWillWait($req->request->get('flag_willing_to_wait')) ->setReasonNotWait($reason) ->setNotWaitingNotes($more_reason) ->setSourceOfAwareness($soa_type) ->setRemarks($remarks) ->setInitialConcern($initial_concern) ->setInitialConcernNotes($initial_concern_notes) ->setGender($gender) ->setCallerClassification($caller_class) ->clearRider(); if ($user != null) { $obj->setProcessedBy($user); } $em->persist($obj); // validate $errors = $this->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)) { // add event $event = new JOEvent(); $event->setDateHappen(new DateTime()) ->setTypeID(JOEventType::HUB_ASSIGN) ->setJobOrder($obj); if ($user != null) { $event->setUser($user); } $em->persist($event); // validated! save the entity $em->flush(); // user mqtt event $payload = [ 'event' => 'outlet_assign' ]; $mclient->sendEvent($obj, $payload); // update redis hub_jo_count for hub // decrement old hub's count and increment new hub's count if ($old_hub != null) $this->hub_dist->decrementJoCountForHub($old_hub); if ($hub != null) $this->hub_dist->incrementJoCountForHub($hub); } return $error_array; } // reject hub for job order public function rejectHub($req, $id) { // get object data $em = $this->em; $jo = $em->getRepository(JobOrder::class)->find($id); $processor = $jo->getProcessedBy(); $user = $this->security->getUser(); // check if we're the one processing, return error otherwise if ($processor == null) throw new AccessDeniedHttpException('Not the processor'); if ($user != null) { if ($processor != null && $processor->getID() != $user->getID()) throw new AccessDeniedHttpException('Not the processor'); } // initialize error list $error_array = []; // make sure job order exists if (empty($jo)) throw new NotFoundHttpException('The item does not exist'); // 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.'; } } // check if this hub has already been rejected on this job order $robj = $em->getRepository(JORejection::class)->findOneBy([ 'job_order' => $jo, 'hub' => $hub ]); if (!empty($robj)) $error_array['hub'] = 'This hub has already been rejected for the current job order.'; // check if reason is set if (empty($req->request->get('reason'))) $error_array['reason'] = 'No reason selected.'; else if (!JORejectionReason::validate($req->request->get('reason'))) $error_array['reason'] = 'Invalid reason specified.'; if (empty($error_array)) { // coordinates $obj = new JORejection(); // set and save values $obj->setDateCreate(new DateTime()) ->setHub($hub) ->setJobOrder($jo) ->setReason($req->request->get('reason')) ->setRemarks($req->request->get('remarks')) ->setContactPerson($req->request->get('contact_person')); if ($user != null) { $obj->setUser($user); } // validate $errors = $this->validator->validate($obj); // add errors to list foreach ($errors as $error) { $error_array[$error->getPropertyPath()] = $error->getMessage(); } } if (empty($error_array)) { // validated! save the entity $em->persist($obj); $em->flush(); } return $error_array; } // set rider for job order public function setRider($req, $id, $mclient) { // initialize error list $error_array = []; // get object data $em = $this->em; $obj = $em->getRepository(JobOrder::class)->find($id); $user = $this->security->getUser(); // make sure this object exists if (empty($obj)) throw new NotFoundHttpException('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.'; } } // check if landmark is set if (empty($req->request->get('landmark'))) $error_array['landmark'] = 'Landmark is required.'; // check if customer is not willing to wait $will_wait = $req->request->get('flag_willing_to_wait'); $reason = ''; $more_reason = ''; if ($will_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) { // get the reason and text $reason = $req->request->get('no_wait_reason'); $more_reason = $req->request->get('not_wait_notes'); } // get source of awareness if any $soa_type = $req->request->get('source_of_awareness', ''); // get remarks $remarks = $req->request->get('remarks', ''); // get initial concern if any $initial_concern = $req->request->get('initial_concern', ''); // get initial concern notes if any $initial_concern_notes = $req->request->get('initial_concern_notes', ''); // get gender if any $gender = $req->request->get('gender', ''); // get caller classification if any $caller_class = $req->request->get('caller_class', ''); if (empty($error_array)) { // rider mqtt event // NOTE: need to send this before saving because rider will be cleared $rider_payload = [ 'event' => 'cancelled', 'reason' => 'Reassigned', 'jo_id' => $obj->getID(), ]; $mclient->sendRiderEvent($obj, $rider_payload); // need to unset first rider's current job order $old_rider = $obj->getRider(); if ($old_rider != null) { if (($old_rider->getCurrentJobOrder() != null) && ($old_rider->getCurrentJobOrder()->getID() == $obj->getID())) { $old_rider->setCurrentJobOrder(); // set available flag for first rider $old_rider->setAvailable(true); } } // 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')) ->setDateAssign(new DateTime()) ->setRider($rider) ->setLandmark($req->request->get('landmark')) ->setWillWait($req->request->get('flag_willing_to_wait')) ->setReasonNotWait($reason) ->setNotWaitingNotes($more_reason) ->setSourceOfAwareness($soa_type) ->setRemarks($remarks) ->setDeliveryStatus(DeliveryStatus::RIDER_ASSIGN) ->setInitialConcern($initial_concern) ->setInitialConcernNotes($initial_concern_notes) ->setGender($gender) ->setCallerClassification($caller_class); if ($user != null) { $obj->setAssignedBy($user); } // validate $errors = $this->validator->validate($obj); $em->persist($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)) { // set new rider's current job order $rider->setCurrentJobOrder($obj); // set new rider's availability to false $rider->setAvailable(false); // add event $event = new JOEvent(); $event->setDateHappen(new DateTime()) ->setTypeID(JOEventType::RIDER_ASSIGN) ->setJobOrder($obj); if ($user != null) { $event->setUser($user); } $em->persist($event); // validated! save the entity $em->flush(); // send event to mobile app $payload = [ 'event' => 'driver_assigned' ]; $mclient->sendEvent($obj, $payload); $mclient->sendRiderEvent($obj, $payload); } return $error_array; } // unlock processor public function unlockProcessor($id) { // clear lock $em = $this->em; $jo = $em->getRepository(JobOrder::class)->find($id); if ($jo != null) { $jo->setProcessedBy(null); $em->flush(); } } // unlock assignor public function unlockAssignor($id) { // clear lock $em = $this->em; $jo = $em->getRepository(JobOrder::class)->find($id); if ($jo != null) { $jo->setAssignedBy(null); $em->flush(); } } // CMB code public function processOneStepJobOrder(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 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.'; } } // check if hub AND rider is selected if ((empty($req->request->get('hub_id'))) && (empty($req->request->get('rider_id')))) { $error_array['hub'] = 'No hub selected.'; } else { if (empty($req->request->get('rider_id'))) { $error_array['rider'] = 'No rider selected.'; } else { // get hub $hub = $em->getRepository(Hub::class)->find($req->request->get('hub_id')); if (empty($hub)) { $error_array['hub'] = 'Invalid hub specified.'; } else { // get rider $rider = $em->getRepository(Rider::class)->find($req->request->get('rider_id')); if (empty($rider)) { $error_array['rider'] = 'Invalid rider specified.'; } } } } 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')) ->setCustomer($cust_vehicle->getCustomer()) ->setCustomerVehicle($cust_vehicle) ->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')) ->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) ->setRider($rider); // 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); $em->flush(); } } return $error_array; } // initialize incoming job order form public function initializeIncomingForm() { $params['obj'] = new JobOrder(); $params['mode'] = 'create'; $this->fillDropdownParameters($params); $this->fillFormTags($params); // get template to display $params['template'] = $this->getTwigTemplate('jo_incoming_form'); // return params return $params; } // CMB code public function initializeOneStepForm() { $params['obj'] = new JobOrder(); $params['mode'] = 'onestep'; $this->fillDropdownParameters($params); $this->fillFormTags($params); // get template to display $params['template'] = $this->getTwigTemplate('jo_onestep'); // return params return $params; } // CMB code public function initializeOneStepEditForm($id, $map_tools) { $em = $this->em; $obj = $em->getRepository(JobOrder::class)->find($id); $params['obj'] = $obj; $params['mode'] = 'onestep-edit'; $params['cvid'] = $obj->getCustomerVehicle()->getID(); $params['vid'] = $obj->getCustomerVehicle()->getVehicle()->getID(); $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_onestep_edit_form'); return $params; } // initialize open edit job order form public function initializeOpenEditForm($id) { $em = $this->em; $jo = $em->getRepository(JobOrder::class)->find($id); $params['obj'] = $jo; $params['mode'] = 'open_edit'; $params['cvid'] = $jo->getCustomerVehicle()->getID(); $params['vid'] = $jo->getCustomerVehicle()->getVehicle()->getID(); $this->fillDropdownParameters($params); $this->fillFormTags($params); // get template to display $params['template'] = $this->getTwigTemplate('jo_open_edit_form'); return $params; } // initialize incoming vehicle form public function initializeIncomingVehicleForm(int $cvid) { $params['mode'] = 'create_vehicle'; $params['cvid'] = $cvid; $em = $this->em; // get customer vehicle $cv = $em->getRepository(CustomerVehicle::class)->find($cvid); $params['vid'] = $cv->getVehicle()->getID(); // make sure this customer vehicle exists if (empty($cv)) { $em->getConnection()->rollback(); throw new NotFoundHttpException('The job order does not exist'); } $jo = new JobOrder(); $jo->setCustomerVehicle($cv) ->setCustomer($cv->getCustomer()); $params['obj'] = $jo; $this->fillDropdownParameters($params); $this->fillFormTags($params); // get template to display $params['template'] = $this->getTwigTemplate('jo_incoming_vehicle_form'); return $params; } // initialize all job orders form for a specific job order id public function initializeAllForm($id) { $em = $this->em; $params['mode'] = 'update-all'; // get row data $obj = $em->getRepository(JobOrder::class)->find($id); // make sure this row exists if (empty($obj)) throw new NotFoundHttpException('The job order does not exist'); $this->fillDropdownParameters($params); $this->fillFormTags($params); // check JO status to determine the mode and submit_url to return if ($obj->getStatus() == JOStatus::CANCELLED) { $params['mode'] = 'fulfill-cancel'; $params['submit_url'] = 'jo_fulfill_cancel_submit'; } else { $params['mode'] = 'update-all'; $params['submit_url'] = ''; } // get template to display $params['template'] = $this->getTwigTemplate('jo_all_form'); $params['obj'] = $obj; $params['status_cancelled'] = JOStatus::CANCELLED; // 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" ], ]; return $params; } // initialize dispatch/processing job order form public function initializeProcessingForm($id, HubSelector $hub_selector, $motiv) { $em = $this->em; // 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 new NotFoundHttpException('The job order does not exist'); } // check status if ($obj->getStatus() != JOStatus::PENDING) { $em->getConnection()->rollback(); throw new NotFoundHttpException('The job order does not have a pending status'); } // check if we are the processor $processor = $obj->getProcessedBy(); // get current user $user = $this->security->getUser(); if ($user != null) { // 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 new AccessDeniedHttpException('Not the processor'); } // make this user be the processor $obj->setProcessedBy($user); } $em->flush(); $em->getConnection()->commit(); } catch(PessimisticLockException $e) { throw new AccessDeniedHttpException('Not the processor'); } // NOTE: we are able to lock, everything should be fine now $params['mode'] = 'update-processing'; $params['status_cancelled'] = JOStatus::CANCELLED; $this->fillDropdownParameters($params); $this->fillFormTags($params); // get rejections $rejections = $obj->getHubRejections(); // get rejection reasons $params['rejection_reasons'] = JORejectionReason::getCollection(); $hub_criteria = new HubCriteria(); // TODO: need to factor out the setting of HubCriteria fields // get battery (if any) $skus = []; $items = []; $invoice = $obj->getInvoice(); $inv_items = $invoice->getItems(); foreach ($inv_items as $inv_item) { $batt = $inv_item->getBattery(); if ($batt == null) continue; $skus[] = $batt->getSapCode(); $item_count = 1; if (!empty($batt->getSapCode())) { $sap_code = $batt->getSapCode(); if (isset($items[$sap_code])) $items[$sap_code] = $item_count + 1; else $items[$sap_code] = $item_count; $hub_criteria->addItem($sap_code, $item_count); } } // get closest hubs // set more hub criteria fields $long = $obj->getCoordinates()->getLongitude(); $lat = $obj->getCoordinates()->getLatitude(); // set result limit and location and date_time $hub_criteria->setPoint($obj->getCoordinates()) ->setDateTime($obj->getDateSchedule()) ->setLimitResults(50); // check if hub filter is enabled. If not, use default values // for the rest of the HubCriteria fields if ($this->hub_filter_enabled == 'true') { error_log('hub filter is enabled'); if ($this->hub_geofence->isCovered($long, $lat)) { // if true, set other values for HubCriteria error_log('Area is covered by hub filtering'); $hub_criteria->setLimitDistance($this->cust_distance_limit) ->setPaymentMethod($obj->getModeOfPayment()) ->setJoType($obj->getServiceType()) ->setRoundRobin(true); } } // check if emergency or not $willing_to_wait = $obj->getWillWait(); if ($willing_to_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) { // reset distance limit if emergency $hub_criteria->setLimitDistance(500); $hub_criteria->setEmergency(true); } // get JO and customer id for logging purposes $jo_id = $obj->getID(); $customer_id = $obj->getCustomer()->getID(); $hub_criteria->setJobOrderId($jo_id) ->setCustomerId($customer_id); $hubs = $hub_selector->find($hub_criteria); $params['hubs'] = []; $branch_codes = []; $inv_data = []; // 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['redis_jo_count'] = $hub['jo_count']; //$hub['redis_jo_count'] = 0; // $hub['jo_count'] = count($hub['hub']->getForAssignmentJobOrders()); $hub['jo_count'] = $hub['redis_jo_count']; // check for rejection $hub['flag_rejected'] = false; $hub_id = $hub['hub']->getID(); foreach ($rejections as $robj) { if ($robj->getHub()->getID() === $hub_id) { $hub['flag_rejected'] = true; break; } } // handle inventory data $bcode = $hub['hub']->getBranchCode(); $hub['inventory'] = 0; if ($bcode != '') { $branch_codes[] = $bcode; $inv_data[$bcode] = [ 'hub_id' => $hub_id, 'branch_code' => $bcode, 'inventory' => 0, ]; } $params['hubs'][$hub_id] = $hub; } $params['obj'] = $obj; // get template to display $params['template'] = $this->getTwigTemplate('jo_processing_form'); // get battery (if any) $skus = []; $invoice = $obj->getInvoice(); $inv_items = $invoice->getItems(); foreach ($inv_items as $inv_item) { $batt = $inv_item->getBattery(); if ($batt == null) continue; $skus[] = $batt->getSapCode(); } // get inventory $mres = $motiv->getInventory($branch_codes, $skus); foreach ($mres as $mres_item) { $bcode = $mres_item['BranchCode']; $inv_count = $mres_item['Quantity']; if (isset($inv_data[$bcode])) { $hub_id = $inv_data[$bcode]['hub_id']; $params['hubs'][$hub_id]['inventory'] = $inv_count; } } error_log(print_r($mres, true)); return $params; } // initialize assign job order form public function initializeAssignForm($id) { $em = $this->em; // manual transaction since we're locking $em->getConnection()->beginTransaction(); $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 new NotFoundHttpException('The job order does not exist'); } // check status if ($obj->getStatus() != JOStatus::RIDER_ASSIGN) { $em->getConnection()->rollback(); throw new NotFoundHttpException('The job order does not have an assigning status'); } // check if super user $user = $this->security->getUser(); if ($user != null) { if ($user->isSuperAdmin()) { // do nothing, just allow page to be accessed } else { // check if hub is assigned to current user $user_hubs = $user->getHubs(); if (!in_array($obj->getHub()->getID(), $user_hubs)) { $em->getConnection()->rollback(); throw new NotFoundHttpException('The job order is not on a hub assigned to this user'); } // check if we are the assignor $assignor = $obj->getAssignedBy(); if ($assignor != null && $assignor->getID() != $user->getID()) { $em->getConnection()->rollback(); throw new AccessDeniedHttpException('Not the assignor'); } // make this user be the assignor $obj->setAssignedBy($user); } } $em->flush(); $em->getConnection()->commit(); } catch (PessimisticLockException $e) { throw new AccessDeniedHttpException('Not the assignor'); } $this->fillDropdownParameters($params); $this->fillFormTags($params); // get template to display $params['template'] = $this->getTwigTemplate('jo_assigning_form'); $params['obj'] = $obj; $params['status_cancelled'] = JOStatus::CANCELLED; return $params; } // initialize fulflll job order form public function initializeFulfillmentForm($id) { $em = $this->em; $params['mode'] = 'update-fulfillment'; // get row data $obj = $em->getRepository(JobOrder::class)->find($id); // make sure this row exists if (empty($obj)) { throw new NotFoundHttpException('The job order does not exist'); } // check status if (!in_array($obj->getStatus(), [JOStatus::ASSIGNED, JOStatus::IN_PROGRESS])) { throw new NotFoundHttpException('The job order does not have a fulfillment status'); } // get current user $user = $this->security->getUser(); // check if hub is assigned to current user $user_hubs = $user->getHubs(); if (!in_array($obj->getHub()->getID(), $user_hubs)) { throw new NotFoundHttpException('The job order is not on a hub assigned to this user'); } $this->fillDropdownParameters($params); $this->fillFormTags($params); // get template to display $params['template'] = $this->getTwigTemplate('jo_fulfillment_form'); $params['obj'] = $obj; $params['status_cancelled'] = JOStatus::CANCELLED; return $params; } // initialize hub form public function initializeHubForm($id, HubSelector $hub_selector, $motiv) { $em = $this->em; $params['mode'] = 'update-reassign-hub'; // get row data $obj = $em->getRepository(JobOrder::class)->find($id); // make sure this row exists if (empty($obj)) { throw new NotFoundHttpException('The job order does not exist'); } $this->fillDropdownParameters($params); $this->fillFormTags($params); // get rejections $rejections = $obj->getHubRejections(); // get rejection reasons $params['rejection_reasons'] = JORejectionReason::getCollection(); $hub_criteria = new HubCriteria(); // get battery (if any) $skus = []; $items = []; $invoice = $obj->getInvoice(); $inv_items = $invoice->getItems(); foreach ($inv_items as $inv_item) { $batt = $inv_item->getBattery(); if ($batt == null) continue; $skus[] = $batt->getSapCode(); $item_count = 1; if (!empty($batt->getSapCode())) { $sap_code = $batt->getSapCode(); if (isset($items[$sap_code])) $items[$sap_code] = $item_count + 1; else $items[$sap_code] = $item_count; } $hub_criteria->addItem($sap_code, $item_count); } // get closest hubs // set more hub criteria fields $long = $obj->getCoordinates()->getLongitude(); $lat = $obj->getCoordinates()->getLatitude(); $hub_criteria->setPoint($obj->getCoordinates()) ->setDateTime($obj->getDateSchedule()) ->setLimitResults(50); if ($this->hub_geofence->isCovered($long, $lat)) { // if true, set other values for HubCriteria // error_log('Area is covered by hub'); $hub_criteria->setLimitDistance($this->cust_distance_limit) ->setPaymentMethod($obj->getModeOfPayment()) ->setJoType($obj->getServiceType()) ->setRoundRobin(true); } // check if emergency or not $willing_to_wait = $obj->getWillWait(); if ($willing_to_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT) $hub_criteria->setEmergency(true); // get JO and customer id for logging purposes $jo_id = $obj->getID(); $customer_id = $obj->getCustomer()->getID(); $hub_criteria->setJobOrderId($jo_id) ->setCustomerId($customer_id); $hubs = $hub_selector->find($hub_criteria); $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; } // counters $hub['rider_count'] = count($hub['hub']->getAvailableRiders()); // $hub['redis_jo_count'] = $hub['jo_count']; $hub['redis_jo_count'] = 0; // $hub['jo_count'] = count($hub['hub']->getForAssignmentJobOrders()); $hub['jo_count'] = $hub['redis_jo_count']; // check for rejection $hub['flag_rejected'] = false; $hub_id = $hub['hub']->getID(); foreach ($rejections as $robj) { if ($robj->getHub()->getID() === $hub_id) { $hub['flag_rejected'] = true; break; } } // handle inventory data $bcode = $hub['hub']->getBranchCode(); $hub['inventory'] = 0; if ($bcode != '') { $branch_codes[] = $bcode; $inv_data[$bcode] = [ 'hub_id' => $hub_id, 'branch_code' => $bcode, 'inventory' => 0, ]; } $params['hubs'][$hub_id] = $hub; } // get battery (if any) $skus = []; $invoice = $obj->getInvoice(); $inv_items = $invoice->getItems(); foreach ($inv_items as $inv_item) { $batt = $inv_item->getBattery(); if ($batt == null) continue; $skus[] = $batt->getSapCode(); } // get inventory $mres = $motiv->getInventory($branch_codes, $skus); foreach ($mres as $mres_item) { $bcode = $mres_item['BranchCode']; $inv_count = $mres_item['Quantity']; if (isset($inv_data[$bcode])) { $hub_id = $inv_data[$bcode]['hub_id']; $params['hubs'][$hub_id]['inventory'] = $inv_count; } } error_log(print_r($mres, true)); $params['obj'] = $obj; // get template to display $params['template'] = $this->getTwigTemplate('jo_open_hub_form'); return $params; } // initialize rider form public function initializeRiderForm($id) { $em = $this->em; $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 new NotFoundHttpException('The job order does not exist'); } // check status if ($obj->getStatus() == JOStatus::PENDING) { $em->getConnection()->rollback(); throw new NotFoundHttpException('The job order does not have an assigned hub'); } $this->fillDropdownParameters($params); $this->fillFormTags($params); $params['obj'] = $obj; $params['status_cancelled'] = JOStatus::CANCELLED; // get template to display $params['template'] = $this->getTwigTemplate('jo_open_rider_form'); return $params; } // generate pdf form for job order public function generatePDFForm($req, $id, $proj_path) { $em = $this->em; $translator = $this->translator; // get row data $obj = $em->getRepository(JobOrder::class)->find($id); // make sure this row exists if (empty($obj)) throw new NotFoundHttpException('The job order does not exist'); // set output filename $filename = 'job-order-' . $obj->getID() . '.pdf'; // translate the title and the logo for the pdf $translated_title = $translator->trans('jo_title_pdf'); $translated_logo = $translator->trans('image_jo_pdf'); // generate the pdf $pdf = new FPDF('P', 'mm', 'letter'); $pdf->AddPage(); $pdf->setTitle($translated_title . ' #' . $obj->getID()); $pdf->SetFillColor(211, 211, 211); // style defaults $margin = 10; $page_width = $pdf->GetPageWidth() - ($margin * 2); $table_col_width = $page_width / 12; $line_height = 5; $jo_line_height = 10; $table_line_height = 7; $font_face = 'Arial'; $body_font_size = 9; $header_font_size = 9; $jo_font_size = 16; $col1_x = $margin; $col2_x = 120; $label_width = 40; $val_width = 60; // insert the logo $image_path = $proj_path . $translated_logo; $pdf->Image($image_path, $col1_x, 10); // insert JO number $pdf->SetFont($font_face, 'B', $jo_font_size); $pdf->SetX($col2_x); $pdf->Cell($label_width, $jo_line_height, $translator->trans('label.pdf.jo_number')); $pdf->SetTextColor(9, 65, 150); $pdf->Cell(0, $jo_line_height, $obj->getID()); // insert customer info $customer = $obj->getCustomer(); $pdf->SetFont($font_face, '', $body_font_size); $pdf->SetTextColor(0, 0, 0); $pdf->Ln($line_height * 7); // get current Y $y = $pdf->GetY(); $pdf->SetXY($col1_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.customer_name')); $pdf->MultiCell($val_width, $line_height, $customer ? $customer->getFirstName() . ' ' . $customer->getLastName() : '', 0, 'L'); // get Y after left cell $y1 = $pdf->GetY(); $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.mobile_phone')); $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneMobile() ? $this->country_code . $customer->getPhoneMobile() : '', 0, 'L'); // get Y after right cell $y2 = $pdf->GetY(); // get row height $y = max($y1, $y2); $pdf->SetXY($col1_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.delivery_date')); $pdf->MultiCell($val_width, $line_height, $obj->getDateSchedule() ? $obj->getDateSchedule()->format("m/d/Y") : '', 0, 'left'); // get Y after left cell $y1 = $pdf->GetY(); $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.landline')); $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneLandline() ? $this->country_code . $customer->getPhoneLandline() : '', 0, 'L'); // get Y after right cell $y2 = $pdf->GetY(); // get row height $y = max($y1, $y2); $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.office_phone')); $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneOffice() ? $this->country_code . $customer->getPhoneOffice() : '', 0, 'L'); $pdf->SetX($col2_x); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.fax')); $pdf->MultiCell($val_width, $line_height, $customer && $customer->getPhoneFax() ? $this->country_code . $customer->getPhoneFax() : '', 0, 'L'); // insert vehicle info $cv = $obj->getCustomerVehicle(); $vehicle = $cv->getVehicle(); $pdf->Ln(); $pdf->SetFont($font_face, 'B', $header_font_size); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.vehicle_details')); $pdf->Ln($line_height * 2); // get current Y $y = $pdf->GetY(); $pdf->SetFont($font_face, '', $body_font_size); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.plate_number')); $pdf->MultiCell($val_width, $line_height, $cv ? $cv->getPlateNumber() : '', 0, 'L'); // get Y after left cell $y1 = $pdf->GetY(); $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.vehicle_color')); $pdf->MultiCell(0, $line_height, $cv ? $cv->getColor() : '', 0, 'L'); // get Y after right cell $y2 = $pdf->GetY(); // get row height $y = max($y1, $y2); $pdf->SetXY($col1_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.brand')); $pdf->MultiCell($val_width, $line_height, $vehicle && $vehicle->getManufacturer() ? $vehicle->getManufacturer()->getName() : '', 0, 'L'); // get Y after left cell $y1 = $pdf->GetY(); $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.model_year')); $pdf->MultiCell(0, $line_height, $cv ? $cv->getModelYear() : '', 0, 'L'); // get Y after right cell $y2 = $pdf->GetY(); // get row height $y = max($y1, $y2); $pdf->SetXY($col1_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.make')); $pdf->MultiCell($val_width, $line_height, $vehicle ? $vehicle->getMake() : '', 0, 'L'); // insert battery info $battery = $cv->getCurrentBattery(); $pdf->Ln(); $pdf->SetFont($font_face, 'B', $header_font_size); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.battery_details')); $pdf->Ln($line_height * 2); $pdf->SetFont($font_face, '', $body_font_size); // get current Y $y = $pdf->GetY(); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.current_battery')); $pdf->MultiCell($val_width, $line_height, $battery && $battery->getManufacturer() && $battery->getModel() && $battery->getSize() ? $battery->getManufacturer()->getName() . ' ' . $battery->getModel()->getName() . ' ' . $battery->getSize()->getName() . ' (' . $battery->getProductCode() . ')' : '', 0, 'L'); // get Y after left cell $y1 = $pdf->GetY(); $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.serial_number')); $pdf->MultiCell(0, $line_height, $cv ? $cv->getWarrantyCode() : '', 0, 'L'); // get Y after right cell $y2 = $pdf->GetY(); // get row height $y = max($y1, $y2); $pdf->SetXY($col1_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.warranty_exp_date')); $pdf->MultiCell($val_width, $line_height, $cv && $cv->getWarrantyExpiration() ? $cv->getWarrantyExpiration()->format("d/m/Y") : '', 0, 'L'); // insert transaction details $pdf->Ln(); $pdf->SetFont($font_face, 'B', $header_font_size); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.transaction_details')); $pdf->Ln($line_height * 2); $pdf->SetFont($font_face, '', $body_font_size); // get current Y $y = $pdf->GetY(); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.warranty_class')); $pdf->MultiCell($val_width, $line_height, WarrantyClass::getName($obj->getWarrantyClass()), 0, 'L'); // get Y after left cell $y1 = $pdf->GetY(); $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.mode_of_payment')); $pdf->MultiCell(0, $line_height, ModeOfPayment::getName($obj->getModeOfPayment()), 0, 'L'); // get Y after right cell $y2 = $pdf->GetY(); // get row height $y = max($y1, $y2); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.delivery_address')); $pdf->MultiCell($val_width, $line_height, $obj->getDeliveryAddress(), 0, 'L'); // get Y after left cell $y1 = $pdf->GetY(); $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.landmark')); $pdf->MultiCell(0, $line_height, $obj->getLandMark(), 0, 'L'); // get Y after right cell $y2 = $pdf->GetY(); // get row height $y = max($y1, $y2); $pdf->SetXY($col1_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.dispatch_time')); $pdf->MultiCell($val_width, $line_height, $obj->getDateSchedule() ? $obj->getDateSchedule()->format("g:i A") : '', 0, 'L'); // get Y after left cell $y1 = $pdf->GetY(); $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.dispatched_by')); $pdf->MultiCell(0, $line_height, $obj->getProcessedBy() ? $obj->getProcessedBy()->getFullName() : '', 0, 'L'); // get Y after right cell $y2 = $pdf->GetY(); // get row height $y = max($y1, $y2); // insert delivery instructions $pdf->SetY($y); $pdf->Ln(); $pdf->SetFont($font_face, 'B', $header_font_size); $pdf->Cell(0, $line_height, $translator->trans('label.pdf.delivery_instructions')); $pdf->Ln(); $pdf->SetFont($font_face, '', $body_font_size); $pdf->MultiCell(0, $line_height, $obj->getDeliveryInstructions(), 1, 'L'); // insert invoice details $pdf->Ln(); $pdf->SetFont($font_face, 'B', $header_font_size); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.invoice_details')); $pdf->Ln(); // invoice table headers $invoice = $obj->getInvoice(); $pdf->SetFont($font_face, 'B', $header_font_size); $pdf->Cell($table_col_width * 6, $table_line_height, $translator->trans('label.pdf.item'), 1, 0, 'L', 1); $pdf->Cell($table_col_width * 2, $table_line_height, $translator->trans('label.pdf.quantity'), 1, 0, 'R', 1); $pdf->Cell($table_col_width * 2, $table_line_height, $translator->trans('label.pdf.unit_price'), 1, 0, 'R', 1); $pdf->Cell($table_col_width * 2, $table_line_height, $translator->trans('label.pdf.amount'), 1, 1, 'R', 1); $pdf->SetFont($font_face, '', $body_font_size); // build invoice items table if ($invoice && !empty($invoice->getItems())) { foreach ($invoice->getItems() as $item) { $pdf->Cell($table_col_width * 6, $table_line_height, $item->getTitle(), 1); $pdf->Cell($table_col_width * 2, $table_line_height, number_format($item->getQuantity()), 1, 0, 'R'); $pdf->Cell($table_col_width * 2, $table_line_height, number_format($item->getPrice(), 2), 1, 0, 'R'); $pdf->Cell($table_col_width * 2, $table_line_height, number_format($item->getPrice() * $item->getQuantity(), 2), 1, 1, 'R'); } } else { $pdf->Cell($table_col_width * 12, 7, 'No items', 1, 1); } $pdf->Ln($line_height * 2); // get current Y $y = $pdf->GetY(); // insert invoice footer details $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.transaction_type')); $pdf->MultiCell($val_width, $line_height, ServiceType::getName($obj->getServiceType()), 0, 'L'); // get Y after left cell $y1 = $pdf->GetY(); $pdf->SetXY($col2_x, $y); $pdf->SetFont($font_face, 'B'); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.subtotal')); $pdf->SetFont($font_face, ''); $pdf->MultiCell(0, $line_height, $invoice ? number_format($invoice->getVATExclusivePrice(), 2) : '', 0, 'R'); // get Y after right cell $y2 = $pdf->GetY(); // get row height $y = max($y1, $y2); $pdf->SetXY($col1_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.or_name')); $pdf->MultiCell($val_width, $line_height, $obj->getORName(), 0, 'L'); // get Y after left cell $y1 = $pdf->GetY(); $pdf->SetXY($col2_x, $y); $pdf->SetFont($font_face, 'B'); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.tax')); $pdf->SetFont($font_face, ''); $pdf->MultiCell(0, $line_height, $invoice ? number_format($invoice->getVAT(), 2) : '', 0, 'R'); // get Y after right cell $y2 = $pdf->GetY(); // get row height $y = max($y1, $y2); $pdf->SetXY($col1_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.emp_id_ref')); $pdf->MultiCell($val_width, $line_height, $obj->getPromoDetail(), 0, 'L'); // get Y after left cell $y1 = $pdf->GetY(); $pdf->SetXY($col2_x, $y); $pdf->SetFont($font_face, 'B'); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.discount')); $pdf->SetFont($font_face, ''); $pdf->MultiCell(0, $line_height, $invoice ? number_format($invoice->getDiscount(), 2) : '', 0, 'R'); // get Y after right cell $y2 = $pdf->GetY(); // get row height $y = max($y1, $y2); $pdf->SetXY($col1_x, $y); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.discount_type')); $pdf->MultiCell($val_width, $line_height, $invoice && $invoice->getPromo() ? $invoice->getPromo()->getName() : '', 0, 'L'); $pdf->SetXY($col2_x, $y); $pdf->SetFont($font_face, 'B'); $pdf->Cell($label_width, $line_height, $translator->trans('label.pdf.final_amount')); $pdf->MultiCell(0, $line_height, $invoice ? number_format($invoice->getTotalPrice(), 2) : '', 0, 'R'); $pdf->SetFont($font_face, ''); $params['obj'] = $pdf; $params['filename'] = $filename; return $params; } public function getTwigTemplate($id) { if (isset($this->template_hash[$id])) { return $this->template_hash[$id]; } return null; } public function getOtherParameters() { // get riders for dropdown $params['riders'] = $this->em->getRepository(Rider::class)->findAll(); // get hubs for dropdown $params['hubs'] = $this->em->getRepository(Hub::class)->findBy(['flag_hub_view' => true]); return $params; } public function updateVehicleBattery(JobOrder $jo) { // check if new battery if (!($this->checkIfNewBattery($jo))) return; // customer vehicle $cv = $jo->getCustomerVehicle(); if ($cv == null) return; // invoice $invoice = $jo->getInvoice(); if ($invoice == null) return; // invoice items $items = $invoice->getItems(); if (count($items) <= 0) return; // get first battery from invoice $battery = null; foreach ($items as $item) { $battery = $item->getBattery(); if ($battery != null) break; } // no battery in order if ($battery == null) return; // warranty expiration $warr = $jo->getWarrantyClass(); $warr_months = 0; if ($warr == WarrantyClass::WTY_PRIVATE) $warr_months = $battery->getWarrantyPrivate(); else if ($warr == WarrantyClass::WTY_COMMERCIAL) $warr_months = $battery->getWarrantyCommercial(); else if ($warr == WarrantyClass::WTY_TNV) $warr_months = 12; $warr_date = new DateTime(); $warr_date->add(new DateInterval('P' . $warr_months . 'M')); // update customer vehicle battery $cv->setCurrentBattery($battery) ->setHasMotoliteBattery(true) ->setWarrantyExpiration($warr_date); } public function checkIfNewBattery(JobOrder $jo) { if ($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW) return true; return false; } protected function fillDropdownParameters(&$params) { $em = $this->em; // db loaded $params['bmfgs'] = $em->getRepository(BatteryManufacturer::class)->findAll(); $params['promos'] = $em->getRepository(Promo::class)->findAll(); // list of hubs $hubs = $em->getRepository(Hub::class)->findBy([], ['name' => 'ASC']); $fac_hubs = []; foreach ($hubs as $hub) { $fac_hubs[$hub->getID()] = $hub->getName() . ' - ' . $hub->getBranch(); } // list of customer tags $params['customer_tags'] = $em->getRepository(CustomerTag::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['facilitated_types'] = FacilitatedType::getCollection(); $params['facilitated_hubs'] = $fac_hubs; $params['sources'] = TransactionOrigin::getCollection(); $params['willing_to_wait_content'] = WillingToWaitContent::getCollection(); $params['no_wait_reasons'] = CustomerNotWaitReason::getCollection(); $params['no_trade_in_reasons'] = NoTradeInReason::getCollection(); $params['soa_types'] = SourceOfAwareness::getCollection(); $params['initial_concern'] = InitialConcern::getCollection(); $params['genders'] = Gender::getCollection(); $params['caller_classifications'] = CallerClassification::getCollection(); } protected function initFormTags(&$params) { // default to editing, as we have more forms editing than creating $params['ftags'] = [ 'title' => 'Job Order Form', 'vehicle_dropdown' => false, 'invoice_edit' => false, 'set_map_coordinate' => true, 'preset_vehicle' => false, 'ticket_table' => true, 'cancel_button' => true, ]; } protected function fillFormTags(&$params) { $this->initFormTags($params); switch ($params['mode']) { case 'create': $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 'create_vehicle': $params['ftags']['set_map_coordinate'] = false; $params['ftags']['invoice_edit'] = true; $params['ftags']['preset_vehicle'] = true; $params['ftags']['ticket_table'] = false; $params['ftags']['cancel_button'] = false; break; case 'open_edit': $params['ftags']['invoice_edit'] = true; $params['ftags']['preset_vehicle'] = true; break; case 'onestep': $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 'onestep-edit': $params['ftags']['invoice_edit'] = true; $params['ftags']['preset_vehicle'] = true; break; } } protected function loadTemplates() { $this->template_hash = []; // add all twig templates for job order to hash // TODO: put this in an array declaration // $this->template_hash = [ // 'blah' => 'blah', // ]; $this->template_hash['jo_incoming_form'] = 'job-order/form.html.twig'; $this->template_hash['jo_open_edit_form'] = 'job-order/form.html.twig'; $this->template_hash['jo_incoming_vehicle_form'] = 'job-order/form.html.twig'; $this->template_hash['jo_processing_form'] = 'job-order/form.html.twig'; $this->template_hash['jo_assigning_form'] = 'job-order/form.html.twig'; $this->template_hash['jo_fulfillment_form'] = 'job-order/form.html.twig'; $this->template_hash['jo_open_hub_form'] = 'job-order/form.html.twig'; $this->template_hash['jo_open_rider_form'] = 'job-order/form.html.twig'; $this->template_hash['jo_all_form'] = 'job-order/form.html.twig'; $this->template_hash['jo_list_processing'] = 'job-order/list.processing.html.twig'; $this->template_hash['jo_list_assigning'] = 'job-order/list.assigning.html.twig'; $this->template_hash['jo_list_fulfillment'] = 'job-order/list.fulfillment.html.twig'; $this->template_hash['jo_list_open'] = 'job-order/list.open.html.twig'; $this->template_hash['jo_list_all'] = 'job-order/list.all.html.twig'; $this->template_hash['jo_popup'] = 'job-order/popup.html.twig'; $this->template_hash['jo_hub_list'] = 'job-order/list.hubview.html.twig'; $this->template_hash['jo_hub_view_form'] = 'job-order/form.html.twig'; } 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, JOStatus::IN_TRANSIT, ]; 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; case 'hub_view_all': $tier_key = 'jo_hub'; $tier_name = 'Open'; $rows_route = 'jo_hub_view_rows'; $edit_route = 'jo_hub_view_form'; $unlock_route = ''; $jo_status = [ JOStatus::PENDING, JOStatus::RIDER_ASSIGN, JOStatus::ASSIGNED, JOStatus::IN_PROGRESS, JOStatus::IN_TRANSIT, ]; break; default: throw new AccessDeniedHttpException('No access.'); } // check acl if (!($this->security->isGranted($tier_key . '.list'))) throw new AccessDeniedHttpException('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 ]; } // 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': if (isset($datatable['query']['data-rows-search'])) { /* $query->innerJoin('q.cus_vehicle', 'cv') ->innerJoin('q.customer', 'c') ->where('cv.plate_number like :filter') ->orWhere('c.phone_mobile like :filter') ->orWhere('c.first_name like :filter or c.last_name like :filter') ->setParameter('filter', $datatable['query']['data-rows-search'] . '%'); */ $query->where('q.plate_number like :filter') ->orWhere('q.phone_mobile like :filter') ->orWhere('q.first_name like :filter') ->orWhere('q.last_name like :filter') ->setParameter('filter', $datatable['query']['data-rows-search'] . '%'); } if (isset($datatable['query']['rider'])) { $query->innerJoin('q.rider', 'r') ->andWhere('r.id = :rider_id') ->setParameter('rider_id', $datatable['query']['rider']); } if (isset($datatable['query']['schedule_date'])) { $start = $datatable['query']['schedule_date'][0] . ' ' . '00:00:00'; $end = $datatable['query']['schedule_date'][1] . ' ' . '23:59:00'; $date_start = DateTime::createFromFormat('m/d/Y H:i:s', $start); $date_end = DateTime::createFromFormat('m/d/Y H:i:s', $end); $query->andWhere('q.date_schedule >= :date_start') ->andWhere('q.date_schedule <= :date_end') ->setParameter('date_start', $date_start) ->setParameter('date_end', $date_end); } $query->andWhere('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': if (isset($datatable['query']['data-rows-search'])) { /* $query->innerJoin('q.cus_vehicle', 'cv') ->innerJoin('q.customer', 'c') ->where('q.status IN (:statuses)') ->andWhere('cv.plate_number like :filter or c.first_name like :filter or c.last_name like :filter or c.phone_mobile like :filter') ->setParameter('statuses', $status, Connection::PARAM_STR_ARRAY) ->setParameter('filter', $datatable['query']['data-rows-search'] . '%'); */ $query->where('q.plate_number like :filter') ->orWhere('q.phone_mobile like :filter') ->orWhere('q.first_name like :filter') ->orWhere('q.last_name like :filter') ->orWhere('q.status IN (:statuses)') ->setParameter('statuses', $status, Connection::PARAM_STR_ARRAY) ->setParameter('filter', $datatable['query']['data-rows-search'] . '%'); } else { $query->where('q.status IN (:statuses)') ->setParameter('statuses', $status, Connection::PARAM_STR_ARRAY); } if (isset($datatable['query']['rider'])) { $query->innerJoin('q.rider', 'r') ->andWhere('r.id = :rider_id') ->setParameter('rider_id', $datatable['query']['rider']); } if (isset($datatable['query']['schedule_date'])) { $start = $datatable['query']['schedule_date'][0] . ' ' . '00:00:00'; $end = $datatable['query']['schedule_date'][1] . ' ' . '23:59:00'; $date_start = DateTime::createFromFormat('m/d/Y H:i:s', $start); $date_end = DateTime::createFromFormat('m/d/Y H:i:s', $end); $query->andWhere('q.date_schedule >= :date_start') ->andWhere('q.date_schedule <= :date_end') ->setParameter('date_start', $date_start) ->setParameter('date_end', $date_end); } break; case 'all': if (isset($datatable['query']['data-rows-search'])) { /* $query->innerJoin('q.cus_vehicle', 'cv') ->innerJoin('q.customer', 'c') ->where('cv.plate_number like :filter') ->orWhere('c.phone_mobile like :filter') ->orWhere('c.first_name like :filter or c.last_name like :filter') ->setParameter('filter', $datatable['query']['data-rows-search'] . '%'); */ $query->where('q.plate_number like :filter') ->orWhere('q.phone_mobile like :filter') ->orWhere('q.first_name like :filter') ->orWhere('q.last_name like :filter') ->setParameter('filter', $datatable['query']['data-rows-search'] . '%'); } if (isset($datatable['query']['rider'])) { $query->innerJoin('q.rider', 'r') ->andWhere('r.id = :rider_id') ->setParameter('rider_id', $datatable['query']['rider']); } if (isset($datatable['query']['schedule_date'])) { $start = $datatable['query']['schedule_date'][0] . ' ' . '00:00:00'; $end = $datatable['query']['schedule_date'][1] . ' ' . '23:59:00'; $date_start = DateTime::createFromFormat('m/d/Y H:i:s', $start); $date_end = DateTime::createFromFormat('m/d/Y H:i:s', $end); $query->andWhere('q.date_schedule >= :date_start') ->andWhere('q.date_schedule <= :date_end') ->setParameter('date_start', $date_start) ->setParameter('date_end', $date_end); } break; case 'hub_view_all': if (isset($datatable['query']['data-rows-search'])) { /* $query->innerJoin('q.cus_vehicle', 'cv') ->innerJoin('q.customer', 'c') ->where('cv.plate_number like :filter') ->orWhere('c.phone_mobile like :filter') ->orWhere('c.first_name like :filter or c.last_name like :filter') ->setParameter('filter', $datatable['query']['data-rows-search'] . '%'); */ $query->where('q.plate_number like :filter') ->orWhere('q.phone_mobile like :filter') ->orWhere('q.first_name like :filter') ->orWhere('q.last_name like :filter') ->setParameter('filter', $datatable['query']['data-rows-search'] . '%'); } if (isset($datatable['query']['hub'])) { $query->innerJoin('q.hub', 'h') ->andWhere('h.id = :hub_id') ->setParameter('hub_id', $datatable['query']['hub']); } else { $query->innerJoin('q.hub', 'h') ->andWhere('h.flag_hub_view = :flag_hub_view') ->setParameter('flag_hub_view', true); } if (isset($datatable['query']['schedule_date'])) { $start = $datatable['query']['schedule_date'][0] . ' ' . '00:00:00'; $end = $datatable['query']['schedule_date'][1] . ' ' . '23:59:00'; $date_start = DateTime::createFromFormat('m/d/Y H:i:s', $start); $date_end = DateTime::createFromFormat('m/d/Y H:i:s', $end); $query->andWhere('q.date_schedule >= :date_start') ->andWhere('q.date_schedule <= :date_end') ->setParameter('date_start', $date_start) ->setParameter('date_end', $date_end); } else { $c_date = new DateTime(); $start_curr_date = $c_date->format('Y-m-d') . ' ' . '00:00:00'; $end_curr_date = $c_date->format('Y-m-d') . ' ' . '23:59:00'; $start_current_date = DateTime::createFromFormat('Y-m-d H:i:s', $start_curr_date); $end_current_date = DateTime::createFromFormat('Y-m-d H:i:s', $end_curr_date); $query->andWhere('q.date_schedule >= :start_current_date') ->andWhere('q.date_schedule <= :end_current_date') ->andWhere('q.status IN (:statuses)') ->setParameter('start_current_date', $start_current_date) ->setParameter('end_current_date', $end_current_date) ->setParameter('statuses', $status, Connection::PARAM_STR_ARRAY); } break; default: $query->where('q.status = :status') ->setParameter('status', $status); } } public function getEditRoute($jo_id, $tier) { if (empty($tier)) return 'jo_open_edit_form'; return $tier; } public function getHubViewRows(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->security->getUser(); if ($user == null) throw new AccessDeniedHttpException('No access.'); $hubs = $user->getHubs(); // get query builder $qb = $this->em->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 $qb = $this->em->getRepository(JobOrder::class) ->createQueryBuilder('q'); $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 $query_obj = $query->setFirstResult($offset) ->setMaxResults($perpage) ->getQuery(); // error_log($query_obj->getSQL()); $obj_rows = $query_obj->getResult(); $statuses = JOStatus::getCollection(); $service_types = ServiceType::getCollection(); // process rows $rows = []; foreach ($obj_rows as $orow) { // add row data $row['id'] = $orow->getID(); $row['customer_name'] = $orow->getCustomer()->getFirstName() . ' ' . $orow->getCustomer()->getLastName(); $row['delivery_address'] = $orow->getDeliveryAddress(); $row['date_schedule'] = $orow->getDateSchedule()->format("d M Y g:i A"); $row['type'] = $orow->isAdvanceOrder() ? 'Advanced Order' : 'Immediate'; $row['service_type'] = $service_types[$orow->getServiceType()]; $row['status'] = $statuses[$orow->getStatus()]; $row['flag_advance'] = $orow->isAdvanceOrder(); $row['plate_number'] = $orow->getCustomerVehicle()->getPlateNumber(); $row['is_mobile'] = $orow->getSource() == TransactionOrigin::MOBILE_APP; $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(); $rows[] = $row; } $params['meta'] = $meta; $params['rows'] = $rows; $params['tier_params'] = $tier_params; return $params; } public function initializeHubViewForm($id) { $em = $this->em; $params['mode'] = 'update-all'; // get row data $obj = $em->getRepository(JobOrder::class)->find($id); // make sure this row exists if (empty($obj)) throw new NotFoundHttpException('The job order does not exist'); $this->fillDropdownParameters($params); $this->fillFormTags($params); // get template to display $params['template'] = $this->getTwigTemplate('jo_hub_view_form'); $params['obj'] = $obj; $params['status_cancelled'] = JOStatus::CANCELLED; // 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" ], ]; return $params; } public function fulfillCancelledJobOrder(Request $req, $id) { // initialize error list $error_array = []; // get object data $em = $this->em; $obj = $em->getRepository(JobOrder::class)->find($id); // make sure this object exists if (empty($obj)) throw new NotFoundHttpException('The item does not exist'); $obj->fulfill(); // the event $event = new JOEvent(); $event->setDateHappen(new DateTime()) ->setTypeID(JOEventType::FULFILL) ->setJobOrder($obj); // get current user $user = $this->security->getUser(); if ($user != null) { $event->setUser($user); } $event->setUser($user); $em->persist($event); $em->flush(); } public function sendSMSToCustomer($phone_number) { // TODO: put this in config file or somewhere $message = $this->translator->trans('message.joborder_completed'); $this->rt->sendSMS($phone_number, $this->translator->trans('message.battery_brand_allcaps'), $message); } }