From f598e4f4261e6bf614339f1289a14979f7f762a8 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 30 May 2023 05:54:16 -0400 Subject: [PATCH] Add tax rule. #744 --- src/Command/TestInvoiceManagerCommand.php | 71 ++++++++++++++------ src/Invoice/BatterySales.php | 1 + src/Invoice/DiscountType.php | 23 ++++++- src/Invoice/Tax.php | 82 +++++++++++++++++++++++ src/Invoice/TradeIn.php | 2 +- src/Service/InvoiceManager.php | 60 ++++++++++++++--- 6 files changed, 204 insertions(+), 35 deletions(-) create mode 100644 src/Invoice/Tax.php diff --git a/src/Command/TestInvoiceManagerCommand.php b/src/Command/TestInvoiceManagerCommand.php index 68051147..485bbacd 100644 --- a/src/Command/TestInvoiceManagerCommand.php +++ b/src/Command/TestInvoiceManagerCommand.php @@ -108,7 +108,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::BATTERY_REPLACEMENT_NEW . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' NO TRADE IN NO DISCOUNT ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -132,7 +132,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::BATTERY_REPLACEMENT_NEW . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' QUANTITY NO TRADE IN NO DISCOUNT ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -154,13 +154,13 @@ class TestInvoiceManagerCommand extends Command $rules = $this->inv_manager->check($criteria); - error_log(print_r($rules, true)); + // error_log(print_r($rules, true)); $invoice_items = $this->inv_manager->compute($criteria, $rules); foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::BATTERY_REPLACEMENT_NEW . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' PREMIUM TRADE IN SAME BATTERY NO DISCOUNT ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -188,7 +188,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::BATTERY_REPLACEMENT_NEW . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' MOTOLITE TRADE IN SAME BATTERY NO DISCOUNT ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -216,7 +216,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::BATTERY_REPLACEMENT_NEW . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' OTHER TRADE IN SAME BATTERY NO DISCOUNT ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -247,7 +247,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::BATTERY_REPLACEMENT_NEW . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' PREMIUM TRADE IN DIFFERENT BATTERY NO DISCOUNT ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -278,7 +278,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::BATTERY_REPLACEMENT_NEW . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' MOTOLITE TRADE IN DIFFERENT BATTERY NO DISCOUNT ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -309,12 +309,39 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::BATTERY_REPLACEMENT_NEW . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' OTHER TRADE IN DIFFERENT BATTERY NO DISCOUNT ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } protected function testBatterySalesTradeInQuantityNoDiscount() { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, trade-in different battery, premium, no discount + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + + $battery_id = 1038; + $battery = $this->em->getRepository(Battery::class)->find($battery_id); + + // add battery + $criteria->addEntry($battery, null, 1); + + $trade_battery_id = 1037; + $trade_battery = $this->em->getRepository(Battery::class)->find($trade_battery_id); + + // add battery for trade in + $criteria->addEntry($trade_battery, 'other', 3); + + $rules = $this->inv_manager->check($criteria); + + // error_log(print_r($rules, true)); + + $invoice_items = $this->inv_manager->compute($criteria, $rules); + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' QUANTITY NO DISCOUNT ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + } } protected function testBatteryReplacementWarranty() @@ -337,7 +364,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::BATTERY_REPLACEMENT_WARRANTY . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_WARRANTY) . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -362,7 +389,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::EMERGENCY_REFUEL . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::EMERGENCY_REFUEL) . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -387,7 +414,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::EMERGENCY_REFUEL . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::EMERGENCY_REFUEL) . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -412,7 +439,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::EMERGENCY_REFUEL . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::EMERGENCY_REFUEL) . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -437,7 +464,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::EMERGENCY_REFUEL . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::EMERGENCY_REFUEL) . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -456,7 +483,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::JUMPSTART_TROUBLESHOOT . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::JUMPSTART_TROUBLESHOOT) . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -475,7 +502,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::JUMPSTART_WARRANTY . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::JUMPSTART_WARRANTY) . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -501,7 +528,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::OVERHEAT_ASSISTANCE . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::OVERHEAT_ASSISTANCE) . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -526,7 +553,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::OVERHEAT_ASSISTANCE . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::OVERHEAT_ASSISTANCE) . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -545,7 +572,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::POST_RECHARGED . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::POST_RECHARGED) . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -564,7 +591,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::POST_REPLACEMENT . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::POST_REPLACEMENT) . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -589,7 +616,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::TIRE_REPAIR . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::TIRE_REPAIR) . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } @@ -614,7 +641,7 @@ class TestInvoiceManagerCommand extends Command foreach ($invoice_items as $invoice_item) { - error_log('TEST: ' . ServiceType::TIRE_REPAIR . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + error_log('TEST: ' . strtoupper(ServiceType::TIRE_REPAIR) . ' ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); } } diff --git a/src/Invoice/BatterySales.php b/src/Invoice/BatterySales.php index d102f950..40d77b9e 100644 --- a/src/Invoice/BatterySales.php +++ b/src/Invoice/BatterySales.php @@ -50,6 +50,7 @@ class BatterySales implements InvoiceInterface $price = $batt->getSellingPrice(); $items[] = [ + 'service_type' => $this->getID(), 'battery' => $batt, 'qty' => $qty, 'title' => $this->getTitle($batt), diff --git a/src/Invoice/DiscountType.php b/src/Invoice/DiscountType.php index 6ce07355..31a6e835 100644 --- a/src/Invoice/DiscountType.php +++ b/src/Invoice/DiscountType.php @@ -27,7 +27,28 @@ class DiscountType implements InvoiceInterface public function compute($criteria, $stype_fees) { - return []; + $items = []; + + $promos = $criteria->getPromos(); + + // 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; + } + + return $items; } } diff --git a/src/Invoice/Tax.php b/src/Invoice/Tax.php new file mode 100644 index 00000000..2044840a --- /dev/null +++ b/src/Invoice/Tax.php @@ -0,0 +1,82 @@ +isTaxable())) + return true; + + return false; + + } + + public function getTemplate() + { + return 'invoice/tax.html.twig'; + } + + public function getID() + { + return 'tax'; + } + + public function compute($items, &$total) + { + foreach ($items as $item) + { + $price = $item['price']; + $qty = $item['qty']; + + if (isset($items['service_type'])) + { + if ($items['service_type'] == 'battery_new') + { + // battery purchase + if (isset($item['battery'])) + { + // battery purchase + $vat = $this->getTaxAmount($price); + + $qty_price = bcmul($price, $qty, 2); + $price_minus_vat = bcsub($price, $vat, 2); + $qty_price_minus_vat = bcmul($price_minus_vat, $qty, 2); + + $total['sell_price'] = bcadd($total['sell_price'], $qty_price, 2); + $total['vat'] = bcadd($total['vat'], $qty_price, 2); + $total['vat_ex_price'] = bcadd($total['vat_ex_price'], $qty_price_minus_vat, 2); + + $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); + } + } + + } + else + { + // everything else + } + } + } + + protected function getTaxAmount($price) + { + $vat_ex_price = $this->getTaxExclusivePrice($price); + $tax_amount = bcsub($price, $vat_ex_price, 2); + + return $tax_amount; + } + + protected function getTaxExclusivePrice($price) + { + $tax_ex_price = bcdiv($price, bcadd(1, self::TAX_RATE, 2), 2); + return $tax_ex_price; + } + +} + diff --git a/src/Invoice/TradeIn.php b/src/Invoice/TradeIn.php index 7e3fd2c1..95d545c8 100644 --- a/src/Invoice/TradeIn.php +++ b/src/Invoice/TradeIn.php @@ -35,7 +35,7 @@ class TradeIn implements InvoiceInterface return 'trade_in'; } - public function compute($criteria) + public function compute($criteria, $stype_fees) { $items = []; diff --git a/src/Service/InvoiceManager.php b/src/Service/InvoiceManager.php index f1db5a73..240e850f 100644 --- a/src/Service/InvoiceManager.php +++ b/src/Service/InvoiceManager.php @@ -44,6 +44,7 @@ class InvoiceManager new Invoice\TireRepair(), new Invoice\DiscountType(), new Invoice\TradeIn(), + new Invoice\Tax, ]; } @@ -80,9 +81,21 @@ class InvoiceManager public function compute($criteria, $active_rules) { + // initialize + $total = [ + 'sell_price' => 0.0, + 'vat' => 0.0, + 'vat_ex_price' => 0.0, + 'ti_rate' => 0.0, + 'total_price' => 0.0, + 'discount' => 0.0, + ]; + // get what is in criteria $stype = $criteria->getServiceType(); $entries = $criteria->getEntries(); + $promos = $criteria->getPromos(); + $is_taxable = $criteria->isTaxable(); // get the service type fees $stype_fees = $this->getServiceTypeFees(); @@ -102,22 +115,36 @@ class InvoiceManager if ($id == $stype) { $items = []; - // process trade-ins by calling the trade-in rule if there are trade-ins - // since it's lumped with only the battery_new service type - if ($flag_trade_in) - { - $tradein_items = $active_rules['trade_in']->compute($criteria); - foreach ($tradein_items as $tradein_item) - { - $items[] = $tradein_item; - } - } $computed_items = $active_rule->compute($criteria, $stype_fees); foreach ($computed_items as $computed_item) { if (!empty($computed_item)) + { $items[] = $computed_item; + } + } + + // check if tax is needed + if ($is_taxable) + { + if (isset($active_rules['tax'])) + { + $active_rule['tax']->compute($items, $total); + } + } + + // process trade-ins by calling the trade-in rule if there are trade-ins among the entries + if ($flag_trade_in) + { + if (isset($active_rules['trade_in'])) + { + $tradein_items = $active_rules['trade_in']->compute($criteria, $stype_fees); + foreach ($tradein_items as $tradein_item) + { + $items[] = $tradein_item; + } + } } foreach ($items as $item) @@ -132,10 +159,21 @@ class InvoiceManager $invoice_item->setBattery($item['battery']); $invoice_items[] = $invoice_item; - } + } + + // process promos, if any + if (count($promos) > 0) + { + if (isset($active_rules['discount_type'])) + { + $discount_items = $active_rules['discount_type']->compute($criteria, $stype_fees); + } + } + } } return $invoice_items; } + }