diff --git a/src/Command/TestInvoiceManagerCommand.php b/src/Command/TestInvoiceManagerCommand.php index 7feafcb9..6c971156 100644 --- a/src/Command/TestInvoiceManagerCommand.php +++ b/src/Command/TestInvoiceManagerCommand.php @@ -16,6 +16,7 @@ use App\Ramcar\ServiceType; use App\Entity\Battery; use App\Entity\CustomerVehicle; +use App\Entity\Promo; class TestInvoiceManagerCommand extends Command { @@ -66,7 +67,18 @@ class TestInvoiceManagerCommand extends Command $this->testBatterySalesTradeInQuantityNoDiscountWithoutTax(); // battery sales with discount with tax + $this->testBatterySalesNoTradeInWithDiscountWithTax(); + // battery sales with discount without tax + $this->testBatterySalesNoTradeInWithDiscountWithoutTax(); + + // battery sales with discount and trade in with tax + $this->testBatterySalesTradeInSameBatteryWithDiscountWithTax(); + $this->testBatterySalesTradeInDifferentBatteryWithDiscountWithTax(); + + // battery sales with discount and trade in without tax + $this->testBatterySalesTradeInSameBatteryWithDiscountWithoutTax(); + $this->testBatterySalesTradeInDifferentBatteryWithDiscountWithoutTax(); // battery replacement warranty with tax $this->testBatteryReplacementWarrantyWithTax(); @@ -126,8 +138,6 @@ class TestInvoiceManagerCommand extends Command $this->testTireRepairWithServiceFeeWithoutTax(); $this->testTireRepairWithoutServiceFeeWithoutTax(); - // TEST SCENARIO: new battery with discount - // TEST SCENARIO: new battery with discount and trade-in return 0; } @@ -814,6 +824,278 @@ class TestInvoiceManagerCommand extends Command } } + // battery sales with discount with tax + protected function testBatterySalesNoTradeInWithDiscountWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, no trade-in, with discount, with tax + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + + $battery_id = 1038; + $battery = $this->em->getRepository(Battery::class)->find($battery_id); + + $promo_id = 1; + $promo = $this->em->getRepository(Promo::class)->find($promo_id); + + $criteria->addEntry($battery, null, 1); + + $criteria->addPromo($promo); + + $criteria->setIsTaxable(); + + $rules = $this->inv_manager->check($criteria); + + // error_log(print_r($rules, true)); + + $invoice_data = $this->inv_manager->compute($criteria, $rules); + + // error_log(print_r(json_encode($invoice_data), true)); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + $promo = $data['promo']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' NO TRADE IN WITH DISCOUNT WITH TAX ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + } + + error_log('PROMO ' . $promo->getName()); + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // battery sales with discount without tax + protected function testBatterySalesNoTradeInWithDiscountWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, no trade-in, with discount, without tax + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + + $battery_id = 1038; + $battery = $this->em->getRepository(Battery::class)->find($battery_id); + + $promo_id = 10; + $promo = $this->em->getRepository(Promo::class)->find($promo_id); + + $criteria->addEntry($battery, null, 1); + + $criteria->addPromo($promo); + + $rules = $this->inv_manager->check($criteria); + + // error_log(print_r($rules, true)); + + $invoice_data = $this->inv_manager->compute($criteria, $rules); + + // error_log(print_r(json_encode($invoice_data), true)); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + $promo = $data['promo']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' NO TRADE IN WITH DISCOUNT WITHOUT TAX ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + } + + error_log('PROMO ' . $promo->getName()); + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // battery sales with discount and trade in with tax + protected function testBatterySalesTradeInSameBatteryWithDiscountWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, no trade-in, with discount, with tax + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + + $battery_id = 1038; + $battery = $this->em->getRepository(Battery::class)->find($battery_id); + + $promo_id = 1; + $promo = $this->em->getRepository(Promo::class)->find($promo_id); + + $criteria->addEntry($battery, null, 1); + + // add battery for trade in + $criteria->addEntry($battery, 'premium', 1); + + $criteria->addPromo($promo); + + $criteria->setIsTaxable(); + + $rules = $this->inv_manager->check($criteria); + + // error_log(print_r($rules, true)); + + $invoice_data = $this->inv_manager->compute($criteria, $rules); + + // error_log(print_r(json_encode($invoice_data), true)); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + $promo = $data['promo']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' TRADE IN SAME BATTERY WITH DISCOUNT WITH TAX ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + } + + error_log('PROMO ' . $promo->getName()); + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesTradeInDifferentBatteryWithDiscountWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, trade-in different battery, premium, with discount, with tax + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + + $battery_id = 1038; + $battery = $this->em->getRepository(Battery::class)->find($battery_id); + + $promo_id = 1; + $promo = $this->em->getRepository(Promo::class)->find($promo_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, 'premium', 1); + + $criteria->addPromo($promo); + + $criteria->setIsTaxable(); + + $rules = $this->inv_manager->check($criteria); + + // error_log(print_r($rules, true)); + + $invoice_data = $this->inv_manager->compute($criteria, $rules); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' TRADE IN DIFFERENT BATTERY WITH DISCOUNT WITH TAX ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // battery sales with discount and trade in without tax + protected function testBatterySalesTradeInSameBatteryWithDiscountWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, no trade-in, with discount, with tax + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + + $battery_id = 1038; + $battery = $this->em->getRepository(Battery::class)->find($battery_id); + + $promo_id = 1; + $promo = $this->em->getRepository(Promo::class)->find($promo_id); + + $criteria->addEntry($battery, null, 1); + + // add battery for trade in + $criteria->addEntry($battery, 'premium', 1); + + $criteria->addPromo($promo); + + $rules = $this->inv_manager->check($criteria); + + // error_log(print_r($rules, true)); + + $invoice_data = $this->inv_manager->compute($criteria, $rules); + + // error_log(print_r(json_encode($invoice_data), true)); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + $promo = $data['promo']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' TRADE IN SAME BATTERY WITH DISCOUNT WITHOUT TAX ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + } + + error_log('PROMO ' . $promo->getName()); + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesTradeInDifferentBatteryWithDiscountWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, trade-in different battery, premium, with discount, without tax + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + + $battery_id = 1038; + $battery = $this->em->getRepository(Battery::class)->find($battery_id); + + $promo_id = 1; + $promo = $this->em->getRepository(Promo::class)->find($promo_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, 'premium', 1); + + $criteria->addPromo($promo); + + $rules = $this->inv_manager->check($criteria); + + // error_log(print_r($rules, true)); + + $invoice_data = $this->inv_manager->compute($criteria, $rules); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::BATTERY_REPLACEMENT_NEW) . ' TRADE IN DIFFERENT BATTERY WITH DISCOUNT WITHOUT TAX ' . $invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + // battery replacement warranty with tax protected function testBatteryReplacementWarrantyWithTax() { diff --git a/src/Invoice/DiscountType.php b/src/Invoice/DiscountType.php index a1bea802..091ff9c6 100644 --- a/src/Invoice/DiscountType.php +++ b/src/Invoice/DiscountType.php @@ -42,15 +42,44 @@ class DiscountType implements InvoiceInterface switch ($apply_to) { case DiscountApply::SRP: - $discount = round($total['sell_price'] * $rate, 2); + $discount = bcmul($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); + // $discount = round($total['sell_price'] * (1 - 1.5 / 0.7 * $rate), 2); + $num1 = bcdiv(1.5, 0.7, 9); + $num1_rate = bcmul($num1, $rate, 9); + $multiplier = bcsub(1, $num1_rate, 9); + + $discount = bcmul($total['sell_price'], $multiplier, 2); break; } + // if discount is higher than 0, add to items + if ($discount > 0) + { + $qty = 1; + $price = bcmul(-1, $discount, 2); + + $items[] = [ + 'promo' => $promo, + 'title' => $this->getTitle(), + 'qty' => $qty, + 'price' => $price, + ]; + } + + $total['discount'] = $discount; + $total['total_price'] = bcsub($total['total_price'], $discount, 2); + return $items; } + + protected function getTitle() + { + $title = 'Promo discount'; + + return $title; + } } diff --git a/src/Service/InvoiceManager.php b/src/Service/InvoiceManager.php index b1baf521..8743a099 100644 --- a/src/Service/InvoiceManager.php +++ b/src/Service/InvoiceManager.php @@ -162,10 +162,15 @@ class InvoiceManager { if (isset($active_rules['discount_type'])) { - $discount_items = $active_rules['discount_type']->compute($criteria, $stype_fees); + $discount_items = $active_rules['discount_type']->compute($criteria, $stype_fees, $total); + foreach ($discount_items as $discount_item) + { + $items[] = $discount_item; + } } } + $promo = null; foreach ($items as $item) { $invoice_item = new InvoiceItem(); @@ -177,11 +182,15 @@ class InvoiceManager if (isset($item['battery'])) $invoice_item->setBattery($item['battery']); + if (isset($item['promo'])) + $promo = $item['promo']; + $invoice_items[] = $invoice_item; } - // also need to return the total + // also need to return the total and the promo $data[] = [ + 'promo' => $promo, 'invoice_items' => $invoice_items, 'total' => $total, ];