doc: Documentation for customer and MCA and Mechant account API (#416)

Co-authored-by: bernard-eugine <114725419+bernard-eugine@users.noreply.github.com>
This commit is contained in:
Kartikeya Hegde
2023-01-19 17:30:45 +05:30
committed by GitHub
parent 5924e93413
commit 89c75b9c7a
6 changed files with 448 additions and 41 deletions

View File

@ -210,9 +210,13 @@ pub struct WebhookDetails {
pub payment_failed_enabled: Option<bool>,
}
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, ToSchema)]
pub struct DeleteResponse {
/// The identifier for the Merchant Account
#[schema(max_length = 255, example = "y3oqhf46pyzuxjbcn2giaqnb44")]
pub merchant_id: String,
/// If the connector is deleted or not
#[schema(example = false)]
pub deleted: bool,
}
@ -324,9 +328,15 @@ pub struct PaymentMethods {
pub payment_experience: Option<Vec<payment_methods::PaymentExperience>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct DeleteMcaResponse {
/// The identifier for the Merchant Account
#[schema(max_length = 255, example = "y3oqhf46pyzuxjbcn2giaqnb44")]
pub merchant_id: String,
/// Unique ID of the connector
#[schema(example = 42)]
pub merchant_connector_id: i32,
/// If the connector is deleted or not
#[schema(example = false)]
pub deleted: bool,
}

View File

@ -1,33 +1,95 @@
use common_utils::{consts, custom_serde, pii};
use masking::Secret;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
/// The customer details
#[derive(Debug, Default, Clone, Deserialize, Serialize, ToSchema)]
pub struct CustomerRequest {
/// The identifier for the customer object. If not provided the customer ID will be autogenerated.
#[schema(max_length = 255, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
#[serde(default = "generate_customer_id")]
pub customer_id: String,
/// The identifier for the Merchant Account
#[schema(max_length = 255, example = "y3oqhf46pyzuxjbcn2giaqnb44")]
#[serde(default = "unknown_merchant", skip)]
pub merchant_id: String,
/// The customer's name
#[schema(max_length = 255, example = "Jon Test")]
pub name: Option<String>,
/// The customer's email address
#[schema(value_type = Option<String>,max_length = 255, example = "JonTest@test.com")]
pub email: Option<Secret<String, pii::Email>>,
/// The customer's phone number
#[schema(value_type = Option<String>,max_length = 255, example = "9999999999")]
pub phone: Option<Secret<String>>,
/// An arbitrary string that you can attach to a customer object.
#[schema(max_length = 255, example = "First Customer")]
pub description: Option<String>,
/// The country code for the customer phone number
#[schema(max_length = 255, example = "+65")]
pub phone_country_code: Option<String>,
/// The address for the customer
#[schema(value_type = Option<Object>,example = json!({
"city": "Bangalore",
"country": "IN",
"line1": "Juspay router",
"line2": "Koramangala",
"line3": "Stallion",
"state": "Karnataka",
"zip": "560095",
"first_name": "John",
"last_name": "Doe"
}))]
pub address: Option<Secret<serde_json::Value>>,
/// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500
/// characters long. Metadata is useful for storing additional, structured information on an
/// object.
#[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
pub metadata: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct CustomerResponse {
/// The identifier for the customer object. If not provided the customer ID will be autogenerated.
#[schema(max_length = 255, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
pub customer_id: String,
/// The customer's name
#[schema(max_length = 255, example = "Jon Test")]
pub name: Option<String>,
/// The customer's email address
#[schema(value_type = Option<String>,max_length = 255, example = "JonTest@test.com")]
pub email: Option<Secret<String, pii::Email>>,
/// The customer's phone number
#[schema(value_type = Option<String>,max_length = 255, example = "9999999999")]
pub phone: Option<Secret<String>>,
/// The country code for the customer phone number
#[schema(max_length = 255, example = "+65")]
pub phone_country_code: Option<String>,
/// An arbitrary string that you can attach to a customer object.
#[schema(max_length = 255, example = "First Customer")]
pub description: Option<String>,
/// The address for the customer
#[schema(value_type = Option<Object>,example = json!({
"city": "Bangalore",
"country": "IN",
"line1": "Juspay router",
"line2": "Koramangala",
"line3": "Stallion",
"state": "Karnataka",
"zip": "560095",
"first_name": "John",
"last_name": "Doe"
}))]
pub address: Option<Secret<serde_json::Value>>,
/// A timestamp (ISO 8601 code) that determines when the customer was created
#[schema(value_type = PrimitiveDateTime,example = "2023-01-18T11:04:09.922Z")]
#[serde(with = "custom_serde::iso8601")]
pub created_at: time::PrimitiveDateTime,
/// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500
/// characters long. Metadata is useful for storing additional, structured information on an
/// object.
#[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
pub metadata: Option<serde_json::Value>,
}
@ -36,11 +98,19 @@ pub struct CustomerId {
pub customer_id: String,
}
#[derive(Default, Debug, Deserialize, Serialize)]
#[derive(Default, Debug, Deserialize, Serialize, ToSchema)]
pub struct CustomerDeleteResponse {
/// The identifier for the customer object
#[schema(max_length = 255, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
pub customer_id: String,
/// Whether customer was deleted or not
#[schema(example = false)]
pub customer_deleted: bool,
/// Whether address was deleted or not
#[schema(example = false)]
pub address_deleted: bool,
/// Whether payment methods deleted or not
#[schema(example = false)]
pub payment_methods_deleted: bool,
}

