Kasper.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. <?php
  2. /**
  3. * This file is part of the Klarna KP module
  4. *
  5. * (c) Klarna Bank AB (publ)
  6. *
  7. * For the full copyright and license information, please view the NOTICE
  8. * and LICENSE files that were distributed with this source code.
  9. */
  10. namespace Klarna\Kp\Model\Api\Builder;
  11. use Klarna\Core\Exception as KlarnaException;
  12. use Klarna\Core\Helper\ConfigHelper;
  13. use Klarna\Core\Helper\DataConverter;
  14. use Klarna\Core\Helper\KlarnaConfig;
  15. use Klarna\Core\Model\Api\Exception as KlarnaApiException;
  16. use Klarna\Core\Model\Checkout\Orderline\Collector;
  17. use Klarna\Core\Model\Fpt\Rate;
  18. use Klarna\Kp\Api\Data\RequestInterface;
  19. use Klarna\Kp\Model\Api\Request;
  20. use Klarna\Kp\Model\Payment\Kp;
  21. use Magento\Directory\Helper\Data as DirectoryHelper;
  22. use Magento\Framework\DataObject;
  23. use Magento\Framework\DataObjectFactory;
  24. use Magento\Framework\Event\ManagerInterface as EventManager;
  25. use Magento\Framework\Url;
  26. use Magento\Quote\Model\Quote\Address;
  27. /**
  28. * Class Kasper
  29. *
  30. * @package Klarna\Kp\Model\Api\Builder
  31. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  32. */
  33. class Kasper extends \Klarna\Core\Model\Api\Builder
  34. {
  35. /**
  36. * @var Request\Builder
  37. */
  38. private $requestBuilder;
  39. /**
  40. * @var DataConverter
  41. */
  42. private $dataConverter;
  43. /** @var Rate $rate */
  44. private $rate;
  45. /**
  46. * Kasper constructor.
  47. *
  48. * @param EventManager $eventManager
  49. * @param Collector $collector
  50. * @param Url $url
  51. * @param ConfigHelper $configHelper
  52. * @param Rate $rate
  53. * @param DirectoryHelper $directoryHelper
  54. * @param \Magento\Framework\Stdlib\DateTime\DateTime $coreDate
  55. * @param DataObject\Copy $objCopyService
  56. * @param \Magento\Customer\Model\AddressRegistry $addressRegistry
  57. * @param KlarnaConfig $klarnaConfig
  58. * @param DataConverter $dataConverter
  59. * @param Request\Builder $requestBuilder
  60. * @param DataObjectFactory $dataObjectFactory
  61. * @param array $data
  62. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  63. */
  64. public function __construct(
  65. EventManager $eventManager,
  66. Collector $collector,
  67. Url $url,
  68. ConfigHelper $configHelper,
  69. Rate $rate,
  70. DirectoryHelper $directoryHelper,
  71. \Magento\Framework\Stdlib\DateTime\DateTime $coreDate,
  72. \Magento\Framework\DataObject\Copy $objCopyService,
  73. \Magento\Customer\Model\AddressRegistry $addressRegistry,
  74. KlarnaConfig $klarnaConfig,
  75. DataConverter $dataConverter,
  76. Request\Builder $requestBuilder,
  77. DataObjectFactory $dataObjectFactory,
  78. array $data = []
  79. ) {
  80. parent::__construct(
  81. $eventManager,
  82. $collector,
  83. $url,
  84. $configHelper,
  85. $directoryHelper,
  86. $coreDate,
  87. $objCopyService,
  88. $addressRegistry,
  89. $klarnaConfig,
  90. $dataObjectFactory,
  91. $data
  92. );
  93. $this->prefix = 'kp';
  94. $this->dataConverter = $dataConverter;
  95. $this->requestBuilder = $requestBuilder;
  96. $this->rate = $rate;
  97. }
  98. /**
  99. * Generate request
  100. *
  101. * @param string $type
  102. * @return $this
  103. * @throws \Klarna\Core\Exception
  104. * @throws \Magento\Framework\Exception\LocalizedException
  105. */
  106. public function generateRequest($type = self::GENERATE_TYPE_CREATE)
  107. {
  108. $this->resetOrderLines();
  109. parent::generateRequest($type);
  110. switch ($type) {
  111. case self::GENERATE_TYPE_CREATE:
  112. case self::GENERATE_TYPE_UPDATE:
  113. return $this->generateCreateUpdate();
  114. case self::GENERATE_TYPE_PLACE:
  115. return $this->generatePlace();
  116. }
  117. return $this;
  118. }
  119. /**
  120. * Generate Create/Update Request
  121. *
  122. * @return $this
  123. * @throws KlarnaApiException
  124. * @throws KlarnaException
  125. * @throws \Magento\Framework\Exception\LocalizedException
  126. */
  127. private function generateCreateUpdate()
  128. {
  129. $requiredAttributes = [
  130. 'purchase_country',
  131. 'purchase_currency',
  132. 'locale',
  133. 'order_amount',
  134. 'orderlines'
  135. ];
  136. /** @var \Magento\Quote\Model\Quote $quote */
  137. $quote = $this->getObject();
  138. $store = $quote->getStore();
  139. $options = array_map('trim', array_filter($this->configHelper->getCheckoutDesignConfig($store)));
  140. /**
  141. * Pre-fill customer details
  142. */
  143. $this->prefillAddresses($quote, $store);
  144. $address = $quote->isVirtual() ? $quote->getBillingAddress() : $quote->getShippingAddress();
  145. $tax = $address->getBaseTaxAmount();
  146. if ($this->configHelper->isFptEnabled($store) && !$this->configHelper->getDisplayInSubtotalFpt($store)) {
  147. $fptResult = $this->rate->getFptTax($quote);
  148. $tax += $fptResult['tax'];
  149. }
  150. $this->requestBuilder->setPurchaseCountry($this->directoryHelper->getDefaultCountry($store))
  151. ->setPurchaseCurrency($quote->getBaseCurrencyCode())
  152. ->setLocale(str_replace('_', '-', $this->configHelper->getLocaleCode()))
  153. ->setOptions($options)
  154. ->setOrderAmount((int)$this->dataConverter->toApiFloat($address->getBaseGrandTotal()))
  155. ->addOrderlines($this->getOrderLines($quote->getStore()))
  156. ->setOrderTaxAmount((int)$this->dataConverter->toApiFloat($tax))
  157. ->setMerchantUrls($this->processMerchantUrls())
  158. ->validate($requiredAttributes, self::GENERATE_TYPE_CREATE);
  159. return $this;
  160. }
  161. /**
  162. * @param $quote
  163. * @param $store
  164. */
  165. public function prefillAddresses($quote, $store)
  166. {
  167. if (!$this->configHelper->isPaymentConfigFlag('data_sharing', $store, Kp::METHOD_CODE)) {
  168. return;
  169. }
  170. if ($this->configHelper->getApiConfig('api_version', $store) !== 'kp_na') {
  171. return;
  172. }
  173. $billingAddress = $this->getAddressData($quote, Address::TYPE_BILLING);
  174. if (!isset($billingAddress['country']) || $billingAddress['country'] !== 'US') {
  175. return;
  176. }
  177. $this->addBillingAddress($billingAddress);
  178. $this->addShippingAddress($this->getAddressData($quote, Address::TYPE_SHIPPING));
  179. return;
  180. }
  181. /**
  182. * @param array $create
  183. */
  184. private function addBillingAddress($address)
  185. {
  186. if ($this->validateAddress($address)) {
  187. $this->requestBuilder->setBillingAddress($address);
  188. }
  189. }
  190. /**
  191. * @param array $address
  192. * @return bool
  193. */
  194. private function validateAddress($address = null)
  195. {
  196. if ($address === null) {
  197. return false;
  198. }
  199. if (!is_array($address)) {
  200. return false;
  201. }
  202. if (!isset($address['email'])) {
  203. return false;
  204. }
  205. return true;
  206. }
  207. /**
  208. * @param array $create
  209. */
  210. private function addShippingAddress($address)
  211. {
  212. if ($this->validateAddress($address)) {
  213. $this->requestBuilder->setShippingAddress($address);
  214. }
  215. }
  216. /**
  217. * Pre-process Merchant URLs
  218. *
  219. * @param bool $nosid
  220. * @param bool $forced_secure
  221. * @return string[]
  222. */
  223. public function processMerchantUrls($nosid = true, $forced_secure = true)
  224. {
  225. /**
  226. * Urls
  227. */
  228. $urlParams = [
  229. '_nosid' => $nosid,
  230. '_forced_secure' => $forced_secure
  231. ];
  232. $merchantUrls = $this->dataObjectFactory->create([
  233. 'data' => [
  234. 'confirmation' => $this->url->getDirectUrl('checkout/onepage/success', $urlParams),
  235. 'notification' => $this->url->getDirectUrl('klarna/api/disabled', $urlParams)
  236. ]
  237. ]);
  238. $this->eventManager->dispatch(
  239. 'klarna_prepare_merchant_urls',
  240. [
  241. 'urls' => $merchantUrls,
  242. 'url_params' => $this->dataObjectFactory->create(['data' => $urlParams])
  243. ]
  244. );
  245. $data = $merchantUrls->toArray();
  246. $data['notification'] = preg_replace('/\/id\/{checkout\.order\.id}/', '', $data['notification']);
  247. unset($data['push']);
  248. return $data;
  249. }
  250. /**
  251. * Generate place order body
  252. *
  253. * @return Kasper
  254. * @throws \Klarna\Core\Exception
  255. * @throws \Klarna\Core\Model\Api\Exception
  256. * @throws \Magento\Framework\Exception\LocalizedException
  257. */
  258. private function generatePlace()
  259. {
  260. $requiredAttributes = [
  261. 'purchase_country',
  262. 'purchase_currency',
  263. 'locale',
  264. 'order_amount',
  265. 'orderlines',
  266. 'merchant_urls',
  267. 'billing_address',
  268. 'shipping_address'
  269. ];
  270. /** @var \Magento\Quote\Model\Quote $quote */
  271. $quote = $this->getObject();
  272. $store = $quote->getStore();
  273. $address = $quote->isVirtual() ? $quote->getBillingAddress() : $quote->getShippingAddress();
  274. /**
  275. * Get customer addresses (shipping and billing)
  276. */
  277. $this->addBillingAddress($this->getAddressData($quote, Address::TYPE_BILLING));
  278. $this->addShippingAddress($this->getAddressData($quote, Address::TYPE_SHIPPING));
  279. $tax = $address->getBaseTaxAmount();
  280. if ($this->configHelper->isFptEnabled($store) && !$this->configHelper->getDisplayInSubtotalFpt($store)) {
  281. $fptResult = $this->rate->getFptTax($quote);
  282. $tax += $fptResult['tax'];
  283. }
  284. $this->requestBuilder->setPurchaseCountry($this->directoryHelper->getDefaultCountry($store))
  285. ->setPurchaseCurrency($quote->getBaseCurrencyCode())
  286. ->setLocale(str_replace('_', '-', $this->configHelper->getLocaleCode()))
  287. ->setOrderAmount((int)$this->dataConverter->toApiFloat($address->getBaseGrandTotal()))
  288. ->addOrderlines($this->getOrderLines($quote->getStore()))
  289. ->setOrderTaxAmount((int)$this->dataConverter->toApiFloat($tax))
  290. ->setMerchantUrls($this->processMerchantUrls())
  291. ->setMerchantReferences($this->getMerchantReferences($quote))
  292. ->validate($requiredAttributes, self::GENERATE_TYPE_PLACE);
  293. return $this;
  294. }
  295. /**
  296. * Get request
  297. *
  298. * @return RequestInterface
  299. *
  300. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  301. * @SuppressWarnings(PHPMD.NPathComplexity)
  302. */
  303. public function getRequest()
  304. {
  305. return $this->requestBuilder->getRequest();
  306. }
  307. }