//! Admin order list, detail, and status updates. use axum_extra::extract::cookie::CookieJar; use loco_rs::prelude::*; use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, Set}; use serde::Deserialize; use serde_json::json; use crate::{ models::{order_items, orders}, views::checkout as view, controllers::i18n::current_lang, shared::{guard, settings}, }; pub(crate) const ORDER_STATUSES: [&str; 4] = ["pending", "paid", "shipped", "cancelled"]; #[derive(Debug, Deserialize)] struct StatusForm { status: String, } #[debug_handler] async fn index( auth: auth::JWT, jar: CookieJar, ViewEngine(v): ViewEngine, State(ctx): State, ) -> Result { guard::current_admin(auth, &ctx).await?; let list = orders::Entity::find() .order_by_desc(orders::Column::CreatedAt) .all(&ctx.db) .await?; let rows: Vec = list.iter().map(view::summary).collect(); format::view( &v, "admin/orders/index.html", json!({ "orders": rows, "lang": current_lang(&jar) }), ) } #[debug_handler] async fn show( auth: auth::JWT, jar: CookieJar, ViewEngine(v): ViewEngine, Path(id): Path, State(ctx): State, ) -> Result { guard::current_admin(auth, &ctx).await?; let order = orders::Entity::find_by_id(id) .one(&ctx.db) .await? .ok_or_else(|| Error::NotFound)?; let items = order_items::Entity::find() .filter(order_items::Column::OrderId.eq(order.id)) .all(&ctx.db) .await?; format::view( &v, "admin/orders/show.html", json!({ "order": view::detail( &order, settings::get(&ctx, "bank_iban").unwrap_or(""), settings::get(&ctx, "bank_account_name").unwrap_or(""), ), "items": view::items(&items), "statuses": ORDER_STATUSES, "lang": current_lang(&jar), }), ) } #[debug_handler] async fn update_status( auth: auth::JWT, Path(id): Path, State(ctx): State, Form(form): Form, ) -> Result { guard::current_admin(auth, &ctx).await?; if !ORDER_STATUSES.contains(&form.status.as_str()) { return Err(Error::BadRequest("invalid status".to_string())); } let order = orders::Entity::find_by_id(id) .one(&ctx.db) .await? .ok_or_else(|| Error::NotFound)?; let mut active = order.into_active_model(); active.status = Set(form.status); active.update(&ctx.db).await?; format::redirect(&format!("/admin/orders/{id}")) } pub fn routes() -> Routes { Routes::new() .add("/admin/orders", get(index)) .add("/admin/orders/{id}", get(show)) .add("/admin/orders/{id}/status", post(update_status)) }