Skip to content

Commit bdf1e51

Browse files
sai-harsha-vardhanSangamesh26sai harshajarnura
authored
feat(router): added dispute accept api, file module apis and dispute evidence submission api (#900)
Co-authored-by: Sangamesh <[email protected]> Co-authored-by: sai harsha <[email protected]> Co-authored-by: Arun Raj M <[email protected]>
1 parent bcbf4c8 commit bdf1e51

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2822
-34
lines changed

config/config.example.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ payu.base_url = "https://secure.snd.payu.com/"
169169
rapyd.base_url = "https://sandboxapi.rapyd.net"
170170
shift4.base_url = "https://api.shift4.com/"
171171
stripe.base_url = "https://api.stripe.com/"
172+
stripe.base_url_file_upload = "https://files.stripe.com/"
172173
worldline.base_url = "https://eu.sandbox.api-ingenico.com/"
173174
worldpay.base_url = "https://try.access.worldpay.com/"
174175
trustpay.base_url = "https://test-tpgw.trustpay.eu/"

config/development.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ payu.base_url = "https://secure.snd.payu.com/"
122122
rapyd.base_url = "https://sandboxapi.rapyd.net"
123123
shift4.base_url = "https://api.shift4.com/"
124124
stripe.base_url = "https://api.stripe.com/"
125+
stripe.base_url_file_upload = "https://files.stripe.com/"
125126
worldline.base_url = "https://eu.sandbox.api-ingenico.com/"
126127
worldpay.base_url = "https://try.access.worldpay.com/"
127128
trustpay.base_url = "https://test-tpgw.trustpay.eu/"
@@ -185,6 +186,10 @@ paypal = { currency = "CHF,DKK,EUR,GBP,NOK,PLN,SEK,USD,AUD,NZD,CAD" }
185186
google_pay = { country = "AL,DZ,AS,AO,AG,AR,AU,AT,AZ,BH,BY,BE,BR,BG,CA,CL,CO,HR,CZ,DK,DO,EG,EE,FI,FR,DE,GR,HK,HU,IN,ID,IE,IL,IT,JP,JO,KZ,KE,KW,LV,LB,LT,LU,MY,MX,NL,NZ,NO,OM,PK,PA,PE,PH,PL,PT,QA,RO,RU,SA,SG,SK,ZA,ES,LK,SE,CH,TW,TH,TR,UA,AE,GB,US,UY,VN" }
186187
apple_pay = { country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US" }
187188

189+
[file_upload_config]
190+
bucket_name = ""
191+
region = ""
192+
188193
[tokenization]
189194
stripe = { long_lived_token = false, payment_method = "wallet"}
190195
checkout = { long_lived_token = false, payment_method = "wallet"}

config/docker_compose.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ payu.base_url = "https://secure.snd.payu.com/"
9696
rapyd.base_url = "https://sandboxapi.rapyd.net"
9797
shift4.base_url = "https://api.shift4.com/"
9898
stripe.base_url = "https://api.stripe.com/"
99+
stripe.base_url_file_upload = "https://files.stripe.com/"
99100
worldline.base_url = "https://eu.sandbox.api-ingenico.com/"
100101
worldpay.base_url = "https://try.access.worldpay.com/"
101102
trustpay.base_url = "https://test-tpgw.trustpay.eu/"

crates/api_models/src/disputes.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,57 @@ pub struct DisputeListConstraints {
7373
#[serde(rename = "received_time.gte")]
7474
pub received_time_gte: Option<PrimitiveDateTime>,
7575
}
76+
77+
#[derive(Default, Clone, Debug, Serialize, Deserialize, ToSchema)]
78+
pub struct SubmitEvidenceRequest {
79+
///Dispute Id
80+
pub dispute_id: String,
81+
/// Logs showing the usage of service by customer
82+
pub access_activity_log: Option<String>,
83+
/// Billing address of the customer
84+
pub billing_address: Option<String>,
85+
/// File Id of cancellation policy
86+
pub cancellation_policy: Option<String>,
87+
/// Details of showing cancellation policy to customer before purchase
88+
pub cancellation_policy_disclosure: Option<String>,
89+
/// Details telling why customer's subscription was not cancelled
90+
pub cancellation_rebuttal: Option<String>,
91+
/// File Id of customer communication
92+
pub customer_communication: Option<String>,
93+
/// Customer email address
94+
pub customer_email_address: Option<String>,
95+
/// Customer name
96+
pub customer_name: Option<String>,
97+
/// IP address of the customer
98+
pub customer_purchase_ip: Option<String>,
99+
/// Fild Id of customer signature
100+
pub customer_signature: Option<String>,
101+
/// Product Description
102+
pub product_description: Option<String>,
103+
/// File Id of receipt
104+
pub receipt: Option<String>,
105+
/// File Id of refund policy
106+
pub refund_policy: Option<String>,
107+
/// Details of showing refund policy to customer before purchase
108+
pub refund_policy_disclosure: Option<String>,
109+
/// Details why customer is not entitled to refund
110+
pub refund_refusal_explanation: Option<String>,
111+
/// Customer service date
112+
pub service_date: Option<String>,
113+
/// File Id service documentation
114+
pub service_documentation: Option<String>,
115+
/// Shipping address of the customer
116+
pub shipping_address: Option<String>,
117+
/// Delivery service that shipped the product
118+
pub shipping_carrier: Option<String>,
119+
/// Shipping date
120+
pub shipping_date: Option<String>,
121+
/// File Id shipping documentation
122+
pub shipping_documentation: Option<String>,
123+
/// Tracking number of shipped product
124+
pub shipping_tracking_number: Option<String>,
125+
/// Any additional supporting file
126+
pub uncategorized_file: Option<String>,
127+
/// Any additional evidence statements
128+
pub uncategorized_text: Option<String>,
129+
}

crates/api_models/src/enums.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,9 @@ impl Connector {
625625
| (Self::Trustpay, PaymentMethod::BankRedirect)
626626
)
627627
}
628+
pub fn supports_file_storage_module(&self) -> bool {
629+
matches!(self, Self::Stripe)
630+
}
628631
}
629632

