From a3d793087d8b30c907560fdd3f890d0e2bc2cde5 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Mon, 5 Feb 2018 01:23:38 +0800 Subject: [PATCH] Fix invoice generation computations --- src/Controller/JobOrderController.php | 83 +++++++++------ src/Ramcar/InvoiceCriteria.php | 20 ++-- src/Service/InvoiceCreator.php | 143 +++++++++++++++++--------- 3 files changed, 159 insertions(+), 87 deletions(-) diff --git a/src/Controller/JobOrderController.php b/src/Controller/JobOrderController.php index 14ff27e8..5da0b9c8 100644 --- a/src/Controller/JobOrderController.php +++ b/src/Controller/JobOrderController.php @@ -632,6 +632,54 @@ class JobOrderController extends BaseController */ } + protected function invoicePromo($em, InvoiceCriteria $criteria, $promo_id) + { + // return error if there's a problem, false otherwise + + if (empty($promo_id)) + return false; + + // check if this is a valid promo + $promo = $em->getRepository(Promo::class)->find($promo_id); + + if (empty($promo)) + return 'Invalid promo specified.'; + + $criteria->addPromo($promo); + return false; + } + + protected function invoiceBatteries($em, InvoiceCriteria $criteria, $items) + { + // return error if there's a problem, false otherwise + + foreach ($items as $item) + { + // check if this is a valid battery + $battery = $em->getRepository(Battery::class)->find($item['battery']); + + if (empty($battery)) + { + $error = 'Invalid battery specified.'; + return $error; + } + + // quantity + $qty = $item['quantity']; + if ($qty < 1) + continue; + + // add to criteria + $criteria->addBattery($battery, $qty); + + // if this is a trade in, add trade in + if (!empty($item['trade_in']) && TradeInType::validate($item['trade_in'])) + $criteria->addTradeIn($item['trade_in'] == 'motolite', $qty); + } + + return null; + } + public function generateInvoice(Request $req, InvoiceCreator $ic) { $error = false; @@ -644,38 +692,11 @@ class JobOrderController extends BaseController // instantiate invoice criteria $criteria = new InvoiceCriteria(); - if (!empty($promo_id)) - { - // check if this is a valid promo - $promo = $em->getRepository(Promo::class)->find($promo_id); - - if (empty($promo)) - $error = 'Invalid promo specified.'; - else - $criteria->addPromo($promo); - } + $error = $this->invoicePromo($em, $criteria, $promo_id); if (!$error) - { - foreach ($items as $item) - { - // check if this is a valid battery - $battery = $em->getRepository(Battery::class)->find($item['battery']); - - if (empty($battery)) - { - $error = 'Invalid battery specified.'; - break; - } - - // add to criteria - $criteria->addBattery($battery); - - // if this is a trade in, add trade in - if (!empty($item['trade_in']) && TradeInType::validate($item['trade_in'])) - $criteria->addTradeIn($item['trade_in'] == 'motolite' ? true : false); - } - } + $error = $this->invoiceBatteries($em, $criteria, $items); + if ($error) { @@ -693,7 +714,7 @@ class JobOrderController extends BaseController $invoice = [ 'discount' => number_format($iobj->getDiscount(), 2), 'trade_in' => number_format($iobj->getTradeIn(), 2), // TODO: computations not done yet for this on invoice creator - 'price' => number_format($iobj->getVATExclusivePrice(), 2), // TODO: computations not done yet for this on invoice creator + 'price' => number_format($iobj->getVATExclusivePrice(), 2), 'vat' => number_format($iobj->getVAT(), 2), 'total_price' => number_format($iobj->getTotalPrice(), 2), 'items' => [] diff --git a/src/Ramcar/InvoiceCriteria.php b/src/Ramcar/InvoiceCriteria.php index 665495fd..777d188b 100644 --- a/src/Ramcar/InvoiceCriteria.php +++ b/src/Ramcar/InvoiceCriteria.php @@ -18,9 +18,10 @@ class InvoiceCriteria $this->trade_ins = []; } - public function addBattery(Battery $battery) + public function addBattery(Battery $battery, $qty = 1) { - $this->batteries[] = $battery; + for ($i = 0; $i < $qty; $i++) + $this->batteries[] = $battery; return $this; } @@ -40,17 +41,20 @@ class InvoiceCriteria return $this->promos; } - public function addTradeIn($is_motolite) + public function addTradeIn($is_motolite, $qty = 1) { // NOTE: this asumes that all the rates for trade-ins are standardized // for motolite and non-motolite trade-ins - if ($is_motolite) - $trade_in = 'motolite'; - else - $trade_in = 'other'; + for ($i = 0; $i < $qty; $i++) + { + if ($is_motolite) + $trade_in = 'motolite'; + else + $trade_in = 'other'; - $this->trade_ins[] = $trade_in; + $this->trade_ins[] = $trade_in; + } return $this; } diff --git a/src/Service/InvoiceCreator.php b/src/Service/InvoiceCreator.php index b54635fd..80ff0414 100644 --- a/src/Service/InvoiceCreator.php +++ b/src/Service/InvoiceCreator.php @@ -3,6 +3,7 @@ namespace App\Service; use App\Ramcar\InvoiceCriteria; +use App\Ramcar\TradeInType; use App\Entity\Invoice; use App\Entity\InvoiceItem; @@ -13,8 +14,8 @@ use Doctrine\Common\Util\Debug; class InvoiceCreator { const VAT_RATE = 0.12; - const TIRATE_MOTOLITE = 300.00; - const TIRATE_OTHER = 150.00; + const TIRATE_MOTOLITE = 200.00; + const TIRATE_OTHER = 100.00; // creates invoice based on the criteria sent public function __construct() @@ -40,6 +41,93 @@ class InvoiceCreator return self::TIRATE_OTHER; } + protected function processBatteries(&$total, InvoiceCriteria $criteria, Invoice $invoice) + { + // get batteries + $batts = $criteria->getBatteries(); + + // consolidate batteries + $con_batts = []; + foreach ($batts as $batt) + { + $batt_id = $batt->getID(); + + // initialize + if (!isset($con_batts[$batt_id])) + $con_batts[$batt->getID()] = [ + 'batt' => $batt, + 'qty' => 0 + ]; + + // increment quantity + $con_batts[$batt_id]['qty']++; + } + + // 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); + + $invoice->addItem($item); + } + } + + protected function processTradeIns(&$total, InvoiceCriteria $criteria, Invoice $invoice) + { + // get trade-ins + $trade_ins = $criteria->getTradeIns(); + + // consolidate + $con_tis = []; + foreach ($trade_ins as $ti) + { + if (!isset($con_tis[$ti])) + $con_tis[$ti] = 0; + + $con_tis[$ti]++; + } + + // process + foreach ($con_tis as $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) . ' battery') + ->setQuantity($qty) + ->setPrice($ti_rate * -1); + + $invoice->addItem($item); + } + } + + protected function processDiscount(&$total, InvoiceCriteria $criteria, Invoice $invoice) + { + } + public function processCriteria(InvoiceCriteria $criteria) { $invoice = new Invoice(); @@ -48,63 +136,22 @@ class InvoiceCreator 'sell_price' => 0.0, 'vat' => 0.0, 'vat_ex_price' => 0.0, - 'ti_rate' => 0.0, - 'total_price' => 0.0, ]; - // get batteries - $batts = $criteria->getBatteries(); - foreach ($batts as $batt) - { - $sell_price = $batt->getSellingPrice(); - $vat = $this->getVATAmount($sell_price); - $vat_ex_price = $this->getVATExclusivePrice($sell_price); - - $total['sell_price'] += $sell_price; - $total['vat'] += $vat; - $total['vat_ex_price'] += $vat_ex_price; - - $total['total_price'] += $sell_price; - - // add item - $item = new InvoiceItem(); - $item->setInvoice($invoice) - ->setTitle($batt->getModel()->getName() . ' ' . $batt->getSize()->getName()) - ->setQuantity(1) - ->setPrice($sell_price); - - $invoice->addItem($item); - } - - // get trade-ins - $trade_ins = $criteria->getTradeIns(); - foreach ($trade_ins as $ti) - { - $ti_rate = $this->getTradeInRate($ti); - - $total['ti_rate'] += $ti_rate; - - $total['total_price'] -= $ti_rate; - - // add item - $item = new InvoiceItem(); - $item->setInvoice($invoice) - ->setTitle('Trade-in battery') - ->setQuantity(1) - ->setPrice($ti_rate); - - $invoice->addItem($item); - } + $this->processBatteries($total, $criteria, $invoice); + $this->processTradeIns($total, $criteria, $invoice); + $this->processDiscount($total, $criteria, $invoice); // 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['ti_rate']); + ->setTradeIn($total['ti_rate']); // dump