PluginProbe
Packeta / 1.5.4
Packeta v1.5.4
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 / Metabox.php

Metabox.php in Packeta 1.5.4, at src/Packetery/Module/Order/Metabox.php

566 lines 18.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class Metabox
4 *
5 * @package Packetery\Order
6 */
7
8 declare( strict_types=1 );
9
10 namespace Packetery\Module\Order;
11
12 use Packetery\Core\Entity;
13 use Packetery\Core\Helper;
14 use Packetery\Module\Carrier\EntityRepository;
15 use Packetery\Module\FormFactory;
16 use Packetery\Module\FormValidators;
17 use Packetery\Module\Log;
18 use Packetery\Module\MessageManager;
19 use Packetery\Module\Options;
20 use Packetery\Module\Plugin;
21 use Packetery\Module\WidgetOptionsBuilder;
22 use PacketeryLatte\Engine;
23 use PacketeryNette\Forms\Form;
24 use PacketeryNette\Http\Request;
25 use WC_Data_Exception;
26 use WC_Order;
27
28 /**
29 * Class Metabox
30 *
31 * @package Packetery\Order
32 */
33 class Metabox {
34
35 public const FIELD_WEIGHT = 'packetery_weight';
36 private const FIELD_ORIGINAL_WEIGHT = 'packetery_original_weight';
37 public const FIELD_WIDTH = 'packetery_width';
38 public const FIELD_LENGTH = 'packetery_length';
39 public const FIELD_HEIGHT = 'packetery_height';
40 public const FIELD_ADULT_CONTENT = 'packetery_adult_content';
41 public const FIELD_COD = 'packetery_COD';
42 public const FIELD_VALUE = 'packetery_value';
43 public const FIELD_DELIVER_ON = 'packetery_deliver_on';
44
45 /**
46 * PacketeryLatte engine.
47 *
48 * @var Engine
49 */
50 private $latte_engine;
51
52 /**
53 * Message manager.
54 *
55 * @var MessageManager
56 */
57 private $message_manager;
58
59 /**
60 * Helper.
61 *
62 * @var Helper
63 */
64 private $helper;
65
66 /**
67 * Order form.
68 *
69 * @var Form
70 */
71 private $order_form;
72
73 /**
74 * HTTP request.
75 *
76 * @var Request
77 */
78 private $request;
79
80 /**
81 * Options provider.
82 *
83 * @var Options\Provider
84 */
85 private $optionsProvider;
86
87 /**
88 * Form factory.
89 *
90 * @var FormFactory
91 */
92 private $formFactory;
93
94 /**
95 * Order repository.
96 *
97 * @var Repository
98 */
99 private $orderRepository;
100
101 /**
102 * Log page.
103 *
104 * @var Log\Page
105 */
106 private $logPage;
107
108 /**
109 * OrderFacade.
110 *
111 * @var AttributeMapper
112 */
113 private $mapper;
114
115 /**
116 * Widget options builder.
117 *
118 * @var WidgetOptionsBuilder
119 */
120 private $widgetOptionsBuilder;
121
122 /**
123 * Carrier repository.
124 *
125 * @var EntityRepository
126 */
127 private $carrierRepository;
128
129 /**
130 * Metabox constructor.
131 *
132 * @param Engine $latte_engine PacketeryLatte engine.
133 * @param MessageManager $message_manager Message manager.
134 * @param Helper $helper Helper.
135 * @param Request $request Http request.
136 * @param Options\Provider $optionsProvider Options provider.
137 * @param FormFactory $formFactory Form factory.
138 * @param Repository $orderRepository Order repository.
139 * @param Log\Page $logPage Log page.
140 * @param AttributeMapper $mapper AttributeMapper.
141 * @param WidgetOptionsBuilder $widgetOptionsBuilder Widget options builder.
142 * @param EntityRepository $carrierRepository Carrier repository.
143 */
144 public function __construct(
145 Engine $latte_engine,
146 MessageManager $message_manager,
147 Helper $helper,
148 Request $request,
149 Options\Provider $optionsProvider,
150 FormFactory $formFactory,
151 Repository $orderRepository,
152 Log\Page $logPage,
153 AttributeMapper $mapper,
154 WidgetOptionsBuilder $widgetOptionsBuilder,
155 EntityRepository $carrierRepository
156 ) {
157 $this->latte_engine = $latte_engine;
158 $this->message_manager = $message_manager;
159 $this->helper = $helper;
160 $this->request = $request;
161 $this->optionsProvider = $optionsProvider;
162 $this->formFactory = $formFactory;
163 $this->orderRepository = $orderRepository;
164 $this->logPage = $logPage;
165 $this->mapper = $mapper;
166 $this->widgetOptionsBuilder = $widgetOptionsBuilder;
167 $this->carrierRepository = $carrierRepository;
168 }
169
170 /**
171 * Registers related hooks.
172 */
173 public function register(): void {
174 add_action(
175 'admin_init',
176 function () {
177 $this->order_form = $this->formFactory->create();
178 $this->add_fields();
179 }
180 );
181 add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
182 add_action( 'save_post', array( $this, 'save_fields' ) );
183 }
184
185 /**
186 * Add metaboxes
187 */
188 public function add_meta_boxes(): void {
189 global $post;
190
191 $order = $this->orderRepository->getById( (int) $post->ID );
192 if ( null === $order ) {
193 return;
194 }
195
196 add_meta_box(
197 'packetery_metabox',
198 __( 'Packeta', 'packeta' ),
199 array(
200 $this,
201 'render_metabox',
202 ),
203 'shop_order',
204 'side',
205 'high'
206 );
207 }
208
209 /**
210 * Adds packetery fields to order form.
211 */
212 public function add_fields(): void {
213 $this->order_form->addHidden( 'packetery_order_metabox_nonce' );
214 $this->order_form->addText( self::FIELD_WEIGHT, __( 'Weight (kg)', 'packeta' ) )
215 ->setRequired( false )
216 ->addRule( $this->order_form::FLOAT, __( 'Provide numeric value!', 'packeta' ) );
217 $this->order_form->addHidden( self::FIELD_ORIGINAL_WEIGHT );
218 $this->order_form->addText( self::FIELD_WIDTH, __( 'Width (mm)', 'packeta' ) )
219 ->setRequired( false )
220 ->addRule( $this->order_form::FLOAT, __( 'Provide numeric value!', 'packeta' ) );
221 $this->order_form->addText( self::FIELD_LENGTH, __( 'Length (mm)', 'packeta' ) )
222 ->setRequired( false )
223 ->addRule( $this->order_form::FLOAT, __( 'Provide numeric value!', 'packeta' ) );
224 $this->order_form->addText( self::FIELD_HEIGHT, __( 'Height (mm)', 'packeta' ) )
225 ->setRequired( false )
226 ->addRule( $this->order_form::FLOAT, __( 'Provide numeric value!', 'packeta' ) );
227 $this->order_form->addCheckbox( self::FIELD_ADULT_CONTENT, __( 'Adult content', 'packeta' ) )
228 ->setRequired( false );
229 $this->order_form->addText( self::FIELD_COD, __( 'Cash on delivery', 'packeta' ) )
230 ->setRequired( false )
231 ->addRule( $this->order_form::FLOAT );
232 $this->order_form->addText( self::FIELD_VALUE, __( 'Order value', 'packeta' ) )
233 ->setRequired( false )
234 ->addRule( $this->order_form::FLOAT );
235 $this->order_form->addText( self::FIELD_DELIVER_ON, __( 'Planned dispatch', 'packeta' ) )
236 ->setHtmlAttribute( 'autocomplete', 'off' )
237 ->setRequired( false )
238 // translators: %s: Represents minimal date for delayed delivery.
239 ->addRule( [ FormValidators::class, 'dateIsLater' ], __( 'Date must be later than %s', 'packeta' ), wp_date( Helper::DATEPICKER_FORMAT ) );
240
241 foreach ( Attribute::$pickupPointAttrs as $pickupPointAttr ) {
242 $this->order_form->addHidden( $pickupPointAttr['name'] );
243 }
244
245 foreach ( Attribute::$homeDeliveryAttrs as $homeDeliveryAttr ) {
246 $this->order_form->addHidden( $homeDeliveryAttr['name'] );
247 }
248
249 $this->order_form->addButton( 'packetery_pick_pickup_point', __( 'Choose pickup point', 'packeta' ) );
250 $this->order_form->addButton( 'packetery_pick_address', __( 'Check shipping address', 'packeta' ) );
251 }
252
253 /**
254 * Renders metabox
255 */
256 public function render_metabox(): void {
257 global $post;
258
259 $wcOrder = $this->orderRepository->getWcOrderById( (int) $post->ID );
260 if ( null === $wcOrder ) {
261 return;
262 }
263
264 $order = $this->orderRepository->getByWcOrder( $wcOrder );
265 if ( null === $order ) {
266 return;
267 }
268 $packetId = $order->getPacketId();
269
270 $showLogsLink = null;
271 if ( $this->logPage->hasAnyRows( (int) $order->getNumber() ) ) {
272 $showLogsLink = $this->logPage->createLogListUrl( (int) $order->getNumber() );
273 }
274
275 if ( $packetId ) {
276 $packetCancelLink = $this->getOrderActionLink( $order, PacketActionsCommonLogic::ACTION_CANCEL_PACKET );
277 $this->latte_engine->render(
278 PACKETERY_PLUGIN_DIR . '/template/order/metabox-overview.latte',
279 [
280 'packetCancelLink' => $packetCancelLink,
281 'packet_id' => $packetId,
282 'packet_tracking_url' => $this->helper->get_tracking_url( $packetId ),
283 'showLogsLink' => $showLogsLink,
284 'translations' => [
285 'packetTrackingOnline' => __( 'Packet tracking online', 'packeta' ),
286 'showLogs' => __( 'Show logs', 'packeta' ),
287 // translators: %s: Order number.
288 'reallyCancelPacketHeading' => sprintf( __( 'Order #%s', 'packeta' ), $order->getCustomNumber() ),
289 // translators: %s: Packet number.
290 'reallyCancelPacket' => sprintf( __( 'Do you really wish to cancel parcel number %s?', 'packeta' ), $packetId ),
291 'cancelPacket' => __( 'Cancel packet', 'packeta' ),
292 ],
293 ]
294 );
295
296 return;
297 }
298
299 $this->order_form->setDefaults(
300 [
301 'packetery_order_metabox_nonce' => wp_create_nonce(),
302 self::FIELD_WEIGHT => $order->getFinalWeight(),
303 self::FIELD_ORIGINAL_WEIGHT => $order->getFinalWeight(),
304 self::FIELD_WIDTH => $order->getWidth(),
305 self::FIELD_LENGTH => $order->getLength(),
306 self::FIELD_HEIGHT => $order->getHeight(),
307 self::FIELD_ADULT_CONTENT => $order->containsAdultContent(),
308 self::FIELD_COD => $order->getCod(),
309 self::FIELD_VALUE => $order->getValue(),
310 self::FIELD_DELIVER_ON => $this->helper->getStringFromDateTime( $order->getDeliverOn(), Helper::DATEPICKER_FORMAT ),
311 ]
312 );
313
314 $prev_invalid_values = get_transient( 'packetery_metabox_nette_form_prev_invalid_values' );
315 if ( $prev_invalid_values ) {
316 $this->order_form->setValues( $prev_invalid_values );
317 $this->order_form->validate();
318 }
319 delete_transient( 'packetery_metabox_nette_form_prev_invalid_values' );
320
321 $showSubmitPacketButton = null !== $order->getFinalWeight() && $order->getFinalWeight() > 0;
322 $packetSubmitUrl = $this->getOrderActionLink( $order, PacketActionsCommonLogic::ACTION_SUBMIT_PACKET );
323
324 $showWidgetButton = $order->isPickupPointDelivery();
325 $widgetButtonError = null;
326 $shippingCountry = $order->getShippingCountry();
327 $showHdWidget = $order->isHomeDelivery() && in_array( $shippingCountry, Entity\Carrier::ADDRESS_VALIDATION_COUNTRIES, true );
328 if (
329 null === $shippingCountry ||
330 // If carrier code is null, it means that more accurate carrier id could not be determined. See Order\Builder.
331 null === $order->getCarrierCode() ||
332 ! $this->carrierRepository->isValidForCountry( $order->isExternalCarrier() ? $order->getCarrierId() : null, $shippingCountry )
333 ) {
334 $carrierCountry = null;
335 if ( null !== $order->getCarrier() ) {
336 $carrierCountry = $order->getCarrier()->getCountry();
337 }
338
339 if ( $order->isPickupPointDelivery() ) {
340 $showWidgetButton = false;
341 if ( empty( $shippingCountry ) ) {
342 $widgetButtonError = __(
343 'The pickup point cannot be changed because the shipping address has no country set. First, change the country of delivery in the shipping address.',
344 'packeta'
345 );
346 } else {
347 $widgetButtonError = sprintf(
348 // translators: %s is country code.
349 __(
350 'The pickup point cannot be changed because the selected carrier does not deliver to country "%s". First, change the country of delivery in the shipping address.',
351 'packeta'
352 ),
353 $shippingCountry
354 );
355 }
356 } elseif ( in_array( $carrierCountry, Entity\Carrier::ADDRESS_VALIDATION_COUNTRIES, true ) ) {
357 $showHdWidget = false;
358 if ( empty( $shippingCountry ) ) {
359 $widgetButtonError = __(
360 'The address cannot be validated because the shipping address has no country set. First, change the country of delivery in the shipping address.',
361 'packeta'
362 );
363 } else {
364 $widgetButtonError = sprintf(
365 // translators: %s is country code.
366 __(
367 'The address cannot be validated because the selected carrier does not deliver to country "%s". First, change the country of delivery in the shipping address.',
368 'packeta'
369 ),
370 $shippingCountry
371 );
372 }
373 }
374 }
375
376 $this->latte_engine->render(
377 PACKETERY_PLUGIN_DIR . '/template/order/metabox-form.latte',
378 [
379 'form' => $this->order_form,
380 'order' => $order,
381 'showWidgetButton' => $showWidgetButton,
382 'widgetButtonError' => $widgetButtonError,
383 'showHdWidget' => $showHdWidget,
384 'showSubmitPacketButton' => $showSubmitPacketButton,
385 'packetSubmitUrl' => $packetSubmitUrl,
386 'orderCurrency' => get_woocommerce_currency_symbol( $order->getCurrency() ),
387 'isCodPayment' => $wcOrder->get_payment_method() === $this->optionsProvider->getCodPaymentMethod(),
388 'logo' => plugin_dir_url( PACKETERY_PLUGIN_DIR . '/packeta.php' ) . 'public/packeta-symbol.png',
389 'showLogsLink' => $showLogsLink,
390 'hasOrderManualWeight' => $order->hasManualWeight(),
391 'isPacketaPickupPoint' => $order->isPacketaInternalPickupPoint(),
392 'translations' => [
393 'showLogs' => __( 'Show logs', 'packeta' ),
394 'weightIsManual' => __( 'Weight is manually set. To calculate weight remove field content and save.', 'packeta' ),
395 'submitPacket' => __( 'Submit to packeta', 'packeta' ),
396 ],
397 ]
398 );
399 }
400
401 /**
402 * Saves added packetery form fields to order metas.
403 *
404 * @param mixed $orderId Order id.
405 *
406 * @return mixed Order id.
407 * @throws WC_Data_Exception When invalid data are passed during shipping address update.
408 */
409 public function save_fields( $orderId ) {
410 $order = $this->orderRepository->getById( $orderId );
411 if (
412 null === $order ||
413 ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) ||
414 null === $this->request->getPost( 'packetery_order_metabox_nonce' )
415 ) {
416 return $orderId;
417 }
418
419 if ( false === $this->order_form->isValid() ) {
420 set_transient( 'packetery_metabox_nette_form_prev_invalid_values', $this->order_form->getValues( true ) );
421 $this->message_manager->flash_message( __( 'Packeta: entered data is not valid!', 'packeta' ), MessageManager::TYPE_ERROR );
422
423 return $orderId;
424 }
425
426 $values = $this->order_form->getValues( 'array' );
427
428 if ( ! wp_verify_nonce( $values['packetery_order_metabox_nonce'] ) ) {
429 $this->message_manager->flash_message( __( 'Session has expired! Please try again.', 'packeta' ), MessageManager::TYPE_ERROR );
430
431 return $orderId;
432 }
433
434 if ( ! current_user_can( 'edit_post', $orderId ) ) {
435 $this->message_manager->flash_message( __( 'You do not have sufficient rights to make changes!', 'packeta' ), MessageManager::TYPE_ERROR );
436
437 return $orderId;
438 }
439
440 $propsToSave = [
441 self::FIELD_WIDTH => ( is_numeric( $values[ self::FIELD_WIDTH ] ) ? (float) number_format( $values[ self::FIELD_WIDTH ], 0, '.', '' ) : null ),
442 self::FIELD_LENGTH => ( is_numeric( $values[ self::FIELD_LENGTH ] ) ? (float) number_format( $values[ self::FIELD_LENGTH ], 0, '.', '' ) : null ),
443 self::FIELD_HEIGHT => ( is_numeric( $values[ self::FIELD_HEIGHT ] ) ? (float) number_format( $values[ self::FIELD_HEIGHT ], 0, '.', '' ) : null ),
444 ];
445
446 if ( ! is_numeric( $values[ self::FIELD_WEIGHT ] ) ) {
447 $propsToSave[ self::FIELD_WEIGHT ] = null;
448 } elseif ( (float) $values[ self::FIELD_WEIGHT ] !== (float) $values[ self::FIELD_ORIGINAL_WEIGHT ] ) {
449 $propsToSave[ self::FIELD_WEIGHT ] = (float) $values[ self::FIELD_WEIGHT ];
450 }
451
452 if ( $values[ Attribute::POINT_ID ] && $order->isPickupPointDelivery() ) {
453 /**
454 * Cannot be null due to the condition at the beginning of the method.
455 *
456 * @var WC_Order $wcOrder
457 */
458 $wcOrder = $this->orderRepository->getWcOrderById( (int) $orderId );
459 foreach ( Attribute::$pickupPointAttrs as $pickupPointAttr ) {
460 $value = $values[ $pickupPointAttr['name'] ];
461
462 if ( Attribute::CARRIER_ID === $pickupPointAttr['name'] ) {
463 $value = ( ! empty( $values[ Attribute::CARRIER_ID ] ) ? $values[ Attribute::CARRIER_ID ] : $order->getCarrierId() );
464 }
465
466 $propsToSave[ $pickupPointAttr['name'] ] = $value;
467
468 if ( $this->optionsProvider->replaceShippingAddressWithPickupPointAddress() ) {
469 $this->mapper->toWcOrderShippingAddress( $wcOrder, $pickupPointAttr['name'], (string) $value );
470 }
471 }
472 $wcOrder->save();
473 }
474
475 if ( '1' === $values[ Attribute::ADDRESS_IS_VALIDATED ] && $order->isHomeDelivery() ) {
476 $address = $this->mapper->toValidatedAddress( $values );
477 $order->setDeliveryAddress( $address );
478 $order->setAddressValidated( true );
479 }
480
481 $order->setAdultContent( $values[ self::FIELD_ADULT_CONTENT ] );
482 $order->setCod( is_numeric( $values[ self::FIELD_COD ] ) ? Helper::simplifyFloat( $values[ self::FIELD_COD ], 10 ) : null );
483 $order->setValue( is_numeric( $values[ self::FIELD_VALUE ] ) ? Helper::simplifyFloat( $values[ self::FIELD_VALUE ], 10 ) : null );
484 $order->setDeliverOn( $this->helper->getDateTimeFromString( $values[ self::FIELD_DELIVER_ON ] ) );
485
486 $orderSize = $this->mapper->toOrderSize( $order, $propsToSave );
487 $order->setSize( $orderSize );
488
489 $pickupPoint = $this->mapper->toOrderEntityPickupPoint( $order, $propsToSave );
490 $order->setPickupPoint( $pickupPoint );
491
492 $this->orderRepository->save( $order );
493
494 return $orderId;
495 }
496
497 /**
498 * Creates pickup point picker settings.
499 *
500 * @return array|null
501 */
502 public function getPickupPointWidgetSettings(): ?array {
503 global $post;
504
505 $order = $this->orderRepository->getById( (int) $post->ID );
506 if ( null === $order || false === $order->isPickupPointDelivery() || null === $order->getShippingCountry() ) {
507 return null;
508 }
509
510 $widgetOptions = $this->widgetOptionsBuilder->createPickupPointForAdmin( $order );
511
512 return [
513 'packeteryApiKey' => $this->optionsProvider->get_api_key(),
514 'pickupPointAttrs' => Attribute::$pickupPointAttrs,
515 'widgetOptions' => $widgetOptions,
516 ];
517 }
518
519 /**
520 * Creates address picker settings.
521 *
522 * @return array|null
523 */
524 public function getAddressWidgetSettings(): ?array {
525 global $post;
526
527 $order = $this->orderRepository->getById( (int) $post->ID );
528 if ( null === $order || false === $order->isHomeDelivery() ) {
529 return null;
530 }
531
532 $widgetOptions = $this->widgetOptionsBuilder->createAddressForAdmin( $order );
533
534 return [
535 'packeteryApiKey' => $this->optionsProvider->get_api_key(),
536 'homeDeliveryAttrs' => Attribute::$homeDeliveryAttrs,
537 'widgetOptions' => $widgetOptions,
538 'translations' => [
539 'addressValidationIsOutOfOrder' => __( 'Address validation is out of order.', 'packeta' ),
540 'invalidAddressCountrySelected' => __( 'The selected country does not correspond to the destination country.', 'packeta' ),
541 ],
542 ];
543 }
544
545 /**
546 * Gets order action link.
547 *
548 * @param Entity\Order $order Order.
549 * @param string $action Action.
550 *
551 * @return string
552 */
553 private function getOrderActionLink( Entity\Order $order, string $action ): string {
554 return add_query_arg(
555 [
556 PacketActionsCommonLogic::PARAM_ORDER_ID => $order->getNumber(),
557 PacketActionsCommonLogic::PARAM_REDIRECT_TO => PacketActionsCommonLogic::REDIRECT_TO_ORDER_DETAIL,
558 Plugin::PARAM_PACKETERY_ACTION => $action,
559 Plugin::PARAM_NONCE => wp_create_nonce( PacketActionsCommonLogic::createNonceAction( $action, $order->getNumber() ) ),
560 ],
561 admin_url( 'admin.php' )
562 );
563 }
564
565 }
566