├── .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 | [![Run in Postman](https://run.pstmn.io/button.svg)](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 | } --------------------------------------------------------------------------------