diff --git a/Api/Config/System/ReturnsInterface.php b/Api/Config/System/ReturnsInterface.php index dac9ca8..5f24df0 100644 --- a/Api/Config/System/ReturnsInterface.php +++ b/Api/Config/System/ReturnsInterface.php @@ -18,6 +18,7 @@ interface ReturnsInterface extends ItemupdateInterface public const XML_PATH_RETURNS_ENABLE = 'magmodules_channable_marketplace/returns/enable'; public const XML_PATH_RETURNS_CREDITMEMO = 'magmodules_channable_marketplace/returns/show_on_creditmemo'; public const XML_PATH_RETURNS_AUTO_MATCH = 'magmodules_channable_marketplace/returns/auto_update'; + public const XML_PATH_GTIN_ATTRIBUTE = 'magmodules_channable/data/ean_attribute'; /** * Check whether returns are enabled @@ -55,4 +56,12 @@ public function getReturnsWebhookUrl(int $storeId): string; * @return bool */ public function autoUpdateReturnsOnCreditmemo(int $storeId = null): bool; + + /** + * Returns attribute set as GTIN + * + * @param int|null $storeId + * @return string + */ + public function getGtinAttribute(int $storeId = null): string; } diff --git a/Helper/Product.php b/Helper/Product.php index f15faf3..c96a828 100644 --- a/Helper/Product.php +++ b/Helper/Product.php @@ -1008,8 +1008,8 @@ public function getPriceCollection($config, $product) $finalPrice = $product->getFinalPrice(); $specialPrice = $product->getSpecialPrice(); } else { - $finalPrice = $product->getPriceInfo()->getPrice('final_price')->getAmount()->getValue(); - $price = $product->getPriceInfo()->getPrice('regular_price')->getAmount()->getValue(); + $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(); } diff --git a/Helper/Source.php b/Helper/Source.php index a420610..a8d58d3 100755 --- a/Helper/Source.php +++ b/Helper/Source.php @@ -44,6 +44,7 @@ class Source extends AbstractHelper const XPATH_INVENTORY = 'magmodules_channable/advanced/inventory'; const XPATH_INVENTORY_DATA = 'magmodules_channable/advanced/inventory_fields'; const XPATH_FORCE_NON_MSI = 'magmodules_channable/advanced/force_non_msi'; + const XPATH_INVENTORY_SOURCE_ITEMS = 'magmodules_channable/advanced/inventory_source_items'; const XPATH_TAX = 'magmodules_channable/advanced/tax'; const XPATH_TAX_INCLUDE_BOTH = 'magmodules_channable/advanced/tax_include_both'; const XPATH_MANAGE_STOCK = 'cataloginventory/item_options/manage_stock'; @@ -612,6 +613,14 @@ public function getAttributes($type, $filters = [], $storeId = null) 'source' => 'backorders' ]; } + + if ($this->getStoreValue(self::XPATH_INVENTORY_SOURCE_ITEMS)) { + $attributes['inventory_source_items'] = [ + 'label' => 'inventory_source_items', + 'source' => 'inventory_source_items' + ]; + } + } $attributes['weight'] = [ 'label' => 'shipping_weight', @@ -791,6 +800,7 @@ public function getInventoryData($type) $invAtt['stock_id'] = null; } else { $invAtt['stock_id'] = $this->inventorySource->execute($websiteCode); + $invAtt['inventory_source_items'] = (bool)$this->getStoreValue(self::XPATH_INVENTORY_SOURCE_ITEMS); } return $invAtt; diff --git a/Model/Config/System/ReturnsRepository.php b/Model/Config/System/ReturnsRepository.php index e81ce02..4e401e8 100644 --- a/Model/Config/System/ReturnsRepository.php +++ b/Model/Config/System/ReturnsRepository.php @@ -48,4 +48,13 @@ public function showOnCreditmemoCreation(int $storeId = null): bool return $this->getStoreValue(self::XML_PATH_RETURNS_CREDITMEMO, $storeId) && $this->isReturnsEnabled($storeId); } + + /** + * @param int|null $storeId + * @return string + */ + public function getGtinAttribute(int $storeId = null): string + { + return $this->getStoreValue(self::XML_PATH_GTIN_ATTRIBUTE, (int)$storeId) ?: 'sku'; + } } diff --git a/Model/Generate.php b/Model/Generate.php index b8897ac..456572e 100644 --- a/Model/Generate.php +++ b/Model/Generate.php @@ -108,10 +108,10 @@ public function generateByStore( $config = $this->sourceHelper->getConfig($storeId, $type, $currency); $productCollection = $this->productModel->getCollection($config, $page, $productIds); - $size = $this->productModel->getCollectionCountWithFilters($productCollection); + $size = $productCollection->getSize(); if (($config['filters']['limit'] > 0) && empty($productIds)) { - $productCollection->setPage($page, $config['filters']['limit'])->getCurPage(); + $productCollection->setPage($page, $config['filters']['limit']); $pages = ceil($size / $config['filters']['limit']); } diff --git a/Service/Order/Shipping/CalculatePrice.php b/Service/Order/Shipping/CalculatePrice.php index 27ea76d..1885fab 100644 --- a/Service/Order/Shipping/CalculatePrice.php +++ b/Service/Order/Shipping/CalculatePrice.php @@ -67,15 +67,18 @@ public function __construct( */ public function execute(Quote $quote, array $orderData, StoreInterface $store): float { - $taxCalculation = $this->configProvider->getNeedsTaxCalulcation('shipping', (int)$store->getId()); - $amount = (float)$orderData['price']['shipping']; - $baseCurrency = $this->storeManager->getStore($quote->getStoreId())->getBaseCurrencyCode(); - if ($baseCurrency != $orderData['price']['currency']) { + if ($amount == 0) { + return $amount; + } + + $baseCurrency = $this->getBaseCurrency($quote); + if ($baseCurrency && $baseCurrency != $orderData['price']['currency']) { $rate = $this->priceManager->convert($amount, $quote->getStoreId()) / $amount; $amount = $amount / $rate; } + $taxCalculation = $this->configProvider->getNeedsTaxCalulcation('shipping', (int)$store->getId()); if (empty($taxCalculation)) { $shippingAddress = $quote->getShippingAddress(); $billingAddress = $quote->getBillingAddress(); @@ -87,4 +90,17 @@ public function execute(Quote $quote, array $orderData, StoreInterface $store): return $amount; } + + /** + * @param Quote $quote + * @return string|null + */ + private function getBaseCurrency(Quote $quote): ?string + { + try { + return $this->storeManager->getStore($quote->getStoreId())->getBaseCurrencyCode(); + } catch (\Exception $exception) { + return null; + } + } } \ No newline at end of file diff --git a/Service/Product/InventoryData.php b/Service/Product/InventoryData.php index a067ca9..5b3339a 100644 --- a/Service/Product/InventoryData.php +++ b/Service/Product/InventoryData.php @@ -23,7 +23,10 @@ class InventoryData * @var array */ private $inventory; - + /** + * @var array + */ + private $inventorySourceItems; /** * @var array */ @@ -45,7 +48,6 @@ public function __construct( * * @param array $skus * @param int $stockId - * * @return void */ private function getInventoryData(array $skus, int $stockId): void @@ -67,6 +69,31 @@ private function getInventoryData(array $skus, int $stockId): void } } + /** + * Get Inventory Data by SKU and StockID + * + * @param array $skus + * @return void + */ + private function getInventorySourceItems(array $skus): void + { + $connection = $this->resourceConnection->getConnection(); + $tableName = $this->resourceConnection->getTableName('inventory_source_item'); + + if (!$connection->isTableExists($tableName)) { + return; + } + + $select = $connection->select() + ->from($tableName) + ->where('sku IN (?)', $skus); + + $inventoryData = $connection->fetchAll($select); + foreach ($inventoryData as $data) { + $this->inventorySourceItems[$data['sku']][$data['source_code']] = $data['quantity']; + } + } + /** * Returns number of reservations by SKU & StockId * @@ -108,6 +135,9 @@ public function load(array $skus, array $config): void if (isset($config['inventory']['stock_id'])) { $this->getInventoryData($skus, (int)$config['inventory']['stock_id']); $this->getReservations($skus, (int)$config['inventory']['stock_id']); + if (!empty($config['inventory']['inventory_source_items'])) { + $this->getInventorySourceItems($skus); + } } } @@ -129,12 +159,14 @@ public function addDataToProduct(Product $product, array $config): Product $inventoryData = $this->inventory[$config['inventory']['stock_id']][$product->getSku()] ?? []; $reservations = $this->reservation[$config['inventory']['stock_id']][$product->getSku()] ?? 0; + $sourceItems = $this->inventorySourceItems[$product->getSku()] ?? []; $qty = isset($inventoryData['quantity']) ? $inventoryData['quantity'] - $reservations : 0; $isSalable = $inventoryData['is_salable'] ?? 0; return $product->setQty($qty) ->setIsSalable($isSalable) - ->setIsInStock($isSalable); + ->setIsInStock($isSalable) + ->setInventorySourceItems($sourceItems); } } diff --git a/Service/Returns/GetByOrder.php b/Service/Returns/GetByOrder.php index ca2f8ab..b8f1ba9 100644 --- a/Service/Returns/GetByOrder.php +++ b/Service/Returns/GetByOrder.php @@ -7,18 +7,37 @@ 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 */ @@ -26,13 +45,22 @@ class GetByOrder /** * @param ReturnsRepository $returnsRepository + * @param ProductFactory $productFactory + * @param ConfigProvider $configProvider + * @param LogRepository $logRepository * @param Json $json */ public function __construct( ReturnsRepository $returnsRepository, + ProductFactory $productFactory, + ConfigProvider $configProvider, + LogRepository $logRepository, Json $json ) { $this->returnsRepository = $returnsRepository; + $this->productFactory = $productFactory; + $this->configProvider = $configProvider; + $this->logRepository = $logRepository; $this->json = $json; } @@ -54,8 +82,9 @@ public function execute(Order $order): ?array } $returnsArray = []; + /** @var ReturnsDataInterface $return */ foreach ($returns as $return) { - if (!$sku = $this->getSkuFromReturnData($return->getItem())) { + if (!$sku = $this->getSkuFromReturnData($return->getItem(), (int)$return->getStoreId())) { continue; } $returnsArray[$sku] = $return; @@ -66,19 +95,61 @@ public function execute(Order $order): ?array /** * @param $itemData + * @param int $storeId * @return string|null */ - private function getSkuFromReturnData($itemData): ?string + private function getSkuFromReturnData($itemData, int $storeId): ?string { if (is_array($itemData)) { - return $itemData['gtin'] ?? null; + return $this->getSkuFromGtin($itemData['gtin'] ?? null, $storeId); } try { $itemData = $this->json->unserialize($itemData); - return $itemData['gtin'] ?? null; + return $this->getSkuFromGtin($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/composer.json b/composer.json index 3325fe7..39f4246 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.17.0", + "version": "1.18.0", "license": "BSD-2-Clause", "homepage": "https://github.com/magmodules/magento2-channable", "require": { diff --git a/etc/adminhtml/system/feed.xml b/etc/adminhtml/system/feed.xml index 242a212..9094ca7 100644 --- a/etc/adminhtml/system/feed.xml +++ b/etc/adminhtml/system/feed.xml @@ -401,6 +401,14 @@ 1 + + + Magento\Config\Model\Config\Source\Yesno + magmodules_channable/advanced/inventory_source_items + + 1 + + Magmodules\Channable\Block\Adminhtml\Design\Heading diff --git a/etc/config.xml b/etc/config.xml index bdf7d04..3eca57c 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -12,7 +12,7 @@ 0 250 - v1.17.0 + v1.18.0 name diff --git a/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml b/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml new file mode 100644 index 0000000..fbe3cc7 --- /dev/null +++ b/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml @@ -0,0 +1,12 @@ + + + + + + +