From e9a1a2eef41a6a293992117e825e3e9909257766 Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Wed, 29 May 2019 12:58:42 +0000 Subject: [PATCH 01/10] Merged PR 13934: Update README.md The link to the Dotdigital documentation for the extension has been updated, as well as providing additional information for enabling symlinks since the option was removed from the admin panel in core. --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 37af23af7..65933371b 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Engagement Cloud for Magento ========================================== -Full support documentation and setup guides available here - https://support.dotmailer.com/hc/en-gb/categories/202610368-Magento +Full support documentation and setup guides available here - https://support.dotdigital.com/hc/en-gb/sections/360000722920-Engagement-Cloud-for-Magento This module uses modman @@ -17,6 +17,14 @@ modman clone https://github.com/dotmailer/dotmailer-magento-extension.git Don't forget to enable symlinks in: `System->Configuration->Advanced->Developer->Template Settings` +Note: Following patch SUPEE-9767 (https://magento.com/security/patches/supee-9767) enabling symlinks via the admin panel is no longer supported. This can be done by running the following SQL query: + +``` +INSERT INTO `core_config_data` (`scope`, `scope_id`, `path`, `value`) + VALUES ('default', '0', 'dev/template/allow_symlink', '1') + ON DUPLICATE KEY UPDATE `value` = '1' +``` + Facts ----- - community & enterprise version. From 5d9d8fff407ec57348666d839460dfe58f02e143 Mon Sep 17 00:00:00 2001 From: Fanis Strezos Date: Wed, 29 May 2019 13:05:16 +0000 Subject: [PATCH 02/10] Merged PR 13887: Review Module is decoupled from contactSync cron and deprecated function removed **How to Test** - Remove or deactivate the Mage_Review Module. - Register a new contact in Mage instance - Run manually contact sync. You ll get a 500 error. - Run `ddg_automation_customer_subscriber_guest_sync` status will stuck to running for a long time till gets to success, and then check your apache logs for errors **Important** - Check carefully all the crons if succeeds with the right result. AND make sure that there is not everywhere else a hard dependency with Mage_Review Module **What added** - Added a new check condition in contactSync functionallity **What Removed** - Removed a deprecated function called `getReviewCounts()` Related work items: #89409 --- .../Email/Model/Apiconnector/Customer.php | 14 +++++--------- .../Email/Model/Resource/Review.php | 2 +- code/Dotdigitalgroup/Email/Model/Review.php | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/code/Dotdigitalgroup/Email/Model/Apiconnector/Customer.php b/code/Dotdigitalgroup/Email/Model/Apiconnector/Customer.php index 6e8224284..5b61b30f3 100755 --- a/code/Dotdigitalgroup/Email/Model/Apiconnector/Customer.php +++ b/code/Dotdigitalgroup/Email/Model/Apiconnector/Customer.php @@ -129,6 +129,10 @@ public function setCustomerData(Mage_Customer_Model_Customer $customer) */ public function setReviewCollection() { + if(!Mage::helper('ddg/moduleChecker')->isReviewModuleAvailable()) { + return; + } + $customerId = $this->object->getId(); $collection = Mage::getModel('review/review')->getCollection() ->addCustomerFilter($customerId) @@ -136,15 +140,7 @@ public function setReviewCollection() $this->reviewCollection = $collection; } - - /** - * @return mixed - */ - public function getReviewCount() - { - return $this->reviewCollection->getSize(); - } - + /** * @return string */ diff --git a/code/Dotdigitalgroup/Email/Model/Resource/Review.php b/code/Dotdigitalgroup/Email/Model/Resource/Review.php index 1154f3a65..5c85606a1 100755 --- a/code/Dotdigitalgroup/Email/Model/Resource/Review.php +++ b/code/Dotdigitalgroup/Email/Model/Resource/Review.php @@ -75,7 +75,7 @@ public function setImported($ids) */ public function populateEmailReviewTable($batchSize) { - if (!Mage::helper('ddg/modulechecker')->isReviewModuleAvailable()) { + if (!Mage::helper('ddg/moduleChecker')->isReviewModuleAvailable()) { return null; } $reviewCollection = Mage::getResourceModel('review/review_collection') diff --git a/code/Dotdigitalgroup/Email/Model/Review.php b/code/Dotdigitalgroup/Email/Model/Review.php index 9f75da184..60faf5845 100755 --- a/code/Dotdigitalgroup/Email/Model/Review.php +++ b/code/Dotdigitalgroup/Email/Model/Review.php @@ -52,7 +52,7 @@ protected function _beforeSave() */ public function sync() { - if(!Mage::helper('ddg/modulechecker')->isReviewModuleAvailable()) { + if(!Mage::helper('ddg/moduleChecker')->isReviewModuleAvailable()) { return array('success' => false, 'message' => 'Review is disabled'); } From 003f6cd9ec0667045ec12b26275b0064214c8b49 Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Mon, 3 Jun 2019 14:37:57 +0000 Subject: [PATCH 03/10] Merged PR 14001: Remove repeated method and move into a trait The Basket and Edc block classes both had a method `getProductImage()` which duplicated code in each. This has been moved into a trait for code cleanliness. **To test:** - Ensure EDC templates still have visible images --- code/Dotdigitalgroup/Email/Block/Basket.php | 24 +++-------------- code/Dotdigitalgroup/Email/Block/Edc.php | 24 +++-------------- .../Email/Block/ProductImageTrait.php | 27 +++++++++++++++++++ 3 files changed, 33 insertions(+), 42 deletions(-) create mode 100644 code/Dotdigitalgroup/Email/Block/ProductImageTrait.php diff --git a/code/Dotdigitalgroup/Email/Block/Basket.php b/code/Dotdigitalgroup/Email/Block/Basket.php index a2ef4952a..542714edd 100755 --- a/code/Dotdigitalgroup/Email/Block/Basket.php +++ b/code/Dotdigitalgroup/Email/Block/Basket.php @@ -1,7 +1,10 @@ getWebsiteConfig(Dotdigitalgroup_Email_Helper_Config::XML_PATH_CONNECTOR_DYNAMIC_PRODUCT_IMAGE) - && $product->getTypeId() == "simple" - ) { - $parentIds = Mage::getModel('catalog/product_type_configurable')->getParentIdsByChild($product->getId()); - if (!empty($parentIds)) { - /** @var Mage_Catalog_Model_Product $parentProduct */ - $parentProduct = Mage::getModel('catalog/product')->load($parentIds[0]); - return $this->helper('catalog/image')->init($parentProduct, 'small_image')->resize(85); - } - } - - return $this->helper('catalog/image')->init($product, 'small_image')->resize(85); - } - /** * @param $product * @param string $code diff --git a/code/Dotdigitalgroup/Email/Block/Edc.php b/code/Dotdigitalgroup/Email/Block/Edc.php index 6e0ee430e..a2d565ee0 100755 --- a/code/Dotdigitalgroup/Email/Block/Edc.php +++ b/code/Dotdigitalgroup/Email/Block/Edc.php @@ -1,7 +1,10 @@ getWebsiteConfig(Dotdigitalgroup_Email_Helper_Config::XML_PATH_CONNECTOR_DYNAMIC_PRODUCT_IMAGE) - && $product->getTypeId() == "simple" - ) { - $parentIds = Mage::getModel('catalog/product_type_configurable')->getParentIdsByChild($product->getId()); - if (!empty($parentIds)) { - /** @var Mage_Catalog_Model_Product $parentProduct */ - $parentProduct = Mage::getModel('catalog/product')->load($parentIds[0]); - return $this->helper('catalog/image')->init($parentProduct, 'small_image')->resize(135); - } - } - - return $this->helper('catalog/image')->init($product, 'small_image')->resize(135); - } } \ No newline at end of file diff --git a/code/Dotdigitalgroup/Email/Block/ProductImageTrait.php b/code/Dotdigitalgroup/Email/Block/ProductImageTrait.php new file mode 100644 index 000000000..da0e72c7d --- /dev/null +++ b/code/Dotdigitalgroup/Email/Block/ProductImageTrait.php @@ -0,0 +1,27 @@ +getWebsiteConfig(Dotdigitalgroup_Email_Helper_Config::XML_PATH_CONNECTOR_DYNAMIC_PRODUCT_IMAGE) + && $product->getTypeId() == "simple" + ) { + $parentIds = Mage::getModel('catalog/product_type_configurable')->getParentIdsByChild($product->getId()); + if (!empty($parentIds)) { + /** @var Mage_Catalog_Model_Product $parentProduct */ + $parentProduct = Mage::getModel('catalog/product')->load($parentIds[0]); + return $this->helper('catalog/image')->init($parentProduct, 'small_image')->resize(135); + } + } + + return $this->helper('catalog/image')->init($product, 'small_image')->resize(135); + } +} \ No newline at end of file From 1e9fc37799d896ca6977660c712da055f189f67b Mon Sep 17 00:00:00 2001 From: Fanis Strezos Date: Mon, 3 Jun 2019 14:58:17 +0000 Subject: [PATCH 04/10] Merged PR 13940: Take the right values per Website At the moment although when we syncing in Store Level we get The Default Values for all the products in EC. **How to test** Create a Website with a multiple views. Then assign a product to this website and set different values (for this product) for each store view. Make sure that the correct values are being syncing in EC Related work items: #87937 --- code/Dotdigitalgroup/Email/Model/Catalog.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/Dotdigitalgroup/Email/Model/Catalog.php b/code/Dotdigitalgroup/Email/Model/Catalog.php index 1d6d688c0..bfe9325a7 100755 --- a/code/Dotdigitalgroup/Email/Model/Catalog.php +++ b/code/Dotdigitalgroup/Email/Model/Catalog.php @@ -199,7 +199,6 @@ protected function _exportCatalog($storeId) ); foreach ($productCollection as $product) { - $product->setStoreId($storeId); $connectorProduct = Mage::getModel('ddg_automation/connector_product', $product); $connectorProducts[] = $connectorProduct; } @@ -224,7 +223,6 @@ protected function _exportInSingle($storeId, $collectionName, $websiteId) $products = $this->_getProductsToExport($storeId, true); if ($products) { foreach ($products as $product) { - $product->setStoreId($storeId); $connectorProduct = Mage::getModel( 'ddg_automation/connector_product', $product ); @@ -285,7 +283,8 @@ protected function _getProductsToExport($store, $modified = false) ->addAttributeToFilter('entity_id', array('in' => $productIds)) ->addCategoryIds() ->addOptionsToResult() - ->addUrlRewrite(); + ->addUrlRewrite() + ->setStoreId($store); //visibility filter if ($visibility = Mage::getStoreConfig( From c6767710b3cfac555605d2e5ea3bd261c388ec61 Mon Sep 17 00:00:00 2001 From: Fanis Strezos Date: Tue, 4 Jun 2019 09:33:27 +0000 Subject: [PATCH 05/10] Merged PR 13902: Custom Product Attributes are syncing now in catalog_sync Till now we don't sync custom product attributes via catalog sync. We do it also only for order sync. So this PR syncs custom attributes via catalog_sync too. **How to test** - Create a new Custom attribute. _Catalog >Attributes >Manage Attribute_ - Assign this attribute to Products _Catalog >Attributes >Manage Attribute Sets then Click on Default in the grid list and then drag and drop the newly created attribute to General_ - Use this Attribute _Now Go to Catalog > Manage Products Click one of the Products and then you will see a new created field with the attribute you set before_ - Include this Attribute to Syncer _Go to Engagement Cloud > Configuration Transactional > Data Include Products Attributes In Order Sync and include the new attribute to Syncer_ - Sync this Product _Now Sync this product via catalog Sync. You Should be able to see this value now on EC on `attributes` field._ - Sync this order _Complete a purchase of this product. You should be able to see the custom attribute in order as well_ **What added** - New Class Created to store the common function between Orders and Products Class - Product Class Refactored - Custom attribute for syncing selection is now available per website **What Changed** - Custom attributes Schema _Custom Attributes now instead of being an array, are returned as an object this time_ Related work items: #89323 --- code/Dotdigitalgroup/Email/Model/Catalog.php | 1 - .../Email/Model/Connector/Order.php | 178 ++--- .../Email/Model/Connector/Product.php | 684 ++++++++---------- .../Model/Connector/Productattributes.php | 121 ++++ code/Dotdigitalgroup/Email/etc/system.xml | 6 +- 5 files changed, 509 insertions(+), 481 deletions(-) create mode 100644 code/Dotdigitalgroup/Email/Model/Connector/Productattributes.php diff --git a/code/Dotdigitalgroup/Email/Model/Catalog.php b/code/Dotdigitalgroup/Email/Model/Catalog.php index bfe9325a7..cd1c5d0bb 100755 --- a/code/Dotdigitalgroup/Email/Model/Catalog.php +++ b/code/Dotdigitalgroup/Email/Model/Catalog.php @@ -226,7 +226,6 @@ protected function _exportInSingle($storeId, $collectionName, $websiteId) $connectorProduct = Mage::getModel( 'ddg_automation/connector_product', $product ); - //register in queue with importer $check = Mage::getModel('ddg_automation/importer') ->registerQueue( diff --git a/code/Dotdigitalgroup/Email/Model/Connector/Order.php b/code/Dotdigitalgroup/Email/Model/Connector/Order.php index 8003d009c..5c2c10817 100755 --- a/code/Dotdigitalgroup/Email/Model/Connector/Order.php +++ b/code/Dotdigitalgroup/Email/Model/Connector/Order.php @@ -89,8 +89,11 @@ class Dotdigitalgroup_Email_Model_Connector_Order */ public $order_status; + /** + * @var string + */ protected $_attributeSet; - + /** * set the order information * @@ -104,13 +107,17 @@ public function setOrderData(Mage_Sales_Model_Order $orderData) $this->store_name = $orderData->getStoreName(2); $created_at = new Zend_Date( - $orderData->getCreatedAt(), Zend_Date::ISO_8601 + $orderData->getCreatedAt(), + Zend_Date::ISO_8601 ); $this->purchase_date = $created_at->toString(Zend_Date::ISO_8601); $this->delivery_method = $orderData->getShippingDescription(); $this->delivery_total = (float)number_format( - $orderData->getShippingAmount(), 2, '.', '' + $orderData->getShippingAmount(), + 2, + '.', + '' ); $this->currency = $orderData->getStoreCurrencyCode(); @@ -119,10 +126,10 @@ public function setOrderData(Mage_Sales_Model_Order $orderData) * and payment method instance exist in magento */ $payment = $orderData->getPayment(); - if($payment) { - if($payment->getMethod()) { + if ($payment) { + if ($payment->getMethod()) { $instance = Mage::helper('payment')->getMethodInstance($payment->getMethod()); - if($instance) { + if ($instance) { $this->payment = $payment->getMethodInstance()->getTitle(); } } @@ -140,10 +147,16 @@ public function setOrderData(Mage_Sales_Model_Order $orderData) $this->_setOrderItems($orderData); //sales data $this->order_subtotal = (float)number_format( - $orderData->getData('subtotal'), 2, '.', '' + $orderData->getData('subtotal'), + 2, + '.', + '' ); $this->discount_ammount = (float)number_format( - $orderData->getData('discount_amount'), 2, '.', '' + $orderData->getData('discount_amount'), + 2, + '.', + '' ); $orderTotal = abs( $orderData->getData('grand_total') - $orderData->getTotalRefunded() @@ -157,16 +170,17 @@ public function setOrderData(Mage_Sales_Model_Order $orderData) */ protected function _setShippingData($orderData) { - if ($orderData->getShippingAddress()) { $shippingData = $orderData->getShippingAddress()->getData(); $this->delivery_address = array( 'delivery_address_1' => $this->_getStreet( - $shippingData['street'], 1 + $shippingData['street'], + 1 ), 'delivery_address_2' => $this->_getStreet( - $shippingData['street'], 2 + $shippingData['street'], + 2 ), 'delivery_city' => $shippingData['city'], 'delivery_region' => $shippingData['region'], @@ -185,10 +199,12 @@ protected function _setBillingData($orderData) $billingData = $orderData->getBillingAddress()->getData(); $this->billing_address = array( 'billing_address_1' => $this->_getStreet( - $billingData['street'], 1 + $billingData['street'], + 1 ), 'billing_address_2' => $this->_getStreet( - $billingData['street'], 2 + $billingData['street'], + 2 ), 'billing_city' => $billingData['city'], 'billing_region' => $billingData['region'], @@ -203,7 +219,7 @@ protected function _setBillingData($orderData) */ protected function _setOrderCustomAttributes($orderData) { - $this->custom = array(); + $this->custom = array(); $helper = Mage::helper('ddg'); $website = Mage::app()->getStore($orderData->getStore()) @@ -219,7 +235,8 @@ protected function _setOrderCustomAttributes($orderData) if (isset($fields[$customAttribute])) { $field = $fields[$customAttribute]; $value = $this->_getCustomAttributeValue( - $field, $orderData + $field, + $orderData ); if ($value) { $this->_assignCustom($field, $value); @@ -261,7 +278,7 @@ public function expose() $propreties = array_diff_key( get_object_vars($this), array_flip(array( - '_attributeSet' + '_attributeSet', )) ); @@ -288,7 +305,10 @@ protected function _getCustomAttributeValue($field, $orderData) case 'decimal': $value = (float)number_format( - $orderData->$function(), 2, '.', '' + $orderData->$function(), + 2, + '.', + '' ); break; @@ -296,7 +316,8 @@ protected function _getCustomAttributeValue($field, $orderData) case 'datetime': case 'date': $date = new Zend_Date( - $orderData->$function(), Zend_Date::ISO_8601 + $orderData->$function(), + Zend_Date::ISO_8601 ); $value = $date->toString(Zend_Date::ISO_8601); break; @@ -322,43 +343,6 @@ protected function _assignCustom($field, $value) $this->custom[$field['COLUMN_NAME']] = $value; } - /** - * Get attributes from attribute set. - * - * @param $attributeSetId - * - * @return array - */ - protected function _getAttributesArray($attributeSetId) - { - $result = array(); - $attributes = Mage::getResourceModel('catalog/product_attribute_collection') - ->setAttributeSetFilter($attributeSetId) - ->getItems(); - - foreach ($attributes as $attribute) { - $result[] = $attribute->getAttributeCode(); - } - - return $result; - } - - /** - * Check string length and limit to 250. - * - * @param $value - * - * @return string - */ - protected function _limitLength($value) - { - if (strlen($value) > 250) { - $value = substr($value, 0, 250); - } - - return $value; - } - /** * @param Mage_Sales_Model_Order_Item $orderItem * @@ -385,11 +369,14 @@ protected function _getOrderItemOptions($orderItem) foreach ($orderItemOptions as $orderItemOption) { if (array_key_exists('value', $orderItemOption) && array_key_exists( - 'label', $orderItemOption + 'label', + $orderItemOption ) ) { $label = str_replace( - ' ', '-', $orderItemOption['label'] + ' ', + '-', + $orderItemOption['label'] ); $options[][$label] = $orderItemOption['value']; } @@ -470,6 +457,7 @@ protected function _setOrderItems($orderData) } $product = $productItem->getProduct(); + $product_attributes = null; if ($product) { // category names @@ -480,65 +468,19 @@ protected function _setOrderItems($orderData) $categories = array(); $categories[] = $cat->getName(); $productCat[]['Name'] = substr( - implode(', ', $categories), 0, 244 + implode(', ', $categories), + 0, + 244 ); } - - $attributes = array(); //selected attributes from config $configAttributes = Mage::helper('ddg')->getWebsiteConfig( Dotdigitalgroup_Email_Helper_Config::XML_PATH_CONNECTOR_SYNC_ORDER_PRODUCT_ATTRIBUTES, $orderData->getStore()->getWebsite() ); if ($configAttributes) { - $configAttributes = explode(',', $configAttributes); - //attributes from attribute set - $attributesFromAttributeSet = $this->_getAttributesArray( - $product->getAttributeSetId() - ); - - foreach ($configAttributes as $attributeCode) { - //if config attribute is in attribute set - if (in_array( - $attributeCode, $attributesFromAttributeSet - )) { - //attribute input type - $inputType = $product->getResource() - ->getAttribute($attributeCode) - ->getFrontend() - ->getInputType(); - - //fetch attribute value from product depending on input type - switch ($inputType) { - case 'multiselect': - case 'select': - case 'dropdown': - $value = $product->getAttributeText( - $attributeCode - ); - break; - case 'date': - $date = new Zend_Date( - $product->getData($attributeCode), Zend_Date::ISO_8601 - ); - $value = $date->toString(Zend_Date::ISO_8601); - break; - default: - $value = $product->getData($attributeCode); - break; - } - - // check limit on text and assign value to array - if (is_string($value)) { - $attributes[][$attributeCode] - = $this->_limitLength($value); - } elseif (is_array($value)) { - $value = implode(', ', $value); - $attributes[][$attributeCode] - = $this->_limitLength($value); - } - } - } + $attributor = Mage::getModel('ddg_automation/connector_productattributes'); + $product_attributes = $attributor->initializeCustomAttributes($configAttributes, $product); } $attributeSetName = $this->_getAttributeSetName($product); @@ -546,14 +488,18 @@ protected function _setOrderItems($orderData) 'name' => $productItem->getName(), 'sku' => $productItem->getSku(), 'qty' => (int)number_format( - $productItem->getData('qty_ordered'), 2 + $productItem->getData('qty_ordered'), + 2 ), 'price' => (float)number_format( - $productItem->getPrice(), 2, '.', '' + $productItem->getPrice(), + 2, + '.', + '' ), 'attribute-set' => $attributeSetName, 'categories' => $productCat, - 'attributes' => $attributes, + 'product_attributes' => $product_attributes, 'custom-options' => $customOptions ); } else { @@ -562,14 +508,18 @@ protected function _setOrderItems($orderData) 'name' => $productItem->getName(), 'sku' => $productItem->getSku(), 'qty' => (int)number_format( - $productItem->getData('qty_ordered'), 2 + $productItem->getData('qty_ordered'), + 2 ), 'price' => (float)number_format( - $productItem->getPrice(), 2, '.', '' + $productItem->getPrice(), + 2, + '.', + '' ), 'attribute-set' => '', 'categories' => array(), - 'attributes' => array(), + 'product_attributes' => $product_attributes, 'custom-options' => $customOptions ); } diff --git a/code/Dotdigitalgroup/Email/Model/Connector/Product.php b/code/Dotdigitalgroup/Email/Model/Connector/Product.php index 816e16ebf..e896ef27b 100755 --- a/code/Dotdigitalgroup/Email/Model/Connector/Product.php +++ b/code/Dotdigitalgroup/Email/Model/Connector/Product.php @@ -1,363 +1,321 @@ -id = $product->getId(); - $this->sku = $product->getSku(); - $this->name = $product->getName(); - $statuses = Mage::getModel('catalog/product_status') - ->getOptionArray(); - $this->status = $statuses[$product->getStatus()]; - $options = Mage::getModel('catalog/product_visibility') - ->getOptionArray(); - $this->visibility = $options[$product->getVisibility()]; - - $this->getMinPrices($product); - - $this->url = $product->getProductUrl(); - $this->imagePath = Mage::getModel('catalog/product_media_config') - ->getMediaUrl($product->getSmallImage()); - $stock = Mage::getModel('cataloginventory/stock_item') - ->loadByProduct($product); - $this->stock = (float)number_format( - $stock->getQty(), - 2, - '.', - '' - ); - - $shortDescription = $product->getShortDescription(); - //limit short description - if (strlen($shortDescription) > 250) { - $shortDescription = substr($shortDescription, 0, 250); - } - - $this->short_description = $shortDescription; - - //category data - $count = 0; - $categoryCollection = $product->getCategoryCollection() - ->addNameToResult(); - foreach ($categoryCollection as $cat) { - $this->categories[$count]['Id'] = $cat->getId(); - $this->categories[$count]['Name'] = $cat->getName(); - $count++; - } - - //website data - $count = 0; - $websiteIds = $product->getWebsiteIds(); - foreach ($websiteIds as $websiteId) { - $website = Mage::app()->getWebsite( - $websiteId - ); - $this->websites[$count]['Id'] = $website->getId(); - $this->websites[$count]['Name'] = $website->getName(); - $count++; - } - - //bundle product options - if ($product->getTypeId() - == Mage_Catalog_Model_Product_Type::TYPE_BUNDLE - ) { - $optionCollection = $product->getTypeInstance() - ->getOptionsCollection(); - $selectionCollection = $product->getTypeInstance() - ->getSelectionsCollection( - $product->getTypeInstance()->getOptionsIds() - ); - $options = $optionCollection->appendSelections($selectionCollection); - foreach ($options as $option) { - $count = 0; - $title = str_replace(' ', '', $option->getDefaultTitle()); - if (!$this->textIsValidForInsightDataKey($title)) { - continue; - } - $selections = $option->getSelections(); - $sOptions = array(); - foreach ($selections as $selection) { - $sOptions[$count]['name'] = $selection->getName(); - $sOptions[$count]['sku'] = $selection->getSku(); - $sOptions[$count]['id'] = $selection->getProductId(); - $sOptions[$count]['price'] = (float)number_format( - $selection->getPrice(), - 2, - '.', - '' - ); - $count++; - } - - $this->$title = $sOptions; - } - } - - //configurable product options - if ($product->getTypeId() - == Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE - ) { - $productAttributeOptions = $product->getTypeInstance(true) - ->getConfigurableAttributesAsArray($product); - foreach ($productAttributeOptions as $productAttribute) { - $count = 0; - $label = strtolower( - str_replace(' ', '', $productAttribute['label']) - ); - if (!$this->textIsValidForInsightDataKey($label)) { - continue; - } - $options = array(); - foreach ($productAttribute['values'] as $attribute) { - $options[$count]['option'] = $attribute['default_label']; - $options[$count]['price'] = (float)number_format( - $attribute['pricing_value'], - 2, - '.', - '' - ); - $count++; - } - - $this->$label = $options; - } - } - } - - /** - * Exposes the class as an array of objects. - * - * @return array - */ - public function expose() - { - return get_object_vars($this); - } - - /** - * Set the Minimum Prices for Configurable and Bundle products. - * - * @param Mage_Catalog_Model_Product $product - * - * @return null - */ - private function getMinPrices($product) - { - switch ($product->getTypeId()) { - case Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE: - $this->getMinConfigurablePrices($product); - break; - case Mage_Catalog_Model_Product_Type::TYPE_BUNDLE: - $this->getMinBundlePrices($product); - break; - case Mage_Catalog_Model_Product_Type::TYPE_GROUPED: - $this->getMinGroupedPrices($product); - break; - default: - $this->price = $product->getPrice(); - $this->specialPrice = $product->getSpecialPrice(); - } - - $this->formatPriceValues(); - } - - /** - * Calculates the Minimum Final Price and Special Price for the Configurable Products. - * - * @param Mage_Catalog_Model_Product $product - * - * @return null - */ - private function getMinConfigurablePrices($product) - { - foreach ($product->getTypeInstance()->getChildrenIds($product->getId()) as $childProductIds) { - foreach ($childProductIds as $id) { - $productById = Mage::getModel('catalog/product')->load($id); - $childPrices[] = $productById->getPrice(); - if ($productById->getSpecialPrice() !== null) { - $childSpecialPrices[] = $productById->getSpecialPrice(); - } - } - } - $this->price = isset($childPrices) ? min($childPrices) : null; - $this->specialPrice = isset($childSpecialPrices) ? min($childSpecialPrices) : null; - } - - /** - * Calculates the Minimum Final Price and Special Price for the Bundle Products. - * - * @param Mage_Catalog_Model_Product $product - * - * @return null - */ - private function getMinBundlePrices($product) - { - $this->price = 0; - $this->specialPrice = 0; - $productTypeInstance = $product->getTypeInstance(true); - $optionCol= $productTypeInstance->getOptionsCollection($product); - $selectionCol= $productTypeInstance->getSelectionsCollection( - $productTypeInstance->getOptionsIds($product), - $product - ); - $optionCol->appendSelections($selectionCol); - foreach ($optionCol as $option) { - if ($option->getRequired()) { - $selections = $option->getSelections(); - $specialPriceArrayFlag = []; - $minPrice = min(array_map(function ($s) use (&$specialPriceArrayFlag) { - if ($s->getSpecialPrice() > 0) { - $specialPriceArrayFlag[] = $s->getSpecialPrice(); - } - return $s->price; - }, $selections)); - $specialPriceSimpleProducts = min($specialPriceArrayFlag); - - if ($specialPriceSimpleProducts > 0) { - if ($product->getSpecialPrice() > 0) { - $specialPriceSimpleProducts = ($specialPriceSimpleProducts * $product->getSpecialPrice()/100); - $this->specialPrice += $specialPriceSimpleProducts; - } else { - $this->specialPrice += $specialPriceSimpleProducts; - } - } elseif ($product->getSpecialPrice() > 0) { - $minSpecialPrice = ($minPrice * $product->getSpecialPrice()/100); - $this->specialPrice += $minSpecialPrice; - } - - $this->price += round($minPrice, 2); - $this->specialPrice = ($this->price === $this->specialPrice) ? null : $this->specialPrice; - } - } - } - - /** - * Calculates the Minimum Final Price and Special Price for the Grouped Products. - * - * @param Mage_Catalog_Model_Product $product - * - * @return null - */ - private function getMinGroupedPrices($product) - { - $childProducts = $product->getTypeInstance(true)->getAssociatedProducts($product); - foreach ($childProducts as $childProduct) { - $childPrices[] = $childProduct->getPrice(); - if ($childProduct->getSpecialPrice() !== null) { - $childSpecialPrices[] = $childProduct->getSpecialPrice(); - } - } - $this->price = isset($childPrices) ? min($childPrices) : null; - $this->specialPrice = isset($childSpecialPrices) ? min($childSpecialPrices) : null; - } - - - /** - * Formats the price values. - * - * @return null - */ - private function formatPriceValues() - { - $this->price = (float)number_format( - $this->price, - 2, - '.', - '' - ); - $this->specialPrice = (float)number_format( - $this->specialPrice, - 2, - '.', - '' - ); - } - - /** - * Ensure text matches insight data key restrictions - * https://support.dotmailer.com/hc/en-gb/articles/212214538-Using-Insight-data-developers-guide-#restrictkeys - * - * @param string $text - * - * @return false|int - */ - private function textIsValidForInsightDataKey($text) - { - return preg_match('/^[a-zA-Z_\\\\-][a-zA-Z0-9_\\\\-]*$/', $text); - } -} +id = $product->getId(); + $this->sku = $product->getSku(); + $this->name = $product->getName(); + $statuses = Mage::getModel('catalog/product_status') + ->getOptionArray(); + $this->status = $statuses[$product->getStatus()]; + $options = Mage::getModel('catalog/product_visibility') + ->getOptionArray(); + $this->visibility = $options[$product->getVisibility()]; + + $this->getMinPrices($product); + + $this->url = $product->getProductUrl(); + $this->imagePath = Mage::getModel('catalog/product_media_config') + ->getMediaUrl($product->getSmallImage()); + $stock = Mage::getModel('cataloginventory/stock_item') + ->loadByProduct($product); + $this->stock = (float)number_format( + $stock->getQty(), + 2, + '.', + '' + ); + + $shortDescription = $product->getShortDescription(); + //limit short description + if (strlen($shortDescription) > 250) { + $shortDescription = substr($shortDescription, 0, 250); + } + + $this->short_description = $shortDescription; + + //category data + $count = 0; + $categoryCollection = $product->getCategoryCollection() + ->addNameToResult(); + foreach ($categoryCollection as $cat) { + $this->categories[$count]['Id'] = $cat->getId(); + $this->categories[$count]['Name'] = $cat->getName(); + $count++; + } + + //website data + $count = 0; + $websiteIds = $product->getWebsiteIds(); + foreach ($websiteIds as $websiteId) { + $website = Mage::app()->getWebsite( + $websiteId + ); + $this->websites[$count]['Id'] = $website->getId(); + $this->websites[$count]['Name'] = $website->getName(); + $count++; + } + + //Custom Attributes + $this->_setCustomAttributes($product); + } + + /** + * Exposes the class as an array of objects. + * + * @return array + */ + public function expose() + { + return get_object_vars($this); + } + + /** + * Set the Minimum Prices for Configurable and Bundle products. + * + * @param Mage_Catalog_Model_Product $product + * + * @return null + */ + private function getMinPrices($product) + { + switch ($product->getTypeId()) { + case Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE: + $this->getMinConfigurablePrices($product); + break; + case Mage_Catalog_Model_Product_Type::TYPE_BUNDLE: + $this->getMinBundlePrices($product); + break; + case Mage_Catalog_Model_Product_Type::TYPE_GROUPED: + $this->getMinGroupedPrices($product); + break; + default: + $this->price = $product->getPrice(); + $this->specialPrice = $product->getSpecialPrice(); + } + + $this->formatPriceValues(); + } + + /** + * Calculates the Minimum Final Price and Special Price for the Configurable Products. + * + * @param Mage_Catalog_Model_Product $product + * + * @return null + */ + private function getMinConfigurablePrices($product) + { + foreach ($product->getTypeInstance()->getChildrenIds($product->getId()) as $childProductIds) { + foreach ($childProductIds as $id) { + $productById = Mage::getModel('catalog/product')->load($id); + $childPrices[] = $productById->getPrice(); + if ($productById->getSpecialPrice() !== null) { + $childSpecialPrices[] = $productById->getSpecialPrice(); + } + } + } + $this->price = isset($childPrices) ? min($childPrices) : null; + $this->specialPrice = isset($childSpecialPrices) ? min($childSpecialPrices) : null; + } + + /** + * Calculates the Minimum Final Price and Special Price for the Bundle Products. + * + * @param Mage_Catalog_Model_Product $product + * + * @return null + */ + private function getMinBundlePrices($product) + { + $this->price = 0; + $this->specialPrice = 0; + $productTypeInstance = $product->getTypeInstance(true); + $optionCol= $productTypeInstance->getOptionsCollection($product); + $selectionCol= $productTypeInstance->getSelectionsCollection( + $productTypeInstance->getOptionsIds($product), + $product + ); + $optionCol->appendSelections($selectionCol); + foreach ($optionCol as $option) { + if ($option->getRequired()) { + $selections = $option->getSelections(); + $specialPriceArrayFlag = []; + $minPrice = min(array_map(function ($s) use (&$specialPriceArrayFlag) { + if ($s->getSpecialPrice() > 0) { + $specialPriceArrayFlag[] = $s->getSpecialPrice(); + } + return $s->price; + }, $selections)); + $specialPriceSimpleProducts = min($specialPriceArrayFlag); + + if ($specialPriceSimpleProducts > 0) { + if ($product->getSpecialPrice() > 0) { + $specialPriceSimpleProducts = ($specialPriceSimpleProducts * $product->getSpecialPrice()/100); + $this->specialPrice += $specialPriceSimpleProducts; + } else { + $this->specialPrice += $specialPriceSimpleProducts; + } + } elseif ($product->getSpecialPrice() > 0) { + $minSpecialPrice = ($minPrice * $product->getSpecialPrice()/100); + $this->specialPrice += $minSpecialPrice; + } + + $this->price += round($minPrice, 2); + $this->specialPrice = ($this->price === $this->specialPrice) ? null : $this->specialPrice; + } + } + } + + /** + * Calculates the Minimum Final Price and Special Price for the Grouped Products. + * + * @param Mage_Catalog_Model_Product $product + * + * @return null + */ + private function getMinGroupedPrices($product) + { + $childProducts = $product->getTypeInstance(true)->getAssociatedProducts($product); + foreach ($childProducts as $childProduct) { + $childPrices[] = $childProduct->getPrice(); + if ($childProduct->getSpecialPrice() !== null) { + $childSpecialPrices[] = $childProduct->getSpecialPrice(); + } + } + $this->price = isset($childPrices) ? min($childPrices) : null; + $this->specialPrice = isset($childSpecialPrices) ? min($childSpecialPrices) : null; + } + + + /** + * Formats the price values. + * + * @return null + */ + private function formatPriceValues() + { + $this->price = (float)number_format( + $this->price, + 2, + '.', + '' + ); + $this->specialPrice = (float)number_format( + $this->specialPrice, + 2, + '.', + '' + ); + } + + /** + * Ensure text matches insight data key restrictions + * https://support.dotmailer.com/hc/en-gb/articles/212214538-Using-Insight-data-developers-guide-#restrictkeys + * + * @param string $text + * + * @return false|int + */ + private function textIsValidForInsightDataKey($text) + { + return preg_match('/^[a-zA-Z_\\\\-][a-zA-Z0-9_\\\\-]*$/', $text); + } + + /** + * Initializes Custom Product Attributes to be imported via Catalog Sync + * @param $product + */ + private function _setCustomAttributes($product) + { + $configAttributes = Mage::helper('ddg')->getWebsiteConfig( + Dotdigitalgroup_Email_Helper_Config::XML_PATH_CONNECTOR_SYNC_ORDER_PRODUCT_ATTRIBUTES, + $product->getStore()->getWebsite() + ); + if ($configAttributes) { + $attributor = Mage::getModel('ddg_automation/connector_productattributes'); + $this->attributes = $attributor->initializeCustomAttributes($configAttributes,$product); + } + } +} diff --git a/code/Dotdigitalgroup/Email/Model/Connector/Productattributes.php b/code/Dotdigitalgroup/Email/Model/Connector/Productattributes.php new file mode 100644 index 000000000..80466d584 --- /dev/null +++ b/code/Dotdigitalgroup/Email/Model/Connector/Productattributes.php @@ -0,0 +1,121 @@ +_getAttributesArray( + $product->getAttributeSetId() + ); + + foreach ($configAttributes as $attributeCode) { + //if config attribute is in attribute set + if (in_array( + $attributeCode, $attributesFromAttributeSet + )) { + //attribute input type + $inputType = $product->getResource() + ->getAttribute($attributeCode) + ->getFrontend() + ->getInputType(); + + $value = $this->getAttributeValue($inputType, $product, $attributeCode); + $this->$attributeCode = $this->limitLength($value); + + } + } + return $this; + } + /** + * Get attributes from attribute set. + * + * @param $attributeSetId + * + * @return array + */ + private function _getAttributesArray($attributeSetId) + { + $result = array(); + $attributes = Mage::getResourceModel('catalog/product_attribute_collection') + ->setAttributeSetFilter($attributeSetId) + ->getItems(); + + foreach ($attributes as $attribute) { + $result[] = $attribute->getAttributeCode(); + } + + return $result; + } + + /** + * Returns attribute value based on input type field + * @param $inputType + * @param $product + * @param $attributeCode + * @return string + * @throws Zend_Date_Exception + */ + private function getAttributeValue($inputType, $product, $attributeCode) + { + switch ($inputType) { + case 'multiselect': + case 'select': + case 'dropdown': + return $product->getAttributeText( + $attributeCode + ); + break; + case 'date': + $date = new Zend_Date( + $product->getData($attributeCode), Zend_Date::ISO_8601 + ); + return $date->toString(Zend_Date::ISO_8601); + break; + default: + return $product->getData($attributeCode); + break; + } + } + + /** + * Validates the length of the string/array + * @param $value + * @return string|null + */ + private function limitLength($value) + { + // check limit on text and assign value to array + if (is_string($value)) { + return $this->_limitLength($value); + } elseif (is_array($value)) { + $value = implode(', ', $value); + return $this->_limitLength($value); + } + return null; + } + + /** + * Check string length and limit to 250. + * + * @param $value + * + * @return string + */ + private function _limitLength($value) + { + if (strlen($value) > 250) { + $value = substr($value, 0, 250); + } + + return $value; + } +} \ No newline at end of file diff --git a/code/Dotdigitalgroup/Email/etc/system.xml b/code/Dotdigitalgroup/Email/etc/system.xml index 202698910..3005cd7a7 100755 --- a/code/Dotdigitalgroup/Email/etc/system.xml +++ b/code/Dotdigitalgroup/Email/etc/system.xml @@ -2622,12 +2622,12 @@ - + multiselect ddg_automation/adminhtml_source_sync_catalog_attributes 180 1 - 0 + 1 0 @@ -2637,7 +2637,7 @@ adminhtml/system_config_source_yesno 190 1 - 0 + 1 0 From 7e0f07fe919f8ab842ef01d19f59e467d7cd112c Mon Sep 17 00:00:00 2001 From: Fanis Strezos Date: Wed, 5 Jun 2019 08:51:26 +0000 Subject: [PATCH 06/10] Merged PR 14036: Clean invalid transactional data keys in order sync We already prevent invalid data keys (i.e. keys that contain special characters or otherwise fail Engagement Cloud's validation rules) in the catalog sync. This reuses the same method to add validation to custom product options retrieved during the order sync. **To test keys for customizable options:** - Create two customizable options on a product. These can be checkboxes required for the purchaser when adding the product to cart. - Option 1 should have an invalid title e.g. "How long will you need the phone?" - Option 2 should have a valid title e.g. "Pick up from depot" - Turn on EC > Configuration > Transactional Data > Include Product Custom Options In Order Sync Sync orders - Only option 2 should be saved into the JSON blob e.g. `"custom-options":[{"Pick-up-from-depot":"Yes"}]` To test keys for product attributes: - Go to any configurable product - Define a new configurable product attribute with an !lleg@l title - Populate new product variants - Run catalog sync to pick up the modified product Related work items: #89341 --- .../Email/Helper/Keyvalidator.php | 53 +++++++++++++++++++ .../Email/Model/Connector/Order.php | 8 ++- 2 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 code/Dotdigitalgroup/Email/Helper/Keyvalidator.php diff --git a/code/Dotdigitalgroup/Email/Helper/Keyvalidator.php b/code/Dotdigitalgroup/Email/Helper/Keyvalidator.php new file mode 100644 index 000000000..b7dc2c6bc --- /dev/null +++ b/code/Dotdigitalgroup/Email/Helper/Keyvalidator.php @@ -0,0 +1,53 @@ +hasInvalidPatternForInsightDataKey($label)) { + $label = $this->stripInvalidCharactersAndIdentify($label, $replaceSpaceWith, $suffix); + } + return $label; + } + + /** + * @param string $label + * + * https://support.dotdigital.com/hc/en-gb/articles/212214538-Using-Insight-data-developers-guide-#restrictkeys + * + * @return false|int + */ + public function hasInvalidPatternForInsightDataKey($label) + { + return preg_match(self::ENGAGEMENT_CLOUD_PERMISSIBLE_KEY_PATTERN, $label); + } + + /** + * Remove invalid characters and append a suffix to avoid possible key collisions. + * + * @param string $label + * @param string $replaceSpaceWith + * @param string $suffix + * + * @return string + */ + private function stripInvalidCharactersAndIdentify($label, $replaceSpaceWith, $suffix) + { + $safeLabel = preg_replace(self::ENGAGEMENT_CLOUD_PERMISSIBLE_KEY_PATTERN, '', $label); + return $safeLabel.$replaceSpaceWith.$suffix; + } +} \ No newline at end of file diff --git a/code/Dotdigitalgroup/Email/Model/Connector/Order.php b/code/Dotdigitalgroup/Email/Model/Connector/Order.php index 5c2c10817..495b9fa9c 100755 --- a/code/Dotdigitalgroup/Email/Model/Connector/Order.php +++ b/code/Dotdigitalgroup/Email/Model/Connector/Order.php @@ -365,6 +365,7 @@ protected function _getOrderItemOptions($orderItem) } $options = array(); + $helper = Mage::helper('ddg/keyvalidator'); foreach ($orderItemOptions as $orderItemOption) { if (array_key_exists('value', $orderItemOption) @@ -373,11 +374,8 @@ protected function _getOrderItemOptions($orderItem) $orderItemOption ) ) { - $label = str_replace( - ' ', - '-', - $orderItemOption['label'] - ); + $label = $helper->cleanLabel($orderItemOption['label'],'-',$orderItemOption['option_id']); + $options[][$label] = $orderItemOption['value']; } } From cac6a0f3726516e870b480cd9bbf4fdd79c5b4c8 Mon Sep 17 00:00:00 2001 From: Fanis Strezos Date: Wed, 5 Jun 2019 09:30:18 +0000 Subject: [PATCH 07/10] Merged PR 14079: apply new Label Copy in product attributes syncing Label copy for product attribute sync updated Related work items: #89975 --- code/Dotdigitalgroup/Email/etc/system.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/Dotdigitalgroup/Email/etc/system.xml b/code/Dotdigitalgroup/Email/etc/system.xml index 3005cd7a7..dfc2e4284 100755 --- a/code/Dotdigitalgroup/Email/etc/system.xml +++ b/code/Dotdigitalgroup/Email/etc/system.xml @@ -2622,14 +2622,14 @@ - + multiselect ddg_automation/adminhtml_source_sync_catalog_attributes 180 1 1 0 - + From 6ab20e6006581284f95c2b26ee0890c9dc358dce Mon Sep 17 00:00:00 2001 From: Fanis Strezos Date: Wed, 5 Jun 2019 11:26:23 +0000 Subject: [PATCH 08/10] Merged PR 14090: Update Release Notes and Module Version to 6.4.16 # V6.4.16 ##### Improvements - We've improved the coverage of catalog sync by allowing selected custom attributes to be included in the synced data - In catalog sync, we are now syncing scoped (store and website) values for products, instead of only the default-level values. - We resolved some code duplication in the dynamic content blocks. ##### Bug Fixes - We are now cleaning any custom transactional data keys prior to import, removing invalid (non-alphanumeric) characters, but not skipping records as before. - The Magento core review module is now decoupled from our contact sync. Related work items: #68184, #79713, #86248, #87169, #88046, #88048, #88049, #88050, #88372 --- README.md | 12 ++++++++++++ code/Dotdigitalgroup/Email/etc/config.xml | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 65933371b..5904e4940 100755 --- a/README.md +++ b/README.md @@ -42,6 +42,18 @@ You are welcome to contribute to Engagement Cloud for Magento! You can either: - Fix a bug: please fork this repo and submit the Pull Request to our [Develop branch](https://github.com/dotmailer/dotmailer-magento-extension/tree/develop) Request a feature on our [roadmap](https://roadmap.dotdigital.com) +# V6.4.16 + +##### Improvements +- We've improved the coverage of catalog sync by allowing selected custom attributes to be included in the synced data. +- In catalog sync, we are now syncing scoped (store and website) values for products, instead of only the default-level values. +- We resolved some code duplication in the dynamic content blocks. + +##### Bug Fixes + +- We are now cleaning any custom transactional data keys prior to import, removing invalid (non-alphanumeric) characters, but not skipping records as before. +- The Magento core review module is now decoupled from our contact sync. + # V6.4.15 ##### Improvements diff --git a/code/Dotdigitalgroup/Email/etc/config.xml b/code/Dotdigitalgroup/Email/etc/config.xml index 4dd1fac24..17dac64dc 100755 --- a/code/Dotdigitalgroup/Email/etc/config.xml +++ b/code/Dotdigitalgroup/Email/etc/config.xml @@ -2,7 +2,7 @@ - 6.4.15 + 6.4.16 From c271e5ea664018c39de13c44d54820675e69549b Mon Sep 17 00:00:00 2001 From: Fanis Strezos Date: Thu, 6 Jun 2019 13:00:18 +0000 Subject: [PATCH 09/10] Merged PR 14121: Hotfix - Review Count function Restored Review Count function Restored --- .../Email/Model/Apiconnector/Customer.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/code/Dotdigitalgroup/Email/Model/Apiconnector/Customer.php b/code/Dotdigitalgroup/Email/Model/Apiconnector/Customer.php index 5b61b30f3..e1d060965 100755 --- a/code/Dotdigitalgroup/Email/Model/Apiconnector/Customer.php +++ b/code/Dotdigitalgroup/Email/Model/Apiconnector/Customer.php @@ -140,7 +140,16 @@ public function setReviewCollection() $this->reviewCollection = $collection; } - + + /** + * @return int + */ + + public function getReviewCount() + { + return $this->reviewCollection->getSize(); + } + /** * @return string */ From f696b47d79f75280e8e970d24cf88174153b112a Mon Sep 17 00:00:00 2001 From: Alastair Mucklow Date: Fri, 7 Jun 2019 08:18:17 +0000 Subject: [PATCH 10/10] Merged PR 14125: Hotfix - fetch correct website-level attributes for sync Pass `$storeId` to `Connector\Product` to fetch correct attributes for scope. Previously `$product->getStore()->getWebsite()` always returns 0 so we always had the attributes list from default config. **To test:** - Configure catalog sync at store level - Configure Product Attributes to sync x and y custom attributes at website 1, but only x attribute at website 2 - Set up a product with both attributes, and assign it to website 1 and 2 - Run catalog sync and importer **Outcome:** - Product synced to website 2 does NOT import a key / value for attribute y. --- code/Dotdigitalgroup/Email/Model/Catalog.php | 5 +++-- .../Email/Model/Connector/Product.php | 21 +++++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/code/Dotdigitalgroup/Email/Model/Catalog.php b/code/Dotdigitalgroup/Email/Model/Catalog.php index cd1c5d0bb..731ba9ed4 100755 --- a/code/Dotdigitalgroup/Email/Model/Catalog.php +++ b/code/Dotdigitalgroup/Email/Model/Catalog.php @@ -199,7 +199,8 @@ protected function _exportCatalog($storeId) ); foreach ($productCollection as $product) { - $connectorProduct = Mage::getModel('ddg_automation/connector_product', $product); + $connectorProduct = Mage::getModel('ddg_automation/connector_product') + ->setProduct($product, $storeId); $connectorProducts[] = $connectorProduct; } @@ -526,4 +527,4 @@ public function handleConfigSaveAfter(Varien_Event_Observer $observer) return $this; } -} \ No newline at end of file +} diff --git a/code/Dotdigitalgroup/Email/Model/Connector/Product.php b/code/Dotdigitalgroup/Email/Model/Connector/Product.php index e896ef27b..bf476e7ca 100755 --- a/code/Dotdigitalgroup/Email/Model/Connector/Product.php +++ b/code/Dotdigitalgroup/Email/Model/Connector/Product.php @@ -78,10 +78,17 @@ class Dotdigitalgroup_Email_Model_Connector_Product public $attributes; /** - * Dotdigitalgroup_Email_Model_Connector_Product constructor. + * Set the product data + * * @param Mage_Catalog_Model_Product $product + * @param string|int|null $storeId + * + * @return $this */ - public function __construct(Mage_Catalog_Model_Product $product) + public function setProduct( + Mage_Catalog_Model_Product $product, + $storeId + ) { $this->id = $product->getId(); $this->sku = $product->getSku(); @@ -138,9 +145,11 @@ public function __construct(Mage_Catalog_Model_Product $product) } //Custom Attributes - $this->_setCustomAttributes($product); + $this->_setCustomAttributes($product, $storeId); + + return $this; } - + /** * Exposes the class as an array of objects. * @@ -307,11 +316,11 @@ private function textIsValidForInsightDataKey($text) * Initializes Custom Product Attributes to be imported via Catalog Sync * @param $product */ - private function _setCustomAttributes($product) + private function _setCustomAttributes($product, $storeId) { $configAttributes = Mage::helper('ddg')->getWebsiteConfig( Dotdigitalgroup_Email_Helper_Config::XML_PATH_CONNECTOR_SYNC_ORDER_PRODUCT_ATTRIBUTES, - $product->getStore()->getWebsite() + Mage::app()->getStore($storeId)->getWebsiteId() ); if ($configAttributes) { $attributor = Mage::getModel('ddg_automation/connector_productattributes');