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
packeta / src / Packetery / Module / Order / Repository.php

Repository.php in Packeta 2.3.2, at src/Packetery/Module/Order/Repository.php

755 lines 22.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class Repository.
4 *
5 * @package Packetery\Module\Order
6 */
7
8 declare( strict_types=1 );
9
10 namespace Packetery\Module\Order;
11
12 use DateTimeImmutable;
13 use Exception;
14 use Packetery\Core\CoreHelper;
15 use Packetery\Core\Entity;
16 use Packetery\Core\Entity\Order;
17 use Packetery\Core\Entity\PickupPoint;
18 use Packetery\Module\Carrier;
19 use Packetery\Module\Carrier\PacketaPickupPointsConfig;
20 use Packetery\Module\CustomsDeclaration;
21 use Packetery\Module\Exception\DeleteErrorException;
22 use Packetery\Module\Exception\InvalidCarrierException;
23 use Packetery\Module\Framework\WcAdapter;
24 use Packetery\Module\ModuleHelper;
25 use Packetery\Module\Shipping\ShippingProvider;
26 use Packetery\Module\WcLogger;
27 use Packetery\Module\WpdbAdapter;
28 use WC_Order;
29 use WP_Post;
30
31 /**
32 * Class Repository.
33 *
34 * @package Packetery\Module\Order
35 */
36 class Repository {
37
38 /**
39 * WpdbAdapter.
40 *
41 * @var WpdbAdapter
42 */
43 private $wpdbAdapter;
44
45 /**
46 * Order factory.
47 *
48 * @var Builder
49 */
50 private $builder;
51
52 /**
53 * CoreHelper.
54 *
55 * @var CoreHelper
56 */
57 private $coreHelper;
58
59 /**
60 * Internal pickup points config.
61 *
62 * @var PacketaPickupPointsConfig
63 */
64 private $pickupPointsConfig;
65
66 /**
67 * Carrier repository.
68 *
69 * @var Carrier\EntityRepository
70 */
71 private $carrierRepository;
72
73 /**
74 * Customs declaration repository.
75 *
76 * @var CustomsDeclaration\Repository
77 */
78 private $customsDeclarationRepository;
79
80 /**
81 * @var WcAdapter
82 */
83 private $wcAdapter;
84
85 /**
86 * Repository constructor.
87 *
88 * @param WpdbAdapter $wpdbAdapter WpdbAdapter.
89 * @param Builder $orderFactory Order factory.
90 * @param CoreHelper $coreHelper CoreHelper.
91 * @param PacketaPickupPointsConfig $pickupPointsConfig Internal pickup points config.
92 * @param Carrier\EntityRepository $carrierRepository Carrier repository.
93 * @param CustomsDeclaration\Repository $customsDeclarationRepository Customs declaration repository.
94 */
95 public function __construct(
96 WpdbAdapter $wpdbAdapter,
97 Builder $orderFactory,
98 CoreHelper $coreHelper,
99 PacketaPickupPointsConfig $pickupPointsConfig,
100 Carrier\EntityRepository $carrierRepository,
101 CustomsDeclaration\Repository $customsDeclarationRepository,
102 WcAdapter $wcAdapter
103 ) {
104 $this->wpdbAdapter = $wpdbAdapter;
105 $this->builder = $orderFactory;
106 $this->coreHelper = $coreHelper;
107 $this->pickupPointsConfig = $pickupPointsConfig;
108 $this->carrierRepository = $carrierRepository;
109 $this->customsDeclarationRepository = $customsDeclarationRepository;
110 $this->wcAdapter = $wcAdapter;
111 }
112
113 /**
114 * Applies custom order status filter.
115 *
116 * @param array<string, string|null> $clauses Query clauses.
117 * @param \WP_Query|null $queryObject WP Query.
118 * @param array<string, string|null> $paramValues Param values.
119 *
120 * @return void
121 */
122 private function applyCustomFilters( array &$clauses, ?\WP_Query $queryObject, array $paramValues ): void {
123 /**
124 * Filters order statuses to exclude in Packeta order list filtering.
125 *
126 * @since 1.4
127 *
128 * @param array $orderStatusesToExclude Order statuses to exclude.
129 * @param \WP_Query|null $queryObject WP Query.
130 * @param array $paramValues Param values.
131 */
132 $orderStatusesToExclude = (array) apply_filters( 'packetery_exclude_orders_with_status', [], $queryObject, $paramValues );
133 if ( count( $orderStatusesToExclude ) === 0 ) {
134 return;
135 }
136
137 if ( ModuleHelper::isHposEnabled() ) {
138 $clauses['where'] .= sprintf( ' AND `%s`.`status` NOT IN (%s)', $this->wpdbAdapter->wcOrders, $this->wpdbAdapter->prepareInClause( $orderStatusesToExclude ) );
139 } else {
140 $clauses['where'] .= sprintf( ' AND `%s`.`post_status` NOT IN (%s)', $this->wpdbAdapter->posts, $this->wpdbAdapter->prepareInClause( $orderStatusesToExclude ) );
141 }
142 }
143
144 /**
145 * Extends SQL query clauses.
146 *
147 * @param array<string, string> $clauses Clauses.
148 * @param \WP_Query|null $queryObject Query object.
149 * @param array<string, string|null> $paramValues Param values.
150 *
151 * @return array<string, string>
152 */
153 public function processClauses( array $clauses, ?\WP_Query $queryObject, array $paramValues ): array {
154 if ( ModuleHelper::isHposEnabled() ) {
155 $clauses['join'] .= ' LEFT JOIN `' . $this->wpdbAdapter->packeteryOrder . '` ON `' . $this->wpdbAdapter->packeteryOrder . '`.`id` = `' . $this->wpdbAdapter->wcOrders . '`.`id`';
156 } else {
157 $clauses['join'] .= ' LEFT JOIN `' . $this->wpdbAdapter->packeteryOrder . '` ON `' . $this->wpdbAdapter->packeteryOrder . '`.`id` = `' . $this->wpdbAdapter->posts . '`.`id`';
158 }
159
160 if ( isset( $paramValues['packetery_carrier_id'] ) && $paramValues['packetery_carrier_id'] !== '' ) {
161 $clauses['where'] .= ' AND `' . $this->wpdbAdapter->packeteryOrder . '`.`carrier_id` = "' . esc_sql( $paramValues['packetery_carrier_id'] ) . '"';
162 $this->applyCustomFilters( $clauses, $queryObject, $paramValues );
163 }
164 if ( isset( $paramValues['packetery_to_submit'] ) && $paramValues['packetery_to_submit'] !== '' ) {
165 $clauses['where'] .= ' AND `' . $this->wpdbAdapter->packeteryOrder . '`.`carrier_id` IS NOT NULL ';
166 $clauses['where'] .= ' AND `' . $this->wpdbAdapter->packeteryOrder . '`.`is_exported` = false ';
167 $this->applyCustomFilters( $clauses, $queryObject, $paramValues );
168 }
169 if ( isset( $paramValues['packetery_to_print'] ) && $paramValues['packetery_to_print'] !== '' ) {
170 $clauses['where'] .= ' AND `' . $this->wpdbAdapter->packeteryOrder . '`.`packet_id` IS NOT NULL ';
171 $clauses['where'] .= ' AND `' . $this->wpdbAdapter->packeteryOrder . '`.`is_label_printed` = false ';
172 $this->applyCustomFilters( $clauses, $queryObject, $paramValues );
173 }
174 if ( isset( $paramValues['packetery_order_type'] ) && $paramValues['packetery_order_type'] !== '' ) {
175 if ( $paramValues['packetery_order_type'] === Entity\Carrier::INTERNAL_PICKUP_POINTS_ID ) {
176 $comparison = 'IN';
177 } else {
178 $comparison = 'NOT IN';
179 }
180 $internalCarriers = array_keys( $this->carrierRepository->getNonFeedCarriers() );
181 $internalCarriers[] = Entity\Carrier::INTERNAL_PICKUP_POINTS_ID;
182 $clauses['where'] .= ' AND `' . $this->wpdbAdapter->packeteryOrder . '`.`carrier_id` ' . $comparison . ' (' . $this->wpdbAdapter->prepareInClause( $internalCarriers ) . ')';
183 $this->applyCustomFilters( $clauses, $queryObject, $paramValues );
184 }
185 if ( isset( $paramValues['orderby'] ) && $paramValues['orderby'] === 'packetery_packet_stored_until' ) {
186 if ( $paramValues['order'] === 'asc' ) {
187 $clauses['orderby'] = '`' . $this->wpdbAdapter->packeteryOrder . '`.`stored_until` ASC';
188 }
189 if ( $paramValues['order'] === 'desc' ) {
190 $clauses['orderby'] = '`' . $this->wpdbAdapter->packeteryOrder . '`.`stored_until` DESC';
191 }
192 }
193
194 return $clauses;
195 }
196
197 /**
198 * Create table to store orders.
199 *
200 * @return bool
201 */
202 public function createOrAlterTable(): bool {
203 $createTableQuery = 'CREATE TABLE ' . $this->wpdbAdapter->packeteryOrder . ' (
204 `id` bigint(20) unsigned NOT NULL,
205 `carrier_id` varchar(15) NOT NULL,
206 `is_exported` tinyint(1) NOT NULL,
207 `packet_id` varchar(15) NULL,
208 `packet_claim_id` varchar(15) NULL,
209 `packet_claim_password` varchar(10) NULL,
210 `consign_password` varchar(10) NULL,
211 `is_label_printed` tinyint(1) NOT NULL,
212 `point_id` varchar(50) NULL,
213 `point_place` varchar(100) NULL,
214 `point_name` varchar(150) NULL,
215 `point_url` varchar(255) NULL,
216 `point_street` varchar(120) NULL,
217 `point_zip` varchar(10) NULL,
218 `point_city` varchar(70) NULL,
219 `address_validated` tinyint(1) NOT NULL,
220 `delivery_address` text NULL,
221 `weight` float NULL,
222 `length` float NULL,
223 `width` float NULL,
224 `height` float NULL,
225 `adult_content` tinyint(1) NULL,
226 `value` double NULL,
227 `cod` double NULL,
228 `api_error_message` text NULL,
229 `api_error_date` datetime NULL,
230 `carrier_number` varchar(50) NULL,
231 `packet_status` varchar(30) NULL,
232 `stored_until` date NULL,
233 `deliver_on` date NULL,
234 `car_delivery_id` varchar(15) NULL,
235 PRIMARY KEY (`id`)
236 ) ' . $this->wpdbAdapter->get_charset_collate();
237
238 return $this->wpdbAdapter->dbDelta( $createTableQuery, $this->wpdbAdapter->packeteryOrder );
239 }
240
241 /**
242 * @throws InvalidCarrierException InvalidCarrierException.
243 */
244 public function getById( int $id ): ?Order {
245 $wcOrder = $this->getWcOrderById( $id );
246 if ( $wcOrder === null ) {
247 return null;
248 }
249
250 return $this->getByWcOrder( $wcOrder );
251 }
252
253 /**
254 * Ignores InvalidCarrierException.
255 */
256 public function getByIdWithValidCarrier( int $id ): ?Order {
257 $wcOrder = $this->getWcOrderById( $id );
258 if ( $wcOrder === null ) {
259 return null;
260 }
261
262 return $this->getByWcOrderWithValidCarrier( $wcOrder );
263 }
264
265 /**
266 * Returns Packeta order, or null.
267 *
268 * @param int $id Order ID.
269 *
270 * @return Order|null
271 */
272 public function findById( int $id ): ?Order {
273 $wcOrder = $this->getWcOrderById( $id );
274 if ( $wcOrder === null ) {
275 return null;
276 }
277
278 $result = $this->getDataById( $wcOrder->get_id() );
279 if ( $result === null ) {
280 return null;
281 }
282
283 try {
284 return $this->builder->build( $wcOrder, $result );
285 } catch ( InvalidCarrierException $invalidCarrierException ) {
286 return null;
287 }
288 }
289
290 /**
291 * Gets Packeta order data by id.
292 *
293 * @param int $id Order id.
294 *
295 * @return object|null
296 */
297 public function getDataById( int $id ): ?object {
298 return $this->wpdbAdapter->get_row(
299 $this->wpdbAdapter->prepare(
300 '
301 SELECT `o`.* FROM `' . $this->wpdbAdapter->packeteryOrder . '` `o`
302 ' . $this->getWcOrderJoinClause() . '
303 WHERE `o`.`id` = %d',
304 $id
305 )
306 );
307 }
308
309 private function getDataByWcOrder( WC_Order $wcOrder ): ?object {
310 if ( ! ShippingProvider::wcOrderHasOurMethod( $wcOrder ) ) {
311 return null;
312 }
313
314 $packeteryOrderData = $this->getDataById( $wcOrder->get_id() );
315 if ( ! is_object( $packeteryOrderData ) ) {
316 return null;
317 }
318
319 return $packeteryOrderData;
320 }
321
322 /**
323 * @throws InvalidCarrierException
324 */
325 public function getByWcOrder( WC_Order $wcOrder ): ?Order {
326 $packeteryOrderData = $this->getDataByWcOrder( $wcOrder );
327 if ( $packeteryOrderData === null ) {
328 return null;
329 }
330
331 return $this->builder->build( $wcOrder, $packeteryOrderData );
332 }
333
334 /**
335 * Ignores InvalidCarrierException.
336 */
337 public function getByWcOrderWithValidCarrier( WC_Order $wcOrder ): ?Order {
338 $packeteryOrderData = $this->getDataByWcOrder( $wcOrder );
339 if ( $packeteryOrderData === null ) {
340 return null;
341 }
342
343 try {
344 return $this->builder->build( $wcOrder, $packeteryOrderData );
345 } catch ( InvalidCarrierException $invalidCarrierException ) {
346 return null;
347 }
348 }
349
350 /**
351 * Transforms order to DB array.
352 *
353 * @param Order $order Order.
354 *
355 * @return array<string, bool|float|int|string|null>
356 */
357 private function orderToDbArray( Order $order ): array {
358 $point = $order->getPickupPoint();
359 if ( $point === null ) {
360 $point = new PickupPoint();
361 }
362
363 $deliveryAddress = null;
364 if ( $order->isAddressValidated() && $order->getDeliveryAddress() !== null ) {
365 $deliveryAddress = wp_json_encode( $order->getDeliveryAddress()->export() );
366 }
367
368 $apiErrorDateTime = $order->getLastApiErrorDateTime();
369 if ( $apiErrorDateTime !== null ) {
370 $apiErrorDateTime = $apiErrorDateTime->format( CoreHelper::MYSQL_DATETIME_FORMAT );
371 }
372
373 $data = [
374 'id' => (int) $order->getNumber(),
375 'carrier_id' => $order->getCarrier()->getId(),
376 'is_exported' => (int) $order->isExported(),
377 'packet_id' => $order->getPacketId(),
378 'packet_claim_id' => $order->getPacketClaimId(),
379 'packet_claim_password' => $order->getPacketClaimPassword(),
380 'consign_password' => $order->getConsignPassword(),
381 'packet_status' => $order->getPacketStatus(),
382 'stored_until' => $this->coreHelper->getStringFromDateTime( $order->getStoredUntil(), CoreHelper::DATEPICKER_FORMAT ),
383 'is_label_printed' => (int) $order->isLabelPrinted(),
384 'carrier_number' => $order->getCarrierNumber(),
385 'weight' => $order->getWeight(),
386 'car_delivery_id' => $order->getCarDeliveryId(),
387 'point_id' => $point->getId(),
388 'point_place' => $point->getPlace(),
389 'point_name' => $point->getName(),
390 'point_url' => $point->getUrl(),
391 'point_street' => $point->getStreet(),
392 'point_zip' => $point->getZip(),
393 'point_city' => $point->getCity(),
394 'address_validated' => (int) $order->isAddressValidated(),
395 'delivery_address' => $deliveryAddress,
396 'length' => $order->getLength(),
397 'width' => $order->getWidth(),
398 'height' => $order->getHeight(),
399 'adult_content' => $order->containsAdultContent(),
400 'cod' => $order->getManualCod(),
401 'value' => $order->getManualValue(),
402 'api_error_message' => $order->getLastApiErrorMessage(),
403 'api_error_date' => $apiErrorDateTime,
404 'deliver_on' => $this->coreHelper->getStringFromDateTime( $order->getDeliverOn(), CoreHelper::DATEPICKER_FORMAT ),
405 ];
406
407 return $data;
408 }
409
410 /**
411 * Saves order.
412 *
413 * @param Order $order Order.
414 *
415 * @return int|false The number of rows updated, or false on error.
416 */
417 public function save( Order $order ) {
418 return $this->saveData( $this->orderToDbArray( $order ) );
419 }
420
421 /**
422 * Saves order data.
423 *
424 * @param array<string, int|string|null|DateTimeImmutable> $orderData Order data.
425 *
426 * @return int|false The number of rows updated, or false on error.
427 */
428 public function saveData( array $orderData ) {
429 $this->onBeforeDataInsertion( $orderData );
430
431 return $this->wpdbAdapter->insertReplaceHelper( $this->wpdbAdapter->packeteryOrder, $orderData, null, 'REPLACE' );
432 }
433
434 /**
435 * Calls logic before order data replace/insert.
436 *
437 * @param array<string, string|null|DateTimeImmutable> $orderData Order data.
438 * @return void
439 */
440 private function onBeforeDataInsertion( array $orderData ): void {
441 $pointId = $orderData['point_id'] ?? null;
442 $carrierId = $orderData['carrier_id'] ?? null;
443 /**
444 * Tells if Packeta debug logs are enabled.
445 *
446 * @since 1.7.2
447 */
448 $isLoggingActive = (bool) apply_filters( 'packeta_enable_debug_logs', false );
449
450 if ( ( $pointId !== null && $pointId !== '' ) || ! $isLoggingActive || ! $this->pickupPointsConfig->isInternalPickupPointCarrier( $carrierId ) ) {
451 return;
452 }
453
454 $wcLogger = $this->wcAdapter->getLogger();
455 $dataToLog = [
456 'order' => $orderData,
457 'trace' => array_map(
458 static function ( array $item ): array {
459 return [
460 'file' => sprintf( '%s(%s)', $item['file'], $item['line'] ),
461 'method' => sprintf( '%s%s%s(...)', $item['class'] ?? '', $item['type'] ?? '', $item['function'] ),
462 ];
463 },
464 ( new Exception() )->getTrace()
465 ),
466 ];
467 $wcLogger->warning(
468 sprintf(
469 'Required value for the pickup point order is not set: %s',
470 wp_json_encode( $dataToLog, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE )
471 ),
472 [ 'source' => 'packeta' ]
473 );
474 }
475
476 /**
477 * Loads order entities by list of ids.
478 *
479 * @param string[] $orderIds Order ids.
480 *
481 * @return Order[]
482 */
483 public function getByIds( array $orderIds ): array {
484 if ( count( $orderIds ) === 0 ) {
485 return [];
486 }
487
488 $wpdbAdapter = $this->wpdbAdapter;
489 $ordersIdsPlaceholder = implode( ', ', array_fill( 0, count( $orderIds ), '%d' ) );
490 $packeteryOrdersResult = $wpdbAdapter->get_results(
491 $wpdbAdapter->prepare(
492 'SELECT * FROM `' . $wpdbAdapter->packeteryOrder . '`
493 WHERE `id` IN (' . $ordersIdsPlaceholder . ')',
494 $orderIds
495 ),
496 OBJECT_K
497 );
498
499 $orderEntities = [];
500 foreach ( $orderIds as $orderId ) {
501 if ( ! isset( $packeteryOrdersResult[ $orderId ] ) ) {
502 continue;
503 }
504
505 $wcOrder = $this->getWcOrderById( (int) $orderId );
506 assert( $wcOrder !== null, 'WC order has to be present' );
507
508 try {
509 $orderEntities[ $orderId ] = $this->builder->build( $wcOrder, $packeteryOrdersResult[ $orderId ] );
510 } catch ( InvalidCarrierException $exception ) {
511 continue;
512 }
513 }
514
515 return $orderEntities;
516 }
517
518 /**
519 * Finds orders.
520 *
521 * @param string[] $allowedPacketStatuses Allowed packet statuses.
522 * @param string[] $allowedOrderStatuses Allowed order statuses.
523 * @param int $maxDays Max number of days of single packet sync.
524 * @param int $limit Number of records.
525 *
526 * @return \Generator<int>
527 * @throws Exception Exception.
528 */
529 public function findStatusSyncingOrderIds( array $allowedPacketStatuses, array $allowedOrderStatuses, int $maxDays, int $limit ): \Generator {
530 $dateLimit = CoreHelper::now()->modify( '- ' . $maxDays . ' days' )->format( 'Y-m-d H:i:s' );
531
532 $andWhere = [ '`o`.`packet_id` IS NOT NULL' ];
533 $hposEnabled = ModuleHelper::isHposEnabled();
534
535 if ( $hposEnabled ) {
536 $andWhere[] = $this->wpdbAdapter->prepare( '`wc_o`.`date_created_gmt` >= %s', $dateLimit );
537 } else {
538 $andWhere[] = $this->wpdbAdapter->prepare( '`wp_p`.`post_date_gmt` >= %s', $dateLimit );
539 }
540
541 $orPacketStatus = [];
542 $orPacketStatus[] = '`o`.`packet_status` IS NULL';
543
544 if ( count( $allowedPacketStatuses ) > 0 ) {
545 $orPacketStatus[] = '`o`.`packet_status` IN (' . $this->wpdbAdapter->prepareInClause( $allowedPacketStatuses ) . ')';
546 }
547
548 if ( count( $orPacketStatus ) > 0 ) {
549 $andWhere[] = '(' . implode( ' OR ', $orPacketStatus ) . ')';
550 }
551
552 if ( count( $allowedOrderStatuses ) > 0 && $hposEnabled ) {
553 $andWhere[] = '`wc_o`.`status` IN (' . $this->wpdbAdapter->prepareInClause( $allowedOrderStatuses ) . ')';
554 } elseif ( count( $allowedOrderStatuses ) > 0 && $hposEnabled === false ) {
555 $andWhere[] = '`wp_p`.`post_status` IN (' . $this->wpdbAdapter->prepareInClause( $allowedOrderStatuses ) . ')';
556 } else {
557 $andWhere[] = '1 = 0';
558 }
559
560 $where = '';
561 if ( count( $andWhere ) > 0 ) {
562 $where = ' WHERE ' . implode( ' AND ', $andWhere );
563 }
564
565 if ( $hposEnabled ) {
566 $orderBy = ' ORDER BY `wc_o`.`date_created_gmt` ';
567 } else {
568 $orderBy = ' ORDER BY `wp_p`.`post_date_gmt` ';
569 }
570
571 $sql = $this->wpdbAdapter->prepare(
572 '
573 SELECT `o`.`id` FROM `' . $this->wpdbAdapter->packeteryOrder . '` `o`
574 ' . $this->getWcOrderJoinClause() . '
575 ' . $where . '
576 ' . $orderBy . '
577 LIMIT %d',
578 $limit
579 );
580
581 $rows = $this->wpdbAdapter->get_results( $sql );
582
583 foreach ( $rows as $row ) {
584 $wcOrder = $this->getWcOrderById( (int) $row->id );
585 if ( $wcOrder === null || ! ShippingProvider::wcOrderHasOurMethod( $wcOrder ) ) {
586 continue;
587 }
588
589 yield (int) $row->id;
590 }
591 }
592
593 /**
594 * Counts order to be submitted.
595 *
596 * @return int
597 */
598 public function countOrdersToSubmit(): int {
599 return $this->countOrders( [ 'packetery_to_submit' => '1' ] );
600 }
601
602 /**
603 * Counts order to be printed.
604 *
605 * @return int
606 */
607 public function countOrdersToPrint(): int {
608 return $this->countOrders( [ 'packetery_to_print' => '1' ] );
609 }
610
611 /**
612 * Counts orders by given params.
613 *
614 * @param array<string, string> $params Params.
615 *
616 * @return int
617 */
618 private function countOrders( array $params ): int {
619 $clauses = [ 'join' => '' ];
620
621 if ( ModuleHelper::isHposEnabled() ) {
622 $clauses['select'] = ' SELECT COUNT(DISTINCT `' . $this->wpdbAdapter->wcOrders . '`.`id`) ';
623 $clauses['from'] = ' FROM `' . $this->wpdbAdapter->wcOrders . '` ';
624 } else {
625 $clauses['select'] = ' SELECT COUNT(DISTINCT `' . $this->wpdbAdapter->posts . '`.`ID`) ';
626 $clauses['from'] = ' FROM `' . $this->wpdbAdapter->posts . '` ';
627 }
628
629 $clauses['where'] = ' WHERE `' . $this->wpdbAdapter->packeteryOrder . '`.`id` IS NOT NULL ';
630 $clauses = $this->processClauses( $clauses, null, $params );
631
632 return (int) $this->wpdbAdapter->get_var(
633 $clauses['select'] .
634 $clauses['from'] .
635 $clauses['join'] .
636 $clauses['where']
637 );
638 }
639
640 /**
641 * Gets WC Order join clause.
642 *
643 * @return string
644 */
645 public function getWcOrderJoinClause(): string {
646 $packeteryTableAlias = 'o';
647
648 if ( ModuleHelper::isHposEnabled() ) {
649 $sourceTableAlias = 'wc_o';
650
651 return sprintf(
652 'JOIN `%s` `%s` ON `%s`.`id` = `%s`.`id`',
653 $this->wpdbAdapter->wcOrders,
654 $sourceTableAlias,
655 $sourceTableAlias,
656 $packeteryTableAlias
657 );
658 }
659
660 $sourceTableAlias = 'wp_p';
661
662 return sprintf(
663 'JOIN `%s` `%s` ON `%s`.`ID` = `%s`.`id`',
664 $this->wpdbAdapter->posts,
665 $sourceTableAlias,
666 $sourceTableAlias,
667 $packeteryTableAlias
668 );
669 }
670
671 /**
672 * Deletes all custom table records linked to permanently deleted orders.
673 *
674 * @return void
675 */
676 public function deleteOrphans(): void {
677 if ( ModuleHelper::isHposEnabled() ) {
678 $this->wpdbAdapter->query(
679 'DELETE `' . $this->wpdbAdapter->packeteryOrder . '` FROM `' . $this->wpdbAdapter->packeteryOrder . '`
680 LEFT JOIN `' . $this->wpdbAdapter->wcOrders . '` ON `' . $this->wpdbAdapter->wcOrders . '`.`id` = `' . $this->wpdbAdapter->packeteryOrder . '`.`id`
681 WHERE `' . $this->wpdbAdapter->wcOrders . '`.`id` IS NULL'
682 );
683
684 return;
685 }
686
687 $this->wpdbAdapter->query(
688 'DELETE `' . $this->wpdbAdapter->packeteryOrder . '` FROM `' . $this->wpdbAdapter->packeteryOrder . '`
689 LEFT JOIN `' . $this->wpdbAdapter->posts . '` ON `' . $this->wpdbAdapter->posts . '`.`ID` = `' . $this->wpdbAdapter->packeteryOrder . '`.`id`
690 WHERE `' . $this->wpdbAdapter->posts . '`.`ID` IS NULL'
691 );
692 }
693
694 /**
695 * Deletes order data including customs declaration and its items from custom tables.
696 *
697 * @param int $orderId Order id.
698 *
699 * @return bool true on success, false in case of db failure.
700 */
701 public function delete( int $orderId ): bool {
702 try {
703 $this->customsDeclarationRepository->delete( (string) $orderId );
704 $this->wpdbAdapter->delete( $this->wpdbAdapter->packeteryOrder, [ 'id' => $orderId ], '%d' );
705
706 return true;
707 } catch ( DeleteErrorException $e ) {
708 return false;
709 }
710 }
711
712 /**
713 * Fires after post deletion.
714 *
715 * @param int|mixed $postId Post id.
716 * @param WP_Post|mixed $post Post object.
717 *
718 * @return void
719 */
720 public function deletedPostHook( $postId, $post ): void {
721 if ( ! is_int( $postId ) ) {
722 WcLogger::logArgumentTypeError( __METHOD__, 'postId', 'int', $postId );
723
724 return;
725 }
726
727 if ( ! $post instanceof WP_Post ) {
728 WcLogger::logArgumentTypeError( __METHOD__, 'post', WP_Post::class, $post );
729
730 return;
731 }
732
733 // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
734 if ( $post->post_type === 'shop_order' ) {
735 $this->delete( $postId );
736 }
737 }
738
739 /**
740 * Gets WC_Order object.
741 *
742 * @param int $id Order id.
743 *
744 * @return WC_Order|null
745 */
746 public function getWcOrderById( int $id ): ?WC_Order {
747 $result = wc_get_order( $id );
748 if ( $result instanceof WC_Order ) {
749 return $result;
750 }
751
752 return null;
753 }
754 }
755