fixed tax service
This commit is contained in:
parent
71705ae9d6
commit
8d134c96c8
|
|
@ -11,130 +11,197 @@
|
|||
|
||||
namespace Beike\Services;
|
||||
|
||||
use Beike\Models\Address;
|
||||
use Beike\Models\TaxRate;
|
||||
|
||||
class TaxService
|
||||
{
|
||||
private $tax_rates = array();
|
||||
private $taxRates = array();
|
||||
private static $taxRules;
|
||||
|
||||
public function __construct($registry) {
|
||||
$this->config = $registry->get('config');
|
||||
$this->db = $registry->get('db');
|
||||
const AVAILABLE_TYPES = ['shipping', 'payment', 'store'];
|
||||
|
||||
public function __construct($data = array())
|
||||
{
|
||||
$countryId = system_setting('base.config_country_id');
|
||||
$zoneId = system_setting('base.config_zone_id');
|
||||
|
||||
$shippingAddress = $data['shipping_address'] ?? null;
|
||||
$paymentAddress = $data['payment_address'] ?? null;
|
||||
|
||||
if ($shippingAddress) {
|
||||
if ($shippingAddress instanceof Address) {
|
||||
$this->setShippingAddress($shippingAddress->country_id, $shippingAddress->zone_id);
|
||||
} elseif ($shippingAddress instanceof \ArrayObject) {
|
||||
$this->setShippingAddress($countryId, $zoneId);
|
||||
} else {
|
||||
$this->setShippingAddress($shippingAddress['country_id'], $shippingAddress['zone_id']);
|
||||
}
|
||||
} elseif (system_setting('base.config_tax_default') == 'shipping') {
|
||||
$this->setShippingAddress($countryId, $zoneId);
|
||||
}
|
||||
|
||||
if ($paymentAddress) {
|
||||
if ($paymentAddress instanceof Address) {
|
||||
$this->setPaymentAddress($paymentAddress->country_id, $paymentAddress->zone_id);
|
||||
} elseif ($paymentAddress instanceof \ArrayObject) {
|
||||
$this->setShippingAddress($countryId, $zoneId);
|
||||
} else {
|
||||
$this->setPaymentAddress($paymentAddress['country_id'], $paymentAddress['zone_id']);
|
||||
}
|
||||
} elseif (system_setting('base.config_tax_default') == 'payment') {
|
||||
$this->setPaymentAddress($countryId, $zoneId);
|
||||
}
|
||||
|
||||
$this->setStoreAddress($countryId, $zoneId);
|
||||
}
|
||||
|
||||
public function unsetRates() {
|
||||
$this->tax_rates = array();
|
||||
public static function getInstance($data = array())
|
||||
{
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public function setShippingAddress($country_id, $zone_id) {
|
||||
$tax_query = $this->db->query("SELECT tr1.tax_class_id, tr2.tax_rate_id, tr2.name, tr2.rate, tr2.type, tr1.priority FROM " . DB_PREFIX . "tax_rule tr1 LEFT JOIN " . DB_PREFIX . "tax_rate tr2 ON (tr1.tax_rate_id = tr2.tax_rate_id) INNER JOIN " . DB_PREFIX . "tax_rate_to_customer_group tr2cg ON (tr2.tax_rate_id = tr2cg.tax_rate_id) LEFT JOIN " . DB_PREFIX . "zone_to_geo_zone z2gz ON (tr2.geo_zone_id = z2gz.geo_zone_id) LEFT JOIN " . DB_PREFIX . "geo_zone gz ON (tr2.geo_zone_id = gz.geo_zone_id) WHERE tr1.based = 'shipping' AND tr2cg.customer_group_id = '" . (int)$this->config->get('config_customer_group_id') . "' AND z2gz.country_id = '" . (int)$country_id . "' AND (z2gz.zone_id = '0' OR z2gz.zone_id = '" . (int)$zone_id . "') ORDER BY tr1.priority ASC");
|
||||
private function getTaxRules($type, $countryId, $zoneId)
|
||||
{
|
||||
if (self::$taxRules !== null && isset(self::$taxRules["$type-$countryId-$zoneId"])) {
|
||||
return self::$taxRules["$type-$countryId-$zoneId"];
|
||||
}
|
||||
|
||||
foreach ($tax_query->rows as $result) {
|
||||
$this->tax_rates[$result['tax_class_id']][$result['tax_rate_id']] = array(
|
||||
'tax_rate_id' => $result['tax_rate_id'],
|
||||
'name' => $result['name'],
|
||||
'rate' => $result['rate'],
|
||||
'type' => $result['type'],
|
||||
'priority' => $result['priority']
|
||||
$customerGroupId = (int)system_setting('base.config_customer_group_id');
|
||||
$sqlBuilder = \DB::table('tax_rule')
|
||||
->leftJoin('tax_rate', 'tax_rule.tax_rate_id', '=', 'tax_rate.tax_rate_id')
|
||||
->join('tax_rate_to_customer_group', 'tax_rate.tax_rate_id', '=', 'tax_rate_to_customer_group.tax_rate_id')
|
||||
->leftJoin('zone_to_geo_zone', 'tax_rate.geo_zone_id', '=', 'zone_to_geo_zone.geo_zone_id')
|
||||
->leftJoin('geo_zone', 'tax_rate.geo_zone_id', '=', 'geo_zone.geo_zone_id')
|
||||
->select('tax_rule.*', 'tax_rate.*')
|
||||
->where('tax_rule.based', $type)
|
||||
->where('tax_rate_to_customer_group.customer_group_id', $customerGroupId)
|
||||
->where('zone_to_geo_zone.country_id', $countryId)
|
||||
->where(function ($query) use ($zoneId) {
|
||||
$query->where('zone_to_geo_zone.zone_id', '=', 0)
|
||||
->orWhere('zone_to_geo_zone.zone_id', '=', (int)$zoneId);
|
||||
})
|
||||
->orderBy('tax_rule.priority', 'asc');
|
||||
$data = $sqlBuilder->get();
|
||||
self::$taxRules["$type-$countryId-$zoneId"] = $data;
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function setAddress($type, $countryId, $zoneId)
|
||||
{
|
||||
if (!in_array($type, self::AVAILABLE_TYPES)) {
|
||||
throw new \Exception('invalid tax types');
|
||||
}
|
||||
|
||||
$data = $this->getTaxRules($type, $countryId, $zoneId);
|
||||
|
||||
foreach ($data as $result) {
|
||||
$this->taxRates[$result->tax_class_id][$result->tax_rate_id] = array(
|
||||
'tax_rate_id' => $result->tax_rate_id,
|
||||
'name' => $result->name,
|
||||
'rate' => $result->rate,
|
||||
'type' => $result->type,
|
||||
'priority' => $result->priority
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function setPaymentAddress($country_id, $zone_id) {
|
||||
$tax_query = $this->db->query("SELECT tr1.tax_class_id, tr2.tax_rate_id, tr2.name, tr2.rate, tr2.type, tr1.priority FROM " . DB_PREFIX . "tax_rule tr1 LEFT JOIN " . DB_PREFIX . "tax_rate tr2 ON (tr1.tax_rate_id = tr2.tax_rate_id) INNER JOIN " . DB_PREFIX . "tax_rate_to_customer_group tr2cg ON (tr2.tax_rate_id = tr2cg.tax_rate_id) LEFT JOIN " . DB_PREFIX . "zone_to_geo_zone z2gz ON (tr2.geo_zone_id = z2gz.geo_zone_id) LEFT JOIN " . DB_PREFIX . "geo_zone gz ON (tr2.geo_zone_id = gz.geo_zone_id) WHERE tr1.based = 'payment' AND tr2cg.customer_group_id = '" . (int)$this->config->get('config_customer_group_id') . "' AND z2gz.country_id = '" . (int)$country_id . "' AND (z2gz.zone_id = '0' OR z2gz.zone_id = '" . (int)$zone_id . "') ORDER BY tr1.priority ASC");
|
||||
|
||||
foreach ($tax_query->rows as $result) {
|
||||
$this->tax_rates[$result['tax_class_id']][$result['tax_rate_id']] = array(
|
||||
'tax_rate_id' => $result['tax_rate_id'],
|
||||
'name' => $result['name'],
|
||||
'rate' => $result['rate'],
|
||||
'type' => $result['type'],
|
||||
'priority' => $result['priority']
|
||||
);
|
||||
}
|
||||
public function unsetRates()
|
||||
{
|
||||
$this->taxRates = array();
|
||||
}
|
||||
|
||||
public function setStoreAddress($country_id, $zone_id) {
|
||||
$tax_query = $this->db->query("SELECT tr1.tax_class_id, tr2.tax_rate_id, tr2.name, tr2.rate, tr2.type, tr1.priority FROM " . DB_PREFIX . "tax_rule tr1 LEFT JOIN " . DB_PREFIX . "tax_rate tr2 ON (tr1.tax_rate_id = tr2.tax_rate_id) INNER JOIN " . DB_PREFIX . "tax_rate_to_customer_group tr2cg ON (tr2.tax_rate_id = tr2cg.tax_rate_id) LEFT JOIN " . DB_PREFIX . "zone_to_geo_zone z2gz ON (tr2.geo_zone_id = z2gz.geo_zone_id) LEFT JOIN " . DB_PREFIX . "geo_zone gz ON (tr2.geo_zone_id = gz.geo_zone_id) WHERE tr1.based = 'store' AND tr2cg.customer_group_id = '" . (int)$this->config->get('config_customer_group_id') . "' AND z2gz.country_id = '" . (int)$country_id . "' AND (z2gz.zone_id = '0' OR z2gz.zone_id = '" . (int)$zone_id . "') ORDER BY tr1.priority ASC");
|
||||
|
||||
foreach ($tax_query->rows as $result) {
|
||||
$this->tax_rates[$result['tax_class_id']][$result['tax_rate_id']] = array(
|
||||
'tax_rate_id' => $result['tax_rate_id'],
|
||||
'name' => $result['name'],
|
||||
'rate' => $result['rate'],
|
||||
'type' => $result['type'],
|
||||
'priority' => $result['priority']
|
||||
);
|
||||
}
|
||||
public function setShippingAddress($countryId, $zoneId)
|
||||
{
|
||||
$this->setAddress('shipping', $countryId, $zoneId);
|
||||
}
|
||||
|
||||
public function calculate($value, $tax_class_id, $calculate = true) {
|
||||
if ($tax_class_id && $calculate) {
|
||||
public function setPaymentAddress($countryId, $zoneId)
|
||||
{
|
||||
$this->setAddress('payment', $countryId, $zoneId);
|
||||
}
|
||||
|
||||
public function setStoreAddress($countryId, $zoneId)
|
||||
{
|
||||
$this->setAddress('store', $countryId, $zoneId);
|
||||
}
|
||||
|
||||
/**
|
||||
* $tax = \App\Models\Library\Tax::getInstance();
|
||||
* $tax->setShippingAddress(1, 0);
|
||||
* $tax->calculate(123.45, 9, $tax->config->getValue('config_tax'))
|
||||
*
|
||||
* @param $value
|
||||
* @param $taxClassId
|
||||
* @param bool|true $calculate
|
||||
* @return mixed
|
||||
*/
|
||||
public function calculate($value, $taxClassId, $calculate = true)
|
||||
{
|
||||
if ($taxClassId && $calculate) {
|
||||
$amount = 0;
|
||||
|
||||
$tax_rates = $this->getRates($value, $tax_class_id);
|
||||
|
||||
foreach ($tax_rates as $tax_rate) {
|
||||
$taxRates = $this->getRates($value, $taxClassId);
|
||||
foreach ($taxRates as $taxRate) {
|
||||
if ($calculate != 'P' && $calculate != 'F') {
|
||||
$amount += $tax_rate['amount'];
|
||||
} elseif ($tax_rate['type'] == $calculate) {
|
||||
$amount += $tax_rate['amount'];
|
||||
$amount += $taxRate['amount'];
|
||||
} elseif ($taxRate['type'] == $calculate) {
|
||||
$amount += $taxRate['amount'];
|
||||
}
|
||||
}
|
||||
|
||||
return $value + $amount;
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function getTax($value, $tax_class_id) {
|
||||
public function getTax($value, $taxClassId)
|
||||
{
|
||||
$amount = 0;
|
||||
|
||||
$tax_rates = $this->getRates($value, $tax_class_id);
|
||||
|
||||
foreach ($tax_rates as $tax_rate) {
|
||||
$amount += $tax_rate['amount'];
|
||||
$taxRates = $this->getRates($value, $taxClassId);
|
||||
foreach ($taxRates as $taxRate) {
|
||||
$amount += $taxRate['amount'];
|
||||
}
|
||||
|
||||
return $amount;
|
||||
}
|
||||
|
||||
public function getRateName($tax_rate_id) {
|
||||
$tax_query = $this->db->query("SELECT name FROM " . DB_PREFIX . "tax_rate WHERE tax_rate_id = '" . (int)$tax_rate_id . "'");
|
||||
|
||||
if ($tax_query->num_rows) {
|
||||
return $tax_query->row['name'];
|
||||
public function getRateName($taxRateId)
|
||||
{
|
||||
$taxRate = TaxRate::query()->find($taxRateId);
|
||||
if ($taxRate) {
|
||||
return $taxRate->name;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function getRates($value, $tax_class_id) {
|
||||
$tax_rate_data = array();
|
||||
public function getRates($value, $taxClassId)
|
||||
{
|
||||
$taxRateData = array();
|
||||
|
||||
if (isset($this->tax_rates[$tax_class_id])) {
|
||||
foreach ($this->tax_rates[$tax_class_id] as $tax_rate) {
|
||||
if (isset($tax_rate_data[$tax_rate['tax_rate_id']])) {
|
||||
$amount = $tax_rate_data[$tax_rate['tax_rate_id']]['amount'];
|
||||
if (isset($this->taxRates[$taxClassId])) {
|
||||
foreach ($this->taxRates[$taxClassId] as $taxRate) {
|
||||
if (isset($taxRateData[$taxRate['tax_rate_id']])) {
|
||||
$amount = $taxRateData[$taxRate['tax_rate_id']]['amount'];
|
||||
} else {
|
||||
$amount = 0;
|
||||
}
|
||||
|
||||
if ($tax_rate['type'] == 'F') {
|
||||
$amount += $tax_rate['rate'];
|
||||
} elseif ($tax_rate['type'] == 'P') {
|
||||
$amount += ($value / 100 * $tax_rate['rate']);
|
||||
if ($taxRate['type'] == 'F') {
|
||||
$amount += $taxRate['rate'];
|
||||
} elseif ($taxRate['type'] == 'P') {
|
||||
$amount += ($value / 100 * $taxRate['rate']);
|
||||
}
|
||||
|
||||
$tax_rate_data[$tax_rate['tax_rate_id']] = array(
|
||||
'tax_rate_id' => $tax_rate['tax_rate_id'],
|
||||
'name' => $tax_rate['name'],
|
||||
'rate' => $tax_rate['rate'],
|
||||
'type' => $tax_rate['type'],
|
||||
'amount' => $amount
|
||||
$taxRateData[$taxRate['tax_rate_id']] = array(
|
||||
'tax_rate_id' => $taxRate['tax_rate_id'],
|
||||
'name' => $taxRate['name'],
|
||||
'rate' => $taxRate['rate'],
|
||||
'type' => $taxRate['type'],
|
||||
'amount' => $amount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $tax_rate_data;
|
||||
return $taxRateData;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue