diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 488631a58b..88bf8b28ab 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -19,10 +19,11 @@ crates/router/src/db/ @juspay/hyperswitch-framework crates/router/src/routes/ @juspay/hyperswitch-framework migrations/ @juspay/hyperswitch-framework api-reference/ @juspay/hyperswitch-framework +api-reference-v2/ @juspay/hyperswitch-framework Cargo.toml @juspay/hyperswitch-framework Cargo.lock @juspay/hyperswitch-framework -postman/ @juspay/hyperswitch-qa +postman/ @juspay/hyperswitch-qa cypress-tests/ @juspay/hyperswitch-qa crates/api_models/src/events/ @juspay/hyperswitch-analytics @@ -94,17 +95,17 @@ crates/diesel_models/src/query/user.rs @juspay/hyperswitch-dashboard crates/diesel_models/src/user @juspay/hyperswitch-dashboard crates/diesel_models/src/user.rs @juspay/hyperswitch-dashboard crates/diesel_models/src/user_role.rs @juspay/hyperswitch-dashboard -crates/router/src/consts/user.rs @juspay/hyperswitch-dashboard +crates/router/src/consts/user.rs @juspay/hyperswitch-dashboard crates/router/src/consts/user_role.rs @juspay/hyperswitch-dashboard -crates/router/src/core/connector_onboarding @juspay/hyperswitch-dashboard -crates/router/src/core/connector_onboarding.rs @juspay/hyperswitch-dashboard +crates/router/src/core/connector_onboarding @juspay/hyperswitch-dashboard +crates/router/src/core/connector_onboarding.rs @juspay/hyperswitch-dashboard crates/router/src/core/errors/user.rs @juspay/hyperswitch-dashboard crates/router/src/core/errors/user @juspay/hyperswitch-dashboard -crates/router/src/core/user @juspay/hyperswitch-dashboard -crates/router/src/core/user.rs @juspay/hyperswitch-dashboard -crates/router/src/core/user_role.rs @juspay/hyperswitch-dashboard +crates/router/src/core/user @juspay/hyperswitch-dashboard +crates/router/src/core/user.rs @juspay/hyperswitch-dashboard +crates/router/src/core/user_role.rs @juspay/hyperswitch-dashboard crates/router/src/core/verify_connector.rs @juspay/hyperswitch-dashboard -crates/router/src/db/dashboard_metadata.rs @juspay/hyperswitch-dashboard +crates/router/src/db/dashboard_metadata.rs @juspay/hyperswitch-dashboard crates/router/src/db/user @juspay/hyperswitch-dashboard crates/router/src/db/user.rs @juspay/hyperswitch-dashboard crates/router/src/db/user_role.rs @juspay/hyperswitch-dashboard diff --git a/api-reference-v2/api-reference/business-profile/business-profile--create.mdx b/api-reference-v2/api-reference/business-profile/business-profile--create.mdx new file mode 100644 index 0000000000..670ec1dc52 --- /dev/null +++ b/api-reference-v2/api-reference/business-profile/business-profile--create.mdx @@ -0,0 +1,3 @@ +--- +openapi: post /v2/profiles +--- diff --git a/api-reference-v2/api-reference/business-profile/business-profile--retrieve.mdx b/api-reference-v2/api-reference/business-profile/business-profile--retrieve.mdx new file mode 100644 index 0000000000..2a3ff1423b --- /dev/null +++ b/api-reference-v2/api-reference/business-profile/business-profile--retrieve.mdx @@ -0,0 +1,3 @@ +--- +openapi: get /v2/profiles/{profile_id} +--- diff --git a/api-reference-v2/api-reference/business-profile/business-profile--update.mdx b/api-reference-v2/api-reference/business-profile/business-profile--update.mdx new file mode 100644 index 0000000000..eebd72dee6 --- /dev/null +++ b/api-reference-v2/api-reference/business-profile/business-profile--update.mdx @@ -0,0 +1,3 @@ +--- +openapi: post /v2/profiles/{profile_id} +--- diff --git a/api-reference-v2/mint.json b/api-reference-v2/mint.json index da6cb686cd..375f50636a 100644 --- a/api-reference-v2/mint.json +++ b/api-reference-v2/mint.json @@ -35,7 +35,7 @@ ] }, { - "group": "Merchant Connector Account", + "group": "Merchant Account", "pages": [ "api-reference/merchant-account/merchant-account--create", "api-reference/merchant-account/merchant-account--retrieve", @@ -49,6 +49,14 @@ "api-reference/merchant-connector-account/merchant-connector--retrieve", "api-reference/merchant-connector-account/merchant-connector--update" ] + }, + { + "group": "Business Profile", + "pages": [ + "api-reference/business-profile/business-profile--create", + "api-reference/business-profile/business-profile--update", + "api-reference/business-profile/business-profile--retrieve" + ] } ], "footerSocials": { diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 4727c20568..5f82523c77 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -422,6 +422,150 @@ } ] } + }, + "/v2/profiles": { + "post": { + "tags": [ + "Business Profile" + ], + "summary": "Business Profile - Create", + "description": "Business Profile - Create\n\nCreates a new *business profile* for a merchant", + "operationId": "Create A Business Profile", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessProfileCreate" + }, + "examples": { + "Create a business profile with profile name": { + "value": { + "profile_name": "shoe_business" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Business Account Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessProfileResponse" + } + } + } + }, + "400": { + "description": "Invalid data" + } + }, + "security": [ + { + "admin_api_key": [] + } + ] + } + }, + "/v2/profiles/{profile_id}": { + "get": { + "tags": [ + "Business Profile" + ], + "summary": "Business Profile - Retrieve", + "description": "Business Profile - Retrieve\n\nRetrieve existing *business profile*", + "operationId": "Retrieve a Business Profile", + "parameters": [ + { + "name": "profile_id", + "in": "path", + "description": "The unique identifier for the business profile", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Business Profile Updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessProfileResponse" + } + } + } + }, + "400": { + "description": "Invalid data" + } + }, + "security": [ + { + "admin_api_key": [] + } + ] + }, + "post": { + "tags": [ + "Business Profile" + ], + "summary": "Business Profile - Update", + "description": "Business Profile - Update\n\nUpdate the *business profile*", + "operationId": "Update a Business Profile", + "parameters": [ + { + "name": "profile_id", + "in": "path", + "description": "The unique identifier for the business profile", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessProfileCreate" + }, + "examples": { + "Update business profile with profile name fields": { + "value": { + "profile_name": "shoe_business" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Business Profile Updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessProfileResponse" + } + } + } + }, + "400": { + "description": "Invalid data" + } + }, + "security": [ + { + "admin_api_key": [] + } + ] + } } }, "components": { @@ -2663,11 +2807,13 @@ }, "BusinessProfileCreate": { "type": "object", + "required": [ + "profile_name" + ], "properties": { "profile_name": { "type": "string", "description": "The name of business profile", - "nullable": true, "maxLength": 64 }, "return_url": { @@ -2709,12 +2855,7 @@ "description": "Metadata is useful for storing additional, unstructured information on an object.", "nullable": true }, - "routing_algorithm": { - "type": "object", - "description": "The routing algorithm to be used for routing payments to desired connectors", - "nullable": true - }, - "intent_fulfillment_time": { + "order_fulfillment_time": { "type": "integer", "format": "int32", "description": "Will be used to determine the time till which your payment will be active once the payment session starts", @@ -2722,15 +2863,10 @@ "nullable": true, "minimum": 0 }, - "frm_routing_algorithm": { - "type": "object", - "description": "The frm routing algorithm to be used for routing payments to desired FRM's", - "nullable": true - }, - "payout_routing_algorithm": { + "order_fulfillment_time_origin": { "allOf": [ { - "$ref": "#/components/schemas/RoutingAlgorithm" + "$ref": "#/components/schemas/OrderFulfillmentTimeOrigin" } ], "nullable": true @@ -2774,14 +2910,14 @@ }, "collect_shipping_details_from_wallet_connector": { "type": "boolean", - "description": "A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc)", + "description": "A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.)", "default": false, "example": false, "nullable": true }, "collect_billing_details_from_wallet_connector": { "type": "boolean", - "description": "A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc)", + "description": "A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.)", "default": false, "example": false, "nullable": true @@ -2811,7 +2947,7 @@ "type": "object", "required": [ "merchant_id", - "profile_id", + "id", "profile_name", "enable_payment_response_hash", "redirect_to_merchant_with_http_post" @@ -2823,9 +2959,9 @@ "example": "y3oqhf46pyzuxjbcn2giaqnb44", "maxLength": 64 }, - "profile_id": { + "id": { "type": "string", - "description": "The default business profile that must be used for creating merchant accounts and payments", + "description": "The identifier for business profile. This must be used for creating merchant accounts, payments and payouts", "example": "pro_abcdefghijklmnopqrstuvwxyz", "maxLength": 64 }, @@ -2849,7 +2985,7 @@ }, "payment_response_hash_key": { "type": "string", - "description": "Refers to the hash key used for calculating the signature for webhooks and redirect response.", + "description": "Refers to the hash key used for calculating the signature for webhooks and redirect response. If the value is not provided, a value is automatically generated.", "nullable": true }, "redirect_to_merchant_with_http_post": { @@ -2871,31 +3007,6 @@ "description": "Metadata is useful for storing additional, unstructured information on an object.", "nullable": true }, - "routing_algorithm": { - "type": "object", - "description": "The routing algorithm to be used for routing payments to desired connectors", - "nullable": true - }, - "intent_fulfillment_time": { - "type": "integer", - "format": "int64", - "description": "Will be used to determine the time till which your payment will be active once the payment session starts", - "example": 900, - "nullable": true - }, - "frm_routing_algorithm": { - "type": "object", - "description": "The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom'", - "nullable": true - }, - "payout_routing_algorithm": { - "allOf": [ - { - "$ref": "#/components/schemas/RoutingAlgorithm" - } - ], - "nullable": true - }, "applepay_verified_domains": { "type": "array", "items": { @@ -2941,14 +3052,14 @@ }, "collect_shipping_details_from_wallet_connector": { "type": "boolean", - "description": "A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc)", + "description": "A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.)", "default": false, "example": false, "nullable": true }, "collect_billing_details_from_wallet_connector": { "type": "boolean", - "description": "A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc)", + "description": "A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.)", "default": false, "example": false, "nullable": true @@ -2970,6 +3081,22 @@ "type": "object", "description": "These key-value pairs are sent as additional custom headers in the outgoing webhook request.", "nullable": true + }, + "order_fulfillment_time": { + "type": "integer", + "format": "int32", + "description": "Will be used to determine the time till which your payment will be active once the payment session starts", + "example": 900, + "nullable": true, + "minimum": 0 + }, + "order_fulfillment_time_origin": { + "allOf": [ + { + "$ref": "#/components/schemas/OrderFulfillmentTimeOrigin" + } + ], + "nullable": true } } }, @@ -8489,6 +8616,13 @@ } } }, + "OrderFulfillmentTimeOrigin": { + "type": "string", + "enum": [ + "create", + "confirm" + ] + }, "OrganizationRequest": { "type": "object", "properties": { diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index a91f64daa8..1ff9ff9679 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -3015,7 +3015,7 @@ }, "security": [ { - "api_key": [] + "admin_api_key": [] } ] }, @@ -3080,7 +3080,7 @@ }, "security": [ { - "api_key": [] + "admin_api_key": [] } ] }, @@ -7252,14 +7252,14 @@ }, "collect_shipping_details_from_wallet_connector": { "type": "boolean", - "description": "A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc)", + "description": "A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.)", "default": false, "example": false, "nullable": true }, "collect_billing_details_from_wallet_connector": { "type": "boolean", - "description": "A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc)", + "description": "A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.)", "default": false, "example": false, "nullable": true @@ -7327,7 +7327,7 @@ }, "payment_response_hash_key": { "type": "string", - "description": "Refers to the hash key used for calculating the signature for webhooks and redirect response.", + "description": "Refers to the hash key used for calculating the signature for webhooks and redirect response. If the value is not provided, a value is automatically generated.", "nullable": true }, "redirect_to_merchant_with_http_post": { @@ -7419,14 +7419,14 @@ }, "collect_shipping_details_from_wallet_connector": { "type": "boolean", - "description": "A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc)", + "description": "A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.)", "default": false, "example": false, "nullable": true }, "collect_billing_details_from_wallet_connector": { "type": "boolean", - "description": "A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc)", + "description": "A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.)", "default": false, "example": false, "nullable": true diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index b073c21951..081b0a1884 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -1920,11 +1920,11 @@ pub struct BusinessProfileCreate { /// Whether to use the billing details passed when creating the intent as payment method billing pub use_billing_as_payment_method_billing: Option, - /// A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc) + /// A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.) #[schema(default = false, example = false)] pub collect_shipping_details_from_wallet_connector: Option, - /// A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc) + /// A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.) #[schema(default = false, example = false)] pub collect_billing_details_from_wallet_connector: Option, @@ -1945,7 +1945,7 @@ pub struct BusinessProfileCreate { #[nutype::nutype( validate(greater_or_equal = MIN_ORDER_FULFILLMENT_EXPIRY, less_or_equal = MAX_ORDER_FULFILLMENT_EXPIRY), - derive(Clone, Debug, Deserialize,Serialize) + derive(Clone, Copy, Debug, Deserialize, Serialize) )] pub struct OrderFulfillmentTime(i64); @@ -1980,7 +1980,7 @@ pub struct BusinessProfileCreate { pub metadata: Option, /// Will be used to determine the time till which your payment will be active once the payment session starts - #[schema(value_type = u32, example = 900)] + #[schema(value_type = Option, example = 900)] pub order_fulfillment_time: Option, /// Whether the order fulfillment time is calculated from the origin or the time of creating the payment, or confirming the payment @@ -2003,11 +2003,11 @@ pub struct BusinessProfileCreate { /// Whether to use the billing details passed when creating the intent as payment method billing pub use_billing_as_payment_method_billing: Option, - /// A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc) + /// A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.) #[schema(default = false, example = false)] pub collect_shipping_details_from_wallet_connector: Option, - /// A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc) + /// A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.) #[schema(default = false, example = false)] pub collect_billing_details_from_wallet_connector: Option, @@ -2052,7 +2052,7 @@ pub struct BusinessProfileResponse { #[schema(default = true, example = true)] pub enable_payment_response_hash: bool, - /// Refers to the hash key used for calculating the signature for webhooks and redirect response. + /// Refers to the hash key used for calculating the signature for webhooks and redirect response. If the value is not provided, a value is automatically generated. pub payment_response_hash_key: Option, /// A boolean value to indicate if redirect to merchant with http post needs to be enabled @@ -2103,11 +2103,11 @@ pub struct BusinessProfileResponse { /// Merchant's config to support extended card info feature pub extended_card_info_config: Option, - /// A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc) + /// A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.) #[schema(default = false, example = false)] pub collect_shipping_details_from_wallet_connector: Option, - /// A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc) + /// A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.) #[schema(default = false, example = false)] pub collect_billing_details_from_wallet_connector: Option, @@ -2149,7 +2149,7 @@ pub struct BusinessProfileResponse { #[schema(default = true, example = true)] pub enable_payment_response_hash: bool, - /// Refers to the hash key used for calculating the signature for webhooks and redirect response. + /// Refers to the hash key used for calculating the signature for webhooks and redirect response. If the value is not provided, a value is automatically generated. pub payment_response_hash_key: Option, /// A boolean value to indicate if redirect to merchant with http post needs to be enabled @@ -2183,11 +2183,11 @@ pub struct BusinessProfileResponse { /// Merchant's config to support extended card info feature pub extended_card_info_config: Option, - /// A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc) + /// A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.) #[schema(default = false, example = false)] pub collect_shipping_details_from_wallet_connector: Option, - /// A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple pay, Google pay etc) + /// A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.) #[schema(default = false, example = false)] pub collect_billing_details_from_wallet_connector: Option, @@ -2206,7 +2206,7 @@ pub struct BusinessProfileResponse { pub outgoing_webhook_custom_http_headers: Option>>, /// Will be used to determine the time till which your payment will be active once the payment session starts - #[schema(value_type = u32, example = 900)] + #[schema(value_type = Option, example = 900)] pub order_fulfillment_time: Option, /// Whether the order fulfillment time is calculated from the origin or the time of creating the payment, or confirming the payment @@ -2214,6 +2214,10 @@ pub struct BusinessProfileResponse { pub order_fulfillment_time_origin: Option, } +#[cfg(all( + any(feature = "v1", feature = "v2"), + not(feature = "business_profile_v2") +))] #[derive(Clone, Debug, Deserialize, ToSchema, Serialize)] #[serde(deny_unknown_fields)] pub struct BusinessProfileUpdate { @@ -2301,6 +2305,87 @@ pub struct BusinessProfileUpdate { #[schema(value_type = Option, example = r#"{ "key1": "value-1", "key2": "value-2" }"#)] pub outgoing_webhook_custom_http_headers: Option>, } + +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)] +#[serde(deny_unknown_fields)] +pub struct BusinessProfileUpdate { + /// The name of business profile + #[schema(max_length = 64)] + pub profile_name: Option, + + /// The URL to redirect after the completion of the operation + #[schema(value_type = Option, max_length = 255, example = "https://www.example.com/success")] + pub return_url: Option, + + /// A boolean value to indicate if payment response hash needs to be enabled + #[schema(default = true, example = true)] + pub enable_payment_response_hash: Option, + + /// Refers to the hash key used for calculating the signature for webhooks and redirect response. If the value is not provided, a value is automatically generated. + pub payment_response_hash_key: Option, + + /// A boolean value to indicate if redirect to merchant with http post needs to be enabled + #[schema(default = false, example = true)] + pub redirect_to_merchant_with_http_post: Option, + + /// Webhook related details + pub webhook_details: Option, + + /// Metadata is useful for storing additional, unstructured information on an object. + #[schema(value_type = Option, example = r#"{ "city": "NY", "unit": "245" }"#)] + pub metadata: Option, + + /// Will be used to determine the time till which your payment will be active once the payment session starts + #[schema(value_type = Option, example = 900)] + pub order_fulfillment_time: Option, + + /// Whether the order fulfillment time is calculated from the origin or the time of creating the payment, or confirming the payment + #[schema(value_type = Option, example = "create")] + pub order_fulfillment_time_origin: Option, + + /// Verified Apple Pay domains for a particular profile + pub applepay_verified_domains: Option>, + + /// Client Secret Default expiry for all payments created under this business profile + #[schema(example = 900)] + pub session_expiry: Option, + + /// Default Payment Link config for all payment links created under this business profile + pub payment_link_config: Option, + + /// External 3DS authentication details + pub authentication_connector_details: Option, + + /// Merchant's config to support extended card info feature + pub extended_card_info_config: Option, + + // Whether to use the billing details passed when creating the intent as payment method billing + pub use_billing_as_payment_method_billing: Option, + + /// A boolean value to indicate if customer shipping details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.) + #[schema(default = false, example = false)] + pub collect_shipping_details_from_wallet_connector: Option, + + /// A boolean value to indicate if customer billing details needs to be collected from wallet connector (Eg. Apple Pay, Google Pay, etc.) + #[schema(default = false, example = false)] + pub collect_billing_details_from_wallet_connector: Option, + + /// Indicates if the MIT (merchant initiated transaction) payments can be made connector + /// agnostic, i.e., MITs may be processed through different connector than CIT (customer + /// initiated transaction) based on the routing rules. + /// If set to `false`, MIT will go through the same connector as the CIT. + pub is_connector_agnostic_mit_enabled: Option, + + /// Default payout link config + #[schema(value_type = Option)] + pub payout_link_config: Option, + + /// These key-value pairs are sent as additional custom headers in the outgoing webhook request. It is recommended not to use more than four key-value pairs. + #[schema(value_type = Option, example = r#"{ "key1": "value-1", "key2": "value-2" }"#)] + pub outgoing_webhook_custom_http_headers: Option>, +} + #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] pub struct BusinessCollectLinkConfig { #[serde(flatten)] diff --git a/crates/diesel_models/src/query/customers.rs b/crates/diesel_models/src/query/customers.rs index 1dc35511c9..568e1f4a9a 100644 --- a/crates/diesel_models/src/query/customers.rs +++ b/crates/diesel_models/src/query/customers.rs @@ -48,7 +48,7 @@ impl Customer { } #[cfg(all(feature = "v2", feature = "customer_v2"))] - pub async fn find_by_global_id(conn: &PgPooledConn, id: &String) -> StorageResult { + pub async fn find_by_global_id(conn: &PgPooledConn, id: &str) -> StorageResult { generics::generic_find_by_id::<::Table, _, _>(conn, id.to_owned()).await } diff --git a/crates/hyperswitch_domain_models/src/business_profile.rs b/crates/hyperswitch_domain_models/src/business_profile.rs index 2af48930ed..b47dc19217 100644 --- a/crates/hyperswitch_domain_models/src/business_profile.rs +++ b/crates/hyperswitch_domain_models/src/business_profile.rs @@ -70,7 +70,6 @@ pub struct BusinessProfileGeneralUpdate { pub intent_fulfillment_time: Option, pub frm_routing_algorithm: Option, pub payout_routing_algorithm: Option, - pub is_recon_enabled: Option, pub applepay_verified_domains: Option>, pub payment_link_config: Option, pub session_expiry: Option, @@ -125,7 +124,6 @@ impl From for BusinessProfileUpdateInternal { intent_fulfillment_time, frm_routing_algorithm, payout_routing_algorithm, - is_recon_enabled, applepay_verified_domains, payment_link_config, session_expiry, @@ -152,7 +150,7 @@ impl From for BusinessProfileUpdateInternal { intent_fulfillment_time, frm_routing_algorithm, payout_routing_algorithm, - is_recon_enabled, + is_recon_enabled: None, applepay_verified_domains, payment_link_config, session_expiry, @@ -466,7 +464,6 @@ pub struct BusinessProfileGeneralUpdate { pub redirect_to_merchant_with_http_post: Option, pub webhook_details: Option, pub metadata: Option, - pub is_recon_enabled: Option, pub applepay_verified_domains: Option>, pub payment_link_config: Option, pub session_expiry: Option, @@ -478,12 +475,8 @@ pub struct BusinessProfileGeneralUpdate { pub collect_billing_details_from_wallet_connector: Option, pub is_connector_agnostic_mit_enabled: Option, pub outgoing_webhook_custom_http_headers: OptionalEncryptableValue, - pub routing_algorithm_id: Option, pub order_fulfillment_time: Option, pub order_fulfillment_time_origin: Option, - pub frm_routing_algorithm_id: Option, - pub payout_routing_algorithm_id: Option, - pub default_fallback_routing: Option, } #[cfg(all(feature = "v2", feature = "business_profile_v2"))] @@ -520,7 +513,6 @@ impl From for BusinessProfileUpdateInternal { redirect_to_merchant_with_http_post, webhook_details, metadata, - is_recon_enabled, applepay_verified_domains, payment_link_config, session_expiry, @@ -532,12 +524,8 @@ impl From for BusinessProfileUpdateInternal { collect_billing_details_from_wallet_connector, is_connector_agnostic_mit_enabled, outgoing_webhook_custom_http_headers, - routing_algorithm_id, order_fulfillment_time, order_fulfillment_time_origin, - frm_routing_algorithm_id, - payout_routing_algorithm_id, - default_fallback_routing, } = *update; Self { profile_name, @@ -548,7 +536,7 @@ impl From for BusinessProfileUpdateInternal { redirect_to_merchant_with_http_post, webhook_details, metadata, - is_recon_enabled, + is_recon_enabled: None, applepay_verified_domains, payment_link_config, session_expiry, @@ -562,12 +550,12 @@ impl From for BusinessProfileUpdateInternal { collect_billing_details_from_wallet_connector, outgoing_webhook_custom_http_headers: outgoing_webhook_custom_http_headers .map(Encryption::from), - routing_algorithm_id, + routing_algorithm_id: None, order_fulfillment_time, order_fulfillment_time_origin, - frm_routing_algorithm_id, - payout_routing_algorithm_id, - default_fallback_routing, + frm_routing_algorithm_id: None, + payout_routing_algorithm_id: None, + default_fallback_routing: None, } } BusinessProfileUpdate::RoutingAlgorithmUpdate { diff --git a/crates/openapi/Cargo.toml b/crates/openapi/Cargo.toml index 8ec2348a70..469e1a0dc9 100644 --- a/crates/openapi/Cargo.toml +++ b/crates/openapi/Cargo.toml @@ -16,7 +16,7 @@ common_utils = { version = "0.1.0", path = "../common_utils" } router_env = { version = "0.1.0", path = "../router_env" } [features] -v2 = ["api_models/v2", "api_models/customer_v2", "api_models/merchant_account_v2", "api_models/routing_v2", "api_models/merchant_connector_account_v2"] +v2 = ["api_models/v2", "api_models/customer_v2", "api_models/merchant_account_v2", "api_models/routing_v2", "api_models/merchant_connector_account_v2", "api_models/business_profile_v2"] v1 = ["api_models/v1"] [lints] diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index cd51a44edf..676debffa2 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -138,10 +138,10 @@ Never share your secret api keys. Keep them guarded and secure. // Routes for Business Profile routes::business_profile::business_profile_create, - routes::business_profile::business_profiles_list, - routes::business_profile::business_profiles_retrieve, - routes::business_profile::business_profiles_update, - routes::business_profile::business_profiles_delete, + routes::business_profile::business_profile_list, + routes::business_profile::business_profile_retrieve, + routes::business_profile::business_profile_update, + routes::business_profile::business_profile_delete, // Routes for disputes routes::disputes::retrieve_dispute, diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index 2b566b856b..3263ec3fc7 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -79,6 +79,11 @@ Never share your secret api keys. Keep them guarded and secure. routes::merchant_account::merchant_account_create, routes::merchant_account::merchant_account_retrieve, routes::merchant_account::merchant_account_update, + + // Routes for business profile + routes::business_profile::business_profile_create, + routes::business_profile::business_profile_retrieve, + routes::business_profile::business_profile_update, ), components(schemas( common_utils::types::MinorUnit, @@ -154,6 +159,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::enums::ConnectorStatus, api_models::enums::AuthorizationStatus, api_models::enums::PaymentMethodStatus, + api_models::enums::OrderFulfillmentTimeOrigin, api_models::admin::MerchantConnectorCreate, api_models::admin::AdditionalMerchantData, api_models::admin::MerchantRecipientData, diff --git a/crates/openapi/src/routes/business_profile.rs b/crates/openapi/src/routes/business_profile.rs index 57da0e5970..1e948b1a63 100644 --- a/crates/openapi/src/routes/business_profile.rs +++ b/crates/openapi/src/routes/business_profile.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "v1")] /// Business Profile - Create /// /// Creates a new *business profile* for a merchant @@ -34,6 +35,35 @@ )] pub async fn business_profile_create() {} +#[cfg(feature = "v2")] +/// Business Profile - Create +/// +/// Creates a new *business profile* for a merchant +#[utoipa::path( + post, + path = "/v2/profiles", + request_body( + content = BusinessProfileCreate, + examples( + ( + "Create a business profile with profile name" = ( + value = json!({ + "profile_name": "shoe_business" + }) + ) + ) + ) + ), + responses( + (status = 200, description = "Business Account Created", body = BusinessProfileResponse), + (status = 400, description = "Invalid data") + ), + tag = "Business Profile", + operation_id = "Create A Business Profile", + security(("admin_api_key" = [])) +)] +pub async fn business_profile_create() {} + /// Business Profile - List /// /// Lists all the *business profiles* under a merchant @@ -50,8 +80,9 @@ pub async fn business_profile_create() {} operation_id = "List Business Profiles", security(("api_key" = [])) )] -pub async fn business_profiles_list() {} +pub async fn business_profile_list() {} +#[cfg(feature = "v1")] /// Business Profile - Update /// /// Update the *business profile* @@ -79,9 +110,40 @@ pub async fn business_profiles_list() {} ), tag = "Business Profile", operation_id = "Update a Business Profile", - security(("api_key" = [])) + security(("admin_api_key" = [])) )] -pub async fn business_profiles_update() {} +pub async fn business_profile_update() {} + +#[cfg(feature = "v2")] +/// Business Profile - Update +/// +/// Update the *business profile* +#[utoipa::path( + post, + path = "/v2/profiles/{profile_id}", + params( + ("profile_id" = String, Path, description = "The unique identifier for the business profile") + ), + request_body( + content = BusinessProfileCreate, + examples( + ( + "Update business profile with profile name fields" = ( + value = json!({ + "profile_name" : "shoe_business" + }) + ) + ) + )), + responses( + (status = 200, description = "Business Profile Updated", body = BusinessProfileResponse), + (status = 400, description = "Invalid data") + ), + tag = "Business Profile", + operation_id = "Update a Business Profile", + security(("admin_api_key" = [])) +)] +pub async fn business_profile_update() {} /// Business Profile - Delete /// @@ -101,8 +163,9 @@ pub async fn business_profiles_update() {} operation_id = "Delete the Business Profile", security(("api_key" = [])) )] -pub async fn business_profiles_delete() {} +pub async fn business_profile_delete() {} +#[cfg(feature = "v1")] /// Business Profile - Retrieve /// /// Retrieve existing *business profile* @@ -119,6 +182,26 @@ pub async fn business_profiles_delete() {} ), tag = "Business Profile", operation_id = "Retrieve a Business Profile", - security(("api_key" = [])) + security(("admin_api_key" = [])) )] -pub async fn business_profiles_retrieve() {} +pub async fn business_profile_retrieve() {} + +#[cfg(feature = "v2")] +/// Business Profile - Retrieve +/// +/// Retrieve existing *business profile* +#[utoipa::path( + get, + path = "/v2/profiles/{profile_id}", + params( + ("profile_id" = String, Path, description = "The unique identifier for the business profile") + ), + responses( + (status = 200, description = "Business Profile Updated", body = BusinessProfileResponse), + (status = 400, description = "Invalid data") + ), + tag = "Business Profile", + operation_id = "Retrieve a Business Profile", + security(("admin_api_key" = [])) +)] +pub async fn business_profile_retrieve() {} diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index 00af58adfa..b3dd10897b 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -36,7 +36,7 @@ v1 = ["api_models/v1", "diesel_models/v1", "hyperswitch_domain_models/v1", "stor business_profile_v2 = ["api_models/business_profile_v2", "diesel_models/business_profile_v2", "hyperswitch_domain_models/business_profile_v2"] customer_v2 = ["api_models/customer_v2", "diesel_models/customer_v2", "hyperswitch_domain_models/customer_v2", "storage_impl/customer_v2"] merchant_account_v2 = ["api_models/merchant_account_v2", "diesel_models/merchant_account_v2", "hyperswitch_domain_models/merchant_account_v2"] -payment_v2 = ["api_models/payment_v2", "diesel_models/payment_v2", "hyperswitch_domain_models/payment_v2"] +payment_v2 = ["api_models/payment_v2", "diesel_models/payment_v2", "hyperswitch_domain_models/payment_v2", "storage_impl/payment_v2"] payment_methods_v2 = ["api_models/payment_methods_v2"] routing_v2 = ["api_models/routing_v2"] merchant_connector_account_v2 = ["api_models/merchant_connector_account_v2", "kgraph_utils/merchant_connector_account_v2", "hyperswitch_domain_models/merchant_connector_account_v2", "diesel_models/merchant_connector_account_v2"] diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 1f5fb06840..ca1b24a06f 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -3344,8 +3344,8 @@ impl BusinessProfileCreateBridge for api::BusinessProfileCreate { helpers::validate_session_expiry(session_expiry.to_owned())?; } - if let Some(intent_fulfillment_expiry) = &self.intent_fulfillment_time { - helpers::validate_intent_fulfillment_expiry(intent_fulfillment_expiry.to_owned())?; + if let Some(intent_fulfillment_expiry) = self.intent_fulfillment_time { + helpers::validate_intent_fulfillment_expiry(intent_fulfillment_expiry)?; } if let Some(ref routing_algorithm) = self.routing_algorithm { @@ -3543,7 +3543,7 @@ impl BusinessProfileCreateBridge for api::BusinessProfileCreate { payout_routing_algorithm_id: None, order_fulfillment_time: self .order_fulfillment_time - .map(|order_fulfillment_time| i64::from(order_fulfillment_time.into_inner())) + .map(|order_fulfillment_time| order_fulfillment_time.into_inner()) .or(Some(common_utils::consts::DEFAULT_ORDER_FULFILLMENT_TIME)), order_fulfillment_time_origin: self.order_fulfillment_time_origin, default_fallback_routing: None, @@ -3695,10 +3695,214 @@ pub async fn delete_business_profile( Ok(service_api::ApplicationResponse::Json(delete_result)) } +#[cfg(feature = "olap")] +#[async_trait::async_trait] +trait BusinessProfileUpdateBridge { + async fn get_update_business_profile_object( + self, + state: &SessionState, + key_store: &domain::MerchantKeyStore, + ) -> RouterResult; +} + #[cfg(all( + feature = "olap", any(feature = "v1", feature = "v2"), not(feature = "business_profile_v2") ))] +#[async_trait::async_trait] +impl BusinessProfileUpdateBridge for api::BusinessProfileUpdate { + async fn get_update_business_profile_object( + self, + state: &SessionState, + key_store: &domain::MerchantKeyStore, + ) -> RouterResult { + if let Some(session_expiry) = &self.session_expiry { + helpers::validate_session_expiry(session_expiry.to_owned())?; + } + + if let Some(intent_fulfillment_expiry) = self.intent_fulfillment_time { + helpers::validate_intent_fulfillment_expiry(intent_fulfillment_expiry)?; + } + + let webhook_details = self.webhook_details.map(ForeignInto::foreign_into); + + if let Some(ref routing_algorithm) = self.routing_algorithm { + let _: api_models::routing::RoutingAlgorithm = routing_algorithm + .clone() + .parse_value("RoutingAlgorithm") + .change_context(errors::ApiErrorResponse::InvalidDataValue { + field_name: "routing_algorithm", + }) + .attach_printable("Invalid routing algorithm given")?; + } + + let payment_link_config = self + .payment_link_config + .map(|payment_link_conf| match payment_link_conf.validate() { + Ok(_) => Ok(payment_link_conf.foreign_into()), + Err(e) => Err(report!(errors::ApiErrorResponse::InvalidRequestData { + message: e.to_string() + })), + }) + .transpose()?; + + let extended_card_info_config = self + .extended_card_info_config + .as_ref() + .map(|config| { + config.encode_to_value().change_context( + errors::ApiErrorResponse::InvalidDataValue { + field_name: "extended_card_info_config", + }, + ) + }) + .transpose()? + .map(Secret::new); + let outgoing_webhook_custom_http_headers = self + .outgoing_webhook_custom_http_headers + .async_map(|headers| cards::create_encrypted_data(state, key_store, headers)) + .await + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt outgoing webhook custom HTTP headers")?; + + let payout_link_config = self + .payout_link_config + .map(|payout_conf| match payout_conf.config.validate() { + Ok(_) => Ok(payout_conf.foreign_into()), + Err(e) => Err(report!(errors::ApiErrorResponse::InvalidRequestData { + message: e.to_string() + })), + }) + .transpose()?; + + Ok(domain::BusinessProfileUpdate::Update(Box::new( + domain::BusinessProfileGeneralUpdate { + profile_name: self.profile_name, + return_url: self.return_url.map(|return_url| return_url.to_string()), + enable_payment_response_hash: self.enable_payment_response_hash, + payment_response_hash_key: self.payment_response_hash_key, + redirect_to_merchant_with_http_post: self.redirect_to_merchant_with_http_post, + webhook_details, + metadata: self.metadata, + routing_algorithm: self.routing_algorithm, + intent_fulfillment_time: self.intent_fulfillment_time.map(i64::from), + frm_routing_algorithm: self.frm_routing_algorithm, + #[cfg(feature = "payouts")] + payout_routing_algorithm: self.payout_routing_algorithm, + #[cfg(not(feature = "payouts"))] + payout_routing_algorithm: None, + applepay_verified_domains: self.applepay_verified_domains, + payment_link_config, + session_expiry: self.session_expiry.map(i64::from), + authentication_connector_details: self + .authentication_connector_details + .map(ForeignInto::foreign_into), + payout_link_config, + extended_card_info_config, + use_billing_as_payment_method_billing: self.use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector: self + .collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector: self + .collect_billing_details_from_wallet_connector, + is_connector_agnostic_mit_enabled: self.is_connector_agnostic_mit_enabled, + outgoing_webhook_custom_http_headers: outgoing_webhook_custom_http_headers + .map(Into::into), + }, + ))) + } +} + +#[cfg(all(feature = "olap", feature = "v2", feature = "business_profile_v2"))] +#[async_trait::async_trait] +impl BusinessProfileUpdateBridge for api::BusinessProfileUpdate { + async fn get_update_business_profile_object( + self, + state: &SessionState, + key_store: &domain::MerchantKeyStore, + ) -> RouterResult { + if let Some(session_expiry) = &self.session_expiry { + helpers::validate_session_expiry(session_expiry.to_owned())?; + } + + let webhook_details = self.webhook_details.map(ForeignInto::foreign_into); + + let payment_link_config = self + .payment_link_config + .map(|payment_link_conf| match payment_link_conf.validate() { + Ok(_) => Ok(payment_link_conf.foreign_into()), + Err(e) => Err(report!(errors::ApiErrorResponse::InvalidRequestData { + message: e.to_string() + })), + }) + .transpose()?; + + let extended_card_info_config = self + .extended_card_info_config + .as_ref() + .map(|config| { + config.encode_to_value().change_context( + errors::ApiErrorResponse::InvalidDataValue { + field_name: "extended_card_info_config", + }, + ) + }) + .transpose()? + .map(Secret::new); + let outgoing_webhook_custom_http_headers = self + .outgoing_webhook_custom_http_headers + .async_map(|headers| cards::create_encrypted_data(state, key_store, headers)) + .await + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt outgoing webhook custom HTTP headers")?; + + let payout_link_config = self + .payout_link_config + .map(|payout_conf| match payout_conf.config.validate() { + Ok(_) => Ok(payout_conf.foreign_into()), + Err(e) => Err(report!(errors::ApiErrorResponse::InvalidRequestData { + message: e.to_string() + })), + }) + .transpose()?; + + Ok(domain::BusinessProfileUpdate::Update(Box::new( + domain::BusinessProfileGeneralUpdate { + profile_name: self.profile_name, + return_url: self.return_url.map(|return_url| return_url.to_string()), + enable_payment_response_hash: self.enable_payment_response_hash, + payment_response_hash_key: self.payment_response_hash_key, + redirect_to_merchant_with_http_post: self.redirect_to_merchant_with_http_post, + webhook_details, + metadata: self.metadata, + applepay_verified_domains: self.applepay_verified_domains, + payment_link_config, + session_expiry: self.session_expiry.map(i64::from), + authentication_connector_details: self + .authentication_connector_details + .map(ForeignInto::foreign_into), + payout_link_config, + extended_card_info_config, + use_billing_as_payment_method_billing: self.use_billing_as_payment_method_billing, + collect_shipping_details_from_wallet_connector: self + .collect_shipping_details_from_wallet_connector, + collect_billing_details_from_wallet_connector: self + .collect_billing_details_from_wallet_connector, + is_connector_agnostic_mit_enabled: self.is_connector_agnostic_mit_enabled, + outgoing_webhook_custom_http_headers: outgoing_webhook_custom_http_headers + .map(Into::into), + order_fulfillment_time: self + .order_fulfillment_time + .map(|order_fulfillment_time| order_fulfillment_time.into_inner()), + order_fulfillment_time_origin: self.order_fulfillment_time_origin, + }, + ))) + } +} + +#[cfg(feature = "olap")] pub async fn update_business_profile( state: SessionState, profile_id: &str, @@ -3730,100 +3934,9 @@ pub async fn update_business_profile( })? } - if let Some(session_expiry) = &request.session_expiry { - helpers::validate_session_expiry(session_expiry.to_owned())?; - } - - if let Some(intent_fulfillment_expiry) = &request.intent_fulfillment_time { - helpers::validate_intent_fulfillment_expiry(intent_fulfillment_expiry.to_owned())?; - } - - let webhook_details = request.webhook_details.map(ForeignInto::foreign_into); - - if let Some(ref routing_algorithm) = request.routing_algorithm { - let _: api_models::routing::RoutingAlgorithm = routing_algorithm - .clone() - .parse_value("RoutingAlgorithm") - .change_context(errors::ApiErrorResponse::InvalidDataValue { - field_name: "routing_algorithm", - }) - .attach_printable("Invalid routing algorithm given")?; - } - - let payment_link_config = request - .payment_link_config - .map(|payment_link_conf| match payment_link_conf.validate() { - Ok(_) => Ok(payment_link_conf.foreign_into()), - Err(e) => Err(report!(errors::ApiErrorResponse::InvalidRequestData { - message: e.to_string() - })), - }) - .transpose()?; - - let extended_card_info_config = request - .extended_card_info_config - .as_ref() - .map(|config| { - config - .encode_to_value() - .change_context(errors::ApiErrorResponse::InvalidDataValue { - field_name: "extended_card_info_config", - }) - }) - .transpose()? - .map(Secret::new); - let outgoing_webhook_custom_http_headers = request - .outgoing_webhook_custom_http_headers - .async_map(|headers| cards::create_encrypted_data(&state, &key_store, headers)) - .await - .transpose() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Unable to encrypt outgoing webhook custom HTTP headers")?; - - let payout_link_config = request - .payout_link_config - .map(|payout_conf| match payout_conf.config.validate() { - Ok(_) => Ok(payout_conf.foreign_into()), - Err(e) => Err(report!(errors::ApiErrorResponse::InvalidRequestData { - message: e.to_string() - })), - }) - .transpose()?; - - let business_profile_update = - domain::BusinessProfileUpdate::Update(Box::new(domain::BusinessProfileGeneralUpdate { - profile_name: request.profile_name, - return_url: request.return_url.map(|return_url| return_url.to_string()), - enable_payment_response_hash: request.enable_payment_response_hash, - payment_response_hash_key: request.payment_response_hash_key, - redirect_to_merchant_with_http_post: request.redirect_to_merchant_with_http_post, - webhook_details, - metadata: request.metadata, - routing_algorithm: request.routing_algorithm, - intent_fulfillment_time: request.intent_fulfillment_time.map(i64::from), - frm_routing_algorithm: request.frm_routing_algorithm, - #[cfg(feature = "payouts")] - payout_routing_algorithm: request.payout_routing_algorithm, - #[cfg(not(feature = "payouts"))] - payout_routing_algorithm: None, - is_recon_enabled: None, - applepay_verified_domains: request.applepay_verified_domains, - payment_link_config, - session_expiry: request.session_expiry.map(i64::from), - authentication_connector_details: request - .authentication_connector_details - .map(ForeignInto::foreign_into), - payout_link_config, - extended_card_info_config, - use_billing_as_payment_method_billing: request.use_billing_as_payment_method_billing, - collect_shipping_details_from_wallet_connector: request - .collect_shipping_details_from_wallet_connector, - collect_billing_details_from_wallet_connector: request - .collect_billing_details_from_wallet_connector, - is_connector_agnostic_mit_enabled: request.is_connector_agnostic_mit_enabled, - outgoing_webhook_custom_http_headers: outgoing_webhook_custom_http_headers - .map(Into::into), - })); + let business_profile_update = request + .get_update_business_profile_object(&state, &key_store) + .await?; let updated_business_profile = db .update_business_profile_by_profile_id( @@ -3843,15 +3956,7 @@ pub async fn update_business_profile( .attach_printable("Failed to parse business profile details")?, )) } -#[cfg(all(feature = "v2", feature = "business_profile_v2"))] -pub async fn update_business_profile( - _state: SessionState, - _profile_id: &str, - _merchant_id: &id_type::MerchantId, - _request: api::BusinessProfileUpdate, -) -> RouterResponse { - todo!() -} + #[cfg(all( feature = "v2", feature = "routing_v2", diff --git a/crates/router/src/core/customers.rs b/crates/router/src/core/customers.rs index d6e66f0fb9..9036c4e0b3 100644 --- a/crates/router/src/core/customers.rs +++ b/crates/router/src/core/customers.rs @@ -861,7 +861,7 @@ impl<'a> VerifyIdForUpdateCustomer<'a> { .find_customer_by_global_id( self.key_manager_state, &id, - &self.merchant_account.get_id(), + self.merchant_account.get_id(), self.key_store, self.merchant_account.storage_scheme, ) @@ -1027,7 +1027,7 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest { default_shipping_address: encrypted_customer_shipping_address.map(Into::into), default_payment_method_id: Some(self.default_payment_method_id.clone()), }, - &key_store, + key_store, merchant_account.storage_scheme, ) .await diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 325935f9f3..16affdf73b 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -1218,7 +1218,7 @@ pub async fn create_recipient( &state.into(), global_id, customer, - &merchant_account.get_id(), + merchant_account.get_id(), updated_customer, key_store, merchant_account.storage_scheme, diff --git a/crates/router/src/db/customers.rs b/crates/router/src/db/customers.rs index 885e7ffc2d..f2688499cc 100644 --- a/crates/router/src/db/customers.rs +++ b/crates/router/src/db/customers.rs @@ -117,7 +117,7 @@ where async fn find_customer_by_global_id( &self, state: &KeyManagerState, - id: &String, + id: &str, merchant_id: &id_type::MerchantId, key_store: &domain::MerchantKeyStore, storage_scheme: MerchantStorageScheme, @@ -719,7 +719,7 @@ mod storage { async fn find_customer_by_global_id( &self, state: &KeyManagerState, - id: &String, + id: &str, _merchant_id: &id_type::MerchantId, key_store: &domain::MerchantKeyStore, storage_scheme: MerchantStorageScheme, @@ -1154,7 +1154,7 @@ mod storage { async fn find_customer_by_global_id( &self, state: &KeyManagerState, - id: &String, + id: &str, merchant_id: &id_type::MerchantId, key_store: &domain::MerchantKeyStore, _storage_scheme: MerchantStorageScheme, @@ -1372,7 +1372,7 @@ impl CustomerInterface for MockDb { async fn find_customer_by_global_id( &self, _state: &KeyManagerState, - _id: &String, + _id: &str, _merchant_id: &id_type::MerchantId, _key_store: &domain::MerchantKeyStore, _storage_scheme: MerchantStorageScheme, diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs index 2f5bf8b679..0f8f26b41d 100644 --- a/crates/router/src/db/kafka_store.rs +++ b/crates/router/src/db/kafka_store.rs @@ -498,7 +498,7 @@ impl CustomerInterface for KafkaStore { async fn find_customer_by_global_id( &self, state: &KeyManagerState, - id: &String, + id: &str, merchant_id: &id_type::MerchantId, key_store: &domain::MerchantKeyStore, storage_scheme: MerchantStorageScheme, diff --git a/crates/router/src/routes/admin.rs b/crates/router/src/routes/admin.rs index 6feb30a08c..353be92163 100644 --- a/crates/router/src/routes/admin.rs +++ b/crates/router/src/routes/admin.rs @@ -955,6 +955,11 @@ pub async fn business_profile_retrieve( .await } +#[cfg(all( + feature = "olap", + any(feature = "v1", feature = "v2"), + not(feature = "business_profile_v2") +))] #[instrument(skip_all, fields(flow = ?Flow::BusinessProfileUpdate))] pub async fn business_profile_update( state: web::Data, @@ -983,6 +988,44 @@ pub async fn business_profile_update( )) .await } + +#[cfg(all(feature = "v2", feature = "business_profile_v2"))] +#[instrument(skip_all, fields(flow = ?Flow::BusinessProfileUpdate))] +pub async fn business_profile_update( + state: web::Data, + req: HttpRequest, + path: web::Path, + json_payload: web::Json, +) -> HttpResponse { + let flow = Flow::BusinessProfileUpdate; + let profile_id = path.into_inner(); + + let merchant_id = match HeaderMapStruct::from(&req).get_merchant_id_from_header() { + Ok(val) => val, + Err(err) => { + return api::log_and_return_error_response(err); + } + }; + + Box::pin(api::server_wrap( + flow, + state, + &req, + json_payload.into_inner(), + |state, _, req, _| update_business_profile(state, &profile_id, &merchant_id, req), + auth::auth_type( + &auth::AdminApiAuth, + &auth::JWTAuthMerchantFromRoute { + merchant_id: merchant_id.clone(), + required_permission: Permission::MerchantAccountWrite, + }, + req.headers(), + ), + api_locking::LockAction::NotApplicable, + )) + .await +} + #[instrument(skip_all, fields(flow = ?Flow::BusinessProfileDelete))] pub async fn business_profile_delete( state: web::Data, diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 3d6fcb103c..955d091202 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -1469,7 +1469,11 @@ impl BusinessProfile { .service(web::resource("").route(web::post().to(business_profile_create))) .service( web::scope("/{profile_id}") - .service(web::resource("").route(web::get().to(business_profile_retrieve))) + .service( + web::resource("") + .route(web::get().to(business_profile_retrieve)) + .route(web::post().to(business_profile_update)), + ) .service( web::resource("/fallback_routing") .route(web::get().to(routing::routing_retrieve_default_config)) diff --git a/crates/router/src/types/api/admin.rs b/crates/router/src/types/api/admin.rs index eb56e3a1db..11b27a583b 100644 --- a/crates/router/src/types/api/admin.rs +++ b/crates/router/src/types/api/admin.rs @@ -185,7 +185,7 @@ impl ForeignTryFrom for BusinessProfileResponse { let order_fulfillment_time = item .order_fulfillment_time - .map(|time| api_models::admin::OrderFulfillmentTime::new(time)) + .map(api_models::admin::OrderFulfillmentTime::new) .transpose() .change_context(errors::ParsingError::IntegerOverflow)?;