1: <?php
2: namespace Opencart\Admin\Controller\Catalog;
3: /**
4: * Class Product
5: *
6: * @package Opencart\Admin\Controller\Catalog
7: */
8: class Product extends \Opencart\System\Engine\Controller {
9: /**
10: * Index
11: *
12: * @return void
13: */
14: public function index(): void {
15: $this->load->language('catalog/product');
16:
17: $this->document->setTitle($this->language->get('heading_title'));
18:
19: if (isset($this->request->get['filter_name'])) {
20: $filter_name = $this->request->get['filter_name'];
21: } else {
22: $filter_name = '';
23: }
24:
25: if (isset($this->request->get['filter_model'])) {
26: $filter_model = $this->request->get['filter_model'];
27: } else {
28: $filter_model = '';
29: }
30:
31: if (isset($this->request->get['filter_price'])) {
32: $filter_price = $this->request->get['filter_price'];
33: } else {
34: $filter_price = '';
35: }
36:
37: if (isset($this->request->get['filter_quantity'])) {
38: $filter_quantity = $this->request->get['filter_quantity'];
39: } else {
40: $filter_quantity = '';
41: }
42:
43: if (isset($this->request->get['filter_status'])) {
44: $filter_status = $this->request->get['filter_status'];
45: } else {
46: $filter_status = '';
47: }
48:
49: $url = '';
50:
51: if (isset($this->request->get['filter_name'])) {
52: $url .= '&filter_name=' . urlencode(html_entity_decode($this->request->get['filter_name'], ENT_QUOTES, 'UTF-8'));
53: }
54:
55: if (isset($this->request->get['filter_model'])) {
56: $url .= '&filter_model=' . urlencode(html_entity_decode($this->request->get['filter_model'], ENT_QUOTES, 'UTF-8'));
57: }
58:
59: if (isset($this->request->get['filter_price'])) {
60: $url .= '&filter_price=' . $this->request->get['filter_price'];
61: }
62:
63: if (isset($this->request->get['filter_quantity'])) {
64: $url .= '&filter_quantity=' . $this->request->get['filter_quantity'];
65: }
66:
67: if (isset($this->request->get['filter_status'])) {
68: $url .= '&filter_status=' . $this->request->get['filter_status'];
69: }
70:
71: if (isset($this->request->get['sort'])) {
72: $url .= '&sort=' . $this->request->get['sort'];
73: }
74:
75: if (isset($this->request->get['order'])) {
76: $url .= '&order=' . $this->request->get['order'];
77: }
78:
79: if (isset($this->request->get['page'])) {
80: $url .= '&page=' . $this->request->get['page'];
81: }
82:
83: $data['breadcrumbs'] = [];
84:
85: $data['breadcrumbs'][] = [
86: 'text' => $this->language->get('text_home'),
87: 'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'])
88: ];
89:
90: $data['breadcrumbs'][] = [
91: 'text' => $this->language->get('heading_title'),
92: 'href' => $this->url->link('catalog/product', 'user_token=' . $this->session->data['user_token'] . $url)
93: ];
94:
95: $data['add'] = $this->url->link('catalog/product.form', 'user_token=' . $this->session->data['user_token'] . $url);
96: $data['copy'] = $this->url->link('catalog/product.copy', 'user_token=' . $this->session->data['user_token']);
97: $data['delete'] = $this->url->link('catalog/product.delete', 'user_token=' . $this->session->data['user_token']);
98:
99: $data['list'] = $this->controller_catalog_product->getList();
100:
101: $data['filter_name'] = $filter_name;
102: $data['filter_model'] = $filter_model;
103: $data['filter_price'] = $filter_price;
104: $data['filter_quantity'] = $filter_quantity;
105: $data['filter_status'] = $filter_status;
106:
107: $data['user_token'] = $this->session->data['user_token'];
108:
109: $data['header'] = $this->load->controller('common/header');
110: $data['column_left'] = $this->load->controller('common/column_left');
111: $data['footer'] = $this->load->controller('common/footer');
112:
113: $this->response->setOutput($this->load->view('catalog/product', $data));
114: }
115:
116: /**
117: * List
118: *
119: * @return void
120: */
121: public function list(): void {
122: $this->load->language('catalog/product');
123:
124: $this->response->setOutput($this->controller_catalog_product->getList());
125: }
126:
127: /**
128: * @return string
129: */
130: protected function getList(): string {
131: if (isset($this->request->get['filter_name'])) {
132: $filter_name = $this->request->get['filter_name'];
133: } else {
134: $filter_name = '';
135: }
136:
137: if (isset($this->request->get['filter_model'])) {
138: $filter_model = $this->request->get['filter_model'];
139: } else {
140: $filter_model = '';
141: }
142:
143: if (isset($this->request->get['filter_price'])) {
144: $filter_price = $this->request->get['filter_price'];
145: } else {
146: $filter_price = '';
147: }
148:
149: if (isset($this->request->get['filter_quantity'])) {
150: $filter_quantity = $this->request->get['filter_quantity'];
151: } else {
152: $filter_quantity = '';
153: }
154:
155: if (isset($this->request->get['filter_status'])) {
156: $filter_status = $this->request->get['filter_status'];
157: } else {
158: $filter_status = '';
159: }
160:
161: if (isset($this->request->get['sort'])) {
162: $sort = (string)$this->request->get['sort'];
163: } else {
164: $sort = 'pd.name';
165: }
166:
167: if (isset($this->request->get['order'])) {
168: $order = (string)$this->request->get['order'];
169: } else {
170: $order = 'ASC';
171: }
172:
173: if (isset($this->request->get['page'])) {
174: $page = (int)$this->request->get['page'];
175: } else {
176: $page = 1;
177: }
178:
179: $url = '';
180:
181: if (isset($this->request->get['filter_name'])) {
182: $url .= '&filter_name=' . urlencode(html_entity_decode($this->request->get['filter_name'], ENT_QUOTES, 'UTF-8'));
183: }
184:
185: if (isset($this->request->get['filter_model'])) {
186: $url .= '&filter_model=' . urlencode(html_entity_decode($this->request->get['filter_model'], ENT_QUOTES, 'UTF-8'));
187: }
188:
189: if (isset($this->request->get['filter_price'])) {
190: $url .= '&filter_price=' . $this->request->get['filter_price'];
191: }
192:
193: if (isset($this->request->get['filter_quantity'])) {
194: $url .= '&filter_quantity=' . $this->request->get['filter_quantity'];
195: }
196:
197: if (isset($this->request->get['filter_status'])) {
198: $url .= '&filter_status=' . $this->request->get['filter_status'];
199: }
200:
201: if (isset($this->request->get['page'])) {
202: $url .= '&page=' . $this->request->get['page'];
203: }
204:
205: $data['action'] = $this->url->link('catalog/product.list', 'user_token=' . $this->session->data['user_token'] . $url);
206:
207: $data['products'] = [];
208:
209: $filter_data = [
210: 'filter_name' => $filter_name,
211: 'filter_model' => $filter_model,
212: 'filter_price' => $filter_price,
213: 'filter_quantity' => $filter_quantity,
214: 'filter_status' => $filter_status,
215: 'sort' => $sort,
216: 'order' => $order,
217: 'start' => ($page - 1) * $this->config->get('config_pagination_admin'),
218: 'limit' => $this->config->get('config_pagination_admin')
219: ];
220:
221: $this->load->model('catalog/product');
222: $this->load->model('tool/image');
223:
224: $results = $this->model_catalog_product->getProducts($filter_data);
225:
226: foreach ($results as $result) {
227: if ($result['image'] && is_file(DIR_IMAGE . html_entity_decode($result['image'], ENT_QUOTES, 'UTF-8'))) {
228: $image = $result['image'];
229: } else {
230: $image = 'no_image.png';
231: }
232:
233: $special = false;
234:
235: $product_specials = $this->model_catalog_product->getSpecials($result['product_id']);
236:
237: foreach ($product_specials as $product_special) {
238: if (($product_special['date_start'] == '0000-00-00' || strtotime($product_special['date_start']) < time()) && ($product_special['date_end'] == '0000-00-00' || strtotime($product_special['date_end']) > time())) {
239: $special = $this->currency->format($product_special['price'], $this->config->get('config_currency'));
240:
241: break;
242: }
243: }
244:
245: $data['products'][] = [
246: 'product_id' => $result['product_id'],
247: 'image' => $this->model_tool_image->resize($image, 40, 40),
248: 'name' => $result['name'],
249: 'model' => $result['model'],
250: 'price' => $this->currency->format($result['price'], $this->config->get('config_currency')),
251: 'special' => $special,
252: 'quantity' => $result['quantity'],
253: 'status' => $result['status'],
254: 'edit' => $this->url->link('catalog/product.form', 'user_token=' . $this->session->data['user_token'] . '&product_id=' . $result['product_id'] . ($result['master_id'] ? '&master_id=' . $result['master_id'] : '') . $url),
255: 'variant' => (!$result['master_id'] ? $this->url->link('catalog/product.form', 'user_token=' . $this->session->data['user_token'] . '&master_id=' . $result['product_id'] . $url) : '')
256: ];
257: }
258:
259: $url = '';
260:
261: if (isset($this->request->get['filter_name'])) {
262: $url .= '&filter_name=' . urlencode(html_entity_decode($this->request->get['filter_name'], ENT_QUOTES, 'UTF-8'));
263: }
264:
265: if (isset($this->request->get['filter_model'])) {
266: $url .= '&filter_model=' . urlencode(html_entity_decode($this->request->get['filter_model'], ENT_QUOTES, 'UTF-8'));
267: }
268:
269: if (isset($this->request->get['filter_price'])) {
270: $url .= '&filter_price=' . $this->request->get['filter_price'];
271: }
272:
273: if (isset($this->request->get['filter_quantity'])) {
274: $url .= '&filter_quantity=' . $this->request->get['filter_quantity'];
275: }
276:
277: if (isset($this->request->get['filter_status'])) {
278: $url .= '&filter_status=' . $this->request->get['filter_status'];
279: }
280:
281: if ($order == 'ASC') {
282: $url .= '&order=DESC';
283: } else {
284: $url .= '&order=ASC';
285: }
286:
287: $data['sort_name'] = $this->url->link('catalog/product.list', 'user_token=' . $this->session->data['user_token'] . '&sort=pd.name' . $url);
288: $data['sort_model'] = $this->url->link('catalog/product.list', 'user_token=' . $this->session->data['user_token'] . '&sort=p.model' . $url);
289: $data['sort_price'] = $this->url->link('catalog/product.list', 'user_token=' . $this->session->data['user_token'] . '&sort=p.price' . $url);
290: $data['sort_quantity'] = $this->url->link('catalog/product.list', 'user_token=' . $this->session->data['user_token'] . '&sort=p.quantity' . $url);
291: $data['sort_order'] = $this->url->link('catalog/product.list', 'user_token=' . $this->session->data['user_token'] . '&sort=p.sort_order' . $url);
292:
293: $url = '';
294:
295: if (isset($this->request->get['filter_name'])) {
296: $url .= '&filter_name=' . urlencode(html_entity_decode($this->request->get['filter_name'], ENT_QUOTES, 'UTF-8'));
297: }
298:
299: if (isset($this->request->get['filter_model'])) {
300: $url .= '&filter_model=' . urlencode(html_entity_decode($this->request->get['filter_model'], ENT_QUOTES, 'UTF-8'));
301: }
302:
303: if (isset($this->request->get['filter_price'])) {
304: $url .= '&filter_price=' . $this->request->get['filter_price'];
305: }
306:
307: if (isset($this->request->get['filter_quantity'])) {
308: $url .= '&filter_quantity=' . $this->request->get['filter_quantity'];
309: }
310:
311: if (isset($this->request->get['filter_status'])) {
312: $url .= '&filter_status=' . $this->request->get['filter_status'];
313: }
314:
315: if (isset($this->request->get['sort'])) {
316: $url .= '&sort=' . $this->request->get['sort'];
317: }
318:
319: if (isset($this->request->get['order'])) {
320: $url .= '&order=' . $this->request->get['order'];
321: }
322:
323: $product_total = $this->model_catalog_product->getTotalProducts($filter_data);
324:
325: $data['pagination'] = $this->load->controller('common/pagination', [
326: 'total' => $product_total,
327: 'page' => $page,
328: 'limit' => $this->config->get('config_pagination_admin'),
329: 'url' => $this->url->link('catalog/product.list', 'user_token=' . $this->session->data['user_token'] . $url . '&page={page}')
330: ]);
331:
332: $data['results'] = sprintf($this->language->get('text_pagination'), ($product_total) ? (($page - 1) * $this->config->get('config_pagination_admin')) + 1 : 0, ((($page - 1) * $this->config->get('config_pagination_admin')) > ($product_total - $this->config->get('config_pagination_admin'))) ? $product_total : ((($page - 1) * $this->config->get('config_pagination_admin')) + $this->config->get('config_pagination_admin')), $product_total, ceil($product_total / $this->config->get('config_pagination_admin')));
333:
334: $data['sort'] = $sort;
335: $data['order'] = $order;
336:
337: return $this->load->view('catalog/product_list', $data);
338: }
339:
340: /**
341: * Form
342: *
343: * @return void
344: */
345: public function form(): void {
346: $this->load->language('catalog/product');
347:
348: $this->document->setTitle($this->language->get('heading_title'));
349:
350: $this->document->addScript('view/javascript/ckeditor/ckeditor.js');
351: $this->document->addScript('view/javascript/ckeditor/adapters/jquery.js');
352:
353: $data['text_form'] = !isset($this->request->get['product_id']) ? $this->language->get('text_add') : $this->language->get('text_edit');
354:
355: $data['error_upload_size'] = sprintf($this->language->get('error_upload_size'), $this->config->get('config_file_max_size'));
356:
357: $data['config_file_max_size'] = ((int)$this->config->get('config_file_max_size') * 1024 * 1024);
358:
359: if (isset($this->request->get['master_id'])) {
360: $this->load->model('catalog/product');
361:
362: $url = $this->url->link('catalog/product.form', 'user_token=' . $this->session->data['user_token'] . '&product_id=' . $this->request->get['master_id']);
363:
364: $data['text_variant'] = sprintf($this->language->get('text_variant'), $url, $url);
365: } else {
366: $data['text_variant'] = '';
367: }
368:
369: $url = '';
370:
371: if (isset($this->request->get['master_id'])) {
372: $url .= '&master_id=' . $this->request->get['master_id'];
373: }
374:
375: if (isset($this->request->get['filter_name'])) {
376: $url .= '&filter_name=' . urlencode(html_entity_decode($this->request->get['filter_name'], ENT_QUOTES, 'UTF-8'));
377: }
378:
379: if (isset($this->request->get['filter_model'])) {
380: $url .= '&filter_model=' . urlencode(html_entity_decode($this->request->get['filter_model'], ENT_QUOTES, 'UTF-8'));
381: }
382:
383: if (isset($this->request->get['filter_price'])) {
384: $url .= '&filter_price=' . $this->request->get['filter_price'];
385: }
386:
387: if (isset($this->request->get['filter_quantity'])) {
388: $url .= '&filter_quantity=' . $this->request->get['filter_quantity'];
389: }
390:
391: if (isset($this->request->get['filter_status'])) {
392: $url .= '&filter_status=' . $this->request->get['filter_status'];
393: }
394:
395: if (isset($this->request->get['sort'])) {
396: $url .= '&sort=' . $this->request->get['sort'];
397: }
398:
399: if (isset($this->request->get['order'])) {
400: $url .= '&order=' . $this->request->get['order'];
401: }
402:
403: if (isset($this->request->get['page'])) {
404: $url .= '&page=' . $this->request->get['page'];
405: }
406:
407: $data['breadcrumbs'] = [];
408:
409: $data['breadcrumbs'][] = [
410: 'text' => $this->language->get('text_home'),
411: 'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'])
412: ];
413:
414: $data['breadcrumbs'][] = [
415: 'text' => $this->language->get('heading_title'),
416: 'href' => $this->url->link('catalog/product', 'user_token=' . $this->session->data['user_token'] . $url)
417: ];
418:
419: $url = '';
420:
421: if (isset($this->request->get['filter_name'])) {
422: $url .= '&filter_name=' . urlencode(html_entity_decode($this->request->get['filter_name'], ENT_QUOTES, 'UTF-8'));
423: }
424:
425: if (isset($this->request->get['filter_model'])) {
426: $url .= '&filter_model=' . urlencode(html_entity_decode($this->request->get['filter_model'], ENT_QUOTES, 'UTF-8'));
427: }
428:
429: if (isset($this->request->get['filter_price'])) {
430: $url .= '&filter_price=' . $this->request->get['filter_price'];
431: }
432:
433: if (isset($this->request->get['filter_quantity'])) {
434: $url .= '&filter_quantity=' . $this->request->get['filter_quantity'];
435: }
436:
437: if (isset($this->request->get['filter_status'])) {
438: $url .= '&filter_status=' . $this->request->get['filter_status'];
439: }
440:
441: if (isset($this->request->get['sort'])) {
442: $url .= '&sort=' . $this->request->get['sort'];
443: }
444:
445: if (isset($this->request->get['order'])) {
446: $url .= '&order=' . $this->request->get['order'];
447: }
448:
449: if (isset($this->request->get['page'])) {
450: $url .= '&page=' . $this->request->get['page'];
451: }
452:
453: $data['save'] = $this->url->link('catalog/product.save', 'user_token=' . $this->session->data['user_token']);
454: $data['back'] = $this->url->link('catalog/product', 'user_token=' . $this->session->data['user_token'] . $url);
455: $data['upload'] = $this->url->link('tool/upload.upload', 'user_token=' . $this->session->data['user_token']);
456:
457: if (isset($this->request->get['product_id'])) {
458: $data['product_id'] = (int)$this->request->get['product_id'];
459: } else {
460: $data['product_id'] = 0;
461: }
462:
463: // If the product_id is the master_id, we need to get the variant info
464: if (isset($this->request->get['product_id'])) {
465: $product_id = (int)$this->request->get['product_id'];
466: } elseif (isset($this->request->get['master_id'])) {
467: $product_id = (int)$this->request->get['master_id'];
468: } else {
469: $product_id = 0;
470: }
471:
472: if ($product_id) {
473: $this->load->model('catalog/product');
474:
475: $product_info = $this->model_catalog_product->getProduct($product_id);
476: }
477:
478: if (isset($this->request->get['master_id'])) {
479: $data['master_id'] = (int)$this->request->get['master_id'];
480: } elseif (!empty($product_info)) {
481: $data['master_id'] = $product_info['master_id'];
482: } else {
483: $data['master_id'] = 0;
484: }
485:
486: $this->load->model('localisation/language');
487:
488: $data['languages'] = $this->model_localisation_language->getLanguages();
489:
490: if (!empty($product_info)) {
491: $data['product_description'] = $this->model_catalog_product->getDescriptions($product_id);
492: } else {
493: $data['product_description'] = [];
494: }
495:
496: if (!empty($product_info)) {
497: $data['model'] = $product_info['model'];
498: } else {
499: $data['model'] = '';
500: }
501:
502: if (!empty($product_info)) {
503: $data['sku'] = $product_info['sku'];
504: } else {
505: $data['sku'] = '';
506: }
507:
508: if (!empty($product_info)) {
509: $data['upc'] = $product_info['upc'];
510: } else {
511: $data['upc'] = '';
512: }
513:
514: if (!empty($product_info)) {
515: $data['ean'] = $product_info['ean'];
516: } else {
517: $data['ean'] = '';
518: }
519:
520: if (!empty($product_info)) {
521: $data['jan'] = $product_info['jan'];
522: } else {
523: $data['jan'] = '';
524: }
525:
526: if (!empty($product_info)) {
527: $data['isbn'] = $product_info['isbn'];
528: } else {
529: $data['isbn'] = '';
530: }
531:
532: if (!empty($product_info)) {
533: $data['mpn'] = $product_info['mpn'];
534: } else {
535: $data['mpn'] = '';
536: }
537:
538: if (!empty($product_info)) {
539: $data['location'] = $product_info['location'];
540: } else {
541: $data['location'] = '';
542: }
543:
544: if (!empty($product_info)) {
545: $data['price'] = $product_info['price'];
546: } else {
547: $data['price'] = '';
548: }
549:
550: $this->load->model('localisation/tax_class');
551:
552: $data['tax_classes'] = $this->model_localisation_tax_class->getTaxClasses();
553:
554: if (!empty($product_info)) {
555: $data['tax_class_id'] = $product_info['tax_class_id'];
556: } else {
557: $data['tax_class_id'] = 0;
558: }
559:
560: if (!empty($product_info)) {
561: $data['quantity'] = $product_info['quantity'];
562: } else {
563: $data['quantity'] = 1;
564: }
565:
566: if (!empty($product_info)) {
567: $data['minimum'] = $product_info['minimum'];
568: } else {
569: $data['minimum'] = 1;
570: }
571:
572: if (!empty($product_info)) {
573: $data['subtract'] = $product_info['subtract'];
574: } else {
575: $data['subtract'] = 1;
576: }
577:
578: $this->load->model('localisation/stock_status');
579:
580: $data['stock_statuses'] = $this->model_localisation_stock_status->getStockStatuses();
581:
582: if (!empty($product_info)) {
583: $data['stock_status_id'] = $product_info['stock_status_id'];
584: } else {
585: $data['stock_status_id'] = 0;
586: }
587:
588: if (!empty($product_info)) {
589: $data['date_available'] = ($product_info['date_available'] != '0000-00-00') ? $product_info['date_available'] : '';
590: } else {
591: $data['date_available'] = date('Y-m-d');
592: }
593:
594: if (!empty($product_info)) {
595: $data['shipping'] = $product_info['shipping'];
596: } else {
597: $data['shipping'] = 1;
598: }
599:
600: if (!empty($product_info)) {
601: $data['length'] = $product_info['length'];
602: } else {
603: $data['length'] = '';
604: }
605:
606: if (!empty($product_info)) {
607: $data['width'] = $product_info['width'];
608: } else {
609: $data['width'] = '';
610: }
611:
612: if (!empty($product_info)) {
613: $data['height'] = $product_info['height'];
614: } else {
615: $data['height'] = '';
616: }
617:
618: $this->load->model('localisation/length_class');
619:
620: $data['length_classes'] = $this->model_localisation_length_class->getLengthClasses();
621:
622: if (!empty($product_info)) {
623: $data['length_class_id'] = $product_info['length_class_id'];
624: } else {
625: $data['length_class_id'] = $this->config->get('config_length_class_id');
626: }
627:
628: if (!empty($product_info)) {
629: $data['weight'] = $product_info['weight'];
630: } else {
631: $data['weight'] = '';
632: }
633:
634: $this->load->model('localisation/weight_class');
635:
636: $data['weight_classes'] = $this->model_localisation_weight_class->getWeightClasses();
637:
638: if (!empty($product_info)) {
639: $data['weight_class_id'] = $product_info['weight_class_id'];
640: } else {
641: $data['weight_class_id'] = $this->config->get('config_weight_class_id');
642: }
643:
644: if (!empty($product_info)) {
645: $data['status'] = $product_info['status'];
646: } else {
647: $data['status'] = true;
648: }
649:
650: if (!empty($product_info)) {
651: $data['sort_order'] = $product_info['sort_order'];
652: } else {
653: $data['sort_order'] = 1;
654: }
655:
656: $this->load->model('catalog/manufacturer');
657:
658: if (!empty($product_info)) {
659: $data['manufacturer_id'] = $product_info['manufacturer_id'];
660: } else {
661: $data['manufacturer_id'] = 0;
662: }
663:
664: if (!empty($product_info)) {
665: $manufacturer_info = $this->model_catalog_manufacturer->getManufacturer($product_info['manufacturer_id']);
666:
667: if ($manufacturer_info) {
668: $data['manufacturer'] = $manufacturer_info['name'];
669: } else {
670: $data['manufacturer'] = '';
671: }
672: } else {
673: $data['manufacturer'] = '';
674: }
675:
676: // Categories
677: $this->load->model('catalog/category');
678:
679: if ($product_id) {
680: $categories = $this->model_catalog_product->getCategories($product_id);
681: } else {
682: $categories = [];
683: }
684:
685: $data['product_categories'] = [];
686:
687: foreach ($categories as $category_id) {
688: $category_info = $this->model_catalog_category->getCategory($category_id);
689:
690: if ($category_info) {
691: $data['product_categories'][] = [
692: 'category_id' => $category_info['category_id'],
693: 'name' => ($category_info['path']) ? $category_info['path'] . ' &gt; ' . $category_info['name'] : $category_info['name']
694: ];
695: }
696: }
697:
698: // Filters
699: $this->load->model('catalog/filter');
700:
701: if (!empty($product_info)) {
702: $filters = $this->model_catalog_product->getFilters($product_id);
703: } else {
704: $filters = [];
705: }
706:
707: $data['product_filters'] = [];
708:
709: foreach ($filters as $filter_id) {
710: $filter_info = $this->model_catalog_filter->getFilter($filter_id);
711:
712: if ($filter_info) {
713: $data['product_filters'][] = [
714: 'filter_id' => $filter_info['filter_id'],
715: 'name' => $filter_info['group'] . ' &gt; ' . $filter_info['name']
716: ];
717: }
718: }
719:
720: // Stores
721: $data['stores'] = [];
722:
723: $data['stores'][] = [
724: 'store_id' => 0,
725: 'name' => $this->language->get('text_default')
726: ];
727:
728: $this->load->model('setting/store');
729:
730: $stores = $this->model_setting_store->getStores();
731:
732: foreach ($stores as $store) {
733: $data['stores'][] = [
734: 'store_id' => $store['store_id'],
735: 'name' => $store['name']
736: ];
737: }
738:
739: if ($product_id) {
740: $data['product_store'] = $this->model_catalog_product->getStores($product_id);
741: } else {
742: $data['product_store'] = [0];
743: }
744:
745: // Downloads
746: $this->load->model('catalog/download');
747:
748: if ($product_id) {
749: $product_downloads = $this->model_catalog_product->getDownloads($product_id);
750: } else {
751: $product_downloads = [];
752: }
753:
754: $data['product_downloads'] = [];
755:
756: foreach ($product_downloads as $download_id) {
757: $download_info = $this->model_catalog_download->getDownload($download_id);
758:
759: if ($download_info) {
760: $data['product_downloads'][] = [
761: 'download_id' => $download_info['download_id'],
762: 'name' => $download_info['name']
763: ];
764: }
765: }
766:
767: // Related
768: if ($product_id) {
769: $product_relateds = $this->model_catalog_product->getRelated($product_id);
770: } else {
771: $product_relateds = [];
772: }
773:
774: $data['product_relateds'] = [];
775:
776: foreach ($product_relateds as $related_id) {
777: $related_info = $this->model_catalog_product->getProduct($related_id);
778:
779: if ($related_info) {
780: $data['product_relateds'][] = [
781: 'product_id' => $related_info['product_id'],
782: 'name' => $related_info['name']
783: ];
784: }
785: }
786:
787: // Attributes
788: $this->load->model('catalog/attribute');
789:
790: if ($product_id) {
791: $product_attributes = $this->model_catalog_product->getAttributes($product_id);
792: } else {
793: $product_attributes = [];
794: }
795:
796: $data['product_attributes'] = [];
797:
798: foreach ($product_attributes as $product_attribute) {
799: $attribute_info = $this->model_catalog_attribute->getAttribute($product_attribute['attribute_id']);
800:
801: if ($attribute_info) {
802: $data['product_attributes'][] = [
803: 'attribute_id' => $product_attribute['attribute_id'],
804: 'name' => $attribute_info['name'],
805: 'product_attribute_description' => $product_attribute['product_attribute_description']
806: ];
807: }
808: }
809:
810: $this->load->model('customer/customer_group');
811:
812: $data['customer_groups'] = $this->model_customer_customer_group->getCustomerGroups();
813:
814: // Options
815: $this->load->model('catalog/option');
816:
817: if ($product_id) {
818: $product_options = $this->model_catalog_product->getOptions($product_id);
819: } else {
820: $product_options = [];
821: }
822:
823: $data['product_options'] = [];
824:
825: foreach ($product_options as $product_option) {
826: $product_option_value_data = [];
827:
828: if (isset($product_option['product_option_value'])) {
829: foreach ($product_option['product_option_value'] as $product_option_value) {
830: $option_value_info = $this->model_catalog_option->getValue($product_option_value['option_value_id']);
831:
832: if ($option_value_info) {
833: $product_option_value_data[] = [
834: 'product_option_value_id' => $product_option_value['product_option_value_id'],
835: 'option_value_id' => $product_option_value['option_value_id'],
836: 'name' => $option_value_info['name'],
837: 'quantity' => $product_option_value['quantity'],
838: 'subtract' => $product_option_value['subtract'],
839: 'price' => $product_option_value['price'],
840: 'price_prefix' => $product_option_value['price_prefix'],
841: 'points' => round($product_option_value['points']),
842: 'points_prefix' => $product_option_value['points_prefix'],
843: 'weight' => round($product_option_value['weight']),
844: 'weight_prefix' => $product_option_value['weight_prefix']
845: ];
846: }
847: }
848: }
849:
850: $data['product_options'][] = [
851: 'product_option_id' => $product_option['product_option_id'],
852: 'product_option_value' => $product_option_value_data,
853: 'option_id' => $product_option['option_id'],
854: 'name' => $product_option['name'],
855: 'type' => $product_option['type'],
856: 'value' => $product_option['value'] ?? '',
857: 'required' => $product_option['required']
858: ];
859: }
860:
861: $data['option_values'] = [];
862:
863: foreach ($data['product_options'] as $product_option) {
864: if ($product_option['type'] == 'select' || $product_option['type'] == 'radio' || $product_option['type'] == 'checkbox' || $product_option['type'] == 'image') {
865: if (!isset($data['option_values'][$product_option['option_id']])) {
866: $data['option_values'][$product_option['option_id']] = $this->model_catalog_option->getValues($product_option['option_id']);
867: }
868: }
869: }
870:
871: // Variants
872: if (!empty($product_info)) {
873: $data['variant'] = $product_info['variant'];
874: } else {
875: $data['variant'] = [];
876: }
877:
878: // Overrides
879: if (!empty($product_info)) {
880: $data['override'] = $product_info['override'];
881: } else {
882: $data['override'] = [];
883: }
884:
885: $data['options'] = [];
886:
887: if (isset($this->request->get['master_id'])) {
888: $product_options = $this->model_catalog_product->getOptions($this->request->get['master_id']);
889:
890: foreach ($product_options as $product_option) {
891: $product_option_value_data = [];
892:
893: foreach ($product_option['product_option_value'] as $product_option_value) {
894: $option_value_info = $this->model_catalog_option->getValue($product_option_value['option_value_id']);
895:
896: if ($option_value_info) {
897: $product_option_value_data[] = [
898: 'product_option_value_id' => $product_option_value['product_option_value_id'],
899: 'option_value_id' => $product_option_value['option_value_id'],
900: 'name' => $option_value_info['name'],
901: 'price' => (float)$product_option_value['price'] ? $product_option_value['price'] : false,
902: 'price_prefix' => $product_option_value['price_prefix']
903: ];
904: }
905: }
906:
907: $option_info = $this->model_catalog_option->getOption($product_option['option_id']);
908:
909: $data['options'][] = [
910: 'product_option_id' => $product_option['product_option_id'],
911: 'product_option_value' => $product_option_value_data,
912: 'option_id' => $product_option['option_id'],
913: 'name' => $option_info['name'],
914: 'type' => $option_info['type'],
915: 'value' => $data['variant'][$product_option['product_option_id']] ?? $product_option['value'],
916: 'required' => $product_option['required']
917: ];
918: }
919: }
920:
921: // Subscriptions
922: $this->load->model('catalog/subscription_plan');
923:
924: $data['subscription_plans'] = $this->model_catalog_subscription_plan->getSubscriptionPlans();
925:
926: if ($product_id) {
927: $data['product_subscriptions'] = $this->model_catalog_product->getSubscriptions($product_id);
928: } else {
929: $data['product_subscriptions'] = [];
930: }
931:
932: // Discount
933: if ($product_id) {
934: $product_discounts = $this->model_catalog_product->getDiscounts($product_id);
935: } else {
936: $product_discounts = [];
937: }
938:
939: $data['product_discounts'] = [];
940:
941: foreach ($product_discounts as $product_discount) {
942: $data['product_discounts'][] = [
943: 'customer_group_id' => $product_discount['customer_group_id'],
944: 'quantity' => $product_discount['quantity'],
945: 'priority' => $product_discount['priority'],
946: 'price' => $product_discount['price'],
947: 'date_start' => ($product_discount['date_start'] != '0000-00-00') ? $product_discount['date_start'] : '',
948: 'date_end' => ($product_discount['date_end'] != '0000-00-00') ? $product_discount['date_end'] : ''
949: ];
950: }
951:
952: // Special
953: if ($product_id) {
954: $product_specials = $this->model_catalog_product->getSpecials($product_id);
955: } else {
956: $product_specials = [];
957: }
958:
959: $data['product_specials'] = [];
960:
961: foreach ($product_specials as $product_special) {
962: $data['product_specials'][] = [
963: 'customer_group_id' => $product_special['customer_group_id'],
964: 'priority' => $product_special['priority'],
965: 'price' => $product_special['price'],
966: 'date_start' => ($product_special['date_start'] != '0000-00-00') ? $product_special['date_start'] : '',
967: 'date_end' => ($product_special['date_end'] != '0000-00-00') ? $product_special['date_end'] : ''
968: ];
969: }
970:
971: // Image
972: if (!empty($product_info)) {
973: $data['image'] = $product_info['image'];
974: } else {
975: $data['image'] = '';
976: }
977:
978: $this->load->model('tool/image');
979:
980: $data['placeholder'] = $this->model_tool_image->resize('no_image.png', (int)$this->config->get('config_image_default_width'), (int)$this->config->get('config_image_default_height'));
981:
982: if ($data['image'] && is_file(DIR_IMAGE . html_entity_decode($data['image'], ENT_QUOTES, 'UTF-8'))) {
983: $data['thumb'] = $this->model_tool_image->resize($data['image'], (int)$this->config->get('config_image_default_width'), (int)$this->config->get('config_image_default_height'));
984: } else {
985: $data['thumb'] = $data['placeholder'];
986: }
987:
988: // Images
989: if ($product_id) {
990: $product_images = $this->model_catalog_product->getImages($product_id);
991: } else {
992: $product_images = [];
993: }
994:
995: $data['product_images'] = [];
996:
997: foreach ($product_images as $product_image) {
998: if ($product_image['image'] && is_file(DIR_IMAGE . html_entity_decode($product_image['image'], ENT_QUOTES, 'UTF-8'))) {
999: $image = $product_image['image'];
1000: $thumb = $product_image['image'];
1001: } else {
1002: $image = '';
1003: $thumb = 'no_image.png';
1004: }
1005:
1006: $data['product_images'][] = [
1007: 'image' => $image,
1008: 'thumb' => $this->model_tool_image->resize($thumb, (int)$this->config->get('config_image_default_width'), (int)$this->config->get('config_image_default_height')),
1009: 'sort_order' => $product_image['sort_order']
1010: ];
1011: }
1012:
1013: // Points
1014: if (!empty($product_info)) {
1015: $data['points'] = $product_info['points'];
1016: } else {
1017: $data['points'] = '';
1018: }
1019:
1020: // Rewards
1021: if ($product_id) {
1022: $data['product_reward'] = $this->model_catalog_product->getRewards($product_id);
1023: } else {
1024: $data['product_reward'] = [];
1025: }
1026:
1027: // SEO
1028: if ($product_id) {
1029: $this->load->model('design/seo_url');
1030:
1031: $data['product_seo_url'] = $this->model_design_seo_url->getSeoUrlsByKeyValue('product_id', $this->request->get['product_id']);
1032: } else {
1033: $data['product_seo_url'] = [];
1034: }
1035:
1036: // Layouts
1037: $this->load->model('design/layout');
1038:
1039: $data['layouts'] = $this->model_design_layout->getLayouts();
1040:
1041: if ($product_id) {
1042: $data['product_layout'] = $this->model_catalog_product->getLayouts($product_id);
1043: } else {
1044: $data['product_layout'] = [];
1045: }
1046:
1047: $data['report'] = $this->getReport();
1048:
1049: $data['user_token'] = $this->session->data['user_token'];
1050:
1051: $data['header'] = $this->load->controller('common/header');
1052: $data['column_left'] = $this->load->controller('common/column_left');
1053: $data['footer'] = $this->load->controller('common/footer');
1054:
1055: $this->response->setOutput($this->load->view('catalog/product_form', $data));
1056: }
1057:
1058: /**
1059: * Save
1060: *
1061: * @return void
1062: */
1063: public function save(): void {
1064: $this->load->language('catalog/product');
1065:
1066: $json = [];
1067:
1068: if (!$this->user->hasPermission('modify', 'catalog/product')) {
1069: $json['error']['warning'] = $this->language->get('error_permission');
1070: }
1071:
1072: foreach ($this->request->post['product_description'] as $language_id => $value) {
1073: if (!oc_validate_length($value['name'], 1, 255)) {
1074: $json['error']['name_' . $language_id] = $this->language->get('error_name');
1075: }
1076:
1077: if (!oc_validate_length($value['meta_title'], 1, 255)) {
1078: $json['error']['meta_title_' . $language_id] = $this->language->get('error_meta_title');
1079: }
1080: }
1081:
1082: if (!oc_validate_length($this->request->post['model'], 1, 64)) {
1083: $json['error']['model'] = $this->language->get('error_model');
1084: }
1085:
1086: $this->load->model('catalog/product');
1087:
1088: if ($this->request->post['master_id']) {
1089: $product_options = $this->model_catalog_product->getOptions($this->request->post['master_id']);
1090:
1091: foreach ($product_options as $product_option) {
1092: if (isset($this->request->post['override']['variant'][$product_option['product_option_id']]) && $product_option['required'] && empty($this->request->post['variant'][$product_option['product_option_id']])) {
1093: $json['error']['option_' . $product_option['product_option_id']] = sprintf($this->language->get('error_required'), $product_option['name']);
1094: }
1095: }
1096: }
1097:
1098: if ($this->request->post['product_seo_url']) {
1099: $this->load->model('design/seo_url');
1100:
1101: foreach ($this->request->post['product_seo_url'] as $store_id => $language) {
1102: foreach ($language as $language_id => $keyword) {
1103: if (!oc_validate_length($keyword, 1, 64)) {
1104: $json['error']['keyword_' . $store_id . '_' . $language_id] = $this->language->get('error_keyword');
1105: }
1106:
1107: if (!oc_validate_seo_url($keyword)) {
1108: $json['error']['keyword_' . $store_id . '_' . $language_id] = $this->language->get('error_keyword_character');
1109: }
1110:
1111: $seo_url_info = $this->model_design_seo_url->getSeoUrlByKeyword($keyword, $store_id);
1112:
1113: if ($seo_url_info && ($seo_url_info['key'] != 'product_id' || !isset($this->request->post['product_id']) || $seo_url_info['value'] != (int)$this->request->post['product_id'])) {
1114: $json['error']['keyword_' . $store_id . '_' . $language_id] = $this->language->get('error_keyword_exists');
1115: }
1116: }
1117: }
1118: }
1119:
1120: if (isset($json['error']) && !isset($json['error']['warning'])) {
1121: $json['error']['warning'] = $this->language->get('error_warning');
1122: }
1123:
1124: if (!$json) {
1125: if (!$this->request->post['product_id']) {
1126: if (!$this->request->post['master_id']) {
1127: // Normal product add
1128: $json['product_id'] = $this->model_catalog_product->addProduct($this->request->post);
1129: } else {
1130: // Variant product add
1131: $json['product_id'] = $this->model_catalog_product->addVariant($this->request->post['master_id'], $this->request->post);
1132: }
1133: } else {
1134: if (!$this->request->post['master_id']) {
1135: // Normal product edit
1136: $this->model_catalog_product->editProduct($this->request->post['product_id'], $this->request->post);
1137: } else {
1138: // Variant product edit
1139: $this->model_catalog_product->editVariant($this->request->post['master_id'], $this->request->post['product_id'], $this->request->post);
1140: }
1141:
1142: // Variant products edit if master product is edited
1143: $this->model_catalog_product->editVariants($this->request->post['product_id'], $this->request->post);
1144: }
1145:
1146: $json['success'] = $this->language->get('text_success');
1147: }
1148:
1149: $this->response->addHeader('Content-Type: application/json');
1150: $this->response->setOutput(json_encode($json));
1151: }
1152:
1153: /**
1154: * Delete
1155: *
1156: * @return void
1157: */
1158: public function delete(): void {
1159: $this->load->language('catalog/product');
1160:
1161: $json = [];
1162:
1163: if (isset($this->request->post['selected'])) {
1164: $selected = $this->request->post['selected'];
1165: } else {
1166: $selected = [];
1167: }
1168:
1169: if (!$this->user->hasPermission('modify', 'catalog/product')) {
1170: $json['error'] = $this->language->get('error_permission');
1171: }
1172:
1173: if (!$json) {
1174: $this->load->model('catalog/product');
1175:
1176: foreach ($selected as $product_id) {
1177: $this->model_catalog_product->deleteProduct($product_id);
1178: }
1179:
1180: $json['success'] = $this->language->get('text_success');
1181: }
1182:
1183: $this->response->addHeader('Content-Type: application/json');
1184: $this->response->setOutput(json_encode($json));
1185: }
1186:
1187: /**
1188: * Copy
1189: *
1190: * @return void
1191: */
1192: public function copy(): void {
1193: $this->load->language('catalog/product');
1194:
1195: $json = [];
1196:
1197: if (isset($this->request->post['selected'])) {
1198: $selected = $this->request->post['selected'];
1199: } else {
1200: $selected = [];
1201: }
1202:
1203: if (!$this->user->hasPermission('modify', 'catalog/product')) {
1204: $json['error'] = $this->language->get('error_permission');
1205: }
1206:
1207: if (!$json) {
1208: $this->load->model('catalog/product');
1209:
1210: foreach ($selected as $product_id) {
1211: $this->model_catalog_product->copyProduct($product_id);
1212: }
1213:
1214: $json['success'] = $this->language->get('text_success');
1215: }
1216:
1217: $this->response->addHeader('Content-Type: application/json');
1218: $this->response->setOutput(json_encode($json));
1219: }
1220:
1221: /**
1222: * Report
1223: *
1224: * @return void
1225: */
1226: public function report(): void {
1227: $this->load->language('catalog/product');
1228:
1229: $this->response->setOutput($this->getReport());
1230: }
1231:
1232: /**
1233: * Get Report
1234: *
1235: * @return string
1236: */
1237: public function getReport(): string {
1238: if (isset($this->request->get['product_id'])) {
1239: $product_id = (int)$this->request->get['product_id'];
1240: } else {
1241: $product_id = 0;
1242: }
1243:
1244: if (isset($this->request->get['page']) && $this->request->get['route'] == 'catalog/product.report') {
1245: $page = (int)$this->request->get['page'];
1246: } else {
1247: $page = 1;
1248: }
1249:
1250: $limit = 10;
1251:
1252: $data['reports'] = [];
1253:
1254: $this->load->model('catalog/product');
1255: $this->load->model('setting/store');
1256:
1257: $results = $this->model_catalog_product->getReports($product_id, ($page - 1) * $limit, $limit);
1258:
1259: foreach ($results as $result) {
1260: $store_info = $this->model_setting_store->getStore($result['store_id']);
1261:
1262: if ($store_info) {
1263: $store = $store_info['name'];
1264: } elseif (!$result['store_id']) {
1265: $store = $this->config->get('config_name');
1266: } else {
1267: $store = '';
1268: }
1269:
1270: $data['reports'][] = [
1271: 'ip' => $result['ip'],
1272: 'store' => $store,
1273: 'country' => $result['country'],
1274: 'date_added' => date($this->language->get('datetime_format'), strtotime($result['date_added']))
1275: ];
1276: }
1277:
1278: $report_total = $this->model_catalog_product->getTotalReports($product_id);
1279:
1280: $data['pagination'] = $this->load->controller('common/pagination', [
1281: 'total' => $report_total,
1282: 'page' => $page,
1283: 'limit' => $limit,
1284: 'url' => $this->url->link('catalog/product.report', 'user_token=' . $this->session->data['user_token'] . '&product_id=' . $product_id . '&page={page}')
1285: ]);
1286:
1287: $data['results'] = sprintf($this->language->get('text_pagination'), ($report_total) ? (($page - 1) * $limit) + 1 : 0, ((($page - 1) * $limit) > ($report_total - $limit)) ? $report_total : ((($page - 1) * $limit) + $limit), $report_total, ceil($report_total / $limit));
1288:
1289: return $this->load->view('catalog/product_report', $data);
1290: }
1291:
1292: /**
1293: * Autocomplete
1294: *
1295: * @return void
1296: */
1297: public function autocomplete(): void {
1298: $json = [];
1299:
1300: if (isset($this->request->get['filter_name'])) {
1301: $filter_name = $this->request->get['filter_name'];
1302: } else {
1303: $filter_name = '';
1304: }
1305:
1306: if (isset($this->request->get['filter_model'])) {
1307: $filter_model = $this->request->get['filter_model'];
1308: } else {
1309: $filter_model = '';
1310: }
1311:
1312: if (isset($this->request->get['limit'])) {
1313: $limit = (int)$this->request->get['limit'];
1314: } else {
1315: $limit = 5;
1316: }
1317:
1318: $filter_data = [
1319: 'filter_name' => $filter_name,
1320: 'filter_model' => $filter_model,
1321: 'start' => 0,
1322: 'limit' => $limit
1323: ];
1324:
1325: $this->load->model('catalog/product');
1326: $this->load->model('catalog/option');
1327: $this->load->model('catalog/subscription_plan');
1328:
1329: $results = $this->model_catalog_product->getProducts($filter_data);
1330:
1331: foreach ($results as $result) {
1332: $option_data = [];
1333:
1334: $product_options = $this->model_catalog_product->getOptions($result['product_id']);
1335:
1336: foreach ($product_options as $product_option) {
1337: $option_info = $this->model_catalog_option->getOption($product_option['option_id']);
1338:
1339: if ($option_info) {
1340: $product_option_value_data = [];
1341:
1342: foreach ($product_option['product_option_value'] as $product_option_value) {
1343: $option_value_info = $this->model_catalog_option->getValue($product_option_value['option_value_id']);
1344:
1345: if ($option_value_info) {
1346: $product_option_value_data[] = [
1347: 'product_option_value_id' => $product_option_value['product_option_value_id'],
1348: 'option_value_id' => $product_option_value['option_value_id'],
1349: 'name' => $option_value_info['name'],
1350: 'price' => (float)$product_option_value['price'] ? $this->currency->format($product_option_value['price'], $this->config->get('config_currency')) : false,
1351: 'price_prefix' => $product_option_value['price_prefix']
1352: ];
1353: }
1354: }
1355:
1356: $option_data[] = [
1357: 'product_option_id' => $product_option['product_option_id'],
1358: 'product_option_value' => $product_option_value_data,
1359: 'option_id' => $product_option['option_id'],
1360: 'name' => $option_info['name'],
1361: 'type' => $option_info['type'],
1362: 'value' => $product_option['value'],
1363: 'required' => $product_option['required']
1364: ];
1365: }
1366: }
1367:
1368: $subscription_plan_data = [];
1369:
1370: $product_subscriptions = $this->model_catalog_product->getSubscriptions($result['product_id']);
1371:
1372: foreach ($product_subscriptions as $product_subscription) {
1373: $subscription_plan_info = $this->model_catalog_subscription_plan->getSubscriptionPlan($product_subscription['subscription_plan_id']);
1374:
1375: if ($subscription_plan_info) {
1376: $subscription_plan_data[] = [
1377: 'subscription_plan_id' => $subscription_plan_info['subscription_plan_id'],
1378: 'name' => $subscription_plan_info['name']
1379: ];
1380: }
1381: }
1382:
1383: $json[] = [
1384: 'product_id' => $result['product_id'],
1385: 'name' => strip_tags(html_entity_decode($result['name'], ENT_QUOTES, 'UTF-8')),
1386: 'model' => $result['model'],
1387: 'option' => $option_data,
1388: 'subscription' => $subscription_plan_data,
1389: 'price' => $result['price']
1390: ];
1391: }
1392:
1393: $this->response->addHeader('Content-Type: application/json');
1394: $this->response->setOutput(json_encode($json));
1395: }
1396: }
1397: