Browse Source

feat(payments-plugin): Make BraintreePlugin metadata configurable

Michael Bromley 3 years ago
parent
commit
99c80e8e8e

+ 9 - 3
packages/payments-plugin/src/braintree/braintree-common.ts

@@ -12,9 +12,11 @@ export function getGateway(args: PaymentMethodArgsHash, options: BraintreePlugin
 }
 
 /**
- * Returns a subset of the Transaction object of interest to the Administrator.
+ * @description
+ * Returns a subset of the Transaction object of interest to the Administrator, plus some
+ * public data which may be useful to display in the storefront account area.
  */
-export function extractMetadataFromTransaction(transaction: Transaction): { [key: string]: any } {
+export function defaultExtractMetadataFn(transaction: Transaction): { [key: string]: any } {
     const metadata: { [key: string]: any } = {
         status: transaction.status,
         currencyIsoCode: transaction.currencyIsoCode,
@@ -25,13 +27,16 @@ export function extractMetadataFromTransaction(transaction: Transaction): { [key
         processorAuthorizationCode: transaction.processorAuthorizationCode,
         processorResponseText: transaction.processorResponseText,
         paymentMethod: transaction.paymentInstrumentType,
+        public: {},
     };
     if (transaction.creditCard && transaction.creditCard.cardType) {
-        metadata.cardData = {
+        const cardData = {
             cardType: transaction.creditCard.cardType,
             last4: transaction.creditCard.last4,
             expirationDate: transaction.creditCard.expirationDate,
         };
+        metadata.cardData = cardData;
+        metadata.public.cardData = cardData;
     }
     if (transaction.paypalAccount && transaction.paypalAccount.authorizationId) {
         metadata.paypalData = {
@@ -42,6 +47,7 @@ export function extractMetadataFromTransaction(transaction: Transaction): { [key
             sellerProtectionStatus: transaction.paypalAccount.sellerProtectionStatus,
             transactionFeeAmount: transaction.paypalAccount.transactionFeeAmount,
         };
+        metadata.public.paypalData = { authorizationId: transaction.paypalAccount.authorizationId };
     }
     return metadata;
 }

+ 7 - 4
packages/payments-plugin/src/braintree/braintree.handler.ts

@@ -11,7 +11,7 @@ import {
 } from '@vendure/core';
 import { BraintreeGateway } from 'braintree';
 
-import { extractMetadataFromTransaction, getGateway } from './braintree-common';
+import { defaultExtractMetadataFn, getGateway } from './braintree-common';
 import { BRAINTREE_PLUGIN_OPTIONS, loggerCtx } from './constants';
 import { BraintreePluginOptions } from './types';
 
@@ -44,7 +44,7 @@ export const braintreePaymentMethodHandler = new PaymentMethodHandler({
             if (options.storeCustomersInBraintree && ctx.activeUserId && customer) {
                 customerId = await getBraintreeCustomerId(ctx, gateway, customer);
             }
-            return processPayment(ctx, gateway, order, amount, metadata.nonce, customerId);
+            return processPayment(ctx, gateway, order, amount, metadata.nonce, customerId, options);
         } catch (e) {
             Logger.error(e, loggerCtx);
             return {
@@ -88,6 +88,7 @@ async function processPayment(
     amount: number,
     paymentMethodNonce: any,
     customerId: string | undefined,
+    pluginOptions: BraintreePluginOptions,
 ) {
     const response = await gateway.transaction.sale({
         customerId,
@@ -99,20 +100,22 @@ async function processPayment(
             storeInVaultOnSuccess: !!customerId,
         },
     });
+    const extractMetadataFn = pluginOptions.extractMetadata ?? defaultExtractMetadataFn;
+    const metadata = extractMetadataFn(response.transaction);
     if (!response.success) {
         return {
             amount,
             state: 'Declined' as const,
             transactionId: response.transaction.id,
             errorMessage: response.message,
-            metadata: extractMetadataFromTransaction(response.transaction),
+            metadata,
         };
     }
     return {
         amount,
         state: 'Settled' as const,
         transactionId: response.transaction.id,
-        metadata: extractMetadataFromTransaction(response.transaction),
+        metadata,
     };
 }
 

+ 56 - 1
packages/payments-plugin/src/braintree/types.ts

@@ -1,6 +1,7 @@
+import { PaymentMetadata } from '@vendure/core';
 import { ConfigArgValues } from '@vendure/core/dist/common/configurable-operation';
 import '@vendure/core/dist/entity/custom-entity-fields';
-import { Environment } from 'braintree';
+import { Environment, Transaction } from 'braintree';
 
 import { braintreePaymentMethodHandler } from './braintree.handler';
 
@@ -39,4 +40,58 @@ export interface BraintreePluginOptions {
      * @default false
      */
     storeCustomersInBraintree?: boolean;
+    /**
+     * @description
+     * Allows you to configure exactly what information from the Braintree
+     * [Transaction object](https://developer.paypal.com/braintree/docs/reference/response/transaction#result-object] (which is returned by the
+     * `transaction.sale()` method of the SDK) should be persisted to the resulting Payment entity metadata.
+     *
+     * By default, the built-in extraction function will return a metadata object that looks like this:
+     *
+     * @example
+     * ```TypeScript
+     * const metadata = {
+     *   "status": "settling",
+     *   "currencyIsoCode": "GBP",
+     *   "merchantAccountId": "my_account_id",
+     *   "cvvCheck": "Not Applicable",
+     *   "avsPostCodeCheck": "Not Applicable",
+     *   "avsStreetAddressCheck": "Not Applicable",
+     *   "processorAuthorizationCode": null,
+     *   "processorResponseText": "Approved",
+     *   // for Paypal payments
+     *   "paymentMethod": "paypal_account",
+     *   "paypalData": {
+     *     "payerEmail": "michael-buyer@paypalsandbox.com",
+     *     "paymentId": "PAYID-MLCXYNI74301746XK8807043",
+     *     "authorizationId": "3BU93594D85624939",
+     *     "payerStatus": "VERIFIED",
+     *     "sellerProtectionStatus": "ELIGIBLE",
+     *     "transactionFeeAmount": "0.54"
+     *   },
+     *   // for credit card payments
+     *   "paymentMethod": "credit_card",
+     *   "cardData": {
+     *     "cardType": "MasterCard",
+     *     "last4": "5454",
+     *     "expirationDate": "02/2023"
+     *   }
+     *   // publicly-available metadata that will be
+     *   // readable from the Shop API
+     *   "public": {
+     *     "cardData": {
+     *       "cardType": "MasterCard",
+     *       "last4": "5454",
+     *       "expirationDate": "02/2023"
+     *     },
+     *     "paypalData": {
+     *       "authorizationId": "3BU93594D85624939",
+     *     }
+     *   }
+     * }
+     * ```
+     *
+     * @since 1.7.0
+     */
+    extractMetadata?: (transaction: Transaction) => PaymentMetadata;
 }