Skip to content

Commit

Permalink
Tokenization for paypal advanced cards
Browse files Browse the repository at this point in the history
  • Loading branch information
turbo124 committed Apr 22, 2024
1 parent 45f378e commit 8d5b8e2
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 45 deletions.
2 changes: 2 additions & 0 deletions app/Models/Gateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ public function getMethods()
GatewayType::PAYPAL => ['refund' => false, 'token_billing' => false],
GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => false],
GatewayType::VENMO => ['refund' => false, 'token_billing' => false],
GatewayType::PAYPAL_ADVANCED_CARDS => ['refund' => false, 'token_billing' => true],
// GatewayType::SEPA => ['refund' => false, 'token_billing' => false],
// GatewayType::BANCONTACT => ['refund' => false, 'token_billing' => false],
// GatewayType::EPS => ['refund' => false, 'token_billing' => false],
Expand All @@ -207,6 +208,7 @@ public function getMethods()
GatewayType::PAYPAL => ['refund' => false, 'token_billing' => false],
GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => false],
GatewayType::VENMO => ['refund' => false, 'token_billing' => false],
GatewayType::PAYPAL_ADVANCED_CARDS => ['refund' => false, 'token_billing' => true],
// GatewayType::SEPA => ['refund' => false, 'token_billing' => false],
// GatewayType::BANCONTACT => ['refund' => false, 'token_billing' => false],
// GatewayType::EPS => ['refund' => false, 'token_billing' => false],
Expand Down
5 changes: 5 additions & 0 deletions app/Models/GatewayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ class GatewayType extends StaticModel

public const PAYLATER = 28;

public const PAYPAL_ADVANCED_CARDS = 29;

public function gateway()
{
return $this->belongsTo(Gateway::class);
Expand Down Expand Up @@ -158,6 +160,9 @@ public static function getAlias($type)
return ctrans('texts.mybank');
case self::PAYLATER:
return ctrans('texts.paypal_paylater');
case self::PAYPAL_ADVANCED_CARDS:
return ctrans('texts.credit_card');

default:
return ' ';
}
Expand Down
61 changes: 61 additions & 0 deletions app/PaymentDrivers/PayPal/PayPalWebhook.php
Original file line number Diff line number Diff line change
Expand Up @@ -399,3 +399,64 @@ private function verifyWebhook(): bool
}
}
*/


/** token created
* {
"id":"WH-1KN88282901968003-82E75604WM969463F",
"event_version":"1.0",
"create_time":"2022-08-15T14:13:48.978Z",
"resource_type":"payment_token",
"resource_version":"3.0",
"event_type":"VAULT.PAYMENT-TOKEN.CREATED",
"summary":"A payment token has been created.",
"resource":{
"time_created":"2022-08-15T07:13:48.964PDT",
"links":[
{
"href":"https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/9n6724m",
"rel":"self",
"method":"GET",
"encType":"application/json"
},
{
"href":"https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/9n6724m",
"rel":"delete",
"method":"DELETE",
"encType":"application/json"
}
],
"id":"9n6724m",
"payment_source":{
"card":{
"last_digits":"1111",
"brand":"VISA",
"expiry":"2027-02",
"billing_address":{
"address_line_1":"2211 N First Street",
"address_line_2":"17.3.160",
"admin_area_2":"San Jose",
"admin_area_1":"CA",
"postal_code":"95131",
"country_code":"US"
}
}
},
"customer":{
"id":"695922590"
}
},
"links":[
{
"href":"https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1KN88282901968003-82E75604WM969463F",
"rel":"self",
"method":"GET"
},
{
"href":"https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1KN88282901968003-82E75604WM969463F/resend",
"rel":"resend",
"method":"POST"
}
]
}
*/
101 changes: 79 additions & 22 deletions app/PaymentDrivers/PayPalRestPaymentDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class PayPalRestPaymentDriver extends BaseDriver
3 => 'paypal',
1 => 'card',
25 => 'venmo',
29 => 'paypal_advanced_cards',
// 9 => 'sepa',
// 12 => 'bancontact',
// 17 => 'eps',
Expand Down Expand Up @@ -117,6 +118,7 @@ private function getPaymentMethod($gateway_type_id): int
"3" => $method = PaymentType::PAYPAL,
"25" => $method = PaymentType::VENMO,
"28" => $method = PaymentType::PAY_LATER,
"29" => $method = PaymentType::CREDIT_CARD_OTHER,
};

return $method;
Expand Down Expand Up @@ -208,6 +210,10 @@ private function getFundingOptions(): string

}

public function processTokenPayment(array $response) {

}