View File

@ -53,6 +53,11 @@ Never share your secret api keys. Keep them guarded and secure.
crate::types::api::refunds::RefundResponse,
crate::types::api::refunds::RefundStatus,
crate::types::api::admin::CreateMerchantAccount,
crate::types::api::admin::DeleteResponse,
crate::types::api::admin::DeleteMcaResponse,
crate::types::api::customers::CustomerRequest,
crate::types::api::customers::CustomerDeleteResponse,
api_models::customers::CustomerResponse,
api_models::enums::RoutingAlgorithm,
api_models::enums::PaymentMethodType,
api_models::enums::PaymentMethodSubType,

View File

@ -21,7 +21,6 @@ use crate::{
)
)]
#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountCreate))]
// #[post("")]
pub async fn merchant_account_create(
state: web::Data<AppState>,
req: HttpRequest,
@ -37,8 +36,18 @@ pub async fn merchant_account_create(
.await
}
/// Merchant Account - Retrieve
/// Retrieve a merchant account details.
#[utoipa::path(
get,
path = "/account/{account_id}",
params (("account_id" = String, Path, description = "The unique identifier for the merchant account")),
responses(
(status = 200, description = "Merchant Account Retrieved", body = MerchantAccountResponse),
(status = 404, description = "Merchant account not found")
)
)]
#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountRetrieve))]
// #[get("/{id}")]
pub async fn retrieve_merchant_account(
state: web::Data<AppState>,
req: HttpRequest,
@ -58,8 +67,19 @@ pub async fn retrieve_merchant_account(
.await
}
/// Merchant Account - Update
/// Update a merchant account details.
#[utoipa::path(
post,
path = "/account/{account_id}",
request_body = CreateMerchantAccount,
params (("account_id" = String, Path, description = "The unique identifier for the merchant account")),
responses(
(status = 200, description = "Merchant Account Updated", body = MerchantAccountResponse),
(status = 404, description = "Merchant account not found")
)
)]
#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountUpdate))]
// #[post["/{id}"]]
pub async fn update_merchant_account(
state: web::Data<AppState>,
req: HttpRequest,
@ -77,6 +97,17 @@ pub async fn update_merchant_account(
.await
}
/// Merchant Account - Delete
/// Delete a merchant account details.
#[utoipa::path(
delete,
path = "/account/{account_id}",
params (("account_id" = String, Path, description = "The unique identifier for the merchant account")),
responses(
(status = 200, description = "Merchant Account Deleted", body = DeleteResponse),
(status = 404, description = "Merchant account not found")
)
)]
#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountDelete))]
// #[delete("/{id}")]
pub async fn delete_merchant_account(
@ -128,8 +159,23 @@ pub async fn payment_connector_create(
.await
}
/// Payment Connector - Retrieve
///
/// Retrieve Payment Connector Details
#[utoipa::path(
get,
path = "/account/{account_id}/connectors/{connector_id}",
params(
("account_id" = String, Path, description = "The unique identifier for the merchant account"),
("connector_id" = i32, Path, description = "The unique identifier for the payment connector")
),
responses(
(status = 200, description = "Payment Connector retrieved successfully", body = PaymentConnectorCreate),
(status = 404, description = "Payment Connector does not exist in records"),
(status = 401, description = "Unauthorized request")
)
)]
#[instrument(skip_all, fields(flow = ?Flow::PaymentConnectorsRetrieve))]
// #[get("/{merchant_id}/connectors/{merchant_connector_id}")]
pub async fn payment_connector_retrieve(
state: web::Data<AppState>,
req: HttpRequest,
@ -153,8 +199,22 @@ pub async fn payment_connector_retrieve(
.await
}
/// Payment Connector - List
///
/// List Payment Connector Details for the merchant
#[utoipa::path(
get,
path = "/account/{account_id}/connectors",
params(
("account_id" = String, Path, description = "The unique identifier for the merchant account"),
),
responses(
(status = 200, description = "Payment Connector list retrieved successfully", body = Vec<PaymentConnectorCreate>),
(status = 404, description = "Payment Connector does not exist in records"),
(status = 401, description = "Unauthorized request")
)
)]
#[instrument(skip_all, fields(flow = ?Flow::PaymentConnectorsList))]
pub async fn payment_connector_list(
state: web::Data<AppState>,
req: HttpRequest,
@ -171,8 +231,24 @@ pub async fn payment_connector_list(
.await
}
/// Payment Connector - Update
///
/// To update an existing Payment Connector. Helpful in enabling / disabling different payment methods and other settings for the connector etc
#[utoipa::path(
post,
path = "/account/{account_id}/connectors/{connector_id}",
request_body = PaymentConnectorCreate,
params(
("account_id" = String, Path, description = "The unique identifier for the merchant account"),
("connector_id" = i32, Path, description = "The unique identifier for the payment connector")
),
responses(
(status = 200, description = "Payment Connector Updated", body = PaymentConnectorCreate),
(status = 404, description = "Payment Connector does not exist in records"),
(status = 401, description = "Unauthorized request")
)
)]
#[instrument(skip_all, fields(flow = ?Flow::PaymentConnectorsUpdate))]
// #[post("/{merchant_id}/connectors/{merchant_connector_id}")]
pub async fn payment_connector_update(
state: web::Data<AppState>,
req: HttpRequest,
@ -192,8 +268,22 @@ pub async fn payment_connector_update(
.await
}
/// Payment Connector - Delete
/// Delete or Detach a Payment Connector from Merchant Account
#[utoipa::path(
delete,
path = "/account/{account_id}/connectors/{connector_id}",
params(
("account_id" = String, Path, description = "The unique identifier for the merchant account"),
("connector_id" = i32, Path, description = "The unique identifier for the payment connector")
),
responses(
(status = 200, description = "Payment Connector Deleted", body = DeleteMcaResponse),
(status = 404, description = "Payment Connector does not exist in records"),
(status = 401, description = "Unauthorized request")
)
)]
#[instrument(skip_all, fields(flow = ?Flow::PaymentConnectorsDelete))]
// #[delete("/{merchant_id}/connectors/{merchant_connector_id}")]
pub async fn payment_connector_delete(
state: web::Data<AppState>,
req: HttpRequest,

View File

@ -8,8 +8,19 @@ use crate::{
types::api::customers,
};
/// Create Customer
///
/// Create a customer object and store the customer details to be reused for future payments. Incase the customer already exists in the system, this API will respond with the customer details.
#[utoipa::path(
post,
path = "/customers",
request_body = CustomerRequest,
responses(
(status = 200, description = "Customer Created", body = CustomerResponse),
(status = 400, description = "Invalid data")
)
)]
#[instrument(skip_all, fields(flow = ?Flow::CustomersCreate))]
// #[post("")]
pub async fn customers_create(
state: web::Data<AppState>,
req: HttpRequest,
@ -25,8 +36,19 @@ pub async fn customers_create(
.await
}
/// Retrieve Customer
///
/// Retrieve a customer's details.
#[utoipa::path(
get,
path = "/customers/{customer_id}",
params (("customer_id" = String, Path, description = "The unique identifier for the Customer")),
responses(
(status = 200, description = "Customer Retrieved", body = CustomerResponse),
(status = 404, description = "Customer was not found")
)
)]
#[instrument(skip_all, fields(flow = ?Flow::CustomersRetrieve))]
// #[get("/{customer_id}")]
pub async fn customers_retrieve(
state: web::Data<AppState>,
req: HttpRequest,
@ -53,8 +75,20 @@ pub async fn customers_retrieve(
.await
}
/// Update Customer
///
/// Updates the customer's details in a customer object.
#[utoipa::path(
post,
path = "/customers/{customer_id}",
request_body = CustomerRequest,
params (("customer_id" = String, Path, description = "The unique identifier for the Customer")),
responses(
(status = 200, description = "Customer was Updated", body = CustomerResponse),
(status = 404, description = "Customer was not found")
)
)]
#[instrument(skip_all, fields(flow = ?Flow::CustomersUpdate))]
// #[post("/{customer_id}")]
pub async fn customers_update(
state: web::Data<AppState>,
req: HttpRequest,
@ -73,8 +107,19 @@ pub async fn customers_update(
.await
}
/// Delete Customer
///
/// Delete a customer record.
#[utoipa::path(
delete,
path = "/customers/{customer_id}",
params (("customer_id" = String, Path, description = "The unique identifier for the Customer")),
responses(
(status = 200, description = "Customer was Deleted", body = CustomerDeleteResponse),
(status = 404, description = "Customer was not found")
)
)]
#[instrument(skip_all, fields(flow = ?Flow::CustomersDelete))]
// #[delete("/{customer_id}")]
pub async fn customers_delete(
state: web::Data<AppState>,
req: HttpRequest,
@ -88,7 +133,6 @@ pub async fn customers_delete(
}
#[instrument(skip_all, fields(flow = ?Flow::CustomersGetMandates))]
// #[get("/{customer_id}/mandates")]
pub async fn get_customer_mandates(
state: web::Data<AppState>,
req: HttpRequest,

View File

@ -507,6 +507,190 @@
}
}
},
"CustomerDeleteResponse": {
"type": "object",
"required": [
"customer_id",
"customer_deleted",
"address_deleted",
"payment_methods_deleted"
],
"properties": {
"customer_id": {
"type": "string",
"description": "The identifier for the customer object",
"example": "cus_y3oqhf46pyzuxjbcn2giaqnb44",
"maxLength": 255
},
"customer_deleted": {
"type": "boolean",
"description": "Whether customer was deleted or not",
"example": false
},
"address_deleted": {
"type": "boolean",
"description": "Whether address was deleted or not",
"example": false
},
"payment_methods_deleted": {
"type": "boolean",
"description": "Whether payment methods deleted or not",
"example": false
}
}
},
"CustomerRequest": {
"type": "object",
"description": "The customer details",
"properties": {
"customer_id": {
"type": "string",
"description": "The identifier for the customer object. If not provided the customer ID will be autogenerated.",
"example": "cus_y3oqhf46pyzuxjbcn2giaqnb44",
"maxLength": 255
},
"name": {
"type": "string",
"description": "The customer's name",
"example": "Jon Test",
"maxLength": 255
},
"email": {
"type": "string",
"description": "The customer's email address",
"example": "JonTest@test.com",
"maxLength": 255
},
"phone": {
"type": "string",
"description": "The customer's phone number",
"example": "9999999999",
"maxLength": 255
},
"description": {
"type": "string",
"description": "An arbitrary string that you can attach to a customer object.",
"example": "First Customer",
"maxLength": 255
},
"phone_country_code": {
"type": "string",
"description": "The country code for the customer phone number",
"example": "+65",
"maxLength": 255
},
"address": {
"type": "object"
},
"metadata": {
"type": "object"
}
}
},
"CustomerResponse": {
"type": "object",
"required": [
"customer_id",
"created_at"
],
"properties": {
"customer_id": {
"type": "string",
"description": "The identifier for the customer object. If not provided the customer ID will be autogenerated.",
"example": "cus_y3oqhf46pyzuxjbcn2giaqnb44",
"maxLength": 255
},
"name": {
"type": "string",
"description": "The customer's name",
"example": "Jon Test",
"maxLength": 255
},
"email": {
"type": "string",
"description": "The customer's email address",
"example": "JonTest@test.com",
"maxLength": 255
},
"phone": {
"type": "string",
"description": "The customer's phone number",
"example": "9999999999",
"maxLength": 255
},
"phone_country_code": {
"type": "string",
"description": "The country code for the customer phone number",
"example": "+65",
"maxLength": 255
},
"description": {
"type": "string",
"description": "An arbitrary string that you can attach to a customer object.",
"example": "First Customer",
"maxLength": 255
},
"address": {
"type": "object"
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A timestamp (ISO 8601 code) that determines when the customer was created",
"example": "2023-01-18T11:04:09.922Z"
},
"metadata": {
"type": "object"
}
}
},
"DeleteMcaResponse": {
"type": "object",
"required": [
"merchant_id",
"merchant_connector_id",
"deleted"
],
"properties": {
"merchant_id": {
"type": "string",
"description": "The identifier for the Merchant Account",
"example": "y3oqhf46pyzuxjbcn2giaqnb44",
"maxLength": 255
},
"merchant_connector_id": {
"type": "integer",
"format": "int32",
"description": "Unique ID of the connector",
"example": 42
},
"deleted": {
"type": "boolean",
"description": "If the connector is deleted or not",
"example": false
}
}
},
"DeleteResponse": {
"type": "object",
"required": [
"merchant_id",
"deleted"
],
"properties": {
"merchant_id": {
"type": "string",
"description": "The identifier for the Merchant Account",
"example": "y3oqhf46pyzuxjbcn2giaqnb44",
"maxLength": 255
},
"deleted": {
"type": "boolean",
"description": "If the connector is deleted or not",
"example": false
}
}
},
"FutureUsage": {
"type": "string",
"enum": [
@ -601,7 +785,9 @@
"MerchantAccountResponse": {
"type": "object",
"required": [
"merchant_id"
"merchant_id",
"enable_payment_response_hash",
"redirect_to_merchant_with_http_post"
],
"properties": {
"merchant_id": {
@ -620,20 +806,38 @@
"description": "API key that will be used for server side API access",
"example": "Ah2354543543523"
},
"merchant_details": {
"$ref": "#/components/schemas/MerchantDetails"
},
"return_url": {
"type": "string",
"description": "The URL to redirect after the completion of the operation",
"example": "https://www.example.com/success",
"maxLength": 255
},
"enable_payment_response_hash": {
"type": "boolean",
"description": "A boolean value to indicate if payment response hash needs to be enabled",
"default": false,
"example": true
},
"payment_response_hash_key": {
"type": "string",
"description": "Refers to the Parent Merchant ID if the merchant being created is a sub-merchant",
"example": "xkkdf909012sdjki2dkh5sdf",
"maxLength": 255
},
"redirect_to_merchant_with_http_post": {
"type": "boolean",
"description": "A boolean value to indicate if redirect to merchant with http post needs to be enabled",
"default": false,
"example": true
},
"merchant_details": {
"$ref": "#/components/schemas/MerchantDetails"
},
"webhook_details": {
"$ref": "#/components/schemas/WebhookDetails"
},
"routing_algorithm": {
"type": "object"
"$ref": "#/components/schemas/RoutingAlgorithm"
},
"sub_merchants_enabled": {
"type": "boolean",
@ -647,30 +851,14 @@
"example": "xkkdf909012sdjki2dkh5sdf",
"maxLength": 255
},
"enable_payment_response_hash": {
"type": "boolean",
"description": "A boolean value to indicate if payment response hash needs to be enabled",
"default": false,
"example": true
},
"payment_response_hash_key": {
"type": "string",
"description": "Refers to the hash key used for payment response"
},
"redirect_to_merchant_with_http_post": {
"type": "boolean",
"description": "A boolean value to indicate if redirect to merchant with http post needs to be enabled",
"default": false,
"example": true
},
"metadata": {
"type": "object"
},
"publishable_key": {
"type": "string",
"description": "API key that will be used for server side API access",
"example": "AH3423bkjbkjdsfbkj"
},
"metadata": {
"type": "object"
},
"locker_id": {
"type": "string",
"description": "An identifier for the vault used to store payment method information.",