diff --git a/config/services.yaml b/config/services.yaml index e85c0d86..38d3aa23 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -115,7 +115,10 @@ services: App\Service\InvoiceGenerator\ResqInvoiceGenerator: ~ # invoice generator interface - App\Service\InvoiceGeneratorInterface: "@App\\Service\\InvoiceGenerator\\ResqInvoiceGenerator" + App\Service\InvoiceGeneratorInterface: "@App\\Service\\InvoiceManager" + + # invoice manager + App\Service\InvoiceManager: ~ # job order generator App\Service\JobOrderHandler\ResqJobOrderHandler: diff --git a/src/Command/TestInvoiceManagerCommand.php b/src/Command/TestInvoiceManagerCommand.php new file mode 100644 index 00000000..6f223edb --- /dev/null +++ b/src/Command/TestInvoiceManagerCommand.php @@ -0,0 +1,2106 @@ +setName('test:generateinvoice') + ->setDescription('Test invoice manager service.') + ->setHelp('Test invoice manager service.'); + } + + public function __construct(InvoiceGeneratorInterface $inv_manager, EntityManagerInterface $em) + { + $this->em = $em; + $this->inv_manager = $inv_manager; + + parent::__construct(); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + // battery sales with tax + $this->testBatterySalesNoTradeInNoDiscountWithTax(); + $this->testBatterySalesQuantityNoTradeInNoDiscountWithTax(); + + + // battery sales without tax + $this->testBatterySalesNoTradeInNoDiscountWithoutTax(); + $this->testBatterySalesQuantityNoTradeInNoDiscountWithoutTax(); + + // battery sales with trade in with tax + $this->testBatterySalesTradeInSameBatteryPremiumNoDiscountWithTax(); + + $this->testBatterySalesTradeInSameBatteryMotoliteNoDiscountWithTax(); + $this->testBatterySalesTradeInSameBatteryOtherNoDiscountWithTax(); + $this->testBatterySalesTradeInDifferentBatteryPremiumNoDiscountWithTax(); + $this->testBatterySalesTradeInDifferentBatteryMotoliteNoDiscountWithTax(); + $this->testBatterySalesTradeInDifferentBatteryOtherNoDiscountWithTax(); + $this->testBatterySalesTradeInQuantityNoDiscountWithTax(); + + // battery sales with trade in without tax + $this->testBatterySalesTradeInSameBatteryPremiumNoDiscountWithoutTax(); + $this->testBatterySalesTradeInSameBatteryMotoliteNoDiscountWithoutTax(); + $this->testBatterySalesTradeInSameBatteryOtherNoDiscountWithoutTax(); + $this->testBatterySalesTradeInDifferentBatteryPremiumNoDiscountWithoutTax(); + $this->testBatterySalesTradeInDifferentBatteryMotoliteNoDiscountWithoutTax(); + $this->testBatterySalesTradeInDifferentBatteryOtherNoDiscountWithoutTax(); + $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(); + + // battery replacement warranty without tax + $this->testBatteryReplacementWarrantyWithoutTax(); + + // fuel with tax + $this->testFuelGasWithServiceFeeWithTax(); + $this->testFuelDieselWithServiceFeeWithTax(); + $this->testFuelGasWithNoServiceFeeWithTax(); + $this->testFuelDieselWithNoServiceFeeWithTax(); + + // fuel without tax + $this->testFuelGasWithServiceFeeWithoutTax(); + $this->testFuelDieselWithServiceFeeWithoutTax(); + $this->testFuelGasWithNoServiceFeeWithoutTax(); + $this->testFuelDieselWithNoServiceFeeWithoutTax(); + + // jumpstart with tax + $this->testJumpstartWithTax(); + + // jumpstart without tax + $this->testJumpstartWithoutTax(); + + // jumpstart warranty with tax + $this->testJumpstartWarrantyWithTax(); + + // jumpstart warranty without tax + $this->testJumpstartWarrantyWithoutTax(); + + // overheat with tax + $this->testOverheatAssistanceWithCoolantWithTax(); + $this->testOverheatAssistanceWithoutCoolantWithTax(); + + // overheat without tax + $this->testOverheatAssistanceWithCoolantWithoutTax(); + $this->testOverheatAssistanceWithoutCoolantWithoutTax(); + + // post-recharged with tax + $this->testPostRechargedWithTax(); + + // post-recharged without tax + $this->testPostRechargedWithoutTax(); + + // post replacement with tax + $this->testPostReplacementWithTax(); + + // post replacement without tax + $this->testPostReplacementWithoutTax(); + + // tire repair with tax + $this->testTireRepairWithServiceFeeWithTax(); + $this->testTireRepairWithoutServiceFeeWithTax(); + + // tire repair without tax + $this->testTireRepairWithServiceFeeWithoutTax(); + $this->testTireRepairWithoutServiceFeeWithoutTax(); + + // test creation of invoice criteria when JO is submitted + $this->testGenerateInvoiceCriteria(); + $this->testGenerateInvoiceCriteriaInvalidPromo(); + $this->testGenerateInvoiceCriteriaInvalidBattery(); + + // test generateDraftInvoice call from ajax call + $this->testGenerateDraftInvoiceNoErrorWithTradeIn(); + $this->testGenerateDraftInvoiceNoErrorNoTradeIn(); + $this->testGenerateDraftInvoiceInvalidBattery(); + $this->testGenerateDraftInvoiceInvalidPromo(); + $this->testGenerateDraftInvoiceNonBatterySales(); + $this->testGenerateDraftInvoiceBatterySalesNoPromo(); + + // test generateInvoiceInvoice call from ajax call + $this->testGenerateInvoice(); + + return 0; + } + + // 1battery sales with tax + protected function testBatterySalesNoTradeInNoDiscountWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, no trade-in, no discount, with tax + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + + $battery_id = 1038; + $battery = $this->em->getRepository(Battery::class)->find($battery_id); + + $criteria->addEntry($battery, null, 1); + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + error_log(print_r(json_encode($invoice_data), true)); + + 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) . ' NO TRADE IN NO DISCOUNT WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesQuantityNoTradeInNoDiscountWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, more than 1, no trade-in, no discount, with tax + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + + $battery_id = 1038; + $battery = $this->em->getRepository(Battery::class)->find($battery_id); + + $criteria->addEntry($battery, null, 2); + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + // error_log(print_r(json_encode($invoice_data), true)); + + 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) . ' QUANTITY NO TRADE IN NO DISCOUNT WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // battery sales without tax + protected function testBatterySalesNoTradeInNoDiscountWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, no trade-in, no discount, no tax + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + + $battery_id = 1038; + $battery = $this->em->getRepository(Battery::class)->find($battery_id); + + $criteria->addEntry($battery, null, 1); + + $invoice_data = $this->inv_manager->compute($criteria); + + // error_log(print_r(json_encode($invoice_data), true)); + + 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) . ' NO TRADE IN NO DISCOUNT WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesQuantityNoTradeInNoDiscountWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, more than 1, no trade-in, no discount, without tax + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + + $battery_id = 1038; + $battery = $this->em->getRepository(Battery::class)->find($battery_id); + + $criteria->addEntry($battery, null, 2); + + $invoice_data = $this->inv_manager->compute($criteria); + + // error_log(print_r(json_encode($invoice_data), true)); + + 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) . ' QUANTITY NO TRADE IN NO DISCOUNT WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // battery sales with trade in with tax + protected function testBatterySalesTradeInSameBatteryPremiumNoDiscountWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, trade-in same 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); + + // add battery for trade in + $criteria->addEntry($battery, 'premium', 1); + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + error_log(print_r(json_encode($invoice_data), true)); + + 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) . ' PREMIUM TRADE IN SAME BATTERY NO DISCOUNT WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesTradeInSameBatteryMotoliteNoDiscountWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, trade-in same battery, motolite, 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); + + // add battery for trade in + $criteria->addEntry($battery, 'motolite', 1); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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) . ' MOTOLITE TRADE IN SAME BATTERY NO DISCOUNT WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesTradeInSameBatteryOtherNoDiscountWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, trade-in same battery, other, 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); + + // add battery for trade in + $criteria->addEntry($battery, 'other', 1); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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) . ' OTHER TRADE IN SAME BATTERY NO DISCOUNT WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesTradeInDifferentBatteryPremiumNoDiscountWithTax() + { + $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, 'premium', 1); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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) . ' PREMIUM TRADE IN DIFFERENT BATTERY NO DISCOUNT WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesTradeInDifferentBatteryMotoliteNoDiscountWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, trade-in different battery, motolite, 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, 'motolite', 1); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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) . ' MOTOLITE TRADE IN DIFFERENT BATTERY NO DISCOUNT WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesTradeInDifferentBatteryOtherNoDiscountWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, trade-in different battery, other, 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', 1); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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) . ' OTHER TRADE IN DIFFERENT BATTERY NO DISCOUNT WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesTradeInQuantityNoDiscountWithTax() + { + $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); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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) . ' QUANTITY TRADE IN NO DISCOUNT WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // start: battery sales with trade in without tax + protected function testBatterySalesTradeInSameBatteryPremiumNoDiscountWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, trade-in same 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); + + // add battery for trade in + $criteria->addEntry($battery, 'premium', 1); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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) . ' PREMIUM TRADE IN SAME BATTERY NO DISCOUNT WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesTradeInSameBatteryMotoliteNoDiscountWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, trade-in same battery, motolite, 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); + + // add battery for trade in + $criteria->addEntry($battery, 'motolite', 1); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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) . ' MOTOLITE TRADE IN SAME BATTERY NO DISCOUNT WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesTradeInSameBatteryOtherNoDiscountWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, trade-in same battery, other, 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); + + // add battery for trade in + $criteria->addEntry($battery, 'other', 1); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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) . ' OTHER TRADE IN SAME BATTERY NO DISCOUNT WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesTradeInDifferentBatteryPremiumNoDiscountWithoutTax() + { + $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, 'premium', 1); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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) . ' PREMIUM TRADE IN DIFFERENT BATTERY NO DISCOUNT WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesTradeInDifferentBatteryMotoliteNoDiscountWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, trade-in different battery, motolite, 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, 'motolite', 1); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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) . ' MOTOLITE TRADE IN DIFFERENT BATTERY NO DISCOUNT WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesTradeInDifferentBatteryOtherNoDiscountWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: new battery, trade-in different battery, other, 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', 1); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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) . ' OTHER TRADE IN DIFFERENT BATTERY NO DISCOUNT WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testBatterySalesTradeInQuantityNoDiscountWithoutTax() + { + $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); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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) . ' QUANTITY TRADE IN NO DISCOUNT WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // 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(); + + $invoice_data = $this->inv_manager->compute($criteria); + + // 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['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + if ($promo != null) + 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); + + $invoice_data = $this->inv_manager->compute($criteria); + + // 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['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + if ($promo != null) + 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(); + + $invoice_data = $this->inv_manager->compute($criteria); + + // 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['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + if ($promo != null) + 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(); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + 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); + + $invoice_data = $this->inv_manager->compute($criteria); + + // 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['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + if ($promo != null) + 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); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // battery replacement warranty with tax + protected function testBatteryReplacementWarrantyWithTax() + { + // TEST SCENARIO: battery replacement warranty with tax + $criteria = new InvoiceCriteria(); + + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_WARRANTY); + + $battery_id = 1038; + $battery = $this->em->getRepository(Battery::class)->find($battery_id); + + $criteria->addEntry($battery, null, 1); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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_WARRANTY) . ' WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // battery replacement warranty without tax + protected function testBatteryReplacementWarrantyWithoutTax() + { + // TEST SCENARIO: battery replacement warranty without tax + $criteria = new InvoiceCriteria(); + + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_WARRANTY); + + $battery_id = 1038; + $battery = $this->em->getRepository(Battery::class)->find($battery_id); + + $criteria->addEntry($battery, null, 1); + + $invoice_data = $this->inv_manager->compute($criteria); + + 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_WARRANTY) . ' WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // fuel with tax + protected function testFuelGasWithServiceFeeWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: fuel, gas, service fee, with tax + $criteria->setServiceType(ServiceType::EMERGENCY_REFUEL); + + // set customer vehicle + $cv_id = 1306614; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::EMERGENCY_REFUEL) . ' GAS WITH SERVICE FEE WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testFuelDieselWithServiceFeeWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: fuel, diesel, service fee, with tax + $criteria->setServiceType(ServiceType::EMERGENCY_REFUEL); + + // set customer vehicle + $cv_id = 1306612; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::EMERGENCY_REFUEL) . ' DIESEL WITH SERVICE FEE WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testFuelGasWithNoServiceFeeWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: fuel, gas, no service fee, with tax + $criteria->setServiceType(ServiceType::EMERGENCY_REFUEL); + + // set customer vehicle + $cv_id = 1306604; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::EMERGENCY_REFUEL) . ' GAS WITH NO SERVICE FEE WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testFuelDieselWithNoServiceFeeWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: fuel, diesel, no service fee, with tax + $criteria->setServiceType(ServiceType::EMERGENCY_REFUEL); + + // set customer vehicle + $cv_id = 1306581; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::EMERGENCY_REFUEL) . ' DIESEL WITH NO SERVICE FEE WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // fuel without tax + protected function testFuelGasWithServiceFeeWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: fuel, gas, service fee, without tax + $criteria->setServiceType(ServiceType::EMERGENCY_REFUEL); + + // set customer vehicle + $cv_id = 1306614; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::EMERGENCY_REFUEL) . ' GAS WITH SERVICE FEE WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testFuelDieselWithServiceFeeWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: fuel, diesel, service fee, without tax + $criteria->setServiceType(ServiceType::EMERGENCY_REFUEL); + + // set customer vehicle + $cv_id = 1306612; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::EMERGENCY_REFUEL) . ' DIESEL WITH SERVICE FEE WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testFuelGasWithNoServiceFeeWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: fuel, gas, no service fee, without tax + $criteria->setServiceType(ServiceType::EMERGENCY_REFUEL); + + // set customer vehicle + $cv_id = 1306604; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::EMERGENCY_REFUEL) . ' GAS WITH NO SERVICE FEE WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testFuelDieselWithNoServiceFeeWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: fuel, diesel, no service fee, without tax + $criteria->setServiceType(ServiceType::EMERGENCY_REFUEL); + + // set customer vehicle + $cv_id = 1306581; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::EMERGENCY_REFUEL) . ' DIESEL WITH NO SERVICE FEE WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // jumpstart with tax + protected function testJumpstartWithTax() + { + // TEST SCENARIO: jumpstart with tax + $criteria = new InvoiceCriteria(); + + $criteria->setServiceType(ServiceType::JUMPSTART_TROUBLESHOOT); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::JUMPSTART_TROUBLESHOOT) . ' WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // jumpstart without tax + protected function testJumpstartWithoutTax() + { + // TEST SCENARIO: jumpstart without tax + $criteria = new InvoiceCriteria(); + + $criteria->setServiceType(ServiceType::JUMPSTART_TROUBLESHOOT); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::JUMPSTART_TROUBLESHOOT) . ' WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // jumpstart warranty with tax + protected function testJumpstartWarrantyWithTax() + { + // TEST SCENARIO: jumpstart warranty with tax + $criteria = new InvoiceCriteria(); + + $criteria->setServiceType(ServiceType::JUMPSTART_WARRANTY); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::JUMPSTART_WARRANTY) . ' WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // jumpstart warranty without tax + protected function testJumpstartWarrantyWithoutTax() + { + // TEST SCENARIO: jumpstart warranty without tax + $criteria = new InvoiceCriteria(); + + $criteria->setServiceType(ServiceType::JUMPSTART_WARRANTY); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::JUMPSTART_WARRANTY) . ' WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // overheat assistance with tax + protected function testOverheatAssistanceWithCoolantWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: overheat assistance with coolant with tax + $criteria->setServiceType(ServiceType::OVERHEAT_ASSISTANCE); + + // set customer vehicle + $cv_id = 1306614; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + $criteria->setHasCoolant(); + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::OVERHEAT_ASSISTANCE) . ' WITH COOLANT WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testOverheatAssistanceWithoutCoolantWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: overheat assistance without coolant with tax + $criteria->setServiceType(ServiceType::OVERHEAT_ASSISTANCE); + + // set customer vehicle + $cv_id = 1306614; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::OVERHEAT_ASSISTANCE) . ' WITHOUT COOLANT WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // overheat assistance without tax + protected function testOverheatAssistanceWithCoolantWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: overheat assistance with coolant without tax + $criteria->setServiceType(ServiceType::OVERHEAT_ASSISTANCE); + + // set customer vehicle + $cv_id = 1306614; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + $criteria->setHasCoolant(); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::OVERHEAT_ASSISTANCE) . ' WITH COOLANT WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testOverheatAssistanceWithoutCoolantWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: overheat assistance without coolant without tax + $criteria->setServiceType(ServiceType::OVERHEAT_ASSISTANCE); + + // set customer vehicle + $cv_id = 1306614; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::OVERHEAT_ASSISTANCE) . ' WITHOUT COOLANT WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // post recharged with tax + protected function testPostRechargedWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: post recharged with tax + $criteria->setServiceType(ServiceType::POST_RECHARGED); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::POST_RECHARGED) . ' WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // post recharged without tax + protected function testPostRechargedWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: post recharged with tax + $criteria->setServiceType(ServiceType::POST_RECHARGED); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::POST_RECHARGED) . ' WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // post replacement with tax + protected function testPostReplacementWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: post replacement with tax + $criteria->setServiceType(ServiceType::POST_REPLACEMENT); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::POST_REPLACEMENT) . ' WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // post replacement without tax + protected function testPostReplacementWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: post replacement without tax + $criteria->setServiceType(ServiceType::POST_REPLACEMENT); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::POST_REPLACEMENT) . ' WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // tire repair with tax + protected function testTireRepairWithServiceFeeWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: tire repair with service fee with tax + $criteria->setServiceType(ServiceType::TIRE_REPAIR); + + // set customer vehicle + $cv_id = 1306612; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::TIRE_REPAIR) . ' WITH SERVICE FEE WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testTireRepairWithoutServiceFeeWithTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: tire repair no service fee with tax + $criteria->setServiceType(ServiceType::TIRE_REPAIR); + + // set customer vehicle + $cv_id = 1306604; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + + $criteria->setIsTaxable(); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::TIRE_REPAIR) . ' WITHOUT SERVICE FEE WITH TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // tire repair without tax + protected function testTireRepairWithServiceFeeWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: tire repair with service fee without tax + $criteria->setServiceType(ServiceType::TIRE_REPAIR); + + // set customer vehicle + $cv_id = 1306612; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::TIRE_REPAIR) . ' WITH SERVICE FEE WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + protected function testTireRepairWithoutServiceFeeWithoutTax() + { + $criteria = new InvoiceCriteria(); + + // TEST SCENARIO: tire repair no service fee without tax + $criteria->setServiceType(ServiceType::TIRE_REPAIR); + + // set customer vehicle + $cv_id = 1306604; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $criteria->setCustomerVehicle($cv); + + $invoice_data = $this->inv_manager->compute($criteria); + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + foreach ($invoice_items as $invoice_item) + { + error_log('TEST: ' . strtoupper(ServiceType::TIRE_REPAIR) . ' WITHOUT SERVICE FEE WITHOUT TAX ' . $invoice_item['title'] . ' ' . $invoice_item['quantity'] . ' ' . $invoice_item['price']); + } + + error_log('TOTAL ' . print_r(json_encode($total), true)); + } + } + + // test creation of invoice criteria when JO is submitted + protected function testGenerateInvoiceCriteria() + { + // create JO, set service type and customer vehicle + $jo = new JobOrder(); + + $jo->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + + // set customer vehicle + $cv_id = 1306604; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $jo->setCustomerVehicle($cv); + + // create error_array + $error_array = []; + + // create array of invoice items + $invoice_items = [[ + 'battery' => 1038, + 'quantity' => 1, + 'trade_in' => '', + ], [ + 'battery' => 1038, + 'quantity' => 1, + 'trade_in' => 'premium' + ]]; + + // error_log(print_r(json_encode($invoice_items), true)); + // promo id + $promo_id = 10; + + $this->inv_manager->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $error_array); + + if (!empty($error_array)) + { + error_log('TEST GENERATE INVOICE CRITERIA: Errors found when generating invoice ' . print_r(json_encode($error_array), true)); + } + } + + protected function testGenerateInvoiceCriteriaInvalidPromo() + { + // create JO, set service type and customer vehicle + $jo = new JobOrder(); + + $jo->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + + // set customer vehicle + $cv_id = 1306604; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $jo->setCustomerVehicle($cv); + + // create error_array + $error_array = []; + + // create array of invoice items + $invoice_items = [[ + 'battery' => 1038, + 'quantity' => 1, + 'trade_in' => '', + ], [ + 'battery' => 1038, + 'quantity' => 1, + 'trade_in' => 'premium' + ]]; + + // error_log(print_r(json_encode($invoice_items), true)); + // promo id + $promo_id = 99; + + $this->inv_manager->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $error_array); + + if (!empty($error_array)) + { + error_log('TEST GENERATE INVOICE CRITERIA INVALID PROMO: Errors found when generating invoice ' . print_r(json_encode($error_array), true)); + } + } + + protected function testGenerateInvoiceCriteriaInvalidBattery() + { + // create JO, set service type and customer vehicle + $jo = new JobOrder(); + + $jo->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + + // set customer vehicle + $cv_id = 1306604; + $cv = $this->em->getRepository(CustomerVehicle::class)->find($cv_id); + + $jo->setCustomerVehicle($cv); + + // create error_array + $error_array = []; + + // create array of invoice items + $invoice_items = [[ + 'battery' => 1, + 'quantity' => 1, + 'trade_in' => '', + ], [ + 'battery' => 1038, + 'quantity' => 1, + 'trade_in' => 'premium' + ]]; + + // error_log(print_r(json_encode($invoice_items), true)); + // promo id + $promo_id = 1; + + $this->inv_manager->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $error_array); + + if (!empty($error_array)) + { + error_log('TEST GENERATE INVOICE CRITERIA INVALID BATTERY: Errors found when generating invoice ' . print_r(json_encode($error_array), true)); + } + } + + // test generateDraftInvoice call from ajax call + protected function testGenerateDraftInvoiceNoErrorWithTradeIn() + { + $criteria = new InvoiceCriteria(); + + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + $criteria->setIsTaxable(); + + $promo_id = 1; + $service_charges = []; + + // create array of invoice items + $items = [[ + 'battery' => 1038, + 'quantity' => 1, + 'trade_in' => '', + ], [ + 'battery' => 1038, + 'quantity' => 1, + 'trade_in' => 'premium' + ]]; + + $error = $this->inv_manager->generateDraftInvoice($criteria, $promo_id, $service_charges, $items); + + if ($error) + error_log('TEST GENERATE DRAFT INVOICE NO ERROR WITH TRADE IN: Errors found when generating draft invoice ' . print_r($error, true)); + else + error_log('TEST GENERATE DRAFT INVOICE NO ERROR WITH TRADE IN: No errors here'); + } + + protected function testGenerateDraftInvoiceNoErrorNoTradeIn() + { + $criteria = new InvoiceCriteria(); + + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + $criteria->setIsTaxable(); + + $promo_id = 1; + $service_charges = []; + + // create array of invoice items + $items = [[ + 'battery' => 1038, + 'quantity' => 1, + 'trade_in' => '', + ]]; + + $error = $this->inv_manager->generateDraftInvoice($criteria, $promo_id, $service_charges, $items); + + if ($error) + error_log('TEST GENERATE DRAFT INVOICE NO ERROR NO TRADE IN: Errors found when generating draft invoice ' . print_r($error, true)); + else + error_log('TEST GENERATE DRAFT INVOICE NO ERROR NO TRADE IN: No errors here'); + } + + protected function testGenerateDraftInvoiceInvalidBattery() + { + $criteria = new InvoiceCriteria(); + + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + $criteria->setIsTaxable(); + + $promo_id = 1; + $service_charges = []; + + // create array of invoice items + $items = [[ + 'battery' => 1038, + 'quantity' => 1, + 'trade_in' => '', + ], [ + 'battery' => 2, + 'quantity' => 1, + 'trade_in' => 'premium' + ]]; + + $error = $this->inv_manager->generateDraftInvoice($criteria, $promo_id, $service_charges, $items); + + if ($error) + error_log('TEST GENERATE DRAFT INVOICE BATTERY ERROR: Errors found when generating draft invoice: ' . print_r($error, true)); + else + error_log('TEST GENERATE DRAFT INVOICE BATTERY ERROR: No errors here'); + } + + protected function testGenerateDraftInvoiceInvalidPromo() + { + $criteria = new InvoiceCriteria(); + + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + $criteria->setIsTaxable(); + + $promo_id = 99; + $service_charges = []; + + // create array of invoice items + $items = [[ + 'battery' => 1038, + 'quantity' => 1, + 'trade_in' => '', + ]]; + + $error = $this->inv_manager->generateDraftInvoice($criteria, $promo_id, $service_charges, $items); + + if ($error) + error_log('TEST GENERATE DRAFT INVOICE PROMO ERROR: Errors found when generating draft invoice ' . print_r($error, true)); + else + error_log('TEST GENERATE DRAFT INVOICE PROMO ERROR: No errors here'); + } + + protected function testGenerateDraftInvoiceNonBatterySales() + { + $criteria = new InvoiceCriteria(); + + $criteria->setServiceType(ServiceType::JUMPSTART_TROUBLESHOOT); + $criteria->setIsTaxable(); + + $promo_id = 1; + $service_charges = []; + + // create array of invoice items + $items = [[ + 'battery' => 1038, + 'quantity' => 1, + 'trade_in' => '', + ]]; + + $error = $this->inv_manager->generateDraftInvoice($criteria, $promo_id, $service_charges, $items); + + if ($error) + error_log('TEST GENERATE DRAFT NON BATTERY SALES: Errors found when generating draft invoice ' . print_r($error, true)); + else + error_log('TEST GENERATE DRAFT NON BATTERY SALES: No errors here'); + } + + protected function testGenerateDraftInvoiceBatterySalesNoPromo() + { + $criteria = new InvoiceCriteria(); + + $criteria->setServiceType(ServiceType::BATTERY_REPLACEMENT_NEW); + $criteria->setIsTaxable(); + + $promo_id = ''; + $service_charges = []; + + // create array of invoice items + $items = [[ + 'battery' => 1038, + 'quantity' => 1, + 'trade_in' => '', + ]]; + + $error = $this->inv_manager->generateDraftInvoice($criteria, $promo_id, $service_charges, $items); + + if ($error) + error_log('TEST GENERATE DRAFT INVOICE BATTERY SALES NO PROMO: Errors found when generating draft invoice ' . print_r($error, true)); + else + error_log('TEST GENERATE DRAFT INVOICE BATTERY SALES NO PROMO: No errors here'); + } + + + // test generateInvoiceInvoice call from ajax call + protected function testGenerateInvoice() + { + $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(); + + $invoice = $this->inv_manager->generateInvoice($criteria); + + if ($invoice != null) + { + error_log('TEST GENERATEINVOICE:'); + error_log('INVOICE'); + error_log('TOTAL PRICE: ' . $invoice->getTotalPrice()); + error_log('VAT EXCLUSIVE PRICE: ' . $invoice->getVATExclusivePrice()); + error_log('VAT: ' . $invoice->getVAT()); + error_log('DISCOUNT: ' . $invoice->getDiscount()); + error_log('TRADE-IN: ' . $invoice->getTradeIn()); + error_log('STATUS: ' . $invoice->getStatus()); + + $invoice_items = $invoice->getItems(); + + foreach ($invoice_items as $invoice_item) + { + error_log($invoice_item->getTitle() . ' ' . $invoice_item->getQuantity() . ' ' . $invoice_item->getPrice()); + } + } + else + { + error_log('TEST GENERATE INVOICE: Error found. '); + } + } + +} diff --git a/src/Controller/APIController.php b/src/Controller/APIController.php index 05f50243..d7b2a8fd 100644 --- a/src/Controller/APIController.php +++ b/src/Controller/APIController.php @@ -2865,6 +2865,9 @@ class APIController extends Controller implements LoggedController $icrit = new InvoiceCriteria(); $icrit->setServiceType($stype); + // set taxable + $icrit->setIsTaxable(true); + // check promo $promo_id = $req->request->get('promo_id'); if (!empty($promo_id)) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index 7aa5650d..3ac82b9a 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -1201,6 +1201,7 @@ class RiderAppController extends APIController $crit->setServiceType($stype_id); $crit->setCustomerVehicle($cv); $crit->setHasCoolant($jo->hasCoolant()); + $crit->setIsTaxable(); if ($promo != null) $crit->addPromo($promo); diff --git a/src/Controller/CustomerAppAPI/InvoiceController.php b/src/Controller/CustomerAppAPI/InvoiceController.php index 1c8ab6c6..ef0cf6b2 100644 --- a/src/Controller/CustomerAppAPI/InvoiceController.php +++ b/src/Controller/CustomerAppAPI/InvoiceController.php @@ -94,6 +94,9 @@ class InvoiceController extends ApiController $icrit->addEntry($batt, $trade_in, 1); + // set if taxable + $icrit->setIsTaxable(); + // send to invoice generator $invoice = $ic->generateInvoice($icrit); diff --git a/src/Controller/CustomerAppAPI/JobOrderController.php b/src/Controller/CustomerAppAPI/JobOrderController.php index 4ddb40ee..cd548a42 100644 --- a/src/Controller/CustomerAppAPI/JobOrderController.php +++ b/src/Controller/CustomerAppAPI/JobOrderController.php @@ -658,6 +658,9 @@ class JobOrderController extends ApiController $icrit->addBattery($batt); */ + // NOTE: trade in is currently not supported. Would it be better + // if we remove trade-in as a required parameter? Or just leave it be + // and simply not process it? // check trade-in // only allow motolite, other, none switch ($trade_in) { @@ -672,6 +675,9 @@ class JobOrderController extends ApiController $icrit->addEntry($batt, $trade_in, 1); + // set taxable + $icrit->setIsTaxable(); + // send to invoice generator $invoice = $ic->generateInvoice($icrit); $jo->setInvoice($invoice); @@ -1074,6 +1080,9 @@ class JobOrderController extends ApiController break; } + // set taxable + $icrit->setIsTaxable(); + $icrit->addEntry($batt, $trade_in, 1); // send to invoice generator diff --git a/src/Controller/JobOrderController.php b/src/Controller/JobOrderController.php index 990b7553..30bc519c 100644 --- a/src/Controller/JobOrderController.php +++ b/src/Controller/JobOrderController.php @@ -737,7 +737,8 @@ class JobOrderController extends Controller // instantiate invoice criteria $criteria = new InvoiceCriteria(); $criteria->setServiceType($stype) - ->setCustomerVehicle($cv); + ->setCustomerVehicle($cv) + ->setIsTaxable(); /* diff --git a/src/Controller/TAPI/JobOrderController.php b/src/Controller/TAPI/JobOrderController.php index 64436a43..8275cbbd 100644 --- a/src/Controller/TAPI/JobOrderController.php +++ b/src/Controller/TAPI/JobOrderController.php @@ -157,6 +157,9 @@ class JobOrderController extends APIController $icrit->setCustomerVehicle($data['customer_vehicle']); + // set taxable + $icrit->setIsTaxable(); + $icrit->addEntry($data['batt'], $data['trade_in_type'], 1); // send to invoice generator diff --git a/src/InvoiceRule/BatteryReplacementWarranty.php b/src/InvoiceRule/BatteryReplacementWarranty.php new file mode 100644 index 00000000..8fbfe76c --- /dev/null +++ b/src/InvoiceRule/BatteryReplacementWarranty.php @@ -0,0 +1,120 @@ +em = $em; + } + + public function getID() + { + return 'battery_warranty'; + } + + public function compute($criteria, &$total) + { + $stype = $criteria->getServiceType(); + + $items = []; + if ($stype == $this->getID()) + { + // get the entries + $entries = $criteria->getEntries(); + + foreach($entries as $entry) + { + $batt = $entry['battery']; + $qty = 1; + $price = $this->getServiceTypeFee(); + + $items[] = [ + 'service_type' => $this->getID(), + 'battery' => $batt, + 'qty' => $qty, + 'title' => $this->getTitle($batt), + 'price' => $price, + ]; + + $qty_price = bcmul($price, $qty, 2); + $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); + } + } + + return $items; + } + + public function getServiceTypeFee() + { + // TODO: we need to to put this somewhere like in .env + // so that if any chanages are to be made, we just edit the file + // instead of the code + return 0; + } + + public function validatePromo($criteria, $promo_id) + { + return false; + } + + public function validateInvoiceItems($criteria, $invoice_items) + { + // check service type. Only battery sales and battery warranty should have invoice items. Since this is the + // battery replacement warranty rule, we only check for battery replacement warranty. + $stype = $criteria->getServiceType(); + if ($stype != ServiceType::BATTERY_REPLACEMENT_WARRANTY) + return null; + + // return error if there's a problem, false otherwise + if (!empty($invoice_items)) + { + // check if this is a valid battery + foreach ($invoice_items as $item) + { + $battery = $this->em->getRepository(Battery::class)->find($item['battery']); + + if (empty($battery)) + { + $error = 'Invalid battery specified.'; + return $error; + } + + // quantity + $qty = $item['quantity']; + if ($qty < 1) + continue; + + // if this is a trade in, add trade in + if (!empty($item['trade_in']) && TradeInType::validate($item['trade_in'])) + $trade_in = $item['trade_in']; + else + $trade_in = null; + + $criteria->addEntry($battery, $trade_in, $qty); + } + } + + return null; + } + + protected function getTitle($battery) + { + $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName() . ' - Service Unit'; + + return $title; + } +} + diff --git a/src/InvoiceRule/BatterySales.php b/src/InvoiceRule/BatterySales.php new file mode 100644 index 00000000..45b060d1 --- /dev/null +++ b/src/InvoiceRule/BatterySales.php @@ -0,0 +1,123 @@ +em = $em; + } + + public function getID() + { + return 'battery_new'; + } + + public function compute($criteria, &$total) + { + $stype = $criteria->getServiceType(); + + $items = []; + if ($stype == $this->getID()) + { + // get the entries + $entries = $criteria->getEntries(); + foreach($entries as $entry) + { + $batt = $entry['battery']; + $qty = $entry['qty']; + $trade_in = null; + + if (isset($entry['trade_in'])) + $trade_in = $entry['trade_in']; + + $size = $batt->getSize(); + + if ($trade_in == null) + { + // battery purchase + $price = $batt->getSellingPrice(); + + $items[] = [ + 'service_type' => $this->getID(), + 'battery' => $batt, + 'qty' => $qty, + 'title' => $this->getTitle($batt), + 'price' => $price, + ]; + + $qty_price = bcmul($price, $qty, 2); + + $total['sell_price'] = bcadd($total['sell_price'], $qty_price, 2); + $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); + } + } + } + + return $items; + } + + public function validatePromo($criteria, $promo_id) + { + return false; + } + + public function validateInvoiceItems($criteria, $invoice_items) + { + // check service type. Only battery sales and battery warranty should have invoice items. Since this is the battery sales + // rule, we only check for battery sales. + $stype = $criteria->getServiceType(); + if ($stype != ServiceType::BATTERY_REPLACEMENT_NEW) + return null; + + // return error if there's a problem, false otherwise + if (!empty($invoice_items)) + { + // check if this is a valid battery + foreach ($invoice_items as $item) + { + $battery = $this->em->getRepository(Battery::class)->find($item['battery']); + + if (empty($battery)) + { + $error = 'Invalid battery specified.'; + return $error; + } + + // quantity + $qty = $item['quantity']; + if ($qty < 1) + continue; + + // if this is a trade in, add trade in + if (!empty($item['trade_in']) && TradeInType::validate($item['trade_in'])) + $trade_in = $item['trade_in']; + else + $trade_in = null; + + $criteria->addEntry($battery, $trade_in, $qty); + } + } + + return null; + } + + protected function getTitle($battery) + { + $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName(); + + return $title; + } +} diff --git a/src/InvoiceRule/DiscountType.php b/src/InvoiceRule/DiscountType.php new file mode 100644 index 00000000..8c89e9e7 --- /dev/null +++ b/src/InvoiceRule/DiscountType.php @@ -0,0 +1,116 @@ +em = $em; + } + + public function getID() + { + return 'discount'; + } + + public function compute($criteria, &$total) + { + $items = []; + + $promos = $criteria->getPromos(); + + if (empty($promos)) + return $items; + + // 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 = 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); + $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; + } + + public function validatePromo($criteria, $promo_id) + { + // return error if there's a problem, false otherwise + // check service type + $stype = $criteria->getServiceType(); + + // discount/promo only applies for battery sales + if ($stype != ServiceType::BATTERY_REPLACEMENT_NEW) + return null; + + if (empty($promo_id)) + { + return false; + } + + // check if this is a valid promo + $promo = $this->em->getRepository(Promo::class)->find($promo_id); + + if (empty($promo)) + return 'Invalid promo specified.'; + + $criteria->addPromo($promo); + return false; + } + + public function validateInvoiceItems($criteria, $invoice_items) + { + return null; + } + + protected function getTitle() + { + $title = 'Promo discount'; + + return $title; + } +} + diff --git a/src/InvoiceRule/Fuel.php b/src/InvoiceRule/Fuel.php new file mode 100644 index 00000000..53e70af9 --- /dev/null +++ b/src/InvoiceRule/Fuel.php @@ -0,0 +1,133 @@ +getServiceType(); + + $items = []; + + if ($stype == $this->getID()) + { + // check if customer vehicle has a motolite battery + $cv = $criteria->getCustomerVehicle(); + if ($cv->hasMotoliteBattery()) + $fee = 0; + else + $fee = $this->getServiceTypeFee(); + + $ftype = $cv->getFuelType(); + + // add the service fee to items + $qty = 1; + $items[] = [ + 'service_type' => $this->getID(), + 'qty' => $qty, + 'title' => $this->getServiceTitle($ftype), + 'price' => $fee, + ]; + + $qty_fee = bcmul($qty, $fee, 2); + $total_price = $qty_fee; + + switch ($ftype) + { + case FuelType::GAS: + case FuelType::DIESEL: + $qty = 1; + $price = $this->getFuelFee($ftype); + $items[] = [ + 'service_type' => $this->getID(), + 'qty' => $qty, + 'title' => $this->getTitle($ftype), + 'price' => $price, + ]; + + $qty_price = bcmul($price, $qty, 2); + $total_price = bcadd($total_price, $qty_price, 2); + + break; + default: + $qty = 1; + $price = 0; + $items[] = [ + 'service_type' => $this->getID(), + 'qty' => $qty, + 'title' => $this->getTitle('Unknown'), + 'price' => $price, + ]; + + $qty_price = bcmul($price, $qty, 2); + $total_price = bcadd($total_price, $qty_price, 2); + + break; + } + + $total['total_price'] = bcadd($total['total_price'], $total_price, 2); + } + + return $items; + } + + public function getServiceTypeFee() + { + // TODO: we need to to put this somewhere like in .env + // so that if any changes are to be made, we just edit the file + // instead of the code + return 300; + } + + public function getFuelFee($fuel_type) + { + // TODO: we need to to put this somewhere like in .env + // so that if any changes are to be made, we just edit the file + // instead of the code + if ($fuel_type == FuelType::GAS) + { + // gas fuel fee + return 320; + } + else + { + // diesel fuel fee + return 340; + } + } + + public function validatePromo($criteria, $promo_id) + { + return false; + } + + public function validateInvoiceItems($criteria, $invoice_items) + { + return null; + } + + protected function getTitle($fuel_type) + { + $title = '4L - ' . ucfirst($fuel_type); + + return $title; + } + + protected function getServiceTitle($fuel_type) + { + $title = 'Service - ' . ServiceType::getName(ServiceType::EMERGENCY_REFUEL); + + return $title; + } +} diff --git a/src/InvoiceRule/Jumpstart.php b/src/InvoiceRule/Jumpstart.php new file mode 100644 index 00000000..a97ddce7 --- /dev/null +++ b/src/InvoiceRule/Jumpstart.php @@ -0,0 +1,64 @@ +getServiceType(); + + $items = []; + + if ($stype == $this->getID()) + { + $fee = $this->getServiceTypeFee(); + + // add the service fee to items + $qty = 1; + $items[] = [ + 'service_type' => $this->getID(), + 'qty' => $qty, + 'title' => $this->getServiceTitle(), + 'price' => $fee, + ]; + + $qty_price = bcmul($fee, $qty, 2); + $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); + } + + return $items; + } + + public function getServiceTypeFee() + { + // TODO: we need to to put this somewhere like in .env + // so that if any chanages are to be made, we just edit the file + // instead of the code + return 150; + } + + public function validatePromo($criteria, $promo_id) + { + return false; + } + + public function validateInvoiceItems($criteria, $invoice_items) + { + return null; + } + + protected function getServiceTitle() + { + $title = 'Service - Troubleshooting fee'; + + return $title; + } +} diff --git a/src/InvoiceRule/JumpstartWarranty.php b/src/InvoiceRule/JumpstartWarranty.php new file mode 100644 index 00000000..34a331e7 --- /dev/null +++ b/src/InvoiceRule/JumpstartWarranty.php @@ -0,0 +1,64 @@ +getServiceType(); + + $items = []; + + if ($stype == $this->getID()) + { + $fee = $this->getServiceTypeFee(); + + // add the service fee to items + $qty = 1; + $items[] = [ + 'service_type' => $this->getID(), + 'qty' => $qty, + 'title' => $this->getServiceTitle(), + 'price' => $fee, + ]; + + $qty_price = bcmul($fee, $qty, 2); + $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); + } + + return $items; + } + + public function getServiceTypeFee() + { + // TODO: we need to to put this somewhere like in .env + // so that if any chanages are to be made, we just edit the file + // instead of the code + return 0; + } + + public function validatePromo($criteria, $promo_id) + { + return false; + } + + public function validateInvoiceItems($criteria, $invoice_items) + { + return null; + } + + protected function getServiceTitle() + { + $title = 'Service - Troubleshooting fee'; + + return $title; + } +} diff --git a/src/InvoiceRule/Overheat.php b/src/InvoiceRule/Overheat.php new file mode 100644 index 00000000..692e5e85 --- /dev/null +++ b/src/InvoiceRule/Overheat.php @@ -0,0 +1,103 @@ +getServiceType(); + $has_coolant = $criteria->hasCoolant(); + + $items = []; + + if ($stype == $this->getID()) + { + // check if customer vehicle has a motolite battery + $cv = $criteria->getCustomerVehicle(); + if ($cv->hasMotoliteBattery()) + $fee = 0; + else + $fee = $this->getServiceTypeFee(); + + // add the service fee to items + $qty = 1; + $items[] = [ + 'service_type' => $this->getID(), + 'qty' => $qty, + 'title' => $this->getServiceTitle(), + 'price' => $fee, + ]; + + $qty_fee = bcmul($qty, $fee, 2); + $total_price = $qty_fee; + + if ($has_coolant) + { + $coolant_fee = $this->getCoolantFee(); + $items[] = [ + 'service_type' => $this->getID(), + 'qty' => $qty, + 'title' => $this->getServiceCoolantTitle(), + 'price' => $coolant_fee, + ]; + + $qty_price = bcmul($coolant_fee, $qty, 2); + $total_price = bcadd($total_price, $qty_price, 2); + } + + $total['total_price'] = bcadd($total['total_price'], $total_price, 2); + } + + return $items; + } + + public function getServiceTypeFee() + { + // TODO: we need to to put this somewhere like in .env + // so that if any chanages are to be made, we just edit the file + // instead of the code + return 300; + } + + public function getCoolantFee() + { + // TODO: we need to to put this somewhere like in .env + // so that if any chanages are to be made, we just edit the file + // instead of the code + return 1600; + } + + public function validatePromo($criteria, $promo_id) + { + return false; + } + + public function validateInvoiceItems($criteria, $invoice_items) + { + return null; + } + + protected function getServiceTitle() + { + $title = 'Service - ' . ServiceType::getName(ServiceType::OVERHEAT_ASSISTANCE); + + return $title; + } + + protected function getServiceCoolantTitle() + { + $title = '4L Coolant'; + + return $title; + } +} diff --git a/src/InvoiceRule/PostRecharged.php b/src/InvoiceRule/PostRecharged.php new file mode 100644 index 00000000..55549aa7 --- /dev/null +++ b/src/InvoiceRule/PostRecharged.php @@ -0,0 +1,64 @@ +getServiceType(); + + $items = []; + + if ($stype == $this->getID()) + { + $fee = $this->getServiceTypeFee(); + + $qty = 1; + $items[] = [ + 'service_type' => $this->getID(), + 'qty' => $qty, + 'title' => $this->getServiceTitle(), + 'price' => $fee, + ]; + + $qty_price = bcmul($fee, $qty, 2); + $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); + + } + + return $items; + } + + public function getServiceTypeFee() + { + // TODO: we need to to put this somewhere like in .env + // so that if any chanages are to be made, we just edit the file + // instead of the code + return 300; + } + + public function validatePromo($criteria, $promo_id) + { + return false; + } + + public function validateInvoiceItems($criteria, $invoice_items) + { + return null; + } + + protected function getServiceTitle() + { + $title = 'Recharge fee'; + + return $title; + } +} diff --git a/src/InvoiceRule/PostReplacement.php b/src/InvoiceRule/PostReplacement.php new file mode 100644 index 00000000..a64c0fce --- /dev/null +++ b/src/InvoiceRule/PostReplacement.php @@ -0,0 +1,63 @@ +getServiceType(); + + $items = []; + + if ($stype == $this->getID()) + { + $fee = $this->getServiceTypeFee(); + + $qty = 1; + $items[] = [ + 'service_type' => $this->getID(), + 'qty' => $qty, + 'title' => $this->getServiceTitle(), + 'price' => $fee, + ]; + + $qty_price = bcmul($fee, $qty, 2); + $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); + } + + return $items; + } + + public function getServiceTypeFee() + { + // TODO: we need to to put this somewhere like in .env + // so that if any chanages are to be made, we just edit the file + // instead of the code + return 0; + } + + public function validatePromo($criteria, $promo_id) + { + return false; + } + + public function validateInvoiceItems($criteria, $invoice_items) + { + return null; + } + + protected function getServiceTitle() + { + $title = 'Battery replacement'; + + return $title; + } +} diff --git a/src/InvoiceRule/Tax.php b/src/InvoiceRule/Tax.php new file mode 100644 index 00000000..231c2d36 --- /dev/null +++ b/src/InvoiceRule/Tax.php @@ -0,0 +1,110 @@ +isTaxable()) + { + // nothing to compute + return []; + } + + $tax_rate = $this->getTaxRate(); + + $is_battery_sales = false; + $total_price = 0; + + // compute tax per item if service type is battery sales + $stype = $criteria->getServiceType(); + + if ($stype == ServiceType::BATTERY_REPLACEMENT_NEW) + { + // get the entries + $entries = $criteria->getEntries(); + + foreach($entries as $entry) + { + // check if entry is trade-in + if (isset($entry['trade_in'])) + { + // continue to next entry + continue; + } + + $battery = $entry['battery']; + $qty = $entry['qty']; + + $price = $battery->getSellingPrice(); + + $vat = $this->getTaxAmount($price, $tax_rate); + + $qty_price = bcmul($price, $qty, 2); + $qty_vat = bcmul($vat, $qty, 2); + $price_minus_vat = bcsub($price, $vat, 2); + $qty_price_minus_vat = bcmul($price_minus_vat, $qty, 2); + + $total['vat'] = bcadd($total['vat'], $qty_vat, 2); + $total['vat_ex_price'] = bcadd($total['vat_ex_price'], $qty_price_minus_vat, 2); + } + } + else + { + // compute VAT after adding all item costs, if service type is not battery sales + $total_price = $total['total_price']; + + $vat_ex_price = $this->getTaxExclusivePrice($total_price, $tax_rate); + $vat = bcsub($total_price, $vat_ex_price, 2); + + $total['vat_ex_price'] = $vat_ex_price; + $total['vat'] = $vat; + } + + return []; + } + + public function validatePromo($criteria, $promo_id) + { + return false; + } + + public function validateInvoiceItems($criteria, $invoice_items) + { + return null; + } + + protected function getTaxAmount($price, $tax_rate) + { + $vat_ex_price = $this->getTaxExclusivePrice($price, $tax_rate); + $tax_amount = bcsub($price, $vat_ex_price, 2); + + return $tax_amount; + } + + protected function getTaxExclusivePrice($price, $tax_rate) + { + $tax_ex_price = bcdiv($price, bcadd(1, $tax_rate, 2), 2); + return $tax_ex_price; + } + + protected function getTaxRate() + { + // TODO: we need to to put this somewhere like in .env + // so that if any chanages are to be made, we just edit the file + // instead of the code + return 0.12; + } +} + diff --git a/src/InvoiceRule/TireRepair.php b/src/InvoiceRule/TireRepair.php new file mode 100644 index 00000000..3ca00714 --- /dev/null +++ b/src/InvoiceRule/TireRepair.php @@ -0,0 +1,69 @@ +getServiceType(); + + $items = []; + + if ($stype == $this->getID()) + { + // check if customer vehicle has a motolite battery + $cv = $criteria->getCustomerVehicle(); + if ($cv->hasMotoliteBattery()) + $fee = 0; + else + $fee = $this->getServiceTypeFee(); + + // add the service fee to items + $qty = 1; + $items[] = [ + 'service_type' => $this->getID(), + 'qty' => $qty, + 'title' => $this->getServiceTitle(), + 'price' => $fee, + ]; + + $qty_price = bcmul($fee, $qty, 2); + $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); + } + + return $items; + } + + protected function getServiceTypeFee() + { + // TODO: we need to to put this somewhere like in .env + // so that if any chanages are to be made, we just edit the file + // instead of the code + return 300; + } + + public function validatePromo($criteria, $promo_id) + { + return false; + } + + public function validateInvoiceItems($criteria, $invoice_items) + { + return null; + } + + protected function getServiceTitle() + { + $title = 'Service - Flat Tire'; + + return $title; + } +} diff --git a/src/InvoiceRule/TradeIn.php b/src/InvoiceRule/TradeIn.php new file mode 100644 index 00000000..8e3c6063 --- /dev/null +++ b/src/InvoiceRule/TradeIn.php @@ -0,0 +1,87 @@ +getEntries(); + foreach($entries as $entry) + { + $batt = $entry['battery']; + $qty = $entry['qty']; + $trade_in_type = null; + + if (isset($entry['trade_in'])) + $trade_in_type = $entry['trade_in']; + + if ($trade_in_type != null) + { + $ti_rate = $this->getTradeInRate($batt, $trade_in_type); + + $qty_ti = bcmul($ti_rate, $qty, 2); + + $total['ti_rate'] = bcadd($total['ti_rate'], $qty_ti, 2); + $total['total_price'] = bcsub($total['total_price'], $qty_ti, 2); + + $price = bcmul($ti_rate, -1, 2); + + $items[] = [ + 'qty' => $qty, + 'title' => $this->getTitle($batt, $trade_in_type), + 'price' => $price, + ]; + } + } + + return $items; + } + + public function validatePromo($criteria, $promo_id) + { + return false; + } + + public function validateInvoiceItems($criteria, $invoice_items) + { + return null; + } + + protected function getTradeInRate($battery, $trade_in_type) + { + $size = $battery->getSize(); + + switch ($trade_in_type) + { + case TradeInType::MOTOLITE: + return $size->getTIPriceMotolite(); + case TradeInType::PREMIUM: + return $size->getTIPricePremium(); + case TradeInType::OTHER: + return $size->getTIPriceOther(); + } + + return 0; + } + + protected function getTitle($battery, $trade_in_type) + { + $title = 'Trade-in ' . TradeInType::getName($trade_in_type) . ' ' . $battery->getSize()->getName() . ' battery'; + + return $title; + } +} + diff --git a/src/InvoiceRuleInterface.php b/src/InvoiceRuleInterface.php new file mode 100644 index 00000000..46f0d015 --- /dev/null +++ b/src/InvoiceRuleInterface.php @@ -0,0 +1,16 @@ +flag_coolant = false; $this->discount = 0; $this->service_charges = []; + $this->flag_taxable = false; } public function setServiceType($stype) @@ -153,4 +155,15 @@ class InvoiceCriteria return $this->service_charges; } + public function setIsTaxable($flag = true) + { + $this->flag_taxable = $flag; + return $this; + } + + public function isTaxable() + { + return $this->flag_taxable; + } + } diff --git a/src/Service/InvoiceManager.php b/src/Service/InvoiceManager.php new file mode 100644 index 00000000..ac3f7316 --- /dev/null +++ b/src/Service/InvoiceManager.php @@ -0,0 +1,285 @@ +em = $em; + $this->security = $security; + $this->validator = $validator; + + $this->available_rules = $this->getAvailableRules(); + } + + public function getAvailableRules() + { + // TODO: get list of invoice rules from .env or a json file? + return [ + new InvoiceRule\BatterySales($this->em), + new InvoiceRule\BatteryReplacementWarranty($this->em), + new InvoiceRule\Jumpstart(), + new InvoiceRule\JumpstartWarranty(), + new InvoiceRule\PostRecharged(), + new InvoiceRule\PostReplacement(), + new InvoiceRule\Overheat(), + new InvoiceRule\Fuel(), + new InvoiceRule\TireRepair(), + new InvoiceRule\DiscountType($this->em), + new InvoiceRule\TradeIn(), + new InvoiceRule\Tax(), + ]; + } + + // this is called when JO is submitted + public function generateInvoiceCriteria($jo, $promo_id, $invoice_items, &$error_array) + { + // instantiate the invoice criteria + $criteria = new InvoiceCriteria(); + $criteria->setServiceType($jo->getServiceType()) + ->setCustomerVehicle($jo->getCustomerVehicle()); + + // set if taxable + // NOTE: ideally, this should be a parameter when calling generateInvoiceCriteria. But that + // would mean adding it as a parameter to the call, impacting all calls + $criteria->setIsTaxable(); + + foreach ($this->available_rules as $avail_rule) + { + $ierror = $avail_rule->validatePromo($criteria, $promo_id); + + // break out of loop when error found + if ($ierror) + break; + } + + if (!$ierror && !empty($invoice_items)) + { + // validate the invoice items (batteries and trade ins) + foreach ($this->available_rules as $avail_rule) + { + $ierror = $avail_rule->validateInvoiceItems($criteria, $invoice_items); + + // break out of loop when error found + if ($ierror) + break; + } + } + + if ($ierror) + { + $error_array['invoice'] = $ierror; + } + else + { + // generate the invoice + $invoice = $this->generateInvoice($criteria); + + // validate + $ierrors = $this->validator->validate($invoice); + + // add errors to list + foreach ($ierrors as $error) { + $error_array[$error->getPropertyPath()] = $error->getMessage(); + } + + // check if invoice already exists for JO + $old_invoice = $jo->getInvoice(); + if ($old_invoice != null) + { + // remove old invoice + $this->em->remove($old_invoice); + $this->em->flush(); + } + + // add invoice to JO + $jo->setInvoice($invoice); + + $this->em->persist($invoice); + } + } + + // this is called by JobOrderController when JS script generateInvoice is called + public function generateDraftInvoice($criteria, $promo_id, $service_charges, $items) + { + foreach ($this->available_rules as $avail_rule) + { + $ierror = $avail_rule->validatePromo($criteria, $promo_id); + + // break out of loop when error found + if ($ierror) + break; + } + + if (!$ierror && !empty($items)) + { + // validate the invoice items (batteries and trade ins) + foreach ($this->available_rules as $avail_rule) + { + $ierror = $avail_rule->validateInvoiceItems($criteria, $items); + + // break out of loop when error found + if ($ierror) + break; + } + } + + return $ierror; + } + + // called by the following: + // (1) JobOrderController when JS script generateInvoice is called + // (2) APIController from newRequestJobOrder + // (3) generateInvoiceCriteria + // (4) RiderAPIHandler's changeService + // (5) TAPI's JobOrderController + public function generateInvoice($criteria) + { + // no need to validate since generateDraftInvoice was called before this was called + // generate the invoice and from APIController, the fields were validated + $invoice_data = $this->compute($criteria); + + $invoice = $this->createInvoice($invoice_data); + + $invoice_items = $invoice->getItems(); + + return $invoice; + } + + public function compute($criteria) + { + // 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(); + + $invoice_items = []; + $data = []; + foreach ($this->available_rules as $rule) + { + $items = $rule->compute($criteria, $total); + + $promo = null; + + if (count($items) > 0) + { + foreach ($items as $item) + { + $title = $item['title']; + $quantity = $item['qty']; + $price = $item['price']; + + $battery = null; + if (isset($item['battery'])) + $battery = $item['battery']; + + $promo = null; + if (isset($item['promo'])) + $promo = $item['promo']; + + $invoice_items[] = [ + 'title' => $title, + 'quantity' => $quantity, + 'price' => $price, + 'battery' => $battery, + 'promo' => $promo, + ]; + } + } + } + + // also need to return the total and the promo + $data[] = [ + 'promo' => $promo, + 'invoice_items' => $invoice_items, + 'total' => $total, + ]; + + return $data; + } + + protected function createInvoice($invoice_data) + { + $invoice = new Invoice(); + + // get current user + $user = $this->security->getUser(); + // check if user is User or APIUser + if ($user instanceof User) + { + $invoice->setCreatedBy($user); + } + + foreach ($invoice_data as $data) + { + $invoice_items = $data['invoice_items']; + $total = $data['total']; + + // check if promo is set + if (isset($data['promo'])) + $promo = $data['promo']; + + foreach ($invoice_items as $item) + { + $invoice_item = new InvoiceItem(); + + $invoice_item->setInvoice($invoice) + ->setTitle($item['title']) + ->setQuantity($item['quantity']) + ->setPrice($item['price']); + + if ($item['battery'] != null) + $invoice_item->setBattery($item['battery']); + + $invoice->addItem($invoice_item); + } + + $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; + } + +} diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index c7cac707..1c213699 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -29,12 +29,13 @@ use App\Entity\CustomerTag; use App\Entity\EmergencyType; use App\Entity\OwnershipType; use App\Entity\CustomerLocation; +use App\Entity\Battery; -use App\Ramcar\InvoiceCriteria; use App\Ramcar\ServiceType; use App\Ramcar\TradeInType; use App\Ramcar\JOEventType; use App\Ramcar\JOStatus; +use App\Ramcar\InvoiceCriteria; use App\Ramcar\WarrantyClass; use App\Ramcar\DiscountApply; use App\Ramcar\ModeOfPayment; @@ -3487,8 +3488,19 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface // db loaded $params['bmfgs'] = $em->getRepository(BatteryManufacturer::class)->findAll(); + $params['trade_in_bmfgs'] = $em->getRepository(BatteryManufacturer::class)->findAll(); $params['promos'] = $em->getRepository(Promo::class)->findAll(); + // list of batteries for trade-in + $ti_batteries = $em->getRepository(Battery::class)->findAll(); + $trade_in_batteries = []; + foreach ($ti_batteries as $ti_battery) + { + $battery_name = $ti_battery->getModel()->getName() . ' ' . $ti_battery->getSize()->getName(); + $trade_in_batteries[$ti_battery->getID()] = $battery_name; + } + $params['trade_in_batteries'] = $trade_in_batteries; + // list of emergency types $e_types = $em->getRepository(EmergencyType::class)->findBy([], ['name' => 'ASC']); $emergency_types = []; diff --git a/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php b/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php index a3bba40b..f992f6e5 100644 --- a/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php +++ b/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php @@ -866,6 +866,9 @@ class ResqRiderAPIHandler implements RiderAPIHandlerInterface $crit->setCustomerVehicle($cv); $crit->setHasCoolant($jo->hasCoolant()); + // set istaxable + $crit->setIsTaxable(); + if ($promo != null) $crit->addPromo($promo); diff --git a/templates/invoice/trade_in.html.twig b/templates/invoice/trade_in.html.twig new file mode 100644 index 00000000..e033143d --- /dev/null +++ b/templates/invoice/trade_in.html.twig @@ -0,0 +1,46 @@ +
+
+ + +
+
+ + +
+
+ + +
+
+ + + +
+
+ + +
+
+
+ +
+
diff --git a/templates/invoice/trade_in.js.twig b/templates/invoice/trade_in.js.twig new file mode 100644 index 00000000..a93fce56 --- /dev/null +++ b/templates/invoice/trade_in.js.twig @@ -0,0 +1,17 @@ +// add trade in battery to invoice +$('#btn-add-trade-in-to-invoice').click(function() { + var bmfg = $("#invoice-trade-in-bmfg").val(); + var battery = $("#invoice-trade-in-battery").val(); + var tradeIn = $("#invoice-trade-in-type").val(); + var qty = $("#invoice-trade-in-quantity").val(); + + // add to invoice array + invoiceItems.push({ + battery: battery, + quantity: qty, + trade_in: tradeIn, + }); + + // regenerate the invoice + generateInvoice(); +}); diff --git a/templates/job-order/form.html.twig b/templates/job-order/form.html.twig index 9a8387b5..b2e17e34 100644 --- a/templates/job-order/form.html.twig +++ b/templates/job-order/form.html.twig @@ -715,6 +715,7 @@ +
@@ -748,6 +750,7 @@
+ {% include('invoice/trade_in.html.twig') %} {% endif %} @@ -1190,7 +1193,6 @@