mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 11:24:45 +08:00
feat(router): add api_models and openapi changes for refunds create api v2 (#6385)
This commit is contained in:
committed by
GitHub
parent
4ef48c39b3
commit
5a10e5867a
@ -0,0 +1,3 @@
|
||||
---
|
||||
openapi: post /v2/refunds
|
||||
---
|
||||
@ -107,6 +107,12 @@
|
||||
"api-reference/customers/customers--delete",
|
||||
"api-reference/customers/customers--list"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Refunds",
|
||||
"pages": [
|
||||
"api-reference/refunds/refunds--create"
|
||||
]
|
||||
}
|
||||
],
|
||||
"footerSocials": {
|
||||
|
||||
@ -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": {
|
||||
@ -18108,6 +18174,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"RefundErrorDetails": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"code",
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"RefundListRequest": {
|
||||
"allOf": [
|
||||
{
|
||||
@ -18298,89 +18379,89 @@
|
||||
"RefundResponse": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"refund_id",
|
||||
"id",
|
||||
"payment_id",
|
||||
"amount",
|
||||
"currency",
|
||||
"status",
|
||||
"connector"
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"connector",
|
||||
"profile_id",
|
||||
"merchant_connector_id"
|
||||
],
|
||||
"properties": {
|
||||
"refund_id": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique Identifier for the refund"
|
||||
"description": "Global Refund Id for the refund"
|
||||
},
|
||||
"payment_id": {
|
||||
"type": "string",
|
||||
"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": {
|
||||
"type": "integer",
|
||||
"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,
|
||||
"minimum": 100
|
||||
},
|
||||
"currency": {
|
||||
"type": "string",
|
||||
"description": "The three-letter ISO currency code"
|
||||
"$ref": "#/components/schemas/Currency"
|
||||
},
|
||||
"status": {
|
||||
"$ref": "#/components/schemas/RefundStatus"
|
||||
},
|
||||
"reason": {
|
||||
"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
|
||||
},
|
||||
"metadata": {
|
||||
"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
|
||||
},
|
||||
"error_message": {
|
||||
"type": "string",
|
||||
"description": "The error message",
|
||||
"nullable": true
|
||||
},
|
||||
"error_code": {
|
||||
"type": "string",
|
||||
"description": "The code for the error",
|
||||
"error_details": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/RefundErrorDetails"
|
||||
}
|
||||
],
|
||||
"nullable": true
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "The timestamp at which refund is created",
|
||||
"nullable": true
|
||||
"description": "The timestamp at which refund is created"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "The timestamp at which refund is updated",
|
||||
"nullable": true
|
||||
"description": "The timestamp at which refund is updated"
|
||||
},
|
||||
"connector": {
|
||||
"type": "string",
|
||||
"description": "The connector used for the refund and the corresponding payment",
|
||||
"example": "stripe"
|
||||
"$ref": "#/components/schemas/Connector"
|
||||
},
|
||||
"profile_id": {
|
||||
"type": "string",
|
||||
"description": "The id of business profile for this refund",
|
||||
"nullable": true
|
||||
"description": "The id of business profile for this refund"
|
||||
},
|
||||
"merchant_connector_id": {
|
||||
"type": "string",
|
||||
"description": "The merchant_connector_id of the processor through which this payment went through",
|
||||
"nullable": true
|
||||
"description": "The merchant_connector_id of the processor through which this payment went through"
|
||||
},
|
||||
"charges": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ChargeRefunds"
|
||||
}
|
||||
],
|
||||
"connector_refund_reference_id": {
|
||||
"type": "string",
|
||||
"description": "The reference id of the connector for the refund",
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
@ -18421,6 +18502,59 @@
|
||||
},
|
||||
"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": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
||||
@ -6,6 +6,7 @@ use crate::refunds::{
|
||||
RefundUpdateRequest, RefundsRetrieveRequest,
|
||||
};
|
||||
|
||||
#[cfg(feature = "v1")]
|
||||
impl ApiEventMetric for RefundRequest {
|
||||
fn get_api_event_type(&self) -> Option<ApiEventsType> {
|
||||
let payment_id = self.payment_id.clone();
|
||||
@ -18,6 +19,7 @@ impl ApiEventMetric for RefundRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "v1")]
|
||||
impl ApiEventMetric for RefundResponse {
|
||||
fn get_api_event_type(&self) -> Option<ApiEventsType> {
|
||||
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 {
|
||||
fn get_api_event_type(&self) -> Option<ApiEventsType> {
|
||||
Some(ApiEventsType::Refund {
|
||||
@ -36,6 +49,7 @@ impl ApiEventMetric for RefundsRetrieveRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "v1")]
|
||||
impl ApiEventMetric for RefundUpdateRequest {
|
||||
fn get_api_event_type(&self) -> Option<ApiEventsType> {
|
||||
Some(ApiEventsType::Refund {
|
||||
@ -45,6 +59,7 @@ impl ApiEventMetric for RefundUpdateRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "v1")]
|
||||
impl ApiEventMetric for RefundManualUpdateRequest {
|
||||
fn get_api_event_type(&self) -> Option<ApiEventsType> {
|
||||
Some(ApiEventsType::Refund {
|
||||
|
||||
@ -61,6 +61,45 @@ pub struct RefundRequest {
|
||||
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)]
|
||||
pub struct RefundsRetrieveBody {
|
||||
pub force_sync: Option<bool>,
|
||||
@ -125,6 +164,7 @@ pub enum RefundType {
|
||||
Instant,
|
||||
}
|
||||
|
||||
#[cfg(feature = "v1")]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, ToSchema)]
|
||||
pub struct RefundResponse {
|
||||
/// Unique Identifier for the refund
|
||||
@ -168,6 +208,78 @@ pub struct RefundResponse {
|
||||
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)]
|
||||
pub struct RefundListRequest {
|
||||
/// The identifier for the payment
|
||||
|
||||
@ -23,10 +23,16 @@ pub enum ApiEventsType {
|
||||
Payment {
|
||||
payment_id: id_type::GlobalPaymentId,
|
||||
},
|
||||
#[cfg(feature = "v1")]
|
||||
Refund {
|
||||
payment_id: Option<id_type::PaymentId>,
|
||||
refund_id: String,
|
||||
},
|
||||
#[cfg(feature = "v2")]
|
||||
Refund {
|
||||
payment_id: id_type::GlobalPaymentId,
|
||||
refund_id: id_type::GlobalRefundId,
|
||||
},
|
||||
PaymentMethod {
|
||||
payment_method_id: String,
|
||||
payment_method: Option<PaymentMethod>,
|
||||
|
||||
@ -10,6 +10,7 @@ mod merchant_connector_account;
|
||||
mod organization;
|
||||
mod payment;
|
||||
mod profile;
|
||||
mod refunds;
|
||||
mod routing;
|
||||
|
||||
#[cfg(feature = "v2")]
|
||||
@ -25,12 +26,16 @@ use diesel::{
|
||||
sql_types,
|
||||
};
|
||||
#[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_connector_account::MerchantConnectorAccountId;
|
||||
pub use organization::OrganizationId;
|
||||
pub use payment::{PaymentId, PaymentReferenceId};
|
||||
pub use profile::ProfileId;
|
||||
pub use refunds::RefundReferenceId;
|
||||
pub use routing::RoutingId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#![allow(unused)]
|
||||
pub mod payment;
|
||||
pub mod payment_methods;
|
||||
pub mod refunds;
|
||||
|
||||
use diesel::{backend::Backend, deserialize::FromSql, serialize::ToSql, sql_types};
|
||||
use error_stack::ResultExt;
|
||||
@ -24,6 +25,7 @@ pub(crate) enum GlobalEntity {
|
||||
Customer,
|
||||
Payment,
|
||||
PaymentMethod,
|
||||
Refund,
|
||||
}
|
||||
|
||||
impl GlobalEntity {
|
||||
@ -32,6 +34,7 @@ impl GlobalEntity {
|
||||
Self::Customer => "cus",
|
||||
Self::Payment => "pay",
|
||||
Self::PaymentMethod => "pm",
|
||||
Self::Refund => "ref",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
71
crates/common_utils/src/id_type/global_id/refunds.rs
Normal file
71
crates/common_utils/src/id_type/global_id/refunds.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
10
crates/common_utils/src/id_type/refunds.rs
Normal file
10
crates/common_utils/src/id_type/refunds.rs
Normal 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);
|
||||
@ -10,8 +10,8 @@ license.workspace = true
|
||||
[features]
|
||||
default = ["kv_store"]
|
||||
kv_store = []
|
||||
v1 = []
|
||||
v2 = []
|
||||
v1 = ["common_utils/v1"]
|
||||
v2 = ["common_utils/v2"]
|
||||
customer_v2 = []
|
||||
payment_methods_v2 = []
|
||||
|
||||
|
||||
@ -317,6 +317,7 @@ pub struct RefundCoreWorkflow {
|
||||
pub connector_transaction_data: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "v1")]
|
||||
impl common_utils::events::ApiEventMetric for Refund {
|
||||
fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
|
||||
Some(common_utils::events::ApiEventsType::Refund {
|
||||
|
||||
@ -123,6 +123,9 @@ Never share your secret api keys. Keep them guarded and secure.
|
||||
|
||||
//Routes for payments
|
||||
routes::payments::payments_create_intent,
|
||||
|
||||
//Routes for refunds
|
||||
routes::refunds::refunds_create,
|
||||
),
|
||||
components(schemas(
|
||||
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::VenmoAdditionalData,
|
||||
api_models::refunds::RefundRequest,
|
||||
api_models::refunds::RefundsCreateRequest,
|
||||
api_models::refunds::RefundErrorDetails,
|
||||
api_models::refunds::RefundType,
|
||||
api_models::refunds::RefundResponse,
|
||||
api_models::refunds::RefundStatus,
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
operation_id = "Create a Refund",
|
||||
security(("api_key" = []))
|
||||
)]
|
||||
#[cfg(feature = "v1")]
|
||||
pub async fn refunds_create() {}
|
||||
|
||||
/// Refunds - Retrieve
|
||||
@ -159,3 +160,55 @@ pub fn refunds_list_profile() {}
|
||||
security(("api_key" = []))
|
||||
)]
|
||||
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() {}
|
||||
|
||||
@ -34,11 +34,18 @@ pub enum OutgoingWebhookEventContent {
|
||||
payout_id: String,
|
||||
content: Value,
|
||||
},
|
||||
#[cfg(feature = "v1")]
|
||||
Refund {
|
||||
payment_id: common_utils::id_type::PaymentId,
|
||||
refund_id: String,
|
||||
content: Value,
|
||||
},
|
||||
#[cfg(feature = "v2")]
|
||||
Refund {
|
||||
payment_id: common_utils::id_type::GlobalPaymentId,
|
||||
refund_id: String,
|
||||
content: Value,
|
||||
},
|
||||
Dispute {
|
||||
payment_id: common_utils::id_type::PaymentId,
|
||||
attempt_id: String,
|
||||
@ -64,7 +71,7 @@ impl OutgoingWebhookEventMetric for OutgoingWebhookContent {
|
||||
}),
|
||||
Self::RefundDetails(refund_payload) => Some(OutgoingWebhookEventContent::Refund {
|
||||
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)
|
||||
.unwrap_or(serde_json::json!({"error":"failed to serialize"})),
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user