Skip to content

Commit 923e720

Browse files
capapeobarcelonap
andauthored
Merge pull request #217 from magento-commerce/MDEE-364-implement-order-export-within-a-timeframe
* Create on demand command to export orders within a time range * Create index to be used on demand export * Refactor of link command to be able to use its functionality * Create new table for storing on demand exported orders Co-authored-by: Oriol Barcelona <obarcelonapa@adobe.com>
2 parents 1eb4f28 + 1db11c8 commit 923e720

10 files changed

Lines changed: 834 additions & 343 deletions

File tree

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\SalesOrdersDataExporter\Console\Command;
9+
10+
use DateTime;
11+
use DateTimeInterface;
12+
use Magento\DataExporter\Model\Indexer\FeedIndexMetadata;
13+
use Magento\DataExporter\Model\Logging\CommerceDataExportLoggerInterface;
14+
use Magento\Framework\Console\Cli;
15+
use Magento\Framework\Intl\DateTimeFactory;
16+
use Magento\SalesOrdersDataExporter\Console\Command\Link;
17+
use Magento\SalesOrdersDataExporter\Model\Indexer\DateTimeRangeOrderProcessor;
18+
use Symfony\Component\Console\Command\Command;
19+
use Symfony\Component\Console\Input\InputArgument;
20+
use Symfony\Component\Console\Input\InputInterface;
21+
use Symfony\Component\Console\Output\OutputInterface;
22+
23+
/**
24+
* Command export orders since certain time in the past
25+
*/
26+
class ExportOnDemand extends Command
27+
{
28+
private const COMMAND_NAME = 'commerce-data-export:orders:export-on-demand';
29+
private CommerceDataExportLoggerInterface $logger;
30+
private FeedIndexMetadata $metadata;
31+
private DateTimeRangeOrderProcessor $processor;
32+
private DateTimeFactory $dateTimeFactory;
33+
private Link $linkCommand;
34+
35+
/**
36+
* @param CommerceDataExportLoggerInterface $logger
37+
* @param FeedIndexMetadata $metadata
38+
* @param DateTimeRangeOrderProcessor $processor
39+
* @param DateTimeRangeOrderProcessor dateTimeFactory
40+
* @param Link $link
41+
*/
42+
public function __construct(
43+
CommerceDataExportLoggerInterface $logger,
44+
FeedIndexMetadata $metadata,
45+
DateTimeRangeOrderProcessor $processor,
46+
DateTimeFactory $dateTimeFactory,
47+
Link $link
48+
)
49+
{
50+
$this->logger = $logger;
51+
$this->metadata = $metadata;
52+
$this->processor = $processor;
53+
$this->dateTimeFactory = $dateTimeFactory;
54+
$this->linkCommand = $link;
55+
parent::__construct();
56+
}
57+
58+
/**
59+
* @inheritdoc
60+
*/
61+
protected function configure()
62+
{
63+
$this
64+
->setName(self::COMMAND_NAME)
65+
->setDescription('Exports orders since certain time in the past on demand.')
66+
->addArgument(
67+
'from',
68+
InputArgument::REQUIRED,
69+
'From date time'
70+
);
71+
72+
parent::configure();
73+
}
74+
75+
/**
76+
* @inheritdoc
77+
*/
78+
protected function execute(InputInterface $input, OutputInterface $output): int
79+
{
80+
$from = $this->dateTimeFactory->create($input->getArgument('from'));
81+
$to = $this->dateTimeFactory->create();
82+
83+
$returnCode = $this->ensureAssignedUuids($from, $to, $output);
84+
if ($returnCode != Cli::RETURN_SUCCESS) {
85+
return Cli::RETURN_FAILURE;
86+
}
87+
88+
$this->processor->fullReindex($this->metadata, $from, $to);
89+
90+
return Cli::RETURN_SUCCESS;
91+
}
92+
93+
private function ensureAssignedUuids(DateTime $from, DateTime $to, OutputInterface $output): int
94+
{
95+
$returnCode = $this->linkCommand->
96+
prepareForExport(
97+
$this->metadata->getBatchSize(),
98+
$output,
99+
$from->format(DateTimeInterface::W3C),
100+
$to->format(DateTimeInterface::W3C)
101+
);
102+
if ($returnCode != Cli::RETURN_SUCCESS) {
103+
$this->logger->error('Command "commerce-data-export:orders:link" failed.');
104+
}
105+
return $returnCode;
106+
}
107+
}

