feat(router): add api_models and openapi changes for refunds create api v2 (#6385)

This commit is contained in:
Sai Harsha Vardhan
2024-10-23 16:53:46 +05:30
committed by GitHub
parent 4ef48c39b3
commit 5a10e5867a
15 changed files with 469 additions and 38 deletions

View File

@ -0,0 +1,3 @@
---
openapi: post /v2/refunds
---

View File

@ -107,6 +107,12 @@
"api-reference/customers/customers--delete", "api-reference/customers/customers--delete",
"api-reference/customers/customers--list" "api-reference/customers/customers--list"
] ]
},
{
"group": "Refunds",
"pages": [
"api-reference/refunds/refunds--create"
]
} }
], ],
"footerSocials": { "footerSocials": {

View File

@ -1847,6 +1847,72 @@
} }
] ]
} }
},
"/v2/refunds": {
"post": {
"tags": [
"Refunds"
],
"summary": "Refunds - Create",
"description": "Creates a refund against an already processed payment. In case of some processors, you can even opt to refund only a partial amount multiple times until the original charge amount has been refunded",
"operationId": "Create a Refund",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RefundsCreateRequest"
},
"examples": {
"Create an instant refund to refund partial amount": {
"value": {
"amount": 654,
"merchant_reference_id": "ref_123",
"payment_id": "{{payment_id}}",
"refund_type": "instant"
}
},
"Create an instant refund to refund the whole amount": {
"value": {
"merchant_reference_id": "ref_123",
"payment_id": "{{payment_id}}",
"refund_type": "instant"
}
},
"Create an instant refund with reason": {
"value": {
"amount": 6540,
"merchant_reference_id": "ref_123",
"payment_id": "{{payment_id}}",
"reason": "Customer returned product",
"refund_type": "instant"
}
}
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Refund created",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RefundResponse"
}
}
}
},
"400": {
"description": "Missing Mandatory fields"
}
},
"security": [
{
"api_key": []
}
]
}
} }
}, },
"components": { "components": {
@ -18108,6 +18174,21 @@
} }
} }
}, },
"RefundErrorDetails": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
}
}
},
"RefundListRequest": { "RefundListRequest": {
"allOf": [ "allOf": [
{ {
@ -18298,89 +18379,89 @@
"RefundResponse": { "RefundResponse": {
"type": "object", "type": "object",
"required": [ "required": [
"refund_id", "id",
"payment_id", "payment_id",
"amount", "amount",
"currency", "currency",
"status", "status",
"connector" "created_at",
"updated_at",
"connector",
"profile_id",
"merchant_connector_id"
], ],
"properties": { "properties": {
"refund_id": { "id": {
"type": "string", "type": "string",
"description": "Unique Identifier for the refund" "description": "Global Refund Id for the refund"
}, },
"payment_id": { "payment_id": {
"type": "string", "type": "string",
"description": "The payment id against which refund is initiated" "description": "The payment id against which refund is initiated"
}, },
"merchant_reference_id": {
"type": "string",
"description": "Unique Identifier for the Refund. This is to ensure idempotency for multiple partial refunds initiated against the same payment.",
"example": "ref_mbabizu24mvu3mela5njyhpit4",
"nullable": true,
"maxLength": 30,
"minLength": 30
},
"amount": { "amount": {
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"description": "The refund amount, which should be less than or equal to the total payment amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc", "description": "The refund amount",
"example": 6540, "example": 6540,
"minimum": 100 "minimum": 100
}, },
"currency": { "currency": {
"type": "string", "$ref": "#/components/schemas/Currency"
"description": "The three-letter ISO currency code"
}, },
"status": { "status": {
"$ref": "#/components/schemas/RefundStatus" "$ref": "#/components/schemas/RefundStatus"
}, },
"reason": { "reason": {
"type": "string", "type": "string",
"description": "An arbitrary string attached to the object. Often useful for displaying to users and your customer support executive", "description": "An arbitrary string attached to the object",
"nullable": true "nullable": true
}, },
"metadata": { "metadata": {
"type": "object", "type": "object",
"description": "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", "description": "Metadata is useful for storing additional, unstructured information on an object",
"nullable": true "nullable": true
}, },
"error_message": { "error_details": {
"type": "string", "allOf": [
"description": "The error message", {
"nullable": true "$ref": "#/components/schemas/RefundErrorDetails"
}, }
"error_code": { ],
"type": "string",
"description": "The code for the error",
"nullable": true "nullable": true
}, },
"created_at": { "created_at": {
"type": "string", "type": "string",
"format": "date-time", "format": "date-time",
"description": "The timestamp at which refund is created", "description": "The timestamp at which refund is created"
"nullable": true
}, },
"updated_at": { "updated_at": {
"type": "string", "type": "string",
"format": "date-time", "format": "date-time",
"description": "The timestamp at which refund is updated", "description": "The timestamp at which refund is updated"
"nullable": true
}, },
"connector": { "connector": {
"type": "string", "$ref": "#/components/schemas/Connector"
"description": "The connector used for the refund and the corresponding payment",
"example": "stripe"
}, },
"profile_id": { "profile_id": {
"type": "string", "type": "string",
"description": "The id of business profile for this refund", "description": "The id of business profile for this refund"
"nullable": true
}, },
"merchant_connector_id": { "merchant_connector_id": {
"type": "string", "type": "string",
"description": "The merchant_connector_id of the processor through which this payment went through", "description": "The merchant_connector_id of the processor through which this payment went through"
"nullable": true
}, },
"charges": { "connector_refund_reference_id": {
"allOf": [ "type": "string",
{ "description": "The reference id of the connector for the refund",
"$ref": "#/components/schemas/ChargeRefunds"
}
],
"nullable": true "nullable": true
} }
} }
@ -18421,6 +18502,59 @@
}, },
"additionalProperties": false "additionalProperties": false
}, },
"RefundsCreateRequest": {
"type": "object",
"required": [
"payment_id"
],
"properties": {
"payment_id": {
"type": "string",
"description": "The payment id against which refund is initiated",
"example": "pay_mbabizu24mvu3mela5njyhpit4",
"maxLength": 30,
"minLength": 30
},
"merchant_reference_id": {
"type": "string",
"description": "Unique Identifier for the Refund. This is to ensure idempotency for multiple partial refunds initiated against the same payment.",
"example": "ref_mbabizu24mvu3mela5njyhpit4",
"nullable": true,
"maxLength": 30,
"minLength": 30
},
"amount": {
"type": "integer",
"format": "int64",
"description": "Total amount for which the refund is to be initiated. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, this will default to the amount_captured of the payment",
"example": 6540,
"nullable": true,
"minimum": 100
},
"reason": {
"type": "string",
"description": "Reason for the refund. Often useful for displaying to users and your customer support executive.",
"example": "Customer returned the product",
"nullable": true,
"maxLength": 255
},
"refund_type": {
"allOf": [
{
"$ref": "#/components/schemas/RefundType"
}
],
"default": "Instant",
"nullable": true
},
"metadata": {
"type": "object",
"description": "Metadata is useful for storing additional, unstructured information on an object.",
"nullable": true
}
},
"additionalProperties": false
},
"RequestIncrementalAuthorization": { "RequestIncrementalAuthorization": {
"type": "string", "type": "string",
"enum": [ "enum": [

View File

@ -6,6 +6,7 @@ use crate::refunds::{
RefundUpdateRequest, RefundsRetrieveRequest, RefundUpdateRequest, RefundsRetrieveRequest,
}; };
#[cfg(feature = "v1")]
impl ApiEventMetric for RefundRequest { impl ApiEventMetric for RefundRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> { fn get_api_event_type(&self) -> Option<ApiEventsType> {
let payment_id = self.payment_id.clone(); let payment_id = self.payment_id.clone();
@ -18,6 +19,7 @@ impl ApiEventMetric for RefundRequest {
} }
} }
#[cfg(feature = "v1")]
impl ApiEventMetric for RefundResponse { impl ApiEventMetric for RefundResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> { fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Refund { Some(ApiEventsType::Refund {
@ -27,6 +29,17 @@ impl ApiEventMetric for RefundResponse {
} }
} }
#[cfg(feature = "v2")]
impl ApiEventMetric for RefundResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Refund {
payment_id: self.payment_id.clone(),
refund_id: self.id.clone(),
})
}
}
#[cfg(feature = "v1")]
impl ApiEventMetric for RefundsRetrieveRequest { impl ApiEventMetric for RefundsRetrieveRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> { fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Refund { Some(ApiEventsType::Refund {
@ -36,6 +49,7 @@ impl ApiEventMetric for RefundsRetrieveRequest {
} }
} }
#[cfg(feature = "v1")]
impl ApiEventMetric for RefundUpdateRequest { impl ApiEventMetric for RefundUpdateRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> { fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Refund { Some(ApiEventsType::Refund {
@ -45,6 +59,7 @@ impl ApiEventMetric for RefundUpdateRequest {
} }
} }
#[cfg(feature = "v1")]
impl ApiEventMetric for RefundManualUpdateRequest { impl ApiEventMetric for RefundManualUpdateRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> { fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Refund { Some(ApiEventsType::Refund {

View File

@ -61,6 +61,45 @@ pub struct RefundRequest {
pub charges: Option<ChargeRefunds>, pub charges: Option<ChargeRefunds>,
} }
#[cfg(feature = "v2")]
#[derive(Debug, ToSchema, Clone, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct RefundsCreateRequest {
/// The payment id against which refund is initiated
#[schema(
max_length = 30,
min_length = 30,
example = "pay_mbabizu24mvu3mela5njyhpit4",
value_type = String,
)]
pub payment_id: common_utils::id_type::GlobalPaymentId,
/// Unique Identifier for the Refund. This is to ensure idempotency for multiple partial refunds initiated against the same payment.
#[schema(
max_length = 30,
min_length = 30,
example = "ref_mbabizu24mvu3mela5njyhpit4",
value_type = Option<String>,
)]
pub merchant_reference_id: Option<common_utils::id_type::RefundReferenceId>,
/// Total amount for which the refund is to be initiated. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, this will default to the amount_captured of the payment
#[schema(value_type = Option<i64> , minimum = 100, example = 6540)]
pub amount: Option<MinorUnit>,
/// Reason for the refund. Often useful for displaying to users and your customer support executive.
#[schema(max_length = 255, example = "Customer returned the product")]
pub reason: Option<String>,
/// To indicate whether to refund needs to be instant or scheduled. Default value is instant
#[schema(default = "Instant", example = "Instant")]
pub refund_type: Option<RefundType>,
/// Metadata is useful for storing additional, unstructured information on an object.
#[schema(value_type = Option<Object>, example = r#"{ "city": "NY", "unit": "245" }"#)]
pub metadata: Option<pii::SecretSerdeValue>,
}
#[derive(Default, Debug, Clone, Deserialize)] #[derive(Default, Debug, Clone, Deserialize)]
pub struct RefundsRetrieveBody { pub struct RefundsRetrieveBody {
pub force_sync: Option<bool>, pub force_sync: Option<bool>,
@ -125,6 +164,7 @@ pub enum RefundType {
Instant, Instant,
} }
#[cfg(feature = "v1")]
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, ToSchema)] #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, ToSchema)]
pub struct RefundResponse { pub struct RefundResponse {
/// Unique Identifier for the refund /// Unique Identifier for the refund
@ -168,6 +208,78 @@ pub struct RefundResponse {
pub charges: Option<ChargeRefunds>, pub charges: Option<ChargeRefunds>,
} }
#[cfg(feature = "v1")]
impl RefundResponse {
pub fn get_refund_id_as_string(&self) -> String {
self.refund_id.clone()
}
}
#[cfg(feature = "v2")]
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, ToSchema)]
pub struct RefundResponse {
/// Global Refund Id for the refund
#[schema(value_type = String)]
pub id: common_utils::id_type::GlobalRefundId,
/// The payment id against which refund is initiated
#[schema(value_type = String)]
pub payment_id: common_utils::id_type::GlobalPaymentId,
/// Unique Identifier for the Refund. This is to ensure idempotency for multiple partial refunds initiated against the same payment.
#[schema(
max_length = 30,
min_length = 30,
example = "ref_mbabizu24mvu3mela5njyhpit4",
value_type = Option<String>,
)]
pub merchant_reference_id: Option<common_utils::id_type::RefundReferenceId>,
/// The refund amount
#[schema(value_type = i64 , minimum = 100, example = 6540)]
pub amount: MinorUnit,
/// The three-letter ISO currency code
#[schema(value_type = Currency)]
pub currency: common_enums::Currency,
/// The status for refund
pub status: RefundStatus,
/// An arbitrary string attached to the object
pub reason: Option<String>,
/// Metadata is useful for storing additional, unstructured information on an object
#[schema(value_type = Option<Object>)]
pub metadata: Option<pii::SecretSerdeValue>,
/// The error details for the refund
pub error_details: Option<RefundErrorDetails>,
/// The timestamp at which refund is created
#[serde(with = "common_utils::custom_serde::iso8601")]
pub created_at: PrimitiveDateTime,
/// The timestamp at which refund is updated
#[serde(with = "common_utils::custom_serde::iso8601")]
pub updated_at: PrimitiveDateTime,
/// The connector used for the refund and the corresponding payment
#[schema(example = "stripe", value_type = Connector)]
pub connector: enums::Connector,
/// The id of business profile for this refund
#[schema(value_type = String)]
pub profile_id: common_utils::id_type::ProfileId,
/// The merchant_connector_id of the processor through which this payment went through
#[schema(value_type = String)]
pub merchant_connector_id: common_utils::id_type::MerchantConnectorAccountId,
/// The reference id of the connector for the refund
pub connector_refund_reference_id: Option<String>,
}
#[cfg(feature = "v2")]
impl RefundResponse {
pub fn get_refund_id_as_string(&self) -> String {
self.id.get_string_repr().to_owned()
}
}
#[cfg(feature = "v2")]
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, ToSchema)]
pub struct RefundErrorDetails {
pub code: String,
pub message: String,
}
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, ToSchema)] #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, ToSchema)]
pub struct RefundListRequest { pub struct RefundListRequest {
/// The identifier for the payment /// The identifier for the payment

View File

@ -23,10 +23,16 @@ pub enum ApiEventsType {
Payment { Payment {
payment_id: id_type::GlobalPaymentId, payment_id: id_type::GlobalPaymentId,
}, },
#[cfg(feature = "v1")]
Refund { Refund {
payment_id: Option<id_type::PaymentId>, payment_id: Option<id_type::PaymentId>,
refund_id: String, refund_id: String,
}, },
#[cfg(feature = "v2")]
Refund {
payment_id: id_type::GlobalPaymentId,
refund_id: id_type::GlobalRefundId,
},
PaymentMethod { PaymentMethod {
payment_method_id: String, payment_method_id: String,
payment_method: Option<PaymentMethod>, payment_method: Option<PaymentMethod>,

View File

@ -10,6 +10,7 @@ mod merchant_connector_account;
mod organization; mod organization;
mod payment; mod payment;
mod profile; mod profile;
mod refunds;
mod routing; mod routing;
#[cfg(feature = "v2")] #[cfg(feature = "v2")]
@ -25,12 +26,16 @@ use diesel::{
sql_types, sql_types,
}; };
#[cfg(feature = "v2")] #[cfg(feature = "v2")]
pub use global_id::{payment::GlobalPaymentId, payment_methods::GlobalPaymentMethodId, CellId}; pub use global_id::{
payment::GlobalPaymentId, payment_methods::GlobalPaymentMethodId, refunds::GlobalRefundId,
CellId,
};
pub use merchant::MerchantId; pub use merchant::MerchantId;
pub use merchant_connector_account::MerchantConnectorAccountId; pub use merchant_connector_account::MerchantConnectorAccountId;
pub use organization::OrganizationId; pub use organization::OrganizationId;
pub use payment::{PaymentId, PaymentReferenceId}; pub use payment::{PaymentId, PaymentReferenceId};
pub use profile::ProfileId; pub use profile::ProfileId;
pub use refunds::RefundReferenceId;
pub use routing::RoutingId; pub use routing::RoutingId;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;

View File

@ -1,6 +1,7 @@
#![allow(unused)] #![allow(unused)]
pub mod payment; pub mod payment;
pub mod payment_methods; pub mod payment_methods;
pub mod refunds;
use diesel::{backend::Backend, deserialize::FromSql, serialize::ToSql, sql_types}; use diesel::{backend::Backend, deserialize::FromSql, serialize::ToSql, sql_types};
use error_stack::ResultExt; use error_stack::ResultExt;
@ -24,6 +25,7 @@ pub(crate) enum GlobalEntity {
Customer, Customer,
Payment, Payment,
PaymentMethod, PaymentMethod,
Refund,
} }
impl GlobalEntity { impl GlobalEntity {
@ -32,6 +34,7 @@ impl GlobalEntity {
Self::Customer => "cus", Self::Customer => "cus",
Self::Payment => "pay", Self::Payment => "pay",
Self::PaymentMethod => "pm", Self::PaymentMethod => "pm",
Self::Refund => "ref",
} }
} }
} }

View File

@ -0,0 +1,71 @@
use error_stack::ResultExt;
use crate::{errors, generate_id_with_default_len, generate_time_ordered_id_without_prefix, types};
/// A global id that can be used to identify a refund
#[derive(
Debug,
Clone,
Hash,
PartialEq,
Eq,
serde::Serialize,
serde::Deserialize,
diesel::expression::AsExpression,
)]
#[diesel(sql_type = diesel::sql_types::Text)]
pub struct GlobalRefundId(super::GlobalId);
// Database related implementations so that this field can be used directly in the database tables
crate::impl_queryable_id_type!(GlobalRefundId);
impl GlobalRefundId {
/// Get string representation of the id
pub fn get_string_repr(&self) -> &str {
self.0.get_string_repr()
}
/// Generate a new GlobalRefundId from a cell id
pub fn generate(cell_id: crate::id_type::CellId) -> Self {
let global_id = super::GlobalId::generate(cell_id, super::GlobalEntity::Refund);
Self(global_id)
}
}
// TODO: refactor the macro to include this id use case as well
impl TryFrom<std::borrow::Cow<'static, str>> for GlobalRefundId {
type Error = error_stack::Report<errors::ValidationError>;
fn try_from(value: std::borrow::Cow<'static, str>) -> Result<Self, Self::Error> {
use error_stack::ResultExt;
let merchant_ref_id = super::GlobalId::from_string(value).change_context(
errors::ValidationError::IncorrectValueProvided {
field_name: "refund_id",
},
)?;
Ok(Self(merchant_ref_id))
}
}
// TODO: refactor the macro to include this id use case as well
impl<DB> diesel::serialize::ToSql<diesel::sql_types::Text, DB> for GlobalRefundId
where
DB: diesel::backend::Backend,
super::GlobalId: diesel::serialize::ToSql<diesel::sql_types::Text, DB>,
{
fn to_sql<'b>(
&'b self,
out: &mut diesel::serialize::Output<'b, '_, DB>,
) -> diesel::serialize::Result {
self.0.to_sql(out)
}
}
impl<DB> diesel::deserialize::FromSql<diesel::sql_types::Text, DB> for GlobalRefundId
where
DB: diesel::backend::Backend,
super::GlobalId: diesel::deserialize::FromSql<diesel::sql_types::Text, DB>,
{
fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
super::GlobalId::from_sql(value).map(Self)
}
}

