saleor-apps-rs/simple-payment-gateway/src/routes/webhooks.rs

199 lines
7.8 KiB
Rust
Raw Normal View History

2024-03-11 13:11:47 +00:00
use anyhow::Context;
use axum::{
2024-03-12 19:48:20 +00:00
body::Body,
2024-03-11 13:11:47 +00:00
extract::State,
http::{HeaderMap, StatusCode},
2024-03-12 19:48:20 +00:00
response::Response,
Json,
2024-03-11 13:11:47 +00:00
};
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::{
ChargeRequestedResult, PaymentGatewayInitializeSessionResponse, RefundRequestedResult,
TransactionChargeRequestedResponse, TransactionInitializeSessionResponse,
TransactionProcessSessionResponse, TransactionRefundRequestedResponse,
TransactionSessionResult,
},
2024-03-11 13:11:47 +00:00
utils::{get_webhook_event_type, EitherWebhookType},
SyncWebhookEventType,
},
};
2024-03-12 19:48:20 +00:00
use serde::{Deserialize, Serialize};
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::{
PaymentGatewayInitializeSession, TransactionActionEnum, TransactionChargeRequested2,
TransactionFlowStrategyEnum, TransactionInitializeSession2, TransactionProcessSession,
TransactionProcessSession2, TransactionRefundRequested2,
},
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 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()
}),
});
let mut res = surf::post(&saleor_api_url).run_graphql(operation).await;
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));
} else {
if let Some(tr) = &mut q_res.transaction {
tr.message = serde_json::to_string(&PaymentMethod {
payment_method: GatewayType::COD,
})?;
webhook_result = WebhookResult::Success;
}
}
}
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
}