Daniel 3 лет назад
Родитель
Сommit
93451b0b7b
5 измененных файлов: 550 добавлений и 0 удалений
  1. +119
    -0
      api/ApiExact.php
  2. +147
    -0
      api/IsotopeDatabaseHandler.php
  3. +271
    -0
      api/Product.php
  4. +12
    -0
      api/apiUpdateProducts.php
  5. +1
    -0
      api/tokenData

+ 119
- 0
api/ApiExact.php Просмотреть файл

@@ -0,0 +1,119 @@
<?php
/**
* @author Daniel Knudsen <d.knudsen@spawntree.de>
* @date 11.07.22
*/

require_once('Product.php');

class ApiExact
{
const API_URL = "https://start.exactonline.de/api";
const CLIENT_ID = "5a04d118-349c-4750-aac3-fa3a386999c6";
const CLIENT_SECRET = "E7Wuqcsp4Lih";
const ACCESS_TOKEN_VALID_DURATION = 600 - 50;

const DIVISION = '58687';
const ITEM_GROUP_UUID = 'df17bdaf-2af7-4e9f-8d60-326e36b57764';
const PRODUCT_CODE_PREFIX = "WR";

public function getAccessToken()
{
$tokenData = json_decode(file_get_contents('./tokenData', true));
if (!property_exists($tokenData, 'expiry_time') || (int)$tokenData->expiry_time < time()) {
$postData = array(
'grant_type' => 'refresh_token',
'refresh_token' => $tokenData->refresh_token,
'client_id' => self::CLIENT_ID,
'client_secret' => self::CLIENT_SECRET
);

$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => self::API_URL . '/oauth2/token',
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_HTTPHEADER => array('Content-Type: application/x-www-form-urlencoded'),
CURLOPT_POSTFIELDS => http_build_query($postData)
));

$response = curl_exec($ch);
curl_close($ch);

$jsonResult = json_decode($response);

if (property_exists($jsonResult, 'error')) {
$msg = $jsonResult->error;
throw new Exception($msg);
}


$jsonResult->expiry_time = time() + self::ACCESS_TOKEN_VALID_DURATION;
file_put_contents('./tokenData', json_encode($jsonResult));

$tokenData = json_decode(file_get_contents('./tokenData', true));
}
return $tokenData->access_token;
}

public function getProducts()
{
$baseUrl = self::API_URL . '/v1/' . self::DIVISION . "/bulk/Logistics/Items?";
$fields = [
'ID',
'StandardSalesPrice',
'SalesVatCode',
'SalesVatCodeDescription',
'Description',
'ExtraDescription',
'IsWebshopItem',
'ItemGroup',
'ItemGroupCode',
'Stock',
'NetWeight',
'GrossWeight',
'Code'
];
$filter = "\$filter=ItemGroup eq guid'".self::ITEM_GROUP_UUID."'";
$select = "&\$select=".$this->getFieldString($fields);
$requestUrl = $baseUrl . $filter . $select;
$response = $this->getApiData($requestUrl);
$responseArr = json_decode($response, 1)['d']['results'];

$res = [];
foreach ($responseArr as $productItem) {
if (
array_key_exists('IsWebshopItem', $productItem) &&
$productItem['IsWebshopItem'] === 1 &&
array_key_exists('Code', $productItem) &&
stripos(strtoupper($productItem['Code']), self::PRODUCT_CODE_PREFIX) === 0
) {
$res[] = Product::createProductFromApiItem($productItem);
}
}
return $res;
}

private function getApiData($url)
{
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $url,
CURLOPT_HTTPHEADER => array('Accept: application/json' , "Authorization: Bearer " . $this->getAccessToken() ),
CURLOPT_RETURNTRANSFER => TRUE,
));
return curl_exec($ch);
}

private function getFieldString($fields)
{
$res = '';
$cnt = count($fields);
$i = 1;
foreach ($fields as $field) {
$res .= $cnt !== $i ? $field . ',' : $field;
$i++;
}
return $res;
}

}

+ 147
- 0
api/IsotopeDatabaseHandler.php Просмотреть файл

