finally it works

This commit is contained in:
Djkáťo 2024-04-15 19:51:15 +02:00
parent fd0a218f23
commit 8e142c813d
4 changed files with 135 additions and 79 deletions

View file

@ -49,7 +49,7 @@ pub fn trace_to_std(config: &Config) -> anyhow::Result<()> {
Ok(()) Ok(())
} }
#[derive(Debug, Clone, Sequence, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Copy, Sequence, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
pub enum PaymentMethodType { pub enum PaymentMethodType {
Accreditation, Accreditation,
@ -94,7 +94,7 @@ pub fn get_active_payment_methods_from_env() -> anyhow::Result<Vec<ActivePayment
false => None, false => None,
}) })
.map(|g| ActivePaymentMethod { .map(|g| ActivePaymentMethod {
typ: g.clone(), typ: g,
name: match (g, &locale) { name: match (g, &locale) {
(PaymentMethodType::COD, LocaleCode::Sk) => "Dobierka".to_owned(), (PaymentMethodType::COD, LocaleCode::Sk) => "Dobierka".to_owned(),
(PaymentMethodType::Cash, LocaleCode::Sk) => "Hotovosť".to_owned(), (PaymentMethodType::Cash, LocaleCode::Sk) => "Hotovosť".to_owned(),

View file

@ -1,4 +1,8 @@
use const_format::concatcp; use const_format::concatcp;
use serde::{Deserialize, Serialize};
use crate::app::PaymentMethodType;
#[cynic::schema("saleor")] #[cynic::schema("saleor")]
mod schema {} mod schema {}
@ -7,6 +11,7 @@ fragment CheckoutDetails on Checkout {
id id
isShippingRequired isShippingRequired
deliveryMethod { deliveryMethod {
__typename
... on Warehouse { ... on Warehouse {
name name
id id
@ -94,6 +99,7 @@ subscription PaymentGatewayInitializeSession {
data data
amount amount
sourceObject { sourceObject {
__typename
... on Checkout { ... on Checkout {
...CheckoutDetails ...CheckoutDetails
} }
@ -117,6 +123,7 @@ subscription transactionInitializeSession {
... on TransactionInitializeSession { ... on TransactionInitializeSession {
data data
sourceObject { sourceObject {
__typename
... on Checkout { ... on Checkout {
...CheckoutDetails ...CheckoutDetails
} }
@ -151,6 +158,7 @@ subscription transactionProcessSession {
actionType actionType
} }
sourceObject { sourceObject {
__typename
... on Checkout { ... on Checkout {
...CheckoutDetails ...CheckoutDetails
} }
@ -247,7 +255,7 @@ pub struct TransactionProcessSession2 {
pub action: TransactionProcessAction, pub action: TransactionProcessAction,
pub source_object: OrderOrCheckout, pub source_object: OrderOrCheckout,
pub transaction: TransactionItem, pub transaction: TransactionItem,
pub data: Option<Json>, pub data: Option<ChosenPaymentMethodData>,
} }
#[derive(cynic::QueryFragment, Debug)] #[derive(cynic::QueryFragment, Debug)]
@ -259,7 +267,7 @@ pub struct TransactionProcessAction {
#[derive(cynic::QueryFragment, Debug)] #[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "TransactionInitializeSession")] #[cynic(graphql_type = "TransactionInitializeSession")]
pub struct TransactionInitializeSession2 { pub struct TransactionInitializeSession2 {
pub data: Option<Json>, pub data: Option<ChosenPaymentMethodData>,
pub source_object: OrderOrCheckout, pub source_object: OrderOrCheckout,
pub transaction: TransactionItem, pub transaction: TransactionItem,
pub action: TransactionProcessAction2, pub action: TransactionProcessAction2,
@ -353,7 +361,7 @@ pub struct ShippingMethod {
#[derive(cynic::QueryFragment, Debug)] #[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "PaymentGatewayInitializeSession")] #[cynic(graphql_type = "PaymentGatewayInitializeSession")]
pub struct PaymentGatewayInitializeSession2 { pub struct PaymentGatewayInitializeSession2 {
pub data: Option<Json>, pub data: Option<ChosenPaymentMethodData>,
pub amount: Option<PositiveDecimal>, pub amount: Option<PositiveDecimal>,
pub source_object: OrderOrCheckout, pub source_object: OrderOrCheckout,
} }
@ -494,9 +502,11 @@ pub enum TransactionFlowStrategyEnum {
Charge, Charge,
} }
#[derive(cynic::Scalar, Debug, Clone)] #[derive(Serialize, Deserialize, Clone, Copy, Debug)]
#[cynic(graphql_type = "JSON")] pub struct ChosenPaymentMethodData {
pub struct Json(pub String); pub payment_method: PaymentMethodType,
}
cynic::impl_scalar!(ChosenPaymentMethodData, schema::JSON);
#[derive(cynic::Scalar, Debug, Clone)] #[derive(cynic::Scalar, Debug, Clone)]
pub struct PositiveDecimal(pub String); pub struct PositiveDecimal(pub f32);

View file

@ -72,16 +72,27 @@ pub enum TransactionUpdateErrorCode {
#[derive(cynic::InputObject, Debug, Default)] #[derive(cynic::InputObject, Debug, Default)]
pub struct TransactionUpdateInput<'a> { pub struct TransactionUpdateInput<'a> {
#[cynic(skip_serializing_if = "Option::is_none")]
pub name: Option<&'a str>, pub name: Option<&'a str>,
#[cynic(skip_serializing_if = "Option::is_none")]
pub message: Option<&'a str>, pub message: Option<&'a str>,
#[cynic(skip_serializing_if = "Option::is_none")]
pub psp_reference: Option<&'a str>, pub psp_reference: Option<&'a str>,
#[cynic(skip_serializing_if = "Option::is_none")]
pub available_actions: Option<Vec<TransactionActionEnum>>, pub available_actions: Option<Vec<TransactionActionEnum>>,
#[cynic(skip_serializing_if = "Option::is_none")]
pub amount_authorized: Option<MoneyInput<'a>>, pub amount_authorized: Option<MoneyInput<'a>>,
#[cynic(skip_serializing_if = "Option::is_none")]
pub amount_charged: Option<MoneyInput<'a>>, pub amount_charged: Option<MoneyInput<'a>>,
#[cynic(skip_serializing_if = "Option::is_none")]
pub amount_refunded: Option<MoneyInput<'a>>, pub amount_refunded: Option<MoneyInput<'a>>,
#[cynic(skip_serializing_if = "Option::is_none")]
pub amount_canceled: Option<MoneyInput<'a>>, pub amount_canceled: Option<MoneyInput<'a>>,
#[cynic(skip_serializing_if = "Option::is_none")]
pub metadata: Option<Vec<MetadataInput<'a>>>, pub metadata: Option<Vec<MetadataInput<'a>>>,
#[cynic(skip_serializing_if = "Option::is_none")]
pub private_metadata: Option<Vec<MetadataInput<'a>>>, pub private_metadata: Option<Vec<MetadataInput<'a>>>,
#[cynic(skip_serializing_if = "Option::is_none")]
pub external_url: Option<&'a str>, pub external_url: Option<&'a str>,
} }

View file

@ -1,7 +1,7 @@
use anyhow::Context; use anyhow::Context;
use axum::{extract::State, http::HeaderMap, Json}; use axum::{extract::State, http::HeaderMap, Json};
use cynic::{http::SurfExt, MutationBuilder}; use cynic::{http::SurfExt, MutationBuilder};
use rust_decimal::Decimal; use rust_decimal::{prelude::FromPrimitive, Decimal};
use saleor_app_sdk::{ use saleor_app_sdk::{
headers::SALEOR_API_URL_HEADER, headers::SALEOR_API_URL_HEADER,
webhooks::{ webhooks::{
@ -52,8 +52,29 @@ pub async fn webhooks(
.to_str()? .to_str()?
.to_owned(); .to_owned();
let event_type = get_webhook_event_type(&headers)?; let event_type = get_webhook_event_type(&headers)?;
debug!("event: {:?}", event_type); debug!("event: {:?}", event_type);
let res: Json<Value> = match event_type {
let res = match create_response(event_type, body, state, &saleor_api_url).await {
Ok(r) => r,
Err(e) => {
error!("Response creation failed: {:?}", e);
return Err(AppError(anyhow::anyhow!(e)));
}
};
debug!("res: {}", &res.to_string());
info!("got webhooks!");
Ok(res)
}
async fn create_response(
event_type: EitherWebhookType,
body: String,
state: AppState,
saleor_api_url: &str,
) -> anyhow::Result<Json<Value>> {
Ok(match event_type {
EitherWebhookType::Sync(a) => match a { EitherWebhookType::Sync(a) => match a {
// SyncWebhookEventType::PaymentListGateways => { // SyncWebhookEventType::PaymentListGateways => {
// let gateways = state // let gateways = state
@ -110,71 +131,53 @@ pub async fn webhooks(
} }
SyncWebhookEventType::TransactionInitializeSession => { SyncWebhookEventType::TransactionInitializeSession => {
let session_data = serde_json::from_str::<TransactionInitializeSession2>(&body)?; let session_data = serde_json::from_str::<TransactionInitializeSession2>(&body)?;
let payment_method: TransactionInitializeSessionData = serde_json::from_str(
&session_data
.data
.context("Missing data field on TransactionInitializeSession2 body")?
.0,
)?;
debug!( debug!(
"Transaction session initialised with '{:?}' payment method.", "Transaction session initialised with '{:?}' payment method.",
&payment_method.payment_method &session_data.data
); );
let str_payment_method = serde_json::to_string(&payment_method)?; let payment_method = session_data
.data
.context("Missing Payment Method in request")?
.payment_method;
let app = state.saleor_app.lock().await; let apl_token = state
let auth_data = app.apl.get(&saleor_api_url).await?; .saleor_app
.lock()
.await
.apl
.get(saleor_api_url)
.await?
.token;
let operation = TransactionUpdate::build(TransactionUpdateVariables { let str_payment_method =
id: &session_data.transaction.id, serde_json::to_string(&TransactionInitializeSessionData { payment_method })?;
transaction: Some(TransactionUpdateInput {
message: Some(&str_payment_method),
..Default::default()
}),
});
let mut res = surf::post(&saleor_api_url)
.header("authorization-bearer", auth_data.token)
.run_graphql(operation)
.await;
let mut webhook_result = WebhookResult::Failiure; update_transaction_message(
if let Ok(r) = &mut res session_data.transaction.id,
&& let Some(data) = &mut r.data str_payment_method.clone(),
&& let Some(q_res) = &mut data.transaction_update apl_token,
{ saleor_api_url.to_owned(),
if !q_res.errors.is_empty() { );
q_res
.errors
.iter()
.for_each(|e| error!("failed update transaction, {:?}", e));
} else if q_res.transaction.is_some() {
webhook_result = WebhookResult::Success;
}
}
Json::from(serde_json::to_value( Json::from(serde_json::to_value(
TransactionInitializeSessionResponse::<u8> { TransactionInitializeSessionResponse::<u8> {
data: None, data: None,
time: None, time: None,
psp_reference: None, psp_reference: Some(
"New transaction from ".to_owned() + &state.manifest.name,
),
external_url: None, external_url: None,
message: None, message: Some(str_payment_method),
amount: Decimal::from_str(&session_data.action.amount.0)?, amount: Decimal::from_f32(session_data.action.amount.0)
result: match (session_data.action.action_type, webhook_result) { .context("failed to convert f32 to dec")?,
(TransactionFlowStrategyEnum::Charge, WebhookResult::Success) => { result: match session_data.action.action_type {
TransactionFlowStrategyEnum::Charge => {
TransactionSessionResult::ChargeSuccess TransactionSessionResult::ChargeSuccess
} }
( TransactionFlowStrategyEnum::Authorization => {
TransactionFlowStrategyEnum::Authorization, TransactionSessionResult::AuthorizationSuccess
WebhookResult::Success,
) => TransactionSessionResult::AuthorizationSuccess,
(TransactionFlowStrategyEnum::Charge, WebhookResult::Failiure) => {
TransactionSessionResult::ChargeFailiure
} }
(
TransactionFlowStrategyEnum::Authorization,
WebhookResult::Failiure,
) => TransactionSessionResult::AuthorizationFailure,
}, },
}, },
)?) )?)
@ -186,10 +189,7 @@ pub async fn webhooks(
psp_reference: "".to_owned(), psp_reference: "".to_owned(),
external_url: None, external_url: None,
message: None, message: None,
amount: data amount: data.action.amount.and_then(|a| Decimal::from_f32(a.0)),
.action
.amount
.and_then(|a| Decimal::from_str(&a.0).ok()),
result: Some(ChargeRequestedResult::ChargeSuccess), result: Some(ChargeRequestedResult::ChargeSuccess),
})?) })?)
} }
@ -200,10 +200,7 @@ pub async fn webhooks(
psp_reference: "".to_owned(), psp_reference: "".to_owned(),
external_url: None, external_url: None,
message: None, message: None,
amount: data amount: data.action.amount.and_then(|a| Decimal::from_f32(a.0)),
.action
.amount
.and_then(|a| Decimal::from_str(&a.0).ok()),
result: Some(RefundRequestedResult::RefundSuccess), result: Some(RefundRequestedResult::RefundSuccess),
})?) })?)
} }
@ -216,10 +213,7 @@ pub async fn webhooks(
psp_reference: "".to_owned(), psp_reference: "".to_owned(),
external_url: None, external_url: None,
message: None, message: None,
amount: data amount: data.action.amount.and_then(|a| Decimal::from_f32(a.0)),
.action
.amount
.and_then(|a| Decimal::from_str(&a.0).ok()),
result: Some(CancelationRequestedResult::CancelSuccess), result: Some(CancelationRequestedResult::CancelSuccess),
}, },
)?) )?)
@ -234,7 +228,8 @@ pub async fn webhooks(
psp_reference: None, psp_reference: None,
external_url: None, external_url: None,
message: None, message: None,
amount: Decimal::from_str(&data.action.amount.0)?, amount: Decimal::from_f32(data.action.amount.0)
.context("failed f32 to Decimal")?,
result: match data.action.action_type { result: match data.action.action_type {
TransactionFlowStrategyEnum::Charge => { TransactionFlowStrategyEnum::Charge => {
TransactionSessionResult::ChargeSuccess TransactionSessionResult::ChargeSuccess
@ -248,13 +243,53 @@ pub async fn webhooks(
_ => Json::from(Value::from_str("")?), _ => Json::from(Value::from_str("")?),
}, },
_ => Json::from(Value::from_str("")?), _ => Json::from(Value::from_str("")?),
}; })
debug!("{:?}", res.to_string()); }
info!("got webhooks!");
Ok(res) fn update_transaction_message(
trans_id: cynic::Id,
str_payment_method: String,
apl_token: String,
saleor_api_url: String,
) {
tokio::spawn(async move {
let operation = TransactionUpdate::build(TransactionUpdateVariables {
id: &trans_id,
transaction: Some(TransactionUpdateInput {
message: Some(&str_payment_method),
..Default::default()
}),
});
debug!("operation: {:?}", serde_json::to_string(&operation));
let mut res = surf::post(saleor_api_url)
.header("authorization-bearer", apl_token)
.run_graphql(operation)
.await;
match &mut res {
Ok(r) => {
if let Some(data) = &mut r.data
&& let Some(q_res) = &mut data.transaction_update
{
if !q_res.errors.is_empty() {
q_res
.errors
.iter()
.for_each(|e| error!("failed update transaction, {:?}", e));
} else if q_res.transaction.is_some() {
debug!("sucessfully set transactions message to payment method");
}
}
}
Err(e) => error!("Failed updating transaction through gql: {:?}", e),
}
});
} }
enum WebhookResult { enum WebhookResult {
Success, Success,
Failiure, // NeedsMessageUpdate(&'a str),
Failure,
} }