PluginProbe
Packeta / 1.5.2
Packeta v1.5.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 / Metabox.php

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

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