PluginProbe
Packeta / 2.0.9
Packeta v2.0.9
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
packeta / src / Packetery / Module / Order / PacketSubmitter.php

PacketSubmitter.php in Packeta 2.0.9, at src/Packetery/Module/Order/PacketSubmitter.php

483 lines 15.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare( strict_types=1 );
4
5 namespace Packetery\Module\Order;
6
7 use Packetery\Core\Api\InvalidRequestException;
8 use Packetery\Core\Api\Soap;
9 use Packetery\Core\Api\Soap\CreatePacketMapper;
10 use Packetery\Core\CoreHelper;
11 use Packetery\Core\Entity;
12 use Packetery\Core\Log;
13 use Packetery\Core\Validator;
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;
20 use WC_Order;
21
22 class PacketSubmitter {
23 const HOOK_PACKET_STATUS_SYNC = 'packetery_packet_status_sync_hook';
24
25 /**
26 * @var Soap\Client
27 */
28 private $soapApiClient;
29
30 /**
31 * @var Validator\Order
32 */
33 private $orderValidator;
34
35 /**
36 * @var Log\ILogger
37 */
38 private $logger;
39
40 /**
41 * @var Repository
42 */
43 private $orderRepository;
44
45 /**
46 * @var CreatePacketMapper
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
90 public function __construct(
91 Soap\Client $soapApiClient,
92 OrderValidatorFactory $orderValidatorFactory,
93 Log\ILogger $logger,
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
104 ) {
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;
118 }
119
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 /**
189 * Submits packet data to Packeta API.
190 *
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
196 */
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();
208
209 return $submissionResult;
210 }
211
212 $orderData = $wcOrder->get_data();
213 $shippingMethods = $wcOrder->get_shipping_methods();
214 $shippingMethod = reset( $shippingMethods );
215
216 $shippingMethodData = $shippingMethod->get_data();
217 $shippingMethodId = $shippingMethodData['method_id'];
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
292 try {
293 $createPacketData = $this->preparePacketData( $order );
294 } catch ( InvalidRequestException $e ) {
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(),
302 ];
303 $record->orderId = $order->getNumber();
304 $this->logger->add( $record );
305
306 $submissionResult->increaseLogsCount();
307 $submissionResult->increaseErrorsCount();
308
309 return $submissionResult;
310 }
311
312 $response = $this->soapApiClient->createPacket( $createPacketData );
313 if ( $response->hasFault() ) {
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,
320 'errorMessage' => $response->getErrorsAsString(),
321 ];
322 $record->orderId = $order->getNumber();
323 $errorMessage = $response->getErrorsAsString( false );
324
325 $submissionResult->increaseErrorsCount();
326 } else {
327 $order->setIsExported( true );
328 $order->setPacketId( $response->getId() );
329 $order->setPacketTrackingUrl( $this->coreHelper->getTrackingUrl( $response->getId() ) );
330
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,
337 'packetId' => $response->getId(),
338 ];
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 }
358 }
359
360 $submissionResult->increaseLogsCount();
361 $this->logger->add( $record );
362 $order->updateApiErrorMessage( $errorMessage );
363 $this->orderRepository->save( $order );
364 } else {
365 $submissionResult->increaseIgnoredCount();
366 }
367
368 return $submissionResult;
369 }
370
371 /**
372 * Prepares packet attributes.
373 *
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.
398 *
399 * @param array<string, int> $submissionResult Submission result.
400 * @param int|null $orderId Order ID.
401 *
402 * @return array<string, null|string>
403 */
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 }
416 }
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 }
451
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 ];
461 }
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 }
482 }
483