PluginProbe
Packeta / 1.5.2
Packeta v1.5.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
packeta / src / Packetery / Module / Order / LabelPrint.php

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

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