Merge branch '778-add-in-app-support-for-battery-trade-ins' into '746-resq-2-0-final'

Resolve "Add in-app support for battery trade-ins"

See merge request jankstudio/resq!889
This commit is contained in:
Ramon Gutierrez 2023-11-22 08:50:51 +00:00
commit ebfa3495a7
4 changed files with 153 additions and 30 deletions

View file

@ -267,6 +267,12 @@ apiv2_account_delete_code_validate:
controller: App\Controller\CustomerAppAPI\AccountController::validateDeleteCode
methods: [POST]
# trade-in support
apiv2_cust_vehicle_trade_in_estimate:
path: /apiv2/vehicles/{id}/trade_in_estimate
controller: App\Controller\CustomerAppAPI\VehicleController::getTradeInEstimate
methods: [GET]
# insurance
apiv2_insurance_vehicle_maker_list:
path: /apiv2/insurance/vehicles/makers
@ -296,4 +302,4 @@ apiv2_insurance_vehicle_client_type_list:
apiv2_insurance_application_create:
path: /apiv2/insurance/application
controller: App\Controller\CustomerAppAPI\InsuranceController::createApplication
methods: [POST]
methods: [POST]

View file

@ -24,7 +24,6 @@ class InvoiceController extends ApiController
'service_type',
'cv_id',
// 'batt_id',
'trade_in',
]);
if (!$validity['is_valid']) {
@ -82,22 +81,31 @@ class InvoiceController extends ApiController
// check trade-in
// only allow motolite, other, none
$trade_in = $req->request->get('trade_in');
switch ($trade_in) {
$trade_in_batt = $req->request->get('trade_in_batt');
$trade_in_type = $req->request->get('trade_in_type');
switch ($trade_in_type) {
case TradeInType::MOTOLITE:
case TradeInType::OTHER:
break;
default:
$trade_in = '';
$trade_in_type = '';
break;
}
// right now, the app does not include trade-ins but this might change in the future
if (empty($trade_in))
$icrit->addEntry($batt, null, 1);
else
$icrit->addEntry($batt, $trade_in, 1);
// add the actual battery item first
$icrit->addEntry($batt, null, 1);
// DEBUG
// if we have a trade in, add it as well
if (!empty($trade_in_type) && !empty($trade_in_batt)) {
$ti_batt_obj = $this->em->getRepository(Battery::class)->find($trade_in_batt);
if (!empty($ti_batt_obj)) {
$icrit->addEntry($ti_batt_obj, $trade_in_type, 1);
}
}
// set if taxable
$icrit->setIsTaxable();

View file

@ -490,7 +490,6 @@ class JobOrderController extends ApiController
$validity = $this->validateRequest($req, [
'service_type',
'cv_id',
'trade_in',
'long',
'lat',
'warranty',
@ -502,7 +501,8 @@ class JobOrderController extends ApiController
}
// trade in type
$trade_in = $req->request->get('trade_in');
$trade_in_batt = $req->request->get('trade_in_batt');
$trade_in_type = $req->request->get('trade_in_type', '');
// address
$address = $req->request->get('delivery_address', 'Set by mobile application');
@ -580,7 +580,7 @@ class JobOrderController extends ApiController
->setTier1Notes('')
->setTier2Notes('')
->setDeliveryAddress($address)
->setTradeInType($trade_in)
->setTradeInType($trade_in_type)
->setDeliveryInstructions($instructions)
// TODO: error check for valid mode of payment
->setModeOfPayment($req->request->get('mode_of_payment'))
@ -669,26 +669,28 @@ class JobOrderController extends ApiController
$icrit->addBattery($batt);
*/
// NOTE: trade in is currently not supported. Would it be better
// if we remove trade-in as a required parameter? Or just leave it be
// and simply not process it?
// check trade-in
// only allow motolite, other, none
switch ($trade_in) {
switch ($trade_in_type) {
case TradeInType::MOTOLITE:
case TradeInType::OTHER:
break;
default:
$trade_in = '';
$trade_in_type = '';
break;
}
// right now, the app does not include trade-ins but this might change in the future
if (empty($trade_in))
$icrit->addEntry($batt, null, 1);
else
$icrit->addEntry($batt, $trade_in, 1);
// add the actual battery item first
$icrit->addEntry($batt, null, 1);
// if we have a trade in, add it as well
if (!empty($trade_in_type) && !empty($trade_in_batt)) {
$ti_batt_obj = $this->em->getRepository(Battery::class)->find($trade_in_batt);
if (!empty($ti_batt_obj)) {
$icrit->addEntry($ti_batt_obj, $trade_in_type, 1);
}
}
// set taxable
$icrit->setIsTaxable();
@ -975,7 +977,6 @@ class JobOrderController extends ApiController
'service_type',
'cv_id',
// 'batt_id',
'trade_in',
'long',
'lat',
'warranty',
@ -987,7 +988,8 @@ class JobOrderController extends ApiController
}
// trade in type
$trade_in = $req->request->get('trade_in');
$trade_in_batt = $req->request->get('trade_in_batt');
$trade_in_type = $req->request->get('trade_in_type', '');
// address
$address = $req->request->get('delivery_address', 'Set by mobile application');
@ -1013,7 +1015,7 @@ class JobOrderController extends ApiController
->setTier1Notes('')
->setTier2Notes('')
->setDeliveryAddress($address)
->setTradeInType($trade_in)
->setTradeInType($trade_in_type)
->setDeliveryInstructions($instructions)
// TODO: error check for valid mode of payment
->setModeOfPayment($req->request->get('mode_of_payment'));
@ -1098,24 +1100,33 @@ class JobOrderController extends ApiController
// check trade-in
// only allow motolite, other, none
switch ($trade_in) {
switch ($trade_in_type) {
case TradeInType::MOTOLITE:
case TradeInType::OTHER:
break;
default:
$trade_in = '';
$trade_in_type = '';
break;
}
// add the actual battery item first
$icrit->addEntry($batt, null, 1);
// if we have a trade in, add it as well
if (!empty($trade_in_type) && !empty($trade_in_batt)) {
$ti_batt_obj = $this->em->getRepository(Battery::class)->find($trade_in_batt);
if (!empty($ti_batt_obj)) {
$icrit->addEntry($ti_batt_obj, $trade_in_type, 1);
}
}
// set taxable
$icrit->setIsTaxable();
// set JO source
$icrit->setSource(TransactionOrigin::MOBILE_APP);
$icrit->addEntry($batt, $trade_in, 1);
// send to invoice generator
$invoice = $ic->generateInvoice($icrit);
$jo->setInvoice($invoice);

View file

@ -6,8 +6,12 @@ use Symfony\Component\HttpFoundation\Request;
use Catalyst\ApiBundle\Component\Response as ApiResponse;
use App\Entity\CustomerVehicle;
use App\Entity\JobOrder;
use App\Entity\VehicleManufacturer;
use App\Entity\Vehicle;
use App\Ramcar\JOStatus;
use App\Ramcar\ServiceType;
use App\Ramcar\TradeInType;
use App\Ramcar\InsuranceApplicationStatus;
use App\Service\PayMongoConnector;
use DateTime;
@ -170,6 +174,39 @@ class VehicleController extends ApiController
]);
}
public function getTradeInEstimate(Request $req, $id)
{
// check requirements
$validity = $this->validateRequest($req);
if (!$validity['is_valid']) {
return new ApiResponse(false, $validity['error']);
}
// get customer vehicle
$cv = $this->em->getRepository(CustomerVehicle::class)->find($id);
// check if it exists
if ($cv == null) {
return new ApiResponse(false, 'Vehicle does not exist.');
}
// check if it's owned by customer
if ($cv->getCustomer()->getID() != $this->session->getCustomer()->getID()) {
return new ApiResponse(false, 'Invalid vehicle.');
}
// check trade in value
$result = $this->getTIEstimateByCV($cv);
// response
return new ApiResponse(true, '', [
'trade_in_batt' => $result['trade_in_batt'],
'trade_in_type' => $result['trade_in_type'],
'trade_in_value' => $result['trade_in_value'],
]);
}
public function listVehicles(Request $req, PayMongoConnector $paymongo)
{
// validate params
@ -283,6 +320,67 @@ class VehicleController extends ApiController
// response
return new ApiResponse();
}
protected function getTIEstimateByCV($cv)
{
// compute for trade in value
$trade_in_batt = null;
$trade_in_value = 0;
$trade_in_type = TradeInType::OTHER;
$previous_jo_found = false;
// check for last battery replacement JO
$last_jo = $this->em->getRepository(JobOrder::class)->findOneBy([
'service_type' => [
ServiceType::BATTERY_REPLACEMENT_NEW, ServiceType::BATTERY_REPLACEMENT_WARRANTY
],
'status' => JOStatus::FULFILLED,
'cus_vehicle' => $cv,
], ['date_create' => 'desc']);
if (!empty($last_jo)) {
$items = $last_jo->getInvoice()->getItems();
foreach ($items as $item) {
// find the first battery item and get its trade-in value
$item_battery = $item->getBattery();
if (!empty($item_battery)) {
$trade_in_type = TradeInType::MOTOLITE;
$trade_in_batt = $item_battery->getID();
$previous_jo_found = true;
$size = $item_battery->getSize();
$trade_in_value = $size->getTIPriceMotolite();
break;
}
}
}
// TODO: possibly refactor this bit
// if no valid previous JO is found, base the trade-in value on recommended batteries
if (!$previous_jo_found) {
$comp_batteries = $cv->getVehicle()->getBatteries();
// get the lowest trade-in value from the list of batteries
if (!empty($comp_batteries)) {
foreach ($comp_batteries as $battery) {
$size = $battery->getSize();
$size_ti = $size->getTIPriceOther();
// get the lowest value or set if not set yet
if ($size_ti < $trade_in_value || $trade_in_value == 0) {
$trade_in_value = $size_ti;
$trade_in_batt = $battery->getID();
}
}
}
}
return [
'trade_in_batt' => $trade_in_batt,
'trade_in_type' => $trade_in_type,
'trade_in_value' => $trade_in_value,
];
}
protected function generateVehicleInfo(CustomerVehicle $cv, $include_insurance = false, PayMongoConnector $paymongo)
{