Implement dynamic payment session
This commit is contained in:
parent
30d0baebc1
commit
5801dbea2d
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -4604,6 +4604,7 @@ name = "stripe_adapter"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"derive_more",
|
||||||
"fulfillment_adapter",
|
"fulfillment_adapter",
|
||||||
"payment_adapter",
|
"payment_adapter",
|
||||||
"payup",
|
"payup",
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::DerefMut;
|
|
||||||
|
|
||||||
pub use config::PaymentProviderConfig;
|
pub use config::PaymentProviderConfig;
|
||||||
pub use model::v3::*;
|
pub use model::v3::*;
|
||||||
@ -32,14 +31,13 @@ pub struct UpdateRequests {
|
|||||||
pub customer_metadata: Option<CustomerMetadata>,
|
pub customer_metadata: Option<CustomerMetadata>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PaymentSessionData {
|
pub trait PaymentSessionData: Send + Sync {
|
||||||
pub id: Option<String>,
|
fn id(&self) -> Option<String>;
|
||||||
pub meta: HashMap<String, AnyData>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PaymentProcessorSessionResponse {
|
pub struct PaymentProcessorSessionResponse {
|
||||||
pub update_requests: Option<UpdateRequests>,
|
pub update_requests: Option<UpdateRequests>,
|
||||||
pub session_data: PaymentSessionData,
|
pub session_data: Box<dyn PaymentSessionData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PaymentProcessorContext {
|
pub struct PaymentProcessorContext {
|
||||||
@ -50,7 +48,7 @@ pub struct PaymentProcessorContext {
|
|||||||
pub resource_id: String,
|
pub resource_id: String,
|
||||||
pub customer: Option<Customer>,
|
pub customer: Option<Customer>,
|
||||||
pub context: PaymentProcessCtx,
|
pub context: PaymentProcessCtx,
|
||||||
pub payment_session_data: PaymentSessionData,
|
pub payment_session_data: Box<dyn PaymentSessionData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
@ -129,6 +127,8 @@ pub enum PError {
|
|||||||
ChargeNotExists(String),
|
ChargeNotExists(String),
|
||||||
#[error("Failed capture charge with id {0:?}")]
|
#[error("Failed capture charge with id {0:?}")]
|
||||||
FailedCapture(String),
|
FailedCapture(String),
|
||||||
|
#[error("Invalid charge for given payment adapter")]
|
||||||
|
InvalidType,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PResult<T> = Result<T, PError>;
|
pub type PResult<T> = Result<T, PError>;
|
||||||
@ -166,82 +166,68 @@ pub trait PaymentAdapter {
|
|||||||
*/
|
*/
|
||||||
async fn refund_payment(
|
async fn refund_payment(
|
||||||
&mut self,
|
&mut self,
|
||||||
payment_session_data: PaymentSessionData,
|
payment_session_data: &mut Box<dyn PaymentSessionData>,
|
||||||
refund_amount: Amount,
|
refund_amount: Amount,
|
||||||
) -> PResult<PaymentSessionData>;
|
) -> PResult<()>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authorize an existing session if it is not already authorized
|
* Authorize an existing session if it is not already authorized
|
||||||
*/
|
*/
|
||||||
async fn authorize_payment(
|
async fn authorize_payment(
|
||||||
&mut self,
|
&mut self,
|
||||||
payment_session_data: PaymentSessionData,
|
payment_session_data: &mut Box<dyn PaymentSessionData>,
|
||||||
data: PaymentProcessCtx,
|
data: PaymentProcessCtx,
|
||||||
) -> PResult<(PaymentSessionStatus, PaymentSessionData)>;
|
) -> PResult<(PaymentSessionStatus, ())>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Capture an existing session
|
* Capture an existing session
|
||||||
*/
|
*/
|
||||||
async fn capture_payment(
|
async fn capture_payment(
|
||||||
&mut self,
|
&mut self,
|
||||||
payment_session_data: PaymentSessionData,
|
payment_session_data: &mut Box<dyn PaymentSessionData>,
|
||||||
) -> PResult<PaymentSessionData>;
|
) -> PResult<()>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete an existing session
|
* Delete an existing session
|
||||||
*/
|
*/
|
||||||
async fn delete_payment(
|
async fn delete_payment(
|
||||||
&mut self,
|
&mut self,
|
||||||
payment_session_data: PaymentSessionData,
|
payment_session_data: &mut Box<dyn PaymentSessionData>,
|
||||||
) -> PResult<PaymentSessionData>;
|
) -> PResult<()>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve an existing session
|
* Retrieve an existing session
|
||||||
*/
|
*/
|
||||||
async fn retrieve_payment(
|
async fn retrieve_payment(
|
||||||
&mut self,
|
&mut self,
|
||||||
payment_session_data: PaymentSessionData,
|
payment_session_data: &mut Box<dyn PaymentSessionData>,
|
||||||
) -> PResult<PaymentSessionData>;
|
) -> PResult<()>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel an existing session
|
* Cancel an existing session
|
||||||
*/
|
*/
|
||||||
async fn cancel_payment(
|
async fn cancel_payment(
|
||||||
&mut self,
|
&mut self,
|
||||||
payment_session_data: PaymentSessionData,
|
payment_session_data: &mut Box<dyn PaymentSessionData>,
|
||||||
) -> PResult<PaymentSessionData>;
|
) -> PResult<()>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the status of the session
|
* Return the status of the session
|
||||||
*/
|
*/
|
||||||
async fn payment_status(
|
async fn payment_status(
|
||||||
&mut self,
|
&mut self,
|
||||||
payment_session_data: &PaymentSessionData,
|
payment_session_data: &mut Box<dyn PaymentSessionData>,
|
||||||
) -> PResult<PaymentSessionStatus>;
|
) -> PResult<PaymentSessionStatus>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// use traitcast::{Traitcast, TraitcastFrom};
|
pub fn session_ref<T: PaymentSessionData + Any>(
|
||||||
|
session: &Box<dyn PaymentSessionData>,
|
||||||
pub trait APaymentSessionData: Any {
|
) -> Option<&T> {
|
||||||
fn id(&self) -> Option<String>;
|
<dyn Any>::downcast_ref(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BPSD(Box<dyn APaymentSessionData>);
|
pub fn session_mut_ref<T: PaymentSessionData + Any>(
|
||||||
|
session: &mut Box<dyn PaymentSessionData>,
|
||||||
impl BPSD {
|
) -> Option<&mut T> {
|
||||||
pub fn as_mut_ref<T>(&mut self) -> Option<&mut T> {
|
<dyn Any>::downcast_mut(session)
|
||||||
use std::boxed::Box;
|
|
||||||
|
|
||||||
let r = self.0.deref_mut();
|
|
||||||
if <dyn Any>::is::<&T>(r) {
|
|
||||||
Some(unsafe { r as &mut T })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn f(mut psd: &mut BPSD) {
|
|
||||||
use std::boxed::Box;
|
|
||||||
let c = psd.deref_mut();
|
|
||||||
}
|
}
|
||||||
|
@ -17,3 +17,4 @@ payup = { version = "*", features = [] }
|
|||||||
tracing = { version = "0.1.37" }
|
tracing = { version = "0.1.37" }
|
||||||
async-trait = { version = "0.1.68" }
|
async-trait = { version = "0.1.68" }
|
||||||
serde = { version = "1.0.162", features = ['derive'] }
|
serde = { version = "1.0.162", features = ['derive'] }
|
||||||
|
derive_more = { version = "0.99.17" }
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#![crate_type = "rlib"]
|
#![crate_type = "rlib"]
|
||||||
|
|
||||||
use std::any::Any;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
|
use derive_more::DerefMut;
|
||||||
use fulfillment_adapter::*;
|
use fulfillment_adapter::*;
|
||||||
use payment_adapter::*;
|
use payment_adapter::*;
|
||||||
use payup::stripe;
|
use payup::stripe;
|
||||||
@ -105,7 +105,7 @@ impl PaymentAdapter for StripePrzelewy24 {
|
|||||||
captured: self.config.capture.clone(),
|
captured: self.config.capture.clone(),
|
||||||
currency: Some(currency_code.into()),
|
currency: Some(currency_code.into()),
|
||||||
description: desc,
|
description: desc,
|
||||||
customer: customer.map(|c| c.id.0.to_string()),
|
customer: customer.as_ref().map(|c| c.id.0.to_string()),
|
||||||
receipt_email: Some(email.0),
|
receipt_email: Some(email.0),
|
||||||
..stripe::Charge::new()
|
..stripe::Charge::new()
|
||||||
}
|
}
|
||||||
@ -113,11 +113,11 @@ impl PaymentAdapter for StripePrzelewy24 {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let update_requests = match customer {
|
let update_requests = match customer.as_ref() {
|
||||||
Some(c) if !c.has_stripe_id() => Some(UpdateRequests {
|
Some(c) if !c.has_stripe_id() => Some(UpdateRequests {
|
||||||
customer_metadata: Some(CustomerMetadata(HashMap::from([(
|
customer_metadata: Some(CustomerMetadata(HashMap::from([(
|
||||||
"id".to_string(),
|
"id".to_string(),
|
||||||
AnyData(change.customer.unwrap_or_default().into_bytes()),
|
AnyData(change.customer.clone().unwrap_or_default().into_bytes()),
|
||||||
)]))),
|
)]))),
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -125,7 +125,7 @@ impl PaymentAdapter for StripePrzelewy24 {
|
|||||||
|
|
||||||
Ok(PaymentProcessorSessionResponse {
|
Ok(PaymentProcessorSessionResponse {
|
||||||
update_requests,
|
update_requests,
|
||||||
session_data: payment_session_data,
|
session_data: Box::new(Charge(change)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,30 +138,30 @@ impl PaymentAdapter for StripePrzelewy24 {
|
|||||||
|
|
||||||
async fn refund_payment(
|
async fn refund_payment(
|
||||||
&mut self,
|
&mut self,
|
||||||
payment_session_data: PaymentSessionData,
|
payment_session_data: &mut Box<dyn PaymentSessionData>,
|
||||||
refund_amount: Amount,
|
refund_amount: Amount,
|
||||||
) -> PResult<PaymentSessionData> {
|
) -> PResult<()> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn authorize_payment(
|
async fn authorize_payment(
|
||||||
&mut self,
|
&mut self,
|
||||||
payment_session_data: PaymentSessionData,
|
payment_session_data: &mut Box<dyn PaymentSessionData>,
|
||||||
data: PaymentProcessCtx,
|
data: PaymentProcessCtx,
|
||||||
) -> PResult<(PaymentSessionStatus, PaymentSessionData)> {
|
) -> PResult<(PaymentSessionStatus, ())> {
|
||||||
self.payment_status(&payment_session_data)
|
self.payment_status(payment_session_data)
|
||||||
.await
|
.await
|
||||||
.map(|status| (status, payment_session_data))
|
.map(|status| (status, ()))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn capture_payment(
|
async fn capture_payment(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut payment_session_data: PaymentSessionData,
|
payment_session_data: &mut Box<dyn PaymentSessionData>,
|
||||||
) -> PResult<PaymentSessionData> {
|
) -> PResult<()> {
|
||||||
let id = payment_session_data
|
let Some(session) = session_mut_ref::<Charge>(payment_session_data) else {
|
||||||
.id
|
return Err(PError::InvalidType);
|
||||||
.clone()
|
};
|
||||||
.ok_or_else(|| PError::NoChargeId)?;
|
let id = session.id().ok_or_else(|| PError::NoChargeId)?;
|
||||||
let charge = stripe::Charge::async_get(self.stripe.clone(), id.clone())
|
let charge = stripe::Charge::async_get(self.stripe.clone(), id.clone())
|
||||||
.await
|
.await
|
||||||
.map_err(|_| PError::ChargeNotExists(id.clone()))?;
|
.map_err(|_| PError::ChargeNotExists(id.clone()))?;
|
||||||
@ -172,38 +172,40 @@ impl PaymentAdapter for StripePrzelewy24 {
|
|||||||
tracing::warn!("{e}");
|
tracing::warn!("{e}");
|
||||||
PError::FailedCapture(id)
|
PError::FailedCapture(id)
|
||||||
})?;
|
})?;
|
||||||
payment_session_data.id = charge.id;
|
session.0 = change;
|
||||||
Ok(payment_session_data)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete_payment(
|
async fn delete_payment(
|
||||||
&mut self,
|
&mut self,
|
||||||
payment_session_data: PaymentSessionData,
|
payment_session_data: &mut Box<dyn PaymentSessionData>,
|
||||||
) -> PResult<PaymentSessionData> {
|
) -> PResult<()> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn retrieve_payment(
|
async fn retrieve_payment(
|
||||||
&mut self,
|
&mut self,
|
||||||
payment_session_data: PaymentSessionData,
|
payment_session_data: &mut Box<dyn PaymentSessionData>,
|
||||||
) -> PResult<PaymentSessionData> {
|
) -> PResult<()> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn cancel_payment(
|
async fn cancel_payment(
|
||||||
&mut self,
|
&mut self,
|
||||||
payment_session_data: PaymentSessionData,
|
payment_session_data: &mut Box<dyn PaymentSessionData>,
|
||||||
) -> PResult<PaymentSessionData> {
|
) -> PResult<()> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn payment_status(
|
async fn payment_status(
|
||||||
&mut self,
|
&mut self,
|
||||||
payment_session_data: &PaymentSessionData,
|
payment_session_data: &mut Box<dyn PaymentSessionData>,
|
||||||
) -> PResult<PaymentSessionStatus> {
|
) -> PResult<PaymentSessionStatus> {
|
||||||
payment_status(
|
payment_status(
|
||||||
self.stripe.clone(),
|
self.stripe.clone(),
|
||||||
payment_session_data.id.clone().unwrap_or_default(),
|
payment_session_data
|
||||||
|
.id()
|
||||||
|
.ok_or_else(|| PError::NoChargeId)?,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| PError::HttpError)
|
.map_err(|_| PError::HttpError)
|
||||||
@ -240,3 +242,12 @@ impl StripeCustomerMetadata for Customer {
|
|||||||
.and_then(|v| String::from_utf8(v.clone()).ok())
|
.and_then(|v| String::from_utf8(v.clone()).ok())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, derive_more::Deref, derive_more::DerefMut)]
|
||||||
|
struct Charge(stripe::Charge);
|
||||||
|
|
||||||
|
impl PaymentSessionData for Charge {
|
||||||
|
fn id(&self) -> Option<String> {
|
||||||
|
self.0.id.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user