View File

@ -0,0 +1,10 @@
crate::id_type!(RefundReferenceId, "A type for refund_reference_id");
crate::impl_id_type_methods!(RefundReferenceId, "refund_reference_id");
// This is to display the `RefundReferenceId` as RefundReferenceId(abcd)
crate::impl_debug_id_type!(RefundReferenceId);
crate::impl_try_from_cow_str_id_type!(RefundReferenceId, "refund_reference_id");
// Database related implementations so that this field can be used directly in the database tables
crate::impl_queryable_id_type!(RefundReferenceId);
crate::impl_to_sql_from_sql_id_type!(RefundReferenceId);

View File

@ -10,8 +10,8 @@ license.workspace = true
[features] [features]
default = ["kv_store"] default = ["kv_store"]
kv_store = [] kv_store = []
v1 = [] v1 = ["common_utils/v1"]
v2 = [] v2 = ["common_utils/v2"]
customer_v2 = [] customer_v2 = []
payment_methods_v2 = [] payment_methods_v2 = []

View File

@ -317,6 +317,7 @@ pub struct RefundCoreWorkflow {
pub connector_transaction_data: Option<String>, pub connector_transaction_data: Option<String>,
} }
#[cfg(feature = "v1")]
impl common_utils::events::ApiEventMetric for Refund { impl common_utils::events::ApiEventMetric for Refund {
fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> { fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
Some(common_utils::events::ApiEventsType::Refund { Some(common_utils::events::ApiEventsType::Refund {

View File

@ -123,6 +123,9 @@ Never share your secret api keys. Keep them guarded and secure.
//Routes for payments //Routes for payments
routes::payments::payments_create_intent, routes::payments::payments_create_intent,
//Routes for refunds
routes::refunds::refunds_create,
), ),
components(schemas( components(schemas(
common_utils::types::MinorUnit, common_utils::types::MinorUnit,
@ -140,6 +143,8 @@ Never share your secret api keys. Keep them guarded and secure.
common_utils::payout_method_utils::PaypalAdditionalData, common_utils::payout_method_utils::PaypalAdditionalData,
common_utils::payout_method_utils::VenmoAdditionalData, common_utils::payout_method_utils::VenmoAdditionalData,
api_models::refunds::RefundRequest, api_models::refunds::RefundRequest,
api_models::refunds::RefundsCreateRequest,
api_models::refunds::RefundErrorDetails,
api_models::refunds::RefundType, api_models::refunds::RefundType,
api_models::refunds::RefundResponse, api_models::refunds::RefundResponse,
api_models::refunds::RefundStatus, api_models::refunds::RefundStatus,

View File

@ -44,6 +44,7 @@
operation_id = "Create a Refund", operation_id = "Create a Refund",
security(("api_key" = [])) security(("api_key" = []))
)] )]
#[cfg(feature = "v1")]
pub async fn refunds_create() {} pub async fn refunds_create() {}
/// Refunds - Retrieve /// Refunds - Retrieve
@ -159,3 +160,55 @@ pub fn refunds_list_profile() {}
security(("api_key" = [])) security(("api_key" = []))
)] )]
pub async fn refunds_filter_list() {} pub async fn refunds_filter_list() {}
/// Refunds - Create
///
/// Creates a refund against an already processed payment. In case of some processors, you can even opt to refund only a partial amount multiple times until the original charge amount has been refunded
#[utoipa::path(
post,
path = "/v2/refunds",
request_body(
content = RefundsCreateRequest,
examples(
(
"Create an instant refund to refund the whole amount" = (
value = json!({
"payment_id": "{{payment_id}}",
"merchant_reference_id": "ref_123",
"refund_type": "instant"
})
)
),
(
"Create an instant refund to refund partial amount" = (
value = json!({
"payment_id": "{{payment_id}}",
"merchant_reference_id": "ref_123",
"refund_type": "instant",
"amount": 654
})
)
),
(
"Create an instant refund with reason" = (
value = json!({
"payment_id": "{{payment_id}}",
"merchant_reference_id": "ref_123",
"refund_type": "instant",
"amount": 6540,
"reason": "Customer returned product"
})
)
),
)
),
responses(
(status = 200, description = "Refund created", body = RefundResponse),
(status = 400, description = "Missing Mandatory fields")
),
tag = "Refunds",
operation_id = "Create a Refund",
security(("api_key" = []))
)]
#[cfg(feature = "v2")]
pub async fn refunds_create() {}

View File

@ -34,11 +34,18 @@ pub enum OutgoingWebhookEventContent {
payout_id: String, payout_id: String,
content: Value, content: Value,
}, },
#[cfg(feature = "v1")]
Refund { Refund {
payment_id: common_utils::id_type::PaymentId, payment_id: common_utils::id_type::PaymentId,
refund_id: String, refund_id: String,
content: Value, content: Value,
}, },
#[cfg(feature = "v2")]
Refund {
payment_id: common_utils::id_type::GlobalPaymentId,
refund_id: String,
content: Value,
},
Dispute { Dispute {
payment_id: common_utils::id_type::PaymentId, payment_id: common_utils::id_type::PaymentId,
attempt_id: String, attempt_id: String,
@ -64,7 +71,7 @@ impl OutgoingWebhookEventMetric for OutgoingWebhookContent {
}), }),
Self::RefundDetails(refund_payload) => Some(OutgoingWebhookEventContent::Refund { Self::RefundDetails(refund_payload) => Some(OutgoingWebhookEventContent::Refund {
payment_id: refund_payload.payment_id.clone(), payment_id: refund_payload.payment_id.clone(),
refund_id: refund_payload.refund_id.clone(), refund_id: refund_payload.get_refund_id_as_string(),
content: masking::masked_serialize(&refund_payload) content: masking::masked_serialize(&refund_payload)
.unwrap_or(serde_json::json!({"error":"failed to serialize"})), .unwrap_or(serde_json::json!({"error":"failed to serialize"})),
}), }),