1: <?php
2: namespace Opencart\System\Library\Cart;
3: /**
4: * Class Cart
5: *
6: * @package Opencart\System\Library\Cart
7: */
8: class Cart {
9: /**
10: * @var object
11: */
12: private object $db;
13: /**
14: * @var object
15: */
16: private object $config;
17: /**
18: * @var object
19: */
20: private object $customer;
21: /**
22: * @var object
23: */
24: private object $session;
25: /**
26: * @var object
27: */
28: private object $tax;
29: /**
30: * @var object
31: */
32: private object $weight;
33: /**
34: * @var array<int, array<string, mixed>>
35: */
36: private array $data = [];
37:
38: /**
39: * Constructor
40: *
41: * @param \Opencart\System\Engine\Registry $registry
42: */
43: public function __construct(\Opencart\System\Engine\Registry $registry) {
44: $this->db = $registry->get('db');
45: $this->config = $registry->get('config');
46: $this->customer = $registry->get('customer');
47: $this->session = $registry->get('session');
48: $this->tax = $registry->get('tax');
49: $this->weight = $registry->get('weight');
50:
51: // Remove all the expired carts with no customer ID
52: $this->db->query("DELETE FROM `" . DB_PREFIX . "cart` WHERE (`api_id` > '0' OR `customer_id` = '0') AND `date_added` < DATE_SUB(NOW(), INTERVAL 1 HOUR)");
53:
54: if ($this->customer->isLogged()) {
55: // We want to change the session ID on all the old items in the customers cart
56: $this->db->query("UPDATE `" . DB_PREFIX . "cart` SET `session_id` = '" . $this->db->escape($this->session->getId()) . "' WHERE `api_id` = '0' AND `customer_id` = '" . (int)$this->customer->getId() . "'");
57:
58: // Once the customer is logged in we want to update the customers cart
59: $cart_query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "cart` WHERE `api_id` = '0' AND `customer_id` = '0' AND `session_id` = '" . $this->db->escape($this->session->getId()) . "'");
60:
61: foreach ($cart_query->rows as $cart) {
62: $this->db->query("DELETE FROM `" . DB_PREFIX . "cart` WHERE `cart_id` = '" . (int)$cart['cart_id'] . "'");
63:
64: // The advantage of using $this->add is that it will check if the products already exist and increase the quantity if necessary.
65: $this->add($cart['product_id'], $cart['quantity'], json_decode($cart['option'], true), $cart['subscription_plan_id'], $cart['override'], $cart['price']);
66: }
67: }
68:
69: // Populate the cart data
70: $this->data = $this->getProducts();
71: }
72:
73: /**
74: * getProducts
75: *
76: * @return array<int, array<string, mixed>>
77: */
78: public function getProducts(): array {
79: if (!$this->data) {
80: $cart_query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "cart` WHERE `api_id` = '" . (isset($this->session->data['api_id']) ? (int)$this->session->data['api_id'] : 0) . "' AND `customer_id` = '" . (int)$this->customer->getId() . "' AND `session_id` = '" . $this->db->escape($this->session->getId()) . "'");
81:
82: foreach ($cart_query->rows as $cart) {
83: $stock = true;
84:
85: $product_query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "product_to_store` `p2s` LEFT JOIN `" . DB_PREFIX . "product` `p` ON (`p2s`.`product_id` = `p`.`product_id`) LEFT JOIN `" . DB_PREFIX . "product_description` `pd` ON (`p`.`product_id` = `pd`.`product_id`) WHERE `p2s`.`store_id` = '" . (int)$this->config->get('config_store_id') . "' AND `p2s`.`product_id` = '" . (int)$cart['product_id'] . "' AND `pd`.`language_id` = '" . (int)$this->config->get('config_language_id') . "' AND `p`.`date_available` <= NOW() AND `p`.`status` = '1'");
86:
87: if ($product_query->num_rows && ($cart['quantity'] > 0)) {
88: $option_price = 0;
89: $option_points = 0;
90: $option_weight = 0;
91:
92: $option_data = [];
93:
94: $product_options = (array)json_decode($cart['option'], true);
95:
96: // Merge variant code with options
97: $variant = json_decode($product_query->row['variant'], true);
98:
99: if ($variant) {
100: foreach ($variant as $key => $value) {
101: $product_options[$key] = $value;
102: }
103: }
104:
105: foreach ($product_options as $product_option_id => $value) {
106: if (!$product_query->row['master_id']) {
107: $product_id = $cart['product_id'];
108: } else {
109: $product_id = $product_query->row['master_id'];
110: }
111:
112: $option_query = $this->db->query("SELECT `po`.`product_option_id`, `po`.`option_id`, `od`.`name`, `o`.`type` FROM `" . DB_PREFIX . "product_option` `po` LEFT JOIN `" . DB_PREFIX . "option` `o` ON (`po`.`option_id` = `o`.`option_id`) LEFT JOIN `" . DB_PREFIX . "option_description` `od` ON (`o`.`option_id` = `od`.`option_id`) WHERE `po`.`product_option_id` = '" . (int)$product_option_id . "' AND `po`.`product_id` = '" . (int)$product_id . "' AND `od`.`language_id` = '" . (int)$this->config->get('config_language_id') . "'");
113:
114: if ($option_query->num_rows) {
115: if ($option_query->row['type'] == 'select' || $option_query->row['type'] == 'radio') {
116: $option_value_query = $this->db->query("SELECT `pov`.`option_value_id`, `ovd`.`name`, `pov`.`quantity`, `pov`.`subtract`, `pov`.`price`, `pov`.`price_prefix`, `pov`.`points`, `pov`.`points_prefix`, `pov`.`weight`, `pov`.`weight_prefix` FROM `" . DB_PREFIX . "product_option_value` `pov` LEFT JOIN `" . DB_PREFIX . "option_value` `ov` ON (`pov`.`option_value_id` = `ov`.`option_value_id`) LEFT JOIN `" . DB_PREFIX . "option_value_description` `ovd` ON (`ov`.`option_value_id` = `ovd`.`option_value_id`) WHERE `pov`.`product_option_value_id` = '" . (int)$value . "' AND `pov`.`product_option_id` = '" . (int)$product_option_id . "' AND `ovd`.`language_id` = '" . (int)$this->config->get('config_language_id') . "'");
117:
118: if ($option_value_query->num_rows) {
119: if ($option_value_query->row['price_prefix'] == '+') {
120: $option_price += $option_value_query->row['price'];
121: } elseif ($option_value_query->row['price_prefix'] == '-') {
122: $option_price -= $option_value_query->row['price'];
123: }
124:
125: if ($option_value_query->row['points_prefix'] == '+') {
126: $option_points += $option_value_query->row['points'];
127: } elseif ($option_value_query->row['points_prefix'] == '-') {
128: $option_points -= $option_value_query->row['points'];
129: }
130:
131: if ($option_value_query->row['weight_prefix'] == '+') {
132: $option_weight += $option_value_query->row['weight'];
133: } elseif ($option_value_query->row['weight_prefix'] == '-') {
134: $option_weight -= $option_value_query->row['weight'];
135: }
136:
137: if ($option_value_query->row['subtract'] && (!$option_value_query->row['quantity'] || ($option_value_query->row['quantity'] < $cart['quantity']))) {
138: $stock = false;
139: }
140:
141: $option_data[] = [
142: 'product_option_id' => $product_option_id,
143: 'product_option_value_id' => $value,
144: 'option_id' => $option_query->row['option_id'],
145: 'option_value_id' => $option_value_query->row['option_value_id'],
146: 'name' => $option_query->row['name'],
147: 'value' => $option_value_query->row['name'],
148: 'type' => $option_query->row['type'],
149: 'quantity' => $option_value_query->row['quantity'],
150: 'subtract' => $option_value_query->row['subtract'],
151: 'price' => $option_value_query->row['price'],
152: 'price_prefix' => $option_value_query->row['price_prefix'],
153: 'points' => $option_value_query->row['points'],
154: 'points_prefix' => $option_value_query->row['points_prefix'],
155: 'weight' => $option_value_query->row['weight'],
156: 'weight_prefix' => $option_value_query->row['weight_prefix']
157: ];
158: }
159: } elseif ($option_query->row['type'] == 'checkbox' && is_array($value)) {
160: foreach ($value as $product_option_value_id) {
161: $option_value_query = $this->db->query("SELECT `pov`.`option_value_id`, `pov`.`quantity`, `pov`.`subtract`, `pov`.`price`, `pov`.`price_prefix`, `pov`.`points`, `pov`.`points_prefix`, `pov`.`weight`, `pov`.`weight_prefix`, `ovd`.`name` FROM `" . DB_PREFIX . "product_option_value` `pov` LEFT JOIN `" . DB_PREFIX . "option_value_description` `ovd` ON (`pov`.`option_value_id` = `ovd`.option_value_id) WHERE `pov`.product_option_value_id = '" . (int)$product_option_value_id . "' AND `pov`.product_option_id = '" . (int)$product_option_id . "' AND `ovd`.language_id = '" . (int)$this->config->get('config_language_id') . "'");
162:
163: if ($option_value_query->num_rows) {
164: if ($option_value_query->row['price_prefix'] == '+') {
165: $option_price += $option_value_query->row['price'];
166: } elseif ($option_value_query->row['price_prefix'] == '-') {
167: $option_price -= $option_value_query->row['price'];
168: }
169:
170: if ($option_value_query->row['points_prefix'] == '+') {
171: $option_points += $option_value_query->row['points'];
172: } elseif ($option_value_query->row['points_prefix'] == '-') {
173: $option_points -= $option_value_query->row['points'];
174: }
175:
176: if ($option_value_query->row['weight_prefix'] == '+') {
177: $option_weight += $option_value_query->row['weight'];
178: } elseif ($option_value_query->row['weight_prefix'] == '-') {
179: $option_weight -= $option_value_query->row['weight'];
180: }
181:
182: if ($option_value_query->row['subtract'] && (!$option_value_query->row['quantity'] || ($option_value_query->row['quantity'] < $cart['quantity']))) {
183: $stock = false;
184: }
185:
186: $option_data[] = [
187: 'product_option_id' => $product_option_id,
188: 'product_option_value_id' => $product_option_value_id,
189: 'option_id' => $option_query->row['option_id'],
190: 'option_value_id' => $option_value_query->row['option_value_id'],
191: 'name' => $option_query->row['name'],
192: 'value' => $option_value_query->row['name'],
193: 'type' => $option_query->row['type'],
194: 'quantity' => $option_value_query->row['quantity'],
195: 'subtract' => $option_value_query->row['subtract'],
196: 'price' => $option_value_query->row['price'],
197: 'price_prefix' => $option_value_query->row['price_prefix'],
198: 'points' => $option_value_query->row['points'],
199: 'points_prefix' => $option_value_query->row['points_prefix'],
200: 'weight' => $option_value_query->row['weight'],
201: 'weight_prefix' => $option_value_query->row['weight_prefix']
202: ];
203: }
204: }
205: } elseif ($option_query->row['type'] == 'text' || $option_query->row['type'] == 'textarea' || $option_query->row['type'] == 'file' || $option_query->row['type'] == 'date' || $option_query->row['type'] == 'datetime' || $option_query->row['type'] == 'time') {
206: $option_data[] = [
207: 'product_option_id' => $product_option_id,
208: 'product_option_value_id' => '',
209: 'option_id' => $option_query->row['option_id'],
210: 'option_value_id' => '',
211: 'name' => $option_query->row['name'],
212: 'value' => $value,
213: 'type' => $option_query->row['type'],
214: 'quantity' => '',
215: 'subtract' => '',
216: 'price' => '',
217: 'price_prefix' => '',
218: 'points' => '',
219: 'points_prefix' => '',
220: 'weight' => '',
221: 'weight_prefix' => ''
222: ];
223: }
224: }
225: }
226:
227: $price = $product_query->row['price'];
228:
229: // Product Discounts
230: $discount_quantity = 0;
231:
232: foreach ($cart_query->rows as $cart_2) {
233: if ($cart_2['product_id'] == $cart['product_id']) {
234: $discount_quantity += $cart_2['quantity'];
235: }
236: }
237:
238: $product_discount_query = $this->db->query("SELECT `price` FROM `" . DB_PREFIX . "product_discount` WHERE `product_id` = '" . (int)$cart['product_id'] . "' AND `customer_group_id` = '" . (int)$this->config->get('config_customer_group_id') . "' AND `quantity` <= '" . (int)$discount_quantity . "' AND ((`date_start` = '0000-00-00' OR `date_start` < NOW()) AND (`date_end` = '0000-00-00' OR `date_end` > NOW())) ORDER BY `quantity` DESC, `priority` ASC, `price` ASC LIMIT 1");
239:
240: if ($product_discount_query->num_rows) {
241: $price = $product_discount_query->row['price'];
242: }
243:
244: // Product Specials
245: $product_special_query = $this->db->query("SELECT `price` FROM `" . DB_PREFIX . "product_special` WHERE `product_id` = '" . (int)$cart['product_id'] . "' AND `customer_group_id` = '" . (int)$this->config->get('config_customer_group_id') . "' AND ((`date_start` = '0000-00-00' OR `date_start` < NOW()) AND (`date_end` = '0000-00-00' OR `date_end` > NOW())) ORDER BY `priority` ASC, `price` ASC LIMIT 1");
246:
247: if ($product_special_query->num_rows) {
248: $price = $product_special_query->row['price'];
249: }
250:
251: $product_total = 0;
252:
253: foreach ($cart_query->rows as $cart_2) {
254: if ($cart_2['product_id'] == $cart['product_id']) {
255: $product_total += $cart_2['quantity'];
256: }
257: }
258:
259: if ($product_query->row['minimum'] > $product_total) {
260: $minimum = false;
261: } else {
262: $minimum = true;
263: }
264:
265: // Reward Points
266: $product_reward_query = $this->db->query("SELECT `points` FROM `" . DB_PREFIX . "product_reward` WHERE `product_id` = '" . (int)$cart['product_id'] . "' AND `customer_group_id` = '" . (int)$this->config->get('config_customer_group_id') . "'");
267:
268: if ($product_reward_query->num_rows) {
269: $reward = $product_reward_query->row['points'];
270: } else {
271: $reward = 0;
272: }
273:
274: // Downloads
275: $download_data = [];
276:
277: $download_query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "product_to_download` `p2d` LEFT JOIN `" . DB_PREFIX . "download` `d` ON (`p2d`.`download_id` = `d`.`download_id`) LEFT JOIN `" . DB_PREFIX . "download_description` `dd` ON (`d`.`download_id` = `dd`.`download_id`) WHERE `p2d`.`product_id` = '" . (int)$cart['product_id'] . "' AND `dd`.`language_id` = '" . (int)$this->config->get('config_language_id') . "'");
278:
279: foreach ($download_query->rows as $download) {
280: $download_data[] = [
281: 'download_id' => $download['download_id'],
282: 'name' => $download['name'],
283: 'filename' => $download['filename'],
284: 'mask' => $download['mask']
285: ];
286: }
287:
288: // Stock
289: if (!$product_query->row['quantity'] || ($product_query->row['quantity'] < $cart['quantity'])) {
290: $stock = false;
291: }
292:
293: $subscription_data = [];
294:
295: $subscription_query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "product_subscription` `ps` LEFT JOIN `" . DB_PREFIX . "subscription_plan` `sp` ON (`ps`.`subscription_plan_id` = `sp`.`subscription_plan_id`) LEFT JOIN `" . DB_PREFIX . "subscription_plan_description` `spd` ON (`sp`.`subscription_plan_id` = `spd`.`subscription_plan_id`) WHERE `ps`.`product_id` = '" . (int)$cart['product_id'] . "' AND `ps`.`subscription_plan_id` = '" . (int)$cart['subscription_plan_id'] . "' AND `ps`.`customer_group_id` = '" . (int)$this->config->get('config_customer_group_id') . "' AND `spd`.`language_id` = '" . (int)$this->config->get('config_language_id') . "' AND `sp`.`status` = '1'");
296:
297: if ($subscription_query->num_rows) {
298: $price = $subscription_query->row['price'];
299:
300: if ($subscription_query->row['trial_status']) {
301: $price = $subscription_query->row['trial_price'];
302: }
303:
304: $subscription_data = [
305: 'subscription_plan_id' => $subscription_query->row['subscription_plan_id'],
306: 'name' => $subscription_query->row['name'],
307: 'trial_price' => $subscription_query->row['trial_price'],
308: 'trial_frequency' => $subscription_query->row['trial_frequency'],
309: 'trial_cycle' => $subscription_query->row['trial_cycle'],
310: 'trial_duration' => $subscription_query->row['trial_duration'],
311: 'trial_remaining' => $subscription_query->row['trial_duration'],
312: 'trial_status' => $subscription_query->row['trial_status'],
313: 'price' => $subscription_query->row['price'],
314: 'frequency' => $subscription_query->row['frequency'],
315: 'cycle' => $subscription_query->row['cycle'],
316: 'duration' => $subscription_query->row['duration'],
317: 'remaining' => $subscription_query->row['duration']
318: ];
319: }
320:
321: if ($cart['override']) {
322: $price = $cart['price'];
323: }
324:
325: $this->data[$cart['cart_id']] = [
326: 'cart_id' => $cart['cart_id'],
327: 'product_id' => $product_query->row['product_id'],
328: 'master_id' => $product_query->row['master_id'],
329: 'name' => $product_query->row['name'],
330: 'model' => $product_query->row['model'],
331: 'shipping' => $product_query->row['shipping'],
332: 'image' => $product_query->row['image'],
333: 'option' => $option_data,
334: 'subscription' => $subscription_data,
335: 'download' => $download_data,
336: 'quantity' => $cart['quantity'],
337: 'minimum' => $minimum,
338: 'subtract' => $product_query->row['subtract'],
339: 'stock' => $stock,
340: 'price' => ($price + $option_price),
341: 'total' => ($price + $option_price) * $cart['quantity'],
342: 'reward' => $reward * $cart['quantity'],
343: 'points' => ($product_query->row['points'] ? ($product_query->row['points'] + $option_points) * $cart['quantity'] : 0),
344: 'tax_class_id' => $product_query->row['tax_class_id'],
345: 'weight' => ($product_query->row['weight'] + $option_weight) * $cart['quantity'],
346: 'weight_class_id' => $product_query->row['weight_class_id'],
347: 'length' => $product_query->row['length'],
348: 'width' => $product_query->row['width'],
349: 'height' => $product_query->row['height'],
350: 'length_class_id' => $product_query->row['length_class_id']
351: ];
352: } else {
353: $this->remove($cart['cart_id']);
354: }
355: }
356: }
357:
358: return $this->data;
359: }
360:
361: /**
362: * Add
363: *
364: * @param int $product_id
365: * @param int $quantity
366: * @param array<mixed> $option
367: * @param int $subscription_plan_id
368: * @param bool $override
369: * @param float $price
370: *
371: * @return void
372: */
373: public function add(int $product_id, int $quantity = 1, array $option = [], int $subscription_plan_id = 0, bool $override = false, float $price = 0): void {
374: $query = $this->db->query("SELECT COUNT(*) AS `total` FROM `" . DB_PREFIX . "cart` WHERE `api_id` = '" . (isset($this->session->data['api_id']) ? (int)$this->session->data['api_id'] : 0) . "' AND `customer_id` = '" . (int)$this->customer->getId() . "' AND `session_id` = '" . $this->db->escape($this->session->getId()) . "' AND `product_id` = '" . (int)$product_id . "' AND `subscription_plan_id` = '" . (int)$subscription_plan_id . "' AND `option` = '" . $this->db->escape(json_encode($option)) . "'");
375:
376: if (!$query->row['total']) {
377: $this->db->query("INSERT INTO `" . DB_PREFIX . "cart` SET `api_id` = '" . (isset($this->session->data['api_id']) ? (int)$this->session->data['api_id'] : 0) . "', `customer_id` = '" . (int)$this->customer->getId() . "', `session_id` = '" . $this->db->escape($this->session->getId()) . "', `product_id` = '" . (int)$product_id . "', `subscription_plan_id` = '" . (int)$subscription_plan_id . "', `option` = '" . $this->db->escape(json_encode($option)) . "', `quantity` = '" . (int)$quantity . "', `override` = '" . (bool)$override . "', `price` = '" . (float)($override ? $price : 0) . "', `date_added` = NOW()");
378: } else {
379: $this->db->query("UPDATE `" . DB_PREFIX . "cart` SET `quantity` = (`quantity` + " . (int)$quantity . ") WHERE `api_id` = '" . (isset($this->session->data['api_id']) ? (int)$this->session->data['api_id'] : 0) . "' AND `customer_id` = '" . (int)$this->customer->getId() . "' AND `session_id` = '" . $this->db->escape($this->session->getId()) . "' AND `product_id` = '" . (int)$product_id . "' AND `subscription_plan_id` = '" . (int)$subscription_plan_id . "' AND `option` = '" . $this->db->escape(json_encode($option)) . "'");
380: }
381:
382: // Clear cart data
383: $this->data = [];
384:
385: // Populate the cart data
386: $this->data = $this->getProducts();
387: }
388:
389: /**
390: * Update
391: *
392: * @param int $cart_id
393: * @param int $quantity
394: *
395: * @return void
396: */
397: public function update(int $cart_id, int $quantity): void {
398: $this->db->query("UPDATE `" . DB_PREFIX . "cart` SET `quantity` = '" . (int)$quantity . "' WHERE `cart_id` = '" . (int)$cart_id . "' AND `api_id` = '" . (isset($this->session->data['api_id']) ? (int)$this->session->data['api_id'] : 0) . "' AND `customer_id` = '" . (int)$this->customer->getId() . "' AND `session_id` = '" . $this->db->escape($this->session->getId()) . "'");
399:
400: // Clear cart data
401: $this->data = [];
402:
403: // Populate the cart data
404: $this->data = $this->getProducts();
405: }
406:
407: /**
408: * Has
409: *
410: * @param int $cart_id
411: *
412: * @return bool
413: */
414: public function has(int $cart_id): bool {
415: return isset($this->data[$cart_id]);
416: }
417:
418: /**
419: * Remove
420: *
421: * @param int $cart_id
422: *
423: * @return void
424: */
425: public function remove(int $cart_id): void {
426: $this->db->query("DELETE FROM `" . DB_PREFIX . "cart` WHERE `cart_id` = '" . (int)$cart_id . "' AND `api_id` = '" . (isset($this->session->data['api_id']) ? (int)$this->session->data['api_id'] : 0) . "' AND `customer_id` = '" . (int)$this->customer->getId() . "' AND `session_id` = '" . $this->db->escape($this->session->getId()) . "'");
427:
428: unset($this->data[$cart_id]);
429: }
430:
431: /**
432: * Clear
433: *
434: * @return void
435: */
436: public function clear(): void {
437: $this->db->query("DELETE FROM `" . DB_PREFIX . "cart` WHERE `api_id` = '" . (isset($this->session->data['api_id']) ? (int)$this->session->data['api_id'] : 0) . "' AND `customer_id` = '" . (int)$this->customer->getId() . "' AND `session_id` = '" . $this->db->escape($this->session->getId()) . "'");
438:
439: $this->data = [];
440: }
441:
442: /**
443: * getSubscriptions
444: *
445: * @return array<int, array<string, mixed>>
446: */
447: public function getSubscriptions(): array {
448: $product_data = [];
449:
450: foreach ($this->getProducts() as $value) {
451: if ($value['subscription']) {
452: $product_data[] = $value;
453: }
454: }
455:
456: return $product_data;
457: }
458:
459: /**
460: * getWeight
461: *
462: * @return float
463: */
464: public function getWeight(): float {
465: $weight = 0;
466:
467: foreach ($this->getProducts() as $product) {
468: if ($product['shipping']) {
469: $weight += $this->weight->convert($product['weight'], $product['weight_class_id'], $this->config->get('config_weight_class_id'));
470: }
471: }
472:
473: return $weight;
474: }
475:
476: /**
477: * getSubTotal
478: *
479: * @return float
480: */
481: public function getSubTotal(): float {
482: $total = 0;
483:
484: foreach ($this->getProducts() as $product) {
485: $total += $product['total'];
486: }
487:
488: return $total;
489: }
490:
491: /**
492: * getTaxes
493: *
494: * @return array<int, float>
495: */
496: public function getTaxes(): array {
497: $tax_data = [];
498:
499: foreach ($this->getProducts() as $product) {
500: if ($product['tax_class_id']) {
501: $tax_rates = $this->tax->getRates($product['price'], $product['tax_class_id']);
502:
503: foreach ($tax_rates as $tax_rate) {
504: if (!isset($tax_data[$tax_rate['tax_rate_id']])) {
505: $tax_data[$tax_rate['tax_rate_id']] = ($tax_rate['amount'] * $product['quantity']);
506: } else {
507: $tax_data[$tax_rate['tax_rate_id']] += ($tax_rate['amount'] * $product['quantity']);
508: }
509: }
510: }
511: }
512:
513: return $tax_data;
514: }
515:
516: /**
517: * getTotal
518: *
519: * @return float
520: */
521: public function getTotal(): float {
522: $total = 0;
523:
524: foreach ($this->getProducts() as $product) {
525: $total += $this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')) * $product['quantity'];
526: }
527:
528: return $total;
529: }
530:
531: /**
532: * countProducts
533: *
534: * @return int
535: */
536: public function countProducts(): int {
537: $product_total = 0;
538:
539: $products = $this->getProducts();
540:
541: foreach ($products as $product) {
542: $product_total += $product['quantity'];
543: }
544:
545: return $product_total;
546: }
547:
548: /**
549: * hadProducts
550: *
551: * @return bool
552: */
553: public function hasProducts(): bool {
554: return (bool)count($this->getProducts());
555: }
556:
557: /**
558: * hasSubscription
559: *
560: * @return bool
561: */
562: public function hasSubscription(): bool {
563: return (bool)count($this->getSubscriptions());
564: }
565:
566: /**
567: * hasStock
568: *
569: * @return bool
570: */
571: public function hasStock(): bool {
572: foreach ($this->getProducts() as $product) {
573: if (!$product['stock']) {
574: return false;
575: }
576: }
577:
578: return true;
579: }
580:
581: /**
582: * hasShipping
583: *
584: * @return bool
585: */
586: public function hasShipping(): bool {
587: foreach ($this->getProducts() as $product) {
588: if ($product['shipping']) {
589: return true;
590: }
591: }
592:
593: return false;
594: }
595:
596: /**
597: * hasDownload
598: *
599: * @return bool
600: */
601: public function hasDownload(): bool {
602: foreach ($this->getProducts() as $product) {
603: if ($product['download']) {
604: return true;
605: }
606: }
607:
608: return false;
609: }
610: }
611: