Add services for the new invoice generator. #744

This commit is contained in:
Korina Cordero 2023-05-22 06:06:12 -04:00
parent da03f13f75
commit 1c02138f52
5 changed files with 294 additions and 0 deletions

View file

@ -15,6 +15,7 @@ class InvoiceCriteria
protected $flag_coolant; protected $flag_coolant;
protected $discount; protected $discount;
protected $service_charges; protected $service_charges;
protected $flag_taxable;
// entries are battery and trade-in combos // entries are battery and trade-in combos
protected $entries; protected $entries;
@ -28,6 +29,7 @@ class InvoiceCriteria
$this->flag_coolant = false; $this->flag_coolant = false;
$this->discount = 0; $this->discount = 0;
$this->service_charges = []; $this->service_charges = [];
$this->flag_taxable = false;
} }
public function setServiceType($stype) public function setServiceType($stype)
@ -153,4 +155,15 @@ class InvoiceCriteria
return $this->service_charges; return $this->service_charges;
} }
public function setIsTaxable($flag = true)
{
$this->flag_taxable = $flag;
return $this;
}
public function isTaxable()
{
return $this->flag_taxable;
}
} }

View file

@ -0,0 +1,40 @@
<?php
namespace App\Service;
class InvoiceBatteryManager
{
public function processBatteries($con_batts, &$total)
{
// process batteries
$invoice_batteries = [];
foreach ($con_batts as $con_data)
{
// get battery
$battery = $con_data['battery'];
// get the quantity to purchase
$qty = $con_data['qty'];
$sell_price = $batt->getSellingPrice();
$computed_price = bcmul($sell_price, $qty, 2);
$invoice_batteries = [
'title' => $battery->getModel()->getName() . ' ' . $battery->getSize()->getName(),
'battery' => $battery,
'qty' => $qty,
'sell_price' => $computed_price,
'vat' => 0.0,
'vat_ex_price' => 0.0,
];
$total['sell_price'] = bcadd($total['sell_price'], $computed_price, 2);
$total['vat'] += 0.00;
$total['vat_ex_price'] += 0.00;
$total['total_price'] = bcadd($total['total_price'], $computed_price, 2);
}
return $invoice_batteries;
}
}

View file

@ -0,0 +1,159 @@
<?php
namespace App\Service;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Doctrine\ORM\EntityManagerInterface;
use App\Ramcar\InvoiceCriteria;
use App\Ramcar\InvoiceStatus;
use App\Entity\Invoice;
use App\Entity\InvoiceItem;
use App\Entity\User;
use App\Entity\Battery;
class InvoiceManager
{
protected $security;
protected $em;
protected $validator;
protected $inv_batt;
protected $inv_trade;
protected $inv_tax;
public function __construct(Security $service, EntityManagerInterface $em, ValidatorInterface $validator,
InvoiceBatteryManager $inv_batt, InvoiceTradeInManager $inv_trade, InvoiceTaxManager $inv_tax)
{
$this->security = $security;
$this->em = $em;
$this->validator = $validator;
$this->inv_batt = $inv_batt;
$this->inv_trade = $inv_trade;
$this->inv_tax = $inv_tax;
}
public function generateInvoice(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();
switch($stype)
{
case ServiceType::JUMPSTART_TROUBLESHOOT:
$this->processJumpstart($total, $invoice);
break;
case ServiceType::JUMPSTART_WARRANTY:
$this->processJumpstartWarranty($total, $invoice);
break;
case ServiceType::BATTERY_REPLACEMENT_NEW:
$this->processEntries($total, $criteria, $invoice);
$this->processDiscount($total, $criteria, $invoice, $cust_tag_info);
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);
break;
case ServiceType::OVERHEAT_ASSISTANCE:
$this->processOverheat($total, $invoice, $cv, $has_coolant);
break;
case ServiceType::EMERGENCY_REFUEL:
$ftype = $criteria->getCustomerVehicle()->getFuelType();
$this->processRefuel($total, $invoice, $cv);
break;
}
// process promos here?
// get current user
$user = $this->security->getUser();
// check if user is User or APIUser
if ($user instanceof User)
{
$invoice->setCreatedBy($user);
}
$invoice->setTotalPrice($total['total_price'])
->setVATExclusivePrice($total['vat_ex_price'])
->setVAT($total['vat'])
->setDiscount($total['discount'])
->setTradeIn($total['ti_rate'])
->setStatus(InvoiceStatus::DRAFT);
return $invoice;
}
// process battery sales and trade-ins
protected function processEntries(&$total, InvoiceCriteria $criteria, Invoice $invoice)
{
$entries = $criteria->getEntries();
$con_batts = [];
$con_tis = [];
foreach($entries as $entry)
{
// batteries purchased should have trade_in set to null
$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
// need to set battery for trade in so we know what battery is for trade in
// possible that battery purchased is not the same battery for trade in
$ti_key = $size->getID() . '|' . $trade_in;
if (!isset($con_tis[$ti_key]))
$con_tis[$ti_key] = [
'batt' => $batt,
'size' => $size,
'trade_in' => $trade_in,
'qty' => 0
];
$con_tis[$ti_key]['qty']++;
}
$inv_batt_entries = $this->inv_batt->processBatteries($con_batts, $total);
$inv_trade_in_entries = $this->inv_trade->processTradeIns($con_tis, $total);
// check if we need to compute tax
if ($criteria->isTaxable())
{
$this->inv_tax->computeTax($inv_batt_entries, $total);
}
}
}

View file

@ -0,0 +1,29 @@
<?php
namespace App\Service;
class InvoiceTaxManager
{
public function computeTax($inv_batt_entries, &$total)
{
foreach ($inv_batt_entries as $batt_entry)
{
$vat = $this->getTaxAmount($sell_price);
$vat_ex_price = $this->getTaxExclusivePrice($sell_price);
// TODO: add to the total array the computed vat prices
}
}
// TODO: use bc functions for these
protected function getTaxAmount($price)
{
$vat_ex_price = $this->getTaxExclusivePrice($price);
return $price - $vat_ex_price;
}
protected function getTaxExclusivePrice($price)
{
return round($price / (1 + self::TAX_RATE), 2);
}
}

View file

@ -0,0 +1,53 @@
<?php
namespace App\Service;
use App\Ramcar\TradeInType;
class InvoiceTradeInManager
{
public function processTradeIns($con_tis, &$total)
{
$invoice_trade_ins = [];
foreach($con_tis as $ti)
{
$qty = $ti['qty'];
$ti_rate = $this->getTradeInRate($ti);
$ti_price = bcmul($ti_rate, -1, 2);
$invoice_trade_ins = [
'title' => 'Trade-in ' . TradeInType::getName($ti['trade_in']) . ' ' . $ti['size']->getName() . ' battery'),
'qty' => $qty,
'price' => $ti_price,
];
$tti_price = bcmul($ti_rate, $qty, 2);
$total['ti_rate'] = bcadd($total['ti_rate'], $tti_price, 2);
$total['total_price'] = bcsub($total['total_price'], $tti_price, 2);
}
return $invoice_trade_ins;
}
protected 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;
}
}