[*] BO : Taxes are now historized
[*] BO : Taxes are no longer stored in the order details row
This commit is contained in:
+86
-34
@@ -25,6 +25,7 @@
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
|
||||
class TaxCore extends ObjectModel
|
||||
{
|
||||
/** @var string Name */
|
||||
@@ -36,6 +37,9 @@ class TaxCore extends ObjectModel
|
||||
/** @var bool active state */
|
||||
public $active;
|
||||
|
||||
/** @var boolean true if the tax has been historized */
|
||||
public $deleted = 0;
|
||||
|
||||
protected $fieldsRequired = array('rate');
|
||||
protected $fieldsValidate = array('rate' => 'isFloat');
|
||||
protected $fieldsRequiredLang = array('name');
|
||||
@@ -53,6 +57,7 @@ class TaxCore extends ObjectModel
|
||||
$this->validateFields();
|
||||
$fields['rate'] = (float)($this->rate);
|
||||
$fields['active'] = (int)($this->active);
|
||||
$fields['deleted'] = (int)($this->deleted);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
@@ -71,7 +76,22 @@ class TaxCore extends ObjectModel
|
||||
{
|
||||
/* Clean associations */
|
||||
TaxRule::deleteTaxRuleByIdTax((int)$this->id);
|
||||
return parent::delete();
|
||||
|
||||
if ($this->isUsed())
|
||||
return $this->historize();
|
||||
else
|
||||
return parent::delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the object with the field deleted to true
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function historize()
|
||||
{
|
||||
$this->deleted = true;
|
||||
return parent::update();
|
||||
}
|
||||
|
||||
public function toggleStatus()
|
||||
@@ -84,9 +104,20 @@ class TaxCore extends ObjectModel
|
||||
|
||||
public function update($nullValues = false)
|
||||
{
|
||||
if (parent::update($nullValues))
|
||||
return $this->_onStatusChange();
|
||||
|
||||
if (!$this->deleted && $this->isUsed())
|
||||
{
|
||||
$historized_tax = new Tax($this->id);
|
||||
$historized_tax->historize();
|
||||
|
||||
// remove the id in order to create a new object
|
||||
$this->id = 0;
|
||||
$this->add();
|
||||
|
||||
// change tax id in the tax rule table
|
||||
TaxRule::swapTaxId($historized_tax->id, $this->id);
|
||||
} else if (parent::update($nullValues))
|
||||
return $this->_onStatusChange();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -97,20 +128,43 @@ class TaxCore extends ObjectModel
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the tax is used in an order details
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isUsed()
|
||||
{
|
||||
return Db::getInstance()->getValue('
|
||||
SELECT COUNT(*) FROM `'._DB_PREFIX_.'order_detail_tax`
|
||||
WHERE `id_tax` = '.(int)$this->id
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available taxes
|
||||
*
|
||||
* @return array Taxes
|
||||
*/
|
||||
public static function getTaxes($id_lang = false, $active = 1)
|
||||
public static function getTaxes($id_lang = false, $active_only = true)
|
||||
{
|
||||
return Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS('
|
||||
SELECT t.id_tax, t.rate'.((int)($id_lang) ? ', tl.name, tl.id_lang ' : '').'
|
||||
FROM `'._DB_PREFIX_.'tax` t
|
||||
'.((int)($id_lang) ? 'LEFT JOIN `'._DB_PREFIX_.'tax_lang` tl ON (t.`id_tax` = tl.`id_tax` AND tl.`id_lang` = '.(int)($id_lang).')'
|
||||
.($active == 1 ? 'WHERE t.`active` = 1' : '').'
|
||||
ORDER BY `name` ASC' : ''));
|
||||
$query = array();
|
||||
$query['select'] = 'SELECT t.id_tax, t.rate';
|
||||
$query['from'] = 'FROM `'._DB_PREFIX_.'tax` t';
|
||||
$query['where'] = 'WHERE t.`deleted` != 1';
|
||||
|
||||
if ($id_lang)
|
||||
{
|
||||
$query['select'] .= ', tl.name, tl.id_lang ';
|
||||
$query['join'] = 'LEFT JOIN `'._DB_PREFIX_.'tax_lang` tl ON (t.`id_tax` = tl.`id_tax` AND tl.`id_lang` = '.(int)($id_lang).')';
|
||||
$query['order'] = 'ORDER BY `name` ASC';
|
||||
}
|
||||
|
||||
if ($active_only)
|
||||
$query['where'] .= ' AND t.`active` = 1';
|
||||
|
||||
return Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(Tools::buildQuery($query));
|
||||
}
|
||||
|
||||
public static function excludeTaxeOption()
|
||||
@@ -136,26 +190,6 @@ class TaxCore extends ObjectModel
|
||||
return $tax ? (int)($tax['id_tax']) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the product tax
|
||||
*
|
||||
* @param integer $id_product
|
||||
* @param integer $id_country
|
||||
* @return Tax
|
||||
*
|
||||
* @deprecated use $product->getTaxesRate() instead
|
||||
*/
|
||||
public static function getProductTaxRate($id_product, $id_address = NULL)
|
||||
{
|
||||
$address = Tax::initializeAddress($id_address);
|
||||
$id_tax_rules = (int)Product::getIdTaxRulesGroupByIdProduct($id_product);
|
||||
|
||||
$tax_manager = TaxManagerFactory::getManager($address, $id_tax_rules);
|
||||
$tax_calculator = $tax_manager->getTaxCalculator();
|
||||
|
||||
return $tax_calculator->getTaxesRate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ecotax tax rate
|
||||
*
|
||||
@@ -169,7 +203,7 @@ class TaxCore extends ObjectModel
|
||||
$tax_manager = TaxManagerFactory::getManager($address, (int)Configuration::get('PS_ECOTAX_TAX_RULES_GROUP_ID'));
|
||||
$tax_calculator = $tax_manager->getTaxCalculator();
|
||||
|
||||
return $tax_calculator->getTaxesRate();
|
||||
return $tax_calculator->getTotalRate();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,7 +220,7 @@ class TaxCore extends ObjectModel
|
||||
$tax_manager = TaxManagerFactory::getManager($address, $id_tax_rules);
|
||||
$tax_calculator = $tax_manager->getTaxCalculator();
|
||||
|
||||
return $tax_calculator->getTaxesRate();
|
||||
return $tax_calculator->getTotalRate();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,11 +265,29 @@ class TaxCore extends ObjectModel
|
||||
|
||||
if (!isset(self::$_product_tax_via_rules[$id_product.'-'.$id_country.'-'.$id_state.'-'.$zipcode]))
|
||||
{
|
||||
$tax_rate = TaxRulesGroup::getTaxesRate((int)Product::getIdTaxRulesGroupByIdProduct((int)$id_product), (int)$id_country, (int)$id_state, $zipcode);
|
||||
$tax_rate = TaxRulesGroup::getTotalRate((int)Product::getIdTaxRulesGroupByIdProduct((int)$id_product), (int)$id_country, (int)$id_state, $zipcode);
|
||||
self::$_product_tax_via_rules[$id_product.'-'.$id_country.'-'.$zipcode] = $tax_rate;
|
||||
}
|
||||
|
||||
return self::$_product_tax_via_rules[$id_product.'-'.$id_country.'-'.$zipcode];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the product tax
|
||||
*
|
||||
* @param integer $id_product
|
||||
* @param integer $id_country
|
||||
* @return Tax
|
||||
*/
|
||||
public static function getProductTaxRate($id_product, $id_address = NULL)
|
||||
{
|
||||
$address = Tax::initializeAddress($id_address);
|
||||
$id_tax_rules = (int)Product::getIdTaxRulesGroupByIdProduct($id_product);
|
||||
|
||||
$tax_manager = TaxManagerFactory::getManager($address, $id_tax_rules);
|
||||
$tax_calculator = $tax_manager->getTaxCalculator();
|
||||
|
||||
return $tax_calculator->getTotalRate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,9 +45,9 @@ class TaxCalculatorCore
|
||||
const ONE_AFTER_ANOTHER_METHOD = 2;
|
||||
|
||||
/**
|
||||
* @var array $taxes_rate
|
||||
* @var array $taxes
|
||||
*/
|
||||
public $taxes_rate;
|
||||
public $taxes;
|
||||
|
||||
/**
|
||||
* @var int $computation_method (COMBINE_METHOD | ONE_AFTER_ANOTHER_METHOD)
|
||||
@@ -56,89 +56,89 @@ class TaxCalculatorCore
|
||||
|
||||
|
||||
/**
|
||||
* @param array $taxes_rate
|
||||
* @param array $taxes
|
||||
* @param int $computation_method (COMBINE_METHOD | ONE_AFTER_ANOTHER_METHOD)
|
||||
*/
|
||||
public function __construct(array $taxes_rate, $computation_method = TaxCalculator::COMBINE_METHOD)
|
||||
public function __construct(array $taxes = array(), $computation_method = TaxCalculator::COMBINE_METHOD)
|
||||
{
|
||||
$this->taxes_rate = $taxes_rate;
|
||||
// sanity check
|
||||
foreach ($taxes as $tax)
|
||||
if (!($tax instanceof Tax))
|
||||
throw new Exception('Invalid Tax Object');
|
||||
|
||||
$this->taxes = $taxes;
|
||||
$this->computation_method = (int)$computation_method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute and add the taxes to the specified price
|
||||
*
|
||||
* @param price
|
||||
* @return price with taxes
|
||||
* @param price_te price tax excluded
|
||||
* @return float price with taxes
|
||||
*/
|
||||
public function addTaxes($price)
|
||||
public function addTaxes($price_te)
|
||||
{
|
||||
$total_price = $price;
|
||||
if ($this->computation_method == TaxCalculator::ONE_AFTER_ANOTHER_METHOD)
|
||||
{
|
||||
foreach ($this->taxes_rate as $tax_rate)
|
||||
$total_price = $total_price * (1 + abs($tax_rate) / 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($this->taxes_rate as $tax_rate)
|
||||
{
|
||||
if ($tax_rate != 0)
|
||||
$total_price = $total_price + ($price * (abs($tax_rate) / 100));
|
||||
}
|
||||
}
|
||||
return $total_price;
|
||||
return $price_te * (1 + ($this->getTotalRate() / 100));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute and remove the taxes to the specified price
|
||||
*
|
||||
* @param price
|
||||
* @param price_ti price tax inclusive
|
||||
* @return price without taxes
|
||||
*/
|
||||
public function removeTaxes($price)
|
||||
public function removeTaxes($price_ti)
|
||||
{
|
||||
$total_price = $price;
|
||||
if ($this->computation_method == TaxCalculator::ONE_AFTER_ANOTHER_METHOD)
|
||||
{
|
||||
foreach ($this->taxes_rate as $tax_rate)
|
||||
$total_price = $total_price / (1 + abs($tax_rate) / 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
$taxes_rate = 0;
|
||||
foreach ($this->taxes_rate as $tax_rate)
|
||||
$taxes_rate += abs($tax_rate);
|
||||
|
||||
$total_price = $total_price / (1 + (abs($taxes_rate) / 100));
|
||||
}
|
||||
|
||||
return $total_price;
|
||||
return $price_ti / (1 + $this->getTotalRate() / 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return total taxes rate
|
||||
* @return float total taxes rate
|
||||
*/
|
||||
public function getTaxesRate()
|
||||
public function getTotalRate()
|
||||
{
|
||||
$taxes_rate = 0;
|
||||
$taxes = 0;
|
||||
if ($this->computation_method == TaxCalculator::ONE_AFTER_ANOTHER_METHOD)
|
||||
{
|
||||
$taxes_rate = 1;
|
||||
foreach ($this->taxes_rate as $rate)
|
||||
$taxes_rate *= (1 + (abs($rate) / 100));
|
||||
$taxes = 1;
|
||||
foreach ($this->taxes as $tax)
|
||||
$taxes *= (1 + (abs($tax->rate) / 100));
|
||||
|
||||
$taxes_rate = $taxes_rate - 1;
|
||||
$taxes_rate = $taxes_rate * 100;
|
||||
$taxes = $taxes - 1;
|
||||
$taxes = $taxes * 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($this->taxes_rate as $rate)
|
||||
$taxes_rate += abs($rate);
|
||||
foreach ($this->taxes as $tax)
|
||||
$taxes += abs($tax->rate);
|
||||
}
|
||||
|
||||
return $taxes_rate;
|
||||
return (float)$taxes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tax amount associated to each taxes of the TaxCalculator
|
||||
*
|
||||
* @param float $price_te
|
||||
* @return array $taxes_amount
|
||||
*/
|
||||
public function getTaxesAmount($price_te)
|
||||
{
|
||||
$taxes_amounts = array();
|
||||
|
||||
foreach ($this->taxes as $tax)
|
||||
{
|
||||
if ($this->computation_method == TaxCalculator::ONE_AFTER_ANOTHER_METHOD)
|
||||
{
|
||||
$taxes_amounts[$tax->rate] = $price_te * (abs($tax->rate) / 100);
|
||||
$price_te = $price_te + $taxes_amounts[$tax->rate];
|
||||
}
|
||||
else
|
||||
$taxes_amounts[$tax->rate] = ($price * (abs($tax->rate) / 100));
|
||||
}
|
||||
|
||||
return $taxes_amounts;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+25
-17
@@ -27,25 +27,25 @@
|
||||
|
||||
class TaxRuleCore extends ObjectModel
|
||||
{
|
||||
public $id_tax_rules_group;
|
||||
public $id_country;
|
||||
public $id_state;
|
||||
public $id_tax_rules_group;
|
||||
public $id_country;
|
||||
public $id_state;
|
||||
public $zipcode_from;
|
||||
public $zipcode_to;
|
||||
public $id_tax;
|
||||
public $id_tax;
|
||||
public $behavior;
|
||||
public $description;
|
||||
|
||||
protected $fieldsRequired = array('id_tax_rules_group', 'id_country', 'id_tax');
|
||||
protected $fieldsValidate = array('id_tax_rules_group' => 'isUnsignedId',
|
||||
'id_country' => 'isUnsignedId',
|
||||
'id_state' => 'isUnsignedId',
|
||||
'zipcode_from' => 'isUnsignedId', // TODO: char
|
||||
'zipcode_to' => 'isUnsignedId', // TODO: char
|
||||
'id_tax' => 'isUnsignedId',
|
||||
'behavior' => 'isUnsignedInt',
|
||||
'description' => 'isUnsignedInt'); // TODO:char
|
||||
|
||||
protected $fieldsRequired = array('id_tax_rules_group', 'id_country', 'id_tax');
|
||||
protected $fieldsValidate = array('id_tax_rules_group' => 'isUnsignedId',
|
||||
'id_country' => 'isUnsignedId',
|
||||
'id_state' => 'isUnsignedId',
|
||||
'zipcode_from' => 'isUnsignedId', // TODO: char
|
||||
'zipcode_to' => 'isUnsignedId', // TODO: char
|
||||
'id_tax' => 'isUnsignedId',
|
||||
'behavior' => 'isUnsignedInt',
|
||||
'description' => 'isUnsignedInt'); // TODO:char
|
||||
|
||||
protected $table = 'tax_rule';
|
||||
protected $identifier = 'id_tax_rule';
|
||||
|
||||
@@ -96,8 +96,6 @@ class TaxRuleCore extends ObjectModel
|
||||
|
||||
public static function getTaxRulesByGroupId($id_lang, $id_group)
|
||||
{
|
||||
|
||||
|
||||
return Db::getInstance()->ExecuteS('
|
||||
SELECT g.`id_tax_rule`,
|
||||
c.`name` AS country_name,
|
||||
@@ -110,7 +108,8 @@ class TaxRuleCore extends ObjectModel
|
||||
LEFT JOIN `'._DB_PREFIX_.'country_lang` c ON (g.`id_country` = c.`id_country` AND id_lang = '.(int)$id_lang.')
|
||||
LEFT JOIN `'._DB_PREFIX_.'state` s ON (g.`id_state` = s.`id_state`)
|
||||
LEFT JOIN `'._DB_PREFIX_.'tax` t ON (g.`id_tax` = t.`id_tax`)
|
||||
WHERE `id_tax_rules_group` = '.(int)$id_group
|
||||
WHERE `id_tax_rules_group` = '.(int)$id_group.'
|
||||
ORDER BY `country_name` ASC, `state_name` ASC, `zipcode_from` ASC, `zipcode_to` ASC'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -175,5 +174,14 @@ class TaxRuleCore extends ObjectModel
|
||||
|
||||
return array($from, $to);
|
||||
}
|
||||
|
||||
public static function swapTaxId($old_id, $new_id)
|
||||
{
|
||||
return Db::getInstance()->Execute('
|
||||
UPDATE `'._DB_PREFIX_.'tax_rule`
|
||||
SET `id_tax` = '.(int)$new_id.'
|
||||
WHERE `id_tax` = '.(int)$old_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,13 +74,13 @@ class TaxRulesTaxManagerCore implements TaxManagerInterface
|
||||
|
||||
$behavior = 0;
|
||||
$first_row = true;
|
||||
$taxes_rates = array();
|
||||
$taxes = array();
|
||||
|
||||
foreach ($rows as $row)
|
||||
{
|
||||
$tax = new Tax((int)$row['id_tax']);
|
||||
|
||||
$taxes_rates[] = $tax->rate;
|
||||
$taxes[] = $tax;
|
||||
|
||||
// the applied behavior correspond to the most specific rules
|
||||
if ($first_row)
|
||||
@@ -93,9 +93,7 @@ class TaxRulesTaxManagerCore implements TaxManagerInterface
|
||||
break;
|
||||
}
|
||||
|
||||
$this->tax_calculator = new TaxCalculator($taxes_rates, $behavior);
|
||||
|
||||
return $this->tax_calculator;
|
||||
return new TaxCalculator($taxes, $behavior);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user