diff --git a/Helper/Product.php b/Helper/Product.php
index 290d1a7..a171988 100644
--- a/Helper/Product.php
+++ b/Helper/Product.php
@@ -1,6 +1,6 @@
galleryReadHandler = $galleryReadHandler;
$this->catalogProductMediaConfig = $catalogProductMediaConfig;
- $this->catalogHelper = $catalogHelper;
$this->productImageHelper = $productImageHelper;
- $this->ruleFactory = $ruleFactory;
$this->eavConfig = $eavConfig;
$this->filter = $filter;
$this->attributeSet = $attributeSet;
$this->catalogProductTypeConfigurable = $catalogProductTypeConfigurable;
$this->catalogProductTypeGrouped = $catalogProductTypeGrouped;
$this->catalogProductTypeBundle = $catalogProductTypeBundle;
- $this->commonPriceModel = $commonPriceModel;
$this->inventoryData = $inventoryData;
$this->mediaData = $mediaData;
+ $this->priceData = $priceData;
$this->logger = $logger;
parent::__construct($context);
}
@@ -217,7 +180,8 @@ public function getDataRow($product, $parent, $config)
$value = $this->getCondition(
$attribute['condition'],
$productData,
- $attribute
+ $attribute,
+ $value
);
}
@@ -376,7 +340,7 @@ public function getAttributeValue($type, $attribute, $config, $product, $simple)
$value = $product->getCategoryIds();
break;
case 'tier_price':
- $value = $this->processTierPrice($product, $config);
+ $value = $this->priceData->processTierPrice($product, $config);
break;
default:
$value = $this->getValue($attribute, $product);
@@ -883,7 +847,7 @@ public function getFormat($value, $attribute, array $config, $product): string
$priceConfig = $config['price_config'];
$priceConfig['currency'] = explode('_', $actions[0])[1];
$priceConfig['exchange_rate'] = $priceConfig['exchange_rate_' . $priceConfig['currency']] ?? 1;
- $value = $this->processPrice($product, (float)$value, $priceConfig);
+ $value = $this->priceData->processPrice($product, (float)$value, $priceConfig);
}
}
if (!empty($attribute['max'])) {
@@ -900,10 +864,10 @@ public function getFormat($value, $attribute, array $config, $product): string
*
* @return string
*/
- public function getCondition($conditions, $product, $attribute)
+ public function getCondition($conditions, $product, $attribute, $value = null)
{
$data = null;
- $value = $product->getData($attribute['source']);
+ $value = $value ?? $product->getData($attribute['source']);
if ($attribute['source'] == 'is_in_stock') {
$value = $this->getAvailability($product);
}
@@ -938,309 +902,12 @@ public function getCondition($conditions, $product, $attribute)
public function getAttributeCollection($type, $config, $product)
{
if ($type == 'price') {
- return $this->getPriceCollection($config, $product);
+ return $this->priceData->execute($config, $product);
}
return [];
}
- /**
- * @param $config
- * @param \Magento\Catalog\Model\Product $product
- *
- * @return array
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- */
- public function getPriceCollection($config, $product)
- {
- switch ($product->getTypeId()) {
- case 'configurable':
- /**
- * Check if config has a final_price (data catalog_product_index_price)
- * If final_price === null product is not salable (out of stock)
- */
- if ($product->getData('final_price') === null) {
- $price = 0;
- $finalPrice = 0;
- } else {
- $price = $product->getData('price');
- $finalPrice = $product->getData('final_price');
- $specialPrice = $product->getSpecialPrice();
- $product['min_price'] = $product['min_price'] >= 0 ? $product['min_price'] : null;
- $product['max_price'] = $product['max_price'] >= 0 ? $product['max_price'] : null;
- }
- break;
- case 'grouped':
- $groupedPriceType = null;
- if (!empty($config['price_config']['grouped_price_type'])) {
- $groupedPriceType = $config['price_config']['grouped_price_type'];
- }
-
- $groupedPrices = $this->getGroupedPrices($product, $config);
- $price = $groupedPrices['min_price'];
- $finalPrice = $groupedPrices['min_price'];
- $product['min_price'] = $groupedPrices['min_price'];
- $product['max_price'] = $groupedPrices['max_price'];
- $product['total_price'] = $groupedPrices['total_price'];
-
- if ($groupedPriceType == 'max') {
- $price = $groupedPrices['max_price'];
- $finalPrice = $price;
- }
-
- if ($groupedPriceType == 'total') {
- $price = $groupedPrices['total_price'];
- $finalPrice = $price;
- }
-
- break;
- case 'bundle':
- $price = $product->getPrice();
- $finalPrice = $product->getFinalPrice();
- $specialPrice = $product->getSpecialPrice();
- $rulePrice = $this->ruleFactory->create()->getRulePrice(
- $config['timestamp'],
- $config['website_id'],
- '',
- $product->getId()
- );
- if ($rulePrice !== null && $rulePrice !== false) {
- $finalPrice = min($finalPrice, $rulePrice);
- }
- break;
- default:
- if (intval($product->getFinalPrice()) !== 0) {
- $price = $product->getPrice();
- $finalPrice = $product->getFinalPrice();
- $specialPrice = $product->getSpecialPrice();
- } else {
- $finalPrice = $product->getPriceInfo()->getPrice('final_price')->getValue();
- $price = $product->getPriceInfo()->getPrice('regular_price')->getValue();
- $product['min_price'] = $product->getPriceInfo()->getPrice('final_price')->getMinimalPrice()->getBaseAmount();
- $product['max_price'] = $product->getPriceInfo()->getPrice('final_price')->getMaximalPrice()->getBaseAmount();
- }
-
- $rulePrice = $this->ruleFactory->create()->getRulePrice(
- $config['timestamp'],
- $config['website_id'],
- '',
- $product->getId()
- );
-
- if ($rulePrice !== null && $rulePrice !== false) {
- $finalPrice = min($finalPrice, $rulePrice);
- }
-
- break;
- }
- $prices = [];
- $attributes = $config['attributes'];
- $config = $config['price_config'];
- $prices[$config['price']] = $this->processPrice($product, $price, $config);
-
- if (!empty($config['tax_include_both'])) {
- $prices[$config['price_excl']] = $this->processPrice($product, $price, $config, false);
- $prices[$config['price_incl']] = $this->processPrice($product, $price, $config, true);
- }
-
- if (isset($finalPrice) && !empty($config['final_price'])) {
- $prices[$config['final_price']] = $this->processPrice($product, $finalPrice, $config);
- }
-
- if (isset($finalPrice) && ($price > $finalPrice) && !empty($config['sales_price'])) {
- $prices[$config['sales_price']] = $this->processPrice($product, $finalPrice, $config);
- if (!empty($config['tax_include_both'])) {
- $prices[$config['sales_price_excl']] = $this->processPrice($product, $finalPrice, $config, false);
- $prices[$config['sales_price_incl']] = $this->processPrice($product, $finalPrice, $config, true);
- }
- }
-
- if (isset($specialPrice) && ($specialPrice == $finalPrice) && !empty($config['sales_date_range'])) {
- if ($product->getSpecialFromDate() && $product->getSpecialToDate()) {
- $from = date('Y-m-d', strtotime($product->getSpecialFromDate()));
- $to = date('Y-m-d', strtotime($product->getSpecialToDate()));
- $prices[$config['sales_date_range']] = $from . '/' . $to;
- }
- }
-
- if ($price <= 0) {
- if (!empty($product['min_price'])) {
- $minPrice = $product['min_price'];
- $prices[$config['price']] = $this->processPrice($product, $minPrice, $config);
- if (!empty($config['tax_include_both'])) {
- $prices[$config['price_excl']] = $this->processPrice($product, $minPrice, $config, false);
- $prices[$config['price_incl']] = $this->processPrice($product, $minPrice, $config, true);
- }
- }
- }
-
- if (!empty($product['min_price']) && !empty($config['min_price'])) {
- if (($finalPrice > 0) && $finalPrice < $product['min_price']) {
- $prices[$config['min_price']] = $this->processPrice($product, $finalPrice, $config);
- } else {
- $prices[$config['min_price']] = $this->processPrice($product, $product['min_price'], $config);
- }
- }
-
- if (!empty($product['max_price']) && !empty($config['max_price'])) {
- $prices[$config['max_price']] = $this->processPrice($product, $product['max_price'], $config);
- }
-
- if (!empty($product['total_price']) && !empty($config['total_price'])) {
- $prices[$config['total_price']] = $this->processPrice($product, $product['total_price'], $config);
- }
-
- if (!empty($config['discount_perc']) && isset($prices[$config['sales_price']])) {
- if ($prices[$config['price']] > 0) {
- $discount = ($prices[$config['sales_price']] - $prices[$config['price']]) / $prices[$config['price']];
- $discount = $discount * -100;
- if ($discount > 0) {
- $prices[$config['discount_perc']] = round($discount, 1) . '%';
- }
- }
- }
-
- if ($extraRenderedPriceFields = preg_grep('/^rendered_price__/', array_keys($attributes))) {
- foreach ($extraRenderedPriceFields as $label) {
- $field = $attributes[$label];
- $renderCurrency = $field['actions'][0] ? explode('_', $field['actions'][0])[1] : null;
- if ($renderCurrency !== $config['currency']) {
- $newConfig = $config;
- $newConfig['currency'] = $renderCurrency;
- $newConfig['exchange_rate'] = $config['exchange_rate_' . $renderCurrency] ?? 1;
- switch ($field['price_source']) {
- case 'price':
- $prices[$field['label']] = $this->processPrice($product, $price, $newConfig);
- break;
- case 'min_price':
- $price = $minPrice ?? $price;
- $prices[$field['label']] = $this->processPrice($product, $price, $newConfig);
- break;
- case 'max_price':
- $price = $maxPrice ?? $price;
- $prices[$field['label']] = $this->processPrice($product, $price, $newConfig);
- break;
- }
- } else {
- $prices[$field['label']] = $prices[$field['price_source']] ?? null;
- }
- }
- }
-
- return $prices;
- }
-
- /**
- * @param \Magento\Catalog\Model\Product $product
- * @param $config
- *
- * @return array|null
- */
- public function getGroupedPrices($product, $config)
- {
- $subProducts = $product->getTypeInstance()->getAssociatedProducts($product);
-
- $minPrice = null;
- $maxPrice = null;
- $totalPrice = null;
-
- foreach ($subProducts as $subProduct) {
- $subProduct->setWebsiteId($config['website_id']);
- if ($subProduct->isSalable()) {
- $price = $this->commonPriceModel->getCatalogPrice($subProduct);
- if ($price < $minPrice || $minPrice === null) {
- $minPrice = $this->commonPriceModel->getCatalogPrice($subProduct);
- $product->setTaxClassId($subProduct->getTaxClassId());
- }
- if ($price > $maxPrice || $maxPrice === null) {
- $maxPrice = $this->commonPriceModel->getCatalogPrice($subProduct);
- $product->setTaxClassId($subProduct->getTaxClassId());
- }
- if ($subProduct->getQty() > 0) {
- $totalPrice += $price * $subProduct->getQty();
- } else {
- $totalPrice += $price;
- }
- }
- }
-
- return ['min_price' => $minPrice, 'max_price' => $maxPrice, 'total_price' => $totalPrice];
- }
-
- /**
- * @param $product
- * @param array $config
- * @return array|null
- */
- public function processTierPrice($product, array $config): ?array
- {
- if (!$product->getData('tier_price')) {
- return null;
- }
-
- $reformattedTierPriced = [];
- foreach ($product->getData('tier_price') as $priceTier) {
- $price = $priceTier['percentage_value']
- ? $product->getPrice() * ($priceTier['percentage_value'] / 100)
- : $priceTier['value'];
-
- $reformattedTierPriced[] = [
- 'price_id' => $priceTier['value_id'],
- 'website_id' => $priceTier['website_id'],
- 'all_groups' => $priceTier['all_groups'],
- 'cust_group' => $priceTier['customer_group_id'],
- 'qty' => $priceTier['qty'],
- 'price' => $this->formatPrice($price, $config)
- ];
- }
-
- return $reformattedTierPriced;
- }
-
- /**
- * @param \Magento\Catalog\Model\Product $product
- * @param $price
- * @param $config
- * @param $includingTax
- *
- * @return float|string
- */
- public function processPrice($product, $price, $config, $includingTax = null)
- {
- if (!empty($config['exchange_rate'])) {
- $price = $price * $config['exchange_rate'];
- }
-
- if ($includingTax !== null) {
- return $this->formatPrice(
- $this->catalogHelper->getTaxPrice($product, $price, $includingTax),
- $config
- );
- }
-
- if (isset($config['incl_vat'])) {
- $price = $this->catalogHelper->getTaxPrice($product, $price, ['incl_vat']);
- }
-
- return $this->formatPrice($price, $config);
- }
-
- /**
- * @param $price
- * @param $config
- *
- * @return string
- */
- public function formatPrice($price, $config)
- {
- $decimal = isset($config['decimal_point']) ? $config['decimal_point'] : '.';
- $price = number_format(floatval(str_replace(',', '.', $price)), 2, $decimal, '');
- if (!empty($config['use_currency']) && ($price >= 0)) {
- $price .= ' ' . $config['currency'];
- }
- return $price;
- }
-
/**
* @param $attributes
* @param array $filters
diff --git a/Helper/Source.php b/Helper/Source.php
index b4d5e3a..db9512e 100755
--- a/Helper/Source.php
+++ b/Helper/Source.php
@@ -515,6 +515,10 @@ public function getAttributes($type, $filters = [], $storeId = null)
];
if ($type != 'api') {
+ $attributes['updated_at'] = [
+ 'label' => 'updated_at',
+ 'source' => 'updated_at',
+ ];
$attributes['created_at'] = [
'label' => 'created_at',
'source' => 'created_at',
diff --git a/Plugin/AddDiscountToInvoice.php b/Plugin/AddDiscountToInvoice.php
new file mode 100644
index 0000000..283eae8
--- /dev/null
+++ b/Plugin/AddDiscountToInvoice.php
@@ -0,0 +1,38 @@
+getOrder();
+ if ($order->getPayment()->getMethod() == 'channable') {
+ $discountAmount = abs((float)$order->getDiscountAmount());
+ if ($discountAmount > 0) {
+ $invoice->setDiscountAmount(-$discountAmount);
+ $invoice->setBaseDiscountAmount(-$discountAmount);
+ $invoice->setGrandTotal($invoice->getGrandTotal() - $discountAmount);
+ $invoice->setBaseGrandTotal($invoice->getBaseGrandTotal() - $discountAmount);
+ }
+ }
+
+ return $invoice;
+ }
+}
diff --git a/Service/Category/CategoryData.php b/Service/Category/CategoryData.php
index ac389e1..673d162 100644
--- a/Service/Category/CategoryData.php
+++ b/Service/Category/CategoryData.php
@@ -10,6 +10,7 @@
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory as CategoryCollectionFactory;
use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection;
use Magento\Framework\App\ResourceConnection;
+use Magento\Framework\Exception\LocalizedException;
use Magento\Store\Model\StoreManagerInterface;
class CategoryData
@@ -44,6 +45,7 @@ public function __construct(
* @param ProductCollection $parents
* @param int $storeId
* @return array
+ * @throws LocalizedException
*/
public function load(ProductCollection $products, ProductCollection $parents, int $storeId): array
{
@@ -68,13 +70,20 @@ public function load(ProductCollection $products, ProductCollection $parents, in
private function getCategoryIdsForCollection(array $productIds): array
{
$connection = $this->resourceConnection->getConnection();
- $tableName = $this->resourceConnection->getTableName('catalog_category_product');
+ $ccpTable = $this->resourceConnection->getTableName('catalog_category_product');
$select = $connection->select()
- ->from($tableName, 'category_id')
+ ->from($ccpTable, 'category_id')
->where('product_id IN (?)', $productIds)
->group('category_id');
+ $categoryIds = $connection->fetchCol($select);
+
+ $cceTable = $this->resourceConnection->getTableName('catalog_category_entity');
+ $select = $connection->select()
+ ->from($cceTable, 'entity_id')
+ ->where('entity_id IN (?) OR parent_id IN (?)', $categoryIds);
+
return $connection->fetchCol($select);
}
@@ -82,13 +91,17 @@ private function getCategoryIdsForCollection(array $productIds): array
* @param array $categoryIds
* @param int $storeId
* @return array
+ * @throws LocalizedException
*/
private function getCategoryTree(array $categoryIds, int $storeId): array
{
$collection = $this->categoryCollectionFactory->create()
->setStoreId($storeId)
->addAttributeToSelect(['name', 'level', 'path', 'url_path', self::EXCLUDE_ATTRIBUTE])
- ->addFieldToFilter('entity_id', ['in' => $categoryIds])
+ ->addFieldToFilter([
+ ['attribute' => 'entity_id', 'in' => $categoryIds],
+ ['attribute' => 'parent_id', 'in' => $categoryIds]
+ ])
->addFieldToFilter('is_active', ['eq' => 1]);
try {
diff --git a/Service/Order/Import.php b/Service/Order/Import.php
index a9c9e44..06d89e2 100755
--- a/Service/Order/Import.php
+++ b/Service/Order/Import.php
@@ -259,9 +259,9 @@ public function execute(ChannableOrderData $orderData): OrderInterface
if (isset($orderData['price']['discount']) && !empty((float)$orderData['price']['discount'])) {
$discountAmount = abs((float)$orderData['price']['discount']);
- $order->setDiscountDescription(__('Channable discount'));
- $order->setBaseDiscountAmount($discountAmount);
- $order->setDiscountAmount($discountAmount);
+ $order->setDiscountDescription($orderData['channel_name']);
+ $order->setBaseDiscountAmount($discountAmount * -1);
+ $order->setDiscountAmount($discountAmount * -1);
$order->setGrandTotal($order->getGrandTotal() - $discountAmount);
$order->setBaseGrandTotal($order->getBaseGrandTotal() - $discountAmount);
}
diff --git a/Service/Order/ImportSimulator.php b/Service/Order/ImportSimulator.php
index cea2389..d8b3fb4 100755
--- a/Service/Order/ImportSimulator.php
+++ b/Service/Order/ImportSimulator.php
@@ -174,7 +174,6 @@ public function getTestData(array $params): array
"middle_name" => "From",
"last_name" => "Channable",
"company" => "Do Not Ship",
- "vat_id" => 'NL0001',
"email" => "dontemail@me.net",
"address_line_1" => "Billing Line 1",
"address_line_2" => "Billing Line 2",
diff --git a/Service/Order/Items/Add.php b/Service/Order/Items/Add.php
index b186c77..83a4158 100644
--- a/Service/Order/Items/Add.php
+++ b/Service/Order/Items/Add.php
@@ -212,11 +212,10 @@ private function getProductPrice(
Quote $quote,
bool $isBusinessOrder
): float {
+ $price = (float)$item['price'];
if ($isBusinessOrder) {
- return (float)$item['price'];
+ return $price;
}
- $price = (float)$item['price'] - $this->getProductWeeTax($product, $quote);
-
if (!$this->configProvider->getNeedsTaxCalulcation('price', (int)$store->getId())) {
$request = $this->taxCalculation->getRateRequest(
$quote->getShippingAddress(),
@@ -231,7 +230,7 @@ private function getProductPrice(
$price = $price / (100 + $percent) * 100;
}
- return $price;
+ return $price - $this->getProductWeeTax($product, $quote);
}
/**
diff --git a/Service/Order/Quote/AddressHandler.php b/Service/Order/Quote/AddressHandler.php
index b05508e..1d06082 100644
--- a/Service/Order/Quote/AddressHandler.php
+++ b/Service/Order/Quote/AddressHandler.php
@@ -135,12 +135,9 @@ public function getAddressData(string $type, array $orderData, Quote $quote): ar
: null,
'postcode' => $address['zip_code'],
'telephone' => $telephone,
- 'vat_id' => !empty($address['vat_id']) ? $address['vat_id'] : null,
+ 'vat_id' => $this->getVatId($type, $orderData, $storeId),
'email' => $email
];
- if (isset($address['vat_number']) && $this->configProvider->isBusinessOrderEnabled()) {
- $addressData['vat_id'] = $address['vat_number'];
- }
if ($this->configProvider->createCustomerOnImport((int)$storeId)) {
$this->saveAddress($addressData, $customerId, $type);
@@ -149,6 +146,35 @@ public function getAddressData(string $type, array $orderData, Quote $quote): ar
return $addressData;
}
+ /**
+ * Channable only sets VAT ID on billing address
+ * In some cases we also need this on shipping address (due to OSS/MOSS)
+ *
+ * @param string $type
+ * @param array $orderData
+ * @param int $storeId
+ * @return string|null
+ */
+ private function getVatId(string $type, array $orderData, int $storeId): ?string
+ {
+ if (!$this->configProvider->isBusinessOrderEnabled($storeId)) {
+ return null;
+ }
+
+ $vatId = !empty($orderData['billing']['vat_number']) ? $orderData['billing']['vat_number'] : null;
+ if ($type == 'billing' || !$vatId) {
+ return $vatId;
+ }
+
+ if (empty($orderData['customer']['business_order']) || !$this->configProvider->importCompanyName($storeId)) {
+ return null;
+ }
+
+ return $orderData['billing']['company'] == $orderData['shipping']['company']
+ ? $vatId
+ : null;
+ }
+
/**
* Removed unwanted characters from email.
* Some Marketplaces add ":" to email what can cause import to fail.
diff --git a/Service/Product/PriceData.php b/Service/Product/PriceData.php
new file mode 100644
index 0000000..2f55ebf
--- /dev/null
+++ b/Service/Product/PriceData.php
@@ -0,0 +1,352 @@
+commonPriceModel = $commonPriceModel;
+ $this->ruleFactory = $ruleFactory;
+ $this->catalogHelper = $catalogHelper;
+ }
+
+ /**
+ * @param array $config
+ * @param Product $product
+ *
+ * @return array
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ */
+ public function execute(array $config, Product$product): array
+ {
+ switch ($product->getTypeId()) {
+ case 'configurable':
+ /**
+ * Check if config has a final_price (data catalog_product_index_price)
+ * If final_price === null product is not salable (out of stock)
+ */
+ if ($product->getData('final_price') === null) {
+ $price = 0;
+ $finalPrice = 0;
+ } else {
+ $price = $product->getData('price');
+ $finalPrice = $product->getData('final_price');
+ $specialPrice = $product->getSpecialPrice();
+ $product['min_price'] = $product['min_price'] >= 0 ? $product['min_price'] : null;
+ $product['max_price'] = $product['max_price'] >= 0 ? $product['max_price'] : null;
+ }
+ break;
+ case 'grouped':
+ $groupedPriceType = null;
+ if (!empty($config['price_config']['grouped_price_type'])) {
+ $groupedPriceType = $config['price_config']['grouped_price_type'];
+ }
+
+ $groupedPrices = $this->getGroupedPrices($product, $config);
+ $price = $groupedPrices['min_price'];
+ $finalPrice = $groupedPrices['min_price'];
+ $product['min_price'] = $groupedPrices['min_price'];
+ $product['max_price'] = $groupedPrices['max_price'];
+ $product['total_price'] = $groupedPrices['total_price'];
+
+ if ($groupedPriceType == 'max') {
+ $price = $groupedPrices['max_price'];
+ $finalPrice = $price;
+ }
+
+ if ($groupedPriceType == 'total') {
+ $price = $groupedPrices['total_price'];
+ $finalPrice = $price;
+ }
+
+ break;
+ case 'bundle':
+ $price = $product->getPrice();
+ $finalPrice = $product->getFinalPrice();
+ $specialPrice = $product->getSpecialPrice();
+ $rulePrice = $this->ruleFactory->create()->getRulePrice(
+ $config['timestamp'],
+ $config['website_id'],
+ '',
+ $product->getId()
+ );
+ if ($rulePrice !== null && $rulePrice !== false) {
+ $finalPrice = min($finalPrice, $rulePrice);
+ }
+ break;
+ default:
+ if ($product->getFinalPrice() !== null) {
+ $price = $product->getPrice();
+ $finalPrice = $product->getFinalPrice();
+ $specialPrice = $product->getSpecialPrice();
+ } else {
+ $finalPrice = $product->getPriceInfo()->getPrice('final_price')->getValue();
+ $price = $product->getPriceInfo()->getPrice('regular_price')->getValue();
+ $product['min_price'] = $product->getPriceInfo()->getPrice('final_price')->getMinimalPrice()->getBaseAmount();
+ $product['max_price'] = $product->getPriceInfo()->getPrice('final_price')->getMaximalPrice()->getBaseAmount();
+ }
+
+ $rulePrice = $this->ruleFactory->create()->getRulePrice(
+ $config['timestamp'],
+ $config['website_id'],
+ '',
+ $product->getId()
+ );
+
+ if ($rulePrice !== null && $rulePrice !== false) {
+ $finalPrice = min($finalPrice, $rulePrice);
+ }
+
+ break;
+ }
+ $prices = [];
+ $attributes = $config['attributes'];
+ $config = $config['price_config'];
+ $prices[$config['price']] = $this->processPrice($product, $price, $config);
+
+ if (!empty($config['tax_include_both'])) {
+ $prices[$config['price_excl']] = $this->processPrice($product, $price, $config, false);
+ $prices[$config['price_incl']] = $this->processPrice($product, $price, $config, true);
+ }
+
+ if (isset($finalPrice) && !empty($config['final_price'])) {
+ $prices[$config['final_price']] = $this->processPrice($product, $finalPrice, $config);
+ }
+
+ if (isset($finalPrice) && ($price > $finalPrice) && !empty($config['sales_price'])) {
+ $prices[$config['sales_price']] = $this->processPrice($product, $finalPrice, $config);
+ if (!empty($config['tax_include_both'])) {
+ $prices[$config['sales_price_excl']] = $this->processPrice($product, $finalPrice, $config, false);
+ $prices[$config['sales_price_incl']] = $this->processPrice($product, $finalPrice, $config, true);
+ }
+ }
+
+ if (isset($specialPrice) && ($specialPrice == $finalPrice) && !empty($config['sales_date_range'])) {
+ if ($product->getSpecialFromDate() && $product->getSpecialToDate()) {
+ $from = date('Y-m-d', strtotime($product->getSpecialFromDate()));
+ $to = date('Y-m-d', strtotime($product->getSpecialToDate()));
+ $prices[$config['sales_date_range']] = $from . '/' . $to;
+ }
+ }
+
+ if ($price <= 0) {
+ if (!empty($product['min_price'])) {
+ $minPrice = $product['min_price'];
+ $prices[$config['price']] = $this->processPrice($product, $minPrice, $config);
+ if (!empty($config['tax_include_both'])) {
+ $prices[$config['price_excl']] = $this->processPrice($product, $minPrice, $config, false);
+ $prices[$config['price_incl']] = $this->processPrice($product, $minPrice, $config, true);
+ }
+ }
+ }
+
+ if (!empty($product['min_price']) && !empty($config['min_price'])) {
+ if (($finalPrice > 0) && $finalPrice < $product['min_price']) {
+ $prices[$config['min_price']] = $this->processPrice($product, $finalPrice, $config);
+ } else {
+ $prices[$config['min_price']] = $this->processPrice($product, $product['min_price'], $config);
+ }
+ }
+
+ if (!empty($product['max_price']) && !empty($config['max_price'])) {
+ $prices[$config['max_price']] = $this->processPrice($product, $product['max_price'], $config);
+ }
+
+ if (!empty($product['total_price']) && !empty($config['total_price'])) {
+ $prices[$config['total_price']] = $this->processPrice($product, $product['total_price'], $config);
+ }
+
+ if (!empty($config['discount_perc']) && isset($prices[$config['sales_price']])) {
+ if ($prices[$config['price']] > 0) {
+ $discount = ($prices[$config['sales_price']] - $prices[$config['price']]) / $prices[$config['price']];
+ $discount = $discount * -100;
+ if ($discount > 0) {
+ $prices[$config['discount_perc']] = round($discount, 1) . '%';
+ }
+ }
+ }
+
+ if ($extraRenderedPriceFields = preg_grep('/^rendered_price__/', array_keys($attributes))) {
+ foreach ($extraRenderedPriceFields as $label) {
+ $field = $attributes[$label];
+ $renderCurrency = $field['actions'][0] ? explode('_', $field['actions'][0])[1] : null;
+ if ($renderCurrency !== $config['currency']) {
+ $newConfig = $config;
+ $newConfig['currency'] = $renderCurrency;
+ $newConfig['exchange_rate'] = $config['exchange_rate_' . $renderCurrency] ?? 1;
+ switch ($field['price_source']) {
+ case 'price':
+ $prices[$field['label']] = $this->processPrice($product, $price, $newConfig);
+ break;
+ case 'min_price':
+ $price = $minPrice ?? $price;
+ $prices[$field['label']] = $this->processPrice($product, $price, $newConfig);
+ break;
+ case 'max_price':
+ $price = $maxPrice ?? $price;
+ $prices[$field['label']] = $this->processPrice($product, $price, $newConfig);
+ break;
+ }
+ } else {
+ $prices[$field['label']] = $prices[$field['price_source']] ?? null;
+ }
+ }
+ }
+
+ return $prices;
+ }
+
+ /**
+ * @param Product $product
+ * @param array $config
+ *
+ * @return array|null
+ */
+ public function getGroupedPrices(Product $product, array $config): ?array
+ {
+ $subProducts = $product->getTypeInstance()->getAssociatedProducts($product);
+
+ $minPrice = null;
+ $maxPrice = null;
+ $totalPrice = null;
+
+ foreach ($subProducts as $subProduct) {
+ $subProduct->setWebsiteId($config['website_id']);
+ if ($subProduct->isSalable()) {
+ $price = $this->commonPriceModel->getCatalogPrice($subProduct);
+ if ($price < $minPrice || $minPrice === null) {
+ $minPrice = $this->commonPriceModel->getCatalogPrice($subProduct);
+ $product->setTaxClassId($subProduct->getTaxClassId());
+ }
+ if ($price > $maxPrice || $maxPrice === null) {
+ $maxPrice = $this->commonPriceModel->getCatalogPrice($subProduct);
+ $product->setTaxClassId($subProduct->getTaxClassId());
+ }
+ if ($subProduct->getQty() > 0) {
+ $totalPrice += $price * $subProduct->getQty();
+ } else {
+ $totalPrice += $price;
+ }
+ }
+ }
+
+ return ['min_price' => $minPrice, 'max_price' => $maxPrice, 'total_price' => $totalPrice];
+ }
+
+ /**
+ * @param Product $product
+ * @param $price
+ * @param array $config
+ * @param bool|null $includingTax
+ *
+ * @return string
+ */
+ public function processPrice(Product $product, $price, array $config, ?bool $includingTax = null): string
+ {
+ if (!empty($config['exchange_rate'])) {
+ $price = $price * $config['exchange_rate'];
+ }
+
+ if ($includingTax !== null) {
+ return $this->formatPrice(
+ $this->catalogHelper->getTaxPrice($product, $price, $includingTax),
+ $config
+ );
+ }
+
+ if (isset($config['incl_vat'])) {
+ $price = $this->catalogHelper->getTaxPrice($product, $price, ['incl_vat']);
+ }
+
+ return $this->formatPrice($price, $config);
+ }
+
+ /**
+ * Format a price based on the provided configuration.
+ *
+ * @param float|string $price The price value to be formatted.
+ * @param array $config Configuration options for formatting.
+ * @return string The formatted price.
+ */
+ public function formatPrice($price, array $config): string
+ {
+ $decimalPoint = $config['decimal_point'] ?? '.';
+ $currency = $config['currency'] ?? '';
+ $useCurrency = !empty($config['use_currency']);
+
+ // Ensure the price is converted to a float.
+ $formattedPrice = number_format(
+ floatval(str_replace(',', '.', (string)$price)),
+ 2,
+ $decimalPoint,
+ ''
+ );
+
+ // Append currency if configured.
+ if ($useCurrency && $formattedPrice >= 0) {
+ $formattedPrice .= ' ' . $currency;
+ }
+
+ return $formattedPrice;
+ }
+
+ /**
+ * Process tier pricing for a product.
+ *
+ * @param Product $product The product instance.
+ * @param array $config Configuration for price formatting.
+ * @return array|null An array of reformatted tier prices or null if none exist.
+ */
+ public function processTierPrice(Product $product, array $config): ?array
+ {
+ if (!$tierPrices = $product->getData('tier_price')) {
+ return null;
+ }
+
+ $reformattedTierPrices = [];
+ foreach ($tierPrices as $priceTier) {
+ $price = !empty($priceTier['percentage_value'])
+ ? $product->getPrice() * (1 - ($priceTier['percentage_value'] / 100)) // Subtract discount
+ : $priceTier['value'];
+
+ $reformattedTierPrices[] = [
+ 'price_id' => $priceTier['value_id'] ?? null,
+ 'website_id' => $priceTier['website_id'] ?? null,
+ 'all_groups' => $priceTier['all_groups'] ?? 0,
+ 'cust_group' => $priceTier['customer_group_id'] ?? null,
+ 'qty' => $priceTier['qty'] ?? 0,
+ 'price' => $this->formatPrice($price, $config)
+ ];
+ }
+
+ return $reformattedTierPrices;
+ }
+}
\ No newline at end of file
diff --git a/Service/Product/TierPriceData.php b/Service/Product/TierPriceData.php
index 340579f..69d8c7c 100644
--- a/Service/Product/TierPriceData.php
+++ b/Service/Product/TierPriceData.php
@@ -43,6 +43,7 @@ public function __construct(
/**
* @param ProductCollection $products
* @param ProductCollection $parents
+ * @param $websiteId
* @return void
*/
public function load(ProductCollection $products, ProductCollection $parents, $websiteId)
diff --git a/Service/Returns/CreateCreditmemo.php b/Service/Returns/CreateCreditmemo.php
index e00df8a..ed8c06f 100644
--- a/Service/Returns/CreateCreditmemo.php
+++ b/Service/Returns/CreateCreditmemo.php
@@ -43,27 +43,25 @@ class CreateCreditmemo
* @var CreditmemoRepositoryInterface
*/
private $creditmemoRepositoryInterface;
-
/**
- * ProcessReturn constructor.
- * @param ReturnsRepository $returnsRepository
- * @param ResourceConnection $resource
- * @param RefundOrder $refundOrder
- * @param ItemCreationFactory $itemCreationFactory
- * @param CreditmemoRepositoryInterface $creditmemoRepositoryInterface
+ * @var GetSkuFromGtin
*/
+ private $getSkuFromGtin;
+
public function __construct(
ReturnsRepository $returnsRepository,
ResourceConnection $resource,
RefundOrder $refundOrder,
ItemCreationFactory $itemCreationFactory,
- CreditmemoRepositoryInterface $creditmemoRepositoryInterface
+ CreditmemoRepositoryInterface $creditmemoRepositoryInterface,
+ GetSkuFromGtin $getSkuFromGtin
) {
$this->returnsRepository = $returnsRepository;
$this->resource = $resource;
$this->refundOrder = $refundOrder;
$this->itemCreationFactory = $itemCreationFactory;
$this->creditmemoRepositoryInterface = $creditmemoRepositoryInterface;
+ $this->getSkuFromGtin = $getSkuFromGtin;
}
/**
@@ -81,9 +79,14 @@ public function execute(ReturnsData $return, ?string $status): string
}
$item = $return->getItem();
- $itemId = $this->findOrderItemId($item, $orderId);
+ $sku = $this->getSkuFromGtin->execute($item['gtin'] ?? null, (int)$return->getStoreId());
+ if (!$sku) {
+ throw new InputException(__('Unable to find SKU for GTIN.'));
+ }
+
+ $itemId = $this->findOrderItemId($sku, $orderId);
if (!$itemId) {
- throw new InputException(__('Unable to locate the order Item-ID if imported return.'));
+ throw new InputException(__('Unable to locate the order Item-ID for imported return.'));
}
$creditmemoItem = $this->itemCreationFactory->create();
@@ -99,11 +102,11 @@ public function execute(ReturnsData $return, ?string $status): string
}
/**
- * @param array $item
+ * @param string $sku
* @param int $orderId
* @return ?int
*/
- private function findOrderItemId(array $item, int $orderId): ?int
+ private function findOrderItemId(string $sku, int $orderId): ?int
{
$connection = $this->resource->getConnection();
@@ -113,7 +116,7 @@ private function findOrderItemId(array $item, int $orderId): ?int
->where('order_id = :order_id');
$bind = [
- ':sku' => $item['gtin'],
+ ':sku' => $sku,
':order_id' => $orderId
];
diff --git a/Service/Returns/GetByOrder.php b/Service/Returns/GetByOrder.php
index b8f1ba9..5b7cf8f 100644
--- a/Service/Returns/GetByOrder.php
+++ b/Service/Returns/GetByOrder.php
@@ -7,60 +7,34 @@
namespace Magmodules\Channable\Service\Returns;
-use Magento\Catalog\Model\ProductFactory;
use Magento\Framework\Serialize\Serializer\Json;
use Magento\Sales\Model\Order;
-use Magmodules\Channable\Api\Config\RepositoryInterface as ConfigProvider;
-use Magmodules\Channable\Api\Log\RepositoryInterface as LogRepository;
use Magmodules\Channable\Api\Returns\Data\DataInterface as ReturnsDataInterface;
use Magmodules\Channable\Api\Returns\RepositoryInterface as ReturnsRepository;
class GetByOrder
{
- /**
- * @var string
- */
- private $gtinAttribute;
/**
* @var ReturnsRepository
*/
private $returnsRepository;
- /**
- * @var ProductFactory
- */
- private $productFactory;
- /**
- * @var ConfigProvider
- */
- private $configProvider;
- /**
- * @var LogRepository
- */
- private $logRepository;
/**
* @var Json
*/
private $json;
-
/**
- * @param ReturnsRepository $returnsRepository
- * @param ProductFactory $productFactory
- * @param ConfigProvider $configProvider
- * @param LogRepository $logRepository
- * @param Json $json
+ * @var GetSkuFromGtin
*/
+ private $getSkuFromGtin;
+
public function __construct(
ReturnsRepository $returnsRepository,
- ProductFactory $productFactory,
- ConfigProvider $configProvider,
- LogRepository $logRepository,
+ GetSkuFromGtin $getSkuFromGtin,
Json $json
) {
$this->returnsRepository = $returnsRepository;
- $this->productFactory = $productFactory;
- $this->configProvider = $configProvider;
- $this->logRepository = $logRepository;
+ $this->getSkuFromGtin = $getSkuFromGtin;
$this->json = $json;
}
@@ -101,55 +75,14 @@ public function execute(Order $order): ?array
private function getSkuFromReturnData($itemData, int $storeId): ?string
{
if (is_array($itemData)) {
- return $this->getSkuFromGtin($itemData['gtin'] ?? null, $storeId);
+ return $this->getSkuFromGtin->execute($itemData['gtin'] ?? null, $storeId);
}
try {
$itemData = $this->json->unserialize($itemData);
- return $this->getSkuFromGtin($itemData['gtin'] ?? null, $storeId);
+ return $this->getSkuFromGtin->execute($itemData['gtin'] ?? null, $storeId);
} catch (\Exception $exception) {
return null;
}
}
-
- /**
- * @param string $gtin
- * @param int $storeId
- * @return string|null
- */
- private function getSkuFromGtin(string $gtin, int $storeId): ?string
- {
- $gtinAttribute = $this->getGtinAttributeCode($storeId);
- if ($gtinAttribute == 'sku' || $gtinAttribute == null) {
- return $gtin;
- }
-
- try {
- if ($gtinAttribute == 'id') {
- if ($product = $this->productFactory->create()->load($gtin)) {
- return $product->getSku();
- }
- }
- if ($product = $this->productFactory->create()->loadByAttribute($gtinAttribute, $gtin)) {
- return $product->getSku();
- }
- } catch (\Exception $exception) {
- $this->logRepository->addErrorLog('getSkuFromGtin', $exception->getMessage());
- }
-
- return $gtin;
- }
-
- /**
- * @param int $storeId
- * @return string
- */
- private function getGtinAttributeCode(int $storeId): string
- {
- if (!$this->gtinAttribute) {
- $this->gtinAttribute = $this->configProvider->getGtinAttribute($storeId);
- }
-
- return $this->gtinAttribute;
- }
}
diff --git a/Service/Returns/GetSkuFromGtin.php b/Service/Returns/GetSkuFromGtin.php
new file mode 100644
index 0000000..9431cd6
--- /dev/null
+++ b/Service/Returns/GetSkuFromGtin.php
@@ -0,0 +1,88 @@
+productFactory = $productFactory;
+ $this->configProvider = $configProvider;
+ $this->logRepository = $logRepository;
+ }
+
+ /**
+ * @param string|null $gtin
+ * @param int $storeId
+ * @return string|null
+ */
+ public function execute(?string $gtin, int $storeId): ?string
+ {
+ $gtinAttribute = $this->getGtinAttributeCode($storeId);
+ if ($gtinAttribute == 'sku' || $gtinAttribute == null || $gtin == null) {
+ return $gtin;
+ }
+
+ try {
+ if ($gtinAttribute == 'id') {
+ if ($product = $this->productFactory->create()->load($gtin)) {
+ return $product->getSku();
+ }
+ }
+ if ($product = $this->productFactory->create()->loadByAttribute($gtinAttribute, $gtin)) {
+ return $product->getSku();
+ }
+ } catch (\Exception $exception) {
+ $this->logRepository->addErrorLog('getSkuFromGtin', $exception->getMessage());
+ }
+
+ return null;
+ }
+
+ /**
+ * @param int $storeId
+ * @return string
+ */
+ private function getGtinAttributeCode(int $storeId): string
+ {
+ if (!$this->gtinAttribute) {
+ $this->gtinAttribute = $this->configProvider->getGtinAttribute($storeId);
+ }
+
+ return $this->gtinAttribute;
+ }
+}
diff --git a/composer.json b/composer.json
index 760acb0..1dc0849 100755
--- a/composer.json
+++ b/composer.json
@@ -2,7 +2,7 @@
"name": "magmodules/magento2-channable",
"description": "Channable integration for Magento 2",
"type": "magento2-module",
- "version": "1.19.1",
+ "version": "1.20.0",
"license": "BSD-2-Clause",
"homepage": "https://github.com/magmodules/magento2-channable",
"require": {
diff --git a/etc/config.xml b/etc/config.xml
index f663b10..3356f09 100644
--- a/etc/config.xml
+++ b/etc/config.xml
@@ -12,7 +12,7 @@
0
250
- v1.19.1
+ v1.20.0
name
diff --git a/etc/di.xml b/etc/di.xml
index bdaaa39..79f2456 100755
--- a/etc/di.xml
+++ b/etc/di.xml
@@ -86,6 +86,10 @@
+
+
+
+