PluginProbe
Packeta / 1.6.3
Packeta v1.6.3
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 / LabelPrint.php

LabelPrint.php in Packeta 1.6.3, at src/Packetery/Module/Order/LabelPrint.php

566 lines 16.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class LabelPrint.
4 *
5 * @package Packetery\Order
6 */
7
8 declare( strict_types=1 );
9
10 namespace Packetery\Module\Order;
11
12 use Packetery\Core\Api\Soap\Client;
13 use Packetery\Core\Api\Soap\Request;
14 use Packetery\Core\Api\Soap\Response;
15 use Packetery\Core\Log;
16 use Packetery\Core\Entity\Order;
17 use Packetery\Module\Exception\InvalidCarrierException;
18 use Packetery\Module\FormFactory;
19 use Packetery\Module\MessageManager;
20 use Packetery\Module\Options\Provider;
21 use Packetery\Module\Plugin;
22 use Packetery\Latte\Engine;
23 use Packetery\Nette\Forms\Form;
24 use Packetery\Nette\Http;
25 use Packetery\Module;
26
27 /**
28 * Class LabelPrint.
29 *
30 * @package Packetery\Order
31 */
32 class LabelPrint {
33 public const ACTION_PACKETA_LABELS = 'print_packeta_labels';
34 public const ACTION_CARRIER_LABELS = 'print_carrier_labels';
35 public const LABEL_TYPE_PARAM = 'label_type';
36 public const MENU_SLUG = 'label-print';
37
38 /**
39 * PacketeryLatte Engine.
40 *
41 * @var Engine PacketeryLatte engine.
42 */
43 private $latteEngine;
44
45 /**
46 * Options Provider
47 *
48 * @var Provider
49 */
50 private $optionsProvider;
51
52 /**
53 * Form factory.
54 *
55 * @var FormFactory Form factory.
56 */
57 private $formFactory;
58
59 /**
60 * Http Request.
61 *
62 * @var Http\Request
63 */
64 private $httpRequest;
65
66 /**
67 * SOAP API Client.
68 *
69 * @var Client SOAP API Client.
70 */
71 private $soapApiClient;
72
73 /**
74 * Message Manager.
75 *
76 * @var MessageManager
77 */
78 private $messageManager;
79
80 /**
81 * Logger.
82 *
83 * @var Log\ILogger
84 */
85 private $logger;
86
87 /**
88 * Order repository.
89 *
90 * @var Repository
91 */
92 private $orderRepository;
93
94 /**
95 * Log page.
96 *
97 * @var Module\Log\Page
98 */
99 private $logPage;
100
101 /**
102 * Packet actions common logic.
103 *
104 * @var PacketActionsCommonLogic
105 */
106 private $packetActionsCommonLogic;
107
108 /**
109 * LabelPrint constructor.
110 *
111 * @param Engine $latteEngine Latte Engine.
112 * @param Provider $optionsProvider Options provider.
113 * @param FormFactory $formFactory Form factory.
114 * @param Http\Request $httpRequest Http Request.
115 * @param Client $soapApiClient SOAP API Client.
116 * @param MessageManager $messageManager Message Manager.
117 * @param Log\ILogger $logger Logger.
118 * @param Repository $orderRepository Order repository.
119 * @param Module\Log\Page $logPage Log page.
120 * @param PacketActionsCommonLogic $packetActionsCommonLogic Packet actions common logic.
121 */
122 public function __construct(
123 Engine $latteEngine,
124 Provider $optionsProvider,
125 FormFactory $formFactory,
126 Http\Request $httpRequest,
127 Client $soapApiClient,
128 MessageManager $messageManager,
129 Log\ILogger $logger,
130 Repository $orderRepository,
131 Module\Log\Page $logPage,
132 PacketActionsCommonLogic $packetActionsCommonLogic
133 ) {
134 $this->latteEngine = $latteEngine;
135 $this->optionsProvider = $optionsProvider;
136 $this->formFactory = $formFactory;
137 $this->httpRequest = $httpRequest;
138 $this->soapApiClient = $soapApiClient;
139 $this->messageManager = $messageManager;
140 $this->logger = $logger;
141 $this->orderRepository = $orderRepository;
142 $this->logPage = $logPage;
143 $this->packetActionsCommonLogic = $packetActionsCommonLogic;
144 }
145
146 /**
147 * Generates id of transient to store order ids.
148 *
149 * @return string
150 */
151 public static function getOrderIdsTransientName(): string {
152 return 'packetery_label_print_order_ids_' . wp_get_session_token();
153 }
154
155 /**
156 * Generates id of transient to store back link.
157 *
158 * @return string
159 */
160 public static function getBackLinkTransientName(): string {
161 return 'packetery_label_print_back_link_' . wp_get_session_token();
162 }
163
164 /**
165 * Gets label type.
166 *
167 * @param Order $order Order.
168 *
169 * @return string
170 */
171 public function getLabelFormatByOrder( Order $order ) {
172 if ( $order->isExternalCarrier() ) {
173 return $this->optionsProvider->get_carrier_label_format();
174 }
175
176 return $this->optionsProvider->get_packeta_label_format();
177 }
178
179 /**
180 * Prepares form and renders template.
181 */
182 public function render(): void {
183 $form = $this->createForm( $this->optionsProvider->getLabelMaxOffset( $this->getLabelFormat() ) );
184
185 $count = 0;
186 $isCarrierLabels = ( $this->httpRequest->getQuery( self::LABEL_TYPE_PARAM ) === self::ACTION_CARRIER_LABELS );
187
188 $orderIdsTransient = $this->getOrderIdsTransient();
189 if ( $orderIdsTransient ) {
190 $orderIds = $this->getPacketIdsFromTransient( $orderIdsTransient, $isCarrierLabels );
191 $count = count( $orderIds );
192 } else {
193 $this->messageManager->flash_message( __( 'No orders were selected', 'packeta' ), MessageManager::TYPE_INFO, MessageManager::RENDERER_PACKETERY, self::MENU_SLUG );
194 }
195
196 $this->latteEngine->render(
197 PACKETERY_PLUGIN_DIR . '/template/order/label-print.latte',
198 [
199 'form' => $form,
200 'count' => $count,
201 'backLink' => get_transient( self::getBackLinkTransientName() ),
202 'flashMessages' => $this->messageManager->renderToString( MessageManager::RENDERER_PACKETERY, self::MENU_SLUG ),
203 'translations' => [
204 'packeta' => __( 'Packeta', 'packeta' ),
205 'labelPrinting' => __( 'Print labels', 'packeta' ),
206 // translators: %s is count.
207 'numberOfLabelsToPrint' => __( 'Number of labels to print: %s', 'packeta' ),
208
209 'back' => __( 'Back', 'packeta' ),
210 'printLabels' => __( 'Print labels', 'packeta' ),
211 ],
212 ]
213 );
214 }
215
216 /**
217 * Gets label format for current job.
218 *
219 * @return string
220 */
221 private function getLabelFormat(): string {
222 $packetaLabelFormat = $this->optionsProvider->get_packeta_label_format();
223 $carrierLabelFormat = $this->optionsProvider->get_carrier_label_format();
224
225 return ( $this->httpRequest->getQuery( self::LABEL_TYPE_PARAM ) === self::ACTION_CARRIER_LABELS ? $carrierLabelFormat : $packetaLabelFormat );
226 }
227
228 /**
229 * Outputs pdf.
230 */
231 public function outputLabelsPdf(): void {
232 if ( $this->httpRequest->getQuery( 'page' ) !== self::MENU_SLUG ) {
233 return;
234 }
235
236 $fallbackToPacketaLabel = false;
237 $isCarrierLabels = ( $this->httpRequest->getQuery( self::LABEL_TYPE_PARAM ) === self::ACTION_CARRIER_LABELS );
238 $idParam = $this->httpRequest->getQuery( 'id' );
239 $packetIdParam = $this->httpRequest->getQuery( 'packet_id' );
240 if ( null !== $idParam && null !== $packetIdParam ) {
241 $fallbackToPacketaLabel = true;
242 $packetIds = [ $idParam => $packetIdParam ];
243 } else {
244 $orderIdsTransient = $this->getOrderIdsTransient();
245 if ( ! $orderIdsTransient ) {
246 return;
247 }
248
249 $packetIds = $this->getPacketIdsFromTransient( $orderIdsTransient, $isCarrierLabels );
250 }
251 if ( ! $packetIds ) {
252 $this->messageManager->flash_message( __( 'No suitable orders were selected', 'packeta' ), 'info' );
253 $this->packetActionsCommonLogic->redirectTo( PacketActionsCommonLogic::REDIRECT_TO_ORDER_GRID );
254 return;
255 }
256
257 $maxOffset = $this->optionsProvider->getLabelMaxOffset( $this->getLabelFormat() );
258 $form = $this->createForm( $maxOffset );
259 $offsetParam = $this->httpRequest->getQuery( 'offset' );
260 if ( 0 === $maxOffset ) {
261 $offset = 0;
262 } elseif ( null !== $offsetParam ) {
263 $offset = (int) $offsetParam;
264 } elseif ( $form->isSubmitted() ) {
265 $data = $form->getValues( 'array' );
266 $offset = $data['offset'];
267 } else {
268 return;
269 }
270
271 if ( $isCarrierLabels ) {
272 $response = $this->requestCarrierLabels( $offset, $packetIds );
273 if ( $fallbackToPacketaLabel && $response->hasFault() ) {
274 $response = $this->requestPacketaLabels( $offset, $packetIds );
275 }
276 } else {
277 $response = $this->requestPacketaLabels( $offset, $packetIds );
278 }
279 if ( ! $response || $response->hasFault() ) {
280 $message = ( null !== $response && $response->hasFault() ) ?
281 __( 'Label printing failed, you can find more information in the Packeta log.', 'packeta' ) :
282 __( 'You selected orders that were not submitted yet', 'packeta' );
283 $this->messageManager->flash_message( $message, MessageManager::TYPE_ERROR );
284
285 $redirectTo = $this->httpRequest->getQuery( PacketActionsCommonLogic::PARAM_REDIRECT_TO );
286 if ( PacketActionsCommonLogic::REDIRECT_TO_ORDER_DETAIL === $redirectTo && null !== $idParam ) {
287 $this->packetActionsCommonLogic->redirectTo( $redirectTo, $this->orderRepository->getById( (int) $idParam, true ) );
288 }
289 $this->packetActionsCommonLogic->redirectTo( PacketActionsCommonLogic::REDIRECT_TO_ORDER_GRID );
290 return;
291 }
292
293 header( 'Content-Type: application/pdf' );
294 header( 'Content-Transfer-Encoding: Binary' );
295 header( 'Content-Length: ' . strlen( $response->getPdfContents() ) );
296 header( 'Content-Disposition: attachment; filename="' . $this->getFilename() . '"' );
297 // @codingStandardsIgnoreStart
298 echo $response->getPdfContents();
299 // @codingStandardsIgnoreEnd
300 exit;
301 }
302
303 /**
304 * Creates offset setting form.
305 *
306 * @param int $maxOffset Maximal offset.
307 * @param string|null $name Form name.
308 *
309 * @return Form
310 */
311 public function createForm( int $maxOffset, string $name = null ): Form {
312 $form = $this->formFactory->create( $name );
313
314 $availableOffsets = [];
315 for ( $i = 0; $i <= $maxOffset; $i ++ ) {
316 $availableOffsets[ $i ] = ( 0 === $i ?
317 __( "don't skip any field on a print sheet", 'packeta' ) :
318 // translators: %s is offset.
319 sprintf( __( 'skip %s fields on first sheet', 'packeta' ), $i )
320 );
321 }
322 $form->addSelect(
323 'offset',
324 __( 'Skip fields', 'packeta' ),
325 $availableOffsets
326 )->checkDefaultValue( false );
327
328 return $form;
329 }
330
331 /**
332 * Registers submenu item.
333 */
334 public function register(): void {
335 add_submenu_page(
336 \Packetery\Module\Options\Page::SLUG,
337 __( 'Print labels', 'packeta' ),
338 __( 'Print labels', 'packeta' ),
339 'manage_woocommerce',
340 self::MENU_SLUG,
341 array(
342 $this,
343 'render',
344 ),
345 20
346 );
347 }
348
349 /**
350 * Hides submenu item.
351 */
352 public function hideFromMenus(): void {
353 Plugin::hideSubmenuItem( self::MENU_SLUG );
354 }
355
356 /**
357 * Prepares labels.
358 *
359 * @param int $offset Offset value.
360 * @param array $packetIds Packet ids.
361 *
362 * @return Response\PacketsLabelsPdf|null
363 */
364 private function requestPacketaLabels( int $offset, array $packetIds ): ?Response\PacketsLabelsPdf {
365 $request = new Request\PacketsLabelsPdf( array_values( $packetIds ), $this->getLabelFormat(), $offset );
366 $response = $this->soapApiClient->packetsLabelsPdf( $request );
367 // TODO: is possible to merge following part of requestPacketaLabels and requestCarrierLabels?
368
369 foreach ( $packetIds as $orderId => $packetId ) {
370 $record = new Log\Record();
371 $record->action = Log\Record::ACTION_LABEL_PRINT;
372 $record->orderId = $orderId;
373 try {
374 $order = $this->orderRepository->getById( $orderId );
375 } catch ( InvalidCarrierException $exception ) {
376 $order = null;
377 }
378
379 if ( ! $response->hasFault() ) {
380 if ( null !== $order ) {
381 $order->setIsLabelPrinted( true );
382 }
383
384 $record->status = Log\Record::STATUS_SUCCESS;
385 $record->title = __( 'Label has been printed successfully.', 'packeta' );
386 } else {
387 $record->status = Log\Record::STATUS_ERROR;
388 $record->title = __( 'Label could not be printed.', 'packeta' );
389 $record->params = [
390 'packetId' => $packetId,
391 'isPacketIdInvalid' => $response->hasInvalidPacketId( (string) $packetId ),
392 'request' => [
393 'packetIds' => $request->getPacketIds(),
394 'format' => $request->getFormat(),
395 'offset' => $request->getOffset(),
396 ],
397 'errorMessage' => $response->getFaultString(),
398 ];
399 }
400
401 $this->logger->add( $record );
402
403 if ( null !== $order ) {
404 $order->updateApiErrorMessage( $response->getFaultString() );
405 $this->orderRepository->save( $order );
406 }
407 }
408
409 return $response;
410 }
411
412 /**
413 * Prepares carrier labels.
414 *
415 * @param int $offset Offset value.
416 * @param array $packetIds Packet ids.
417 *
418 * @return Response\PacketsCourierLabelsPdf
419 */
420 private function requestCarrierLabels( int $offset, array $packetIds ): Response\PacketsCourierLabelsPdf {
421 $packetIdsWithCourierNumbers = $this->getPacketIdsWithCourierNumbers( $packetIds );
422 $request = new Request\PacketsCourierLabelsPdf( array_values( $packetIdsWithCourierNumbers ), $this->getLabelFormat(), $offset );
423 $response = $this->soapApiClient->packetsCarrierLabelsPdf( $request );
424
425 foreach ( $packetIdsWithCourierNumbers as $orderId => $pairItem ) {
426 $record = new Log\Record();
427 $record->action = Log\Record::ACTION_CARRIER_LABEL_PRINT;
428 $record->orderId = $orderId;
429 try {
430 $order = $this->orderRepository->getById( $orderId );
431 } catch ( InvalidCarrierException $exception ) {
432 $order = null;
433 }
434
435 if ( ! $response->hasFault() ) {
436 if ( null !== $order ) {
437 $order->setIsLabelPrinted( true );
438 $order->setCarrierNumber( $pairItem['courierNumber'] );
439 }
440
441 $record->status = Log\Record::STATUS_SUCCESS;
442 $record->title = __( 'Carrier label has been printed successfully.', 'packeta' );
443 } else {
444 $record->status = Log\Record::STATUS_ERROR;
445 $record->title = __( 'Carrier label could not be printed.', 'packeta' );
446 $record->params = [
447 'packetId' => $pairItem['packetId'],
448 'courierNumber' => $pairItem['courierNumber'],
449 'isPacketIdInvalid' => $response->hasInvalidPacketId( (string) $pairItem['packetId'] ),
450 'isCourierNumberInvalid' => $response->hasInvalidCourierNumber( (string) $pairItem['courierNumber'] ),
451 'request' => [
452 'packetIdsWithCourierNumbers' => $request->getPacketIdsWithCourierNumbers(),
453 'format' => $request->getFormat(),
454 'offset' => $request->getOffset(),
455 ],
456 'errorMessage' => $response->getFaultString(),
457 ];
458 }
459 $this->logger->add( $record );
460
461 if ( null !== $order ) {
462 $order->updateApiErrorMessage( $response->getFaultString() );
463 $this->orderRepository->save( $order );
464 }
465 }
466
467 return $response;
468 }
469
470 /**
471 * Gets filename for label pdf.
472 *
473 * @return string
474 */
475 private function getFilename(): string {
476 return 'packeta_labels_' . strtolower( str_replace( ' ', '_', $this->getLabelFormat() ) ) . '.pdf';
477 }
478
479 /**
480 * Gets saved packet ids.
481 *
482 * @param array $orderIds Order IDs from transient.
483 * @param bool $isCarrierLabels Are carrier labels requested?.
484 *
485 * @return string[]
486 */
487 private function getPacketIdsFromTransient( array $orderIds, bool $isCarrierLabels ): array {
488 $orders = $this->orderRepository->getByIds( $orderIds );
489 $packetIds = [];
490 foreach ( $orders as $order ) {
491 if ( null === $order->getPacketId() ) {
492 continue;
493 }
494 if ( ! $isCarrierLabels || $order->isExternalCarrier() ) {
495 $packetIds[ $order->getNumber() ] = $order->getPacketId();
496 }
497 }
498
499 return $packetIds;
500 }
501
502 /**
503 * Gets order IDs transient.
504 *
505 * @return array|null
506 */
507 private function getOrderIdsTransient(): ?array {
508 $orderIds = get_transient( self::getOrderIdsTransientName() );
509 if ( is_array( $orderIds ) ) {
510 return $orderIds;
511 }
512
513 return null;
514 }
515
516 /**
517 * Gets carrier packet numbers from API.
518 *
519 * @param string[] $packetIds List of packet ids.
520 *
521 * @return array[]
522 */
523 private function getPacketIdsWithCourierNumbers( array $packetIds ): array {
524 $pairs = [];
525 foreach ( $packetIds as $orderId => $packetId ) {
526 $request = new Request\PacketCourierNumber( $packetId );
527 $response = $this->soapApiClient->packetCourierNumber( $request );
528 if ( $response->hasFault() ) {
529 if ( $response->hasWrongPassword() ) {
530 $this->messageManager->flash_message( __( 'Please set a proper API password.', 'packeta' ), MessageManager::TYPE_ERROR );
531
532 return [];
533 }
534
535 $record = new Log\Record();
536 $record->action = Log\Record::ACTION_CARRIER_NUMBER_RETRIEVING;
537 $record->status = Log\Record::STATUS_ERROR;
538 $record->title = __( 'Carrier number could not be retrieved.', 'packeta' );
539 $record->params = [
540 'packetId' => $request->getPacketId(),
541 'errorMessage' => $response->getFaultString(),
542 ];
543 $record->orderId = $orderId;
544 $this->logger->add( $record );
545 try {
546 $order = $this->orderRepository->getById( $orderId );
547 } catch ( InvalidCarrierException $exception ) {
548 $order = null;
549 }
550 if ( null !== $order ) {
551 $order->updateApiErrorMessage( $response->getFaultString() );
552 $this->orderRepository->save( $order );
553 }
554 continue;
555 }
556 $pairs[ $orderId ] = [
557 'packetId' => $packetId,
558 'courierNumber' => $response->getNumber(),
559 ];
560 }
561
562 return $pairs;
563 }
564
565 }
566