PluginProbe
Packeta / 1.3.1
Packeta v1.3.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
packeta / src / Packetery / Module / Order / Repository.php

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

450 lines 11.9 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 Packetery\Core\Entity\Order;
13 use Packetery\Core\Entity\PickupPoint;
14 use Packetery\Core\Entity\Size;
15 use Packetery\Core\Entity\Address;
16 use Packetery\Module\Carrier;
17 use Packetery\Module\ShippingMethod;
18 use WP_Post;
19
20 /**
21 * Class Repository.
22 *
23 * @package Packetery\Module\Order
24 */
25 class Repository {
26
27 /**
28 * Wpdb.
29 *
30 * @var \wpdb
31 */
32 private $wpdb;
33
34 /**
35 * Order factory.
36 *
37 * @var Builder
38 */
39 private $builder;
40
41 /**
42 * Repository constructor.
43 *
44 * @param \wpdb $wpdb Wpdb.
45 * @param Builder $orderFactory Order factory.
46 */
47 public function __construct( \wpdb $wpdb, Builder $orderFactory ) {
48 $this->wpdb = $wpdb;
49 $this->builder = $orderFactory;
50 }
51
52 /**
53 * Extends WP_Query to include custom table.
54 *
55 * @link https://wordpress.stackexchange.com/questions/50305/how-to-extend-wp-query-to-include-custom-table-in-query
56 *
57 * @param array $clauses Clauses.
58 * @param \WP_Query $queryObject WP_Query.
59 * @param array $paramValues Param values.
60 *
61 * @return array
62 */
63 public function processPostClauses( array $clauses, \WP_Query $queryObject, array $paramValues ): array {
64 if ( isset( $queryObject->query['post_type'] ) &&
65 (
66 'shop_order' === $queryObject->query['post_type'] ||
67 ( is_array( $queryObject->query['post_type'] ) && in_array( 'shop_order', $queryObject->query['post_type'], true ) )
68 )
69 ) {
70 // TODO: Introduce variable.
71 $clauses['join'] .= ' LEFT JOIN `' . $this->wpdb->packetery_order . '` ON `' . $this->wpdb->packetery_order . '`.`id` = `' . $this->wpdb->posts . '`.`id`';
72
73 if ( $paramValues['packetery_carrier_id'] ) {
74 $clauses['where'] .= ' AND `' . $this->wpdb->packetery_order . '`.`carrier_id` = "' . $this->wpdb->_real_escape( $paramValues['packetery_carrier_id'] ) . '"';
75 }
76 if ( $paramValues['packetery_to_submit'] ) {
77 $clauses['where'] .= ' AND `' . $this->wpdb->packetery_order . '`.`carrier_id` IS NOT NULL ';
78 $clauses['where'] .= ' AND `' . $this->wpdb->packetery_order . '`.`is_exported` = false ';
79 }
80 if ( $paramValues['packetery_to_print'] ) {
81 $clauses['where'] .= ' AND `' . $this->wpdb->packetery_order . '`.`packet_id` IS NOT NULL ';
82 $clauses['where'] .= ' AND `' . $this->wpdb->packetery_order . '`.`is_label_printed` = false ';
83 }
84 if ( $paramValues['packetery_order_type'] ) {
85 if ( Carrier\Repository::INTERNAL_PICKUP_POINTS_ID === $paramValues['packetery_order_type'] ) {
86 $clauses['where'] .= ' AND `' . $this->wpdb->packetery_order . '`.`carrier_id` = "' . $this->wpdb->_real_escape( Carrier\Repository::INTERNAL_PICKUP_POINTS_ID ) . '"';
87 } else {
88 $clauses['where'] .= ' AND `' . $this->wpdb->packetery_order . '`.`carrier_id` != "' . $this->wpdb->_real_escape( Carrier\Repository::INTERNAL_PICKUP_POINTS_ID ) . '"';
89 }
90 }
91 }
92
93 return $clauses;
94 }
95
96 /**
97 * Create table to store orders.
98 *
99 * @return bool
100 */
101 public function createTable(): bool {
102 $wpdb = $this->wpdb;
103
104 return $wpdb->query(
105 'CREATE TABLE IF NOT EXISTS `' . $wpdb->packetery_order . '` (
106 `id` bigint(20) unsigned NOT NULL,
107 `carrier_id` varchar(255) NOT NULL,
108 `is_exported` boolean NOT NULL,
109 `packet_id` varchar(255) NULL,
110 `is_label_printed` boolean NOT NULL,
111 `point_id` varchar(255) NULL,
112 `point_name` varchar(255) NULL,
113 `point_url` varchar(255) NULL,
114 `point_street` varchar(255) NULL,
115 `point_zip` varchar(255) NULL,
116 `point_city` varchar(255) NULL,
117 `address_validated` boolean NOT NULL,
118 `delivery_address` TEXT NULL,
119 `weight` float NULL,
120 `length` float NULL,
121 `width` float NULL,
122 `height` float NULL,
123 `carrier_number` varchar(255) NULL,
124 `packet_status` varchar(255) NULL,
125 PRIMARY KEY (`id`)
126 ) ' . $wpdb->get_charset_collate()
127 );
128 }
129
130 /**
131 * Drop table used to store orders.
132 */
133 public function drop(): void {
134 $wpdb = $this->wpdb;
135 $wpdb->query( 'DROP TABLE IF EXISTS `' . $wpdb->packetery_order . '`' );
136 }
137
138 /**
139 * Gets order data.
140 *
141 * @param int $id Order id.
142 *
143 * @return Order|null
144 */
145 public function getById( int $id ): ?Order {
146 $wcOrder = wc_get_order( $id );
147 if ( ! $wcOrder instanceof \WC_Order ) {
148 return null;
149 }
150
151 return $this->getByWcOrder( $wcOrder );
152 }
153
154 /**
155 * Gets order by wc order.
156 *
157 * @param \WC_Order $wcOrder WC Order.
158 *
159 * @return Order|null
160 */
161 public function getByWcOrder( \WC_Order $wcOrder ): ?Order {
162 if ( ! $wcOrder->has_shipping_method( ShippingMethod::PACKETERY_METHOD_ID ) ) {
163 return null;
164 }
165
166 $wpdb = $this->wpdb;
167
168 $result = $wpdb->get_row(
169 $wpdb->prepare(
170 '
171 SELECT o.* FROM `' . $wpdb->packetery_order . '` o
172 JOIN `' . $wpdb->posts . '` as wp_p ON wp_p.ID = o.id
173 WHERE o.`id` = %d',
174 $wcOrder->get_id()
175 )
176 );
177
178 if ( ! $result ) {
179 return null;
180 }
181
182 $partialOrder = $this->createPartialOrder( $result );
183 return $this->builder->finalize( $wcOrder, $partialOrder );
184 }
185
186 /**
187 * Creates partial order.
188 *
189 * @param \stdClass $result DB result.
190 *
191 * @return Order
192 */
193 private function createPartialOrder( \stdClass $result ): Order {
194 $partialOrder = new Order(
195 $result->id,
196 $result->carrier_id
197 );
198
199 $orderWeight = $this->parseFloat( $result->weight );
200 if ( null !== $orderWeight ) {
201 $partialOrder->setWeight( $orderWeight );
202 }
203 $partialOrder->setPacketId( $result->packet_id );
204 $partialOrder->setSize( new Size( $this->parseFloat( $result->length ), $this->parseFloat( $result->width ), $this->parseFloat( $result->height ) ) );
205 $partialOrder->setIsExported( (bool) $result->is_exported );
206 $partialOrder->setIsLabelPrinted( (bool) $result->is_label_printed );
207 $partialOrder->setCarrierNumber( $result->carrier_number );
208 $partialOrder->setPacketStatus( $result->packet_status );
209 $partialOrder->setAddressValidated( (bool) $result->address_validated );
210
211 if ( $result->delivery_address ) {
212 $deliveryAddressDecoded = json_decode( $result->delivery_address, false );
213 $deliveryAddress = new Address(
214 $deliveryAddressDecoded->street,
215 $deliveryAddressDecoded->city,
216 $deliveryAddressDecoded->zip
217 );
218
219 $deliveryAddress->setHouseNumber( $deliveryAddressDecoded->houseNumber );
220 $deliveryAddress->setLongitude( $deliveryAddressDecoded->longitude );
221 $deliveryAddress->setLatitude( $deliveryAddressDecoded->latitude );
222 $deliveryAddress->setCounty( $deliveryAddressDecoded->county );
223
224 $partialOrder->setDeliveryAddress( $deliveryAddress );
225 }
226
227 if ( null !== $result->point_id ) {
228 $pickUpPoint = new PickupPoint(
229 $result->point_id,
230 $result->point_name,
231 $result->point_city,
232 $result->point_zip,
233 $result->point_street,
234 $result->point_url
235 );
236
237 $partialOrder->setPickupPoint( $pickUpPoint );
238 }
239
240 return $partialOrder;
241 }
242
243 /**
244 * Parses string value as float.
245 *
246 * @param string|float|null $value Value.
247 *
248 * @return float|null
249 */
250 private function parseFloat( $value ): ?float {
251 if ( null === $value || '' === $value ) {
252 return null;
253 }
254
255 return (float) $value;
256 }
257
258 /**
259 * Transforms order to DB array.
260 *
261 * @param Order $order Order.
262 *
263 * @return array
264 */
265 private function orderToDbArray( Order $order ): array {
266 $point = $order->getPickupPoint();
267 if ( null === $point ) {
268 $point = new PickupPoint();
269 }
270
271 $deliveryAddress = null;
272 if ( $order->isAddressValidated() && $order->getDeliveryAddress() ) {
273 $deliveryAddress = wp_json_encode( $order->getDeliveryAddress()->export() );
274 }
275
276 $data = [
277 'id' => (int) $order->getNumber(),
278 'carrier_id' => $order->getCarrierId(),
279 'is_exported' => (int) $order->isExported(),
280 'packet_id' => $order->getPacketId(),
281 'packet_status' => $order->getPacketStatus(),
282 'is_label_printed' => (int) $order->isLabelPrinted(),
283 'carrier_number' => $order->getCarrierNumber(),
284 'weight' => $order->getWeight(),
285 'point_id' => $point->getId(),
286 'point_name' => $point->getName(),
287 'point_url' => $point->getUrl(),
288 'point_street' => $point->getStreet(),
289 'point_zip' => $point->getZip(),
290 'point_city' => $point->getCity(),
291 'address_validated' => (int) $order->isAddressValidated(),
292 'delivery_address' => $deliveryAddress,
293 'length' => $order->getLength(),
294 'width' => $order->getWidth(),
295 'height' => $order->getHeight(),
296 ];
297
298 return $data;
299 }
300
301 /**
302 * Saves order.
303 *
304 * @param Order $order Order.
305 *
306 * @return void
307 */
308 public function save( Order $order ): void {
309 $this->wpdb->_insert_replace_helper( $this->wpdb->packetery_order, $this->orderToDbArray( $order ), null, 'REPLACE' );
310 }
311
312 /**
313 * Loads order entities by list of ids.
314 *
315 * @param array $orderIds Order ids.
316 *
317 * @return Order[]
318 */
319 public function getByIds( array $orderIds ): array {
320 $orderEntities = [];
321 $posts = get_posts(
322 [
323 'post_type' => 'shop_order',
324 'post__in' => $orderIds,
325 'post_status' => [ 'any', 'trash' ],
326 'nopaging' => true,
327 ]
328 );
329 foreach ( $posts as $post ) {
330 $wcOrder = wc_get_order( $post );
331 // In case WC_Order does not exist, result set is limited to existing records.
332 if ( ! $wcOrder ) {
333 continue;
334 }
335 $order = $this->getByWcOrder( $wcOrder );
336 if ( $order ) {
337 $orderEntities[ $order->getNumber() ] = $order;
338 }
339 }
340
341 return $orderEntities;
342 }
343
344 /**
345 * Finds orders.
346 *
347 * @param int $limit Number of records.
348 *
349 * @return iterable|Order[]
350 */
351 public function findStatusSyncingOrders( int $limit ): iterable {
352 $wpdb = $this->wpdb;
353
354 $rows = $wpdb->get_results(
355 $wpdb->prepare(
356 '
357 SELECT o.* FROM `' . $wpdb->packetery_order . '` o
358 JOIN `' . $wpdb->posts . '` wp_p ON wp_p.`ID` = o.`id`
359 WHERE ( o.`packet_status` IS NULL OR o.`packet_status` NOT IN ("delivered", "returned", "cancelled") ) AND o.`packet_id` IS NOT NULL
360 ORDER BY wp_p.`post_date`
361 LIMIT %d',
362 $limit
363 )
364 );
365
366 foreach ( $rows as $row ) {
367 $wcOrder = wc_get_order( $row->id );
368 if ( false === $wcOrder || ! $wcOrder->has_shipping_method( ShippingMethod::PACKETERY_METHOD_ID ) ) {
369 continue;
370 }
371
372 $partial = $this->createPartialOrder( $row );
373 yield $this->builder->finalize( $wcOrder, $partial );
374 }
375 }
376
377 /**
378 * Counts order to be submitted.
379 *
380 * @return int
381 */
382 public function countOrdersToSubmit(): int {
383 $wpdb = $this->wpdb;
384
385 return (int) $wpdb->get_var(
386 'SELECT COUNT(DISTINCT o.id) FROM `' . $wpdb->packetery_order . '` o
387 JOIN `' . $wpdb->posts . '` wp_p ON wp_p.`ID` = o.`id`
388 WHERE o.`carrier_id` IS NOT NULL AND o.`is_exported` = false'
389 );
390 }
391
392 /**
393 * Counts order to be printed.
394 *
395 * @return int
396 */
397 public function countOrdersToPrint(): int {
398 $wpdb = $this->wpdb;
399
400 return (int) $wpdb->get_var(
401 'SELECT COUNT(DISTINCT o.id) FROM `' . $wpdb->packetery_order . '` o
402 JOIN `' . $wpdb->posts . '` wp_p ON wp_p.`ID` = o.`id`
403 WHERE o.`packet_id` IS NOT NULL AND o.`is_label_printed` = false'
404 );
405 }
406
407 /**
408 * Deletes all custom table records linked to permanently deleted orders.
409 *
410 * @return void
411 */
412 public function deleteOrphans(): void {
413 $wpdb = $this->wpdb;
414
415 $wpdb->query(
416 'DELETE `' . $wpdb->packetery_order . '` FROM `' . $wpdb->packetery_order . '`
417 LEFT JOIN `' . $wpdb->posts . '` ON `' . $wpdb->posts . '`.`ID` = `' . $wpdb->packetery_order . '`.`id`
418 WHERE `' . $wpdb->posts . '`.`ID` IS NULL'
419 );
420 }
421
422 /**
423 * Deletes data from custom table.
424 *
425 * @param int $orderId Order id.
426 *
427 * @return void
428 */
429 private function delete( int $orderId ): void {
430 $wpdb = $this->wpdb;
431
432 $wpdb->delete( $wpdb->packetery_order, [ 'id' => $orderId ], '%d' );
433 }
434
435 /**
436 * Fires after post deletion.
437 *
438 * @param int $postId Post id.
439 * @param WP_Post $post Post object.
440 *
441 * @return void
442 */
443 public function deletedPostHook( int $postId, WP_Post $post ): void {
444 if ( 'shop_order' === $post->post_type ) {
445 $this->delete( $postId );
446 }
447 }
448
449 }
450