1
1
use api_models:: webhooks:: IncomingWebhookEvent ;
2
2
use cards:: CardNumber ;
3
- use common_enums:: {
4
- AttemptStatus , AuthenticationType , CaptureMethod , CountryAlpha2 , Currency , RefundStatus ,
5
- } ;
3
+ use common_enums:: { AttemptStatus , AuthenticationType , CountryAlpha2 , Currency , RefundStatus } ;
6
4
use common_utils:: { errors:: CustomResult , ext_traits:: XmlExt , pii:: Email , types:: FloatMajorUnit } ;
7
5
use error_stack:: { report, Report , ResultExt } ;
8
6
use hyperswitch_domain_models:: {
@@ -351,6 +349,7 @@ pub struct NmiCompleteResponse {
351
349
pub cvvresponse : Option < String > ,
352
350
pub orderid : String ,
353
351
pub response_code : String ,
352
+ customer_vault_id : Option < Secret < String > > ,
354
353
}
355
354
356
355
impl
@@ -377,17 +376,27 @@ impl
377
376
Ok ( PaymentsResponseData :: TransactionResponse {
378
377
resource_id : ResponseId :: ConnectorTransactionId ( item. response . transactionid ) ,
379
378
redirection_data : Box :: new ( None ) ,
380
- mandate_reference : Box :: new ( None ) ,
379
+ mandate_reference : match item. response . customer_vault_id {
380
+ Some ( vault_id) => Box :: new ( Some (
381
+ hyperswitch_domain_models:: router_response_types:: MandateReference {
382
+ connector_mandate_id : Some ( vault_id. expose ( ) ) ,
383
+ payment_method_id : None ,
384
+ mandate_metadata : None ,
385
+ connector_mandate_request_reference_id : None ,
386
+ } ,
387
+ ) ) ,
388
+ None => Box :: new ( None ) ,
389
+ } ,
381
390
connector_metadata : None ,
382
391
network_txn_id : None ,
383
392
connector_response_reference_id : Some ( item. response . orderid ) ,
384
393
incremental_authorization_allowed : None ,
385
394
charges : None ,
386
395
} ) ,
387
- if let Some ( CaptureMethod :: Automatic ) = item. data . request . capture_method {
388
- AttemptStatus :: CaptureInitiated
396
+ if item. data . request . is_auto_capture ( ) ? {
397
+ AttemptStatus :: Charged
389
398
} else {
390
- AttemptStatus :: Authorizing
399
+ AttemptStatus :: Authorized
391
400
} ,
392
401
) ,
393
402
Response :: Declined | Response :: Error => (
@@ -417,6 +426,18 @@ fn get_nmi_error_response(response: NmiCompleteResponse, http_code: u16) -> Erro
417
426
}
418
427
}
419
428
429
+ #[ derive( Debug , Serialize ) ]
430
+ pub struct NmiValidateRequest {
431
+ #[ serde( rename = "type" ) ]
432
+ transaction_type : TransactionType ,
433
+ security_key : Secret < String > ,
434
+ ccnumber : CardNumber ,
435
+ ccexp : Secret < String > ,
436
+ cvv : Secret < String > ,
437
+ orderid : String ,
438
+ customer_vault : CustomerAction ,
439
+ }
440
+
420
441
#[ derive( Debug , Serialize ) ]
421
442
pub struct NmiPaymentsRequest {
422
443
#[ serde( rename = "type" ) ]
@@ -429,6 +450,8 @@ pub struct NmiPaymentsRequest {
429
450
#[ serde( flatten) ]
430
451
merchant_defined_field : Option < NmiMerchantDefinedField > ,
431
452
orderid : String ,
453
+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
454
+ customer_vault : Option < CustomerAction > ,
432
455
}
433
456
434
457
#[ derive( Debug , Serialize ) ]
@@ -462,6 +485,12 @@ pub enum PaymentMethod {
462
485
CardThreeDs ( Box < CardThreeDsData > ) ,
463
486
GPay ( Box < GooglePayData > ) ,
464
487
ApplePay ( Box < ApplePayData > ) ,
488
+ MandatePayment ( Box < MandatePayment > ) ,
489
+ }
490
+
491
+ #[ derive( Debug , Serialize ) ]
492
+ pub struct MandatePayment {
493
+ customer_vault_id : Secret < String > ,
465
494
}
466
495
467
496
#[ derive( Debug , Serialize ) ]
@@ -503,25 +532,70 @@ impl TryFrom<&NmiRouterData<&PaymentsAuthorizeRouterData>> for NmiPaymentsReques
503
532
} ;
504
533
let auth_type: NmiAuthType = ( & item. router_data . connector_auth_type ) . try_into ( ) ?;
505
534
let amount = item. amount ;
506
- let payment_method = PaymentMethod :: try_from ( (
507
- & item. router_data . request . payment_method_data ,
508
- Some ( item. router_data ) ,
509
- ) ) ?;
510
535
511
- Ok ( Self {
512
- transaction_type,
513
- security_key : auth_type. api_key ,
514
- amount,
515
- currency : item. router_data . request . currency ,
516
- payment_method,
517
- merchant_defined_field : item
518
- . router_data
519
- . request
520
- . metadata
521
- . as_ref ( )
522
- . map ( NmiMerchantDefinedField :: new) ,
523
- orderid : item. router_data . connector_request_reference_id . clone ( ) ,
524
- } )
536
+ match item
537
+ . router_data
538
+ . request
539
+ . mandate_id
540
+ . clone ( )
541
+ . and_then ( |mandate_ids| mandate_ids. mandate_reference_id )
542
+ {
543
+ Some ( api_models:: payments:: MandateReferenceId :: ConnectorMandateId (
544
+ connector_mandate_id,
545
+ ) ) => Ok ( Self {
546
+ transaction_type,
547
+ security_key : auth_type. api_key ,
548
+ amount,
549
+ currency : item. router_data . request . currency ,
550
+ payment_method : PaymentMethod :: MandatePayment ( Box :: new ( MandatePayment {
551
+ customer_vault_id : Secret :: new (
552
+ connector_mandate_id
553
+ . get_connector_mandate_id ( )
554
+ . ok_or ( ConnectorError :: MissingConnectorMandateID ) ?,
555
+ ) ,
556
+ } ) ) ,
557
+ merchant_defined_field : item
558
+ . router_data
559
+ . request
560
+ . metadata
561
+ . as_ref ( )
562
+ . map ( NmiMerchantDefinedField :: new) ,
563
+ orderid : item. router_data . connector_request_reference_id . clone ( ) ,
564
+ customer_vault : None ,
565
+ } ) ,
566
+ Some ( api_models:: payments:: MandateReferenceId :: NetworkMandateId ( _) )
567
+ | Some ( api_models:: payments:: MandateReferenceId :: NetworkTokenWithNTI ( _) ) => {
568
+ Err ( ConnectorError :: NotImplemented (
569
+ get_unimplemented_payment_method_error_message ( "nmi" ) ,
570
+ ) ) ?
571
+ }
572
+ None => {
573
+ let payment_method = PaymentMethod :: try_from ( (
574
+ & item. router_data . request . payment_method_data ,
575
+ Some ( item. router_data ) ,
576
+ ) ) ?;
577
+
578
+ Ok ( Self {
579
+ transaction_type,
580
+ security_key : auth_type. api_key ,
581
+ amount,
582
+ currency : item. router_data . request . currency ,
583
+ payment_method,
584
+ merchant_defined_field : item
585
+ . router_data
586
+ . request
587
+ . metadata
588
+ . as_ref ( )
589
+ . map ( NmiMerchantDefinedField :: new) ,
590
+ orderid : item. router_data . connector_request_reference_id . clone ( ) ,
591
+ customer_vault : item
592
+ . router_data
593
+ . request
594
+ . is_mandate_payment ( )
595
+ . then_some ( CustomerAction :: AddCustomer ) ,
596
+ } )
597
+ }
598
+ }
525
599
}
526
600
}
527
601
@@ -670,20 +744,36 @@ impl TryFrom<&ApplePayWalletData> for PaymentMethod {
670
744
}
671
745
}
672
746
673
- impl TryFrom < & SetupMandateRouterData > for NmiPaymentsRequest {
747
+ impl TryFrom < & SetupMandateRouterData > for NmiValidateRequest {
674
748
type Error = Error ;
675
749
fn try_from ( item : & SetupMandateRouterData ) -> Result < Self , Self :: Error > {
676
- let auth_type: NmiAuthType = ( & item. connector_auth_type ) . try_into ( ) ?;
677
- let payment_method = PaymentMethod :: try_from ( ( & item. request . payment_method_data , None ) ) ?;
678
- Ok ( Self {
679
- transaction_type : TransactionType :: Validate ,
680
- security_key : auth_type. api_key ,
681
- amount : FloatMajorUnit :: zero ( ) ,
682
- currency : item. request . currency ,
683
- payment_method,
684
- merchant_defined_field : None ,
685
- orderid : item. connector_request_reference_id . clone ( ) ,
686
- } )
750
+ match item. request . amount {
751
+ Some ( amount) if amount > 0 => Err ( ConnectorError :: FlowNotSupported {
752
+ flow : "Setup Mandate with non zero amount" . to_string ( ) ,
753
+ connector : "NMI" . to_string ( ) ,
754
+ }
755
+ . into ( ) ) ,
756
+ _ => {
757
+ if let PaymentMethodData :: Card ( card_details) = & item. request . payment_method_data {
758
+ let auth_type: NmiAuthType = ( & item. connector_auth_type ) . try_into ( ) ?;
759
+ Ok ( Self {
760
+ transaction_type : TransactionType :: Validate ,
761
+ security_key : auth_type. api_key ,
762
+ ccnumber : card_details. card_number . clone ( ) ,
763
+ ccexp : card_details
764
+ . get_card_expiry_month_year_2_digit_with_delimiter ( "" . to_string ( ) ) ?,
765
+ cvv : card_details. card_cvc . clone ( ) ,
766
+ orderid : item. connector_request_reference_id . clone ( ) ,
767
+ customer_vault : CustomerAction :: AddCustomer ,
768
+ } )
769
+ } else {
770
+ Err ( ConnectorError :: NotImplemented (
771
+ get_unimplemented_payment_method_error_message ( "Nmi" ) ,
772
+ )
773
+ . into ( ) )
774
+ }
775
+ }
776
+ }
687
777
}
688
778
}
689
779
754
844
incremental_authorization_allowed : None ,
755
845
charges : None ,
756
846
} ) ,
757
- AttemptStatus :: CaptureInitiated ,
847
+ AttemptStatus :: Charged ,
758
848
) ,
759
849
Response :: Declined | Response :: Error => (
760
850
Err ( get_standard_error_response ( item. response , item. http_code ) ) ,
@@ -835,6 +925,7 @@ pub struct StandardResponse {
835
925
pub cvvresponse : Option < String > ,
836
926
pub orderid : String ,
837
927
pub response_code : String ,
928
+ pub customer_vault_id : Option < Secret < String > > ,
838
929
}
839
930
840
931
impl < T > TryFrom < ResponseRouterData < SetupMandate , StandardResponse , T , PaymentsResponseData > >
@@ -851,7 +942,17 @@ impl<T> TryFrom<ResponseRouterData<SetupMandate, StandardResponse, T, PaymentsRe
851
942
item. response . transactionid . clone ( ) ,
852
943
) ,
853
944
redirection_data : Box :: new ( None ) ,
854
- mandate_reference : Box :: new ( None ) ,
945
+ mandate_reference : match item. response . customer_vault_id {
946
+ Some ( vault_id) => Box :: new ( Some (
947
+ hyperswitch_domain_models:: router_response_types:: MandateReference {
948
+ connector_mandate_id : Some ( vault_id. expose ( ) ) ,
949
+ payment_method_id : None ,
950
+ mandate_metadata : None ,
951
+ connector_mandate_request_reference_id : None ,
952
+ } ,
953
+ ) ) ,
954
+ None => Box :: new ( None ) ,
955
+ } ,
855
956
connector_metadata : None ,
856
957
network_txn_id : None ,
857
958
connector_response_reference_id : Some ( item. response . orderid ) ,
@@ -905,15 +1006,25 @@ impl TryFrom<PaymentsResponseRouterData<StandardResponse>>
905
1006
item. response . transactionid . clone ( ) ,
906
1007
) ,
907
1008
redirection_data : Box :: new ( None ) ,
908
- mandate_reference : Box :: new ( None ) ,
1009
+ mandate_reference : match item. response . customer_vault_id {
1010
+ Some ( vault_id) => Box :: new ( Some (
1011
+ hyperswitch_domain_models:: router_response_types:: MandateReference {
1012
+ connector_mandate_id : Some ( vault_id. expose ( ) ) ,
1013
+ payment_method_id : None ,
1014
+ mandate_metadata : None ,
1015
+ connector_mandate_request_reference_id : None ,
1016
+ } ,
1017
+ ) ) ,
1018
+ None => Box :: new ( None ) ,
1019
+ } ,
909
1020
connector_metadata : None ,
910
1021
network_txn_id : None ,
911
1022
connector_response_reference_id : Some ( item. response . orderid ) ,
912
1023
incremental_authorization_allowed : None ,
913
1024
charges : None ,
914
1025
} ) ,
915
- if let Some ( CaptureMethod :: Automatic ) = item. data . request . capture_method {
916
- AttemptStatus :: CaptureInitiated
1026
+ if item. data . request . is_auto_capture ( ) ? {
1027
+ AttemptStatus :: Charged
917
1028
} else {
918
1029
AttemptStatus :: Authorized
919
1030
} ,
@@ -1102,7 +1213,7 @@ impl TryFrom<RefundsResponseRouterData<Capture, StandardResponse>> for RefundsRo
1102
1213
impl From < Response > for RefundStatus {
1103
1214
fn from ( item : Response ) -> Self {
1104
1215
match item {
1105
- Response :: Approved => Self :: Pending ,
1216
+ Response :: Approved => Self :: Success ,
1106
1217
Response :: Declined | Response :: Error => Self :: Failure ,
1107
1218
}
1108
1219
}
0 commit comments