diff --git a/Model/Api/Invoice.php b/Model/Api/Invoice.php index a1958705..2bd37fc7 100644 --- a/Model/Api/Invoice.php +++ b/Model/Api/Invoice.php @@ -99,6 +99,13 @@ class Invoice */ protected $blNegatePrice = false; + /** + * Determines if product category url has to be send + * + * @var bool + */ + protected $blSendCategoryUrl = false; + /** * Constructor * @@ -118,18 +125,27 @@ public function setNegatePrice($blNegatePrice) $this->blNegatePrice = $blNegatePrice; } + /** + * @param bool $blSendCategoryUrl + */ + public function setSendCategoryUrl($blSendCategoryUrl) + { + $this->blSendCategoryUrl = $blSendCategoryUrl; + } + /** * Add parameters for a invoice position * - * @param string $sId item identification - * @param double $dPrice item price - * @param string $sItemType item type - * @param int $iAmount item amount - * @param string $sDesc item description - * @param double $dVat item tax rate + * @param string $sId item identification + * @param double $dPrice item price + * @param string $sItemType item type + * @param int $iAmount item amount + * @param string $sDesc item description + * @param double $dVat item tax rate + * @param string $sCategoryUrl category url * @return void */ - protected function addInvoicePosition($sId, $dPrice, $sItemType, $iAmount, $sDesc, $dVat) + protected function addInvoicePosition($sId, $dPrice, $sItemType, $iAmount, $sDesc, $dVat, $sCategoryUrl = false) { $iMultiplier = 1; if ($this->blNegatePrice === true) { @@ -141,6 +157,9 @@ protected function addInvoicePosition($sId, $dPrice, $sItemType, $iAmount, $sDes $this->oRequest->addParameter('no['.$this->iIndex.']', $iAmount); // add invoice item amount $this->oRequest->addParameter('de['.$this->iIndex.']', $sDesc); // add invoice item description $this->oRequest->addParameter('va['.$this->iIndex.']', $this->toolkitHelper->formatNumber($dVat * 100, 0)); // expected * 100 to also handle vats with decimals + if ($sCategoryUrl !== false) { + $this->oRequest->addParameter('add_paydata[category_path_'.$sId.']', $sCategoryUrl); // add category url of a product, needed for BNPL payment methods + } $this->dAmount += $dPrice * $iAmount; // needed for return of the main method $this->iIndex++; // increase index for next item } @@ -212,13 +231,43 @@ protected function addProductItem($oItem, $aPositions) if ($this->toolkitHelper->getConfigParam('currency', 'global', 'payone_general', $this->getStoreCode()) == 'display') { $dPrice = $oItem->getPriceInclTax(); } - $this->addInvoicePosition($oItem->getSku(), $dPrice, 'goods', $iAmount, $oItem->getName(), $oItem->getTaxPercent()); // add invoice params to request + + $sCategoryUrl = false; + if ($this->blSendCategoryUrl === true) { + $oCategory = $this->getProductCategory($oItem); + if (!empty($oCategory) && !empty($oCategory->getUrl())) { + $sCategoryUrl = $oCategory->getUrl(); + } + } + + $this->addInvoicePosition($oItem->getSku(), $dPrice, 'goods', $iAmount, $oItem->getName(), $oItem->getTaxPercent(), $sCategoryUrl); // add invoice params to request if ($this->dTax === false) { // is dTax not set yet? $this->dTax = $oItem->getTaxPercent(); // set the tax for following entities which dont have the vat attached to it } } } + /** + * Try to get a category from given order item + * + * @param \Magento\Sales\Model\Order\Item $oItem + * @return \Magento\Catalog\Model\Category|false + */ + protected function getProductCategory($oItem) + { + $oProduct = $oItem->getProduct(); + if ($oProduct) { + $oCategoryCollection = $oProduct->getCategoryCollection(); + if (count($oCategoryCollection) > 0) { + $oCategory = $oCategoryCollection->getFirstItem(); + if ($oCategory) { + return $oCategory; + } + } + } + return false; + } + protected function addGiftCardItem($oOrder) { $giftCards = json_decode($oOrder->getData('gift_cards') ?? '', true); diff --git a/Model/Api/Request/Authorization.php b/Model/Api/Request/Authorization.php index e0be897c..2e114c71 100644 --- a/Model/Api/Request/Authorization.php +++ b/Model/Api/Request/Authorization.php @@ -26,6 +26,7 @@ namespace Payone\Core\Model\Api\Request; +use Payone\Core\Model\Methods\BNPL\BNPLBase; use Payone\Core\Model\Methods\Klarna\KlarnaBase; use Payone\Core\Model\PayoneConfig; use Payone\Core\Model\Methods\PayoneMethod; @@ -172,6 +173,9 @@ protected function setAuthorizationParameters(PayoneMethod $oPayment, Order $oOr $this->setPaymentParameters($oPayment, $oOrder); // add payment specific parameters if ($this->apiHelper->isInvoiceDataNeeded($oPayment)) { + if ($oPayment instanceof BNPLBase) { // only for BNPL methods it is needed that a category url is sent for each product + $this->invoiceGenerator->setSendCategoryUrl(true); + } $this->invoiceGenerator->addProductInfo($this, $oOrder); // add invoice parameters } } diff --git a/Test/Unit/Model/Api/InvoiceTest.php b/Test/Unit/Model/Api/InvoiceTest.php index 19a063ca..299b153a 100644 --- a/Test/Unit/Model/Api/InvoiceTest.php +++ b/Test/Unit/Model/Api/InvoiceTest.php @@ -97,7 +97,7 @@ private function getItemMock($type = Item::class) { $item = $this->getMockBuilder($type) ->disableOriginalConstructor() - ->setMethods(['isDummy', 'getProductId', 'getQtyOrdered', 'getSku', 'getPriceInclTax', 'getBasePriceInclTax', 'getName', 'getTaxPercent', 'getOrigData', 'getParentItemId', 'getQty']) + ->setMethods(['isDummy', 'getProductId', 'getQtyOrdered', 'getSku', 'getPriceInclTax', 'getBasePriceInclTax', 'getName', 'getTaxPercent', 'getOrigData', 'getParentItemId', 'getQty', 'getProduct']) ->getMock(); $item->method('isDummy')->willReturn(false); $item->method('getProductId')->willReturn('12345'); @@ -120,8 +120,20 @@ public function testAddProductInfo() $this->amastyHelper->method('getAmastyGiftCards')->willReturn([['base_gift_amount' => 5, 'gift_amount' => 5, 'code' => 'TEST']]); $authorization = $this->getMockBuilder(Authorization::class)->disableOriginalConstructor()->getMock(); + + $category = $this->getMockBuilder(\Magento\Catalog\Model\Category::class)->disableOriginalConstructor()->getMock(); + $category->method('getUrl')->willReturn("some random url"); + + $categoryCollection = $this->getMockBuilder(\Magento\Framework\Data\Collection::class)->disableOriginalConstructor()->getMock(); + $categoryCollection->method('count')->willReturn(1); + $categoryCollection->method('getFirstItem')->willReturn($category); - $items = [$this->getItemMock()]; + $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)->disableOriginalConstructor()->getMock(); + $product->method('getCategoryCollection')->willReturn($categoryCollection); + + $item = $this->getItemMock(); + $item->method('getProduct')->willReturn($product); + $items = [$item]; $expected = 110; @@ -144,6 +156,7 @@ public function testAddProductInfo() $order->method('getStore')->willReturn($this->store); $order->method('getGiftCards')->willReturn('[{"i":365,"c":"testcode","a":10,"ba":10,"authorized":10}]'); + $this->classToTest->setSendCategoryUrl(true); $result = $this->classToTest->addProductInfo($authorization, $order, false); $this->assertEquals($expected, $result); } @@ -156,7 +169,9 @@ public function testAddProductInfoDisplay() $authorization = $this->getMockBuilder(Authorization::class)->disableOriginalConstructor()->getMock(); - $items = [$this->getItemMock()]; + $item = $this->getItemMock(); + $item->method('getProduct')->willReturn(null); + $items = [$item]; $expected = 106; @@ -184,6 +199,7 @@ public function testAddProductInfoDisplay() $order->method('getStore')->willReturn($this->store); $order->method('getGiftCards')->willReturn('[{"i":365,"c":"testcode","a":10,"ba":10,"authorized":10}]'); + $this->classToTest->setSendCategoryUrl(true); $result = $this->classToTest->addProductInfo($authorization, $order, false); $this->assertEquals($expected, $result); } @@ -300,4 +316,16 @@ public function testAddProductInfoQuote() $result = $this->classToTest->addProductInfo($authorization, $order, false, false, 5); $this->assertEquals($expected, $result); } + + public function testSetNegatePrice() + { + $result = $this->classToTest->setNegatePrice(true); + $this->assertNull($result); + } + + public function testSetSendCategoryUrl() + { + $result = $this->classToTest->setSendCategoryUrl(true); + $this->assertNull($result); + } } diff --git a/Test/Unit/Model/Api/Request/AuthorizationTest.php b/Test/Unit/Model/Api/Request/AuthorizationTest.php index 9249a89a..067a12a4 100644 --- a/Test/Unit/Model/Api/Request/AuthorizationTest.php +++ b/Test/Unit/Model/Api/Request/AuthorizationTest.php @@ -31,6 +31,7 @@ use Payone\Core\Helper\Database; use Payone\Core\Model\Api\Request\Authorization as ClassToTest; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Payone\Core\Model\Methods\BNPL\Debit; use Payone\Core\Model\Methods\PayoneMethod; use Payone\Core\Helper\Api; use Payone\Core\Helper\Toolkit; @@ -212,4 +213,45 @@ public function testSendRequestPaypal() $result = $this->classToTest->sendRequest($payment, $order, 100); $this->assertEquals($response, $result); } + + public function testSendRequestBNPL() + { + $payment = $this->getMockBuilder(Debit::class)->disableOriginalConstructor()->getMock(); + $payment->method('getAuthorizationMode')->willReturn('authorization'); + $payment->method('getOperationMode')->willReturn('test'); + $payment->method('hasCustomConfig')->willReturn(true); + $payment->method('formatReferenceNumber')->willReturn('12345'); + $payment->method('getCode')->willReturn(PayoneConfig::METHOD_BNPL_DEBIT); + $payment->method('getClearingtype')->willReturn('wlt'); + $payment->method('getPaymentSpecificParameters')->willReturn([]); + $payment->method('needsRedirectUrls')->willReturn(true); + $payment->method('needsTransactionParam')->willReturn(true); + $payment->method('getSuccessUrl')->willReturn('http://testdomain.com'); + $payment->method('getErrorUrl')->willReturn('http://testdomain.com'); + $payment->method('getCancelUrl')->willReturn('http://testdomain.com'); + $payment->method('getCustomConfigParam')->willReturn('true'); + + $address = $this->getAddressMock(); + + $store = $this->getMockBuilder(StoreInterface::class)->disableOriginalConstructor()->getMock(); + $store->method('getCode')->willReturn('test'); + + $order = $this->getMockBuilder(Order::class) + ->disableOriginalConstructor() + ->setMethods(['getRealOrderId', 'getOrderCurrencyCode', 'getCustomerId', 'getCustomerEmail', 'getBillingAddress', 'getShippingAddress', 'getStore']) + ->getMock(); + $order->method('getRealOrderId')->willReturn('54321'); + $order->method('getOrderCurrencyCode')->willReturn('EUR'); + $order->method('getCustomerId')->willReturn('12345'); + $order->method('getCustomerEmail')->willReturn('test@test.com'); + $order->method('getBillingAddress')->willReturn($address); + $order->method('getShippingAddress')->willReturn(false); + $order->method('getStore')->willReturn($store); + + $response = ['status' => 'VALID']; + $this->apiHelper->method('sendApiRequest')->willReturn($response); + + $result = $this->classToTest->sendRequest($payment, $order, 100); + $this->assertEquals($response, $result); + } }