Merge branch 'master' of gitlab.com:jankstudio/resq
This commit is contained in:
commit
1efd5250e8
5 changed files with 410 additions and 1 deletions
|
|
@ -115,7 +115,7 @@ class Battery
|
|||
*/
|
||||
protected $total_height;
|
||||
|
||||
// selling price
|
||||
// selling price (vat inclusive)
|
||||
/**
|
||||
* @ORM\Column(type="decimal", precision=7, scale=2, nullable=true)
|
||||
* @Assert\NotBlank()
|
||||
|
|
|
|||
|
|
@ -3,8 +3,13 @@
|
|||
namespace App;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="invoice")
|
||||
*/
|
||||
class Invoice
|
||||
{
|
||||
// unique id
|
||||
|
|
@ -40,9 +45,162 @@ class Invoice
|
|||
*/
|
||||
protected $created_by;
|
||||
|
||||
// the job order the invoice was created from
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="JobOrder", inversedBy="invoice")
|
||||
* @ORM\JoinColumn(name="job_order_id", referencedColumnName="id")
|
||||
*/
|
||||
protected $job_order;
|
||||
|
||||
// invoice items
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity="InvoiceItem", mappedBy="invoice")
|
||||
*/
|
||||
protected $invoice_items;
|
||||
|
||||
// total discount (amount, not %)
|
||||
/**
|
||||
* @ORM\Column(type="decimal", precision=9, scale=2)
|
||||
*/
|
||||
protected $discount;
|
||||
|
||||
// total vat (amount, not %)
|
||||
/**
|
||||
* @ORM\Column(type="decimal", precision=9, scale=2)
|
||||
*/
|
||||
protected $vat;
|
||||
|
||||
// total price (amount)
|
||||
/**
|
||||
* @ORM\Column(type="decimal", precision=9, scale=2)
|
||||
*/
|
||||
protected $total_price;
|
||||
|
||||
// status
|
||||
/**
|
||||
* @ORM\Column(type="string", length=40)
|
||||
*/
|
||||
protected $status;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->date_create = new DateTime();
|
||||
$this->invoice_items = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getID()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getDateCreate()
|
||||
{
|
||||
return $this->date_create;
|
||||
}
|
||||
|
||||
public function setDatePaid(DateTime $date)
|
||||
{
|
||||
$this->date_paid = $date;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDatePaid()
|
||||
{
|
||||
return $this->date_paid;
|
||||
}
|
||||
|
||||
public function setDateCancel(DateTime $date)
|
||||
{
|
||||
$this->date_cancel = $date;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDateCancel()
|
||||
{
|
||||
return $this->date_cancel;
|
||||
}
|
||||
|
||||
public function setCreatedBy(User $user)
|
||||
{
|
||||
$this->created_by = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedBy()
|
||||
{
|
||||
return $this->created_by;
|
||||
}
|
||||
|
||||
public function setJobOrder(JobOrder $job_order)
|
||||
{
|
||||
$this->job_order = $job_order;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getJobOrder()
|
||||
{
|
||||
return $this->job_order;
|
||||
}
|
||||
|
||||
public function addItem(InvoiceItem $item)
|
||||
{
|
||||
$this->invoice_items->add($item);
|
||||
$item->setInvoice($this);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function clearItems()
|
||||
{
|
||||
$this->invoice_items->clear();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getItems()
|
||||
{
|
||||
return $this->invoice_items;
|
||||
}
|
||||
|
||||
public function setDiscount($discount)
|
||||
{
|
||||
$this->discount = $discount;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDiscount()
|
||||
{
|
||||
return $this->discount;
|
||||
}
|
||||
|
||||
public function setVAT($vat)
|
||||
{
|
||||
$this->vat = $vat;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getVAT()
|
||||
{
|
||||
return $this->vat;
|
||||
}
|
||||
|
||||
public function setTotalPrice($price)
|
||||
{
|
||||
$this->total_price = $price;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTotalPrice()
|
||||
{
|
||||
return $this->total_price;
|
||||
}
|
||||
|
||||
public function setStatus($status)
|
||||
{
|
||||
$this->status = $status;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStatus()
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
100
src/Entity/InvoiceItem.php
Normal file
100
src/Entity/InvoiceItem.php
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="invoice_item")
|
||||
*/
|
||||
class InvoiceItem
|
||||
{
|
||||
// unique id
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
// invoice the item is linked to
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Invoice", inversedBy="items")
|
||||
* @ORM\JoinColumn(name="invoice_id", referencedColumnName="id")
|
||||
*/
|
||||
protected $invoice;
|
||||
|
||||
// title of item
|
||||
/**
|
||||
* @ORM\Column(type="string", length=80)
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
// quantity
|
||||
/**
|
||||
* @ORM\Column(type="smallint")
|
||||
*/
|
||||
protected $qty;
|
||||
|
||||
// price of item, negative for discounts
|
||||
/**
|
||||
* @ORM\Column(type="decimal", precision=9, scale=2)
|
||||
*/
|
||||
protected $price;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->title = '';
|
||||
$this->price = 0.0;
|
||||
}
|
||||
|
||||
public function getID()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setInvoice(Invoice $invoice)
|
||||
{
|
||||
$this->invoice = $invoice;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getInvoice()
|
||||
{
|
||||
return $this->invoice;
|
||||
}
|
||||
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setQuantity($qty)
|
||||
{
|
||||
$this->qty = $qty;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getQuantity()
|
||||
{
|
||||
return $this->qty;
|
||||
}
|
||||
|
||||
public function setPrice($price)
|
||||
{
|
||||
$this->price = $price;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPrice()
|
||||
{
|
||||
return $this->price;
|
||||
}
|
||||
}
|
||||
60
src/Ramcar/InvoiceCriteria.php
Normal file
60
src/Ramcar/InvoiceCriteria.php
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace App\Ramcar;
|
||||
|
||||
use App\Entity\Battery;
|
||||
|
||||
class InvoiceCriteria
|
||||
{
|
||||
protected $batteries;
|
||||
protected $promos;
|
||||
protected $trade_in;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->batteries = [];
|
||||
$this->promos = [];
|
||||
$this->trade_ins = [];
|
||||
}
|
||||
|
||||
public function addBattery(Battery $battery)
|
||||
{
|
||||
$this->batteries[] = $battery;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBatteries()
|
||||
{
|
||||
return $this->batteries;
|
||||
}
|
||||
|
||||
public function addPromo($promo)
|
||||
{
|
||||
$this->promos[] = $promo;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPromos()
|
||||
{
|
||||
return $this->promos;
|
||||
}
|
||||
|
||||
public function addTradeIn($is_motolite)
|
||||
{
|
||||
// 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';
|
||||
|
||||
$this->trade_ins[] = $trade_in;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTradeIns()
|
||||
{
|
||||
return $this->trade_ins;
|
||||
}
|
||||
}
|
||||
91
src/Service/InvoiceCreator.php
Normal file
91
src/Service/InvoiceCreator.php
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Ramcar\InvoiceCriteria;
|
||||
|
||||
use App\Entity\Invoice;
|
||||
use App\Entity\InvoiceItem;
|
||||
use App\Entity\User;
|
||||
|
||||
class InvoiceCreator
|
||||
{
|
||||
const VAT_RATE = 0.12;
|
||||
const TIRATE_MOTOLITE = 300.00;
|
||||
const TIRATE_OTHER = 150.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)
|
||||
{
|
||||
if ($trade_in == 'motolite')
|
||||
return TIRATE_MOTOLITE;
|
||||
|
||||
return TIRATE_OTHER;
|
||||
}
|
||||
|
||||
public function processCriteria(InvoiceCriteria $criteria)
|
||||
{
|
||||
$invoice = new Invoice();
|
||||
|
||||
$total = [
|
||||
'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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// TODO: check if any promo is applied
|
||||
// apply discounts
|
||||
$promos = $criteria->getPromos();
|
||||
|
||||
$invoice->setTotalPrice($total['total_price'])
|
||||
->setVAT($total['vat'])
|
||||
->setDiscount($total['ti_rate']);
|
||||
|
||||
return $invoice;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue