Fix invoice generation computations

This commit is contained in:
Kendrick Chan 2018-02-05 01:23:38 +08:00
parent 141212d4e6
commit a3d793087d
3 changed files with 159 additions and 87 deletions

View file

@ -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' => []

View file

@ -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;
}

View file

@ -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