-
Notifications
You must be signed in to change notification settings - Fork 2k
/
Copy pathadmin.rs
3078 lines (2548 loc) · 134 KB
/
admin.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
use std::collections::{HashMap, HashSet};
use common_types::primitive_wrappers;
use common_utils::{
consts,
crypto::Encryptable,
errors::{self, CustomResult},
ext_traits::Encode,
id_type, link_utils, pii,
};
#[cfg(feature = "v1")]
use common_utils::{crypto::OptionalEncryptableName, ext_traits::ValueExt};
#[cfg(feature = "v2")]
use masking::ExposeInterface;
use masking::{PeekInterface, Secret};
use serde::{Deserialize, Serialize};
use url;
use utoipa::ToSchema;
use super::payments::AddressDetails;
#[cfg(feature = "v1")]
use crate::routing;
use crate::{
consts::{MAX_ORDER_FULFILLMENT_EXPIRY, MIN_ORDER_FULFILLMENT_EXPIRY},
enums as api_enums, payment_methods,
};
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)]
pub struct MerchantAccountListRequest {
pub organization_id: id_type::OrganizationId,
}
#[cfg(feature = "v1")]
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)]
#[serde(deny_unknown_fields)]
pub struct MerchantAccountCreate {
/// The identifier for the Merchant Account
#[schema(value_type = String, max_length = 64, min_length = 1, example = "y3oqhf46pyzuxjbcn2giaqnb44")]
pub merchant_id: id_type::MerchantId,
/// Name of the Merchant Account
#[schema(value_type= Option<String>,example = "NewAge Retailer")]
pub merchant_name: Option<Secret<String>>,
/// Details about the merchant, can contain phone and emails of primary and secondary contact person
pub merchant_details: Option<MerchantDetails>,
/// The URL to redirect after the completion of the operation
#[schema(value_type = Option<String>, max_length = 255, example = "https://www.example.com/success")]
pub return_url: Option<url::Url>,
/// Webhook related details
pub webhook_details: Option<WebhookDetails>,
/// The routing algorithm to be used for routing payments to desired connectors
#[serde(skip)]
#[schema(deprecated)]
pub routing_algorithm: Option<serde_json::Value>,
/// The routing algorithm to be used for routing payouts to desired connectors
#[cfg(feature = "payouts")]
#[schema(value_type = Option<RoutingAlgorithm>,example = json!({"type": "single", "data": "wise"}))]
pub payout_routing_algorithm: Option<serde_json::Value>,
/// A boolean value to indicate if the merchant is a sub-merchant under a master or a parent merchant. By default, its value is false.
#[schema(default = false, example = false)]
pub sub_merchants_enabled: Option<bool>,
/// Refers to the Parent Merchant ID if the merchant being created is a sub-merchant
#[schema(max_length = 255, example = "xkkdf909012sdjki2dkh5sdf", value_type = Option<String>)]
pub parent_merchant_id: Option<id_type::MerchantId>,
/// A boolean value to indicate if payment response hash needs to be enabled
#[schema(default = false, example = true)]
pub enable_payment_response_hash: Option<bool>,
/// Refers to the hash key used for calculating the signature for webhooks and redirect response. If the value is not provided, a value is automatically generated.
pub payment_response_hash_key: Option<String>,
/// A boolean value to indicate if redirect to merchant with http post needs to be enabled.
#[schema(default = false, example = true)]
pub redirect_to_merchant_with_http_post: Option<bool>,
/// Metadata is useful for storing additional, unstructured information on an object
#[schema(value_type = Option<Object>, example = r#"{ "city": "NY", "unit": "245" }"#)]
pub metadata: Option<MerchantAccountMetadata>,
/// API key that will be used for client side API access. A publishable key has to be always paired with a `client_secret`.
/// A `client_secret` can be obtained by creating a payment with `confirm` set to false
#[schema(example = "AH3423bkjbkjdsfbkj")]
pub publishable_key: Option<String>,
/// An identifier for the vault used to store payment method information.
#[schema(example = "locker_abc123")]
pub locker_id: Option<String>,
/// Details about the primary business unit of the merchant account
#[schema(value_type = Option<PrimaryBusinessDetails>)]
pub primary_business_details: Option<Vec<PrimaryBusinessDetails>>,
/// The frm routing algorithm to be used for routing payments to desired FRM's
#[schema(value_type = Option<Object>,example = json!({"type": "single", "data": "signifyd"}))]
pub frm_routing_algorithm: Option<serde_json::Value>,
/// The id of the organization to which the merchant belongs to, if not passed an organization is created
#[schema(value_type = Option<String>, max_length = 64, min_length = 1, example = "org_q98uSGAYbjEwqs0mJwnz")]
pub organization_id: Option<id_type::OrganizationId>,
/// Default payment method collect link config
#[schema(value_type = Option<BusinessCollectLinkConfig>)]
pub pm_collect_link_config: Option<BusinessCollectLinkConfig>,
/// Product Type of this merchant account
#[schema(value_type = Option<MerchantProductType>, example = "Orchestration")]
pub product_type: Option<api_enums::MerchantProductType>,
}
#[cfg(feature = "v1")]
impl MerchantAccountCreate {
pub fn get_merchant_reference_id(&self) -> id_type::MerchantId {
self.merchant_id.clone()
}
pub fn get_payment_response_hash_key(&self) -> Option<String> {
self.payment_response_hash_key.clone().or(Some(
common_utils::crypto::generate_cryptographically_secure_random_string(64),
))
}
pub fn get_primary_details_as_value(
&self,
) -> CustomResult<serde_json::Value, errors::ParsingError> {
self.primary_business_details
.clone()
.unwrap_or_default()
.encode_to_value()
}
pub fn get_pm_link_config_as_value(
&self,
) -> CustomResult<Option<serde_json::Value>, errors::ParsingError> {
self.pm_collect_link_config
.as_ref()
.map(|pm_collect_link_config| pm_collect_link_config.encode_to_value())
.transpose()
}
pub fn get_merchant_details_as_secret(
&self,
) -> CustomResult<Option<pii::SecretSerdeValue>, errors::ParsingError> {
self.merchant_details
.as_ref()
.map(|merchant_details| merchant_details.encode_to_value().map(Secret::new))
.transpose()
}
pub fn get_metadata_as_secret(
&self,
) -> CustomResult<Option<pii::SecretSerdeValue>, errors::ParsingError> {
self.metadata
.as_ref()
.map(|metadata| metadata.encode_to_value().map(Secret::new))
.transpose()
}
pub fn parse_routing_algorithm(&self) -> CustomResult<(), errors::ParsingError> {
match self.routing_algorithm {
Some(ref routing_algorithm) => {
let _: routing::RoutingAlgorithm =
routing_algorithm.clone().parse_value("RoutingAlgorithm")?;
Ok(())
}
None => Ok(()),
}
}
// Get the enable payment response hash as a boolean, where the default value is true
pub fn get_enable_payment_response_hash(&self) -> bool {
self.enable_payment_response_hash.unwrap_or(true)
}
}
#[cfg(feature = "v2")]
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)]
#[serde(deny_unknown_fields)]
#[schema(as = MerchantAccountCreate)]
pub struct MerchantAccountCreateWithoutOrgId {
/// Name of the Merchant Account, This will be used as a prefix to generate the id
#[schema(value_type= String, max_length = 64, example = "NewAge Retailer")]
pub merchant_name: Secret<common_utils::new_type::MerchantName>,
/// Details about the merchant, contains phone and emails of primary and secondary contact person.
pub merchant_details: Option<MerchantDetails>,
/// Metadata is useful for storing additional, unstructured information about the merchant account.
#[schema(value_type = Option<Object>, example = r#"{ "city": "NY", "unit": "245" }"#)]
pub metadata: Option<pii::SecretSerdeValue>,
#[schema(value_type = Option<MerchantProductType>)]
pub product_type: Option<api_enums::MerchantProductType>,
}
// In v2 the struct used in the API is MerchantAccountCreateWithoutOrgId
// The following struct is only used internally, so we can reuse the common
// part of `create_merchant_account` without duplicating its code for v2
#[cfg(feature = "v2")]
#[derive(Clone, Debug, Serialize, ToSchema)]
pub struct MerchantAccountCreate {
pub merchant_name: Secret<common_utils::new_type::MerchantName>,
pub merchant_details: Option<MerchantDetails>,
pub metadata: Option<pii::SecretSerdeValue>,
pub organization_id: id_type::OrganizationId,
/// Product Type of this merchant account
#[schema(value_type = Option<MerchantProductType>)]
pub product_type: Option<api_enums::MerchantProductType>,
}
#[cfg(feature = "v2")]
impl MerchantAccountCreate {
pub fn get_merchant_reference_id(&self) -> id_type::MerchantId {
id_type::MerchantId::from_merchant_name(self.merchant_name.clone().expose())
}
pub fn get_merchant_details_as_secret(
&self,
) -> CustomResult<Option<pii::SecretSerdeValue>, errors::ParsingError> {
self.merchant_details
.as_ref()
.map(|merchant_details| merchant_details.encode_to_value().map(Secret::new))
.transpose()
}
pub fn get_metadata_as_secret(
&self,
) -> CustomResult<Option<pii::SecretSerdeValue>, errors::ParsingError> {
self.metadata
.as_ref()
.map(|metadata| metadata.encode_to_value().map(Secret::new))
.transpose()
}
pub fn get_primary_details_as_value(
&self,
) -> CustomResult<serde_json::Value, errors::ParsingError> {
Vec::<PrimaryBusinessDetails>::new().encode_to_value()
}
}
#[derive(Clone, Debug, Deserialize, Serialize, ToSchema)]
pub struct CardTestingGuardConfig {
/// Determines if Card IP Blocking is enabled for profile
pub card_ip_blocking_status: CardTestingGuardStatus,
/// Determines the unsuccessful payment threshold for Card IP Blocking for profile
pub card_ip_blocking_threshold: i32,
/// Determines if Guest User Card Blocking is enabled for profile
pub guest_user_card_blocking_status: CardTestingGuardStatus,
/// Determines the unsuccessful payment threshold for Guest User Card Blocking for profile
pub guest_user_card_blocking_threshold: i32,
/// Determines if Customer Id Blocking is enabled for profile
pub customer_id_blocking_status: CardTestingGuardStatus,
/// Determines the unsuccessful payment threshold for Customer Id Blocking for profile
pub customer_id_blocking_threshold: i32,
/// Determines Redis Expiry for Card Testing Guard for profile
pub card_testing_guard_expiry: i32,
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum CardTestingGuardStatus {
Enabled,
Disabled,
}
#[derive(Clone, Debug, Deserialize, Serialize, ToSchema)]
pub struct AuthenticationConnectorDetails {
/// List of authentication connectors
#[schema(value_type = Vec<AuthenticationConnectors>)]
pub authentication_connectors: Vec<common_enums::AuthenticationConnectors>,
/// URL of the (customer service) website that will be shown to the shopper in case of technical errors during the 3D Secure 2 process.
pub three_ds_requestor_url: String,
/// Merchant app declaring their URL within the CReq message so that the Authentication app can call the Merchant app after OOB authentication has occurred.
pub three_ds_requestor_app_url: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize, ToSchema)]
pub struct MerchantAccountMetadata {
pub compatible_connector: Option<api_enums::Connector>,
#[serde(flatten)]
pub data: Option<pii::SecretSerdeValue>,
}
#[cfg(feature = "v1")]
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)]
#[serde(deny_unknown_fields)]
pub struct MerchantAccountUpdate {
/// The identifier for the Merchant Account
#[schema(max_length = 64, example = "y3oqhf46pyzuxjbcn2giaqnb44", value_type = String)]
pub merchant_id: id_type::MerchantId,
/// Name of the Merchant Account
#[schema(example = "NewAge Retailer")]
pub merchant_name: Option<String>,
/// Details about the merchant
pub merchant_details: Option<MerchantDetails>,
/// The URL to redirect after the completion of the operation
#[schema(value_type = Option<String>, max_length = 255, example = "https://www.example.com/success")]
pub return_url: Option<url::Url>,
/// Webhook related details
pub webhook_details: Option<WebhookDetails>,
/// The routing algorithm to be used for routing payments to desired connectors
#[serde(skip)]
#[schema(deprecated)]
pub routing_algorithm: Option<serde_json::Value>,
/// The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom'
#[cfg(feature = "payouts")]
#[schema(value_type = Option<RoutingAlgorithm>,example = json!({"type": "single", "data": "wise"}))]
pub payout_routing_algorithm: Option<serde_json::Value>,
/// A boolean value to indicate if the merchant is a sub-merchant under a master or a parent merchant. By default, its value is false.
#[schema(default = false, example = false)]
pub sub_merchants_enabled: Option<bool>,
/// Refers to the Parent Merchant ID if the merchant being created is a sub-merchant
#[schema(max_length = 255, example = "xkkdf909012sdjki2dkh5sdf", value_type = Option<String>)]
pub parent_merchant_id: Option<id_type::MerchantId>,
/// A boolean value to indicate if payment response hash needs to be enabled
#[schema(default = false, example = true)]
pub enable_payment_response_hash: Option<bool>,
/// Refers to the hash key used for calculating the signature for webhooks and redirect response.
pub payment_response_hash_key: Option<String>,
/// A boolean value to indicate if redirect to merchant with http post needs to be enabled
#[schema(default = false, example = true)]
pub redirect_to_merchant_with_http_post: Option<bool>,
/// Metadata is useful for storing additional, unstructured information on an object.
#[schema(value_type = Option<Object>, example = r#"{ "city": "NY", "unit": "245" }"#)]
pub metadata: Option<pii::SecretSerdeValue>,
/// API key that will be used for server side API access
#[schema(example = "AH3423bkjbkjdsfbkj")]
pub publishable_key: Option<String>,
/// An identifier for the vault used to store payment method information.
#[schema(example = "locker_abc123")]
pub locker_id: Option<String>,
/// Details about the primary business unit of the merchant account
pub primary_business_details: Option<Vec<PrimaryBusinessDetails>>,
/// The frm routing algorithm to be used for routing payments to desired FRM's
#[schema(value_type = Option<Object>,example = json!({"type": "single", "data": "signifyd"}))]
pub frm_routing_algorithm: Option<serde_json::Value>,
/// The default profile that must be used for creating merchant accounts and payments
#[schema(max_length = 64, value_type = Option<String>)]
pub default_profile: Option<id_type::ProfileId>,
/// Default payment method collect link config
#[schema(value_type = Option<BusinessCollectLinkConfig>)]
pub pm_collect_link_config: Option<BusinessCollectLinkConfig>,
}
#[cfg(feature = "v1")]
impl MerchantAccountUpdate {
pub fn get_primary_details_as_value(
&self,
) -> CustomResult<Option<serde_json::Value>, errors::ParsingError> {
self.primary_business_details
.as_ref()
.map(|primary_business_details| primary_business_details.encode_to_value())
.transpose()
}
pub fn get_pm_link_config_as_value(
&self,
) -> CustomResult<Option<serde_json::Value>, errors::ParsingError> {
self.pm_collect_link_config
.as_ref()
.map(|pm_collect_link_config| pm_collect_link_config.encode_to_value())
.transpose()
}
pub fn get_merchant_details_as_secret(
&self,
) -> CustomResult<Option<pii::SecretSerdeValue>, errors::ParsingError> {
self.merchant_details
.as_ref()
.map(|merchant_details| merchant_details.encode_to_value().map(Secret::new))
.transpose()
}
pub fn get_metadata_as_secret(
&self,
) -> CustomResult<Option<pii::SecretSerdeValue>, errors::ParsingError> {
self.metadata
.as_ref()
.map(|metadata| metadata.encode_to_value().map(Secret::new))
.transpose()
}
pub fn get_webhook_details_as_value(
&self,
) -> CustomResult<Option<serde_json::Value>, errors::ParsingError> {
self.webhook_details
.as_ref()
.map(|webhook_details| webhook_details.encode_to_value())
.transpose()
}
pub fn parse_routing_algorithm(&self) -> CustomResult<(), errors::ParsingError> {
match self.routing_algorithm {
Some(ref routing_algorithm) => {
let _: routing::RoutingAlgorithm =
routing_algorithm.clone().parse_value("RoutingAlgorithm")?;
Ok(())
}
None => Ok(()),
}
}
// Get the enable payment response hash as a boolean, where the default value is true
pub fn get_enable_payment_response_hash(&self) -> bool {
self.enable_payment_response_hash.unwrap_or(true)
}
}
#[cfg(feature = "v2")]
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)]
#[serde(deny_unknown_fields)]
pub struct MerchantAccountUpdate {
/// Name of the Merchant Account
#[schema(example = "NewAge Retailer")]
pub merchant_name: Option<String>,
/// Details about the merchant
pub merchant_details: Option<MerchantDetails>,
/// Metadata is useful for storing additional, unstructured information on an object.
#[schema(value_type = Option<Object>, example = r#"{ "city": "NY", "unit": "245" }"#)]
pub metadata: Option<pii::SecretSerdeValue>,
}
#[cfg(feature = "v2")]
impl MerchantAccountUpdate {
pub fn get_merchant_details_as_secret(
&self,
) -> CustomResult<Option<pii::SecretSerdeValue>, errors::ParsingError> {
self.merchant_details
.as_ref()
.map(|merchant_details| merchant_details.encode_to_value().map(Secret::new))
.transpose()
}
pub fn get_metadata_as_secret(
&self,
) -> CustomResult<Option<pii::SecretSerdeValue>, errors::ParsingError> {
self.metadata
.as_ref()
.map(|metadata| metadata.encode_to_value().map(Secret::new))
.transpose()
}
}
#[cfg(feature = "v1")]
#[derive(Clone, Debug, ToSchema, Serialize)]
pub struct MerchantAccountResponse {
/// The identifier for the Merchant Account
#[schema(max_length = 64, example = "y3oqhf46pyzuxjbcn2giaqnb44", value_type = String)]
pub merchant_id: id_type::MerchantId,
/// Name of the Merchant Account
#[schema(value_type = Option<String>,example = "NewAge Retailer")]
pub merchant_name: OptionalEncryptableName,
/// The URL to redirect after completion of the payment
#[schema(max_length = 255, example = "https://www.example.com/success")]
pub return_url: Option<String>,
/// A boolean value to indicate if payment response hash needs to be enabled
#[schema(default = false, example = true)]
pub enable_payment_response_hash: bool,
/// Refers to the hash key used for calculating the signature for webhooks and redirect response. If the value is not provided, a value is automatically generated.
#[schema(max_length = 255, example = "xkkdf909012sdjki2dkh5sdf")]
pub payment_response_hash_key: Option<String>,
/// A boolean value to indicate if redirect to merchant with http post needs to be enabled
#[schema(default = false, example = true)]
pub redirect_to_merchant_with_http_post: bool,
/// Details about the merchant
#[schema(value_type = Option<MerchantDetails>)]
pub merchant_details: Option<Encryptable<pii::SecretSerdeValue>>,
/// Webhook related details
pub webhook_details: Option<WebhookDetails>,
/// The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom'
#[serde(skip)]
#[schema(deprecated)]
pub routing_algorithm: Option<serde_json::Value>,
/// The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom'
#[cfg(feature = "payouts")]
#[schema(value_type = Option<RoutingAlgorithm>,example = json!({"type": "single", "data": "wise"}))]
pub payout_routing_algorithm: Option<serde_json::Value>,
/// A boolean value to indicate if the merchant is a sub-merchant under a master or a parent merchant. By default, its value is false.
#[schema(default = false, example = false)]
pub sub_merchants_enabled: Option<bool>,
/// Refers to the Parent Merchant ID if the merchant being created is a sub-merchant
#[schema(max_length = 255, example = "xkkdf909012sdjki2dkh5sdf", value_type = Option<String>)]
pub parent_merchant_id: Option<id_type::MerchantId>,
/// API key that will be used for server side API access
#[schema(example = "AH3423bkjbkjdsfbkj")]
pub publishable_key: Option<String>,
/// Metadata is useful for storing additional, unstructured information on an object.
#[schema(value_type = Option<Object>, example = r#"{ "city": "NY", "unit": "245" }"#)]
pub metadata: Option<pii::SecretSerdeValue>,
/// An identifier for the vault used to store payment method information.
#[schema(example = "locker_abc123")]
pub locker_id: Option<String>,
/// Details about the primary business unit of the merchant account
#[schema(value_type = Vec<PrimaryBusinessDetails>)]
pub primary_business_details: Vec<PrimaryBusinessDetails>,
/// The frm routing algorithm to be used to process the incoming request from merchant to outgoing payment FRM.
#[schema(value_type = Option<RoutingAlgorithm>, max_length = 255, example = r#"{"type": "single", "data": "stripe" }"#)]
pub frm_routing_algorithm: Option<serde_json::Value>,
/// The organization id merchant is associated with
#[schema(value_type = String, max_length = 64, min_length = 1, example = "org_q98uSGAYbjEwqs0mJwnz")]
pub organization_id: id_type::OrganizationId,
/// A boolean value to indicate if the merchant has recon service is enabled or not, by default value is false
pub is_recon_enabled: bool,
/// The default profile that must be used for creating merchant accounts and payments
#[schema(max_length = 64, value_type = Option<String>)]
pub default_profile: Option<id_type::ProfileId>,
/// Used to indicate the status of the recon module for a merchant account
#[schema(value_type = ReconStatus, example = "not_requested")]
pub recon_status: api_enums::ReconStatus,
/// Default payment method collect link config
#[schema(value_type = Option<BusinessCollectLinkConfig>)]
pub pm_collect_link_config: Option<BusinessCollectLinkConfig>,
/// Product Type of this merchant account
#[schema(value_type = Option<MerchantProductType>, example = "Orchestration")]
pub product_type: Option<api_enums::MerchantProductType>,
}
#[cfg(feature = "v2")]
#[derive(Clone, Debug, ToSchema, Serialize)]
pub struct MerchantAccountResponse {
/// The identifier for the Merchant Account
#[schema(max_length = 64, example = "y3oqhf46pyzuxjbcn2giaqnb44", value_type = String)]
pub id: id_type::MerchantId,
/// Name of the Merchant Account
#[schema(value_type = String,example = "NewAge Retailer")]
pub merchant_name: Secret<String>,
/// Details about the merchant
#[schema(value_type = Option<MerchantDetails>)]
pub merchant_details: Option<Encryptable<pii::SecretSerdeValue>>,
/// API key that will be used for server side API access
#[schema(example = "AH3423bkjbkjdsfbkj")]
pub publishable_key: String,
/// Metadata is useful for storing additional, unstructured information on an object.
#[schema(value_type = Option<Object>, example = r#"{ "city": "NY", "unit": "245" }"#)]
pub metadata: Option<pii::SecretSerdeValue>,
/// The id of the organization which the merchant is associated with
#[schema(value_type = String, max_length = 64, min_length = 1, example = "org_q98uSGAYbjEwqs0mJwnz")]
pub organization_id: id_type::OrganizationId,
/// Used to indicate the status of the recon module for a merchant account
#[schema(value_type = ReconStatus, example = "not_requested")]
pub recon_status: api_enums::ReconStatus,
/// Product Type of this merchant account
#[schema(value_type = Option<MerchantProductType>, example = "Orchestration")]
pub product_type: Option<api_enums::MerchantProductType>,
}
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)]
#[serde(deny_unknown_fields)]
pub struct MerchantDetails {
/// The merchant's primary contact name
#[schema(value_type = Option<String>, max_length = 255, example = "John Doe")]
pub primary_contact_person: Option<Secret<String>>,
/// The merchant's primary phone number
#[schema(value_type = Option<String>, max_length = 255, example = "999999999")]
pub primary_phone: Option<Secret<String>>,
/// The merchant's primary email address
#[schema(value_type = Option<String>, max_length = 255, example = "[email protected]")]
pub primary_email: Option<pii::Email>,
/// The merchant's secondary contact name
#[schema(value_type = Option<String>, max_length= 255, example = "John Doe2")]
pub secondary_contact_person: Option<Secret<String>>,
/// The merchant's secondary phone number
#[schema(value_type = Option<String>, max_length = 255, example = "999999988")]
pub secondary_phone: Option<Secret<String>>,
/// The merchant's secondary email address
#[schema(value_type = Option<String>, max_length = 255, example = "[email protected]")]
pub secondary_email: Option<pii::Email>,
/// The business website of the merchant
#[schema(max_length = 255, example = "www.example.com")]
pub website: Option<String>,
/// A brief description about merchant's business
#[schema(
max_length = 255,
example = "Online Retail with a wide selection of organic products for North America"
)]
pub about_business: Option<String>,
/// The merchant's address details
pub address: Option<AddressDetails>,
}
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct PrimaryBusinessDetails {
#[schema(value_type = CountryAlpha2)]
pub country: api_enums::CountryAlpha2,
#[schema(example = "food")]
pub business: String,
}
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)]
#[serde(deny_unknown_fields)]
pub struct WebhookDetails {
///The version for Webhook
#[schema(max_length = 255, max_length = 255, example = "1.0.2")]
pub webhook_version: Option<String>,
///The user name for Webhook login
#[schema(max_length = 255, max_length = 255, example = "ekart_retail")]
pub webhook_username: Option<String>,
///The password for Webhook login
#[schema(value_type = Option<String>, max_length = 255, example = "ekart@123")]
pub webhook_password: Option<Secret<String>>,
///The url for the webhook endpoint
#[schema(value_type = Option<String>, example = "www.ekart.com/webhooks")]
pub webhook_url: Option<Secret<String>>,
/// If this property is true, a webhook message is posted whenever a new payment is created
#[schema(example = true)]
pub payment_created_enabled: Option<bool>,
/// If this property is true, a webhook message is posted whenever a payment is successful
#[schema(example = true)]
pub payment_succeeded_enabled: Option<bool>,
/// If this property is true, a webhook message is posted whenever a payment fails
#[schema(example = true)]
pub payment_failed_enabled: Option<bool>,
}
#[derive(Debug, Serialize, ToSchema)]
pub struct MerchantAccountDeleteResponse {
/// The identifier for the Merchant Account
#[schema(max_length = 255, example = "y3oqhf46pyzuxjbcn2giaqnb44", value_type = String)]
pub merchant_id: id_type::MerchantId,
/// If the connector is deleted or not
#[schema(example = false)]
pub deleted: bool,
}
#[derive(Default, Debug, Deserialize, Serialize)]
pub struct MerchantId {
pub merchant_id: id_type::MerchantId,
}
#[cfg(feature = "v1")]
#[derive(Debug, Deserialize, ToSchema, Serialize)]
pub struct MerchantConnectorId {
#[schema(value_type = String)]
pub merchant_id: id_type::MerchantId,
#[schema(value_type = String)]
pub merchant_connector_id: id_type::MerchantConnectorAccountId,
}
#[cfg(feature = "v2")]
#[derive(Debug, Deserialize, ToSchema, Serialize)]
pub struct MerchantConnectorId {
#[schema(value_type = String)]
pub id: id_type::MerchantConnectorAccountId,
}
#[cfg(feature = "v2")]
/// Create a new Merchant Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc."
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct MerchantConnectorCreate {
/// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.
#[schema(value_type = ConnectorType, example = "payment_processor")]
pub connector_type: api_enums::ConnectorType,
/// Name of the Connector
#[schema(value_type = Connector, example = "stripe")]
pub connector_name: api_enums::Connector,
/// This is an unique label you can generate and pass in order to identify this connector account on your Hyperswitch dashboard and reports, If not passed then if will take `connector_name`_`profile_name`. Eg: if your profile label is `default`, connector label can be `stripe_default`
#[schema(example = "stripe_US_travel")]
pub connector_label: Option<String>,
/// Identifier for the profile, if not provided default will be chosen from merchant account
#[schema(max_length = 64, value_type = String)]
pub profile_id: id_type::ProfileId,
/// An object containing the required details/credentials for a Connector account.
#[schema(value_type = Option<MerchantConnectorDetails>,example = json!({ "auth_type": "HeaderKey","api_key": "Basic MyVerySecretApiKey" }))]
pub connector_account_details: Option<pii::SecretSerdeValue>,
/// An object containing the details about the payment methods that need to be enabled under this merchant connector account
#[schema(value_type = PaymentMethodsEnabled)]
pub payment_methods_enabled: Option<Vec<common_types::payment_methods::PaymentMethodsEnabled>>,
/// Webhook details of this merchant connector
#[schema(example = json!({
"connector_webhook_details": {
"merchant_secret": "1234567890987654321"
}
}))]
pub connector_webhook_details: Option<MerchantConnectorWebhookDetails>,
/// Metadata is useful for storing additional, unstructured information on an object.
#[schema(value_type = Option<Object>,max_length = 255,example = json!({ "city": "NY", "unit": "245" }))]
pub metadata: Option<pii::SecretSerdeValue>,
/// A boolean value to indicate if the connector is disabled. By default, its value is false.
#[schema(default = false, example = false)]
pub disabled: Option<bool>,
/// Contains the frm configs for the merchant connector
#[schema(example = json!(consts::FRM_CONFIGS_EG))]
pub frm_configs: Option<Vec<FrmConfigs>>,
/// pm_auth_config will relate MCA records to their respective chosen auth services, based on payment_method and pmt
#[schema(value_type = Option<Object>)]
pub pm_auth_config: Option<pii::SecretSerdeValue>,
#[schema(value_type = Option<ConnectorStatus>, example = "inactive")]
// By default the ConnectorStatus is Active
pub status: Option<api_enums::ConnectorStatus>,
/// In case the merchant needs to store any additional sensitive data
#[schema(value_type = Option<AdditionalMerchantData>)]
pub additional_merchant_data: Option<AdditionalMerchantData>,
/// The connector_wallets_details is used to store wallet details such as certificates and wallet credentials
#[schema(value_type = Option<ConnectorWalletDetails>)]
pub connector_wallets_details: Option<ConnectorWalletDetails>,
/// Additional data that might be required by hyperswitch, to enable some specific features.
#[schema(value_type = Option<MerchantConnectorAccountFeatureMetadata>)]
pub feature_metadata: Option<MerchantConnectorAccountFeatureMetadata>,
}
#[cfg(feature = "v2")]
impl MerchantConnectorCreate {
pub fn get_transaction_type(&self) -> api_enums::TransactionType {
match self.connector_type {
#[cfg(feature = "payouts")]
api_enums::ConnectorType::PayoutProcessor => api_enums::TransactionType::Payout,
_ => api_enums::TransactionType::Payment,
}
}
pub fn get_frm_config_as_secret(&self) -> Option<Vec<Secret<serde_json::Value>>> {
match self.frm_configs.as_ref() {
Some(frm_value) => {
let configs_for_frm_value: Vec<Secret<serde_json::Value>> = frm_value
.iter()
.map(|config| config.encode_to_value().map(Secret::new))
.collect::<Result<Vec<_>, _>>()
.ok()?;
Some(configs_for_frm_value)
}
None => None,
}
}
pub fn get_connector_label(&self, profile_name: String) -> String {
match self.connector_label.clone() {
Some(connector_label) => connector_label,
None => format!("{}_{}", self.connector_name, profile_name),
}
}
}
#[cfg(feature = "v1")]
/// Create a new Merchant Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc."
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct MerchantConnectorCreate {
/// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.
#[schema(value_type = ConnectorType, example = "payment_processor")]
pub connector_type: api_enums::ConnectorType,
/// Name of the Connector
#[schema(value_type = Connector, example = "stripe")]
pub connector_name: api_enums::Connector,
/// This is an unique label you can generate and pass in order to identify this connector account on your Hyperswitch dashboard and reports. Eg: if your profile label is `default`, connector label can be `stripe_default`
#[schema(example = "stripe_US_travel")]
pub connector_label: Option<String>,
/// Identifier for the profile, if not provided default will be chosen from merchant account
#[schema(max_length = 64, value_type = Option<String>)]
pub profile_id: Option<id_type::ProfileId>,
/// An object containing the required details/credentials for a Connector account.
#[schema(value_type = Option<MerchantConnectorDetails>,example = json!({ "auth_type": "HeaderKey","api_key": "Basic MyVerySecretApiKey" }))]
pub connector_account_details: Option<pii::SecretSerdeValue>,
/// An object containing the details about the payment methods that need to be enabled under this merchant connector account
#[schema(example = json!([
{
"payment_method": "wallet",
"payment_method_types": [
"upi_collect",
"upi_intent"
],
"payment_method_issuers": [
"labore magna ipsum",
"aute"
],
"payment_schemes": [
"Discover",
"Discover"
],
"accepted_currencies": {
"type": "enable_only",
"list": ["USD", "EUR"]
},
"accepted_countries": {
"type": "disable_only",
"list": ["FR", "DE","IN"]
},
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
}
]))]
pub payment_methods_enabled: Option<Vec<PaymentMethodsEnabled>>,
/// Webhook details of this merchant connector
#[schema(example = json!({
"connector_webhook_details": {
"merchant_secret": "1234567890987654321"
}
}))]
pub connector_webhook_details: Option<MerchantConnectorWebhookDetails>,
/// Metadata is useful for storing additional, unstructured information on an object.
#[schema(value_type = Option<Object>,max_length = 255,example = json!({ "city": "NY", "unit": "245" }))]
pub metadata: Option<pii::SecretSerdeValue>,
/// A boolean value to indicate if the connector is in Test mode. By default, its value is false.
#[schema(default = false, example = false)]
pub test_mode: Option<bool>,
/// A boolean value to indicate if the connector is disabled. By default, its value is false.
#[schema(default = false, example = false)]
pub disabled: Option<bool>,
/// Contains the frm configs for the merchant connector
#[schema(example = json!(consts::FRM_CONFIGS_EG))]
pub frm_configs: Option<Vec<FrmConfigs>>,
/// The business country to which the connector account is attached. To be deprecated soon. Use the 'profile_id' instead
#[schema(value_type = Option<CountryAlpha2>, example = "US")]
pub business_country: Option<api_enums::CountryAlpha2>,
/// The business label to which the connector account is attached. To be deprecated soon. Use the 'profile_id' instead
pub business_label: Option<String>,
/// The business sublabel to which the connector account is attached. To be deprecated soon. Use the 'profile_id' instead
#[schema(example = "chase")]
pub business_sub_label: Option<String>,
/// Unique ID of the connector
#[schema(example = "mca_5apGeP94tMts6rg3U3kR", value_type = Option<String>)]
pub merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
#[schema(value_type = Option<Object>)]
pub pm_auth_config: Option<pii::SecretSerdeValue>,
#[schema(value_type = Option<ConnectorStatus>, example = "inactive")]
pub status: Option<api_enums::ConnectorStatus>,
/// In case the merchant needs to store any additional sensitive data
#[schema(value_type = Option<AdditionalMerchantData>)]
pub additional_merchant_data: Option<AdditionalMerchantData>,
/// The connector_wallets_details is used to store wallet details such as certificates and wallet credentials
#[schema(value_type = Option<ConnectorWalletDetails>)]
pub connector_wallets_details: Option<ConnectorWalletDetails>,
}
#[cfg(feature = "v1")]
impl MerchantConnectorCreate {
pub fn get_transaction_type(&self) -> api_enums::TransactionType {
match self.connector_type {
#[cfg(feature = "payouts")]
api_enums::ConnectorType::PayoutProcessor => api_enums::TransactionType::Payout,
_ => api_enums::TransactionType::Payment,
}
}
pub fn get_frm_config_as_secret(&self) -> Option<Vec<Secret<serde_json::Value>>> {
match self.frm_configs.as_ref() {
Some(frm_value) => {
let configs_for_frm_value: Vec<Secret<serde_json::Value>> = frm_value
.iter()
.map(|config| config.encode_to_value().map(Secret::new))
.collect::<Result<Vec<_>, _>>()
.ok()?;
Some(configs_for_frm_value)
}
None => None,
}
}
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum AdditionalMerchantData {
OpenBankingRecipientData(MerchantRecipientData),
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
/// Feature metadata for merchant connector account
pub struct MerchantConnectorAccountFeatureMetadata {
/// Revenue recovery metadata for merchant connector account
pub revenue_recovery: Option<RevenueRecoveryMetadata>,
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
/// Revenue recovery metadata for merchant connector account
pub struct RevenueRecoveryMetadata {
/// The maximum number of retries allowed for an invoice. This limit is set by the merchant for each `billing connector`. Once this limit is reached, no further retries will be attempted.
#[schema(value_type = u16, example = "15")]
pub max_retry_count: u16,
/// Maximum number of `billing connector` retries before revenue recovery can start executing retries.
#[schema(value_type = u16, example = "10")]
pub billing_connector_retry_threshold: u16,
/// Billing account reference id is payment gateway id at billing connector end.
/// Merchants need to provide a mapping between these merchant connector account and the corresponding account reference IDs for each `billing connector`.
#[schema(value_type = u16, example = r#"{ "mca_vDSg5z6AxnisHq5dbJ6g": "stripe_123", "mca_vDSg5z6AumisHqh4x5m1": "adyen_123" }"#)]
pub billing_account_reference: HashMap<id_type::MerchantConnectorAccountId, String>,
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum MerchantAccountData {
Iban {
#[schema(value_type= String)]
iban: Secret<String>,
name: String,
#[schema(value_type= Option<String>)]
#[serde(skip_serializing_if = "Option::is_none")]
connector_recipient_id: Option<Secret<String>>,
},
Bacs {
#[schema(value_type= String)]
account_number: Secret<String>,
#[schema(value_type= String)]
sort_code: Secret<String>,
name: String,
#[schema(value_type= Option<String>)]
#[serde(skip_serializing_if = "Option::is_none")]
connector_recipient_id: Option<Secret<String>>,