Add route for job order creation using third party API. #686

This commit is contained in:
Korina Cordero 2022-06-20 06:50:06 +00:00
parent c8a8bc53af
commit 08050416bb
4 changed files with 269 additions and 151 deletions

6
config/routes/tapi.yaml Normal file
View file

@ -0,0 +1,6 @@
# third party api
tapi_jo_request:
path: /tapi/job_order
controller: App\Controller\TAPI\JobOrderController::requestJobOrder
methods: [POST]

View file

@ -160,7 +160,8 @@ class APIUserController extends Controller
$meta = ['rider_id' => $rider_id]; $meta = ['rider_id' => $rider_id];
// set api user in rider // set api user in rider
$rider->setAPIUser($obj); if ($rider != null)
$rider->setAPIUser($obj);
// set and save values // set and save values
$obj->setName($req->request->get('name')) $obj->setName($req->request->get('name'))

View file

@ -48,6 +48,7 @@ use App\Entity\JOEvent;
use App\Entity\Customer; use App\Entity\Customer;
use App\Entity\Hub; use App\Entity\Hub;
use App\Entity\Invoice; use App\Entity\Invoice;
use App\Entity\Vehicle;
use DateTime; use DateTime;
use DateInterval; use DateInterval;
@ -70,6 +71,7 @@ class JobOrderController extends APIController
HubSelector $hub_select, HubDistributor $hub_dist, HubFilterLogger $hub_filter_logger, HubSelector $hub_select, HubDistributor $hub_dist, HubFilterLogger $hub_filter_logger,
HubFilteringGeoChecker $hub_geofence, EntityManagerInterface $em) HubFilteringGeoChecker $hub_geofence, EntityManagerInterface $em)
{ {
// TODO: fix all the responses
$this->denyAccessUnlessGranted('tapi_jo.request', null, 'No access.'); $this->denyAccessUnlessGranted('tapi_jo.request', null, 'No access.');
// check required parameters and api key // check required parameters and api key
@ -82,21 +84,19 @@ class JobOrderController extends APIController
'first_name', 'first_name',
'last_name', 'last_name',
'mobile_number', 'mobile_number',
'vehicle_manufacturer', 'vehicle_manufacturer_id',
'vehicle_model', 'vehicle_model_id',
'plate_number' 'plate_number'
]; ];
$res = $this->checkParamsAndKey($req, $em, $required_params); $msg = $this->checkRequiredParameters($req, $required_params);
if ($res->isError()) if ($msg)
return $res->getReturnResponse(); return new APIResponse(false, $msg);
// get data from request // get data from request
$data = []; $status = $this->getJobOrderRequestInfo($req, $data);
$data = $this->getJobOrderRequestInfo($req, $data); if ($status != null)
return new APIResponse(false, $status);
// process customer and vehicle information
$this->processCustomerAndVehicleInformation($data, $em);
$is_covered = false; $is_covered = false;
// geofence // geofence
@ -105,72 +105,43 @@ class JobOrderController extends APIController
if (!$is_covered) if (!$is_covered)
{ {
// TODO: put geofence error message in config file somewhere // TODO: put geofence error message in config file somewhere
$res->setError(true) $msg = 'Oops! Our service is limited to some areas in Metro Manila, Laguna, and Baguio only. We will update you as soon as we are able to cover your area';
->setErrorMessage('Oops! Our service is limited to some areas in Metro Manila, Laguna, and Baguio only. We will update you as soon as we are able to cover your area'); return new APIResponse(false, $msg);
return $res->getReturnResponse();
} }
$jo = new JobOrder(); $jo = new JobOrder();
$jo->setSource(TransactionOrigin::MOBILE_APP) $jo->setSource($data['source'])
->setStatus(JOStatus::PENDING) ->setStatus(JOStatus::PENDING)
->setDeliveryInstructions('') ->setDeliveryInstructions($data['instructions'])
->setTier1Notes('') ->setTier1Notes('')
->setTier2Notes('') ->setTier2Notes('')
->setDeliveryAddress($address) ->setDeliveryAddress($data['address'])
->setTradeInType($trade_in) ->setTradeInType($data['trade_in_type'])
->setDeliveryInstructions($instructions) ->setDeliveryInstructions($data['instructions'])
// TODO: error check for valid mode of payment
->setModeOfPayment($data['payment_mode']) ->setModeOfPayment($data['payment_mode'])
->setAdvanceOrder($data['is_advance_order']) ->setAdvanceOrder($data['is_advance_order'])
->setStatusAutoAssign(AutoAssignStatus::NOT_ASSIGNED) ->setStatusAutoAssign(AutoAssignStatus::NOT_ASSIGNED)
->setLandmark($landmark); ->setLandmark($data['landmark']);
$jo->setCustomer($cust); $jo->setCustomer($data['customer']);
// set coordinates // set coordinates
$point = new Point($long, $lat); $point = new Point($data['long'], $data['lat']);
$jo->setCoordinates($point); $jo->setCoordinates($point);
// make invoice criteria // make invoice criteria
$icrit = new InvoiceCriteria(); $icrit = new InvoiceCriteria();
$icrit->setServiceType($stype); $icrit->setServiceType($data['service_type']);
// TODO add promo to criteria if any // TODO add promo to criteria if any
// check promo // check promo
// put in criteria // put in criteria
$icrit->addPromo($promo); $icrit->addPromo($data['promo']);
// check customer vehicle $icrit->setCustomerVehicle($data['customer_vehicle']);
$cv = $em->getRepository(CustomerVehicle::class)->find($req->request->get('cv_id')); $jo->setCustomerVehicle($data['customer_vehicle']);
if ($cv == null)
{
$res->setError(true)
->setErrorMessage('Invalid customer vehicle id');
return $res->getReturnResponse();
}
$icrit->setCustomerVehicle($cv);
$jo->setCustomerVehicle($cv);
// check if customer owns vehicle $icrit->addEntry($data['batt'], $data['trade_in_type'], 1);
if ($cust->getID() != $cv->getCustomer()->getID())
{
$res->setError(true)
->setErrorMessage('Customer does not own vehicle');
return $res->getReturnResponse();
}
switch ($trade_in)
{
case TradeInType::MOTOLITE:
case TradeInType::OTHER:
break;
default:
$trade_in = '';
break;
}
$icrit->addEntry($batt, $trade_in, 1);
// send to invoice generator // send to invoice generator
$invoice = $ic->generateInvoice($icrit); $invoice = $ic->generateInvoice($icrit);
@ -200,7 +171,7 @@ class JobOrderController extends APIController
{ {
// error_log('hub filter is enabled'); // error_log('hub filter is enabled');
// check if customer location is in hub filter area // check if customer location is in hub filter area
if ($hub_geofence->isCovered($long, $lat)) if ($hub_geofence->isCovered($data['long'], $data['lat']))
{ {
// if true, set other values for HubCriteria // if true, set other values for HubCriteria
// TODO: set this properly, since the other flags // TODO: set this properly, since the other flags
@ -213,6 +184,7 @@ class JobOrderController extends APIController
} }
// check if batt is null // check if batt is null
$batt = $data['batt'];
if ($batt != null) if ($batt != null)
{ {
// add battery to items // add battery to items
@ -222,6 +194,7 @@ class JobOrderController extends APIController
} }
// get customer id. No JO id at this point // get customer id. No JO id at this point
$cust = $data['customer'];
$customer_id = $cust->getID(); $customer_id = $cust->getID();
$hub_criteria->setCustomerId($customer_id); $hub_criteria->setCustomerId($customer_id);
@ -326,7 +299,7 @@ class JobOrderController extends APIController
$jo->setStatusAutoAssign(AutoAssignStatus::HUB_ASSIGNED); $jo->setStatusAutoAssign(AutoAssignStatus::HUB_ASSIGNED);
if ($date_schedule != null) if ($date_schedule != null)
$jo->setDateSchedule($date_schedule); $jo->setDateSchedule($data['date_schedule']);
// update redis hub_jo_count for hub // update redis hub_jo_count for hub
$hub_dist->incrementJoCountForHub($hub); $hub_dist->incrementJoCountForHub($hub);
@ -414,41 +387,10 @@ class JobOrderController extends APIController
'invoice' => $invoice_data 'invoice' => $invoice_data
]; ];
// need to check for customer tag/promo
// check service type
if ($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW)
{
$customer = $cv->getCustomer();
$customer_tags = $customer->getCustomerTagObjects();
if (!empty($customer_tags))
{
foreach ($customer_tags as $customer_tag)
{
if ($customer_tag->getID() == $invoice->getUsedCustomerTagId())
{
// remove associated entity
$customer->removeCustomerTag($customer_tag);
// log the availment of promo from customer
$created_by = $req->query->get('api_key');;
$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();
$promo_logger->logPromoInfo($created_by, $cust_id, $cust_fname, $cust_lname, $jo_id,
$invoice_id, $amount);
}
}
}
}
// set data // set data
$res->setData($data); $message = 'Job order created.';
return $res->getReturnResponse(); return new APIResponse(true, $message, $data);
} }
public function getEstimate(Request $req, InvoiceGeneratorInterface $ic, EntityManagerInterface $em) public function getEstimate(Request $req, InvoiceGeneratorInterface $ic, EntityManagerInterface $em)
@ -1528,14 +1470,27 @@ class JobOrderController extends APIController
protected function getJobOrderRequestInfo(Request $req, EntityManagerInterface $em, &$data) protected function getJobOrderRequestInfo(Request $req, EntityManagerInterface $em, &$data)
{ {
$error = $this->validateRequest($req);
if ($error != null)
{
// there is a validation error
return $error;
}
$r = $req->request; $r = $req->request;
// at this point, the request data has been validated
// trade-in type // trade-in type
$trade_in_type = $this->cleanText($r->get('trade_in_type')); $trade_in_type = $this->cleanText($r->get('trade_in_type'));
if (!TradeInType::validate($trade_in_type)) switch ($trade_in_type)
{ {
$message = 'Invalid trade in type'; case TradeInType::MOTOLITE:
return $message; case TradeInType::OTHER:
break;
default:
$trade_in_type = '';
break;
} }
// address // address
@ -1551,22 +1506,11 @@ class JobOrderController extends APIController
$long = $r->get('longitude'); $long = $r->get('longitude');
$lat = $r->get('latitude'); $lat = $r->get('latitude');
// validate service type // get service type
$stype = $this->cleanText($r->get('service_type')); $stype = $this->cleanText($r->get('service_type'));
if (!ServiceType::validate($stype))
{
$message = 'Invalid service type';
return $message;
}
// get mode of payment // get mode of payment
// TODO: do we need to validate this?
$payment_mode = $this->clean($r->get('mode_of_payment')); $payment_mode = $this->clean($r->get('mode_of_payment'));
if (!ModeOfPayment::validate($payment_mode))
{
$message = 'Invalid mode of payment';
return $message;
}
$advance_order = $r->get('flag_advance_order'); $advance_order = $r->get('flag_advance_order');
// check for 'false' text // check for 'false' text
@ -1596,6 +1540,97 @@ class JobOrderController extends APIController
} }
} }
// get promo
$promo_id = $r->get('promo_id');
$promo = $em->getRepository(Promo::class)->find($promo_id);
// check battery
$batt_id = $req->request->get('batt_id');
$batt = $em->getRepository(Battery::class)->find($batt_id);
// get customer and vehicle info
$fname = trim($r->get('first_name', ''));
$lname = trim($r->get('last_name', ''));
$mobile = $r->get('mobile_number', '');
// validate mobile number
$clean_mobile = $this->cleanPhoneNumber($mobile);
$vmanu_id = $r->get('vehicle_manufacturer');
// find vehicle manufacturer
$vmanu = $em->getRepository(VehicleManufacturer::class)->find($vmanu_id);
$vmodel_id = $r->get('vehicle_model');
// find vehicle
$vehicle = $em->getRepository(Vehicle::class)->find($vmodel_id);
$plate_number = $r->get('plate_number');
// clean plate number
$clean_plate = $this->cleanPlateNumber($plate_number);
$c_data = [
'first_name' => $fname,
'last_name' => $lname,
'mobile' => $clean_mobile,
'vmanu' => $vmanu,
'vehicle' => $vehicle,
'plate_number' => $clean_plate,
];
// process customer and vehicle information
$cust_data = $this->processCustomerAndVehicleInformation($c_data, $em);
$data = [
'trade_in_type' => $trade_in_type,
'service_type' => $stype,
'long' => $long,
'lat' => $lat,
'payment_mode' => $payment_mode,
'address' => $address,
'instructions' => $instructions,
'landmark' => $landmark,
'is_advance_order' => $flag_advance_order,
'hub' => $hub,
'date_schedule' => $date_schedule,
'promo' => $promo,
'batt' => $batt,
'customer' => $cust_data['customer'],
'customer_vehicle' => $cust_data['customer_vehicle'],
'source' => TransactionOrigin::THIRD_PARTY,
];
return null;
}
protected function validateRequest(Request $req, EntityManagerInterface $em)
{
$r = $req->request;
// validate trade-in type
$trade_in_type = $this->cleanText($r->get('trade_in_type'));
if (!TradeInType::validate($trade_in_type))
{
$message = 'Invalid trade in type';
return $message;
}
// validate service type
$stype = $this->cleanText($r->get('service_type'));
if (!ServiceType::validate($stype))
{
$message = 'Invalid service type';
return $message;
}
// validate mode of payment
$payment_mode = $this->clean($r->get('mode_of_payment'));
if (!ModeOfPayment::validate($payment_mode))
{
$message = 'Invalid mode of payment';
return $message;
}
// check promo // check promo
$promo = null; $promo = null;
$promo_id = $r->get('promo_id'); $promo_id = $r->get('promo_id');
@ -1603,7 +1638,7 @@ class JobOrderController extends APIController
{ {
$promo = $em->getRepository(Promo::class)->find($promo_id); $promo = $em->getRepository(Promo::class)->find($promo_id);
if ($promo == null) if ($promo == null)
{ {
$message = 'Invalid promo id'; $message = 'Invalid promo id';
return $message; return $message;
} }
@ -1612,7 +1647,7 @@ class JobOrderController extends APIController
// check battery // check battery
$batt = null; $batt = null;
$batt_id = $req->request->get('batt_id'); $batt_id = $req->request->get('batt_id');
if ($batt_id != null) if ($empty($batt_id))
{ {
$batt = $em->getRepository(Battery::class)->find($batt_id); $batt = $em->getRepository(Battery::class)->find($batt_id);
if ($batt == null) if ($batt == null)
@ -1622,12 +1657,8 @@ class JobOrderController extends APIController
} }
} }
// get customer and vehicle info
$fname = $r->get('first_name', '');
$lname = $r->get('last_name', '');
$mobile = $r->get('mobile_number', '');
// validate mobile number // validate mobile number
$mobile = $r->get('mobile_number', '');
$clean_mobile = $this->cleanPhoneNumber($mobile); $clean_mobile = $this->cleanPhoneNumber($mobile);
if ($clean_mobile == false) if ($clean_mobile == false)
{ {
@ -1635,66 +1666,144 @@ class JobOrderController extends APIController
return $message; return $message;
} }
$vmanu = $r->get('vehicle_manufacturer', ''); $vmanu = null;
$vmodel = $r->get('vehicle_model', ''); $vmanu_id = $r->get('vehicle_manufacturer');
$plate_number = $r->get('plate_number'); // validate the vehicle manufacturer id
// find vehicle manufacturer
$vmanu = $em->getRepository(VehicleManufacturer::class)->find($vmanu_id);
if ($vmanu == null)
{
$message = 'Invalid vehicle manufacturer id.';
return $message;
}
// clean plate number $vmodel = null;
$clean_plate = $this->cleanPlateNumber($plate_number); $vmodel_id = $r->get('vehicle_model');
// validate the vehicle model id
// find vehicle
$vmodel = $em->getRepository(Vehicle::class)->find($vmodel_id);
if ($vmodel = null)
{
$message = 'Invalid vehicle model id.';
return $message;
}
$data = [ // confirm that vehicle model's manufacturer is the same as the one in vehicle
'trade_in_type' => $trade_in_type, if ($vmodel->getManufacturer()->getID != $vmanu_id)
'service_type' => $stype, {
'long' => $long, $message = 'Invalid vehicle manufacturer id for vehicle model.';
'lat' => $lat, return $message;
'payment_mode' => $payment_mode, }
'first_name' => $fname,
'last_name' => $lname,
'mobile' => $clean_mobile,
'vmanu' => $vmanu,
'vmodel' => $model,
'plate_number' => $clean_plate,
'address' => $address,
'instructions' => $instructions,
'landmark' => $landmark,
'is_advance_order' => $flag_advance_order,
'hub' => $hub,
'date_schedule' => $date_schedule,
'promo' => $promo,
'batt' => $batt,
];
return null; return null;
} }
protected function processCustomerAndVehicleInformation($data, EntityManagerInterface $em) protected function processCustomerAndVehicleInformation($data, EntityManagerInterface $em)
{ {
$c_data = [];
// retrieve customer info // retrieve customer info
$fname = $data['first_name']; $fname = $data['first_name'];
$lname = $data['last_name']; $lname = $data['last_name'];
$vmanu = $data['vmanu']; $vmanu = $data['vmanu'];
$vmodel = $data['vmodel']; $vehicle = $data['vehicle'];
$plate_number = $data['plate_number']; $plate_number = $data['plate_number'];
$mobile = $data['mobile']; $mobile = $data['mobile'];
// find customer given phone number $cust = null;
$cust = $em->getRepository(Customer::class)->findOneBy(['phone_mobile' => $mobile]); $cust_vehicle = null;
if ($cust == null) // find customer + customer vehicle combo
$cv = $this->findCustomerAndCustomerVehicle($data, $em);
if ($cv == null)
{ {
// create new customer and customer vehicle // find customer given phone number
} $cust = $em->getRepository(Customer::class)->findOneBy(['phone_mobile' => $mobile]);
else
{ if ($cust == null)
// find customer vehicle using plate number {
$cv = $em->getRepository(CustomerVehicle::class)->findOneBy(['plate_number' => $plate_number]); // get the api_user that made the call so that it gets added to the source
if ($cv == null) // source becomes TAPI_USER_<insert name of api user here>
$user_id = $_SERVER['HTTP_X_CATA_API_KEY'];
$source = 'TAPI_USER';
$username = '';
if (!empty($user_id))
{
$api_user = $this->getUser();
if ($api_user != null)
{
$username = $api_user->getName();
$source = $source . '_' . $username;
}
}
// create new customer and customer vehicle
$cust = new Customer();
$cust->setFirstName($fname)
->setLastName($lname)
->setPhoneMobile($mobile)
->setCreateSource($source);
$em->persist($cust);
// add customer vehicle
$cust_vehicle = $this->createCustomerVehicle($em, $cust, $vehicle);
}
else
{ {
// create customer vehicle // create customer vehicle
$cust_vehicle = $this->createCustomerVehicle($em, $cust, $vehicle);
} }
$em->flush();
} }
return $cust; $c_data = [
'customer' => $cust,
'customer_vehicle' => $cust_vehicle,
];
return $c_data;
}
protected function createCustomerVehicle(EntityManagerInterface $em, Customer $cust, Vehicle $vehicle)
{
// add customer vehicle
$cust_vehicle = new CustomerVehicle();
$cust_vehicle->setCustomer($cust)
->setPlateNumber($plate_number)
->setVehicle($vehicle);
$em->persist($cust_vehicle);
return $cust_vehicle;
}
protected function findCustomerAndCustomerVehicle($data, EntityManagerInterface $em)
{
$plate_number = $data['plate_number'];
$mobile = $data['mobile'];
$query = $em->createQuery('SELECT cv, c FROM App\Entity\CustomerVehicle cv
JOIN cv.customer c
WHERE cv.plate_number = :plate_number
AND c.phone_mobile = :phone_mobile');
$query->setParameter('plate_number', $plate_number)
->setParameter('phone_mobile', $mobile);
$cust_results = $query->iterate();
$cust_vehicle = null;
foreach ($cust_results as $row)
{
$cust_vehicle = $row[0];
}
return $cust_vehicle;
} }
protected function cleanPhoneNumber($mobile) protected function cleanPhoneNumber($mobile)

View file

@ -11,6 +11,7 @@ class TransactionOrigin extends NameValue
const MOBILE_APP = 'mobile_app'; const MOBILE_APP = 'mobile_app';
const WALK_IN = 'walk_in'; const WALK_IN = 'walk_in';
const LAZADA = 'lazada'; const LAZADA = 'lazada';
const THIRD_PARTY = 'third_party';
// TODO: for now, resq also gets the walk-in option // TODO: for now, resq also gets the walk-in option
const COLLECTION = [ const COLLECTION = [
@ -21,5 +22,6 @@ class TransactionOrigin extends NameValue
'mobile_app' => 'Mobile App', 'mobile_app' => 'Mobile App',
'walk_in' => 'Walk-in', 'walk_in' => 'Walk-in',
'lazada' => 'Lazada', 'lazada' => 'Lazada',
'third_party' => 'Third Party',
]; ];
} }