/**
     * Does the actual import
     */
    public function import()
    {
        $row = Shopware()->Db()->fetchAll('
			SELECT *
				FROM plenty_mapping_category
				WHERE plentyID LIKE "' . $this->Category->CategoryID . ';%"
				LIMIT 1
		');
        if (!$row) {
            // PyLog()->message('Sync:Item:Category', 'Skipping the category »' . $this->Category->Name . '« (not found)');
            return;
        }
        $index = explode(PlentymarketsMappingEntityCategory::DELIMITER, $row[0]['shopwareID']);
        $categoryId = $index[0];
        /** @var Shopware\Models\Category\Category $Category */
        $Category = Shopware()->Models()->find('Shopware\\Models\\Category\\Category', $categoryId);
        // If the shopware category wasn't found, something is terribly wrong
        if (!$Category) {
            PyLog()->message('Sync:Item:Category', 'Skipping the category »' . $this->Category->Name . '« (not found)');
            return;
        }
        // Update the category only if the name's changed
        if ($Category->getName() != $this->Category->Name || $Category->getPosition() != $this->Category->Position) {
            PyLog()->message('Sync:Item:Category', 'Updating the category »' . $this->Category->Name . '«');
            $Category->setName($this->Category->Name);
            $Category->setPosition($this->Category->Position);
            Shopware()->Models()->persist($Category);
            Shopware()->Models()->flush();
        }
    }
 /**
  * generate the thumbnails
  */
 public function generate()
 {
     if (!count($this->media)) {
         return;
     }
     $manager = Shopware()->Container()->get('thumbnail_manager');
     PyLog()->message('Sync:Item:Image:Thumbnail', 'Starting to generate thumbnails for ' . count($this->media) . ' media resources');
     while ($media = array_pop($this->media)) {
         $manager->createMediaThumbnail($media, array(), true);
     }
     PyLog()->message('Sync:Item:Image:Thumbnail', 'Finished generating thumbnails');
 }
 /**
  * Does the actual import
  */
 public function import()
 {
     try {
         $SHOPWARE_id = PlentymarketsMappingController::getPropertyGroupByPlentyID($this->Group->PropertyGroupID);
         PyLog()->message('Sync:Item:Producer', 'Updating the property group »' . $this->Group->FrontendName . '«');
     } catch (PlentymarketsMappingExceptionNotExistant $E) {
         PyLog()->message('Sync:Item:Producer', 'Skipping the property group »' . $this->Group->FrontendName . '«');
         return;
     }
     /** @var Shopware\Models\Property\Group $Group */
     $Group = Shopware()->Models()->find('Shopware\\Models\\Property\\Group', $SHOPWARE_id);
     // Set the new data
     $Group->setName($this->Group->FrontendName);
     Shopware()->Models()->persist($Group);
     Shopware()->Models()->flush();
 }
 /**
  * Does the actual import
  */
 public function import()
 {
     try {
         $SHOPWARE_id = PlentymarketsMappingController::getProducerByPlentyID($this->Producer->ProducerID);
         PyLog()->message('Sync:Item:Producer', 'Updating the producer »' . $this->Producer->ProducerName . '«');
     } catch (PlentymarketsMappingExceptionNotExistant $E) {
         PyLog()->message('Sync:Item:Producer', 'Skipping the producer »' . $this->Producer->ProducerName . '«');
         return;
     }
     /** @var Shopware\Models\Article\Supplier $Supplier */
     $Supplier = Shopware()->Models()->find('Shopware\\Models\\Article\\Supplier', $SHOPWARE_id);
     // Set the new data
     $Supplier->setName($this->Producer->ProducerName);
     Shopware()->Models()->persist($Supplier);
     Shopware()->Models()->flush();
 }
 /**
  * Does the actual import
  */
 public function import()
 {
     try {
         $SHOPWARE_id = PlentymarketsMappingController::getPropertyByPlentyID($this->Option->PropertyID);
         PyLog()->message('Sync:Item:Property:Option', 'Updating the property option »' . $this->Option->PropertyFrontendName . '«');
     } catch (PlentymarketsMappingExceptionNotExistant $E) {
         PyLog()->message('Sync:Item:Property:Option', 'Skipping the property option »' . $this->Option->PropertyFrontendName . '«');
         return;
     }
     $propertyParts = explode(';', $SHOPWARE_id);
     $optionId = $propertyParts[1];
     /** @var Shopware\Models\Property\Option $Option */
     $Option = Shopware()->Models()->find('Shopware\\Models\\Property\\Option', $optionId);
     // Set the new data
     $Option->setName($this->Option->PropertyFrontendName);
     Shopware()->Models()->persist($Option);
     Shopware()->Models()->flush();
 }
 /**
  * Deletes all existing images of the item
  */
 public function purge()
 {
     /**
      * @var \Shopware\Components\Api\Resource\Media $MediaResource
      * @var \Shopware\Components\Api\Resource\Article $ArticleResource
      */
     $MediaResource = \Shopware\Components\Api\Manager::getResource('Media');
     $ArticleResource = \Shopware\Components\Api\Manager::getResource('Article');
     $article = $ArticleResource->getOne($this->SHOPWARE_itemId);
     foreach ($article['images'] as $image) {
         try {
             $MediaResource->delete($image['mediaId']);
         } catch (Exception $E) {
             PyLog()->error('Sync:Item:Image', 'The media resource with the id »' . $image['mediaId'] . '« of the item image »' . $image['description'] . '« could not be deleted (' . $E->getMessage() . ')');
         }
     }
     $ArticleResource->update($this->SHOPWARE_itemId, array('images' => array()));
 }
 /**
  * Does the actual import work
  */
 public function import()
 {
     PlentymarketsLogger::getInstance()->message('Sync:Item:Bundle', 'LastUpdate: ' . date('r', PlentymarketsConfig::getInstance()->getImportItemBundleLastUpdateTimestamp(time())));
     $numberOfBundlesUpdated = 0;
     $timestamp = PlentymarketsConfig::getInstance()->getImportItemBundleLastUpdateTimestamp(1);
     $now = time();
     // Get all bundles
     $Request_GetItemBundles = new PlentySoapRequest_GetItemBundles();
     $Request_GetItemBundles->LastUpdate = $timestamp;
     $Request_GetItemBundles->Page = 0;
     do {
         /** @var PlentySoapResponse_GetItemBundles $Response_GetItemBundles */
         $Response_GetItemBundles = PlentymarketsSoapClient::getInstance()->GetItemBundles($Request_GetItemBundles);
         $pages = max($Response_GetItemBundles->Pages, 1);
         PlentymarketsLogger::getInstance()->message('Sync:Item:Bundle', 'Page: ' . ($Request_GetItemBundles->Page + 1) . '/' . $pages);
         foreach ($Response_GetItemBundles->ItemBundles->item as $PlentySoapObject_Bundle) {
             $PlentymarketsImportEntityItemBundle = new PlentymarketsImportEntityItemBundle($PlentySoapObject_Bundle);
             try {
                 $PlentymarketsImportEntityItemBundle->import();
                 ++$numberOfBundlesUpdated;
             } catch (PlentymarketsImportException $e) {
                 PyLog()->error('Sync:Item:Bundle', $e->getMessage(), $e->getCode());
             }
         }
     } while (++$Request_GetItemBundles->Page < $Response_GetItemBundles->Pages);
     PlentymarketsConfig::getInstance()->setImportItemBundleLastUpdateTimestamp($now);
     // Log
     if ($numberOfBundlesUpdated == 0) {
         PlentymarketsLogger::getInstance()->message('Sync:Item:Bundle', 'No item bundle has been updated or created.');
     } else {
         if ($numberOfBundlesUpdated == 1) {
             PlentymarketsLogger::getInstance()->message('Sync:Item:Bundle', '1 item bundle has been updated or created.');
         } else {
             PlentymarketsLogger::getInstance()->message('Sync:Item:Bundle', $numberOfBundlesUpdated . ' item bundles have been updated or created.');
         }
     }
 }
 /**
  * Deletes all existing images of the item
  */
 public function purge()
 {
     /**
      * @var \Shopware\Components\Api\Resource\Media $MediaResource
      * @var \Shopware\Components\Api\Resource\Article $ArticleResource
      */
     $MediaResource = \Shopware\Components\Api\Manager::getResource('Media');
     $ArticleResource = \Shopware\Components\Api\Manager::getResource('Article');
     $article = $ArticleResource->getOne($this->SHOPWARE_itemId);
     foreach ($article['images'] as $image) {
         try {
             $MediaResource->delete($image['mediaId']);
         } catch (Exception $E) {
             PyLog()->error('Sync:Item:Image', 'The media resource with the id »' . $image['mediaId'] . '« of the item image »' . $image['description'] . '« could not be deleted (' . $E->getMessage() . ')');
         }
     }
     // Delete all variant image mappings of the item
     // Add the main detail
     $article['details'][] = $article['mainDetail'];
     foreach ($article['details'] as $detail) {
         Shopware()->Db()->query("DELETE FROM `s_articles_img` WHERE article_detail_id = ?", array($detail['id']));
     }
     $ArticleResource->update($this->SHOPWARE_itemId, array('images' => array()));
 }
 /**
  * Fixes the item with an empty order number
  */
 public function fixEmptyItemDetailNumberAction()
 {
     $articleRepository = Shopware()->Models()->getRepository('Shopware\\Models\\Article\\Detail');
     /** @var Shopware\Models\Article\Detail $detail */
     $detail = $articleRepository->findOneBy(array('number' => ''));
     if ($detail) {
         $number = PlentymarketsImportItemHelper::getItemNumber();
         $detail->setNumber($number);
         Shopware()->Models()->persist($detail);
         Shopware()->Models()->flush();
         PyLog()->message('Fix:Item:Detail:Number', 'The number of the item detail with the id »' . $detail->getId() . '« has been set to »' . $number . '«.');
     } else {
         PyLog()->message('Fix:Item:Detail:Number', 'No item without a number has been found');
     }
 }
 /**
  * Update the prices for a variant
  *
  * @param integer $detailId
  * @return bool
  */
 public function updateVariant($detailId)
 {
     $Detail = Shopware()->Models()->find('Shopware\\Models\\Article\\Detail', $detailId);
     if (!$Detail instanceof Shopware\Models\Article\Detail) {
         return PlentymarketsLogger::getInstance()->error('Sync:Item:Price', 'The price of the item detail with the id »' . $detailId . '« could not be updated (item corrupt)', 3610);
     }
     $currentPrice = $this->PLENTY_PriceSet->Price + $this->PLENTY_markup;
     $Article = $Detail->getArticle();
     $ArticleResource = \Shopware\Components\Api\Manager::getResource('Article');
     // Update
     $ArticleResource->update($Article->getId(), array('variants' => array(array('number' => $Detail->getNumber(), 'prices' => $this->getPrices()))));
     PyLog()->message('Sync:Item:Price', 'The price of the variant with the number »' . $Detail->getNumber() . '« has been set to »' . money_format('%.2n', $currentPrice) . '«.');
 }
 /**
  * Imports the item bundle
  *
  * @throws Exception
  */
 protected function importBundle()
 {
     // Get the bundle head
     $Request_GetItemsBase = new PlentySoapRequest_GetItemsBase();
     $Request_GetItemsBase->GetAttributeValueSets = false;
     $Request_GetItemsBase->GetCategories = false;
     $Request_GetItemsBase->GetCategoryNames = false;
     $Request_GetItemsBase->GetItemAttributeMarkup = false;
     $Request_GetItemsBase->GetItemOthers = false;
     $Request_GetItemsBase->GetItemProperties = false;
     $Request_GetItemsBase->GetItemSuppliers = false;
     $Request_GetItemsBase->GetItemURL = 0;
     $Request_GetItemsBase->GetLongDescription = false;
     $Request_GetItemsBase->GetMetaDescription = false;
     $Request_GetItemsBase->GetShortDescription = false;
     $Request_GetItemsBase->GetTechnicalData = false;
     $Request_GetItemsBase->ItemID = $this->PLENTY_bundleHeadId;
     $Request_GetItemsBase->Page = 0;
     /** @var PlentySoapResponse_GetItemsBase $Response_GetItemsBase */
     $Response_GetItemsBase = PlentymarketsSoapClient::getInstance()->GetItemsBase($Request_GetItemsBase);
     if ($Response_GetItemsBase->Success == false || !isset($Response_GetItemsBase->ItemsBase->item[0])) {
         throw new PlentymarketsImportException('The item bundle with SKU »' . $this->PLENTY_bundle->SKU . '« can not be imported (SOAP call failed).', 3701);
     }
     /** @var PlentySoapObject_ItemBase $ItemBase */
     $ItemBase = $Response_GetItemsBase->ItemsBase->item[0];
     try {
         // Get the existing bundle
         $shopwareBundleId = PlentymarketsMappingController::getItemBundleByPlentyID($this->PLENTY_bundleHeadId);
         /** @var Shopware\CustomModels\Bundle\Bundle $Bundle */
         $Bundle = Shopware()->Models()->find('Shopware\\CustomModels\\Bundle\\Bundle', $shopwareBundleId);
         $currentShopwareBundleHeadItemDetailId = $Bundle->getArticle()->getMainDetail()->getId();
         if (!isset($this->SHOPWARE_bundleItemDetailList[$currentShopwareBundleHeadItemDetailId])) {
             // If the item which is the bundle head in shopware
             // has been removed in plentymarkets, the bundle has to get a new
             // head item. If this is not possible, the bundle will be delete.
             try {
                 $mainDetail = $this->getShopwareBundleItemDetail();
                 /** @var Shopware\Models\Article\Article $Article */
                 $Article = $mainDetail->getArticle();
                 PyLog()->message('Sync:Item:Bundle', 'The item »' . $Article->getName() . '« with the number »' . $mainDetail->getNumber() . '« is now the master item of the item bundle with the number »' . $Bundle->getNumber() . '«.');
                 $Bundle->setArticle($Article);
             } catch (PlentymarketsImportException $e) {
                 PlentymarketsMappingController::deleteItemBundleByShopwareID($Bundle->getId());
                 PyLog()->message('Sync:Item:Bundle', 'The item bundle with the number »' . $Bundle->getNumber() . '« will be deleted because no item can be identified as the master item. The previous master item with the number »' . $Bundle->getArticle()->getMainDetail()->getNumber() . '« is no longer part of the item bundle.');
                 // Delete the bundle
                 Shopware()->Models()->remove($Bundle);
                 Shopware()->Models()->flush();
                 throw $e;
             }
         }
         $action = 'update';
     } catch (PlentymarketsMappingExceptionNotExistant $E) {
         $action = 'create';
         // Create a new one
         $Bundle = new Shopware\CustomModels\Bundle\Bundle();
         $mainDetail = $this->getShopwareBundleItemDetail();
         /** @var Shopware\Models\Article\Article $Article */
         $Article = $mainDetail->getArticle();
         PyLog()->message('Sync:Item:Bundle', 'The item »' . $Article->getName() . '« with the number »' . $mainDetail->getNumber() . '« will be the master item of the item bundle with the number »' . $ItemBase->ItemNo . '«.');
         // Set the stuff which needs to be set just one
         $Bundle->setArticle($Article);
         $Bundle->setType(1);
         $Bundle->setDiscountType('abs');
         $Bundle->setQuantity(0);
         $Bundle->setCreated();
         $Bundle->setSells(0);
         if (method_exists($Bundle, 'setDisplayGlobal')) {
             $Bundle->setDisplayGlobal(true);
         }
     }
     //
     $Bundle->setName($ItemBase->Texts->Name);
     $Bundle->setShowName(0);
     $Bundle->setNumber($ItemBase->ItemNo);
     $isLimited = $ItemBase->Stock->Limitation == 1;
     $Bundle->setLimited($isLimited);
     $isActive = $ItemBase->Availability->Inactive == 0 && $ItemBase->Availability->Webshop == 1;
     $Bundle->setActive($isActive);
     /**@var Shopware\Models\Customer\Group $CG */
     $CG = $this->getCustomerGroup();
     $shopwareBundleHeadItemId = $Bundle->getArticle()->getId();
     $items = array();
     foreach ($Bundle->getArticles() as $item) {
         /** @var Shopware\CustomModels\Bundle\Article $item */
         $itemDetailId = $item->getArticleDetail()->getId();
         // Not in the bundle or already done
         if (!isset($this->SHOPWARE_bundleItemDetailList[$itemDetailId])) {
             continue;
         }
         $quantity = $this->SHOPWARE_bundleItemDetailList[$itemDetailId]['quantity'];
         // If it is also the main item, the quantity needs to be reduced by one
         if ($item->getArticleDetail()->getArticle()->getId() == $shopwareBundleHeadItemId) {
             // If there is just one, the item is skipped since it is the HEAD - it will not be added as an item
             if ($quantity == 1) {
                 unset($this->SHOPWARE_bundleItemDetailList[$itemDetailId]);
                 continue;
             }
             // If the amount is higher - reduce item - the item is the HEAD and inside the bundle
             // in plenty it is just inside the bundle
             $quantity -= 1;
         }
         // Unset the detail - the rest of this array will be added as new items to the bundle
         unset($this->SHOPWARE_bundleItemDetailList[$itemDetailId]);
         // Update the quantity if changed
         if ($item->getQuantity() != $quantity) {
             $item->setQuantity($quantity);
         }
         $items[] = $item;
     }
     // Add all items, which aren't yet in the bundle
     foreach ($this->SHOPWARE_bundleItemDetailList as $config) {
         /** @var Shopware\Models\Article\Detail $detail */
         $detail = $config['detail'];
         // If the head is inside the bundle too, the amount needs to be reduced
         if ($detail->getArticle()->getId() == $shopwareBundleHeadItemId) {
             if ($config['quantity'] > 1) {
                 $config['quantity'] -= 1;
             } else {
                 if ($config['quantity'] == 1) {
                     continue;
                 }
             }
         }
         $ArticleNew = new Shopware\CustomModels\Bundle\Article();
         $ItemDetail = $detail;
         $quantity = $config['quantity'];
         $ArticleNew->setArticleDetail($ItemDetail);
         $ArticleNew->setQuantity($quantity);
         $items[] = $ArticleNew;
     }
     // Set the bundle items
     $Bundle->setArticles($items);
     $newPrice = $ItemBase->PriceSet->Price;
     $newPrice /= (100 + $ItemBase->PriceSet->VAT) / 100;
     $isPriceFound = false;
     $prices = array();
     foreach ($Bundle->getPrices() as $price) {
         /** @var Shopware\CustomModels\Bundle\Price $price */
         if ($price->getCustomerGroup()->getKey() == $CG->getKey()) {
             $price->setPrice($newPrice);
             $isPriceFound = true;
         }
         $prices[] = $price;
     }
     if (!$isPriceFound) {
         $Price = new Shopware\CustomModels\Bundle\Price();
         $Price->setBundle($Bundle);
         $Price->setCustomerGroup($CG);
         $Price->setPrice($newPrice);
         $prices[] = $Price;
         $Bundle->setPrices($prices);
     }
     $Bundle->setCustomerGroups(array($CG));
     Shopware()->Models()->persist($Bundle);
     Shopware()->Models()->flush();
     if ($action == 'create') {
         PlentymarketsMappingController::addItemBundle($Bundle->getId(), $this->PLENTY_bundleHeadId);
         PyLog()->message('Sync:Item:Bundle', 'The item bundle »' . $ItemBase->Texts->Name . '« with the number »' . $ItemBase->ItemNo . '« has been created');
     } else {
         PyLog()->message('Sync:Item:Bundle', 'The item bundle »' . $ItemBase->Texts->Name . '« with the number »' . $ItemBase->ItemNo . '« has been updated');
     }
 }
    /**
     * Deletes a page of invalid data
     *
     * @param integer $start
     * @param integer $offset
     */
    public function deleteInvalidData($start, $offset)
    {
        // Controller
        $controller = new PlentymarketsImportControllerItem();
        // StoreIds
        $stores = Shopware()->Db()->fetchAll('
			SELECT plentyID FROM plenty_mapping_shop
		');
        // Customer group
        $customerGroupKey = PlentymarketsConfig::getInstance()->getDefaultCustomerGroupKey();
        $customerGroupRepository = Shopware()->Models()->getRepository('Shopware\\Models\\Customer\\Group');
        $customerGroups = $customerGroupRepository->findBy(array('key' => $customerGroupKey));
        $customerGroup = array_pop($customerGroups);
        //
        foreach ($this->getInvalidData($start, $offset) as $data) {
            PyLog()->message('Fix:Item:Price', 'Start of fixing corrupt prices of the item id ' . $data['itemId']);
            // Search
            foreach (explode(',', $data['detailIds']) as $detailId) {
                try {
                    /** @var \Shopware\Models\Article\Detail $Detail */
                    $Detail = Shopware()->Models()->find('\\Shopware\\Models\\Article\\Detail', $detailId);
                    $price = new Shopware\Models\Article\Price();
                    $price->setFrom(1);
                    $price->setPrice(1);
                    $price->setPercent(0);
                    $price->setArticle($Detail->getArticle());
                    $price->setDetail($Detail);
                    $price->setCustomerGroup($customerGroup);
                    Shopware()->Models()->persist($price);
                } catch (Exception $E) {
                    PyLog()->debug($E->getMessage());
                }
            }
            Shopware()->Models()->flush();
            PyLog()->message('Fix:Item:Price', 'Finished with the fixing corrupt prices of the item id »' . $data['itemId'] . '«');
            try {
                foreach ($stores as $store) {
                    // Update the complete item from plenty
                    $controller->importItem(PlentymarketsMappingController::getItemByShopwareID($data['itemId']), $store['plentyID']);
                }
            } catch (Exception $e) {
                PyLog()->error('Fix:Item:Price', $e->getMessage());
            }
            // Stop after the first
            break;
        }
    }
 /**
  * imports the item for the given shop
  *
  * @param integer $itemId
  * @param integer $storeId
  * @throws PlentymarketsImportException
  */
 public function importItem($itemId, $storeId)
 {
     // Check whether the item has already been imported
     $full = !isset($this->itemIdsDone[$itemId]);
     // Build the request
     $Request_GetItemsBase = new PlentySoapRequest_GetItemsBase();
     $Request_GetItemsBase->GetAttributeValueSets = $full;
     $Request_GetItemsBase->GetCategories = true;
     $Request_GetItemsBase->GetCategoryNames = true;
     $Request_GetItemsBase->GetItemAttributeMarkup = $full;
     $Request_GetItemsBase->GetItemOthers = $full;
     //$Request_GetItemsBase->GetItemProperties = $full;
     $Request_GetItemsBase->GetItemProperties = true;
     $Request_GetItemsBase->GetItemSuppliers = false;
     $Request_GetItemsBase->GetItemURL = 0;
     $Request_GetItemsBase->GetLongDescription = $full;
     $Request_GetItemsBase->GetMetaDescription = false;
     $Request_GetItemsBase->GetShortDescription = $full;
     $Request_GetItemsBase->GetTechnicalData = false;
     $Request_GetItemsBase->StoreID = $storeId;
     $Request_GetItemsBase->ItemID = $itemId;
     // get the main language of the shop
     //$mainLang = array_values(PlentymarketsTranslation::getInstance()->getShopMainLanguage(PlentymarketsMappingController::getShopByPlentyID($storeId)));
     // set the main language of the shop in soap request
     //$Request_GetItemsBase->Lang = PlentymarketsTranslation::getInstance()->getPlentyLocaleFormat($mainLang[0]['locale']);
     $Request_GetItemsBase->Lang = 'de';
     // Do the request
     $Response_GetItemsBase = PlentymarketsSoapClient::getInstance()->GetItemsBase($Request_GetItemsBase);
     // On error
     if ($Response_GetItemsBase->Success == false) {
         // Re-add the item to the stack and quit
         PlentymarketsImportStackItem::getInstance()->addItem($itemId, $storeId);
         return;
     }
     // Item not found
     if (!isset($Response_GetItemsBase->ItemsBase->item[0])) {
         return;
     }
     //
     $ItemBase = $Response_GetItemsBase->ItemsBase->item[0];
     // Skip bundles
     if ($ItemBase->BundleType == 'bundle' && PlentymarketsConfig::getInstance()->getItemBundleHeadActionID(IMPORT_ITEM_BUNDLE_HEAD_NO) == IMPORT_ITEM_BUNDLE_HEAD_NO) {
         PlentymarketsLogger::getInstance()->message('Sync:Item', 'The item »' . $ItemBase->Texts->Name . '« will be skipped (bundle)');
         return;
     }
     // get the item texts in all active languages
     $itemTexts = array();
     $shopId = PlentymarketsMappingController::getShopByPlentyID($storeId);
     //if this is a main shop , get the item texts translation for its main language and its shop languages
     if (PlentymarketsTranslation::isMainShop($shopId)) {
         // get all active languages of the shop (from shopware)
         $activeLanguages = PlentymarketsTranslation::getShopActiveLanguages($shopId);
         foreach ($activeLanguages as $localeId => $language) {
             $Request_GetItemsTexts = new PlentySoapRequest_GetItemsTexts();
             $Request_GetItemsTexts->ItemsList = array();
             $Object_RequestItems = new PlentySoapObject_RequestItems();
             $Object_RequestItems->ExternalItemNumer = null;
             // string
             $Object_RequestItems->ItemId = $itemId;
             // string
             $Object_RequestItems->ItemNumber = null;
             // string
             $Object_RequestItems->Lang = PlentymarketsTranslation::getPlentyLocaleFormat($language['locale']);
             // string
             $Request_GetItemsTexts->ItemsList[] = $Object_RequestItems;
             $Response_GetItemsTexts = PlentymarketsSoapClient::getInstance()->GetItemsTexts($Request_GetItemsTexts);
             if (isset($Response_GetItemsTexts->ItemTexts->item[0])) {
                 $itemText = array();
                 // save the language infos for the item texts
                 $itemText['locale'] = $language['locale'];
                 // if mainShopId == null, then it is the main shop and no language shop
                 // each language shop has a mainShopId
                 if (!is_null($language['mainShopId'])) {
                     $itemText['languageShopId'] = PlentymarketsTranslation::getLanguageShopID($localeId, $language['mainShopId']);
                 } elseif (PlentymarketsTranslation::getPlentyLocaleFormat($language['locale']) != 'de') {
                     // set the language for the main shop if the main language is not German
                     $itemText['languageShopId'] = $shopId;
                 }
                 $itemText['texts'] = $Response_GetItemsTexts->ItemTexts->item[0];
                 $itemTexts[] = $itemText;
             }
         }
     }
     try {
         $shopId = PlentymarketsMappingController::getShopByPlentyID($storeId);
         $Shop = Shopware()->Models()->find('Shopware\\Models\\Shop\\Shop', $shopId);
         $Importuer = new PlentymarketsImportEntityItem($ItemBase, $Shop);
         // The item has already been updated
         if (!$full) {
             // so we just need to do the categories
             $Importuer->importCategories();
             //if this is a main shop , import the translation for its main language and its shop languages
             if (PlentymarketsTranslation::isMainShop($shopId)) {
                 if (!empty($itemTexts)) {
                     // Do the import for item texts translation
                     $Importuer->saveItemTextsTranslation($itemTexts);
                 }
                 // Do the import for the property value translations
                 $Importuer->importItemPropertyValueTranslations();
             }
         } else {
             // Do a full import
             $Importuer->import();
             //if this is a main shop , import the translation for its main language and its shop languages
             if (PlentymarketsTranslation::isMainShop($shopId)) {
                 if (!empty($itemTexts)) {
                     // Do the import for item texts translation
                     $Importuer->saveItemTextsTranslation($itemTexts);
                 }
                 // Do the import for the property value translations
                 $Importuer->importItemPropertyValueTranslations();
             }
             // Add it to the link controller
             PlentymarketsImportControllerItemLinked::getInstance()->addItem($ItemBase->ItemID);
             // Mark this item as done
             $this->itemIdsDone[$ItemBase->ItemID] = true;
         }
         // Log the usage data
         PyLog()->usage();
     } catch (Shopware\Components\Api\Exception\ValidationException $E) {
         PlentymarketsLogger::getInstance()->error('Sync:Item:Validation', 'The item »' . $ItemBase->Texts->Name . '« with the id »' . $ItemBase->ItemID . '« could not be imported', 3010);
         foreach ($E->getViolations() as $ConstraintViolation) {
             PlentymarketsLogger::getInstance()->error('Sync:Item:Validation', $ConstraintViolation->getMessage());
             PlentymarketsLogger::getInstance()->error('Sync:Item:Validation', $ConstraintViolation->getPropertyPath() . ': ' . $ConstraintViolation->getInvalidValue());
         }
     } catch (Shopware\Components\Api\Exception\OrmException $E) {
         PlentymarketsLogger::getInstance()->error('Sync:Item:Orm', 'The item »' . $ItemBase->Texts->Name . '« with the id »' . $ItemBase->ItemID . '« could not be imported (' . $E->getMessage() . ')', 3020);
         PlentymarketsLogger::getInstance()->error('Sync:Item:Orm', $E->getTraceAsString(), 1000);
         throw new PlentymarketsImportException('The item import will be stopped (internal database error)', 3021);
     } catch (PlentymarketsImportItemNumberException $E) {
         PlentymarketsLogger::getInstance()->error('Sync:Item:Number', $E->getMessage(), $E->getCode());
     } catch (PlentymarketsImportItemException $E) {
         PlentymarketsLogger::getInstance()->error('Sync:Item:Number', $E->getMessage(), $E->getCode());
     } catch (Exception $E) {
         PlentymarketsLogger::getInstance()->error('Sync:Item', 'The item »' . $ItemBase->Texts->Name . '« with the id »' . $ItemBase->ItemID . '« could not be imported', 3000);
         PlentymarketsLogger::getInstance()->error('Sync:Item', $E->getTraceAsString(), 1000);
         PlentymarketsLogger::getInstance()->error('Sync:Item', get_class($E));
         PlentymarketsLogger::getInstance()->error('Sync:Item', $E->getMessage());
     }
 }
 /**
  * Returns the klarna transaction id.
  *
  * @return string
  */
 protected function getKlarnaTransactionId()
 {
     $orderNumber = $this->order['number'];
     try {
         if ($this->pluginExists('PigmbhKlarnaPayment')) {
             // eid / shop_id
             $sql = 'SELECT shop_id FROM Pi_klarna_payment_multistore WHERE order_number = ?';
             $multistore = Shopware()->Db()->query($sql, array($orderNumber))->fetchObject();
             // pclass
             $sql = 'SELECT pclassid FROM Pi_klarna_payment_pclass where ordernumber = ?';
             $pclass = Shopware()->Db()->query($sql, array($orderNumber))->fetchObject();
             // Transaction ID
             $sql = 'SELECT transactionid FROM Pi_klarna_payment_order_data WHERE order_number = ?';
             $order = Shopware()->Db()->query($sql, array($orderNumber))->fetchObject();
             return sprintf('%s_%s_%s', $order->transactionid, $pclass->pclassid, $multistore->shop_id);
         } elseif ($this->pluginExists('SwagPaymentKlarna') || $this->pluginExists('SwagPaymentKlarnaKpm')) {
             /*
              * @var Klarna $klarna
              */
             $this->klarnaService = Shopware()->Container()->get('KlarnaService');
             if (!empty($this->order['languageIso'])) {
                 $this->klarnaService->setLanguage($this->order['languageIso']);
             } else {
                 throw new Exception('order language missing');
             }
             if (!empty($this->order['billing']['country']['iso'])) {
                 $this->klarnaService->setCountry($this->order['billing']['country']['iso']);
             } else {
                 throw new Exception('order country missing');
             }
             if (!empty($this->order['currency'])) {
                 $this->klarnaService->setCurrency($this->order['currency']);
             } else {
                 throw new Exception('order currency missing');
             }
             /**
              * @var KlarnaPClass
              */
             $pclass = $this->getKlarnaPClass();
             if (!empty($pclass)) {
                 if (isset($this->order['payment']['name']) && $this->order['payment']['name'] == 'klarna_invoice') {
                     $classId = KlarnaPClass::INVOICE;
                 } else {
                     $classId = $pclass->getId();
                 }
                 return sprintf('%s_%s_%s', $this->order['transactionId'], $classId, $pclass->getEid());
             } else {
                 throw new Exception('No compatible pclass found');
             }
         } else {
             throw new Exception('No compatible Klarna payment plugin found');
         }
     } catch (Exception $e) {
         PyLog()->error('Sync:Order:PaymentKlarna', $e->getMessage());
     }
     return '';
 }
    /**
     * Prunes the item bundles
     */
    protected function pruneItemBundles()
    {
        // Register the modules
        PlentymarketsUtils::registerBundleModules();
        // Create a temporary table
        Shopware()->Db()->exec('
			CREATE TEMPORARY TABLE IF NOT EXISTS plenty_cleanup_item_bundle
				(bundleId INT UNSIGNED, INDEX (bundleId))
				ENGINE = MEMORY;
		');
        // Get all bundles - regardless of store ids
        $Request_GetItemBundles = new PlentySoapRequest_GetItemBundles();
        $Request_GetItemBundles->LastUpdate = 0;
        $Request_GetItemBundles->Page = 0;
        do {
            /** @var PlentySoapResponse_GetItemBundles $Response_GetItemsBase */
            $Response_GetItemBundles = PlentymarketsSoapClient::getInstance()->GetItemBundles($Request_GetItemBundles);
            // Call failed
            if (is_null($Response_GetItemBundles) || !property_exists($Response_GetItemBundles, 'ItemBundles')) {
                // Log
                PlentymarketsLogger::getInstance()->error('Cleanup:Item:Bundle', 'Aborting. GetItemBundles apparently failed');
                // Delete the temporary table
                Shopware()->Db()->exec('
					DROP TEMPORARY TABLE plenty_cleanup_item_bundle
				');
                return;
            }
            $bundleIds = array();
            // Collect the bundle head ids
            foreach ($Response_GetItemBundles->ItemBundles->item as $bundle) {
                /** @var PlentySoapObject_Bundle $bundle */
                $plentyBundleHeadSku = explode('-', $bundle->SKU);
                $plentyBundleHeadId = (int) $plentyBundleHeadSku[0];
                $bundleIds[] = $plentyBundleHeadId;
            }
            if (empty($bundleIds)) {
                break;
            }
            // Build the sql statement
            $bundleIdsSql = implode(', ', array_map(function ($itemId) {
                return sprintf('(%u)', $itemId);
            }, $bundleIds));
            // Fill the table
            Shopware()->Db()->exec('
				INSERT IGNORE INTO plenty_cleanup_item_bundle VALUES ' . $bundleIdsSql . '
			');
        } while (++$Request_GetItemBundles->Page < $Response_GetItemBundles->Pages);
        // Get all shopware bundles which are no longer in plentymarkets
        $bundles = Shopware()->Db()->fetchAll('
			SELECT
					id
				FROM s_articles_bundles
				WHERE
					id NOT IN (
						SELECT pmi.shopwareID
							FROM plenty_cleanup_item_bundle pci
							LEFT JOIN plenty_mapping_item_bundle pmi ON pmi.plentyID = pci.bundleId
							WHERE pmi.shopwareID IS NOT NULL
					)
		');
        // And delete them
        foreach ($bundles as $bundle) {
            /** @var Shopware\CustomModels\Bundle\Bundle $bundle */
            $bundle = Shopware()->Models()->find('Shopware\\CustomModels\\Bundle\\Bundle', $bundle['id']);
            Shopware()->Models()->remove($bundle);
            // Log
            PyLog()->message('Cleanup:Item:Bundle', 'The item bundle »' . $bundle->getName() . '« with the number »' . $bundle->getNumber() . '« has been deleted');
        }
        Shopware()->Models()->flush();
        Shopware()->Db()->delete('plenty_mapping_item_bundle', 'shopwareID NOT IN (SELECT id FROM s_articles_bundles)');
    }
 /**
  * Performes a SOAP call
  *
  * @see SoapClient::__call()
  */
 public function __call($call, $args)
 {
     $retries = 0;
     do {
         try {
             $headers = $this->__getLastResponseHeaders();
             if ($headers) {
                 preg_match('/X-Plenty-Soap-Calls-Left: (-?\\d+)/', $headers, $matches);
                 $callsLeft = isset($matches[1]) ? (int) $matches[1] : -1;
                 preg_match('/X-Plenty-Soap-Seconds-Left: (-?\\d+)/', $headers, $matches);
                 $secondsLeft = isset($matches[1]) ? (int) $matches[1] : -1;
                 if (!($callsLeft % 50)) {
                     PyLog()->message('Soap:CallLimit', sprintf('Soap-Calls-Left: %d – Soap-Seconds-Left: %d', $callsLeft, $secondsLeft));
                 }
                 // check if the limit of the soap calls is already reached
                 if ($callsLeft != -1 && $callsLeft <= 10) {
                     $sleep = $secondsLeft + 5;
                     PyLog()->message('Soap:CallLimit', sprintf('Soap call limit reached. Waiting %d seconds.', $sleep));
                     sleep($sleep);
                     PyLog()->message('Soap:CallLimit', sprintf('Waited %d seconds.', $sleep));
                 }
             }
             // Call
             $Response = $this->doCall($call, $args);
             // Quit the loop on success
             break;
         } catch (Exception $E) {
             ++$retries;
             // Calculate seconds based on the number of retries
             $seconds = self::NUMBER_OF_SECONDS_SLEEP * $retries;
             // Try to get a new token
             if ($E->getMessage() == 'Unauthorized Request - Invalid Token') {
                 // Log the error
                 PlentymarketsLogger::getInstance()->error('Soap:Call', $call . ' failed: Unauthorized Request - Invalid Token', 1110);
                 // Refresh the token
                 $this->getToken();
                 $this->setSoapHeaders();
             } else {
                 PlentymarketsLogger::getInstance()->message('Soap:Call', $call . ' will wait ' . $seconds . ' seconds and then try again (' . $retries . '/' . self::NUMBER_OF_RETRIES_MAX . ')');
                 sleep($seconds);
             }
         }
     } while ($retries < self::NUMBER_OF_RETRIES_MAX);
     // Log the call's success state
     if (isset($Response->Success) && $Response->Success == true) {
         if ($call == 'GetServerTime') {
             if (!$this->Config->getApiIgnoreGetServerTime()) {
                 PlentymarketsLogger::getInstance()->message('Soap:Call', 'GetServerTime success');
             }
         } else {
             PlentymarketsLogger::getInstance()->message('Soap:Call', $call . ' success');
         }
         // Remember the timestamp
         if (!empty($this->timestampConfigKey)) {
             $this->Config->set($this->timestampConfigKey, time());
         }
     } else {
         PlentymarketsLogger::getInstance()->error('Soap:Call', $call . ' failed', 1100);
         if (isset($Response) && $this->Config->getApiLogHttpHeaders(false)) {
             PlentymarketsLogger::getInstance()->error('Soap:Call', var_export($Response, true));
         }
         if (isset($E) && $E instanceof Exception) {
             PlentymarketsLogger::getInstance()->error('Soap:Call:Request', htmlspecialchars($this->__getLastRequest()));
             PlentymarketsLogger::getInstance()->error('Soap:Call', $E->getMessage());
         }
     }
     // Log the HTTP headers?
     if ($this->Config->getApiLogHttpHeaders(false)) {
         PlentymarketsLogger::getInstance()->message('Soap:Call:Header:Request', $this->__getLastRequestHeaders());
         PlentymarketsLogger::getInstance()->message('Soap:Call:Header:Response', $this->__getLastResponseHeaders());
     }
     // Remember the timestamp for soap calls number of any kind
     if (!empty($this->soapCallsTimestampConfigKey)) {
         $this->Config->set($this->soapCallsTimestampConfigKey, time());
     }
     ++$this->numberOfCalls;
     return $Response;
 }
 /**
  * Runs the import of an expicit entity
  */
 protected function runEntity($entity)
 {
     $timestamp = time();
     PyConf()->set(sprintf('ImportItem%sLastRunTimestamp', $entity), time());
     PyConf()->set(sprintf('ImportItem%sNextRunTimestamp', $entity), time() + $this->cronJobInterval);
     if (PyStatus()->maySynchronize()) {
         PyLog()->message('Sync:Item:' . $entity, 'Starting');
         try {
             $controller = sprintf('PlentymarketsImportControllerItem%s', $entity);
             $Controller = new $controller();
             $Controller->run((int) PyConf()->get(sprintf('ImportItem%sLastUpdateTimestamp', $entity)));
             PyConf()->set(sprintf('ImportItem%sStatus', $entity), 1);
             PyConf()->set(sprintf('ImportItem%sLastUpdateTimestamp', $entity), $timestamp);
             PyConf()->erase(sprintf('ImportItem%sError', $entity));
         } catch (PlentymarketsImportException $E) {
             PyConf()->set(sprintf('ImportItem%sStatus', $entity), 2);
             PyConf()->set(sprintf('ImportItem%sError', $entity), $E->getMessage());
         }
         PyLog()->message('Sync:Item:' . $entity, 'Finished');
     } else {
         PyConf()->set(sprintf('ImportItem%sStatus', $entity), 0);
     }
     PyConf()->setImportItemAssociateLastEnity($entity);
 }
 /**
  * Returns the customer class id
  *
  * @return integer|null
  */
 protected function getCustomerClassId()
 {
     try {
         return PlentymarketsMappingController::getCustomerClassByShopwareID($this->Customer->getGroup()->getId());
     } catch (Exception $E) {
         PyLog()->debug($E->getMessage());
         return null;
     }
 }
 /**
  * Imports the attribtue
  */
 protected function importAttribute()
 {
     try {
         $SHOPWARE_attributeId = PlentymarketsMappingController::getAttributeGroupByPlentyID($this->Attribute->Id);
         PyLog()->message('Sync:Item:Attribute', 'Updating the attribute »' . $this->Attribute->FrontendName . '«');
     } catch (PlentymarketsMappingExceptionNotExistant $E) {
         PyLog()->message('Sync:Item:Attribute', 'Skipping the attribute »' . $this->Attribute->FrontendName . '«');
         return;
     }
     /** @var Shopware\Models\Article\Configurator\Group $Group */
     $Group = Shopware()->Models()->find('Shopware\\Models\\Article\\Configurator\\Group', $SHOPWARE_attributeId);
     // Set the new data
     if (!is_null($this->Attribute->FrontendName)) {
         $Group->setName($this->Attribute->FrontendName);
     } elseif (!is_null($this->Attribute->BackendName)) {
         // use backend-name if frontend-name doesn't exists
         $Group->setName($this->Attribute->BackendName);
     } else {
         PyLog()->message('Sync:Item:Attribute', 'No valid name for the attribute with id »' . $this->Attribute->Id . '«');
         return;
     }
     $Group->setPosition($this->Attribute->Position);
     $this->Group = $Group;
 }