1<?php 2/** 3 * Copyright since 2007 PrestaShop SA and Contributors 4 * PrestaShop is an International Registered Trademark & Property of PrestaShop SA 5 * 6 * NOTICE OF LICENSE 7 * 8 * This source file is subject to the Open Software License (OSL 3.0) 9 * that is bundled with this package in the file LICENSE.md. 10 * It is also available through the world-wide-web at this URL: 11 * https://opensource.org/licenses/OSL-3.0 12 * If you did not receive a copy of the license and are unable to 13 * obtain it through the world-wide-web, please send an email 14 * to license@prestashop.com so we can send you a copy immediately. 15 * 16 * DISCLAIMER 17 * 18 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer 19 * versions in the future. If you wish to customize PrestaShop for your 20 * needs please refer to https://devdocs.prestashop.com/ for more information. 21 * 22 * @author PrestaShop SA and Contributors <contact@prestashop.com> 23 * @copyright Since 2007 PrestaShop SA and Contributors 24 * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) 25 */ 26 27namespace PrestaShop\PrestaShop\Adapter\Presenter\Order; 28 29use Address; 30use AddressFormat; 31use Carrier; 32use Cart; 33use Configuration; 34use Context; 35use Currency; 36use CustomerMessage; 37use Doctrine\Common\Annotations\AnnotationException; 38use Order; 39use OrderReturn; 40use PrestaShop\PrestaShop\Adapter\Presenter\AbstractLazyArray; 41use PrestaShop\PrestaShop\Adapter\Presenter\Cart\CartPresenter; 42use PrestaShop\PrestaShop\Adapter\Presenter\Object\ObjectPresenter; 43use PrestaShop\PrestaShop\Adapter\Product\PriceFormatter; 44use PrestaShopBundle\Translation\TranslatorComponent; 45use PrestaShopException; 46use ProductDownload; 47use ReflectionException; 48use TaxConfiguration; 49use Tools; 50 51class OrderLazyArray extends AbstractLazyArray 52{ 53 /** @var CartPresenter */ 54 private $cartPresenter; 55 56 /** @var ObjectPresenter */ 57 private $objectPresenter; 58 59 /** @var PriceFormatter */ 60 private $priceFormatter; 61 62 /** @var TranslatorComponent */ 63 private $translator; 64 65 /** @var TaxConfiguration */ 66 private $taxConfiguration; 67 68 /** @var Order */ 69 private $order; 70 71 /** @var OrderSubtotalLazyArray */ 72 private $subTotals; 73 74 /** 75 * OrderArray constructor. 76 * 77 * @throws AnnotationException 78 * @throws ReflectionException 79 */ 80 public function __construct(Order $order) 81 { 82 $this->order = $order; 83 $this->cartPresenter = new CartPresenter(); 84 $this->objectPresenter = new ObjectPresenter(); 85 $this->priceFormatter = new PriceFormatter(); 86 $this->translator = Context::getContext()->getTranslator(); 87 $this->taxConfiguration = new TaxConfiguration(); 88 $this->subTotals = new OrderSubtotalLazyArray($this->order); 89 parent::__construct(); 90 } 91 92 /** 93 * @arrayAccess 94 * 95 * @return mixed 96 */ 97 public function getTotals() 98 { 99 $amounts = $this->getAmounts(); 100 101 return $amounts['totals']; 102 } 103 104 /** 105 * @arrayAccess 106 * 107 * @return int 108 */ 109 public function getIdAddressInvoice() 110 { 111 return $this->order->id_address_invoice; 112 } 113 114 /** 115 * @arrayAccess 116 * 117 * @return int 118 */ 119 public function getIdAddressDelivery() 120 { 121 return $this->order->id_address_delivery; 122 } 123 124 /** 125 * @arrayAccess 126 * 127 * @return mixed 128 */ 129 public function getSubtotals() 130 { 131 return $this->subTotals; 132 } 133 134 /** 135 * @arrayAccess 136 * 137 * @return int 138 */ 139 public function getProductsCount() 140 { 141 return count($this->getProducts()); 142 } 143 144 /** 145 * @arrayAccess 146 * 147 * @return mixed 148 * 149 * @throws PrestaShopException 150 */ 151 public function getShipping() 152 { 153 $details = $this->getDetails(); 154 155 return $details['shipping']; 156 } 157 158 /** 159 * @arrayAccess 160 * 161 * @return array 162 */ 163 public function getProducts() 164 { 165 $order = $this->order; 166 $cart = new Cart($order->id_cart); 167 168 $orderProducts = $order->getProducts(); 169 $cartProducts = $this->cartPresenter->present($cart); 170 $orderPaid = $order->getCurrentOrderState() && $order->getCurrentOrderState()->paid; 171 172 $includeTaxes = $this->includeTaxes(); 173 foreach ($orderProducts as &$orderProduct) { 174 // Use data from OrderDetail in case that the Product has been deleted 175 $orderProduct['name'] = $orderProduct['product_name']; 176 $orderProduct['quantity'] = $orderProduct['product_quantity']; 177 $orderProduct['id_product'] = $orderProduct['product_id']; 178 $orderProduct['id_product_attribute'] = $orderProduct['product_attribute_id']; 179 180 $productPrice = $includeTaxes ? 'product_price_wt' : 'product_price'; 181 $totalPrice = $includeTaxes ? 'total_wt' : 'total_price'; 182 183 $orderProduct['price'] = $this->priceFormatter->format( 184 $orderProduct[$productPrice], 185 Currency::getCurrencyInstance((int) $order->id_currency) 186 ); 187 $orderProduct['total'] = $this->priceFormatter->format( 188 $orderProduct[$totalPrice], 189 Currency::getCurrencyInstance((int) $order->id_currency) 190 ); 191 192 if ($orderPaid && $orderProduct['is_virtual']) { 193 $id_product_download = ProductDownload::getIdFromIdProduct($orderProduct['product_id']); 194 $product_download = new ProductDownload($id_product_download); 195 if ($product_download->display_filename != '') { 196 $orderProduct['download_link'] = 197 $product_download->getTextLink(false, $orderProduct['download_hash']) 198 . '&id_order=' . (int) $order->id 199 . '&secure_key=' . $order->secure_key; 200 } 201 } 202 203 foreach ($cartProducts['products'] as $cartProduct) { 204 if (($cartProduct['id_product'] === $orderProduct['id_product']) 205 && ($cartProduct['id_product_attribute'] === $orderProduct['id_product_attribute']) 206 ) { 207 if (isset($cartProduct['attributes'])) { 208 $orderProduct['attributes'] = $cartProduct['attributes']; 209 } else { 210 $orderProduct['attributes'] = []; 211 } 212 $orderProduct['cover'] = $cartProduct['cover']; 213 $orderProduct['default_image'] = $cartProduct['default_image']; 214 $orderProduct['unit_price_full'] = $cartProduct['unit_price_full']; 215 break; 216 } 217 } 218 219 OrderReturn::addReturnedQuantity($orderProducts, $order->id); 220 } 221 222 $orderProducts = $this->cartPresenter->addCustomizedData($orderProducts, $cart); 223 224 return $orderProducts; 225 } 226 227 /** 228 * @arrayAccess 229 * 230 * @return array 231 */ 232 public function getAmounts() 233 { 234 $order = $this->order; 235 236 $amounts['subtotals'] = $this->subTotals; 237 238 $amounts['totals'] = []; 239 $amount = $this->includeTaxes() ? $order->total_paid : $order->total_paid_tax_excl; 240 $amounts['totals']['total'] = [ 241 'type' => 'total', 242 'label' => $this->translator->trans('Total', [], 'Shop.Theme.Checkout'), 243 'amount' => $amount, 244 'value' => $this->priceFormatter->format($amount, Currency::getCurrencyInstance((int) $order->id_currency)), 245 ]; 246 247 $amounts['totals']['total_paid'] = [ 248 'type' => 'total_paid', 249 'label' => $this->translator->trans('Total paid', [], 'Shop.Theme.Checkout'), 250 'amount' => $order->total_paid_real, 251 'value' => $this->priceFormatter->format( 252 $order->total_paid_real, 253 Currency::getCurrencyInstance((int) $order->id_currency) 254 ), 255 ]; 256 257 $amounts['totals']['total_including_tax'] = [ 258 'type' => 'total_including_tax', 259 'label' => $this->translator->trans('Total (tax incl.)', [], 'Shop.Theme.Checkout'), 260 'amount' => $order->total_paid_tax_incl, 261 'value' => $this->priceFormatter->format( 262 $order->total_paid_tax_incl, 263 Currency::getCurrencyInstance((int) $order->id_currency) 264 ), 265 ]; 266 267 $amounts['totals']['total_excluding_tax'] = [ 268 'type' => 'total_excluding_tax', 269 'label' => $this->translator->trans('Total (tax excl.)', [], 'Shop.Theme.Checkout'), 270 'amount' => $order->total_paid_tax_excl, 271 'value' => $this->priceFormatter->format( 272 $order->total_paid_tax_excl, 273 Currency::getCurrencyInstance((int) $order->id_currency) 274 ), 275 ]; 276 277 return $amounts; 278 } 279 280 /** 281 * @arrayAccess 282 * 283 * @return OrderDetailLazyArray 284 */ 285 public function getDetails() 286 { 287 return new OrderDetailLazyArray($this->order); 288 } 289 290 /** 291 * @arrayAccess 292 * 293 * @return array 294 */ 295 public function getHistory() 296 { 297 $order = $this->order; 298 299 $orderHistory = []; 300 $context = Context::getContext(); 301 $historyList = $order->getHistory($context->language->id, false, true); 302 303 foreach ($historyList as $historyId => $history) { 304 // HistoryList only contains order states that are not hidden to customers, the last visible order state, 305 // that is to say the one we get in the first iteration 306 if ($historyId === array_key_first($historyList)) { 307 $historyId = 'current'; 308 } 309 $orderHistory[$historyId] = $history; 310 $orderHistory[$historyId]['history_date'] = Tools::displayDate($history['date_add'], null, false); 311 $orderHistory[$historyId]['contrast'] = (Tools::getBrightness($history['color']) > 128) ? 'dark' : 'bright'; 312 } 313 314 if (!isset($orderHistory['current'])) { 315 $orderHistory['current'] = $this->getDefaultHistory(); 316 } 317 318 return $orderHistory; 319 } 320 321 /** 322 * @arrayAccess 323 * 324 * @return array 325 */ 326 public function getMessages() 327 { 328 $order = $this->order; 329 330 $messages = []; 331 $customerMessages = CustomerMessage::getMessagesByOrderId((int) $order->id, false); 332 333 foreach ($customerMessages as $cmId => $customerMessage) { 334 $messages[$cmId] = $customerMessage; 335 $messages[$cmId]['message'] = nl2br($customerMessage['message']); 336 $messages[$cmId]['message_date'] = Tools::displayDate($customerMessage['date_add'], null, true); 337 if (isset($customerMessage['elastname']) && $customerMessage['elastname']) { 338 $messages[$cmId]['name'] = $customerMessage['efirstname'] . ' ' . $customerMessage['elastname']; 339 } elseif ($customerMessage['clastname']) { 340 $messages[$cmId]['name'] = $customerMessage['cfirstname'] . ' ' . $customerMessage['clastname']; 341 } else { 342 $messages[$cmId]['name'] = Configuration::get('PS_SHOP_NAME'); 343 } 344 } 345 346 return $messages; 347 } 348 349 /** 350 * @arrayAccess 351 * 352 * @return array 353 */ 354 public function getCarrier() 355 { 356 $order = $this->order; 357 358 $carrier = new Carrier((int) $order->id_carrier, (int) $order->getAssociatedLanguage()->getId()); 359 $orderCarrier = $this->objectPresenter->present($carrier); 360 $orderCarrier['name'] = ($carrier->name == '0') ? Configuration::get('PS_SHOP_NAME') : $carrier->name; 361 $orderCarrier['delay'] = $carrier->delay; 362 363 return $orderCarrier; 364 } 365 366 /** 367 * @arrayAccess 368 * 369 * @return array 370 */ 371 public function getAddresses() 372 { 373 $order = $this->order; 374 375 $orderAddresses = [ 376 'delivery' => [], 377 'invoice' => [], 378 ]; 379 380 $addressDelivery = new Address((int) $order->id_address_delivery); 381 $addressInvoice = new Address((int) $order->id_address_invoice); 382 383 if (!$order->isVirtual()) { 384 $orderAddresses['delivery'] = $this->objectPresenter->present($addressDelivery); 385 $orderAddresses['delivery']['formatted'] = 386 AddressFormat::generateAddress($addressDelivery, [], '<br />'); 387 } 388 389 $orderAddresses['invoice'] = $this->objectPresenter->present($addressInvoice); 390 $orderAddresses['invoice']['formatted'] = AddressFormat::generateAddress($addressInvoice, [], '<br />'); 391 392 return $orderAddresses; 393 } 394 395 /** 396 * @arrayAccess 397 * 398 * @return string 399 */ 400 public function getFollowUp() 401 { 402 $order = $this->order; 403 404 $carrier = $this->getCarrier(); 405 if (!empty($carrier['url']) && !empty($order->shipping_number)) { 406 return str_replace('@', $order->shipping_number, $carrier['url']); 407 } 408 409 return ''; 410 } 411 412 /** 413 * @arrayAccess 414 * 415 * @return array 416 */ 417 public function getLabels() 418 { 419 return [ 420 'tax_short' => ($this->includeTaxes()) 421 ? $this->translator->trans('(tax incl.)', [], 'Shop.Theme.Global') 422 : $this->translator->trans('(tax excl.)', [], 'Shop.Theme.Global'), 423 'tax_long' => ($this->includeTaxes()) 424 ? $this->translator->trans('(tax included)', [], 'Shop.Theme.Global') 425 : $this->translator->trans('(tax excluded)', [], 'Shop.Theme.Global'), 426 ]; 427 } 428 429 /** 430 * @return bool|mixed 431 */ 432 private function includeTaxes() 433 { 434 return $this->taxConfiguration->includeTaxes(); 435 } 436 437 /** 438 * @return array 439 */ 440 private function getDefaultHistory() 441 { 442 return [ 443 'id_order_state' => '', 444 'invoice' => '', 445 'send_email' => '', 446 'module_name' => '', 447 'color' => '', 448 'unremovable' => '', 449 'hidden' => '', 450 'loggable' => '', 451 'delivery' => '', 452 'shipped' => '', 453 'paid' => '', 454 'pdf_invoice' => '', 455 'pdf_delivery' => '', 456 'deleted' => '', 457 'id_order_history' => '', 458 'id_employee' => '', 459 'id_order' => '', 460 'date_add' => '', 461 'employee_firstname' => '', 462 'employee_lastname' => '', 463 'ostate_name' => '', 464 'history_date' => '', 465 'contrast' => '', 466 ]; 467 } 468} 469