latteEngine = $latteEngine; $this->messageManager = $messageManager; $this->coreHelper = $coreHelper; $this->request = $request; $this->optionsProvider = $optionsProvider; $this->orderRepository = $orderRepository; $this->logPage = $logPage; $this->mapper = $mapper; $this->widgetOptionsBuilder = $widgetOptionsBuilder; $this->carrierRepository = $carrierRepository; $this->orderValidator = $orderValidatorFactory->create(); $this->detailCommonLogic = $detailCommonLogic; $this->orderForm = $orderForm; $this->carrierModal = $carrierModal; $this->wpAdapter = $wpAdapter; $this->packetStatusResolver = $packetStatusResolver; } public function register(): void { add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) ); } public function add_meta_boxes(): void { if ( ! $this->detailCommonLogic->isPacketeryOrder() ) { return; } $this->initializeForm(); $parts = $this->prepareMetaboxParts(); if ( count( $parts ) > 0 ) { add_meta_box( 'packetery_metabox', $this->wpAdapter->__( 'Packeta', 'packeta' ), array( $this, 'render_metabox', ), ModuleHelper::isHposEnabled() ? wc_get_page_screen_id( 'shop-order' ) : 'shop_order', 'side', 'high' ); } } public function render_metabox(): void { $parts = $this->prepareMetaboxParts(); if ( isset( $parts[ self::PART_ERROR ] ) ) { ModuleHelper::renderString( $parts[ self::PART_ERROR ] ); return; } if ( isset( $parts[ self::PART_CARRIER_CHANGE ] ) ) { ModuleHelper::renderString( $parts[ self::PART_CARRIER_CHANGE ] ); } if ( isset( $parts[ self::PART_CARRIER_CHANGE ], $parts[ self::PART_MAIN ] ) ) { ModuleHelper::renderString( '
' ); } if ( isset( $parts[ self::PART_MAIN ] ) ) { ModuleHelper::renderString( $parts[ self::PART_MAIN ] ); } } /** * @return array */ private function prepareMetaboxParts(): array { static $partsCache; if ( isset( $partsCache ) ) { return $partsCache; } $orderId = $this->detailCommonLogic->getOrderId(); if ( $orderId === null ) { $partsCache = []; return $partsCache; } try { $order = $this->orderRepository->getById( $orderId ); } catch ( InvalidCarrierException $exception ) { $partsCache = [ self::PART_ERROR => $this->latteEngine->renderToString( PACKETERY_PLUGIN_DIR . '/template/order/metabox-form-error.latte', [ 'errorMessage' => $exception->getMessage(), ] ), ]; return $partsCache; } $parts = []; if ( $this->carrierModal->canBeDisplayed() ) { $parts[ self::PART_CARRIER_CHANGE ] = $this->carrierModal->getMetaboxHtml(); } if ( $order === null ) { $partsCache = $parts; return $partsCache; } $showLogsLink = null; if ( $this->logPage->hasAnyRows( (int) $order->getNumber() ) ) { $showLogsLink = $this->logPage->createLogListUrl( (int) $order->getNumber() ); } $packetClaimUrl = null; if ( $order->isPacketClaimCreationPossible() ) { $packetClaimUrl = $this->getOrderActionLink( $order, PacketActionsCommonLogic::ACTION_SUBMIT_PACKET_CLAIM ); } $packetClaimCancelUrl = null; $packetClaimTrackingUrl = null; if ( $order->getPacketClaimId() !== null ) { $packetClaimCancelUrl = $this->getOrderActionLink( $order, PacketActionsCommonLogic::ACTION_CANCEL_PACKET, [ PacketActionsCommonLogic::PARAM_PACKET_ID => $order->getPacketClaimId(), ] ); $packetClaimTrackingUrl = $this->coreHelper->getTrackingUrl( $order->getPacketClaimId() ); } $runWizardUrl = $this->wpAdapter->adminUrl( "admin.php?page=wc-orders&action=edit&id={$orderId}&wizard-enabled=true&wizard-order-detail-edit-packet-enabled=true" ); $showRunWizardButton = (bool) $this->wpAdapter->applyFilters( 'packeta_order_detail_show_run_wizard_button', true ); $packetId = $order->getPacketId(); if ( $packetId !== null ) { $packetCancelLink = $this->getOrderActionLink( $order, PacketActionsCommonLogic::ACTION_CANCEL_PACKET, [ PacketActionsCommonLogic::PARAM_PACKET_ID => $packetId, ] ); $packetStatusTranslatedName = $this->packetStatusResolver->getTranslatedName( $order->getPacketStatus() ); /** @var array $statusClasses */ $statusClasses = [ 'received data' => 'received-data', 'unknown' => 'unknown', 'delivered' => 'delivered', 'cancelled' => 'cancelled', 'returned' => 'returned', 'rejected by recipient' => 'rejected', ]; $statusClass = 'delivery-status'; $statusType = $order->getPacketStatus(); if ( isset( $statusClasses[ $statusType ] ) ) { $statusClass = $statusClasses[ $statusType ]; } $invalidFields = $this->orderForm->getInvalidFieldsFromValidationResult( $this->orderValidator->validate( $order ) ); $invalidFieldsMessage = $this->orderForm->getInvalidFieldsMessageFromValidationResult( $invalidFields, $order ); $parts[ self::PART_MAIN ] = $this->latteEngine->renderToString( PACKETERY_PLUGIN_DIR . '/template/order/metabox-common.latte', [ 'order' => $order, 'showConsignPasswordForZBox' => $this->optionsProvider->isShowConsignPasswordForZBoxEnabled(), 'packetStatusTranslatedName' => $packetStatusTranslatedName, 'statusClass' => $statusClass, 'isPacketSubmissionPossible' => false, 'orderWarningFields' => [], 'invalidFieldsMessage' => $invalidFieldsMessage, 'packetCancelLink' => $packetCancelLink, 'packetTrackingUrl' => $this->coreHelper->getTrackingUrl( $packetId ), 'packetClaimTrackingUrl' => $packetClaimTrackingUrl, 'showLogsLink' => $showLogsLink, 'packetClaimUrl' => $packetClaimUrl, 'packetClaimCancelUrl' => $packetClaimCancelUrl, 'runWizardUrl' => $runWizardUrl, 'showRunWizardButton' => $showRunWizardButton, 'storedUntil' => $this->coreHelper->getStringFromDateTime( $order->getStoredUntil(), CoreHelper::DATEPICKER_FORMAT ), 'translations' => [ 'packetTrackingOnline' => $this->wpAdapter->__( 'Packet tracking online', 'packeta' ), 'packetClaimTrackingOnline' => $this->wpAdapter->__( 'Packet claim tracking', 'packeta' ), 'showLogs' => $this->wpAdapter->__( 'Show logs', 'packeta' ), // translators: %s: Order number. 'reallyCancelPacketHeading' => sprintf( $this->wpAdapter->__( 'Order #%s', 'packeta' ), $order->getCustomNumber() ), // translators: %s: Packet number. 'reallyCancelPacket' => sprintf( $this->wpAdapter->__( 'Do you really wish to cancel parcel number %s?', 'packeta' ), $packetId ), // translators: %s: Packet claim number. 'reallyCancelPacketClaim' => sprintf( $this->wpAdapter->__( 'Do you really wish to cancel packet claim number %s?', 'packeta' ), $order->getPacketClaimId() ), 'cancelPacket' => $this->wpAdapter->__( 'Cancel packet', 'packeta' ), 'createPacketClaim' => $this->wpAdapter->__( 'Create packet claim', 'packeta' ), 'printPacketLabel' => $this->wpAdapter->__( 'Print packet label', 'packeta' ), 'printPacketClaimLabel' => $this->wpAdapter->__( 'Print packet claim label', 'packeta' ), 'cancelPacketClaim' => $this->wpAdapter->__( 'Cancel packet claim', 'packeta' ), 'packetClaimPassword' => $this->wpAdapter->__( 'Packet claim password', 'packeta' ), 'submissionPassword' => $this->wpAdapter->__( 'submission password', 'packeta' ), 'zboxConsignPassword' => $this->wpAdapter->__( 'Consignment code', 'packeta' ), 'setStoredUntil' => $this->wpAdapter->__( 'Set the pickup date extension', 'packeta' ), 'runWizard' => $this->wpAdapter->__( 'Run options wizard', 'packeta' ), ], ] ); $partsCache = $parts; return $partsCache; } $unit = $this->optionsProvider->getDimensionsUnit(); $this->orderForm->setDefaults( $this->form, $order->getFinalWeight(), $order->getCalculatedWeight(), $unit === OptionsProvider::DIMENSIONS_UNIT_CM ? ModuleHelper::convertToCentimeters( (int) $order->getLength() ) : $order->getLength(), $unit === OptionsProvider::DIMENSIONS_UNIT_CM ? ModuleHelper::convertToCentimeters( (int) $order->getWidth() ) : $order->getWidth(), $unit === OptionsProvider::DIMENSIONS_UNIT_CM ? ModuleHelper::convertToCentimeters( (int) $order->getHeight() ) : $order->getHeight(), $order->getFinalCod(), $order->getCalculatedCod(), $order->getFinalValue(), $order->getCalculatedValue(), $order->containsAdultContent(), $this->coreHelper->getStringFromDateTime( $order->getDeliverOn(), CoreHelper::DATEPICKER_FORMAT ) ); $prevInvalidValues = get_transient( Transients::METABOX_NETTE_FORM_PREV_INVALID_VALUES ); if ( $prevInvalidValues !== null && $prevInvalidValues !== false ) { $this->form->setValues( $prevInvalidValues ); $this->form->validate(); } delete_transient( Transients::METABOX_NETTE_FORM_PREV_INVALID_VALUES ); $isPacketSubmissionPossible = $this->orderValidator->isValid( $order ); $packetSubmitUrl = $this->getOrderActionLink( $order, PacketActionsCommonLogic::ACTION_SUBMIT_PACKET ); $showWidgetButton = $order->isPickupPointDelivery(); $widgetButtonError = null; $shippingCountry = $order->getShippingCountry(); $showHdWidget = $order->isHomeDelivery() && in_array( $shippingCountry, Entity\Carrier::ADDRESS_VALIDATION_COUNTRIES, true ); if ( $shippingCountry === null || ! $this->carrierRepository->isValidForCountry( $order->getCarrier()->getId(), $shippingCountry ) ) { if ( $order->isPickupPointDelivery() ) { $showWidgetButton = false; if ( $shippingCountry === null ) { $widgetButtonError = $this->wpAdapter->__( 'The pickup point cannot be changed because the shipping address has no country set. First, change the country of delivery in the shipping address.', 'packeta' ); } else { $widgetButtonError = sprintf( // translators: %s is country code. $this->wpAdapter->__( '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.', 'packeta' ), $shippingCountry ); } } elseif ( in_array( $order->getCarrier()->getCountry(), Entity\Carrier::ADDRESS_VALIDATION_COUNTRIES, true ) ) { $showHdWidget = false; if ( $shippingCountry === null ) { $widgetButtonError = $this->wpAdapter->__( 'The address cannot be validated because the shipping address has no country set. First, change the country of delivery in the shipping address.', 'packeta' ); } else { $widgetButtonError = sprintf( // translators: %s is country code. $this->wpAdapter->__( '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.', 'packeta' ), $shippingCountry ); } } } $invalidFields = $this->orderForm->getInvalidFieldsFromValidationResult( $this->orderValidator->validate( $order ) ); $invalidFieldsMessage = $this->orderForm->getInvalidFieldsMessageFromValidationResult( $invalidFields, $order ); $parts[ self::PART_MAIN ] = $this->latteEngine->renderToString( PACKETERY_PLUGIN_DIR . '/template/order/metabox-form.latte', [ 'form' => $this->form, 'order' => $order, 'showConsignPasswordForZBox' => $this->optionsProvider->isShowConsignPasswordForZBoxEnabled(), 'showWidgetButton' => $showWidgetButton, 'widgetButtonError' => $widgetButtonError, 'showHdWidget' => $showHdWidget, 'isPacketSubmissionPossible' => $isPacketSubmissionPossible, 'orderWarningFields' => $invalidFields, 'invalidFieldsMessage' => $invalidFieldsMessage, 'packetCancelLink' => null, 'packetTrackingUrl' => null, 'packetStatusTranslatedName' => null, 'packetSubmitUrl' => $packetSubmitUrl, 'packetClaimTrackingUrl' => $packetClaimTrackingUrl, 'packetClaimUrl' => $packetClaimUrl, 'packetClaimCancelUrl' => $packetClaimCancelUrl, 'runWizardUrl' => $runWizardUrl, 'showRunWizardButton' => $showRunWizardButton, 'orderCurrency' => get_woocommerce_currency_symbol( $order->getCurrency() ), 'isCodPayment' => $order->hasCod(), 'allowsAdultContent' => $order->allowsAdultContent(), 'requiresSizeDimensions' => $order->getCarrier()->requiresSize(), 'logo' => plugin_dir_url( PACKETERY_PLUGIN_DIR . '/packeta.php' ) . 'public/images/packeta-symbol.png', 'showLogsLink' => $showLogsLink, 'hasOrderManualWeight' => $order->hasManualWeight(), 'hasOrderManualCod' => $order->hasManualCod(), 'hasOrderManualValue' => $order->hasManualValue(), 'isPacketaPickupPoint' => $order->isPacketaInternalPickupPoint(), 'pickupPointAttributes' => Attribute::$pickupPointAttributes, 'homeDeliveryAttributes' => Attribute::$homeDeliveryAttributes, 'translations' => [ 'packetSubmissionValidationErrorTooltip' => $this->wpAdapter->__( 'It is not possible to submit the shipment because all the information required for this shipment is not filled:', 'packeta' ), 'showLogs' => $this->wpAdapter->__( 'Show logs', 'packeta' ), 'weightIsManual' => $this->wpAdapter->__( 'Weight is manually set. To calculate weight remove field content and save.', 'packeta' ), 'codIsManual' => $this->wpAdapter->__( 'COD value is manually set. To calculate the value remove field content and save.', 'packeta' ), 'valueIsManual' => $this->wpAdapter->__( 'Order value is manually set. To calculate the value remove field content and save.', 'packeta' ), 'submitPacket' => $this->wpAdapter->__( 'Submit to Packeta', 'packeta' ), 'runWizard' => $this->wpAdapter->__( 'Run options wizard', 'packeta' ), 'packetClaimTrackingOnline' => $this->wpAdapter->__( 'Packet claim tracking', 'packeta' ), 'printPacketClaimLabel' => $this->wpAdapter->__( 'Print packet claim label', 'packeta' ), 'cancelPacketClaim' => $this->wpAdapter->__( 'Cancel packet claim', 'packeta' ), 'packetClaimPassword' => $this->wpAdapter->__( 'Packet claim password', 'packeta' ), 'submissionPassword' => $this->wpAdapter->__( 'submission password', 'packeta' ), 'zboxConsignPassword' => $this->wpAdapter->__( 'Z-BOX consign password', 'packeta' ), // translators: %s: Order number. 'reallyCancelPacketHeading' => sprintf( $this->wpAdapter->__( 'Order #%s', 'packeta' ), $order->getCustomNumber() ), // translators: %s: Packet claim number. 'reallyCancelPacketClaim' => sprintf( $this->wpAdapter->__( 'Do you really wish to cancel packet claim number %s?', 'packeta' ), $order->getPacketClaimId() ), ], ] ); $partsCache = $parts; return $partsCache; } /** * Saves added packetery form fields to order metas. * * @param Entity\Order $order Order. * @param WC_Order $wcOrder WC Order. * * @return void * @throws WC_Data_Exception When invalid data are passed during shipping address update. */ public function saveFields( Entity\Order $order, WC_Order $wcOrder ): void { $this->initializeForm(); $orderId = (int) $order->getNumber(); if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || $this->request->getPost( 'packetery_order_metabox_nonce' ) === null ) { return; } if ( $this->form->isValid() === false ) { set_transient( Transients::METABOX_NETTE_FORM_PREV_INVALID_VALUES, $this->form->getValues( 'array' ) ); $this->messageManager->flash_message( $this->wpAdapter->__( 'Packeta: entered data is not valid!', 'packeta' ), MessageManager::TYPE_ERROR ); return; } /** @var array $formValues */ $formValues = $this->form->getValues( 'array' ); if ( wp_verify_nonce( $formValues['packetery_order_metabox_nonce'] ) !== 1 ) { $this->messageManager->flash_message( $this->wpAdapter->__( 'Session has expired! Please try again.', 'packeta' ), MessageManager::TYPE_ERROR ); return; } if ( ! current_user_can( 'edit_post', $orderId ) ) { $this->messageManager->flash_message( $this->wpAdapter->__( 'You do not have sufficient rights to make changes!', 'packeta' ), MessageManager::TYPE_ERROR ); return; } $propsToSave = []; foreach ( [ Form::FIELD_LENGTH, Form::FIELD_WIDTH, Form::FIELD_HEIGHT ] as $dimension ) { $propsToSave[ $dimension ] = $this->optionsProvider->getSanitizedDimensionValueInMm( $formValues[ $dimension ] ); } $formWeightEqualsToCalculated = (float) $formValues[ Form::FIELD_WEIGHT ] === (float) $formValues[ Form::FIELD_ORIGINAL_WEIGHT ]; if ( ! is_numeric( $formValues[ Form::FIELD_WEIGHT ] ) || $formWeightEqualsToCalculated ) { $propsToSave[ Form::FIELD_WEIGHT ] = null; } else { $propsToSave[ Form::FIELD_WEIGHT ] = (float) $formValues[ Form::FIELD_WEIGHT ]; } $order->setWeight( $propsToSave[ Form::FIELD_WEIGHT ] ); if ( $formValues[ Attribute::POINT_ID ] && $order->isPickupPointDelivery() ) { foreach ( Attribute::$pickupPointAttributes as $pickupPointAttr ) { $pickupPointValue = $formValues[ $pickupPointAttr['name'] ]; if ( $pickupPointAttr['name'] === Attribute::CARRIER_ID ) { if ( isset( $formValues[ Attribute::CARRIER_ID ] ) && $formValues[ Attribute::CARRIER_ID ] !== '' ) { $pickupPointValue = $formValues[ Attribute::CARRIER_ID ]; } else { $pickupPointValue = $order->getCarrier()->getId(); } } $propsToSave[ $pickupPointAttr['name'] ] = $pickupPointValue; if ( $this->optionsProvider->replaceShippingAddressWithPickupPointAddress() ) { $this->mapper->toWcOrderShippingAddress( $wcOrder, $pickupPointAttr['name'], (string) $pickupPointValue ); } } } if ( $formValues[ Attribute::ADDRESS_IS_VALIDATED ] === '1' && $order->isHomeDelivery() ) { $address = $this->mapper->toValidatedAddress( $formValues ); $order->setDeliveryAddress( $address ); $order->setAddressValidated( true ); } $order->setAdultContent( $formValues[ Form::FIELD_ADULT_CONTENT ] ); $formCodEqualsToCalculated = (float) $formValues[ Form::FIELD_COD ] === (float) $formValues[ Form::FIELD_CALCULATED_COD ]; if ( ! is_numeric( $formValues[ Form::FIELD_COD ] ) || $formCodEqualsToCalculated ) { $order->setManualCod( null ); } else { $order->setManualCod( is_numeric( $formValues[ Form::FIELD_COD ] ) ? CoreHelper::simplifyFloat( $formValues[ Form::FIELD_COD ], 10 ) : null ); } $formValueEqualsToCalculated = (float) $formValues[ Form::FIELD_VALUE ] === (float) $formValues[ Form::FIELD_CALCULATED_VALUE ]; if ( ! is_numeric( $formValues[ Form::FIELD_VALUE ] ) || $formValueEqualsToCalculated ) { $order->setManualValue( null ); } else { $order->setManualValue( is_numeric( $formValues[ Form::FIELD_VALUE ] ) ? CoreHelper::simplifyFloat( $formValues[ Form::FIELD_VALUE ], 10 ) : null ); } $order->setDeliverOn( $this->coreHelper->getDateTimeFromString( $formValues[ Form::FIELD_DELIVER_ON ] ) ); $orderSize = $this->mapper->toOrderSize( $order, $propsToSave ); $order->setSize( $orderSize ); $pickupPoint = $this->mapper->toOrderEntityPickupPoint( $order, $propsToSave ); $order->setPickupPoint( $pickupPoint ); $updatedRowCount = $this->orderRepository->save( $order ); if ( $updatedRowCount === false ) { $this->messageManager->flash_message( (string) $this->wpAdapter->__( 'An error occurred while saving the order. More details in WC log.', 'packeta' ), MessageManager::TYPE_ERROR ); } } /** * Creates pickup point picker settings. * * @return array */ public function getPickupPointWidgetSettings(): ?array { $order = $this->detailCommonLogic->getOrder(); if ( $order === null || $order->isPickupPointDelivery() === false || $order->getShippingCountry() === null ) { return null; } $widgetOptions = $this->widgetOptionsBuilder->createPickupPointForAdmin( $order ); return [ 'packeteryApiKey' => $this->optionsProvider->get_api_key(), 'pickupPointAttrs' => Attribute::$pickupPointAttributes, 'widgetOptions' => $widgetOptions, ]; } /** * Creates address picker settings. * * @return mixed[]|null */ public function getAddressWidgetSettings(): ?array { $order = $this->detailCommonLogic->getOrder(); if ( $order === null || $order->isHomeDelivery() === false ) { return null; } $widgetOptions = $this->widgetOptionsBuilder->createAddressForAdmin( $order ); return [ 'packeteryApiKey' => $this->optionsProvider->get_api_key(), 'homeDeliveryAttrs' => Attribute::$homeDeliveryAttributes, 'widgetOptions' => $widgetOptions, 'translations' => [ 'addressValidationIsOutOfOrder' => $this->wpAdapter->__( 'Address validation is out of order.', 'packeta' ), 'invalidAddressCountrySelected' => $this->wpAdapter->__( 'The selected country does not correspond to the destination country.', 'packeta' ), ], ]; } /** * Gets order action link. * * @param Entity\Order $order Order. * @param string $action Action. * @param array $extraParams Extra params. * * @return string */ private function getOrderActionLink( Entity\Order $order, string $action, array $extraParams = [] ): string { $baseParams = [ PacketActionsCommonLogic::PARAM_ORDER_ID => $order->getNumber(), PacketActionsCommonLogic::PARAM_REDIRECT_TO => PacketActionsCommonLogic::REDIRECT_TO_ORDER_DETAIL, Plugin::PARAM_PACKETERY_ACTION => $action, Plugin::PARAM_NONCE => wp_create_nonce( PacketActionsCommonLogic::createNonceAction( $action, $order->getNumber() ) ), ]; return add_query_arg( array_merge( $baseParams, $extraParams ), admin_url( 'admin.php' ) ); } /** * Initializes form to render or process. * * @return void */ private function initializeForm(): void { $this->form = $this->orderForm->create(); $this->form->addHidden( 'packetery_order_metabox_nonce' ); $this->form->setDefaults( [ 'packetery_order_metabox_nonce' => wp_create_nonce() ] ); foreach ( Attribute::$pickupPointAttributes as $pickupPointAttr ) { $this->form->addHidden( $pickupPointAttr['name'] ); } foreach ( Attribute::$homeDeliveryAttributes as $homeDeliveryAttr ) { $this->form->addHidden( $homeDeliveryAttr['name'] ); } $this->form->addButton( 'packetery_pick_pickup_point', $this->wpAdapter->__( 'Choose pickup point', 'packeta' ) ); $this->form->addButton( 'packetery_pick_address', $this->wpAdapter->__( 'Check shipping address', 'packeta' ) ); } }