em = $em; $this->available_rules = $this->getAvailableRules(); } public function getAvailableRules() { // TODO: get list of invoice rules from .env return [ new Invoice\ServiceType(), new Invoice\BatterySales(), new Invoice\BatteryReplacementWarranty(), new Invoice\Jumpstart(), new Invoice\JumpstartWarranty(), new Invoice\PostRecharged(), new Invoice\PostReplacement(), new Invoice\Overheat(), new Invoice\Fuel(), new Invoice\TireRepair(), new Invoice\DiscountType(), new Invoice\TradeIn(), new Invoice\Tax, ]; } public function getServiceTypeFees() { return [ 'service_fee' => 300, 'coolant_fee' => 1600, 'post_recharged_fee' => 300, 'jumpstart_troubleshoot_fee' => 150, 'jumpstart_warranty_fee' => 0, 'battery_replacement_fee' => 0, 'battery_warranty_fee' => 0, 'other_services_fee' => 200, 'fuel_fee_gas' => 320, 'fuel_fee_diesel' => 320, ]; } public function getTaxRate() { return 0.12; } // check what rules to use given the criteria public function check($criteria) { $active_rules = []; foreach ($this->available_rules as $rule) { $is_active = $rule->check($criteria); if ($is_active) $active_rules[$rule->getID()] = $rule; } return $active_rules; } public function compute($criteria, $active_rules) { // initialize $total = [ 'sell_price' => 0.0, 'vat' => 0.0, 'vat_ex_price' => 0.0, 'ti_rate' => 0.0, 'total_price' => 0.0, 'discount' => 0.0, ]; // get what is in criteria $stype = $criteria->getServiceType(); $entries = $criteria->getEntries(); $promos = $criteria->getPromos(); $is_taxable = $criteria->isTaxable(); // get the service type fees $stype_fees = $this->getServiceTypeFees(); $flag_trade_in = false; foreach ($entries as $entry) { if ($entry['trade_in'] != null) { $flag_trade_in = true; } } $invoice_items = []; $data = []; foreach ($active_rules as $id => $active_rule) { // each criteria can only have one service type // find the rule for the service type if ($id == $stype) { $items = []; $computed_items = $active_rule->compute($criteria, $stype_fees); foreach ($computed_items as $computed_item) { if (!empty($computed_item)) { $items[] = $computed_item; } } // process trade-ins by calling the trade-in rule if there are trade-ins among the entries if ($flag_trade_in) { if (isset($active_rules['trade_in'])) { $tradein_items = $active_rules['trade_in']->compute($criteria, $stype_fees, $total); foreach ($tradein_items as $tradein_item) { $items[] = $tradein_item; } } } // check if tax is needed if ($is_taxable) { $tax_rate = $this->getTaxRate(); if (isset($active_rules['tax'])) { $active_rules['tax']->compute($tax_rate, $items, $total); } } foreach ($items as $item) { $invoice_item = new InvoiceItem(); $invoice_item->setTitle($item['title']) ->setQuantity($item['qty']) ->setPrice($item['price']); if (isset($item['battery'])) $invoice_item->setBattery($item['battery']); $invoice_items[] = $invoice_item; } // process promos, if any if (count($promos) > 0) { if (isset($active_rules['discount_type'])) { $discount_items = $active_rules['discount_type']->compute($criteria, $stype_fees); } } // also need to return the total $data[] = [ 'invoice_items' => $invoice_items, 'total' => $total, ]; } } return $data; } }