public function processPaymentResponse($request)
{

Expand All @@ -216,6 +222,9 @@ public function processPaymentResponse($request)
$request['gateway_response'] = str_replace("Error: ", "", $request['gateway_response']);
$response = json_decode($request['gateway_response'], true);

if(isset($response['gateway_response']['token']) && strlen($response['gateway_response']['token']) > 2)
return $this->processTokenPayment($response);

// nlog($response);
//capture
$orderID = $response['orderID'];
Expand Down Expand Up @@ -272,6 +281,8 @@ public function processPaymentResponse($request)

if(isset($response['status']) && $response['status'] == 'COMPLETED' && isset($response['purchase_units'])) {

nlog($response->json());

$data = [
'payment_type' => $this->getPaymentMethod($request->gateway_type_id),
'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'],
Expand All @@ -281,8 +292,40 @@ public function processPaymentResponse($request)

$payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);

if ($request->has('store_card') && $request->input('store_card') === true) {
$payment_source = $response->json()['payment_source'];

if(isset($payment_source['card']) && ($payment_source['card']['attributes']['vault']['status'] ?? false) && $payment_source['card']['attributes']['vault']['status'] == 'VAULTED'){

$last4 = $payment_source['card']['last_digits'];
$expiry = $payment_source['card']['expiry']; //'2025-01'
$expiry_meta = explode('-', $expiry);
$brand = $payment_source['card']['brand'];

$payment_meta = new \stdClass();
$payment_meta->exp_month = $expiry_meta[1] ?? '';
$payment_meta->exp_year = $expiry_meta[0] ?? $expiry;
$payment_meta->brand = $brand;
$payment_meta->last4 = $last4;
$payment_meta->type = GatewayType::CREDIT_CARD;

$token = $payment_source['card']['attributes']['vault']['id']; // 09f28652d01257021
$gateway_customer_reference = $payment_source['card']['attributes']['vault']['customer']['id']; //rbTHnLsZqE;

$data['token'] = $token;
$data['payment_method_id'] = GatewayType::PAYPAL_ADVANCED_CARDS;
$data['payment_meta'] = $payment_meta;
$data['payment_method_id'] = GatewayType::CREDIT_CARD;

$additional['gateway_customer_reference'] = $gateway_customer_reference;

$this->storeGatewayToken($data, $additional);

}
}

SystemLogger::dispatch(
['response' => $response, 'data' => $data],
['response' => $response->json(), 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL,
Expand Down Expand Up @@ -329,32 +372,40 @@ private function getClientToken(): string

private function getPaymentSource(): array
{

if($this->gateway_type_id == 1) {
//@todo - roll back here for advanced payments vs hosted card fields.
if($this->gateway_type_id == GatewayType::PAYPAL_ADVANCED_CARDS) {

return [
"card" => [
"attributes" => [
"verification" => [
"method" => "SCA_WHEN_REQUIRED", //SCA_ALWAYS
// "method" => "SCA_ALWAYS", //SCA_ALWAYS
],
"vault" => [
"store_in_vault" => "ON_SUCCESS", //must listen to this webhook - VAULT.PAYMENT-TOKEN.CREATED webhook.
],
],
"name" => $this->client->present()->primary_contact_name(),
"email_address" => $this->client->present()->email(),
"address" => [
"address_line_1" => $this->client->address1,
"address_line_2" => $this->client->address2,
"admin_area_2" => $this->client->city,
"admin_area_1" => $this->client->state,
"postal_code" => $this->client->postal_code,
"country_code" => $this->client->country->iso_3166_2,
],
"experience_context" => [
"user_action" => "PAY_NOW"
],
"experience_context" => [
"shipping_preference" => "SET_PROVIDED_ADDRESS"
],
// "name" => $this->client->present()->primary_contact_name(),
// "email_address" => $this->client->present()->email(),
// "address" => [
// "address_line_1" => $this->client->address1,
// "address_line_2" => $this->client->address2,
// "admin_area_2" => $this->client->city,
// "admin_area_1" => $this->client->state,
// "postal_code" => $this->client->postal_code,
// "country_code" => $this->client->country->iso_3166_2,
// ],
// "experience_context" => [
// "user_action" => "PAY_NOW"
// ],
"stored_credential" => [
"payment_initiator" => "MERCHANT", //"CUSTOMER" who initiated the transaction?
"payment_type" => "UNSCHEDULED",
// "payment_initiator" => "MERCHANT", //"CUSTOMER" who initiated the transaction?
"payment_initiator" => "CUSTOMER", //"" who initiated the transaction?
"payment_type" => "UNSCHEDULED", //UNSCHEDULED
"usage"=> "DERIVED",
],
],
Expand Down Expand Up @@ -406,9 +457,9 @@ private function createOrder(array $data): string
"custom_id" => $this->payment_hash->hash,
"description" => ctrans('texts.invoice_number') . '# ' . $invoice->number,
"invoice_id" => $invoice->number,
"payment_instruction" => [
"disbursement_mode" => "INSTANT",
],
// "payment_instruction" => [
// "disbursement_mode" => "INSTANT",
// ],
$this->getShippingAddress(),
"amount" => [
"value" => (string) $data['amount_with_fee'],
Expand Down Expand Up @@ -440,6 +491,8 @@ private function createOrder(array $data): string
$order['purchase_units'][0]["shipping"] = $shipping;
}

nlog($order);

$r = $this->gatewayRequest('/v2/checkout/orders', 'post', $order);

// nlog($r->json());
Expand All @@ -463,7 +516,11 @@ private function getShippingAddress(): ?array
],
]

: null;
: [
"name" => [
"full_name" => $this->client->present()->name()
]
];

}

Expand Down
1 change: 1 addition & 0 deletions lang/en/texts.php
Original file line number Diff line number Diff line change
Expand Up @@ -5296,6 +5296,7 @@
'rappen_rounding' => 'Rappen Rounding',
'rappen_rounding_help' => 'Round amount to 5 cents',
'assign_group' => 'Assign group',
'paypal_advanced_cards' => 'Advanced Card Payments',
);

return $lang;

0 comments on commit 8d5b8e2

Please sign in to comment.