Skip to content

Conversation

@SGFGOV
Copy link
Contributor

@SGFGOV SGFGOV commented Oct 24, 2025

Added a few extra fields to capture some of line item and card related data in the custom fields

Summary by CodeRabbit

  • New Features

    • Expanded transaction line items with enhanced details including product codes, commodity codes, descriptions, URLs, tax and discount amounts.
    • Added card details validation support for payment initiation.
  • Chores

    • Updated plugin version to 0.0.15.

@coderabbitai
Copy link

coderabbitai bot commented Oct 24, 2025

Walkthrough

The PR bumps the Braintree payment plugin to version 0.0.15 and integrates cart service functionality into BraintreeBase. Transaction request creation is now asynchronous and includes cart validation, enhanced line item construction with extended fields, and expanded validation schema for card details.

Changes

Cohort / File(s) Summary
Version Update
plugins/braintree-payment/package.json
Bumped plugin version from 0.0.14 to 0.0.15.
Cart Integration & Async Transaction Builder
plugins/braintree-payment/src/providers/payment-braintree/src/core/braintree-base.ts
Added cartService property (ICartModuleService); made getTransactionCreateRequestBody async and updated callers to await it; enhanced line item construction with extended fields (name, productCode, commodityCode, description, url, unitOfMeasure, taxAmount, discountAmount, quantity, unitAmount, totalAmount, unitTaxAmount); added cart validation by cart_id; extended validation schema with optional cardDetails object.

Sequence Diagram

sequenceDiagram
    participant Caller as Caller (initiatePayment/<br/>createTransaction)
    participant BraintreeBase as BraintreeBase
    participant CartService as CartService
    participant Braintree as Braintree API

    Caller->>BraintreeBase: initiatePayment() / createTransaction()
    
    Note over BraintreeBase: New: Async flow
    BraintreeBase->>BraintreeBase: getTransactionCreateRequestBody() [async]
    
    BraintreeBase->>CartService: retrieve cart by cart_id
    CartService-->>BraintreeBase: CartDTO
    
    alt Cart found
        BraintreeBase->>BraintreeBase: Build enhanced line items<br/>(with cart currency,<br/>extended fields)
        BraintreeBase-->>Caller: Promise<TransactionRequest>
        Caller->>Braintree: submit transaction
        Braintree-->>Caller: response
    else Cart not found
        BraintreeBase-->>Caller: throw NOT_FOUND error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Fix/cached token 2 #21: Modifies the same BraintreeBase provider core, introducing changes to public API surface and async behaviors that align with this PR's structural refactoring.
  • Export types from braintree-payment plugin #18: Touches Braintree core types and class declarations; this PR's modifications to BraintreeBase signature and public member exports build upon that foundation.

Suggested reviewers

  • antony-lambdacurry
  • dwene

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The title "Fix additional card validation" refers to only one aspect of the changeset—the extension of the validation schema with cardDetails fields—while the primary changes involve significant architectural modifications: cart service integration, async transaction creation refactoring, and substantial line item construction expansion (with multiple new fields like productCode, commodityCode, description, url, etc.). Additionally, the verb "Fix" is misleading, as the PR description indicates these are additions rather than bug fixes ("Added a few extra fields..."), which misrepresents the nature of the changes to developers scanning the repository history. Consider revising the title to more accurately reflect the primary changes, such as "Add cart integration and expand line item fields in Braintree payment provider" or "Enhance Braintree transaction data with cart integration and extended line items," which would better communicate the scope and nature of the modifications to reviewers and future maintainers.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-additional-card-validation

Comment @coderabbitai help to get the list of available commands and usage tips.

@SGFGOV SGFGOV requested review from dwene and lcmohsen October 24, 2025 17:41
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/braintree-payment/src/providers/payment-braintree/src/core/braintree-base.ts (1)

551-563: Remove unused cardDetails schema validation — type contract mismatch

The BraintreeInitiatePaymentData interface (line 92) only declares payment_method_nonce?: string, but the schema accepts cardDetails (lines 555–561). This creates a type safety violation: the validated data includes fields the return type doesn't declare, and these fields are never used.

Since cardDetails is not in the type interface and is not extracted or persisted in initiatePayment (verified at lines 577–596), remove this schema validation entirely:

const schema = z.object({
  paymentMethodNonce: z.string().optional(),
  payment_method_nonce: z.string().optional(),
-  cardDetails:z.object({
-    cardType: z.string().optional(),
-    lastFour: z.string().optional(),
-    lastTwo: z.string().optional(),
-    expirationMonth: z.string().optional(),
-    expirationYear: z.string().optional(),
-    cardholderName: z.string().optional(),
-  }).optional(),
});
🧹 Nitpick comments (2)
plugins/braintree-payment/package.json (1)

3-3: Version bump to 0.0.15 — proceed, but align release hygiene

  • Make sure CHANGELOG and tag/release notes reflect the async API change and new L2/L3 fields.
  • If the plugin now requires the CART module at runtime, document this in README.
  • Optional: peerDependency "@medusajs/medusa" is pinned to "2.8.2". Consider "^2.8.2" to avoid resolution conflicts when stores upgrade patch/minor.
