lots of small things
This commit is contained in:
parent
768a1cf7bd
commit
332084b105
17 changed files with 785 additions and 29 deletions
9
.env
9
.env
|
@ -1,8 +1,11 @@
|
|||
## COMMON VARIABLES FOR ALL APPS
|
||||
REQUIRED_SALEOR_VERSION="^3.13"
|
||||
APP_API_BASE_URL="http://10.100.110.234:3000"
|
||||
APL="Redis"
|
||||
APL_URL="redis://localhost:6380/2"
|
||||
LOG_LEVEL="DEBUG"
|
||||
|
||||
## THESE VARIABLES ARE FOR SITEMAP-GENERATOR APP
|
||||
SITEMAP_TARGET_FOLDER="./temp"
|
||||
# Available fields can be found in ./sitemap-generator/src/queries/event_subjects_updated.rs: ProductUpdate
|
||||
SITEMAP_PRODUCT_TEMPLATE="https://example.com/{product.category.slug}/{product.slug}"
|
||||
|
@ -14,3 +17,9 @@ SITEMAP_COLLECTION_TEMPLATE="https://example.com/collection/{collection.slug}"
|
|||
SITEMAP_PAGES_TEMPLATE="https://example.com/{page.slug}"
|
||||
# Without trailing "/"!
|
||||
SITEMAP_INDEX_HOSTNAME="https://example.com"
|
||||
|
||||
## THESE VARIABLES ARE FOR SIMPLE-PAYMENT-GATEWAY APP
|
||||
#To see all possible options, check simple-payment-gateway/src/app:GatewayTypes
|
||||
ACTIVE_GATEWAYS="cod,cash,transfer"
|
||||
# only SK,EN available :). Determines what language the gateway names will be in storefront
|
||||
LOCALE="SK"
|
||||
|
|
27
Cargo.lock
generated
27
Cargo.lock
generated
|
@ -841,6 +841,26 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enum-iterator"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "600536cfe9e2da0820aa498e570f6b2b9223eec3ce2f835c8ae4861304fa4794"
|
||||
dependencies = [
|
||||
"enum-iterator-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enum-iterator-derive"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03cdc46ec28bd728e67540c528013c6a10eb69a02eb31078a1bda695438cbfb8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "envy"
|
||||
version = "0.4.2"
|
||||
|
@ -2454,7 +2474,7 @@ checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
|||
|
||||
[[package]]
|
||||
name = "saleor-app-sdk"
|
||||
version = "0.1.0"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -2701,6 +2721,7 @@ dependencies = [
|
|||
"cynic",
|
||||
"cynic-codegen",
|
||||
"dotenvy",
|
||||
"enum-iterator",
|
||||
"envy",
|
||||
"redis",
|
||||
"saleor-app-sdk",
|
||||
|
@ -2901,9 +2922,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.26.1"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "723b93e8addf9aa965ebe2d11da6d7540fa2283fcea14b3371ff055f7ba13f5f"
|
||||
checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
[toolchain]
|
||||
channel = "nightly"
|
||||
targets = ["x86_64-unknown-linux-musl"]
|
4
rust-toolchain.tomln
Normal file
4
rust-toolchain.tomln
Normal file
|
@ -0,0 +1,4 @@
|
|||
[toolchain]
|
||||
channel = "nightly"
|
||||
#targets = ["x86_64-unknown-linux-musl"]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
|
@ -1,6 +1,7 @@
|
|||
pub mod apl;
|
||||
pub mod config;
|
||||
pub mod headers;
|
||||
pub mod locales;
|
||||
pub mod manifest;
|
||||
pub mod middleware;
|
||||
pub mod webhooks;
|
||||
|
@ -25,6 +26,7 @@ pub struct AuthData {
|
|||
pub app_id: String,
|
||||
pub jwks: Option<String>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for AuthData {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
|
|
47
sdk/src/locales.rs
Normal file
47
sdk/src/locales.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum LocaleCode {
|
||||
Ar,
|
||||
Az,
|
||||
Bg,
|
||||
Bn,
|
||||
Ca,
|
||||
Cs,
|
||||
Da,
|
||||
De,
|
||||
El,
|
||||
En,
|
||||
Es,
|
||||
EsCO,
|
||||
Et,
|
||||
Fa,
|
||||
Fr,
|
||||
Hi,
|
||||
Hu,
|
||||
Hy,
|
||||
Id,
|
||||
Is,
|
||||
It,
|
||||
Ja,
|
||||
Ko,
|
||||
Mn,
|
||||
Nb,
|
||||
Nl,
|
||||
Pl,
|
||||
Pt,
|
||||
PtBR,
|
||||
Ro,
|
||||
Ru,
|
||||
Sk,
|
||||
Sl,
|
||||
Sq,
|
||||
Sr,
|
||||
Sv,
|
||||
Th,
|
||||
Tr,
|
||||
Uk,
|
||||
Vi,
|
||||
ZhHans,
|
||||
ZhHant,
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
pub mod sync_response;
|
||||
pub mod utils;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
223
sdk/src/webhooks/sync_response.rs
Normal file
223
sdk/src/webhooks/sync_response.rs
Normal file
|
@ -0,0 +1,223 @@
|
|||
use serde::Serialize;
|
||||
|
||||
//Why are these few in snake_case but rest is camelCase?
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct CheckoutCalculateTaxesResponse {
|
||||
pub shipping_price_gross_amount: f32,
|
||||
pub shipping_price_net_amount: f32,
|
||||
pub shipping_tax_rate: f32,
|
||||
pub lines: Vec<LinesResponse>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct LinesResponse {
|
||||
pub total_gross_amount: f32,
|
||||
pub total_net_amount: f32,
|
||||
pub tax_rate: f32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct CheckoutFilterShippingMethodsResponse {
|
||||
pub excluded_methods: Vec<ExcludedMethodsResponse>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct ExcludedMethodsResponse {
|
||||
pub id: String,
|
||||
pub reason: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct OrderCalculateTaxes(CheckoutCalculateTaxesResponse);
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct OrderFilterShippingMethods(CheckoutFilterShippingMethodsResponse);
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct ShippingListMethodsForCheckout(Vec<ShippingListMethodsForCheckoutVec>);
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
struct ShippingListMethodsForCheckoutVec {
|
||||
pub id: String,
|
||||
pub name: Option<String>,
|
||||
pub amount: f32,
|
||||
pub currency: String,
|
||||
pub maximum_delivery_days: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum ChargeRequestedResult {
|
||||
ChargeSuccess,
|
||||
ChargeFailiure,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct TransactionChargeRequestedResponse {
|
||||
pub psp_reference: String,
|
||||
pub result: Option<ChargeRequestedResult>,
|
||||
pub amount: Option<f32>,
|
||||
pub time: Option<String>,
|
||||
pub external_url: Option<String>,
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum RefundRequestedResult {
|
||||
RefundSuccess,
|
||||
RefundFailiure,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TransactionRefundRequestedResponse {
|
||||
pub psp_reference: String,
|
||||
pub result: Option<RefundRequestedResult>,
|
||||
pub amount: Option<f32>,
|
||||
pub time: Option<String>,
|
||||
pub external_url: Option<String>,
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum CancelationRequestedResult {
|
||||
CancelSuccess,
|
||||
CancelFailiure,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TransactionCancelationRequestedResponse {
|
||||
pub psp_reference: String,
|
||||
pub result: Option<CancelationRequestedResult>,
|
||||
pub amount: Option<f32>,
|
||||
pub time: Option<String>,
|
||||
pub external_url: Option<String>,
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct PaymentGatewayInitializeSessionResponse<T: Serialize> {
|
||||
pub data: T,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum TransactionSessionResult {
|
||||
ChargeSuccess,
|
||||
ChargeFailiure,
|
||||
ChargeRequested,
|
||||
ChargeActionRequired,
|
||||
AuthorizationSuccess,
|
||||
AuthorizationFailure,
|
||||
AuthorizationRequested,
|
||||
AuthorizationActionRequired,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TransactionInitializeSessionResponse<T: Serialize> {
|
||||
pub psp_reference: Option<String>,
|
||||
pub data: Option<T>,
|
||||
pub result: TransactionSessionResult,
|
||||
pub amount: f32,
|
||||
pub time: Option<String>,
|
||||
pub external_url: Option<String>,
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TransactionProcessSessionResponse<T: Serialize> {
|
||||
pub psp_reference: Option<String>,
|
||||
pub data: Option<T>,
|
||||
pub result: TransactionSessionResult,
|
||||
pub amount: f32,
|
||||
pub time: Option<String>,
|
||||
pub external_url: Option<String>,
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum PaymentMethodTokenizationResult {
|
||||
SucessfullyTokenized,
|
||||
AdditionalActionRequired,
|
||||
Pending,
|
||||
FailedToTokenize,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PaymentMethodProcessTokenizationSession<T: Serialize> {
|
||||
pub result: PaymentMethodTokenizationResult,
|
||||
/**
|
||||
Should be present when `PaymentMethodTokenizationResult::{SuccessfullyTokenized && AdditionalActionRequired}`
|
||||
*/
|
||||
pub id: Option<String>,
|
||||
pub data: Option<T>,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct PaymentMethodInitializeTokenizationSession<T: Serialize>(
|
||||
PaymentMethodProcessTokenizationSession<T>,
|
||||
);
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum PaymentGatewayTokenisationResult {
|
||||
SuccessfullyInitialized,
|
||||
FailedToInitialize,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct PaymentGatewayInitializeTokenizationSession<T: Serialize> {
|
||||
pub result: PaymentGatewayTokenisationResult,
|
||||
pub data: Option<T>,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum StoredPaymentMethodDeleteResult {
|
||||
SucessfullyDeleted,
|
||||
FailedToDelete,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct StoredPaymentMethodDeleteRequested {
|
||||
pub result: StoredPaymentMethodDeleteResult,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
//TODO: Dahek is Array<"INTERACTIVE"> from app-sdk/../sync-webhook-response-builder.ts:LIST_STORED_PAYMENT_METHODS?
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PaymentMethod<T: Serialize> {
|
||||
pub id: String,
|
||||
pub supported_payment_flows: Vec<T>,
|
||||
#[serde(rename = "type")]
|
||||
pub typ: String,
|
||||
pub credit_card_info: Option<CreditCardInfo>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreditCardInfo {
|
||||
brand: String,
|
||||
last_digits: String,
|
||||
exp_month: String,
|
||||
exp_year: String,
|
||||
first_digits: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ListStoredPaymentMethodsResponse<T: Serialize, C: Serialize> {
|
||||
payment_methods: Vec<PaymentMethod<C>>,
|
||||
name: Option<String>,
|
||||
data: Option<T>,
|
||||
}
|
|
@ -34,6 +34,7 @@ surf.workspace = true
|
|||
cynic = { workspace = true, features = ["http-surf"] }
|
||||
cynic-codegen.workspace = true
|
||||
const_format = "0.2.32"
|
||||
enum-iterator = "2.0.0"
|
||||
|
||||
[build-dependencies]
|
||||
cynic-codegen.workspace = true
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use axum::{
|
||||
http::StatusCode,
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use enum_iterator::{all, Sequence};
|
||||
use std::{fmt::Display, str::FromStr, sync::Arc};
|
||||
|
||||
use saleor_app_sdk::{config::Config, manifest::AppManifest, SaleorApp};
|
||||
use saleor_app_sdk::{config::Config, locales::LocaleCode, manifest::AppManifest, SaleorApp};
|
||||
use serde::{
|
||||
de::{self, Visitor},
|
||||
Deserialize, Deserializer, Serialize,
|
||||
};
|
||||
// Make our own error that wraps `anyhow::Error`.
|
||||
pub struct AppError(anyhow::Error);
|
||||
|
||||
|
@ -38,9 +42,66 @@ pub fn trace_to_std(config: &Config) {
|
|||
.init();
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Sequence, Serialize)]
|
||||
pub enum GatewayType {
|
||||
Accreditation,
|
||||
Cash,
|
||||
/**
|
||||
Acronym for Cash on Delivery
|
||||
*/
|
||||
COD,
|
||||
Inkaso,
|
||||
Other,
|
||||
Transfer,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AppState {
|
||||
pub saleor_app: Arc<tokio::sync::Mutex<SaleorApp>>,
|
||||
pub config: Config,
|
||||
pub manifest: AppManifest,
|
||||
pub active_gateways: Vec<ActiveGateway>,
|
||||
}
|
||||
|
||||
pub fn get_active_gateways_from_env() -> anyhow::Result<Vec<ActiveGateway>> {
|
||||
dotenvy::dotenv()?;
|
||||
//eg: "accreditation,cod,other,transfer"
|
||||
let env_types = std::env::var("ACTIVE_GATEWAYS")?;
|
||||
let locale = std::env::var("LOCALE")?;
|
||||
let locale = match locale.as_str() {
|
||||
"SK" => LocaleCode::Sk,
|
||||
"EN" => LocaleCode::En,
|
||||
l => unimplemented!("Locale {l} not implemented"),
|
||||
};
|
||||
|
||||
let str_types: Vec<_> = env_types.split(",").collect();
|
||||
let gateway_types = str_types
|
||||
.iter()
|
||||
.zip(all::<GatewayType>())
|
||||
.filter_map(|(s, g)| match format!("{:?}", g).to_lowercase() == *s {
|
||||
true => Some(g),
|
||||
false => None,
|
||||
})
|
||||
.map(|g| )
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct ActiveGateway {
|
||||
pub gateway_type: GatewayType,
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub currencies: Vec<String>,
|
||||
//don't need this one yet
|
||||
pub config: [(); 0],
|
||||
}
|
||||
impl ActiveGateway{
|
||||
fn from_gateway_type(ty: &GatewayType) -> Self {
|
||||
all_currencies =
|
||||
match type {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,11 +16,11 @@ use std::sync::Arc;
|
|||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::{
|
||||
app::{trace_to_std, AppState},
|
||||
app::{get_active_gateways_from_env, trace_to_std, AppState},
|
||||
queries::event_transactions::{
|
||||
sub_payment_gateway_initialize_session, sub_transaction_charge_requested,
|
||||
sub_transaction_initialize_session, sub_transaction_process_session,
|
||||
sub_transaction_refund_requested,
|
||||
sub_list_payment_gateways, sub_payment_gateway_initialize_session,
|
||||
sub_transaction_charge_requested, sub_transaction_initialize_session,
|
||||
sub_transaction_process_session, sub_transaction_refund_requested,
|
||||
},
|
||||
routes::create_routes,
|
||||
};
|
||||
|
@ -63,6 +63,12 @@ async fn main() -> anyhow::Result<()> {
|
|||
.add_sync_event(SyncWebhookEventType::PaymentGatewayInitializeSession)
|
||||
.build(),
|
||||
)
|
||||
.add_webhook(
|
||||
WebhookManifest::new(&config)
|
||||
.set_query(sub_list_payment_gateways)
|
||||
.add_sync_event(SyncWebhookEventType::PaymentListGateways)
|
||||
.build(),
|
||||
)
|
||||
.add_permissions(vec![
|
||||
AppPermission::HandlePayments,
|
||||
AppPermission::ManageOrders,
|
||||
|
@ -70,7 +76,9 @@ async fn main() -> anyhow::Result<()> {
|
|||
AppPermission::HandleCheckouts,
|
||||
])
|
||||
.build();
|
||||
|
||||
let app_state = AppState {
|
||||
active_gateways: get_active_gateways_from_env()?,
|
||||
manifest: app_manifest,
|
||||
config: config.clone(),
|
||||
saleor_app: Arc::new(Mutex::new(saleor_app)),
|
||||
|
|
|
@ -55,6 +55,18 @@ fragment OrderDetails on Order {
|
|||
}
|
||||
"#;
|
||||
|
||||
pub const sub_list_payment_gateways: &str = r#"
|
||||
subscription ListPaymentGateways {
|
||||
event {
|
||||
... on PaymentListGateways {
|
||||
checkout {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
pub const sub_payment_gateway_initialize_session: &str = concatcp!(
|
||||
r#"
|
||||
subscription PaymentGatewayInitializeSession {
|
||||
|
@ -178,3 +190,246 @@ subscription transactionCancelationRequested {
|
|||
"#,
|
||||
fragment_transaction_details
|
||||
);
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "TransactionRefundRequested")]
|
||||
pub struct TransactionRefundRequested2 {
|
||||
pub action: TransactionAction,
|
||||
pub transaction: Option<TransactionItem>,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "TransactionProcessSession")]
|
||||
pub struct TransactionProcessSession2 {
|
||||
pub action: TransactionProcessAction,
|
||||
pub source_object: OrderOrCheckout,
|
||||
pub transaction: TransactionItem,
|
||||
pub data: Option<Json>,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
pub struct TransactionProcessAction {
|
||||
pub amount: PositiveDecimal,
|
||||
pub action_type: TransactionFlowStrategyEnum,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "TransactionInitializeSession")]
|
||||
pub struct TransactionInitializeSession2 {
|
||||
pub data: Option<Json>,
|
||||
pub source_object: OrderOrCheckout,
|
||||
pub transaction: TransactionItem,
|
||||
pub action: TransactionProcessAction2,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "TransactionProcessAction")]
|
||||
pub struct TransactionProcessAction2 {
|
||||
pub amount: PositiveDecimal,
|
||||
pub currency: String,
|
||||
pub action_type: TransactionFlowStrategyEnum,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "TransactionChargeRequested")]
|
||||
pub struct TransactionChargeRequested2 {
|
||||
pub action: TransactionAction,
|
||||
pub transaction: Option<TransactionItem>,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "TransactionCancelationRequested")]
|
||||
pub struct TransactionCancelationRequested2 {
|
||||
pub action: TransactionAction,
|
||||
pub transaction: Option<TransactionItem>,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
pub struct TransactionItem {
|
||||
pub id: cynic::Id,
|
||||
pub actions: Vec<TransactionActionEnum>,
|
||||
pub external_url: String,
|
||||
pub message: String,
|
||||
pub authorized_amount: Money,
|
||||
pub authorize_pending_amount: Money,
|
||||
pub canceled_amount: Money,
|
||||
pub cancel_pending_amount: Money,
|
||||
pub charged_amount: Money,
|
||||
pub charge_pending_amount: Money,
|
||||
pub refunded_amount: Money,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
pub struct TransactionAction {
|
||||
pub amount: Option<PositiveDecimal>,
|
||||
pub action_type: TransactionActionEnum,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "Subscription")]
|
||||
pub struct TransactionRefundRequested {
|
||||
pub event: Option<Event>,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "Subscription")]
|
||||
pub struct TransactionProcessSession {
|
||||
pub event: Option<Event2>,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "Subscription")]
|
||||
pub struct TransactionInitializeSession {
|
||||
pub event: Option<Event3>,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "Subscription")]
|
||||
pub struct TransactionChargeRequested {
|
||||
pub event: Option<Event4>,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "Subscription")]
|
||||
pub struct TransactionCancelationRequested {
|
||||
pub event: Option<Event5>,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "Subscription")]
|
||||
pub struct PaymentGatewayInitializeSession {
|
||||
pub event: Option<Event6>,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "PaymentGatewayInitializeSession")]
|
||||
pub struct PaymentGatewayInitializeSession2 {
|
||||
pub data: Option<Json>,
|
||||
pub amount: Option<PositiveDecimal>,
|
||||
pub source_object: OrderOrCheckout,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
pub struct Order {
|
||||
pub checkout_id: Option<cynic::Id>,
|
||||
pub id: cynic::Id,
|
||||
pub status: OrderStatus,
|
||||
pub is_paid: bool,
|
||||
pub payment_status: PaymentChargeStatusEnum,
|
||||
pub charge_status: OrderChargeStatusEnum,
|
||||
pub can_finalize: bool,
|
||||
pub total_balance: Money,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
pub struct Money {
|
||||
pub currency: String,
|
||||
pub amount: f64,
|
||||
}
|
||||
|
||||
#[derive(cynic::InlineFragments, Debug)]
|
||||
#[cynic(graphql_type = "Event")]
|
||||
pub enum Event6 {
|
||||
PaymentGatewayInitializeSession2(PaymentGatewayInitializeSession2),
|
||||
#[cynic(fallback)]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(cynic::InlineFragments, Debug)]
|
||||
#[cynic(graphql_type = "Event")]
|
||||
pub enum Event5 {
|
||||
TransactionCancelationRequested2(TransactionCancelationRequested2),
|
||||
#[cynic(fallback)]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(cynic::InlineFragments, Debug)]
|
||||
#[cynic(graphql_type = "Event")]
|
||||
pub enum Event4 {
|
||||
TransactionChargeRequested2(TransactionChargeRequested2),
|
||||
#[cynic(fallback)]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(cynic::InlineFragments, Debug)]
|
||||
#[cynic(graphql_type = "Event")]
|
||||
pub enum Event3 {
|
||||
TransactionInitializeSession2(TransactionInitializeSession2),
|
||||
#[cynic(fallback)]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(cynic::InlineFragments, Debug)]
|
||||
#[cynic(graphql_type = "Event")]
|
||||
pub enum Event2 {
|
||||
TransactionProcessSession2(TransactionProcessSession2),
|
||||
#[cynic(fallback)]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(cynic::InlineFragments, Debug)]
|
||||
pub enum Event {
|
||||
TransactionRefundRequested2(TransactionRefundRequested2),
|
||||
#[cynic(fallback)]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(cynic::InlineFragments, Debug)]
|
||||
pub enum OrderOrCheckout {
|
||||
Order(Order),
|
||||
#[cynic(fallback)]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(cynic::Enum, Clone, Copy, Debug)]
|
||||
pub enum OrderChargeStatusEnum {
|
||||
None,
|
||||
Partial,
|
||||
Full,
|
||||
Overcharged,
|
||||
}
|
||||
|
||||
#[derive(cynic::Enum, Clone, Copy, Debug)]
|
||||
pub enum OrderStatus {
|
||||
Draft,
|
||||
Unconfirmed,
|
||||
Unfulfilled,
|
||||
PartiallyFulfilled,
|
||||
PartiallyReturned,
|
||||
Returned,
|
||||
Fulfilled,
|
||||
Canceled,
|
||||
Expired,
|
||||
}
|
||||
|
||||
#[derive(cynic::Enum, Clone, Copy, Debug)]
|
||||
pub enum PaymentChargeStatusEnum {
|
||||
NotCharged,
|
||||
Pending,
|
||||
PartiallyCharged,
|
||||
FullyCharged,
|
||||
PartiallyRefunded,
|
||||
FullyRefunded,
|
||||
Refused,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
#[derive(cynic::Enum, Clone, Copy, Debug)]
|
||||
pub enum TransactionActionEnum {
|
||||
Charge,
|
||||
Refund,
|
||||
Cancel,
|
||||
}
|
||||
|
||||
#[derive(cynic::Enum, Clone, Copy, Debug)]
|
||||
pub enum TransactionFlowStrategyEnum {
|
||||
Authorization,
|
||||
Charge,
|
||||
}
|
||||
|
||||
#[derive(cynic::Scalar, Debug, Clone)]
|
||||
#[cynic(graphql_type = "JSON")]
|
||||
pub struct Json(pub String);
|
||||
|
||||
#[derive(cynic::Scalar, Debug, Clone)]
|
||||
pub struct PositiveDecimal(pub String);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#[cynic::schema("saleor")]
|
||||
mod schema {}
|
||||
/*
|
||||
mutation transactionUpdate($id: ID!, $transaction: TransactionUpdateInput) {
|
||||
transactionUpdate(id: $id, transaction: $transaction) {
|
||||
|
@ -15,3 +17,85 @@ mutation transactionUpdate($id: ID!, $transaction: TransactionUpdateInput) {
|
|||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[derive(cynic::QueryVariables, Debug)]
|
||||
pub struct TransactionUpdateVariables<'a> {
|
||||
pub id: &'a cynic::Id,
|
||||
pub transaction: Option<TransactionUpdateInput<'a>>,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "Mutation", variables = "TransactionUpdateVariables")]
|
||||
pub struct TransactionUpdate {
|
||||
#[arguments(id: $id, transaction: $transaction)]
|
||||
pub transaction_update: Option<TransactionUpdate2>,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
#[cynic(graphql_type = "TransactionUpdate")]
|
||||
pub struct TransactionUpdate2 {
|
||||
pub transaction: Option<TransactionItem>,
|
||||
pub errors: Vec<TransactionUpdateError>,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
pub struct TransactionUpdateError {
|
||||
pub field: Option<String>,
|
||||
pub message: Option<String>,
|
||||
pub code: TransactionUpdateErrorCode,
|
||||
}
|
||||
|
||||
#[derive(cynic::QueryFragment, Debug)]
|
||||
pub struct TransactionItem {
|
||||
pub id: cynic::Id,
|
||||
pub actions: Vec<TransactionActionEnum>,
|
||||
pub external_url: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(cynic::Enum, Clone, Copy, Debug)]
|
||||
pub enum TransactionActionEnum {
|
||||
Charge,
|
||||
Refund,
|
||||
Cancel,
|
||||
}
|
||||
|
||||
#[derive(cynic::Enum, Clone, Copy, Debug)]
|
||||
pub enum TransactionUpdateErrorCode {
|
||||
Invalid,
|
||||
GraphqlError,
|
||||
NotFound,
|
||||
IncorrectCurrency,
|
||||
MetadataKeyRequired,
|
||||
Unique,
|
||||
}
|
||||
|
||||
#[derive(cynic::InputObject, Debug)]
|
||||
pub struct TransactionUpdateInput<'a> {
|
||||
pub name: Option<&'a str>,
|
||||
pub message: Option<&'a str>,
|
||||
pub psp_reference: Option<&'a str>,
|
||||
pub available_actions: Option<Vec<TransactionActionEnum>>,
|
||||
pub amount_authorized: Option<MoneyInput<'a>>,
|
||||
pub amount_charged: Option<MoneyInput<'a>>,
|
||||
pub amount_refunded: Option<MoneyInput<'a>>,
|
||||
pub amount_canceled: Option<MoneyInput<'a>>,
|
||||
pub metadata: Option<Vec<MetadataInput<'a>>>,
|
||||
pub private_metadata: Option<Vec<MetadataInput<'a>>>,
|
||||
pub external_url: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(cynic::InputObject, Debug)]
|
||||
pub struct MoneyInput<'a> {
|
||||
pub currency: &'a str,
|
||||
pub amount: PositiveDecimal,
|
||||
}
|
||||
|
||||
#[derive(cynic::InputObject, Debug)]
|
||||
pub struct MetadataInput<'a> {
|
||||
pub key: &'a str,
|
||||
pub value: &'a str,
|
||||
}
|
||||
|
||||
#[derive(cynic::Scalar, Debug, Clone)]
|
||||
pub struct PositiveDecimal(pub String);
|
||||
|
|
|
@ -22,7 +22,7 @@ pub fn create_routes(state: AppState) -> Router {
|
|||
(StatusCode::NOT_FOUND, "Not found")
|
||||
}
|
||||
let service = handle_404.into_service();
|
||||
let serve_dir = ServeDir::new("saleor-app-template/public").not_found_service(service);
|
||||
let serve_dir = ServeDir::new("simple-payment-gateway/public").not_found_service(service);
|
||||
|
||||
Router::new()
|
||||
.layer(middleware::from_fn(webhook_signature_verifier))
|
||||
|
|
|
@ -5,7 +5,7 @@ use axum::{
|
|||
http::{HeaderMap, StatusCode},
|
||||
};
|
||||
use saleor_app_sdk::{AuthData, AuthToken};
|
||||
use tracing::{debug, info};
|
||||
use tracing::{debug, error, info};
|
||||
|
||||
use crate::app::{AppError, AppState};
|
||||
|
||||
|
@ -29,12 +29,25 @@ pub async fn register(
|
|||
let auth_data = AuthData {
|
||||
jwks: None,
|
||||
token: auth_token.auth_token,
|
||||
domain: Some(state.config.app_api_base_url),
|
||||
app_id: state.manifest.id,
|
||||
domain: Some(state.config.app_api_base_url.clone()),
|
||||
app_id: state.manifest.id.clone(),
|
||||
saleor_api_url: saleor_api_url.clone(),
|
||||
};
|
||||
app.apl.set(auth_data).await?;
|
||||
|
||||
app.apl.set(auth_data.clone()).await?;
|
||||
//unlock the mutex guard so state isn't borrowed anymore and it can move
|
||||
std::mem::drop(app);
|
||||
info!("registered app for{:?}", &saleor_api_url);
|
||||
tokio::spawn(async move {
|
||||
match register_active_gateways(&state, auth_data).await {
|
||||
Ok(_) => info!("Payment gateways registered"),
|
||||
Err(e) => error!("Failed registering gateways, {e}"),
|
||||
};
|
||||
});
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
||||
pub async fn register_active_gateways(state: &AppState, auth_data: AuthData) -> anyhow::Result<()> {
|
||||
// Maybe AppFetch manifest? Tho I might not need to since I already have it
|
||||
// AppsInstallations to see if it's still installing
|
||||
todo!()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Context;
|
||||
use axum::{
|
||||
body::Body,
|
||||
extract::State,
|
||||
http::{HeaderMap, StatusCode},
|
||||
response::Response,
|
||||
Json,
|
||||
};
|
||||
use saleor_app_sdk::{
|
||||
headers::SALEOR_API_URL_HEADER,
|
||||
|
@ -10,15 +15,20 @@ use saleor_app_sdk::{
|
|||
SyncWebhookEventType,
|
||||
},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use tracing::{debug, error, info};
|
||||
|
||||
use crate::app::{AppError, AppState};
|
||||
use crate::{
|
||||
app::{ActiveGateway, AppError, AppState},
|
||||
queries::event_transactions::PaymentGatewayInitializeSession,
|
||||
};
|
||||
|
||||
pub async fn webhooks(
|
||||
headers: HeaderMap,
|
||||
State(state): State<AppState>,
|
||||
body: String,
|
||||
) -> Result<StatusCode, AppError> {
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
debug!("/api/webhooks");
|
||||
debug!("req: {:?}", body);
|
||||
debug!("headers: {:?}", headers);
|
||||
|
@ -29,30 +39,47 @@ pub async fn webhooks(
|
|||
.to_str()?
|
||||
.to_owned();
|
||||
let event_type = get_webhook_event_type(&headers)?;
|
||||
match event_type {
|
||||
let res: Json<Value> = match event_type {
|
||||
EitherWebhookType::Sync(a) => match a {
|
||||
SyncWebhookEventType::PaymentGatewayInitializeSession => {
|
||||
initialize_gateway(&state, &url).await?;
|
||||
Json::from(serde_json::to_value(JsonResponse {
|
||||
data: JsonResponseData {
|
||||
current_gateway: ActiveGateway::COD,
|
||||
},
|
||||
})?)
|
||||
}
|
||||
SyncWebhookEventType::TransactionProcessSession
|
||||
| SyncWebhookEventType::TransactionChargeRequested
|
||||
| SyncWebhookEventType::TransactionRefundRequested
|
||||
| SyncWebhookEventType::TransactionInitializeSession => {
|
||||
update_transaction_response(&state, &url).await?;
|
||||
todo!()
|
||||
}
|
||||
_ => (),
|
||||
_ => Json::from(Value::from_str("")?),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
_ => Json::from(Value::from_str("")?),
|
||||
};
|
||||
|
||||
info!("got webhooks!");
|
||||
Ok(StatusCode::OK)
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
async fn initialize_gateway(state: &AppState, saleor_api_url: &str) -> anyhow::Result<()> {
|
||||
todo!()
|
||||
#[derive(Serialize, Clone, Debug)]
|
||||
pub struct JsonResponse {
|
||||
data: JsonResponseData,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone, Debug)]
|
||||
pub struct JsonResponseData {
|
||||
current_gateway: ActiveGateway,
|
||||
}
|
||||
|
||||
async fn update_transaction_response(state: &AppState, saleor_api_url: &str) -> anyhow::Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn new_transaction_response(state: &AppState, saleor_api_url: &str) -> anyhow::Result<()> {
|
||||
debug!("Creating new transaction");
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
|
|
@ -25,6 +25,9 @@ pub fn create_routes(state: AppState) -> Router {
|
|||
//TODO : Fix this relative path issue in workspaces
|
||||
let serve_dir = ServeDir::new("./sitemap-generator/public").not_found_service(service);
|
||||
|
||||
//TODO Query for everything using the app auth token
|
||||
//TODO "Failed fetching initial products: More than one channel exists, please spocify which
|
||||
//one"
|
||||
Router::new()
|
||||
.route("/api/webhooks", any(webhooks))
|
||||
.layer(middleware::from_fn(webhook_signature_verifier))
|
||||
|
|
Loading…
Reference in a new issue