PluginProbe
Packeta / 2.1
Packeta v2.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 / Upgrade.php

Upgrade.php in Packeta 2.1, at src/Packetery/Module/Upgrade.php

490 lines 14.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class Upgrade.
4 *
5 * @package Packetery\Module
6 */
7
8 declare( strict_types=1 );
9
10 namespace Packetery\Module;
11
12 use Packetery\Core;
13 use Packetery\Core\Log\ILogger;
14 use Packetery\Core\Log\Record;
15 use Packetery\Module\Carrier\EntityRepository;
16 use Packetery\Module\Options\OptionNames;
17 use Packetery\Module\Options\OptionsProvider;
18 use Packetery\Module\Upgrade\Version_1_4_2;
19
20 /**
21 * Class Upgrade.
22 */
23 class Upgrade {
24
25 const POST_TYPE_VALIDATED_ADDRESS = 'packetery_address';
26
27 const META_LENGTH = 'packetery_length';
28 const META_WIDTH = 'packetery_width';
29 const META_HEIGHT = 'packetery_height';
30 const META_PACKET_STATUS = 'packetery_packet_status';
31 const META_WEIGHT = 'packetery_weight';
32 const META_CARRIER_ID = 'packetery_carrier_id';
33 const META_IS_EXPORTED = 'packetery_is_exported';
34 const META_IS_LABEL_PRINTED = 'packetery_is_label_printed';
35 const META_CARRIER_NUMBER = 'packetery_carrier_number';
36 const META_PACKET_ID = 'packetery_packet_id';
37 const META_POINT_ID = 'packetery_point_id';
38 const META_POINT_NAME = 'packetery_point_name';
39 const META_POINT_CITY = 'packetery_point_city';
40 const META_POINT_ZIP = 'packetery_point_zip';
41 const META_POINT_STREET = 'packetery_point_street';
42 const META_POINT_URL = 'packetery_point_url';
43
44 /**
45 * Order repository.
46 *
47 * @var Order\Repository
48 */
49 private $orderRepository;
50
51 /**
52 * Message manager.
53 *
54 * @var MessageManager
55 */
56 private $messageManager;
57
58 /**
59 * Logger.
60 *
61 * @var ILogger
62 */
63 private $logger;
64
65 /**
66 * Log repository.
67 *
68 * @var Log\Repository
69 */
70 private $logRepository;
71
72 /**
73 * Carrier repository.
74 *
75 * @var Carrier\Repository
76 */
77 private $carrierRepository;
78
79 /**
80 * Customs declaration repository.
81 *
82 * @var CustomsDeclaration\Repository
83 */
84 private $customsDeclarationRepository;
85
86 /**
87 * WpdbAdapter.
88 *
89 * @var WpdbAdapter
90 */
91 private $wpdbAdapter;
92
93 /**
94 * Options provider.
95 *
96 * @var OptionsProvider
97 */
98 private $optionsProvider;
99
100 /**
101 * @var EntityRepository
102 */
103 private $carrierEntityRepository;
104
105 public function __construct(
106 Order\Repository $orderRepository,
107 MessageManager $messageManager,
108 ILogger $logger,
109 Log\Repository $logRepository,
110 WpdbAdapter $wpdbAdapter,
111 Carrier\Repository $carrierRepository,
112 CustomsDeclaration\Repository $customsDeclarationRepository,
113 OptionsProvider $optionsProvider,
114 EntityRepository $carrierEntityRepository
115 ) {
116 $this->orderRepository = $orderRepository;
117 $this->messageManager = $messageManager;
118 $this->logger = $logger;
119 $this->logRepository = $logRepository;
120 $this->wpdbAdapter = $wpdbAdapter;
121 $this->carrierRepository = $carrierRepository;
122 $this->customsDeclarationRepository = $customsDeclarationRepository;
123 $this->optionsProvider = $optionsProvider;
124 $this->carrierEntityRepository = $carrierEntityRepository;
125 }
126
127 /**
128 * Checks previous plugin version and runs upgrade if needed.
129 * https://www.sitepoint.com/wordpress-plugin-updates-right-way/
130 *
131 * @return void
132 */
133 public function check(): void {
134 $oldVersion = get_option( OptionNames::VERSION );
135 if ( $oldVersion === Plugin::VERSION ) {
136 return;
137 }
138
139 $this->runCreateTables();
140
141 // If no previous version detected, no upgrade will be run.
142 if ( $oldVersion !== null && $oldVersion !== false ) {
143 if ( version_compare( $oldVersion, '1.2.0', '<' ) ) {
144 $logEntries = get_posts(
145 [
146 'post_type' => 'packetery_log',
147 'post_status' => 'any',
148 'nopaging' => true,
149 'fields' => 'ids',
150 ]
151 );
152 foreach ( $logEntries as $logEntryId ) {
153 wp_delete_post( $logEntryId, true );
154 }
155
156 unregister_post_type( 'packetery_log' );
157
158 $this->migrateWpOrderMetadata();
159 $addressEntries = get_posts(
160 [
161 'post_type' => self::POST_TYPE_VALIDATED_ADDRESS,
162 'post_status' => 'any',
163 'nopaging' => true,
164 'fields' => 'ids',
165 ]
166 );
167 foreach ( $addressEntries as $addressEntryId ) {
168 wp_delete_post( $addressEntryId, true );
169 }
170
171 unregister_post_type( self::POST_TYPE_VALIDATED_ADDRESS );
172 }
173
174 if ( version_compare( $oldVersion, '1.2.6', '<' ) ) {
175 $this->orderRepository->deleteOrphans();
176 }
177
178 if ( version_compare( $oldVersion, '1.4.2', '<' ) ) {
179 $migration = new Version_1_4_2( $this->wpdbAdapter );
180 $migration->run();
181 }
182
183 if ( version_compare( $oldVersion, '1.5', '<' ) ) {
184 wp_clear_scheduled_hook( CronService::CRON_CARRIERS_HOOK );
185 }
186
187 if ( version_compare( $oldVersion, '1.6.0', '<' ) ) {
188 wp_clear_scheduled_hook( CronService::CRON_LOG_AUTO_DELETION_HOOK );
189 wp_clear_scheduled_hook( CronService::CRON_PACKET_STATUS_SYNC_HOOK );
190 }
191
192 if ( version_compare( $oldVersion, '1.7.0', '<' ) ) {
193 $orderStatusAutoChange = $this->optionsProvider->isOrderStatusAutoChangeEnabled();
194 $autoOrderStatus = $this->optionsProvider->getAutoOrderStatus();
195 $syncSettings = $this->optionsProvider->getOptionsByName( OptionNames::PACKETERY_SYNC );
196 if ( $orderStatusAutoChange ) {
197 $syncSettings['allow_order_status_change'] = true;
198 }
199 if ( $autoOrderStatus !== null ) {
200 $syncSettings['order_status_change_packet_statuses'] = [
201 Core\Entity\PacketStatus::RECEIVED_DATA => $autoOrderStatus,
202 ];
203 }
204
205 update_option( OptionNames::PACKETERY_SYNC, $syncSettings );
206 }
207
208 if ( version_compare( $oldVersion, '1.7.1', '<' ) ) {
209 $syncSettings = $this->optionsProvider->getOptionsByName( OptionNames::PACKETERY_SYNC );
210 if (
211 isset( $syncSettings['order_status_change_packet_statuses'][ Core\Entity\PacketStatus::RECEIVED_DATA ] ) &&
212 $syncSettings['order_status_change_packet_statuses'][ Core\Entity\PacketStatus::RECEIVED_DATA ] === ''
213 ) {
214 unset( $syncSettings['order_status_change_packet_statuses'][ Core\Entity\PacketStatus::RECEIVED_DATA ] );
215 update_option( OptionNames::PACKETERY_SYNC, $syncSettings );
216 }
217 }
218
219 if ( version_compare( $oldVersion, '1.8.0', '<' ) ) {
220 $generalSettings = $this->optionsProvider->getOptionsByName( OptionNames::PACKETERY );
221 if ( isset( $generalSettings['cod_payment_method'] ) ) {
222 $generalSettings['cod_payment_methods'] = [ $generalSettings['cod_payment_method'] ];
223 unset( $generalSettings['cod_payment_method'] );
224 }
225
226 update_option( OptionNames::PACKETERY, $generalSettings );
227 }
228
229 if ( version_compare( $oldVersion, '2.1.0', '<' ) ) {
230 add_option( OptionNames::PACKETERY_TUTORIAL_ORDER_DETAIL_EDIT_PACKET, 0 );
231 add_option( OptionNames::PACKETERY_TUTORIAL_ORDER_GRID_EDIT_PACKET, 0 );
232 }
233 } else {
234 add_option( OptionNames::PACKETERY_TUTORIAL_ORDER_DETAIL_EDIT_PACKET, 1 );
235 add_option( OptionNames::PACKETERY_TUTORIAL_ORDER_GRID_EDIT_PACKET, 1 );
236 }
237
238 update_option( OptionNames::VERSION, Plugin::VERSION );
239 }
240
241 public function runCreateTables(): void {
242 $this->createLogTable();
243 $this->createCarrierTable();
244 $this->createOrderTable();
245 $this->createCustomsDeclarationTables();
246 }
247
248 /**
249 * Migrates WP order metadata.
250 *
251 * @return void
252 */
253 private function migrateWpOrderMetadata(): void {
254 $this->createOrderTable();
255
256 // Did not work when called from plugins_loaded hook.
257 $orders = wc_get_orders(
258 [
259 'nopaging' => true,
260 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
261 'meta_query' => [
262 [
263 'key' => self::META_CARRIER_ID,
264 'compare' => 'EXISTS',
265 ],
266 [
267 'key' => self::META_CARRIER_ID,
268 'compare' => '!=',
269 'value' => '',
270 ],
271 ],
272 ]
273 );
274
275 foreach ( $orders as $order ) {
276 $orderEntity = new Core\Entity\Order(
277 (string) $order->get_id(),
278 $this->carrierEntityRepository->getAnyById( $this->getMetaAsNullableString( $order, self::META_CARRIER_ID ) )
279 );
280 $order->delete_meta_data( self::META_CARRIER_ID );
281
282 $orderEntity->setWeight( $this->getMetaAsNullableFloat( $order, self::META_WEIGHT ) );
283 $order->delete_meta_data( self::META_WEIGHT );
284
285 $orderEntity->setPacketStatus( $this->getMetaAsNullableString( $order, self::META_PACKET_STATUS ) );
286 $order->delete_meta_data( self::META_PACKET_STATUS );
287
288 $orderEntity->setIsExported( (bool) $this->getMetaAsNullableString( $order, self::META_IS_EXPORTED ) );
289 $order->delete_meta_data( self::META_IS_EXPORTED );
290
291 $orderEntity->setIsLabelPrinted( (bool) $this->getMetaAsNullableString( $order, self::META_IS_LABEL_PRINTED ) );
292 $order->delete_meta_data( self::META_IS_LABEL_PRINTED );
293
294 $orderEntity->setCarrierNumber( $this->getMetaAsNullableString( $order, self::META_CARRIER_NUMBER ) );
295 $order->delete_meta_data( self::META_CARRIER_NUMBER );
296
297 $orderEntity->setPacketId( $this->getMetaAsNullableString( $order, self::META_PACKET_ID ) );
298 $order->delete_meta_data( self::META_PACKET_ID );
299
300 $orderEntity->setSize(
301 new Core\Entity\Size(
302 $this->getMetaAsNullableFloat( $order, self::META_LENGTH ),
303 $this->getMetaAsNullableFloat( $order, self::META_WIDTH ),
304 $this->getMetaAsNullableFloat( $order, self::META_HEIGHT )
305 )
306 );
307 $order->delete_meta_data( self::META_LENGTH );
308 $order->delete_meta_data( self::META_WIDTH );
309 $order->delete_meta_data( self::META_HEIGHT );
310
311 if ( $this->getMetaAsNullableString( $order, self::META_POINT_ID ) !== null ) {
312 $orderEntity->setPickupPoint(
313 new Core\Entity\PickupPoint(
314 $this->getMetaAsNullableString( $order, self::META_POINT_ID ),
315 $this->getMetaAsNullableString( $order, self::META_POINT_NAME ),
316 $this->getMetaAsNullableString( $order, self::META_POINT_CITY ),
317 $this->getMetaAsNullableString( $order, self::META_POINT_ZIP ),
318 $this->getMetaAsNullableString( $order, self::META_POINT_STREET ),
319 $this->getMetaAsNullableString( $order, self::META_POINT_URL )
320 )
321 );
322 }
323 $order->delete_meta_data( self::META_POINT_ID );
324 $order->delete_meta_data( self::META_POINT_NAME );
325 $order->delete_meta_data( self::META_POINT_CITY );
326 $order->delete_meta_data( self::META_POINT_ZIP );
327 $order->delete_meta_data( self::META_POINT_STREET );
328 $order->delete_meta_data( self::META_POINT_URL );
329
330 $validatedAddressId = $this->getValidatedAddressIdByOrderId( (int) $order->get_id() );
331 if ( $validatedAddressId !== null ) {
332 $validatedAddress = $this->createAddressFromPostId( $validatedAddressId );
333 $orderEntity->setAddressValidated( true );
334 $orderEntity->setDeliveryAddress( $validatedAddress );
335 }
336
337 $this->orderRepository->save( $orderEntity );
338 $order->save_meta_data();
339 }
340 }
341
342 /**
343 * Creates active widget address using woocommerce order id.
344 *
345 * @param int $addressId Address ID.
346 *
347 * @return Core\Entity\Address|null
348 */
349 public function createAddressFromPostId( int $addressId ): ?Core\Entity\Address {
350 $address = new Core\Entity\Address(
351 get_post_meta( $addressId, 'street', true ),
352 get_post_meta( $addressId, 'city', true ),
353 get_post_meta( $addressId, 'postCode', true )
354 );
355 $address->setHouseNumber( get_post_meta( $addressId, 'houseNumber', true ) );
356 $address->setCounty( get_post_meta( $addressId, 'county', true ) );
357 $address->setLongitude( get_post_meta( $addressId, 'longitude', true ) );
358 $address->setLatitude( get_post_meta( $addressId, 'latitude', true ) );
359
360 return $address;
361 }
362
363 /**
364 * Gets active address.
365 *
366 * @param int $orderId Order ID.
367 *
368 * @return int|null
369 */
370 public function getValidatedAddressIdByOrderId( int $orderId ): ?int {
371 $postIds = get_posts(
372 [
373 'post_type' => self::POST_TYPE_VALIDATED_ADDRESS,
374 'post_status' => 'any',
375 'nopaging' => true,
376 'numberposts' => 1,
377 'fields' => 'ids',
378 'post_parent' => $orderId,
379 ]
380 );
381
382 if ( count( $postIds ) === 0 ) {
383 return null;
384 }
385
386 return (int) array_shift( $postIds );
387 }
388
389 /**
390 * Gets meta property of order as string.
391 *
392 * @param \WC_Order $order Order.
393 * @param string $key Meta order key.
394 *
395 * @return string|null
396 */
397 private function getMetaAsNullableString( \WC_Order $order, string $key ): ?string {
398 $value = $order->get_meta( $key, true );
399
400 return ( ( $value !== null && $value !== '' ) ? (string) $value : null );
401 }
402
403 /**
404 * Gets meta property of order as float.
405 *
406 * @param \WC_Order $order Order.
407 * @param string $key Meta order key.
408 *
409 * @return float|null
410 */
411 private function getMetaAsNullableFloat( \WC_Order $order, string $key ): ?float {
412 $value = $order->get_meta( $key, true );
413
414 return ( ( $value !== null && $value !== '' ) ? (float) $value : null );
415 }
416
417 /**
418 * Creates log table.
419 *
420 * @return void
421 */
422 private function createLogTable(): void {
423 if ( $this->logRepository->createOrAlterTable() === false ) {
424 $this->messageManager->flash_message(
425 // translators: %s: Short table name.
426 sprintf( __( 'Database %s table could not be created or altered, more information might be found in WooCommerce logs.', 'packeta' ), 'log' ),
427 MessageManager::TYPE_ERROR
428 );
429 }
430 }
431
432 /**
433 * Creates carrier table.
434 *
435 * @return void
436 */
437 private function createCarrierTable(): void {
438 if ( $this->carrierRepository->createOrAlterTable() === false ) {
439 $this->flashAndLog( 'carrier', Record::ACTION_CARRIER_TABLE_NOT_CREATED );
440 }
441 }
442
443 /**
444 * Creates order table.
445 *
446 * @return void
447 */
448 private function createOrderTable(): void {
449 if ( $this->orderRepository->createOrAlterTable() === false ) {
450 $this->flashAndLog( 'order', Record::ACTION_ORDER_TABLE_NOT_CREATED );
451 }
452 }
453
454 /**
455 * Creates order table.
456 *
457 * @return void
458 */
459 private function createCustomsDeclarationTables(): void {
460 if ( $this->customsDeclarationRepository->createOrAlterTable() === false ) {
461 $this->flashAndLog( 'customs_declaration', Record::ACTION_CUSTOMS_DECLARATION_TABLE_NOT_CREATED );
462 }
463
464 if ( $this->customsDeclarationRepository->createOrAlterItemTable() === false ) {
465 $this->flashAndLog( 'customs_declaration_item', Record::ACTION_CUSTOMS_DECLARATION_ITEM_TABLE_NOT_CREATED );
466 }
467 }
468
469 /**
470 * Flashes error and logs to Packeta log.
471 *
472 * @param string $table Short table name.
473 * @param string $action Log action.
474 *
475 * @return void
476 */
477 private function flashAndLog( string $table, string $action ): void {
478 // translators: %s: Short table name.
479 $flashMessage = sprintf( __( 'Database %s table of Packeta plugin could not be created or altered, you can find more information in Packeta log.', 'packeta' ), $table );
480 $this->messageManager->flash_message( $flashMessage, MessageManager::TYPE_ERROR );
481
482 $record = new Record();
483 $record->action = $action;
484 $record->status = Record::STATUS_ERROR;
485 // translators: %s: Short table name.
486 $record->title = sprintf( __( 'Database %s table could not be created or altered, more information might be found in WooCommerce logs.', 'packeta' ), $table );
487 $this->logger->add( $record );
488 }
489 }
490