630633
#[derive(

crates/api_models/src/files.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
1+
use utoipa::ToSchema;
12

3+
#[derive(Debug, serde::Serialize, ToSchema)]
4+
pub struct CreateFileResponse {
5+
/// ID of the file created
6+
pub file_id: String,
7+
}

crates/router/Cargo.toml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ build = "src/build.rs"
1111

1212
[features]
1313
default = ["kv_store", "stripe", "oltp", "olap", "accounts_cache"]
14+
s3 = []
1415
kms = ["external_services/kms"]
1516
basilisk = ["kms"]
1617
stripe = ["dep:serde_qs"]
17-
sandbox = ["kms", "stripe", "basilisk"]
18-
production = ["kms", "stripe", "basilisk"]
18+
sandbox = ["kms", "stripe", "basilisk", "s3"]
19+
production = ["kms", "stripe", "basilisk", "s3"]
1920
olap = []
2021
oltp = []
2122
kv_store = []
@@ -60,7 +61,7 @@ num_cpus = "1.15.0"
6061
once_cell = "1.17.1"
6162
rand = "0.8.5"
6263
regex = "1.7.3"
63-
reqwest = { version = "0.11.16", features = ["json", "native-tls", "gzip"] }
64+
reqwest = { version = "0.11.16", features = ["json", "native-tls", "gzip", "multipart"] }
6465
ring = "0.16.20"
6566
serde = { version = "1.0.160", features = ["derive"] }
6667
serde_json = "1.0.96"
@@ -88,6 +89,10 @@ redis_interface = { version = "0.1.0", path = "../redis_interface" }
8889
router_derive = { version = "0.1.0", path = "../router_derive" }
8990
router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"] }
9091
storage_models = { version = "0.1.0", path = "../storage_models", features = ["kv_store"] }
92+
actix-multipart = "0.6.0"
93+
aws-sdk-s3 = "0.25.0"
94+
aws-config = "0.55.1"
95+
infer = "0.13.0"
9196

9297
[build-dependencies]
9398
router_env = { version = "0.1.0", path = "../router_env", default-features = false }

