From b5926ee039cfb490c6393b7daa84325eef717f76 Mon Sep 17 00:00:00 2001 From: OpenXE <> Date: Fri, 2 Dec 2022 12:19:42 +0000 Subject: [PATCH] Bugfix www/pages/shopimporter_shopware6.php --- www/pages/shopimporter_shopware6.php | 7634 +++++++++++++------------- 1 file changed, 3817 insertions(+), 3817 deletions(-) diff --git a/www/pages/shopimporter_shopware6.php b/www/pages/shopimporter_shopware6.php index 3189b694..c6cfa630 100644 --- a/www/pages/shopimporter_shopware6.php +++ b/www/pages/shopimporter_shopware6.php @@ -1,3820 +1,3820 @@ -app = $app; - $this->intern = true; - if ($intern) { - return; - } - $this->app->ActionHandlerInit($this); - - $this->app->ActionHandler('list', 'Shopimporter_Shopware6List'); - $this->app->ActionHandler('auth', 'ImportAuth'); - $this->app->ActionHandler('sendlistlager', 'ImportSendListLager'); - $this->app->ActionHandler('getauftraegeanzahl', 'ImportGetAuftraegeAnzahl'); - $this->app->ActionHandler('getauftrag', 'ImportGetAuftrag'); - $this->app->ActionHandler('deleteauftrag', 'ImportDeleteAuftrag'); - $this->app->ActionHandler('updateauftrag', 'ImportUpdateAuftrag'); - $this->app->ActionHandler('storniereauftrag','ImportStorniereAuftrag'); - $this->app->ActionHandler('getarticle','ImportGetArticle'); - $this->app->ActionHandler('getarticlelist','ImportGetArticleList'); - $this->app->ActionHandler("updatezahlungsstatus","ImportUpdateZahlungsstatus"); - $this->app->DefaultActionHandler('list'); - - $this->app->ActionHandlerListen($app); - } - - /** - * @param string $productId - * - * @return mixed - */ - public function addSyncCustomFieldToProduct(string $productId) - { - $customField = [ - 'customFields' => [ - 'wawision_shopimporter_syncstate' => 1 - ] - ]; - - return $this->shopwareRequest('PATCH', "product/{$productId}", $customField); - } - - /** - * @param string $orderId - * - * @return mixed - */ - public function addCustomFieldToOrder(string $orderId) - { - $customField = [ - 'customFields' => [ - 'wawision_shopimporter_syncstate' => 1 - ] - ]; - - return $this->shopwareRequest('PATCH', "order/{$orderId}", $customField); - } - - public function ImportGetArticleList() - { - $page = 1; - $limit = 500; - - do { - $productIdsToAdd = []; - $searchdata = [ - 'limit' => $limit, - 'page' => $page, - 'filter' => [ - [ - 'field' => 'product.parentId', - 'type' => 'equals', - 'value' => null - ] - ] - ]; - - $productsInShop = $this->shopwareRequest('POST', 'search/product', $searchdata); - if (!empty($productsInShop['data'])) { - foreach ($productsInShop['data'] as $productInShop) { - $productIdsToAdd[] = $productInShop['id']; - } - } - - foreach ($productIdsToAdd as $productId) { - $this->app->DB->Insert("INSERT INTO shopexport_getarticles (shop, nummer) VALUES ('$this->shopid', '" . $this->app->DB->real_escape_string($productId) . "')"); - } - $page++; - } while (count($productsInShop['data']) === $limit); - - - $anzahl = $this->app->DB->Select("SELECT COUNT(id) FROM shopexport_getarticles WHERE shop=$this->shopid"); - $this->app->erp->SetKonfigurationValue('artikelimportanzahl_' . $this->shopid, $anzahl); - - } - - /** - * @param string $method - * @param string $endpoint - * @param string $data - * - * @param array $headerInformation - * @return mixed - */ - public function shopwareRequest($method, $endpoint, $data = '', $headerInformation = []) - { - $accessToken = $this->shopwareToken(); - $url = $this->ShopUrl; - $url .= 'v2/' . $endpoint; - - $ch = curl_init(); - $headerInformation[] = 'Content-Type:application/json'; - $headerInformation[] = 'Authorization:Bearer ' . $accessToken['token']; - curl_setopt($ch, CURLOPT_URL, $url); - if (!empty($data)) { - curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); - } - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); - curl_setopt($ch, CURLOPT_HTTPHEADER, $headerInformation); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - $response = curl_exec($ch); - if (curl_error($ch)) { - $this->error[] = curl_error($ch); - } - curl_close($ch); - - return json_decode($response, true); - } - - /** - * @return array - */ - protected function shopwareToken() - { - $result = []; - - $result['success'] = true; - $result['token'] = $this->accessToken; - $result['message'] = 'Keine Antwort von API erhalten.'; - - if (!empty($result['token'])) { - return $result; - } - - $result['success'] = false; - - $data = [ - 'username' => $this->UserName, - 'password' => $this->Password, - 'grant_type' => 'password', - 'scopes' => 'write', - 'client_id' => 'administration', - ]; - - $ch = curl_init($this->ShopUrl . 'oauth/token'); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); - curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ - 'Accept: application/json', - 'Content-Type: application/json', - 'Cache-Control: no-cache', - ] - ); - $response = json_decode(curl_exec($ch), true); - - if (!empty((string)$response['title'])) { - $result['message'] = $response['title']; - } - - if (!empty($response['access_token'])) { - $result['success'] = true; - $this->accessToken = $response['access_token']; - $result['token'] = $response['access_token']; - } - - return $result; - } - - public function ImportGetArticle() - { - $tmp = $this->CatchRemoteCommand('data'); - - if (isset($tmp['nummerintern'])) { - $nummer = $tmp['nummerintern']; - $response = $this->shopwareRequest('GET', 'product/' . $nummer); - if (empty($response['data'])) { - $this->error[] = 'Artikel in der Shop Datenbank nicht gefunden!'; - return; - } - $nummer = $response['data']['attributes']['productNumber']; - } else { - $nummer = $tmp['nummer']; - } - $articleInfo = $this->shopwareRequest('GET', 'product?filter[product.productNumber]=' . $nummer . - '&associations[manufacturer][]&associations[properties][]'); - if (empty($articleInfo['data'][0])) { - $this->error[] = 'Artikel in der Shop Datenbank nicht gefunden!'; - return; - } - $articleIdInShop = $articleInfo['data'][0]['id']; - if(empty($articleInfo['data'][0]['customFields']) - || empty($articleInfo['data'][0]['customFields']['wawision_shopimporter_syncstate'])){ - $this->addSyncCustomFieldToProduct((string)$articleIdInShop); - } - - $articleInfo = $this->shopwareRequest('GET', 'product?filter[product.productNumber]=' . $nummer . - '&associations[manufacturer][]&associations[properties][]'); - $associatedInformation = []; - $properties = []; - foreach ($articleInfo['included'] as $includedInformation) { - if ($includedInformation['type'] === 'property_group_option') { - $properties[$includedInformation['id']] = $includedInformation['attributes']; - } else { - $associatedInformation[$includedInformation['id']] = $includedInformation['attributes']; - } - } - $groups = []; - if (!empty($properties)) { - $groupsInShop = $this->shopwareRequest('GET', 'property-group'); - foreach ($groupsInShop['data'] as $groupInShop) { - $groups[$groupInShop['id']] = $groupInShop['attributes']['name']; - } - } - $media = $this->shopwareRequest('GET', 'product/' . $articleIdInShop . '/media'); - $imagesToAdd = []; - if (!empty($media['included'])) { - foreach ($media['included'] as $mediaInfo) { - if ($mediaInfo['type'] === 'media') { - $imagesToAdd[] = [ - 'content' => base64_encode(@file_get_contents($mediaInfo['attributes']['url'])), - 'path' => $mediaInfo['attributes']['url'], - 'id' => $mediaInfo['id'] - ]; - } - } - } - $articleInfo = $articleInfo['data'][0]['attributes']; - - $data = []; - $data['name'] = $articleInfo['name']; - if (isset($tmp['nummerintern'])) { - $data['nummer'] = $articleInfo['productNumber']; - } - - - $data['artikelnummerausshop'] = $articleInfo['productNumber']; - $data['restmenge'] = $articleInfo['stock']; - $data['uebersicht_de'] = $articleInfo['description']; - $data['preis_netto'] = $articleInfo['price'][0]['net']; - if (!empty($articleInfo['price'][0]['listPrice'])) { - $data['pseudopreis'] = $articleInfo['price'][0]['listPrice']; - } - $data['aktiv'] = $articleInfo['active']; - if (!empty($articleInfo['weight'])) { - $data['gewicht'] = $articleInfo['weight']; - } - if (!empty($articleInfo['manufacturerNumber'])) { - $data['herstellernummer'] = $articleInfo['manufacturerNumber']; - } - if (!empty($articleInfo['ean'])) { - $data['ean'] = $articleInfo['ean']; - } - if (!empty($articleInfo['manufacturerId'])) { - $data['hersteller'] = $associatedInformation[$articleInfo['manufacturerId']]['name']; - } - if (!empty($articleInfo['taxId'])) { - $data['umsatzsteuer'] = $associatedInformation[$articleInfo['taxId']]['taxRate']; - } - if (!empty($properties)) { - foreach ($properties as $property) { - if ($this->propertyOption === 'toProperties') { - $data['eigenschaften'][] = [ - 'name' => $groups[$property['groupId']], - 'values' => $property['name'], - ]; - } - if ($this->propertyOption === 'toCustomFields') { - $data['freifeld_' . $groups[$property['groupId']]] = $property['name']; - } - } - } - if (!empty($articleInfo['customFields'])) { - foreach ($articleInfo['customFields'] as $customFieldName => $customFieldValue) { - if ($this->freeFieldOption === 'toProperties') { - $data['eigenschaften'][] = [ - 'name' => $customFieldName, - 'values' => $customFieldValue - ]; - } - if ($this->freeFieldOption === 'toCustomFields') { - $data['freifeld_' . $customFieldName] = $customFieldValue; - } - } - } - if (!empty($imagesToAdd)) { - $data['bilder'] = $imagesToAdd; - } - - - if ($articleInfo['childCount'] > 0) { - $data = [$data]; - - $limit = 50; - $page = 1; - $optionInfo = []; - $optionGroupInfo = []; - do { - - $searchdata = [ - 'limit' => $limit, - 'page' => $page, - 'filter' => [ - [ - 'field' => 'product.parentId', - 'type' => 'equals', - 'value' => $articleIdInShop - ] - ], - 'sort' => [ - [ - 'field' => 'product.options.groupId', - 'naturalSorting' => false, - 'order' => 'ASC' - ], - [ - 'field' => 'product.options.id', - 'naturalSorting' => false, - 'order' => 'ASC' - ] - ], - 'associations' => [ - 'options' => [ - 'sort' => [ - [ - 'field' => 'groupId', - 'naturalSorting' => false, - 'order' => 'ASC' - ], - [ - 'field' => 'id', - 'naturalSorting' => false, - 'order' => 'ASC' - ] - ] - ] - ] - ]; - $variantsInShop = $this->shopwareRequest('POST', 'search/product', $searchdata); - foreach ($variantsInShop['included'] as $includedInfo) { - if ($includedInfo['type'] === 'property_group_option') { - $optionInfo[$includedInfo['id']] = $includedInfo['attributes']; - if (empty($optionGroupInfo[$includedInfo['attributes']['groupId']])) { - $optionGroupInfo[$includedInfo['attributes']['groupId']] = (!empty($optionGroupInfo)?count($optionGroupInfo):0) + 1; - } - } - } - - foreach ($variantsInShop['data'] as $variantInShop) { - $variantData = []; - $variantName = $data[0]['name']; - foreach ($variantInShop['attributes']['optionIds'] as $optionId) { - $variantData['matrixprodukt_wert' . $optionGroupInfo[$optionInfo[$optionId]['groupId']]] = - $optionInfo[$optionId]['name']; - $variantName .= ' - ' . $optionInfo[$optionId]['name']; - } - - $variantData['name'] = $variantName; - $variantData['nummer'] = $variantInShop['attributes']['productNumber']; - $variantData['artikelnummerausshop'] = $variantInShop['attributes']['productNumber']; - $variantData['restmenge'] = $variantInShop['attributes']['stock']; - $variantData['uebersicht_de'] = $variantInShop['attributes']['description']; - if (empty($variantInShop['attributes']['price'][0]['net'])) { - $variantData['preis_netto'] = $data[0]['preis_netto']; - } else { - $variantData['preis_netto'] = $variantInShop['attributes']['price'][0]['net']; - } - if (!empty($variantInShop['attributes']['price'][0]['listPrice'])) { - $variantData['pseudopreis'] = $variantInShop['attributes']['price'][0]['listPrice']; - } - $variantData['aktiv'] = $variantInShop['attributes']['active']; - if (!empty($variantInShop['attributes']['weight'])) { - $variantData['gewicht'] = $variantInShop['attributes']['weight']; - } - if (!empty($variantInShop['attributes']['manufacturerNumber'])) { - $variantData['herstellernummer'] = $variantInShop['attributes']['manufacturerNumber']; - } - if (!empty($variantInShop['attributes']['ean'])) { - $variantData['ean'] = $variantInShop['attributes']['ean']; - } - if (!empty($data[0]['umsatzsteuer'])) { - $variantData['umsatzsteuer'] = $data[0]['umsatzsteuer']; - } - - $data[] = $variantData; - } - - $page++; - } while (count($variantsInShop['data']) > $limit); - - foreach ($optionGroupInfo as $groupId => $sorting) { - $data[0]['matrixprodukt_gruppe' . $sorting] = $groups[$groupId]; - } - foreach ($optionInfo as $optionData) { - $data[0]['matrixprodukt_optionen' . $optionGroupInfo[$optionData['groupId']]][] = $optionData['name']; - } - } - - //TODO Staffelpreise - //TODO Kategorien - //TODO Freifelder - //TODO Crossselling - - return $data; - } - - /** - * @param array $data - * - * @return array - */ - public function checkApiApp($data) - { - foreach (['shopwareUserName', 'shopwarePassword', 'shopwareUrl'] as $field) { - if (empty($data['data'][$field])) { - return ['success' => false, 'error' => sprintf('%s is empty', $field)]; - } - } - - $shops = $this->app->DB->SelectArr( - sprintf( - "SELECT `einstellungen_json`, `bezeichnung`,`id` - FROM `shopexport` - WHERE `modulename` = 'shopimporter_shopware6' - AND `einstellungen_json` IS NOT NULL AND `einstellungen_json` <> ''" - ) - ); - if (empty($shops)) { - return [ - 'info' => [ - 'Shop' => 'Shopware', - 'info' => 'Url ' . $data['data']['shopwareUrl'], - ] - ]; - } - foreach ($shops as $shop) { - if (empty($shop['einstellungen_json'])) { - continue; - } - $json = @json_decode($shop['einstellungen_json'], true); - if (empty($json['felder']) || empty($json['felder']['shopwareUrl'])) { - continue; - } - if ($json['felder']['shopwareUrl'] === $data['data']['shopwareUrl']) { - return [ - 'success' => false, - 'error' => sprintf('Shop with url %s allready exists', $data['data']['shopwareUrl']) - ]; - } - } - - return [ - 'info' => [ - 'Shop' => 'Shopware', - 'info' => 'Url ' . $data['data']['shopwareUrl'], - ] - ]; - } - - /** - * - */ - public function Shopimporter_Shopware6List() - { - $msg = $this->app->erp->base64_url_encode('
Sie können hier die Shops einstellen
'); - header('Location: index.php?module=onlineshops&action=list&msg=' . $msg); - exit; - } - - /** - * @param $shopid - * @param $data - */ - public function getKonfig($shopid, $data) - { - $this->shopid = $shopid; - $this->data = $data; - $importerSettings = $this->app->DB->SelectArr("SELECT `einstellungen_json`, `kategorienuebertragen` FROM `shopexport` WHERE `id` = '$shopid' LIMIT 1"); - $importerSettings = reset($importerSettings); - - $this->exportCategories = (bool) $importerSettings['kategorienuebertragen']; - - $einstellungen = []; - if (!empty($importerSettings['einstellungen_json'])) { - $einstellungen = json_decode($importerSettings['einstellungen_json'], true); - } - $this->protocol = $einstellungen['felder']['protocol']; - $this->UserName = $einstellungen['felder']['shopwareUserName']; - $this->Password = $einstellungen['felder']['shopwarePassword']; - $this->ShopUrl = rtrim($einstellungen['felder']['shopwareUrl'], '/') . '/'; - $this->createManufacturerAllowed = false; - if ($einstellungen['felder']['shopwareAllowCreateManufacturer'] === '1') { - $this->createManufacturerAllowed = true; - } - $this->defaultManufacturer = $einstellungen['felder']['shopwareDefaultManufacturer']; - $this->defaultRuleName = $einstellungen['felder']['shopwareDefaultRuleName']; - $this->statesToFetch = $einstellungen['felder']['statesToFetch']; - $this->deliveryStatesToFetch = $einstellungen['felder']['deliveryStatesToFetch']; - $this->transactionStatesToFetch = $einstellungen['felder']['transactionStatesToFetch']; - $this->salesChannelToFetch = $einstellungen['felder']['salesChannelToFetch']; - $this->orderSearchLimit = $einstellungen['felder']['orderSearchLimit']; - $this->freeFieldOption = $einstellungen['felder']['shopwareFreeFieldOption']; - $this->propertyOption = $einstellungen['felder']['shopwarePropertyOption']; - $this->shopwareDefaultSalesChannel = $einstellungen['felder']['shopwareDefaultSalesChannel']; - $this->shopwareMediaFolder = $einstellungen['felder']['shopwareMediaFolder']; - $query = sprintf('SELECT `steuerfreilieferlandexport` FROM `shopexport` WHERE `id` = %d', $this->shopid); - $this->taxationByDestinationCountry = !empty($this->app->DB->Select($query)); - - $this->client = $this->app->Container->get('Shopware6Client'); - $this->client->setCredentials( - $this->UserName, - $this->Password, - $this->ShopUrl - ); - } - - /** - * @return array - */ - public function EinstellungenStruktur() - { - return - [ - 'ausblenden' => ['abholmodus' => ['ab_nummer']], - 'functions' => ['exportartikelbaum','getarticlelist','updatezahlungsstatus'], - 'felder' => [ - 'protocol' => [ - 'typ' => 'checkbox', - 'bezeichnung' => '{|Protokollierung im Logfile|}:', - ], - 'shopwareUserName' => [ - 'typ' => 'text', - 'bezeichnung' => '{|Benutzername|}:', - 'size' => 40, - ], - 'shopwarePassword' => [ - 'typ' => 'text', - 'bezeichnung' => '{|Passwort|}:', - 'size' => 40, - ], - 'shopwareUrl' => [ - 'typ' => 'text', - 'bezeichnung' => '{|Shop API URL|}:', - 'size' => 40, - ], - 'shopwareDefaultManufacturer' => [ - 'typ' => 'text', - 'bezeichnung' => '{|Standard Hersteller|}:', - 'size' => 40, - 'default' => 'Keine Herstellerinformation', - ], - 'shopwareAllowCreateManufacturer' => [ - 'typ' => 'checkbox', - 'bezeichnung' => '{|Bei Artikelexport Hersteller anlegen|}:', - ], - 'shopwareDefaultRuleName' => [ - 'typ' => 'text', - 'bezeichnung' => '{|Name der Standardpreisgruppe|}:', - 'size' => 40, - 'default' => 'All customers', - ], - 'shopwarePropertyOption' => [ - 'heading' => '{|Eigenschaften / Freifeld Zuordnung|}', - 'typ' => 'select', - 'bezeichnung' => '{|Xentral Artikel Eigenschaften|}:', - 'size' => 40, - 'default' => 'toProperties', - 'optionen' => ['toProperties' => '{|Shopware Eigenschaften|}', 'toCustomFields' => '{|Shopware Zusatzfelder|}', 'doNotExport' => '{|Nicht übertragen|}'] - ], - 'shopwareFreeFieldOption' => [ - 'typ' => 'select', - 'bezeichnung' => '{|Xentral Artikel Freifelder|}:', - 'size' => 40, - 'default' => 'toCustomFields', - 'optionen' => ['toProperties' => '{|Shopware Eigenschaften|}', 'toCustomFields' => '{|Shopware Zusatzfelder|}', 'doNotExport' => '{|Nicht übertragen|}'] - ], - 'shopwareDefaultSalesChannel' => [ - 'heading' => '{|Artikelexport Standardeinstellungen|}', - 'typ' => 'text', - 'bezeichnung' => '{|Standard Sichtbarkeit|}:', - 'size' => 40 - ], - 'shopwareMediaFolder' => [ - 'typ' => 'text', - 'bezeichnung' => '{|Media Folder für Artikelbilder|}:', - 'size' => 40, - 'default' => 'Product Media' - ], - 'statesToFetch' => [ - 'typ' => 'text', - 'bezeichnung' => '{|Abzuholender Bestellstatus|}:', - 'size' => 40, - 'default' => 'open', - 'col' => 2, - 'info' => '
Erlaubte Werte: open;in_progress;completed;cancelled' - ], - 'deliveryStatesToFetch' => [ - 'typ' => 'text', - 'bezeichnung' => '{|Eingrenzen auf Lieferstatus|}:', - 'size' => 40, - 'default' => '', - 'col' => 2, - 'info' => '
Erlaubte Werte: open;shipped_partially;shipped;returned;returned_partially;cancelled' - ], - 'transactionStatesToFetch' => [ - 'typ' => 'text', - 'bezeichnung' => '{|Eingrenzen auf Bezahlstatus|}:', - 'size' => 40, - 'default' => '', - 'col' => 2, - 'info' => '
Erlaubte Werte: open;paid;authorized;paid_partially;refunded;refunded_partially;reminded;cancelled' - ], - 'salesChannelToFetch' => [ - 'typ' => 'text', - 'bezeichnung' => '{|Eingrenzen auf Sales Channel|}:', - 'size' => 40, - 'default' => '', - 'col' => 2, - 'info' => '
Klicke auf "Verbindung prüfen" um die verfügbaren Channels (bitte die Id verwenden) anzuzeigen.' - ], - 'orderSearchLimit' => [ - 'typ' => 'select', - 'bezeichnung' => '{|Anzahl Aufträge abholen|}:', - 'optionen' => [ - '25' => '25', - '50' => '50', - '75' => '75', - '100' => '100', - ], - 'default' => '25', - 'col' => 2 - ], - ], - ]; - } - - public function ImportUpdateZahlungsstatus() - { - $tmp = $this->CatchRemoteCommand('data'); - $auftrag = $tmp['auftrag']; - - $transactions = $this->shopwareRequest('GET', 'order/'.$auftrag.'/transactions'); - $transactionId = $transactions['data'][0]['id']; - - if(empty($transactionId)){ - return; - } - - $response = $this->shopwareRequest('POST', '_action/order_transaction/'.$transactionId.'/state/paid'); - if (!empty($response['id'])) { - return 'ok'; - } - } - - public function ImportSendArtikelbaum(){ - $xentralCategoryTree = []; - $this->app->erp->GetKategorienbaum($xentralCategoryTree, 0, 0, $this->shopid); - - $xentralCategoryIdToParentId = []; - foreach ($xentralCategoryTree as $key => $value) { - $xentralCategoryTree[$key]['erledigt'] = false; - $xentralCategoryTree[$key]['shopid'] = ''; - $xentralCategoryTree[$key]['aktiv'] = false; - $xentralCategoryIdToParentId[$value['id']] = $key; - } - - $parentCategoryId = null; - foreach ($xentralCategoryTree as $index => $categoryData) { - $this->createCategoryTree($index, $xentralCategoryTree, $xentralCategoryIdToParentId, $parentCategoryId); - } - } - - protected function createCategoryTree($id, &$xentralCategoryTree, $xentralCategoryIdToParentId, $parentCategoryId) - { - $parentId = $parentCategoryId; - if ($xentralCategoryTree[$id]['parent']) { - $parentId = $xentralCategoryTree[$xentralCategoryIdToParentId[$xentralCategoryTree[$id]['parent']]]['shopid']; - } - if ($xentralCategoryTree[$id]['parent'] && !$xentralCategoryTree[$xentralCategoryIdToParentId[$xentralCategoryTree[$id]['parent']]]['erledigt']) { - $this->createCategoryTree($xentralCategoryIdToParentId[$xentralCategoryTree[$id]['parent']], $xentralCategoryTree, $xentralCategoryIdToParentId, $parentCategoryId); - } - $xentralCategoryTree[$id]['erledigt'] = true; - - $categoryName = $xentralCategoryTree[$id]['bezeichnung']; - $searchdata = [ - 'limit' => 25, - 'filter' => [ - [ - 'field' => 'category.name', - 'type' => 'equals', - 'value' => $categoryName - ], - [ - 'field' => 'category.parentId', - 'type' => 'equals', - 'value' => $parentId - ] - ] - ]; - - $categoriesInShop = $this->shopwareRequest('POST', 'search/category', $searchdata); - - $categoryId = ''; - if (!empty($categoriesInShop['data'])) { - $categoryId = $categoriesInShop['data'][0]['id']; - } - - if (!$categoryId) { - $categoryData = [ - 'parentId' => $parentId, - 'name' => $categoryName - ]; - $result = $this->shopwareRequest('POST', 'category?_response=true', $categoryData); - if ($result['data']['id']) { - $categoryId = $result['data']['id']; - } - } - - if ($categoryId) { - $xentralCategoryTree[$id]['shopid'] = $categoryId; - } - } - - /** - * @return int - */ - public function ImportSendListLager() - { - $tmp = $this->CatchRemoteCommand('data'); - - $count = 0; - foreach ($tmp as $article) { - $artikel = $article['artikel']; - if ($artikel === 'ignore') { - continue; - } - $nummer = $article['nummer']; - $fremdnummer = $article['fremdnummer']; - if (!empty($fremdnummer)) { - $nummer = $fremdnummer; - } - $articleInfo = $this->shopwareRequest('GET', 'product?filter[product.productNumber]=' . $nummer); - - if (empty($articleInfo['data'][0]['id'])) { - $this->Shopware6Log('Artikel wurde nicht im Shop gefunden: ' . $nummer, $articleInfo); - continue; - } - if(empty($articleInfo['data'][0]['customFields']) - || empty($articleInfo['data'][0]['customFields']['wawision_shopimporter_syncstate'])){ - $this->addSyncCustomFieldToProduct((string)$articleInfo['data'][0]['id']); - } - - $active = true; - if ($article['inaktiv']) { - $active = false; - } - - $stock = $article['anzahl_lager']; - if (!empty($article['pseudolager'])) { - $stock = $article['pseudolager']; - } - $stock = $this->getCorrectedStockFromAvailable($active, (int)$stock, $articleInfo); - $data = [ - 'stock' => $stock, - 'active' => $active, - ]; - $response = $this->shopwareRequest('PATCH', 'product/' . $articleInfo['data'][0]['id'], $data); - $this->Shopware6Log('Lagerbestand konnte nicht uebertragen werden fuer Artikel: ' . $nummer, $response); - $count++; - } - - return $count; - } - - /** - * @param bool $isStockActive - * @param int $stock - * @param array|null $articleInfo - * - * @return int - */ - public function getCorrectedStockFromAvailable(bool $isStockActive, int $stock, ?array $articleInfo): int - { - if(!$isStockActive) { - return $stock; - } - if(empty($articleInfo)) { - return $stock; - } - if(!isset($articleInfo['data'][0]['attributes']['availableStock'])) { - return $stock; - } - if(!isset($articleInfo['data'][0]['attributes']['availableStock'])) { - return $stock; - } - $reserved = (int)$articleInfo['data'][0]['attributes']['stock'] - - (int)$articleInfo['data'][0]['attributes']['availableStock']; - if($reserved <= 0) { - return $stock; - } - - return $stock + $reserved; - } - - /** - * @param string $message - * @param mixed $dump - */ - public function Shopware6Log($message, $dump = '') - { - if ($this->protocol) { - $this->app->erp->Logfile($message, print_r($dump, true)); - } - } - - /** - * @return int - */ - public function ImportSendList() - { - $articleList = $this->CatchRemoteCommand('data'); - - $successCounter = 0; - foreach ($articleList as $article) { - $number = $article['nummer']; - $articleInfo = $this->shopwareRequest( - 'GET', - sprintf('product?filter[product.productNumber]=%s', $number) - ); - $articleIdShopware = ''; - if (!empty($articleInfo['data'][0]['id'])) { - $articleIdShopware = $articleInfo['data'][0]['id']; - } - - $quantity = $article['anzahl_lager']; - if (!empty($article['pseudolager'])) { - $quantity = $article['pseudolager']; - } - $inaktiv = $article['inaktiv']; - $active = true; - if (!empty($inaktiv)) { - $active = false; - } - $quantity = $this->getCorrectedStockFromAvailable($active, (int)$quantity, $articleInfo); - $taxRate = (float)$article['steuersatz']; - - $taxId = $this->getTaxIdByRate($taxRate); - - $mediaToAdd = $this->mediaToExport($article, $articleIdShopware); - - $categoriesToAdd = []; - if($this->exportCategories){ - $categoriesToAdd = $this->categoriesToExport($article, $articleIdShopware); - } - - $propertiesToAdd = $this->propertiesToExport($article, $articleIdShopware); - - $crosselingToAdd = $this->crosssellingToExport($article, $articleIdShopware); - - $systemFieldsToAdd = $this->systemFieldsToExport($article, $articleIdShopware); - - $deliveryTimeId = null; - if(!empty($article['lieferzeitmanuell'])){ - $deliveryTimeId = $this->getDeliveryTimeId($article['lieferzeitmanuell']); - } - - if (empty($systemFieldsToAdd['visibilities']) && !empty($this->shopwareDefaultSalesChannel)) { - $systemFieldsToAdd['visibilities'] = $this->modifySalesChannel(explode(',', $this->shopwareDefaultSalesChannel), $articleIdShopware); - } - - if(empty($systemFieldsToAdd['unitId']) && !empty($article['einheit']) ){ - $systemFieldsToAdd['unitId'] = $this->unitToAdd($article['einheit']); - } - - - //Hersteller in Shopware suchen bzw. Anlegen - $manufacturerName = $article['hersteller']; - $manufacturerId = $this->getManufacturerIdByName($manufacturerName); - - if ($manufacturerId === null && $this->createManufacturerAllowed === true) { - $manufacturerId = $this->createManufacturer($manufacturerName); - } - - if (empty($manufacturerId)) { - return 'error: Für den Artikelexport ist die Herstellerinformation zwingend erforderlich'; - } - - $isCloseOut = false; - if(!empty($article['restmenge'])){ - $isCloseOut = true; - } - - $description = $this->prepareDescription($article['uebersicht_de']); - $ean = $article['ean']; - $metaTitle = $article['metatitle_de']; - $metaDescription = $article['metadescription_de']; - $metaKeywords = $article['metakeywords_de']; - - $manufacturerNumber = $article['herstellernummer']; - if (empty($manufacturerNumber)) { - $manufacturerNumber = ''; - } - - $weight = (float)$article['gewicht']; - $length = (float)$article['laenge'] * 10; - $height = (float)$article['hoehe'] * 10; - $width = (float)$article['breite'] * 10; - - $purchasePrice = (float)$article['einkaufspreis']; - - $currencyId = $this->findCurrencyId($article['waehrung']); - $price = [ - 'net' => $article['preis'], - 'gross' => $article['bruttopreis'], - 'currencyId' => $currencyId, - 'linked' => true]; - - if (!empty($article['pseudopreis'])) { - $price['listPrice'] = [ - 'currencyId' => $currencyId, - 'gross' => $article['pseudopreis'], - 'linked' => true, - 'net' => $article['pseudopreis']/(1+$taxRate/100) - ]; - } - - $data = [ - 'name' => $article['name_de'], - 'isCloseout' => $isCloseOut, - 'productNumber' => $number, - 'manufacturerId' => $manufacturerId, - 'stock' => (int)$quantity, - 'taxId' => $taxId, - 'active' => $active, - 'description' => $description, - 'ean' => $ean, - 'metaTitle' => $metaTitle, - 'metaDescription' => $metaDescription, - 'keywords' => $metaKeywords, - 'manufacturerNumber' => $manufacturerNumber, - 'length' => $length, - 'width' => $width, - 'height' => $height, - 'weight' => $weight, - 'purchasePrice' => $purchasePrice, - 'price' => [$price], - 'categories' => $categoriesToAdd, - 'properties' => $propertiesToAdd, - 'crossSellings' => $crosselingToAdd, - 'media' => $mediaToAdd, - 'deliveryTimeId' => $deliveryTimeId - ]; - - $data = array_merge($data, $systemFieldsToAdd); - if(empty($data['customFields']) - || empty($data['customFields']['wawision_shopimporter_syncstate'])){ - $data['customFields']['wawision_shopimporter_syncstate'] = 1; - } - - if (empty($articleIdShopware)) { - $result = $this->shopwareRequest('POST', - 'product?_response=true', $data); - if (!empty($result['data']['id'])) { - $articleIdShopware = $result['data']['id']; - $articleInfo['data'][0] = $result['data']; - } - } else { - $headerInformation = []; - $languageId = $this->getLanguageIdByCountryIso('DE'); - if (!empty($languageId)) { - $headerInformation[] = 'sw-language-id: ' . $languageId; - } - $result = $this->shopwareRequest('PATCH', - sprintf('product/%s?_response=true', $articleIdShopware), $data, $headerInformation); - } - - if(!empty($articleIdShopware)){ - $this->exportTranslationsForArticle($article, $articleIdShopware); - } - - $this->addCoverImage($article, $articleIdShopware); - - if (empty($result['data']) || is_array($result['errors'])) { - $this->Shopware6Log('Artikelexport fehlgeschlagen', ['data:' => $data, 'response' => $result]); - continue; - } - - $this->exportSeoUrls($article, $articleIdShopware); - - $this->exportVariants($article, $articleIdShopware, $currencyId); - - if (empty($result['data']) || is_array($result['errors'])) { - $this->Shopware6Log('Artikelexport bei Bildübertragung fehlgeschlagen', ['data:' => $data, 'response' => $result]); - continue; - } - - $defaultPrices = $this->getPricesFromArray($article['staffelpreise_standard'] ?? []); - $groupPrices = $this->getPricesFromArray($article['staffelpreise_gruppen'] ?? []); - - if (!empty($defaultPrices) || !empty($groupPrices)) { - $this->deleteOldBulkPrices($articleIdShopware); - } - if (!empty($defaultPrices)) { - foreach ($defaultPrices as $priceData) { - $this->exportBulkPriceForGroup($articleIdShopware, $this->defaultRuleName, $priceData); - } - } - if (!empty($groupPrices)) { - foreach ($groupPrices as $priceData) { - $this->exportBulkPriceForGroup($articleIdShopware, $priceData->getGroupName(), $priceData); - } - } - - $successCounter++; - } - - return $successCounter; - } - - protected function exportBulkPriceForGroup(string $productId, string $groupName, PriceData $priceData): void - { - $currencyId = $this->findCurrencyId($priceData->getCurrency()); - - $groupRuleId = $this->client->getGroupRuleId($groupName); - if (empty($groupRuleId)) { - $this->Shopware6Log("Fehler: Gruppe {$groupName} konnte im Shop nicht gefunden werden"); - return; - } - - $result = $this->client->saveBulkPrice($productId, $groupRuleId, $currencyId, $priceData); - if (empty($result['data'])) { - $this->Shopware6Log("Fehler: Staffelpreis für Gruppe {$groupName} konnte nicht exportiert werden", $result); - } - } - - /** - * @param string $deliveryTimeText - * - * @return string|null - */ - protected function getDeliveryTimeId(string $deliveryTimeText): ?string - { - $searchCommand = [ - 'limit' => 5, - 'filter' => [ - [ - 'field' => 'name', - 'type' => 'equals', - 'value' => $deliveryTimeText - ] - ] - ]; - $result = $this->shopwareRequest('POST', 'search/delivery-time', $searchCommand); - - if (empty($result['data'][0]['id'])) { - return null; - } - - return $result['data'][0]['id']; - } - - /** - * @param string $description - * @return string - */ - protected function prepareDescription($description): string - { - $markupSubstitute = [ - '/"/' => '"', - '/<([^&]+)>/' => '<\1>', - '/\\/' => '', - '/\\<\/strong>/' => '', - '/\\/' => '', - '/\\<\/em>/' => '', - '/&/' => '&', - ]; - - return (string)preg_replace(array_keys($markupSubstitute), array_values($markupSubstitute), $description); - } - - /** - * @param array $article - * @param string $articleIdShopware - */ - protected function exportTranslationsForArticle(array $article, string $articleIdShopware): void - { - $customFieldsToAdd = $this->customFieldsToExport($article, $articleIdShopware); - - $preparedTranslations = []; - $preparedTranslations['DE'] = [ - 'name' => $article['name_de'], - 'description' => $this->prepareDescription($article['uebersicht_de']), - 'metaTitle' => $article['metatitle_de'], - 'metaDescription' => $article['metadescription_de'], - 'keywords' => $article['metakeywords_de'], - 'customFields' => [] - ]; - if(!empty($customFieldsToAdd['DE'])){ - $preparedTranslations['DE']['customFields'] = $customFieldsToAdd['DE']; - } - $preparedTranslations['GB'] = [ - 'name' => $article['name_en'], - 'description' => $this->prepareDescription($article['uebersicht_en']), - 'metaTitle' => $article['metatitle_en'], - 'metaDescription' => $article['metadescription_en'], - 'keywords' => $article['metakeywords_en'], - 'customFields' => [], - ]; - if(!empty($customFieldsToAdd['GB'])){ - $preparedTranslations['GB']['customFields'] = $customFieldsToAdd['GB']; - } - foreach ($article['texte'] as $translation) { - if ($translation['sprache'] === 'EN') { - $translation['sprache'] = 'GB'; - } - $preparedTranslations[$translation['sprache']] = [ - 'name' => $translation['name'], - 'description' => $this->prepareDescription($translation['beschreibung_online']), - 'metaTitle' => $translation['meta_title'], - 'metaDescription' => $translation['meta_description'], - 'keywords' => $translation['meta_keywords'], - ]; - if(!empty($customFieldsToAdd[$translation['sprache']])){ - $preparedTranslations[$translation['sprache']]['customFields'] = $customFieldsToAdd[$translation['sprache']]; - } - } - - foreach ($preparedTranslations as $countryIsoCode => $translation) { - $languageId = $this->getLanguageIdByCountryIso($countryIsoCode); - if (empty($languageId)) { - $this->Shopware6Log('Language Id not found for country: ' . $countryIsoCode); - continue; - } - - $headerInformation = ['sw-language-id: ' . $languageId]; - $this->shopwareRequest( - 'PATCH', - sprintf('product/%s', $articleIdShopware), - $translation, $headerInformation - ); - } - } - - /** - * @param string $countryIso - * - * @return string|null - */ - protected function getLanguageIdByCountryIso(string $countryIso): ?string - { - if(array_key_exists($countryIso, $this->knownShopLanguageIds)){ - return $this->knownShopLanguageIds[$countryIso]; - } - - $searchCommand = [ - 'limit' => 5, - 'filter' => [ - [ - 'field' => 'country.iso', - 'type' => 'equals', - 'value' => $countryIso - ] - ] - ]; - $countryInformation = $this->shopwareRequest('POST', 'search/country', $searchCommand); - - foreach ($countryInformation['data'] as $country){ - $searchCommand = [ - 'limit' => 5, - 'filter' => [ - [ - 'field' => 'locale.territory', - 'type' => 'equals', - 'value' => $country['attributes']['name'] - ] - ] - ]; - $localeInformation = $this->shopwareRequest('POST', 'search/locale', $searchCommand); - foreach ($localeInformation['data'] as $locale) { - $searchCommand = [ - 'limit' => 5, - 'filter' => [ - [ - 'field' => 'language.localeId', - 'type' => 'equals', - 'value' => $locale['id'] - ] - ] - ]; - $languageInformation = $this->shopwareRequest('POST', 'search/language', $searchCommand); - if (!empty($languageInformation['data'][0]['id'])) { - $this->knownShopLanguageIds[$countryIso] = $languageInformation['data'][0]['id']; - return $languageInformation['data'][0]['id']; - } - } - } - $this->knownShopLanguageIds[$countryIso] = null; - - return null; - } - - /** - * @param string $manufacturerName - * - * @return null|string - */ - protected function createManufacturer(string $manufacturerName): ?string - { - $data = ['name' => $manufacturerName]; - $response = $this->shopwareRequest('POST', 'product-manufacturer?_response=true', $data); - - $manufacturerId = null; - if(!empty($response['data']['id'])){ - $manufacturerId = $response['data']['id']; - $this->knownManufacturerIds[$manufacturerName] = $manufacturerId; - } - - return $manufacturerId; - } - - /** - * @param string $manufacturerName - * - * @return null|string - */ - protected function getManufacturerIdByName(string $manufacturerName): ?string - { - if (!empty($this->knownManufacturerIds[$manufacturerName])) { - return $this->knownManufacturerIds[$manufacturerName]; - } - - $manufacturerId = null; - if (empty($manufacturerName)) { - $manufacturerName = $this->defaultManufacturer; - } - $manufacturer = $this->shopwareRequest( - 'GET', - 'product-manufacturer?filter[product_manufacturer.name]=' . urlencode($manufacturerName) - ); - $manufacturerId = $manufacturer['data'][0]['id']; - $this->knownManufacturerIds[$manufacturerName] = $manufacturerId; - - return $manufacturerId; - } - - /** - * @param float $taxRate - * - * @return string - */ - protected function getTaxIdByRate(float $taxRate): string{ - if(empty($this->taxesInShop)){ - $this->taxesInShop = $this->shopwareRequest('GET', 'tax'); - } - foreach ($this->taxesInShop['data'] as $taxData) { - if (abs(($taxData['attributes']['taxRate']-$taxRate)) < 0.0001 ) { - return $taxData['id']; - } - } - - return $this->taxesInShop['data'][0]['id']; - } - - /** - * @param array $internalArticleData - * @param string $articleIdShopware - * - * @return array - */ - protected function mediaToExport($internalArticleData, $articleIdShopware) - { - $mediaToAdd = [ - ]; - - if (empty($internalArticleData['Dateien'])) { - return $mediaToAdd; - } - $internalMediaIds = []; - - $searchdata = [ - 'limit' => 1, - 'filter' => [ - [ - 'field' => 'name', - 'type' => 'equals', - 'value' => $this->shopwareMediaFolder - ] - ] - ]; - $mediaFolderData = $this->shopwareRequest('POST', 'search/media-folder', $searchdata); - if(empty($mediaFolderData['data'][0]['id'])){ - $this->Shopware6ErrorLog('Kein Media Folder gefunden für: ', $this->shopwareMediaFolder); - return []; - } - - $mediaFolderId = $mediaFolderData['data'][0]['id']; - - foreach ($internalArticleData['Dateien'] as $internalFile) { - $filename = explode('.', $internalFile['filename']); - unset($filename[(!empty($filename)?count($filename):0) - 1]); - $filename = $internalFile['id'].'_'.implode($filename); - $extension = $internalFile['extension']; - $imageTitle = (string)$internalFile['titel']; - $imageAltText = (string)$internalFile['beschreibung']; - $accessToken = $this->shopwareToken(); - - $searchdata = [ - 'limit' => 5, - 'filter' => [ - [ - 'field' => 'media.fileName', - 'type' => 'equals', - 'value' => $filename - ] - ] - ]; - $mediaData = $this->shopwareRequest('POST', 'search/media', $searchdata); - if (!empty($mediaData['data'][0]['id'])) { - $internalMediaIds[] = $mediaData['data'][0]['id']; - if($mediaData['data'][0]['attributes']['title'] !== $imageTitle - || $mediaData['data'][0]['attributes']['alt'] !== $imageAltText){ - $this->setMediaTitleAndAltText($mediaData['data'][0]['id'], $imageTitle, $imageAltText); - } - continue; - } - - $mediaData = $this->shopwareRequest('POST', 'media?_response=true', []); - if(empty($mediaData['data']['id'])){ - $this->Shopware6Log('Error when creating media for sku: ' . $internalArticleData['nummer'], - ['mediaData' => $mediaData, 'title' => $imageTitle, 'text' => $imageAltText]); - continue; - } - $mediaId = $mediaData['data']['id']; - $this->setMediaTitleAndAltText($mediaId, $imageTitle, $imageAltText); - - $mediaAssociationData = [ - [ - 'action' => 'upsert', - 'entity' => 'media', - 'payload' => [ - [ - 'id' => $mediaId, - 'mediaFolderId' => $mediaFolderId - ] - ] - ] - ]; - $this->shopwareRequest('POST', '_action/sync?_response=true', $mediaAssociationData); - - $url = $this->ShopUrl . 'v2/_action/media/' . $mediaId . '/upload?extension=' . $extension . '&fileName=' . $filename; - $ch = curl_init(); - $setHeaders = [ - 'Content-Type:image/' . $extension, - 'Authorization:Bearer ' . $accessToken['token'] - ]; - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_POSTFIELDS, base64_decode($internalFile['datei'])); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); - curl_setopt($ch, CURLOPT_HTTPHEADER, $setHeaders); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_exec($ch); - - $internalMediaIds[] = $mediaId; - } - - $existingMediaConnection = []; - if (!empty($articleIdShopware)) { - $existingMediaConnection = $this->shopwareRequest('GET', 'product/' . $articleIdShopware . '/media?limit=100'); - foreach ($existingMediaConnection['data'] as $existingConnection) { - if (!in_array($existingConnection['attributes']['mediaId'], $internalMediaIds, false)) { - $this->shopwareRequest('DELETE', 'product/' . $articleIdShopware . '/media/' . $existingConnection['id']); - } - } - } - - $alreadyAddedMediaIDs = []; - if (!empty($existingMediaConnection)) { - foreach ($existingMediaConnection['data'] as $existingConnection) { - $alreadyAddedMediaIDs[$existingConnection['attributes']['mediaId']] = $existingConnection['id']; - } - } - $position = 0; - foreach ($internalMediaIds as $mediaId) { - $mediaDataSet = [ - 'mediaId' => $mediaId, - 'position' => $position - ]; - if (array_key_exists($mediaId, $alreadyAddedMediaIDs)) { - $mediaDataSet['id'] = $alreadyAddedMediaIDs[$mediaId]; - } - $mediaToAdd[] = $mediaDataSet; - $position++; - } - - return $mediaToAdd; - } - - /** - * @param string $mediaId - * @param string $title - * @param string $altText - */ - protected function setMediaTitleAndAltText(string $mediaId, string $title, string $altText): void - { - $this->shopwareRequest('PATCH', 'media/' . $mediaId, - ['title' => $title, - 'alt' => $altText - ] - ); - } - - /** - * @param array $articleInXentral - * @param string $articleIdShopware - */ - protected function addCoverImage($articleInXentral, $articleIdShopware){ - if(empty($articleIdShopware)){ - return; - } - if(empty($articleInXentral['Dateien'])){ - return; - } - $existingMediaConnection = $this->shopwareRequest('GET', 'product/' . $articleIdShopware . '/media?limit=100'); - if(empty($existingMediaConnection['data'])){ - return; - } - foreach ($articleInXentral['Dateien'] as $xentralFile) { - $filename = explode('.', $xentralFile['filename']); - unset($filename[(!empty($filename)?count($filename):0) - 1]); - $filename = $xentralFile['id'].'_'.implode($filename); - - $searchdata = [ - 'limit' => 5, - 'filter' => [ - [ - 'field' => 'media.fileName', - 'type' => 'equals', - 'value' => $filename - ] - ] - ]; - $mediaData = $this->shopwareRequest('POST', 'search/media', $searchdata); - $mediaId = $mediaData['data'][0]['id']; - - foreach ($existingMediaConnection['data'] as $mediaConnection){ - if($mediaId === $mediaConnection['attributes']['mediaId']){ - - $this->shopwareRequest('PATCH', - sprintf('product/%s?_response=true', $articleIdShopware),['coverId' => $mediaConnection['id']]); - return; - } - } - } - } - - /** - * @param array $articleInXentral - * @param string $articleIdShopware - * @return array - */ - protected function categoriesToExport($articleInXentral, $articleIdShopware) - { - $categoryName = $articleInXentral['kategoriename']; - $categoryTree = $articleInXentral['kategorien']; - - $categoriesToAdd = []; - if (empty($categoryName) && empty($categoryTree)) { - return $categoriesToAdd; - } - - $categoriesInXentral = []; - if (!empty($categoryTree)) { - $rootcategory = null; - $categoryTreeid = []; - foreach ($categoryTree as $categoryData) { - $categoryData['shopwareparent'] = 0; - if (!$categoryData['parent']) { - $categoryData['shopwareid'] = $rootcategory; - } - $categoryTreeid[$categoryData['id']] = $categoryData; - } - - foreach ($categoryTree as $categoryData) { - $parentid = $rootcategory; - if (!empty($categoryData['parent'])) { - $parentid = $this->getCategoryParentId($categoryData, $categoryTreeid); - } - - $searchdata = [ - 'limit' => 25, - 'filter' => [ - [ - 'field' => 'category.name', - 'type' => 'equals', - 'value' => $categoryData['name'] - ] - ] - ]; - if (!empty($parentid)) { - $searchdata['filter'][] = [ - 'field' => 'category.parentId', - 'type' => 'equals', - 'value' => $parentid - ]; - } - $result = $this->shopwareRequest('POST', 'search/category', $searchdata); - - - if (!empty($result['data'][0]['id'])) { - $categoryTreeid[$categoryData['id']]['shopwareid'] = $result['data'][0]['id']; - $categoriesInXentral[] = $result['data'][0]['id']; - } - } - } else if (!empty($categoryName)) { - $searchdata = [ - 'limit' => 25, - 'filter' => [ - [ - 'field' => 'category.name', - 'type' => 'equals', - 'value' => $categoryName - ] - ] - ]; - - $result = $this->shopwareRequest('POST', 'search/category', $searchdata); - - if (!empty($result['data'][0]['id'])) { - $categoriesInXentral[] = $result['data'][0]['id']; - } - } - - if (!empty($articleIdShopware)) { - $existingCategories = $this->shopwareRequest('GET', 'product/' . $articleIdShopware . '/categories?limit=50'); - foreach ($existingCategories['data'] as $existingCategory) { - if (!in_array($existingCategory['id'], $categoriesInXentral, false)) { - $this->shopwareRequest('DELETE', 'product/' . $articleIdShopware . '/categories/' . $existingCategory['id']); - } - } - } - foreach ($categoriesInXentral as $categoryId) { - $categoriesToAdd[] = ['id' => $categoryId]; - } - - - return $categoriesToAdd; - } - - /** - * @param $categoryData - * @param $categoryTreeId - * @return string|null - */ - protected function getCategoryParentId($categoryData, &$categoryTreeId) - { - $parentId = $categoryTreeId[$categoryData['parent']]['shopwareid']; - if (!empty($parentId)) { - return $parentId; - } - - $parentCategoryData = $this->app->DB->SelectRow("SELECT id,parent,bezeichnung AS name FROM artikelkategorien WHERE id<>'' AND id<>'0' AND id='" . $categoryData['parent'] . "' LIMIT 1"); - if (empty($parentCategoryData)) { - return null; - } - - $searchData = [ - 'limit' => 25, - 'filter' => [ - [ - 'field' => 'category.name', - 'type' => 'equals', - 'value' => $parentCategoryData['name'] - ] - ] - ]; - $result = $this->shopwareRequest('POST', 'search/category', $searchData); - - if (count($result['data']) < 1) { - return null; - } - - if (count($result['data']) === 1) { - $parentCategoryData['shopwareid'] = $result['data'][0]['id']; - $categoryTreeId[$parentCategoryData['id']] = $parentCategoryData; - return $result['data'][0]['id']; - } - - $grandparentId = $this->getCategoryParentId($parentCategoryData, $categoryTreeId); - - $searchData = [ - 'limit' => 25, - 'filter' => [ - [ - 'field' => 'category.name', - 'type' => 'equals', - 'value' => $parentCategoryData['name'] - ], - [ - 'field' => 'category.parentId', - 'type' => 'equals', - 'value' => $grandparentId - ] - ] - ]; - $result = $this->shopwareRequest('POST', 'search/category', $searchData); - - - if (count($result['data']) === 1) { - $parentCategoryData['shopwareid'] = $result['data'][0]['id']; - $categoryTreeId[$parentCategoryData['id']] = $parentCategoryData; - return $result['data'][0]['id']; - } - return null; - } - - /** - * @param string $propertyName - * - * @return string|null - */ - protected function getPropertyGroupId($propertyName): ?string - { - if(array_key_exists($propertyName, $this->knownPropertyGroupIds)){ - return $this->knownPropertyGroupIds[$propertyName]; - } - - $searchData = [ - 'limit' => 25, - 'filter' => [ - [ - 'field' => 'property_group.name', - 'type' => 'equals', - 'value' => $propertyName - ] - ] - ]; - - $germanLanguageId = $this->getLanguageIdByCountryIso('DE'); - $headerInformation = ['sw-language-id: ' . $germanLanguageId]; - $propertyData = $this->shopwareRequest( - 'POST', - 'search/property-group', - $searchData, - $headerInformation); - if (empty($propertyData['data'][0]['id'])) { - return null; - } - - $this->knownPropertyGroupIds[$propertyName] = $propertyData['data'][0]['id']; - - return $propertyData['data'][0]['id']; - } - - /** - * @param string $propertyName - * @return null|string - */ - protected function createPropertyGroup($propertyName): ?string - { - $propertyGroupData = [ - 'displayType' => 'text', - 'name' => $propertyName, - 'sortingType' => 'alphanumeric' - ]; - $propertyGroup = $this->shopwareRequest( - 'POST', - 'property-group?_response=true', - $propertyGroupData); - - $this->knownPropertyGroupIds[$propertyName] = $propertyGroup['data']['id']; - - if (empty($propertyGroup['data']['id'])) { - return null; - } - - return $propertyGroup['data']['id']; - } - - /** - * @param string $propertyGroupId - * @param string $propertyName - * @param string $countryIsoCode - */ - protected function createTranslationForPropertyGroup($propertyGroupId, $propertyName, $countryIsoCode): void - { - $languageId = $this->getLanguageIdByCountryIso($countryIsoCode); - if (empty($languageId)) { - return; - } - - $headerInformation = ['sw-language-id: ' . $languageId]; - - $translation = [ - 'name' => $propertyName, - ]; - - $this->shopwareRequest( - 'PATCH', - sprintf('property-group/%s', $propertyGroupId), - $translation, - $headerInformation); - } - - /** - * @param string $propertyGroupId - * @param string $propertyOptionName - * @param string $countryIsoCode - * @return mixed|null - */ - protected function getPropertyOptionId($propertyGroupId, $propertyOptionName, $countryIsoCode = 'DE'): ?string - { - $searchData = [ - 'limit' => 25, - 'filter' => [ - [ - 'field' => 'property_group_option.name', - 'type' => 'equals', - 'value' => $propertyOptionName - ] - ] - ]; - $languageId = $this->getLanguageIdByCountryIso($countryIsoCode); - $headerInformation = ['sw-language-id: ' . $languageId]; - $optionData = $this->shopwareRequest( - 'POST', - 'search/property-group/' . $propertyGroupId . '/options', - $searchData, - $headerInformation); - - if (empty($optionData['data'][0]['id'])) { - return null; - } - - return $optionData['data'][0]['id']; - } - - /** - * @param string $propertyGroupId - * @param string $propertyOptionName - * @return null|string - */ - protected function createPropertyOption($propertyGroupId, $propertyOptionName): ?string - { - $propertyOptionData = [ - 'id' => '', - 'name' => $propertyOptionName - ]; - $createdPropertyOption = $this->shopwareRequest( - 'POST', - 'property-group/' . $propertyGroupId . '/options?_response=true', - $propertyOptionData); - - if (empty($createdPropertyOption['data']['id'])) { - return null; - } - - return $createdPropertyOption['data']['id']; - } - - /** - * @param string $optionId - * @param string $optionName - * @param string $countryIsoCode - */ - protected function createTranslationForPropertyOption($optionId, $optionName, $countryIsoCode): void - { - $languageId = $this->getLanguageIdByCountryIso($countryIsoCode); - if (empty($languageId)) { - return; - } - $headerInformation = ['sw-language-id: ' . $languageId]; - $translation = [ - 'name' => $optionName, - ]; - - $this->shopwareRequest( - 'PATCH', - sprintf('property-group-option/%s', $optionId), - $translation, - $headerInformation); - } - - /** - * @param array $internalArticle - * @param string $articleIdShopware - * @return array - */ - protected function propertiesToExport($internalArticle, $articleIdShopware): array - { - $propertiesToAdd = $this->getPropertiesFromArticle($internalArticle); - if (empty($propertiesToAdd)) { - return []; - } - $assignedProperties = []; - - foreach ($propertiesToAdd as $propertyDefaultName => $countryIsoToPropertyTranslation) { - if (empty($countryIsoToPropertyTranslation['DE'])) { - continue; - } - $propertyGroupId = ''; - if (array_key_exists($propertyDefaultName, $this->knownPropertyGroupIds)) { - $propertyGroupId = $this->knownPropertyGroupIds[$propertyDefaultName]; - } - if (empty($propertyGroupId)) { - $propertyGroupId = $this->getPropertyGroupId($propertyDefaultName); - } - if (empty($propertyGroupId)) { - $propertyGroupId = $this->createPropertyGroup($propertyDefaultName); - } - if (empty($propertyGroupId)) { - $this->Shopware6Log('PropertyGroup kann nicht erstellt werden: ' . $propertyDefaultName); - continue; - } - - foreach ($countryIsoToPropertyTranslation as $countryIsoCode => $translation) { - $this->createTranslationForPropertyGroup($propertyGroupId, $translation['name'], $countryIsoCode); - } - - - $optionId = $this->getPropertyOptionId($propertyGroupId, $countryIsoToPropertyTranslation['DE']['value'], 'DE'); - if (empty($optionId)) { - $optionId = $this->createPropertyOption($propertyGroupId, $countryIsoToPropertyTranslation['DE']['value']); - } - if (empty($optionId)) { - $this->Shopware6Log('Option kann nicht erstellt werden: ' . $countryIsoToPropertyTranslation['DE']['value']); - continue; - } - - $assignedProperties[] = $optionId; - - foreach ($countryIsoToPropertyTranslation as $countryIsoCode => $translation) { - $this->createTranslationForPropertyOption($optionId, $translation['value'], $countryIsoCode); - } - } - - if (!empty($articleIdShopware)) { - $existingProperties = $this->shopwareRequest('GET', 'product/' . $articleIdShopware . '/properties?limit=100'); - foreach ($existingProperties['data'] as $existingProperty) { - if (!in_array($existingProperty['id'], $assignedProperties, false)) { - $this->shopwareRequest('DELETE', 'product/' . $articleIdShopware . '/properties/' . $existingProperty['id']); - } - } - } - - $propertiesToAdd = []; - foreach ($assignedProperties as $propertyOptionId) { - $propertiesToAdd[] = ['id' => $propertyOptionId]; - } - - return $propertiesToAdd; - } - - /** - * @param string $name - * @param string $value - * @return bool - */ - protected function propertyMustBeIgnored(string $name, string $value): bool - { - return empty($value) || - strpos($name, 'customField_') === 0 || - stripos($name, 'shopware6_') !== false; - } - - /** - * @param array $internalArticleData - * @return array - */ - protected function getPropertiesFromArticle($internalArticleData): array - { - //'Farbe' => [['DE' => ['name' => 'Farbe, 'value' => 'Gelb']], - // ['EN' => ['name' => 'Colour, 'value' => 'Yellow']]] - $propertiesToAdd = []; - if (!empty($internalArticleData['eigenschaften'])) { - foreach ($internalArticleData['eigenschaften'] as $property) { - if ($this->propertyMustBeIgnored($property['name'], $property['values'])) { - continue; - } - if (strpos($property['name'], 'property_') === 0) { - $propertyName = substr($property['name'], 9); - $propertiesToAdd[$propertyName]['DE'] = [ - 'name' => $propertyName, - 'value' => $property['values']]; - continue; - } - if ($this->propertyOption === 'toProperties') { - $propertiesToAdd[$property['name']]['DE'] = [ - 'name' => $property['name'], - 'value' => $property['values']]; - } - } - } - - if (!empty($internalArticleData['eigenschaftenuebersetzungen'])) { - foreach ($internalArticleData['eigenschaftenuebersetzungen'] as $translatedProperty) { - if ($translatedProperty['language_to'] === 'EN') { - $translatedProperty['language_to'] = 'GB'; - } - if ($this->propertyMustBeIgnored($translatedProperty['property_to'], $translatedProperty['property_value_to'])) { - continue; - } - if (strpos($translatedProperty['property_to'], 'property_') === 0) { - $propertiesToAdd[$translatedProperty['property_from']][$translatedProperty['language_to']] = [ - 'name' => substr($translatedProperty['property_to'], 9), - 'value' => $translatedProperty['property_value_to']]; - continue; - } - if ($this->propertyOption === 'toProperties') { - $propertiesToAdd[$translatedProperty['property_from']][$translatedProperty['language_to']] = [ - 'name' => $translatedProperty['property_to'], - 'value' => $translatedProperty['property_value_to']]; - } - } - } - - if (!empty($internalArticleData['freifelder'])) { - foreach ($internalArticleData['freifelder']['DE'] as $freeFieldKey => $freeFieldValue) { - if ($this->propertyMustBeIgnored($freeFieldKey, $freeFieldValue)) { - continue; - } - if (strpos($freeFieldKey, 'property_') === 0) { - $propertyName = substr($freeFieldKey, 9); - $propertiesToAdd[$propertyName]['DE'] = [ - 'name' => $propertyName, - 'value' => $freeFieldValue - ]; - continue; - } - if ($this->freeFieldOption === 'toProperties') { - $propertiesToAdd[$freeFieldKey]['DE'] = [ - 'name' => $freeFieldKey, - 'value' => $freeFieldValue - ]; - } - } - - foreach ($internalArticleData['freifelder'] as $languageIso => $freeFields) { - if ($languageIso === 'DE') { - continue; - } - if ($languageIso === 'EN') { - $languageIso = 'GB'; - } - foreach ($freeFields as $freeFieldData) { - if ($this->propertyMustBeIgnored($freeFieldData['mapping'], $freeFieldData['wert'])) { - continue; - } - if (strpos($freeFieldData['mapping'], 'property_') === 0) { - $propertyName = substr($freeFieldData['mapping'], 9); - $propertiesToAdd[$propertyName][$languageIso] = [ - 'name' => $propertyName, - 'value' => $freeFieldData['wert'] - ]; - continue; - } - if ($this->freeFieldOption === 'toProperties') { - $propertiesToAdd[$freeFieldData['mapping']][$languageIso] = [ - 'name' => $freeFieldData['mapping'], - 'value' => $freeFieldData['wert'] - ]; - } - } - } - } - - return $propertiesToAdd; - } - - /** - * @param array $articleInXentral - * @param string $articleIdShopware - * - * @return array - */ - protected function customFieldsToExport($articleInXentral, $articleIdShopware): array - { - $customFieldsToAdd = $this->getCustomFieldsFromArticle($articleInXentral); - if (empty($customFieldsToAdd)) { - return []; - } - $languageId = $this->getLanguageIdByCountryIso('DE'); - $headerInformation = ['sw-language-id: ' . $languageId]; - - $customFields = []; - if (!empty($articleIdShopware)) { - $articleInfo = $this->shopwareRequest( - 'GET', 'product/' . $articleIdShopware, - [], - $headerInformation); - $customFields['DE'] = $articleInfo['data'][0]['attributes']['customFields']; - if ($customFields === null) { - $customFields = []; - } - } - - foreach ($customFieldsToAdd as $defaultFieldName => $countryIsoCodeToCustomFieldData) { - $customFieldDefinition = $this->shopwareRequest( - 'GET', - sprintf('custom-field?filter[custom_field.name]=%s', $defaultFieldName), - [], - $headerInformation - ); - if (empty($customFieldDefinition)) { - $this->Shopware6Log('Freifeld entspricht keinem shopware Freifeld', $defaultFieldName); - continue; - } - - foreach ($countryIsoCodeToCustomFieldData as $countryIsoCode => $customFieldData) { - $name = $customFieldData['name']; - $value = $customFieldData['value']; - if ($value === '') { - continue; - } - if($countryIsoCode === 'EN'){ - $countryIsoCode = 'GB'; - } - $fieldType = $customFieldDefinition['data'][0]['attributes']['type']; - $controlType = $customFieldDefinition['data'][0]['attributes']['config']['componentName']; - - switch ($fieldType) { - case 'text': - case 'html': - if ($controlType === 'sw-media-field') { - $this->Shopware6Log( - 'Warnung: Freifelder vom Type "medium" werden nicht unterstützt.' - ); - } else { - $customFields[$countryIsoCode][$name] = (string)$value; - } - break; - case 'bool': - $customFields[$countryIsoCode][$name] = filter_var($value, FILTER_VALIDATE_BOOLEAN); - break; - case 'int': - $customFields[$countryIsoCode][$name] = (int)$value; - break; - case 'float': - $customFields[$countryIsoCode][$name] = (float)$value; - break; - case 'select': - $options = $customFieldDefinition['data'][0]['attributes']['config']['options']; - $allowedValues = []; - foreach ($options as $option) { - $allowedValues[] = $option['value']; - } - if ($controlType === 'sw-single-select') { - if (in_array($value, $allowedValues, true)) { - $customFields[$countryIsoCode][$name] = $value; - } else { - $this->Shopware6Log( - sprintf('Warnung: Freifeld "%s"="%s"; ungültiger Wert', $name, $value), - ['allowed values' => $allowedValues] - ); - } - } - if ($controlType === 'sw-multi-select') { - $value = explode(',', $value); - foreach ($value as &$item) { - $item = trim($item); - } - unset($item); - if (array_intersect($value, $allowedValues) === $value) { - $customFields[$countryIsoCode][$name] = $value; - } else { - $this->Shopware6Log( - sprintf('Warnung: Freifeld "%s"; ungültiger Wert', $name), - ['values' => $value, 'allowed values' => $allowedValues] - ); - } - } - break; - default: - $this->Shopware6Log( - 'Warnung: Freifeld enthält falschen Typ.', - ['freifeld' => $name, 'wert' => $value] - ); - continue 2; - } - } - } - - - return $customFields; - } - - /** - * @param string $name - * @param string $value - * @return bool - */ - protected function customFieldMustBeIgnored(string $name, string $value): bool - { - return empty($value) || - strpos($name, 'property_') === 0 || - stripos($name, 'shopware6_') !== false; - } - - /** - * @param array $articleInXentral - * @return array - */ - protected function getCustomFieldsFromArticle($articleInXentral): array - { - $customFieldsToAdd = []; - if (!empty($articleInXentral['eigenschaften'])) { - foreach ($articleInXentral['eigenschaften'] as $propertyInXentral) { - if ($this->customFieldMustBeIgnored($propertyInXentral['name'], $propertyInXentral['values'])) { - continue; - } - if (strpos($propertyInXentral['name'], 'customField_') === 0) { - $customFieldName = substr($propertyInXentral['name'], 12); - $customFieldsToAdd[$customFieldName]['DE'] = [ - 'name' => $customFieldName, - 'value' => $propertyInXentral['values'] - ]; - continue; - } - if ($this->propertyOption === 'toCustomFields') { - $customFieldsToAdd[$propertyInXentral['name']]['DE'] = [ - 'name' => $propertyInXentral['name'], - 'value' => $propertyInXentral['values'] - ]; - } - } - } - if (!empty($articleInXentral['eigenschaftenuebersetzungen'])) { - foreach ($articleInXentral['eigenschaftenuebersetzungen'] as $translatedProperty) { - if ($this->customFieldMustBeIgnored($translatedProperty['property_to'], $translatedProperty['property_value_to'])) { - continue; - } - if (strpos($translatedProperty['property_to'], 'customField_') === 0) { - $customFieldName = substr($translatedProperty['property_to'], 12); - $customFieldsToAdd[$customFieldName][$translatedProperty['language_to']] = [ - 'name' => $customFieldName, - 'value' => $translatedProperty['property_value_to'] - ]; - continue; - } - if ($this->propertyOption === 'toCustomFields') { - $customFieldsToAdd[$translatedProperty['property_to']][$translatedProperty['language_to']] = [ - 'name' => $translatedProperty['property_to'], - 'value' => $translatedProperty['property_value_to'] - ]; - } - } - } - - if (!empty($articleInXentral['freifelder'])) { - foreach ($articleInXentral['freifelder']['DE'] as $freeFieldKey => $freeFieldValue) { - if ($this->customFieldMustBeIgnored($freeFieldKey, $freeFieldValue)) { - continue; - } - if (strpos($freeFieldKey, 'customField_') === 0) { - $customFieldName = substr($freeFieldKey, 12); - $customFieldsToAdd[$customFieldName]['DE'] = [ - 'name' => $customFieldName, - 'value' => $freeFieldValue - ]; - continue; - } - if ($this->freeFieldOption === 'toCustomFields') { - $customFieldsToAdd[$freeFieldKey]['DE'] = [ - 'name' => $freeFieldKey, - 'value' => $freeFieldValue - ]; - } - } - - foreach ($articleInXentral['freifelder'] as $countryIsoCode => $freeFieldTranslations) { - if ($countryIsoCode === 'DE') { - continue; - } - foreach ($freeFieldTranslations as $freeFieldTranslation){ - if ($this->customFieldMustBeIgnored($freeFieldTranslation['mapping'], $freeFieldTranslation['wert'])) { - continue; - } - if ($countryIsoCode === 'EN') { - $countryIsoCode = 'GB'; - } - if (strpos($freeFieldTranslation['mapping'], 'customField_') === 0) { - $customFieldName = substr($freeFieldTranslation['mapping'], 12); - $customFieldsToAdd[$customFieldName][$countryIsoCode] = [ - 'name' => $customFieldName, - 'value' => $freeFieldTranslation['wert'] - ]; - continue; - } - if ($this->freeFieldOption === 'toCustomFields') { - $customFieldsToAdd[$freeFieldTranslation['mapping']][$countryIsoCode] = [ - 'name' => $freeFieldTranslation['mapping'], - 'value' => $freeFieldTranslation['wert'] - ]; - } - } - } - } - - return $customFieldsToAdd; - } - - /** - * @param array $articleInXentral - * @param int $articleIdShopware - * - * @return array - */ - protected function crosssellingToExport($articleInXentral, $articleIdShopware){ - if (empty($articleInXentral['crosssellingartikel'])) { - return []; - } - - $crosssellingArticles = []; - foreach ($articleInXentral['crosssellingartikel'] as $crosssellingArticle){ - $type = 'Ähnlich'; - if($crosssellingArticle['art'] == 2){ - $type = 'Zubehör'; - } - $crosssellingArticles[$type][] = $crosssellingArticle['nummer']; - } - $crossselingInformation = []; - foreach ($crosssellingArticles as $type => $articles){ - if(!empty($articleIdShopware)){ - $existingCrossSellings = $this->shopwareRequest('GET', sprintf('product/%s/cross-sellings/', - $articleIdShopware)); - if(!empty($existingCrossSellings['data'])){ - foreach ($existingCrossSellings['data'] as $existingCrossSelling){ - if($existingCrossSelling['attributes']['name'] === $type){ - $this->shopwareRequest('DELETE', sprintf('product/%s/cross-sellings/%s/', - $articleIdShopware, $existingCrossSelling['id'])); - } - } - } - } - - $crosselingToAdd = []; - foreach ($articles as $articleNumber) { - $articleInfo = $this->shopwareRequest( - 'GET', - sprintf('product?filter[product.productNumber]=%s', $articleNumber) - ); - - if(empty($articleInfo['data'][0]['id'])){ - continue; - } - $crosselingToAdd[] = $articleInfo['data'][0]['id']; - } - if(empty($crosselingToAdd)){ - continue; - } - $crossselingInformationForType = [ - 'active' => true, - 'name' => $type, - 'assignedProducts' => [], - 'type' => 'productList', - 'sortBy' => 'name', - 'limit' => 24, - 'position' => 1 - ]; - $position = 1; - foreach ($crosselingToAdd as $articleId){ - $crossselingInformationForType['assignedProducts'][] = [ - 'productId' => $articleId, - 'position' => $position, - ]; - $position++; - } - $crossselingInformation[] = $crossselingInformationForType; - } - - - return $crossselingInformation; - } - - /** - * @param string $unitShortCode - * - * @return string - */ - protected function unitToAdd(string $unitShortCode): string{ - $searchData = [ - 'limit' => 25, - 'source' => [ - 'id' - ], - 'filter' => [ - [ - 'field' => 'unit.shortCode', - 'type' => 'equals', - 'value' => $unitShortCode - ] - ] - ]; - $unitInShopware = $this->shopwareRequest( - 'POST', - 'search/unit', - $searchData); - - if(!empty($unitInShopware['data'][0]['id'])){ - return $unitInShopware['data'][0]['id']; - } - - $query = sprintf("SELECT `internebemerkung` FROM `artikeleinheit` WHERE `einheit_de` = '%s' LIMIT 1", - $unitShortCode); - $unitName = $this->app->DB->Select($query); - if(empty($unitName)){ - $unitName = $unitShortCode; - } - - $unitInformation = [ - 'name' => $unitName, - 'shortCode' => $unitShortCode - ]; - $result = $this->shopwareRequest('POST', 'unit?_response=true', $unitInformation); - - if(empty($result['data']['id'])){ - return ''; - } - - return $result['data']['id']; - } - - /** - * @param array $internArticle - * @param int $articleIdShopware - * - * @return array - */ - protected function systemFieldsToExport($internArticle, $articleIdShopware): array - { - $internalSpecialFields = []; - foreach ($internArticle['freifelder']['DE'] as $freeFieldName => $freeFieldValue) { - if (stripos($freeFieldName, 'shopware6_') !== false) { - $internalSpecialFields[$freeFieldName] = $freeFieldValue; - } - } - foreach ($internArticle['eigenschaften'] as $property) { - if (stripos($property['name'], 'shopware6_') !== false) { - $internalSpecialFields[$property['name']] = $property['values']; - } - } - - $systemFields = []; - foreach ($internalSpecialFields as $fieldName => $fieldValue) { - switch (strtolower($fieldName)) { - case 'shopware6_sales_channel': - $systemFields['visibilities'] = $this->modifySalesChannel(explode(',', $fieldValue), $articleIdShopware); - break; - case 'shopware6_purchase_unit': - $systemFields['purchaseUnit'] = (float)str_replace(',', '.', $fieldValue); - break; - case 'shopware6_reference_unit': - $systemFields['referenceUnit'] = (float)str_replace(',', '.', $fieldValue); - break; - case 'shopware6_unit': - $systemFields['unitId'] = $this->unitToAdd($fieldValue); - break; - case 'shopware6_pack_unit': - $systemFields['packUnit'] = (string)$fieldValue; - break; - case 'shopware6_restock_time': - $systemFields['restockTime'] = (int)$fieldValue; - break; - case 'shopware6_pack_unit_plural': - $systemFields['packUnitPlural'] = (string)$fieldValue; - break; - } - } - - return $systemFields; - } - - /** - * @param array $salesChannelNames - * @param string $articleIdInShopware - * - * @return array - */ - protected function modifySalesChannel($salesChannelNames, $articleIdInShopware) - { - $salesChannelInXentralIds = []; - foreach ($salesChannelNames as $salesChannelName) { - $salesChannelInfo = $this->shopwareRequest('GET', - sprintf('sales-channel?filter[sales_channel.name]=%s', urlencode(trim($salesChannelName))) - ); - if (!empty($salesChannelInfo['data'][0]['id'])) { - $salesChannelInXentralIds[] = $salesChannelInfo['data'][0]['id']; - } - } - - $existingVisibilities = $this->shopwareRequest( - 'GET', - sprintf('product/%s/visibilities', $articleIdInShopware) - ); - - $existingSalesChannelIds = []; - if (!empty($existingVisibilities['data'])) { - foreach ($existingVisibilities['data'] as $visibility) { - $existingSalesChannelIds[$visibility['id']] = $visibility['attributes']['salesChannelId']; - } - } - - foreach ($existingSalesChannelIds as $associationId => $existingSalesChannelId){ - if (!in_array($existingSalesChannelId, $salesChannelInXentralIds,true)) { - $this->shopwareRequest('DELETE', sprintf('product/%s/visibilities/%s/', - $articleIdInShopware, $associationId)); - } - } - - $salesChannelsToAdd = []; - foreach ($salesChannelInXentralIds as $salesChannelInXentralId){ - if (!in_array($salesChannelInXentralId, $existingSalesChannelIds,true)) { - $salesChannelsToAdd[] = $salesChannelInXentralId; - } - } - - $visibilities = []; - foreach ($salesChannelsToAdd as $salesChannelIdToAdd) { - $visibilities[] = [ - 'salesChannelId' => $salesChannelIdToAdd, - 'visibility' => 30 - ]; - } - - return $visibilities; - } - - /** - * @param string $isoCode - * - * @return string - */ - protected function findCurrencyId($isoCode) - { - - $this->requestCurrencyMappingLazy(); - if (isset($this->currencyMapping[strtoupper($isoCode)])) { - return $this->currencyMapping[strtoupper($isoCode)]; - } - $this->Shopware6Log( - sprintf('Warnung: Kein Mapping für Waehrung "%s" gefunden.', $isoCode), - $this->currencyMapping - ); - - return null; - } - - /** - * request currency mapping only once - */ - protected function requestCurrencyMappingLazy() - { - - if ($this->currencyMapping !== null) { - return; - } - $currencies = $this->shopwareRequest('GET', 'currency'); - if (!isset($currencies['data'])) { - $this->Shopware6Log('Kann Währungsmapping nicht abrufen', $currencies); - } - foreach ($currencies['data'] as $currency) { - $isoCode = strtoupper($currency['attributes']['isoCode']); - $this->currencyMapping[$isoCode] = $currency['id']; - } - } - - /** - * @param array $internalArticleData - * @param string $articleIdInShopware - * @return bool - */ - public function exportSeoUrls(array $internalArticleData, string $articleIdInShopware): bool - { - if (empty($articleIdInShopware)) { - return false; - } - - $preparedSeoInformation = []; - foreach ($internalArticleData['freifelder'] as $countryIsoCode => $freeFieldInformation) { - if($countryIsoCode === 'EN'){ - $countryIsoCode = 'GB'; - } - if($countryIsoCode === 'DE'){ - foreach ($freeFieldInformation as $freeFieldName => $freeFieldValue) { - if (stripos($freeFieldName, 'shopware6_seo_url') !== false) { - $preparedSeoInformation[$countryIsoCode][$freeFieldName] = $freeFieldValue; - } - } - }else{ - foreach ($freeFieldInformation as $freeFieldData) { - if (stripos($freeFieldData['mapping'], 'shopware6_seo_url') !== false) { - $preparedSeoInformation[$countryIsoCode][$freeFieldData['mapping']] = $freeFieldData['wert']; - } - } - } - } - foreach ($internalArticleData['eigenschaften'] as $property) { - if (stripos($property['name'], 'shopware6_seo_url') !== false) { - $preparedSeoInformation['DE'][$property['name']] = $property['values']; - } - } - foreach ($internalArticleData['eigenschaftenuebersetzungen'] as $propertyTranslation) { - if($propertyTranslation['language_to'] === 'EN'){ - $propertyTranslation['language_to'] = 'GB'; - } - if (stripos($propertyTranslation['property_to'], 'shopware6_seo_url') !== false) { - $preparedSeoInformation[$propertyTranslation['language_to']][$propertyTranslation['property_to']] = $propertyTranslation['property_value_to']; - } - } - - $specificSalesChannelSeoUrls = []; - $defaultSeoUrls = []; - foreach ($preparedSeoInformation as $countryIsoCode => $channelAssociations) { - foreach ($channelAssociations as $fieldName => $fieldValue){ - if(strtolower($fieldName) === 'shopware6_seo_url'){ - $defaultSeoUrls[$countryIsoCode] = $fieldValue; - }else{ - $seoInformation = explode('|', $fieldName); - $specificSalesChannelSeoUrls[$countryIsoCode][array_pop($seoInformation)] = $fieldValue; - } - } - } - - if (empty($specificSalesChannelSeoUrls) && empty($defaultSeoUrls)) { - return false; - } - - $salesChannelsIdToName = []; - $salesChannels = $this->shopwareRequest('GET','sales-channel'); - foreach ($salesChannels['data'] as $salesChannel) { - $salesChannelsIdToName[$salesChannel['id']] = $salesChannel['attributes']['name']; - } - - foreach ($preparedSeoInformation as $countryIsoCode => $x){ - $languageId = $this->getLanguageIdByCountryIso($countryIsoCode); - if (empty($languageId)) { - $this->Shopware6Log('Language Id not found for country: ' . $countryIsoCode); - continue; - } - - $headerInformation = ['sw-language-id: ' . $languageId]; - foreach ($salesChannelsIdToName as $salesChannelId => $salesChannelName) { - $seoUrlToUse = $defaultSeoUrls[$countryIsoCode]; - if (!empty($specificSalesChannelSeoUrls[$countryIsoCode][$salesChannelName])) { - $seoUrlToUse = $specificSalesChannelSeoUrls[$countryIsoCode][$salesChannelsIdToName[$salesChannelName]]; - } - if (empty($seoUrlToUse)) { - continue; - } - $seoDataToSend = [ - 'seoPathInfo' => $seoUrlToUse, - '_isNew' => true, - 'isModified' => true, - 'isCanonical' => true, - 'isDeleted' => false, - 'routeName' => 'frontend.detail.page', - 'foreignKey' => $articleIdInShopware, - 'pathInfo' => '/detail/'.$articleIdInShopware, - 'languageId' => $languageId, - 'salesChannelId' => $salesChannelId]; - $this->shopwareRequest('PATCH', '_action/seo-url/canonical', $seoDataToSend, $headerInformation); - } - } - - return true; - } - - /** - * @param array $article - * @param string $articleIdShopware - * @param string $currencyId - * - * @return bool - */ - protected function exportVariants($article, $articleIdShopware, $currencyId): bool - { - $languageId = $this->getLanguageIdByCountryIso('DE'); - if (empty($languageId)) { - return false; - } - if (empty($article['matrix_varianten']) || empty($articleIdShopware)) { - return false; - } - $internalGroupPropertiesToShopwareId = []; - foreach ($article['matrix_varianten']['gruppen'] as $propertyGroupName => $internalPropertyGroupValues) { - $propertyGroupId = ''; - if (array_key_exists($propertyGroupName, $this->knownPropertyGroupIds)) { - $propertyGroupId = $this->knownPropertyGroupIds[$propertyGroupName]; - } - if (empty($propertyGroupId)) { - $propertyGroupId = $this->getPropertyGroupId($propertyGroupName); - } - if (empty($propertyGroupId)) { - $propertyGroupId = $this->createPropertyGroup($propertyGroupName); - } - if (empty($propertyGroupId)) { - $this->Shopware6Log('PropertyGroup kann nicht erstellt werden: ' . $propertyGroupName); - return false; - } - - if (!empty($article['matrix_varianten']['texte'])) { - $this->createTranslationForPropertyGroup($propertyGroupId, $propertyGroupName, 'DE'); - - foreach ($article['matrix_varianten']['texte']['gruppen'] as $countryIsoCode => $matrixGroupTranslation) { - if ($countryIsoCode === 'EN') { - $countryIsoCode = 'GB'; - } - - $this->createTranslationForPropertyGroup($propertyGroupId, $matrixGroupTranslation[$propertyGroupName], $countryIsoCode); - } - } - - $languageId = $this->getLanguageIdByCountryIso('DE'); - $headerInformation = ['sw-language-id: ' . $languageId]; - $shopwarePropertyGroupOptions = $this->shopwareRequest( - 'GET', - 'property-group/' . $propertyGroupId . '/options?limit=100', - $headerInformation); - foreach ($shopwarePropertyGroupOptions['data'] as $shopwarePropertyGroupOption) { - $propertyValue = $shopwarePropertyGroupOption['attributes']['name']; - $internalGroupPropertiesToShopwareId[$propertyGroupName][$propertyValue] = $shopwarePropertyGroupOption['id']; - } - - foreach ($internalPropertyGroupValues as $internalPropertyGroupValue => $valueNotNeeded) { - if (!array_key_exists($internalPropertyGroupValue, $internalGroupPropertiesToShopwareId[$propertyGroupName])) { - $newOptionData = [ - 'name' => (string)$internalPropertyGroupValue - ]; - $optionData = $this->shopwareRequest( - 'POST', - 'property-group/' . $propertyGroupId . '/options?_response=true', - $newOptionData); - $internalGroupPropertiesToShopwareId[$propertyGroupName][$internalPropertyGroupValue] = $optionData['data']['id']; - } - } - - if (!empty($article['matrix_varianten']['texte'])) { - foreach ($internalPropertyGroupValues as $optionValue => $valueNotNeeded) { - $optionId = $internalGroupPropertiesToShopwareId[$propertyGroupName][$optionValue]; - $this->createTranslationForPropertyOption( - $optionId, - $optionValue, - 'DE'); - foreach ($article['matrix_varianten']['texte']['werte'] as $countryIsoCode => $matrixOptionTranslations) { - if ($countryIsoCode === 'EN') { - $countryIsoCode = 'GB'; - } - if (array_key_exists($optionValue, $matrixOptionTranslations)) { - $this->createTranslationForPropertyOption( - $optionId, - $matrixOptionTranslations[$optionValue], - $countryIsoCode); - } - } - } - } - } - - $existingCombinations = $this->shopwareRequest( - 'GET', - '_action/product/' . $articleIdShopware . '/combinations'); - $existingCombinationsByNumber = []; - - foreach ($existingCombinations as $combinationId => $combinationInfo) { - $existingCombinationsByNumber[$combinationInfo['productNumber']] = [ - 'id' => $combinationId, - 'options' => [], - ]; - foreach ($combinationInfo['options'] as $combinationOption) { - $existingCombinationsByNumber[$combinationInfo['productNumber']]['options'][$combinationOption] = $combinationOption; - } - } - - - foreach ($article['artikel_varianten'] as $variant) { - $internalVariantMatrixData = $article['matrix_varianten']['artikel'][$variant['artikel']]; - $productNumber = $internalVariantMatrixData[0]['nummer']; - $name = $variant['name_de']; - $stock = $variant['lag']; - $ean = $variant['ean']; - $weight = (float)$variant['gewicht']; - $pseudoPrice = $variant['pseudopreis']; - if (empty($pseudoPrice)) { - $pseudoPrice = 0; - } - if (!empty($variant['pseudolager'])) { - $stock = $variant['pseudolager']; - } - $active = true; - if (!empty($variant['inaktiv'])) { - $active = false; - } - $isCloseOut = false; - if (!empty($variant['restmenge'])) { - $isCloseOut = true; - } - - $variantProductData = [ - 'active' => $active, - 'isCloseout' => $isCloseOut, - 'name' => $name, - 'description' => null, - 'weight' => null, - 'price' => [ - [ - 'currencyId' => $currencyId, - 'gross' => $variant['bruttopreis'], - 'net' => $variant['preis'], - 'linked' => true, - 'listPrice' => [ - 'currencyId' => $currencyId, - 'gross' => $pseudoPrice, - 'linked' => true, - 'net' => $pseudoPrice / (1 + $variant['steuersatz'] / 100) - ] - ] - ], - 'stock' => (int)$stock, - 'ean' => null, - 'taxId' => $this->getTaxIdByRate($variant['steuersatz']), - ]; - if(!empty($weight)){ - $variantProductData['weight'] = $weight; - } - if(!empty($ean)){ - $variantProductData['ean'] = $ean; - } - if (!empty($variant['uebersicht_de'])) { - $variantProductData['description'] = $variant['uebersicht_de']; - } - - $renewVariant = false; - $options = []; - foreach ($internalVariantMatrixData as $expression) { - if (!in_array( - $internalGroupPropertiesToShopwareId[$expression['name']][$expression['values']], - $existingCombinationsByNumber[$productNumber]['options'], - false)) { - $renewVariant = true; - } else { - unset($existingCombinationsByNumber[$productNumber]['options'][$internalGroupPropertiesToShopwareId[$expression['name']][$expression['values']]]); - } - $options[] = ['id' => $internalGroupPropertiesToShopwareId[$expression['name']][$expression['values']]]; - } - - if (!empty($existingCombinationsByNumber[$productNumber]['options'])) { - $renewVariant = true; - } - - $variantImageData = [ - 'Dateien' => [] - ]; - $variantProductId = ''; - if (!empty($existingCombinationsByNumber[$productNumber]['id']) && !$renewVariant) { - $variantProductId = $existingCombinationsByNumber[$productNumber]['id']; - } - if (!empty($variant['Dateien']['id'])) { - foreach ($variant['Dateien']['id'] as $index => $fileId) { - $variantImageData['Dateien'][] = [ - 'filename' => $variant['Dateien']['filename'][$index], - 'extension' => $variant['Dateien']['extension'][$index], - 'datei' => $variant['Dateien']['datei'][$index], - 'beschreibung' => $variant['Dateien']['beschreibung'][$index], - 'titel' => $variant['Dateien']['titel'][$index], - 'id' => $fileId, - ]; - } - } - $mediaToAdd = $this->mediaToExport($variantImageData, $variantProductId); - $variantProductData['media'] = $mediaToAdd; - - if ($renewVariant) { - if (!empty($existingCombinationsByNumber[$productNumber]['id'])) { - $this->shopwareRequest('DELETE', 'product/' . $existingCombinationsByNumber[$productNumber]['id']); - } - $variantProductData['productNumber'] = $productNumber; - $variantProductData['parentId'] = $articleIdShopware; - $variantProductData['options'] = $options; - - $result = $this->shopwareRequest('POST', 'product?_response=true', $variantProductData); - $variantProductId = $result['data']['id']; - } else { - $variantProductId = $existingCombinationsByNumber[$productNumber]['id']; - $this->shopwareRequest('PATCH', 'product/' . $variantProductId, $variantProductData); - } - - $defaultPrices = $this->getPricesFromArray($variant['staffelpreise_standard'] ?? []); - $groupPrices = $this->getPricesFromArray($variant['staffelpreise_gruppen'] ?? []); - - $this->deleteOldBulkPrices($variantProductId); - if (!empty($defaultPrices)) { - foreach ($defaultPrices as $priceData) { - $this->exportBulkPriceForGroup($variantProductId, $this->defaultRuleName, $priceData); - } - } - if (!empty($groupPrices)) { - foreach ($groupPrices as $priceData) { - $this->exportBulkPriceForGroup($variantProductId, $priceData->getGroupName(), $priceData); - } - } - - $this->addCoverImage($variantImageData, $variantProductId); - } - - $existingConfigurations = $this->shopwareRequest( - 'GET', 'product/' . $articleIdShopware . '/configuratorSettings'); - $optionIdsToAdd = []; - foreach ($article['artikel_varianten'] as $variant) { - foreach ($article['matrix_varianten']['artikel'][$variant['artikel']] as $matrixInfo) { - $configurationExists = false; - foreach ($existingConfigurations['data'] as $configuration) { - if ($configuration['attributes']['optionId'] === $internalGroupPropertiesToShopwareId[$matrixInfo['name']][$matrixInfo['values']]) { - $configurationExists = true; - break; - } - } - if (!$configurationExists) { - $optionIdsToAdd[] = $internalGroupPropertiesToShopwareId[$matrixInfo['name']][$matrixInfo['values']]; - } - } - } - if (!empty($optionIdsToAdd)) { - $optionIdsToAdd = array_flip(array_flip($optionIdsToAdd)); - $configurationData = [ - 'configuratorSettings' => [] - ]; - foreach ($optionIdsToAdd as $id) { - $configurationData['configuratorSettings'][] = ['optionId' => $id]; - } - - $this->shopwareRequest( - 'PATCH', - sprintf('product/%s', $articleIdShopware), - $configurationData - ); - - $existingConfigurations = $this->shopwareRequest( - 'GET', 'product/' . $articleIdShopware . '/configuratorSettings'); - $optionsToSort = []; - foreach ($article['artikel_varianten'] as $variant) { - foreach ($article['matrix_varianten']['artikel'][$variant['artikel']] as $matrixInfo) { - foreach ($existingConfigurations['data'] as $configuration) { - if ($configuration['attributes']['optionId'] === $internalGroupPropertiesToShopwareId[$matrixInfo['name']][$matrixInfo['values']]) { - $optionsToSort[] = $configuration['id']; - break; - } - } - } - } - if (!empty($optionsToSort)) { - $optionsToSort = array_flip(array_flip($optionsToSort)); - $configurationData = [ - 'configuratorSettings' => [] - ]; - $position = 1; - - foreach ($optionsToSort as $id) { - $configurationData['configuratorSettings'][] = [ - 'id' => $id, - 'position' => $position]; - $position++; - } - - $this->shopwareRequest( - 'PATCH', - sprintf('product/%s', $articleIdShopware), - $configurationData - ); - } - } - - return true; - } - - /** - * @param $priceArray - * @return PriceData[] - */ - protected function getPricesFromArray($priceArray): array{ - return array_map(static function($price){ - return new PriceData( - (int)$price['ab_menge'], - (float)$price['preis'], - (float)$price['bruttopreis'], - $price['waehrung'], - $price['gruppeextern'] ?? '') ; - },$priceArray); - } - - /** - * delete all old price entries for a product - * - * @param string $productId - */ - protected function deleteOldBulkPrices($productId) - { - //TODO Instead of deleting all old prices we should rather check first whether they are still in order - $oldPrices = $this->shopwareRequest( - 'GET', - sprintf('product-price?filter[product_price.productId]=%s', $productId) - ); - if (is_array($oldPrices)) { - foreach ($oldPrices['data'] as $deletePrice) { - $this->shopwareRequest('DELETE', 'product-price/' . $deletePrice['id']); - } - } else { - $this->Shopware6Log('Fehler: Alte Preise wurden nicht gelöscht', $productId); - } - } - - /** - * @return int - */ - public function getOrderSearchLimit(): int - { - if(in_array($this->orderSearchLimit, ['50', '75', '100'])) { - return (int)$this->orderSearchLimit; - } - - return 25; - } - - /** - * @return int - */ - public function ImportGetAuftraegeAnzahl() - { - $order = null; - $dataToGet = $this->CatchRemoteCommand('data'); - - if (empty($this->statesToFetch)) { - return false; - } - - $ordersToProcess = $this->getOrdersToProcess($this->getOrderSearchLimit()); - - return count($ordersToProcess['data']); - } - - /** - * @param string $parameter1 - * @param string $parameter2 - */ - public function Shopware6ErrorLog($parameter1, $parameter2 = '') - { - $this->app->DB->Insert( - sprintf( - "INSERT INTO `shopexport_log` - (shopid, typ, parameter1, parameter2, bearbeiter, zeitstempel) - VALUES (%d, 'fehler', '%s','%s','%s',NOW())", - $this->shopid, - $this->app->DB->real_escape_string($parameter1), - $this->app->DB->real_escape_string($parameter2), - $this->app->DB->real_escape_string($this->app->User->GetName()) - ) - ); - } - - /** - * @param array $stateMachinesIds - * @return array - */ - protected function getTransactionStateIdsToFetch($stateMachinesIds): array - { - $transactionStateIdsToFetch = []; - if (!empty($this->transactionStatesToFetch)) { - $transactionStatesToFetch = explode(';', $this->transactionStatesToFetch); - foreach ($transactionStatesToFetch as $transactionStateToFetch) { - $stateInformation = $this->shopwareRequest('GET', 'state-machine-state?filter[technicalName]=' . - trim($transactionStateToFetch) . '&filter[stateMachineId]=' . $stateMachinesIds['order_transaction.state']); - if (empty($stateInformation['data'])) { - $this->Shopware6ErrorLog('Zahlungsstatus für Abholung nicht gefunden', $transactionStateToFetch); - return false; - } - foreach ($stateInformation['data'] as $state) { - $transactionStateIdsToFetch[] = $state['id']; - } - } - } - - return $transactionStateIdsToFetch; - } - - /** - * @param int $limit - * - * @return mixed - */ - protected function getOrdersToProcess(int $limit) - { - $searchData = [ - 'limit' => $limit, - 'includes' => [ - 'order' => ['id'] - ], - 'sort' => [ - [ - 'field' => 'order.createdAt', - 'direction' => 'DESC' - ] - ], - 'filter' => [] - ]; - - $searchData['filter'][] = [ - 'field' => 'stateMachineState.technicalName', - 'type' => 'equalsAny', - 'value' => explode(';', $this->statesToFetch) - ]; - - if (!empty($this->deliveryStatesToFetch)) { - $searchData['filter'][] = [ - 'field' => 'deliveries.stateMachineState.technicalName', - 'type' => 'equalsAny', - 'value' => explode(';', $this->deliveryStatesToFetch) - ]; - } - if (!empty($this->transactionStatesToFetch)) { - $searchData['filter'][] = [ - 'field' => 'transactions.stateMachineState.technicalName', - 'type' => 'equalsAny', - 'value' => explode(';', $this->transactionStatesToFetch) - ]; - } - - if (!empty($this->salesChannelToFetch)) { - $searchData['filter'][] = [ - 'field' => 'order.salesChannelId', - 'type' => 'equals', - 'value' => $this->salesChannelToFetch - ]; - } - - return $this->shopwareRequest('POST', 'search/order', $searchData); - } - - /** - * @return int|mixed - */ - public function ImportGetAuftrag() - { - $voucherArticleId = $this->app->DB->Select("SELECT s.artikelrabatt FROM `shopexport` AS `s` WHERE s.id='$this->shopid' LIMIT 1"); - $voucherArticleNumber = $this->app->DB->Select("SELECT a.nummer FROM `artikel` AS `a` WHERE a.id='$voucherArticleId' LIMIT 1"); - - $dataToGet = $this->CatchRemoteCommand('data'); - if (empty($this->statesToFetch)) { - return false; - } - $expectOrderArray = !empty($dataToGet['anzgleichzeitig']) && (int)$dataToGet['anzgleichzeitig'] > 1; - $expectNumber = !empty($dataToGet['nummer']); - $order = null; - if($expectNumber) { - $order = $this->shopwareRequest('GET', 'order/' . $dataToGet['nummer'] . '?associations[currency][]'); - if(empty($order['data'])) { - return false; - } - $ordersToProcess = ['data' => [ ['id' => $dataToGet['nummer']] ]]; - $orderIncludedData = $order['included']; - $order = $order['data']; - } - elseif(!$expectOrderArray) { - $ordersToProcess = $this->getOrdersToProcess(1); - } - elseif(!$expectNumber) { - $ordersToProcess = $this->getOrdersToProcess($this->getOrderSearchLimit()); - } - if (empty($ordersToProcess['data'])) { - return false; - } - - $fetchedOrders = []; - if (isset($ordersToFetch['data']['id']) && !isset($ordersToFetch['data'][0])) { - $ordersToFetch['data'] = [$ordersToFetch['data']]; - } - foreach ($ordersToProcess['data'] as $currentlyOpenOrder) { - $orderIdToFetch = $currentlyOpenOrder['id']; - - if (empty($dataToGet['nummer']) || empty($order)) { - $order = $this->shopwareRequest('GET', 'order/' . $orderIdToFetch.'?associations[currency][]'); - $orderIncludedData = $order['included']; - $order = $order['data']; - } - $cart = []; - try { - $timestamp = date_create_from_format('Y-m-d\TH:i:s+', $order['attributes']['createdAt']); - $cart['zeitstempel'] = $timestamp->format('Y-m-d H:i:s'); - } catch (Exception $ex) { - - } - $cart['auftrag'] = $order['id']; - $cart['subshop'] = $order['attributes']['salesChannelId']; - $cart['order'] = $order; - $cart['onlinebestellnummer'] = $order['attributes']['orderNumber']; - $cart['gesamtsumme'] = $order['attributes']['amountTotal']; - $cart['versandkostenbrutto'] = $order['attributes']['shippingTotal']; - $cart['bestelldatum'] = substr($order['attributes']['orderDate'], 0, 10); - if (!empty($order['attributes']['customerComment'])) { - $cart['freitext'] = $order['attributes']['customerComment']; - } - - foreach ($orderIncludedData as $includedDataSet){ - if($includedDataSet['type'] === 'currency'){ - $cart['waehrung'] = $includedDataSet['attributes']['isoCode']; - } - } - - $deliveryInfo = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/deliveries'); - $shippingMethod = $this->shopwareRequest('GET', - 'order-delivery/' . $deliveryInfo['data'][0]['id'] . '/shipping-method'); - $order['shippingMethod'] = $shippingMethod; - $cart['lieferung'] = $shippingMethod['data'][0]['attributes']['name']; - - $customer = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/order-customer'); - $order['customer'] = $customer; - $cart['email'] = $customer['data']['0']['attributes']['email']; - - $addresses = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/addresses?associations[salutation][]&associations[country][]'); - $order['addresses'] = $addresses; - $deliveryCountryId = ''; - $billingCountryId = ''; - $billingSalutationId = ''; - foreach ($addresses['data'] as $address) { - if ($address['id'] === $order['attributes']['billingAddressId']) { - if (!empty($address['attributes']['vatId'])) { - $cart['ustid'] = $address['attributes']['vatId']; - } - $cart['name'] = $address['attributes']['firstName'] . ' ' . $address['attributes']['lastName']; - if (!empty($address['attributes']['company'])) { - $cart['ansprechpartner'] = $cart['name']; - $cart['name'] = $address['attributes']['company']; - } - $cart['strasse'] = $address['attributes']['street']; - $cart['abteilung'] = $address['attributes']['department']; - $cart['adresszusatz'] = trim($address['attributes']['additionalAddressLine1'].' '. - $address['attributes']['additionalAddressLine2']); - $cart['telefon'] = $address['attributes']['phoneNumber']; - $cart['plz'] = $address['attributes']['zipcode']; - $cart['ort'] = $address['attributes']['city']; - $billingCountryId = $address['attributes']['countryId']; - $billingSalutationId = $address['attributes']['salutationId']; - } - if ($address['id'] !== $order['attributes']['billingAddressId']) { - $cart['abweichendelieferadresse'] = 1; - if (!empty($address['attributes']['vatId'])) { - $cart['lieferadresse_ustid'] = $address['attributes']['vatId']; - } - $cart['lieferadresse_name'] = $address['attributes']['firstName'] . ' ' . $address['attributes']['lastName']; - if (!empty($address['attributes']['company'])) { - $cart['lieferadresse_ansprechpartner'] = $cart['lieferadresse_name']; - $cart['lieferadresse_name'] = $address['attributes']['company']; - } - $cart['lieferadresse_strasse'] = $address['attributes']['street']; - $cart['lieferadresse_abteilung'] = $address['attributes']['department']; - $cart['lieferadresse_adresszusatz'] = trim($address['attributes']['additionalAddressLine1'].' '. - $address['attributes']['additionalAddressLine2']); - $cart['lieferadresse_plz'] = $address['attributes']['zipcode']; - $cart['lieferadresse_ort'] = $address['attributes']['city']; - $deliveryCountryId = $address['attributes']['countryId']; - } - } - - $anrede = 'herr'; - $land = 'DE'; - $lieferadresseLand = 'DE'; - foreach ($addresses['included'] as $includedInfo) { - if ($includedInfo['id'] === $billingCountryId) { - $land = $includedInfo['attributes']['iso']; - } - if ($includedInfo['id'] === $deliveryCountryId) { - $lieferadresseLand = $includedInfo['attributes']['iso']; - } - if ($includedInfo['id'] === $billingSalutationId) { - $salutation = $includedInfo['attributes']['salutationKey']; - if ($salutation === 'ms' || $salutation === 'mrs') { - $anrede = 'frau'; - } - } - } - - $cart['anrede'] = $anrede; - $cart['land'] = $land; - if (!empty($cart['abweichendelieferadresse'])) { - $cart['lieferadresse_land'] = $lieferadresseLand; - } - - $transactionData = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/transactions'); - $cart['transacion_data'] = $transactionData; - if (!empty($transactionData['data'][0]['attributes']['customFields']['swag_paypal_pui_payment_instruction']['reference_number'])) { - $cart['transaktionsnummer'] = $transactionData['data'][0]['attributes']['customFields']['swag_paypal_pui_payment_instruction']['reference_number']; - } - if (empty($cart['transaktionsnummer'] && !empty($transactionData['data'][0]['attributes']['customFields']['swag_paypal_order_id']))) { - $cart['transaktionsnummer'] = (string)$transactionData['data'][0]['attributes']['customFields']['swag_paypal_order_id']; - } - if (empty($cart['transaktionsnummer'] && !empty($transactionData['data'][0]['attributes']['customFields']['swag_paypal_transaction_id']))) { - $livePayPalData = $this->shopwareRequest('GET', 'paypal/payment-details/' . $order['id'] . '/' . $transactionData['data'][0]['attributes']['customFields']['swag_paypal_transaction_id']); - if (!empty($livePayPalData['transactions'])) { - foreach ($livePayPalData['transactions'] as $payPalData) { - foreach ($payPalData['related_resources'] as $ressources) { - if ($ressources['sale']['state'] === 'completed') { - $cart['transaktionsnummer'] = $ressources['sale']['id']; - break 2; - } - } - } - } - } - if( - empty($cart['transaktionsnummer']) - && isset($transactionData['data'][0]['attributes']['customFields']['stripe_payment_context']['payment']['payment_intent_id']) - ){ - $cart['transaktionsnummer'] = $transactionData['data'][0]['attributes']['customFields']['stripe_payment_context']['payment']['payment_intent_id']; - } - - $paymentMethodId = $transactionData['data'][0]['attributes']['paymentMethodId']; - $paymentMethod = $this->shopwareRequest('GET', 'payment-method/' . $paymentMethodId); - $cart['zahlungsweise'] = $paymentMethod['data']['attributes']['name']; - - $taxedCountry = $land; - if($this->taxationByDestinationCountry){ - $taxedCountry = $lieferadresseLand; - } - if($order['attributes']['amountTotal'] === $order['attributes']['amountNet']){ - if($this->app->erp->IstEU($taxedCountry)){ - $cart['ust_befreit'] = 1; - }elseif($this->app->erp->Export($taxedCountry)){ - $cart['ust_befreit'] = 2; - }else{ - $cart['ust_befreit'] = 3; - } - } - - $lineItems = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/line-items'); - $order['lineItems'] = $lineItems; - $cart['articlelist'] = []; - - $taxRate = 0; - foreach ($lineItems['data'] as $lineItem) { - if ($lineItem['attributes']['price']['calculatedTaxes'][0]['taxRate'] > $taxRate) { - $taxRate = $lineItem['attributes']['price']['calculatedTaxes'][0]['taxRate']; - } - } - - $orderPriceType = 'price'; - if(in_array($order['attributes']['taxStatus'], ['net', 'tax-free'])) { - $orderPriceType = 'price_netto'; - $cart['versandkostennetto'] = $cart['versandkostenbrutto']; - unset($cart['versandkostenbrutto']); - } - - foreach ($lineItems['data'] as $lineItem) { - $productPriceType = $orderPriceType; - if(empty($lineItem['attributes']['price']['calculatedTaxes'][0]['taxRate'])){ - $productPriceType = 'price_netto'; - } - $articleId = null; - if($lineItem['attributes']['price']['unitPrice'] < 0) { - $articleId = $voucherArticleNumber; - } - elseif(isset($lineItem['attributes']['payload']['productNumber'])){ - $articleId = $lineItem['attributes']['payload']['productNumber']; - } - $product = [ - 'articleid' => $articleId, - 'name' => $lineItem['attributes']['label'], - 'quantity' => $lineItem['attributes']['quantity'], - $productPriceType => $lineItem['attributes']['price']['unitPrice'], - 'steuersatz' => $lineItem['attributes']['price']['calculatedTaxes'][0]['taxRate'], - ]; - $cart['articlelist'][] = $product; - } - - $cart['order'] = $order; - $fetchedOrders[] = [ - 'id' => $cart['auftrag'], - 'sessionid' => '', - 'logdatei' => '', - 'warenkorb' => base64_encode(serialize($cart)), - 'warenkorbjson' => base64_encode(json_encode($cart)), - ]; - $this->Shopware6Log('Ergebnis: Auftrag', $order); - $this->Shopware6Log('Ergebnis: Adresse', $addresses); - $this->Shopware6Log('Ergebnis: Positionen', $lineItems); - } - - return $fetchedOrders; - } - - /** - * @return void - */ - public function ImportDeleteAuftrag() - { - $tmp = $this->CatchRemoteCommand('data'); - $auftrag = $tmp['auftrag']; - - $this->shopwareRequest('POST', '_action/order/'.$auftrag.'/state/process'); - $this->addCustomFieldToOrder((string)$auftrag); - } - - /** - * @return void - */ - public function ImportUpdateAuftrag() - { - $tmp = $this->CatchRemoteCommand('data'); - $auftrag = $tmp['auftrag']; - $tracking = $tmp['tracking']; - - $this->shopwareRequest('POST', '_action/order/'.$auftrag.'/state/complete'); - - $deliveries = $this->shopwareRequest('GET', 'order/'.$auftrag.'/deliveries'); - $deliveryId = $deliveries['data'][0]['id']; - - if(!empty($deliveryId)){ - $this->shopwareRequest('POST', '_action/order_delivery/'.$deliveryId.'/state/ship'); - - $deliveryData = [ - 'trackingCodes' => [$tracking] - ]; - $this->shopwareRequest('PATCH', 'order-delivery/'.$deliveryId,$deliveryData); - } - - $this->sendInvoce($auftrag); - $this->addCustomFieldToOrder((string)$auftrag); - if(empty($tmp['orderId'])) { - return; - } - $this->updateStorageForOrderIntId((int)$tmp['orderId']); - } - - public function ImportStorniereAuftrag() - { - $tmp = $this->CatchRemoteCommand('data'); - $auftrag = $tmp['auftrag']; - - $this->shopwareRequest('POST', '_action/order/'.$auftrag.'/state/cancel'); - $this->addCustomFieldToOrder((string)$auftrag); - } - - /** - * @param string $extOrderId - */ - protected function sendInvoce($extOrderId) - { - $order = $this->app->DB->SelectRow( - sprintf( - "SELECT `rechnungid`, `id` FROM `auftrag` WHERE shopextid='%s'", - $extOrderId - ) - ); - $invoiceId = 0; - if (!empty($order['rechnungid'])) { - $invoiceId = $order['rechnungid']; - $sql = sprintf("SELECT projekt, belegnr FROM rechnung WHERE id='%s'", $invoiceId); - $invoiceData = $this->app->DB->SelectRow($sql); - } - if (empty($invoiceId) && !empty($order['id'])) { - $invoiceData = $this->app->DB->SelectRow( - sprintf( - "SELECT `id`, `projekt`, `belegnr` - FROM `rechnung` - WHERE `auftragid` = %d AND `status` <> 'storniert' AND `status` <> 'angelegt' - LIMIT 1", - $order['id'] - ) - ); - if (!empty($invoiceData)) { - $invoiceId = $invoiceData['id']; - } - } - - if (!empty($invoiceData['belegnr'])) { - $projekt = $invoiceData['projekt']; - if (class_exists('RechnungPDFCustom')) { - $Brief = new RechnungPDFCustom($this->app, $projekt); - } else { - $Brief = new RechnungPDF($this->app, $projekt); - } - - $Brief->GetRechnung($invoiceId); - $filePath = $Brief->displayTMP(true); - - $documentNumber = $invoiceData['belegnr']; - $invoiceDocumentData = [ - 'config' => [ - 'custom' => [ - 'invoiceNumber' => $documentNumber, - ], - 'documentComment' => 'Aus Xentral heraus erstellte Rechnung', - 'documentNumber' => $documentNumber, - ], - 'referenced_document_id' => null, - 'static' => true - ]; - - $documentData = $this->shopwareRequest('POST', '_action/order/' . $extOrderId . '/document/invoice', $invoiceDocumentData); - $documentId = $documentData['documentId']; - - $accessToken = $this->shopwareToken(); - $url = $this->ShopUrl . 'v2/_action/document/' . $documentId . '/upload?_response=true&extension=pdf&fileName=' . $documentNumber; - - $ch = curl_init(); - $setHeaders = [ - 'Content-Type:application/pdf', - 'Authorization:Bearer ' . $accessToken['token'] - ]; - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents($filePath)); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); - curl_setopt($ch, CURLOPT_HTTPHEADER, $setHeaders); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - $response = json_decode(curl_exec($ch), true); - curl_close($ch); - if (!empty($response['errors'])) { - $this->Shopware6Log( - 'Fehler bei Rechnugnsübertragung für ' . $documentNumber, $response['errors'] - ); - } - } - } - - /** - * @return string - */ - public function ImportAuth() - { - $tokeninfo = $this->shopwareToken(); - - - if (!$tokeninfo['success']) { - return 'failed: ' . $tokeninfo['message']; - } - if($this->data === 'info'){ - $salesChannelsInShopware = $this->client->getAllSalesChannels(); - $salesChannelsToShow = ['subshops' => []]; - foreach ($salesChannelsInShopware['data'] as $salesChannelInShopware){ - $salesChannelsToShow['subshops'][] = [ - 'id'=>$salesChannelInShopware['id'], - 'name'=>$salesChannelInShopware['name'], - 'aktiv'=>$salesChannelInShopware['active'] - ]; - } - return $salesChannelsToShow; - } - - return 'success'; - } - - /** - * Build category tree as displayed in article info - * May be useful for setting category in the future - * but probably obsolete - * - * @param string $categoryName - * @param array $categoryTree - * - * @return array - */ - protected function appendCategoryTree($categoryName, $categoryTree = []) - { - $shopwareCategory = $this->shopwareRequest( - 'GET', - 'category?filter[category.name]=' . urlencode($categoryName) - ); - if (!isset($shopwareCategory['data'][0]['id'])) { - return $categoryTree; - } - $categoryInfo = $shopwareCategory['data'][0]['attributes']; - $categories[] = [(int)$categoryInfo['level'], $shopwareCategory['data'][0]['id']]; - $path = $categoryInfo['path']; - if (!empty($path)) { - $pathArray = explode('|', $path); - foreach ($pathArray as $nodeId) { - if ($nodeId === '') { - continue; - } - $nodeCategory = $this->shopwareRequest('GET', 'category/' . $nodeId); - if (isset($nodeCategory['data']['id'])) { - $categories[] = [(int)$nodeCategory['data']['attributes']['level'], $nodeId]; - unset($nodeCategory); - } - } - } - foreach ($categories as $category) { - $level = $category[0]; - if (!isset($categoryTree[$level])) { - $categoryTree[$level] = []; - } - if (!in_array($category, $categoryTree[$level], true)) { - $categoryTree[$level][] = $category[1]; - } - } - ksort($categoryTree); - - return $categoryTree; - } - - /** - * @param array $postData - * - * @return array - */ - public function updatePostDataForAssistent($postData) - { - if(!empty($this->ShopUrl)) { - $postData['shopwareUrl'] = $this->ShopUrl; - } - return $postData; - } - - /** - * @param array $shopArr - * @param array $postData - * - * @return array - */ - public function updateShopexportArr($shopArr, $postData) - { - $shopArr['stornoabgleich'] = 1; - $shopArr['demomodus'] = 0; - - return $shopArr; - } - - /** - * @return JsonResponse|null - */ - public function AuthByAssistent() - { - $shopwareUrl = $this->app->Secure->GetPOST('shopwareUrl'); - $shopwareUserName = $this->app->Secure->GetPOST('shopwareUserName'); - $shopwarePassword = $this->app->Secure->GetPOST('shopwarePassword'); - $step = (int)$this->app->Secure->GetPOST('step'); - - if($step <= 1){ - if(empty($shopwareUrl)){ - return new JsonResponse(['error' => 'Bitte die URL des Shops angeben.'], JsonResponse::HTTP_BAD_REQUEST); - } - if(empty($shopwareUserName)){ - return new JsonResponse(['error' => 'Bitte den Benutzernamen angeben'], JsonResponse::HTTP_BAD_REQUEST); - } - if(empty($shopwarePassword)){ - return new JsonResponse(['error' => 'Bitte das Passwort angeben'], JsonResponse::HTTP_BAD_REQUEST); - } - - $this->UserName = $shopwareUserName; - $this->Password = $shopwarePassword; - $shopwareUrl = rtrim($shopwareUrl, '/') . '/'; - $testUrls = []; - $hasNoHttp = strpos($shopwareUrl,'http') !== 0; - if(substr($shopwareUrl, -5) !== '/api/') { - if($hasNoHttp) { - $testUrls[] = 'https://'.$shopwareUrl.'api/'; - $testUrls[] = 'http://'.$shopwareUrl.'api/'; - } - $testUrls[] = $shopwareUrl.'api/'; - } - elseif($hasNoHttp) { - $testUrls[] = 'https://'.$shopwareUrl; - $testUrls[] = 'http://'.$shopwareUrl; - } - else { - $testUrls[] = $shopwareUrl; - } - foreach($testUrls as $testUrl) { - $this->ShopUrl = $testUrl; - $tokeninfo = $this->shopwareToken(); - if(!empty($tokeninfo['success'])) { - break; - } - } - - if(!$tokeninfo['success']){ - return new JsonResponse(['error' => $tokeninfo['message']], JsonResponse::HTTP_BAD_REQUEST); - } - } - - return null; - } - - /** - * @return string - */ - public function getClickByClickHeadline() - { - return 'Bitte im Shopware Backend einen eigenen Benutzer für Xentral anlegen und diese - Zugangsdaten hier eintragen.'; - } - - /** - * @return array - */ - public function getStructureDataForClickByClickSave() - { - return [ - 'shopwareAllowCreateManufacturer' => 1, - ]; - } - - /** - * @return array[] - */ - public function getCreateForm() - { - return [ - [ - 'id' => 0, - 'name' => 'urls', - 'inputs' => [ - [ - 'label' => 'URL des Shops', - 'type' => 'text', - 'name' => 'shopwareUrl', - 'validation' => true, - ], - ], - ], - [ - 'id' => 1, - 'name' => 'username', - 'inputs' => [ - [ - 'label' => 'Benutzername aus Shopware', - 'type' => 'text', - 'name' => 'shopwareUserName', - 'validation' => true, - ], - ], - ], - [ - 'id' => 2, - 'name' => 'password', - 'inputs' => [ - [ - 'label' => 'Passwort aus Shopware', - 'type' => 'password', - 'name' => 'shopwarePassword', - 'validation' => true, - ], - ], - ], - ]; - } - - public function getBoosterHeadline(): string - { - return 'Shopware 6 Business Booster App'; - } - - public function getBoosterSubHeadline(): string - { - return 'Bitte gehe auf Shopware 6 und installiere dort das Plugin Xentral Business Booster App. - Dort kann man sich dann mit ein paar Klicks mit Xentral verbinden.'; - } - - /** - * @param int $intOrderId - * - * @return array - */ - protected function getArticleShopLinks(int $intOrderId): array - { - return $this->app->DB->SelectPairs( - "SELECT DISTINCT ao.artikel, a.nummer - FROM `auftrag_position` AS `ap` - INNER JOIN `auftrag` AS `ab` ON ap.auftrag = ab.id - INNER JOIN `artikel` AS `a` ON ap.artikel = a.id - INNER JOIN `artikel_onlineshops` AS `ao` ON ab.shop = ao.shop AND a.id = ao.artikel - WHERE ab.id = {$intOrderId} AND ao.aktiv = 1" - ); - } - - /** - * @param array $articleIds - */ - protected function updateArticleCacheToSync(array $articleIds): void - { - if(empty($articleIds)) { - return; - } - $articleIdsString = implode(', ', $articleIds); - $this->app->DB->Update( - "UPDATE `artikel` - SET `laststorage_changed` = DATE_ADD(NOW(), INTERVAL 1 SECOND) - WHERE `id` IN ({$articleIdsString})" - ); - } - - /** - * @param array $articleIds - */ - protected function updateArticleOnlineShopCache(array $articleIds): void - { - if(empty($articleIds)) { - return; - } - $articleIdsString = implode(', ', $articleIds); - $this->app->DB->Update( - "UPDATE `artikel_onlineshops` - SET `storage_cache` = -999, `pseudostorage_cache` = -999 - WHERE `artikel` IN ({$articleIdsString}) AND `aktiv` = 1 AND `shop` = {$this->shopid}" - ); - } - - /** - * @param int $intOrderId - */ - protected function updateStorageForOrderIntId(int $intOrderId): void - { - $articles = $this->getArticleShopLinks($intOrderId); - if(empty($articles)) { - return; - } - $articleIds = array_keys($articles); - $this->updateArticleCacheToSync($articleIds); - $this->updateArticleOnlineShopCache($articleIds); - - $isStorageSyncCronjobActive = (int)$this->app->DB->Select( - "SELECT COUNT(`id`) FROM `prozessstarter` WHERE `aktiv` = 1 AND `parameter` = 'lagerzahlen'" - ) > 0; - if(!$isStorageSyncCronjobActive) { - return; - } - foreach($articleIds as $articleId) { - try { - $this->app->erp->LagerSync($articleId, false, [$this->shopid]); - } - catch (Exception $e) { - $articleNumber = $articles[$articleId]; - $this->Shopware6ErrorLog('LagerSync konnte nicht ausgeführt werden', $articleNumber); - } - } - - $this->updateArticleCacheToSync($articleIds); - } -} +app = $app; + $this->intern = true; + if ($intern) { + return; + } + $this->app->ActionHandlerInit($this); + + $this->app->ActionHandler('list', 'Shopimporter_Shopware6List'); + $this->app->ActionHandler('auth', 'ImportAuth'); + $this->app->ActionHandler('sendlistlager', 'ImportSendListLager'); + $this->app->ActionHandler('getauftraegeanzahl', 'ImportGetAuftraegeAnzahl'); + $this->app->ActionHandler('getauftrag', 'ImportGetAuftrag'); + $this->app->ActionHandler('deleteauftrag', 'ImportDeleteAuftrag'); + $this->app->ActionHandler('updateauftrag', 'ImportUpdateAuftrag'); + $this->app->ActionHandler('storniereauftrag','ImportStorniereAuftrag'); + $this->app->ActionHandler('getarticle','ImportGetArticle'); + $this->app->ActionHandler('getarticlelist','ImportGetArticleList'); + $this->app->ActionHandler("updatezahlungsstatus","ImportUpdateZahlungsstatus"); + $this->app->DefaultActionHandler('list'); + + $this->app->ActionHandlerListen($app); + } + + /** + * @param string $productId + * + * @return mixed + */ + public function addSyncCustomFieldToProduct(string $productId) + { + $customField = [ + 'customFields' => [ + 'wawision_shopimporter_syncstate' => 1 + ] + ]; + + return $this->shopwareRequest('PATCH', "product/{$productId}", $customField); + } + + /** + * @param string $orderId + * + * @return mixed + */ + public function addCustomFieldToOrder(string $orderId) + { + $customField = [ + 'customFields' => [ + 'wawision_shopimporter_syncstate' => 1 + ] + ]; + + return $this->shopwareRequest('PATCH', "order/{$orderId}", $customField); + } + + public function ImportGetArticleList() + { + $page = 1; + $limit = 500; + + do { + $productIdsToAdd = []; + $searchdata = [ + 'limit' => $limit, + 'page' => $page, + 'filter' => [ + [ + 'field' => 'product.parentId', + 'type' => 'equals', + 'value' => null + ] + ] + ]; + + $productsInShop = $this->shopwareRequest('POST', 'search/product', $searchdata); + if (!empty($productsInShop['data'])) { + foreach ($productsInShop['data'] as $productInShop) { + $productIdsToAdd[] = $productInShop['id']; + } + } + + foreach ($productIdsToAdd as $productId) { + $this->app->DB->Insert("INSERT INTO shopexport_getarticles (shop, nummer) VALUES ('$this->shopid', '" . $this->app->DB->real_escape_string($productId) . "')"); + } + $page++; + } while (count($productsInShop['data']) === $limit); + + + $anzahl = $this->app->DB->Select("SELECT COUNT(id) FROM shopexport_getarticles WHERE shop=$this->shopid"); + $this->app->erp->SetKonfigurationValue('artikelimportanzahl_' . $this->shopid, $anzahl); + + } + + /** + * @param string $method + * @param string $endpoint + * @param string $data + * + * @param array $headerInformation + * @return mixed + */ + public function shopwareRequest($method, $endpoint, $data = '', $headerInformation = []) + { + $accessToken = $this->shopwareToken(); + $url = $this->ShopUrl; + $url .= 'v2/' . $endpoint; + + $ch = curl_init(); + $headerInformation[] = 'Content-Type:application/json'; + $headerInformation[] = 'Authorization:Bearer ' . $accessToken['token']; + curl_setopt($ch, CURLOPT_URL, $url); + if (!empty($data)) { + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + } + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headerInformation); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $response = curl_exec($ch); + if (curl_error($ch)) { + $this->error[] = curl_error($ch); + } + curl_close($ch); + + return json_decode($response, true); + } + + /** + * @return array + */ + protected function shopwareToken() + { + $result = []; + + $result['success'] = true; + $result['token'] = $this->accessToken; + $result['message'] = 'Keine Antwort von API erhalten.'; + + if (!empty($result['token'])) { + return $result; + } + + $result['success'] = false; + + $data = [ + 'username' => $this->UserName, + 'password' => $this->Password, + 'grant_type' => 'password', + 'scopes' => 'write', + 'client_id' => 'administration', + ]; + + $ch = curl_init($this->ShopUrl . 'oauth/token'); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Accept: application/json', + 'Content-Type: application/json', + 'Cache-Control: no-cache', + ] + ); + $response = json_decode(curl_exec($ch), true); + + if (!empty((string)$response['title'])) { + $result['message'] = $response['title']; + } + + if (!empty($response['access_token'])) { + $result['success'] = true; + $this->accessToken = $response['access_token']; + $result['token'] = $response['access_token']; + } + + return $result; + } + + public function ImportGetArticle() + { + $tmp = $this->CatchRemoteCommand('data'); + + if (isset($tmp['nummerintern'])) { + $nummer = $tmp['nummerintern']; + $response = $this->shopwareRequest('GET', 'product/' . $nummer); + if (empty($response['data'])) { + $this->error[] = 'Artikel in der Shop Datenbank nicht gefunden!'; + return; + } + $nummer = $response['data']['attributes']['productNumber']; + } else { + $nummer = $tmp['nummer']; + } + $articleInfo = $this->shopwareRequest('GET', 'product?filter[product.productNumber]=' . $nummer . + '&associations[manufacturer][]&associations[properties][]'); + if (empty($articleInfo['data'][0])) { + $this->error[] = 'Artikel in der Shop Datenbank nicht gefunden!'; + return; + } + $articleIdInShop = $articleInfo['data'][0]['id']; + if(empty($articleInfo['data'][0]['customFields']) + || empty($articleInfo['data'][0]['customFields']['wawision_shopimporter_syncstate'])){ + $this->addSyncCustomFieldToProduct((string)$articleIdInShop); + } + + $articleInfo = $this->shopwareRequest('GET', 'product?filter[product.productNumber]=' . $nummer . + '&associations[manufacturer][]&associations[properties][]'); + $associatedInformation = []; + $properties = []; + foreach ($articleInfo['included'] as $includedInformation) { + if ($includedInformation['type'] === 'property_group_option') { + $properties[$includedInformation['id']] = $includedInformation['attributes']; + } else { + $associatedInformation[$includedInformation['id']] = $includedInformation['attributes']; + } + } + $groups = []; + if (!empty($properties)) { + $groupsInShop = $this->shopwareRequest('GET', 'property-group'); + foreach ($groupsInShop['data'] as $groupInShop) { + $groups[$groupInShop['id']] = $groupInShop['attributes']['name']; + } + } + $media = $this->shopwareRequest('GET', 'product/' . $articleIdInShop . '/media'); + $imagesToAdd = []; + if (!empty($media['included'])) { + foreach ($media['included'] as $mediaInfo) { + if ($mediaInfo['type'] === 'media') { + $imagesToAdd[] = [ + 'content' => base64_encode(@file_get_contents($mediaInfo['attributes']['url'])), + 'path' => $mediaInfo['attributes']['url'], + 'id' => $mediaInfo['id'] + ]; + } + } + } + $articleInfo = $articleInfo['data'][0]['attributes']; + + $data = []; + $data['name'] = $articleInfo['name']; + if (isset($tmp['nummerintern'])) { + $data['nummer'] = $articleInfo['productNumber']; + } + + + $data['artikelnummerausshop'] = $articleInfo['productNumber']; + $data['restmenge'] = $articleInfo['stock']; + $data['uebersicht_de'] = $articleInfo['description']; + $data['preis_netto'] = $articleInfo['price'][0]['net']; + if (!empty($articleInfo['price'][0]['listPrice'])) { + $data['pseudopreis'] = $articleInfo['price'][0]['listPrice']; + } + $data['aktiv'] = $articleInfo['active']; + if (!empty($articleInfo['weight'])) { + $data['gewicht'] = $articleInfo['weight']; + } + if (!empty($articleInfo['manufacturerNumber'])) { + $data['herstellernummer'] = $articleInfo['manufacturerNumber']; + } + if (!empty($articleInfo['ean'])) { + $data['ean'] = $articleInfo['ean']; + } + if (!empty($articleInfo['manufacturerId'])) { + $data['hersteller'] = $associatedInformation[$articleInfo['manufacturerId']]['name']; + } + if (!empty($articleInfo['taxId'])) { + $data['umsatzsteuer'] = $associatedInformation[$articleInfo['taxId']]['taxRate']; + } + if (!empty($properties)) { + foreach ($properties as $property) { + if ($this->propertyOption === 'toProperties') { + $data['eigenschaften'][] = [ + 'name' => $groups[$property['groupId']], + 'values' => $property['name'], + ]; + } + if ($this->propertyOption === 'toCustomFields') { + $data['freifeld_' . $groups[$property['groupId']]] = $property['name']; + } + } + } + if (!empty($articleInfo['customFields'])) { + foreach ($articleInfo['customFields'] as $customFieldName => $customFieldValue) { + if ($this->freeFieldOption === 'toProperties') { + $data['eigenschaften'][] = [ + 'name' => $customFieldName, + 'values' => $customFieldValue + ]; + } + if ($this->freeFieldOption === 'toCustomFields') { + $data['freifeld_' . $customFieldName] = $customFieldValue; + } + } + } + if (!empty($imagesToAdd)) { + $data['bilder'] = $imagesToAdd; + } + + + if ($articleInfo['childCount'] > 0) { + $data = [$data]; + + $limit = 50; + $page = 1; + $optionInfo = []; + $optionGroupInfo = []; + do { + + $searchdata = [ + 'limit' => $limit, + 'page' => $page, + 'filter' => [ + [ + 'field' => 'product.parentId', + 'type' => 'equals', + 'value' => $articleIdInShop + ] + ], + 'sort' => [ + [ + 'field' => 'product.options.groupId', + 'naturalSorting' => false, + 'order' => 'ASC' + ], + [ + 'field' => 'product.options.id', + 'naturalSorting' => false, + 'order' => 'ASC' + ] + ], + 'associations' => [ + 'options' => [ + 'sort' => [ + [ + 'field' => 'groupId', + 'naturalSorting' => false, + 'order' => 'ASC' + ], + [ + 'field' => 'id', + 'naturalSorting' => false, + 'order' => 'ASC' + ] + ] + ] + ] + ]; + $variantsInShop = $this->shopwareRequest('POST', 'search/product', $searchdata); + foreach ($variantsInShop['included'] as $includedInfo) { + if ($includedInfo['type'] === 'property_group_option') { + $optionInfo[$includedInfo['id']] = $includedInfo['attributes']; + if (empty($optionGroupInfo[$includedInfo['attributes']['groupId']])) { + $optionGroupInfo[$includedInfo['attributes']['groupId']] = (!empty($optionGroupInfo)?count($optionGroupInfo):0) + 1; + } + } + } + + foreach ($variantsInShop['data'] as $variantInShop) { + $variantData = []; + $variantName = $data[0]['name']; + foreach ($variantInShop['attributes']['optionIds'] as $optionId) { + $variantData['matrixprodukt_wert' . $optionGroupInfo[$optionInfo[$optionId]['groupId']]] = + $optionInfo[$optionId]['name']; + $variantName .= ' - ' . $optionInfo[$optionId]['name']; + } + + $variantData['name'] = $variantName; + $variantData['nummer'] = $variantInShop['attributes']['productNumber']; + $variantData['artikelnummerausshop'] = $variantInShop['attributes']['productNumber']; + $variantData['restmenge'] = $variantInShop['attributes']['stock']; + $variantData['uebersicht_de'] = $variantInShop['attributes']['description']; + if (empty($variantInShop['attributes']['price'][0]['net'])) { + $variantData['preis_netto'] = $data[0]['preis_netto']; + } else { + $variantData['preis_netto'] = $variantInShop['attributes']['price'][0]['net']; + } + if (!empty($variantInShop['attributes']['price'][0]['listPrice'])) { + $variantData['pseudopreis'] = $variantInShop['attributes']['price'][0]['listPrice']; + } + $variantData['aktiv'] = $variantInShop['attributes']['active']; + if (!empty($variantInShop['attributes']['weight'])) { + $variantData['gewicht'] = $variantInShop['attributes']['weight']; + } + if (!empty($variantInShop['attributes']['manufacturerNumber'])) { + $variantData['herstellernummer'] = $variantInShop['attributes']['manufacturerNumber']; + } + if (!empty($variantInShop['attributes']['ean'])) { + $variantData['ean'] = $variantInShop['attributes']['ean']; + } + if (!empty($data[0]['umsatzsteuer'])) { + $variantData['umsatzsteuer'] = $data[0]['umsatzsteuer']; + } + + $data[] = $variantData; + } + + $page++; + } while (count($variantsInShop['data']) > $limit); + + foreach ($optionGroupInfo as $groupId => $sorting) { + $data[0]['matrixprodukt_gruppe' . $sorting] = $groups[$groupId]; + } + foreach ($optionInfo as $optionData) { + $data[0]['matrixprodukt_optionen' . $optionGroupInfo[$optionData['groupId']]][] = $optionData['name']; + } + } + + //TODO Staffelpreise + //TODO Kategorien + //TODO Freifelder + //TODO Crossselling + + return $data; + } + + /** + * @param array $data + * + * @return array + */ + public function checkApiApp($data) + { + foreach (['shopwareUserName', 'shopwarePassword', 'shopwareUrl'] as $field) { + if (empty($data['data'][$field])) { + return ['success' => false, 'error' => sprintf('%s is empty', $field)]; + } + } + + $shops = $this->app->DB->SelectArr( + sprintf( + "SELECT `einstellungen_json`, `bezeichnung`,`id` + FROM `shopexport` + WHERE `modulename` = 'shopimporter_shopware6' + AND `einstellungen_json` IS NOT NULL AND `einstellungen_json` <> ''" + ) + ); + if (empty($shops)) { + return [ + 'info' => [ + 'Shop' => 'Shopware', + 'info' => 'Url ' . $data['data']['shopwareUrl'], + ] + ]; + } + foreach ($shops as $shop) { + if (empty($shop['einstellungen_json'])) { + continue; + } + $json = @json_decode($shop['einstellungen_json'], true); + if (empty($json['felder']) || empty($json['felder']['shopwareUrl'])) { + continue; + } + if ($json['felder']['shopwareUrl'] === $data['data']['shopwareUrl']) { + return [ + 'success' => false, + 'error' => sprintf('Shop with url %s allready exists', $data['data']['shopwareUrl']) + ]; + } + } + + return [ + 'info' => [ + 'Shop' => 'Shopware', + 'info' => 'Url ' . $data['data']['shopwareUrl'], + ] + ]; + } + + /** + * + */ + public function Shopimporter_Shopware6List() + { + $msg = $this->app->erp->base64_url_encode('
Sie können hier die Shops einstellen
'); + header('Location: index.php?module=onlineshops&action=list&msg=' . $msg); + exit; + } + + /** + * @param $shopid + * @param $data + */ + public function getKonfig($shopid, $data) + { + $this->shopid = $shopid; + $this->data = $data; + $importerSettings = $this->app->DB->SelectArr("SELECT `einstellungen_json`, `kategorienuebertragen` FROM `shopexport` WHERE `id` = '$shopid' LIMIT 1"); + $importerSettings = reset($importerSettings); + + $this->exportCategories = (bool) $importerSettings['kategorienuebertragen']; + + $einstellungen = []; + if (!empty($importerSettings['einstellungen_json'])) { + $einstellungen = json_decode($importerSettings['einstellungen_json'], true); + } + $this->protocol = $einstellungen['felder']['protocol']; + $this->UserName = $einstellungen['felder']['shopwareUserName']; + $this->Password = $einstellungen['felder']['shopwarePassword']; + $this->ShopUrl = rtrim($einstellungen['felder']['shopwareUrl'], '/') . '/'; + $this->createManufacturerAllowed = false; + if ($einstellungen['felder']['shopwareAllowCreateManufacturer'] === '1') { + $this->createManufacturerAllowed = true; + } + $this->defaultManufacturer = $einstellungen['felder']['shopwareDefaultManufacturer']; + $this->defaultRuleName = $einstellungen['felder']['shopwareDefaultRuleName']; + $this->statesToFetch = $einstellungen['felder']['statesToFetch']; + $this->deliveryStatesToFetch = $einstellungen['felder']['deliveryStatesToFetch']; + $this->transactionStatesToFetch = $einstellungen['felder']['transactionStatesToFetch']; + $this->salesChannelToFetch = $einstellungen['felder']['salesChannelToFetch']; + $this->orderSearchLimit = $einstellungen['felder']['orderSearchLimit']; + $this->freeFieldOption = $einstellungen['felder']['shopwareFreeFieldOption']; + $this->propertyOption = $einstellungen['felder']['shopwarePropertyOption']; + $this->shopwareDefaultSalesChannel = $einstellungen['felder']['shopwareDefaultSalesChannel']; + $this->shopwareMediaFolder = $einstellungen['felder']['shopwareMediaFolder']; + $query = sprintf('SELECT `steuerfreilieferlandexport` FROM `shopexport` WHERE `id` = %d', $this->shopid); + $this->taxationByDestinationCountry = !empty($this->app->DB->Select($query)); + + $this->client = $this->app->Container->get('Shopware6Client'); + $this->client->setCredentials( + $this->UserName, + $this->Password, + $this->ShopUrl + ); + } + + /** + * @return array + */ + public function EinstellungenStruktur() + { + return + [ + 'ausblenden' => ['abholmodus' => ['ab_nummer']], + 'functions' => ['exportartikelbaum','getarticlelist','updatezahlungsstatus'], + 'felder' => [ + 'protocol' => [ + 'typ' => 'checkbox', + 'bezeichnung' => '{|Protokollierung im Logfile|}:', + ], + 'shopwareUserName' => [ + 'typ' => 'text', + 'bezeichnung' => '{|Benutzername|}:', + 'size' => 40, + ], + 'shopwarePassword' => [ + 'typ' => 'text', + 'bezeichnung' => '{|Passwort|}:', + 'size' => 40, + ], + 'shopwareUrl' => [ + 'typ' => 'text', + 'bezeichnung' => '{|Shop API URL|}:', + 'size' => 40, + ], + 'shopwareDefaultManufacturer' => [ + 'typ' => 'text', + 'bezeichnung' => '{|Standard Hersteller|}:', + 'size' => 40, + 'default' => 'Keine Herstellerinformation', + ], + 'shopwareAllowCreateManufacturer' => [ + 'typ' => 'checkbox', + 'bezeichnung' => '{|Bei Artikelexport Hersteller anlegen|}:', + ], + 'shopwareDefaultRuleName' => [ + 'typ' => 'text', + 'bezeichnung' => '{|Name der Standardpreisgruppe|}:', + 'size' => 40, + 'default' => 'All customers', + ], + 'shopwarePropertyOption' => [ + 'heading' => '{|Eigenschaften / Freifeld Zuordnung|}', + 'typ' => 'select', + 'bezeichnung' => '{|Xentral Artikel Eigenschaften|}:', + 'size' => 40, + 'default' => 'toProperties', + 'optionen' => ['toProperties' => '{|Shopware Eigenschaften|}', 'toCustomFields' => '{|Shopware Zusatzfelder|}', 'doNotExport' => '{|Nicht übertragen|}'] + ], + 'shopwareFreeFieldOption' => [ + 'typ' => 'select', + 'bezeichnung' => '{|Xentral Artikel Freifelder|}:', + 'size' => 40, + 'default' => 'toCustomFields', + 'optionen' => ['toProperties' => '{|Shopware Eigenschaften|}', 'toCustomFields' => '{|Shopware Zusatzfelder|}', 'doNotExport' => '{|Nicht übertragen|}'] + ], + 'shopwareDefaultSalesChannel' => [ + 'heading' => '{|Artikelexport Standardeinstellungen|}', + 'typ' => 'text', + 'bezeichnung' => '{|Standard Sichtbarkeit|}:', + 'size' => 40 + ], + 'shopwareMediaFolder' => [ + 'typ' => 'text', + 'bezeichnung' => '{|Media Folder für Artikelbilder|}:', + 'size' => 40, + 'default' => 'Product Media' + ], + 'statesToFetch' => [ + 'typ' => 'text', + 'bezeichnung' => '{|Abzuholender Bestellstatus|}:', + 'size' => 40, + 'default' => 'open', + 'col' => 2, + 'info' => '
Erlaubte Werte: open;in_progress;completed;cancelled' + ], + 'deliveryStatesToFetch' => [ + 'typ' => 'text', + 'bezeichnung' => '{|Eingrenzen auf Lieferstatus|}:', + 'size' => 40, + 'default' => '', + 'col' => 2, + 'info' => '
Erlaubte Werte: open;shipped_partially;shipped;returned;returned_partially;cancelled' + ], + 'transactionStatesToFetch' => [ + 'typ' => 'text', + 'bezeichnung' => '{|Eingrenzen auf Bezahlstatus|}:', + 'size' => 40, + 'default' => '', + 'col' => 2, + 'info' => '
Erlaubte Werte: open;paid;authorized;paid_partially;refunded;refunded_partially;reminded;cancelled' + ], + 'salesChannelToFetch' => [ + 'typ' => 'text', + 'bezeichnung' => '{|Eingrenzen auf Sales Channel|}:', + 'size' => 40, + 'default' => '', + 'col' => 2, + 'info' => '
Klicke auf "Verbindung prüfen" um die verfügbaren Channels (bitte die Id verwenden) anzuzeigen.' + ], + 'orderSearchLimit' => [ + 'typ' => 'select', + 'bezeichnung' => '{|Anzahl Aufträge abholen|}:', + 'optionen' => [ + '25' => '25', + '50' => '50', + '75' => '75', + '100' => '100', + ], + 'default' => '25', + 'col' => 2 + ], + ], + ]; + } + + public function ImportUpdateZahlungsstatus() + { + $tmp = $this->CatchRemoteCommand('data'); + $auftrag = $tmp['auftrag']; + + $transactions = $this->shopwareRequest('GET', 'order/'.$auftrag.'/transactions'); + $transactionId = $transactions['data'][0]['id']; + + if(empty($transactionId)){ + return; + } + + $response = $this->shopwareRequest('POST', '_action/order_transaction/'.$transactionId.'/state/paid'); + if (!empty($response['id'])) { + return 'ok'; + } + } + + public function ImportSendArtikelbaum(){ + $xentralCategoryTree = []; + $this->app->erp->GetKategorienbaum($xentralCategoryTree, 0, 0, $this->shopid); + + $xentralCategoryIdToParentId = []; + foreach ($xentralCategoryTree as $key => $value) { + $xentralCategoryTree[$key]['erledigt'] = false; + $xentralCategoryTree[$key]['shopid'] = ''; + $xentralCategoryTree[$key]['aktiv'] = false; + $xentralCategoryIdToParentId[$value['id']] = $key; + } + + $parentCategoryId = null; + foreach ($xentralCategoryTree as $index => $categoryData) { + $this->createCategoryTree($index, $xentralCategoryTree, $xentralCategoryIdToParentId, $parentCategoryId); + } + } + + protected function createCategoryTree($id, &$xentralCategoryTree, $xentralCategoryIdToParentId, $parentCategoryId) + { + $parentId = $parentCategoryId; + if ($xentralCategoryTree[$id]['parent']) { + $parentId = $xentralCategoryTree[$xentralCategoryIdToParentId[$xentralCategoryTree[$id]['parent']]]['shopid']; + } + if ($xentralCategoryTree[$id]['parent'] && !$xentralCategoryTree[$xentralCategoryIdToParentId[$xentralCategoryTree[$id]['parent']]]['erledigt']) { + $this->createCategoryTree($xentralCategoryIdToParentId[$xentralCategoryTree[$id]['parent']], $xentralCategoryTree, $xentralCategoryIdToParentId, $parentCategoryId); + } + $xentralCategoryTree[$id]['erledigt'] = true; + + $categoryName = $xentralCategoryTree[$id]['bezeichnung']; + $searchdata = [ + 'limit' => 25, + 'filter' => [ + [ + 'field' => 'category.name', + 'type' => 'equals', + 'value' => $categoryName + ], + [ + 'field' => 'category.parentId', + 'type' => 'equals', + 'value' => $parentId + ] + ] + ]; + + $categoriesInShop = $this->shopwareRequest('POST', 'search/category', $searchdata); + + $categoryId = ''; + if (!empty($categoriesInShop['data'])) { + $categoryId = $categoriesInShop['data'][0]['id']; + } + + if (!$categoryId) { + $categoryData = [ + 'parentId' => $parentId, + 'name' => $categoryName + ]; + $result = $this->shopwareRequest('POST', 'category?_response=true', $categoryData); + if ($result['data']['id']) { + $categoryId = $result['data']['id']; + } + } + + if ($categoryId) { + $xentralCategoryTree[$id]['shopid'] = $categoryId; + } + } + + /** + * @return int + */ + public function ImportSendListLager() + { + $tmp = $this->CatchRemoteCommand('data'); + + $count = 0; + foreach ($tmp as $article) { + $artikel = $article['artikel']; + if ($artikel === 'ignore') { + continue; + } + $nummer = $article['nummer']; + $fremdnummer = $article['fremdnummer']; + if (!empty($fremdnummer)) { + $nummer = $fremdnummer; + } + $articleInfo = $this->shopwareRequest('GET', 'product?filter[product.productNumber]=' . $nummer); + + if (empty($articleInfo['data'][0]['id'])) { + $this->Shopware6Log('Artikel wurde nicht im Shop gefunden: ' . $nummer, $articleInfo); + continue; + } + if(empty($articleInfo['data'][0]['customFields']) + || empty($articleInfo['data'][0]['customFields']['wawision_shopimporter_syncstate'])){ + $this->addSyncCustomFieldToProduct((string)$articleInfo['data'][0]['id']); + } + + $active = true; + if ($article['inaktiv']) { + $active = false; + } + + $stock = $article['anzahl_lager']; + if (!empty($article['pseudolager'])) { + $stock = $article['pseudolager']; + } + $stock = $this->getCorrectedStockFromAvailable($active, (int)$stock, $articleInfo); + $data = [ + 'stock' => $stock, + 'active' => $active, + ]; + $response = $this->shopwareRequest('PATCH', 'product/' . $articleInfo['data'][0]['id'], $data); + $this->Shopware6Log('Lagerbestand konnte nicht uebertragen werden fuer Artikel: ' . $nummer, $response); + $count++; + } + + return $count; + } + + /** + * @param bool $isStockActive + * @param int $stock + * @param array|null $articleInfo + * + * @return int + */ + public function getCorrectedStockFromAvailable(bool $isStockActive, int $stock, ?array $articleInfo): int + { + if(!$isStockActive) { + return $stock; + } + if(empty($articleInfo)) { + return $stock; + } + if(!isset($articleInfo['data'][0]['attributes']['availableStock'])) { + return $stock; + } + if(!isset($articleInfo['data'][0]['attributes']['availableStock'])) { + return $stock; + } + $reserved = (int)$articleInfo['data'][0]['attributes']['stock'] + - (int)$articleInfo['data'][0]['attributes']['availableStock']; + if($reserved <= 0) { + return $stock; + } + + return $stock + $reserved; + } + + /** + * @param string $message + * @param mixed $dump + */ + public function Shopware6Log($message, $dump = '') + { + if ($this->protocol) { + $this->app->erp->Logfile($message, print_r($dump, true)); + } + } + + /** + * @return int + */ + public function ImportSendList() + { + $articleList = $this->CatchRemoteCommand('data'); + + $successCounter = 0; + foreach ($articleList as $article) { + $number = $article['nummer']; + $articleInfo = $this->shopwareRequest( + 'GET', + sprintf('product?filter[product.productNumber]=%s', $number) + ); + $articleIdShopware = ''; + if (!empty($articleInfo['data'][0]['id'])) { + $articleIdShopware = $articleInfo['data'][0]['id']; + } + + $quantity = $article['anzahl_lager']; + if (!empty($article['pseudolager'])) { + $quantity = $article['pseudolager']; + } + $inaktiv = $article['inaktiv']; + $active = true; + if (!empty($inaktiv)) { + $active = false; + } + $quantity = $this->getCorrectedStockFromAvailable($active, (int)$quantity, $articleInfo); + $taxRate = (float)$article['steuersatz']; + + $taxId = $this->getTaxIdByRate($taxRate); + + $mediaToAdd = $this->mediaToExport($article, $articleIdShopware); + + $categoriesToAdd = []; + if($this->exportCategories){ + $categoriesToAdd = $this->categoriesToExport($article, $articleIdShopware); + } + + $propertiesToAdd = $this->propertiesToExport($article, $articleIdShopware); + + $crosselingToAdd = $this->crosssellingToExport($article, $articleIdShopware); + + $systemFieldsToAdd = $this->systemFieldsToExport($article, $articleIdShopware); + + $deliveryTimeId = null; + if(!empty($article['lieferzeitmanuell'])){ + $deliveryTimeId = $this->getDeliveryTimeId($article['lieferzeitmanuell']); + } + + if (empty($systemFieldsToAdd['visibilities']) && !empty($this->shopwareDefaultSalesChannel)) { + $systemFieldsToAdd['visibilities'] = $this->modifySalesChannel(explode(',', $this->shopwareDefaultSalesChannel), $articleIdShopware); + } + + if(empty($systemFieldsToAdd['unitId']) && !empty($article['einheit']) ){ + $systemFieldsToAdd['unitId'] = $this->unitToAdd($article['einheit']); + } + + + //Hersteller in Shopware suchen bzw. Anlegen + $manufacturerName = $article['hersteller']; + $manufacturerId = $this->getManufacturerIdByName($manufacturerName); + + if ($manufacturerId === null && $this->createManufacturerAllowed === true) { + $manufacturerId = $this->createManufacturer($manufacturerName); + } + + if (empty($manufacturerId)) { + return 'error: Für den Artikelexport ist die Herstellerinformation zwingend erforderlich'; + } + + $isCloseOut = false; + if(!empty($article['restmenge'])){ + $isCloseOut = true; + } + + $description = $this->prepareDescription($article['uebersicht_de']); + $ean = $article['ean']; + $metaTitle = $article['metatitle_de']; + $metaDescription = $article['metadescription_de']; + $metaKeywords = $article['metakeywords_de']; + + $manufacturerNumber = $article['herstellernummer']; + if (empty($manufacturerNumber)) { + $manufacturerNumber = ''; + } + + $weight = (float)$article['gewicht']; + $length = (float)$article['laenge'] * 10; + $height = (float)$article['hoehe'] * 10; + $width = (float)$article['breite'] * 10; + + $purchasePrice = (float)$article['einkaufspreis']; + + $currencyId = $this->findCurrencyId($article['waehrung']); + $price = [ + 'net' => $article['preis'], + 'gross' => $article['bruttopreis'], + 'currencyId' => $currencyId, + 'linked' => true]; + + if (!empty($article['pseudopreis'])) { + $price['listPrice'] = [ + 'currencyId' => $currencyId, + 'gross' => $article['pseudopreis'], + 'linked' => true, + 'net' => $article['pseudopreis']/(1+$taxRate/100) + ]; + } + + $data = [ + 'name' => $article['name_de'], + 'isCloseout' => $isCloseOut, + 'productNumber' => $number, + 'manufacturerId' => $manufacturerId, + 'stock' => (int)$quantity, + 'taxId' => $taxId, + 'active' => $active, + 'description' => $description, + 'ean' => $ean, + 'metaTitle' => $metaTitle, + 'metaDescription' => $metaDescription, + 'keywords' => $metaKeywords, + 'manufacturerNumber' => $manufacturerNumber, + 'length' => $length, + 'width' => $width, + 'height' => $height, + 'weight' => $weight, + 'purchasePrice' => $purchasePrice, + 'price' => [$price], + 'categories' => $categoriesToAdd, + 'properties' => $propertiesToAdd, + 'crossSellings' => $crosselingToAdd, + 'media' => $mediaToAdd, + 'deliveryTimeId' => $deliveryTimeId + ]; + + $data = array_merge($data, $systemFieldsToAdd); + if(empty($data['customFields']) + || empty($data['customFields']['wawision_shopimporter_syncstate'])){ + $data['customFields']['wawision_shopimporter_syncstate'] = 1; + } + + if (empty($articleIdShopware)) { + $result = $this->shopwareRequest('POST', + 'product?_response=true', $data); + if (!empty($result['data']['id'])) { + $articleIdShopware = $result['data']['id']; + $articleInfo['data'][0] = $result['data']; + } + } else { + $headerInformation = []; + $languageId = $this->getLanguageIdByCountryIso('DE'); + if (!empty($languageId)) { + $headerInformation[] = 'sw-language-id: ' . $languageId; + } + $result = $this->shopwareRequest('PATCH', + sprintf('product/%s?_response=true', $articleIdShopware), $data, $headerInformation); + } + + if(!empty($articleIdShopware)){ + $this->exportTranslationsForArticle($article, $articleIdShopware); + } + + $this->addCoverImage($article, $articleIdShopware); + + if (empty($result['data']) || is_array($result['errors'])) { + $this->Shopware6Log('Artikelexport fehlgeschlagen', ['data:' => $data, 'response' => $result]); + continue; + } + + $this->exportSeoUrls($article, $articleIdShopware); + + $this->exportVariants($article, $articleIdShopware, $currencyId); + + if (empty($result['data']) || is_array($result['errors'])) { + $this->Shopware6Log('Artikelexport bei Bildübertragung fehlgeschlagen', ['data:' => $data, 'response' => $result]); + continue; + } + + $defaultPrices = $this->getPricesFromArray($article['staffelpreise_standard'] ?? []); + $groupPrices = $this->getPricesFromArray($article['staffelpreise_gruppen'] ?? []); + + if (!empty($defaultPrices) || !empty($groupPrices)) { + $this->deleteOldBulkPrices($articleIdShopware); + } + if (!empty($defaultPrices)) { + foreach ($defaultPrices as $priceData) { + $this->exportBulkPriceForGroup($articleIdShopware, $this->defaultRuleName, $priceData); + } + } + if (!empty($groupPrices)) { + foreach ($groupPrices as $priceData) { + $this->exportBulkPriceForGroup($articleIdShopware, $priceData->getGroupName(), $priceData); + } + } + + $successCounter++; + } + + return $successCounter; + } + + protected function exportBulkPriceForGroup(string $productId, string $groupName, PriceData $priceData): void + { + $currencyId = $this->findCurrencyId($priceData->getCurrency()); + + $groupRuleId = $this->client->getGroupRuleId($groupName); + if (empty($groupRuleId)) { + $this->Shopware6Log("Fehler: Gruppe {$groupName} konnte im Shop nicht gefunden werden"); + return; + } + + $result = $this->client->saveBulkPrice($productId, $groupRuleId, $currencyId, $priceData); + if (empty($result['data'])) { + $this->Shopware6Log("Fehler: Staffelpreis für Gruppe {$groupName} konnte nicht exportiert werden", $result); + } + } + + /** + * @param string $deliveryTimeText + * + * @return string|null + */ + protected function getDeliveryTimeId(string $deliveryTimeText): ?string + { + $searchCommand = [ + 'limit' => 5, + 'filter' => [ + [ + 'field' => 'name', + 'type' => 'equals', + 'value' => $deliveryTimeText + ] + ] + ]; + $result = $this->shopwareRequest('POST', 'search/delivery-time', $searchCommand); + + if (empty($result['data'][0]['id'])) { + return null; + } + + return $result['data'][0]['id']; + } + + /** + * @param string $description + * @return string + */ + protected function prepareDescription($description): string + { + $markupSubstitute = [ + '/"/' => '"', + '/<([^&]+)>/' => '<\1>', + '/\\/' => '', + '/\\<\/strong>/' => '', + '/\\/' => '', + '/\\<\/em>/' => '', + '/&/' => '&', + ]; + + return (string)preg_replace(array_keys($markupSubstitute), array_values($markupSubstitute), $description); + } + + /** + * @param array $article + * @param string $articleIdShopware + */ + protected function exportTranslationsForArticle(array $article, string $articleIdShopware): void + { + $customFieldsToAdd = $this->customFieldsToExport($article, $articleIdShopware); + + $preparedTranslations = []; + $preparedTranslations['DE'] = [ + 'name' => $article['name_de'], + 'description' => $this->prepareDescription($article['uebersicht_de']), + 'metaTitle' => $article['metatitle_de'], + 'metaDescription' => $article['metadescription_de'], + 'keywords' => $article['metakeywords_de'], + 'customFields' => [] + ]; + if(!empty($customFieldsToAdd['DE'])){ + $preparedTranslations['DE']['customFields'] = $customFieldsToAdd['DE']; + } + $preparedTranslations['GB'] = [ + 'name' => $article['name_en'], + 'description' => $this->prepareDescription($article['uebersicht_en']), + 'metaTitle' => $article['metatitle_en'], + 'metaDescription' => $article['metadescription_en'], + 'keywords' => $article['metakeywords_en'], + 'customFields' => [], + ]; + if(!empty($customFieldsToAdd['GB'])){ + $preparedTranslations['GB']['customFields'] = $customFieldsToAdd['GB']; + } + foreach ($article['texte'] as $translation) { + if ($translation['sprache'] === 'EN') { + $translation['sprache'] = 'GB'; + } + $preparedTranslations[$translation['sprache']] = [ + 'name' => $translation['name'], + 'description' => $this->prepareDescription($translation['beschreibung_online']), + 'metaTitle' => $translation['meta_title'], + 'metaDescription' => $translation['meta_description'], + 'keywords' => $translation['meta_keywords'], + ]; + if(!empty($customFieldsToAdd[$translation['sprache']])){ + $preparedTranslations[$translation['sprache']]['customFields'] = $customFieldsToAdd[$translation['sprache']]; + } + } + + foreach ($preparedTranslations as $countryIsoCode => $translation) { + $languageId = $this->getLanguageIdByCountryIso($countryIsoCode); + if (empty($languageId)) { + $this->Shopware6Log('Language Id not found for country: ' . $countryIsoCode); + continue; + } + + $headerInformation = ['sw-language-id: ' . $languageId]; + $this->shopwareRequest( + 'PATCH', + sprintf('product/%s', $articleIdShopware), + $translation, $headerInformation + ); + } + } + + /** + * @param string $countryIso + * + * @return string|null + */ + protected function getLanguageIdByCountryIso(string $countryIso): ?string + { + if(array_key_exists($countryIso, $this->knownShopLanguageIds)){ + return $this->knownShopLanguageIds[$countryIso]; + } + + $searchCommand = [ + 'limit' => 5, + 'filter' => [ + [ + 'field' => 'country.iso', + 'type' => 'equals', + 'value' => $countryIso + ] + ] + ]; + $countryInformation = $this->shopwareRequest('POST', 'search/country', $searchCommand); + + foreach ($countryInformation['data'] as $country){ + $searchCommand = [ + 'limit' => 5, + 'filter' => [ + [ + 'field' => 'locale.territory', + 'type' => 'equals', + 'value' => $country['attributes']['name'] + ] + ] + ]; + $localeInformation = $this->shopwareRequest('POST', 'search/locale', $searchCommand); + foreach ($localeInformation['data'] as $locale) { + $searchCommand = [ + 'limit' => 5, + 'filter' => [ + [ + 'field' => 'language.localeId', + 'type' => 'equals', + 'value' => $locale['id'] + ] + ] + ]; + $languageInformation = $this->shopwareRequest('POST', 'search/language', $searchCommand); + if (!empty($languageInformation['data'][0]['id'])) { + $this->knownShopLanguageIds[$countryIso] = $languageInformation['data'][0]['id']; + return $languageInformation['data'][0]['id']; + } + } + } + $this->knownShopLanguageIds[$countryIso] = null; + + return null; + } + + /** + * @param string $manufacturerName + * + * @return null|string + */ + protected function createManufacturer(string $manufacturerName): ?string + { + $data = ['name' => $manufacturerName]; + $response = $this->shopwareRequest('POST', 'product-manufacturer?_response=true', $data); + + $manufacturerId = null; + if(!empty($response['data']['id'])){ + $manufacturerId = $response['data']['id']; + $this->knownManufacturerIds[$manufacturerName] = $manufacturerId; + } + + return $manufacturerId; + } + + /** + * @param string $manufacturerName + * + * @return null|string + */ + protected function getManufacturerIdByName(string $manufacturerName): ?string + { + if (!empty($this->knownManufacturerIds[$manufacturerName])) { + return $this->knownManufacturerIds[$manufacturerName]; + } + + $manufacturerId = null; + if (empty($manufacturerName)) { + $manufacturerName = $this->defaultManufacturer; + } + $manufacturer = $this->shopwareRequest( + 'GET', + 'product-manufacturer?filter[product_manufacturer.name]=' . urlencode($manufacturerName) + ); + $manufacturerId = $manufacturer['data'][0]['id']; + $this->knownManufacturerIds[$manufacturerName] = $manufacturerId; + + return $manufacturerId; + } + + /** + * @param float $taxRate + * + * @return string + */ + protected function getTaxIdByRate(float $taxRate): string{ + if(empty($this->taxesInShop)){ + $this->taxesInShop = $this->shopwareRequest('GET', 'tax'); + } + foreach ($this->taxesInShop['data'] as $taxData) { + if (abs(($taxData['attributes']['taxRate']-$taxRate)) < 0.0001 ) { + return $taxData['id']; + } + } + + return $this->taxesInShop['data'][0]['id']; + } + + /** + * @param array $internalArticleData + * @param string $articleIdShopware + * + * @return array + */ + protected function mediaToExport($internalArticleData, $articleIdShopware) + { + $mediaToAdd = [ + ]; + + if (empty($internalArticleData['Dateien'])) { + return $mediaToAdd; + } + $internalMediaIds = []; + + $searchdata = [ + 'limit' => 1, + 'filter' => [ + [ + 'field' => 'name', + 'type' => 'equals', + 'value' => $this->shopwareMediaFolder + ] + ] + ]; + $mediaFolderData = $this->shopwareRequest('POST', 'search/media-folder', $searchdata); + if(empty($mediaFolderData['data'][0]['id'])){ + $this->Shopware6ErrorLog('Kein Media Folder gefunden für: ', $this->shopwareMediaFolder); + return []; + } + + $mediaFolderId = $mediaFolderData['data'][0]['id']; + + foreach ($internalArticleData['Dateien'] as $internalFile) { + $filename = explode('.', $internalFile['filename']); + unset($filename[(!empty($filename)?count($filename):0) - 1]); + $filename = $internalFile['id'].'_'.implode($filename); + $extension = $internalFile['extension']; + $imageTitle = (string)$internalFile['titel']; + $imageAltText = (string)$internalFile['beschreibung']; + $accessToken = $this->shopwareToken(); + + $searchdata = [ + 'limit' => 5, + 'filter' => [ + [ + 'field' => 'media.fileName', + 'type' => 'equals', + 'value' => $filename + ] + ] + ]; + $mediaData = $this->shopwareRequest('POST', 'search/media', $searchdata); + if (!empty($mediaData['data'][0]['id'])) { + $internalMediaIds[] = $mediaData['data'][0]['id']; + if($mediaData['data'][0]['attributes']['title'] !== $imageTitle + || $mediaData['data'][0]['attributes']['alt'] !== $imageAltText){ + $this->setMediaTitleAndAltText($mediaData['data'][0]['id'], $imageTitle, $imageAltText); + } + continue; + } + + $mediaData = $this->shopwareRequest('POST', 'media?_response=true', []); + if(empty($mediaData['data']['id'])){ + $this->Shopware6Log('Error when creating media for sku: ' . $internalArticleData['nummer'], + ['mediaData' => $mediaData, 'title' => $imageTitle, 'text' => $imageAltText]); + continue; + } + $mediaId = $mediaData['data']['id']; + $this->setMediaTitleAndAltText($mediaId, $imageTitle, $imageAltText); + + $mediaAssociationData = [ + [ + 'action' => 'upsert', + 'entity' => 'media', + 'payload' => [ + [ + 'id' => $mediaId, + 'mediaFolderId' => $mediaFolderId + ] + ] + ] + ]; + $this->shopwareRequest('POST', '_action/sync?_response=true', $mediaAssociationData); + + $url = $this->ShopUrl . 'v2/_action/media/' . $mediaId . '/upload?extension=' . $extension . '&fileName=' . $filename; + $ch = curl_init(); + $setHeaders = [ + 'Content-Type:image/' . $extension, + 'Authorization:Bearer ' . $accessToken['token'] + ]; + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POSTFIELDS, base64_decode($internalFile['datei'])); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); + curl_setopt($ch, CURLOPT_HTTPHEADER, $setHeaders); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_exec($ch); + + $internalMediaIds[] = $mediaId; + } + + $existingMediaConnection = []; + if (!empty($articleIdShopware)) { + $existingMediaConnection = $this->shopwareRequest('GET', 'product/' . $articleIdShopware . '/media?limit=100'); + foreach ($existingMediaConnection['data'] as $existingConnection) { + if (!in_array($existingConnection['attributes']['mediaId'], $internalMediaIds, false)) { + $this->shopwareRequest('DELETE', 'product/' . $articleIdShopware . '/media/' . $existingConnection['id']); + } + } + } + + $alreadyAddedMediaIDs = []; + if (!empty($existingMediaConnection)) { + foreach ($existingMediaConnection['data'] as $existingConnection) { + $alreadyAddedMediaIDs[$existingConnection['attributes']['mediaId']] = $existingConnection['id']; + } + } + $position = 0; + foreach ($internalMediaIds as $mediaId) { + $mediaDataSet = [ + 'mediaId' => $mediaId, + 'position' => $position + ]; + if (array_key_exists($mediaId, $alreadyAddedMediaIDs)) { + $mediaDataSet['id'] = $alreadyAddedMediaIDs[$mediaId]; + } + $mediaToAdd[] = $mediaDataSet; + $position++; + } + + return $mediaToAdd; + } + + /** + * @param string $mediaId + * @param string $title + * @param string $altText + */ + protected function setMediaTitleAndAltText(string $mediaId, string $title, string $altText): void + { + $this->shopwareRequest('PATCH', 'media/' . $mediaId, + ['title' => $title, + 'alt' => $altText + ] + ); + } + + /** + * @param array $articleInXentral + * @param string $articleIdShopware + */ + protected function addCoverImage($articleInXentral, $articleIdShopware){ + if(empty($articleIdShopware)){ + return; + } + if(empty($articleInXentral['Dateien'])){ + return; + } + $existingMediaConnection = $this->shopwareRequest('GET', 'product/' . $articleIdShopware . '/media?limit=100'); + if(empty($existingMediaConnection['data'])){ + return; + } + foreach ($articleInXentral['Dateien'] as $xentralFile) { + $filename = explode('.', $xentralFile['filename']); + unset($filename[(!empty($filename)?count($filename):0) - 1]); + $filename = $xentralFile['id'].'_'.implode($filename); + + $searchdata = [ + 'limit' => 5, + 'filter' => [ + [ + 'field' => 'media.fileName', + 'type' => 'equals', + 'value' => $filename + ] + ] + ]; + $mediaData = $this->shopwareRequest('POST', 'search/media', $searchdata); + $mediaId = $mediaData['data'][0]['id']; + + foreach ($existingMediaConnection['data'] as $mediaConnection){ + if($mediaId === $mediaConnection['attributes']['mediaId']){ + + $this->shopwareRequest('PATCH', + sprintf('product/%s?_response=true', $articleIdShopware),['coverId' => $mediaConnection['id']]); + return; + } + } + } + } + + /** + * @param array $articleInXentral + * @param string $articleIdShopware + * @return array + */ + protected function categoriesToExport($articleInXentral, $articleIdShopware) + { + $categoryName = $articleInXentral['kategoriename']; + $categoryTree = $articleInXentral['kategorien']; + + $categoriesToAdd = []; + if (empty($categoryName) && empty($categoryTree)) { + return $categoriesToAdd; + } + + $categoriesInXentral = []; + if (!empty($categoryTree)) { + $rootcategory = null; + $categoryTreeid = []; + foreach ($categoryTree as $categoryData) { + $categoryData['shopwareparent'] = 0; + if (!$categoryData['parent']) { + $categoryData['shopwareid'] = $rootcategory; + } + $categoryTreeid[$categoryData['id']] = $categoryData; + } + + foreach ($categoryTree as $categoryData) { + $parentid = $rootcategory; + if (!empty($categoryData['parent'])) { + $parentid = $this->getCategoryParentId($categoryData, $categoryTreeid); + } + + $searchdata = [ + 'limit' => 25, + 'filter' => [ + [ + 'field' => 'category.name', + 'type' => 'equals', + 'value' => $categoryData['name'] + ] + ] + ]; + if (!empty($parentid)) { + $searchdata['filter'][] = [ + 'field' => 'category.parentId', + 'type' => 'equals', + 'value' => $parentid + ]; + } + $result = $this->shopwareRequest('POST', 'search/category', $searchdata); + + + if (!empty($result['data'][0]['id'])) { + $categoryTreeid[$categoryData['id']]['shopwareid'] = $result['data'][0]['id']; + $categoriesInXentral[] = $result['data'][0]['id']; + } + } + } else if (!empty($categoryName)) { + $searchdata = [ + 'limit' => 25, + 'filter' => [ + [ + 'field' => 'category.name', + 'type' => 'equals', + 'value' => $categoryName + ] + ] + ]; + + $result = $this->shopwareRequest('POST', 'search/category', $searchdata); + + if (!empty($result['data'][0]['id'])) { + $categoriesInXentral[] = $result['data'][0]['id']; + } + } + + if (!empty($articleIdShopware)) { + $existingCategories = $this->shopwareRequest('GET', 'product/' . $articleIdShopware . '/categories?limit=50'); + foreach ($existingCategories['data'] as $existingCategory) { + if (!in_array($existingCategory['id'], $categoriesInXentral, false)) { + $this->shopwareRequest('DELETE', 'product/' . $articleIdShopware . '/categories/' . $existingCategory['id']); + } + } + } + foreach ($categoriesInXentral as $categoryId) { + $categoriesToAdd[] = ['id' => $categoryId]; + } + + + return $categoriesToAdd; + } + + /** + * @param $categoryData + * @param $categoryTreeId + * @return string|null + */ + protected function getCategoryParentId($categoryData, &$categoryTreeId) + { + $parentId = $categoryTreeId[$categoryData['parent']]['shopwareid']; + if (!empty($parentId)) { + return $parentId; + } + + $parentCategoryData = $this->app->DB->SelectRow("SELECT id,parent,bezeichnung AS name FROM artikelkategorien WHERE id<>'' AND id<>'0' AND id='" . $categoryData['parent'] . "' LIMIT 1"); + if (empty($parentCategoryData)) { + return null; + } + + $searchData = [ + 'limit' => 25, + 'filter' => [ + [ + 'field' => 'category.name', + 'type' => 'equals', + 'value' => $parentCategoryData['name'] + ] + ] + ]; + $result = $this->shopwareRequest('POST', 'search/category', $searchData); + + if (count($result['data']) < 1) { + return null; + } + + if (count($result['data']) === 1) { + $parentCategoryData['shopwareid'] = $result['data'][0]['id']; + $categoryTreeId[$parentCategoryData['id']] = $parentCategoryData; + return $result['data'][0]['id']; + } + + $grandparentId = $this->getCategoryParentId($parentCategoryData, $categoryTreeId); + + $searchData = [ + 'limit' => 25, + 'filter' => [ + [ + 'field' => 'category.name', + 'type' => 'equals', + 'value' => $parentCategoryData['name'] + ], + [ + 'field' => 'category.parentId', + 'type' => 'equals', + 'value' => $grandparentId + ] + ] + ]; + $result = $this->shopwareRequest('POST', 'search/category', $searchData); + + + if (count($result['data']) === 1) { + $parentCategoryData['shopwareid'] = $result['data'][0]['id']; + $categoryTreeId[$parentCategoryData['id']] = $parentCategoryData; + return $result['data'][0]['id']; + } + return null; + } + + /** + * @param string $propertyName + * + * @return string|null + */ + protected function getPropertyGroupId($propertyName): ?string + { + if(array_key_exists($propertyName, $this->knownPropertyGroupIds)){ + return $this->knownPropertyGroupIds[$propertyName]; + } + + $searchData = [ + 'limit' => 25, + 'filter' => [ + [ + 'field' => 'property_group.name', + 'type' => 'equals', + 'value' => $propertyName + ] + ] + ]; + + $germanLanguageId = $this->getLanguageIdByCountryIso('DE'); + $headerInformation = ['sw-language-id: ' . $germanLanguageId]; + $propertyData = $this->shopwareRequest( + 'POST', + 'search/property-group', + $searchData, + $headerInformation); + if (empty($propertyData['data'][0]['id'])) { + return null; + } + + $this->knownPropertyGroupIds[$propertyName] = $propertyData['data'][0]['id']; + + return $propertyData['data'][0]['id']; + } + + /** + * @param string $propertyName + * @return null|string + */ + protected function createPropertyGroup($propertyName): ?string + { + $propertyGroupData = [ + 'displayType' => 'text', + 'name' => $propertyName, + 'sortingType' => 'alphanumeric' + ]; + $propertyGroup = $this->shopwareRequest( + 'POST', + 'property-group?_response=true', + $propertyGroupData); + + $this->knownPropertyGroupIds[$propertyName] = $propertyGroup['data']['id']; + + if (empty($propertyGroup['data']['id'])) { + return null; + } + + return $propertyGroup['data']['id']; + } + + /** + * @param string $propertyGroupId + * @param string $propertyName + * @param string $countryIsoCode + */ + protected function createTranslationForPropertyGroup($propertyGroupId, $propertyName, $countryIsoCode): void + { + $languageId = $this->getLanguageIdByCountryIso($countryIsoCode); + if (empty($languageId)) { + return; + } + + $headerInformation = ['sw-language-id: ' . $languageId]; + + $translation = [ + 'name' => $propertyName, + ]; + + $this->shopwareRequest( + 'PATCH', + sprintf('property-group/%s', $propertyGroupId), + $translation, + $headerInformation); + } + + /** + * @param string $propertyGroupId + * @param string $propertyOptionName + * @param string $countryIsoCode + * @return mixed|null + */ + protected function getPropertyOptionId($propertyGroupId, $propertyOptionName, $countryIsoCode = 'DE'): ?string + { + $searchData = [ + 'limit' => 25, + 'filter' => [ + [ + 'field' => 'property_group_option.name', + 'type' => 'equals', + 'value' => $propertyOptionName + ] + ] + ]; + $languageId = $this->getLanguageIdByCountryIso($countryIsoCode); + $headerInformation = ['sw-language-id: ' . $languageId]; + $optionData = $this->shopwareRequest( + 'POST', + 'search/property-group/' . $propertyGroupId . '/options', + $searchData, + $headerInformation); + + if (empty($optionData['data'][0]['id'])) { + return null; + } + + return $optionData['data'][0]['id']; + } + + /** + * @param string $propertyGroupId + * @param string $propertyOptionName + * @return null|string + */ + protected function createPropertyOption($propertyGroupId, $propertyOptionName): ?string + { + $propertyOptionData = [ + 'id' => '', + 'name' => $propertyOptionName + ]; + $createdPropertyOption = $this->shopwareRequest( + 'POST', + 'property-group/' . $propertyGroupId . '/options?_response=true', + $propertyOptionData); + + if (empty($createdPropertyOption['data']['id'])) { + return null; + } + + return $createdPropertyOption['data']['id']; + } + + /** + * @param string $optionId + * @param string $optionName + * @param string $countryIsoCode + */ + protected function createTranslationForPropertyOption($optionId, $optionName, $countryIsoCode): void + { + $languageId = $this->getLanguageIdByCountryIso($countryIsoCode); + if (empty($languageId)) { + return; + } + $headerInformation = ['sw-language-id: ' . $languageId]; + $translation = [ + 'name' => $optionName, + ]; + + $this->shopwareRequest( + 'PATCH', + sprintf('property-group-option/%s', $optionId), + $translation, + $headerInformation); + } + + /** + * @param array $internalArticle + * @param string $articleIdShopware + * @return array + */ + protected function propertiesToExport($internalArticle, $articleIdShopware): array + { + $propertiesToAdd = $this->getPropertiesFromArticle($internalArticle); + if (empty($propertiesToAdd)) { + return []; + } + $assignedProperties = []; + + foreach ($propertiesToAdd as $propertyDefaultName => $countryIsoToPropertyTranslation) { + if (empty($countryIsoToPropertyTranslation['DE'])) { + continue; + } + $propertyGroupId = ''; + if (array_key_exists($propertyDefaultName, $this->knownPropertyGroupIds)) { + $propertyGroupId = $this->knownPropertyGroupIds[$propertyDefaultName]; + } + if (empty($propertyGroupId)) { + $propertyGroupId = $this->getPropertyGroupId($propertyDefaultName); + } + if (empty($propertyGroupId)) { + $propertyGroupId = $this->createPropertyGroup($propertyDefaultName); + } + if (empty($propertyGroupId)) { + $this->Shopware6Log('PropertyGroup kann nicht erstellt werden: ' . $propertyDefaultName); + continue; + } + + foreach ($countryIsoToPropertyTranslation as $countryIsoCode => $translation) { + $this->createTranslationForPropertyGroup($propertyGroupId, $translation['name'], $countryIsoCode); + } + + + $optionId = $this->getPropertyOptionId($propertyGroupId, $countryIsoToPropertyTranslation['DE']['value'], 'DE'); + if (empty($optionId)) { + $optionId = $this->createPropertyOption($propertyGroupId, $countryIsoToPropertyTranslation['DE']['value']); + } + if (empty($optionId)) { + $this->Shopware6Log('Option kann nicht erstellt werden: ' . $countryIsoToPropertyTranslation['DE']['value']); + continue; + } + + $assignedProperties[] = $optionId; + + foreach ($countryIsoToPropertyTranslation as $countryIsoCode => $translation) { + $this->createTranslationForPropertyOption($optionId, $translation['value'], $countryIsoCode); + } + } + + if (!empty($articleIdShopware)) { + $existingProperties = $this->shopwareRequest('GET', 'product/' . $articleIdShopware . '/properties?limit=100'); + foreach ($existingProperties['data'] as $existingProperty) { + if (!in_array($existingProperty['id'], $assignedProperties, false)) { + $this->shopwareRequest('DELETE', 'product/' . $articleIdShopware . '/properties/' . $existingProperty['id']); + } + } + } + + $propertiesToAdd = []; + foreach ($assignedProperties as $propertyOptionId) { + $propertiesToAdd[] = ['id' => $propertyOptionId]; + } + + return $propertiesToAdd; + } + + /** + * @param string $name + * @param string $value + * @return bool + */ + protected function propertyMustBeIgnored(string $name, string $value): bool + { + return empty($value) || + strpos($name, 'customField_') === 0 || + stripos($name, 'shopware6_') !== false; + } + + /** + * @param array $internalArticleData + * @return array + */ + protected function getPropertiesFromArticle($internalArticleData): array + { + //'Farbe' => [['DE' => ['name' => 'Farbe, 'value' => 'Gelb']], + // ['EN' => ['name' => 'Colour, 'value' => 'Yellow']]] + $propertiesToAdd = []; + if (!empty($internalArticleData['eigenschaften'])) { + foreach ($internalArticleData['eigenschaften'] as $property) { + if ($this->propertyMustBeIgnored($property['name'], $property['values'])) { + continue; + } + if (strpos($property['name'], 'property_') === 0) { + $propertyName = substr($property['name'], 9); + $propertiesToAdd[$propertyName]['DE'] = [ + 'name' => $propertyName, + 'value' => $property['values']]; + continue; + } + if ($this->propertyOption === 'toProperties') { + $propertiesToAdd[$property['name']]['DE'] = [ + 'name' => $property['name'], + 'value' => $property['values']]; + } + } + } + + if (!empty($internalArticleData['eigenschaftenuebersetzungen'])) { + foreach ($internalArticleData['eigenschaftenuebersetzungen'] as $translatedProperty) { + if ($translatedProperty['language_to'] === 'EN') { + $translatedProperty['language_to'] = 'GB'; + } + if ($this->propertyMustBeIgnored($translatedProperty['property_to'], $translatedProperty['property_value_to'])) { + continue; + } + if (strpos($translatedProperty['property_to'], 'property_') === 0) { + $propertiesToAdd[$translatedProperty['property_from']][$translatedProperty['language_to']] = [ + 'name' => substr($translatedProperty['property_to'], 9), + 'value' => $translatedProperty['property_value_to']]; + continue; + } + if ($this->propertyOption === 'toProperties') { + $propertiesToAdd[$translatedProperty['property_from']][$translatedProperty['language_to']] = [ + 'name' => $translatedProperty['property_to'], + 'value' => $translatedProperty['property_value_to']]; + } + } + } + + if (!empty($internalArticleData['freifelder'])) { + foreach ($internalArticleData['freifelder']['DE'] as $freeFieldKey => $freeFieldValue) { + if ($this->propertyMustBeIgnored($freeFieldKey, $freeFieldValue)) { + continue; + } + if (strpos($freeFieldKey, 'property_') === 0) { + $propertyName = substr($freeFieldKey, 9); + $propertiesToAdd[$propertyName]['DE'] = [ + 'name' => $propertyName, + 'value' => $freeFieldValue + ]; + continue; + } + if ($this->freeFieldOption === 'toProperties') { + $propertiesToAdd[$freeFieldKey]['DE'] = [ + 'name' => $freeFieldKey, + 'value' => $freeFieldValue + ]; + } + } + + foreach ($internalArticleData['freifelder'] as $languageIso => $freeFields) { + if ($languageIso === 'DE') { + continue; + } + if ($languageIso === 'EN') { + $languageIso = 'GB'; + } + foreach ($freeFields as $freeFieldData) { + if ($this->propertyMustBeIgnored($freeFieldData['mapping'], $freeFieldData['wert'])) { + continue; + } + if (strpos($freeFieldData['mapping'], 'property_') === 0) { + $propertyName = substr($freeFieldData['mapping'], 9); + $propertiesToAdd[$propertyName][$languageIso] = [ + 'name' => $propertyName, + 'value' => $freeFieldData['wert'] + ]; + continue; + } + if ($this->freeFieldOption === 'toProperties') { + $propertiesToAdd[$freeFieldData['mapping']][$languageIso] = [ + 'name' => $freeFieldData['mapping'], + 'value' => $freeFieldData['wert'] + ]; + } + } + } + } + + return $propertiesToAdd; + } + + /** + * @param array $articleInXentral + * @param string $articleIdShopware + * + * @return array + */ + protected function customFieldsToExport($articleInXentral, $articleIdShopware): array + { + $customFieldsToAdd = $this->getCustomFieldsFromArticle($articleInXentral); + if (empty($customFieldsToAdd)) { + return []; + } + $languageId = $this->getLanguageIdByCountryIso('DE'); + $headerInformation = ['sw-language-id: ' . $languageId]; + + $customFields = []; + if (!empty($articleIdShopware)) { + $articleInfo = $this->shopwareRequest( + 'GET', 'product/' . $articleIdShopware, + [], + $headerInformation); + $customFields['DE'] = $articleInfo['data'][0]['attributes']['customFields']; + if ($customFields === null) { + $customFields = []; + } + } + + foreach ($customFieldsToAdd as $defaultFieldName => $countryIsoCodeToCustomFieldData) { + $customFieldDefinition = $this->shopwareRequest( + 'GET', + sprintf('custom-field?filter[custom_field.name]=%s', $defaultFieldName), + [], + $headerInformation + ); + if (empty($customFieldDefinition)) { + $this->Shopware6Log('Freifeld entspricht keinem shopware Freifeld', $defaultFieldName); + continue; + } + + foreach ($countryIsoCodeToCustomFieldData as $countryIsoCode => $customFieldData) { + $name = $customFieldData['name']; + $value = $customFieldData['value']; + if ($value === '') { + continue; + } + if($countryIsoCode === 'EN'){ + $countryIsoCode = 'GB'; + } + $fieldType = $customFieldDefinition['data'][0]['attributes']['type']; + $controlType = $customFieldDefinition['data'][0]['attributes']['config']['componentName']; + + switch ($fieldType) { + case 'text': + case 'html': + if ($controlType === 'sw-media-field') { + $this->Shopware6Log( + 'Warnung: Freifelder vom Type "medium" werden nicht unterstützt.' + ); + } else { + $customFields[$countryIsoCode][$name] = (string)$value; + } + break; + case 'bool': + $customFields[$countryIsoCode][$name] = filter_var($value, FILTER_VALIDATE_BOOLEAN); + break; + case 'int': + $customFields[$countryIsoCode][$name] = (int)$value; + break; + case 'float': + $customFields[$countryIsoCode][$name] = (float)$value; + break; + case 'select': + $options = $customFieldDefinition['data'][0]['attributes']['config']['options']; + $allowedValues = []; + foreach ($options as $option) { + $allowedValues[] = $option['value']; + } + if ($controlType === 'sw-single-select') { + if (in_array($value, $allowedValues, true)) { + $customFields[$countryIsoCode][$name] = $value; + } else { + $this->Shopware6Log( + sprintf('Warnung: Freifeld "%s"="%s"; ungültiger Wert', $name, $value), + ['allowed values' => $allowedValues] + ); + } + } + if ($controlType === 'sw-multi-select') { + $value = explode(',', $value); + foreach ($value as &$item) { + $item = trim($item); + } + unset($item); + if (array_intersect($value, $allowedValues) === $value) { + $customFields[$countryIsoCode][$name] = $value; + } else { + $this->Shopware6Log( + sprintf('Warnung: Freifeld "%s"; ungültiger Wert', $name), + ['values' => $value, 'allowed values' => $allowedValues] + ); + } + } + break; + default: + $this->Shopware6Log( + 'Warnung: Freifeld enthält falschen Typ.', + ['freifeld' => $name, 'wert' => $value] + ); + continue 2; + } + } + } + + + return $customFields; + } + + /** + * @param string $name + * @param string $value + * @return bool + */ + protected function customFieldMustBeIgnored(string $name, string $value): bool + { + return empty($value) || + strpos($name, 'property_') === 0 || + stripos($name, 'shopware6_') !== false; + } + + /** + * @param array $articleInXentral + * @return array + */ + protected function getCustomFieldsFromArticle($articleInXentral): array + { + $customFieldsToAdd = []; + if (!empty($articleInXentral['eigenschaften'])) { + foreach ($articleInXentral['eigenschaften'] as $propertyInXentral) { + if ($this->customFieldMustBeIgnored($propertyInXentral['name'], $propertyInXentral['values'])) { + continue; + } + if (strpos($propertyInXentral['name'], 'customField_') === 0) { + $customFieldName = substr($propertyInXentral['name'], 12); + $customFieldsToAdd[$customFieldName]['DE'] = [ + 'name' => $customFieldName, + 'value' => $propertyInXentral['values'] + ]; + continue; + } + if ($this->propertyOption === 'toCustomFields') { + $customFieldsToAdd[$propertyInXentral['name']]['DE'] = [ + 'name' => $propertyInXentral['name'], + 'value' => $propertyInXentral['values'] + ]; + } + } + } + if (!empty($articleInXentral['eigenschaftenuebersetzungen'])) { + foreach ($articleInXentral['eigenschaftenuebersetzungen'] as $translatedProperty) { + if ($this->customFieldMustBeIgnored($translatedProperty['property_to'], $translatedProperty['property_value_to'])) { + continue; + } + if (strpos($translatedProperty['property_to'], 'customField_') === 0) { + $customFieldName = substr($translatedProperty['property_to'], 12); + $customFieldsToAdd[$customFieldName][$translatedProperty['language_to']] = [ + 'name' => $customFieldName, + 'value' => $translatedProperty['property_value_to'] + ]; + continue; + } + if ($this->propertyOption === 'toCustomFields') { + $customFieldsToAdd[$translatedProperty['property_to']][$translatedProperty['language_to']] = [ + 'name' => $translatedProperty['property_to'], + 'value' => $translatedProperty['property_value_to'] + ]; + } + } + } + + if (!empty($articleInXentral['freifelder'])) { + foreach ($articleInXentral['freifelder']['DE'] as $freeFieldKey => $freeFieldValue) { + if ($this->customFieldMustBeIgnored($freeFieldKey, $freeFieldValue)) { + continue; + } + if (strpos($freeFieldKey, 'customField_') === 0) { + $customFieldName = substr($freeFieldKey, 12); + $customFieldsToAdd[$customFieldName]['DE'] = [ + 'name' => $customFieldName, + 'value' => $freeFieldValue + ]; + continue; + } + if ($this->freeFieldOption === 'toCustomFields') { + $customFieldsToAdd[$freeFieldKey]['DE'] = [ + 'name' => $freeFieldKey, + 'value' => $freeFieldValue + ]; + } + } + + foreach ($articleInXentral['freifelder'] as $countryIsoCode => $freeFieldTranslations) { + if ($countryIsoCode === 'DE') { + continue; + } + foreach ($freeFieldTranslations as $freeFieldTranslation){ + if ($this->customFieldMustBeIgnored($freeFieldTranslation['mapping'], $freeFieldTranslation['wert'])) { + continue; + } + if ($countryIsoCode === 'EN') { + $countryIsoCode = 'GB'; + } + if (strpos($freeFieldTranslation['mapping'], 'customField_') === 0) { + $customFieldName = substr($freeFieldTranslation['mapping'], 12); + $customFieldsToAdd[$customFieldName][$countryIsoCode] = [ + 'name' => $customFieldName, + 'value' => $freeFieldTranslation['wert'] + ]; + continue; + } + if ($this->freeFieldOption === 'toCustomFields') { + $customFieldsToAdd[$freeFieldTranslation['mapping']][$countryIsoCode] = [ + 'name' => $freeFieldTranslation['mapping'], + 'value' => $freeFieldTranslation['wert'] + ]; + } + } + } + } + + return $customFieldsToAdd; + } + + /** + * @param array $articleInXentral + * @param int $articleIdShopware + * + * @return array + */ + protected function crosssellingToExport($articleInXentral, $articleIdShopware){ + if (empty($articleInXentral['crosssellingartikel'])) { + return []; + } + + $crosssellingArticles = []; + foreach ($articleInXentral['crosssellingartikel'] as $crosssellingArticle){ + $type = 'Ähnlich'; + if($crosssellingArticle['art'] == 2){ + $type = 'Zubehör'; + } + $crosssellingArticles[$type][] = $crosssellingArticle['nummer']; + } + $crossselingInformation = []; + foreach ($crosssellingArticles as $type => $articles){ + if(!empty($articleIdShopware)){ + $existingCrossSellings = $this->shopwareRequest('GET', sprintf('product/%s/cross-sellings/', + $articleIdShopware)); + if(!empty($existingCrossSellings['data'])){ + foreach ($existingCrossSellings['data'] as $existingCrossSelling){ + if($existingCrossSelling['attributes']['name'] === $type){ + $this->shopwareRequest('DELETE', sprintf('product/%s/cross-sellings/%s/', + $articleIdShopware, $existingCrossSelling['id'])); + } + } + } + } + + $crosselingToAdd = []; + foreach ($articles as $articleNumber) { + $articleInfo = $this->shopwareRequest( + 'GET', + sprintf('product?filter[product.productNumber]=%s', $articleNumber) + ); + + if(empty($articleInfo['data'][0]['id'])){ + continue; + } + $crosselingToAdd[] = $articleInfo['data'][0]['id']; + } + if(empty($crosselingToAdd)){ + continue; + } + $crossselingInformationForType = [ + 'active' => true, + 'name' => $type, + 'assignedProducts' => [], + 'type' => 'productList', + 'sortBy' => 'name', + 'limit' => 24, + 'position' => 1 + ]; + $position = 1; + foreach ($crosselingToAdd as $articleId){ + $crossselingInformationForType['assignedProducts'][] = [ + 'productId' => $articleId, + 'position' => $position, + ]; + $position++; + } + $crossselingInformation[] = $crossselingInformationForType; + } + + + return $crossselingInformation; + } + + /** + * @param string $unitShortCode + * + * @return string + */ + protected function unitToAdd(string $unitShortCode): string{ + $searchData = [ + 'limit' => 25, + 'source' => [ + 'id' + ], + 'filter' => [ + [ + 'field' => 'unit.shortCode', + 'type' => 'equals', + 'value' => $unitShortCode + ] + ] + ]; + $unitInShopware = $this->shopwareRequest( + 'POST', + 'search/unit', + $searchData); + + if(!empty($unitInShopware['data'][0]['id'])){ + return $unitInShopware['data'][0]['id']; + } + + $query = sprintf("SELECT `internebemerkung` FROM `artikeleinheit` WHERE `einheit_de` = '%s' LIMIT 1", + $unitShortCode); + $unitName = $this->app->DB->Select($query); + if(empty($unitName)){ + $unitName = $unitShortCode; + } + + $unitInformation = [ + 'name' => $unitName, + 'shortCode' => $unitShortCode + ]; + $result = $this->shopwareRequest('POST', 'unit?_response=true', $unitInformation); + + if(empty($result['data']['id'])){ + return ''; + } + + return $result['data']['id']; + } + + /** + * @param array $internArticle + * @param int $articleIdShopware + * + * @return array + */ + protected function systemFieldsToExport($internArticle, $articleIdShopware): array + { + $internalSpecialFields = []; + foreach ($internArticle['freifelder']['DE'] as $freeFieldName => $freeFieldValue) { + if (stripos($freeFieldName, 'shopware6_') !== false) { + $internalSpecialFields[$freeFieldName] = $freeFieldValue; + } + } + foreach ($internArticle['eigenschaften'] as $property) { + if (stripos($property['name'], 'shopware6_') !== false) { + $internalSpecialFields[$property['name']] = $property['values']; + } + } + + $systemFields = []; + foreach ($internalSpecialFields as $fieldName => $fieldValue) { + switch (strtolower($fieldName)) { + case 'shopware6_sales_channel': + $systemFields['visibilities'] = $this->modifySalesChannel(explode(',', $fieldValue), $articleIdShopware); + break; + case 'shopware6_purchase_unit': + $systemFields['purchaseUnit'] = (float)str_replace(',', '.', $fieldValue); + break; + case 'shopware6_reference_unit': + $systemFields['referenceUnit'] = (float)str_replace(',', '.', $fieldValue); + break; + case 'shopware6_unit': + $systemFields['unitId'] = $this->unitToAdd($fieldValue); + break; + case 'shopware6_pack_unit': + $systemFields['packUnit'] = (string)$fieldValue; + break; + case 'shopware6_restock_time': + $systemFields['restockTime'] = (int)$fieldValue; + break; + case 'shopware6_pack_unit_plural': + $systemFields['packUnitPlural'] = (string)$fieldValue; + break; + } + } + + return $systemFields; + } + + /** + * @param array $salesChannelNames + * @param string $articleIdInShopware + * + * @return array + */ + protected function modifySalesChannel($salesChannelNames, $articleIdInShopware) + { + $salesChannelInXentralIds = []; + foreach ($salesChannelNames as $salesChannelName) { + $salesChannelInfo = $this->shopwareRequest('GET', + sprintf('sales-channel?filter[sales_channel.name]=%s', urlencode(trim($salesChannelName))) + ); + if (!empty($salesChannelInfo['data'][0]['id'])) { + $salesChannelInXentralIds[] = $salesChannelInfo['data'][0]['id']; + } + } + + $existingVisibilities = $this->shopwareRequest( + 'GET', + sprintf('product/%s/visibilities', $articleIdInShopware) + ); + + $existingSalesChannelIds = []; + if (!empty($existingVisibilities['data'])) { + foreach ($existingVisibilities['data'] as $visibility) { + $existingSalesChannelIds[$visibility['id']] = $visibility['attributes']['salesChannelId']; + } + } + + foreach ($existingSalesChannelIds as $associationId => $existingSalesChannelId){ + if (!in_array($existingSalesChannelId, $salesChannelInXentralIds,true)) { + $this->shopwareRequest('DELETE', sprintf('product/%s/visibilities/%s/', + $articleIdInShopware, $associationId)); + } + } + + $salesChannelsToAdd = []; + foreach ($salesChannelInXentralIds as $salesChannelInXentralId){ + if (!in_array($salesChannelInXentralId, $existingSalesChannelIds,true)) { + $salesChannelsToAdd[] = $salesChannelInXentralId; + } + } + + $visibilities = []; + foreach ($salesChannelsToAdd as $salesChannelIdToAdd) { + $visibilities[] = [ + 'salesChannelId' => $salesChannelIdToAdd, + 'visibility' => 30 + ]; + } + + return $visibilities; + } + + /** + * @param string $isoCode + * + * @return string + */ + protected function findCurrencyId($isoCode) + { + + $this->requestCurrencyMappingLazy(); + if (isset($this->currencyMapping[strtoupper($isoCode)])) { + return $this->currencyMapping[strtoupper($isoCode)]; + } + $this->Shopware6Log( + sprintf('Warnung: Kein Mapping für Waehrung "%s" gefunden.', $isoCode), + $this->currencyMapping + ); + + return null; + } + + /** + * request currency mapping only once + */ + protected function requestCurrencyMappingLazy() + { + + if ($this->currencyMapping !== null) { + return; + } + $currencies = $this->shopwareRequest('GET', 'currency'); + if (!isset($currencies['data'])) { + $this->Shopware6Log('Kann Währungsmapping nicht abrufen', $currencies); + } + foreach ($currencies['data'] as $currency) { + $isoCode = strtoupper($currency['attributes']['isoCode']); + $this->currencyMapping[$isoCode] = $currency['id']; + } + } + + /** + * @param array $internalArticleData + * @param string $articleIdInShopware + * @return bool + */ + public function exportSeoUrls(array $internalArticleData, string $articleIdInShopware): bool + { + if (empty($articleIdInShopware)) { + return false; + } + + $preparedSeoInformation = []; + foreach ($internalArticleData['freifelder'] as $countryIsoCode => $freeFieldInformation) { + if($countryIsoCode === 'EN'){ + $countryIsoCode = 'GB'; + } + if($countryIsoCode === 'DE'){ + foreach ($freeFieldInformation as $freeFieldName => $freeFieldValue) { + if (stripos($freeFieldName, 'shopware6_seo_url') !== false) { + $preparedSeoInformation[$countryIsoCode][$freeFieldName] = $freeFieldValue; + } + } + }else{ + foreach ($freeFieldInformation as $freeFieldData) { + if (stripos($freeFieldData['mapping'], 'shopware6_seo_url') !== false) { + $preparedSeoInformation[$countryIsoCode][$freeFieldData['mapping']] = $freeFieldData['wert']; + } + } + } + } + foreach ($internalArticleData['eigenschaften'] as $property) { + if (stripos($property['name'], 'shopware6_seo_url') !== false) { + $preparedSeoInformation['DE'][$property['name']] = $property['values']; + } + } + foreach ($internalArticleData['eigenschaftenuebersetzungen'] as $propertyTranslation) { + if($propertyTranslation['language_to'] === 'EN'){ + $propertyTranslation['language_to'] = 'GB'; + } + if (stripos($propertyTranslation['property_to'], 'shopware6_seo_url') !== false) { + $preparedSeoInformation[$propertyTranslation['language_to']][$propertyTranslation['property_to']] = $propertyTranslation['property_value_to']; + } + } + + $specificSalesChannelSeoUrls = []; + $defaultSeoUrls = []; + foreach ($preparedSeoInformation as $countryIsoCode => $channelAssociations) { + foreach ($channelAssociations as $fieldName => $fieldValue){ + if(strtolower($fieldName) === 'shopware6_seo_url'){ + $defaultSeoUrls[$countryIsoCode] = $fieldValue; + }else{ + $seoInformation = explode('|', $fieldName); + $specificSalesChannelSeoUrls[$countryIsoCode][array_pop($seoInformation)] = $fieldValue; + } + } + } + + if (empty($specificSalesChannelSeoUrls) && empty($defaultSeoUrls)) { + return false; + } + + $salesChannelsIdToName = []; + $salesChannels = $this->shopwareRequest('GET','sales-channel'); + foreach ($salesChannels['data'] as $salesChannel) { + $salesChannelsIdToName[$salesChannel['id']] = $salesChannel['attributes']['name']; + } + + foreach ($preparedSeoInformation as $countryIsoCode => $x){ + $languageId = $this->getLanguageIdByCountryIso($countryIsoCode); + if (empty($languageId)) { + $this->Shopware6Log('Language Id not found for country: ' . $countryIsoCode); + continue; + } + + $headerInformation = ['sw-language-id: ' . $languageId]; + foreach ($salesChannelsIdToName as $salesChannelId => $salesChannelName) { + $seoUrlToUse = $defaultSeoUrls[$countryIsoCode]; + if (!empty($specificSalesChannelSeoUrls[$countryIsoCode][$salesChannelName])) { + $seoUrlToUse = $specificSalesChannelSeoUrls[$countryIsoCode][$salesChannelsIdToName[$salesChannelName]]; + } + if (empty($seoUrlToUse)) { + continue; + } + $seoDataToSend = [ + 'seoPathInfo' => $seoUrlToUse, + '_isNew' => true, + 'isModified' => true, + 'isCanonical' => true, + 'isDeleted' => false, + 'routeName' => 'frontend.detail.page', + 'foreignKey' => $articleIdInShopware, + 'pathInfo' => '/detail/'.$articleIdInShopware, + 'languageId' => $languageId, + 'salesChannelId' => $salesChannelId]; + $this->shopwareRequest('PATCH', '_action/seo-url/canonical', $seoDataToSend, $headerInformation); + } + } + + return true; + } + + /** + * @param array $article + * @param string $articleIdShopware + * @param string $currencyId + * + * @return bool + */ + protected function exportVariants($article, $articleIdShopware, $currencyId): bool + { + $languageId = $this->getLanguageIdByCountryIso('DE'); + if (empty($languageId)) { + return false; + } + if (empty($article['matrix_varianten']) || empty($articleIdShopware)) { + return false; + } + $internalGroupPropertiesToShopwareId = []; + foreach ($article['matrix_varianten']['gruppen'] as $propertyGroupName => $internalPropertyGroupValues) { + $propertyGroupId = ''; + if (array_key_exists($propertyGroupName, $this->knownPropertyGroupIds)) { + $propertyGroupId = $this->knownPropertyGroupIds[$propertyGroupName]; + } + if (empty($propertyGroupId)) { + $propertyGroupId = $this->getPropertyGroupId($propertyGroupName); + } + if (empty($propertyGroupId)) { + $propertyGroupId = $this->createPropertyGroup($propertyGroupName); + } + if (empty($propertyGroupId)) { + $this->Shopware6Log('PropertyGroup kann nicht erstellt werden: ' . $propertyGroupName); + return false; + } + + if (!empty($article['matrix_varianten']['texte'])) { + $this->createTranslationForPropertyGroup($propertyGroupId, $propertyGroupName, 'DE'); + + foreach ($article['matrix_varianten']['texte']['gruppen'] as $countryIsoCode => $matrixGroupTranslation) { + if ($countryIsoCode === 'EN') { + $countryIsoCode = 'GB'; + } + + $this->createTranslationForPropertyGroup($propertyGroupId, $matrixGroupTranslation[$propertyGroupName], $countryIsoCode); + } + } + + $languageId = $this->getLanguageIdByCountryIso('DE'); + $headerInformation = ['sw-language-id: ' . $languageId]; + $shopwarePropertyGroupOptions = $this->shopwareRequest( + 'GET', + 'property-group/' . $propertyGroupId . '/options?limit=100', + $headerInformation); + foreach ($shopwarePropertyGroupOptions['data'] as $shopwarePropertyGroupOption) { + $propertyValue = $shopwarePropertyGroupOption['attributes']['name']; + $internalGroupPropertiesToShopwareId[$propertyGroupName][$propertyValue] = $shopwarePropertyGroupOption['id']; + } + + foreach ($internalPropertyGroupValues as $internalPropertyGroupValue => $valueNotNeeded) { + if (!array_key_exists($internalPropertyGroupValue, $internalGroupPropertiesToShopwareId[$propertyGroupName])) { + $newOptionData = [ + 'name' => (string)$internalPropertyGroupValue + ]; + $optionData = $this->shopwareRequest( + 'POST', + 'property-group/' . $propertyGroupId . '/options?_response=true', + $newOptionData); + $internalGroupPropertiesToShopwareId[$propertyGroupName][$internalPropertyGroupValue] = $optionData['data']['id']; + } + } + + if (!empty($article['matrix_varianten']['texte'])) { + foreach ($internalPropertyGroupValues as $optionValue => $valueNotNeeded) { + $optionId = $internalGroupPropertiesToShopwareId[$propertyGroupName][$optionValue]; + $this->createTranslationForPropertyOption( + $optionId, + $optionValue, + 'DE'); + foreach ($article['matrix_varianten']['texte']['werte'] as $countryIsoCode => $matrixOptionTranslations) { + if ($countryIsoCode === 'EN') { + $countryIsoCode = 'GB'; + } + if (array_key_exists($optionValue, $matrixOptionTranslations)) { + $this->createTranslationForPropertyOption( + $optionId, + $matrixOptionTranslations[$optionValue], + $countryIsoCode); + } + } + } + } + } + + $existingCombinations = $this->shopwareRequest( + 'GET', + '_action/product/' . $articleIdShopware . '/combinations'); + $existingCombinationsByNumber = []; + + foreach ($existingCombinations as $combinationId => $combinationInfo) { + $existingCombinationsByNumber[$combinationInfo['productNumber']] = [ + 'id' => $combinationId, + 'options' => [], + ]; + foreach ($combinationInfo['options'] as $combinationOption) { + $existingCombinationsByNumber[$combinationInfo['productNumber']]['options'][$combinationOption] = $combinationOption; + } + } + + + foreach ($article['artikel_varianten'] as $variant) { + $internalVariantMatrixData = $article['matrix_varianten']['artikel'][$variant['artikel']]; + $productNumber = $internalVariantMatrixData[0]['nummer']; + $name = $variant['name_de']; + $stock = $variant['lag']; + $ean = $variant['ean']; + $weight = (float)$variant['gewicht']; + $pseudoPrice = $variant['pseudopreis']; + if (empty($pseudoPrice)) { + $pseudoPrice = 0; + } + if (!empty($variant['pseudolager'])) { + $stock = $variant['pseudolager']; + } + $active = true; + if (!empty($variant['inaktiv'])) { + $active = false; + } + $isCloseOut = false; + if (!empty($variant['restmenge'])) { + $isCloseOut = true; + } + + $variantProductData = [ + 'active' => $active, + 'isCloseout' => $isCloseOut, + 'name' => $name, + 'description' => null, + 'weight' => null, + 'price' => [ + [ + 'currencyId' => $currencyId, + 'gross' => $variant['bruttopreis'], + 'net' => $variant['preis'], + 'linked' => true, + 'listPrice' => [ + 'currencyId' => $currencyId, + 'gross' => $pseudoPrice, + 'linked' => true, + 'net' => $pseudoPrice / (1 + $variant['steuersatz'] / 100) + ] + ] + ], + 'stock' => (int)$stock, + 'ean' => null, + 'taxId' => $this->getTaxIdByRate($variant['steuersatz']), + ]; + if(!empty($weight)){ + $variantProductData['weight'] = $weight; + } + if(!empty($ean)){ + $variantProductData['ean'] = $ean; + } + if (!empty($variant['uebersicht_de'])) { + $variantProductData['description'] = $variant['uebersicht_de']; + } + + $renewVariant = false; + $options = []; + foreach ($internalVariantMatrixData as $expression) { + if (!in_array( + $internalGroupPropertiesToShopwareId[$expression['name']][$expression['values']], + $existingCombinationsByNumber[$productNumber]['options'], + false)) { + $renewVariant = true; + } else { + unset($existingCombinationsByNumber[$productNumber]['options'][$internalGroupPropertiesToShopwareId[$expression['name']][$expression['values']]]); + } + $options[] = ['id' => $internalGroupPropertiesToShopwareId[$expression['name']][$expression['values']]]; + } + + if (!empty($existingCombinationsByNumber[$productNumber]['options'])) { + $renewVariant = true; + } + + $variantImageData = [ + 'Dateien' => [] + ]; + $variantProductId = ''; + if (!empty($existingCombinationsByNumber[$productNumber]['id']) && !$renewVariant) { + $variantProductId = $existingCombinationsByNumber[$productNumber]['id']; + } + if (!empty($variant['Dateien']['id'])) { + foreach ($variant['Dateien']['id'] as $index => $fileId) { + $variantImageData['Dateien'][] = [ + 'filename' => $variant['Dateien']['filename'][$index], + 'extension' => $variant['Dateien']['extension'][$index], + 'datei' => $variant['Dateien']['datei'][$index], + 'beschreibung' => $variant['Dateien']['beschreibung'][$index], + 'titel' => $variant['Dateien']['titel'][$index], + 'id' => $fileId, + ]; + } + } + $mediaToAdd = $this->mediaToExport($variantImageData, $variantProductId); + $variantProductData['media'] = $mediaToAdd; + + if ($renewVariant) { + if (!empty($existingCombinationsByNumber[$productNumber]['id'])) { + $this->shopwareRequest('DELETE', 'product/' . $existingCombinationsByNumber[$productNumber]['id']); + } + $variantProductData['productNumber'] = $productNumber; + $variantProductData['parentId'] = $articleIdShopware; + $variantProductData['options'] = $options; + + $result = $this->shopwareRequest('POST', 'product?_response=true', $variantProductData); + $variantProductId = $result['data']['id']; + } else { + $variantProductId = $existingCombinationsByNumber[$productNumber]['id']; + $this->shopwareRequest('PATCH', 'product/' . $variantProductId, $variantProductData); + } + + $defaultPrices = $this->getPricesFromArray($variant['staffelpreise_standard'] ?? []); + $groupPrices = $this->getPricesFromArray($variant['staffelpreise_gruppen'] ?? []); + + $this->deleteOldBulkPrices($variantProductId); + if (!empty($defaultPrices)) { + foreach ($defaultPrices as $priceData) { + $this->exportBulkPriceForGroup($variantProductId, $this->defaultRuleName, $priceData); + } + } + if (!empty($groupPrices)) { + foreach ($groupPrices as $priceData) { + $this->exportBulkPriceForGroup($variantProductId, $priceData->getGroupName(), $priceData); + } + } + + $this->addCoverImage($variantImageData, $variantProductId); + } + + $existingConfigurations = $this->shopwareRequest( + 'GET', 'product/' . $articleIdShopware . '/configuratorSettings'); + $optionIdsToAdd = []; + foreach ($article['artikel_varianten'] as $variant) { + foreach ($article['matrix_varianten']['artikel'][$variant['artikel']] as $matrixInfo) { + $configurationExists = false; + foreach ($existingConfigurations['data'] as $configuration) { + if ($configuration['attributes']['optionId'] === $internalGroupPropertiesToShopwareId[$matrixInfo['name']][$matrixInfo['values']]) { + $configurationExists = true; + break; + } + } + if (!$configurationExists) { + $optionIdsToAdd[] = $internalGroupPropertiesToShopwareId[$matrixInfo['name']][$matrixInfo['values']]; + } + } + } + if (!empty($optionIdsToAdd)) { + $optionIdsToAdd = array_flip(array_flip($optionIdsToAdd)); + $configurationData = [ + 'configuratorSettings' => [] + ]; + foreach ($optionIdsToAdd as $id) { + $configurationData['configuratorSettings'][] = ['optionId' => $id]; + } + + $this->shopwareRequest( + 'PATCH', + sprintf('product/%s', $articleIdShopware), + $configurationData + ); + + $existingConfigurations = $this->shopwareRequest( + 'GET', 'product/' . $articleIdShopware . '/configuratorSettings'); + $optionsToSort = []; + foreach ($article['artikel_varianten'] as $variant) { + foreach ($article['matrix_varianten']['artikel'][$variant['artikel']] as $matrixInfo) { + foreach ($existingConfigurations['data'] as $configuration) { + if ($configuration['attributes']['optionId'] === $internalGroupPropertiesToShopwareId[$matrixInfo['name']][$matrixInfo['values']]) { + $optionsToSort[] = $configuration['id']; + break; + } + } + } + } + if (!empty($optionsToSort)) { + $optionsToSort = array_flip(array_flip($optionsToSort)); + $configurationData = [ + 'configuratorSettings' => [] + ]; + $position = 1; + + foreach ($optionsToSort as $id) { + $configurationData['configuratorSettings'][] = [ + 'id' => $id, + 'position' => $position]; + $position++; + } + + $this->shopwareRequest( + 'PATCH', + sprintf('product/%s', $articleIdShopware), + $configurationData + ); + } + } + + return true; + } + + /** + * @param $priceArray + * @return PriceData[] + */ + protected function getPricesFromArray($priceArray): array{ + return array_map(static function($price){ + return new PriceData( + (int)$price['ab_menge'], + (float)$price['preis'], + (float)$price['bruttopreis'], + $price['waehrung'], + $price['gruppeextern'] ?? '') ; + },$priceArray); + } + + /** + * delete all old price entries for a product + * + * @param string $productId + */ + protected function deleteOldBulkPrices($productId) + { + //TODO Instead of deleting all old prices we should rather check first whether they are still in order + $oldPrices = $this->shopwareRequest( + 'GET', + sprintf('product-price?filter[product_price.productId]=%s', $productId) + ); + if (is_array($oldPrices)) { + foreach ($oldPrices['data'] as $deletePrice) { + $this->shopwareRequest('DELETE', 'product-price/' . $deletePrice['id']); + } + } else { + $this->Shopware6Log('Fehler: Alte Preise wurden nicht gelöscht', $productId); + } + } + + /** + * @return int + */ + public function getOrderSearchLimit(): int + { + if(in_array($this->orderSearchLimit, ['50', '75', '100'])) { + return (int)$this->orderSearchLimit; + } + + return 25; + } + + /** + * @return int + */ + public function ImportGetAuftraegeAnzahl() + { + $order = null; + $dataToGet = $this->CatchRemoteCommand('data'); + + if (empty($this->statesToFetch)) { + return false; + } + + $ordersToProcess = $this->getOrdersToProcess($this->getOrderSearchLimit()); + + return (!empty(count($ordersToProcess['data'])?count($ordersToProcess['data']):0); + } + + /** + * @param string $parameter1 + * @param string $parameter2 + */ + public function Shopware6ErrorLog($parameter1, $parameter2 = '') + { + $this->app->DB->Insert( + sprintf( + "INSERT INTO `shopexport_log` + (shopid, typ, parameter1, parameter2, bearbeiter, zeitstempel) + VALUES (%d, 'fehler', '%s','%s','%s',NOW())", + $this->shopid, + $this->app->DB->real_escape_string($parameter1), + $this->app->DB->real_escape_string($parameter2), + $this->app->DB->real_escape_string($this->app->User->GetName()) + ) + ); + } + + /** + * @param array $stateMachinesIds + * @return array + */ + protected function getTransactionStateIdsToFetch($stateMachinesIds): array + { + $transactionStateIdsToFetch = []; + if (!empty($this->transactionStatesToFetch)) { + $transactionStatesToFetch = explode(';', $this->transactionStatesToFetch); + foreach ($transactionStatesToFetch as $transactionStateToFetch) { + $stateInformation = $this->shopwareRequest('GET', 'state-machine-state?filter[technicalName]=' . + trim($transactionStateToFetch) . '&filter[stateMachineId]=' . $stateMachinesIds['order_transaction.state']); + if (empty($stateInformation['data'])) { + $this->Shopware6ErrorLog('Zahlungsstatus für Abholung nicht gefunden', $transactionStateToFetch); + return false; + } + foreach ($stateInformation['data'] as $state) { + $transactionStateIdsToFetch[] = $state['id']; + } + } + } + + return $transactionStateIdsToFetch; + } + + /** + * @param int $limit + * + * @return mixed + */ + protected function getOrdersToProcess(int $limit) + { + $searchData = [ + 'limit' => $limit, + 'includes' => [ + 'order' => ['id'] + ], + 'sort' => [ + [ + 'field' => 'order.createdAt', + 'direction' => 'DESC' + ] + ], + 'filter' => [] + ]; + + $searchData['filter'][] = [ + 'field' => 'stateMachineState.technicalName', + 'type' => 'equalsAny', + 'value' => explode(';', $this->statesToFetch) + ]; + + if (!empty($this->deliveryStatesToFetch)) { + $searchData['filter'][] = [ + 'field' => 'deliveries.stateMachineState.technicalName', + 'type' => 'equalsAny', + 'value' => explode(';', $this->deliveryStatesToFetch) + ]; + } + if (!empty($this->transactionStatesToFetch)) { + $searchData['filter'][] = [ + 'field' => 'transactions.stateMachineState.technicalName', + 'type' => 'equalsAny', + 'value' => explode(';', $this->transactionStatesToFetch) + ]; + } + + if (!empty($this->salesChannelToFetch)) { + $searchData['filter'][] = [ + 'field' => 'order.salesChannelId', + 'type' => 'equals', + 'value' => $this->salesChannelToFetch + ]; + } + + return $this->shopwareRequest('POST', 'search/order', $searchData); + } + + /** + * @return int|mixed + */ + public function ImportGetAuftrag() + { + $voucherArticleId = $this->app->DB->Select("SELECT s.artikelrabatt FROM `shopexport` AS `s` WHERE s.id='$this->shopid' LIMIT 1"); + $voucherArticleNumber = $this->app->DB->Select("SELECT a.nummer FROM `artikel` AS `a` WHERE a.id='$voucherArticleId' LIMIT 1"); + + $dataToGet = $this->CatchRemoteCommand('data'); + if (empty($this->statesToFetch)) { + return false; + } + $expectOrderArray = !empty($dataToGet['anzgleichzeitig']) && (int)$dataToGet['anzgleichzeitig'] > 1; + $expectNumber = !empty($dataToGet['nummer']); + $order = null; + if($expectNumber) { + $order = $this->shopwareRequest('GET', 'order/' . $dataToGet['nummer'] . '?associations[currency][]'); + if(empty($order['data'])) { + return false; + } + $ordersToProcess = ['data' => [ ['id' => $dataToGet['nummer']] ]]; + $orderIncludedData = $order['included']; + $order = $order['data']; + } + elseif(!$expectOrderArray) { + $ordersToProcess = $this->getOrdersToProcess(1); + } + elseif(!$expectNumber) { + $ordersToProcess = $this->getOrdersToProcess($this->getOrderSearchLimit()); + } + if (empty($ordersToProcess['data'])) { + return false; + } + + $fetchedOrders = []; + if (isset($ordersToFetch['data']['id']) && !isset($ordersToFetch['data'][0])) { + $ordersToFetch['data'] = [$ordersToFetch['data']]; + } + foreach ($ordersToProcess['data'] as $currentlyOpenOrder) { + $orderIdToFetch = $currentlyOpenOrder['id']; + + if (empty($dataToGet['nummer']) || empty($order)) { + $order = $this->shopwareRequest('GET', 'order/' . $orderIdToFetch.'?associations[currency][]'); + $orderIncludedData = $order['included']; + $order = $order['data']; + } + $cart = []; + try { + $timestamp = date_create_from_format('Y-m-d\TH:i:s+', $order['attributes']['createdAt']); + $cart['zeitstempel'] = $timestamp->format('Y-m-d H:i:s'); + } catch (Exception $ex) { + + } + $cart['auftrag'] = $order['id']; + $cart['subshop'] = $order['attributes']['salesChannelId']; + $cart['order'] = $order; + $cart['onlinebestellnummer'] = $order['attributes']['orderNumber']; + $cart['gesamtsumme'] = $order['attributes']['amountTotal']; + $cart['versandkostenbrutto'] = $order['attributes']['shippingTotal']; + $cart['bestelldatum'] = substr($order['attributes']['orderDate'], 0, 10); + if (!empty($order['attributes']['customerComment'])) { + $cart['freitext'] = $order['attributes']['customerComment']; + } + + foreach ($orderIncludedData as $includedDataSet){ + if($includedDataSet['type'] === 'currency'){ + $cart['waehrung'] = $includedDataSet['attributes']['isoCode']; + } + } + + $deliveryInfo = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/deliveries'); + $shippingMethod = $this->shopwareRequest('GET', + 'order-delivery/' . $deliveryInfo['data'][0]['id'] . '/shipping-method'); + $order['shippingMethod'] = $shippingMethod; + $cart['lieferung'] = $shippingMethod['data'][0]['attributes']['name']; + + $customer = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/order-customer'); + $order['customer'] = $customer; + $cart['email'] = $customer['data']['0']['attributes']['email']; + + $addresses = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/addresses?associations[salutation][]&associations[country][]'); + $order['addresses'] = $addresses; + $deliveryCountryId = ''; + $billingCountryId = ''; + $billingSalutationId = ''; + foreach ($addresses['data'] as $address) { + if ($address['id'] === $order['attributes']['billingAddressId']) { + if (!empty($address['attributes']['vatId'])) { + $cart['ustid'] = $address['attributes']['vatId']; + } + $cart['name'] = $address['attributes']['firstName'] . ' ' . $address['attributes']['lastName']; + if (!empty($address['attributes']['company'])) { + $cart['ansprechpartner'] = $cart['name']; + $cart['name'] = $address['attributes']['company']; + } + $cart['strasse'] = $address['attributes']['street']; + $cart['abteilung'] = $address['attributes']['department']; + $cart['adresszusatz'] = trim($address['attributes']['additionalAddressLine1'].' '. + $address['attributes']['additionalAddressLine2']); + $cart['telefon'] = $address['attributes']['phoneNumber']; + $cart['plz'] = $address['attributes']['zipcode']; + $cart['ort'] = $address['attributes']['city']; + $billingCountryId = $address['attributes']['countryId']; + $billingSalutationId = $address['attributes']['salutationId']; + } + if ($address['id'] !== $order['attributes']['billingAddressId']) { + $cart['abweichendelieferadresse'] = 1; + if (!empty($address['attributes']['vatId'])) { + $cart['lieferadresse_ustid'] = $address['attributes']['vatId']; + } + $cart['lieferadresse_name'] = $address['attributes']['firstName'] . ' ' . $address['attributes']['lastName']; + if (!empty($address['attributes']['company'])) { + $cart['lieferadresse_ansprechpartner'] = $cart['lieferadresse_name']; + $cart['lieferadresse_name'] = $address['attributes']['company']; + } + $cart['lieferadresse_strasse'] = $address['attributes']['street']; + $cart['lieferadresse_abteilung'] = $address['attributes']['department']; + $cart['lieferadresse_adresszusatz'] = trim($address['attributes']['additionalAddressLine1'].' '. + $address['attributes']['additionalAddressLine2']); + $cart['lieferadresse_plz'] = $address['attributes']['zipcode']; + $cart['lieferadresse_ort'] = $address['attributes']['city']; + $deliveryCountryId = $address['attributes']['countryId']; + } + } + + $anrede = 'herr'; + $land = 'DE'; + $lieferadresseLand = 'DE'; + foreach ($addresses['included'] as $includedInfo) { + if ($includedInfo['id'] === $billingCountryId) { + $land = $includedInfo['attributes']['iso']; + } + if ($includedInfo['id'] === $deliveryCountryId) { + $lieferadresseLand = $includedInfo['attributes']['iso']; + } + if ($includedInfo['id'] === $billingSalutationId) { + $salutation = $includedInfo['attributes']['salutationKey']; + if ($salutation === 'ms' || $salutation === 'mrs') { + $anrede = 'frau'; + } + } + } + + $cart['anrede'] = $anrede; + $cart['land'] = $land; + if (!empty($cart['abweichendelieferadresse'])) { + $cart['lieferadresse_land'] = $lieferadresseLand; + } + + $transactionData = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/transactions'); + $cart['transacion_data'] = $transactionData; + if (!empty($transactionData['data'][0]['attributes']['customFields']['swag_paypal_pui_payment_instruction']['reference_number'])) { + $cart['transaktionsnummer'] = $transactionData['data'][0]['attributes']['customFields']['swag_paypal_pui_payment_instruction']['reference_number']; + } + if (empty($cart['transaktionsnummer'] && !empty($transactionData['data'][0]['attributes']['customFields']['swag_paypal_order_id']))) { + $cart['transaktionsnummer'] = (string)$transactionData['data'][0]['attributes']['customFields']['swag_paypal_order_id']; + } + if (empty($cart['transaktionsnummer'] && !empty($transactionData['data'][0]['attributes']['customFields']['swag_paypal_transaction_id']))) { + $livePayPalData = $this->shopwareRequest('GET', 'paypal/payment-details/' . $order['id'] . '/' . $transactionData['data'][0]['attributes']['customFields']['swag_paypal_transaction_id']); + if (!empty($livePayPalData['transactions'])) { + foreach ($livePayPalData['transactions'] as $payPalData) { + foreach ($payPalData['related_resources'] as $ressources) { + if ($ressources['sale']['state'] === 'completed') { + $cart['transaktionsnummer'] = $ressources['sale']['id']; + break 2; + } + } + } + } + } + if( + empty($cart['transaktionsnummer']) + && isset($transactionData['data'][0]['attributes']['customFields']['stripe_payment_context']['payment']['payment_intent_id']) + ){ + $cart['transaktionsnummer'] = $transactionData['data'][0]['attributes']['customFields']['stripe_payment_context']['payment']['payment_intent_id']; + } + + $paymentMethodId = $transactionData['data'][0]['attributes']['paymentMethodId']; + $paymentMethod = $this->shopwareRequest('GET', 'payment-method/' . $paymentMethodId); + $cart['zahlungsweise'] = $paymentMethod['data']['attributes']['name']; + + $taxedCountry = $land; + if($this->taxationByDestinationCountry){ + $taxedCountry = $lieferadresseLand; + } + if($order['attributes']['amountTotal'] === $order['attributes']['amountNet']){ + if($this->app->erp->IstEU($taxedCountry)){ + $cart['ust_befreit'] = 1; + }elseif($this->app->erp->Export($taxedCountry)){ + $cart['ust_befreit'] = 2; + }else{ + $cart['ust_befreit'] = 3; + } + } + + $lineItems = $this->shopwareRequest('GET', 'order/' . $order['id'] . '/line-items'); + $order['lineItems'] = $lineItems; + $cart['articlelist'] = []; + + $taxRate = 0; + foreach ($lineItems['data'] as $lineItem) { + if ($lineItem['attributes']['price']['calculatedTaxes'][0]['taxRate'] > $taxRate) { + $taxRate = $lineItem['attributes']['price']['calculatedTaxes'][0]['taxRate']; + } + } + + $orderPriceType = 'price'; + if(in_array($order['attributes']['taxStatus'], ['net', 'tax-free'])) { + $orderPriceType = 'price_netto'; + $cart['versandkostennetto'] = $cart['versandkostenbrutto']; + unset($cart['versandkostenbrutto']); + } + + foreach ($lineItems['data'] as $lineItem) { + $productPriceType = $orderPriceType; + if(empty($lineItem['attributes']['price']['calculatedTaxes'][0]['taxRate'])){ + $productPriceType = 'price_netto'; + } + $articleId = null; + if($lineItem['attributes']['price']['unitPrice'] < 0) { + $articleId = $voucherArticleNumber; + } + elseif(isset($lineItem['attributes']['payload']['productNumber'])){ + $articleId = $lineItem['attributes']['payload']['productNumber']; + } + $product = [ + 'articleid' => $articleId, + 'name' => $lineItem['attributes']['label'], + 'quantity' => $lineItem['attributes']['quantity'], + $productPriceType => $lineItem['attributes']['price']['unitPrice'], + 'steuersatz' => $lineItem['attributes']['price']['calculatedTaxes'][0]['taxRate'], + ]; + $cart['articlelist'][] = $product; + } + + $cart['order'] = $order; + $fetchedOrders[] = [ + 'id' => $cart['auftrag'], + 'sessionid' => '', + 'logdatei' => '', + 'warenkorb' => base64_encode(serialize($cart)), + 'warenkorbjson' => base64_encode(json_encode($cart)), + ]; + $this->Shopware6Log('Ergebnis: Auftrag', $order); + $this->Shopware6Log('Ergebnis: Adresse', $addresses); + $this->Shopware6Log('Ergebnis: Positionen', $lineItems); + } + + return $fetchedOrders; + } + + /** + * @return void + */ + public function ImportDeleteAuftrag() + { + $tmp = $this->CatchRemoteCommand('data'); + $auftrag = $tmp['auftrag']; + + $this->shopwareRequest('POST', '_action/order/'.$auftrag.'/state/process'); + $this->addCustomFieldToOrder((string)$auftrag); + } + + /** + * @return void + */ + public function ImportUpdateAuftrag() + { + $tmp = $this->CatchRemoteCommand('data'); + $auftrag = $tmp['auftrag']; + $tracking = $tmp['tracking']; + + $this->shopwareRequest('POST', '_action/order/'.$auftrag.'/state/complete'); + + $deliveries = $this->shopwareRequest('GET', 'order/'.$auftrag.'/deliveries'); + $deliveryId = $deliveries['data'][0]['id']; + + if(!empty($deliveryId)){ + $this->shopwareRequest('POST', '_action/order_delivery/'.$deliveryId.'/state/ship'); + + $deliveryData = [ + 'trackingCodes' => [$tracking] + ]; + $this->shopwareRequest('PATCH', 'order-delivery/'.$deliveryId,$deliveryData); + } + + $this->sendInvoce($auftrag); + $this->addCustomFieldToOrder((string)$auftrag); + if(empty($tmp['orderId'])) { + return; + } + $this->updateStorageForOrderIntId((int)$tmp['orderId']); + } + + public function ImportStorniereAuftrag() + { + $tmp = $this->CatchRemoteCommand('data'); + $auftrag = $tmp['auftrag']; + + $this->shopwareRequest('POST', '_action/order/'.$auftrag.'/state/cancel'); + $this->addCustomFieldToOrder((string)$auftrag); + } + + /** + * @param string $extOrderId + */ + protected function sendInvoce($extOrderId) + { + $order = $this->app->DB->SelectRow( + sprintf( + "SELECT `rechnungid`, `id` FROM `auftrag` WHERE shopextid='%s'", + $extOrderId + ) + ); + $invoiceId = 0; + if (!empty($order['rechnungid'])) { + $invoiceId = $order['rechnungid']; + $sql = sprintf("SELECT projekt, belegnr FROM rechnung WHERE id='%s'", $invoiceId); + $invoiceData = $this->app->DB->SelectRow($sql); + } + if (empty($invoiceId) && !empty($order['id'])) { + $invoiceData = $this->app->DB->SelectRow( + sprintf( + "SELECT `id`, `projekt`, `belegnr` + FROM `rechnung` + WHERE `auftragid` = %d AND `status` <> 'storniert' AND `status` <> 'angelegt' + LIMIT 1", + $order['id'] + ) + ); + if (!empty($invoiceData)) { + $invoiceId = $invoiceData['id']; + } + } + + if (!empty($invoiceData['belegnr'])) { + $projekt = $invoiceData['projekt']; + if (class_exists('RechnungPDFCustom')) { + $Brief = new RechnungPDFCustom($this->app, $projekt); + } else { + $Brief = new RechnungPDF($this->app, $projekt); + } + + $Brief->GetRechnung($invoiceId); + $filePath = $Brief->displayTMP(true); + + $documentNumber = $invoiceData['belegnr']; + $invoiceDocumentData = [ + 'config' => [ + 'custom' => [ + 'invoiceNumber' => $documentNumber, + ], + 'documentComment' => 'Aus Xentral heraus erstellte Rechnung', + 'documentNumber' => $documentNumber, + ], + 'referenced_document_id' => null, + 'static' => true + ]; + + $documentData = $this->shopwareRequest('POST', '_action/order/' . $extOrderId . '/document/invoice', $invoiceDocumentData); + $documentId = $documentData['documentId']; + + $accessToken = $this->shopwareToken(); + $url = $this->ShopUrl . 'v2/_action/document/' . $documentId . '/upload?_response=true&extension=pdf&fileName=' . $documentNumber; + + $ch = curl_init(); + $setHeaders = [ + 'Content-Type:application/pdf', + 'Authorization:Bearer ' . $accessToken['token'] + ]; + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents($filePath)); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); + curl_setopt($ch, CURLOPT_HTTPHEADER, $setHeaders); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $response = json_decode(curl_exec($ch), true); + curl_close($ch); + if (!empty($response['errors'])) { + $this->Shopware6Log( + 'Fehler bei Rechnugnsübertragung für ' . $documentNumber, $response['errors'] + ); + } + } + } + + /** + * @return string + */ + public function ImportAuth() + { + $tokeninfo = $this->shopwareToken(); + + + if (!$tokeninfo['success']) { + return 'failed: ' . $tokeninfo['message']; + } + if($this->data === 'info'){ + $salesChannelsInShopware = $this->client->getAllSalesChannels(); + $salesChannelsToShow = ['subshops' => []]; + foreach ($salesChannelsInShopware['data'] as $salesChannelInShopware){ + $salesChannelsToShow['subshops'][] = [ + 'id'=>$salesChannelInShopware['id'], + 'name'=>$salesChannelInShopware['name'], + 'aktiv'=>$salesChannelInShopware['active'] + ]; + } + return $salesChannelsToShow; + } + + return 'success'; + } + + /** + * Build category tree as displayed in article info + * May be useful for setting category in the future + * but probably obsolete + * + * @param string $categoryName + * @param array $categoryTree + * + * @return array + */ + protected function appendCategoryTree($categoryName, $categoryTree = []) + { + $shopwareCategory = $this->shopwareRequest( + 'GET', + 'category?filter[category.name]=' . urlencode($categoryName) + ); + if (!isset($shopwareCategory['data'][0]['id'])) { + return $categoryTree; + } + $categoryInfo = $shopwareCategory['data'][0]['attributes']; + $categories[] = [(int)$categoryInfo['level'], $shopwareCategory['data'][0]['id']]; + $path = $categoryInfo['path']; + if (!empty($path)) { + $pathArray = explode('|', $path); + foreach ($pathArray as $nodeId) { + if ($nodeId === '') { + continue; + } + $nodeCategory = $this->shopwareRequest('GET', 'category/' . $nodeId); + if (isset($nodeCategory['data']['id'])) { + $categories[] = [(int)$nodeCategory['data']['attributes']['level'], $nodeId]; + unset($nodeCategory); + } + } + } + foreach ($categories as $category) { + $level = $category[0]; + if (!isset($categoryTree[$level])) { + $categoryTree[$level] = []; + } + if (!in_array($category, $categoryTree[$level], true)) { + $categoryTree[$level][] = $category[1]; + } + } + ksort($categoryTree); + + return $categoryTree; + } + + /** + * @param array $postData + * + * @return array + */ + public function updatePostDataForAssistent($postData) + { + if(!empty($this->ShopUrl)) { + $postData['shopwareUrl'] = $this->ShopUrl; + } + return $postData; + } + + /** + * @param array $shopArr + * @param array $postData + * + * @return array + */ + public function updateShopexportArr($shopArr, $postData) + { + $shopArr['stornoabgleich'] = 1; + $shopArr['demomodus'] = 0; + + return $shopArr; + } + + /** + * @return JsonResponse|null + */ + public function AuthByAssistent() + { + $shopwareUrl = $this->app->Secure->GetPOST('shopwareUrl'); + $shopwareUserName = $this->app->Secure->GetPOST('shopwareUserName'); + $shopwarePassword = $this->app->Secure->GetPOST('shopwarePassword'); + $step = (int)$this->app->Secure->GetPOST('step'); + + if($step <= 1){ + if(empty($shopwareUrl)){ + return new JsonResponse(['error' => 'Bitte die URL des Shops angeben.'], JsonResponse::HTTP_BAD_REQUEST); + } + if(empty($shopwareUserName)){ + return new JsonResponse(['error' => 'Bitte den Benutzernamen angeben'], JsonResponse::HTTP_BAD_REQUEST); + } + if(empty($shopwarePassword)){ + return new JsonResponse(['error' => 'Bitte das Passwort angeben'], JsonResponse::HTTP_BAD_REQUEST); + } + + $this->UserName = $shopwareUserName; + $this->Password = $shopwarePassword; + $shopwareUrl = rtrim($shopwareUrl, '/') . '/'; + $testUrls = []; + $hasNoHttp = strpos($shopwareUrl,'http') !== 0; + if(substr($shopwareUrl, -5) !== '/api/') { + if($hasNoHttp) { + $testUrls[] = 'https://'.$shopwareUrl.'api/'; + $testUrls[] = 'http://'.$shopwareUrl.'api/'; + } + $testUrls[] = $shopwareUrl.'api/'; + } + elseif($hasNoHttp) { + $testUrls[] = 'https://'.$shopwareUrl; + $testUrls[] = 'http://'.$shopwareUrl; + } + else { + $testUrls[] = $shopwareUrl; + } + foreach($testUrls as $testUrl) { + $this->ShopUrl = $testUrl; + $tokeninfo = $this->shopwareToken(); + if(!empty($tokeninfo['success'])) { + break; + } + } + + if(!$tokeninfo['success']){ + return new JsonResponse(['error' => $tokeninfo['message']], JsonResponse::HTTP_BAD_REQUEST); + } + } + + return null; + } + + /** + * @return string + */ + public function getClickByClickHeadline() + { + return 'Bitte im Shopware Backend einen eigenen Benutzer für Xentral anlegen und diese + Zugangsdaten hier eintragen.'; + } + + /** + * @return array + */ + public function getStructureDataForClickByClickSave() + { + return [ + 'shopwareAllowCreateManufacturer' => 1, + ]; + } + + /** + * @return array[] + */ + public function getCreateForm() + { + return [ + [ + 'id' => 0, + 'name' => 'urls', + 'inputs' => [ + [ + 'label' => 'URL des Shops', + 'type' => 'text', + 'name' => 'shopwareUrl', + 'validation' => true, + ], + ], + ], + [ + 'id' => 1, + 'name' => 'username', + 'inputs' => [ + [ + 'label' => 'Benutzername aus Shopware', + 'type' => 'text', + 'name' => 'shopwareUserName', + 'validation' => true, + ], + ], + ], + [ + 'id' => 2, + 'name' => 'password', + 'inputs' => [ + [ + 'label' => 'Passwort aus Shopware', + 'type' => 'password', + 'name' => 'shopwarePassword', + 'validation' => true, + ], + ], + ], + ]; + } + + public function getBoosterHeadline(): string + { + return 'Shopware 6 Business Booster App'; + } + + public function getBoosterSubHeadline(): string + { + return 'Bitte gehe auf Shopware 6 und installiere dort das Plugin Xentral Business Booster App. + Dort kann man sich dann mit ein paar Klicks mit Xentral verbinden.'; + } + + /** + * @param int $intOrderId + * + * @return array + */ + protected function getArticleShopLinks(int $intOrderId): array + { + return $this->app->DB->SelectPairs( + "SELECT DISTINCT ao.artikel, a.nummer + FROM `auftrag_position` AS `ap` + INNER JOIN `auftrag` AS `ab` ON ap.auftrag = ab.id + INNER JOIN `artikel` AS `a` ON ap.artikel = a.id + INNER JOIN `artikel_onlineshops` AS `ao` ON ab.shop = ao.shop AND a.id = ao.artikel + WHERE ab.id = {$intOrderId} AND ao.aktiv = 1" + ); + } + + /** + * @param array $articleIds + */ + protected function updateArticleCacheToSync(array $articleIds): void + { + if(empty($articleIds)) { + return; + } + $articleIdsString = implode(', ', $articleIds); + $this->app->DB->Update( + "UPDATE `artikel` + SET `laststorage_changed` = DATE_ADD(NOW(), INTERVAL 1 SECOND) + WHERE `id` IN ({$articleIdsString})" + ); + } + + /** + * @param array $articleIds + */ + protected function updateArticleOnlineShopCache(array $articleIds): void + { + if(empty($articleIds)) { + return; + } + $articleIdsString = implode(', ', $articleIds); + $this->app->DB->Update( + "UPDATE `artikel_onlineshops` + SET `storage_cache` = -999, `pseudostorage_cache` = -999 + WHERE `artikel` IN ({$articleIdsString}) AND `aktiv` = 1 AND `shop` = {$this->shopid}" + ); + } + + /** + * @param int $intOrderId + */ + protected function updateStorageForOrderIntId(int $intOrderId): void + { + $articles = $this->getArticleShopLinks($intOrderId); + if(empty($articles)) { + return; + } + $articleIds = array_keys($articles); + $this->updateArticleCacheToSync($articleIds); + $this->updateArticleOnlineShopCache($articleIds); + + $isStorageSyncCronjobActive = (int)$this->app->DB->Select( + "SELECT COUNT(`id`) FROM `prozessstarter` WHERE `aktiv` = 1 AND `parameter` = 'lagerzahlen'" + ) > 0; + if(!$isStorageSyncCronjobActive) { + return; + } + foreach($articleIds as $articleId) { + try { + $this->app->erp->LagerSync($articleId, false, [$this->shopid]); + } + catch (Exception $e) { + $articleNumber = $articles[$articleId]; + $this->Shopware6ErrorLog('LagerSync konnte nicht ausgeführt werden', $articleNumber); + } + } + + $this->updateArticleCacheToSync($articleIds); + } +}