Skip to content

Commit 419c840

Browse files
Feature: auto process 'complete' returns option
1 parent fa3eb1d commit 419c840

7 files changed

Lines changed: 108 additions & 118 deletions

File tree

Api/Config/System/ReturnsInterface.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ interface ReturnsInterface extends ItemupdateInterface
1818
public const XML_PATH_RETURNS_ENABLE = 'magmodules_channable_marketplace/returns/enable';
1919
public const XML_PATH_RETURNS_CREDITMEMO = 'magmodules_channable_marketplace/returns/show_on_creditmemo';
2020
public const XML_PATH_RETURNS_AUTO_MATCH = 'magmodules_channable_marketplace/returns/auto_update';
21+
public const XML_PATH_RETURNS_AUTO_PROCESS = 'magmodules_channable_marketplace/returns/auto_process_complete';
2122
public const XML_PATH_GTIN_ATTRIBUTE = 'magmodules_channable/data/ean_attribute';
2223

2324
/**
@@ -53,6 +54,14 @@ public function getReturnsWebhookUrl(int $storeId): string;
5354
*/
5455
public function autoUpdateReturnsOnCreditmemo(?int $storeId = null): bool;
5556

57+
/**
58+
* Check whether returns should be automatically processed
59+
*
60+
* @param int|null $storeId
61+
* @return bool
62+
*/
63+
public function autoProcessCompeteReturns(?int $storeId = null): bool;
64+
5665
/**
5766
* Returns attribute set as GTIN
5867
*

Model/Config/System/ReturnsRepository.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ public function autoUpdateReturnsOnCreditmemo(?int $storeId = null): bool
4040
return (bool)$this->getStoreValue(self::XML_PATH_RETURNS_AUTO_MATCH, (int)$storeId);
4141
}
4242

43+
/**
44+
* @inheritDoc
45+
*/
46+
public function autoProcessCompeteReturns(?int $storeId = null): bool
47+
{
48+
return (bool)$this->getStoreValue(self::XML_PATH_RETURNS_AUTO_PROCESS, (int)$storeId);
49+
}
50+
4351
/**
4452
* @inheritDoc
4553
*/

Service/Returns/CreateCreditmemo.php

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,36 +17,15 @@
1717
use Magmodules\Channable\Api\Returns\Data\DataInterface as ReturnsData;
1818
use Magmodules\Channable\Api\Returns\RepositoryInterface as ReturnsRepository;
1919