crates/router/src/compatibility/stripe/errors.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,20 @@ pub enum StripeErrorCode {
182182
IncorrectConnectorNameGiven,
183183
#[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "No such {object}: '{id}'")]
184184
ResourceMissing { object: String, id: String },
185+
#[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "File validation failed")]
186+
FileValidationFailed,
187+
#[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "File not found in the request")]
188+
MissingFile,
189+
#[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "File puropse not found in the request")]
190+
MissingFilePurpose,
191+
#[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "File content type not found")]
192+
MissingFileContentType,
193+
#[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "Dispute id not found in the request")]
194+
MissingDisputeId,
195+
#[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "File does not exists in our records")]
196+
FileNotFound,
197+
#[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "File not available")]
198+
FileNotAvailable,
185199
// [#216]: https://github.com/juspay/hyperswitch/issues/216
186200
// Implement the remaining stripe error codes
187201

@@ -466,6 +480,16 @@ impl From<errors::ApiErrorResponse> for StripeErrorCode {
466480
object: "dispute".to_owned(),
467481
id: dispute_id,
468482
},
483+
errors::ApiErrorResponse::DisputeStatusValidationFailed { reason } => {
484+
Self::InternalServerError
485+
}
486+
errors::ApiErrorResponse::FileValidationFailed { .. } => Self::FileValidationFailed,
487+
errors::ApiErrorResponse::MissingFile => Self::MissingFile,
488+
errors::ApiErrorResponse::MissingFilePurpose => Self::MissingFilePurpose,
489+
errors::ApiErrorResponse::MissingFileContentType => Self::MissingFileContentType,
490+
errors::ApiErrorResponse::MissingDisputeId => Self::MissingDisputeId,
491+
errors::ApiErrorResponse::FileNotFound => Self::FileNotFound,
492+
errors::ApiErrorResponse::FileNotAvailable => Self::FileNotAvailable,
469493
errors::ApiErrorResponse::NotSupported { .. } => Self::InternalServerError,
470494
}
471495
}
@@ -514,7 +538,14 @@ impl actix_web::ResponseError for StripeErrorCode {
514538
| Self::PaymentIntentUnexpectedState { .. }
515539
| Self::DuplicatePayment { .. }
516540
| Self::IncorrectConnectorNameGiven
517-
| Self::ResourceMissing { .. } => StatusCode::BAD_REQUEST,
541+
| Self::ResourceMissing { .. }
542+
| Self::FileValidationFailed
543+
| Self::MissingFile
544+
| Self::MissingFileContentType
545+
| Self::MissingFilePurpose
546+
| Self::MissingDisputeId
547+
| Self::FileNotFound
548+
| Self::FileNotAvailable => StatusCode::BAD_REQUEST,
518549
Self::RefundFailed
519550
| Self::InternalServerError
520551
| Self::MandateActive

crates/router/src/compatibility/wrap.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ where
5656
}
5757
Ok(api::ApplicationResponse::StatusOk) => api::http_response_ok(),
5858
Ok(api::ApplicationResponse::TextPlain(text)) => api::http_response_plaintext(text),
59+
Ok(api::ApplicationResponse::FileData((file_data, content_type))) => {
60+
api::http_response_file_data(file_data, content_type)
61+
}
5962
Ok(api::ApplicationResponse::JsonForRedirection(response)) => {
6063
match serde_json::to_string(&response) {
6164
Ok(res) => api::http_redirect_response(res, response),

crates/router/src/configs/settings.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ pub struct Settings {
6262
pub api_keys: ApiKeys,
6363
#[cfg(feature = "kms")]
6464
pub kms: kms::KmsConfig,
65+
#[cfg(feature = "s3")]
66+
pub file_upload_config: FileUploadConfig,
6567
pub tokenization: TokenizationConfig,
6668
}
6769

@@ -306,7 +308,7 @@ pub struct Connectors {
306308
pub payu: ConnectorParams,
307309
pub rapyd: ConnectorParams,
308310
pub shift4: ConnectorParams,
309-
pub stripe: ConnectorParams,
311+
pub stripe: ConnectorParamsWithFileUploadUrl,
310312
pub worldline: ConnectorParams,
311313
pub worldpay: ConnectorParams,
312314
pub trustpay: ConnectorParamsWithMoreUrls,
@@ -328,6 +330,13 @@ pub struct ConnectorParamsWithMoreUrls {
328330
pub base_url_bank_redirects: String,
329331
}
330332

333+
#[derive(Debug, Deserialize, Clone, Default)]
334+
#[serde(default)]
335+
pub struct ConnectorParamsWithFileUploadUrl {
336+
pub base_url: String,
337+
pub base_url_file_upload: String,
338+
}
339+
331340
#[derive(Debug, Clone, Deserialize)]
332341
#[serde(default)]
333342
pub struct SchedulerSettings {
@@ -387,6 +396,16 @@ pub struct ApiKeys {
387396
pub hash_key: String,
388397
}
389398

399+
#[cfg(feature = "s3")]
400+
#[derive(Debug, Deserialize, Clone, Default)]
401+
#[serde(default)]
402+
pub struct FileUploadConfig {
403+
/// The AWS region to send file uploads
404+
pub region: String,
405+
/// The AWS s3 bucket to send file uploads
406+
pub bucket_name: String,
407+
}
408+
390409
impl Settings {
391410
pub fn new() -> ApplicationResult<Self> {
392411
Self::with_config_path(None)
@@ -465,7 +484,8 @@ impl Settings {
465484
self.kms
466485
.validate()
467486
.map_err(|error| ApplicationError::InvalidConfigurationValueError(error.into()))?;
468-
487+
#[cfg(feature = "s3")]
488+
self.file_upload_config.validate()?;
469489
Ok(())
470490
}
471491
}

0 commit comments

Comments
 (0)