Info.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Paypal\Model;
  7. /**
  8. * PayPal payment information model
  9. *
  10. * Aware of all PayPal payment methods
  11. * Collects and provides access to PayPal-specific payment data
  12. * Provides business logic information about payment flow
  13. */
  14. class Info
  15. {
  16. /**
  17. * Cross-models public exchange keys
  18. *
  19. * @var string
  20. */
  21. const PAYER_ID = 'payer_id';
  22. const PAYER_EMAIL = 'email';
  23. const PAYER_STATUS = 'payer_status';
  24. const ADDRESS_ID = 'address_id';
  25. const ADDRESS_STATUS = 'address_status';
  26. const PROTECTION_EL = 'protection_eligibility';
  27. const FRAUD_FILTERS = 'collected_fraud_filters';
  28. const CORRELATION_ID = 'correlation_id';
  29. const AVS_CODE = 'avs_result';
  30. const AVSADDR = 'avsaddr';
  31. const AVSZIP = 'avszip';
  32. const IAVS = 'iavs';
  33. const CVV2MATCH = 'cvv2match';
  34. const CVV_2_MATCH = 'cvv_2_check_result';
  35. // Next two fields are required for Brazil
  36. const BUYER_TAX_ID = 'buyer_tax_id';
  37. const BUYER_TAX_ID_TYPE = 'buyer_tax_id_type';
  38. const PAYMENT_STATUS = 'payment_status';
  39. const PENDING_REASON = 'pending_reason';
  40. const IS_FRAUD = 'is_fraud_detected';
  41. const PAYMENT_STATUS_GLOBAL = 'paypal_payment_status';
  42. const PENDING_REASON_GLOBAL = 'paypal_pending_reason';
  43. const IS_FRAUD_GLOBAL = 'paypal_is_fraud_detected';
  44. /**
  45. * Possible buyer's tax id types (Brazil only)
  46. */
  47. const BUYER_TAX_ID_TYPE_CPF = 'BR_CPF';
  48. const BUYER_TAX_ID_TYPE_CNPJ = 'BR_CNPJ';
  49. /**
  50. * All payment information map
  51. *
  52. * @var array
  53. */
  54. protected $_paymentMap = [
  55. self::PAYER_ID => self::PAYPAL_PAYER_ID,
  56. self::PAYER_EMAIL => self::PAYPAL_PAYER_EMAIL,
  57. self::PAYER_STATUS => self::PAYPAL_PAYER_STATUS,
  58. self::ADDRESS_ID => self::PAYPAL_ADDRESS_ID,
  59. self::ADDRESS_STATUS => self::PAYPAL_ADDRESS_STATUS,
  60. self::PROTECTION_EL => self::PAYPAL_PROTECTION_ELIGIBILITY,
  61. self::FRAUD_FILTERS => self::PAYPAL_FRAUD_FILTERS,
  62. self::CORRELATION_ID => self::PAYPAL_CORRELATION_ID,
  63. self::AVS_CODE => self::PAYPAL_AVS_CODE,
  64. self::CVV_2_MATCH => self::PAYPAL_CVV_2_MATCH,
  65. self::BUYER_TAX_ID => self::BUYER_TAX_ID,
  66. self::BUYER_TAX_ID_TYPE => self::BUYER_TAX_ID_TYPE,
  67. self::AVSADDR => self::PAYPAL_AVSADDR,
  68. self::AVSZIP => self::PAYPAL_AVSZIP,
  69. self::IAVS => self::PAYPAL_IAVS,
  70. self::CVV2MATCH => self::PAYPAL_CVV2MATCH
  71. ];
  72. /**
  73. * System information map
  74. *
  75. * @var array
  76. */
  77. protected $_systemMap = [
  78. self::PAYMENT_STATUS => self::PAYMENT_STATUS_GLOBAL,
  79. self::PENDING_REASON => self::PENDING_REASON_GLOBAL,
  80. self::IS_FRAUD => self::IS_FRAUD_GLOBAL,
  81. ];
  82. /**
  83. * PayPal payment status possible values
  84. *
  85. * @var string
  86. */
  87. const PAYMENTSTATUS_NONE = 'none';
  88. const PAYMENTSTATUS_COMPLETED = 'completed';
  89. const PAYMENTSTATUS_DENIED = 'denied';
  90. const PAYMENTSTATUS_EXPIRED = 'expired';
  91. const PAYMENTSTATUS_FAILED = 'failed';
  92. const PAYMENTSTATUS_INPROGRESS = 'in_progress';
  93. const PAYMENTSTATUS_PENDING = 'pending';
  94. const PAYMENTSTATUS_REFUNDED = 'refunded';
  95. const PAYMENTSTATUS_REFUNDEDPART = 'partially_refunded';
  96. const PAYMENTSTATUS_REVERSED = 'reversed';
  97. const PAYMENTSTATUS_UNREVERSED = 'canceled_reversal';
  98. const PAYMENTSTATUS_PROCESSED = 'processed';
  99. const PAYMENTSTATUS_VOIDED = 'voided';
  100. const PAYMENTSTATUS_REVIEW = 'paymentreview';
  101. /**
  102. * PayPal payment transaction type
  103. */
  104. const TXN_TYPE_ADJUSTMENT = 'adjustment';
  105. const TXN_TYPE_NEW_CASE = 'new_case';
  106. /**
  107. * PayPal payment reason code when payment_status is Reversed, Refunded, or Canceled_Reversal.
  108. */
  109. const PAYMENT_REASON_CODE_REFUND = 'refund';
  110. /**
  111. * PayPal order status for Reverse payment status
  112. */
  113. const ORDER_STATUS_REVERSED = 'paypal_reversed';
  114. /**
  115. * PayPal order status for Canceled Reversal payment status
  116. */
  117. const ORDER_STATUS_CANCELED_REVERSAL = 'paypal_canceled_reversal';
  118. /**
  119. * Map of payment information available to customer
  120. *
  121. * @var string[]
  122. */
  123. protected $_paymentPublicMap = ['paypal_payer_email', self::BUYER_TAX_ID, self::BUYER_TAX_ID_TYPE];
  124. /**
  125. * Rendered payment map cache
  126. *
  127. * @var array
  128. */
  129. protected $_paymentMapFull = [];
  130. /**
  131. * Cache for storing label translations
  132. *
  133. * @var array
  134. */
  135. protected $_labelCodesCache = [];
  136. /**
  137. * Paypal payer id code key
  138. */
  139. const PAYPAL_PAYER_ID = 'paypal_payer_id';
  140. /**
  141. * Paypal payer email code key
  142. */
  143. const PAYPAL_PAYER_EMAIL = 'paypal_payer_email';
  144. /**
  145. * Paypal payer status code key
  146. */
  147. const PAYPAL_PAYER_STATUS = 'paypal_payer_status';
  148. /**
  149. * Paypal address id code key
  150. */
  151. const PAYPAL_ADDRESS_ID = 'paypal_address_id';
  152. /**
  153. * Paypal address status code key
  154. */
  155. const PAYPAL_ADDRESS_STATUS = 'paypal_address_status';
  156. /**
  157. * Paypal protection eligibility code key
  158. */
  159. const PAYPAL_PROTECTION_ELIGIBILITY = 'paypal_protection_eligibility';
  160. /**
  161. * Paypal fraud filters code key
  162. */
  163. const PAYPAL_FRAUD_FILTERS = 'paypal_fraud_filters';
  164. /**
  165. * Paypal correlation id code key
  166. */
  167. const PAYPAL_CORRELATION_ID = 'paypal_correlation_id';
  168. /**
  169. * Paypal avs code key
  170. */
  171. const PAYPAL_AVS_CODE = 'paypal_avs_code';
  172. /**
  173. * Paypal cvv2 code key
  174. */
  175. const PAYPAL_CVV_2_MATCH = 'paypal_cvv_2_match';
  176. /**
  177. * Item labels key for label codes cache
  178. */
  179. const ITEM_LABELS = 'item labels';
  180. /**
  181. * Paypal avs street code key
  182. */
  183. const PAYPAL_AVSADDR = 'avsaddr';
  184. /**
  185. * Paypal avs zip code key
  186. */
  187. const PAYPAL_AVSZIP = 'avszip';
  188. /**
  189. * Paypal avs international code key
  190. */
  191. const PAYPAL_IAVS = 'iavs';
  192. /**
  193. * Paypal cvv2 code key
  194. */
  195. const PAYPAL_CVV2MATCH = 'cvv2match';
  196. /**
  197. * All available payment info getter
  198. *
  199. * @param \Magento\Payment\Model\InfoInterface $payment
  200. * @param bool $labelValuesOnly
  201. * @return array
  202. */
  203. public function getPaymentInfo(\Magento\Payment\Model\InfoInterface $payment, $labelValuesOnly = false)
  204. {
  205. // collect paypal-specific info
  206. $result = $this->_getFullInfo(array_values($this->_paymentMap), $payment, $labelValuesOnly);
  207. // add last_trans_id
  208. $label = __('Last Transaction ID');
  209. $value = $payment->getLastTransId();
  210. if ($labelValuesOnly) {
  211. $result[(string)$label] = $value;
  212. } else {
  213. $result['last_trans_id'] = ['label' => $label, 'value' => $value];
  214. }
  215. return $result;
  216. }
  217. /**
  218. * Public payment info getter
  219. *
  220. * @param \Magento\Payment\Model\InfoInterface $payment
  221. * @param bool $labelValuesOnly
  222. * @return array
  223. */
  224. public function getPublicPaymentInfo(\Magento\Payment\Model\InfoInterface $payment, $labelValuesOnly = false)
  225. {
  226. return $this->_getFullInfo($this->_paymentPublicMap, $payment, $labelValuesOnly);
  227. }
  228. /**
  229. * Grab data from source and map it into payment
  230. *
  231. * @param array|\Magento\Framework\DataObject|callback $from
  232. * @param \Magento\Payment\Model\InfoInterface $payment
  233. * @return void
  234. */
  235. public function importToPayment($from, \Magento\Payment\Model\InfoInterface $payment)
  236. {
  237. $fullMap = array_merge($this->_paymentMap, $this->_systemMap);
  238. if (is_object($from)) {
  239. $from = [$from, 'getDataUsingMethod'];
  240. }
  241. \Magento\Framework\DataObject\Mapper::accumulateByMap($from, [$payment, 'setAdditionalInformation'], $fullMap);
  242. }
  243. /**
  244. * Grab data from payment and map it into target
  245. *
  246. * @param \Magento\Payment\Model\InfoInterface $payment
  247. * @param array|\Magento\Framework\DataObject|callback $to
  248. * @param array|null $map
  249. * @return array|\Magento\Framework\DataObject
  250. */
  251. public function &exportFromPayment(\Magento\Payment\Model\InfoInterface $payment, $to, array $map = null)
  252. {
  253. $fullMap = array_merge($this->_paymentMap, $this->_systemMap);
  254. \Magento\Framework\DataObject\Mapper::accumulateByMap(
  255. [$payment, 'getAdditionalInformation'],
  256. $to,
  257. $map ? $map : array_flip($fullMap)
  258. );
  259. return $to;
  260. }
  261. /**
  262. * Check whether the payment is in review state
  263. *
  264. * @param \Magento\Payment\Model\InfoInterface $payment
  265. * @return bool
  266. */
  267. public static function isPaymentReviewRequired(\Magento\Payment\Model\InfoInterface $payment)
  268. {
  269. $paymentStatus = $payment->getAdditionalInformation(self::PAYMENT_STATUS_GLOBAL);
  270. if (self::PAYMENTSTATUS_PENDING === $paymentStatus) {
  271. $pendingReason = $payment->getAdditionalInformation(self::PENDING_REASON_GLOBAL);
  272. return !in_array($pendingReason, ['authorization', 'order']);
  273. }
  274. return false;
  275. }
  276. /**
  277. * Check whether fraud order review detected and can be reviewed
  278. *
  279. * @param \Magento\Payment\Model\InfoInterface $payment
  280. * @return bool
  281. */
  282. public static function isFraudReviewAllowed(\Magento\Payment\Model\InfoInterface $payment)
  283. {
  284. return self::isPaymentReviewRequired(
  285. $payment
  286. ) && 1 == $payment->getAdditionalInformation(
  287. self::IS_FRAUD_GLOBAL
  288. );
  289. }
  290. /**
  291. * Check whether the payment is completed
  292. *
  293. * @param \Magento\Payment\Model\InfoInterface $payment
  294. * @return bool
  295. */
  296. public static function isPaymentCompleted(\Magento\Payment\Model\InfoInterface $payment)
  297. {
  298. $paymentStatus = $payment->getAdditionalInformation(self::PAYMENT_STATUS_GLOBAL);
  299. return self::PAYMENTSTATUS_COMPLETED === $paymentStatus;
  300. }
  301. /**
  302. * Check whether the payment was processed successfully
  303. *
  304. * @param \Magento\Payment\Model\InfoInterface $payment
  305. * @return bool
  306. */
  307. public static function isPaymentSuccessful(\Magento\Payment\Model\InfoInterface $payment)
  308. {
  309. $paymentStatus = $payment->getAdditionalInformation(self::PAYMENT_STATUS_GLOBAL);
  310. if (in_array(
  311. $paymentStatus,
  312. [
  313. self::PAYMENTSTATUS_COMPLETED,
  314. self::PAYMENTSTATUS_INPROGRESS,
  315. self::PAYMENTSTATUS_REFUNDED,
  316. self::PAYMENTSTATUS_REFUNDEDPART,
  317. self::PAYMENTSTATUS_UNREVERSED,
  318. self::PAYMENTSTATUS_PROCESSED
  319. ]
  320. )
  321. ) {
  322. return true;
  323. }
  324. $pendingReason = $payment->getAdditionalInformation(self::PENDING_REASON_GLOBAL);
  325. return self::PAYMENTSTATUS_PENDING === $paymentStatus && in_array(
  326. $pendingReason,
  327. ['authorization', 'order']
  328. );
  329. }
  330. /**
  331. * Check whether the payment was processed unsuccessfully or failed
  332. *
  333. * @param \Magento\Payment\Model\InfoInterface $payment
  334. * @return bool
  335. */
  336. public static function isPaymentFailed(\Magento\Payment\Model\InfoInterface $payment)
  337. {
  338. $paymentStatus = $payment->getAdditionalInformation(self::PAYMENT_STATUS_GLOBAL);
  339. return in_array(
  340. $paymentStatus,
  341. [
  342. self::PAYMENTSTATUS_DENIED,
  343. self::PAYMENTSTATUS_EXPIRED,
  344. self::PAYMENTSTATUS_FAILED,
  345. self::PAYMENTSTATUS_REVERSED,
  346. self::PAYMENTSTATUS_VOIDED
  347. ]
  348. );
  349. }
  350. /**
  351. * Explain pending payment reason code
  352. *
  353. * @param string $code
  354. * @return \Magento\Framework\Phrase
  355. * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_html_IPNandPDTVariables
  356. * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_GetTransactionDetails
  357. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  358. */
  359. public static function explainPendingReason($code)
  360. {
  361. switch ($code) {
  362. case 'address':
  363. return __('This customer didn\'t include a confirmed address.');
  364. case 'authorization':
  365. case 'order':
  366. return __('The payment is authorized but not settled.');
  367. case 'echeck':
  368. return __('The payment eCheck is not cleared.');
  369. case 'intl':
  370. return __('The merchant holds a non-U.S. account and doesn\'t have a withdrawal mechanism.');
  371. case 'multi-currency':
  372. // break is intentionally omitted
  373. case 'multi_currency':
  374. // break is intentionally omitted
  375. case 'multicurrency':
  376. return __('The payment currency doesn\'t match any of the merchant\'s balances currency.');
  377. case 'paymentreview':
  378. return __('The payment is pending while it is being reviewed by PayPal for risk.');
  379. case 'unilateral':
  380. return __(
  381. 'The payment is pending because it was made to an email address that '
  382. . 'is not yet registered or confirmed.'
  383. );
  384. case 'verify':
  385. return __('The merchant account is not yet verified.');
  386. case 'upgrade':
  387. return __(
  388. 'The payment was made via credit card.'
  389. . ' In order to receive funds merchant must upgrade account to Business or Premier status.'
  390. );
  391. case 'none':
  392. // break is intentionally omitted
  393. case 'other':
  394. // break is intentionally omitted
  395. default:
  396. return __('Sorry, but something went wrong. Please contact PayPal customer service.');
  397. }
  398. }
  399. /**
  400. * Explain the refund or chargeback reason code
  401. *
  402. * @param string $code
  403. * @return string
  404. * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_html_IPNandPDTVariables
  405. * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_GetTransactionDetails
  406. */
  407. public static function explainReasonCode($code)
  408. {
  409. $comments = [
  410. 'chargeback' => __('A reversal has occurred on this transaction due to a chargeback by your customer.'),
  411. 'guarantee' => __(
  412. 'A reversal has occurred on this transaction due to your customer triggering a money-back guarantee.'
  413. ),
  414. 'buyer-complaint' => __(
  415. 'A reversal has occurred on this transaction due to a'
  416. . ' complaint about the transaction from your customer.'
  417. ),
  418. 'buyer_complaint' => __(
  419. 'A reversal has occurred on this transaction due to a'
  420. . ' complaint about the transaction from your customer.'
  421. ),
  422. 'refund' => __(
  423. 'A reversal has occurred on this transaction because you have given the customer a refund.'
  424. ),
  425. 'adjustment_reversal' => __('Reversal of an adjustment.'),
  426. 'admin_fraud_reversal' => __('Transaction reversal due to fraud detected by PayPal administrators.'),
  427. 'admin_reversal' => __('Transaction reversal by PayPal administrators.'),
  428. 'chargeback_reimbursement' => __('Reimbursement for a chargeback.'),
  429. 'chargeback_settlement' => __('Settlement of a chargeback.'),
  430. 'unauthorized_spoof' => __(
  431. 'A reversal has occurred on this transaction because of a'
  432. . ' customer dispute suspecting unauthorized spoof.'
  433. ),
  434. 'non_receipt' => __('Buyer claims that he did not receive goods or service.'),
  435. 'not_as_described' => __(
  436. 'Buyer claims that the goods or service received differ from'
  437. . ' merchant’s description of the goods or service.'
  438. ),
  439. 'unauthorized' => __('Buyer claims that he/she did not authorize transaction.'),
  440. 'adjustment_reimburse' => __('A case that has been resolved and close requires a reimbursement.'),
  441. 'duplicate' => __('Buyer claims that a possible duplicate payment was made to the merchant.'),
  442. 'merchandise' => __('Buyer claims that the received merchandise is unsatisfactory, defective, or damaged.'),
  443. ];
  444. return isset($comments[$code])
  445. ? $comments[$code]
  446. : __('Unknown reason. Please contact PayPal customer service.');
  447. }
  448. /**
  449. * Whether a reversal/refund can be disputed with PayPal
  450. *
  451. * @param string $code
  452. * @return bool;
  453. */
  454. public static function isReversalDisputable($code)
  455. {
  456. $listOfDisputeCodes = [
  457. 'none' => true,
  458. 'other' => true,
  459. 'chargeback' => true,
  460. 'buyer-complaint' => true,
  461. 'adjustment_reversal' => true,
  462. 'guarantee' => false,
  463. 'refund' => false,
  464. 'chargeback_reimbursement' => false,
  465. 'chargeback_settlement' => false,
  466. ];
  467. return isset($listOfDisputeCodes[$code]) ? $listOfDisputeCodes[$code] : false;
  468. }
  469. /**
  470. * Render info item
  471. *
  472. * @param array $keys
  473. * @param \Magento\Payment\Model\InfoInterface $payment
  474. * @param bool $labelValuesOnly
  475. * @return array
  476. */
  477. protected function _getFullInfo(array $keys, \Magento\Payment\Model\InfoInterface $payment, $labelValuesOnly)
  478. {
  479. $result = [];
  480. foreach ($keys as $key) {
  481. if (!isset($this->_paymentMapFull[$key])) {
  482. $this->_paymentMapFull[$key] = [];
  483. }
  484. if (!isset($this->_paymentMapFull[$key]['label'])) {
  485. if (!$payment->hasAdditionalInformation($key)) {
  486. $this->_paymentMapFull[$key]['label'] = false;
  487. $this->_paymentMapFull[$key]['value'] = false;
  488. } else {
  489. $value = $payment->getAdditionalInformation($key);
  490. $this->_paymentMapFull[$key]['label'] = (string)$this->_getLabel($key);
  491. $this->_paymentMapFull[$key]['value'] = $this->_getValue($value, $key);
  492. }
  493. }
  494. if (!empty($this->_paymentMapFull[$key]['value'])) {
  495. if ($labelValuesOnly) {
  496. $value = $this->_paymentMapFull[$key]['value'];
  497. $value = is_array($value) ? array_map('__', $value) : __($value);
  498. $result[$this->_paymentMapFull[$key]['label']] = $value;
  499. } else {
  500. $result[$key] = $this->_paymentMapFull[$key];
  501. }
  502. }
  503. }
  504. return $result;
  505. }
  506. /**
  507. * Render info item labels
  508. *
  509. * @param string $key
  510. * @return string
  511. */
  512. protected function _getLabel($key)
  513. {
  514. if (!isset($this->_labelCodesCache[self::ITEM_LABELS])) {
  515. $this->_labelCodesCache[self::ITEM_LABELS] = [
  516. self::PAYPAL_PAYER_ID => __('Payer ID'),
  517. self::PAYPAL_PAYER_EMAIL => __('Payer Email'),
  518. self::PAYPAL_PAYER_STATUS => __('Payer Status'),
  519. self::PAYPAL_ADDRESS_ID => __('Payer Address ID'),
  520. self::PAYPAL_ADDRESS_STATUS => __('Payer Address Status'),
  521. self::PAYPAL_PROTECTION_ELIGIBILITY => __('Merchant Protection Eligibility'),
  522. self::PAYPAL_FRAUD_FILTERS => __('Triggered Fraud Filters'),
  523. self::PAYPAL_CORRELATION_ID => __('Last Correlation ID'),
  524. self::PAYPAL_AVS_CODE => __('Address Verification System Response'),
  525. self::PAYPAL_CVV_2_MATCH => __('CVV2 Check Result by PayPal'),
  526. self::PAYPAL_CVV2MATCH => __('CVV2 Check Result by PayPal'),
  527. self::PAYPAL_AVSADDR => __('AVS Street Match'),
  528. self::PAYPAL_AVSZIP => __('AVS zip'),
  529. self::PAYPAL_IAVS => __('International AVS response'),
  530. self::BUYER_TAX_ID => __('Buyer\'s Tax ID'),
  531. self::BUYER_TAX_ID_TYPE => __('Buyer\'s Tax ID Type'),
  532. ];
  533. }
  534. return isset($this->_labelCodesCache[self::ITEM_LABELS][$key])
  535. ? $this->_labelCodesCache[self::ITEM_LABELS][$key]
  536. : '';
  537. }
  538. /**
  539. * Get case type label
  540. *
  541. * @param string $key
  542. * @return string
  543. */
  544. public static function getCaseTypeLabel($key)
  545. {
  546. $labels = [
  547. 'chargeback' => __('Chargeback'),
  548. 'complaint' => __('Complaint'),
  549. 'dispute' => __('Dispute'),
  550. ];
  551. $value = isset($labels[$key]) ? $labels[$key] : '';
  552. return $value;
  553. }
  554. /**
  555. * Apply a filter upon value getting
  556. *
  557. * @param string $value
  558. * @param string $key
  559. * @return string
  560. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  561. */
  562. protected function _getValue($value, $key)
  563. {
  564. $label = '';
  565. $outputValue = implode(', ', (array) $value);
  566. switch ($key) {
  567. case self::PAYPAL_IAVS:
  568. case self::PAYPAL_AVSZIP:
  569. case self::PAYPAL_AVSADDR:
  570. case self::PAYPAL_AVS_CODE:
  571. $label = $this->_getAvsLabel($outputValue);
  572. break;
  573. case self::PAYPAL_CVV2MATCH:
  574. case self::PAYPAL_CVV_2_MATCH:
  575. $label = $this->_getCvv2Label($outputValue);
  576. break;
  577. case self::PAYPAL_FRAUD_FILTERS:
  578. if (is_array($value)) {
  579. return $value;
  580. }
  581. break;
  582. case self::BUYER_TAX_ID_TYPE:
  583. $outputValue = $this->_getBuyerIdTypeValue($outputValue);
  584. // fall-through intentional
  585. default:
  586. return $outputValue;
  587. }
  588. return sprintf('#%s%s', $outputValue, $outputValue == $label ? '' : ': ' . $label);
  589. }
  590. /**
  591. * Attempt to convert AVS check result code into label
  592. *
  593. * @param string $value
  594. * @return string
  595. * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_AVSResponseCodes
  596. */
  597. protected function _getAvsLabel($value)
  598. {
  599. if (!isset($this->_labelCodesCache[self::PAYPAL_AVS_CODE])) {
  600. $this->_labelCodesCache[self::PAYPAL_AVS_CODE] = [
  601. 'A' => __('Matched Address only (no ZIP)'), // Visa, MasterCard, Discover and American Express
  602. 'B' => __('Matched Address only (no ZIP) International'), // international "A"
  603. 'N' => __('No Details matched'),
  604. 'C' => __('No Details matched. International'), // international "N"
  605. 'X' => __('Exact Match.'),
  606. 'D' => __('Exact Match. Address and Postal Code. International'), // international "X"
  607. 'F' => __('Exact Match. Address and Postal Code. UK-specific'), // UK-specific "X"
  608. 'E' => __('N/A. Not allowed for MOTO (Internet/Phone) transactions'),
  609. 'G' => __('N/A. Global Unavailable'),
  610. 'I' => __('N/A. International Unavailable'),
  611. 'Z' => __('Matched five-digit ZIP only (no Address)'),
  612. 'P' => __('Matched Postal Code only (no Address)'), // international "Z"
  613. 'R' => __('N/A. Retry'),
  614. 'S' => __('N/A. Service not Supported'),
  615. 'U' => __('N/A. Unavailable'),
  616. 'W' => __('Matched whole nine-digit ZIP (no Address)'),
  617. 'Y' => __('Yes. Matched Address and five-digit ZIP'),
  618. '0' => __('All the address information matched'), // Maestro and Solo
  619. '1' => __('None of the address information matched'),
  620. '2' => __('Part of the address information matched'),
  621. '3' => __('N/A. The merchant did not provide AVS information'),
  622. '4' => __('N/A. Address not checked, or acquirer had no response. Service not available'),
  623. ];
  624. }
  625. return isset($this->_labelCodesCache[self::PAYPAL_AVS_CODE][$value])
  626. ? $this->_labelCodesCache[self::PAYPAL_AVS_CODE][$value]
  627. : $value;
  628. }
  629. /**
  630. * Attempt to convert CVV2 check result code into label
  631. *
  632. * @param string $value
  633. * @return string
  634. * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_AVSResponseCodes
  635. */
  636. protected function _getCvv2Label($value)
  637. {
  638. if (!isset($this->_labelCodesCache[self::PAYPAL_CVV_2_MATCH])) {
  639. $this->_labelCodesCache[self::PAYPAL_CVV_2_MATCH] = [
  640. // Visa, MasterCard, Discover and American Express
  641. 'M' => __('Matched (CVV2CSC)'),
  642. 'N' => __('No match'),
  643. 'P' => __('N/A. Not processed'),
  644. 'S' => __('N/A. Service not supported'),
  645. 'U' => __('N/A. Service not available'),
  646. 'X' => __('N/A. No response'),
  647. 'Y' => __('Matched (CVV2CSC)'),
  648. // Maestro and Solo
  649. '0' => __('Matched (CVV2)'),
  650. '1' => __('No match'),
  651. '2' => __('N/A. The merchant has not implemented CVV2 code handling'),
  652. '3' => __('N/A. Merchant has indicated that CVV2 is not present on card'),
  653. '4' => __('N/A. Service not available'),
  654. ];
  655. }
  656. return isset($this->_labelCodesCache[self::PAYPAL_CVV_2_MATCH][$value])
  657. ? $this->_labelCodesCache[self::PAYPAL_CVV_2_MATCH][$value]
  658. : $value;
  659. }
  660. /**
  661. * Retrieve buyer id type value based on code received from PayPal (Brazil only)
  662. *
  663. * @param string $code
  664. * @return string
  665. */
  666. protected function _getBuyerIdTypeValue($code)
  667. {
  668. if (!isset($this->_labelCodesCache[self::BUYER_TAX_ID_TYPE])) {
  669. $this->_labelCodesCache[self::BUYER_TAX_ID_TYPE] = [
  670. self::BUYER_TAX_ID_TYPE_CNPJ => __('CNPJ'),
  671. self::BUYER_TAX_ID_TYPE_CPF => __('CPF'),
  672. ];
  673. }
  674. return isset($this->_labelCodesCache[self::BUYER_TAX_ID_TYPE][$code])
  675. ? $this->_labelCodesCache[self::BUYER_TAX_ID_TYPE][$code]
  676. : '';
  677. }
  678. }