1: <?php
2: namespace Opencart\System\Library\Cart;
3: /**
4: * Class Tax
5: *
6: * @package Opencart\System\Library\Cart
7: */
8: class Tax {
9: /**
10: * @var object
11: */
12: private object $db;
13: /**
14: * @var object
15: */
16: private object $config;
17: /**
18: * @var array<int, array<int, array<string, mixed>>>
19: */
20: private array $tax_rates = [];
21:
22: /**
23: * Constructor
24: *
25: * @param \Opencart\System\Engine\Registry $registry
26: */
27: public function __construct(\Opencart\System\Engine\Registry $registry) {
28: $this->db = $registry->get('db');
29: $this->config = $registry->get('config');
30: }
31:
32: /**
33: * setShippingAddress
34: *
35: * @param int $country_id
36: * @param int $zone_id
37: *
38: * @return void
39: */
40: public function setShippingAddress(int $country_id, int $zone_id): void {
41: $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");
42:
43: foreach ($tax_query->rows as $result) {
44: $this->tax_rates[$result['tax_class_id']][$result['tax_rate_id']] = [
45: 'tax_rate_id' => $result['tax_rate_id'],
46: 'name' => $result['name'],
47: 'rate' => $result['rate'],
48: 'type' => $result['type'],
49: 'priority' => $result['priority']
50: ];
51: }
52: }
53:
54: /**
55: * setPaymentAddress
56: *
57: * @param int $country_id
58: * @param int $zone_id
59: *
60: * @return void
61: */
62: public function setPaymentAddress(int $country_id, int $zone_id): void {
63: $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");
64:
65: foreach ($tax_query->rows as $result) {
66: $this->tax_rates[$result['tax_class_id']][$result['tax_rate_id']] = [
67: 'tax_rate_id' => $result['tax_rate_id'],
68: 'name' => $result['name'],
69: 'rate' => $result['rate'],
70: 'type' => $result['type'],
71: 'priority' => $result['priority']
72: ];
73: }
74: }
75:
76: /**
77: * setStoreAddress
78: *
79: * @param int $country_id
80: * @param int $zone_id
81: *
82: * @return void
83: */
84: public function setStoreAddress(int $country_id, int $zone_id): void {
85: $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");
86:
87: foreach ($tax_query->rows as $result) {
88: $this->tax_rates[$result['tax_class_id']][$result['tax_rate_id']] = [
89: 'tax_rate_id' => $result['tax_rate_id'],
90: 'name' => $result['name'],
91: 'rate' => $result['rate'],
92: 'type' => $result['type'],
93: 'priority' => $result['priority']
94: ];
95: }
96: }
97:
98: /**
99: * Calculate
100: *
101: * @param float $value
102: * @param int $tax_class_id
103: * @param bool $calculate
104: *
105: * @return float
106: */
107: public function calculate(float $value, int $tax_class_id, bool $calculate = true): float {
108: if ($tax_class_id && $calculate) {
109: $amount = 0;
110:
111: $tax_rates = $this->getRates($value, $tax_class_id);
112:
113: foreach ($tax_rates as $tax_rate) {
114: $amount += $tax_rate['amount'];
115: }
116:
117: return $value + $amount;
118: } else {
119: return $value;
120: }
121: }
122:
123: /**
124: * getTax
125: *
126: * @param float $value
127: * @param int $tax_class_id
128: *
129: * @return float
130: */
131: public function getTax(float $value, int $tax_class_id): float {
132: $amount = 0;
133:
134: $tax_rates = $this->getRates($value, $tax_class_id);
135:
136: foreach ($tax_rates as $tax_rate) {
137: $amount += $tax_rate['amount'];
138: }
139:
140: return $amount;
141: }
142:
143: /**
144: * getRateName
145: *
146: * @param int $tax_rate_id
147: *
148: * @return false|string
149: */
150: public function getRateName(int $tax_rate_id) {
151: $tax_query = $this->db->query("SELECT `name` FROM `" . DB_PREFIX . "tax_rate` WHERE `tax_rate_id` = '" . (int)$tax_rate_id . "'");
152:
153: if ($tax_query->num_rows) {
154: return $tax_query->row['name'];
155: } else {
156: return false;
157: }
158: }
159:
160: /**
161: * getRates
162: *
163: * @param float $value
164: * @param int $tax_class_id
165: *
166: * @return array<int, array<string, mixed>>
167: */
168: public function getRates(float $value, int $tax_class_id): array {
169: $tax_rate_data = [];
170:
171: if (isset($this->tax_rates[$tax_class_id])) {
172: foreach ($this->tax_rates[$tax_class_id] as $tax_rate) {
173: if (isset($tax_rate_data[$tax_rate['tax_rate_id']])) {
174: $amount = $tax_rate_data[$tax_rate['tax_rate_id']]['amount'];
175: } else {
176: $amount = 0;
177: }
178:
179: if ($tax_rate['type'] == 'F') {
180: $amount += $tax_rate['rate'];
181: } elseif ($tax_rate['type'] == 'P') {
182: $amount += ($value / 100 * $tax_rate['rate']);
183: }
184:
185: $tax_rate_data[$tax_rate['tax_rate_id']] = [
186: 'tax_rate_id' => $tax_rate['tax_rate_id'],
187: 'name' => $tax_rate['name'],
188: 'rate' => $tax_rate['rate'],
189: 'type' => $tax_rate['type'],
190: 'amount' => $amount
191: ];
192: }
193: }
194:
195: return $tax_rate_data;
196: }
197:
198: /**
199: * Clear
200: *
201: * @return void
202: */
203: public function clear(): void {
204: $this->tax_rates = [];
205: }
206: }
207: