Browse Source

feat(payments-plugin): BraintreePlugin make card vault optional

Closes #1651
Michael Bromley 3 years ago
parent
commit
16ad00cd3b

+ 14 - 3
packages/payments-plugin/src/braintree/braintree.handler.ts

@@ -38,17 +38,27 @@ export const braintreePaymentMethodHandler = new PaymentMethodHandler({
     async createPayment(ctx, order, amount, args, metadata) {
         const gateway = getGateway(args, options);
         let customerId: string | undefined;
+        const { nonce, storeCardInVault } = metadata;
+        if (!nonce) {
+            return {
+                amount,
+                state: 'Error' as const,
+                transactionId: '',
+                errorMessage: `No "nonce" value was specified in the metadata`,
+                metadata,
+            };
+        }
         try {
             await entityHydrator.hydrate(ctx, order, { relations: ['customer'] });
             const customer = order.customer;
             if (options.storeCustomersInBraintree && ctx.activeUserId && customer) {
                 customerId = await getBraintreeCustomerId(ctx, gateway, customer);
             }
-            return processPayment(ctx, gateway, order, amount, metadata.nonce, customerId, options);
+            return processPayment(ctx, gateway, order, amount, nonce, customerId, options, storeCardInVault);
         } catch (e) {
             Logger.error(e, loggerCtx);
             return {
-                amount: order.total,
+                amount,
                 state: 'Error' as const,
                 transactionId: '',
                 errorMessage: e.toString(),
@@ -89,6 +99,7 @@ async function processPayment(
     paymentMethodNonce: any,
     customerId: string | undefined,
     pluginOptions: BraintreePluginOptions,
+    storeCardInVault = true,
 ) {
     const response = await gateway.transaction.sale({
         customerId,
@@ -97,7 +108,7 @@ async function processPayment(
         paymentMethodNonce,
         options: {
             submitForSettlement: true,
-            storeInVaultOnSuccess: !!customerId,
+            storeInVaultOnSuccess: !!customerId && storeCardInVault,
         },
     });
     const extractMetadataFn = pluginOptions.extractMetadata ?? defaultExtractMetadataFn;

+ 42 - 0
packages/payments-plugin/src/braintree/braintree.plugin.ts

@@ -186,7 +186,49 @@ import { BraintreePluginOptions } from './types';
  *         dropin.clearSelectedPaymentMethod();
  *   }
  * }
+ *
+ * ## Storing cards in the vault
+ *
+ * Braintree has a "vault" mechanism which allows it to store the credit card information for a Customer, so that on the next purchase
+ * the stored details do not need to be re-entered.
+ *
+ * To enable this feature, you need to ensure that the {@link BraintreePluginOptions} `storeCustomersInBraintree` option is set to
+ * `true`. This will allow Braintree to associate a unique ID to each of your Customers.
+ *
+ * From v1.7.0, you can then specify on a per-payment basis whether a card should be stored in the vault. By default, all cards will
+ * be automatically stored in the vault. But you can opt out of this behavior by specifying the `storeCardInVault` property in the `metadata` object
+ * supplied to the `addPaymentToOrder` mutation:
+ *
+ * @example
+ * ```TypeScript {hl_lines=[21]}
+ * const { addPaymentToOrder } = await graphQlClient.query(gql`
+ *   mutation AddPayment($input: PaymentInput!) {
+ *     addPaymentToOrder(input: $input) {
+ *       ... on Order {
+ *         id
+ *         payments {
+ *           id
+ *           # ... etc
+ *         }
+ *       }
+ *       ... on ErrorResult {
+ *         errorCode
+ *         message
+ *       }
+ *     }
+ *   }`, {
+ *     input: {
+ *       method: 'braintree',
+ *       metadata: {
+ *         nonce: paymentResult.nonce,
+ *         storeCardInVault: false,
+ *       },
+ *     },
+ *   },
+ * );
  * ```
+ *
+ *
  * @docsCategory payments-plugin
  * @docsPage BraintreePlugin
  */