@@ -0,0 +1,147 @@
<?php
/**
* @author Daniel Knudsen <d.knudsen@spawntree.de>
* @date 11.07.22
*/

require_once('Product.php');

class IsotopeDatabaseHandler
{
const USER = 'root';
const PASSWORD = '';
const HOST = '127.0.0.1';
const DB_NAME = 'wash_n_roll';

private $dbHandle;

public function __construct()
{
try {
$this->dbHandle = new PDO('mysql:host='.self::HOST.';dbname='.self::DB_NAME.';charset=utf8',self::USER, self::PASSWORD);
$this->dbHandle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
}


public function updateProducts(array $products)
{
/** @var Product $product */
foreach ($products as $product) {
$productId = $this->updateProduct($product);
$productPriceId = $this->updatePrice($product, $productId);
$this->updatePriceTier($product, $productPriceId);
}


}

private function updateProduct(Product $product)
{
$alias = 'exact-product-'.$product->getCode();
$shippingWeight = $product->getGrossWeight() !== '' ?
($product->getNetWeight() !== '' ? $product->getNetWeight() : '') : '';
$sql =
"INSERT into `tl_iso_product` (
pid,
gid,
tstamp,
language,
dateAdded,
type,
fallback,
alias,
gtin,
sku,
name,
description,
meta_title,
baseprice,
shipping_weight,
shipping_exempt,
shipping_pickup,
shipping_price,
protected,
guests,
cssID,
published,
start,
stop
) VALUES (
0,
0,
".time().",
'',
".time().",
2,
'',
'$alias',
'',
'".$product->getCode()."',
'".$product->getDescription()."',
'".$product->getExtraDescription()."',
'',
'',
'$shippingWeight',
'',
'',
0.00,
'',
'',
'',
'0',
'',
''
)";
$this->dbHandle->query($sql);
return $this->dbHandle->lastInsertId();
}

private function updatePrice(Product $product, $productDbId)
{
$sql =
"INSERT INTO `tl_iso_product_price` (
pid,
tstamp,
tax_class,
config_id,
member_group,
start,
stop
) VALUES (
$productDbId,
".time().",
1,
0,
0,
'',
''
)";
$this->dbHandle->query($sql);
return $this->dbHandle->lastInsertId();
}

private function updatePriceTier(Product $product, $productPriceDbId)
{
$price = $product->getStandardSalesPrice() * (1 + Product::VAT);
$sql =
"INSERT INTO `tl_iso_product_pricetier` (
pid,
tstamp,
min,
price
) VALUES (
$productPriceDbId,
".time().",
1,
$price
)";
$this->dbHandle->query($sql);
return $this->dbHandle->lastInsertId();
}
}

+ 271
- 0
api/Product.php Просмотреть файл

@@ -0,0 +1,271 @@
<?php
/**
* @author Daniel Knudsen <d.knudsen@spawntree.de>
* @date 11.07.22
*/


