PluginProbe
Packeta / 1.5.0
Packeta v1.5.0
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.0, at src/Packetery/Module/Order/Metabox.php

499 lines 16.1 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 $this->latte_engine->render(
313 PACKETERY_PLUGIN_DIR . '/template/order/metabox-form.latte',
314 [
315 'form' => $this->order_form,
316 'order' => $order,
317 'showSubmitPacketButton' => $showSubmitPacketButton,
318 'packetSubmitUrl' => $packetSubmitUrl,
319 'orderCurrency' => get_woocommerce_currency_symbol( $order->getCurrency() ),
320 'isCodPayment' => $wcOrder->get_payment_method() === $this->optionsProvider->getCodPaymentMethod(),
321 'logo' => plugin_dir_url( PACKETERY_PLUGIN_DIR . '/packeta.php' ) . 'public/packeta-symbol.png',
322 'showLogsLink' => $showLogsLink,
323 'hasOrderManualWeight' => $order->hasManualWeight(),
324 'isPacketaPickupPoint' => $order->isPacketaInternalPickupPoint(),
325 'translations' => [
326 'showLogs' => __( 'Show logs', 'packeta' ),
327 'weightIsManual' => __( 'Weight is manually set. To calculate weight remove field content and save.', 'packeta' ),
328 'submitPacket' => __( 'Submit to packeta', 'packeta' ),
329 ],
330 ]
331 );
332 }
333
334 /**
335 * Saves added packetery form fields to order metas.
336 *
337 * @param mixed $orderId Order id.
338 *
339 * @return mixed Order id.
340 * @throws WC_Data_Exception When invalid data are passed during shipping address update.
341 */
342 public function save_fields( $orderId ) {
343 $order = $this->orderRepository->getById( $orderId );
344 if (
345 null === $order ||
346 ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) ||
347 null === $this->request->getPost( 'packetery_order_metabox_nonce' )
348 ) {
349 return $orderId;
350 }
351
352 if ( false === $this->order_form->isValid() ) {
353 set_transient( 'packetery_metabox_nette_form_prev_invalid_values', $this->order_form->getValues( true ) );
354 $this->message_manager->flash_message( __( 'Packeta: entered data is not valid!', 'packeta' ), MessageManager::TYPE_ERROR );
355
356 return $orderId;
357 }
358
359 $values = $this->order_form->getValues( 'array' );
360
361 if ( ! wp_verify_nonce( $values['packetery_order_metabox_nonce'] ) ) {
362 $this->message_manager->flash_message( __( 'Session has expired! Please try again.', 'packeta' ), MessageManager::TYPE_ERROR );
363
364 return $orderId;
365 }
366
367 if ( ! current_user_can( 'edit_post', $orderId ) ) {
368 $this->message_manager->flash_message( __( 'You do not have sufficient rights to make changes!', 'packeta' ), MessageManager::TYPE_ERROR );
369
370 return $orderId;
371 }
372
373 $propsToSave = [
374 self::FIELD_WIDTH => ( is_numeric( $values[ self::FIELD_WIDTH ] ) ? (float) number_format( $values[ self::FIELD_WIDTH ], 0, '.', '' ) : null ),
375 self::FIELD_LENGTH => ( is_numeric( $values[ self::FIELD_LENGTH ] ) ? (float) number_format( $values[ self::FIELD_LENGTH ], 0, '.', '' ) : null ),
376 self::FIELD_HEIGHT => ( is_numeric( $values[ self::FIELD_HEIGHT ] ) ? (float) number_format( $values[ self::FIELD_HEIGHT ], 0, '.', '' ) : null ),
377 ];
378
379 if ( ! is_numeric( $values[ self::FIELD_WEIGHT ] ) ) {
380 $propsToSave[ self::FIELD_WEIGHT ] = null;
381 } elseif ( (float) $values[ self::FIELD_WEIGHT ] !== (float) $values[ self::FIELD_ORIGINAL_WEIGHT ] ) {
382 $propsToSave[ self::FIELD_WEIGHT ] = (float) $values[ self::FIELD_WEIGHT ];
383 }
384
385 if ( $values[ Attribute::POINT_ID ] && $order->isPickupPointDelivery() ) {
386 /**
387 * Cannot be null due to the condition at the beginning of the method.
388 *
389 * @var WC_Order $wcOrder
390 */
391 $wcOrder = $this->orderRepository->getWcOrderById( (int) $orderId );
392 foreach ( Attribute::$pickupPointAttrs as $pickupPointAttr ) {
393 $value = $values[ $pickupPointAttr['name'] ];
394
395 if ( Attribute::CARRIER_ID === $pickupPointAttr['name'] ) {
396 $value = ( ! empty( $values[ Attribute::CARRIER_ID ] ) ? $values[ Attribute::CARRIER_ID ] : $order->getCarrierId() );
397 }
398
399 $propsToSave[ $pickupPointAttr['name'] ] = $value;
400
401 if ( $this->optionsProvider->replaceShippingAddressWithPickupPointAddress() ) {
402 $this->mapper->toWcOrderShippingAddress( $wcOrder, $pickupPointAttr['name'], (string) $value );
403 }
404 }
405 $wcOrder->save();
406 }
407
408 if ( '1' === $values[ Attribute::ADDRESS_IS_VALIDATED ] && $order->isHomeDelivery() ) {
409 $address = $this->mapper->toValidatedAddress( $values );
410 $order->setDeliveryAddress( $address );
411 $order->setAddressValidated( true );
412 }
413
414 $order->setAdultContent( $values[ self::FIELD_ADULT_CONTENT ] );
415 $order->setCod( is_numeric( $values[ self::FIELD_COD ] ) ? Helper::simplifyFloat( $values[ self::FIELD_COD ], 10 ) : null );
416 $order->setValue( is_numeric( $values[ self::FIELD_VALUE ] ) ? Helper::simplifyFloat( $values[ self::FIELD_VALUE ], 10 ) : null );
417 $order->setDeliverOn( $this->helper->getDateTimeFromString( $values[ self::FIELD_DELIVER_ON ] ) );
418
419 $orderSize = $this->mapper->toOrderSize( $order, $propsToSave );
420 $order->setSize( $orderSize );
421
422 $pickupPoint = $this->mapper->toOrderEntityPickupPoint( $order, $propsToSave );
423 $order->setPickupPoint( $pickupPoint );
424
425 $this->orderRepository->save( $order );
426
427 return $orderId;
428 }
429
430 /**
431 * Creates pickup point picker settings.
432 *
433 * @return array|null
434 */
435 public function getPickupPointWidgetSettings(): ?array {
436 global $post;
437
438 $order = $this->orderRepository->getById( (int) $post->ID );
439 if ( null === $order || false === $order->isPickupPointDelivery() ) {
440 return null;
441 }
442
443 $widgetOptions = $this->widgetOptionsBuilder->createPickupPointForAdmin( $order );
444
445 return [
446 'packeteryApiKey' => $this->optionsProvider->get_api_key(),
447 'pickupPointAttrs' => Attribute::$pickupPointAttrs,
448 'widgetOptions' => $widgetOptions,
449 ];
450 }
451
452 /**
453 * Creates address picker settings.
454 *
455 * @return array|null
456 */
457 public function getAddressWidgetSettings(): ?array {
458 global $post;
459
460 $order = $this->orderRepository->getById( (int) $post->ID );
461 if ( null === $order || false === $order->isHomeDelivery() ) {
462 return null;
463 }
464
465 $widgetOptions = $this->widgetOptionsBuilder->createAddressForAdmin( $order );
466
467 return [
468 'packeteryApiKey' => $this->optionsProvider->get_api_key(),
469 'homeDeliveryAttrs' => Attribute::$homeDeliveryAttrs,
470 'widgetOptions' => $widgetOptions,
471 'translations' => [
472 'addressValidationIsOutOfOrder' => __( 'Address validation is out of order.', 'packeta' ),
473 'invalidAddressCountrySelected' => __( 'The selected country does not correspond to the destination country.', 'packeta' ),
474 ],
475 ];
476 }
477
478 /**
479 * Gets order action link.
480 *
481 * @param Entity\Order $order Order.
482 * @param string $action Action.
483 *
484 * @return string
485 */
486 private function getOrderActionLink( Entity\Order $order, string $action ): string {
487 return add_query_arg(
488 [
489 PacketActionsCommonLogic::PARAM_ORDER_ID => $order->getNumber(),
490 PacketActionsCommonLogic::PARAM_REDIRECT_TO => PacketActionsCommonLogic::REDIRECT_TO_ORDER_DETAIL,
491 Plugin::PARAM_PACKETERY_ACTION => $action,
492 Plugin::PARAM_NONCE => wp_create_nonce( PacketActionsCommonLogic::createNonceAction( $action, $order->getNumber() ) ),
493 ],
494 admin_url( 'admin.php' )
495 );
496 }
497
498 }
499