Version 4.5.0
This commit is contained in:
1 parent
1a0c7fd3c2
commit
f79dcf067a
3791 files changed
+248032
-76372
No files matched your search
@@ -12,7 +12,7 @@
|
||||
namespace IPS\nexus\Gateway;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -41,18 +41,14 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
|
||||
/* Card payments can only be certain currency amounts and require name and billing address */
|
||||
if ( $settings['type'] === 'card' )
|
||||
{
|
||||
/* Supported Currencies via https://developer.paypal.com/docs/integration/direct/rest/currency-codes/ */
|
||||
if ( !\in_array( $amount->currency, array( 'AUD', 'USD', 'CZK', 'DKK', 'HKD', 'ILS', 'CAD', 'EUR', 'MXN', 'NZD', 'NOK', 'PHP', 'PLN', 'JPY', 'GBP', 'RUB', 'SGD', 'SEK', 'CHF', 'THB' ) ) or !$customer->cm_first_name or !$customer->cm_last_name or !$billingAddress )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
/* Card payments require name and billing address */
|
||||
if ( isset( $settings['type'] ) and $settings['type'] === 'card' and ( !$customer->cm_first_name or !$customer->cm_last_name or !$billingAddress ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Billing agreements require a billing address */
|
||||
elseif ( count( $recurrings ) == 1 and ( isset( $settings['billing_agreements'] ) and $settings['billing_agreements'] == 'required' ) and !$billingAddress )
|
||||
elseif ( static::_canProcessRecurringsAsBillingAgreement( $recurrings ) and ( isset( $settings['billing_agreements'] ) and $settings['billing_agreements'] == 'required' ) and !$billingAddress )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -221,20 +217,22 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
/**
|
||||
* Can store cards?
|
||||
*
|
||||
* @param bool $adminCreatableOnly If TRUE, will only return gateways where the admin (opposed to the user) can create a new option
|
||||
* @return bool
|
||||
*/
|
||||
public function canStoreCards()
|
||||
public function canStoreCards( $adminCreatableOnly = FALSE )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
return ( isset( $settings['type'] ) and $settings['type'] === 'card' and $settings['vault'] );
|
||||
return ( isset( $settings['type'] ) and $settings['type'] === 'card' and isset( $settings['vault'] ) and $settings['vault'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin can manually charge using this gateway?
|
||||
*
|
||||
* @param \IPS\nexus\Customer $customer The customer we're wanting to charge
|
||||
* @return bool
|
||||
*/
|
||||
public function canAdminCharge()
|
||||
public function canAdminCharge( \IPS\nexus\Customer $customer )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
return ( isset( $settings['type'] ) and $settings['type'] === 'card' );
|
||||
@@ -248,7 +246,7 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
public function billingAgreements()
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
return ( isset( $settings['type'] ) and $settings['type'] === 'paypal' ) and ( isset( $settings['billing_agreements'] ) and in_array( $settings['billing_agreements'], array( 'required', 'optional' ) ) );
|
||||
return ( ( isset( $settings['type'] ) and $settings['type'] === 'paypal' ) or !isset( $settings['type'] ) ) and ( isset( $settings['billing_agreements'] ) and \in_array( $settings['billing_agreements'], array( 'required', 'optional' ) ) );
|
||||
}
|
||||
|
||||
/* !Payment Gateway */
|
||||
@@ -256,24 +254,25 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
/**
|
||||
* Payment Screen Fields
|
||||
*
|
||||
* @param \IPS\nexus\Invoice $invoice Invoice
|
||||
* @param \IPS\nexus\Money $amount The amount to pay now
|
||||
* @param \IPS\nexus\Customer $member The member the payment screen is for (if in the ACP charging to a member's card) or NULL for currently logged in member
|
||||
* @param array $recurrings Details about recurring costs
|
||||
* @param \IPS\nexus\Invoice $invoice Invoice
|
||||
* @param \IPS\nexus\Money $amount The amount to pay now
|
||||
* @param \IPS\nexus\Customer $member The member the payment screen is for (if in the ACP charging to a member's card) or NULL for currently logged in member
|
||||
* @param array $recurrings Details about recurring costs
|
||||
* @param bool $type 'checkout' means the cusotmer is doing this on the normal checkout screen, 'admin' means the admin is doing this in the ACP, 'card' means the user is just adding a card
|
||||
* @return array
|
||||
*/
|
||||
public function paymentScreen( \IPS\nexus\Invoice $invoice, \IPS\nexus\Money $amount, \IPS\nexus\Customer $member = NULL, $recurrings = array() )
|
||||
public function paymentScreen( \IPS\nexus\Invoice $invoice, \IPS\nexus\Money $amount, \IPS\nexus\Customer $member = NULL, $recurrings = array(), $type = 'checkout' )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
if ( $settings['type'] === 'card' )
|
||||
if ( isset( $settings['type'] ) and $settings['type'] === 'card' )
|
||||
{
|
||||
return array( 'card' => new \IPS\nexus\Form\CreditCard( $this->id . '_card', NULL, TRUE, array(
|
||||
'types' => array( \IPS\nexus\CreditCard::TYPE_VISA, \IPS\nexus\CreditCard::TYPE_MASTERCARD, \IPS\nexus\CreditCard::TYPE_DISCOVER, \IPS\nexus\CreditCard::TYPE_AMERICAN_EXPRESS ),
|
||||
'save' => $settings['vault'] ? $this : NULL,
|
||||
'save' => ( isset( $settings['vault'] ) and $settings['vault'] ) ? $this : NULL,
|
||||
'member' => $member
|
||||
) ) );
|
||||
}
|
||||
elseif ( $settings['billing_agreements'] == 'optional' and count( $recurrings ) == 1 and $invoice->billaddress )
|
||||
elseif ( isset( $settings['billing_agreements'] ) and $settings['billing_agreements'] == 'optional' and static::_canProcessRecurringsAsBillingAgreement( $recurrings ) and $invoice->billaddress )
|
||||
{
|
||||
return array( 'billing_agreement' => new \IPS\Helpers\Form\Checkbox( 'paypal_billing_agreement', TRUE, FALSE ) );
|
||||
}
|
||||
@@ -287,23 +286,24 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
* @param array|\IPS\nexus\Customer\CreditCard $values Values from form OR a stored card object if this gateway supports them
|
||||
* @param \IPS\nexus\Fraud\MaxMind\Request|NULL $maxMind *If* MaxMind is enabled, the request object will be passed here so gateway can additional data before request is made
|
||||
* @param array $recurrings Details about recurring costs
|
||||
* @param string|NULL $source 'checkout' if the customer is doing this at a normal checkout, 'renewal' is an automatically generated renewal invoice, 'manual' is admin manually charging. NULL is unknown
|
||||
* @return \IPS\DateTime|NULL Auth is valid until or NULL to indicate auth is good forever
|
||||
* @throws \LogicException Message will be displayed to user
|
||||
*/
|
||||
public function auth( \IPS\nexus\Transaction $transaction, $values, \IPS\nexus\Fraud\MaxMind\Request $maxMind = NULL, $recurrings = array() )
|
||||
public function auth( \IPS\nexus\Transaction $transaction, $values, \IPS\nexus\Fraud\MaxMind\Request $maxMind = NULL, $recurrings = array(), $source = NULL )
|
||||
{
|
||||
/* We need a transaction ID */
|
||||
$transaction->save();
|
||||
|
||||
/* Do it */
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
if ( $settings['type'] === 'card' )
|
||||
if ( isset( $settings['type'] ) and $settings['type'] === 'card' )
|
||||
{
|
||||
return $this->_cardAuth( is_array( $values ) ? $values[ $this->id . '_card' ] : $values, $transaction, $maxMind );
|
||||
return $this->_cardAuth( \is_array( $values ) ? $values[ $this->id . '_card' ] : $values, $transaction, $maxMind );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( count( $recurrings ) == 1 and ( $settings['billing_agreements'] == 'required' or ( $settings['billing_agreements'] == 'optional' and $values['paypal_billing_agreement'] ) ) )
|
||||
if ( static::_canProcessRecurringsAsBillingAgreement( $recurrings ) and ( $settings['billing_agreements'] == 'required' or ( $settings['billing_agreements'] == 'optional' and $values['paypal_billing_agreement'] ) ) )
|
||||
{
|
||||
foreach ( $recurrings as $recurrance )
|
||||
{
|
||||
@@ -381,8 +381,8 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
'credit_card' => array(
|
||||
'number' => $card->number,
|
||||
'type' => $cardType,
|
||||
'expire_month' => intval( $card->expMonth ),
|
||||
'expire_year' => intval( $card->expYear ),
|
||||
'expire_month' => \intval( $card->expMonth ),
|
||||
'expire_year' => \intval( $card->expYear ),
|
||||
'cvv2' => $card->ccv,
|
||||
'first_name' => $this->_getFirstName( $transaction ),
|
||||
'last_name' => $this->_getLastName( $transaction ),
|
||||
@@ -473,6 +473,8 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
*/
|
||||
protected function _billingAgreementAuth( \IPS\nexus\Transaction $transaction, \IPS\nexus\Fraud\MaxMind\Request $maxMind = NULL, \IPS\nexus\Purchase\RenewalTerm $term, $items )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
|
||||
/* Work out the name */
|
||||
$titles = array();
|
||||
foreach ( $items as $item )
|
||||
@@ -480,110 +482,125 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
$titles[] = ( $item->name . ( $item->quantity > 1 ? " x{$item->quantity}" : '' ) );
|
||||
}
|
||||
$title = implode( ', ', $titles );
|
||||
if ( mb_strlen( $title ) > 128 )
|
||||
if ( mb_strlen( $title ) > 127 )
|
||||
{
|
||||
$title = mb_substr( $title, 0, 125 ) . '...';
|
||||
$title = mb_substr( $title, 0, 124 ) . '...';
|
||||
}
|
||||
$description = sprintf( $transaction->member->language()->get('transaction_number'), $transaction->id );
|
||||
|
||||
/* Create Billing Plan */
|
||||
$paymentDefinitions = array();
|
||||
$definition = array(
|
||||
'name' => 'Payment Definition',
|
||||
'type' => 'REGULAR',
|
||||
/* Create a product */
|
||||
$product = $this->api( 'catalogs/products', array(
|
||||
'name' => $title,
|
||||
'description' => $description,
|
||||
'type' => 'DIGITAL',
|
||||
) );
|
||||
|
||||
/* Create a plan */
|
||||
$renewalAmountIncludingTax = $term->cost->amount->multiply( new \IPS\Math\Number( $term->tax ? ( (string) ( 1 + $term->tax->rate( $transaction->invoice->billaddress ) ) ) : '1' ) );
|
||||
$billingCycle = array(
|
||||
'pricing_scheme' => array(
|
||||
'fixed_price' => array(
|
||||
'currency_code' => $term->cost->currency,
|
||||
'value' => ( new \IPS\nexus\Money( $renewalAmountIncludingTax, $term->cost->currency ) )->amountAsString()
|
||||
),
|
||||
),
|
||||
'frequency' => array(),
|
||||
'tenure_type' => 'REGULAR',
|
||||
'sequence' => 1,
|
||||
'total_cycles' => 0
|
||||
);
|
||||
if ( $term->interval->y )
|
||||
{
|
||||
$definition['frequency_interval'] = $term->interval->y;
|
||||
$definition['frequency'] = 'YEAR';
|
||||
$billingCycle['frequency']['interval_unit'] = 'YEAR';
|
||||
$billingCycle['frequency']['interval_count'] = $term->interval->y;
|
||||
}
|
||||
elseif ( $term->interval->m )
|
||||
{
|
||||
$definition['frequency_interval'] = $term->interval->m;
|
||||
$definition['frequency'] = 'MONTH';
|
||||
$billingCycle['frequency']['interval_unit'] = 'MONTH';
|
||||
$billingCycle['frequency']['interval_count'] = $term->interval->m;
|
||||
}
|
||||
elseif ( $term->interval->d )
|
||||
{
|
||||
$definition['frequency_interval'] = $term->interval->d;
|
||||
$definition['frequency'] = 'DAY';
|
||||
if ( $term->interval->d % 7 == 0 )
|
||||
{
|
||||
$billingCycle['frequency']['interval_unit'] = 'WEEK';
|
||||
$billingCycle['frequency']['interval_count'] = $term->interval->d / 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
$billingCycle['frequency']['interval_unit'] = 'DAY';
|
||||
$billingCycle['frequency']['interval_count'] = $term->interval->d;
|
||||
}
|
||||
}
|
||||
$definition['cycles'] = '0';
|
||||
$definition['amount'] = array(
|
||||
'currency' => $term->cost->currency,
|
||||
'value' => $term->cost->amountAsString()
|
||||
$planDetails = array(
|
||||
'product_id' => $product['id'],
|
||||
'name' => $title,
|
||||
'description' => $description,
|
||||
'billing_cycles' => array(),
|
||||
'payment_preferences' => array(
|
||||
'auto_bill_outstanding' => TRUE,
|
||||
'payment_failure_threshold' => \intval( $settings['billing_agreement_allowed_fails'] )
|
||||
),
|
||||
'taxes' => array(
|
||||
'percentage' => $term->tax ? ( $term->tax->rate( $transaction->invoice->billaddress ) * 100 ) : '0',
|
||||
'inclusive' => TRUE
|
||||
),
|
||||
'quantity_supported' => FALSE
|
||||
);
|
||||
if ( $term->tax )
|
||||
if ( $transaction->amount->amount->compare( $renewalAmountIncludingTax ) === 0 )
|
||||
{
|
||||
$taxableAmount = $term->cost->amount;
|
||||
$taxRate = new \IPS\Math\Number( (string) $term->tax->rate( $transaction->invoice->billaddress ) );
|
||||
$taxAmount = new \IPS\nexus\Money( $taxableAmount->multiply( $taxRate ), $term->cost->currency );
|
||||
|
||||
$definition['charge_models'] = array(
|
||||
array(
|
||||
'type' => 'TAX',
|
||||
'amount' => array(
|
||||
'currency' => $term->cost->currency,
|
||||
'value' => $taxAmount->amountAsString()
|
||||
)
|
||||
),
|
||||
);
|
||||
$planDetails['billing_cycles'][] = $billingCycle;
|
||||
}
|
||||
$paymentDefinitions[] = $definition;
|
||||
$response = $this->api( 'payments/billing-plans', array(
|
||||
'name' => $description,
|
||||
'description' => $title,
|
||||
'type' => 'INFINITE',
|
||||
'payment_definitions' => $paymentDefinitions,
|
||||
'merchant_preferences' => array(
|
||||
'setup_fee' => array(
|
||||
'currency' => $transaction->amount->currency,
|
||||
'value' => $transaction->amount->amountAsString(),
|
||||
else
|
||||
{
|
||||
$planDetails['billing_cycles'][] = array(
|
||||
'pricing_scheme' => array(
|
||||
'fixed_price' => array(
|
||||
'currency_code' => $transaction->amount->currency,
|
||||
'value' => $transaction->amount->amountAsString()
|
||||
),
|
||||
),
|
||||
'cancel_url' => (string) $transaction->invoice->checkoutUrl(),
|
||||
'return_url' => \IPS\Settings::i()->base_url . 'applications/nexus/interface/gateways/paypal.php?billingAgreement=1&nexusTransactionId=' . $transaction->id,
|
||||
'initial_fail_amount_action' => 'CANCEL',
|
||||
'frequency' => $billingCycle['frequency'],
|
||||
'tenure_type' => 'TRIAL',
|
||||
'sequence' => 1,
|
||||
'total_cycles' => 1
|
||||
);
|
||||
|
||||
$billingCycle['sequence'] = 2;
|
||||
$planDetails['billing_cycles'][] = $billingCycle;
|
||||
}
|
||||
$plan = $this->api( 'billing/plans', $planDetails );
|
||||
|
||||
/* Create a subscription */
|
||||
$subscription = $this->api( 'billing/subscriptions', array(
|
||||
'plan_id' => $plan['id'],
|
||||
'quantity' => '1',
|
||||
'subscriber' => array(
|
||||
'name' => array(
|
||||
'given_name' => $this->_getFirstName( $transaction ),
|
||||
'surname' => $this->_getLastName( $transaction )
|
||||
),
|
||||
'email_address' => $transaction->member->email,
|
||||
),
|
||||
'application_context' => array(
|
||||
'brand_name' => \IPS\Settings::i()->board_name,
|
||||
'locale' => $transaction->member->language()->bcp47(),
|
||||
'shipping_preference' => 'NO_SHIPPING',
|
||||
'user_action' => 'SUBSCRIBE_NOW',
|
||||
'payment_method' => array(
|
||||
'payer_selected' => 'PAYPAL',
|
||||
'payee_preferred' => 'UNRESTRICTED',
|
||||
'category' => 'CUSTOMER_PRESENT_RECURRING_FIRST',
|
||||
),
|
||||
'cancel_url' => (string) $transaction->invoice->checkoutUrl(),
|
||||
'return_url' => \IPS\Settings::i()->base_url . 'applications/nexus/interface/gateways/paypal.php?subscription=1&nexusTransactionId=' . $transaction->id,
|
||||
)
|
||||
) );
|
||||
$billingPlanId = $response['id'];
|
||||
|
||||
/* Activate it */
|
||||
$response = $this->api( 'payments/billing-plans/' . $billingPlanId, array(
|
||||
array(
|
||||
'path' => '/',
|
||||
'value' => array(
|
||||
'state' => 'ACTIVE'
|
||||
),
|
||||
'op' => 'replace',
|
||||
)
|
||||
), 'patch' );
|
||||
|
||||
/* Create Billing Agreement */
|
||||
$payerInfo = array( 'email' => $transaction->member->email );
|
||||
if ( $transaction->member->cm_phone )
|
||||
{
|
||||
$payerInfo['phone'] = $transaction->member->cm_phone;
|
||||
}
|
||||
$payerInfo['billing_address'] = $this->_getAddress( $transaction->invoice->billaddress, $transaction->invoice->member );
|
||||
$billingAgreementData = array(
|
||||
'name' => $description,
|
||||
'description' => $title,
|
||||
'start_date' => \IPS\DateTime::create()->add( $term->interval )->rfc3339(),
|
||||
'payer' => array(
|
||||
'payment_method' => 'paypal',
|
||||
'payer_info' => $payerInfo,
|
||||
)
|
||||
);
|
||||
if ( $transaction->invoice->shipaddress )
|
||||
{
|
||||
$billingAgreementData['shipping_address'] = $this->_getAddress( $transaction->invoice->shipaddress, $transaction->invoice->member );
|
||||
}
|
||||
$billingAgreementData['plan'] = array( 'id' => $billingPlanId );
|
||||
$response = $this->api( 'payments/billing-agreements', $billingAgreementData );
|
||||
|
||||
/* Redirect */
|
||||
foreach ( $response['links'] as $link )
|
||||
foreach ( $subscription['links'] as $link )
|
||||
{
|
||||
if ( $link['rel'] === 'approval_url' )
|
||||
if ( $link['rel'] === 'approve' )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::external( $link['href'] ) );
|
||||
}
|
||||
@@ -628,7 +645,22 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
}
|
||||
else
|
||||
{
|
||||
$authId = $transaction->gw_id;
|
||||
if( $transaction->billing_agreement )
|
||||
{
|
||||
try
|
||||
{
|
||||
$sale = $this->api( "payments/sale/{$transaction->gw_id}", NULL, 'get' );
|
||||
return $this->refund( $transaction ); // "Sales" came from Billing Agreements and have already been captured
|
||||
}
|
||||
catch ( \IPS\nexus\Gateway\PayPal\Exception $e )
|
||||
{
|
||||
$authId = $transaction->gw_id;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$authId = $transaction->gw_id;
|
||||
}
|
||||
}
|
||||
|
||||
/* Void it */
|
||||
@@ -644,37 +676,6 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
*/
|
||||
public function capture( \IPS\nexus\Transaction $transaction )
|
||||
{
|
||||
/* If this is for a billing agreement, it should have automatically been captured - all we need to do is check its status, and if
|
||||
it has been captured, record the ID - otherwise return an error explaining what's going on.
|
||||
The only time we normally get here is if its the initial transaction and PayPal didn't take payment before the user was redirected back
|
||||
(in which case the status will be STATUS_GATEWAY_PENDING) but if has been an issue (with Maxmind, for example) it could be STATUS_HELD */
|
||||
if ( $transaction->billing_agreement )
|
||||
{
|
||||
$response = 'WAIT';
|
||||
$transactions = $this->api( "payments/billing-agreements/{$transaction->billing_agreement->gw_id}/transactions?start_date=" . date( 'Y-m-d', $transaction->date->getTimestamp() - 86400 ) . '&end_date=' . date( 'Y-m-d' ), NULL, 'get' );
|
||||
foreach ( $transactions['agreement_transaction_list'] as $t )
|
||||
{
|
||||
if ( ( !$transaction->gw_id or $transaction->gw_id == $t['transaction_id'] ) and $transaction->amount->currency == $t['amount']['currency'] and $transaction->amount->amountAsString() == $t['amount']['value'] )
|
||||
{
|
||||
if ( $t['status'] == 'Completed' )
|
||||
{
|
||||
$transaction->gw_id = $t['transaction_id'];
|
||||
$transaction->save();
|
||||
return TRUE;
|
||||
}
|
||||
elseif ( $t['status'] == 'Refunded' )
|
||||
{
|
||||
$response = 'RFND';
|
||||
}
|
||||
elseif ( $t['status'] == 'Failed' )
|
||||
{
|
||||
$response = 'FAIL';
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new \RuntimeException( $response );
|
||||
}
|
||||
|
||||
/* Try to find the authorization ID */
|
||||
if ( mb_substr( $transaction->gw_id, 0, 4 ) === 'PAY-' )
|
||||
{
|
||||
@@ -695,7 +696,22 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
}
|
||||
else
|
||||
{
|
||||
$authId = $transaction->gw_id;
|
||||
if( $transaction->billing_agreement )
|
||||
{
|
||||
try
|
||||
{
|
||||
$sale = $this->api( "payments/sale/{$transaction->gw_id}", NULL, 'get' );
|
||||
return TRUE; // "Sales" came from Billing Agreements and have already been captured
|
||||
}
|
||||
catch ( \IPS\nexus\Gateway\PayPal\Exception $e )
|
||||
{
|
||||
$authId = $transaction->gw_id;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$authId = $transaction->gw_id;
|
||||
}
|
||||
}
|
||||
|
||||
/* Capture it */
|
||||
@@ -797,13 +813,38 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'paypal_type', $settings['type'], TRUE, array( 'options' => array( 'paypal' => 'paypal_type_paypal', 'card' => 'paypal_type_card' ), 'toggles' => array( 'paypal' => array( 'paypal_billing_agreements' ), 'card' => array( 'paypal_vault' ) ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'paypal_billing_agreements', $this->id ? ( (string) $settings['billing_agreements'] ) : 'optional', FALSE, array( 'options' => array(
|
||||
'required' => 'paypal_billing_agreements_req',
|
||||
'optional' => 'paypal_billing_agreements_opt',
|
||||
'' => 'paypal_billing_agreements_dis',
|
||||
) ), NULL, NULL, NULL, 'paypal_billing_agreements' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'paypal_vault', $this->id ? $settings['vault'] : TRUE, FALSE, array(), NULL, NULL, NULL, 'paypal_vault' ) );
|
||||
if ( isset( $settings['type'] ) and $settings['type'] === 'card' )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'paypal_type', $settings['type'], TRUE, array( 'options' => array( 'paypal' => 'paypal_type_paypal', 'card' => 'paypal_type_card' ), 'toggles' => array( 'paypal' => array( 'paypal_billing_agreements' ), 'card' => array( 'paypal_vault' ) ) ) ) );
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'paypal_billing_agreements', ( $this->id AND isset( $settings['billing_agreements'] ) ) ? (string) $settings['billing_agreements'] : '', FALSE, array(
|
||||
'options' => array(
|
||||
'required' => 'paypal_billing_agreements_req',
|
||||
'optional' => 'paypal_billing_agreements_opt',
|
||||
'' => 'paypal_billing_agreements_dis',
|
||||
),
|
||||
'toggles' => array(
|
||||
'required' => array( 'paypal_billing_agreement_allowed_fails' ),
|
||||
'optional' => array( 'paypal_billing_agreement_allowed_fails' ),
|
||||
)
|
||||
), function( $val ) {
|
||||
if ( $val )
|
||||
{
|
||||
if ( \IPS\Http\Url::internal('')->data['scheme'] !== 'https' )
|
||||
{
|
||||
throw new \DomainException('paypal_billing_agreements_https');
|
||||
}
|
||||
}
|
||||
}, NULL, NULL, 'paypal_billing_agreements' ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'paypal_billing_agreement_allowed_fails', ( $this->id AND isset( $settings['billing_agreement_allowed_fails'] ) ) ? $settings['billing_agreement_allowed_fails'] : 0, FALSE, array( 'unlimited' => 0, 'min' => 1 ), NULL, \IPS\Member::loggedIn()->language()->addToStack('paypal_billing_agreement_allowed_fails_prefix'), \IPS\Member::loggedIn()->language()->addToStack('paypal_billing_agreement_allowed_fails_suffix'), 'paypal_billing_agreement_allowed_fails' ) );
|
||||
|
||||
if ( isset( $settings['type'] ) and $settings['type'] === 'card' )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'paypal_vault', ( $this->id and isset( $settings['vault'] ) ) ? $settings['vault'] : TRUE, FALSE, array(), NULL, NULL, NULL, 'paypal_vault' ) );
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'paypal_client_id', $settings['client_id'], TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'paypal_secret', $settings['secret'], TRUE ) );
|
||||
}
|
||||
@@ -819,13 +860,51 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->getNewToken( $settings );
|
||||
$token = $this->getNewToken( $settings );
|
||||
$settings['token'] = $token['access_token'];
|
||||
$settings['token_expire'] = ( time() + $token['expires_in'] );
|
||||
|
||||
if ( isset( $settings['billing_agreements'] ) and $settings['billing_agreements'] )
|
||||
{
|
||||
$correctWebhookUrl = \IPS\Settings::i()->base_url . 'applications/nexus/interface/gateways/paypal-webhook.php';
|
||||
$webhookId = NULL;
|
||||
$webhooks = $this->api( 'notifications/webhooks', NULL, 'get', TRUE, $settings );
|
||||
foreach ( $webhooks['webhooks'] as $webhook )
|
||||
{
|
||||
if ( $webhook['url'] === $correctWebhookUrl )
|
||||
{
|
||||
foreach ( $webhook['event_types'] as $eventType )
|
||||
{
|
||||
if ( $eventType['name'] === '*' )
|
||||
{
|
||||
$webhookId = $webhook['id'];
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !$webhookId )
|
||||
{
|
||||
$response = $this->api( 'notifications/webhooks', array(
|
||||
'url' => $correctWebhookUrl,
|
||||
'event_types' => array(
|
||||
array(
|
||||
'name' => '*'
|
||||
)
|
||||
)
|
||||
), 'post', TRUE, $settings );
|
||||
$webhookId = $response['id'];
|
||||
}
|
||||
$settings['webhook_id'] = $webhookId;
|
||||
}
|
||||
|
||||
\IPS\core\AdminNotification::remove( 'nexus', 'ConfigurationError', "pm{$this->id}" );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
throw new \InvalidArgumentException( $e->getMessage() ?: \IPS\Member::loggedIn()->language()->addToStack('paypal_connection_error'), $e->getCode() );
|
||||
}
|
||||
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
@@ -834,24 +913,27 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
/**
|
||||
* Send API Request
|
||||
*
|
||||
* @param string $uri The API to request (e.g. "payments/payment")
|
||||
* @param array $data The data to send
|
||||
* @param string $method Method (get/post)
|
||||
* @parsam bool $expectResponse
|
||||
* @param string $uri The API to request (e.g. "payments/payment")
|
||||
* @param array $data The data to send
|
||||
* @param string $method Method (get/post)
|
||||
* @param array|NULL $settings Settings (NULL for saved setting)
|
||||
* @return array|null
|
||||
* @throws \IPS\Http|Exception
|
||||
* @throws \IPS\nexus\Gateway\PayPal\Exception
|
||||
*/
|
||||
public function api( $uri, $data=NULL, $method='post', $expectResponse=TRUE )
|
||||
public function api( $uri, $data=NULL, $method='post', $expectResponse=TRUE, $settings=NULL )
|
||||
{
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
if ( !isset( $settings['token'] ) or $settings['token_expire'] < time() )
|
||||
if ( !$settings )
|
||||
{
|
||||
$token = $this->getNewToken();
|
||||
$settings['token'] = $token['access_token'];
|
||||
$settings['token_expire'] = ( time() + $token['expires_in'] );
|
||||
$this->settings = json_encode( $settings );
|
||||
$this->save();
|
||||
$settings = json_decode( $this->settings, TRUE );
|
||||
if ( !isset( $settings['token'] ) or $settings['token_expire'] < time() )
|
||||
{
|
||||
$token = $this->getNewToken();
|
||||
$settings['token'] = $token['access_token'];
|
||||
$settings['token_expire'] = ( time() + $token['expires_in'] );
|
||||
$this->settings = json_encode( $settings );
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
$response = \IPS\Http\Url::external( 'https://' . ( \IPS\NEXUS_TEST_GATEWAYS ? 'api.sandbox.paypal.com' : 'api.paypal.com' ) . '/v1/' . $uri )
|
||||
@@ -869,7 +951,7 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
throw new \IPS\nexus\Gateway\PayPal\Exception( $response, mb_substr( $uri, -7 ) === '/refund' );
|
||||
}
|
||||
|
||||
if ( in_array( $method, array( 'delete', 'patch' ) ) or $response->httpResponseCode == 204 )
|
||||
if ( \in_array( $method, array( 'delete', 'patch' ) ) or $response->httpResponseCode == 204 )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@@ -1032,4 +1114,25 @@ class _PayPal extends \IPS\nexus\Gateway
|
||||
|
||||
return $payPalTransactionData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can we handle the renewal terms in a billing agreement?
|
||||
*
|
||||
* @param array $recurrings Details about recurring costs
|
||||
* @return array
|
||||
*/
|
||||
protected static function _canProcessRecurringsAsBillingAgreement( array $recurrings )
|
||||
{
|
||||
if ( \count( $recurrings ) == 1 )
|
||||
{
|
||||
$recurrance = array_pop( $recurrings );
|
||||
|
||||
if ( $recurrance['dueDate']->getTimestamp() === \IPS\DateTime::create()->add( $recurrance['term']->interval )->getTimestamp() )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user