2024-03-11 13:11:47 +00:00
|
|
|
use anyhow::Context;
|
2024-03-14 13:51:55 +00:00
|
|
|
use axum::{extract::State, http::HeaderMap, Json};
|
2024-03-14 13:33:22 +00:00
|
|
|
use cynic::{http::SurfExt, MutationBuilder};
|
|
|
|
use rust_decimal::Decimal;
|
2024-03-11 13:11:47 +00:00
|
|
|
use saleor_app_sdk::{
|
|
|
|
headers::SALEOR_API_URL_HEADER,
|
|
|
|
webhooks::{
|
2024-03-14 13:33:22 +00:00
|
|
|
sync_response::{
|
2024-03-14 14:05:57 +00:00
|
|
|
CancelationRequestedResult, ChargeRequestedResult,
|
|
|
|
PaymentGatewayInitializeSessionResponse, RefundRequestedResult,
|
|
|
|
TransactionCancelationRequestedResponse, TransactionChargeRequestedResponse,
|
|
|
|
TransactionInitializeSessionResponse, TransactionProcessSessionResponse,
|
|
|
|
TransactionRefundRequestedResponse, TransactionSessionResult,
|
2024-03-14 13:33:22 +00:00
|
|
|
},
|
2024-03-11 13:11:47 +00:00
|
|
|
utils::{get_webhook_event_type, EitherWebhookType},
|
|
|
|
SyncWebhookEventType,
|
|
|
|
},
|
|
|
|
};
|
2024-03-14 13:51:55 +00:00
|
|
|
use serde::Serialize;
|
2024-03-12 19:48:20 +00:00
|
|
|
use serde_json::Value;
|
2024-03-14 13:33:22 +00:00
|
|
|
use std::str::FromStr;
|
2024-03-11 13:11:47 +00:00
|
|
|
use tracing::{debug, error, info};
|
|
|
|
|
2024-03-12 19:48:20 +00:00
|
|
|
use crate::{
|
2024-03-14 13:33:22 +00:00
|
|
|
app::{ActiveGateway, AppError, AppState, GatewayType},
|
|
|
|
queries::{
|
|
|
|
event_transactions::{
|
2024-03-14 14:05:57 +00:00
|
|
|
TransactionCancelationRequested, TransactionChargeRequested2,
|
|
|
|
TransactionFlowStrategyEnum, TransactionInitializeSession2, TransactionProcessSession2,
|
|
|
|
TransactionRefundRequested2,
|
2024-03-14 13:33:22 +00:00
|
|
|
},
|
|
|
|
mutation_transaction_update::{
|
|
|
|
TransactionUpdate, TransactionUpdateInput, TransactionUpdateVariables,
|
|
|
|
},
|
|
|
|
},
|
2024-03-12 19:48:20 +00:00
|
|
|
};
|
2024-03-11 13:11:47 +00:00
|
|
|
|
|
|
|
pub async fn webhooks(
|
|
|
|
headers: HeaderMap,
|
|
|
|
State(state): State<AppState>,
|
|
|
|
body: String,
|
2024-03-12 19:48:20 +00:00
|
|
|
) -> Result<Json<Value>, AppError> {
|
2024-03-11 13:11:47 +00:00
|
|
|
debug!("/api/webhooks");
|
|
|
|
debug!("req: {:?}", body);
|
|
|
|
debug!("headers: {:?}", headers);
|
|
|
|
|
2024-03-14 13:33:22 +00:00
|
|
|
let saleor_api_url = headers
|
2024-03-11 13:11:47 +00:00
|
|
|
.get(SALEOR_API_URL_HEADER)
|
|
|
|
.context("missing saleor api url header")?
|
|
|
|
.to_str()?
|
|
|
|
.to_owned();
|
|
|
|
let event_type = get_webhook_event_type(&headers)?;
|
2024-03-12 19:48:20 +00:00
|
|
|
let res: Json<Value> = match event_type {
|
2024-03-11 13:11:47 +00:00
|
|
|
EitherWebhookType::Sync(a) => match a {
|
2024-03-14 14:05:57 +00:00
|
|
|
SyncWebhookEventType::TransactionCancelationRequested => {
|
|
|
|
let data = serde_json::from_str::<TransactionChargeRequested2>(&body)?;
|
|
|
|
Json::from(serde_json::to_value(
|
|
|
|
TransactionCancelationRequestedResponse {
|
|
|
|
time: None,
|
|
|
|
psp_reference: "".to_owned(),
|
|
|
|
external_url: None,
|
|
|
|
message: None,
|
|
|
|
amount: data
|
|
|
|
.action
|
|
|
|
.amount
|
|
|
|
.and_then(|a| Decimal::from_str(&a.0).ok()),
|
|
|
|
result: Some(CancelationRequestedResult::CancelSuccess),
|
|
|
|
},
|
|
|
|
)?)
|
|
|
|
}
|
2024-03-14 13:33:22 +00:00
|
|
|
SyncWebhookEventType::PaymentGatewayInitializeSession => Json::from(
|
|
|
|
serde_json::to_value(PaymentGatewayInitializeSessionResponse::<u8> { data: None })?,
|
|
|
|
),
|
|
|
|
SyncWebhookEventType::TransactionProcessSession => {
|
|
|
|
let data = serde_json::from_str::<TransactionProcessSession2>(&body)?;
|
|
|
|
Json::from(serde_json::to_value(TransactionProcessSessionResponse::<
|
|
|
|
u8,
|
|
|
|
> {
|
|
|
|
data: None,
|
|
|
|
time: None,
|
|
|
|
psp_reference: None,
|
|
|
|
external_url: None,
|
|
|
|
message: None,
|
|
|
|
amount: Decimal::from_str(&data.action.amount.0)?,
|
|
|
|
result: match data.action.action_type {
|
|
|
|
TransactionFlowStrategyEnum::Charge => {
|
|
|
|
TransactionSessionResult::ChargeSuccess
|
|
|
|
}
|
|
|
|
TransactionFlowStrategyEnum::Authorization => {
|
|
|
|
TransactionSessionResult::AuthorizationSuccess
|
|
|
|
}
|
2024-03-12 19:48:20 +00:00
|
|
|
},
|
|
|
|
})?)
|
2024-03-11 13:11:47 +00:00
|
|
|
}
|
2024-03-14 13:33:22 +00:00
|
|
|
SyncWebhookEventType::TransactionChargeRequested => {
|
|
|
|
let data = serde_json::from_str::<TransactionChargeRequested2>(&body)?;
|
|
|
|
Json::from(serde_json::to_value(TransactionChargeRequestedResponse {
|
|
|
|
time: None,
|
|
|
|
psp_reference: "".to_owned(),
|
|
|
|
external_url: None,
|
|
|
|
message: None,
|
|
|
|
amount: data
|
|
|
|
.action
|
|
|
|
.amount
|
|
|
|
.and_then(|a| Decimal::from_str(&a.0).ok()),
|
|
|
|
result: Some(ChargeRequestedResult::ChargeSuccess),
|
|
|
|
})?)
|
|
|
|
}
|
|
|
|
SyncWebhookEventType::TransactionRefundRequested => {
|
|
|
|
let data = serde_json::from_str::<TransactionRefundRequested2>(&body)?;
|
|
|
|
Json::from(serde_json::to_value(TransactionRefundRequestedResponse {
|
|
|
|
time: None,
|
|
|
|
psp_reference: "".to_owned(),
|
|
|
|
external_url: None,
|
|
|
|
message: None,
|
|
|
|
amount: data
|
|
|
|
.action
|
|
|
|
.amount
|
|
|
|
.and_then(|a| Decimal::from_str(&a.0).ok()),
|
|
|
|
result: Some(RefundRequestedResult::RefundSuccess),
|
|
|
|
})?)
|
|
|
|
}
|
|
|
|
SyncWebhookEventType::TransactionInitializeSession => {
|
|
|
|
let data = serde_json::from_str::<TransactionInitializeSession2>(&body)?;
|
|
|
|
let app = state.saleor_app.lock().await;
|
|
|
|
let auth_data = app.apl.get(&saleor_api_url).await?;
|
|
|
|
let operation = TransactionUpdate::build(TransactionUpdateVariables {
|
|
|
|
id: &data.transaction.id,
|
|
|
|
transaction: Some(TransactionUpdateInput {
|
|
|
|
message: Some(""),
|
|
|
|
..Default::default()
|
|
|
|
}),
|
|
|
|
});
|
2024-03-14 13:51:55 +00:00
|
|
|
let mut res = surf::post(&saleor_api_url)
|
|
|
|
.header("authorization-bearer", auth_data.token)
|
|
|
|
.run_graphql(operation)
|
|
|
|
.await;
|
2024-03-14 13:33:22 +00:00
|
|
|
|
|
|
|
let mut webhook_result = WebhookResult::Failiure;
|
|
|
|
if let Ok(r) = &mut res
|
|
|
|
&& 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));
|
2024-03-14 13:51:55 +00:00
|
|
|
} else if let Some(tr) = &mut q_res.transaction {
|
|
|
|
tr.message = serde_json::to_string(&PaymentMethod {
|
|
|
|
payment_method: GatewayType::COD,
|
|
|
|
})?;
|
|
|
|
webhook_result = WebhookResult::Success;
|
2024-03-14 13:33:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Json::from(serde_json::to_value(
|
|
|
|
TransactionInitializeSessionResponse::<u8> {
|
|
|
|
data: None,
|
|
|
|
time: None,
|
|
|
|
psp_reference: None,
|
|
|
|
external_url: None,
|
|
|
|
message: None,
|
|
|
|
amount: Decimal::from_str(&data.action.amount.0)?,
|
|
|
|
result: match (data.action.action_type, webhook_result) {
|
|
|
|
(TransactionFlowStrategyEnum::Charge, WebhookResult::Success) => {
|
|
|
|
TransactionSessionResult::ChargeSuccess
|
|
|
|
}
|
|
|
|
(
|
|
|
|
TransactionFlowStrategyEnum::Authorization,
|
|
|
|
WebhookResult::Success,
|
|
|
|
) => TransactionSessionResult::AuthorizationSuccess,
|
|
|
|
(TransactionFlowStrategyEnum::Charge, WebhookResult::Failiure) => {
|
|
|
|
TransactionSessionResult::ChargeFailiure
|
|
|
|
}
|
|
|
|
(
|
|
|
|
TransactionFlowStrategyEnum::Authorization,
|
|
|
|
WebhookResult::Failiure,
|
|
|
|
) => TransactionSessionResult::AuthorizationFailure,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
)?)
|
2024-03-11 13:11:47 +00:00
|
|
|
}
|
2024-03-12 19:48:20 +00:00
|
|
|
_ => Json::from(Value::from_str("")?),
|
2024-03-11 13:11:47 +00:00
|
|
|
},
|
2024-03-12 19:48:20 +00:00
|
|
|
_ => Json::from(Value::from_str("")?),
|
|
|
|
};
|
2024-03-11 13:11:47 +00:00
|
|
|
|
|
|
|
info!("got webhooks!");
|
2024-03-12 19:48:20 +00:00
|
|
|
Ok(res)
|
2024-03-11 13:11:47 +00:00
|
|
|
}
|
|
|
|
|
2024-03-12 19:48:20 +00:00
|
|
|
#[derive(Serialize, Clone, Debug)]
|
|
|
|
pub struct JsonResponse {
|
|
|
|
data: JsonResponseData,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize, Clone, Debug)]
|
|
|
|
pub struct JsonResponseData {
|
|
|
|
current_gateway: ActiveGateway,
|
2024-03-11 13:11:47 +00:00
|
|
|
}
|
2024-03-14 13:33:22 +00:00
|
|
|
enum WebhookResult {
|
|
|
|
Success,
|
|
|
|
Failiure,
|
2024-03-11 13:11:47 +00:00
|
|
|
}
|
2024-03-12 19:48:20 +00:00
|
|
|
|
2024-03-14 13:33:22 +00:00
|
|
|
#[derive(Serialize, Clone, Debug)]
|
|
|
|
struct PaymentMethod {
|
|
|
|
payment_method: GatewayType,
|
2024-03-12 19:48:20 +00:00
|
|
|
}
|