From d6afbe8011feedfada7561499771eb4b9d031969 Mon Sep 17 00:00:00 2001 From: ItsMeShashank Date: Mon, 12 Dec 2022 15:36:45 +0530 Subject: [PATCH] refactor(router): move api models into separate crate (#103) --- Cargo.lock | 19 + crates/api_models/Cargo.toml | 17 + crates/api_models/src/admin.rs | 126 +++ crates/api_models/src/bank_accounts.rs | 1 + crates/api_models/src/cards.rs | 1 + crates/api_models/src/customers.rs | 51 ++ crates/api_models/src/disputes.rs | 1 + crates/api_models/src/enums.rs | 478 ++++++++++ crates/api_models/src/files.rs | 1 + crates/api_models/src/lib.rs | 13 + crates/api_models/src/mandates.rs | 37 + crates/api_models/src/payment_methods.rs | 189 ++++ crates/api_models/src/payments.rs | 843 ++++++++++++++++++ crates/api_models/src/payouts.rs | 1 + crates/api_models/src/refunds.rs | 56 ++ crates/api_models/src/webhooks.rs | 48 + crates/common_utils/Cargo.toml | 1 + crates/common_utils/src/consts.rs | 12 + crates/common_utils/src/lib.rs | 14 + crates/router/Cargo.toml | 1 + .../compatibility/stripe/customers/types.rs | 3 +- crates/router/src/core/customers.rs | 5 +- crates/router/src/core/mandate.rs | 5 +- .../router/src/core/payment_methods/cards.rs | 2 +- crates/router/src/core/payments.rs | 6 +- crates/router/src/core/payments/helpers.rs | 10 +- .../payments/operations/payment_cancel.rs | 2 +- .../payments/operations/payment_capture.rs | 3 +- .../payments/operations/payment_confirm.rs | 3 +- .../payments/operations/payment_create.rs | 3 +- .../operations/payment_method_validate.rs | 2 +- .../payments/operations/payment_session.rs | 2 +- .../core/payments/operations/payment_start.rs | 2 +- .../payments/operations/payment_update.rs | 2 +- crates/router/src/lib.rs | 1 + crates/router/src/macros.rs | 46 + crates/router/src/types.rs | 6 - crates/router/src/types/api/admin.rs | 169 ++-- crates/router/src/types/api/customers.rs | 68 +- crates/router/src/types/api/enums.rs | 448 +--------- crates/router/src/types/api/mandates.rs | 62 +- .../router/src/types/api/payment_methods.rs | 206 +---- crates/router/src/types/api/payments.rs | 750 +--------------- crates/router/src/types/api/refunds.rs | 59 +- crates/router/src/types/api/webhooks.rs | 51 +- crates/router/src/types/transformers.rs | 154 +++- crates/router/src/utils/custom_serde.rs | 146 --- crates/storage_models/Cargo.toml | 8 + crates/storage_models/src/lib.rs | 1 + 49 files changed, 2272 insertions(+), 1863 deletions(-) create mode 100644 crates/api_models/Cargo.toml create mode 100644 crates/api_models/src/admin.rs create mode 100644 crates/api_models/src/bank_accounts.rs create mode 100644 crates/api_models/src/cards.rs create mode 100644 crates/api_models/src/customers.rs create mode 100644 crates/api_models/src/disputes.rs create mode 100644 crates/api_models/src/enums.rs create mode 100644 crates/api_models/src/files.rs create mode 100644 crates/api_models/src/lib.rs create mode 100644 crates/api_models/src/mandates.rs create mode 100644 crates/api_models/src/payment_methods.rs create mode 100644 crates/api_models/src/payments.rs create mode 100644 crates/api_models/src/payouts.rs create mode 100644 crates/api_models/src/refunds.rs create mode 100644 crates/api_models/src/webhooks.rs create mode 100644 crates/common_utils/src/consts.rs create mode 100644 crates/router/src/macros.rs create mode 100644 crates/storage_models/Cargo.toml create mode 100644 crates/storage_models/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 47aea9f5a2..71bdc995ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -307,6 +307,19 @@ version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +[[package]] +name = "api_models" +version = "0.1.0" +dependencies = [ + "common_utils", + "masking", + "router_derive", + "serde", + "serde_json", + "strum", + "time", +] + [[package]] name = "arc-swap" version = "1.5.1" @@ -905,6 +918,7 @@ dependencies = [ "error-stack", "fake", "masking", + "nanoid", "once_cell", "proptest", "regex", @@ -2599,6 +2613,7 @@ dependencies = [ "actix-http", "actix-rt", "actix-web", + "api_models", "async-bb8-diesel", "async-trait", "awc", @@ -2978,6 +2993,10 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "storage_models" +version = "0.1.0" + [[package]] name = "strsim" version = "0.8.0" diff --git a/crates/api_models/Cargo.toml b/crates/api_models/Cargo.toml new file mode 100644 index 0000000000..adcb63e16b --- /dev/null +++ b/crates/api_models/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "api_models" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1.0.145", features = ["derive"] } +serde_json = "1.0.85" +strum = { version = "0.24.1", features = ["derive"] } +time = { version = "0.3.14", features = ["serde", "serde-well-known", "std"] } + +# First party crates +common_utils = { version = "0.1.0", path = "../common_utils" } +masking = { version = "0.1.0", path = "../masking" } +router_derive = { version = "0.1.0", path = "../router_derive" } diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs new file mode 100644 index 0000000000..b0b3ea2e43 --- /dev/null +++ b/crates/api_models/src/admin.rs @@ -0,0 +1,126 @@ +use common_utils::pii; +use masking::{Secret, StrongSecret}; +use serde::{Deserialize, Serialize}; + +pub use self::CreateMerchantAccount as MerchantAccountResponse; +use super::payments::AddressDetails; +use crate::enums as api_enums; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct CreateMerchantAccount { + pub merchant_id: String, + pub merchant_name: Option, + pub api_key: Option>, + pub merchant_details: Option, + pub return_url: Option, + pub webhook_details: Option, + pub routing_algorithm: Option, + pub custom_routing_rules: Option>, + pub sub_merchants_enabled: Option, + pub parent_merchant_id: Option, + pub enable_payment_response_hash: Option, + pub payment_response_hash_key: Option, + pub redirect_to_merchant_with_http_post: Option, + pub metadata: Option, + pub publishable_key: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct MerchantDetails { + pub primary_contact_person: Option>, + pub primary_phone: Option>, + pub primary_email: Option>, + pub secondary_contact_person: Option>, + pub secondary_phone: Option>, + pub secondary_email: Option>, + pub website: Option, + pub about_business: Option, + pub address: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct WebhookDetails { + pub webhook_version: Option, + pub webhook_username: Option, + pub webhook_password: Option>, + pub webhook_url: Option>, + pub payment_created_enabled: Option, + pub payment_succeeded_enabled: Option, + pub payment_failed_enabled: Option, +} + +#[derive(Default, Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct CustomRoutingRules { + pub payment_methods_incl: Option>, //FIXME Add enums for all PM enums + pub payment_methods_excl: Option>, + pub payment_method_types_incl: Option>, + pub payment_method_types_excl: Option>, + pub payment_method_issuers_incl: Option>, + pub payment_method_issuers_excl: Option>, + pub countries_incl: Option>, + pub countries_excl: Option>, + pub currencies_incl: Option>, + pub currencies_excl: Option>, + pub metadata_filters_keys: Option>, + pub metadata_filters_values: Option>, + pub connectors_pecking_order: Option>, + pub connectors_traffic_weightage_key: Option>, + pub connectors_traffic_weightage_value: Option>, +} + +#[derive(Debug, Serialize)] +pub struct DeleteResponse { + pub merchant_id: String, + pub deleted: bool, +} + +#[derive(Default, Debug, Deserialize, Serialize)] +pub struct MerchantId { + pub merchant_id: String, +} + +#[derive(Default, Debug, Deserialize, Serialize)] +pub struct MerchantConnectorId { + pub merchant_id: String, + pub merchant_connector_id: i32, +} +//Merchant Connector Account CRUD +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct PaymentConnectorCreate { + pub connector_type: api_enums::ConnectorType, + pub connector_name: String, + pub merchant_connector_id: Option, + pub connector_account_details: Option>, + pub test_mode: Option, + pub disabled: Option, + pub payment_methods_enabled: Option>, + pub metadata: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct PaymentMethods { + pub payment_method: api_enums::PaymentMethodType, + pub payment_method_types: Option>, + pub payment_method_issuers: Option>, + pub payment_schemes: Option>, + pub accepted_currencies: Option>, + pub accepted_countries: Option>, + pub minimum_amount: Option, + pub maximum_amount: Option, + pub recurring_enabled: bool, + pub installment_payment_enabled: bool, + pub payment_experience: Option>, //TODO +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DeleteMcaResponse { + pub merchant_id: String, + pub merchant_connector_id: i32, + pub deleted: bool, +} diff --git a/crates/api_models/src/bank_accounts.rs b/crates/api_models/src/bank_accounts.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/crates/api_models/src/bank_accounts.rs @@ -0,0 +1 @@ + diff --git a/crates/api_models/src/cards.rs b/crates/api_models/src/cards.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/crates/api_models/src/cards.rs @@ -0,0 +1 @@ + diff --git a/crates/api_models/src/customers.rs b/crates/api_models/src/customers.rs new file mode 100644 index 0000000000..27611334fe --- /dev/null +++ b/crates/api_models/src/customers.rs @@ -0,0 +1,51 @@ +use common_utils::{consts, custom_serde, pii}; +use masking::Secret; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Default, Clone, Deserialize, Serialize)] +pub struct CustomerRequest { + #[serde(default = "generate_customer_id")] + pub customer_id: String, + #[serde(default = "unknown_merchant", skip)] + pub merchant_id: String, + pub name: Option, + pub email: Option>, + pub phone: Option>, + pub description: Option, + pub phone_country_code: Option, + pub address: Option>, + pub metadata: Option, +} + +#[derive(Debug, Clone, Serialize)] +pub struct CustomerResponse { + pub customer_id: String, + pub name: Option, + pub email: Option>, + pub phone: Option>, + pub phone_country_code: Option, + pub description: Option, + pub address: Option>, + #[serde(with = "custom_serde::iso8601")] + pub created_at: time::PrimitiveDateTime, + pub metadata: Option, +} + +#[derive(Default, Debug, Deserialize, Serialize)] +pub struct CustomerId { + pub customer_id: String, +} + +#[derive(Default, Debug, Deserialize, Serialize)] +pub struct CustomerDeleteResponse { + pub customer_id: String, + pub deleted: bool, +} + +pub fn generate_customer_id() -> String { + common_utils::generate_id(consts::ID_LENGTH, "cus") +} + +fn unknown_merchant() -> String { + String::from("merchant_unknown") +} diff --git a/crates/api_models/src/disputes.rs b/crates/api_models/src/disputes.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/crates/api_models/src/disputes.rs @@ -0,0 +1 @@ + diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs new file mode 100644 index 0000000000..b7738d8b07 --- /dev/null +++ b/crates/api_models/src/enums.rs @@ -0,0 +1,478 @@ +#[derive( + Clone, + Copy, + Debug, + Default, + Eq, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, +)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum AttemptStatus { + Started, + AuthenticationFailed, + JuspayDeclined, + PendingVbv, + VbvSuccessful, + Authorized, + AuthorizationFailed, + Charged, + Authorizing, + CodInitiated, + Voided, + VoidInitiated, + CaptureInitiated, + CaptureFailed, + VoidFailed, + AutoRefunded, + PartialCharged, + #[default] + Pending, + Failure, + PaymentMethodAwaited, + ConfirmationAwaited, +} + +#[derive( + Clone, + Copy, + Debug, + Default, + Eq, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, +)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum AuthenticationType { + #[default] + ThreeDs, + NoThreeDs, +} + +#[derive( + Clone, + Copy, + Debug, + Default, + Eq, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, +)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum CaptureMethod { + #[default] + Automatic, + Manual, + ManualMultiple, + Scheduled, +} + +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + strum::Display, + strum::EnumString, + serde::Deserialize, + serde::Serialize, +)] +#[strum(serialize_all = "snake_case")] +#[serde(rename_all = "snake_case")] +pub enum ConnectorType { + /// PayFacs, Acquirers, Gateways, BNPL etc + PaymentProcessor, + /// Fraud, Currency Conversion, Crypto etc + PaymentVas, + /// Accounting, Billing, Invoicing, Tax etc + FinOperations, + /// Inventory, ERP, CRM, KYC etc + FizOperations, + /// Payment Networks like Visa, MasterCard etc + Networks, + /// All types of banks including corporate / commercial / personal / neo banks + BankingEntities, + /// All types of non-banking financial institutions including Insurance, Credit / Lending etc + NonBankingFinance, +} + +#[allow(clippy::upper_case_acronyms)] +#[derive( + Clone, + Copy, + Debug, + Default, + Eq, + Hash, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, +)] +pub enum Currency { + AED, + ALL, + AMD, + ARS, + AUD, + AWG, + AZN, + BBD, + BDT, + BHD, + BMD, + BND, + BOB, + BRL, + BSD, + BWP, + BZD, + CAD, + CHF, + CNY, + COP, + CRC, + CUP, + CZK, + DKK, + DOP, + DZD, + EGP, + ETB, + EUR, + FJD, + GBP, + GHS, + GIP, + GMD, + GTQ, + GYD, + HKD, + HNL, + HRK, + HTG, + HUF, + IDR, + ILS, + INR, + JMD, + JOD, + JPY, + KES, + KGS, + KHR, + KRW, + KWD, + KYD, + KZT, + LAK, + LBP, + LKR, + LRD, + LSL, + MAD, + MDL, + MKD, + MMK, + MNT, + MOP, + MUR, + MVR, + MWK, + MXN, + MYR, + NAD, + NGN, + NIO, + NOK, + NPR, + NZD, + OMR, + PEN, + PGK, + PHP, + PKR, + PLN, + QAR, + RUB, + SAR, + SCR, + SEK, + SGD, + SLL, + SOS, + SSP, + SVC, + SZL, + THB, + TTD, + TWD, + TZS, + #[default] + USD, + UYU, + UZS, + YER, + ZAR, +} + +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, +)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum EventType { + PaymentSucceeded, +} + +#[derive( + Clone, + Copy, + Debug, + Default, + Eq, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, +)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum IntentStatus { + Succeeded, + Failed, + Cancelled, + Processing, + RequiresCustomerAction, + RequiresPaymentMethod, + #[default] + RequiresConfirmation, + RequiresCapture, +} + +#[derive( + Clone, + Copy, + Debug, + Default, + Eq, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, +)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum FutureUsage { + #[default] + OffSession, + OnSession, +} + +#[derive( + Clone, + Copy, + Debug, + Eq, + Hash, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, +)] +#[strum(serialize_all = "snake_case")] +#[serde(rename_all = "snake_case")] +pub enum PaymentMethodIssuerCode { + JpHdfc, + JpIcici, + JpGooglepay, + JpApplepay, + JpPhonepay, + JpWechat, + JpSofort, + JpGiropay, + JpSepa, + JpBacs, +} + +#[derive( + Clone, + Copy, + Debug, + Eq, + Hash, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, +)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum PaymentMethodSubType { + Credit, + Debit, + UpiIntent, + UpiCollect, + CreditCardInstallments, + PayLaterInstallments, +} + +#[derive( + Clone, + Copy, + Debug, + Default, + Eq, + Hash, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, +)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum PaymentMethodType { + Card, + PaymentContainer, + #[default] + BankTransfer, + BankDebit, + PayLater, + Netbanking, + Upi, + OpenBanking, + ConsumerFinance, + Wallet, + Klarna, + Paypal, +} + +#[derive( + Clone, + Copy, + Debug, + Eq, + Hash, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, +)] +#[serde(rename_all = "lowercase")] +#[strum(serialize_all = "lowercase")] +pub enum WalletIssuer { + GooglePay, + ApplePay, +} + +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, strum::Display, strum::EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum RefundStatus { + Failure, + ManualReview, + #[default] + Pending, + Success, + TransactionFailure, +} + +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, +)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum RoutingAlgorithm { + RoundRobin, + MaxConversion, + MinCost, + Custom, +} + +#[derive( + Clone, + Copy, + Debug, + Eq, + PartialEq, + Default, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, +)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum MandateStatus { + #[default] + Active, + Inactive, + Pending, + Revoked, +} + +impl From for IntentStatus { + fn from(s: AttemptStatus) -> Self { + match s { + AttemptStatus::Charged | AttemptStatus::AutoRefunded => IntentStatus::Succeeded, + + AttemptStatus::ConfirmationAwaited => IntentStatus::RequiresConfirmation, + AttemptStatus::PaymentMethodAwaited => IntentStatus::RequiresPaymentMethod, + + AttemptStatus::Authorized => IntentStatus::RequiresCapture, + AttemptStatus::PendingVbv => IntentStatus::RequiresCustomerAction, + + AttemptStatus::PartialCharged + | AttemptStatus::Started + | AttemptStatus::VbvSuccessful + | AttemptStatus::Authorizing + | AttemptStatus::CodInitiated + | AttemptStatus::VoidInitiated + | AttemptStatus::CaptureInitiated + | AttemptStatus::Pending => IntentStatus::Processing, + + AttemptStatus::AuthenticationFailed + | AttemptStatus::AuthorizationFailed + | AttemptStatus::VoidFailed + | AttemptStatus::JuspayDeclined + | AttemptStatus::CaptureFailed + | AttemptStatus::Failure => IntentStatus::Failed, + AttemptStatus::Voided => IntentStatus::Cancelled, + } + } +} diff --git a/crates/api_models/src/files.rs b/crates/api_models/src/files.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/crates/api_models/src/files.rs @@ -0,0 +1 @@ + diff --git a/crates/api_models/src/lib.rs b/crates/api_models/src/lib.rs new file mode 100644 index 0000000000..e5a864c7a4 --- /dev/null +++ b/crates/api_models/src/lib.rs @@ -0,0 +1,13 @@ +pub mod admin; +pub mod bank_accounts; +pub mod cards; +pub mod customers; +pub mod disputes; +pub mod enums; +pub mod files; +pub mod mandates; +pub mod payment_methods; +pub mod payments; +pub mod payouts; +pub mod refunds; +pub mod webhooks; diff --git a/crates/api_models/src/mandates.rs b/crates/api_models/src/mandates.rs new file mode 100644 index 0000000000..5d6462fa94 --- /dev/null +++ b/crates/api_models/src/mandates.rs @@ -0,0 +1,37 @@ +use masking::Secret; +use serde::{Deserialize, Serialize}; + +use crate::{enums as api_enums, payments}; + +#[derive(Default, Debug, Deserialize, Serialize)] +pub struct MandateId { + pub mandate_id: String, +} + +#[derive(Default, Debug, Deserialize, Serialize)] +pub struct MandateRevokedResponse { + pub mandate_id: String, + pub status: api_enums::MandateStatus, +} + +#[derive(Default, Debug, Deserialize, Serialize)] +pub struct MandateResponse { + pub mandate_id: String, + pub status: api_enums::MandateStatus, + pub payment_method_id: String, + pub payment_method: String, + pub card: Option, + pub customer_acceptance: Option, +} + +#[derive(Default, Debug, Deserialize, Serialize)] +pub struct MandateCardDetails { + pub last4_digits: Option, + pub card_exp_month: Option>, + pub card_exp_year: Option>, + pub card_holder_name: Option>, + pub card_token: Option>, + pub scheme: Option, + pub issuer_country: Option, + pub card_fingerprint: Option>, +} diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs new file mode 100644 index 0000000000..2f93df2f0b --- /dev/null +++ b/crates/api_models/src/payment_methods.rs @@ -0,0 +1,189 @@ +use common_utils::pii; +use masking::Secret; +use serde::{Deserialize, Serialize}; +use time::PrimitiveDateTime; + +use crate::enums as api_enums; + +#[derive(Debug, Deserialize, Serialize, Clone)] +#[serde(deny_unknown_fields)] +pub struct CreatePaymentMethod { + pub merchant_id: Option, + pub payment_method: api_enums::PaymentMethodType, + pub payment_method_type: Option, + pub payment_method_issuer: Option, + pub payment_method_issuer_code: Option, + pub card: Option, + pub metadata: Option, + pub customer_id: Option, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +#[serde(deny_unknown_fields)] +pub struct CardDetail { + pub card_number: Secret, + pub card_exp_month: Secret, + pub card_exp_year: Secret, + pub card_holder_name: Option>, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct PaymentMethodResponse { + pub payment_method_id: String, + pub payment_method: api_enums::PaymentMethodType, + pub payment_method_type: Option, + pub payment_method_issuer: Option, + pub payment_method_issuer_code: Option, + pub card: Option, + //TODO: Populate this on request? + // pub accepted_country: Option>, + // pub accepted_currency: Option>, + // pub minimum_amount: Option, + // pub maximum_amount: Option, + pub recurring_enabled: bool, + pub installment_payment_enabled: bool, + pub payment_experience: Option>, //TODO change it to enum + pub metadata: Option, + #[serde(default, with = "common_utils::custom_serde::iso8601::option")] + pub created: Option, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct CardDetailFromLocker { + pub scheme: Option, + pub issuer_country: Option, + pub last4_digits: Option, + #[serde(skip)] + pub card_number: Option>, + pub expiry_month: Option>, + pub expiry_year: Option>, + pub card_token: Option>, + pub card_holder_name: Option>, + pub card_fingerprint: Option>, +} + +//List Payment Method +#[derive(Debug, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ListPaymentMethodRequest { + pub accepted_countries: Option>, + pub accepted_currencies: Option>, + pub amount: Option, + pub recurring_enabled: Option, + pub installment_payment_enabled: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ListPaymentMethodResponse { + pub payment_method: api_enums::PaymentMethodType, + pub payment_method_types: Option>, + pub payment_method_issuers: Option>, + pub payment_method_issuer_code: Option>, + pub payment_schemes: Option>, + pub accepted_countries: Option>, + pub accepted_currencies: Option>, + pub minimum_amount: Option, + pub maximum_amount: Option, + pub recurring_enabled: bool, + pub installment_payment_enabled: bool, + pub payment_experience: Option>, //TODO change it to enum +} + +#[derive(Debug, Serialize)] +pub struct ListCustomerPaymentMethodsResponse { + pub enabled_payment_methods: Vec, + pub customer_payment_methods: Vec, +} + +#[derive(Debug, Serialize)] +pub struct DeletePaymentMethodResponse { + pub payment_method_id: String, + pub deleted: bool, +} + +#[derive(Debug, Serialize)] +pub struct CustomerPaymentMethod { + pub payment_token: String, + pub customer_id: String, + pub payment_method: api_enums::PaymentMethodType, + pub payment_method_type: Option, + pub payment_method_issuer: Option, + pub payment_method_issuer_code: Option, + //TODO: Populate this on request? + // pub accepted_country: Option>, + // pub accepted_currency: Option>, + // pub minimum_amount: Option, + // pub maximum_amount: Option, + pub recurring_enabled: bool, + pub installment_payment_enabled: bool, + pub payment_experience: Option>, //TODO change it to enum + pub card: Option, + pub metadata: Option, + #[serde(default, with = "common_utils::custom_serde::iso8601::option")] + pub created: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct PaymentMethodId { + pub payment_method_id: String, +} + +//------------------------------------------------TokenizeService------------------------------------------------ +#[derive(Debug, Serialize, Deserialize)] +pub struct TokenizePayloadEncrypted { + pub payload: String, + pub key_id: String, + pub version: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct TokenizePayloadRequest { + pub value1: String, + pub value2: String, + pub lookup_key: String, + pub service_name: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GetTokenizePayloadRequest { + pub lookup_key: String, + pub get_value2: bool, +} + +#[derive(Debug, Serialize)] +pub struct DeleteTokenizeByTokenRequest { + pub lookup_key: String, +} + +#[derive(Debug, Serialize)] //FIXME yet to be implemented +pub struct DeleteTokenizeByDateRequest { + pub buffer_minutes: i32, + pub service_name: String, + pub max_rows: i32, +} + +#[derive(Debug, Deserialize)] +pub struct GetTokenizePayloadResponse { + pub lookup_key: String, + pub get_value2: Option, +} +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TokenizedCardValue1 { + pub card_number: String, + pub exp_year: String, + pub exp_month: String, + pub name_on_card: Option, + pub nickname: Option, + pub card_last_four: Option, + pub card_token: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TokenizedCardValue2 { + pub card_security_code: Option, + pub card_fingerprint: Option, + pub external_id: Option, + pub customer_id: Option, +} diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs new file mode 100644 index 0000000000..2e6991baea --- /dev/null +++ b/crates/api_models/src/payments.rs @@ -0,0 +1,843 @@ +use common_utils::pii; +use masking::{PeekInterface, Secret}; +use router_derive::Setter; +use time::PrimitiveDateTime; + +use crate::{enums as api_enums, refunds}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum PaymentOp { + Create, + Update, + Confirm, +} + +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] +#[serde(deny_unknown_fields)] +pub struct PaymentsRequest { + #[serde(default, deserialize_with = "payment_id_type::deserialize_option")] + pub payment_id: Option, + pub merchant_id: Option, + #[serde(default, deserialize_with = "amount::deserialize_option")] + pub amount: Option, + pub currency: Option, + pub capture_method: Option, + pub amount_to_capture: Option, + #[serde(default, with = "common_utils::custom_serde::iso8601::option")] + pub capture_on: Option, + pub confirm: Option, + pub customer_id: Option, + pub email: Option>, + pub name: Option>, + pub phone: Option>, + pub phone_country_code: Option, + pub off_session: Option, + pub description: Option, + pub return_url: Option, + pub setup_future_usage: Option, + pub authentication_type: Option, + pub payment_method_data: Option, + pub payment_method: Option, + pub payment_token: Option, + pub shipping: Option
, + pub billing: Option
, + pub statement_descriptor_name: Option, + pub statement_descriptor_suffix: Option, + pub metadata: Option, + pub client_secret: Option, + pub mandate_data: Option, + pub mandate_id: Option, + pub browser_info: Option, +} + +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)] +pub enum Amount { + Value(i32), + #[default] + Zero, +} + +impl From for i32 { + fn from(amount: Amount) -> Self { + match amount { + Amount::Value(v) => v, + Amount::Zero => 0, + } + } +} +impl From for Amount { + fn from(val: i32) -> Self { + match val { + 0 => Amount::Zero, + amount => Amount::Value(amount), + } + } +} + +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] +#[serde(deny_unknown_fields)] +pub struct PaymentsRedirectRequest { + pub payment_id: String, + pub merchant_id: String, + pub connector: String, + pub param: String, +} + +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] +#[serde(deny_unknown_fields)] +pub struct VerifyRequest { + // The merchant_id is generated through api key + // and is later passed in the struct + pub merchant_id: Option, + pub customer_id: Option, + pub email: Option>, + pub name: Option>, + pub phone: Option>, + pub phone_country_code: Option, + pub payment_method: Option, + pub payment_method_data: Option, + pub payment_token: Option, + pub mandate_data: Option, + pub setup_future_usage: Option, + pub off_session: Option, + pub client_secret: Option, +} + +impl From for VerifyRequest { + fn from(item: PaymentsRequest) -> Self { + Self { + client_secret: item.client_secret, + merchant_id: item.merchant_id, + customer_id: item.customer_id, + email: item.email, + name: item.name, + phone: item.phone, + phone_country_code: item.phone_country_code, + payment_method: item.payment_method, + payment_method_data: item.payment_method_data, + payment_token: item.payment_token, + mandate_data: item.mandate_data, + setup_future_usage: item.setup_future_usage, + off_session: item.off_session, + } + } +} + +pub enum MandateTxnType { + NewMandateTxn, + RecurringMandateTxn, +} + +#[derive(Default, Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] +#[serde(deny_unknown_fields)] +pub struct MandateData { + pub customer_acceptance: CustomerAcceptance, + pub mandate_type: MandateType, +} + +#[derive(Clone, Eq, PartialEq, Copy, Debug, Default, serde::Serialize, serde::Deserialize)] +pub struct SingleUseMandate { + pub amount: i32, + pub currency: api_enums::Currency, +} + +#[derive(Clone, Eq, PartialEq, Copy, Debug, Default, serde::Serialize, serde::Deserialize)] +pub struct MandateAmountData { + pub amount: i32, + pub currency: api_enums::Currency, +} + +#[derive(Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] +pub enum MandateType { + SingleUse(MandateAmountData), + MultiUse(Option), +} + +impl Default for MandateType { + fn default() -> Self { + Self::MultiUse(None) + } +} + +#[derive(Default, Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] +#[serde(deny_unknown_fields)] +pub struct CustomerAcceptance { + pub acceptance_type: AcceptanceType, + #[serde(default, with = "common_utils::custom_serde::iso8601::option")] + pub accepted_at: Option, + pub online: Option, +} + +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, PartialEq, Eq, Clone)] +#[serde(rename_all = "lowercase")] +pub enum AcceptanceType { + Online, + #[default] + Offline, +} + +#[derive(Default, Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] +#[serde(deny_unknown_fields)] +pub struct OnlineMandate { + pub ip_address: Secret, + pub user_agent: String, +} + +#[derive(Default, Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)] +pub struct CCard { + pub card_number: Secret, + pub card_exp_month: Secret, + pub card_exp_year: Secret, + pub card_holder_name: Secret, + pub card_cvc: Secret, +} + +#[derive(Default, Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)] +pub struct PayLaterData { + pub billing_email: String, + pub country: String, +} + +#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)] +pub enum PaymentMethod { + #[serde(rename(deserialize = "card"))] + Card(CCard), + #[serde(rename(deserialize = "bank_transfer"))] + BankTransfer, + #[serde(rename(deserialize = "wallet"))] + Wallet(WalletData), + #[serde(rename(deserialize = "pay_later"))] + PayLater(PayLaterData), + #[serde(rename(deserialize = "paypal"))] + Paypal, +} + +#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)] +pub struct WalletData { + pub issuer_name: api_enums::WalletIssuer, + pub token: String, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize)] +pub struct CCardResponse { + last4: String, + exp_month: String, + exp_year: String, +} + +#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize)] +pub enum PaymentMethodDataResponse { + #[serde(rename = "card")] + Card(CCardResponse), + #[serde(rename(deserialize = "bank_transfer"))] + BankTransfer, + Wallet(WalletData), + PayLater(PayLaterData), + Paypal, +} + +impl Default for PaymentMethod { + fn default() -> Self { + PaymentMethod::BankTransfer + } +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub enum PaymentIdType { + PaymentIntentId(String), + ConnectorTransactionId(String), + PaymentTxnId(String), +} + +impl Default for PaymentIdType { + fn default() -> Self { + Self::PaymentIntentId(Default::default()) + } +} + +//#[derive(Debug, serde::Deserialize, serde::Serialize)] +//#[serde(untagged)] +//pub enum enums::CaptureMethod { +//Automatic, +//Manual, +//} + +//impl Default for enums::CaptureMethod { +//fn default() -> Self { +//enums::CaptureMethod::Manual +//} +//} + +#[derive(Default, Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] +#[serde(deny_unknown_fields)] +pub struct Address { + pub address: Option, + pub phone: Option, +} + +// used by customers also, could be moved outside +#[derive(Clone, Default, Debug, Eq, serde::Deserialize, serde::Serialize, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct AddressDetails { + pub city: Option, + pub country: Option, + pub line1: Option>, + pub line2: Option>, + pub line3: Option>, + pub zip: Option>, + pub state: Option>, + pub first_name: Option>, + pub last_name: Option>, +} + +#[derive(Debug, Clone, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize)] +pub struct PhoneDetails { + pub number: Option>, + pub country_code: Option, +} + +#[derive(Debug, Clone, Default, Eq, PartialEq, serde::Deserialize)] +pub struct PaymentsCaptureRequest { + pub payment_id: Option, + pub merchant_id: Option, + pub amount_to_capture: Option, + pub refund_uncaptured_amount: Option, + pub statement_descriptor_suffix: Option, + pub statement_descriptor_prefix: Option, +} + +#[derive(Default, Clone, Debug, Eq, PartialEq, serde::Serialize)] +pub struct UrlDetails { + pub url: String, + pub method: String, +} +#[derive(Default, Clone, Debug, Eq, PartialEq, serde::Serialize)] +pub struct AuthenticationForStartResponse { + pub authentication: UrlDetails, +} +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)] +#[serde(rename_all = "snake_case")] +pub enum NextActionType { + RedirectToUrl, + DisplayQrCode, + InvokeSdkClient, + TriggerApi, +} +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)] +pub struct NextAction { + #[serde(rename = "type")] + pub next_action_type: NextActionType, + pub redirect_to_url: Option, +} + +#[derive(Setter, Clone, Default, Debug, Eq, PartialEq, serde::Serialize)] +pub struct PaymentsResponse { + pub payment_id: Option, + pub merchant_id: Option, + pub status: api_enums::IntentStatus, + pub amount: i32, + pub amount_capturable: Option, + pub amount_received: Option, + pub client_secret: Option>, + #[serde(with = "common_utils::custom_serde::iso8601::option")] + pub created: Option, + pub currency: String, + pub customer_id: Option, + pub description: Option, + pub refunds: Option>, + pub mandate_id: Option, + pub mandate_data: Option, + pub setup_future_usage: Option, + pub off_session: Option, + #[serde(with = "common_utils::custom_serde::iso8601::option")] + pub capture_on: Option, + pub capture_method: Option, + #[auth_based] + pub payment_method: Option, + #[auth_based] + pub payment_method_data: Option, + pub payment_token: Option, + pub shipping: Option
, + pub billing: Option
, + pub metadata: Option, + pub email: Option>, + pub name: Option>, + pub phone: Option>, + pub return_url: Option, + pub authentication_type: Option, + pub statement_descriptor_name: Option, + pub statement_descriptor_suffix: Option, + pub next_action: Option, + pub cancellation_reason: Option, + pub error_code: Option, //TODO: Add error code column to the database + pub error_message: Option, +} + +#[derive(Clone, Debug, serde::Deserialize)] +#[serde(deny_unknown_fields)] +pub struct PaymentListConstraints { + pub customer_id: Option, + pub starting_after: Option, + pub ending_before: Option, + #[serde(default = "default_limit")] + pub limit: i64, + #[serde(default, with = "common_utils::custom_serde::iso8601::option")] + pub created: Option, + #[serde(default, with = "common_utils::custom_serde::iso8601::option")] + #[serde(rename = "created.lt")] + pub created_lt: Option, + #[serde(default, with = "common_utils::custom_serde::iso8601::option")] + #[serde(rename = "created.gt")] + pub created_gt: Option, + #[serde(default, with = "common_utils::custom_serde::iso8601::option")] + #[serde(rename = "created.lte")] + pub created_lte: Option, + #[serde(default, with = "common_utils::custom_serde::iso8601::option")] + #[serde(rename = "created.gte")] + pub created_gte: Option, +} + +#[derive(Clone, Debug, serde::Serialize)] +pub struct PaymentListResponse { + pub size: usize, + pub data: Vec, +} + +#[derive(Setter, Clone, Default, Debug, Eq, PartialEq, serde::Serialize)] +pub struct VerifyResponse { + pub verify_id: Option, + pub merchant_id: Option, + // pub status: enums::VerifyStatus, + pub client_secret: Option>, + pub customer_id: Option, + pub email: Option>, + pub name: Option>, + pub phone: Option>, + pub mandate_id: Option, + #[auth_based] + pub payment_method: Option, + #[auth_based] + pub payment_method_data: Option, + pub payment_token: Option, + pub error_code: Option, + pub error_message: Option, +} + +fn default_limit() -> i64 { + 10 +} + +#[derive(Default, Debug, serde::Deserialize, serde::Serialize)] +pub struct PaymentsRedirectionResponse { + pub redirect_url: String, +} + +pub struct MandateValidationFields { + pub mandate_id: Option, + pub confirm: Option, + pub customer_id: Option, + pub mandate_data: Option, + pub setup_future_usage: Option, + pub off_session: Option, +} + +impl From<&PaymentsRequest> for MandateValidationFields { + fn from(req: &PaymentsRequest) -> Self { + Self { + mandate_id: req.mandate_id.clone(), + confirm: req.confirm, + customer_id: req.customer_id.clone(), + mandate_data: req.mandate_data.clone(), + setup_future_usage: req.setup_future_usage, + off_session: req.off_session, + } + } +} + +impl From<&VerifyRequest> for MandateValidationFields { + fn from(req: &VerifyRequest) -> Self { + Self { + mandate_id: None, + confirm: Some(true), + customer_id: req.customer_id.clone(), + mandate_data: req.mandate_data.clone(), + off_session: req.off_session, + setup_future_usage: req.setup_future_usage, + } + } +} + +impl From for PaymentsResponse { + fn from(item: PaymentsRequest) -> Self { + let payment_id = match item.payment_id { + Some(PaymentIdType::PaymentIntentId(id)) => Some(id), + _ => None, + }; + + Self { + payment_id, + merchant_id: item.merchant_id, + setup_future_usage: item.setup_future_usage, + off_session: item.off_session, + shipping: item.shipping, + billing: item.billing, + metadata: item.metadata, + capture_method: item.capture_method, + payment_method: item.payment_method, + capture_on: item.capture_on, + payment_method_data: item + .payment_method_data + .map(PaymentMethodDataResponse::from), + email: item.email, + name: item.name, + phone: item.phone, + payment_token: item.payment_token, + return_url: item.return_url, + authentication_type: item.authentication_type, + statement_descriptor_name: item.statement_descriptor_name, + statement_descriptor_suffix: item.statement_descriptor_suffix, + mandate_data: item.mandate_data, + ..Default::default() + } + } +} + +impl From for VerifyResponse { + fn from(item: VerifyRequest) -> Self { + Self { + merchant_id: item.merchant_id, + customer_id: item.customer_id, + email: item.email, + name: item.name, + phone: item.phone, + payment_method: item.payment_method, + payment_method_data: item + .payment_method_data + .map(PaymentMethodDataResponse::from), + payment_token: item.payment_token, + ..Default::default() + } + } +} + +impl From for PaymentsResponse { + fn from(item: PaymentsStartRequest) -> Self { + Self { + payment_id: Some(item.payment_id), + merchant_id: Some(item.merchant_id), + ..Default::default() + } + } +} + +impl From for PaymentsResponse { + fn from(item: PaymentsSessionRequest) -> Self { + let payment_id = match item.payment_id { + PaymentIdType::PaymentIntentId(id) => Some(id), + _ => None, + }; + + Self { + payment_id, + ..Default::default() + } + } +} + +impl From for PaymentsSessionResponse { + fn from(_item: PaymentsSessionRequest) -> Self { + Self { + session_token: vec![], + } + } +} + +impl From for PaymentsRequest { + fn from(item: PaymentsStartRequest) -> Self { + Self { + payment_id: Some(PaymentIdType::PaymentIntentId(item.payment_id)), + merchant_id: Some(item.merchant_id), + ..Default::default() + } + } +} + +impl From for PaymentsResponse { + // After removing the request from the payments_to_payments_response this will no longer be needed + fn from(item: PaymentsRetrieveRequest) -> Self { + let payment_id = match item.resource_id { + PaymentIdType::PaymentIntentId(id) => Some(id), + _ => None, + }; + + Self { + payment_id, + merchant_id: item.merchant_id, + ..Default::default() + } + } +} + +impl From for PaymentsResponse { + fn from(item: PaymentsCancelRequest) -> Self { + Self { + payment_id: Some(item.payment_id), + cancellation_reason: item.cancellation_reason, + ..Default::default() + } + } +} + +impl From for PaymentsResponse { + // After removing the request from the payments_to_payments_response this will no longer be needed + fn from(item: PaymentsCaptureRequest) -> Self { + Self { + payment_id: item.payment_id, + amount_received: item.amount_to_capture, + ..Self::default() + } + } +} + +impl From for CCardResponse { + fn from(card: CCard) -> Self { + let card_number_length = card.card_number.peek().clone().len(); + Self { + last4: card.card_number.peek().clone()[card_number_length - 4..card_number_length] + .to_string(), + exp_month: card.card_exp_month.peek().clone(), + exp_year: card.card_exp_year.peek().clone(), + } + } +} + +impl From for PaymentMethodDataResponse { + fn from(payment_method_data: PaymentMethod) -> Self { + match payment_method_data { + PaymentMethod::Card(card) => PaymentMethodDataResponse::Card(CCardResponse::from(card)), + PaymentMethod::BankTransfer => PaymentMethodDataResponse::BankTransfer, + PaymentMethod::PayLater(pay_later_data) => { + PaymentMethodDataResponse::PayLater(pay_later_data) + } + PaymentMethod::Wallet(wallet_data) => PaymentMethodDataResponse::Wallet(wallet_data), + PaymentMethod::Paypal => PaymentMethodDataResponse::Paypal, + } + } +} + +#[derive(Debug, Clone, serde::Serialize)] +pub struct PgRedirectResponse { + pub payment_id: String, + pub status: api_enums::IntentStatus, + pub gateway_id: String, + pub customer_id: Option, + pub amount: Option, +} + +#[derive(Debug, serde::Serialize, PartialEq, Eq, serde::Deserialize)] +pub struct RedirectionResponse { + pub return_url: String, + pub params: Vec<(String, String)>, + pub return_url_with_query_params: String, + pub http_method: String, + pub headers: Vec<(String, String)>, +} + +#[derive(Debug, serde::Deserialize)] +pub struct PaymentsResponseForm { + pub transaction_id: String, + // pub transaction_reference_id: String, + pub merchant_id: String, + pub order_id: String, +} + +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] +pub struct PaymentsRetrieveRequest { + pub resource_id: PaymentIdType, + pub merchant_id: Option, + pub force_sync: bool, + pub param: Option, + pub connector: Option, +} + +#[derive(Debug, Clone, serde::Serialize)] +pub struct ConnectorSessionToken { + pub connector_name: String, + pub session_token: String, +} + +#[derive(Default, Debug, serde::Deserialize, Clone)] +pub struct PaymentsSessionRequest { + pub payment_id: PaymentIdType, + pub client_secret: String, +} + +#[derive(Default, Debug, serde::Serialize, Clone)] +pub struct PaymentsSessionResponse { + pub session_token: Vec, +} + +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] +pub struct PaymentRetrieveBody { + pub merchant_id: Option, + pub force_sync: Option, +} +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] +pub struct PaymentsCancelRequest { + #[serde(skip)] + pub payment_id: String, + pub cancellation_reason: Option, +} + +#[derive(Default, Debug, serde::Deserialize, serde::Serialize)] +pub struct PaymentsStartRequest { + pub payment_id: String, + pub merchant_id: String, + pub txn_id: String, +} + +mod payment_id_type { + use std::fmt; + + use serde::{ + de::{self, Visitor}, + Deserializer, + }; + + use super::PaymentIdType; + + struct PaymentIdVisitor; + struct OptionalPaymentIdVisitor; + + impl<'de> Visitor<'de> for PaymentIdVisitor { + type Value = PaymentIdType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("payment id") + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + Ok(PaymentIdType::PaymentIntentId(value.to_string())) + } + } + + impl<'de> Visitor<'de> for OptionalPaymentIdVisitor { + type Value = Option; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("payment id") + } + + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(PaymentIdVisitor).map(Some) + } + + fn visit_none(self) -> Result + where + E: de::Error, + { + Ok(None) + } + + fn visit_unit(self) -> Result + where + E: de::Error, + { + Ok(None) + } + } + + #[allow(dead_code)] + pub(crate) fn deserialize<'a, D>(deserializer: D) -> Result + where + D: Deserializer<'a>, + { + deserializer.deserialize_any(PaymentIdVisitor) + } + + pub(crate) fn deserialize_option<'a, D>( + deserializer: D, + ) -> Result, D::Error> + where + D: Deserializer<'a>, + { + deserializer.deserialize_option(OptionalPaymentIdVisitor) + } +} + +mod amount { + use serde::de; + + use super::Amount; + struct AmountVisitor; + struct OptionalAmountVisitor; + + // This is defined to provide guarded deserialization of amount + // which itself handles zero and non-zero values internally + impl<'de> de::Visitor<'de> for AmountVisitor { + type Value = Amount; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "amount as integer") + } + + fn visit_u64(self, v: u64) -> Result + where + E: de::Error, + { + self.visit_i64(v as i64) + } + + fn visit_i64(self, v: i64) -> Result + where + E: de::Error, + { + Ok(match v { + 0 => Amount::Zero, + amount => Amount::Value(amount as i32), + }) + } + } + + impl<'de> de::Visitor<'de> for OptionalAmountVisitor { + type Value = Option; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "option of amount (as integer)") + } + + fn visit_some(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_i64(AmountVisitor).map(Some) + } + + fn visit_none(self) -> Result + where + E: de::Error, + { + Ok(None) + } + } + + #[allow(dead_code)] + pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + deserializer.deserialize_any(AmountVisitor) + } + pub(crate) fn deserialize_option<'de, D>(deserializer: D) -> Result, D::Error> + where + D: de::Deserializer<'de>, + { + deserializer.deserialize_option(OptionalAmountVisitor) + } +} diff --git a/crates/api_models/src/payouts.rs b/crates/api_models/src/payouts.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/crates/api_models/src/payouts.rs @@ -0,0 +1 @@ + diff --git a/crates/api_models/src/refunds.rs b/crates/api_models/src/refunds.rs new file mode 100644 index 0000000000..2586b1a576 --- /dev/null +++ b/crates/api_models/src/refunds.rs @@ -0,0 +1,56 @@ +use serde::{Deserialize, Serialize}; + +use crate::enums; + +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct RefundRequest { + pub refund_id: Option, + pub payment_id: String, + pub merchant_id: Option, + pub amount: Option, + pub reason: Option, + //FIXME: Make it refund_type instant or scheduled refund + pub force_process: Option, + pub metadata: Option, +} + +#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] +pub struct RefundResponse { + pub refund_id: String, + pub payment_id: String, + pub amount: i32, + pub currency: String, + pub reason: Option, + pub status: RefundStatus, + pub metadata: Option, + pub error_message: Option, +} + +#[derive(Debug, Eq, Clone, PartialEq, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum RefundStatus { + Succeeded, + Failed, + Pending, + Review, +} + +impl Default for RefundStatus { + fn default() -> Self { + RefundStatus::Pending + } +} + +impl From for RefundStatus { + fn from(status: enums::RefundStatus) -> Self { + match status { + enums::RefundStatus::Failure | enums::RefundStatus::TransactionFailure => { + RefundStatus::Failed + } + enums::RefundStatus::ManualReview => RefundStatus::Review, + enums::RefundStatus::Pending => RefundStatus::Pending, + enums::RefundStatus::Success => RefundStatus::Succeeded, + } + } +} diff --git a/crates/api_models/src/webhooks.rs b/crates/api_models/src/webhooks.rs new file mode 100644 index 0000000000..ddc4ffa13a --- /dev/null +++ b/crates/api_models/src/webhooks.rs @@ -0,0 +1,48 @@ +use common_utils::custom_serde; +use serde::{Deserialize, Serialize}; +use time::PrimitiveDateTime; + +use crate::{enums as api_enums, payments}; + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum IncomingWebhookEvent { + PaymentIntentSuccess, +} + +pub enum WebhookFlow { + Payment, + Refund, + Subscription, +} + +impl From for WebhookFlow { + fn from(evt: IncomingWebhookEvent) -> Self { + match evt { + IncomingWebhookEvent::PaymentIntentSuccess => Self::Payment, + } + } +} + +pub type MerchantWebhookConfig = std::collections::HashSet; + +pub struct IncomingWebhookDetails { + pub object_reference_id: String, + pub resource_object: Vec, +} + +#[derive(Debug, Clone, Serialize)] +pub struct OutgoingWebhook { + pub merchant_id: String, + pub event_id: String, + pub event_type: api_enums::EventType, + pub content: OutgoingWebhookContent, + #[serde(default, with = "custom_serde::iso8601")] + pub timestamp: PrimitiveDateTime, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(tag = "type", content = "object", rename_all = "snake_case")] +pub enum OutgoingWebhookContent { + PaymentDetails(payments::PaymentsResponse), +} diff --git a/crates/common_utils/Cargo.toml b/crates/common_utils/Cargo.toml index 6080e6f33e..569fdd39a5 100644 --- a/crates/common_utils/Cargo.toml +++ b/crates/common_utils/Cargo.toml @@ -10,6 +10,7 @@ license = "Apache-2.0" [dependencies] bytes = "1.3.0" error-stack = "0.2.4" +nanoid = "0.4.0" once_cell = "1.16.0" regex = "1.7.0" serde = { version = "1.0.149", features = ["derive"] } diff --git a/crates/common_utils/src/consts.rs b/crates/common_utils/src/consts.rs new file mode 100644 index 0000000000..5ba50fb56b --- /dev/null +++ b/crates/common_utils/src/consts.rs @@ -0,0 +1,12 @@ +//! Commonly used constants + +/// Number of characters in a generated ID +pub const ID_LENGTH: usize = 20; + +/// Characters to use for generating NanoID +pub(crate) const ALPHABETS: [char; 62] = [ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', + 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', + 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', + 'V', 'W', 'X', 'Y', 'Z', +]; diff --git a/crates/common_utils/src/lib.rs b/crates/common_utils/src/lib.rs index d20570b28c..85cdbfe807 100644 --- a/crates/common_utils/src/lib.rs +++ b/crates/common_utils/src/lib.rs @@ -13,6 +13,7 @@ )] #![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR" ), "/", "README.md"))] +pub mod consts; pub mod custom_serde; pub mod errors; pub mod ext_traits; @@ -29,3 +30,16 @@ pub mod date_time { PrimitiveDateTime::new(utc_date_time.date(), utc_date_time.time()) } } + +/// Generate a nanoid with the given prefix and length +#[inline] +pub fn generate_id(length: usize, prefix: &str) -> String { + format!("{}_{}", prefix, nanoid::nanoid!(length, &consts::ALPHABETS)) +} + +/// Generate a nanoid with the given prefix and a default length +#[inline] +pub fn generate_id_with_default_len(prefix: &str) -> String { + let len = consts::ID_LENGTH; + format!("{}_{}", prefix, nanoid::nanoid!(len, &consts::ALPHABETS)) +} diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index bf15152141..f1c78431c5 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -63,6 +63,7 @@ url = { version = "2.3.1", features = ["serde"] } uuid = { version = "1.2.2", features = ["serde", "v4"] } # First party crates +api_models = { version = "0.1.0", path = "../api_models" } common_utils = { version = "0.1.0", path = "../common_utils" } masking = { version = "0.1.0", path = "../masking" } redis_interface = { version = "0.1.0", path = "../redis_interface" } diff --git a/crates/router/src/compatibility/stripe/customers/types.rs b/crates/router/src/compatibility/stripe/customers/types.rs index e5b5be732a..8b1716d7e7 100644 --- a/crates/router/src/compatibility/stripe/customers/types.rs +++ b/crates/router/src/compatibility/stripe/customers/types.rs @@ -58,7 +58,7 @@ pub(crate) struct CustomerDeleteResponse { impl From for api::CustomerRequest { fn from(req: CreateCustomerRequest) -> Self { Self { - customer_id: api::generate_customer_id(), + customer_id: api_models::customers::generate_customer_id(), name: req.name, phone: req.phone, email: req.email, @@ -86,6 +86,7 @@ impl From for api::CustomerRequest { impl From for CreateCustomerResponse { fn from(cust: api::CustomerResponse) -> Self { + let cust = cust.into_inner(); Self { id: cust.customer_id, object: "customer".to_owned(), diff --git a/crates/router/src/core/customers.rs b/crates/router/src/core/customers.rs index c5d0acdd89..6a4617be6c 100644 --- a/crates/router/src/core/customers.rs +++ b/crates/router/src/core/customers.rs @@ -5,7 +5,10 @@ use crate::{ core::errors::{self, RouterResponse, StorageErrorExt}, db::StorageInterface, services, - types::{api::customers, storage}, + types::{ + api::customers::{self, CustomerRequestExt}, + storage, + }, }; #[instrument(skip(db))] diff --git a/crates/router/src/core/mandate.rs b/crates/router/src/core/mandate.rs index 42a54646e6..6f78f869a3 100644 --- a/crates/router/src/core/mandate.rs +++ b/crates/router/src/core/mandate.rs @@ -7,7 +7,10 @@ use crate::{ routes::AppState, services, types::{ - api::{customers, mandates}, + api::{ + customers, + mandates::{self, MandateResponseExt}, + }, storage, }, }; diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index c94da51c1c..d0bc34ba32 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -16,7 +16,7 @@ use crate::{ routes::AppState, services, types::{ - api, + api::{self, CreatePaymentMethodExt}, storage::{self, enums}, }, utils::{self, BytesExt, OptionExt, StringExt, ValueExt}, diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 9b6da9716c..61a47e4bc2 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -32,7 +32,7 @@ use crate::{ services, types::{ self, - api::{self, PaymentsResponse, PaymentsRetrieveRequest}, + api::{self, PaymentIdTypeExt, PaymentsResponse, PaymentsRetrieveRequest}, storage::{self, enums}, }, utils::{self, OptionExt}, @@ -406,7 +406,7 @@ where { payment_data .sessions_token - .push(types::ConnectorSessionToken { + .push(api::ConnectorSessionToken { connector_name, session_token, }); @@ -462,7 +462,7 @@ where pub force_sync: Option, pub payment_method_data: Option, pub refunds: Vec, - pub sessions_token: Vec, + pub sessions_token: Vec, } #[derive(Debug)] diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 9e1c146db2..b1805c5d1f 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -22,7 +22,7 @@ use crate::{ services, types::{ self, - api::{self, enums as api_enums}, + api::{self, enums as api_enums, CustomerAcceptanceExt, MandateValidationFieldsExt}, storage::{self, enums as storage_enums, ephemeral_key}, }, utils::{ @@ -1092,9 +1092,9 @@ pub fn make_url_with_signature( params: parameters, return_url_with_query_params: url.to_string(), http_method: if merchant_account.redirect_to_merchant_with_http_post { - services::Method::Post + services::Method::Post.to_string() } else { - services::Method::Get + services::Method::Get.to_string() }, headers: Vec::new(), }) @@ -1160,14 +1160,14 @@ pub fn generate_mandate( Some(match data.mandate_type { api::MandateType::SingleUse(data) => new_mandate .set_mandate_amount(Some(data.amount)) - .set_mandate_currency(Some(data.currency)) + .set_mandate_currency(Some(data.currency.into())) .set_mandate_type(storage_enums::MandateType::SingleUse) .to_owned(), api::MandateType::MultiUse(op_data) => match op_data { Some(data) => new_mandate .set_mandate_amount(Some(data.amount)) - .set_mandate_currency(Some(data.currency)), + .set_mandate_currency(Some(data.currency.into())), None => &mut new_mandate, } .set_mandate_type(storage_enums::MandateType::MultiUse) diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs index c99c92c054..2bb11f5222 100644 --- a/crates/router/src/core/payments/operations/payment_cancel.rs +++ b/crates/router/src/core/payments/operations/payment_cancel.rs @@ -14,7 +14,7 @@ use crate::{ db::StorageInterface, routes::AppState, types::{ - api, + api::{self, PaymentIdTypeExt}, storage::{self, enums, Customer}, }, utils::OptionExt, diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs index bfad77e603..95fe0858dc 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -13,8 +13,7 @@ use crate::{ db::StorageInterface, routes::AppState, types::{ - api, - api::PaymentsCaptureRequest, + api::{self, PaymentIdTypeExt, PaymentsCaptureRequest}, storage::{self, enums}, }, utils::OptionExt, diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index b4a062806c..0e0ada459c 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -15,7 +15,8 @@ use crate::{ db::StorageInterface, routes::AppState, types::{ - self, api, + self, + api::{self, PaymentIdTypeExt}, storage::{self, enums}, }, utils::{self, OptionExt}, diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 3d1b1cde4c..9233979645 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -17,7 +17,8 @@ use crate::{ db::StorageInterface, routes::AppState, types::{ - self, api, + self, + api::{self, PaymentIdTypeExt}, storage::{ self, enums::{self, IntentStatus}, diff --git a/crates/router/src/core/payments/operations/payment_method_validate.rs b/crates/router/src/core/payments/operations/payment_method_validate.rs index 76f7110e7a..3c91337730 100644 --- a/crates/router/src/core/payments/operations/payment_method_validate.rs +++ b/crates/router/src/core/payments/operations/payment_method_validate.rs @@ -19,7 +19,7 @@ use crate::{ routes::AppState, types::{ self, - api::{self, enums as api_enums}, + api::{self, enums as api_enums, PaymentIdTypeExt}, storage::{self, enums as storage_enums}, }, utils, diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index 8b777a06bc..c87b17b205 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -14,7 +14,7 @@ use crate::{ db::StorageInterface, routes::AppState, types::{ - api, + api::{self, PaymentIdTypeExt}, storage::{self, enums}, }, utils::OptionExt, diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs index 17e66296a5..c4dcaf29fc 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -14,7 +14,7 @@ use crate::{ db::StorageInterface, routes::AppState, types::{ - api, + api::{self, PaymentIdTypeExt}, storage::{self, enums, Customer}, }, utils::OptionExt, diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 09b8ed76e8..21e37d1907 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -15,7 +15,7 @@ use crate::{ db::StorageInterface, routes::AppState, types::{ - api, + api::{self, PaymentIdTypeExt}, storage::{self, enums}, }, utils::{OptionExt, StringExt}, diff --git a/crates/router/src/lib.rs b/crates/router/src/lib.rs index c918af20f9..06afd4d62e 100644 --- a/crates/router/src/lib.rs +++ b/crates/router/src/lib.rs @@ -27,6 +27,7 @@ pub mod core; pub mod cors; pub mod db; pub mod env; +pub(crate) mod macros; pub mod routes; pub mod scheduler; diff --git a/crates/router/src/macros.rs b/crates/router/src/macros.rs new file mode 100644 index 0000000000..3cf687099d --- /dev/null +++ b/crates/router/src/macros.rs @@ -0,0 +1,46 @@ +#[macro_export] +macro_rules! newtype_impl { + ($is_pub:vis, $name:ident, $ty_path:path) => { + impl std::ops::Deref for $name { + type Target = $ty_path; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl std::ops::DerefMut for $name { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + impl From<$ty_path> for $name { + fn from(ty: $ty_path) -> Self { + Self(ty) + } + } + + impl $name { + pub fn into_inner(self) -> $ty_path { + self.0 + } + } + }; +} + +#[macro_export] +macro_rules! newtype { + ($is_pub:vis $name:ident = $ty_path:path) => { + $is_pub struct $name(pub $ty_path); + + $crate::newtype_impl!($is_pub, $name, $ty_path); + }; + + ($is_pub:vis $name:ident = $ty_path:path, derives = ($($trt:path),*)) => { + #[derive($($trt),*)] + $is_pub struct $name(pub $ty_path); + + $crate::newtype_impl!($is_pub, $name, $ty_path); + }; +} diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 03e8cdcffa..571a11b423 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -121,12 +121,6 @@ pub struct PaymentsSessionData { //TODO: Add the fields here as required } -#[derive(Debug, Clone, serde::Serialize)] -pub struct ConnectorSessionToken { - pub connector_name: String, - pub session_token: String, -} - #[derive(serde::Serialize, Debug)] pub struct PaymentsSessionResponseData { pub client_token: Option, diff --git a/crates/router/src/types/api/admin.rs b/crates/router/src/types/api/admin.rs index 7dd16e9dc5..3de3da6133 100644 --- a/crates/router/src/types/api/admin.rs +++ b/crates/router/src/types/api/admin.rs @@ -1,127 +1,62 @@ -use serde::{Deserialize, Serialize}; - -pub use self::CreateMerchantAccount as MerchantAccountResponse; -use super::payments::AddressDetails; -use crate::{ - pii::{self, Secret, StrongSecret}, - types::api::enums as api_enums, +pub use api_models::admin::{ + CreateMerchantAccount, CustomRoutingRules, DeleteMcaResponse, DeleteResponse, + MerchantConnectorId, MerchantDetails, MerchantId, PaymentConnectorCreate, PaymentMethods, + WebhookDetails, }; -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -pub struct CreateMerchantAccount { - pub merchant_id: String, - pub merchant_name: Option, - pub api_key: Option>, - pub merchant_details: Option, - pub return_url: Option, - pub webhook_details: Option, - pub routing_algorithm: Option, - pub custom_routing_rules: Option>, - pub sub_merchants_enabled: Option, - pub parent_merchant_id: Option, - pub enable_payment_response_hash: Option, - pub payment_response_hash_key: Option, - pub redirect_to_merchant_with_http_post: Option, - pub metadata: Option, - pub publishable_key: Option, -} +//use serde::{Serialize, Deserialize}; +pub use self::CreateMerchantAccount as MerchantAccountResponse; -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -pub struct MerchantDetails { - pub primary_contact_person: Option>, - pub primary_phone: Option>, - pub primary_email: Option>, - pub secondary_contact_person: Option>, - pub secondary_phone: Option>, - pub secondary_email: Option>, - pub website: Option, - pub about_business: Option, - pub address: Option, -} +//use crate::newtype; -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -pub struct WebhookDetails { - pub webhook_version: Option, - pub webhook_username: Option, - pub webhook_password: Option>, - pub webhook_url: Option>, - pub payment_created_enabled: Option, - pub payment_succeeded_enabled: Option, - pub payment_failed_enabled: Option, -} +//use api_models::admin; -#[derive(Default, Clone, Debug, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -pub struct CustomRoutingRules { - pub payment_methods_incl: Option>, //FIXME Add enums for all PM enums - pub payment_methods_excl: Option>, - pub payment_method_types_incl: Option>, - pub payment_method_types_excl: Option>, - pub payment_method_issuers_incl: Option>, - pub payment_method_issuers_excl: Option>, - pub countries_incl: Option>, - pub countries_excl: Option>, - pub currencies_incl: Option>, - pub currencies_excl: Option>, - pub metadata_filters_keys: Option>, - pub metadata_filters_values: Option>, - pub connectors_pecking_order: Option>, - pub connectors_traffic_weightage_key: Option>, - pub connectors_traffic_weightage_value: Option>, -} +//newtype!( +//pub CreateMerchantAccount = admin::CreateMerchantAccount, +//derives = (Clone, Debug, Deserialize, Serialize) +//); -#[derive(Debug, Serialize)] -pub struct DeleteResponse { - pub merchant_id: String, - pub deleted: bool, -} +//newtype!( +//pub MerchantDetails = admin::MerchantDetails, +//derives = (Clone, Debug, Deserialize, Serialize) +//); -#[derive(Default, Debug, Deserialize, Serialize)] -pub struct MerchantId { - pub merchant_id: String, -} +//newtype!( +//pub WebhookDetails = admin::WebhookDetails, +//derives = (Clone, Debug, Deserialize, Serialize) +//); -#[derive(Default, Debug, Deserialize, Serialize)] -pub struct MerchantConnectorId { - pub merchant_id: String, - pub merchant_connector_id: i32, -} -//Merchant Connector Account CRUD -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct PaymentConnectorCreate { - pub connector_type: api_enums::ConnectorType, - pub connector_name: String, - pub merchant_connector_id: Option, - pub connector_account_details: Option>, - pub test_mode: Option, - pub disabled: Option, - pub payment_methods_enabled: Option>, - pub metadata: Option, -} +//newtype!( +//pub CustomRoutingRules = admin::CustomRoutingRules, +//derives = (Default, Clone, Debug, Deserialize, Serialize) +//); -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct PaymentMethods { - pub payment_method: api_enums::PaymentMethodType, - pub payment_method_types: Option>, - pub payment_method_issuers: Option>, - pub payment_schemes: Option>, - pub accepted_currencies: Option>, - pub accepted_countries: Option>, - pub minimum_amount: Option, - pub maximum_amount: Option, - pub recurring_enabled: bool, - pub installment_payment_enabled: bool, - pub payment_experience: Option>, //TODO -} +//newtype!( +//pub DeleteResponse = admin::DeleteResponse, +//derives = (Debug, Serialize) +//); -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct DeleteMcaResponse { - pub merchant_id: String, - pub merchant_connector_id: i32, - pub deleted: bool, -} +//newtype!( +//pub MerchantId = admin::MerchantId, +//derives = (Default, Debug, Deserialize, Serialize) +//); + +//newtype!( +//pub MerchantConnectorId = admin::MerchantConnectorId, +//derives = (Default, Debug, Deserialize, Serialize) +//); + +//newtype!( +//pub PaymentConnectorCreate = admin::PaymentConnectorCreate, +//derives = (Debug, Clone, Serialize, Deserialize) +//); + +//newtype!( +//pub PaymentMethods = admin::PaymentMethods, +//derives = (Debug, Clone, Serialize, Deserialize) +//); + +//newtype!( +//pub DeleteMcaResponse = admin::DeleteMcaResponse, +//derives = (Debug, Clone, Serialize, Deserialize) +//); diff --git a/crates/router/src/types/api/customers.rs b/crates/router/src/types/api/customers.rs index 1800307369..6cd0edd7e1 100644 --- a/crates/router/src/types/api/customers.rs +++ b/crates/router/src/types/api/customers.rs @@ -1,31 +1,27 @@ -use common_utils::custom_serde; +use api_models::customers; +pub use api_models::customers::{CustomerDeleteResponse, CustomerId, CustomerRequest}; use error_stack::ResultExt; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use crate::{ - consts, core::errors::{self, RouterResult}, - pii::{self, PeekInterface, Secret}, + newtype, + pii::PeekInterface, types::storage, utils::{self, ValidateCall}, }; -#[derive(Debug, Default, Clone, Deserialize, Serialize)] -pub struct CustomerRequest { - #[serde(default = "generate_customer_id")] - pub customer_id: String, - #[serde(default = "unknown_merchant", skip)] - pub merchant_id: String, - pub name: Option, - pub email: Option>, - pub phone: Option>, - pub description: Option, - pub phone_country_code: Option, - pub metadata: Option, +newtype!( + pub CustomerResponse = customers::CustomerResponse, + derives = (Debug, Clone, Serialize) +); + +pub(crate) trait CustomerRequestExt: Sized { + fn validate(self) -> RouterResult; } -impl CustomerRequest { - pub(crate) fn validate(self) -> RouterResult { +impl CustomerRequestExt for CustomerRequest { + fn validate(self) -> RouterResult { self.email .as_ref() .validate_opt(|email| utils::validate_email(email.peek())) @@ -38,22 +34,9 @@ impl CustomerRequest { } } -#[derive(Debug, Clone, Serialize)] -pub struct CustomerResponse { - pub customer_id: String, - pub name: Option, - pub email: Option>, - pub phone: Option>, - pub phone_country_code: Option, - pub description: Option, - #[serde(with = "custom_serde::iso8601")] - pub created_at: time::PrimitiveDateTime, - pub metadata: Option, -} - impl From for CustomerResponse { fn from(cust: storage::Customer) -> Self { - Self { + customers::CustomerResponse { customer_id: cust.customer_id, name: cust.name, email: cust.email, @@ -62,25 +45,8 @@ impl From for CustomerResponse { description: cust.description, created_at: cust.created_at, metadata: cust.metadata, + address: None, } + .into() } } - -#[derive(Default, Debug, Deserialize, Serialize)] -pub struct CustomerId { - pub customer_id: String, -} - -#[derive(Default, Debug, Deserialize, Serialize)] -pub struct CustomerDeleteResponse { - pub customer_id: String, - pub deleted: bool, -} - -pub fn generate_customer_id() -> String { - utils::generate_id(consts::ID_LENGTH, "cus") -} - -fn unknown_merchant() -> String { - String::from("merchant_unknown") -} diff --git a/crates/router/src/types/api/enums.rs b/crates/router/src/types/api/enums.rs index 8db8250bb5..f048bbea39 100644 --- a/crates/router/src/types/api/enums.rs +++ b/crates/router/src/types/api/enums.rs @@ -1,447 +1 @@ -#[derive( - Clone, - Copy, - Debug, - Default, - Eq, - PartialEq, - serde::Deserialize, - serde::Serialize, - strum::Display, - strum::EnumString, -)] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -pub enum AttemptStatus { - Started, - AuthenticationFailed, - JuspayDeclined, - PendingVbv, - VbvSuccessful, - Authorized, - AuthorizationFailed, - Charged, - Authorizing, - CodInitiated, - Voided, - VoidInitiated, - CaptureInitiated, - CaptureFailed, - VoidFailed, - AutoRefunded, - PartialCharged, - #[default] - Pending, - Failure, - PaymentMethodAwaited, - ConfirmationAwaited, -} - -#[derive( - Clone, - Copy, - Debug, - Default, - Eq, - PartialEq, - serde::Deserialize, - serde::Serialize, - strum::Display, - strum::EnumString, -)] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -pub enum AuthenticationType { - #[default] - ThreeDs, - NoThreeDs, -} - -#[derive( - Clone, - Copy, - Debug, - Default, - Eq, - PartialEq, - serde::Deserialize, - serde::Serialize, - strum::Display, - strum::EnumString, -)] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -pub enum CaptureMethod { - #[default] - Automatic, - Manual, - ManualMultiple, - Scheduled, -} - -#[derive( - Clone, - Copy, - Debug, - Eq, - PartialEq, - strum::Display, - strum::EnumString, - serde::Deserialize, - serde::Serialize, -)] -#[strum(serialize_all = "snake_case")] -#[serde(rename_all = "snake_case")] -pub enum ConnectorType { - /// PayFacs, Acquirers, Gateways, BNPL etc - PaymentProcessor, - /// Fraud, Currency Conversion, Crypto etc - PaymentVas, - /// Accounting, Billing, Invoicing, Tax etc - FinOperations, - /// Inventory, ERP, CRM, KYC etc - FizOperations, - /// Payment Networks like Visa, MasterCard etc - Networks, - /// All types of banks including corporate / commercial / personal / neo banks - BankingEntities, - /// All types of non-banking financial institutions including Insurance, Credit / Lending etc - NonBankingFinance, -} - -#[allow(clippy::upper_case_acronyms)] -#[derive( - Clone, - Copy, - Debug, - Default, - Eq, - Hash, - PartialEq, - serde::Deserialize, - serde::Serialize, - strum::Display, - strum::EnumString, -)] -pub enum Currency { - AED, - ALL, - AMD, - ARS, - AUD, - AWG, - AZN, - BBD, - BDT, - BHD, - BMD, - BND, - BOB, - BRL, - BSD, - BWP, - BZD, - CAD, - CHF, - CNY, - COP, - CRC, - CUP, - CZK, - DKK, - DOP, - DZD, - EGP, - ETB, - EUR, - FJD, - GBP, - GHS, - GIP, - GMD, - GTQ, - GYD, - HKD, - HNL, - HRK, - HTG, - HUF, - IDR, - ILS, - INR, - JMD, - JOD, - JPY, - KES, - KGS, - KHR, - KRW, - KWD, - KYD, - KZT, - LAK, - LBP, - LKR, - LRD, - LSL, - MAD, - MDL, - MKD, - MMK, - MNT, - MOP, - MUR, - MVR, - MWK, - MXN, - MYR, - NAD, - NGN, - NIO, - NOK, - NPR, - NZD, - OMR, - PEN, - PGK, - PHP, - PKR, - PLN, - QAR, - RUB, - SAR, - SCR, - SEK, - SGD, - SLL, - SOS, - SSP, - SVC, - SZL, - THB, - TTD, - TWD, - TZS, - #[default] - USD, - UYU, - UZS, - YER, - ZAR, -} - -#[derive( - Clone, - Copy, - Debug, - Eq, - PartialEq, - serde::Deserialize, - serde::Serialize, - strum::Display, - strum::EnumString, -)] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -pub enum EventType { - PaymentSucceeded, -} - -#[derive( - Clone, - Copy, - Debug, - Default, - Eq, - PartialEq, - serde::Deserialize, - serde::Serialize, - strum::Display, - strum::EnumString, -)] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -pub enum IntentStatus { - Succeeded, - Failed, - Cancelled, - Processing, - RequiresCustomerAction, - RequiresPaymentMethod, - #[default] - RequiresConfirmation, - RequiresCapture, -} - -#[derive( - Clone, - Copy, - Debug, - Default, - Eq, - PartialEq, - serde::Deserialize, - serde::Serialize, - strum::Display, - strum::EnumString, -)] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -pub enum FutureUsage { - #[default] - OffSession, - OnSession, -} - -#[derive( - Clone, - Copy, - Debug, - Eq, - Hash, - PartialEq, - serde::Deserialize, - serde::Serialize, - strum::Display, - strum::EnumString, -)] -#[strum(serialize_all = "snake_case")] -#[serde(rename_all = "snake_case")] -pub enum PaymentMethodIssuerCode { - JpHdfc, - JpIcici, - JpGooglepay, - JpApplepay, - JpPhonepay, - JpWechat, - JpSofort, - JpGiropay, - JpSepa, - JpBacs, -} - -#[derive( - Clone, - Copy, - Debug, - Eq, - Hash, - PartialEq, - serde::Deserialize, - serde::Serialize, - strum::Display, - strum::EnumString, -)] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -pub enum PaymentMethodSubType { - Credit, - Debit, - UpiIntent, - UpiCollect, - CreditCardInstallments, - PayLaterInstallments, -} - -#[derive( - Clone, - Copy, - Debug, - Default, - Eq, - Hash, - PartialEq, - serde::Deserialize, - serde::Serialize, - strum::Display, - strum::EnumString, -)] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -pub enum PaymentMethodType { - Card, - PaymentContainer, - #[default] - BankTransfer, - BankDebit, - PayLater, - Netbanking, - Upi, - OpenBanking, - ConsumerFinance, - Wallet, - Klarna, - Paypal, -} - -#[derive( - Clone, - Copy, - Debug, - Eq, - Hash, - PartialEq, - serde::Deserialize, - serde::Serialize, - strum::Display, - strum::EnumString, -)] -#[serde(rename_all = "lowercase")] -#[strum(serialize_all = "lowercase")] -pub enum WalletIssuer { - GooglePay, - ApplePay, -} - -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, strum::Display, strum::EnumString)] -#[strum(serialize_all = "snake_case")] -pub enum RefundStatus { - Failure, - ManualReview, - #[default] - Pending, - Success, - TransactionFailure, -} - -#[derive( - Clone, - Copy, - Debug, - Eq, - PartialEq, - serde::Deserialize, - serde::Serialize, - strum::Display, - strum::EnumString, -)] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -pub enum RoutingAlgorithm { - RoundRobin, - MaxConversion, - MinCost, - Custom, -} - -#[derive( - Clone, - Copy, - Debug, - Eq, - PartialEq, - Default, - serde::Deserialize, - serde::Serialize, - strum::Display, - strum::EnumString, -)] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -pub enum MandateStatus { - #[default] - Active, - Inactive, - Pending, - Revoked, -} +pub use api_models::enums::*; diff --git a/crates/router/src/types/api/mandates.rs b/crates/router/src/types/api/mandates.rs index 6b6f5934a5..d2b44126e2 100644 --- a/crates/router/src/types/api/mandates.rs +++ b/crates/router/src/types/api/mandates.rs @@ -1,3 +1,5 @@ +use api_models::mandates; +pub use api_models::mandates::{MandateId, MandateResponse, MandateRevokedResponse}; use error_stack::ResultExt; use serde::{Deserialize, Serialize}; @@ -6,40 +8,27 @@ use crate::{ errors::{self, RouterResult, StorageErrorExt}, payment_methods, }, - pii::Secret, + newtype, routes::AppState, types::{ - api::{self, enums as api_enums}, + api, storage::{self, enums as storage_enums}, }, }; -#[derive(Default, Debug, Deserialize, Serialize)] -pub struct MandateId { - pub mandate_id: String, +newtype!( + pub MandateCardDetails = mandates::MandateCardDetails, + derives = (Default, Debug, Deserialize, Serialize) +); + +#[async_trait::async_trait] +pub(crate) trait MandateResponseExt: Sized { + async fn from_db_mandate(state: &AppState, mandate: storage::Mandate) -> RouterResult; } -#[derive(Default, Debug, Deserialize, Serialize)] -pub struct MandateRevokedResponse { - pub mandate_id: String, - pub status: api_enums::MandateStatus, -} - -#[derive(Default, Debug, Deserialize, Serialize)] -pub struct MandateResponse { - pub mandate_id: String, - pub status: api_enums::MandateStatus, - pub payment_method_id: String, - pub payment_method: String, - pub card: Option, - pub customer_acceptance: Option, -} - -impl MandateResponse { - pub async fn from_db_mandate( - state: &AppState, - mandate: storage::Mandate, - ) -> RouterResult { +#[async_trait::async_trait] +impl MandateResponseExt for MandateResponse { + async fn from_db_mandate(state: &AppState, mandate: storage::Mandate) -> RouterResult { let db = &*state.store; let payment_method = db .find_payment_method(&mandate.payment_method_id) @@ -47,6 +36,7 @@ impl MandateResponse { .map_err(|error| { error.to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound) })?; + let card = if payment_method.payment_method == storage_enums::PaymentMethodType::Card { let get_card_resp = payment_methods::cards::get_card_from_legacy_locker( state, @@ -57,11 +47,12 @@ impl MandateResponse { let card_detail = payment_methods::transformers::get_card_detail(&payment_method, get_card_resp.card) .change_context(errors::ApiErrorResponse::InternalServerError)?; - Some(MandateCardDetails::from(card_detail)) + Some(MandateCardDetails::from(card_detail).into_inner()) } else { None }; - Ok(MandateResponse { + + Ok(Self { mandate_id: mandate.mandate_id, customer_acceptance: Some(api::payments::CustomerAcceptance { acceptance_type: if mandate.customer_ip_address.is_some() { @@ -83,21 +74,9 @@ impl MandateResponse { } } -#[derive(Default, Debug, Deserialize, Serialize)] -pub struct MandateCardDetails { - pub last4_digits: Option, - pub card_exp_month: Option>, - pub card_exp_year: Option>, - pub card_holder_name: Option>, - pub card_token: Option>, - pub scheme: Option, - pub issuer_country: Option, - pub card_fingerprint: Option>, -} - impl From for MandateCardDetails { fn from(card_details_from_locker: api::payment_methods::CardDetailFromLocker) -> Self { - Self { + mandates::MandateCardDetails { last4_digits: card_details_from_locker.last4_digits, card_exp_month: card_details_from_locker.expiry_month.clone(), card_exp_year: card_details_from_locker.expiry_year.clone(), @@ -107,5 +86,6 @@ impl From for MandateCardDetails { issuer_country: card_details_from_locker.issuer_country, card_fingerprint: card_details_from_locker.card_fingerprint, } + .into() } } diff --git a/crates/router/src/types/api/payment_methods.rs b/crates/router/src/types/api/payment_methods.rs index 4d591de01f..3f4dc68866 100644 --- a/crates/router/src/types/api/payment_methods.rs +++ b/crates/router/src/types/api/payment_methods.rs @@ -1,14 +1,18 @@ use std::collections::HashMap; +pub use api_models::payment_methods::{ + CardDetail, CardDetailFromLocker, CreatePaymentMethod, CustomerPaymentMethod, + DeletePaymentMethodResponse, DeleteTokenizeByDateRequest, DeleteTokenizeByTokenRequest, + GetTokenizePayloadRequest, GetTokenizePayloadResponse, ListCustomerPaymentMethodsResponse, + ListPaymentMethodRequest, ListPaymentMethodResponse, PaymentMethodId, PaymentMethodResponse, + TokenizePayloadEncrypted, TokenizePayloadRequest, TokenizedCardValue1, TokenizedCardValue2, +}; use error_stack::report; use literally::hmap; use once_cell::sync::Lazy; -use serde::{Deserialize, Serialize}; -use time::PrimitiveDateTime; use crate::{ core::errors::{self, RouterResult}, - pii::{self, Secret}, types::api::enums as api_enums, }; @@ -68,21 +72,20 @@ static PAYMENT_METHOD_ISSUER_SET: Lazy< } }); -#[derive(Debug, Deserialize, Serialize, Clone)] -#[serde(deny_unknown_fields)] -pub struct CreatePaymentMethod { - pub merchant_id: Option, - pub payment_method: api_enums::PaymentMethodType, - pub payment_method_type: Option, - pub payment_method_issuer: Option, - pub payment_method_issuer_code: Option, - pub card: Option, - pub metadata: Option, - pub customer_id: Option, +pub(crate) trait CreatePaymentMethodExt { + fn validate(&self) -> RouterResult<()>; + fn check_subtype_mapping( + dict: &HashMap>, + the_type: T, + the_subtype: Option, + ) -> bool + where + T: std::cmp::Eq + std::hash::Hash, + U: std::cmp::PartialEq; } -impl CreatePaymentMethod { - pub fn validate(&self) -> RouterResult<()> { +impl CreatePaymentMethodExt for CreatePaymentMethod { + fn validate(&self) -> RouterResult<()> { let pm_subtype_map = Lazy::get(&PAYMENT_METHOD_TYPE_SET) .unwrap_or_else(|| Lazy::force(&PAYMENT_METHOD_TYPE_SET)); if !Self::check_subtype_mapping( @@ -131,174 +134,3 @@ impl CreatePaymentMethod { .unwrap_or(true) } } - -#[derive(Debug, Deserialize, Serialize, Clone)] -#[serde(deny_unknown_fields)] -pub struct CardDetail { - pub card_number: Secret, - pub card_exp_month: Secret, - pub card_exp_year: Secret, - pub card_holder_name: Option>, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct PaymentMethodResponse { - pub payment_method_id: String, - pub payment_method: api_enums::PaymentMethodType, - pub payment_method_type: Option, - pub payment_method_issuer: Option, - pub payment_method_issuer_code: Option, - pub card: Option, - //TODO: Populate this on request? - // pub accepted_country: Option>, - // pub accepted_currency: Option>, - // pub minimum_amount: Option, - // pub maximum_amount: Option, - pub recurring_enabled: bool, - pub installment_payment_enabled: bool, - pub payment_experience: Option>, //TODO change it to enum - pub metadata: Option, - #[serde(default, with = "common_utils::custom_serde::iso8601::option")] - pub created: Option, -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct CardDetailFromLocker { - pub scheme: Option, - pub issuer_country: Option, - pub last4_digits: Option, - #[serde(skip)] - pub card_number: Option>, - pub expiry_month: Option>, - pub expiry_year: Option>, - pub card_token: Option>, - pub card_holder_name: Option>, - pub card_fingerprint: Option>, -} - -//List Payment Method -#[derive(Debug, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct ListPaymentMethodRequest { - pub accepted_countries: Option>, - pub accepted_currencies: Option>, - pub amount: Option, - pub recurring_enabled: Option, - pub installment_payment_enabled: Option, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct ListPaymentMethodResponse { - pub payment_method: api_enums::PaymentMethodType, - pub payment_method_types: Option>, - pub payment_method_issuers: Option>, - pub payment_method_issuer_code: Option>, - pub payment_schemes: Option>, - pub accepted_countries: Option>, - pub accepted_currencies: Option>, - pub minimum_amount: Option, - pub maximum_amount: Option, - pub recurring_enabled: bool, - pub installment_payment_enabled: bool, - pub payment_experience: Option>, //TODO change it to enum -} - -#[derive(Debug, Serialize)] -pub struct ListCustomerPaymentMethodsResponse { - pub enabled_payment_methods: Vec, - pub customer_payment_methods: Vec, -} - -#[derive(Debug, Serialize)] -pub struct DeletePaymentMethodResponse { - pub payment_method_id: String, - pub deleted: bool, -} - -#[derive(Debug, Serialize)] -pub struct CustomerPaymentMethod { - pub payment_token: String, - pub customer_id: String, - pub payment_method: api_enums::PaymentMethodType, - pub payment_method_type: Option, - pub payment_method_issuer: Option, - pub payment_method_issuer_code: Option, - //TODO: Populate this on request? - // pub accepted_country: Option>, - // pub accepted_currency: Option>, - // pub minimum_amount: Option, - // pub maximum_amount: Option, - pub recurring_enabled: bool, - pub installment_payment_enabled: bool, - pub payment_experience: Option>, //TODO change it to enum - pub card: Option, - pub metadata: Option, - #[serde(default, with = "common_utils::custom_serde::iso8601::option")] - pub created: Option, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct PaymentMethodId { - pub payment_method_id: String, -} - -//------------------------------------------------TokenizeService------------------------------------------------ -#[derive(Debug, Serialize, Deserialize)] -pub struct TokenizePayloadEncrypted { - pub payload: String, - pub key_id: String, - pub version: Option, -} - -#[derive(Debug, Serialize, Deserialize, router_derive::DebugAsDisplay)] -pub struct TokenizePayloadRequest { - pub value1: String, - pub value2: String, - pub lookup_key: String, - pub service_name: String, -} - -#[derive(Debug, Serialize, Deserialize, router_derive::DebugAsDisplay)] -pub struct GetTokenizePayloadRequest { - pub lookup_key: String, - pub get_value2: bool, -} - -#[derive(Debug, Serialize, router_derive::DebugAsDisplay)] -pub struct DeleteTokenizeByTokenRequest { - pub lookup_key: String, -} - -#[derive(Debug, Serialize)] //FIXME yet to be implemented -pub struct DeleteTokenizeByDateRequest { - pub buffer_minutes: i32, - pub service_name: String, - pub max_rows: i32, -} - -#[derive(Debug, Deserialize, router_derive::DebugAsDisplay)] -pub struct GetTokenizePayloadResponse { - pub lookup_key: String, - pub get_value2: Option, -} -#[derive(Debug, Serialize, Deserialize, router_derive::DebugAsDisplay)] -#[serde(rename_all = "camelCase")] -pub struct TokenizedCardValue1 { - pub card_number: String, - pub exp_year: String, - pub exp_month: String, - pub name_on_card: Option, - pub nickname: Option, - pub card_last_four: Option, - pub card_token: Option, -} - -#[derive(Debug, Serialize, Deserialize, router_derive::DebugAsDisplay)] -#[serde(rename_all = "camelCase")] - -pub struct TokenizedCardValue2 { - pub card_security_code: Option, - pub card_fingerprint: Option, - pub external_id: Option, - pub customer_id: Option, -} diff --git a/crates/router/src/types/api/payments.rs b/crates/router/src/types/api/payments.rs index e2b3b72327..4ddc554aca 100644 --- a/crates/router/src/types/api/payments.rs +++ b/crates/router/src/types/api/payments.rs @@ -1,66 +1,31 @@ +use api_models::payments; +pub use api_models::payments::{ + AcceptanceType, Address, AddressDetails, Amount, AuthenticationForStartResponse, CCard, + ConnectorSessionToken, CustomerAcceptance, MandateData, MandateTxnType, MandateType, + MandateValidationFields, NextAction, NextActionType, OnlineMandate, PayLaterData, + PaymentIdType, PaymentListConstraints, PaymentListResponse, PaymentMethod, + PaymentMethodDataResponse, PaymentOp, PaymentRetrieveBody, PaymentsCancelRequest, + PaymentsCaptureRequest, PaymentsRedirectRequest, PaymentsRedirectionResponse, PaymentsRequest, + PaymentsResponse, PaymentsResponseForm, PaymentsRetrieveRequest, PaymentsSessionRequest, + PaymentsSessionResponse, PaymentsStartRequest, PgRedirectResponse, PhoneDetails, + RedirectionResponse, UrlDetails, VerifyRequest, VerifyResponse, WalletData, +}; use error_stack::{IntoReport, ResultExt}; -use masking::{PeekInterface, Secret}; -use router_derive::Setter; +use masking::PeekInterface; use time::PrimitiveDateTime; use crate::{ core::errors, - pii, services::api, - types::{self, api as api_types, api::enums as api_enums, storage}, - utils::custom_serde, + types::{self, api as api_types}, }; -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum PaymentOp { - Create, - Update, - Confirm, +pub(crate) trait PaymentsRequestExt { + fn is_mandate(&self) -> Option; } -#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] -#[serde(deny_unknown_fields)] -pub struct PaymentsRequest { - #[serde( - default, - deserialize_with = "custom_serde::payment_id_type::deserialize_option" - )] - pub payment_id: Option, - pub merchant_id: Option, - #[serde(default, deserialize_with = "custom_serde::amount::deserialize_option")] - pub amount: Option, - pub currency: Option, - pub capture_method: Option, - pub amount_to_capture: Option, - #[serde(default, with = "common_utils::custom_serde::iso8601::option")] - pub capture_on: Option, - pub confirm: Option, - pub customer_id: Option, - pub email: Option>, - pub name: Option>, - pub phone: Option>, - pub phone_country_code: Option, - pub off_session: Option, - pub description: Option, - pub return_url: Option, - pub setup_future_usage: Option, - pub authentication_type: Option, - pub payment_method_data: Option, - pub payment_method: Option, - pub payment_token: Option, - pub shipping: Option
, - pub billing: Option
, - pub statement_descriptor_name: Option, - pub statement_descriptor_suffix: Option, - pub metadata: Option, - pub client_secret: Option, - pub mandate_data: Option, - pub mandate_id: Option, - pub browser_info: Option, -} - -impl PaymentsRequest { - pub fn is_mandate(&self) -> Option { +impl PaymentsRequestExt for PaymentsRequest { + fn is_mandate(&self) -> Option { match (&self.mandate_data, &self.mandate_id) { (None, None) => None, (_, Some(_)) => Some(MandateTxnType::RecurringMandateTxn), @@ -69,231 +34,31 @@ impl PaymentsRequest { } } -#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)] -pub enum Amount { - Value(i32), - #[default] - Zero, +pub(crate) trait CustomerAcceptanceExt { + fn get_ip_address(&self) -> Option; + fn get_user_agent(&self) -> Option; + fn get_accepted_at(&self) -> PrimitiveDateTime; } -impl From for i32 { - fn from(amount: Amount) -> Self { - match amount { - Amount::Value(v) => v, - Amount::Zero => 0, - } - } -} -impl From for Amount { - fn from(val: i32) -> Self { - match val { - 0 => Amount::Zero, - amount => Amount::Value(amount), - } - } -} - -#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] -#[serde(deny_unknown_fields)] -pub struct PaymentsRedirectRequest { - pub payment_id: String, - pub merchant_id: String, - pub connector: String, - pub param: String, -} - -#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] -#[serde(deny_unknown_fields)] -pub struct VerifyRequest { - // The merchant_id is generated through api key - // and is later passed in the struct - pub merchant_id: Option, - pub customer_id: Option, - pub email: Option>, - pub name: Option>, - pub phone: Option>, - pub phone_country_code: Option, - pub payment_method: Option, - pub payment_method_data: Option, - pub payment_token: Option, - pub mandate_data: Option, - pub setup_future_usage: Option, - pub off_session: Option, - pub client_secret: Option, -} - -impl From for VerifyRequest { - fn from(item: PaymentsRequest) -> Self { - Self { - client_secret: item.client_secret, - merchant_id: item.merchant_id, - customer_id: item.customer_id, - email: item.email, - name: item.name, - phone: item.phone, - phone_country_code: item.phone_country_code, - payment_method: item.payment_method, - payment_method_data: item.payment_method_data, - payment_token: item.payment_token, - mandate_data: item.mandate_data, - setup_future_usage: item.setup_future_usage, - off_session: item.off_session, - } - } -} - -pub enum MandateTxnType { - NewMandateTxn, - RecurringMandateTxn, -} - -#[derive(Default, Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] -#[serde(deny_unknown_fields)] -pub struct MandateData { - pub customer_acceptance: CustomerAcceptance, - pub mandate_type: MandateType, -} - -#[derive(Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] -pub enum MandateType { - SingleUse(storage::MandateAmountData), - MultiUse(Option), -} - -impl Default for MandateType { - fn default() -> Self { - Self::MultiUse(None) - } -} - -#[derive(Default, Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] -#[serde(deny_unknown_fields)] -pub struct CustomerAcceptance { - pub acceptance_type: AcceptanceType, - #[serde(default, with = "common_utils::custom_serde::iso8601::option")] - pub accepted_at: Option, - pub online: Option, -} - -impl CustomerAcceptance { - pub fn get_ip_address(&self) -> Option { +impl CustomerAcceptanceExt for CustomerAcceptance { + fn get_ip_address(&self) -> Option { self.online .as_ref() .map(|data| data.ip_address.peek().to_owned()) } - pub fn get_user_agent(&self) -> Option { + + fn get_user_agent(&self) -> Option { self.online.as_ref().map(|data| data.user_agent.clone()) } - pub fn get_accepted_at(&self) -> PrimitiveDateTime { + + fn get_accepted_at(&self) -> PrimitiveDateTime { self.accepted_at .unwrap_or_else(common_utils::date_time::now) } } -#[derive(Default, Debug, serde::Deserialize, serde::Serialize, PartialEq, Eq, Clone)] -#[serde(rename_all = "lowercase")] -pub enum AcceptanceType { - Online, - #[default] - Offline, -} - -#[derive(Default, Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] -#[serde(deny_unknown_fields)] -pub struct OnlineMandate { - pub ip_address: Secret, - pub user_agent: String, -} - impl super::Router for PaymentsRequest {} -#[derive(Default, Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)] -pub struct CCard { - pub card_number: Secret, - pub card_exp_month: Secret, - pub card_exp_year: Secret, - pub card_holder_name: Secret, - pub card_cvc: Secret, -} - -#[derive(Default, Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)] -pub struct PayLaterData { - pub billing_email: String, - pub country: String, -} - -#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)] -pub enum PaymentMethod { - #[serde(rename(deserialize = "card"))] - Card(CCard), - #[serde(rename(deserialize = "bank_transfer"))] - BankTransfer, - #[serde(rename(deserialize = "wallet"))] - Wallet(WalletData), - #[serde(rename(deserialize = "pay_later"))] - PayLater(PayLaterData), - #[serde(rename(deserialize = "paypal"))] - Paypal, -} - -#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)] -pub struct WalletData { - pub issuer_name: api_enums::WalletIssuer, - pub token: String, -} - -#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize)] -pub struct CCardResponse { - last4: String, - exp_month: String, - exp_year: String, -} - -#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize)] -pub enum PaymentMethodDataResponse { - #[serde(rename = "card")] - Card(CCardResponse), - #[serde(rename(deserialize = "bank_transfer"))] - BankTransfer, - Wallet(WalletData), - PayLater(PayLaterData), - Paypal, -} - -impl Default for PaymentMethod { - fn default() -> Self { - PaymentMethod::BankTransfer - } -} - -#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -pub enum PaymentIdType { - PaymentIntentId(String), - ConnectorTransactionId(String), - PaymentTxnId(String), -} - -impl PaymentIdType { - pub fn get_payment_intent_id(&self) -> errors::CustomResult { - match self { - Self::PaymentIntentId(id) => Ok(id.clone()), - Self::ConnectorTransactionId(_) | Self::PaymentTxnId(_) => { - Err(errors::ValidationError::IncorrectValueProvided { - field_name: "payment_id", - }) - .into_report() - .attach_printable("Expected payment intent ID but got connector transaction ID") - } - } - } -} - -impl Default for PaymentIdType { - fn default() -> Self { - Self::PaymentIntentId(Default::default()) - } -} - // Core related api layer. #[derive(Debug, Clone)] pub struct Authorize; @@ -311,194 +76,31 @@ pub struct Session; #[derive(Debug, Clone)] pub struct Verify; -//#[derive(Debug, serde::Deserialize, serde::Serialize)] -//#[serde(untagged)] -//pub enum enums::CaptureMethod { -//Automatic, -//Manual, -//} - -//impl Default for enums::CaptureMethod { -//fn default() -> Self { -//enums::CaptureMethod::Manual -//} -//} - -#[derive(Default, Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] -#[serde(deny_unknown_fields)] -pub struct Address { - pub address: Option, - pub phone: Option, +pub(crate) trait PaymentIdTypeExt { + fn get_payment_intent_id(&self) -> errors::CustomResult; } -// used by customers also, could be moved outside -#[derive(Clone, Default, Debug, Eq, serde::Deserialize, serde::Serialize, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct AddressDetails { - pub city: Option, - pub country: Option, - pub line1: Option>, - pub line2: Option>, - pub line3: Option>, - pub zip: Option>, - pub state: Option>, - pub first_name: Option>, - pub last_name: Option>, +impl PaymentIdTypeExt for PaymentIdType { + fn get_payment_intent_id(&self) -> errors::CustomResult { + match self { + Self::PaymentIntentId(id) => Ok(id.clone()), + Self::ConnectorTransactionId(_) | Self::PaymentTxnId(_) => { + Err(errors::ValidationError::IncorrectValueProvided { + field_name: "payment_id", + }) + .into_report() + .attach_printable("Expected payment intent ID but got connector transaction ID") + } + } + } } -#[derive(Debug, Clone, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize)] -pub struct PhoneDetails { - pub number: Option>, - pub country_code: Option, +pub(crate) trait MandateValidationFieldsExt { + fn is_mandate(&self) -> Option; } -#[derive(Debug, Clone, Default, Eq, PartialEq, serde::Deserialize)] -pub(crate) struct PaymentsCaptureRequest { - pub payment_id: Option, - pub merchant_id: Option, - pub amount_to_capture: Option, - pub refund_uncaptured_amount: Option, - pub statement_descriptor_suffix: Option, - pub statement_descriptor_prefix: Option, -} - -#[derive(Default, Clone, Debug, Eq, PartialEq, serde::Serialize)] -pub struct UrlDetails { - pub url: String, - pub method: String, -} -#[derive(Default, Clone, Debug, Eq, PartialEq, serde::Serialize)] -pub struct AuthenticationForStartResponse { - pub authentication: UrlDetails, -} -#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)] -#[serde(rename_all = "snake_case")] -pub enum NextActionType { - RedirectToUrl, - DisplayQrCode, - InvokeSdkClient, - TriggerApi, -} -#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)] -pub struct NextAction { - #[serde(rename = "type")] - pub next_action_type: NextActionType, - pub redirect_to_url: Option, -} - -#[derive(Setter, Clone, Default, Debug, Eq, PartialEq, serde::Serialize)] -pub struct PaymentsResponse { - pub payment_id: Option, - pub merchant_id: Option, - pub status: api_enums::IntentStatus, - pub amount: i32, - pub amount_capturable: Option, - pub amount_received: Option, - pub client_secret: Option>, - #[serde(with = "common_utils::custom_serde::iso8601::option")] - pub created: Option, - pub currency: String, - pub customer_id: Option, - pub description: Option, - pub refunds: Option>, - pub mandate_id: Option, - pub mandate_data: Option, - pub setup_future_usage: Option, - pub off_session: Option, - #[serde(with = "common_utils::custom_serde::iso8601::option")] - pub capture_on: Option, - pub capture_method: Option, - #[auth_based] - pub payment_method: Option, - #[auth_based] - pub payment_method_data: Option, - pub payment_token: Option, - pub shipping: Option
, - pub billing: Option
, - pub metadata: Option, - pub email: Option>, - pub name: Option>, - pub phone: Option>, - pub return_url: Option, - pub authentication_type: Option, - pub statement_descriptor_name: Option, - pub statement_descriptor_suffix: Option, - pub next_action: Option, - pub cancellation_reason: Option, - pub error_code: Option, //TODO: Add error code column to the database - pub error_message: Option, -} - -#[derive(Clone, Debug, serde::Deserialize)] -#[serde(deny_unknown_fields)] -pub struct PaymentListConstraints { - pub customer_id: Option, - pub starting_after: Option, - pub ending_before: Option, - #[serde(default = "default_limit")] - pub limit: i64, - #[serde(default, with = "common_utils::custom_serde::iso8601::option")] - pub created: Option, - #[serde(default, with = "common_utils::custom_serde::iso8601::option")] - #[serde(rename = "created.lt")] - pub created_lt: Option, - #[serde(default, with = "common_utils::custom_serde::iso8601::option")] - #[serde(rename = "created.gt")] - pub created_gt: Option, - #[serde(default, with = "common_utils::custom_serde::iso8601::option")] - #[serde(rename = "created.lte")] - pub created_lte: Option, - #[serde(default, with = "common_utils::custom_serde::iso8601::option")] - #[serde(rename = "created.gte")] - pub created_gte: Option, -} - -#[derive(Clone, Debug, serde::Serialize)] -pub struct PaymentListResponse { - pub size: usize, - pub data: Vec, -} - -#[derive(Setter, Clone, Default, Debug, Eq, PartialEq, serde::Serialize)] -pub struct VerifyResponse { - pub verify_id: Option, - pub merchant_id: Option, - // pub status: enums::VerifyStatus, - pub client_secret: Option>, - pub customer_id: Option, - pub email: Option>, - pub name: Option>, - pub phone: Option>, - pub mandate_id: Option, - #[auth_based] - pub payment_method: Option, - #[auth_based] - pub payment_method_data: Option, - pub payment_token: Option, - pub error_code: Option, - pub error_message: Option, -} - -fn default_limit() -> i64 { - 10 -} - -#[derive(Default, Debug, serde::Deserialize, serde::Serialize)] -pub struct PaymentsRedirectionResponse { - pub redirect_url: String, -} - -pub struct MandateValidationFields { - pub mandate_id: Option, - pub confirm: Option, - pub customer_id: Option, - pub mandate_data: Option, - pub setup_future_usage: Option, - pub off_session: Option, -} - -impl MandateValidationFields { - pub fn is_mandate(&self) -> Option { +impl MandateValidationFieldsExt for MandateValidationFields { + fn is_mandate(&self) -> Option { match (&self.mandate_data, &self.mandate_id) { (None, None) => None, (_, Some(_)) => Some(MandateTxnType::RecurringMandateTxn), @@ -507,128 +109,9 @@ impl MandateValidationFields { } } -impl From<&PaymentsRequest> for MandateValidationFields { - fn from(req: &PaymentsRequest) -> Self { - Self { - mandate_id: req.mandate_id.clone(), - confirm: req.confirm, - customer_id: req.customer_id.clone(), - mandate_data: req.mandate_data.clone(), - setup_future_usage: req.setup_future_usage, - off_session: req.off_session, - } - } -} - -impl From<&VerifyRequest> for MandateValidationFields { - fn from(req: &VerifyRequest) -> Self { - Self { - mandate_id: None, - confirm: Some(true), - customer_id: req.customer_id.clone(), - mandate_data: req.mandate_data.clone(), - off_session: req.off_session, - setup_future_usage: req.setup_future_usage, - } - } -} - -impl PaymentsRedirectionResponse { - pub fn new(redirect_url: &str) -> Self { - Self { - redirect_url: redirect_url.to_owned(), - } - } -} - -impl From for PaymentsResponse { - fn from(item: PaymentsRequest) -> Self { - let payment_id = match item.payment_id { - Some(api_types::PaymentIdType::PaymentIntentId(id)) => Some(id), - _ => None, - }; - - Self { - payment_id, - merchant_id: item.merchant_id, - setup_future_usage: item.setup_future_usage, - off_session: item.off_session, - shipping: item.shipping, - billing: item.billing, - metadata: item.metadata, - capture_method: item.capture_method, - payment_method: item.payment_method, - capture_on: item.capture_on, - payment_method_data: item - .payment_method_data - .map(PaymentMethodDataResponse::from), - email: item.email, - name: item.name, - phone: item.phone, - payment_token: item.payment_token, - return_url: item.return_url, - authentication_type: item.authentication_type, - statement_descriptor_name: item.statement_descriptor_name, - statement_descriptor_suffix: item.statement_descriptor_suffix, - mandate_data: item.mandate_data, - ..Default::default() - } - } -} - -impl From for VerifyResponse { - fn from(item: VerifyRequest) -> Self { - Self { - merchant_id: item.merchant_id, - customer_id: item.customer_id, - email: item.email, - name: item.name, - phone: item.phone, - payment_method: item.payment_method, - payment_method_data: item - .payment_method_data - .map(PaymentMethodDataResponse::from), - payment_token: item.payment_token, - ..Default::default() - } - } -} - -impl From for PaymentsResponse { - fn from(item: PaymentsStartRequest) -> Self { - Self { - payment_id: Some(item.payment_id), - merchant_id: Some(item.merchant_id), - ..Default::default() - } - } -} - -impl From for PaymentsResponse { - fn from(item: PaymentsSessionRequest) -> Self { - let payment_id = match item.payment_id { - api_types::PaymentIdType::PaymentIntentId(id) => Some(id), - _ => None, - }; - - Self { - payment_id, - ..Default::default() - } - } -} - -impl From for PaymentsSessionResponse { - fn from(_item: PaymentsSessionRequest) -> Self { - Self { - session_token: vec![], - } - } -} - impl From for PaymentsResponse { fn from(item: types::storage::PaymentIntent) -> Self { - Self { + payments::PaymentsResponse { payment_id: Some(item.payment_id), merchant_id: Some(item.merchant_id), status: item.status.into(), @@ -645,105 +128,7 @@ impl From for PaymentsResponse { } } -impl From for PaymentsRequest { - fn from(item: PaymentsStartRequest) -> Self { - Self { - payment_id: Some(PaymentIdType::PaymentIntentId(item.payment_id)), - merchant_id: Some(item.merchant_id), - ..Default::default() - } - } -} - -impl From for PaymentsResponse { - // After removing the request from the payments_to_payments_response this will no longer be needed - fn from(item: PaymentsRetrieveRequest) -> Self { - let payment_id = match item.resource_id { - PaymentIdType::PaymentIntentId(id) => Some(id), - _ => None, - }; - - Self { - payment_id, - merchant_id: item.merchant_id, - ..Default::default() - } - } -} - -impl From for PaymentsResponse { - fn from(item: PaymentsCancelRequest) -> Self { - Self { - payment_id: Some(item.payment_id), - cancellation_reason: item.cancellation_reason, - ..Default::default() - } - } -} - -impl From for PaymentsResponse { - // After removing the request from the payments_to_payments_response this will no longer be needed - fn from(item: PaymentsCaptureRequest) -> Self { - Self { - payment_id: item.payment_id, - amount_received: item.amount_to_capture, - ..Self::default() - } - } -} - -#[derive(Debug, Clone, serde::Serialize)] -pub struct PgRedirectResponse { - pub payment_id: String, - pub status: api_enums::IntentStatus, - pub gateway_id: String, - pub customer_id: Option, - pub amount: Option, -} - -#[derive(Debug, serde::Serialize, PartialEq, Eq, serde::Deserialize)] -pub struct RedirectionResponse { - pub return_url: String, - pub params: Vec<(String, String)>, - pub return_url_with_query_params: String, - pub http_method: api::Method, - pub headers: Vec<(String, String)>, -} - -#[derive(Debug, serde::Deserialize)] -pub struct PaymentsResponseForm { - pub transaction_id: String, - // pub transaction_reference_id: String, - pub merchant_id: String, - pub order_id: String, -} - // Extract only the last 4 digits of card -impl From for CCardResponse { - fn from(card: CCard) -> Self { - let card_number_length = card.card_number.peek().clone().len(); - Self { - last4: card.card_number.peek().clone()[card_number_length - 4..card_number_length] - .to_string(), - exp_month: card.card_exp_month.peek().clone(), - exp_year: card.card_exp_year.peek().clone(), - } - } -} - -impl From for PaymentMethodDataResponse { - fn from(payment_method_data: PaymentMethod) -> Self { - match payment_method_data { - PaymentMethod::Card(card) => PaymentMethodDataResponse::Card(CCardResponse::from(card)), - PaymentMethod::BankTransfer => PaymentMethodDataResponse::BankTransfer, - PaymentMethod::PayLater(pay_later_data) => { - PaymentMethodDataResponse::PayLater(pay_later_data) - } - PaymentMethod::Wallet(wallet_data) => PaymentMethodDataResponse::Wallet(wallet_data), - PaymentMethod::Paypal => PaymentMethodDataResponse::Paypal, - } - } -} pub trait PaymentAuthorize: api::ConnectorIntegration @@ -786,45 +171,6 @@ pub trait Payment: { } -#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] -pub struct PaymentsRetrieveRequest { - pub resource_id: PaymentIdType, - pub merchant_id: Option, - pub force_sync: bool, - pub param: Option, - pub connector: Option, -} - -#[derive(Default, Debug, serde::Deserialize, Clone)] -pub struct PaymentsSessionRequest { - pub payment_id: PaymentIdType, - pub client_secret: String, -} - -#[derive(Default, Debug, serde::Serialize, Clone)] -pub struct PaymentsSessionResponse { - pub session_token: Vec, -} - -#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] -pub struct PaymentRetrieveBody { - pub merchant_id: Option, - pub force_sync: Option, -} -#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] -pub struct PaymentsCancelRequest { - #[serde(skip)] - pub payment_id: String, - pub cancellation_reason: Option, -} - -#[derive(Default, Debug, serde::Deserialize, serde::Serialize)] -pub struct PaymentsStartRequest { - pub payment_id: String, - pub merchant_id: String, - pub txn_id: String, -} - #[cfg(test)] mod payments_test { #![allow(clippy::expect_used)] diff --git a/crates/router/src/types/api/refunds.rs b/crates/router/src/types/api/refunds.rs index 8fc29dda0a..11104cc96d 100644 --- a/crates/router/src/types/api/refunds.rs +++ b/crates/router/src/types/api/refunds.rs @@ -1,66 +1,11 @@ -use serde::{Deserialize, Serialize}; +pub use api_models::refunds::{RefundRequest, RefundResponse, RefundStatus}; use super::ConnectorCommon; use crate::{ services::api, - types::{self, api::enums as api_enums, storage::enums as storage_enums}, + types::{self, storage::enums as storage_enums}, }; -#[derive(Default, Debug, Clone, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct RefundRequest { - pub refund_id: Option, - pub payment_id: String, - pub merchant_id: Option, - pub amount: Option, - pub reason: Option, - //FIXME: Make it refund_type instant or scheduled refund - pub force_process: Option, - pub metadata: Option, -} - -impl super::Router for RefundRequest {} - -#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)] -pub struct RefundResponse { - pub refund_id: String, - pub payment_id: String, - pub amount: i32, - pub currency: String, - pub reason: Option, - pub status: RefundStatus, - pub metadata: Option, - pub error_message: Option, -} - -#[derive(Debug, Eq, Clone, PartialEq, Deserialize, Serialize)] -#[serde(rename_all = "snake_case")] -pub enum RefundStatus { - Succeeded, - Failed, - Pending, - Review, -} - -impl Default for RefundStatus { - fn default() -> Self { - RefundStatus::Pending - } -} - -impl From for RefundStatus { - fn from(status: api_enums::RefundStatus) -> Self { - match status { - api_enums::RefundStatus::Failure | api_enums::RefundStatus::TransactionFailure => { - RefundStatus::Failed - } - api_enums::RefundStatus::ManualReview => RefundStatus::Review, - api_enums::RefundStatus::Pending => RefundStatus::Pending, - api_enums::RefundStatus::Success => RefundStatus::Succeeded, - } - } -} - impl From for RefundStatus { fn from(status: storage_enums::RefundStatus) -> Self { match status { diff --git a/crates/router/src/types/api/webhooks.rs b/crates/router/src/types/api/webhooks.rs index 20263ee15a..cc0718979f 100644 --- a/crates/router/src/types/api/webhooks.rs +++ b/crates/router/src/types/api/webhooks.rs @@ -1,60 +1,17 @@ -use common_utils::custom_serde; +pub use api_models::webhooks::{ + IncomingWebhookDetails, IncomingWebhookEvent, MerchantWebhookConfig, OutgoingWebhook, + OutgoingWebhookContent, WebhookFlow, +}; use error_stack::ResultExt; -use serde::{Deserialize, Serialize}; -use time::PrimitiveDateTime; use super::ConnectorCommon; use crate::{ core::errors::{self, CustomResult}, db::StorageInterface, services, - types::{api, api::enums as api_enums}, utils::crypto, }; -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum IncomingWebhookEvent { - PaymentIntentSuccess, -} - -pub enum WebhookFlow { - Payment, - Refund, - Subscription, -} - -impl From for WebhookFlow { - fn from(evt: IncomingWebhookEvent) -> Self { - match evt { - IncomingWebhookEvent::PaymentIntentSuccess => Self::Payment, - } - } -} - -pub type MerchantWebhookConfig = std::collections::HashSet; - -pub struct IncomingWebhookDetails { - pub object_reference_id: String, - pub resource_object: Vec, -} - -#[derive(Debug, Clone, Serialize)] -pub struct OutgoingWebhook { - pub merchant_id: String, - pub event_id: String, - pub event_type: api_enums::EventType, - pub content: OutgoingWebhookContent, - #[serde(default, with = "custom_serde::iso8601")] - pub timestamp: PrimitiveDateTime, -} - -#[derive(Debug, Clone, Serialize)] -#[serde(tag = "type", content = "object", rename_all = "snake_case")] -pub enum OutgoingWebhookContent { - PaymentDetails(api::PaymentsResponse), -} - #[async_trait::async_trait] pub trait IncomingWebhook: ConnectorCommon + Sync { fn get_webhook_body_decoding_algorithm( diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 7813d0123e..60b62867c1 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -1,7 +1,6 @@ -use crate::{ - core::errors, - types::{api::enums as api_enums, storage::enums as storage_enums}, -}; +use api_models::enums as api_enums; + +use crate::{core::errors, types::storage::enums as storage_enums}; impl From for storage_enums::RoutingAlgorithm { fn from(algo: api_enums::RoutingAlgorithm) -> Self { @@ -177,43 +176,6 @@ impl From for storage_enums::IntentStatus { } } -impl From for api_enums::IntentStatus { - fn from(s: api_enums::AttemptStatus) -> Self { - match s { - api_enums::AttemptStatus::Charged | api_enums::AttemptStatus::AutoRefunded => { - api_enums::IntentStatus::Succeeded - } - - api_enums::AttemptStatus::ConfirmationAwaited => { - api_enums::IntentStatus::RequiresConfirmation - } - api_enums::AttemptStatus::PaymentMethodAwaited => { - api_enums::IntentStatus::RequiresPaymentMethod - } - - api_enums::AttemptStatus::Authorized => api_enums::IntentStatus::RequiresCapture, - api_enums::AttemptStatus::PendingVbv => api_enums::IntentStatus::RequiresCustomerAction, - - api_enums::AttemptStatus::PartialCharged - | api_enums::AttemptStatus::Started - | api_enums::AttemptStatus::VbvSuccessful - | api_enums::AttemptStatus::Authorizing - | api_enums::AttemptStatus::CodInitiated - | api_enums::AttemptStatus::VoidInitiated - | api_enums::AttemptStatus::CaptureInitiated - | api_enums::AttemptStatus::Pending => api_enums::IntentStatus::Processing, - - api_enums::AttemptStatus::AuthenticationFailed - | api_enums::AttemptStatus::AuthorizationFailed - | api_enums::AttemptStatus::VoidFailed - | api_enums::AttemptStatus::JuspayDeclined - | api_enums::AttemptStatus::CaptureFailed - | api_enums::AttemptStatus::Failure => api_enums::IntentStatus::Failed, - api_enums::AttemptStatus::Voided => api_enums::IntentStatus::Cancelled, - } - } -} - impl From for storage_enums::IntentStatus { fn from(s: storage_enums::AttemptStatus) -> Self { match s { @@ -345,3 +307,113 @@ impl From for api_enums::AuthenticationType { } } } + +impl From for storage_enums::Currency { + fn from(currency: api_enums::Currency) -> Self { + match currency { + api_enums::Currency::AED => Self::AED, + api_enums::Currency::ALL => Self::ALL, + api_enums::Currency::AMD => Self::AMD, + api_enums::Currency::ARS => Self::ARS, + api_enums::Currency::AUD => Self::AUD, + api_enums::Currency::AWG => Self::AWG, + api_enums::Currency::AZN => Self::AZN, + api_enums::Currency::BBD => Self::BBD, + api_enums::Currency::BDT => Self::BDT, + api_enums::Currency::BHD => Self::BHD, + api_enums::Currency::BMD => Self::BMD, + api_enums::Currency::BND => Self::BND, + api_enums::Currency::BOB => Self::BOB, + api_enums::Currency::BRL => Self::BRL, + api_enums::Currency::BSD => Self::BSD, + api_enums::Currency::BWP => Self::BWP, + api_enums::Currency::BZD => Self::BZD, + api_enums::Currency::CAD => Self::CAD, + api_enums::Currency::CHF => Self::CHF, + api_enums::Currency::CNY => Self::CNY, + api_enums::Currency::COP => Self::COP, + api_enums::Currency::CRC => Self::CRC, + api_enums::Currency::CUP => Self::CUP, + api_enums::Currency::CZK => Self::CZK, + api_enums::Currency::DKK => Self::DKK, + api_enums::Currency::DOP => Self::DOP, + api_enums::Currency::DZD => Self::DZD, + api_enums::Currency::EGP => Self::EGP, + api_enums::Currency::ETB => Self::ETB, + api_enums::Currency::EUR => Self::EUR, + api_enums::Currency::FJD => Self::FJD, + api_enums::Currency::GBP => Self::GBP, + api_enums::Currency::GHS => Self::GHS, + api_enums::Currency::GIP => Self::GIP, + api_enums::Currency::GMD => Self::GMD, + api_enums::Currency::GTQ => Self::GTQ, + api_enums::Currency::GYD => Self::GYD, + api_enums::Currency::HKD => Self::HKD, + api_enums::Currency::HNL => Self::HNL, + api_enums::Currency::HRK => Self::HRK, + api_enums::Currency::HTG => Self::HTG, + api_enums::Currency::HUF => Self::HUF, + api_enums::Currency::IDR => Self::IDR, + api_enums::Currency::ILS => Self::ILS, + api_enums::Currency::INR => Self::INR, + api_enums::Currency::JMD => Self::JMD, + api_enums::Currency::JOD => Self::JOD, + api_enums::Currency::JPY => Self::JPY, + api_enums::Currency::KES => Self::KES, + api_enums::Currency::KGS => Self::KGS, + api_enums::Currency::KHR => Self::KHR, + api_enums::Currency::KRW => Self::KRW, + api_enums::Currency::KWD => Self::KWD, + api_enums::Currency::KYD => Self::KYD, + api_enums::Currency::KZT => Self::KZT, + api_enums::Currency::LAK => Self::LAK, + api_enums::Currency::LBP => Self::LBP, + api_enums::Currency::LKR => Self::LKR, + api_enums::Currency::LRD => Self::LRD, + api_enums::Currency::LSL => Self::LSL, + api_enums::Currency::MAD => Self::MAD, + api_enums::Currency::MDL => Self::MDL, + api_enums::Currency::MKD => Self::MKD, + api_enums::Currency::MMK => Self::MMK, + api_enums::Currency::MNT => Self::MNT, + api_enums::Currency::MOP => Self::MOP, + api_enums::Currency::MUR => Self::MUR, + api_enums::Currency::MVR => Self::MVR, + api_enums::Currency::MWK => Self::MWK, + api_enums::Currency::MXN => Self::MXN, + api_enums::Currency::MYR => Self::MYR, + api_enums::Currency::NAD => Self::NAD, + api_enums::Currency::NGN => Self::NGN, + api_enums::Currency::NIO => Self::NIO, + api_enums::Currency::NOK => Self::NOK, + api_enums::Currency::NPR => Self::NPR, + api_enums::Currency::NZD => Self::NZD, + api_enums::Currency::OMR => Self::OMR, + api_enums::Currency::PEN => Self::PEN, + api_enums::Currency::PGK => Self::PGK, + api_enums::Currency::PHP => Self::PHP, + api_enums::Currency::PKR => Self::PKR, + api_enums::Currency::PLN => Self::PLN, + api_enums::Currency::QAR => Self::QAR, + api_enums::Currency::RUB => Self::RUB, + api_enums::Currency::SAR => Self::SAR, + api_enums::Currency::SCR => Self::SCR, + api_enums::Currency::SEK => Self::SEK, + api_enums::Currency::SGD => Self::SGD, + api_enums::Currency::SLL => Self::SLL, + api_enums::Currency::SOS => Self::SOS, + api_enums::Currency::SSP => Self::SSP, + api_enums::Currency::SVC => Self::SVC, + api_enums::Currency::SZL => Self::SZL, + api_enums::Currency::THB => Self::THB, + api_enums::Currency::TTD => Self::TTD, + api_enums::Currency::TWD => Self::TWD, + api_enums::Currency::TZS => Self::TZS, + api_enums::Currency::USD => Self::USD, + api_enums::Currency::UYU => Self::UYU, + api_enums::Currency::UZS => Self::UZS, + api_enums::Currency::YER => Self::YER, + api_enums::Currency::ZAR => Self::ZAR, + } + } +} diff --git a/crates/router/src/utils/custom_serde.rs b/crates/router/src/utils/custom_serde.rs index 1196c3af56..8b13789179 100644 --- a/crates/router/src/utils/custom_serde.rs +++ b/crates/router/src/utils/custom_serde.rs @@ -1,147 +1 @@ -pub(crate) mod payment_id_type { - use std::fmt; - use serde::{ - de::{self, Visitor}, - Deserializer, - }; - - use crate::types::api::PaymentIdType; - - struct PaymentIdVisitor; - struct OptionalPaymentIdVisitor; - - impl<'de> Visitor<'de> for PaymentIdVisitor { - type Value = PaymentIdType; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("payment id") - } - - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - Ok(PaymentIdType::PaymentIntentId(value.to_string())) - } - } - - impl<'de> Visitor<'de> for OptionalPaymentIdVisitor { - type Value = Option; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("payment id") - } - - fn visit_some(self, deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_any(PaymentIdVisitor).map(Some) - } - - fn visit_none(self) -> Result - where - E: de::Error, - { - Ok(None) - } - - fn visit_unit(self) -> Result - where - E: de::Error, - { - Ok(None) - } - } - - #[allow(dead_code)] - pub(crate) fn deserialize<'a, D>(deserializer: D) -> Result - where - D: Deserializer<'a>, - { - deserializer.deserialize_any(PaymentIdVisitor) - } - - pub(crate) fn deserialize_option<'a, D>( - deserializer: D, - ) -> Result, D::Error> - where - D: Deserializer<'a>, - { - deserializer.deserialize_option(OptionalPaymentIdVisitor) - } -} - -pub(crate) mod amount { - use serde::de; - - use crate::types::api; - struct AmountVisitor; - struct OptionalAmountVisitor; - - // This is defined to provide guarded deserialization of amount - // which itself handles zero and non-zero values internally - impl<'de> de::Visitor<'de> for AmountVisitor { - type Value = api::Amount; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(formatter, "amount as integer") - } - - fn visit_u64(self, v: u64) -> Result - where - E: de::Error, - { - self.visit_i64(v as i64) - } - - fn visit_i64(self, v: i64) -> Result - where - E: de::Error, - { - Ok(match v { - 0 => api::Amount::Zero, - amount => api::Amount::Value(amount as i32), - }) - } - } - - impl<'de> de::Visitor<'de> for OptionalAmountVisitor { - type Value = Option; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(formatter, "option of amount (as integer)") - } - - fn visit_some(self, deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserialize(deserializer).map(Some) - } - - fn visit_none(self) -> Result - where - E: de::Error, - { - Ok(None) - } - } - - #[allow(dead_code)] - pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - deserializer.deserialize_i64(AmountVisitor) - } - pub(crate) fn deserialize_option<'de, D>( - deserializer: D, - ) -> Result, D::Error> - where - D: de::Deserializer<'de>, - { - deserializer.deserialize_option(OptionalAmountVisitor) - } -} diff --git a/crates/storage_models/Cargo.toml b/crates/storage_models/Cargo.toml new file mode 100644 index 0000000000..89a7c3882c --- /dev/null +++ b/crates/storage_models/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "storage_models" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/crates/storage_models/src/lib.rs b/crates/storage_models/src/lib.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/crates/storage_models/src/lib.rs @@ -0,0 +1 @@ +