before log
This commit is contained in:
parent
c8fc93ecf3
commit
9c2c174a43
BIN
apiDocs/eComZone Dropshipping - API documentation.pdf
Normal file
BIN
apiDocs/eComZone Dropshipping - API documentation.pdf
Normal file
Binary file not shown.
133
apiDocs/readme.md
Normal file
133
apiDocs/readme.md
Normal file
@ -0,0 +1,133 @@
|
||||
##
|
||||
|
||||
prestashop integration with ecom-zone-api
|
||||
|
||||
eComZone Dropshipping - API
|
||||
documentation
|
||||
|
||||
1. Introduction
|
||||
Generate API token on platform page: https://dropship.ecomzone.eu/api-key.
|
||||
To generate API token, your account must be confirmed by our dropshipping manager.
|
||||
If you need help, please contact nemanja@ecomzone.eu or via WhatsApp
|
||||
+38670290400
|
||||
API token use in request, either as bearer-token or as token parameter.
|
||||
2. Endpoints
|
||||
Use different endpoints based on the action you want to take.
|
||||
Catalog endpoint - Use, when you want to see a full product catalog.
|
||||
Product endpoint - Use, when you want to see all data/information about a specific
|
||||
product.
|
||||
Ordering endpoint - Use, when you want to send orders to the platform.
|
||||
Order endpoint - Use, when you want to see information about a specific order.
|
||||
Rate-limit = 120 requests per minute per IP address
|
||||
2.1 CATALOG ENDPOINT
|
||||
GET https://dropship.ecomzone.eu/api/catalog
|
||||
On this endpoint, we have pagination. By default, it will show 1000 products in
|
||||
response.
|
||||
By adding the url parameter per_page, you can set the number of products per page in
|
||||
response.
|
||||
per_page = integer (optional, min = 10, max = 1000)
|
||||
Example:https://dropship.ecomzone.eu/api/catalog?per_page=10
|
||||
If you set per_page < 10, the system will automatically switch per_page = 10.
|
||||
2.1.1. CURL
|
||||
2.1.2 RESPONSE
|
||||
http status-code
|
||||
Response body as json-encoded array. Each array member is data for one
|
||||
product.
|
||||
Paginated:
|
||||
Pagination response data:
|
||||
|
||||
- "current_page": 1,
|
||||
- "next_page_url": "null",
|
||||
- "path": "https://dropship.ecomzone.eu/api/catalog",
|
||||
- "per_page": "1000",
|
||||
- "prev_page_url": null,
|
||||
- "to": 561,
|
||||
- "total": 561
|
||||
Product_id is part of full_sku, which determines variation of the product(color, size). If
|
||||
there is only 1 product_id, it means that product has only 1 variation, but when creating
|
||||
an order, you still need to send full_sku(main_sku + product_id).
|
||||
2.2 PRODUCT ENDPOINT
|
||||
GET https://dropship.ecomzone.eu/api/product/{main_sku}
|
||||
{main_sku} = product sku
|
||||
Example, in case of Kitchen food processor {2246-911}
|
||||
https://dropship.ecomzone.eu/api/product/2246-911
|
||||
2.2.1 CURL
|
||||
2.2.2 RESPONSE
|
||||
http-code
|
||||
response-body json-encoded array:
|
||||
- status: ok or error
|
||||
- message: error message in case of status = error
|
||||
- data as json-econded array with detail data about product, product-variations,
|
||||
stocks
|
||||
2.3 ORDERING ENDPOINT
|
||||
POST https://dropship.ecomzone.eu/api/ordering
|
||||
request: orders as json-encoded array
|
||||
Each array member represents data for specific order with parameters:
|
||||
- order_index (string or integer) (optional): For indexing specific order in response
|
||||
- ext_id ( string max 20 char ) (optional): Internal order_id, which is visible on platform
|
||||
- shop_name (string max 20 char) (optional): Your custom shop_name, which will be
|
||||
visible on shipping labels as sender of package
|
||||
- payment['method'](string 2 char 'cod' or 'pp') (required):Cash On Delivery or Prepaid
|
||||
- payment['customer_price'] (number integer or decimal) ( required if payment-method =
|
||||
'cod'): Amount which is collected from end customer
|
||||
//customer_price value needs to be sent in local currency
|
||||
- customer_data['full_name] (string max 200) (required): Full name and surname of
|
||||
customer
|
||||
- customer_data['email'] (string max 100) (required): Email address of customer
|
||||
- customer_data['phone_number'] (string max 45) (required): Phone number of
|
||||
customer
|
||||
- customer_data['country'] (string 2 char)(required): Alpha-2 customer country-code
|
||||
- customer_data['address'] (string max 1000) (required): Customer address
|
||||
- customer_data['city] (string max 100) (required): Customer city name
|
||||
- customer_data['post_code'](string max 45)(required): Postal code
|
||||
- customer_data['comment'] (STRING MAX 1000)(optional): Comment/note for courier
|
||||
items: array with data about products in order
|
||||
- items['full_sku'](string) (required): Full-sku of products
|
||||
- items['quantity']( number integer )(required): Quantity of single product in order
|
||||
2.3.1 CURL
|
||||
2.3.2 RESPONSE
|
||||
http status-code (200 - if all orders from request has been successfully imported;
|
||||
202 - if 1 or more orders from request is not imported)
|
||||
response body is in form, json-encoded array:
|
||||
- status: ok(200), accepted(202) or error(422)
|
||||
- message:
|
||||
- data['received] : number of orders in request
|
||||
- data['imported]: number of successfully imported orders
|
||||
- index: json-encoded array with status of each order from request(if
|
||||
order_index is set in request)
|
||||
index['order_index']['status]: ok or error
|
||||
index['order_index]['order_id']: If indexed order was successfully imported
|
||||
(status = ok), here we return order_id, under which order was imported on
|
||||
platform
|
||||
index['order_index]['note]: If order was not imported (status = error), here
|
||||
we return an error message explaining why it was not imported ( which
|
||||
data is incorrect or missing).
|
||||
Use “comment”: “test” or “TEST” when sending test orders, so that they don’t
|
||||
get confirmed automatically in our system.
|
||||
2.4 ORDER ENDPOINT
|
||||
GET https://dropship.ecomzone.eu/api/order/{order_id}
|
||||
{order_id} = ID of order from eComZone platform
|
||||
If the requested order_id does not belong to the user, the response will be
|
||||
401-unauthorized.
|
||||
2.4.1 CURL
|
||||
2.4.2 RESPONSE
|
||||
http-code
|
||||
response-body contains data about order in form json-encoded array:
|
||||
- status: ok or error
|
||||
- data as json-encoded array:
|
||||
- currency
|
||||
- order_status: title of current status
|
||||
- order_created_time: time in format Y-m-d H:i:sa
|
||||
- last_order_status_changed: time of last status changed, in format Y-m-d H:i:s
|
||||
- payment_method: cod or pp
|
||||
- customer_price: value that is collected from customers (cod orders)
|
||||
- returned_bonus: value of return bonus (if exists)
|
||||
- order_tracking_number: tracking number
|
||||
- order_tracking_url: tracking url
|
||||
- order_details['items_cost']: total cost of products in order
|
||||
- order_details['tax']: total amount of tax in order (if exists)
|
||||
- order_details['shipping]: shipping price
|
||||
- order_details['subtotal']: total value/cost of order
|
||||
- order_details['bonus]: bonus amount which we deduct from total cost of order (if
|
||||
exists)
|
||||
- order_details['total']: final value/amount of order to pay
|
||||
BIN
eComZone Dropshipping - API documentation.pdf
Normal file
BIN
eComZone Dropshipping - API documentation.pdf
Normal file
Binary file not shown.
BIN
modules.zip
Normal file
BIN
modules.zip
Normal file
Binary file not shown.
BIN
modules/ecomzone.zip
Normal file
BIN
modules/ecomzone.zip
Normal file
Binary file not shown.
106
modules/ecomzone/classes/EcomZoneAPI.php
Normal file
106
modules/ecomzone/classes/EcomZoneAPI.php
Normal file
@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
class EcomZoneAPI
|
||||
{
|
||||
private $apiKey;
|
||||
private $apiUrl;
|
||||
private $lastRequestTime;
|
||||
private $requestCount = 0;
|
||||
private const RATE_LIMIT = 120; // requests per minute
|
||||
private const RATE_WINDOW = 60; // seconds
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->apiKey = Configuration::get('ECOMZONE_API_KEY');
|
||||
$this->apiUrl = Configuration::get('ECOMZONE_API_URL');
|
||||
$this->lastRequestTime = time();
|
||||
}
|
||||
|
||||
private function checkRateLimit()
|
||||
{
|
||||
$currentTime = time();
|
||||
if ($currentTime - $this->lastRequestTime >= self::RATE_WINDOW) {
|
||||
$this->requestCount = 0;
|
||||
$this->lastRequestTime = $currentTime;
|
||||
}
|
||||
|
||||
if ($this->requestCount >= self::RATE_LIMIT) {
|
||||
throw new Exception('Rate limit exceeded. Please wait before making more requests.');
|
||||
}
|
||||
|
||||
$this->requestCount++;
|
||||
}
|
||||
|
||||
public function getCatalog($perPage = 1000)
|
||||
{
|
||||
$this->checkRateLimit();
|
||||
$url = $this->apiUrl . '/catalog';
|
||||
return $this->makeRequest('GET', $url, ['per_page' => $perPage]);
|
||||
}
|
||||
|
||||
public function getProduct($sku)
|
||||
{
|
||||
$this->checkRateLimit();
|
||||
$url = $this->apiUrl . '/product/' . urlencode($sku);
|
||||
return $this->makeRequest('GET', $url);
|
||||
}
|
||||
|
||||
public function createOrder($orderData)
|
||||
{
|
||||
$this->checkRateLimit();
|
||||
$url = $this->apiUrl . '/ordering';
|
||||
return $this->makeRequest('POST', $url, $orderData);
|
||||
}
|
||||
|
||||
private function makeRequest($method, $url, $params = [])
|
||||
{
|
||||
try {
|
||||
$curl = curl_init();
|
||||
|
||||
$options = [
|
||||
CURLOPT_URL => $url . ($method === 'GET' && !empty($params) ? '?' . http_build_query($params) : ''),
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_ENCODING => '',
|
||||
CURLOPT_MAXREDIRS => 10,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||||
CURLOPT_CUSTOMREQUEST => $method,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Authorization: Bearer ' . $this->apiKey,
|
||||
'Accept: application/json',
|
||||
'Content-Type: application/json'
|
||||
],
|
||||
];
|
||||
|
||||
if ($method === 'POST') {
|
||||
$options[CURLOPT_POSTFIELDS] = json_encode($params);
|
||||
}
|
||||
|
||||
curl_setopt_array($curl, $options);
|
||||
|
||||
$response = curl_exec($curl);
|
||||
$err = curl_error($curl);
|
||||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close($curl);
|
||||
|
||||
if ($err) {
|
||||
throw new Exception("cURL Error: " . $err);
|
||||
}
|
||||
|
||||
if ($httpCode >= 400) {
|
||||
throw new Exception("HTTP Error: " . $httpCode . " Response: " . $response);
|
||||
}
|
||||
|
||||
return json_decode($response, true);
|
||||
} catch (Exception $e) {
|
||||
PrestaShopLogger::addLog(
|
||||
'EcomZone API Error: ' . $e->getMessage(),
|
||||
3,
|
||||
null,
|
||||
'EcomZone'
|
||||
);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
modules/ecomzone/config.xml
Normal file
12
modules/ecomzone/config.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<module>
|
||||
<name>ecomzone</name>
|
||||
<displayName><![CDATA[EcomZone Integration]]></displayName>
|
||||
<version><![CDATA[1.0.0]]></version>
|
||||
<description><![CDATA[Integrates PrestaShop with EcomZone Dropshipping API]]></description>
|
||||
<author><![CDATA[Your Name]]></author>
|
||||
<tab><![CDATA[market_place]]></tab>
|
||||
<is_configurable>1</is_configurable>
|
||||
<need_instance>0</need_instance>
|
||||
<limited_countries></limited_countries>
|
||||
</module>
|
||||
157
modules/ecomzone/ecomzone.php
Normal file
157
modules/ecomzone/ecomzone.php
Normal file
@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
if (!defined('_PS_VERSION_')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class EcomZone extends Module
|
||||
{
|
||||
private $errors = [];
|
||||
private $api;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->name = 'ecomzone';
|
||||
$this->tab = 'market_place';
|
||||
$this->version = '1.0.0';
|
||||
$this->author = 'Your Name';
|
||||
$this->need_instance = 0;
|
||||
$this->bootstrap = true;
|
||||
$this->ps_versions_compliancy = [
|
||||
'min' => '1.7.0.0',
|
||||
'max' => _PS_VERSION_
|
||||
];
|
||||
|
||||
parent::__construct();
|
||||
|
||||
$this->displayName = $this->l('EcomZone Integration');
|
||||
$this->description = $this->l('Integrates PrestaShop with EcomZone Dropshipping API');
|
||||
|
||||
// Initialize API
|
||||
require_once(dirname(__FILE__) . '/classes/EcomZoneAPI.php');
|
||||
$this->api = new EcomZoneAPI();
|
||||
}
|
||||
|
||||
public function install()
|
||||
{
|
||||
if (!parent::install()) {
|
||||
$this->errors[] = $this->l('Could not install the module');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->registerHook('actionProductUpdate')) {
|
||||
$this->errors[] = $this->l('Could not register hooks');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Configuration::updateValue('ECOMZONE_API_KEY', '') ||
|
||||
!Configuration::updateValue('ECOMZONE_API_URL', 'https://dropship.ecomzone.eu/api')) {
|
||||
$this->errors[] = $this->l('Could not set default configuration');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
$output = '';
|
||||
|
||||
if (Tools::isSubmit('submitEcomZone')) {
|
||||
$apiKey = Tools::getValue('ECOMZONE_API_KEY');
|
||||
|
||||
if (!$apiKey) {
|
||||
$output .= $this->displayError($this->l('API Key is required'));
|
||||
} else {
|
||||
Configuration::updateValue('ECOMZONE_API_KEY', $apiKey);
|
||||
$output .= $this->displayConfirmation($this->l('Settings updated'));
|
||||
}
|
||||
}
|
||||
|
||||
return $output . $this->displayForm();
|
||||
}
|
||||
|
||||
public function displayForm()
|
||||
{
|
||||
$fields_form[0]['form'] = [
|
||||
'legend' => [
|
||||
'title' => $this->l('Settings'),
|
||||
],
|
||||
'input' => [
|
||||
[
|
||||
'type' => 'text',
|
||||
'label' => $this->l('API Key'),
|
||||
'name' => 'ECOMZONE_API_KEY',
|
||||
'required' => true,
|
||||
'size' => 50
|
||||
],
|
||||
],
|
||||
'submit' => [
|
||||
'title' => $this->l('Save'),
|
||||
'class' => 'btn btn-default pull-right'
|
||||
]
|
||||
];
|
||||
|
||||
$helper = new HelperForm();
|
||||
$helper->module = $this;
|
||||
$helper->name_controller = $this->name;
|
||||
$helper->token = Tools::getAdminTokenLite('AdminModules');
|
||||
$helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
|
||||
$helper->default_form_language = Configuration::get('PS_LANG_DEFAULT');
|
||||
$helper->fields_value['ECOMZONE_API_KEY'] = Configuration::get('ECOMZONE_API_KEY');
|
||||
|
||||
return $helper->generateForm($fields_form);
|
||||
}
|
||||
|
||||
public function getErrors()
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
public function hookActionProductUpdate($params)
|
||||
{
|
||||
try {
|
||||
$product = $params['product'];
|
||||
$productId = $product->id;
|
||||
|
||||
// Get product reference (SKU)
|
||||
$reference = $product->reference;
|
||||
|
||||
if (!empty($reference)) {
|
||||
// Get product data from EcomZone
|
||||
$ecomZoneProduct = $this->api->getProduct($reference);
|
||||
|
||||
if ($ecomZoneProduct && isset($ecomZoneProduct['data'])) {
|
||||
// Update stock
|
||||
if (isset($ecomZoneProduct['data']['stock'])) {
|
||||
StockAvailable::setQuantity($productId, 0, (int)$ecomZoneProduct['data']['stock']);
|
||||
}
|
||||
|
||||
// Update price
|
||||
if (isset($ecomZoneProduct['data']['product_price'])) {
|
||||
$product->price = (float)$ecomZoneProduct['data']['product_price'];
|
||||
$product->update();
|
||||
}
|
||||
|
||||
PrestaShopLogger::addLog(
|
||||
sprintf('EcomZone: Updated product %s (ID: %d)', $reference, $productId),
|
||||
1, // Notice level
|
||||
null,
|
||||
'Product',
|
||||
$productId,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
PrestaShopLogger::addLog(
|
||||
sprintf('EcomZone: Error updating product %d: %s', $productId, $e->getMessage()),
|
||||
3, // Error level
|
||||
null,
|
||||
'Product',
|
||||
$productId,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
8
modules/ecomzone/index.php
Normal file
8
modules/ecomzone/index.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
header('Location: ../');
|
||||
exit;
|
||||
8
modules/ecomzone/vendor/index.php
vendored
Normal file
8
modules/ecomzone/vendor/index.php
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
header('Location: ../');
|
||||
exit;
|
||||
20
modules/ecomzone/views/templates/admin/configure.tpl
Normal file
20
modules/ecomzone/views/templates/admin/configure.tpl
Normal file
@ -0,0 +1,20 @@
|
||||
<form method="post" action="{$current|escape:'html':'UTF-8'}&token={$token|escape:'html':'UTF-8'}">
|
||||
<div class="panel">
|
||||
<div class="panel-heading">
|
||||
<i class="icon-cogs"></i> {l s='EcomZone Settings' mod='ecomzone'}
|
||||
</div>
|
||||
<div class="form-wrapper">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-lg-3">{l s='API Key' mod='ecomzone'}</label>
|
||||
<div class="col-lg-9">
|
||||
<input type="text" name="ECOMZONE_API_KEY" value="{$ECOMZONE_API_KEY|escape:'html':'UTF-8'}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<button type="submit" name="submitEcomZone" class="btn btn-default pull-right">
|
||||
<i class="process-icon-save"></i> {l s='Save' mod='ecomzone'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
Loading…
Reference in New Issue
Block a user