SalesOrdersDataExporter/Console/Command/Link.php

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,35 @@ protected function execute(InputInterface $input, OutputInterface $output)
135135
? (new \DateTime($input->getOption(self::OPTION_TO)))->format(\DateTimeInterface::W3C)
136136
: null;
137137

138+
return $this->prepareForExport($batchSize, $output, $from, $to, $state);
139+
} catch (\Throwable $e) {
140+
$output->writeln('<error>Failed to update UUID. Check logs</error>');
141+
$this->logger->error(
142+
sprintf('Command "%s" failed. Error message: %s', self::COMMAND_NAME, $e->getMessage())
143+
);
144+
145+
return Cli::RETURN_FAILURE;
146+
}
147+
}
148+
149+
/**
150+
* Updating UUID
151+
*
152+
* @param int $batchSize
153+
* @param OutputInterface $output
154+
* @param string $from
155+
* @param string $to
156+
* @param string $state
157+
* @return int
158+
*/
159+
public function prepareForExport(
160+
int $batchSize,
161+
OutputInterface $output,
162+
string $from = null,
163+
string $to = null,
164+
string $state = ''
165+
) {
166+
try {
138167
$output->writeln(
139168
sprintf(
140169
'<info>Start updating UUID with parameters [state=%s, from=%s, to=%s, batch_size=%s]</info>',
@@ -150,6 +179,14 @@ protected function execute(InputInterface $input, OutputInterface $output)
150179
$this->uuidManager->assignBulk($entityIds, $type);
151180
$updatedEntities += count($entityIds);
152181
}
182+
$output->writeln(
183+
sprintf(
184+
'<info>Update completed successfully, %s entities updated</info>',
185+
$updatedEntities
186+
)
187+
);
188+
return Cli::RETURN_SUCCESS;
189+
153190
} catch (\Throwable $e) {
154191
$output->writeln('<error>Failed to update UUID. Check logs</error>');
155192
$this->logger->error(
@@ -158,15 +195,6 @@ protected function execute(InputInterface $input, OutputInterface $output)
158195

159196
return Cli::RETURN_FAILURE;
160197
}
161-
162-
$output->writeln(
163-
sprintf(
164-
'<info>Update completed successfully, %s entities updated</info>',
165-
$updatedEntities
166-
)
167-
);
168-
169-
return Cli::RETURN_SUCCESS;
170198
}
171199

172200
/**
@@ -178,6 +206,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
178206
*/
179207
private function getOrders(string $state, int $batchSize, string $from = null, string $to = null): \Generator
180208
{
209+
181210
$mapTypes = array_map(function ($type) {
182211
$type['table'] = $this->resourceConnection->getTableName($type['table']);
183212
return $type;
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\SalesOrdersDataExporter\Model\Indexer;
9+
10+
use DateTime;
11+
use Exception;
12+
use Generator;
13+
use Magento\DataExporter\Model\Indexer\EntityIdsProviderInterface;
14+
use Magento\DataExporter\Model\Indexer\FeedIndexMetadata;
15+
use Magento\Framework\App\ResourceConnection;
16+
use Magento\Framework\DB\Query\BatchIteratorFactory;
17+
18+
/**
19+
* Returns IDs needed by indexer for a given feed.
20+
*/
21+
class DateTimeRangeOrderIdsProvider implements EntityIdsProviderInterface
22+
{
23+
private ResourceConnection $resourceConnection;
24+
private BatchIteratorFactory $batchIteratorFactory;
25+
private DateTime $from;
26+
private DateTime $to;
27+
28+
public function __construct(
29+
ResourceConnection $resourceConnection,
30+
BatchIteratorFactory $batchIteratorFactory,
31+
DateTime $from,
32+
DateTime $to
33+
) {
34+
$this->from = $from;
35+
$this->to = $to;
36+
$this->resourceConnection = $resourceConnection;
37+
$this->batchIteratorFactory = $batchIteratorFactory;
38+
}
39+
40+
/**
41+
* @inheritdoc
42+
*
43+
* @param FeedIndexMetadata $metadata
44+
* @return Generator|null
45+
*/
46+
public function getAllIds(FeedIndexMetadata $metadata): ?Generator
47+
{
48+
$fieldName = $metadata->getFeedIdentity();
49+
$tableName = $this->resourceConnection->getTableName($metadata->getSourceTableName());
50+
return $this->findOrders($this->from, $this->to, $fieldName, $tableName, $metadata->getBatchSize());
51+
}
52+
53+
/**
54+
* @param FeedIndexMetadata $metadata
55+
* @param array $ids
56+
* @return array
57+
* @throws Exception
58+
*/
59+
public function getAffectedIds(FeedIndexMetadata $metadata, array $ids): array
60+
{
61+
return $ids;
62+
}
63+
64+
private function findOrders(
65+
DateTime $from,
66+
DateTime $to,
67+
string $fieldName,
68+
string $tableName,
69+
int $batchSize = 100
70+
): Generator {
71+
$connection = $this->resourceConnection->getConnection();
72+
$select = $connection->select()
73+
->from(
74+
['order' => $tableName],
75+
[$fieldName => 'entity_id']
76+
)
77+
->where('order.created_at >= ?', $from)
78+
->where('order.created_at <= ?', $to);
79+
80+
$iterator = $this->batchIteratorFactory->create(
81+
[
82+
'select' => $select,
83+
'batchSize' => $batchSize,
84+
'correlationName' => 'order',
85+
'rangeField' => 'entity_id',
86+
'rangeFieldAlias' => $fieldName,
87+
]
88+
);
89+
90+
foreach ($iterator as $batchSelect) {
91+
yield $connection->fetchAll($batchSelect);
92+
}
93+
}
94+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\SalesOrdersDataExporter\Model\Indexer;
9+
10+
use Magento\DataExporter\Model\Indexer\DataSerializerInterface;
11+
use Magento\DataExporter\Model\Indexer\FeedIndexMetadata;
12+
use Magento\DataExporter\Model\Indexer\FeedIndexProcessorInterface;
13+
use Magento\Framework\App\ResourceConnection;
14+
use Magento\Framework\DB\Query\BatchIteratorFactory;
15+
16+
class DateTimeRangeOrderProcessor
17+
{
18+
private ResourceConnection $resourceConnection;
19+
private BatchIteratorFactory $batchIteratorFactory;
20+
private DataSerializerInterface $serializer;
21+
private FeedIndexProcessorInterface $delegatingProcessor;
22+
23+
public function __construct(
24+
ResourceConnection $resourceConnection,
25+
BatchIteratorFactory $batchIteratorFactory,
26+
DataSerializerInterface $serializer,
27+
FeedIndexProcessorInterface $delegatingProcessor
28+
) {
29+
$this->resourceConnection = $resourceConnection;
30+
$this->batchIteratorFactory = $batchIteratorFactory;
31+
$this->serializer = $serializer;
32+
$this->delegatingProcessor = $delegatingProcessor;
33+
}
34+
35+
public function fullReindex(FeedIndexMetadata $metadata, $from, $to): void
36+
{
37+
$idsProvider = new DateTimeRangeOrderIdsProvider(
38+
$this->resourceConnection,
39+
$this->batchIteratorFactory,
40+
$from,
41+
$to
42+
);
43+
$this->delegatingProcessor->fullReindex($metadata, $this->serializer, $idsProvider);
44+
}
45+
}

SalesOrdersDataExporter/README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,13 @@ bin/magento indexer:reindex sales_order_data_exporter_v2
3737

3838
Reindexing is currently limited to orders modified in the last 7 days.
3939

40-
Note that `commerce-data-export:orders:link` will assign uuids to the orders older than last 7 days but only orders
41-
modified within that timeframe will be exported.
40+
Note that `commerce-data-export:orders:link` will assign uuids to the orders older than last 7 days but only orders
41+
modified within that timeframe will be exported.
42+
43+
### Orders on demand
44+
Posibility to load sales orders from a date on SaaS Order Service. It's an independent process from usual sales order flow.
45+
To load orders:
46+
```shell
47+
bin/magento commerce-data-export:orders:export-on-demand yyyymmdd
48+
```
49+
The command will assing uuids to orders and index them in sales_data_export_on_demand_orders. As it is a on demand op, no index is scheduled.

0 commit comments

Comments
 (0)