finally it works
This commit is contained in:
parent
fd0a218f23
commit
8e142c813d
4 changed files with 135 additions and 79 deletions
|
@ -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(),
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue