PluginProbe
Packeta / 2.3.2
Packeta v2.3.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 / CarrierModal.php

CarrierModal.php in Packeta 2.3.2, at src/Packetery/Module/Order/CarrierModal.php

346 lines 8.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class CarrierModal.
4 *
5 * @package Packetery
6 */
7
8 declare( strict_types=1 );
9
10 namespace Packetery\Module\Order;
11
12 use Packetery\Latte;
13 use Packetery\Module\Carrier;
14 use Packetery\Module\Carrier\CarrierOptionsFactory;
15 use Packetery\Module\Framework\WpAdapter;
16 use Packetery\Module\MessageManager;
17 use Packetery\Module\ModuleHelper;
18 use Packetery\Module\Options\OptionsProvider;
19 use Packetery\Nette\Forms;
20 use Packetery\Nette\Forms\Controls\SubmitButton;
21 use RuntimeException;
22 use WC_Order_Item_Shipping;
23
24 /**
25 * Class CarrierModal.
26 *
27 * @package Packetery
28 */
29 class CarrierModal {
30
31 public const MODAL_ID = 'wc-packetery-carrier-modal';
32
33 /**
34 * Latte engine.
35 *
36 * @var Latte\Engine
37 */
38 private $latteEngine;
39
40 /**
41 * Order detail common logic.
42 *
43 * @var DetailCommonLogic
44 */
45 private $detailCommonLogic;
46
47 /**
48 * Order repository.
49 *
50 * @var CarrierModalFormFactory
51 */
52 private $carrierModalFormFactory;
53
54 /**
55 * Carrier repository.
56 *
57 * @var Carrier\EntityRepository
58 */
59 private $carrierRepository;
60
61 /**
62 * Order repository.
63 *
64 * @var Repository
65 */
66 private $orderRepository;
67
68 /**
69 * @var OptionsProvider
70 */
71 private $optionsProvider;
72
73 /**
74 * Carrier options factory.
75 *
76 * @var CarrierOptionsFactory
77 */
78 private $carrierOptionsFactory;
79
80 /**
81 * @var MessageManager
82 */
83 private $messageManager;
84
85 /**
86 * @var WpAdapter
87 */
88 private $wpAdapter;
89
90 public function __construct(
91 Latte\Engine $latteEngine,
92 DetailCommonLogic $detailCommonLogic,
93 CarrierModalFormFactory $carrierModalFormFactory,
94 Repository $orderRepository,
95 Carrier\EntityRepository $carrierRepository,
96 OptionsProvider $optionsProvider,
97 CarrierOptionsFactory $carrierOptionsFactory,
98 MessageManager $messageManager,
99 WpAdapter $wpAdapter
100 ) {
101 $this->latteEngine = $latteEngine;
102 $this->detailCommonLogic = $detailCommonLogic;
103 $this->carrierModalFormFactory = $carrierModalFormFactory;
104 $this->orderRepository = $orderRepository;
105 $this->carrierRepository = $carrierRepository;
106 $this->optionsProvider = $optionsProvider;
107 $this->carrierOptionsFactory = $carrierOptionsFactory;
108 $this->messageManager = $messageManager;
109 $this->wpAdapter = $wpAdapter;
110 }
111
112 /**
113 * Registers order modal.
114 *
115 * @return void
116 */
117 public function register(): void {
118 add_action( 'admin_head', [ $this, 'renderCarrierModal' ] );
119 }
120
121 /**
122 * Renders modal.
123 *
124 * @return void
125 */
126 public function renderCarrierModal(): void {
127 if (
128 $this->detailCommonLogic->isPacketeryOrder() === false ||
129 $this->canBeDisplayed() === false
130 ) {
131 return;
132 }
133
134 $form = $this->carrierModalFormFactory->create(
135 $this->getCarrierOptionsByCountry(),
136 $this->getCurrentCarrier()
137 );
138 $form->onSuccess[] = [ $this, 'onFormSuccess' ];
139
140 $submitButton = $form['submit'];
141 if ( $submitButton instanceof SubmitButton && $submitButton->isSubmittedBy() ) {
142 $form->fireEvents();
143 }
144
145 $this->latteEngine->render(
146 PACKETERY_PLUGIN_DIR . '/template/order/carrier-modal.latte',
147 [
148 'id' => self::MODAL_ID,
149 'form' => $form,
150 'translations' => [
151 'header' => __( 'Set carrier', 'packeta' ),
152 'closeModalPanel' => __( 'Close modal panel', 'packeta' ),
153 ],
154 ]
155 );
156 }
157
158 /**
159 * On form success.
160 *
161 * @param Forms\Form $form Form.
162 *
163 * @return void
164 *
165 * @throws RuntimeException In case carrier id could not be obtained.
166 */
167 public function onFormSuccess( Forms\Form $form ): void {
168 $values = $form->getValues();
169 $orderId = $this->detailCommonLogic->getOrderId();
170 $newCarrierId = (string) $values[ CarrierModalFormFactory::FIELD_CARRIER_ID ];
171 if ( $orderId === null ) {
172 throw new RuntimeException( 'Packeta: Failed to process carrier change, new carrier id ' . $newCarrierId );
173 }
174
175 $order = $this->detailCommonLogic->getOrder();
176 if ( $order !== null && $order->getCarrier()->getId() !== $newCarrierId ) {
177 $deletionSuccess = $this->orderRepository->delete( (int) $order->getNumber() );
178 if ( $deletionSuccess === false ) {
179 $this->messageManager->flash_message(
180 (string) $this->wpAdapter->__( 'An error occurred while deleting the order. More details in WC log.', 'packeta' ),
181 MessageManager::TYPE_ERROR
182 );
183 }
184 }
185
186 $carrierTitle = $this->createNewCarrierOrder( $orderId, $newCarrierId );
187 $this->updateOrderDeliveryTitle( $orderId, $carrierTitle );
188
189 // Without it, the widget cannot be opened and metabox has no values. Needed even in case no change was made.
190 if ( wp_safe_redirect( ModuleHelper::getOrderDetailUrl( $orderId ) ) ) {
191 exit;
192 }
193 }
194
195 /**
196 * Saves order stub with new Carrier, if instantiable.
197 *
198 * @param int $orderId Order id.
199 * @param string $newCarrierId Carrier id.
200 *
201 * @return string
202 *
203 * @throws RuntimeException In case carrier is not instantiable.
204 */
205 private function createNewCarrierOrder( int $orderId, string $newCarrierId ): string {
206 $newCarrier = $this->carrierRepository->getAnyById( $newCarrierId );
207 if ( $newCarrier === null ) {
208 throw new RuntimeException( 'Packeta: Failed to get instance of carrier with id ' . $newCarrierId );
209 }
210 $updatedRowCount = $this->orderRepository->saveData(
211 [
212 'id' => $orderId,
213 'carrier_id' => $newCarrierId,
214 ]
215 );
216 if ( $updatedRowCount === false ) {
217 $this->messageManager->flash_message(
218 (string) $this->wpAdapter->__( 'An error occurred while saving the order. More details in WC log.', 'packeta' ),
219 MessageManager::TYPE_ERROR
220 );
221 }
222
223 $options = $this->carrierOptionsFactory->createByCarrierId( $newCarrier->getId() );
224 if ( ! $options->hasOptions() ) {
225 throw new RuntimeException( 'Missing options for carrier ' . $newCarrier->getId() );
226 }
227
228 return $options->getName();
229 }
230
231 /**
232 * Gets carrier names by the country of destination.
233 *
234 * @return string[]
235 */
236 private function getCarrierOptionsByCountry(): array {
237 static $carrierOptions;
238
239 if ( isset( $carrierOptions ) ) {
240 return $carrierOptions;
241 }
242
243 $wcOrderId = $this->detailCommonLogic->getOrderId();
244 if ( $wcOrderId === null ) {
245 return [];
246 }
247
248 $wcOrder = $this->orderRepository->getWcOrderById( $wcOrderId );
249 if ( $wcOrder === null ) {
250 return [];
251 }
252
253 $shippingCountry = ModuleHelper::getWcOrderCountry( $wcOrder );
254 if ( $shippingCountry === '' ) {
255 return [];
256 }
257
258 $carriers = $this->carrierRepository->getByCountryIncludingNonFeed( $shippingCountry, false );
259
260 $carrierOptions = [];
261 foreach ( $carriers as $carrier ) {
262 $options = $this->carrierOptionsFactory->createByCarrierId( $carrier->getId() );
263 if ( $options->hasOptions() ) {
264 $carrierOptions[ $carrier->getId() ] = $options->getName();
265 }
266 }
267
268 return $carrierOptions;
269 }
270
271 /**
272 * There must be two carriers at least and no packet id.
273 *
274 * @return bool
275 */
276 public function canBeDisplayed(): bool {
277 $carrierOptions = $this->getCarrierOptionsByCountry();
278 if ( $carrierOptions === [] ) {
279 return false;
280 }
281
282 if ( $this->optionsProvider->isWcCarrierConfigEnabled() ) {
283 return false;
284 }
285
286 $order = $this->detailCommonLogic->getOrder();
287
288 return ( $order === null || $order->getPacketId() === null );
289 }
290
291 /**
292 * Gets metabox HTML with carrier selection button.
293 *
294 * @return string
295 */
296 public function getMetaboxHtml(): string {
297 return $this->latteEngine->renderToString(
298 PACKETERY_PLUGIN_DIR . '/template/order/metabox-carrier.latte',
299 [
300 'translations' => [
301 'setCarrier' => __( 'Set carrier', 'packeta' ),
302 ],
303 ]
304 );
305 }
306
307 /**
308 * Get current order carrier.
309 *
310 * @return string|null
311 */
312 private function getCurrentCarrier(): ?string {
313 $order = $this->detailCommonLogic->getOrder();
314 if ( $order === null ) {
315 return null;
316 }
317
318 return $order->getCarrier()->getId();
319 }
320
321 /**
322 * Update the delivery title of a specific order.
323 *
324 * @param int $orderId The ID of the order to update.
325 * @param string $carrierTitle The new shipping title to set.
326 *
327 * @return void
328 */
329 private function updateOrderDeliveryTitle( int $orderId, string $carrierTitle ): void {
330 $order = $this->orderRepository->getWcOrderById( $orderId );
331 if ( $order === null ) {
332 return;
333 }
334 $shippingItems = $order->get_items( 'shipping' );
335 if ( is_array( $shippingItems ) && count( $shippingItems ) > 0 ) {
336 $firstItem = reset( $shippingItems );
337 if ( $firstItem instanceof WC_Order_Item_Shipping ) {
338 $firstItem->set_method_title( $carrierTitle );
339 $firstItem->save();
340 $order->calculate_totals();
341 $order->save();
342 }
343 }
344 }
345 }
346