resq/src/Service/InvoiceCreator.php

382 lines
11 KiB
PHP

<?php
namespace App\Service;
use App\Ramcar\InvoiceCriteria;
use App\Ramcar\TradeInType;
use App\Ramcar\DiscountApply;
use App\Ramcar\ServiceType;
use App\Ramcar\FuelType;
use App\Entity\Invoice;
use App\Entity\InvoiceItem;
use App\Entity\User;
use Doctrine\Common\Util\Debug;
class InvoiceCreator
{
const VAT_RATE = 0.12;
// 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($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);
$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 processRefuel(&$total, $invoice, $ftype)
{
$item = new InvoiceItem();
// service charge
$item->setInvoice($invoice)
->setTitle('Service - ' . ServiceType::getName(ServiceType::EMERGENCY_REFUEL))
->setQuantity(1)
->setPrice(200.00);
$invoice->addItem($item);
$total['total_price'] = 200.00;
$fuel = new InvoiceItem();
switch ($ftype)
{
case FuelType::GAS:
$fuel->setInvoice($invoice)
->setTitle('Fuel - Gas')
->setQuantity(1)
->setPrice(200);
$invoice->addItem($fuel);
$total['total_price'] += 200.00;
break;
case FuelType::DIESEL:
$fuel->setInvoice($invoice)
->setTitle('Fuel - Diesel')
->setQuantity(1)
->setPrice(150);
$total['total_price'] += 150.00;
$invoice->addItem($fuel);
break;
default:
$fuel->setInvoice($invoice)
->setTitle('Fuel - Unknown')
->setQuantity(1)
->setPrice(0);
$total['total_price'] += 0.00;
$invoice->addItem($fuel);
break;
}
}
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::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:
case ServiceType::OVERHEAT_ASSISTANCE:
$this->processOtherServices($total, $invoice, $stype);
break;
case ServiceType::EMERGENCY_REFUEL:
$ftype = $criteria->getCustomerVehicle()->getFuelType();
$this->processRefuel($total, $invoice, $ftype);
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;
}
}