PluginProbe
Packeta / 2.3.2
Packeta v2.3.2
2.3.2 2.3.1 trunk 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3.0 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 All 56 releases
← All changes | src/Packetery/Module/Order/PacketSubmitter.php +382 -78 1.4.22.3.2 View file →
@@ -1,10 +1,5 @@
1 1 <?php
2 -/**
3 - * Class PacketSubmitter
4 - *
5 - * @package Packetery\Api
6 - */
7 2
8 3 declare( strict_types=1 );
9 4
10 5 namespace Packetery\Module\Order;
@@ -9,104 +4,301 @@
9 4
10 5 namespace Packetery\Module\Order;
11 6
12 7 use Packetery\Core\Api\InvalidRequestException;
13 -use Packetery\Core\Api\Soap\Client;
8 +use Packetery\Core\Api\Soap;
9 +use Packetery\Core\Api\Soap\CreatePacketMapper;
10 +use Packetery\Core\CoreHelper;
14 11 use Packetery\Core\Entity;
15 12 use Packetery\Core\Log;
16 13 use Packetery\Core\Validator;
17 -use Packetery\Core\Api\Soap\CreatePacketMapper;
18 -use Packetery\Module\ShippingMethod;
14 +use Packetery\Module;
15 +use Packetery\Module\CustomsDeclaration;
16 +use Packetery\Module\MessageManager;
17 +use Packetery\Module\ModuleHelper;
18 +use Packetery\Module\Shipping\ShippingProvider;
19 +use Packetery\Nette\Http\Request;
19 20 use WC_Order;
20 21
21 -/**
22 - * Class PacketSubmitter
23 - *
24 - * @package Packetery\Api
25 - */
26 22 class PacketSubmitter {
23 + const HOOK_PACKET_STATUS_SYNC = 'packetery_packet_status_sync_hook';
27 24
28 25 /**
29 - * SOAP API Client.
30 - *
31 - * @var Client SOAP API Client.
26 + * @var Soap\Client
32 27 */
33 28 private $soapApiClient;
34 29
35 30 /**
36 - * Order validator.
37 - *
38 31 * @var Validator\Order
39 32 */
40 33 private $orderValidator;
41 34
42 35 /**
43 - * ILogger.
44 - *
45 36 * @var Log\ILogger
46 37 */
47 38 private $logger;
48 39
49 40 /**
50 - * Order repository.
51 - *
52 41 * @var Repository
53 42 */
54 43 private $orderRepository;
55 44
56 45 /**
57 - * CreatePacketMapper.
58 - *
59 46 * @var CreatePacketMapper
60 47 */
61 48 private $createPacketMapper;
62 49
63 50 /**
64 - * OrderApi constructor.
65 - *
66 - * @param Client $soapApiClient SOAP API Client.
67 - * @param Validator\Order $orderValidator Order validator.
68 - * @param Log\ILogger $logger Logger.
69 - * @param Repository $orderRepository Order repository.
70 - * @param CreatePacketMapper $createPacketMapper CreatePacketMapper.
51 + * @var Request
71 52 */
53 + private $request;
54 +
55 + /**
56 + * @var MessageManager
57 + */
58 + private $messageManager;
59 +
60 + /**
61 + * @var Module\Log\Page
62 + */
63 + private $logPage;
64 +
65 + /**
66 + * @var PacketActionsCommonLogic
67 + */
68 + private $commonLogic;
69 +
70 + /**
71 + * @var CustomsDeclaration\Repository
72 + */
73 + private $customsDeclarationRepository;
74 +
75 + /**
76 + * @var PacketSynchronizer
77 + */
78 + private $packetSynchronizer;
79 +
80 + /**
81 + * @var ModuleHelper
82 + */
83 + private $moduleHelper;
84 +
85 + /**
86 + * @var CoreHelper
87 + */
88 + private $coreHelper;
89 +
90 + /**
91 + * @var ConsignPasswordSynchronizer
92 + */
93 + private $consignPasswordSynchronizer;
94 +
72 95 public function __construct(
73 - Client $soapApiClient,
74 - Validator\Order $orderValidator,
96 + Soap\Client $soapApiClient,
97 + OrderValidatorFactory $orderValidatorFactory,
75 98 Log\ILogger $logger,
76 99 Repository $orderRepository,
77 - CreatePacketMapper $createPacketMapper
100 + CreatePacketMapper $createPacketMapper,
101 + Request $request,
102 + MessageManager $messageManager,
103 + Module\Log\Page $logPage,
104 + PacketActionsCommonLogic $commonLogic,
105 + CustomsDeclaration\Repository $customsDeclarationRepository,
106 + PacketSynchronizer $packetSynchronizer,
107 + ModuleHelper $moduleHelper,
108 + CoreHelper $coreHelper,
109 + ConsignPasswordSynchronizer $consignPasswordSynchronizer
78 110 ) {
79 - $this->soapApiClient = $soapApiClient;
80 - $this->orderValidator = $orderValidator;
81 - $this->logger = $logger;
82 - $this->orderRepository = $orderRepository;
83 - $this->createPacketMapper = $createPacketMapper;
111 + $this->soapApiClient = $soapApiClient;
112 + $this->orderValidator = $orderValidatorFactory->create();
113 + $this->logger = $logger;
114 + $this->orderRepository = $orderRepository;
115 + $this->createPacketMapper = $createPacketMapper;
116 + $this->request = $request;
117 + $this->messageManager = $messageManager;
118 + $this->logPage = $logPage;
119 + $this->commonLogic = $commonLogic;
120 + $this->customsDeclarationRepository = $customsDeclarationRepository;
121 + $this->packetSynchronizer = $packetSynchronizer;
122 + $this->moduleHelper = $moduleHelper;
123 + $this->coreHelper = $coreHelper;
124 + $this->consignPasswordSynchronizer = $consignPasswordSynchronizer;
84 125 }
85 126
86 127 /**
128 + * Process action
129 + *
130 + * @return void
131 + */
132 + public function processAction(): void {
133 + $order = $this->commonLogic->getOrder();
134 + $redirectTo = $this->request->getQuery( PacketActionsCommonLogic::PARAM_REDIRECT_TO );
135 +
136 + if ( $order === null ) {
137 + $record = new Log\Record();
138 + $record->action = Log\Record::ACTION_PACKET_SENDING;
139 + $record->status = Log\Record::STATUS_ERROR;
140 + $record->orderId = null;
141 + $record->title = __( 'Packet submission error', 'packeta' );
142 + $record->params = [
143 + 'referer' => (string) $this->request->getReferer(),
144 + 'errorMessage' => 'Order not found',
145 + ];
146 +
147 + $this->logger->add( $record );
148 +
149 + $this->messageManager->flash_message( __( 'Order not found', 'packeta' ), MessageManager::TYPE_ERROR );
150 + $this->commonLogic->redirectTo( $redirectTo, $order );
151 +
152 + return;
153 + }
154 +
155 + $this->commonLogic->checkAction( PacketActionsCommonLogic::ACTION_SUBMIT_PACKET, $order );
156 +
157 + $submissionResult = $this->submitPacket(
158 + $this->orderRepository->getWcOrderById( (int) $order->getNumber() ),
159 + $order,
160 + true
161 + );
162 + $resultsCounter = $submissionResult->getCounter();
163 + $submissionResultMessages = $this->getTranslatedSubmissionMessages( $resultsCounter, (int) $order->getNumber() );
164 +
165 + if ( $resultsCounter['success'] > 0 ) {
166 + $this->messageManager->flashMessageObject(
167 + Module\Message::create()
168 + ->setText( $submissionResultMessages['success'] )
169 + ->setEscape( false )
170 + );
171 + }
172 +
173 + if ( $resultsCounter['ignored'] > 0 ) {
174 + $this->messageManager->flashMessageObject(
175 + Module\Message::create()
176 + ->setText( $submissionResultMessages['ignored'] )
177 + ->setEscape( false )
178 + ->setType( MessageManager::TYPE_INFO )
179 + );
180 + }
181 +
182 + if ( $resultsCounter['errors'] > 0 ) {
183 + $this->messageManager->flashMessageObject(
184 + Module\Message::create()
185 + ->setText( $submissionResultMessages['errors'] )
186 + ->setEscape( false )
187 + ->setType( MessageManager::TYPE_ERROR )
188 + );
189 + }
190 +
191 + $redirectTo = $this->request->getQuery( PacketActionsCommonLogic::PARAM_REDIRECT_TO );
192 + $this->commonLogic->redirectTo( $redirectTo, $order );
193 + }
194 +
195 + /**
87 196 * Submits packet data to Packeta API.
88 197 *
89 - * @param WC_Order $order WC order.
90 - * @param array $resultsCounter Array with results.
198 + * @param WC_Order $wcOrder WC order.
199 + * @param Entity\Order|null $order Order.
200 + * @param bool $immediatePacketStatusCheck Whether to sync status immediately.
201 + *
202 + * @return PacketSubmissionResult
91 203 */
92 - public function submitPacket( WC_Order $order, array &$resultsCounter ): void {
93 - $commonEntity = $this->orderRepository->getByWcOrder( $order );
94 - if ( null === $commonEntity ) {
95 - $resultsCounter['ignored'] ++;
204 + public function submitPacket(
205 + WC_Order $wcOrder,
206 + ?Entity\Order $order = null,
207 + bool $immediatePacketStatusCheck = false
208 + ): PacketSubmissionResult {
209 + $submissionResult = new PacketSubmissionResult();
210 + if ( $order === null ) {
211 + $order = $this->orderRepository->getByWcOrderWithValidCarrier( $wcOrder );
212 + }
213 + if ( $order === null ) {
214 + $submissionResult->increaseIgnoredCount();
96 215
97 - return;
216 + return $submissionResult;
98 217 }
99 218
100 - $orderData = $order->get_data();
101 - $shippingMethods = $order->get_shipping_methods();
219 + $orderData = $wcOrder->get_data();
220 + $shippingMethods = $wcOrder->get_shipping_methods();
102 221 $shippingMethod = reset( $shippingMethods );
103 222
104 223 $shippingMethodData = $shippingMethod->get_data();
105 224 $shippingMethodId = $shippingMethodData['method_id'];
106 - if ( ShippingMethod::PACKETERY_METHOD_ID === $shippingMethodId && ! $commonEntity->isExported() ) {
225 + if ( ShippingProvider::isPacketaMethod( $shippingMethodId ) && ! $order->isExported() ) {
226 + $customsDeclaration = $order->getCustomsDeclaration();
227 + if (
228 + $customsDeclaration !== null &&
229 + $customsDeclaration->getInvoiceFileId() === null &&
230 + $customsDeclaration->hasInvoiceFileContent()
231 + ) {
232 + $invoiceFileResponse = $this->soapApiClient->createStorageFile(
233 + new Soap\Request\CreateStorageFile(
234 + // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
235 + base64_encode( $customsDeclaration->getInvoiceFile() ),
236 + sprintf( 'invoice_%s.pdf', $customsDeclaration->getId() )
237 + )
238 + );
239 +
240 + if ( $invoiceFileResponse->hasFault() ) {
241 + $record = new Log\Record();
242 + $record->action = Log\Record::ACTION_PACKET_SENDING;
243 + $record->status = Log\Record::STATUS_ERROR;
244 + $record->title = __( 'Packet invoice file could not be created.', 'packeta' );
245 + $record->params = [
246 + 'errorMessage' => $invoiceFileResponse->getFaultString(),
247 + ];
248 + $record->orderId = $order->getNumber();
249 + $this->logger->add( $record );
250 + $submissionResult->increaseLogsCount();
251 +
252 + $submissionResult->increaseErrorsCount();
253 + $order->updateApiErrorMessage( $invoiceFileResponse->getFaultString() );
254 + $this->orderRepository->save( $order );
255 +
256 + return $submissionResult;
257 + }
258 +
259 + $customsDeclaration->setInvoiceFileId( $invoiceFileResponse->getId() );
260 + $this->customsDeclarationRepository->save( $customsDeclaration );
261 + }
262 +
263 + if (
264 + $customsDeclaration !== null &&
265 + $customsDeclaration->getEadFileId() === null &&
266 + $customsDeclaration->hasEadFileContent()
267 + ) {
268 + $eadFileResponse = $this->soapApiClient->createStorageFile(
269 + new Soap\Request\CreateStorageFile(
270 + // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
271 + base64_encode( $customsDeclaration->getEadFile() ),
272 + sprintf( 'ead_%s.pdf', $customsDeclaration->getId() )
273 + )
274 + );
275 +
276 + if ( $eadFileResponse->hasFault() ) {
277 + $record = new Log\Record();
278 + $record->action = Log\Record::ACTION_PACKET_SENDING;
279 + $record->status = Log\Record::STATUS_ERROR;
280 + $record->title = __( 'Packet ead file could not be created.', 'packeta' );
281 + $record->params = [
282 + 'errorMessage' => $eadFileResponse->getFaultString(),
283 + ];
284 + $record->orderId = $order->getNumber();
285 + $this->logger->add( $record );
286 + $submissionResult->increaseLogsCount();
287 +
288 + $submissionResult->increaseErrorsCount();
289 + $order->updateApiErrorMessage( $eadFileResponse->getFaultString() );
290 + $this->orderRepository->save( $order );
291 +
292 + return $submissionResult;
293 + }
294 +
295 + $customsDeclaration->setEadFileId( $eadFileResponse->getId() );
296 + $this->customsDeclarationRepository->save( $customsDeclaration );
297 + }
298 +
107 299 try {
108 - $createPacketData = $this->preparePacketData( $commonEntity );
300 + $createPacketData = $this->preparePacketData( $order );
109 301 } catch ( InvalidRequestException $e ) {
110 302 $record = new Log\Record();
111 303 $record->action = Log\Record::ACTION_PACKET_SENDING;
112 304 $record->status = Log\Record::STATUS_ERROR;
@@ -111,20 +303,23 @@
111 303 $record->action = Log\Record::ACTION_PACKET_SENDING;
112 304 $record->status = Log\Record::STATUS_ERROR;
113 305 $record->title = __( 'Packet could not be created.', 'packeta' );
114 306 $record->params = [
115 - 'orderId' => $orderData['id'],
116 - 'errorMessage' => $e->getMessage(),
307 + 'orderId' => $orderData['id'],
308 + 'errorMessages' => $e->getMessages(),
117 309 ];
118 - $record->orderId = $commonEntity->getNumber();
310 + $record->orderId = $order->getNumber();
119 311 $this->logger->add( $record );
120 312
121 - $resultsCounter['logs'] ++;
122 - $resultsCounter['errors'] ++;
313 + $submissionResult->increaseLogsCount();
314 + $submissionResult->increaseErrorsCount();
123 315
124 - return;
316 + return $submissionResult;
125 317 }
126 318
319 + $shouldScheduleConsignPasswordFetch = false;
320 + $consignPasswordFetchImmediate = false;
321 +
127 322 $response = $this->soapApiClient->createPacket( $createPacketData );
128 323 if ( $response->hasFault() ) {
129 324 $record = new Log\Record();
130 325 $record->action = Log\Record::ACTION_PACKET_SENDING;
@@ -133,36 +328,62 @@
133 328 $record->params = [
134 329 'request' => $createPacketData,
135 330 'errorMessage' => $response->getErrorsAsString(),
136 331 ];
137 - $record->orderId = $commonEntity->getNumber();
138 - $this->logger->add( $record );
332 + $record->orderId = $order->getNumber();
333 + $errorMessage = $response->getErrorsAsString( false );
139 334
140 - $resultsCounter['logs'] ++;
141 - $resultsCounter['errors'] ++;
335 + $submissionResult->increaseErrorsCount();
142 336 } else {
143 - $commonEntity->setIsExported( true );
144 - $commonEntity->setPacketId( (string) $response->getId() );
145 - $this->orderRepository->save( $commonEntity );
337 + $order->setIsExported( true );
338 + $order->setPacketId( $response->getId() );
339 + $order->setPacketTrackingUrl( $this->coreHelper->getTrackingUrl( $response->getId() ) );
146 340
147 - $resultsCounter['success'] ++;
148 -
149 341 $record = new Log\Record();
150 342 $record->action = Log\Record::ACTION_PACKET_SENDING;
151 343 $record->status = Log\Record::STATUS_SUCCESS;
152 - $record->title = __( 'Packet was sucessfully created.', 'packeta' );
344 + $record->title = __( 'Packet was successfully created.', 'packeta' );
153 345 $record->params = [
154 346 'request' => $createPacketData,
155 347 'packetId' => $response->getId(),
156 348 ];
157 - $record->orderId = $commonEntity->getNumber();
158 - $this->logger->add( $record );
349 + $record->orderId = $order->getNumber();
350 + $errorMessage = null;
159 351
160 - $resultsCounter['logs'] ++;
352 + $submissionResult->increaseSuccessCount();
353 +
354 + $wcOrder->add_order_note(
355 + sprintf(
356 + // translators: %s represents a packet tracking link.
357 + __( 'Packeta: Packet %s has been created', 'packeta' ),
358 + $this->moduleHelper->createHtmlLink( $order->getPacketTrackingUrl(), $order->getPacketBarcode() )
359 + )
360 + );
361 + $wcOrder->save();
362 +
363 + if ( $immediatePacketStatusCheck || ! function_exists( 'as_enqueue_async_action' ) ) {
364 + $this->packetSynchronizer->syncStatus( $order );
365 + } else {
366 + as_enqueue_async_action( self::HOOK_PACKET_STATUS_SYNC, [ $order->getNumber() ] );
367 + }
368 +
369 + $shouldScheduleConsignPasswordFetch = true;
370 + $consignPasswordFetchImmediate = $immediatePacketStatusCheck;
161 371 }
372 +
373 + $submissionResult->increaseLogsCount();
374 + $this->logger->add( $record );
375 + $order->updateApiErrorMessage( $errorMessage );
376 + $this->orderRepository->save( $order );
377 +
378 + if ( $shouldScheduleConsignPasswordFetch ) {
379 + $this->consignPasswordSynchronizer->schedule( $order, $consignPasswordFetchImmediate );
380 + }
162 381 } else {
163 - $resultsCounter['ignored'] ++;
382 + $submissionResult->increaseIgnoredCount();
164 383 }
384 +
385 + return $submissionResult;
165 386 }
166 387
167 388 /**
168 389 * Prepares packet attributes.
@@ -167,19 +388,16 @@
167 388 /**
168 389 * Prepares packet attributes.
169 390 *
170 391 * @param Entity\Order $order Order entity.
171 - *
172 - * @return array
392 + * @return array<string, string|null|bool>
173 393 * @throws InvalidRequestException For the case request is not eligible to be sent to API.
174 394 */
175 395 private function preparePacketData( Entity\Order $order ): array {
176 - /*
177 - TODO: extend validator to return specific errors.
178 - if ( ! $this->orderValidator->validate( $commonEntity ) ) {
179 - throw new InvalidRequestException( 'All required order attributes are not set.' );
396 + $validationErrors = $this->orderValidator->validate( $order );
397 + if ( count( $validationErrors ) > 0 ) {
398 + throw new InvalidRequestException( 'All required order attributes are not set.', $validationErrors );
180 399 }
181 - */
182 400
183 401 $createPacketData = $this->createPacketMapper->fromOrderToArray( $order );
184 402
185 403 /**
@@ -188,8 +406,94 @@
188 406 * @since 1.4
189 407 *
190 408 * @param array $createPacketData CreatePacket request data.
191 409 */
192 - return apply_filters( 'packeta_create_packet', $createPacketData );
410 + return (array) apply_filters( 'packeta_create_packet', $createPacketData );
193 411 }
194 412
413 + /**
414 + * Gets translated messages by submission result.
415 + *
416 + * @param array<string, int> $submissionResult Submission result.
417 + * @param int|null $orderId Order ID.
418 + *
419 + * @return array<string, null|string>
420 + */
421 + public function getTranslatedSubmissionMessages( array $submissionResult, ?int $orderId ): array {
422 + $success = null;
423 + if ( is_numeric( $submissionResult['success'] ) && $submissionResult['success'] > 0 ) {
424 + if ( $submissionResult['logs'] > 0 ) {
425 + $success = sprintf( // translators: 1: link start 2: link end.
426 + esc_html__( 'Shipments were submitted successfully. %1$sShow logs%2$s', 'packeta' ),
427 + '<a href="' . $this->logPage->createLogListUrl( $orderId ) . '">',
428 + '</a>'
429 + );
430 + } else {
431 + $success = esc_html__( 'Shipments were submitted successfully.', 'packeta' );
432 + }
433 + }
434 + $ignored = null;
435 + if ( is_numeric( $submissionResult['ignored'] ) && $submissionResult['ignored'] > 0 ) {
436 + if ( $submissionResult['logs'] > 0 ) {
437 + $ignored = sprintf( // translators: 1: total number of shipments 2: link start 3: link end.
438 + esc_html__( 'Some shipments (%1$s in total) were not submitted (these were submitted already or are not Packeta orders). %2$sShow logs%3$s', 'packeta' ),
439 + $submissionResult['ignored'],
440 + '<a href="' . $this->logPage->createLogListUrl( $orderId ) . '">',
441 + '</a>'
442 + );
443 + } else {
444 + $ignored = sprintf( // translators: %s is count.
445 + esc_html__( 'Some shipments (%s in total) were not submitted (these were submitted already or are not Packeta orders).', 'packeta' ),
446 + $submissionResult['ignored']
447 + );
448 + }
449 + }
450 + $errors = null;
451 + if ( is_numeric( $submissionResult['errors'] ) && $submissionResult['errors'] > 0 ) {
452 + if ( $submissionResult['logs'] > 0 ) {
453 + $errors = sprintf( // translators: 1: total number of shipments 2: link start 3: link end.
454 + esc_html__( 'Some shipments (%1$s in total) failed to be submitted to Packeta. %2$sShow logs%3$s', 'packeta' ),
455 + $submissionResult['errors'],
456 + '<a href="' . $this->logPage->createLogListUrl( $orderId ) . '">',
457 + '</a>'
458 + );
459 + } else {
460 + $errors = sprintf( // translators: %s is count.
461 + esc_html__( 'Some shipments (%s in total) failed to be submitted to Packeta.', 'packeta' ),
462 + $submissionResult['errors']
463 + );
464 + }
465 + } elseif ( isset( $submissionResult['errors'] ) ) {
466 + $errors = esc_html( (string) $submissionResult['errors'] );
467 + }
468 +
469 + if ( is_numeric( $submissionResult['statusUnchanged'] ) && $submissionResult['statusUnchanged'] > 0 ) {
470 + $errors = esc_html__( 'Some order statuses have not been automatically changed.', 'packeta' );
471 + }
472 +
473 + return [
474 + 'success' => $success,
475 + 'ignored' => $ignored,
476 + 'errors' => $errors,
477 + ];
478 + }
479 +
480 + /**
481 + * Registers action for cron.
482 + *
483 + * @return void
484 + */
485 + public function registerCronAction(): void {
486 + add_action(
487 + self::HOOK_PACKET_STATUS_SYNC,
488 + function ( string $orderId ): void {
489 + $order = $this->orderRepository->getByIdWithValidCarrier( (int) $orderId );
490 + if ( $order === null ) {
491 + return;
492 + }
493 + $this->packetSynchronizer->syncStatus( $order );
494 + },
495 + 10,
496 + 1
497 + );
498 + }
195 499 }