resq/src/Service/InvoiceCreator.php

249 lines
7 KiB
PHP

<?php
namespace App\Service;
use App\Ramcar\InvoiceCriteria;
use App\Ramcar\TradeInType;
use App\Ramcar\DiscountApply;
use App\Ramcar\ServiceType;
use App\Entity\Invoice;
use App\Entity\InvoiceItem;
use App\Entity\User;
use Doctrine\Common\Util\Debug;
class InvoiceCreator
{
const VAT_RATE = 0.12;
const TIRATE_MOTOLITE = 200.00;
const TIRATE_OTHER = 100.00;
// creates invoice based on the criteria sent
public function __construct()
{
}
public function getVATAmount($price)
{
$vat_ex_price = $this->getVATExclusivePrice($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($trade_in)
{
// TODO: modify this with the prices based on size
if ($trade_in == 'motolite')
return self::TIRATE_MOTOLITE;
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)
->setBattery($batt);
$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)
{
$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);
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 processWarranty(&$total, InvoiceCriteria $criteria, $invoice)
{
error_log('processing warranty');
$batteries = $criteria->getBatteries();
foreach ($batteries as $batt)
{
$item = new InvoiceItem();
$item->setInvoice($invoice)
->setTitle($batt->getModel()->getName() . ' ' . $batt->getSize()->getName() . ' - Service Unit')
->setQuantity(1)
->setPrice(0.00);
$invoice->addItem($item);
}
}
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();
error_log($stype);
switch ($stype)
{
case ServiceType::JUMPSTART_TROUBLESHOOT:
$this->processJumpstart($total, $invoice);
break;
case ServiceType::BATTERY_REPLACEMENT_NEW:
$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;
}
// 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;
}
}