├── .gitignore
├── README.md
└── catalog
└── controller
└── custom
└── api.php
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | .idea
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Opencart Custom & Customizabla API module
2 |
3 | This module provides `Tax Rates`, `Orders` and `Products` lists endpoints but you can add new endpoints by simple touches.
4 |
5 | ## Installation
6 |
7 | - Download this repo
8 | - Copy files to opencart root folder
9 |
10 | ## Config
11 |
12 | - Login to opencart dashboard
13 | - Navigate System > Users > API
14 | - Create new user with status `enabled`
15 | - v3+: Add your IP to Allowed IP Adresses section
16 |
17 | ## Test Endpoints
18 |
19 | [](https://app.getpostman.com/run-collection/52bc0d9ab37e582e01fe)
20 |
21 | Demo Environment
22 | ```
23 | {
24 | "id": "8c8f2e2e-9853-c500-07d4-5fbb6f006c4a",
25 | "name": "Opencart Custom Api",
26 | "values": [
27 | {
28 | "enabled": true,
29 | "key": "base",
30 | "value": "http://opencart-api.yedincisenol.com/",
31 | "type": "text"
32 | },
33 | {
34 | "enabled": true,
35 | "key": "apiUsername",
36 | "value": "apidemo",
37 | "type": "text"
38 | },
39 | {
40 | "enabled": true,
41 | "key": "apiPassword",
42 | "value": "TEFgfrpDu8KJSDtv21wweANMIe5PBmV5hU2ICE0BA1nS0uUlyl7sMkYg06N8sZNyAcKVHgcAtSav6cssWWmtY0yFUofTXmgde3iMwzkQjqzZfzTLRptOmJSDFLF4vKhx7GtBW8OJTBMymzCyikxKYWr6Y7jCuuEuIN6YHqCT4a00tsb30wmFZh0TCpphs4Cup1ypdQ8e8U4kPPFTbnCRafMVYrLhpYnwTmCVanUeeBmGDixfuGBZfgvHkDnbrldV",
43 | "type": "text"
44 | }
45 | ],
46 | }
47 | ```
48 |
49 | > Important: For try endpoints you must call first, login endpoints for your version
50 |
51 | ## Contributing
52 |
53 | - Add more endpoints
54 | - Open issue any bug on the project
55 | - Add more document about the project
56 |
57 | ## Security Vulnerabilities
58 |
59 | If you discover a security vulnerability within Laravel api startup, please send an e-mail to İbrahim S. Orencik at o@yedincisenol.com. All security vulnerabilities will be promptly addressed.
60 |
--------------------------------------------------------------------------------
/catalog/controller/custom/api.php:
--------------------------------------------------------------------------------
1 | [],
18 | 'meta' => []
19 | ];
20 | private $dbPrefix = DB_PREFIX;
21 | public function __construct($registry)
22 | {
23 | parent::__construct($registry);
24 | $this->load->model('catalog/product');
25 |
26 | if ($this->startsWith(VERSION, '2.')) {
27 | $this->dbColumnName = 'name';
28 | }
29 | }
30 |
31 | /**
32 | * Authenticate user
33 | *
34 | * @return bool
35 | */
36 | public function auth()
37 | {
38 | if (!isset($this->request->get['token'])) {
39 | return $this->error();
40 | }
41 |
42 | $token = $this->request->get['token'];
43 |
44 | try {
45 | $data = $this->tryParseToken($token);
46 | } catch (Exception $e) {
47 | return $this->error($e->getMessage());
48 | }
49 |
50 | $username = $data['username'];
51 | $key = $data['key'];
52 |
53 | $sqlFormat = "SELECT * FROM %sapi WHERE status = 1 and `%s`='%s' and `key`='%s'";
54 | $sql = sprintf($sqlFormat, DB_PREFIX, $this->dbColumnName, $username, $key);
55 |
56 | $query = $this->db->query($sql);
57 |
58 | if (isset($query->row) && isset($query->row['api_id'])) {
59 | return true;
60 | }
61 |
62 | return $this->error();
63 | }
64 |
65 | /**
66 | * @param $token
67 | *
68 | * @return bool|array
69 | * @throws Exception
70 | */
71 | private function tryParseToken($token)
72 | {
73 | $encodedJson = base64_decode($token);
74 | if (!$encodedJson) {
75 | throw new Exception('token can not decoded');
76 | }
77 |
78 | $decodedJson = json_decode($encodedJson, true);
79 | if (!isset($decodedJson['username'])) {
80 | throw new Exception('username not found');
81 | }
82 |
83 | if (!isset($decodedJson['key'])) {
84 | throw new Exception('key not found');
85 | }
86 | return $decodedJson;
87 | }
88 |
89 | /**
90 | * @return bool|void
91 | */
92 | public function login()
93 | {
94 | $json = [];
95 |
96 | if (!isset($this->request->post['username'])) {
97 | return $this->error('username not found');
98 | }
99 |
100 | if (!isset($this->request->post['key'])) {
101 | return $this->error('key not found');
102 | }
103 |
104 | $username = $this->request->post['username'];
105 | $key = $this->request->post['key'];
106 |
107 | $sqlFormat = "SELECT * FROM %sapi WHERE status = 1 and `%s`='%s' and `key`='%s'";
108 | $sql = sprintf($sqlFormat, DB_PREFIX, $this->dbColumnName, $username, $key);
109 |
110 | $query = $this->db->query($sql);
111 |
112 | $row = $query->row;
113 | if (!isset($row[$this->dbColumnName]) || !isset($row['key'])) {
114 | return $this->error();
115 | }
116 |
117 | $username = $row[$this->dbColumnName];
118 | $key = $row['key'];
119 |
120 | $json['success'] = $this->language->get('text_success');
121 | $json['token'] = base64_encode(json_encode(['username' => $username, 'key' => $key]));
122 | unset($this->data['data'], $this->data['meta']);
123 |
124 | $this->data = $json;
125 | }
126 |
127 | /**
128 | * @param null $msg
129 | *
130 | * @return bool
131 | */
132 | private function error($msg = null)
133 | {
134 | if (!$msg) {
135 | $msg = $this->language->get('error_permission');
136 | }
137 |
138 | unset($this->data['data'], $this->data['meta']);
139 | $this->data['error'] = true;
140 | $this->data['message'] = $msg;
141 |
142 | return false;
143 | }
144 |
145 | /**
146 | * Customers custom fields
147 | */
148 | public function customeroption()
149 | {
150 | if ($this->auth()) {
151 | $data['custom_fields'] = (new ModelAccountCustomField($this->registry))->getCustomFields();
152 | $data['customer_groups'] = $this->getCustomerGroup();
153 | $data['order_statuses'] = (new ModelLocalisationOrderStatus($this->registry))->getOrderStatuses();
154 |
155 | $this->setResponseData($data);
156 | }
157 | }
158 |
159 | public function getCustomerGroup()
160 | {
161 | return (new ModelAccountCustomerGroup($this->registry))->getCustomerGroups();
162 | }
163 |
164 | /**
165 | * Tax list
166 | */
167 | public function tax()
168 | {
169 | if ($this->auth()) {
170 | $taxes = (new ModelLocalisationTaxClass($this->registry))->getTaxClasses();
171 | $this->setResponseData($taxes);
172 | }
173 | }
174 |
175 | /**
176 | * Order List
177 | */
178 | public function order()
179 | {
180 | if ($this->auth()) {
181 | $order = new ModelSaleOrder($this->registry);
182 | $orders = $this->getOrders($_GET);
183 | $orders = $this->paginate($orders);
184 | $orders = array_map(function ($aorder) use ($order) {
185 | $aorder['custom_field'] = $this->decode($aorder['custom_field']);
186 | $aorder['payment_custom_field'] = $this->decode($aorder['payment_custom_field']);
187 | $aorder['customer_custom_field'] = $this->decode($aorder['customer_custom_field']);
188 | $aorder['products'] = array_map(function ($product) use ($order) {
189 | $aproduct = $product;
190 | $aproduct['options'] = $order->getOrderOptions($product['order_id'], $product['order_product_id']);
191 | return $aproduct;
192 | }, $order->getOrderProducts($aorder['order_id']));
193 | $aorder['totals'] = $this->getOrderTotals($aorder['order_id'], $aorder['shipping_code'], $aorder['payment_country_id']);
194 | $aorder['coupon'] = $this->getOrderCoupon($aorder['order_id']);
195 | return $aorder;
196 | }, $orders);
197 | $this->setResponseData($orders);
198 | }
199 | }
200 |
201 | /**
202 | * Category List
203 | */
204 | public function category()
205 | {
206 | if ($this->auth()) {
207 |
208 | $sql = 'SELECT * FROM ' . DB_PREFIX . 'category c LEFT JOIN ' . DB_PREFIX .
209 | 'category_description cd ON (c.category_id = cd.category_id) LEFT JOIN ' . DB_PREFIX .
210 | "category_to_store c2s ON (c.category_id = c2s.category_id) WHERE cd.language_id = '" .
211 | (int)$this->config->get('config_language_id') . "' AND c2s.store_id = '" . (int)$this->config->get('config_store_id') ."' ";
212 | if (isset($_GET['status'])) {
213 | $sql .= " AND c.status = '". $_GET['status'] ."' ";
214 | }
215 | $sql .= " ORDER BY c.sort_order, LCASE(cd.name)";
216 |
217 | $query = $this->db->query($sql);
218 | $categories = $this->paginate($query->rows);
219 | $this->setResponseData($categories);
220 | }
221 | }
222 |
223 | private function decode($string)
224 | {
225 | if ($this->json_validate($string)) {
226 | return json_decode($string, true);
227 | } else {
228 | return unserialize($string);
229 | }
230 | }
231 |
232 | function json_validate($string)
233 | {
234 | // decode the JSON data
235 | $result = json_decode($string);
236 |
237 | // switch and check possible JSON errors
238 | switch (json_last_error()) {
239 | case JSON_ERROR_NONE:
240 | $error = ''; // JSON is valid // No error has occurred
241 | break;
242 | case JSON_ERROR_DEPTH:
243 | $error = 'The maximum stack depth has been exceeded.';
244 | break;
245 | case JSON_ERROR_STATE_MISMATCH:
246 | $error = 'Invalid or malformed JSON.';
247 | break;
248 | case JSON_ERROR_CTRL_CHAR:
249 | $error = 'Control character error, possibly incorrectly encoded.';
250 | break;
251 | case JSON_ERROR_SYNTAX:
252 | $error = 'Syntax error, malformed JSON.';
253 | break;
254 | // PHP >= 5.3.3
255 | case JSON_ERROR_UTF8:
256 | $error = 'Malformed UTF-8 characters, possibly incorrectly encoded.';
257 | break;
258 | // PHP >= 5.5.0
259 | case JSON_ERROR_RECURSION:
260 | $error = 'One or more recursive references in the value to be encoded.';
261 | break;
262 | // PHP >= 5.5.0
263 | case JSON_ERROR_INF_OR_NAN:
264 | $error = 'One or more NAN or INF values in the value to be encoded.';
265 | break;
266 | case JSON_ERROR_UNSUPPORTED_TYPE:
267 | $error = 'A value of a type that cannot be encoded was given.';
268 | break;
269 | default:
270 | $error = 'Unknown JSON error occured.';
271 | break;
272 | }
273 |
274 | if ($error !== '') {
275 | // throw the Exception or exit // or whatever :)
276 | return false;
277 | }
278 |
279 | // everything is OK
280 | return true;
281 | }
282 |
283 | /**
284 | * Ger orders details
285 | *
286 | * @param $order_id
287 | * @param $shippingCode
288 | * @param $countryID
289 | *
290 | * @return array
291 | */
292 | private function getOrderTotals($order_id, $shippingCode, $countryID)
293 | {
294 | $query = $this->db->query('SELECT * FROM ' . DB_PREFIX . "order_total
295 | WHERE order_id = '" . (int)$order_id . "' ORDER BY sort_order");
296 |
297 | $totals = array_map(function ($row) use ($countryID, $shippingCode) {
298 | $code = $row['code'];
299 | if ($code == 'shipping')
300 | list($code) = explode('.', $shippingCode);
301 |
302 | $row['tax'] = $this->getTotalsTaxRate($code, $countryID);
303 | return $row;
304 | }, $query->rows);
305 |
306 | return $totals;
307 | }
308 |
309 | private function getOrderCoupon($order_id)
310 | {
311 | $prefix = DB_PREFIX;
312 | $query = $this->db->query("SELECT * FROM {$prefix}coupon_history ch JOIN {$prefix}coupon c ON ch.coupon_id = c.coupon_id WHERE ch.order_id = {$order_id}");
313 |
314 | return $query->rows;
315 | }
316 |
317 | /**
318 | * Calculate tax rates
319 | * @param $key
320 | * @param $countryID
321 | * @return mixed
322 | */
323 | private function getTotalsTaxRate($key, $countryID)
324 | {
325 | $prefix = $this->dbPrefix;
326 | $query = $this->db->query("select {$prefix}tax_rate.* from {$prefix}tax_rate
327 | inner join {$prefix}setting on {$prefix}setting.`key` = '{$key}_tax_class_id'
328 | INNER JOIN {$prefix}tax_class on {$prefix}tax_class.tax_class_id = {$prefix}setting.value
329 | INNER JOIN {$prefix}zone_to_geo_zone on {$prefix}zone_to_geo_zone.country_id = {$countryID}
330 | left JOIN {$prefix}tax_rule on {$prefix}tax_rule.tax_class_id = {$prefix}tax_class.tax_class_id
331 | where {$prefix}tax_rate.geo_zone_id = {$prefix}zone_to_geo_zone.geo_zone_id and {$prefix}tax_rule.tax_rate_id = {$prefix}tax_rate.tax_rate_id
332 | group by {$prefix}tax_rate.tax_rate_id");
333 |
334 | return $query->rows;
335 | }
336 |
337 | /**
338 | * Product list
339 | */
340 | public function product()
341 | {
342 | if ($this->auth()) {
343 | $languageId = $this->config->get('config_language_id');
344 | $prefix = $this->dbPrefix;
345 | $stockCode = $_GET['sku'] ?? null;
346 | $queryWhere = '';
347 | if ($stockCode) {
348 | $queryWhere = " where sku ='$stockCode'";
349 | }
350 | // get products
351 | $query = $this->db->query(
352 | "SELECT (select cp.category_id
353 | from {$prefix}product_to_category ptc2
354 | INNER JOIN {$prefix}category_path cp on (cp.category_id = ptc2.category_id)
355 | where ptc2.product_id = p.product_id order by cp.level desc limit 1) as category_id,
356 | pd.*, p.*, m.name AS manufacturer, wcd.unit as weight_unit
357 | from {$prefix}product as p
358 | inner join {$prefix}product_description as pd on pd.product_id = p.product_id and pd.language_id = $languageId
359 | LEFT JOIN {$prefix}manufacturer m ON (p.manufacturer_id = m.manufacturer_id)
360 | LEFT JOIN {$prefix}weight_class wc on (p.weight_class_id = wc.weight_class_id)
361 | LEFT JOIN {$prefix}weight_class_description wcd on (wc.weight_class_id = wcd.weight_class_id)
362 | $queryWhere
363 | order by pd.name, p.model, p.price, p.quantity, p.status, p.sort_order"
364 | );
365 | $productRows = $this->paginate($query->rows);
366 | $products = [];
367 | $taxes = (new ModelLocalisationTaxClass($this->registry))->getTaxClasses();
368 | foreach ($productRows as $row) {
369 | $images = $this->db->query("SELECT * FROM {$this->dbPrefix}product_image WHERE product_id = {$row['product_id']}");
370 | $row['images'] = $images->rows;
371 | $options = $this->db->query(
372 | "SELECT opv.option_id,
373 | opv.option_value_id,
374 | opv.product_option_value_id,
375 | opv.price_prefix,
376 | opv.price,
377 | opv.quantity,
378 | opv.subtract,
379 | ovd.name as option_value_label,
380 | od.name as option_label
381 | FROM {$this->dbPrefix}product_option_value as opv
382 | inner join {$this->dbPrefix}option_value_description ovd on opv.option_value_id = ovd.option_value_id
383 | inner join {$this->dbPrefix}option_description od on opv.option_id = od.option_id
384 | WHERE opv.product_id = {$row['product_id']}
385 | and ovd.language_id = {$languageId} LIMIT 50"
386 | );
387 | $row['options'] = $options->rows;
388 | $row['tax_rate'] = $this->getTaxRate($taxes, $row['tax_class_id']);
389 | $products[] = $row;
390 | }
391 |
392 | $this->setResponseData($products);
393 | }
394 | }
395 |
396 | private function getTaxRate($taxes, $taxClassId) {
397 | $taxes = array_filter($taxes, function ($tax) use ($taxClassId) {
398 | return $tax['tax_class_id'] == $taxClassId;
399 | });
400 | if (count($taxes) < 1) {
401 | return null;
402 | }
403 | $tax = reset($taxes);
404 |
405 | preg_match('/(\d+)%|%(\d+)/', $tax['title'], $match);
406 |
407 | return array_pop($match);
408 | }
409 |
410 | /**
411 | * Add data to response
412 | *
413 | * @param $data
414 | */
415 | private function setResponseData($data)
416 | {
417 | $this->data['data'] = $data;
418 | }
419 |
420 | /**
421 | * Paginate result set
422 | *
423 | * @param $results
424 | * @param null $page
425 | * @param null $limit
426 | *
427 | * @return array
428 | */
429 | private function paginate($results, $page = null, $limit = null)
430 | {
431 | if ($page == null) $page = max(@$_GET['page'], 1);
432 | if ($limit == null) $limit = isset($_GET['limit']) ? $_GET['limit'] : self::limit;
433 |
434 | $paginate['total'] = count($results);
435 | $paginate['current_page'] = $page;
436 | $paginate['per_page'] = $limit;
437 | $paginate['total_pages'] = ceil(count($results) / $limit);
438 |
439 | $this->data['meta']['pagination'] = $paginate;
440 |
441 | return array_slice($results, ($page - 1) * $limit, $limit);
442 | }
443 |
444 | /**
445 | * Order List
446 | */
447 | private function getOrders($data = array())
448 | {
449 | $sql = 'SELECT o.*, (SELECT os.name FROM ' . DB_PREFIX . "order_status os WHERE os.order_status_id = o.order_status_id AND os.language_id = '" . (int)$this->config->get('config_language_id') . "') AS status, o.shipping_code, o.total, o.currency_code, o.currency_value, o.date_added, o.date_modified, (SELECT custom_field FROM " . DB_PREFIX . 'customer where customer_id = o.customer_id) as customer_custom_field FROM `' . DB_PREFIX . 'order` o';
450 |
451 | if (isset($data['filter_order_status'])) {
452 | $implode = array();
453 | $order_statuses = explode(',', $data['filter_order_status']);
454 | foreach ($order_statuses as $order_status_id) {
455 | $implode[] = "o.order_status_id = '" . (int)$order_status_id . "'";
456 | }
457 |
458 | if ($implode) {
459 | $sql .= ' WHERE (' . implode(' OR ', $implode) . ')';
460 | } else {
461 |
462 | }
463 | } else {
464 | $sql .= " WHERE o.order_status_id > '0'";
465 | }
466 |
467 | if (!empty($data['filter_order_id'])) {
468 | $sql .= " AND o.order_id = '" . (int)$data['filter_order_id'] . "'";
469 | }
470 |
471 | if (!empty($data['filter_customer'])) {
472 | $sql .= " AND CONCAT(o.firstname, ' ', o.lastname) LIKE '%" . $this->db->escape($data['filter_customer']) . "%'";
473 | }
474 |
475 | if (!empty($data['filter_date_added'])) {
476 | $sql .= " AND DATE(o.date_added) >= DATE('" . $this->db->escape($data['filter_date_added']) . "')";
477 | }
478 |
479 | if (!empty($data['filter_date_modified'])) {
480 | $sql .= " AND DATE(o.date_modified) >= DATE('" . $this->db->escape($data['filter_date_modified']) . "')";
481 | }
482 |
483 | if (!empty($data['filter_total'])) {
484 | $sql .= " AND o.total = '" . (float)$data['filter_total'] . "'";
485 | }
486 |
487 | $sort_data = array(
488 | 'o.order_id',
489 | 'customer',
490 | 'status',
491 | 'o.date_added',
492 | 'o.date_modified',
493 | 'o.total'
494 | );
495 |
496 | if (isset($data['sort']) && in_array($data['sort'], $sort_data)) {
497 | $sql .= ' ORDER BY ' . $data['sort'];
498 | } else {
499 | $sql .= ' ORDER BY o.date_modified';
500 | }
501 |
502 | if (isset($data['order']) && ($data['order'] == 'DESC')) {
503 | $sql .= ' DESC';
504 | } else {
505 | $sql .= ' ASC';
506 | }
507 |
508 | $query = $this->db->query($sql);
509 |
510 | return $query->rows;
511 | }
512 |
513 | /**
514 | * @param $string
515 | * @param $startString
516 | *
517 | * @return bool
518 | */
519 | function startsWith($string, $startString)
520 | {
521 | $len = strlen($startString);
522 |
523 | return (substr($string, 0, $len) === $startString);
524 | }
525 |
526 | /**
527 | * Echo response
528 | */
529 | private function response()
530 | {
531 | if (isset($this->request->server['HTTP_ORIGIN'])) {
532 | $this->response->addHeader('Access-Control-Allow-Origin: ' . $this->request->server['HTTP_ORIGIN']);
533 | $this->response->addHeader('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
534 | $this->response->addHeader('Access-Control-Max-Age: 1000');
535 | $this->response->addHeader('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
536 | }
537 |
538 | $this->response->addHeader('X-Opencart-Version: ' . VERSION);
539 | $this->response->addHeader('Content-Type: application/json');
540 | if(!$this->response->getOutput()) {
541 | $this->response->setOutput(json_encode($this->data));
542 | }
543 | }
544 |
545 | /**
546 | * Return response
547 | */
548 | public function __destruct()
549 | {
550 | $this->response();
551 | }
552 |
553 | /**
554 | * Order Status
555 | */
556 | public function orderStatus()
557 | {
558 | $request = json_decode(file_get_contents('php://input'), true);
559 | $orderId = $request['order_id'];
560 | $orderStatusId = $request['order_status_id'];
561 | (new ModelCheckoutOrder($this->registry))->addOrderHistory($orderId, $orderStatusId, '', true);
562 | }
563 |
564 | /**
565 | * Manufacturer List
566 | */
567 | public function manufacturer()
568 | {
569 | if ($this->auth()) {
570 |
571 | $sql = "SELECT * FROM " . DB_PREFIX . "manufacturer m LEFT JOIN " . DB_PREFIX . "manufacturer_to_store m2s ON (m.manufacturer_id = m2s.manufacturer_id) WHERE m2s.store_id = '" . (int)$this->config->get('config_store_id') . "' ORDER BY name ASC";
572 |
573 | $query = $this->db->query($sql);
574 | $manufacturers = $this->paginate($query->rows);
575 | $this->setResponseData($manufacturers);
576 | }
577 | }
578 |
579 | /**
580 | * lengthCLass List
581 | */
582 | public function lengthCLass()
583 | {
584 | if ($this->auth()) {
585 |
586 | $sql = "select lc.length_class_id as id, lcd.title, lcd.unit from " . DB_PREFIX . "length_class lc
587 | left join " . DB_PREFIX . "length_class_description lcd on lc.length_class_id = lcd.length_class_id
588 | Where lcd.language_id = " . (int)$this->config->get('config_language_id');
589 |
590 | $query = $this->db->query($sql);
591 | $this->setResponseData($query->rows);
592 | }
593 | }
594 |
595 | /**
596 | * weightClass List
597 | */
598 | public function weightClass()
599 | {
600 | if ($this->auth()) {
601 |
602 | $sql = "select wd.unit, wd.title, w.weight_class_id from " . DB_PREFIX . "weight_class w
603 | left join " . DB_PREFIX . "weight_class_description wd on w.weight_class_id = wd.weight_class_id
604 | Where wd.language_id = " . (int)$this->config->get('config_language_id');
605 |
606 | $query = $this->db->query($sql);
607 | $this->setResponseData($query->rows);
608 | }
609 | }
610 |
611 | /**
612 | * Product Create
613 | */
614 | public function createProduct()
615 | {
616 | if (!$this->auth()) {
617 | return $this->error('Geçersiz AccessToken.');
618 | }
619 |
620 | $data = $this->request->post;
621 |
622 | if(!$data['model'] || !$data['name'] || !$data['meta_title']) {
623 | return $this->error('Model, product title, and SEO title are required fields.');
624 | }
625 | $model = $this->db->escape($data['model']);
626 | $sku = $this->db->escape($data['sku'] ?? null);
627 | $quantity = $data['quantity'] ?? null;
628 | $manufacturerId = $data['manufacturer_id'] ?? null;
629 | $price = $data['price'] ?? null;
630 | $weight = $data['weight'] ?? null;
631 | $weightClassId = $data['weight_class_id'] ?? null;
632 | $length = $data['length'] ?? null;
633 | $width = $data['width'] ?? null;
634 | $height = $data['height'] ?? null;
635 | $lengthClassId = $data['length_class_id'] ?? null;
636 | $status = $data['status'] ?? null;
637 | $taxClassId = $data['tax_class_id'] ?? null;
638 | $name = $this->db->escape($data['name'] ?? null);
639 | $description = $this->db->escape($data['description'] ?? null);
640 | $tag = $this->db->escape($data['tag'] ?? null);
641 | $metaTitle = $this->db->escape($data['meta_title'] ?? null);
642 | $metaDescription = $this->db->escape($data['meta_description'] ?? null);
643 | $metaKeyword = $this->db->escape($data['meta_keyword'] ?? null);
644 | $categoryId = $this->db->escape($data['category_id'] ?? null);
645 | $this->db->query(
646 | "INSERT INTO {$this->dbPrefix}product SET
647 | model = '{$model}',
648 | sku = ' {$sku}',
649 | quantity = '{$quantity}',
650 | manufacturer_id = '{$manufacturerId} ',
651 | price = '{$price}',
652 | weight = '{$weight}',
653 | weight_class_id = '{$weightClassId}',
654 | length = '{$length}',
655 | width = '{$width}',
656 | height = '{$height}',
657 | length_class_id = '{$lengthClassId}',
658 | status = '{$status}',
659 | tax_class_id = '{$taxClassId}',
660 | date_added = NOW(), date_modified = NOW();"
661 | );
662 |
663 | $productId = $this->db->getLastId();
664 | $this->db->query("INSERT INTO {$this->dbPrefix}product_to_store SET product_id = '{$productId}',store_id = '{$this->config->get('config_store_id')}';");
665 |
666 | $this->db->query(
667 | "INSERT INTO {$this->dbPrefix}product_description SET
668 | product_id = '{$productId}',
669 | language_id = '{$this->config->get('config_language_id')}',
670 | name = '{$name}',
671 | description = '{$description}',
672 | tag = '{$tag}',
673 | meta_title = '{$metaTitle}',
674 | meta_description = '{$metaDescription}',
675 | meta_keyword = '{$metaKeyword}';"
676 | );
677 |
678 | $this->db->query("INSERT INTO {$this->dbPrefix}product_to_category SET product_id = '{$productId}', category_id = '{$categoryId}';");
679 |
680 | foreach ($data['product_images'] ?? [] as $product_image) {
681 | if ($path = $this->imageUpload($product_image, $model)) {
682 | $this->db->query("INSERT INTO {$this->dbPrefix}product_image SET product_id = '{$productId}', image = '{$this->db->escape($path)}';");
683 | }
684 | }
685 |
686 | $this->setResponseData($this->getProductQuery($productId));
687 | }
688 |
689 | /**
690 | * Product Update
691 | */
692 | public function updateProduct()
693 | {
694 | if (!$this->auth()) {
695 | return false;
696 | }
697 | $productId = $_GET['product_id'];
698 | $data = $this->request->post;
699 |
700 | $model = $this->db->escape($data['model']);
701 | $sku = $this->db->escape($data['sku']) ?? null;
702 | $manufacturerId = $data['manufacturer_id'] ?? null;
703 | $weight = $data['weight'] ?? null;
704 | $weightClassId = $data['weight_class_id'] ?? null;
705 | $length = $data['length'] ?? null;
706 | $width = $data['width'] ?? null;
707 | $height = $data['height'] ?? null;
708 | $lengthClassId = $data['length_class_id'] ?? null;
709 | $status = $data['status'] ?? null;
710 | $taxClassId = $data['tax_class_id'] ?? null;
711 | $name = $this->db->escape($data['name'] ?? null);
712 | $description = $this->db->escape($data['description'] ?? null);
713 | $tag = $this->db->escape($data['tag'] ?? null);
714 | $metaTitle = $this->db->escape($data['meta_title'] ?? null);
715 | $metaDescription = $this->db->escape($data['meta_description'] ?? null);
716 | $metaKeyword = $this->db->escape($data['meta_keyword'] ?? null);
717 | $categoryId = $this->db->escape($data['category_id'] ?? null);
718 |
719 | $this->db->query(
720 | "UPDATE {$this->dbPrefix}product SET model = '{$this->db->escape($model)}',
721 | sku = '{$this->db->escape($sku)}',
722 | manufacturer_id = '{$manufacturerId}',
723 | weight = '{$weight}',
724 | weight_class_id = '{$weightClassId}',
725 | length = '{$length}',
726 | width = '{$width}',
727 | height = '{$height}',
728 | length_class_id = '{$lengthClassId}',
729 | status = '{$status}',
730 | tax_class_id = '{$taxClassId}',
731 | date_modified = NOW() WHERE product_id = '{$productId}';"
732 | );
733 |
734 | $this->db->query(
735 | "UPDATE {$this->dbPrefix}product_description SET
736 | name = '{$this->db->escape($name)}',
737 | description = '{$this->db->escape($description)}',
738 | tag = '{$tag}',
739 | meta_title = '{$metaTitle}',
740 | meta_description = '{$metaDescription}',
741 | meta_keyword = '{$metaKeyword}'
742 | WHERE product_id = '{$productId}' AND language_id = '{$this->config->get('config_language_id')}';"
743 | );
744 |
745 | $this->db->query("DELETE FROM {$this->dbPrefix}product_to_category WHERE product_id = '{$productId}';");
746 |
747 |
748 | $this->db->query("INSERT INTO {$this->dbPrefix}product_to_category SET product_id = '{$productId}', category_id = '{$categoryId}';");
749 |
750 | $this->setResponseData($this->getProductQuery($productId));
751 | }
752 |
753 | /**
754 | * Image Upload
755 | */
756 | public function imageUpload()
757 | {
758 | if (!$this->auth()) {
759 | return false;
760 | }
761 | $data = $this->request->post;
762 | $url = $data['url'];
763 | $productId = $data['product_id'];
764 | $order = $data['sort_order'];
765 |
766 | $image = file_get_contents($url);
767 | if (empty($image) || !$url) {
768 | return null;
769 | }
770 | $filename = basename($url);
771 |
772 | if (!is_dir(DIR_IMAGE . 'catalog/' . $productId)) {
773 | mkdir(DIR_IMAGE . 'catalog/' . $productId, 0700);
774 | }
775 | file_put_contents(DIR_IMAGE . 'catalog/' . $productId . '/' . $filename, file_get_contents($url));
776 |
777 | $path = 'catalog/' . $productId . '/' . $filename;
778 |
779 | if ($order == 1) {
780 | $this->db->query(
781 | "UPDATE {$this->dbPrefix}product SET
782 | image = '{$this->db->escape($path)}',
783 | date_modified = NOW() WHERE product_id = '{$productId}';"
784 | );
785 | } else {
786 | $this->db->query(
787 | "INSERT INTO {$this->dbPrefix}product_image SET
788 | product_id = '{$productId} ',
789 | image = '{$this->db->escape($path)}',
790 | sort_order = {$order};"
791 | );
792 | }
793 |
794 | $this->setResponseData(
795 | [
796 | 'path' => $path,
797 | 'product_id' => $productId
798 | ]
799 | );
800 | }
801 |
802 | public function updateProductImages()
803 | {
804 | $data = $this->request->post;
805 | $productId = $data['product_id'];
806 |
807 | $this->db->query("DELETE FROM {$this->dbPrefix}product_image WHERE product_id = '{$productId}';");
808 | foreach ($data['images'] ?? [] as $key => $image) {
809 | if ($key == 0) {
810 | $this->db->query(
811 | "UPDATE {$this->dbPrefix}product SET
812 | image = '{$this->db->escape($image['path'])}',
813 | date_modified = NOW() WHERE product_id = '{$productId}';"
814 | );
815 | } else {
816 | $this->db->query(
817 | "INSERT INTO {$this->dbPrefix}product_image SET
818 | product_id = '{$productId}',
819 | image = '{$this->db->escape($image['path'])}',
820 | sort_order = {$image['sort_order']};");
821 | }
822 | }
823 | }
824 |
825 | public function updateStockAndPrice()
826 | {
827 | if (!$this->auth()) {
828 | return false;
829 | }
830 |
831 | $productId = $_GET['product_id'];
832 | $data = $this->request->post;
833 | $sql = "UPDATE {$this->dbPrefix}product SET ";
834 | if (isset($data['quantity'])) {
835 | $sql .= "quantity = '{$data['quantity']}',";
836 | }
837 | if (isset($data['price'])) {
838 | $sql .= " price = '{$data['price']}',";
839 | }
840 | if (isset($data['status'])) {
841 | $sql .= " status = '{$data['status']}',";
842 | }
843 |
844 | $sql .= "date_modified = NOW() WHERE product_id = '{$productId}';";
845 | $this->db->query($sql);
846 |
847 | $this->setResponseData($this->getProductQuery($productId));
848 | }
849 |
850 | /**
851 | * Get Product
852 | */
853 | public function getProduct()
854 | {
855 | if ($this->auth()) {
856 | $productId = $_GET['product_id'];
857 |
858 | $this->setResponseData($this->getProductQuery($productId));
859 | }
860 | }
861 |
862 | private function getProductQuery($productId) {
863 | $languageId = $this->config->get('config_language_id');
864 |
865 | $query = $this->db->query(
866 | "SELECT (select cp.category_id
867 | from {$this->dbPrefix}product_to_category ptc2
868 | INNER JOIN {$this->dbPrefix}category_path cp on (cp.category_id = ptc2.category_id)
869 | where ptc2.product_id = p.product_id order by cp.level desc limit 1) as category_id,
870 | pd.*, p.*, m.name AS manufacturer, wcd.unit as weight_unit
871 | from {$this->dbPrefix}product as p
872 | inner join {$this->dbPrefix}product_description as pd on pd.product_id = p.product_id and pd.language_id = $languageId
873 | LEFT JOIN {$this->dbPrefix}manufacturer m ON (p.manufacturer_id = m.manufacturer_id)
874 | LEFT JOIN {$this->dbPrefix}weight_class wc on (p.weight_class_id = wc.weight_class_id)
875 | LEFT JOIN {$this->dbPrefix}weight_class_description wcd on (wc.weight_class_id = wcd.weight_class_id)
876 | where p.product_id = '" . $productId . "'
877 | order by pd.name, p.model, p.price, p.quantity, p.status, p.sort_order limit 1"
878 | );
879 |
880 | $data = $query->row;
881 | $images = $this->db->query("SELECT * FROM {$this->dbPrefix}product_image WHERE product_id = $productId");
882 | $taxes = (new ModelLocalisationTaxClass($this->registry))->getTaxClasses();
883 | $data['tax_rate'] = $this->getTaxRate($taxes, $data['tax_class_id']);
884 | $data['images'] = $images->rows;
885 | $options = $this->db->query(
886 | "SELECT opv.option_id,
887 | opv.option_value_id,
888 | opv.product_option_value_id,
889 | opv.price_prefix,
890 | opv.price,
891 | opv.quantity,
892 | opv.subtract,
893 | ovd.name as option_value_label,
894 | od.name as option_label
895 | FROM {$this->dbPrefix}product_option_value as opv
896 | inner join {$this->dbPrefix}option_value_description ovd on opv.option_value_id = ovd.option_value_id
897 | inner join {$this->dbPrefix}option_description od on opv.option_id = od.option_id
898 | WHERE opv.product_id = {$productId}
899 | and ovd.language_id = {$languageId} LIMIT 50"
900 | );
901 | $data['options'] = $options->rows;
902 |
903 | return $data;
904 | }
905 |
906 | public function updateProductOptionPrice()
907 | {
908 | if (!$this->auth()) {
909 | return false;
910 | }
911 | $data = $this->request->post;
912 |
913 | $this->db->query(
914 | "UPDATE {$this->dbPrefix}product_option_value SET
915 | price = '{$data['price']}',
916 | price_prefix = '{$data['price_prefix']}'
917 | WHERE product_option_value_id = '{$_GET['product_option_value_id']}';"
918 | );
919 | }
920 |
921 | public function updateProductOptionQuantity()
922 | {
923 | if (!$this->auth()) {
924 | return false;
925 | }
926 | $data = $this->request->post;
927 |
928 | $this->db->query(
929 | "UPDATE {$this->dbPrefix}product_option_value SET
930 | quantity = '{$data['quantity']}',
931 | subtract = '1'
932 | WHERE product_option_value_id = '{$_GET['product_option_value_id']}';"
933 | );
934 | }
935 |
936 | public function currencies()
937 | {
938 | if ($this->auth()) {
939 | $defaultCurrencyCode = $this->config->get('config_currency');
940 |
941 | $query = $this->db->query(
942 | "SELECT currency_id, title, code, symbol_left, symbol_right, value, status
943 | FROM {$this->dbPrefix}currency"
944 | );
945 | $currencies = array_map(function ($currency) use ($defaultCurrencyCode) {
946 | $currency['is_default'] = ($currency['code'] === $defaultCurrencyCode) ? true : false;
947 | return $currency;
948 | }, $query->rows);
949 |
950 | $this->setResponseData($currencies);
951 | }
952 | }
953 |
954 | public function setOrderInvoice() {
955 | if (!$this->auth()) {
956 | return false;
957 | }
958 |
959 | if (empty($this->request->post['order_id']) || empty($this->request->post['invoice_url'])) {
960 | return $this->error('Missing parameter (order_id or invoice_url) was sent.');
961 | }
962 |
963 | $this->load->model('checkout/order');
964 |
965 | $order_id = $this->request->post['order_id'];
966 | $invoice_url = $this->request->post['invoice_url'];
967 |
968 | // Check Order Exists
969 | $query = $this->db->query("SELECT comment FROM `" . DB_PREFIX . "order` WHERE order_id = '" . $order_id . "'");
970 | if (!$query->num_rows) {
971 | return $this->error('Order not found.');
972 | }
973 |
974 | $existing_comment = $query->row['comment'];
975 |
976 | // Remove old invoice link
977 | $updated_comment = preg_replace('/Faturayı indirmek için tıklayın<\/a>/', '', $existing_comment);
978 |
979 | // Add invoice link
980 | $new_comment = trim($updated_comment . ' Faturayı indirmek için tıklayın.');
981 |
982 | // Update comment with invoice link
983 | $this->db->query("UPDATE `" . DB_PREFIX . "order` SET comment = '" . $this->db->escape($new_comment) . "' WHERE order_id = '" . (int)$order_id . "'");
984 |
985 | return true;
986 | }
987 | }
--------------------------------------------------------------------------------