20-
/**
21-
* Class ProcessReturn
22-
*/
2320
class CreateCreditmemo
2421
{
2522

26-
/**
27-
* @var ReturnsRepository
28-
*/
29-
private $returnsRepository;
30-
/**
31-
* @var RefundOrder
32-
*/
33-
private $refundOrder;
34-
/**
35-
* @var ItemCreationFactory
36-
*/
37-
private $itemCreationFactory;
38-
/**
39-
* @var ResourceConnection
40-
*/
41-
private $resource;
42-
/**
43-
* @var CreditmemoRepositoryInterface
44-
*/
45-
private $creditmemoRepositoryInterface;
46-
/**
47-
* @var GetSkuFromGtin
48-
*/
49-
private $getSkuFromGtin;
23+
private ReturnsRepository $returnsRepository;
24+
private ResourceConnection $resource;
25+
private RefundOrder $refundOrder;
26+
private ItemCreationFactory $itemCreationFactory;
27+
private CreditmemoRepositoryInterface $creditmemoRepositoryInterface;
28+
private GetSkuFromGtin $getSkuFromGtin;
5029

5130
public function __construct(
5231
ReturnsRepository $returnsRepository,
@@ -79,20 +58,32 @@ public function execute(ReturnsData $return, ?string $status): string
7958
}
8059

8160
$item = $return->getItem();
82-
$sku = $this->getSkuFromGtin->execute($item['gtin'] ?? null, (int)$return->getStoreId());
83-
if (!$sku) {
61+
if (!isset($item['gtin'])) {
62+
throw new InputException(__('GTIN is missing in return item data.'));
63+
}
64+
65+
if (!$sku = $this->getSkuFromGtin->execute($item['gtin'], (int)$return->getStoreId())) {
8466
throw new InputException(__('Unable to find SKU for GTIN.'));
8567
}
8668

87-
$itemId = $this->findOrderItemId($sku, $orderId);
69+
$itemId = $this->getOrderItemIdBySku($sku, $orderId);
8870
if (!$itemId) {
8971
throw new InputException(__('Unable to locate the order Item-ID for imported return.'));
9072
}
9173

9274
$creditmemoItem = $this->itemCreationFactory->create();
75+
76+
if (!isset($item['quantity'])) {
77+
throw new InputException(__('Missing quantity for credit memo item.'));
78+
}
79+
80+
if (!is_numeric($item['quantity']) || $item['quantity'] <= 0) {
81+
throw new InputException(__('Invalid quantity value.'));
82+
}
83+
9384
$creditmemoItem->setQty($item['quantity'])->setOrderItemId($itemId);
9485

95-
$itemIdsToRefund[] = $creditmemoItem;
86+
$itemIdsToRefund = [$creditmemoItem];
9687
$creditmemoId = $this->refundOrder->execute($orderId, $itemIdsToRefund);
9788

9889
$creditmemo = $this->creditmemoRepositoryInterface->get($creditmemoId);
@@ -104,9 +95,9 @@ public function execute(ReturnsData $return, ?string $status): string
10495
/**
10596
* @param string $sku
10697
* @param int $orderId
107-
* @return ?int
98+
* @return int|null
10899
*/
109-
private function findOrderItemId(string $sku, int $orderId): ?int
100+
private function getOrderItemIdBySku(string $sku, int $orderId): ?int
110101
{
111102
$connection = $this->resource->getConnection();
112103

Service/Returns/ImportReturn.php

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,37 +10,37 @@
1010
use Exception;
1111
use Magento\Framework\App\ResourceConnection;
1212
use Magento\Framework\Stdlib\ArrayManager;
13+
use Magmodules\Channable\Api\Returns\Data\DataInterface as ReturnData;
1314
use Magmodules\Channable\Api\Returns\RepositoryInterface as ReturnsRepository;
15+
use Magmodules\Channable\Api\Log\RepositoryInterface as LogRepository;
16+
use Magmodules\Channable\Api\Config\RepositoryInterface as ConfigProvider;
1417

1518
class ImportReturn
1619
{
1720

18-
/**
19-
* @var ReturnsRepository
20-
*/
21-
private $returnsRepository;
22-
/**
23-
* @var ResourceConnection
24-
*/
25-
private $resource;
26-
/**
27-
* @var ArrayManager
28-
*/
29-
private $arrayManager;
21+
public const AUTO_PROCESS = ['complete', 'accepted'];
22+
23+
private CreateCreditmemo $createCreditmemo;
24+
private ReturnsRepository $returnsRepository;
25+
private ResourceConnection $resource;
26+
private ArrayManager $arrayManager;
27+
private ConfigProvider $configProvider;
28+
private LogRepository $logRepository;
3029

31-
/**
32-
* @param ResourceConnection $resource
33-
* @param ReturnsRepository $returnsRepository
34-
* @param ArrayManager $arrayManager
35-
*/
3630
public function __construct(
31+
CreateCreditmemo $createCreditmemo,
3732
ResourceConnection $resource,
3833
ReturnsRepository $returnsRepository,
39-
ArrayManager $arrayManager
34+
ArrayManager $arrayManager,
35+
ConfigProvider $configProvider,
36+
LogRepository $logRepository
4037
) {
38+
$this->createCreditmemo = $createCreditmemo;
4139
$this->returnsRepository = $returnsRepository;
4240
$this->resource = $resource;
4341
$this->arrayManager = $arrayManager;
42+
$this->configProvider = $configProvider;
43+
$this->logRepository = $logRepository;
4444
}
4545

4646
/**
@@ -59,9 +59,9 @@ public function execute(array $returnData, int $storeId): array
5959
$address = $returnData['address'] ?? [];
6060
$orderIncrementId = $item['order_id'] ?? null;
6161

62-
$returns = $this->returnsRepository->create();
63-
$returns->setStoreId($storeId)
64-
->setOrderId((int)$item['order_id'])
62+
$return = $this->returnsRepository->create();
63+
$return->setStoreId($storeId)
64+
->setOrderId((int)$orderIncrementId)
6565
->setChannableId((int)$returnData['channable_id'])
6666
->setChannelName($returnData['channel_name'])
6767
->setChannelId($returnData['channel_id'])
@@ -74,52 +74,61 @@ public function execute(array $returnData, int $storeId): array
7474
->setComment($item['comment'])
7575
->setMagentoIncrementId((string)$orderIncrementId);
7676

77-
if ($orderIncrementId && $salesOrderGridData = $this->getMagentoOrder((string)$orderIncrementId)) {
78-
$returns->setMagentoOrderId((int)$salesOrderGridData['entity_id']);
77+
if ($orderIncrementId && $entityId = $this->getOrderEntityIdByIncrementId((string)$orderIncrementId)) {
78+
$return->setMagentoOrderId($entityId);
7979
}
8080

8181
if ($channelReturnId = $this->arrayManager->get('meta/channel_return_id', $returnData)) {
82-
$returns->setChannelReturnId($channelReturnId);
82+
$return->setChannelReturnId($channelReturnId);
8383
}
8484

8585
if ($channelOrderId = $this->arrayManager->get('meta/channel_order_id', $returnData)) {
86-
$returns->setChannelOrderId($channelOrderId);
86+
$return->setChannelOrderId($channelOrderId);
8787
}
8888

8989
if ($channelOrderIdInternal = $this->arrayManager->get('meta/channel_order_id_internal', $returnData)) {
90-
$returns->setChannelOrderIdInternal($channelOrderIdInternal);
90+
$return->setChannelOrderIdInternal($channelOrderIdInternal);
9191
}
9292

9393
if ($platformOrderId = $this->arrayManager->get('meta/platform_order_id', $returnData)) {
94-
$returns->setPlatformOrderId($platformOrderId);
94+
$return->setPlatformOrderId($platformOrderId);
9595
}
9696

9797
try {
98-
$returns = $this->returnsRepository->save($returns);
98+
$return = $this->returnsRepository->save($return);
9999
$response['validated'] = 'true';
100-
$response['return_id'] = $returns->getEntityId();
100+
$response['return_id'] = $return->getEntityId();
101101
} catch (Exception $e) {
102+
$this->logRepository->addErrorLog('ImportReturn', $e->getMessage());
102103
$response['validated'] = 'false';
103104
$response['errors'] = $e->getMessage();
104105
}
105106

107+
if ($this->autoProcessReturn($return, $storeId)) {
108+
try {
109+
$this->createCreditmemo->execute($return, $return->getStatus());
110+
} catch (\Exception $e) {
111+
$this->logRepository->addErrorLog('Creditmemo on ImportReturn', $e->getMessage());
112+
}
113+
}
114+
106115
return $response;
107116
}
108117

109-
/**
110-
* Get Magento order by increment id
111-
*
112-
* @param string $incrementId
113-
*
114-
* @return mixed
115-
*/
116-
public function getMagentoOrder(string $incrementId)
118+
private function autoProcessReturn(ReturnData $return, int $storeId): bool
119+
{
120+
return in_array($return->getStatus(), self::AUTO_PROCESS)
121+
&& $this->configProvider->autoProcessCompeteReturns($storeId);
122+
}
123+
124+
private function getOrderEntityIdByIncrementId(string $incrementId): ?int
117125
{
118126
$connection = $this->resource->getConnection();
119127
$select = $connection->select()
120-
->from($this->resource->getTableName('sales_order_grid'))
128+
->from($this->resource->getTableName('sales_order'), ['entity_id'])
121129
->where('increment_id = :increment_id');
122130
$bind = [':increment_id' => $incrementId];
123-
return $connection->fetchRow($select, $bind);
131+
$result = $connection->fetchOne($select, $bind);
132+
return $result !== false ? (int)$result : null;
124133
}
125134
}

Service/Returns/ImportSimulator.php

Lines changed: 11 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -28,50 +28,18 @@ class ImportSimulator
2828
/**
2929
* Available options
3030
*/
31-
public const PARAMS = ['product_id', 'import_order'];
31+
public const PARAMS = ['product_id', 'import_order', 'status'];
3232

33-
/**
34-
* @var int
35-
*/
36-
private $storeId = null;
37-
/**
38-
* @var int
39-
*/
40-
private $productId = null;
33+
private ?int $storeId = null;
34+
private ?int $productId = null;
4135

42-
/**
43-
* @var ProductRepositoryInterface
44-
*/
45-
private $productRepository;
46-
/**
47-
* @var ProductCollectionFactory
48-
*/
49-
private $productCollection;
50-
/**
51-
* @var ConfigProvider
52-
*/
53-
private $configProvider;
54-
/**
55-
* @var Random
56-
*/
57-
private $random;
58-
/**
59-
* @var ImportReturn
60-
*/
61-
private $importReturn;
62-
/**
63-
* @var OrderImportSimulator
64-
*/
65-
private $orderImportSimulator;
36+
private ProductRepositoryInterface $productRepository;
37+
private ProductCollectionFactory $productCollection;
38+
private ConfigProvider $configProvider;
39+
private Random $random;
40+
private ImportReturn $importReturn;
41+
private OrderImportSimulator $orderImportSimulator;
6642

67-
/**
68-
* @param ImportReturn $importReturn
69-
* @param OrderImportSimulator $orderImportSimulator
70-
* @param ProductRepositoryInterface $productRepository
71-
* @param ProductCollectionFactory $productCollection
72-
* @param ConfigProvider $configProvider
73-
* @param Random $random
74-
*/
7543
public function __construct(
7644
ImportReturn $importReturn,
7745
OrderImportSimulator $orderImportSimulator,
@@ -93,7 +61,6 @@ public function __construct(
9361
*
9462
* @param int $storeId
9563
* @param array $params
96-
*
9764
* @return array
9865
* @throws LocalizedException
9966
* @throws NoSuchEntityException
@@ -118,7 +85,6 @@ public function execute(int $storeId, array $params = []): array
11885
* Get test data in Channable Returns format
11986
*
12087
* @param array|null $params
121-
*
12288
* @return array
12389
* @throws LocalizedException
12490
* @throws NoSuchEntityException
@@ -134,7 +100,7 @@ public function getTestData(?array $params = []): array
134100
$random = $this->random->getRandomString(5, '0123456789');
135101

136102
return [
137-
'status' => 'new',
103+
'status' => !empty($params['status']) ? $params['status'] : 'new',
138104
'channel_name' => 'Channable',
139105
'channel_id' => 'TEST-' . $random,
140106
'channable_id' => $random,
@@ -187,7 +153,7 @@ public function getTestDataFromTestOrder(?array $params = []): array
187153
$address = $order->getBillingAddress();
188154

189155
return [
190-
'status' => 'new',
156+
'status' => !empty($params['status']) ? $params['status'] : 'new',
191157
'channel_name' => $additional['channel_name'],
192158
'channel_id' => $additional['channel_id'],
193159
'channable_id' => $additional['channable_id'],

etc/adminhtml/system/returns.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,15 @@
4949
<config_path>magmodules_channable_marketplace/returns/auto_update</config_path>
5050
<comment>Activating this option will automatically approve 'pending' returns upon the creation of a credit memo for the respective order. This action will override the return block selection option from the if it is enabled. Enable this feature when you have established processes in place to automate your credit memo workflow.</comment>
5151
</field>
52+
<field id="auto_process_complete" translate="label" type="select" sortOrder="13" showInDefault="1" showInWebsite="1" showInStore="1">
53+
<label>Creditmemo completed returns</label>
54+
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
55+
<config_path>magmodules_channable_marketplace/returns/auto_process_complete</config_path>
56+
<comment><![CDATA[When enabled, a credit memo will be created automatically for returns imported with the status 'complete'. These returns are handled and fulfilled directly by the marketplace.]]></comment>
57+
</field>
5258
<field id="selftest" translate="label" type="button" sortOrder="14" showInDefault="1" showInWebsite="0" showInStore="1">
5359
<frontend_model>Magmodules\Channable\Block\Adminhtml\System\Config\Button\Selftest</frontend_model>
5460
</field>
5561
</group>
5662
</section>
57-
</include>
63+
</include>

etc/config.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
<returns>
5757
<show_on_creditmemo>1</show_on_creditmemo>
5858
<auto_match>1</auto_match>
59+
<auto_process_complete>0</auto_process_complete>
5960
</returns>
6061
<item>
6162
<enable>0</enable>

0 commit comments

Comments
 (0)