getVATExclusivePrice($price); return $price - $vat_ex_price; // return round($vat_ex_price * self::VAT_RATE, 2); } public function getVATExclusivePrice($price) { return round($price / (1 + self::VAT_RATE), 2); } public function getTradeInRate($ti) { $size = $ti['size']; $trade_in = $ti['trade_in']; if ($trade_in == null) return 0; switch ($trade_in) { case TradeInType::MOTOLITE: return $size->getTIPriceMotolite(); case TradeInType::PREMIUM: return $size->getTIPricePremium(); case TradeInType::OTHER: return $size->getTIPriceOther(); } return 0; } protected function processEntries(&$total, InvoiceCriteria $criteria, Invoice $invoice) { // error_log('processing entries...'); $entries = $criteria->getEntries(); $con_batts = []; $con_tis = []; foreach ($entries as $entry) { $batt = $entry['battery']; $qty = $entry['qty']; $trade_in = $entry['trade_in']; $size = $batt->getSize(); // consolidate batteries $batt_id = $batt->getID(); if (!isset($con_batts[$batt_id])) $con_batts[$batt->getID()] = [ 'batt' => $batt, 'qty' => 0 ]; $con_batts[$batt_id]['qty']++; // no trade-in if ($trade_in == null) continue; // consolidate trade-ins $ti_key = $size->getID() . '|' . $trade_in; if (!isset($con_tis[$ti_key])) $con_tis[$ti_key] = [ 'size' => $size, 'trade_in' => $trade_in, 'qty' => 0 ]; $con_tis[$ti_key]['qty']++; } $this->processBatteries($total, $con_batts, $invoice); $this->processTradeIns($total, $con_tis, $invoice); } protected function processBatteries(&$total, $con_batts, Invoice $invoice) { // process batteries foreach ($con_batts as $con_data) { $batt = $con_data['batt']; $qty = $con_data['qty']; $sell_price = $batt->getSellingPrice(); $vat = $this->getVATAmount($sell_price); // $vat_ex_price = $this->getVATExclusivePrice($sell_price); $total['sell_price'] += $sell_price * $qty; $total['vat'] += $vat * $qty; $total['vat_ex_price'] += ($sell_price - $vat) * $qty; $total['total_price'] += $sell_price * $qty; // add item $item = new InvoiceItem(); $item->setInvoice($invoice) ->setTitle($batt->getModel()->getName() . ' ' . $batt->getSize()->getName()) ->setQuantity($qty) ->setPrice($sell_price) ->setBattery($batt); $invoice->addItem($item); } } protected function processTradeIns(&$total, $con_tis, Invoice $invoice) { foreach ($con_tis as $ti) { $qty = $ti['qty']; $ti_rate = $this->getTradeInRate($ti); $total['ti_rate'] += $ti_rate * $qty; $total['total_price'] -= $ti_rate * $qty; // add item $item = new InvoiceItem(); $item->setInvoice($invoice) ->setTitle('Trade-in ' . TradeInType::getName($ti['trade_in']) . ' ' . $ti['size']->getName() . ' battery') ->setQuantity($qty) ->setPrice($ti_rate * -1); $invoice->addItem($item); } } protected function processDiscount(&$total, InvoiceCriteria $criteria, Invoice $invoice) { $promos = $criteria->getPromos(); if (count($promos) < 1) return; // NOTE: only get first promo because only one is applicable anyway $promo = $promos[0]; $rate = $promo->getDiscountRate(); $apply_to = $promo->getDiscountApply(); switch ($apply_to) { case DiscountApply::SRP: $discount = round($total['sell_price'] * $rate, 2); break; case DiscountApply::OPL: // $discount = round($total['sell_price'] * 0.6 / 0.7 * $rate, 2); $discount = round($total['sell_price'] * (1 - 1.5 / 0.7 * $rate), 2); break; } // if discount is higher than 0, display in invoice if ($discount > 0) { $item = new InvoiceItem(); $item->setInvoice($invoice) ->setTitle('Promo discount') ->setQuantity(1) ->setPrice(-1 * $discount); $invoice->addItem($item); } $total['discount'] = $discount; $total['total_price'] -= $discount; // process $invoice->setPromo($promo); } public function processJumpstart(&$total, $invoice) { // add troubleshooting fee $item = new InvoiceItem(); $item->setInvoice($invoice) ->setTitle('Troubleshooting fee') ->setQuantity(1) ->setPrice(150.00); $invoice->addItem($item); $total['sell_price'] = 150.00; $total['vat_ex_price'] = 150.00; $total['total_price'] = 150.00; } public function processJumpstartWarranty(&$total, $invoice) { $item = new InvoiceItem(); $item->setInvoice($invoice) ->setTitle('Troubleshooting fee') ->setQuantity(1) ->setPrice(0.00); $invoice->addItem($item); } public function processRecharge(&$total, $invoice) { // add recharge fee $item = new InvoiceItem(); $item->setInvoice($invoice) ->setTitle('Recharge fee') ->setQuantity(1) ->setPrice(300.00); $invoice->addItem($item); $total['sell_price'] = 300.00; $total['vat_ex_price'] = 300.00; $total['total_price'] = 300.00; } public function processReplacement(&$total, $invoice) { // add recharge fee $item = new InvoiceItem(); $item->setInvoice($invoice) ->setTitle('Battery replacement') ->setQuantity(1) ->setPrice(0.00); $invoice->addItem($item); } public function processWarranty(&$total, InvoiceCriteria $criteria, $invoice) { // error_log('processing warranty'); $entries = $criteria->getEntries(); foreach ($entries as $entry) { $batt = $entry['battery']; $item = new InvoiceItem(); $item->setInvoice($invoice) ->setTitle($batt->getModel()->getName() . ' ' . $batt->getSize()->getName() . ' - Service Unit') ->setQuantity(1) ->setPrice(0.00) ->setBattery($batt); $invoice->addItem($item); } } public function processOtherServices(&$total, $invoice, $stype) { $item = new InvoiceItem(); $item->setInvoice($invoice) ->setTitle('Service - ' . ServiceType::getName($stype)) ->setQuantity(1) ->setPrice(200.00); $invoice->addItem($item); $total['total_price'] = 200.00; } public function processOverheat(&$total, $invoice, $cv, $has_coolant) { // free if they have a motolite battery if ($cv->hasMotoliteBattery()) $fee = 0; else $fee = self::SERVICE_FEE; $item = new InvoiceItem(); $item->setInvoice($invoice) ->setTitle('Service - Overheat Assistance') ->setQuantity(1) ->setPrice($fee); $invoice->addItem($item); $total_price = $fee; if ($has_coolant) { $coolant = new InvoiceItem(); $coolant->setInvoice($invoice) ->setTitle('4L Coolant') ->setQuantity(1) ->setPrice(1600); $invoice->addItem($coolant); $total_price += 1600; } $vat_ex_price = $this->getVATExclusivePrice($total_price); $vat = $total_price - $vat_ex_price; $total['total_price'] = $total_price; $total['vat_ex_price'] = $vat_ex_price; $total['vat'] = $vat; } public function processTireRepair(&$total, $invoice, $cv) { // free if they have a motolite battery if ($cv->hasMotoliteBattery()) $fee = 0; else $fee = self::SERVICE_FEE; $item = new InvoiceItem(); $item->setInvoice($invoice) ->setTitle('Service - Flat Tire') ->setQuantity(1) ->setPrice($fee); $invoice->addItem($item); $total_price = $fee; $vat_ex_price = $this->getVATExclusivePrice($total_price); $vat = $total_price - $vat_ex_price; $total['total_price'] = $total_price; $total['vat_ex_price'] = $vat_ex_price; $total['vat'] = $vat; } public function processRefuel(&$total, $invoice, $cv) { // free if they have a motolite battery if ($cv->hasMotoliteBattery()) $fee = 0; else $fee = self::SERVICE_FEE; $ftype = $cv->getFuelType(); $item = new InvoiceItem(); // service charge $item->setInvoice($invoice) ->setTitle('Service - ' . ServiceType::getName(ServiceType::EMERGENCY_REFUEL)) ->setQuantity(1) ->setPrice($fee); $invoice->addItem($item); $total_price = $fee; // $total['total_price'] = 200.00; $gas_price = 260; $diesel_price = 220; $fuel = new InvoiceItem(); //error_log('fuel type - ' . $ftype); switch ($ftype) { case FuelType::GAS: $fuel->setInvoice($invoice) ->setTitle('4L Fuel - Gas') ->setQuantity(1) ->setPrice($gas_price); $invoice->addItem($fuel); $total_price += $gas_price; break; case FuelType::DIESEL: $fuel->setInvoice($invoice) ->setTitle('4L Fuel - Diesel') ->setQuantity(1) ->setPrice($diesel_price); $total_price += $diesel_price; $invoice->addItem($fuel); break; default: // NOTE: should never get to this point $fuel->setInvoice($invoice) ->setTitle('Fuel - Unknown') ->setQuantity(1) ->setPrice(0); $total_price += 0.00; $invoice->addItem($fuel); break; } $vat_ex_price = $this->getVATExclusivePrice($total_price); $vat = $total_price - $vat_ex_price; $total['total_price'] = $total_price; $total['vat_ex_price'] = $vat_ex_price; $total['vat'] = $vat; } public function processCriteria(InvoiceCriteria $criteria) { // initialize $invoice = new Invoice(); $total = [ 'sell_price' => 0.0, 'vat' => 0.0, 'vat_ex_price' => 0.0, 'ti_rate' => 0.0, 'total_price' => 0.0, 'discount' => 0.0, ]; $stype = $criteria->getServiceType(); $cv = $criteria->getCustomerVehicle(); $has_coolant = $criteria->hasCoolant(); // error_log($stype); switch ($stype) { case ServiceType::JUMPSTART_TROUBLESHOOT: $this->processJumpstart($total, $invoice); break; case ServiceType::JUMPSTART_WARRANTY: $this->processJumpstartWarranty($total, $invoice); case ServiceType::BATTERY_REPLACEMENT_NEW: $this->processEntries($total, $criteria, $invoice); /* $this->processBatteries($total, $criteria, $invoice); $this->processTradeIns($total, $criteria, $invoice); */ $this->processDiscount($total, $criteria, $invoice); break; case ServiceType::BATTERY_REPLACEMENT_WARRANTY: $this->processWarranty($total, $criteria, $invoice); break; case ServiceType::POST_RECHARGED: $this->processRecharge($total, $invoice); break; case ServiceType::POST_REPLACEMENT: $this->processReplacement($total, $invoice); break; case ServiceType::TIRE_REPAIR: $this->processTireRepair($total, $invoice, $cv); // $this->processOtherServices($total, $invoice, $stype); break; case ServiceType::OVERHEAT_ASSISTANCE: $this->processOverheat($total, $invoice, $cv, $has_coolant); break; case ServiceType::EMERGENCY_REFUEL: //error_log('processing refuel'); $ftype = $criteria->getCustomerVehicle()->getFuelType(); $this->processRefuel($total, $invoice, $cv); break; } // TODO: check if any promo is applied // apply discounts $promos = $criteria->getPromos(); $invoice->setTotalPrice($total['total_price']) ->setVATExclusivePrice($total['vat_ex_price']) ->setVAT($total['vat']) ->setDiscount($total['discount']) ->setTradeIn($total['ti_rate']); // dump //Debug::dump($invoice, 1); return $invoice; } }