@@ -109,12 +109,17 @@ const validateOptionalString = (value: unknown, fieldName: string): string | und
109109} ;
110110
111111// Error handling utility that preserves full error context
112- export const buildBraintreeError = ( error : unknown , operation : string , logger : Logger , context ?: Record < string , unknown > ) : MedusaError => {
112+ export const buildBraintreeError = (
113+ error : unknown ,
114+ operation : string ,
115+ logger : Logger ,
116+ context ?: Record < string , unknown > ,
117+ ) : MedusaError => {
113118 const errorMessage = error instanceof Error ? error . message : String ( error ) ;
114-
119+
115120 // Preserve full error context in logging
116121 logger . error ( `Braintree ${ operation } failed: ${ errorMessage } ` , error instanceof Error ? error : undefined ) ;
117-
122+
118123 return new MedusaError ( MedusaError . Types . INVALID_DATA , `Failed to ${ operation } : ${ errorMessage } ` ) ;
119124} ;
120125
@@ -216,7 +221,6 @@ class BraintreeBase extends AbstractPaymentProvider<BraintreeOptions> {
216221 }
217222
218223 private formatToTwoDecimalStringIfFinite ( amount : unknown ) : string | undefined {
219-
220224 const n = Number ( amount ) ;
221225 if ( ! Number . isFinite ( n ) ) return undefined ;
222226 return formatToTwoDecimalString ( n ) ;
@@ -337,10 +341,15 @@ class BraintreeBase extends AbstractPaymentProvider<BraintreeOptions> {
337341 if ( ! sessionData . payment_method_nonce )
338342 throw new MedusaError ( MedusaError . Types . INVALID_ARGUMENT , 'Payment method nonce is required' ) ;
339343
340- if ( ! transaction )
341- transaction = await this . createTransaction ( {
342- input,
343- } ) ;
344+ if ( ! transaction ) {
345+ try {
346+ transaction = await this . createTransaction ( {
347+ input,
348+ } ) ;
349+ } catch ( error ) {
350+ throw error ;
351+ }
352+ }
344353
345354 const paymentStatusRequest : GetPaymentStatusInput = {
346355 ...input ,
@@ -363,7 +372,7 @@ class BraintreeBase extends AbstractPaymentProvider<BraintreeOptions> {
363372 } ;
364373 } catch ( error ) {
365374 this . logger . error ( `Error authorizing transaction: ${ error . message } ` , error ) ;
366- throw new MedusaError ( MedusaError . Types . INVALID_DATA , `Failed to authorize transaction` ) ;
375+ throw new MedusaError ( MedusaError . Types . INVALID_DATA , error . message ?? 'Unknown error' ) ;
367376 }
368377 }
369378
@@ -442,14 +451,14 @@ class BraintreeBase extends AbstractPaymentProvider<BraintreeOptions> {
442451 countryCodeAlpha2 : this . sanitizeCountryCodeAlpha2 ( context . shipping_address ?. country_code ) ,
443452 }
444453 : undefined ;
445- let cart : CartDTO | undefined ;
446- if ( context . items ?. [ 0 ] ?. cart_id ) {
447- cart = await this . cartService . retrieveCart ( context . items ?. [ 0 ] ?. cart_id as string ) ;
448- if ( ! cart ) {
449- throw new MedusaError ( MedusaError . Types . NOT_FOUND , 'Cart not found' ) ;
450- }
451- }
452-
454+ let cart : CartDTO | undefined ;
455+ if ( context . items ?. [ 0 ] ?. cart_id ) {
456+ cart = await this . cartService . retrieveCart ( context . items ?. [ 0 ] ?. cart_id as string ) ;
457+ if ( ! cart ) {
458+ throw new MedusaError ( MedusaError . Types . NOT_FOUND , 'Cart not found' ) ;
459+ }
460+ }
461+
453462 const lineItems = context . items
454463 ?. slice ( 0 , 249 )
455464 . map ( ( item ) => {
@@ -464,8 +473,8 @@ class BraintreeBase extends AbstractPaymentProvider<BraintreeOptions> {
464473 kind : 'debit' ,
465474 name : name . substring ( 0 , 127 ) , // Max 127 characters
466475 productCode : ( ( item . metadata ?. productCode as string ) ?? item . product_id ) . substring ( 0 , 12 ) , // Max 12 characters
467- commodityCode : ( ( item . metadata ?. commodityCode as string ) ?? " placeholder" ) . substring ( 0 , 12 ) , // Max 12 characters
468- description : ( item . product_description ?? " Healthcare" ) . substring ( 0 , 127 ) , // Max 127 characters
476+ commodityCode : ( ( item . metadata ?. commodityCode as string ) ?? ' placeholder' ) . substring ( 0 , 12 ) , // Max 12 characters
477+ description : ( item . product_description ?? ' Healthcare' ) . substring ( 0 , 127 ) , // Max 127 characters
469478 url : `/${ item . product_handle } ` . substring ( 0 , 255 ) , // Max 255 characters
470479 unitOfMeasure : ( ( cart ?. currency_code as string ) ?. toUpperCase ( ) ?? 'USD' ) . substring ( 0 , 12 ) , // Max 12 characters
471480 taxAmount : this . formatToTwoDecimalStringIfFinite ( Number ( item . tax_total ) ) , // Must be decimal string
@@ -552,14 +561,16 @@ class BraintreeBase extends AbstractPaymentProvider<BraintreeOptions> {
552561 const schema = z . object ( {
553562 paymentMethodNonce : z . string ( ) . optional ( ) ,
554563 payment_method_nonce : z . string ( ) . optional ( ) ,
555- cardDetails :z . object ( {
556- cardType : z . string ( ) . optional ( ) ,
557- lastFour : z . string ( ) . optional ( ) ,
558- lastTwo : z . string ( ) . optional ( ) ,
559- expirationMonth : z . string ( ) . optional ( ) ,
560- expirationYear : z . string ( ) . optional ( ) ,
561- cardholderName : z . string ( ) . optional ( ) ,
562- } ) . optional ( ) ,
564+ cardDetails : z
565+ . object ( {
566+ cardType : z . string ( ) . optional ( ) ,
567+ lastFour : z . string ( ) . optional ( ) ,
568+ lastTwo : z . string ( ) . optional ( ) ,
569+ expirationMonth : z . string ( ) . optional ( ) ,
570+ expirationYear : z . string ( ) . optional ( ) ,
571+ cardholderName : z . string ( ) . optional ( ) ,
572+ } )
573+ . optional ( ) ,
563574 } ) ;
564575
565576 const result = schema . safeParse ( data ) ;
@@ -626,7 +637,7 @@ class BraintreeBase extends AbstractPaymentProvider<BraintreeOptions> {
626637 if ( ! saleResponse . success ) {
627638 throw new MedusaError (
628639 MedusaError . Types . PAYMENT_AUTHORIZATION_ERROR ,
629- `Failed to create Braintree transaction: ${ JSON . stringify ( saleResponse ) } ` ,
640+ saleResponse . transaction . gatewayRejectionReason ?? 'Unknown error' ,
630641 ) ;
631642 }
632643
@@ -636,7 +647,9 @@ class BraintreeBase extends AbstractPaymentProvider<BraintreeOptions> {
636647 if ( saleResponse . transaction ?. id ) {
637648 await this . gateway . transaction . void ( saleResponse . transaction . id ) ;
638649 }
639- throw buildBraintreeError ( error , 'sync payment session' , this . logger , { transactionId : saleResponse . transaction ?. id } ) ;
650+ throw buildBraintreeError ( error , 'sync payment session' , this . logger , {
651+ transactionId : saleResponse . transaction ?. id ,
652+ } ) ;
640653 }
641654 } catch ( error ) {
642655 throw buildBraintreeError ( error , 'create Braintree transaction' , this . logger ) ;
@@ -660,7 +673,6 @@ class BraintreeBase extends AbstractPaymentProvider<BraintreeOptions> {
660673 } catch ( e ) {
661674 throw buildBraintreeError ( e , 'delete Braintree payment' , this . logger ) ;
662675 }
663-
664676 } else {
665677 return {
666678 data : {
@@ -734,12 +746,12 @@ class BraintreeBase extends AbstractPaymentProvider<BraintreeOptions> {
734746
735747 let shouldVoid = [ 'submitted_for_settlement' , 'authorized' ] . includes ( transaction . status ) ;
736748
737- if ( process . env . TEST_FORCE_SETTLED === 'true' ) {
749+ if ( process . env . TEST_FORCE_SETTLED === 'true' ) {
738750 shouldVoid = false ;
739751 await this . gateway . testing . settle ( transaction . id ) ;
740752 transaction = await this . retrieveTransaction ( transaction . id ) ;
741753 }
742-
754+
743755 if ( shouldVoid ) {
744756 const voidResponse = await this . gateway . transaction . void ( transaction . id ) ;
745757
@@ -785,8 +797,6 @@ class BraintreeBase extends AbstractPaymentProvider<BraintreeOptions> {
785797 `Failed to create Braintree refund: ${ refundResponse . message } ` ,
786798 ) ;
787799
788-
789-
790800 const refundResult : RefundPaymentOutput = {
791801 data : {
792802 ...input . data ,
@@ -896,7 +906,6 @@ class BraintreeBase extends AbstractPaymentProvider<BraintreeOptions> {
896906 } catch ( e ) {
897907 throw buildBraintreeError ( e , 'delete account holder' , this . logger ) ;
898908 }
899-
900909 }
901910
902911 async getWebhookActionAndData ( webhookData : ProviderWebhookPayload [ 'payload' ] ) : Promise < WebhookActionResult > {
0 commit comments