Agreement.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Paypal\Model\Method;
  7. use Magento\Payment\Model\InfoInterface;
  8. use Magento\Sales\Model\Order\Payment;
  9. use Magento\Store\Model\Store;
  10. /**
  11. * Paypal Billing Agreement method
  12. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  13. */
  14. class Agreement extends \Magento\Paypal\Model\Payment\Method\Billing\AbstractAgreement implements
  15. \Magento\Paypal\Model\Billing\Agreement\MethodInterface
  16. {
  17. /**
  18. * Method code
  19. *
  20. * @var string
  21. */
  22. protected $_code = \Magento\Paypal\Model\Config::METHOD_BILLING_AGREEMENT;
  23. /**
  24. * Method instance setting
  25. *
  26. * @var bool
  27. */
  28. protected $_canAuthorize = true;
  29. /**
  30. * Method instance setting
  31. *
  32. * @var bool
  33. */
  34. protected $_canCapture = true;
  35. /**
  36. * Method instance setting
  37. *
  38. * @var bool
  39. */
  40. protected $_canCapturePartial = true;
  41. /**
  42. * Method instance setting
  43. *
  44. * @var bool
  45. */
  46. protected $_canRefund = true;
  47. /**
  48. * Method instance setting
  49. *
  50. * @var bool
  51. */
  52. protected $_canRefundInvoicePartial = true;
  53. /**
  54. * Method instance setting
  55. *
  56. * @var bool
  57. */
  58. protected $_canVoid = true;
  59. /**
  60. * Method instance setting
  61. *
  62. * @var bool
  63. */
  64. protected $_canUseCheckout = true;
  65. /**
  66. * Method instance setting
  67. *
  68. * @var bool
  69. */
  70. protected $_canUseInternal = true;
  71. /**
  72. * Method instance setting
  73. *
  74. * @var bool
  75. */
  76. protected $_canFetchTransactionInfo = true;
  77. /**
  78. * Method instance setting
  79. *
  80. * @var bool
  81. */
  82. protected $_canReviewPayment = true;
  83. /**
  84. * Website Payments Pro instance
  85. *
  86. * @var \Magento\Paypal\Model\Pro
  87. */
  88. protected $_pro;
  89. /**
  90. * @var \Magento\Store\Model\StoreManagerInterface
  91. */
  92. protected $_storeManager;
  93. /**
  94. * @var \Magento\Framework\UrlInterface
  95. */
  96. protected $_urlBuilder;
  97. /**
  98. * @var \Magento\Paypal\Model\CartFactory
  99. */
  100. protected $_cartFactory;
  101. /**
  102. * @param \Magento\Framework\Model\Context $context
  103. * @param \Magento\Framework\Registry $registry
  104. * @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory
  105. * @param \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory
  106. * @param \Magento\Payment\Helper\Data $paymentData
  107. * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
  108. * @param \Magento\Payment\Model\Method\Logger $logger
  109. * @param \Magento\Paypal\Model\Billing\AgreementFactory $agreementFactory
  110. * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  111. * @param \Magento\Paypal\Model\ProFactory $proFactory
  112. * @param \Magento\Framework\UrlInterface $urlBuilder
  113. * @param \Magento\Paypal\Model\CartFactory $cartFactory
  114. * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
  115. * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
  116. * @param array $data
  117. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  118. */
  119. public function __construct(
  120. \Magento\Framework\Model\Context $context,
  121. \Magento\Framework\Registry $registry,
  122. \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,
  123. \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory,
  124. \Magento\Payment\Helper\Data $paymentData,
  125. \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
  126. \Magento\Payment\Model\Method\Logger $logger,
  127. \Magento\Paypal\Model\Billing\AgreementFactory $agreementFactory,
  128. \Magento\Store\Model\StoreManagerInterface $storeManager,
  129. \Magento\Paypal\Model\ProFactory $proFactory,
  130. \Magento\Framework\UrlInterface $urlBuilder,
  131. \Magento\Paypal\Model\CartFactory $cartFactory,
  132. \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
  133. \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
  134. array $data = []
  135. ) {
  136. $this->_storeManager = $storeManager;
  137. $this->_urlBuilder = $urlBuilder;
  138. $this->_cartFactory = $cartFactory;
  139. parent::__construct(
  140. $context,
  141. $registry,
  142. $extensionFactory,
  143. $customAttributeFactory,
  144. $paymentData,
  145. $scopeConfig,
  146. $logger,
  147. $agreementFactory,
  148. $resource,
  149. $resourceCollection,
  150. $data
  151. );
  152. $proInstance = array_shift($data);
  153. if ($proInstance && $proInstance instanceof \Magento\Paypal\Model\Pro) {
  154. $this->_pro = $proInstance;
  155. } else {
  156. $this->_pro = $proFactory->create();
  157. }
  158. $this->_pro->setMethod($this->_code);
  159. }
  160. /**
  161. * Store setter
  162. * Also updates store ID in config object
  163. *
  164. * @param Store|int $store
  165. * @return $this
  166. */
  167. public function setStore($store)
  168. {
  169. $this->setData('store', $store);
  170. if (null === $store) {
  171. $store = $this->_storeManager->getStore()->getId();
  172. }
  173. $this->_pro->getConfig()->setStoreId(is_object($store) ? $store->getId() : $store);
  174. return $this;
  175. }
  176. /**
  177. * Init billing agreement
  178. *
  179. * @param \Magento\Paypal\Model\Billing\AbstractAgreement $agreement
  180. * @return $this
  181. */
  182. public function initBillingAgreementToken(\Magento\Paypal\Model\Billing\AbstractAgreement $agreement)
  183. {
  184. $api = $this->_pro->getApi()->setReturnUrl(
  185. $agreement->getReturnUrl()
  186. )->setCancelUrl(
  187. $agreement->getCancelUrl()
  188. )->setBillingType(
  189. $this->_pro->getApi()->getBillingAgreementType()
  190. );
  191. $api->callSetCustomerBillingAgreement();
  192. $agreement->setRedirectUrl($this->_pro->getConfig()->getStartBillingAgreementUrl($api->getToken()));
  193. return $this;
  194. }
  195. /**
  196. * Retrieve billing agreement customer details by token
  197. *
  198. * @param \Magento\Paypal\Model\Billing\AbstractAgreement $agreement
  199. * @return array
  200. */
  201. public function getBillingAgreementTokenInfo(\Magento\Paypal\Model\Billing\AbstractAgreement $agreement)
  202. {
  203. $api = $this->_pro->getApi()->setToken($agreement->getToken());
  204. $api->callGetBillingAgreementCustomerDetails();
  205. $responseData = [
  206. 'token' => $api->getData('token'),
  207. 'email' => $api->getData('email'),
  208. 'payer_id' => $api->getData('payer_id'),
  209. 'payer_status' => $api->getData('payer_status'),
  210. ];
  211. $agreement->addData($responseData);
  212. return $responseData;
  213. }
  214. /**
  215. * Create billing agreement by token specified in request
  216. *
  217. * @param \Magento\Paypal\Model\Billing\AbstractAgreement $agreement
  218. * @return $this
  219. */
  220. public function placeBillingAgreement(\Magento\Paypal\Model\Billing\AbstractAgreement $agreement)
  221. {
  222. $api = $this->_pro->getApi()->setToken($agreement->getToken());
  223. $api->callCreateBillingAgreement();
  224. $agreement->setBillingAgreementId($api->getData('billing_agreement_id'));
  225. return $this;
  226. }
  227. /**
  228. * Update billing agreement status
  229. *
  230. * @param \Magento\Paypal\Model\Billing\AbstractAgreement $agreement
  231. * @return $this
  232. * @throws \Exception|\Magento\Framework\Exception\LocalizedException
  233. */
  234. public function updateBillingAgreementStatus(\Magento\Paypal\Model\Billing\AbstractAgreement $agreement)
  235. {
  236. $targetStatus = $agreement->getStatus();
  237. $api = $this->_pro->getApi()->setReferenceId(
  238. $agreement->getReferenceId()
  239. )->setBillingAgreementStatus(
  240. $targetStatus
  241. );
  242. try {
  243. $api->callUpdateBillingAgreement();
  244. } catch (\Magento\Framework\Exception\LocalizedException $e) {
  245. // when BA was already canceled, just pretend that the operation succeeded
  246. if (!(\Magento\Paypal\Model\Billing\Agreement::STATUS_CANCELED == $targetStatus &&
  247. $api->getIsBillingAgreementAlreadyCancelled())
  248. ) {
  249. throw $e;
  250. }
  251. }
  252. return $this;
  253. }
  254. /**
  255. * Authorize payment
  256. *
  257. * @param \Magento\Framework\DataObject|InfoInterface $payment
  258. * @param float $amount
  259. * @return $this
  260. */
  261. public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount)
  262. {
  263. return $this->_placeOrder($payment, $amount);
  264. }
  265. /**
  266. * Void payment
  267. *
  268. * @param \Magento\Framework\DataObject|InfoInterface|Payment $payment
  269. * @return $this
  270. * @throws \Magento\Framework\Exception\LocalizedException
  271. */
  272. public function void(\Magento\Payment\Model\InfoInterface $payment)
  273. {
  274. $this->_pro->void($payment);
  275. return $this;
  276. }
  277. /**
  278. * Capture payment
  279. *
  280. * @param \Magento\Framework\DataObject|InfoInterface|Payment $payment
  281. * @param float $amount
  282. * @return $this
  283. */
  284. public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount)
  285. {
  286. if (false === $this->_pro->capture($payment, $amount)) {
  287. $this->_placeOrder($payment, $amount);
  288. }
  289. return $this;
  290. }
  291. /**
  292. * Refund capture
  293. *
  294. * @param \Magento\Framework\DataObject|InfoInterface|Payment $payment
  295. * @param float $amount
  296. * @return $this
  297. * @throws \Magento\Framework\Exception\LocalizedException
  298. */
  299. public function refund(\Magento\Payment\Model\InfoInterface $payment, $amount)
  300. {
  301. $this->_pro->refund($payment, $amount);
  302. return $this;
  303. }
  304. /**
  305. * Cancel payment
  306. *
  307. * @param \Magento\Framework\DataObject|InfoInterface|Payment $payment
  308. * @return $this
  309. */
  310. public function cancel(\Magento\Payment\Model\InfoInterface $payment)
  311. {
  312. $this->_pro->cancel($payment);
  313. return $this;
  314. }
  315. /**
  316. * Whether payment can be reviewed
  317. * @return bool
  318. * @internal param InfoInterface|Payment $payment
  319. */
  320. public function canReviewPayment()
  321. {
  322. return parent::canReviewPayment() && $this->_pro->canReviewPayment($this->getInfoInstance());
  323. }
  324. /**
  325. * Attempt to accept a pending payment
  326. *
  327. * @param InfoInterface|Payment $payment
  328. * @return bool
  329. */
  330. public function acceptPayment(InfoInterface $payment)
  331. {
  332. parent::acceptPayment($payment);
  333. return $this->_pro->reviewPayment($payment, \Magento\Paypal\Model\Pro::PAYMENT_REVIEW_ACCEPT);
  334. }
  335. /**
  336. * Attempt to deny a pending payment
  337. *
  338. * @param InfoInterface|Payment $payment
  339. * @return bool
  340. */
  341. public function denyPayment(InfoInterface $payment)
  342. {
  343. parent::denyPayment($payment);
  344. return $this->_pro->reviewPayment($payment, \Magento\Paypal\Model\Pro::PAYMENT_REVIEW_DENY);
  345. }
  346. /**
  347. * Fetch transaction details info
  348. *
  349. * @param InfoInterface $payment
  350. * @param string $transactionId
  351. * @return array
  352. */
  353. public function fetchTransactionInfo(InfoInterface $payment, $transactionId)
  354. {
  355. return $this->_pro->fetchTransactionInfo($payment, $transactionId);
  356. }
  357. /**
  358. * Place an order with authorization or capture action
  359. *
  360. * @param Payment $payment
  361. * @param float $amount
  362. * @return $this
  363. */
  364. protected function _placeOrder(Payment $payment, $amount)
  365. {
  366. $order = $payment->getOrder();
  367. /** @var \Magento\Paypal\Model\Billing\Agreement $billingAgreement */
  368. $billingAgreement = $this->_agreementFactory->create()->load(
  369. $payment->getAdditionalInformation(
  370. \Magento\Paypal\Model\Payment\Method\Billing\AbstractAgreement::TRANSPORT_BILLING_AGREEMENT_ID
  371. )
  372. );
  373. $cart = $this->_cartFactory->create(['salesModel' => $order]);
  374. $proConfig = $this->_pro->getConfig();
  375. $api = $this->_pro->getApi()->setReferenceId(
  376. $billingAgreement->getReferenceId()
  377. )->setPaymentAction(
  378. $proConfig->getValue('paymentAction')
  379. )->setAmount(
  380. $amount
  381. )->setCurrencyCode(
  382. $payment->getOrder()->getBaseCurrencyCode()
  383. )->setNotifyUrl(
  384. $this->_urlBuilder->getUrl('paypal/ipn/')
  385. )->setPaypalCart(
  386. $cart
  387. )->setIsLineItemsEnabled(
  388. $proConfig->getValue('lineItemsEnabled')
  389. )->setInvNum(
  390. $order->getIncrementId()
  391. );
  392. // call api and import transaction and other payment information
  393. $api->callDoReferenceTransaction();
  394. $this->_pro->importPaymentInfo($api, $payment);
  395. $api->callGetTransactionDetails();
  396. $this->_pro->importPaymentInfo($api, $payment);
  397. $payment->setTransactionId($api->getTransactionId())->setIsTransactionClosed(0);
  398. if ($api->getBillingAgreementId()) {
  399. $order->addRelatedObject($billingAgreement);
  400. $billingAgreement->setIsObjectChanged(true);
  401. $billingAgreement->addOrderRelation($order);
  402. }
  403. return $this;
  404. }
  405. /**
  406. * @param object $quote
  407. * @return bool
  408. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  409. */
  410. protected function _isAvailable($quote)
  411. {
  412. return $this->_pro->getConfig()->isMethodAvailable($this->_code);
  413. }
  414. /**
  415. * Payment action getter compatible with payment model
  416. *
  417. * @see \Magento\Sales\Model\Payment::place()
  418. * @return string
  419. */
  420. public function getConfigPaymentAction()
  421. {
  422. return $this->_pro->getConfig()->getPaymentAction();
  423. }
  424. }