PluginProbe
Packeta / trunk
Packeta vtrunk
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 trunk, at src/Packetery/Module/Upgrade.php

492 lines 14.8 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 null,
316 $this->getMetaAsNullableString( $order, self::META_POINT_NAME ),
317 $this->getMetaAsNullableString( $order, self::META_POINT_CITY ),
318 $this->getMetaAsNullableString( $order, self::META_POINT_ZIP ),
319 $this->getMetaAsNullableString( $order, self::META_POINT_STREET ),
320 $this->getMetaAsNullableString( $order, self::META_POINT_URL )
321 )
322 );
323 }
324 $order->delete_meta_data( self::META_POINT_ID );
325 $order->delete_meta_data( self::META_POINT_NAME );
326 $order->delete_meta_data( self::META_POINT_CITY );
327 $order->delete_meta_data( self::META_POINT_ZIP );
328 $order->delete_meta_data( self::META_POINT_STREET );
329 $order->delete_meta_data( self::META_POINT_URL );
330
331 $validatedAddressId = $this->getValidatedAddressIdByOrderId( (int) $order->get_id() );
332 if ( $validatedAddressId !== null ) {
333 $validatedAddress = $this->createAddressFromPostId( $validatedAddressId );
334 $orderEntity->setAddressValidated( true );
335 $orderEntity->setDeliveryAddress( $validatedAddress );
336 }
337
338 $this->orderRepository->save( $orderEntity );
339 // Ignore errors. Save the metadata even if the previous call fails.
340 $order->save_meta_data();
341 }
342 }
343
344 /**
345 * Creates active widget address using woocommerce order id.
346 *
347 * @param int $addressId Address ID.
348 *
349 * @return Core\Entity\Address|null
350 */
351 public function createAddressFromPostId( int $addressId ): ?Core\Entity\Address {
352 $address = new Core\Entity\Address(
353 get_post_meta( $addressId, 'street', true ),
354 get_post_meta( $addressId, 'city', true ),
355 get_post_meta( $addressId, 'postCode', true )
356 );
357 $address->setHouseNumber( get_post_meta( $addressId, 'houseNumber', true ) );
358 $address->setCounty( get_post_meta( $addressId, 'county', true ) );
359 $address->setLongitude( get_post_meta( $addressId, 'longitude', true ) );
360 $address->setLatitude( get_post_meta( $addressId, 'latitude', true ) );
361
362 return $address;
363 }
364
365 /**
366 * Gets active address.
367 *
368 * @param int $orderId Order ID.
369 *
370 * @return int|null
371 */
372 public function getValidatedAddressIdByOrderId( int $orderId ): ?int {
373 $postIds = get_posts(
374 [
375 'post_type' => self::POST_TYPE_VALIDATED_ADDRESS,
376 'post_status' => 'any',
377 'nopaging' => true,
378 'numberposts' => 1,
379 'fields' => 'ids',
380 'post_parent' => $orderId,
381 ]
382 );
383
384 if ( count( $postIds ) === 0 ) {
385 return null;
386 }
387
388 return (int) array_shift( $postIds );
389 }
390
391 /**
392 * Gets meta property of order as string.
393 *
394 * @param \WC_Order $order Order.
395 * @param string $key Meta order key.
396 *
397 * @return string|null
398 */
399 private function getMetaAsNullableString( \WC_Order $order, string $key ): ?string {
400 $value = $order->get_meta( $key, true );
401
402 return ( ( $value !== null && $value !== '' ) ? (string) $value : null );
403 }
404
405 /**
406 * Gets meta property of order as float.
407 *
408 * @param \WC_Order $order Order.
409 * @param string $key Meta order key.
410 *
411 * @return float|null
412 */
413 private function getMetaAsNullableFloat( \WC_Order $order, string $key ): ?float {
414 $value = $order->get_meta( $key, true );
415
416 return ( ( $value !== null && $value !== '' ) ? (float) $value : null );
417 }
418
419 /**
420 * Creates log table.
421 *
422 * @return void
423 */
424 private function createLogTable(): void {
425 if ( $this->logRepository->createOrAlterTable() === false ) {
426 $this->messageManager->flash_message(
427 // translators: %s: Short table name.
428 sprintf( __( 'Database %s table could not be created or altered, more information might be found in WooCommerce logs.', 'packeta' ), 'log' ),
429 MessageManager::TYPE_ERROR
430 );
431 }
432 }
433
434 /**
435 * Creates carrier table.
436 *
437 * @return void
438 */
439 private function createCarrierTable(): void {
440 if ( $this->carrierRepository->createOrAlterTable() === false ) {
441 $this->flashAndLog( 'carrier', Record::ACTION_CARRIER_TABLE_NOT_CREATED );
442 }
443 }
444
445 /**
446 * Creates order table.
447 *
448 * @return void
449 */
450 private function createOrderTable(): void {
451 if ( $this->orderRepository->createOrAlterTable() === false ) {
452 $this->flashAndLog( 'order', Record::ACTION_ORDER_TABLE_NOT_CREATED );
453 }
454 }
455
456 /**
457 * Creates order table.
458 *
459 * @return void
460 */
461 private function createCustomsDeclarationTables(): void {
462 if ( $this->customsDeclarationRepository->createOrAlterTable() === false ) {
463 $this->flashAndLog( 'customs_declaration', Record::ACTION_CUSTOMS_DECLARATION_TABLE_NOT_CREATED );
464 }
465
466 if ( $this->customsDeclarationRepository->createOrAlterItemTable() === false ) {
467 $this->flashAndLog( 'customs_declaration_item', Record::ACTION_CUSTOMS_DECLARATION_ITEM_TABLE_NOT_CREATED );
468 }
469 }
470
471 /**
472 * Flashes error and logs to Packeta log.
473 *
474 * @param string $table Short table name.
475 * @param string $action Log action.
476 *
477 * @return void
478 */
479 private function flashAndLog( string $table, string $action ): void {
480 // translators: %s: Short table name.
481 $flashMessage = sprintf( __( 'Database %s table of Packeta plugin could not be created or altered, you can find more information in Packeta log.', 'packeta' ), $table );
482 $this->messageManager->flash_message( $flashMessage, MessageManager::TYPE_ERROR );
483
484 $record = new Record();
485 $record->action = $action;
486 $record->status = Record::STATUS_ERROR;
487 // translators: %s: Short table name.
488 $record->title = sprintf( __( 'Database %s table could not be created or altered, more information might be found in WooCommerce logs.', 'packeta' ), $table );
489 $this->logger->add( $record );
490 }
491 }
492