class Product
{
const VAT = 0.19;

private $id;
private $standardSalesPrice;
private $salesVatCode;
private $salesVatCodeDescription;
private $description;
private $extraDescription;
private $isWebShopItem;
private $itemGroup;
private $itemGroupCode;
private $stock;
private $netWeight;
private $grossWeight;
private $code;

public static function getFields()
{
return [
'ID',
'StandardSalesPrice',
'SalesVatCode',
'SalesVatCodeDescription',
'Description',
'ExtraDescription',
'IsWebshopItem',
'ItemGroup',
'ItemGroupCode',
'Stock',
'NetWeight',
'GrossWeight',
'Code',
];
}

public static function createProductFromApiItem(array $item)
{
$res = new self();
$res->setId($item['ID']);
$res->setStandardSalesPrice($item['StandardSalesPrice']);
$res->setSalesVatCode($item['SalesVatCode']);
$res->setSalesVatCodeDescription($item['SalesVatCodeDescription']);
$res->setDescription($item['Description']);
$res->setExtraDescription($item['ExtraDescription']);
$res->setIsWebShopItem($item['IsWebshopItem']);
$res->setItemGroup($item['ItemGroup']);
$res->setItemGroupCode($item['ItemGroupCode']);
$res->setStock($item['Stock']);
$res->setNetWeight($item['NetWeight']);
$res->setGrossWeight($item['GrossWeight']);
$res->setCode($item['Code']);
return $res;
}

/**
* @return mixed
*/
public function getId()
{
return $this->id;
}

/**
* @param mixed $id
*/
public function setId($id)
{
$this->id = $id;
}

/**
* @return mixed
*/
public function getStandardSalesPrice()
{
return $this->standardSalesPrice;
}

/**
* @param mixed $standardSalesPrice
*/
public function setStandardSalesPrice($standardSalesPrice)
{
$this->standardSalesPrice = $standardSalesPrice;
}

/**
* @return mixed
*/
public function getSalesVatCode()
{
return $this->salesVatCode;
}

/**
* @param mixed $salesVatCode
*/
public function setSalesVatCode($salesVatCode)
{
$this->salesVatCode = $salesVatCode;
}

/**
* @return mixed
*/
public function getSalesVatCodeDescription()
{
return $this->salesVatCodeDescription;
}

/**
* @param mixed $salesVatCodeDescription
*/
public function setSalesVatCodeDescription($salesVatCodeDescription)
{
$this->salesVatCodeDescription = $salesVatCodeDescription;
}

/**
* @return mixed
*/
public function getDescription()
{
return $this->description;
}

/**
* @param mixed $description
*/
public function setDescription($description)
{
$this->description = $description;
}

/**
* @return mixed
*/
public function getExtraDescription()
{
return $this->extraDescription;
}

/**
* @param mixed $extraDescription
*/
public function setExtraDescription($extraDescription)
{
$this->extraDescription = $extraDescription;
}

/**
* @return mixed
*/
public function getIsWebShopItem()
{
return $this->isWebShopItem;
}

/**
* @param mixed $isWebShopItem
*/
public function setIsWebShopItem($isWebShopItem)
{
$this->isWebShopItem = $isWebShopItem;
}

/**
* @return mixed
*/
public function getItemGroup()
{
return $this->itemGroup;
}

/**
* @param mixed $itemGroup
*/
public function setItemGroup($itemGroup)
{
$this->itemGroup = $itemGroup;
}

/**
* @return mixed
*/
public function getItemGroupCode()
{
return $this->itemGroupCode;
}

/**
* @param mixed $itemGroupCode
*/
public function setItemGroupCode($itemGroupCode)
{
$this->itemGroupCode = $itemGroupCode;
}

/**
* @return mixed
*/
public function getStock()
{
return $this->stock;
}

/**
* @param mixed $stock
*/
public function setStock($stock)
{
$this->stock = $stock;
}

/**
* @return mixed
*/
public function getNetWeight()
{
return $this->netWeight;
}

/**
* @param mixed $netWeight
*/
public function setNetWeight($netWeight)
{
$this->netWeight = $netWeight;
}

/**
* @return mixed
*/
public function getGrossWeight()
{
return $this->grossWeight;
}

/**
* @param mixed $grossWeight
*/
public function setGrossWeight($grossWeight)
{
$this->grossWeight = $grossWeight;
}

/**
* @return mixed
*/
public function getCode()
{
return $this->code;
}

/**
* @param mixed $code
*/
public function setCode($code)
{
$this->code = $code;
}
}

+ 12
- 0
api/apiUpdateProducts.php Просмотреть файл

@@ -0,0 +1,12 @@
<?php
require __DIR__ . '/ApiExact.php';
require __DIR__ . '/IsotopeDatabaseHandler.php';

$apiConnector = new ApiExact();
$databaseHandler = new IsotopeDatabaseHandler();

//echo $apiConnector->getAccessToken() . "\n";
$products = $apiConnector->getProducts();
$databaseHandler->updateProducts($products);

$b = 0;

+ 1
- 0
api/tokenData Просмотреть файл

