| @@ -1,9 +1,9 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | /** |
| 3 | - * Class Order | |
| 3 | + * Class Builder | |
| 4 | 4 | * |
| 5 | - * @package Packetery\Module\EntityFactory | |
| 5 | + * @package Packetery | |
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | declare( strict_types=1 ); |
| 9 | 9 | |
| @@ -8,20 +8,35 @@ | ||
| 8 | 8 | declare( strict_types=1 ); |
| 9 | 9 | |
| 10 | 10 | namespace Packetery\Module\Order; |
| 11 | 11 | |
| 12 | +use DateTimeImmutable; | |
| 13 | +use DateTimeZone; | |
| 14 | +use Packetery\Core\CoreHelper; | |
| 12 | 15 | use Packetery\Core\Entity; |
| 13 | 16 | use Packetery\Core\Entity\Address; |
| 14 | -use Packetery\Module\Calculator; | |
| 17 | +use Packetery\Core\Entity\Order; | |
| 18 | +use Packetery\Core\Entity\PickupPoint; | |
| 19 | +use Packetery\Core\Entity\Size; | |
| 15 | 20 | use Packetery\Module\Carrier; |
| 16 | -use Packetery\Module\Options\Provider; | |
| 21 | +use Packetery\Module\Carrier\PacketaPickupPointsConfig; | |
| 22 | +use Packetery\Module\CustomsDeclaration; | |
| 23 | +use Packetery\Module\Exception\InvalidCarrierException; | |
| 24 | +use Packetery\Module\ModuleHelper; | |
| 25 | +use Packetery\Module\Options\OptionsProvider; | |
| 26 | +use Packetery\Module\Payment\PaymentHelper; | |
| 17 | 27 | use Packetery\Module\Product; |
| 28 | +use Packetery\Module\WeightCalculator; | |
| 29 | +use stdClass; | |
| 18 | 30 | use WC_Order; |
| 31 | +use WC_Order_Item_Product; | |
| 32 | +use WC_Product; | |
| 19 | 33 | |
| 34 | +// phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps | |
| 20 | 35 | /** |
| 21 | - * Class Order | |
| 36 | + * Class Builder | |
| 22 | 37 | * |
| 23 | - * @package Packetery\Module\EntityFactory | |
| 38 | + * @package Packetery | |
| 24 | 39 | */ |
| 25 | 40 | class Builder { |
| 26 | 41 | |
| 27 | 42 | /** |
| @@ -26,59 +41,182 @@ | ||
| 26 | 41 | |
| 27 | 42 | /** |
| 28 | 43 | * Options provider. |
| 29 | 44 | * |
| 30 | - * @var Provider Options provider. | |
| 45 | + * @var OptionsProvider Options provider. | |
| 31 | 46 | */ |
| 32 | 47 | private $optionsProvider; |
| 33 | 48 | |
| 34 | 49 | /** |
| 35 | - * Carrier repository. | |
| 50 | + * Weight calculator. | |
| 36 | 51 | * |
| 37 | - * @var Carrier\Repository Carrier repository. | |
| 52 | + * @var WeightCalculator | |
| 38 | 53 | */ |
| 39 | - private $carrierRepository; | |
| 54 | + private $calculator; | |
| 40 | 55 | |
| 41 | 56 | /** |
| 42 | - * Weight calculator. | |
| 57 | + * Customs declaration repository. | |
| 43 | 58 | * |
| 44 | - * @var Calculator | |
| 59 | + * @var CustomsDeclaration\Repository | |
| 45 | 60 | */ |
| 46 | - private $calculator; | |
| 61 | + private $customsDeclarationRepository; | |
| 47 | 62 | |
| 48 | 63 | /** |
| 49 | - * Order constructor. | |
| 64 | + * Internal pickup points config. | |
| 50 | 65 | * |
| 51 | - * @param Provider $optionsProvider Options Provider. | |
| 52 | - * @param Carrier\Repository $carrierRepository Carrier repository. | |
| 53 | - * @param Calculator $calculator Weight calculator. | |
| 66 | + * @var PacketaPickupPointsConfig | |
| 54 | 67 | */ |
| 68 | + private $pickupPointsConfig; | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * CoreHelper. | |
| 72 | + * | |
| 73 | + * @var CoreHelper | |
| 74 | + */ | |
| 75 | + private $coreHelper; | |
| 76 | + | |
| 77 | + /** | |
| 78 | + * Payment helper. | |
| 79 | + * | |
| 80 | + * @var PaymentHelper | |
| 81 | + */ | |
| 82 | + private $paymentHelper; | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * Carrier repository. | |
| 86 | + * | |
| 87 | + * @var Carrier\EntityRepository | |
| 88 | + */ | |
| 89 | + private $carrierRepository; | |
| 90 | + | |
| 91 | + /** | |
| 92 | + * Builder constructor. | |
| 93 | + * | |
| 94 | + * @param OptionsProvider $optionsProvider Options Provider. | |
| 95 | + * @param WeightCalculator $calculator Weight calculator. | |
| 96 | + * @param CustomsDeclaration\Repository $customsDeclarationRepository Customs declaration repository. | |
| 97 | + * @param PacketaPickupPointsConfig $pickupPointsConfig Internal pickup points config. | |
| 98 | + * @param CoreHelper $coreHelper CoreHelper. | |
| 99 | + * @param PaymentHelper $paymentHelper Payment helper. | |
| 100 | + * @param Carrier\EntityRepository $carrierRepository Carrier repository. | |
| 101 | + */ | |
| 55 | 102 | public function __construct( |
| 56 | - Provider $optionsProvider, | |
| 57 | - Carrier\Repository $carrierRepository, | |
| 58 | - Calculator $calculator | |
| 103 | + OptionsProvider $optionsProvider, | |
| 104 | + WeightCalculator $calculator, | |
| 105 | + CustomsDeclaration\Repository $customsDeclarationRepository, | |
| 106 | + PacketaPickupPointsConfig $pickupPointsConfig, | |
| 107 | + CoreHelper $coreHelper, | |
| 108 | + PaymentHelper $paymentHelper, | |
| 109 | + Carrier\EntityRepository $carrierRepository | |
| 59 | 110 | ) { |
| 60 | - $this->optionsProvider = $optionsProvider; | |
| 61 | - $this->carrierRepository = $carrierRepository; | |
| 62 | - $this->calculator = $calculator; | |
| 111 | + $this->optionsProvider = $optionsProvider; | |
| 112 | + $this->calculator = $calculator; | |
| 113 | + $this->customsDeclarationRepository = $customsDeclarationRepository; | |
| 114 | + $this->pickupPointsConfig = $pickupPointsConfig; | |
| 115 | + $this->coreHelper = $coreHelper; | |
| 116 | + $this->paymentHelper = $paymentHelper; | |
| 117 | + $this->carrierRepository = $carrierRepository; | |
| 63 | 118 | } |
| 64 | 119 | |
| 65 | 120 | /** |
| 66 | - * Creates common order entity from WC_Order. | |
| 121 | + * Creates order entity from WC_Order and plugin data. | |
| 67 | 122 | * |
| 68 | - * @param WC_Order $wcOrder WC_Order. | |
| 69 | - * @param Entity\Order $order Partial order. | |
| 123 | + * @param WC_Order $wcOrder WC_Order. | |
| 124 | + * @param stdClass $result Db result, plugin specific data. | |
| 70 | 125 | * |
| 71 | 126 | * @return Entity\Order |
| 127 | + * @throws InvalidCarrierException In case Carrier entity could not be created. | |
| 72 | 128 | */ |
| 73 | - public function finalize( WC_Order $wcOrder, Entity\Order $order ): Entity\Order { | |
| 129 | + public function build( WC_Order $wcOrder, stdClass $result ): Entity\Order { | |
| 130 | + $country = ModuleHelper::getWcOrderCountry( $wcOrder ); | |
| 131 | + if ( $country === '' ) { | |
| 132 | + throw new InvalidCarrierException( __( 'Please set the country of the delivery address first.', 'packeta' ) ); | |
| 133 | + } | |
| 134 | + | |
| 135 | + $carrierId = $this->pickupPointsConfig->getFixedCarrierId( $result->carrier_id, $country ); | |
| 136 | + $carrier = $this->carrierRepository->getAnyById( $carrierId ); | |
| 137 | + if ( $carrier === null ) { | |
| 138 | + throw new InvalidCarrierException( | |
| 139 | + sprintf( | |
| 140 | + // translators: %s is carrier id. | |
| 141 | + __( 'Order carrier is invalid (%s). Please contact Packeta support.', 'packeta' ), | |
| 142 | + $carrierId | |
| 143 | + ) | |
| 144 | + ); | |
| 145 | + } | |
| 146 | + | |
| 147 | + $order = new Order( $result->id, $carrier ); | |
| 148 | + $orderWeight = $this->parseFloat( $result->weight ); | |
| 149 | + if ( $orderWeight !== null ) { | |
| 150 | + $order->setWeight( $orderWeight ); | |
| 151 | + } | |
| 152 | + $order->setPacketId( $result->packet_id ); | |
| 153 | + $order->setPacketTrackingUrl( $this->coreHelper->getTrackingUrl( $result->packet_id ) ); | |
| 154 | + $order->setPacketClaimId( $result->packet_claim_id ); | |
| 155 | + $order->setPacketClaimTrackingUrl( $this->coreHelper->getTrackingUrl( $result->packet_claim_id ) ); | |
| 156 | + $order->setPacketClaimPassword( $result->packet_claim_password ); | |
| 157 | + $order->setSize( new Size( $this->parseFloat( $result->length ), $this->parseFloat( $result->width ), $this->parseFloat( $result->height ) ) ); | |
| 158 | + $order->setIsExported( (bool) $result->is_exported ); | |
| 159 | + $order->setIsLabelPrinted( (bool) $result->is_label_printed ); | |
| 160 | + $order->setCarrierNumber( $result->carrier_number ); | |
| 161 | + $order->setPacketStatus( $result->packet_status ); | |
| 162 | + $order->setStoredUntil( $this->coreHelper->getDateTimeFromString( $result->stored_until ) ); | |
| 163 | + $order->setAddressValidated( (bool) $result->address_validated ); | |
| 164 | + $order->setAdultContent( $this->parseBool( $result->adult_content ) ); | |
| 165 | + $order->setManualValue( $this->parseFloat( $result->value ) ); | |
| 166 | + $order->setManualCod( $this->parseFloat( $result->cod ) ); | |
| 167 | + $order->setDeliverOn( $this->coreHelper->getDateTimeFromString( $result->deliver_on ) ); | |
| 168 | + $order->setLastApiErrorMessage( $result->api_error_message ); | |
| 169 | + $order->setLastApiErrorDateTime( | |
| 170 | + ( $result->api_error_date === null ) | |
| 171 | + ? null | |
| 172 | + : DateTimeImmutable::createFromFormat( | |
| 173 | + CoreHelper::MYSQL_DATETIME_FORMAT, | |
| 174 | + $result->api_error_date, | |
| 175 | + new DateTimeZone( 'UTC' ) | |
| 176 | + )->setTimezone( wp_timezone() ) | |
| 177 | + ); | |
| 178 | + | |
| 179 | + if ( $result->delivery_address ) { | |
| 180 | + $deliveryAddressDecoded = json_decode( $result->delivery_address, false ); | |
| 181 | + $deliveryAddress = new Address( | |
| 182 | + $deliveryAddressDecoded->street, | |
| 183 | + $deliveryAddressDecoded->city, | |
| 184 | + $deliveryAddressDecoded->zip | |
| 185 | + ); | |
| 186 | + | |
| 187 | + $deliveryAddress->setHouseNumber( $deliveryAddressDecoded->houseNumber ); | |
| 188 | + $deliveryAddress->setLongitude( $deliveryAddressDecoded->longitude ); | |
| 189 | + $deliveryAddress->setLatitude( $deliveryAddressDecoded->latitude ); | |
| 190 | + $deliveryAddress->setCounty( $deliveryAddressDecoded->county ); | |
| 191 | + | |
| 192 | + $order->setDeliveryAddress( $deliveryAddress ); | |
| 193 | + } | |
| 194 | + | |
| 195 | + if ( $result->car_delivery_id ) { | |
| 196 | + $order->setCarDeliveryId( $result->car_delivery_id ); | |
| 197 | + } | |
| 198 | + | |
| 199 | + if ( $result->point_id !== null ) { | |
| 200 | + $pickUpPoint = new PickupPoint( | |
| 201 | + $result->point_id, | |
| 202 | + $result->point_name, | |
| 203 | + $result->point_city, | |
| 204 | + $result->point_zip, | |
| 205 | + $result->point_street, | |
| 206 | + $result->point_url | |
| 207 | + ); | |
| 208 | + | |
| 209 | + $order->setPickupPoint( $pickUpPoint ); | |
| 210 | + } | |
| 211 | + | |
| 74 | 212 | $order->setCalculatedWeight( $this->calculator->calculateOrderWeight( $wcOrder ) ); |
| 75 | 213 | |
| 76 | - if ( null === $order->containsAdultContent() ) { | |
| 214 | + if ( $order->containsAdultContent() === null ) { | |
| 77 | 215 | $order->setAdultContent( $this->containsAdultContent( $wcOrder ) ); |
| 78 | 216 | } |
| 79 | 217 | |
| 80 | - $order->setShippingCountry( strtolower( $wcOrder->get_shipping_country() ) ); | |
| 218 | + $order->setShippingCountry( ModuleHelper::getWcOrderCountry( $wcOrder ) ); | |
| 81 | 219 | |
| 82 | 220 | $orderData = $wcOrder->get_data(); |
| 83 | 221 | $contactInfo = ( $wcOrder->has_shipping_address() ? $orderData['shipping'] : $orderData['billing'] ); |
| 84 | 222 | |
| @@ -85,14 +223,12 @@ | ||
| 85 | 223 | $order->setName( $contactInfo['first_name'] ); |
| 86 | 224 | $order->setSurname( $contactInfo['last_name'] ); |
| 87 | 225 | $order->setEshop( $this->optionsProvider->get_sender() ); |
| 88 | 226 | |
| 89 | - if ( null === $order->getValue() ) { | |
| 90 | - $order->setValue( (float) $wcOrder->get_total( 'raw' ) ); | |
| 91 | - } | |
| 227 | + $order->setCalculatedValue( (float) $wcOrder->get_total( 'raw' ) ); | |
| 92 | 228 | |
| 93 | 229 | $address = $order->getDeliveryAddress(); |
| 94 | - if ( null === $address ) { | |
| 230 | + if ( $address === null ) { | |
| 95 | 231 | $order->setAddressValidated( false ); |
| 96 | 232 | $address = new Address( $contactInfo['address_1'], $contactInfo['city'], $contactInfo['postcode'] ); |
| 97 | 233 | } |
| 98 | 234 | |
| @@ -100,35 +236,31 @@ | ||
| 100 | 236 | $order->setCustomNumber( $wcOrder->get_order_number() ); |
| 101 | 237 | |
| 102 | 238 | // Shipping address phone is optional. |
| 103 | 239 | $order->setPhone( $orderData['billing']['phone'] ); |
| 104 | - if ( ! empty( $contactInfo['phone'] ) ) { | |
| 240 | + if ( isset( $contactInfo['phone'] ) && $contactInfo['phone'] !== '' ) { | |
| 105 | 241 | $order->setPhone( $contactInfo['phone'] ); |
| 106 | 242 | } |
| 107 | 243 | // Additional address information. |
| 108 | - if ( ! empty( $contactInfo['address_2'] ) ) { | |
| 244 | + if ( isset( $contactInfo['address_2'] ) && $contactInfo['address_2'] !== '' ) { | |
| 109 | 245 | $order->setNote( $contactInfo['address_2'] ); |
| 110 | 246 | } |
| 111 | 247 | |
| 112 | 248 | $order->setEmail( $orderData['billing']['email'] ); |
| 113 | - $codMethod = $this->optionsProvider->getCodPaymentMethod(); | |
| 114 | - if ( null === $order->getCod() && $orderData['payment_method'] === $codMethod ) { | |
| 115 | - $order->setCod( $order->getValue() ); | |
| 249 | + $hasCodPaymentMethod = $this->paymentHelper->isCodPaymentMethod( $orderData['payment_method'] ); | |
| 250 | + if ( $hasCodPaymentMethod ) { | |
| 251 | + $order->setCalculatedCod( $order->getCalculatedValue() ); | |
| 252 | + // manual COD is set from DB directly | |
| 253 | + } else { | |
| 254 | + $order->setCalculatedCod( null ); | |
| 255 | + $order->setManualCod( null ); | |
| 116 | 256 | } |
| 117 | 257 | |
| 118 | - if ( $orderData['payment_method'] !== $codMethod ) { | |
| 119 | - $order->setCod( null ); | |
| 120 | - } | |
| 121 | - | |
| 122 | 258 | $order->setSize( $order->getSize() ); |
| 259 | + $order->setCurrency( $wcOrder->get_currency() ); | |
| 123 | 260 | |
| 124 | - if ( $order->isExternalCarrier() ) { | |
| 125 | - $carrier = $this->carrierRepository->getById( (int) $order->getCarrierId() ); | |
| 126 | - $order->setCarrier( $carrier ); | |
| 127 | - } | |
| 261 | + $order->setCustomsDeclaration( $this->customsDeclarationRepository->getByOrderNumber( $order->getNumber() ) ); | |
| 128 | 262 | |
| 129 | - $order->setCurrency( $wcOrder->get_currency() ); | |
| 130 | - | |
| 131 | 263 | return $order; |
| 132 | 264 | } |
| 133 | 265 | |
| 134 | 266 | /** |
| @@ -139,13 +271,15 @@ | ||
| 139 | 271 | * @return bool |
| 140 | 272 | */ |
| 141 | 273 | private function containsAdultContent( WC_Order $wcOrder ): bool { |
| 142 | 274 | foreach ( $wcOrder->get_items() as $item ) { |
| 143 | - $product = $item->get_product(); | |
| 144 | - if ( $product ) { | |
| 145 | - $productEntity = new Product\Entity( $product ); | |
| 146 | - if ( $productEntity->isPhysical() && $productEntity->isAgeVerification18PlusRequired() ) { | |
| 147 | - return true; | |
| 275 | + if ( $item instanceof WC_Order_Item_Product ) { | |
| 276 | + $product = $item->get_product(); | |
| 277 | + if ( $product instanceof WC_Product ) { | |
| 278 | + $productEntity = new Product\Entity( $product ); | |
| 279 | + if ( $productEntity->isPhysical() && $productEntity->isAgeVerificationRequired() ) { | |
| 280 | + return true; | |
| 281 | + } | |
| 148 | 282 | } |
| 149 | 283 | } |
| 150 | 284 | } |
| 151 | 285 | |
| @@ -151,5 +285,34 @@ | ||
| 151 | 285 | |
| 152 | 286 | return false; |
| 153 | 287 | } |
| 154 | 288 | |
| 289 | + /** | |
| 290 | + * Parses string value as float. | |
| 291 | + * | |
| 292 | + * @param string|float|null $value Value. | |
| 293 | + * | |
| 294 | + * @return float|null | |
| 295 | + */ | |
| 296 | + private function parseFloat( $value ): ?float { | |
| 297 | + if ( $value === null || $value === '' ) { | |
| 298 | + return null; | |
| 299 | + } | |
| 300 | + | |
| 301 | + return (float) $value; | |
| 302 | + } | |
| 303 | + | |
| 304 | + /** | |
| 305 | + * Parses string value as float. | |
| 306 | + * | |
| 307 | + * @param string|int|null $value Value. | |
| 308 | + * | |
| 309 | + * @return bool|null | |
| 310 | + */ | |
| 311 | + private function parseBool( $value ): ?bool { | |
| 312 | + if ( $value === null || $value === '' ) { | |
| 313 | + return null; | |
| 314 | + } | |
| 315 | + | |
| 316 | + return (bool) $value; | |
| 317 | + } | |
| 155 | 318 | } |