plugins/braintree-payment/src/providers/payment-braintree/src/core/braintree-base.ts (1)

445-452: Avoid fetching cart just to derive unitOfMeasure; and don’t assume first item’s cart_id

  • Using items[0].cart_id is brittle if items is empty or mixed.
  • You only use cart to set unitOfMeasure later, but unitOfMeasure is not currency. This fetch adds latency for little value.

Consider removing the cart fetch and sourcing unitOfMeasure from item metadata (or default 'EA'), not currency. If you keep the fetch, prefer a cart_id from context rather than inferring from the first item.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between cb6277e and ee1e624.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (2)
  • plugins/braintree-payment/package.json (1 hunks)
  • plugins/braintree-payment/src/providers/payment-braintree/src/core/braintree-base.ts (9 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
plugins/braintree-payment/src/providers/payment-braintree/src/core/braintree-base.ts (1)
plugins/braintree-payment/src/providers/payment-braintree/src/types/index.ts (1)
  • BraintreeOptions (3-12)
🔇 Additional comments (3)
plugins/braintree-payment/src/providers/payment-braintree/src/core/braintree-base.ts (3)

21-33: New CartDTO/ICartModuleService imports — OK

Imports look correct for using Modules.CART.

Confirm runtime availability of Modules.CART in all environments where this plugin runs (local, worker, background processors). If it can be absent, add a guard in constructor.


399-416: Async request body — LGTM

Changing getTransactionCreateRequestBody to async is appropriate given the cart fetch. Call sites updated below.

Also applies to: 413-413


615-622: Awaiting async request body — LGTM

Call site updated to await the async builder.

Please re-run typecheck and end-to-end sale flow to ensure no other paths depended on the old sync signature.

Comment on lines +127 to 136
cartService: ICartModuleService;

protected constructor(container: BraintreeConstructorArgs, options: BraintreeOptions) {
super(container, options);

this.options_ = options;
this.logger = container[ContainerRegistrationKeys.LOGGER];
this.cache = container[Modules.CACHE];
this.cartService = container[Modules.CART] as ICartModuleService;
this.init();
Copy link

@coderabbitai coderabbitai bot Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard DI for cartService or declare hard requirement

container[Modules.CART] may be undefined in some deployments, causing a TypeError on use. Either explicitly document CART as a hard requirement or guard the resolution and fallback.

Apply this minimal guard:

-    this.cartService = container[Modules.CART] as ICartModuleService;
+    this.cartService = container[Modules.CART] as ICartModuleService;
+    if (!this.cartService) {
+      this.logger.warn('BraintreeBase: CART module not available; skipping cart-derived fields');
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cartService: ICartModuleService;
protected constructor(container: BraintreeConstructorArgs, options: BraintreeOptions) {
super(container, options);
this.options_ = options;
this.logger = container[ContainerRegistrationKeys.LOGGER];
this.cache = container[Modules.CACHE];
this.cartService = container[Modules.CART] as ICartModuleService;
this.init();
cartService: ICartModuleService;
protected constructor(container: BraintreeConstructorArgs, options: BraintreeOptions) {
super(container, options);
this.options_ = options;
this.logger = container[ContainerRegistrationKeys.LOGGER];
this.cache = container[Modules.CACHE];
this.cartService = container[Modules.CART] as ICartModuleService;
if (!this.cartService) {
this.logger.warn('BraintreeBase: CART module not available; skipping cart-derived fields');
}
this.init();
🤖 Prompt for AI Agents
In
plugins/braintree-payment/src/providers/payment-braintree/src/core/braintree-base.ts
around lines 127 to 136, the DI resolution for cartService uses
container[Modules.CART] directly which can be undefined and cause a TypeError;
add a guard when resolving cartService: check if container[Modules.CART] exists
and either assign it to this.cartService or throw a clear error indicating that
the CART module is required (or assign a safe fallback/null and update usages to
handle absence). Ensure the constructor documents the hard requirement if you
choose to throw, or implement the safe-null pattern and defensive checks where
cartService is used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in Documentation

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SGFGOV, thank you for addressing the concern! Documenting the CART module as a required dependency is a valid approach. This ensures that users of the plugin are aware of the requirement during setup and configuration.

🐰

@lcmohsen lcmohsen merged commit f80de76 into main Oct 27, 2025
1 check passed
Comment on lines +446 to +451
if(context.items?.[0]?.cart_id) {
cart = await this.cartService.retrieveCart(context.items?.[0]?.cart_id as string);
if (!cart) {
throw new MedusaError(MedusaError.Types.NOT_FOUND, 'Cart not found');
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm @SGFGOV it might not have been the best choice to pull in the cart module here. The braintree payment plugin can be used for cart purchases, but also order edit, which doesn't have a cart. Is there a reason you needed to pull in the cart here, instead of including more information here: https://github.com/lambda-curry/360training/blob/dev/apps/medusa/src/workflows/complete-360-cart/complete-360-cart.ts#L254C13-L254C25

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SGFGOV any reason we decided to commit a package-lock when we only use yarn here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants