Ordermanagement.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. <?php
  2. /**
  3. * This file is part of the Klarna Order Management 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\Ordermanagement\Model\Api;
  11. use Klarna\Core\Helper\ConfigHelper;
  12. use Klarna\Core\Helper\DataConverter;
  13. use Klarna\Core\Helper\KlarnaConfig;
  14. use Klarna\Core\Model\Api\BuilderFactory;
  15. use Klarna\Ordermanagement\Api\ApiInterface;
  16. use Klarna\Ordermanagement\Model\Api\Rest\Service\Ordermanagement as OrdermanagementApi;
  17. use Magento\Framework\DataObject;
  18. use Magento\Framework\DataObjectFactory;
  19. use Magento\Framework\Event\ManagerInterface;
  20. use Magento\Framework\Exception\LocalizedException;
  21. use Magento\Sales\Model\Order\Creditmemo;
  22. use Magento\Sales\Model\Order\Invoice;
  23. /**
  24. * Class Ordermanagement
  25. *
  26. * @package Klarna\Ordermanagement\Model\Api
  27. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  28. */
  29. class Ordermanagement implements ApiInterface
  30. {
  31. /**
  32. * Order fraud statuses
  33. */
  34. const ORDER_FRAUD_STATUS_ACCEPTED = 'ACCEPTED';
  35. const ORDER_FRAUD_STATUS_REJECTED = 'REJECTED';
  36. const ORDER_FRAUD_STATUS_PENDING = 'PENDING';
  37. const RET_ORDER_FRAUD_STATUS_ACCEPTED = 1;
  38. const RET_ORDER_FRAUD_STATUS_REJECTED = -1;
  39. const RET_ORDER_FRAUD_STATUS_PENDING = 0;
  40. /**
  41. * Order notification statuses
  42. */
  43. const ORDER_NOTIFICATION_FRAUD_REJECTED = 'FRAUD_RISK_REJECTED';
  44. const ORDER_NOTIFICATION_FRAUD_ACCEPTED = 'FRAUD_RISK_ACCEPTED';
  45. const ORDER_NOTIFICATION_FRAUD_STOPPED = 'FRAUD_RISK_STOPPED';
  46. /**
  47. * API allowed shipping method code
  48. */
  49. const KLARNA_API_SHIPPING_METHOD_HOME = "Home";
  50. const KLARNA_API_SHIPPING_METHOD_PICKUPSTORE = "PickUpStore";
  51. const KLARNA_API_SHIPPING_METHOD_BOXREG = "BoxReg";
  52. const KLARNA_API_SHIPPING_METHOD_BOXUNREG = "BoxUnreg";
  53. const KLARNA_API_SHIPPING_METHOD_PICKUPPOINT = "PickUpPoint";
  54. const KLARNA_API_SHIPPING_METHOD_OWN = "Own";
  55. /**
  56. * @var DataObject
  57. */
  58. private $klarnaOrder;
  59. /**
  60. * @var OrdermanagementApi
  61. */
  62. private $orderManagement;
  63. /**
  64. * @var ConfigHelper
  65. */
  66. private $helper;
  67. /**
  68. * @var BuilderFactory
  69. */
  70. private $builderFactory;
  71. /**
  72. * @var ManagerInterface
  73. */
  74. private $eventManager;
  75. /**
  76. * API type code
  77. *
  78. * @var string
  79. */
  80. private $builderType = '';
  81. /**
  82. * @var KlarnaConfig
  83. */
  84. private $klarnaConfig;
  85. /**
  86. * @var DataConverter
  87. */
  88. private $dataConverter;
  89. /**
  90. * @var DataObjectFactory
  91. */
  92. private $dataObjectFactory;
  93. /**
  94. * OrdermanagementApi constructor.
  95. *
  96. * @param OrdermanagementApi $orderManagement
  97. * @param ConfigHelper $helper
  98. * @param KlarnaConfig $klarnaConfig
  99. * @param DataConverter $dataConverter
  100. * @param BuilderFactory $builderFactory
  101. * @param ManagerInterface $eventManager
  102. * @param DataObjectFactory $dataObjectFactory
  103. * @param string $builderType
  104. */
  105. public function __construct(
  106. OrdermanagementApi $orderManagement,
  107. ConfigHelper $helper,
  108. KlarnaConfig $klarnaConfig,
  109. DataConverter $dataConverter,
  110. BuilderFactory $builderFactory,
  111. ManagerInterface $eventManager,
  112. DataObjectFactory $dataObjectFactory,
  113. $builderType = ''
  114. ) {
  115. $this->orderManagement = $orderManagement;
  116. $this->helper = $helper;
  117. $this->builderFactory = $builderFactory;
  118. $this->eventManager = $eventManager;
  119. $this->builderType = $builderType;
  120. $this->klarnaConfig = $klarnaConfig;
  121. $this->dataConverter = $dataConverter;
  122. $this->dataObjectFactory = $dataObjectFactory;
  123. }
  124. /**
  125. * Get the fraud status of an order to determine if it should be accepted or denied within Magento
  126. *
  127. * Return value of 1 means accept
  128. * Return value of 0 means still pending
  129. * Return value of -1 means deny
  130. *
  131. * @param string $orderId
  132. *
  133. * @return int
  134. */
  135. public function getFraudStatus($orderId)
  136. {
  137. $klarnaOrder = $this->orderManagement->getOrder($orderId);
  138. $klarnaOrder = $this->dataObjectFactory->create(['data' => $klarnaOrder]);
  139. switch ($klarnaOrder->getFraudStatus()) {
  140. case self::ORDER_FRAUD_STATUS_ACCEPTED:
  141. return self::RET_ORDER_FRAUD_STATUS_ACCEPTED;
  142. case self::ORDER_FRAUD_STATUS_REJECTED:
  143. return self::RET_ORDER_FRAUD_STATUS_REJECTED;
  144. case self::ORDER_FRAUD_STATUS_PENDING:
  145. default:
  146. return self::RET_ORDER_FRAUD_STATUS_PENDING;
  147. }
  148. }
  149. /**
  150. * Acknowledge an order in order management
  151. *
  152. * @param string $orderId
  153. *
  154. * @return DataObject
  155. */
  156. public function acknowledgeOrder($orderId)
  157. {
  158. $response = $this->orderManagement->acknowledgeOrder($orderId);
  159. $response = $this->dataObjectFactory->create(['data' => $response]);
  160. return $response;
  161. }
  162. /**
  163. * Update merchant references for a Klarna order
  164. *
  165. * @param string $orderId
  166. * @param string $reference1
  167. * @param string $reference2
  168. *
  169. * @return DataObject
  170. */
  171. public function updateMerchantReferences($orderId, $reference1, $reference2 = null)
  172. {
  173. $response = $this->orderManagement->updateMerchantReferences($orderId, $reference1, $reference2);
  174. $response = $this->dataObjectFactory->create(['data' => $response]);
  175. return $response;
  176. }
  177. /**
  178. * Capture an amount on an order
  179. *
  180. * @param string $orderId
  181. * @param float $amount
  182. * @param Invoice $invoice
  183. *
  184. * @return DataObject
  185. * @throws LocalizedException
  186. * @throws \Klarna\Core\Exception
  187. * @throws \Klarna\Core\Model\Api\Exception
  188. */
  189. public function capture($orderId, $amount, $invoice = null)
  190. {
  191. $data = [
  192. 'captured_amount' => $this->dataConverter->toApiFloat($amount)
  193. ];
  194. $data = $this->prepareOrderLines($data, $invoice);
  195. $data = $this->checkShippingDelay($data);
  196. $response = $this->orderManagement->captureOrder($orderId, $data);
  197. $response = $this->dataObjectFactory->create(['data' => $response]);
  198. /**
  199. * If a capture fails, attempt to extend the auth and attempt capture again.
  200. * This work in certain cases that cannot be detected via api calls
  201. */
  202. if (!$response->getIsSuccessful()) {
  203. $extendResponse = $this->orderManagement->extendAuthorization($orderId);
  204. $extendResponse = $this->dataObjectFactory->create(['data' => $extendResponse]);
  205. if ($extendResponse->getIsSuccessful()) {
  206. $response = $this->orderManagement->captureOrder($orderId, $data);
  207. $response = $this->dataObjectFactory->create(['data' => $response]);
  208. }
  209. }
  210. if ($response->getIsSuccessful()) {
  211. $responseObject = $response->getResponseObject();
  212. $captureId = $this->orderManagement
  213. ->getLocationResourceId($responseObject['headers']['Location']);
  214. if ($captureId) {
  215. $captureDetails = $this->orderManagement->getCapture($orderId, $captureId);
  216. $captureDetails = $this->dataObjectFactory->create(['data' => $captureDetails]);
  217. if ($captureDetails->getKlarnaReference()) {
  218. $captureDetails->setTransactionId($captureDetails->getKlarnaReference());
  219. }
  220. return $captureDetails;
  221. }
  222. }
  223. return $response;
  224. }
  225. /**
  226. * Add shipping info to capture
  227. *
  228. * @param string $orderId
  229. * @param string $captureId
  230. * @param array $shippingInfo
  231. * @return array|DataObject
  232. */
  233. public function addShippingInfo($orderId, $captureId, $shippingInfo)
  234. {
  235. $data = $this->prepareShippingInfo($shippingInfo);
  236. $response = $this->orderManagement->addShippingInfo($orderId, $captureId, $data);
  237. $response = $this->dataObjectFactory->create(['data' => $response]);
  238. return $response;
  239. }
  240. /**
  241. * Prepare shipping info
  242. *
  243. * @param array $shippingInfo
  244. * @return array
  245. */
  246. private function prepareShippingInfo(array $shippingInfo)
  247. {
  248. $data = [];
  249. foreach ($shippingInfo as $shipping) {
  250. $data['shipping_info'][] = [
  251. 'tracking_number' => substr($shipping['number'], 0, 100),
  252. 'shipping_method' => $this->getKlarnaShippingMethod($shipping),
  253. 'shipping_company' => substr($shipping['title'], 0, 100)
  254. ];
  255. }
  256. return $data;
  257. }
  258. /**
  259. * Get Api Accepted shipping method,For merchant who implement this feature
  260. * Create Plugin to overwrite this default method code
  261. * Allowed values matches (PickUpStore|Home|BoxReg|BoxUnreg|PickUpPoint|Own)
  262. *
  263. * @param array $shipping
  264. * @return string
  265. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  266. */
  267. public function getKlarnaShippingMethod(array $shipping)
  268. {
  269. return self::KLARNA_API_SHIPPING_METHOD_HOME;
  270. }
  271. /**
  272. * @param array $data
  273. * @param Invoice|Creditmemo|null $document
  274. * @return array
  275. * @throws LocalizedException
  276. * @throws \Klarna\Core\Exception
  277. */
  278. private function prepareOrderLines($data, $document = null)
  279. {
  280. /**
  281. * Get items for capture
  282. */
  283. if ($document instanceof Invoice || $document instanceof Creditmemo) {
  284. $orderItems = $this->getGenerator()
  285. ->setObject($document)
  286. ->collectOrderLines($document->getStore())
  287. ->getOrderLines($document->getStore(), true);
  288. if ($orderItems) {
  289. $data['order_lines'] = $orderItems;
  290. }
  291. }
  292. return $data;
  293. }
  294. /**
  295. * @return \Klarna\Core\Api\BuilderInterface
  296. * @throws \Magento\Framework\Exception\LocalizedException
  297. */
  298. private function getGenerator()
  299. {
  300. return $this->builderFactory->create($this->builderType);
  301. }
  302. /**
  303. * Set shipping delay for capture
  304. *
  305. * Change this setting when items will not be shipped for x amount of days after capture.
  306. * For instance, you capture on Friday but won't ship until Monday. A 3 day shipping delay would be set.
  307. *
  308. * @param array $data
  309. * @param int $shippingDelay
  310. * @return array
  311. */
  312. public function checkShippingDelay($data, $shippingDelay = 0)
  313. {
  314. $shippingDelayObject = $this->dataObjectFactory->create(['data' => ['shipping_delay' => $shippingDelay]]);
  315. $this->eventManager->dispatch(
  316. 'klarna_capture_shipping_delay',
  317. ['shipping_delay_object' => $shippingDelayObject]
  318. );
  319. if ($shippingDelayObject->getShippingDelay()) {
  320. $data['shipping_delay'] = $shippingDelayObject->getShippingDelay();
  321. }
  322. return $data;
  323. }
  324. /**
  325. * Refund for an order
  326. *
  327. * @param string $orderId
  328. * @param float $amount
  329. * @param Creditmemo $creditMemo
  330. *
  331. * @return DataObject
  332. * @throws \Klarna\Core\Exception
  333. * @throws LocalizedException
  334. */
  335. public function refund($orderId, $amount, $creditMemo = null)
  336. {
  337. $data = [
  338. 'refunded_amount' => $this->dataConverter->toApiFloat($amount)
  339. ];
  340. if (!is_null($creditMemo->getCustomerNote())) {
  341. $data['description'] = $creditMemo->getCustomerNote();
  342. }
  343. $data = $this->prepareOrderLines($data, $creditMemo);
  344. $response = $this->orderManagement->refund($orderId, $data);
  345. $response = $this->dataObjectFactory->create(['data' => $response]);
  346. if ($response->getIsSuccessful()) {
  347. $response->setTransactionId($this->orderManagement->getLocationResourceId($response));
  348. }
  349. return $response;
  350. }
  351. /**
  352. * Cancel an order
  353. *
  354. * @param string $orderId
  355. *
  356. * @return DataObject
  357. */
  358. public function cancel($orderId)
  359. {
  360. $response = $this->orderManagement->cancelOrder($orderId);
  361. $response = $this->dataObjectFactory->create(['data' => $response]);
  362. return $response;
  363. }
  364. /**
  365. * Release the authorization on an order
  366. *
  367. * @param string $orderId
  368. *
  369. * @return DataObject
  370. */
  371. public function release($orderId)
  372. {
  373. $response = $this->orderManagement->releaseAuthorization($orderId);
  374. $response = $this->dataObjectFactory->create(['data' => $response]);
  375. return $response;
  376. }
  377. /**
  378. * Get order details for a completed Klarna order
  379. *
  380. * @param string $orderId
  381. *
  382. * @return DataObject
  383. */
  384. public function getPlacedKlarnaOrder($orderId)
  385. {
  386. $response = $this->orderManagement->getOrder($orderId);
  387. $response = $this->dataObjectFactory->create(['data' => $response]);
  388. return $response;
  389. }
  390. /**
  391. * Get Klarna Checkout Reservation Id
  392. *
  393. * @return string
  394. */
  395. public function getReservationId()
  396. {
  397. return $this->getKlarnaOrder()->getOrderId();
  398. }
  399. /**
  400. * Get Klarna checkout order details
  401. *
  402. * @return DataObject
  403. */
  404. public function getKlarnaOrder()
  405. {
  406. if ($this->klarnaOrder === null) {
  407. $this->klarnaOrder = $this->dataObjectFactory->create();
  408. }
  409. return $this->klarnaOrder;
  410. }
  411. /**
  412. * Set Klarna checkout order details
  413. *
  414. * @param DataObject $klarnaOrder
  415. *
  416. * @return $this
  417. */
  418. public function setKlarnaOrder(DataObject $klarnaOrder)
  419. {
  420. $this->klarnaOrder = $klarnaOrder;
  421. return $this;
  422. }
  423. /**
  424. * {@inheritdoc}
  425. * @throws \Klarna\Core\Exception
  426. */
  427. public function resetForStore($store, $methodCode)
  428. {
  429. $versionConfig = $this->klarnaConfig->getVersionConfig($store);
  430. $this->setBuilderType($this->klarnaConfig->getOmBuilderType($versionConfig, $methodCode));
  431. $user = $this->helper->getApiConfig('merchant_id', $store);
  432. $password = $this->helper->getApiConfig('shared_secret', $store);
  433. $test_mode = $this->helper->isApiConfigFlag('test_mode', $store);
  434. $url = $versionConfig->getUrl($test_mode);
  435. $this->orderManagement->resetForStore($user, $password, $url);
  436. return $this;
  437. }
  438. /**
  439. * {@inheritdoc}
  440. */
  441. public function setBuilderType($builderType)
  442. {
  443. $this->builderType = $builderType;
  444. return $this;
  445. }
  446. }