diff --git a/Gateway/Request/NexiCheckout/GlobalRequestBuilder.php b/Gateway/Request/NexiCheckout/GlobalRequestBuilder.php index 2b094eb..d0860e9 100644 --- a/Gateway/Request/NexiCheckout/GlobalRequestBuilder.php +++ b/Gateway/Request/NexiCheckout/GlobalRequestBuilder.php @@ -7,10 +7,14 @@ use libphonenumber\PhoneNumberUtil; use Magento\Bundle\Model\Product\Price; use Magento\Bundle\Model\Product\Type as BundleType; +use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\ConfigurableProduct\Model\Product\Type\Configurable as ConfigurableType; use Magento\Framework\Encryption\EncryptorInterface; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\UrlInterface; use Magento\Quote\Model\Quote; +use Magento\Sales\Api\Data\CreditmemoInterface; +use Magento\Sales\Api\Data\InvoiceInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Item as OrderItem; use Magento\Tax\Model\Sales\Total\Quote\CommonTaxCollector; @@ -35,6 +39,7 @@ class GlobalRequestBuilder * @param EncryptorInterface $encryptor * @param WebhookHandler $webhookHandler * @param AmountConverter $amountConverter + * @param ProductRepositoryInterface $productRepository */ public function __construct( private readonly UrlInterface $url, @@ -42,6 +47,7 @@ public function __construct( private readonly EncryptorInterface $encryptor, private readonly WebhookHandler $webhookHandler, private readonly AmountConverter $amountConverter, + private readonly ProductRepositoryInterface $productRepository ) { } @@ -185,21 +191,21 @@ public function getShippingTaxRate(Order|Quote $paymentSubject) /** * Build payload with order items data based on product type * - * @param Order|Quote $paymentSubject + * @param Order|Quote|CreditmemoInterface|InvoiceInterface $paymentSubject * * @return array */ - public function getProductsData(Order|Quote $paymentSubject): array + public function getProductsData(Order|Quote|CreditmemoInterface|InvoiceInterface $paymentSubject): array { $items = []; /** @var OrderItem|Quote\Item $item */ - foreach ($paymentSubject->getAllVisibleItems() as $item) { + foreach ($paymentSubject->getAllItems() as $item) { - if ($item->getParentItem()) { + if ($item->getParentItem() || (double)$item->getBasePrice() === 0.0) { continue; } - switch ($item->getProductType()) { + switch ($this->getProductType($item)) { case ConfigurableType::TYPE_CODE: $children = $this->getChildren($item); foreach ($children as $childItem) { @@ -275,15 +281,38 @@ private function createItemBaseData(mixed $item): array /** * Get children items of a given order item or quote item. * - * @param OrderItem|Quote\Item $item - * + * @param mixed $item * @return array|Quote\Item\AbstractItem[] */ - private function getChildren(OrderItem|Quote\Item $item): array + private function getChildren(mixed $item): array { - $children = $item instanceof OrderItem ? $item->getChildrenItems() : $item->getChildren(); + if ($item instanceof \Magento\Sales\Model\Order\Item) { + return $item->getChildrenItems(); + } + + if ($item instanceof \Magento\Quote\Model\Quote\Item\AbstractItem) { + return $item->getChildren(); + } + + if ($item instanceof \Magento\Sales\Model\Order\Invoice\Item + || $item instanceof \Magento\Sales\Model\Order\Creditmemo\Item + ) { + $orderItem = $item->getOrderItem(); + $childOrderItems = $orderItem->getChildrenItems(); + + $saleDocument = $item->getInvoice() ?? $item->getCreditmemo(); + $childrenItems = []; - return $children; + foreach ($saleDocument->getAllItems() as $saleDocChild) { + if (in_array($saleDocChild->getOrderItem(), $childOrderItems, true)) { + $childrenItems[] = $saleDocChild; + } + } + + return $childrenItems; + } + + return []; } /** @@ -319,7 +348,7 @@ private function appendPriceData(array $data, mixed $item): array $data['netTotalAmount'] = $this->amountConverter->convertToNexiAmount( $item->getBaseRowTotal() - $item->getBaseDiscountAmount() ); - $data['taxRate'] = $this->amountConverter->convertToNexiAmount($item->getTaxPercent()); + $data['taxRate'] = $this->amountConverter->convertToNexiAmount($this->getTaxRate($item)); $data['taxAmount'] = $this->amountConverter->convertToNexiAmount($item->getBaseTaxAmount()); return $data; @@ -347,4 +376,39 @@ public function buildPaymentMethodsConfiguration(Quote|Order $salesObject): arra ) ]; } + + /** + * Calculate the tax rate for a given item. + * + * @param mixed $item + * + * @return mixed + */ + private function getTaxRate(mixed $item): mixed + { + if ($item->getTaxPercent()) { + return $item->getTaxPercent(); + } + return $item->getTaxAmount() * 100 / $item->getRowTotal(); + } + + /** + * Get product type by product ID + * + * @param mixed $item + * @return string|null + */ + private function getProductType(mixed $item) : string|null + { + if ($item->getProductType()) { + return $item->getProductType(); + } + + try { + $product = $this->productRepository->getById($item->getProductId()); + return $product->getTypeId(); + } catch (NoSuchEntityException $e) { + return null; + } + } } diff --git a/Gateway/Request/NexiCheckout/SalesDocumentItemsBuilder.php b/Gateway/Request/NexiCheckout/SalesDocumentItemsBuilder.php index c985277..8eabb6e 100644 --- a/Gateway/Request/NexiCheckout/SalesDocumentItemsBuilder.php +++ b/Gateway/Request/NexiCheckout/SalesDocumentItemsBuilder.php @@ -19,10 +19,12 @@ class SalesDocumentItemsBuilder * * @param AmountConverter $amountConverter * @param StringSanitizer $stringSanitizer + * @param GlobalRequestBuilder $globalRequestBuilder */ public function __construct( private readonly AmountConverter $amountConverter, private readonly StringSanitizer $stringSanitizer, + private readonly GlobalRequestBuilder $globalRequestBuilder, ) { } @@ -35,23 +37,7 @@ public function __construct( */ public function build(CreditmemoInterface|InvoiceInterface $salesObject): array { - $items = []; - foreach ($salesObject->getAllItems() as $item) { - if ((double)$item->getBasePrice() === 0.0) { - continue; - } - $items[] = new Item( - name : $this->stringSanitizer->sanitize($item->getName()), - quantity : (float)$item->getQty(), - unit : 'pcs', - unitPrice : $this->amountConverter->convertToNexiAmount($item->getBasePrice()), - grossTotalAmount: $this->amountConverter->convertToNexiAmount($item->getBaseRowTotalInclTax()), - netTotalAmount : $this->amountConverter->convertToNexiAmount($item->getBaseRowTotal()), - reference : $this->stringSanitizer->sanitize($item->getSku()), - taxRate : $this->amountConverter->convertToNexiAmount($this->calculateTaxRate($item)), - taxAmount : $this->amountConverter->convertToNexiAmount($item->getBaseTaxAmount()), - ); - } + $items = $this->globalRequestBuilder->getProductsData($salesObject); if ($salesObject->getShippingInclTax()) { $items[] = new Item( @@ -73,18 +59,6 @@ public function build(CreditmemoInterface|InvoiceInterface $salesObject): array return $items; } - /** - * Calculate the tax rate for a given item. - * - * @param mixed $item - * - * @return mixed - */ - private function calculateTaxRate(mixed $item): mixed - { - return $item->getTaxAmount() / $item->getRowTotal() * 100; - } - /** * Calculate the shipping tax rate for a given sales object. * diff --git a/Observer/ScheduledCartValidation.php b/Observer/ScheduledCartValidation.php index 4f83e10..a1868e5 100644 --- a/Observer/ScheduledCartValidation.php +++ b/Observer/ScheduledCartValidation.php @@ -3,6 +3,7 @@ namespace Nexi\Checkout\Observer; +use Magento\Customer\Model\Session; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Exception\LocalizedException; @@ -18,10 +19,12 @@ class ScheduledCartValidation implements ObserverInterface * * @param CartRepositoryInterface $cartRepository * @param TotalConfigProvider $totalConfigProvider + * @param Session $customerSession */ public function __construct( private CartRepositoryInterface $cartRepository, - private TotalConfigProvider $totalConfigProvider + private TotalConfigProvider $totalConfigProvider, + private Session $customerSession ) { } @@ -46,6 +49,10 @@ public function execute(Observer $observer) ->getProduct() ->getCustomAttribute(PreventDifferentScheduledCart::SCHEDULE_CODE); + if (!$this->customerSession->isLoggedIn() && $cartItemSchedule) { + throw new LocalizedException(__("Can't place order with scheduled products when not logged in")); + } + if ($cartItemSchedule && $cartItemSchedule->getValue()) { if (null !== $cartSchedule && $cartSchedule !== $cartItemSchedule->getValue()) { throw new LocalizedException(__("Can't place order with different scheduled products in cart")); diff --git a/view/frontend/templates/info/checkout.phtml b/view/frontend/templates/info/checkout.phtml new file mode 100644 index 0000000..d46a165 --- /dev/null +++ b/view/frontend/templates/info/checkout.phtml @@ -0,0 +1,30 @@ + + += $block->getChildHtml() ?> +
| = $escaper->escapeHtml(__('Payment Provider')) ?> | +|
|---|---|
| = $escaper->escapeHtml(__('Payment Method')) ?> | += $escaper->escapeHtml( + $block->getSelectedPaymentMethodData()[Nexi::SELECTED_PATMENT_METHOD] ?? '' + ) ?> | +
| = $escaper->escapeHtml(__('Payment Type')) ?> | += $escaper->escapeHtml( + $block->getSelectedPaymentMethodData()[Nexi::SELECTED_PATMENT_TYPE] ?? '' + ) ?> | +