diff --git a/www/pages/shopimporter_mirakl.php b/www/pages/shopimporter_mirakl.php
index 48537af5..2f369bd6 100644
--- a/www/pages/shopimporter_mirakl.php
+++ b/www/pages/shopimporter_mirakl.php
@@ -29,6 +29,7 @@ class Shopimporter_Mirakl extends ShopimporterBase {
private $category_identifier;
private $offer_field_map;
+ private $product_field_map;
public function __construct($app, $intern = false) {
$this->app = $app;
@@ -81,6 +82,31 @@ class Shopimporter_Mirakl extends ShopimporterBase {
'info' => '',
'default' => 'kategoriename'
],
+ 'product_field_map' => [
+ 'typ' => 'textarea',
+ 'bezeichnung' => '{|Zuordnung Produkt-Felder je Kategorie (JSON)|}:',
+ 'cols' => 80,
+ 'rows' => 20,
+ 'info' => 'Die Felder werden vom Mirakl-Betreiber vorgegeben. Ist keine Kategorie definiert, gilt der Eintrag für alle Artikel. Jedes Feld kann wie folgt zugeordnet werden:
Artikelfeld: "Mirakel-Feldname": {"feld": "xyz"} oder kurz "Mirakel-Feldname": "xyz",
Freifeld: "Mirakel-Feldname": {"freifeld": "Bezeichnung in Shop"} (Siehe Reiter "Freifelder"),
Eigenschaft: "Mirakel-Feldname": {"eigenschaft": "Eigenschaftenname xyz"},
Fester Wert: "Mirakel-Feldname": {"wert": "xyz"}
Zusatzfelder zusätzlich mit der Eigenschaft "zusatzfeld": true versehen: z.B. "Mirakel-Feldname": {"feld": "name_de", "zusatzfeld": true}',
+ 'placeholder' => '[
+ {
+ "kategorien": [
+ "Schuhe", "Hosen"
+ ],
+ "felder": {
+ "category": {"freifeld": "Kategorie"},
+ "Product.SellerProductID": {"feld": "nummer"},
+ "SHOP.PRODUCT.TITLE": {"feld": "nummer"},
+ "ATT.GLOBAL.Brandname": {"feld": "preis"},
+ "Product.BaseUnit": {"freifeld": "Kategorie"},
+ "ATT.GLOBAL.NoCUperOU": {"eigenschaft": "Mirakl Steuertext"},
+ "ATT.GLOBAL.NoCUperOU__UNIT": {"wert": "false","zusatzfeld": true},
+ "Product.TaxIndicator": {"wert": "1","zusatzfeld": true}
+ }
+ }
+]'
+ ],
+
'offer_field_map' => [
'typ' => 'textarea',
'bezeichnung' => '{|Zuordnung Angebots-Felder je Kategorie (JSON)|}:',
@@ -145,10 +171,11 @@ class Shopimporter_Mirakl extends ShopimporterBase {
$this->category_identifier = array($einstellungen['felder']['category_identifier_source'] => $einstellungen['felder']['category_identifier_source_value']);
- $this->offer_field_map = json_decode($einstellungen['felder']['offer_field_map'], true, flags: JSON_THROW_ON_ERROR);
+ $this->offer_field_map = json_decode($einstellungen['felder']['offer_field_map'], true, flags: JSON_THROW_ON_ERROR);
+ $this->product_field_map = json_decode($einstellungen['felder']['product_field_map'], true, flags: JSON_THROW_ON_ERROR);
}
- private function miraklRequest(string $endpoint, $postdata = null, array $getdata = null, string $content_type = null, bool $raw = false) {
+ private function miraklRequest(string $endpoint, $postdata = null, array $getdata = null, string $content_type = null, bool $raw = false, $debug = false, $debugurl = null) {
$ch = curl_init();
$url_addition = "";
@@ -171,10 +198,17 @@ class Shopimporter_Mirakl extends ShopimporterBase {
if (!empty($postdata)) {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
+
$headers[] = 'Content-Type: ' . $content_type;
}
- curl_setopt($ch, CURLOPT_URL, $this->shopUrl . $endpoint . $url_addition);
+ if ($debugurl) {
+ $url = $debugurl;
+ } else {
+ $url = $this->shopUrl;
+ }
+
+ curl_setopt($ch, CURLOPT_URL, $url . $endpoint . $url_addition);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_VERBOSE, true);
@@ -187,11 +221,12 @@ class Shopimporter_Mirakl extends ShopimporterBase {
$information = curl_getinfo($ch);
-/* print_r($information);
- print_r($postdata);
- print_r($response);
- exit();
-*/
+ if ($debug) {
+ print_r($information);
+ print_r($postdata);
+ print_r($response);
+ exit();
+ }
if ($raw)
return $response;
@@ -287,6 +322,8 @@ class Shopimporter_Mirakl extends ShopimporterBase {
public function ImportSendList() {
$articleList = $this->CatchRemoteCommand('data');
+
+ $this->Log('ImportSendList start', print_r($articleList,true));
// First gather all articles as offers and send them
// Wait for import to finish
@@ -378,12 +415,15 @@ class Shopimporter_Mirakl extends ShopimporterBase {
$json_for_mirakl = json_encode($data_for_mirakl);
+ $this->Log('posting offer data', $json_for_mirakl);
+
$result = [];
$response = $this->miraklRequest('offers', postdata: $json_for_mirakl, content_type: 'application/json', raw: true);
$result = json_decode($response);
if (!isset($result->import_id)) {
+ $this->Log('posting offer data error', print_r($response,true));
return(array('status' => false, 'message' => "Angebotsimport in Mirakl abgelehnt: ".print_r($response,true)));
}
@@ -405,16 +445,120 @@ class Shopimporter_Mirakl extends ShopimporterBase {
}
if ($status == 'FAILED') {
+ $this->Log('importing of offer data failed in mirakl', print_r($response,true));
return(array('status' => false, 'message' => "Angebotsimport in Mirakl fehlgeschlagen: ".print_r($response,true)));
}
-
+
if ($result->lines_in_error == 0) {
+ $this->Log('importing of offer data ok', print_r($response,true));
return($result->lines_in_success);
}
- // Check errors
- $response = $this->miraklRequest('offers/imports/'.$import_id.'/error_report', raw: true);
- return(array('status' => false, 'message' => "Angebotsimport in Mirakl hat Fehler: ".print_r($response,true)));
+ $this->Log('importing of offer returned with '.$result->lines_in_error.' lines', print_r($response,true));
+
+ $result = array();
+ // Check errors with CSV unfucking...
+ $response = $this->miraklRequest('offers/imports/'.$import_id.'/error_report', raw: true);
+ $response_lines = preg_split('/\R/', $response, flags: PREG_SPLIT_NO_EMPTY);
+
+ $error_message_key = null;
+ $firstline = true;
+
+ foreach ($response_lines as $response_line) {
+
+ $response_array = str_getcsv($response_line,';','"');
+
+ if ($firstline) {
+ $error_message_key = array_search("error-message",$response_array);
+ $firstline = false;
+ continue;
+ }
+
+ switch ($response_array[$error_message_key]) {
+ case 'The product does not exist':
+
+ // Try to create the product
+ $product_for_mirakl = array();
+
+ print_r($this->product_field_map);
+
+ foreach ($this->product_field_map as $product_field_entry) {
+ foreach ($product_field_entry['felder'] as $product_field => $product_field_source) {
+ if (!is_array($product_field_source)) {
+ $product_field_source = array('feld' => $product_field_source);
+ }
+ $product_field_value = null;
+ $product_field_value = $this->GetFieldValue($article, $product_field_source);
+ $product_for_mirakl[$product_field] = $product_field_value;
+ }
+ }
+
+ $this->Log('creating product', print_r($product_for_mirakl,true));
+
+ // Create CSV from array
+ $csv1 .= '"'.implode('";"',array_keys($product_for_mirakl)).'"';
+ $csv2 .= '"'.implode('";"',$product_for_mirakl).'"';
+ $csv = $csv1."\r\n".$csv2;
+
+ $result = [];
+
+ $this->Log('creating product csv', print_r($csv,true));
+
+ $postdata = array('file' => new CURLStringFile(postname: 'import.csv', data: $csv));
+
+ $response = $this->miraklRequest('products/imports', postdata: $postdata, content_type: 'multipart/form-data', raw: true);
+
+ $result = json_decode($response);
+
+ $this->Log('posting product data posted', print_r($result,true));
+
+ if (!isset($result->import_id)) {
+ $this->Log('posting product data error', print_r($response,true));
+ return(array('status' => false, 'message' => "Produktimport in Mirakl abgelehnt: ".print_r($response,true)));
+ }
+
+ $import_id = $result->import_id;
+
+ // Wait for import to finish
+
+ $status = null;
+
+ /*
+ WAITING_SYNCHRONIZATION_PRODUCT, WAITING, RUNNING, COMPLETE, FAILED
+ */
+
+ while ($status != 'COMPLETE' && $status != 'FAILED') {
+ sleep(5);
+ $response = $this->miraklRequest('products/imports/'.$import_id, raw: true);
+ $result = json_decode($response);
+ $status = $result->import_status;
+ }
+
+ if ($status == 'FAILED') {
+ $this->Log('importing of product data failed in mirakl', print_r($response,true));
+ return(array('status' => false, 'message' => "Produktimport in Mirakl fehlgeschlagen: ".print_r($response,true)));
+ }
+
+ if ($result->transform_lines_in_error == 0) {
+ $this->Log('importing of product data ok', print_r($response,true));
+ return($result->lines_in_success);
+ }
+
+ $this->Log('importing of product returned with '.$result->transform_lines_in_error.' error lines', print_r($response,true));
+
+ $response = $this->miraklRequest('products/imports/'.$import_id.'/transformation_error_report', raw: true);
+
+ $this->Log('product import error report', print_r($response,true));
+
+
+ break;
+ default:
+ $result[] = array('Unhandled error' => $response_array);
+ break;
+ }
+ }
+
+ return(array('status' => false, 'message' => "Angebotsimport in Mirakl hat Fehler: ".print_r($result,true)));
}
@@ -424,7 +568,7 @@ class Shopimporter_Mirakl extends ShopimporterBase {
private function Log($message, $dump = '') {
if ($this->protocol) {
- $this->app->erp->Logfile($message, print_r($dump, true));
+ $this->app->erp->Logfile('Mirakl (Shop '.$this->shopid.') '.$message, print_r($dump, true));
}
}