diff --git a/.env b/.env index 8915e24..997de49 100644 --- a/.env +++ b/.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" diff --git a/Cargo.lock b/Cargo.lock index b8de512..7bf0747 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index 124501d..0000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,3 +0,0 @@ -[toolchain] -channel = "nightly" -targets = ["x86_64-unknown-linux-musl"] diff --git a/rust-toolchain.tomln b/rust-toolchain.tomln new file mode 100644 index 0000000..4c8ab40 --- /dev/null +++ b/rust-toolchain.tomln @@ -0,0 +1,4 @@ +[toolchain] +channel = "nightly" +#targets = ["x86_64-unknown-linux-musl"] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 2723f36..5166046 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -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, } + impl std::fmt::Display for AuthData { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( diff --git a/sdk/src/locales.rs b/sdk/src/locales.rs new file mode 100644 index 0000000..b5f4e16 --- /dev/null +++ b/sdk/src/locales.rs @@ -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, +} diff --git a/sdk/src/webhooks/mod.rs b/sdk/src/webhooks/mod.rs index bbc0580..d041195 100644 --- a/sdk/src/webhooks/mod.rs +++ b/sdk/src/webhooks/mod.rs @@ -1,3 +1,4 @@ +pub mod sync_response; pub mod utils; use serde::{Deserialize, Serialize}; diff --git a/sdk/src/webhooks/sync_response.rs b/sdk/src/webhooks/sync_response.rs new file mode 100644 index 0000000..477e448 --- /dev/null +++ b/sdk/src/webhooks/sync_response.rs @@ -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, +} + +#[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, +} + +#[derive(Serialize, Debug, Clone)] +pub struct ExcludedMethodsResponse { + pub id: String, + pub reason: Option, +} + +#[derive(Serialize, Debug, Clone)] +pub struct OrderCalculateTaxes(CheckoutCalculateTaxesResponse); + +#[derive(Serialize, Debug, Clone)] +pub struct OrderFilterShippingMethods(CheckoutFilterShippingMethodsResponse); + +#[derive(Serialize, Debug, Clone)] +pub struct ShippingListMethodsForCheckout(Vec); + +#[derive(Serialize, Debug, Clone)] +struct ShippingListMethodsForCheckoutVec { + pub id: String, + pub name: Option, + pub amount: f32, + pub currency: String, + pub maximum_delivery_days: Option, +} + +#[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, + pub amount: Option, + pub time: Option, + pub external_url: Option, + pub message: Option, +} + +#[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, + pub amount: Option, + pub time: Option, + pub external_url: Option, + pub message: Option, +} + +#[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, + pub amount: Option, + pub time: Option, + pub external_url: Option, + pub message: Option, +} + +#[derive(Serialize, Debug, Clone)] +pub struct PaymentGatewayInitializeSessionResponse { + 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 { + pub psp_reference: Option, + pub data: Option, + pub result: TransactionSessionResult, + pub amount: f32, + pub time: Option, + pub external_url: Option, + pub message: Option, +} + +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct TransactionProcessSessionResponse { + pub psp_reference: Option, + pub data: Option, + pub result: TransactionSessionResult, + pub amount: f32, + pub time: Option, + pub external_url: Option, + pub message: Option, +} + +#[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 { + pub result: PaymentMethodTokenizationResult, + /** + Should be present when `PaymentMethodTokenizationResult::{SuccessfullyTokenized && AdditionalActionRequired}` + */ + pub id: Option, + pub data: Option, + pub error: Option, +} + +#[derive(Serialize, Debug, Clone)] +pub struct PaymentMethodInitializeTokenizationSession( + PaymentMethodProcessTokenizationSession, +); + +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum PaymentGatewayTokenisationResult { + SuccessfullyInitialized, + FailedToInitialize, +} + +#[derive(Serialize, Debug, Clone)] +pub struct PaymentGatewayInitializeTokenizationSession { + pub result: PaymentGatewayTokenisationResult, + pub data: Option, + pub error: Option, +} + +#[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, +} + +//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 { + pub id: String, + pub supported_payment_flows: Vec, + #[serde(rename = "type")] + pub typ: String, + pub credit_card_info: Option, +} + +#[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, +} + +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ListStoredPaymentMethodsResponse { + payment_methods: Vec>, + name: Option, + data: Option, +} diff --git a/simple-payment-gateway/Cargo.toml b/simple-payment-gateway/Cargo.toml index a980817..1595898 100644 --- a/simple-payment-gateway/Cargo.toml +++ b/simple-payment-gateway/Cargo.toml @@ -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 diff --git a/simple-payment-gateway/src/app.rs b/simple-payment-gateway/src/app.rs index 14944ec..6c3d883 100644 --- a/simple-payment-gateway/src/app.rs +++ b/simple-payment-gateway/src/app.rs @@ -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>, pub config: Config, pub manifest: AppManifest, + pub active_gateways: Vec, +} + +pub fn get_active_gateways_from_env() -> anyhow::Result> { + 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::()) + .filter_map(|(s, g)| match format!("{:?}", g).to_lowercase() == *s { + true => Some(g), + false => None, + }) + .map(|g| ) + .collect::>(); + + todo!() +} + +#[derive(Debug, Clone, Serialize)] +pub struct ActiveGateway { + pub gateway_type: GatewayType, + pub id: String, + pub name: String, + pub currencies: Vec, + //don't need this one yet + pub config: [(); 0], +} +impl ActiveGateway{ + fn from_gateway_type(ty: &GatewayType) -> Self { + all_currencies = + match type { + + } + } } diff --git a/simple-payment-gateway/src/main.rs b/simple-payment-gateway/src/main.rs index 93a875b..2c9d2bb 100644 --- a/simple-payment-gateway/src/main.rs +++ b/simple-payment-gateway/src/main.rs @@ -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)), diff --git a/simple-payment-gateway/src/queries/event_transactions.rs b/simple-payment-gateway/src/queries/event_transactions.rs index 6695f3b..750c10e 100644 --- a/simple-payment-gateway/src/queries/event_transactions.rs +++ b/simple-payment-gateway/src/queries/event_transactions.rs @@ -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, +} + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(graphql_type = "TransactionProcessSession")] +pub struct TransactionProcessSession2 { + pub action: TransactionProcessAction, + pub source_object: OrderOrCheckout, + pub transaction: TransactionItem, + pub data: Option, +} + +#[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, + 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, +} + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(graphql_type = "TransactionCancelationRequested")] +pub struct TransactionCancelationRequested2 { + pub action: TransactionAction, + pub transaction: Option, +} + +#[derive(cynic::QueryFragment, Debug)] +pub struct TransactionItem { + pub id: cynic::Id, + pub actions: Vec, + 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, + pub action_type: TransactionActionEnum, +} + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(graphql_type = "Subscription")] +pub struct TransactionRefundRequested { + pub event: Option, +} + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(graphql_type = "Subscription")] +pub struct TransactionProcessSession { + pub event: Option, +} + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(graphql_type = "Subscription")] +pub struct TransactionInitializeSession { + pub event: Option, +} + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(graphql_type = "Subscription")] +pub struct TransactionChargeRequested { + pub event: Option, +} + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(graphql_type = "Subscription")] +pub struct TransactionCancelationRequested { + pub event: Option, +} + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(graphql_type = "Subscription")] +pub struct PaymentGatewayInitializeSession { + pub event: Option, +} + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(graphql_type = "PaymentGatewayInitializeSession")] +pub struct PaymentGatewayInitializeSession2 { + pub data: Option, + pub amount: Option, + pub source_object: OrderOrCheckout, +} + +#[derive(cynic::QueryFragment, Debug)] +pub struct Order { + pub checkout_id: Option, + 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); diff --git a/simple-payment-gateway/src/queries/mutation_transaction_update.rs b/simple-payment-gateway/src/queries/mutation_transaction_update.rs index 26499c6..02e162e 100644 --- a/simple-payment-gateway/src/queries/mutation_transaction_update.rs +++ b/simple-payment-gateway/src/queries/mutation_transaction_update.rs @@ -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>, +} + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(graphql_type = "Mutation", variables = "TransactionUpdateVariables")] +pub struct TransactionUpdate { + #[arguments(id: $id, transaction: $transaction)] + pub transaction_update: Option, +} + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(graphql_type = "TransactionUpdate")] +pub struct TransactionUpdate2 { + pub transaction: Option, + pub errors: Vec, +} + +#[derive(cynic::QueryFragment, Debug)] +pub struct TransactionUpdateError { + pub field: Option, + pub message: Option, + pub code: TransactionUpdateErrorCode, +} + +#[derive(cynic::QueryFragment, Debug)] +pub struct TransactionItem { + pub id: cynic::Id, + pub actions: Vec, + 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>, + pub amount_authorized: Option>, + pub amount_charged: Option>, + pub amount_refunded: Option>, + pub amount_canceled: Option>, + pub metadata: Option>>, + pub private_metadata: Option>>, + 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); diff --git a/simple-payment-gateway/src/routes/mod.rs b/simple-payment-gateway/src/routes/mod.rs index 5124453..0af534a 100644 --- a/simple-payment-gateway/src/routes/mod.rs +++ b/simple-payment-gateway/src/routes/mod.rs @@ -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)) diff --git a/simple-payment-gateway/src/routes/register.rs b/simple-payment-gateway/src/routes/register.rs index 2203984..9379881 100644 --- a/simple-payment-gateway/src/routes/register.rs +++ b/simple-payment-gateway/src/routes/register.rs @@ -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!() +} diff --git a/simple-payment-gateway/src/routes/webhooks.rs b/simple-payment-gateway/src/routes/webhooks.rs index ec70877..758e792 100644 --- a/simple-payment-gateway/src/routes/webhooks.rs +++ b/simple-payment-gateway/src/routes/webhooks.rs @@ -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, body: String, -) -> Result { +) -> Result, 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 = 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!() +} diff --git a/sitemap-generator/src/routes/mod.rs b/sitemap-generator/src/routes/mod.rs index ee95703..5c251e7 100644 --- a/sitemap-generator/src/routes/mod.rs +++ b/sitemap-generator/src/routes/mod.rs @@ -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))