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