diff --git a/config/routes/apiv2.yaml b/config/routes/apiv2.yaml index ec999b90..9f183530 100644 --- a/config/routes/apiv2.yaml +++ b/config/routes/apiv2.yaml @@ -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] \ No newline at end of file + methods: [POST] diff --git a/src/Controller/CustomerAppAPI/InvoiceController.php b/src/Controller/CustomerAppAPI/InvoiceController.php index 379ccd32..a5c3a8b8 100644 --- a/src/Controller/CustomerAppAPI/InvoiceController.php +++ b/src/Controller/CustomerAppAPI/InvoiceController.php @@ -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(); diff --git a/src/Controller/CustomerAppAPI/JobOrderController.php b/src/Controller/CustomerAppAPI/JobOrderController.php index bd91e9fb..143f2a2e 100644 --- a/src/Controller/CustomerAppAPI/JobOrderController.php +++ b/src/Controller/CustomerAppAPI/JobOrderController.php @@ -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); diff --git a/src/Controller/CustomerAppAPI/VehicleController.php b/src/Controller/CustomerAppAPI/VehicleController.php index abe65df8..bc1e29c2 100644 --- a/src/Controller/CustomerAppAPI/VehicleController.php +++ b/src/Controller/CustomerAppAPI/VehicleController.php @@ -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) {