diff --git a/classes/order/Order.php b/classes/order/Order.php index 3268193c2..cc87a51bd 100644 --- a/classes/order/Order.php +++ b/classes/order/Order.php @@ -2598,8 +2598,53 @@ class OrderCore extends ObjectModel Product::PRICE_ADDITION_TYPE_WITH_ROOM ) ) { - $additionalTaxAmounts = $tax_calculator->getTaxesAmount($autoAddedPriceExcl); - $totalTaxBase += $autoAddedPriceExcl; + $autoAddedServiceData = $objServiceProductOrderDetail->getRoomTypeServiceProducts( + $order_detail['id_order'], + 0, 0, + $order_detail['product_id'], + 0, 0, 0, + false, false, true, + Product::PRICE_ADDITION_TYPE_WITH_ROOM + ); + + // We are getting auto added service for specific room.There will be only on htl_booking_detail but can have multiple auto added service with room. + // Note: All the auto added service with room have same id_tax_rule group + $autoAddedServiceData = array_shift($autoAddedServiceData); + $autoAddedServices = $autoAddedServiceData['additional_services']; + + // Calculate total quantity of auto-added services + $totalAutoAddedQty = array_reduce($autoAddedServices, function ($quantity, $service) { + $qty = isset($service['quantity']) ? $service['quantity'] : 0; + return $quantity + $qty; + }, 0); + + $firstAutoAddedService = array_shift($autoAddedServices); + $id_tax_rule_group = $firstAutoAddedService['id_tax_rules_group']; + + // If tax group is different from order detail, add tax info separately + if ($order_detail['id_tax_rules_group'] != $id_tax_rule_group) { + $objAddress = new Address((int)$this->id_address_tax); + $autoAddedServiceTaxManager = TaxManagerFactory::getManager($objAddress, (int)$id_tax_rule_group); + $autoAddedServiceTaxCalculator = $autoAddedServiceTaxManager->getTaxCalculator(); + // Calculate tax for the total price + $additionalTaxAmounts = $autoAddedServiceTaxCalculator->getTaxesAmount($autoAddedPriceExcl); + foreach ($additionalTaxAmounts as $taxId => $amount) { + $objTax = new Tax((int)$taxId); + $groupedTaxDetails[$taxId] = array( + 'id_order_detail' => $firstAutoAddedService['id_order_detail'], + 'id_tax' => $taxId, + 'tax_rate' => $objTax->rate, + 'unit_tax_base' => $autoAddedPriceExcl / $totalAutoAddedQty, + 'total_tax_base' => $autoAddedPriceExcl, + 'unit_amount' => $amount, + 'total_amount' => Tools::processPriceRounding($amount, $totalAutoAddedQty), + ); + } + } else { + // Calculate tax for the total price + $additionalTaxAmounts = $tax_calculator->getTaxesAmount($autoAddedPriceExcl); + $totalTaxBase += $autoAddedPriceExcl; + } } $taxBaseShare = $totalTaxBase; diff --git a/classes/order/OrderInvoice.php b/classes/order/OrderInvoice.php index 3531e04ac..5d0a6ae21 100644 --- a/classes/order/OrderInvoice.php +++ b/classes/order/OrderInvoice.php @@ -650,7 +650,7 @@ class OrderInvoiceCore extends ObjectModel 'total_price_tax_excl' => 0, 'total_amount' => 0, 'id_tax' => $row['id_tax'], - 'rate' => $key, + 'rate' => sprintf('%.3f', $row['tax_rate']), ); } diff --git a/classes/pdf/HTMLTemplateOrderSlip.php b/classes/pdf/HTMLTemplateOrderSlip.php index c520fe521..71a7e5f18 100644 --- a/classes/pdf/HTMLTemplateOrderSlip.php +++ b/classes/pdf/HTMLTemplateOrderSlip.php @@ -231,10 +231,11 @@ class HTMLTemplateOrderSlipCore extends HTMLTemplateInvoice { $breakdowns = array( 'room_tax' => $this->getRoomTypeTaxesBreakdown(), + 'service_products_tax' => $this->getServiceProductsTaxesBreakdown($this->order), 'shipping_tax' => $this->getShippingTaxesBreakdown(), 'ecotax_tax' => $this->order_slip->getEcoTaxTaxesBreakdown(), ); - + foreach ($breakdowns as $type => $bd) { if (empty($bd)) { unset($breakdowns[$type]); @@ -339,6 +340,68 @@ class HTMLTemplateOrderSlipCore extends HTMLTemplateInvoice return $breakdown; } + public function getServiceProductsTaxesBreakdown() + { + $sum_composite_taxes = !$this->useOneAfterAnotherTaxComputationMethod(); + + // $breakdown will be an array with tax rates as keys and at least the columns: + // - 'total_price_tax_excl' + // - 'total_amount' + $breakdown = array(); + $order_detail = array_filter($this->order->products, function($v) { + return (!$v['is_booking_product'] && ( + $v['selling_preference_type'] == Product::SELLING_PREFERENCE_STANDALONE + || $v['selling_preference_type'] == Product::SELLING_PREFERENCE_HOTEL_STANDALONE + )); + }); + + $details = $this->order->getProductTaxesDetails($order_detail, false); + + if ($sum_composite_taxes) { + $grouped_details = array(); + foreach ($details as $row) { + if (!isset($grouped_details[$row['id_order_detail']])) { + $grouped_details[$row['id_order_detail']] = array( + 'tax_rate' => 0, + 'total_tax_base' => $row['total_tax_base'], + 'total_amount' => 0, + 'id_tax' => $row['id_tax'], + ); + } + + $grouped_details[$row['id_order_detail']]['tax_rate'] += $row['tax_rate']; + $grouped_details[$row['id_order_detail']]['total_amount'] += $row['total_amount']; + } + $details = $grouped_details; + } + foreach ($details as $row) { + if (!$sum_composite_taxes) { + $key = $row['id_tax']; + } else { + $key = sprintf('%.3f', $row['tax_rate']); + } + if (!isset($breakdown[$key])) { + $breakdown[$key] = array( + 'total_price_tax_excl' => 0, + 'total_amount' => 0, + 'id_tax' => $row['id_tax'], + 'rate' => sprintf('%.3f', $row['tax_rate']), + ); + } + + $breakdown[$key]['total_price_tax_excl'] += $row['total_tax_base']; + $breakdown[$key]['total_amount'] += $row['total_amount']; + } + + foreach ($breakdown as $key => $data) { + $breakdown[$key]['total_price_tax_excl'] = Tools::ps_round($data['total_price_tax_excl'], _PS_PRICE_COMPUTE_PRECISION_, $this->order->round_mode); + $breakdown[$key]['total_amount'] = Tools::ps_round($data['total_amount'], _PS_PRICE_COMPUTE_PRECISION_, $this->order->round_mode); + } + + ksort($breakdown); + return $breakdown; + } + /** * Returns Shipping tax breakdown elements * diff --git a/classes/tax/TaxCalculator.php b/classes/tax/TaxCalculator.php index 8add1f597..df2d2d6df 100644 --- a/classes/tax/TaxCalculator.php +++ b/classes/tax/TaxCalculator.php @@ -140,11 +140,14 @@ class TaxCalculatorCore $taxes_amounts = array(); foreach ($this->taxes as $tax) { + if (!isset($taxes_amounts[$tax->id])) { + $taxes_amounts[$tax->id] = 0; + } if ($this->computation_method == TaxCalculator::ONE_AFTER_ANOTHER_METHOD) { - $taxes_amounts[$tax->id] = $price_te * (abs($tax->rate) / 100); + $taxes_amounts[$tax->id] += $price_te * (abs($tax->rate) / 100); $price_te = $price_te + $taxes_amounts[$tax->id]; } else { - $taxes_amounts[$tax->id] = ($price_te * (abs($tax->rate) / 100)); + $taxes_amounts[$tax->id] += ($price_te * (abs($tax->rate) / 100)); } } diff --git a/modules/hotelreservationsystem/classes/RoomTypeServiceProductPrice.php b/modules/hotelreservationsystem/classes/RoomTypeServiceProductPrice.php index aca9e3b8a..68c401732 100644 --- a/modules/hotelreservationsystem/classes/RoomTypeServiceProductPrice.php +++ b/modules/hotelreservationsystem/classes/RoomTypeServiceProductPrice.php @@ -71,6 +71,8 @@ class RoomTypeServiceProductPrice extends ObjectModel { $cache_key = 'RoomTypeServiceProductPrice::getProductRoomTypePriceAndTax'.$idProduct.'_'.$idElement.'_'.$elementType; if (!Cache::isStored($cache_key)) { + $objServiceProductCartDetail = new ServiceProductCartDetail(); + $objServiceProduct = new Product((int)$idProduct); if ($result = Db::getInstance()->getRow(' SELECT spp.`price`, spp.`id_tax_rules_group`, p.`auto_add_to_cart`, p.`price_addition_type` FROM `'._DB_PREFIX_.'product` p @@ -88,6 +90,15 @@ class RoomTypeServiceProductPrice extends ObjectModel $result['id_tax_rules_group'] = Product::getIdTaxRulesGroupByIdProduct((int)$idElement); } } + } elseif ($objServiceProduct->auto_add_to_cart + && $elementType == RoomTypeServiceProduct::WK_ELEMENT_TYPE_ROOM_TYPE + && $objServiceProduct->price_addition_type == Product::PRICE_ADDITION_TYPE_WITH_ROOM + && $objServiceProductCartDetail->alreadyExists(Context::getContext()->cart->id, $idProduct) + ) { + $result = array(); + $result['auto_add_to_cart'] = 1; + $result['price_addition_type'] = Product::PRICE_ADDITION_TYPE_WITH_ROOM; + $result['id_tax_rules_group'] = Product::getIdTaxRulesGroupByIdProduct((int)$idElement); } Cache::store($cache_key, $result); diff --git a/modules/hotelreservationsystem/classes/ServiceProductOrderDetail.php b/modules/hotelreservationsystem/classes/ServiceProductOrderDetail.php index 33202537b..ca8f99057 100644 --- a/modules/hotelreservationsystem/classes/ServiceProductOrderDetail.php +++ b/modules/hotelreservationsystem/classes/ServiceProductOrderDetail.php @@ -304,6 +304,8 @@ class ServiceProductOrderDetail extends ObjectModel 'name' => $product['name'], 'quantity' => $product['quantity'], 'allow_multiple_quantity' => $product['product_allow_multiple_quantity'], + 'tax_computation_method' => $product['tax_computation_method'], + 'id_tax_rules_group' => $product['id_tax_rules_group'], 'price_calculation_method' => $product['product_price_calculation_method'], 'product_tax' => $product_tax, 'product_tax_label' => $product_tax_label,