@@ -0,0 +1 @@
{"access_token":"stampDE001.gAAAAHwOSGEkvQm9cR0GLsLKi-DF5HztPTxwFs1cElb0YqYwsA4Du2xEN2_QDZQaRP2S7JqojAxH7Pgh9bGX8aMk_w2Mc6E8Za3DfOCs5_IU89TUfIZfo-OlriYaWguDBjIhWDV7uyb0fyMk83Vplk4hffbmyTdvoTA1GbmvO9x-wEWYVAIAAIAAAAAMQCUSoZTK5-qcCHPI6G15WhlRHy2qHRJKJIJ3ugg6F95dz8Wq4oLsgD4Ej7n_9zloDUbYzABmiTMs6vu-wa4R3DjXmDtvZ5tFauTNTvlSVdbo-rT5rbHUo_LcdGTdE18njXZDBpK7K58cQXVq4zGxViUoqzrEu8aiqDhfwI93_pAXr1ABdwTj6sFxzeqRTAwIo2WVBG7uwzvYLQCrCUqpzxfxUgwH0FBbjEzcglBx56hNshomL4SNqbqqGIKaK1lNGOKz0jkxnuRdY0-nlBPsi0FN6goQDAE3wfKUFzj8DU0nyQAZhdedAtk4q3AT1mPnM9wuOxIwp3EXDeuYkiCIQNWSvU7WJJaWMqfRPrab86diQ5ffBxWDVc0HnpHgQVWr0peKvzLXS4lx5_pTgwLaJUurvlRbG0LI88x-qcMmGgbj2a54FaF93RrNOtHaheiGZh_CBDwqbT54vrFaxxwp-yNmYLVk2-2c70RUwobUInw9E_eR2RNPU9oHGQTMTQR9at_3jZ5dR68UyrY6BMCGJrqrTvSpXkmJNKhkjP9WHlWtz-dC-gt_m2cYaWifow76NAKHONyRk3-i6Qu3vKDc8vXyyi-RLeX6R0nLYV07p7yHsgSo2E8em5C6KdkHIQjJIanYyHUVf7noHJMuKIrrvaHBfdTuiC1ZbemwzPCsb7sdOftAb5vW3oxSEMmckuCVEROmeTyoZCDAV5oyecNAah73Sx7WLx87npWFhC0F71myL11vkWf5MSt8lQ-o-kZCt0Wws7h9KStVrb3mux9v","token_type":"bearer","expires_in":"600","refresh_token":"stampDE001.vhK0!IAAAANf_ePo7TNLoW4eBzZwdyynZfR7KhO8joJp6EgWw0pF58QEAAAFBqPStZfQ04DNGVJ23edCAkbZsdhwNjz3GfWOQoMaGhf3uoG8iydpqma1dDKY3MmFI5CNNxIKvpiN0jnvHqgi0g6O5QijAmgtB3_sVmzs4L0ODxGt3Befp2rJKu2MMBDySEJ_00XVZzBIKmZqVA6XUflZ7mfbotp22vTRbthYOMZlyz0OIT1leJKHfU8XYgB5Zzp8gPHxsSca93Kh3_3CQRp0ZoGR5YKSh1C2zw8QyVCBU_092gLonzTGHKlaIUd6nVT4oIhzXC9i9Dh7wL-9PSfk7m9OqJ7wX0h-p8wkO4bqjkSJofeglSrAvS3G1U8yo0QpxmJQW1FHsm-7q1s6w4O03LV9LsSZX93Wjm8mMq789tlZFZh7-MqO5_zQcwmgizMVDMbBsxPUMU1ITOrTYBAalNf9kyLvrGE-M4jhK_qQbGQ3FATy25U3QjoEQC9K_PWNyqY2XrzPDHSAoprI6hZxY9lYY71tDg3L10KB6BFXDM6bDj_oWa0BAI-TfO_cKRPhXxt9bAquWxhLYHNFdV-d0Il7FeRgI_Dmp7OsKYuFw6rrd6C8Vuz1AxuTaNT1G3V-ugUn5L-VV12JiLgMTTrBLK6OGh5fooDE3Li8tM7WiA5-K9HgP3Jsesdrl2O7ClBUFRrrhtiQINNgkLN1f","expiry_time":1657581261}

Загрузка…
Отмена
Сохранить