Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Payflowpro.php
Go to the documentation of this file.
1 <?php
7 namespace Magento\Paypal\Model;
8 
11 use Magento\Payment\Helper\Formatter;
14 use Magento\Payment\Model\Method\ConfigInterfaceFactory;
24 
30 class Payflowpro extends \Magento\Payment\Model\Method\Cc implements GatewayInterface
31 {
32  use Formatter;
33 
37  const TRXTYPE_AUTH_ONLY = 'A';
38 
39  const TRXTYPE_SALE = 'S';
40 
41  const TRXTYPE_CREDIT = 'C';
42 
44 
45  const TRXTYPE_DELAYED_VOID = 'V';
46 
47  const TRXTYPE_DELAYED_VOICE = 'F';
48 
50 
51  const TRXTYPE_ACCEPT_DENY = 'U';
52 
53  const UPDATEACTION_APPROVED = 'APPROVE';
54 
55  const UPDATEACTION_DECLINED_BY_MERCHANT = 'FPS_MERCHANT_DECLINE';
56 
60  const TENDER_CC = 'C';
61 
65  const TRANSACTION_URL = 'https://payflowpro.paypal.com/transaction';
66 
67  const TRANSACTION_URL_TEST_MODE = 'https://pilot-payflowpro.paypal.com/transaction';
68 
73 
75 
77 
79 
81 
83 
85 
87 
88  const PNREF = 'pnref';
89 
92  'firstname' => 'billtofirstname',
93  'lastname' => 'billtolastname',
94  'address' => 'billtostreet',
95  'city' => 'billtocity',
96  'state' => 'billtostate',
97  'zip' => 'billtozip',
98  'country' => 'billtocountry',
99  'phone' => 'billtophone',
100  'email' => 'billtoemail',
101  'nametoship' => 'shiptofirstname',
102  'addresstoship' => 'shiptostreet',
103  'citytoship' => 'shiptocity',
104  'statetoship' => 'shiptostate',
105  'ziptoship' => 'shiptozip',
106  'countrytoship' => 'shiptocountry',
107  'phonetoship' => 'shiptophone',
108  'emailtoship' => 'shiptoemail',
109  'faxtoship' => 'shiptofax',
110  'method' => 'tender',
111  'cscmatch' => 'cvv2match',
112  'type' => 'trxtype',
113  'cclast4' => 'acct',
114  'ccavsstatus' => 'avsdata',
115  'amt' => 'amt',
116  'transtime' => 'transtime',
117  'expdate' => 'expdate',
118  'securetoken' => 'securetoken',
119  'securetokenid' => 'securetokenid',
120  'authcode' => 'authcode',
121  'hostcode' => 'hostcode',
122  'pnref' => 'pnref',
123  'cc_type' => 'cardtype'
124  ];
125 
132  private $ccTypeMap = [
133  '0' => 'VI',
134  '1' => 'MC',
135  '2' => 'DI',
136  '3' => 'AE',
137  '4' => 'DN',
138  '5' => 'JCB'
139  ];
140 
147 
153  protected $_isGateway = true;
154 
160  protected $_canAuthorize = true;
161 
167  protected $_canCapture = true;
168 
174  protected $_canCapturePartial = true;
175 
181  protected $_canRefund = true;
182 
188  protected $_canRefundInvoicePartial = true;
189 
195  protected $_canVoid = true;
196 
202  protected $_canUseInternal = true;
203 
209  protected $_canUseCheckout = true;
210 
216  protected $_canSaveCc = false;
217 
223  protected $_isProxy = false;
224 
230  protected $_canFetchTransactionInfo = true;
231 
237  protected $_canReviewPayment = true;
238 
244  protected $_clientTimeout = 45;
245 
251  protected $_debugReplacePrivateDataKeys = ['user', 'pwd', 'acct', 'expdate', 'cvv2'];
252 
256  protected $storeManager;
257 
261  protected $configFactory;
262 
266  private $config;
267 
271  private $gateway;
272 
276  private $errorHandler;
277 
297  public function __construct(
298  \Magento\Framework\Model\Context $context,
299  \Magento\Framework\Registry $registry,
300  \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,
301  \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory,
302  \Magento\Payment\Helper\Data $paymentData,
303  \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
304  \Magento\Payment\Model\Method\Logger $logger,
305  \Magento\Framework\Module\ModuleListInterface $moduleList,
306  \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
308  ConfigInterfaceFactory $configFactory,
309  Gateway $gateway,
310  HandlerInterface $errorHandler,
311  \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
312  \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
313  array $data = []
314  ) {
315  $this->storeManager = $storeManager;
316  $this->configFactory = $configFactory;
317  $this->gateway = $gateway;
318  parent::__construct(
319  $context,
320  $registry,
321  $extensionFactory,
322  $customAttributeFactory,
323  $paymentData,
324  $scopeConfig,
325  $logger,
326  $moduleList,
327  $localeDate,
328  $resource,
329  $resourceCollection,
330  $data
331  );
332  $this->errorHandler = $errorHandler;
333  }
334 
342  public function isAvailable(\Magento\Quote\Api\Data\CartInterface $quote = null)
343  {
344  return parent::isAvailable($quote) && $this->getConfig()->isMethodAvailable($this->getCode());
345  }
346 
353  public function isActive($storeId = null)
354  {
355  $pathPayflowPro = 'payment/' . Config::METHOD_PAYFLOWPRO . '/active';
356  $pathPaymentPro = 'payment/' . Config::METHOD_PAYMENT_PRO . '/active';
357 
358  return (bool)(int) $this->_scopeConfig->getValue($pathPayflowPro, ScopeInterface::SCOPE_STORE, $storeId)
359  || (bool)(int) $this->_scopeConfig->getValue($pathPaymentPro, ScopeInterface::SCOPE_STORE, $storeId);
360  }
361 
367  public function getConfigPaymentAction()
368  {
369  return $this->getConfig()->getPaymentAction();
370  }
371 
382  {
383  $request = $this->_buildPlaceRequest($payment, $amount);
384  $this->addRequestOrderInfo($request, $payment->getOrder());
385  $request->setTrxtype(self::TRXTYPE_AUTH_ONLY);
386  $response = $this->postRequest($request, $this->getConfig());
387  $this->processErrors($response);
388  $this->setTransStatus($payment, $response);
389  return $this;
390  }
391 
398  protected function _getCaptureAmount($amount)
399  {
400  $infoInstance = $this->getInfoInstance();
401  $amountToPay = $amount;
402  $authorizedAmount = $infoInstance->getAmountAuthorized();
403  return abs($amountToPay - $authorizedAmount) < 0.00001 ? 0 : $amountToPay;
404  }
405 
416  {
417  if ($payment->getAdditionalInformation(self::PNREF)) {
418  $request = $this->buildBasicRequest();
419  $request->setAmt($this->formatPrice($amount));
420  $request->setTrxtype(self::TRXTYPE_SALE);
421  $request->setOrigid($payment->getAdditionalInformation(self::PNREF));
422  $payment->unsAdditionalInformation(self::PNREF);
423  } elseif ($payment->getParentTransactionId()) {
424  $request = $this->buildBasicRequest();
425  $request->setOrigid($payment->getParentTransactionId());
426  $captureAmount = $this->_getCaptureAmount($amount);
427  if ($captureAmount) {
428  $request->setAmt($this->formatPrice($captureAmount));
429  }
430  $trxType = $this->getInfoInstance()->hasAmountPaid() ? self::TRXTYPE_SALE : self::TRXTYPE_DELAYED_CAPTURE;
431  $request->setTrxtype($trxType);
432  } else {
433  $request = $this->_buildPlaceRequest($payment, $amount);
434  $request->setTrxtype(self::TRXTYPE_SALE);
435  }
436  $this->addRequestOrderInfo($request, $payment->getOrder());
437 
438  $response = $this->postRequest($request, $this->getConfig());
439  $this->processErrors($response);
440  $this->setTransStatus($payment, $response);
441  return $this;
442  }
443 
452  public function void(\Magento\Payment\Model\InfoInterface $payment)
453  {
454  $request = $this->buildBasicRequest();
455  $request->setTrxtype(self::TRXTYPE_DELAYED_VOID);
456  $request->setOrigid($payment->getParentTransactionId());
457  $response = $this->postRequest($request, $this->getConfig());
458  $this->processErrors($response);
459 
460  if ($response->getResultCode() == self::RESPONSE_CODE_APPROVED) {
461  $payment->setTransactionId(
462  $response->getPnref()
463  )->setIsTransactionClosed(
464  1
465  )->setShouldCloseParentTransaction(
466  1
467  );
468  }
469 
470  return $this;
471  }
472 
478  public function canVoid()
479  {
480  if ($this->getInfoInstance()->getAmountPaid()) {
481  $this->_canVoid = false;
482  }
483 
484  return $this->_canVoid;
485  }
486 
493  public function cancel(\Magento\Payment\Model\InfoInterface $payment)
494  {
495  if (!$payment->getOrder()->getInvoiceCollection()->count()) {
496  return $this->void($payment);
497  }
498 
499  return false;
500  }
501 
512  {
513  $request = $this->buildBasicRequest();
514  $request->setTrxtype(self::TRXTYPE_CREDIT);
515  $request->setOrigid($payment->getParentTransactionId());
516  $request->setAmt($this->formatPrice($amount));
517  $response = $this->postRequest($request, $this->getConfig());
518  $this->processErrors($response);
519 
520  if ($response->getResultCode() == self::RESPONSE_CODE_APPROVED) {
521  $payment->setTransactionId($response->getPnref())->setIsTransactionClosed(true);
522  }
523  return $this;
524  }
525 
533  public function fetchTransactionInfo(InfoInterface $payment, $transactionId)
534  {
535  $response = $this->transactionInquiryRequest($payment, $transactionId);
536 
537  $this->processErrors($response);
538 
539  if (!$this->_isTransactionUnderReview($response->getOrigresult())) {
540  $payment->setTransactionId($response->getOrigpnref())->setIsTransactionClosed(0);
541  if ($response->getOrigresult() == self::RESPONSE_CODE_APPROVED) {
542  $payment->setIsTransactionApproved(true);
544  $payment->setIsTransactionDenied(true);
545  }
546  }
547 
548  $rawData = $response->getData();
549  return $rawData ? $rawData : [];
550  }
551 
558  protected static function _isTransactionUnderReview($status)
559  {
560  if (in_array($status, [self::RESPONSE_CODE_APPROVED, self::RESPONSE_CODE_DECLINED_BY_MERCHANT])) {
561  return false;
562  }
563  return true;
564  }
565 
571  public function getConfig()
572  {
573  if (!$this->config) {
574  $storeId = $this->storeManager->getStore($this->getStore())->getId();
575 
576  $this->config = $this->configFactory->create();
577 
578  $this->config->setStoreId($storeId);
579  $this->config->setMethodInstance($this);
580  $this->config->setMethod($this);
581  }
582 
583  return $this->config;
584  }
585 
589  public function postRequest(DataObject $request, ConfigInterface $config)
590  {
591  try {
592  return $this->gateway->postRequest($request, $config);
593  } catch (\Zend_Http_Client_Exception $e) {
594  throw new LocalizedException(
595  __('Payment Gateway is unreachable at the moment. Please use another payment option.'),
596  $e
597  );
598  }
599  }
600 
609  {
610  $request = $this->buildBasicRequest();
611  $request->setAmt($this->formatPrice($amount));
612  $request->setAcct($payment->getCcNumber());
613  $request->setExpdate(sprintf('%02d', $payment->getCcExpMonth()) . substr($payment->getCcExpYear(), -2, 2));
614  $request->setCvv2($payment->getCcCid());
615 
616  $order = $payment->getOrder();
617  $request->setCurrency($order->getBaseCurrencyCode());
619  return $request;
620  }
621 
627  public function buildBasicRequest()
628  {
629  $request = new DataObject();
630 
632  $config = $this->getConfig();
633 
634  $request->setUser($this->getConfigData('user'));
635  $request->setVendor($this->getConfigData('vendor'));
636  $request->setPartner($this->getConfigData('partner'));
637  $request->setPwd($this->getConfigData('pwd'));
638  $request->setVerbosity($this->getConfigData('verbosity'));
639  $request->setData('BUTTONSOURCE', $config->getBuildNotationCode());
640  $request->setTender(self::TENDER_CC);
641 
642  return $request;
643  }
644 
654  {
655  if ($response->getResultCode() == self::RESPONSE_CODE_VOID_ERROR) {
656  throw new \Magento\Framework\Exception\State\InvalidTransitionException(
657  __("The verification transaction can't be voided. ")
658  );
659  } elseif ($response->getResultCode() != self::RESPONSE_CODE_APPROVED &&
661  ) {
662  throw new \Magento\Payment\Gateway\Command\CommandException(__($response->getRespmsg()));
664  throw new \Magento\Payment\Gateway\Command\CommandException(__($response->getRespmsg()));
665  }
666  }
667 
675  {
676  return $this->reviewPayment($payment, self::UPDATEACTION_APPROVED);
677  }
678 
686  {
687  return $this->reviewPayment($payment, self::UPDATEACTION_DECLINED_BY_MERCHANT);
688  }
689 
697  public function reviewPayment(InfoInterface $payment, $action)
698  {
699  $request = $this->buildBasicRequest();
700  $transactionId = ($payment->getCcTransId()) ? $payment->getCcTransId() : $payment->getLastTransId();
701  $request->setTrxtype(self::TRXTYPE_ACCEPT_DENY);
702  $request->setOrigid($transactionId);
703  $request->setUpdateaction($action);
704 
705  $response = $this->postRequest($request, $this->getConfig());
706  $payment->setAdditionalInformation((array)$response->getData());
707  $this->processErrors($response);
708 
709  if (!$this->_isTransactionUnderReview($response->getOrigresult())) {
710  $payment->setTransactionId($response->getOrigpnref())->setIsTransactionClosed(0);
711  if ($response->getOrigresult() == self::RESPONSE_CODE_APPROVED) {
712  $payment->setIsTransactionApproved(true);
714  $payment->setIsTransactionDenied(true);
715  }
716  }
717  $rawData = $response->getData();
718  return ($rawData) ? $rawData : [];
719  }
720 
727  public function setBilling(DataObject $request, $billing)
728  {
729  $request->setFirstname(
730  $billing->getFirstname()
731  )->setLastname(
732  $billing->getLastname()
733  )->setStreet(
734  implode(' ', $billing->getStreet())
735  )->setCity(
736  $billing->getCity()
737  )->setState(
738  $billing->getRegionCode()
739  )->setZip(
740  $billing->getPostcode()
741  )->setCountry(
742  $billing->getCountryId()
743  );
744  return $request;
745  }
746 
753  public function setShipping($request, $shipping)
754  {
755  $request->setShiptofirstname(
756  $shipping->getFirstname()
757  )->setShiptolastname(
758  $shipping->getLastname()
759  )->setShiptostreet(
760  implode(' ', $shipping->getStreet())
761  )->setShiptocity(
762  $shipping->getCity()
763  )->setShiptostate(
764  $shipping->getRegionCode()
765  )->setShiptozip(
766  $shipping->getPostcode()
767  )->setShiptocountry(
768  $shipping->getCountryId()
769  );
770  return $request;
771  }
772 
782  {
783  $response->setData(array_change_key_case($postData));
784 
785  foreach ($this->_responseParamsMappings as $originKey => $key) {
786  if ($response->getData($key) !== null) {
787  $response->setData($originKey, $response->getData($key));
788  }
789  }
790 
791  $response->setData(
792  'avsdata',
793  $this->mapResponseAvsData(
794  $response->getData('avsaddr'),
795  $response->getData('avszip')
796  )
797  );
798 
799  $response->setData(
800  'name',
801  $this->mapResponseBillToName(
802  $response->getData('billtofirstname'),
803  $response->getData('billtolastname')
804  )
805  );
806 
807  $response->setData(
809  $this->mapResponseCreditCardType(
811  )
812  );
813 
814  return $response;
815  }
816 
825  {
826  if ($payment instanceof InfoInterface) {
827  $this->errorHandler->handle($payment, $response);
828  }
829 
830  switch ($response->getResultCode()) {
832  $payment->setTransactionId($response->getPnref())->setIsTransactionClosed(0);
833  break;
836  $payment->setTransactionId($response->getPnref())->setIsTransactionClosed(0);
837  $payment->setIsTransactionPending(true);
838  $payment->setIsFraudDetected(true);
839  break;
841  throw new \Magento\Framework\Exception\LocalizedException(
842  __($response->getRespmsg())
843  );
844  default:
845  break;
846  }
847  return $payment;
848  }
849 
856  {
857  $billing = $order->getBillingAddress();
858  if (!empty($billing)) {
859  $request = $this->setBilling($request, $billing);
860  $request->setEmail($order->getCustomerEmail());
861  }
862  $shipping = $order->getShippingAddress();
863  if (!empty($shipping)) {
864  $request = $this->setShipping($request, $shipping);
865  return $request;
866  }
867  return $request;
868  }
869 
877  {
878  $id = $order->getId();
879  // for auth request order id is not exists yet
880  if (!empty($id)) {
881  $request->setPonum($id);
882  }
883  $orderIncrementId = $order->getIncrementId();
884  $request->setCustref($orderIncrementId)
885  ->setInvnum($orderIncrementId)
886  ->setComment1($orderIncrementId);
887  }
888 
896  public function assignData(DataObject $data)
897  {
898  $this->_eventManager->dispatch(
899  'payment_method_assign_data_' . $this->getCode(),
900  [
902  AbstractDataAssignObserver::MODEL_CODE => $this->getInfoInstance(),
904  ]
905  );
906 
907  $this->_eventManager->dispatch(
908  'payment_method_assign_data',
909  [
911  AbstractDataAssignObserver::MODEL_CODE => $this->getInfoInstance(),
913  ]
914  );
915 
916  return $this;
917  }
918 
925  protected function transactionInquiryRequest(InfoInterface $payment, $transactionId)
926  {
927  $request = $this->buildBasicRequest();
928  $request->setTrxtype(self::TRXTYPE_DELAYED_INQUIRY);
929  $transactionId = $payment->getCcTransId() ? $payment->getCcTransId() : $transactionId;
930  $request->setOrigid($transactionId);
931  $response = $this->postRequest($request, $this->getConfig());
932 
933  return $response;
934  }
935 
943  private function mapResponseAvsData($avsAddr, $avsZip)
944  {
945  return isset($avsAddr, $avsZip) ? $avsAddr . $avsZip : null;
946  }
947 
955  private function mapResponseBillToName($billToFirstName, $billToLastName)
956  {
957  return isset($billToFirstName, $billToLastName)
958  ? implode(' ', [$billToFirstName, $billToLastName])
959  : null;
960  }
961 
968  private function mapResponseCreditCardType($ccType)
969  {
970  return isset($this->ccTypeMap[$ccType]) ? $this->ccTypeMap[$ccType] : $ccType;
971  }
972 }
$response
Definition: 404.php:11
fetchTransactionInfo(InfoInterface $payment, $transactionId)
Definition: Payflowpro.php:533
assignData(DataObject $data)
Definition: Payflowpro.php:896
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
capture(\Magento\Payment\Model\InfoInterface $payment, $amount)
Definition: Payflowpro.php:415
denyPayment(InfoInterface $payment)
Definition: Payflowpro.php:685
$config
Definition: fraud_order.php:17
$id
Definition: fieldset.phtml:14
setAdditionalInformation($key, $value=null)
mapGatewayResponse(array $postData, DataObject $response)
Definition: Payflowpro.php:781
$quote
reviewPayment(InfoInterface $payment, $action)
Definition: Payflowpro.php:697
cancel(\Magento\Payment\Model\InfoInterface $payment)
Definition: Payflowpro.php:493
$order
Definition: order.php:55
__()
Definition: __.php:13
$resource
Definition: bulk.php:12
$logger
fillCustomerContacts(DataObject $order, DataObject $request)
Definition: Payflowpro.php:855
transactionInquiryRequest(InfoInterface $payment, $transactionId)
Definition: Payflowpro.php:925
authorize(\Magento\Payment\Model\InfoInterface $payment, $amount)
Definition: Payflowpro.php:381
$amount
Definition: order.php:14
$payment
Definition: order.php:17
static _isTransactionUnderReview($status)
Definition: Payflowpro.php:558
setBilling(DataObject $request, $billing)
Definition: Payflowpro.php:727
addRequestOrderInfo(DataObject $request, Order $order)
Definition: Payflowpro.php:876
refund(\Magento\Payment\Model\InfoInterface $payment, $amount)
Definition: Payflowpro.php:511
acceptPayment(InfoInterface $payment)
Definition: Payflowpro.php:674
void(\Magento\Payment\Model\InfoInterface $payment)
Definition: Payflowpro.php:452
$status
Definition: order_status.php:8
processErrors(DataObject $response)
Definition: Payflowpro.php:653
_buildPlaceRequest(DataObject $payment, $amount)
Definition: Payflowpro.php:608
postRequest(DataObject $request, ConfigInterface $config)
Definition: Payflowpro.php:589
$ccType
Definition: info.phtml:16
isAvailable(\Magento\Quote\Api\Data\CartInterface $quote=null)
Definition: Payflowpro.php:342
setShipping($request, $shipping)
Definition: Payflowpro.php:753
setTransStatus($payment, $response)
Definition: Payflowpro.php:824
__construct(\Magento\Framework\Model\Context $context, \Magento\Framework\Registry $registry, \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory, \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory, \Magento\Payment\Helper\Data $paymentData, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Payment\Model\Method\Logger $logger, \Magento\Framework\Module\ModuleListInterface $moduleList, \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate, \Magento\Store\Model\StoreManagerInterface $storeManager, ConfigInterfaceFactory $configFactory, Gateway $gateway, HandlerInterface $errorHandler, \Magento\Framework\Model\ResourceModel\AbstractResource $resource=null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection=null, array $data=[])
Definition: Payflowpro.php:297