Medusa
This commit is contained in:
parent
8e1f9625d1
commit
30d0baebc1
74
Cargo.lock
generated
74
Cargo.lock
generated
@ -336,6 +336,12 @@ version = "1.0.71"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anymap"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "argon2"
|
name = "argon2"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@ -1101,6 +1107,16 @@ dependencies = [
|
|||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ctor"
|
||||||
|
version = "0.1.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxx"
|
name = "cxx"
|
||||||
version = "1.0.94"
|
version = "1.0.94"
|
||||||
@ -1791,6 +1807,17 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ghost"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e77ac7b51b8e6313251737fcef4b1c01a2ea102bde68415b62c0ee9268fec357"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.15",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.26.2"
|
version = "0.26.2"
|
||||||
@ -2293,6 +2320,28 @@ dependencies = [
|
|||||||
"unic-langid",
|
"unic-langid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inventory"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0eb5160c60ba1e809707918ee329adb99d222888155835c6feedba19f6c3fd4"
|
||||||
|
dependencies = [
|
||||||
|
"ctor",
|
||||||
|
"ghost",
|
||||||
|
"inventory-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inventory-impl"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7e41b53715c6f0c4be49510bb82dee2c1e51c8586d885abe65396e82ed518548"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-extras"
|
name = "io-extras"
|
||||||
version = "0.15.0"
|
version = "0.15.0"
|
||||||
@ -3184,12 +3233,15 @@ name = "payment_adapter"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"chrono",
|
||||||
"config",
|
"config",
|
||||||
"futures",
|
"futures",
|
||||||
"model",
|
"model",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"toml 0.7.3",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"traitcast",
|
||||||
"uuid 1.3.2",
|
"uuid 1.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4555,6 +4607,7 @@ dependencies = [
|
|||||||
"fulfillment_adapter",
|
"fulfillment_adapter",
|
||||||
"payment_adapter",
|
"payment_adapter",
|
||||||
"payup",
|
"payup",
|
||||||
|
"serde",
|
||||||
"tokio 1.28.0",
|
"tokio 1.28.0",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@ -5170,6 +5223,27 @@ dependencies = [
|
|||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "traitcast"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f80b1cde694e5ff2dcb33875530f2f031a9a34dec8ba2744cacaf80a88658740"
|
||||||
|
dependencies = [
|
||||||
|
"inventory",
|
||||||
|
"lazy_static",
|
||||||
|
"traitcast_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "traitcast_core"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aabba8f4a83963f61a84d8cfc5829b4fad692aa6c6ad5d7b08b9549777e3cc4a"
|
||||||
|
dependencies = [
|
||||||
|
"anymap",
|
||||||
|
"inventory",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "trust-dns-native-tls"
|
name = "trust-dns-native-tls"
|
||||||
version = "0.20.4"
|
version = "0.20.4"
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum FError {
|
pub enum FError {
|
||||||
|
#[error("Payment gate request failed")]
|
||||||
HttpError,
|
HttpError,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9,6 +11,7 @@ pub struct FulfillmentOption {}
|
|||||||
pub trait FulfillmentPayload {}
|
pub trait FulfillmentPayload {}
|
||||||
pub trait FulfillmentCart {}
|
pub trait FulfillmentCart {}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
pub trait FulfillmentAdapter {
|
pub trait FulfillmentAdapter {
|
||||||
fn identifier() -> &'static str;
|
fn identifier() -> &'static str;
|
||||||
|
|
||||||
@ -22,7 +25,7 @@ pub trait FulfillmentAdapter {
|
|||||||
* to create shipping options in Medusa that can be chosen between by
|
* to create shipping options in Medusa that can be chosen between by
|
||||||
* the customer.
|
* the customer.
|
||||||
*/
|
*/
|
||||||
fn fulfillment_options(&mut self) -> FResult<&[FulfillmentOption]>;
|
async fn fulfillment_options(&mut self) -> FResult<Vec<FulfillmentOption>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called before a shipping method is set on a cart to ensure that the
|
* Called before a shipping method is set on a cart to ensure that the
|
||||||
@ -31,7 +34,7 @@ pub trait FulfillmentAdapter {
|
|||||||
* point. It is up to the fulfillment provider to enforce that the
|
* point. It is up to the fulfillment provider to enforce that the
|
||||||
* correct data is being sent through.
|
* correct data is being sent through.
|
||||||
*/
|
*/
|
||||||
fn validate_fulfillment_payload<P: FulfillmentPayload, C: FulfillmentCart>(
|
async fn validate_fulfillment_payload<P: FulfillmentPayload, C: FulfillmentCart>(
|
||||||
&mut self,
|
&mut self,
|
||||||
payload: P,
|
payload: P,
|
||||||
cart: C,
|
cart: C,
|
||||||
@ -41,33 +44,35 @@ pub trait FulfillmentAdapter {
|
|||||||
* Called before a shipping option is created in Admin. Use this to
|
* Called before a shipping option is created in Admin. Use this to
|
||||||
* ensure that a fulfillment option does in fact exist.
|
* ensure that a fulfillment option does in fact exist.
|
||||||
*/
|
*/
|
||||||
fn validate_option<P: FulfillmentPayload>(&mut self, payload: P) -> FResult<bool>;
|
async fn validate_option<P: FulfillmentPayload>(&mut self, payload: P) -> FResult<bool>;
|
||||||
|
|
||||||
fn can_calculate<P: FulfillmentPayload>(&mut self, payload: P) -> FResult<bool>;
|
async fn can_calculate<P: FulfillmentPayload>(&mut self, payload: P) -> FResult<bool>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to calculate a price for a given shipping option.
|
* Used to calculate a price for a given shipping option.
|
||||||
*/
|
*/
|
||||||
fn calculate_price<P: FulfillmentPayload, C: FulfillmentCart>(data: P, cart: C)
|
async fn calculate_price<P: FulfillmentPayload, C: FulfillmentCart>(
|
||||||
-> FResult<u64>;
|
data: P,
|
||||||
|
cart: C,
|
||||||
|
) -> FResult<u64>;
|
||||||
|
|
||||||
// FULFILLMENT
|
// FULFILLMENT
|
||||||
fn create_fulfillment(&mut self);
|
async fn create_fulfillment(&mut self);
|
||||||
|
|
||||||
fn cancel_fulfillment(&mut self);
|
async fn cancel_fulfillment(&mut self);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to retrieve documents associated with a fulfillment.
|
* Used to retrieve documents associated with a fulfillment.
|
||||||
* Will default to returning no documents.
|
* Will default to returning no documents.
|
||||||
*/
|
*/
|
||||||
fn fulfillment_documents(&mut self);
|
async fn fulfillment_documents(&mut self);
|
||||||
|
|
||||||
// REFUND
|
// REFUND
|
||||||
fn create_return(&mut self);
|
async fn create_return(&mut self);
|
||||||
|
|
||||||
fn return_documents(&mut self);
|
async fn return_documents(&mut self);
|
||||||
|
|
||||||
//
|
//
|
||||||
fn shipment_documents(&mut self);
|
async fn shipment_documents(&mut self);
|
||||||
fn documents(&mut self);
|
async fn documents(&mut self);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
pub mod api;
|
pub mod api;
|
||||||
|
|
||||||
pub mod encrypt;
|
pub mod encrypt;
|
||||||
|
pub mod v3;
|
||||||
|
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::ops;
|
use std::ops;
|
||||||
|
4031
crates/model/src/v3.rs
Normal file
4031
crates/model/src/v3.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -58,35 +58,72 @@ impl PayUPayment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PaymentAdapter for PayUPayment {
|
impl PaymentAdapter for PayUPayment {
|
||||||
fn init(&mut self) -> PResult<Status> {
|
async fn new(config: Config) -> Self {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn teardown(&mut self) -> PResult<Status> {
|
async fn initialize_payment(
|
||||||
|
&mut self,
|
||||||
|
ctx: PaymentProcessorContext,
|
||||||
|
) -> PResult<PaymentProcessorSessionResponse> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_payment(&mut self, msg: CreatePayment) -> PResult<PaymentCreated> {
|
async fn update_payment(
|
||||||
|
&mut self,
|
||||||
|
ctx: PaymentProcessorContext,
|
||||||
|
) -> PResult<Option<PaymentProcessorSessionResponse>> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retrieve_payment(&mut self) {
|
async fn refund_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
refund_amount: Amount,
|
||||||
|
) -> PResult<PaymentSessionData> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn authorize_payment(&mut self) {
|
async fn authorize_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
data: PaymentProcessCtx,
|
||||||
|
) -> PResult<(PaymentSessionStatus, PaymentSessionData)> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn capture_payment(&mut self) {
|
async fn capture_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
) -> PResult<PaymentSessionData> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn refund_payment(&mut self, msg: RefundPayment) -> PResult<Refunded> {
|
async fn delete_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
) -> PResult<PaymentSessionData> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_payment(&mut self, msg: DeletePayment) -> PResult<Deleted> {
|
async fn retrieve_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
) -> PResult<PaymentSessionData> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn cancel_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
) -> PResult<PaymentSessionData> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn payment_status(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: &PaymentSessionData,
|
||||||
|
) -> PResult<PaymentSessionStatus> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,3 +12,6 @@ thiserror = { version = "1" }
|
|||||||
tracing = { version = "0" }
|
tracing = { version = "0" }
|
||||||
uuid = { version = "1", features = ['v4'] }
|
uuid = { version = "1", features = ['v4'] }
|
||||||
async-trait = { version = "0.1.68" }
|
async-trait = { version = "0.1.68" }
|
||||||
|
chrono = { version = "0.4.24" }
|
||||||
|
toml = { version = "0.7.3" }
|
||||||
|
traitcast = { version = "0.5.0" }
|
||||||
|
@ -1,29 +1,13 @@
|
|||||||
|
#![feature(trait_upcasting)]
|
||||||
|
|
||||||
|
use std::any::Any;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
pub use config::PaymentProviderConfig;
|
pub use config::PaymentProviderConfig;
|
||||||
pub use model::*;
|
pub use model::v3::*;
|
||||||
pub use uuid;
|
pub use uuid;
|
||||||
|
use uuid::Uuid;
|
||||||
pub const CONFIG_POS: u32 = 3;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, thiserror::Error, serde::Serialize, serde::Deserialize)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub enum Error {
|
|
||||||
#[error("Malformed create payment message")]
|
|
||||||
MalformedCreatePayment,
|
|
||||||
#[error("Malformed payment status update message")]
|
|
||||||
MalformedStatusUpdate,
|
|
||||||
#[error("Malformed authorize response")]
|
|
||||||
MalformedAuthorize,
|
|
||||||
#[error("Message pack: malformed create payment message")]
|
|
||||||
MsgPackDeserializationFailed,
|
|
||||||
#[error("Provider rejected authorization")]
|
|
||||||
AuthorizeFailed,
|
|
||||||
#[error("Provider rejected order")]
|
|
||||||
PaymentFailed,
|
|
||||||
#[error("HTTP request failed")]
|
|
||||||
HttpFailed,
|
|
||||||
#[error("Unknown host operation {0:?}")]
|
|
||||||
UnknownOperation(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@ -32,59 +16,99 @@ pub enum Status {
|
|||||||
Failure = 1,
|
Failure = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
pub struct AnyData(pub Vec<u8>);
|
||||||
#[repr(C)]
|
|
||||||
pub struct Buyer {
|
pub struct PaymentProcessorError {
|
||||||
/// Required customer e-mail
|
pub error: String,
|
||||||
pub email: String,
|
pub code: Option<String>,
|
||||||
/// Required customer phone number
|
pub detail: Option<AnyData>,
|
||||||
pub phone: String,
|
|
||||||
/// Required customer first name
|
|
||||||
pub first_name: String,
|
|
||||||
/// Required customer last name
|
|
||||||
pub last_name: String,
|
|
||||||
/// Required customer language
|
|
||||||
pub language: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
pub struct CustomerMetadata(pub HashMap<String, AnyData>);
|
||||||
#[repr(C)]
|
|
||||||
pub struct Product {
|
pub struct PaymentProcessCtx(pub HashMap<String, AnyData>);
|
||||||
pub id: i32,
|
|
||||||
pub name: String,
|
pub struct UpdateRequests {
|
||||||
pub unit_price: i32,
|
pub customer_metadata: Option<CustomerMetadata>,
|
||||||
pub quantity_unit: String,
|
|
||||||
pub quantity: i32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
pub struct PaymentSessionData {
|
||||||
#[repr(C)]
|
pub id: Option<String>,
|
||||||
pub struct Item {
|
pub meta: HashMap<String, AnyData>,
|
||||||
pub product_id: i32,
|
|
||||||
pub quantity: i32,
|
|
||||||
pub quantity_unit: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
pub struct PaymentProcessorSessionResponse {
|
||||||
|
pub update_requests: Option<UpdateRequests>,
|
||||||
|
pub session_data: PaymentSessionData,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PaymentProcessorContext {
|
||||||
|
pub billing_address: Option<Address>,
|
||||||
|
pub email: Email,
|
||||||
|
pub currency_code: CurrencyCode,
|
||||||
|
pub amount: Amount,
|
||||||
|
pub resource_id: String,
|
||||||
|
pub customer: Option<Customer>,
|
||||||
|
pub context: PaymentProcessCtx,
|
||||||
|
pub payment_session_data: PaymentSessionData,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct CreatePayment {
|
pub struct CreatePayment {
|
||||||
pub buyer: Buyer,
|
// pub buyer: Buyer,
|
||||||
pub customer_ip: String,
|
pub customer_ip: String,
|
||||||
pub currency: String,
|
pub currency: String,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub cart_products: Vec<Product>,
|
pub cart_products: Vec<Product>,
|
||||||
pub items: Vec<Item>,
|
pub items: Vec<LineItem>,
|
||||||
|
|
||||||
|
//
|
||||||
|
pub cart: Cart,
|
||||||
|
pub customer: Option<Customer>,
|
||||||
|
pub customer_groups: Option<CustomerGroup>,
|
||||||
|
pub gift_cards: Vec<GiftCard>,
|
||||||
|
pub region: Region,
|
||||||
|
pub related_discounts: HashMap<DiscountId, Discount>,
|
||||||
|
pub related_shipping_methods: HashMap<Uuid, ShippingMethod>,
|
||||||
|
// cart line items and [LineItem::original_item_id]
|
||||||
|
pub related_items: HashMap<Uuid, LineItem>,
|
||||||
|
/// [Payment::swap_id]
|
||||||
|
pub related_payments: HashMap<PaymentId, Payment>,
|
||||||
|
pub related_line_item_adjustments: HashMap<LineItemAdjustmentId, LineItemAdjustment>,
|
||||||
|
pub related_tax_lines: HashMap<Uuid, LineItemTaxLine>,
|
||||||
|
pub related_currencies: HashMap<CurrencyCode, Currency>,
|
||||||
|
/// [Return::swap_id]
|
||||||
|
pub related_returns: HashMap<ReturnId, Return>,
|
||||||
|
//
|
||||||
pub order_ext_id: Option<String>,
|
pub order_ext_id: Option<String>,
|
||||||
pub notify_uri: String,
|
pub notify_uri: String,
|
||||||
pub continue_uri: String,
|
pub continue_uri: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug)]
|
||||||
pub struct PaymentCreated {
|
pub struct PaymentCreated {
|
||||||
pub ext_order_id: Option<ExtOrderId>,
|
pub ext_order_id: Option<ExtOrderId>,
|
||||||
pub redirect_uri: Option<String>,
|
pub redirect_uri: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug)]
|
||||||
|
pub struct DeletePayment {
|
||||||
|
pub ext_order_id: Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Deleted {
|
||||||
|
pub ext_order_id: Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RefundPayment {
|
||||||
|
pub refund: RefundType,
|
||||||
|
pub provider_order_id: Uuid,
|
||||||
|
pub description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum RefundType {
|
pub enum RefundType {
|
||||||
/// Refund entire payment
|
/// Refund entire payment
|
||||||
Full,
|
Full,
|
||||||
@ -92,97 +116,132 @@ pub enum RefundType {
|
|||||||
Partial(Price),
|
Partial(Price),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug)]
|
||||||
pub struct RefundPayment {
|
|
||||||
pub refund: RefundType,
|
|
||||||
pub provider_order_id: String,
|
|
||||||
pub description: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub struct Refunded {}
|
pub struct Refunded {}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub struct UpdateStatus {
|
pub enum PError {
|
||||||
pub payload: Vec<u8>,
|
#[error("Payment gate request failed")]
|
||||||
|
HttpError,
|
||||||
|
#[error("Operation requires Charge id")]
|
||||||
|
NoChargeId,
|
||||||
|
#[error("There's no charge with id {0:?}")]
|
||||||
|
ChargeNotExists(String),
|
||||||
|
#[error("Failed capture charge with id {0:?}")]
|
||||||
|
FailedCapture(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub struct StatusUpdated {}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub struct DeletePayment {
|
|
||||||
pub ext_order_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub struct Deleted {
|
|
||||||
pub ext_order_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub enum HttpMethod {
|
|
||||||
Get,
|
|
||||||
Post,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum PaymentSessionStatus {
|
|
||||||
Pending,
|
|
||||||
RequiresMore,
|
|
||||||
Canceled,
|
|
||||||
Authorized,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct HttpRequest {
|
|
||||||
pub method: HttpMethod,
|
|
||||||
pub url: String,
|
|
||||||
pub headers: Vec<(String, String)>,
|
|
||||||
pub bearer_auth: Option<String>,
|
|
||||||
pub body: Option<Vec<u8>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod tracing {
|
|
||||||
macro_rules! log_levels {
|
|
||||||
($($lvl: ident),+) => {
|
|
||||||
$(
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! $lvl {
|
|
||||||
($fmt: expr) => {
|
|
||||||
wapc::console_log($fmt);
|
|
||||||
};
|
|
||||||
($fmt: expr, $arg1: expr) => {
|
|
||||||
wapc::console_log(&format!($fmt, $arg1));
|
|
||||||
};
|
|
||||||
($fmt: expr, $arg1: expr, $arg2: expr) => {
|
|
||||||
wapc::console_log(&format!($fmt, $arg1, $arg2));
|
|
||||||
};
|
|
||||||
($fmt: expr, $arg1: expr, $arg2: expr, $arg3: expr) => {
|
|
||||||
wapc::console_log(&format!($fmt, $arg1, $arg2, $arg3));
|
|
||||||
};
|
|
||||||
($fmt: expr, $arg1: expr, $arg2: expr, $arg3: expr, $arg4: expr) => {
|
|
||||||
wapc::console_log(&format!($fmt, $arg1, $arg2, $arg3, $arg4));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
};
|
|
||||||
}
|
|
||||||
log_levels!(error, warn, debug, info, trace, log);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum PError {}
|
|
||||||
|
|
||||||
pub type PResult<T> = Result<T, PError>;
|
pub type PResult<T> = Result<T, PError>;
|
||||||
|
|
||||||
pub trait PaymentAdapter {
|
pub struct Config(String);
|
||||||
fn init(&mut self) -> PResult<Status>;
|
|
||||||
fn teardown(&mut self) -> PResult<Status>;
|
|
||||||
|
|
||||||
fn create_payment(&mut self, msg: CreatePayment) -> PResult<PaymentCreated>;
|
impl Config {
|
||||||
fn retrieve_payment(&mut self);
|
pub fn config<S: serde::de::DeserializeOwned>(self) -> Result<S, toml::de::Error> {
|
||||||
fn authorize_payment(&mut self);
|
toml::from_str(&self.0)
|
||||||
fn capture_payment(&mut self);
|
}
|
||||||
fn refund_payment(&mut self, msg: RefundPayment) -> PResult<Refunded>;
|
}
|
||||||
fn delete_payment(&mut self, msg: DeletePayment) -> PResult<Deleted>;
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
pub trait PaymentAdapter {
|
||||||
|
async fn new(config: Config) -> Self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiate a payment session with the external provider
|
||||||
|
*/
|
||||||
|
async fn initialize_payment(
|
||||||
|
&mut self,
|
||||||
|
ctx: PaymentProcessorContext,
|
||||||
|
) -> PResult<PaymentProcessorSessionResponse>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an existing payment session
|
||||||
|
*/
|
||||||
|
async fn update_payment(
|
||||||
|
&mut self,
|
||||||
|
ctx: PaymentProcessorContext,
|
||||||
|
) -> PResult<Option<PaymentProcessorSessionResponse>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refund an existing session
|
||||||
|
*/
|
||||||
|
async fn refund_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
refund_amount: Amount,
|
||||||
|
) -> PResult<PaymentSessionData>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorize an existing session if it is not already authorized
|
||||||
|
*/
|
||||||
|
async fn authorize_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
data: PaymentProcessCtx,
|
||||||
|
) -> PResult<(PaymentSessionStatus, PaymentSessionData)>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capture an existing session
|
||||||
|
*/
|
||||||
|
async fn capture_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
) -> PResult<PaymentSessionData>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an existing session
|
||||||
|
*/
|
||||||
|
async fn delete_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
) -> PResult<PaymentSessionData>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve an existing session
|
||||||
|
*/
|
||||||
|
async fn retrieve_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
) -> PResult<PaymentSessionData>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel an existing session
|
||||||
|
*/
|
||||||
|
async fn cancel_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
) -> PResult<PaymentSessionData>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the status of the session
|
||||||
|
*/
|
||||||
|
async fn payment_status(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: &PaymentSessionData,
|
||||||
|
) -> PResult<PaymentSessionStatus>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use traitcast::{Traitcast, TraitcastFrom};
|
||||||
|
|
||||||
|
pub trait APaymentSessionData: Any {
|
||||||
|
fn id(&self) -> Option<String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BPSD(Box<dyn APaymentSessionData>);
|
||||||
|
|
||||||
|
impl BPSD {
|
||||||
|
pub fn as_mut_ref<T>(&mut self) -> Option<&mut T> {
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
@ -1,396 +1,399 @@
|
|||||||
use std::collections::HashMap;
|
// use std::collections::HashMap;
|
||||||
use std::fs::read_dir;
|
// use std::fs::read_dir;
|
||||||
use std::path::PathBuf;
|
// use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
// use std::str::FromStr;
|
||||||
use std::sync::mpsc::Sender;
|
// use std::sync::mpsc::Sender;
|
||||||
use std::sync::{Arc, LockResult, MutexGuard};
|
// use std::sync::{Arc, LockResult, MutexGuard};
|
||||||
|
//
|
||||||
use config::{AppConfig, SharedAppConfig, UpdateConfig};
|
// use config::{AppConfig, SharedAppConfig, UpdateConfig};
|
||||||
use payment_adapter::{HttpMethod, HttpRequest};
|
// use payment_adapter::{HttpMethod, HttpRequest};
|
||||||
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
|
// use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
|
||||||
use wapc::WasiParams;
|
// use wapc::WasiParams;
|
||||||
use wapc_pool::{HostPool, HostPoolBuilder};
|
// use wapc_pool::{HostPool, HostPoolBuilder};
|
||||||
|
//
|
||||||
use crate::rpc::ModuleSender;
|
// use crate::rpc::ModuleSender;
|
||||||
|
//
|
||||||
// mod actions;
|
// // mod actions;
|
||||||
// mod context;
|
// // mod context;
|
||||||
// mod db;
|
// // mod db;
|
||||||
mod mqtt;
|
// mod mqtt;
|
||||||
// pub mod pay_u_adapter;
|
// // pub mod pay_u_adapter;
|
||||||
mod rpc;
|
// mod rpc;
|
||||||
// pub mod t_pay_adapter;
|
// // pub mod t_pay_adapter;
|
||||||
|
//
|
||||||
#[derive(Clone)]
|
// #[derive(Clone)]
|
||||||
pub enum WasmMsg {
|
// pub enum WasmMsg {
|
||||||
CreateOrder {
|
// CreateOrder {
|
||||||
create_payment: payment_adapter::CreatePayment,
|
// create_payment: payment_adapter::CreatePayment,
|
||||||
tx: Sender<ResultMsg>,
|
// tx: Sender<ResultMsg>,
|
||||||
},
|
// },
|
||||||
UpdateStatus {
|
// UpdateStatus {
|
||||||
update_status: payment_adapter::UpdateStatus,
|
// update_status: payment_adapter::UpdateStatus,
|
||||||
tx: Sender<ResultMsg>,
|
// tx: Sender<ResultMsg>,
|
||||||
},
|
// },
|
||||||
Cancel {
|
// Cancel {
|
||||||
cancel: payment_adapter::RefundPayment,
|
// cancel: payment_adapter::RefundPayment,
|
||||||
tx: Sender<ResultMsg>,
|
// tx: Sender<ResultMsg>,
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[derive(Clone)]
|
// #[derive(Clone)]
|
||||||
pub enum ResultMsg {
|
// pub enum ResultMsg {
|
||||||
OrderCreated(payment_adapter::PaymentCreated),
|
// OrderCreated(payment_adapter::PaymentCreated),
|
||||||
StatusUpdated(payment_adapter::StatusUpdated),
|
// StatusUpdated(payment_adapter::StatusUpdated),
|
||||||
Cancel(payment_adapter::Refunded),
|
// Cancel(payment_adapter::Refunded),
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
pub struct HostChannel {
|
// pub struct HostChannel {
|
||||||
pub host: HostPool,
|
// pub host: HostPool,
|
||||||
pub channel: std::sync::mpsc::Receiver<WasmMsg>,
|
// pub channel: std::sync::mpsc::Receiver<WasmMsg>,
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
impl HostChannel {
|
// impl HostChannel {
|
||||||
pub fn start(self) {
|
// pub fn start(self) {
|
||||||
tokio::spawn(async move {
|
// tokio::spawn(async move {
|
||||||
let HostChannel {
|
// let HostChannel {
|
||||||
host: pool,
|
// host: pool,
|
||||||
channel,
|
// channel,
|
||||||
} = self;
|
// } = self;
|
||||||
|
//
|
||||||
loop {
|
// loop {
|
||||||
let msg = match channel.recv() {
|
// let msg = match channel.recv() {
|
||||||
Ok(msg) => msg,
|
// Ok(msg) => msg,
|
||||||
_ => continue,
|
// _ => continue,
|
||||||
};
|
// };
|
||||||
match msg {
|
// match msg {
|
||||||
WasmMsg::CreateOrder {
|
// WasmMsg::CreateOrder {
|
||||||
create_payment: msg,
|
// create_payment: msg,
|
||||||
tx,
|
// tx,
|
||||||
} => {
|
// } => {
|
||||||
Self::send_and_rec(
|
// Self::send_and_rec(
|
||||||
"create_payment",
|
// "create_payment",
|
||||||
msg,
|
// msg,
|
||||||
tx,
|
// tx,
|
||||||
&pool,
|
// &pool,
|
||||||
ResultMsg::OrderCreated,
|
// ResultMsg::OrderCreated,
|
||||||
)
|
// )
|
||||||
.await
|
// .await
|
||||||
.ok();
|
// .ok();
|
||||||
}
|
// }
|
||||||
WasmMsg::UpdateStatus {
|
// WasmMsg::UpdateStatus {
|
||||||
update_status: msg,
|
// update_status: msg,
|
||||||
tx,
|
// tx,
|
||||||
} => {
|
// } => {
|
||||||
Self::send_and_rec(
|
// Self::send_and_rec(
|
||||||
"update_status",
|
// "update_status",
|
||||||
msg,
|
// msg,
|
||||||
tx,
|
// tx,
|
||||||
&pool,
|
// &pool,
|
||||||
ResultMsg::StatusUpdated,
|
// ResultMsg::StatusUpdated,
|
||||||
)
|
// )
|
||||||
.await
|
// .await
|
||||||
.ok();
|
// .ok();
|
||||||
}
|
// }
|
||||||
WasmMsg::Cancel { cancel: msg, tx } => {
|
// WasmMsg::Cancel { cancel: msg, tx } => {
|
||||||
Self::send_and_rec("cancel_order", msg, tx, &pool, ResultMsg::Cancel)
|
// Self::send_and_rec("cancel_order", msg, tx, &pool,
|
||||||
.await
|
// ResultMsg::Cancel) .await
|
||||||
.ok();
|
// .ok();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
async fn send_and_rec<R, T, F>(
|
// async fn send_and_rec<R, T, F>(
|
||||||
name: &str,
|
// name: &str,
|
||||||
msg: R,
|
// msg: R,
|
||||||
tx: Sender<ResultMsg>,
|
// tx: Sender<ResultMsg>,
|
||||||
pool: &HostPool,
|
// pool: &HostPool,
|
||||||
f: F,
|
// f: F,
|
||||||
) -> Result<(), ()>
|
// ) -> Result<(), ()>
|
||||||
where
|
// where
|
||||||
R: serde::Serialize,
|
// R: serde::Serialize,
|
||||||
T: serde::de::DeserializeOwned,
|
// T: serde::de::DeserializeOwned,
|
||||||
F: FnOnce(T) -> ResultMsg,
|
// F: FnOnce(T) -> ResultMsg,
|
||||||
{
|
// {
|
||||||
macro_rules! ok_or_bail {
|
// macro_rules! ok_or_bail {
|
||||||
($run: expr) => {
|
// ($run: expr) => {
|
||||||
match $run {
|
// match $run {
|
||||||
Ok(r) => r,
|
// Ok(r) => r,
|
||||||
_ => return Err(()),
|
// _ => return Err(()),
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
let msg = ok_or_bail!(wapc_codec::messagepack::serialize(msg));
|
// let msg = ok_or_bail!(wapc_codec::messagepack::serialize(msg));
|
||||||
let call_result = ok_or_bail!(pool.call(name, msg).await);
|
// let call_result = ok_or_bail!(pool.call(name, msg).await);
|
||||||
let result: T = ok_or_bail!(wapc_codec::messagepack::deserialize(&call_result));
|
// let result: T =
|
||||||
if let Err(e) = tx.send(f(result)) {
|
// ok_or_bail!(wapc_codec::messagepack::deserialize(&call_result)); if
|
||||||
tracing::error!("{e:?}");
|
// let Err(e) = tx.send(f(result)) { tracing::error!("{e:?}");
|
||||||
Err(())
|
// Err(())
|
||||||
} else {
|
// } else {
|
||||||
Ok(())
|
// Ok(())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[derive(Clone)]
|
// #[derive(Clone)]
|
||||||
pub struct Modules(Arc<std::sync::Mutex<HashMap<String, ModuleSender>>>);
|
// pub struct Modules(Arc<std::sync::Mutex<HashMap<String, ModuleSender>>>);
|
||||||
|
//
|
||||||
impl Modules {
|
// impl Modules {
|
||||||
pub fn new(h: HashMap<String, ModuleSender>) -> Self {
|
// pub fn new(h: HashMap<String, ModuleSender>) -> Self {
|
||||||
Self(Arc::new(std::sync::Mutex::new(h)))
|
// Self(Arc::new(std::sync::Mutex::new(h)))
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
pub fn lock(&self) -> LockResult<MutexGuard<'_, HashMap<String, ModuleSender>>> {
|
// pub fn lock(&self) -> LockResult<MutexGuard<'_, HashMap<String,
|
||||||
self.0.lock()
|
// ModuleSender>>> { self.0.lock()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[derive(gumdrop::Options)]
|
// #[derive(gumdrop::Options)]
|
||||||
pub struct Opts {
|
// pub struct Opts {
|
||||||
pub adapters_path: Option<PathBuf>,
|
// pub adapters_path: Option<PathBuf>,
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
impl UpdateConfig for Opts {
|
// impl UpdateConfig for Opts {
|
||||||
fn update_config(&self, config: &mut AppConfig) {
|
// fn update_config(&self, config: &mut AppConfig) {
|
||||||
if let Some(path) = self.adapters_path.clone() {
|
// if let Some(path) = self.adapters_path.clone() {
|
||||||
config.payment_mut().adapters_path = Some(path);
|
// config.payment_mut().adapters_path = Some(path);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[tokio::main]
|
// #[tokio::main]
|
||||||
async fn main() {
|
// async fn main() {
|
||||||
config::init_tracing("payments");
|
// config::init_tracing("payments");
|
||||||
|
//
|
||||||
let opts: Opts = gumdrop::parse_args_default_or_exit();
|
// let opts: Opts = gumdrop::parse_args_default_or_exit();
|
||||||
|
//
|
||||||
let config = config::default_load(&opts);
|
// let config = config::default_load(&opts);
|
||||||
let files = scan_adapters_dir(&config);
|
// let files = scan_adapters_dir(&config);
|
||||||
let mut modules = HashMap::with_capacity(files.len());
|
// let mut modules = HashMap::with_capacity(files.len());
|
||||||
|
//
|
||||||
load_adapters(&config, &mut modules, files).await;
|
// load_adapters(&config, &mut modules, files).await;
|
||||||
|
//
|
||||||
// for pool in modules.values() {
|
// // for pool in modules.values() {
|
||||||
// let msg = payment_adapter::CreatePayment {
|
// // let msg = payment_adapter::CreatePayment {
|
||||||
// buyer: payment_adapter::Buyer {
|
// // buyer: payment_adapter::Buyer {
|
||||||
// email: "hello@example.com".to_string(),
|
// // email: "hello@example.com".to_string(),
|
||||||
// phone: "530698478".to_string(),
|
// // phone: "530698478".to_string(),
|
||||||
// first_name: "Joe".to_string(),
|
// // first_name: "Joe".to_string(),
|
||||||
// last_name: "Doe".to_string(),
|
// // last_name: "Doe".to_string(),
|
||||||
// language: "pl".to_string(),
|
// // language: "pl".to_string(),
|
||||||
// },
|
// // },
|
||||||
// customer_ip: "12.22.34.54".to_string(),
|
// // customer_ip: "12.22.34.54".to_string(),
|
||||||
// currency: "PLN".to_string(),
|
// // currency: "PLN".to_string(),
|
||||||
// description: "Nesciunt fugit libero quis dolorum quo.
|
// // description: "Nesciunt fugit libero quis dolorum quo.
|
||||||
// Tempore aut nisi voluptatem. Odio et aspernatur est. Sint vel
|
// // Tempore aut nisi voluptatem. Odio et aspernatur est. Sint vel
|
||||||
// molestias sunt cumque quibusdam reprehenderit est.".to_string(),
|
// // molestias sunt cumque quibusdam reprehenderit est.".to_string(),
|
||||||
// cart_products: vec![Product {
|
// // cart_products: vec![Product {
|
||||||
// id: 23,
|
// // id: 23,
|
||||||
// name: "Socks".to_string(),
|
// // name: "Socks".to_string(),
|
||||||
// unit_price: 1542,
|
// // unit_price: 1542,
|
||||||
// quantity_unit: "Unit".to_string(),
|
// // quantity_unit: "Unit".to_string(),
|
||||||
// quantity: 2,
|
// // quantity: 2,
|
||||||
// }],
|
// // }],
|
||||||
// items: vec![Item {
|
// // items: vec![Item {
|
||||||
// product_id: 23,
|
// // product_id: 23,
|
||||||
// quantity: 2,
|
// // quantity: 2,
|
||||||
// quantity_unit: "Unit".to_string(),
|
// // quantity_unit: "Unit".to_string(),
|
||||||
// }],
|
// // }],
|
||||||
// order_ext_id: None,
|
// // order_ext_id: None,
|
||||||
// notify_uri: "https://localhost:3030/notify_uri".to_string(),
|
// // notify_uri: "https://localhost:3030/notify_uri".to_string(),
|
||||||
// continue_uri: "https://localhost:3030/continue_uri".to_string(),
|
// // continue_uri: "https://localhost:3030/continue_uri".to_string(),
|
||||||
// };
|
// // };
|
||||||
//
|
// //
|
||||||
// tracing::info!("Start create_payment");
|
// // tracing::info!("Start create_payment");
|
||||||
// let call_result = pool
|
// // let call_result = pool
|
||||||
// .call(
|
// // .call(
|
||||||
// "create_payment",
|
// // "create_payment",
|
||||||
// wapc_codec::messagepack::serialize(msg).unwrap(),
|
// // wapc_codec::messagepack::serialize(msg).unwrap(),
|
||||||
// )
|
// // )
|
||||||
// .await
|
// // .await
|
||||||
// .unwrap();
|
// // .unwrap();
|
||||||
// let result: payment_adapter::OrderCreated =
|
// // let result: payment_adapter::OrderCreated =
|
||||||
// wapc_codec::messagepack::deserialize(&call_result).unwrap();
|
// // wapc_codec::messagepack::deserialize(&call_result).unwrap();
|
||||||
//
|
// //
|
||||||
// tracing::info!("create payment res {:?}", result)
|
// // tracing::info!("create payment res {:?}", result)
|
||||||
// }
|
// // }
|
||||||
|
//
|
||||||
let modules = Modules::new(modules);
|
// let modules = Modules::new(modules);
|
||||||
let mqtt_client = mqtt::start(config.clone(), modules.clone()).await;
|
// let mqtt_client = mqtt::start(config.clone(), modules.clone()).await;
|
||||||
rpc::start(config, mqtt_client, modules.clone()).await;
|
// rpc::start(config, mqtt_client, modules.clone()).await;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
async fn load_adapters(
|
// async fn load_adapters(
|
||||||
config: &SharedAppConfig,
|
// config: &SharedAppConfig,
|
||||||
modules: &mut HashMap<String, ModuleSender>,
|
// modules: &mut HashMap<String, ModuleSender>,
|
||||||
files: Vec<PathBuf>,
|
// files: Vec<PathBuf>,
|
||||||
) {
|
// ) {
|
||||||
for file in files {
|
// for file in files {
|
||||||
let module = std::fs::read(&file).unwrap();
|
// let module = std::fs::read(&file).unwrap();
|
||||||
let engine = wasmtime_provider::WasmtimeEngineProviderBuilder::new()
|
// let engine = wasmtime_provider::WasmtimeEngineProviderBuilder::new()
|
||||||
.module_bytes(&module)
|
// .module_bytes(&module)
|
||||||
.wasi_params(WasiParams::default())
|
// .wasi_params(WasiParams::default())
|
||||||
.build()
|
// .build()
|
||||||
.unwrap();
|
// .unwrap();
|
||||||
|
//
|
||||||
let pool = HostPoolBuilder::new()
|
// let pool = HostPoolBuilder::new()
|
||||||
.name("pool")
|
// .name("pool")
|
||||||
.factory(move || {
|
// .factory(move || {
|
||||||
wapc::WapcHost::new(
|
// wapc::WapcHost::new(
|
||||||
Box::new(engine.clone()),
|
// Box::new(engine.clone()),
|
||||||
Some(Box::new(
|
// Some(Box::new(
|
||||||
move |_a, binding, _namespace, msg_name, payload| {
|
// move |_a, binding, _namespace, msg_name, payload| {
|
||||||
Ok(host_call(binding, msg_name, payload)?)
|
// Ok(host_call(binding, msg_name, payload)?)
|
||||||
},
|
// },
|
||||||
)),
|
// )),
|
||||||
)
|
// )
|
||||||
.unwrap()
|
// .unwrap()
|
||||||
})
|
// })
|
||||||
.max_threads(5)
|
// .max_threads(5)
|
||||||
.build();
|
// .build();
|
||||||
let name = pool
|
// let name = pool
|
||||||
.call("name", vec![])
|
// .call("name", vec![])
|
||||||
.await
|
// .await
|
||||||
.unwrap_or_else(|e| panic!("Failed to load adapter {file:?} `name`. {e}"));
|
// .unwrap_or_else(|e| panic!("Failed to load adapter {file:?}
|
||||||
let name: String = wapc_codec::messagepack::deserialize(&name)
|
// `name`. {e}")); let name: String =
|
||||||
.unwrap_or_else(|e| panic!("Adapter `name` ({name:?}) is not valid string. {e}"));
|
// wapc_codec::messagepack::deserialize(&name) .unwrap_or_else(|e|
|
||||||
|
// panic!("Adapter `name` ({name:?}) is not valid string. {e}"));
|
||||||
let msg = config
|
//
|
||||||
.lock()
|
// let msg = config
|
||||||
.payment()
|
// .lock()
|
||||||
.providers
|
// .payment()
|
||||||
.get(&name)
|
// .providers
|
||||||
.cloned()
|
// .get(&name)
|
||||||
.unwrap_or_default();
|
// .cloned()
|
||||||
|
// .unwrap_or_default();
|
||||||
tracing::info!("Start init");
|
//
|
||||||
pool.call("init", wapc_codec::messagepack::serialize(msg).unwrap())
|
// tracing::info!("Start init");
|
||||||
.await
|
// pool.call("init", wapc_codec::messagepack::serialize(msg).unwrap())
|
||||||
.unwrap();
|
// .await
|
||||||
|
// .unwrap();
|
||||||
let (tx, rx) = std::sync::mpsc::channel();
|
//
|
||||||
HostChannel {
|
// let (tx, rx) = std::sync::mpsc::channel();
|
||||||
host: pool,
|
// HostChannel {
|
||||||
channel: rx,
|
// host: pool,
|
||||||
}
|
// channel: rx,
|
||||||
.start();
|
// }
|
||||||
|
// .start();
|
||||||
modules.insert(name, ModuleSender::new(tx));
|
//
|
||||||
}
|
// modules.insert(name, ModuleSender::new(tx));
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
fn scan_adapters_dir(config: &SharedAppConfig) -> Vec<PathBuf> {
|
//
|
||||||
let adapters_path = config.lock().payment().adapters_path.clone();
|
// fn scan_adapters_dir(config: &SharedAppConfig) -> Vec<PathBuf> {
|
||||||
let adapters = adapters_path.unwrap_or_else(|| panic!("No payment adapters path provided"));
|
// let adapters_path = config.lock().payment().adapters_path.clone();
|
||||||
let dir = read_dir(&adapters).unwrap_or_else(|e| {
|
// let adapters = adapters_path.unwrap_or_else(|| panic!("No payment
|
||||||
panic!(
|
// adapters path provided")); let dir =
|
||||||
"Failed to load payment adapters at path {:?}. {}",
|
// read_dir(&adapters).unwrap_or_else(|e| { panic!(
|
||||||
adapters, e
|
// "Failed to load payment adapters at path {:?}. {}",
|
||||||
)
|
// adapters, e
|
||||||
});
|
// )
|
||||||
let files = dir
|
// });
|
||||||
.filter_map(|r| r.map(|r| r.path()).ok())
|
// let files = dir
|
||||||
.filter(|file| file.extension().and_then(|s| s.to_str()) == Some("wasm"))
|
// .filter_map(|r| r.map(|r| r.path()).ok())
|
||||||
.collect::<Vec<_>>();
|
// .filter(|file| file.extension().and_then(|s| s.to_str()) ==
|
||||||
|
// Some("wasm")) .collect::<Vec<_>>();
|
||||||
if files.is_empty() {
|
//
|
||||||
panic!("No payment adapters found in adapters directory");
|
// if files.is_empty() {
|
||||||
}
|
// panic!("No payment adapters found in adapters directory");
|
||||||
files
|
// }
|
||||||
}
|
// files
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // #[tracing::instrument]
|
||||||
|
// fn host_call(binding: &str, name: &str, payload: &[u8]) -> Result<Vec<u8>,
|
||||||
|
// payment_adapter::Error> { match name {
|
||||||
|
// "http_req" => {
|
||||||
|
// let req: HttpRequest = match
|
||||||
|
// wapc_codec::messagepack::deserialize(payload) { Ok(req) =>
|
||||||
|
// req, Err(e) => {
|
||||||
|
// tracing::error!("{:?} payload {:?}", binding, payload);
|
||||||
|
// tracing::error!("Failed to deserialize. {}", e);
|
||||||
|
// return
|
||||||
|
// Err(payment_adapter::Error::MsgPackDeserializationFailed); }
|
||||||
|
// };
|
||||||
|
// http_request(req)
|
||||||
|
// }
|
||||||
|
// _ => Err(payment_adapter::Error::UnknownOperation(name.to_string())),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
// #[tracing::instrument]
|
// #[tracing::instrument]
|
||||||
fn host_call(binding: &str, name: &str, payload: &[u8]) -> Result<Vec<u8>, payment_adapter::Error> {
|
// fn http_request(req: HttpRequest) -> Result<Vec<u8>, payment_adapter::Error>
|
||||||
match name {
|
// { tracing::info!("{:?}", req);
|
||||||
"http_req" => {
|
// let HttpRequest {
|
||||||
let req: HttpRequest = match wapc_codec::messagepack::deserialize(payload) {
|
// method,
|
||||||
Ok(req) => req,
|
// url,
|
||||||
Err(e) => {
|
// headers,
|
||||||
tracing::error!("{:?} payload {:?}", binding, payload);
|
// bearer_auth,
|
||||||
tracing::error!("Failed to deserialize. {}", e);
|
// body,
|
||||||
return Err(payment_adapter::Error::MsgPackDeserializationFailed);
|
// } = req;
|
||||||
}
|
// let client = reqwest::blocking::ClientBuilder::default()
|
||||||
};
|
// .user_agent("curl/7.82.0")
|
||||||
http_request(req)
|
// // Do not follow redirect!
|
||||||
}
|
// .redirect(reqwest::redirect::Policy::none())
|
||||||
_ => Err(payment_adapter::Error::UnknownOperation(name.to_string())),
|
// .connection_verbose(true)
|
||||||
}
|
// .build()
|
||||||
}
|
// .expect("Failed to create client");
|
||||||
|
//
|
||||||
|
// let headers = {
|
||||||
|
// let len = headers.len();
|
||||||
|
// headers
|
||||||
|
// .into_iter()
|
||||||
|
// .fold(HeaderMap::with_capacity(len), |mut m, (k, v)| {
|
||||||
|
// if let (Ok(v), Ok(k)) =
|
||||||
|
// (HeaderValue::from_str(v.as_str()),
|
||||||
|
// HeaderName::from_str(&k)) {
|
||||||
|
// m.insert(k, v);
|
||||||
|
// }
|
||||||
|
// m
|
||||||
|
// })
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// let response = match (method, bearer_auth) {
|
||||||
|
// (HttpMethod::Get, Some(bearer)) => client
|
||||||
|
// .get(url)
|
||||||
|
// .headers(headers)
|
||||||
|
// .bearer_auth(bearer)
|
||||||
|
// .send()
|
||||||
|
// .map_err(|e| {
|
||||||
|
// tracing::error!("{}", e);
|
||||||
|
// payment_adapter::Error::HttpFailed
|
||||||
|
// })?,
|
||||||
|
// (HttpMethod::Get, _) =>
|
||||||
|
// client.get(url).headers(headers).send().map_err(|e| {
|
||||||
|
// tracing::error!("{}", e); payment_adapter::Error::HttpFailed
|
||||||
|
// })?,
|
||||||
|
// (HttpMethod::Post, Some(bearer)) => client
|
||||||
|
// .post(url)
|
||||||
|
// .headers(headers)
|
||||||
|
// .bearer_auth(bearer)
|
||||||
|
// .body(body.unwrap_or_default())
|
||||||
|
// .send()
|
||||||
|
// .map_err(|e| {
|
||||||
|
// tracing::error!("{}", e);
|
||||||
|
// payment_adapter::Error::HttpFailed
|
||||||
|
// })?,
|
||||||
|
// (HttpMethod::Post, None) => client
|
||||||
|
// .post(url)
|
||||||
|
// .headers(headers)
|
||||||
|
// .body(body.unwrap_or_default())
|
||||||
|
// .send()
|
||||||
|
// .map_err(|e| {
|
||||||
|
// eprintln!("POST NONE {}", e);
|
||||||
|
// tracing::error!("{}", e);
|
||||||
|
// payment_adapter::Error::HttpFailed
|
||||||
|
// })?,
|
||||||
|
// };
|
||||||
|
// tracing::info!("HTTP response status {:?}", response.status());
|
||||||
|
// let text = response.bytes().map_err(|e| {
|
||||||
|
// tracing::error!("{}", e);
|
||||||
|
// payment_adapter::Error::HttpFailed
|
||||||
|
// })?;
|
||||||
|
// tracing::info!("HTTP Result {:?}", text);
|
||||||
|
// Ok(text.to_vec())
|
||||||
|
// }
|
||||||
|
|
||||||
#[tracing::instrument]
|
fn main() {}
|
||||||
fn http_request(req: HttpRequest) -> Result<Vec<u8>, payment_adapter::Error> {
|
|
||||||
tracing::info!("{:?}", req);
|
|
||||||
let HttpRequest {
|
|
||||||
method,
|
|
||||||
url,
|
|
||||||
headers,
|
|
||||||
bearer_auth,
|
|
||||||
body,
|
|
||||||
} = req;
|
|
||||||
let client = reqwest::blocking::ClientBuilder::default()
|
|
||||||
.user_agent("curl/7.82.0")
|
|
||||||
// Do not follow redirect!
|
|
||||||
.redirect(reqwest::redirect::Policy::none())
|
|
||||||
.connection_verbose(true)
|
|
||||||
.build()
|
|
||||||
.expect("Failed to create client");
|
|
||||||
|
|
||||||
let headers = {
|
|
||||||
let len = headers.len();
|
|
||||||
headers
|
|
||||||
.into_iter()
|
|
||||||
.fold(HeaderMap::with_capacity(len), |mut m, (k, v)| {
|
|
||||||
if let (Ok(v), Ok(k)) =
|
|
||||||
(HeaderValue::from_str(v.as_str()), HeaderName::from_str(&k))
|
|
||||||
{
|
|
||||||
m.insert(k, v);
|
|
||||||
}
|
|
||||||
m
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
let response = match (method, bearer_auth) {
|
|
||||||
(HttpMethod::Get, Some(bearer)) => client
|
|
||||||
.get(url)
|
|
||||||
.headers(headers)
|
|
||||||
.bearer_auth(bearer)
|
|
||||||
.send()
|
|
||||||
.map_err(|e| {
|
|
||||||
tracing::error!("{}", e);
|
|
||||||
payment_adapter::Error::HttpFailed
|
|
||||||
})?,
|
|
||||||
(HttpMethod::Get, _) => client.get(url).headers(headers).send().map_err(|e| {
|
|
||||||
tracing::error!("{}", e);
|
|
||||||
payment_adapter::Error::HttpFailed
|
|
||||||
})?,
|
|
||||||
(HttpMethod::Post, Some(bearer)) => client
|
|
||||||
.post(url)
|
|
||||||
.headers(headers)
|
|
||||||
.bearer_auth(bearer)
|
|
||||||
.body(body.unwrap_or_default())
|
|
||||||
.send()
|
|
||||||
.map_err(|e| {
|
|
||||||
tracing::error!("{}", e);
|
|
||||||
payment_adapter::Error::HttpFailed
|
|
||||||
})?,
|
|
||||||
(HttpMethod::Post, None) => client
|
|
||||||
.post(url)
|
|
||||||
.headers(headers)
|
|
||||||
.body(body.unwrap_or_default())
|
|
||||||
.send()
|
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("POST NONE {}", e);
|
|
||||||
tracing::error!("{}", e);
|
|
||||||
payment_adapter::Error::HttpFailed
|
|
||||||
})?,
|
|
||||||
};
|
|
||||||
tracing::info!("HTTP response status {:?}", response.status());
|
|
||||||
let text = response.bytes().map_err(|e| {
|
|
||||||
tracing::error!("{}", e);
|
|
||||||
payment_adapter::Error::HttpFailed
|
|
||||||
})?;
|
|
||||||
tracing::info!("HTTP Result {:?}", text);
|
|
||||||
Ok(text.to_vec())
|
|
||||||
}
|
|
||||||
|
@ -7,7 +7,7 @@ use config::SharedAppConfig;
|
|||||||
use payment_adapter::RefundPayment;
|
use payment_adapter::RefundPayment;
|
||||||
use tarpc::context;
|
use tarpc::context;
|
||||||
|
|
||||||
use crate::{Modules, ResultMsg, WasmMsg};
|
use crate::{Modules, ResultMsg};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ModuleSender {
|
pub struct ModuleSender {
|
||||||
@ -59,7 +59,7 @@ impl PaymentsServer {
|
|||||||
.clone())
|
.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
#[tarpc::server]
|
#[tarpc::server]
|
||||||
impl Payments for PaymentsServer {
|
impl Payments for PaymentsServer {
|
||||||
async fn start_payment(
|
async fn start_payment(
|
||||||
@ -156,3 +156,4 @@ pub async fn start(config: SharedAppConfig, mqtt_client: AsyncClient, modules: M
|
|||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
@ -13,6 +13,7 @@ rustflags = ["-C", "prefer-dynamic", "-C", "rpath"]
|
|||||||
payment_adapter = { path = "../payment_adapter" }
|
payment_adapter = { path = "../payment_adapter" }
|
||||||
fulfillment_adapter = { path = "../fulfillment_adapter" }
|
fulfillment_adapter = { path = "../fulfillment_adapter" }
|
||||||
tokio = { version = "1.27.0" }
|
tokio = { version = "1.27.0" }
|
||||||
payup = { version = "*" }
|
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'] }
|
||||||
|
@ -1,126 +1,242 @@
|
|||||||
#![crate_type = "rlib"]
|
#![crate_type = "rlib"]
|
||||||
|
|
||||||
use fulfillment_adapter::{
|
use std::any::Any;
|
||||||
FError, FResult, FulfillmentAdapter, FulfillmentCart, FulfillmentOption, FulfillmentPayload,
|
use std::collections::HashMap;
|
||||||
};
|
use std::ops::DerefMut;
|
||||||
use payment_adapter::{
|
|
||||||
CreatePayment, DeletePayment, Deleted, PResult, PaymentAdapter, PaymentCreated,
|
|
||||||
PaymentSessionStatus, RefundPayment, Refunded, Status,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct StripeAdapter {
|
use fulfillment_adapter::*;
|
||||||
stripe: payup::stripe::Auth,
|
use payment_adapter::*;
|
||||||
|
use payup::stripe;
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||||
|
pub enum CaptureMethod {
|
||||||
|
Automatic,
|
||||||
|
Manual,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StripeAdapter {
|
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||||
fn payment_status(&mut self, ext_id: String) -> FResult<PaymentSessionStatus> {
|
pub enum SetupFutureUsage {
|
||||||
let charge = payup::stripe::Charge::get(self.stripe.clone(), ext_id).map_err(|e| {
|
OnSession,
|
||||||
|
OffSession,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||||
|
pub struct StripeConfig {
|
||||||
|
pub api_key: String,
|
||||||
|
pub client: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct StripeIntent {
|
||||||
|
pub capture_method: CaptureMethod,
|
||||||
|
pub setup_future_usage: SetupFutureUsage,
|
||||||
|
pub payment_method_types: &'static [&'static str],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StripeAdapter {
|
||||||
|
stripe: stripe::Auth,
|
||||||
|
config: StripeConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn payment_status(stripe: stripe::Auth, ext_id: String) -> FResult<PaymentSessionStatus> {
|
||||||
|
let charge: stripe::Charge = stripe::Charge::async_get(stripe, ext_id)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
tracing::warn!("{e}");
|
tracing::warn!("{e}");
|
||||||
FError::HttpError
|
FError::HttpError
|
||||||
})?;
|
})?;
|
||||||
Ok(match charge.status.as_deref() {
|
Ok(match charge.status.as_deref() {
|
||||||
Some("requires_payment_method" | "requires_confirmation" | "processing") => {
|
Some("requires_payment_method" | "requires_confirmation" | "processing") => {
|
||||||
PaymentSessionStatus::Pending
|
PaymentSessionStatus::Pending
|
||||||
}
|
}
|
||||||
Some("requires_action") => PaymentSessionStatus::RequiresMore,
|
Some("requires_action") => PaymentSessionStatus::RequiresMore,
|
||||||
Some("canceled") => PaymentSessionStatus::Canceled,
|
Some("canceled") => PaymentSessionStatus::Canceled,
|
||||||
Some("requires_capture" | "succeeded") => PaymentSessionStatus::Authorized,
|
Some("requires_capture" | "succeeded") => PaymentSessionStatus::Authorized,
|
||||||
_ => PaymentSessionStatus::Pending,
|
_ => PaymentSessionStatus::Pending,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize, serde::Serialize)]
|
||||||
|
pub struct StripePrzelewy24Config {
|
||||||
|
pub api_key: String,
|
||||||
|
pub client: String,
|
||||||
|
pub webhook_secret: String,
|
||||||
|
pub capture: Option<bool>,
|
||||||
|
pub automatic_payment_methods: Option<bool>,
|
||||||
|
pub payment_description: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StripePrzelewy24 {
|
||||||
|
stripe: stripe::Auth,
|
||||||
|
config: StripePrzelewy24Config,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl PaymentAdapter for StripePrzelewy24 {
|
||||||
|
async fn new(config: Config) -> Self {
|
||||||
|
let config: StripePrzelewy24Config =
|
||||||
|
config.config().expect("Malformed Stripe Przelewy24 config");
|
||||||
|
let stripe = stripe::Auth::new(config.client.clone(), config.api_key.clone());
|
||||||
|
Self { config, stripe }
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn initialize_payment(
|
||||||
|
&mut self,
|
||||||
|
ctx: PaymentProcessorContext,
|
||||||
|
) -> PResult<PaymentProcessorSessionResponse> {
|
||||||
|
let PaymentProcessorContext {
|
||||||
|
billing_address: _,
|
||||||
|
email,
|
||||||
|
currency_code,
|
||||||
|
amount,
|
||||||
|
resource_id: _,
|
||||||
|
customer,
|
||||||
|
context,
|
||||||
|
payment_session_data,
|
||||||
|
} = ctx;
|
||||||
|
let desc = context
|
||||||
|
.0
|
||||||
|
.get("payment_description")
|
||||||
|
.and_then(|v| String::from_utf8(v.0.clone()).ok())
|
||||||
|
.or_else(|| self.config.payment_description.clone());
|
||||||
|
|
||||||
|
let change: stripe::Charge = stripe::Charge {
|
||||||
|
amount: Some(amount.0.to_string()),
|
||||||
|
captured: self.config.capture.clone(),
|
||||||
|
currency: Some(currency_code.into()),
|
||||||
|
description: desc,
|
||||||
|
customer: customer.map(|c| c.id.0.to_string()),
|
||||||
|
receipt_email: Some(email.0),
|
||||||
|
..stripe::Charge::new()
|
||||||
|
}
|
||||||
|
.async_post(self.stripe.clone())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let update_requests = match customer {
|
||||||
|
Some(c) if !c.has_stripe_id() => Some(UpdateRequests {
|
||||||
|
customer_metadata: Some(CustomerMetadata(HashMap::from([(
|
||||||
|
"id".to_string(),
|
||||||
|
AnyData(change.customer.unwrap_or_default().into_bytes()),
|
||||||
|
)]))),
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(PaymentProcessorSessionResponse {
|
||||||
|
update_requests,
|
||||||
|
session_data: payment_session_data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl PaymentAdapter for StripeAdapter {
|
async fn update_payment(
|
||||||
fn init(&mut self) -> PResult<Status> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn teardown(&mut self) -> PResult<Status> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn create_payment(&mut self, msg: CreatePayment) -> PResult<PaymentCreated> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn retrieve_payment(&mut self) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn authorize_payment(&mut self) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn capture_payment(&mut self) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn refund_payment(&mut self, msg: RefundPayment) -> PResult<Refunded> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn delete_payment(&mut self, msg: DeletePayment) -> PResult<Deleted> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FulfillmentAdapter for StripeAdapter {
|
|
||||||
fn identifier() -> &'static str {
|
|
||||||
"stripe"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fulfillment_options(&mut self) -> FResult<&[FulfillmentOption]> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate_fulfillment_payload<P: FulfillmentPayload, C: FulfillmentCart>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
payload: P,
|
ctx: PaymentProcessorContext,
|
||||||
cart: C,
|
) -> PResult<Option<PaymentProcessorSessionResponse>> {
|
||||||
) -> FResult<bool> {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_option<P: FulfillmentPayload>(&mut self, payload: P) -> FResult<bool> {
|
async fn refund_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
refund_amount: Amount,
|
||||||
|
) -> PResult<PaymentSessionData> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_calculate<P: FulfillmentPayload>(&mut self, payload: P) -> FResult<bool> {
|
async fn authorize_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
data: PaymentProcessCtx,
|
||||||
|
) -> PResult<(PaymentSessionStatus, PaymentSessionData)> {
|
||||||
|
self.payment_status(&payment_session_data)
|
||||||
|
.await
|
||||||
|
.map(|status| (status, payment_session_data))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn capture_payment(
|
||||||
|
&mut self,
|
||||||
|
mut payment_session_data: PaymentSessionData,
|
||||||
|
) -> PResult<PaymentSessionData> {
|
||||||
|
let id = payment_session_data
|
||||||
|
.id
|
||||||
|
.clone()
|
||||||
|
.ok_or_else(|| PError::NoChargeId)?;
|
||||||
|
let charge = stripe::Charge::async_get(self.stripe.clone(), id.clone())
|
||||||
|
.await
|
||||||
|
.map_err(|_| PError::ChargeNotExists(id.clone()))?;
|
||||||
|
let change = charge
|
||||||
|
.async_capture(self.stripe.clone())
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
tracing::warn!("{e}");
|
||||||
|
PError::FailedCapture(id)
|
||||||
|
})?;
|
||||||
|
payment_session_data.id = charge.id;
|
||||||
|
Ok(payment_session_data)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn delete_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
) -> PResult<PaymentSessionData> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_price<P: FulfillmentPayload, C: FulfillmentCart>(
|
async fn retrieve_payment(
|
||||||
data: P,
|
&mut self,
|
||||||
cart: C,
|
payment_session_data: PaymentSessionData,
|
||||||
) -> FResult<u64> {
|
) -> PResult<PaymentSessionData> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_fulfillment(&mut self) {
|
async fn cancel_payment(
|
||||||
|
&mut self,
|
||||||
|
payment_session_data: PaymentSessionData,
|
||||||
|
) -> PResult<PaymentSessionData> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cancel_fulfillment(&mut self) {
|
async fn payment_status(
|
||||||
todo!()
|
&mut self,
|
||||||
}
|
payment_session_data: &PaymentSessionData,
|
||||||
|
) -> PResult<PaymentSessionStatus> {
|
||||||
fn fulfillment_documents(&mut self) {
|
payment_status(
|
||||||
todo!()
|
self.stripe.clone(),
|
||||||
}
|
payment_session_data.id.clone().unwrap_or_default(),
|
||||||
|
)
|
||||||
fn create_return(&mut self) {
|
.await
|
||||||
todo!()
|
.map_err(|_| PError::HttpError)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fn return_documents(&mut self) {
|
|
||||||
todo!()
|
impl StripePrzelewy24 {
|
||||||
}
|
pub fn payment_intent_options() -> StripeIntent {
|
||||||
|
StripeIntent {
|
||||||
fn shipment_documents(&mut self) {
|
capture_method: CaptureMethod::Automatic,
|
||||||
todo!()
|
setup_future_usage: SetupFutureUsage::OnSession,
|
||||||
}
|
payment_method_types: &["p24"],
|
||||||
|
}
|
||||||
fn documents(&mut self) {
|
}
|
||||||
todo!()
|
}
|
||||||
|
|
||||||
|
pub trait StripeCustomerMetadata {
|
||||||
|
fn has_stripe_id(&self) -> bool;
|
||||||
|
|
||||||
|
fn stripe_id(&self) -> Option<String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StripeCustomerMetadata for Customer {
|
||||||
|
fn has_stripe_id(&self) -> bool {
|
||||||
|
self.metadata
|
||||||
|
.as_ref()
|
||||||
|
.map_or_else(|| false, |h| h.contains_key("stripe_id"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stripe_id(&self) -> Option<String> {
|
||||||
|
self.metadata
|
||||||
|
.as_ref()?
|
||||||
|
.get("stripe_id")
|
||||||
|
.and_then(|v| String::from_utf8(v.clone()).ok())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user