use model::*; use sqlx::PgPool; use super::Result; use crate::{ create_order_item, db_async_handler, shopping_cart_set_state, CreateOrderItem, ShoppingCartSetState, }; #[derive(Debug, Copy, Clone, PartialEq, serde::Serialize, thiserror::Error)] #[serde(rename_all = "kebab-case", tag = "account-order")] pub enum Error { #[error("Can't create account order")] CantCreate, #[error("Can't find account order does to lack of identity")] NoIdentity, #[error("Account order does not exists")] NotExists, #[error("Failed to load all account orders")] All, } #[derive(actix::Message)] #[rtype(result = "Result>")] pub struct AllAccountOrders; db_async_handler!(AllAccountOrders, all_orders, Vec); pub(crate) async fn all_orders(_msg: AllAccountOrders, pool: PgPool) -> Result> { sqlx::query_as( r#" SELECT id, buyer_id, status, order_ext_id, service_order_id, checkout_notes, address_id FROM orders ORDER BY id DESC "#, ) .fetch_all(&pool) .await .map_err(|e| { log::error!("{e:?}"); super::Error::AccountOrder(Error::All) }) } pub mod create_order { use model::{ProductId, Quantity, QuantityUnit}; pub struct OrderItem { pub product_id: ProductId, pub quantity: Quantity, pub quantity_unit: QuantityUnit, } } #[derive(actix::Message)] #[rtype(result = "Result")] pub struct CreateAccountOrder { pub buyer_id: AccountId, pub items: Vec, pub shopping_cart_id: ShoppingCartId, pub checkout_notes: Option, } db_async_handler!( CreateAccountOrder, create_account_order, Order, inner_create_account_order ); pub(crate) async fn create_account_order( msg: CreateAccountOrder, t: &mut sqlx::Transaction<'_, sqlx::Postgres>, ) -> Result { let order: Order = match sqlx::query_as( r#" INSERT INTO orders (buyer_id, status) VALUES ($1, $2, $3) RETURNING id, buyer_id, status, order_ext_id, service_order_id, checkout_notes, address_id "#, ) .bind(msg.buyer_id) .bind(OrderStatus::Confirmed) .fetch_one(&mut *t) .await { Ok(order) => order, Err(e) => { log::error!("{e:?}"); return Err(super::Error::AccountOrder(Error::CantCreate)); } }; for item in msg.items { if let Err(e) = create_order_item( CreateOrderItem { product_id: item.product_id, order_id: order.id, quantity: item.quantity, quantity_unit: item.quantity_unit, }, &mut *t, ) .await { log::error!("{e:?}"); return Err(super::Error::AccountOrder(Error::CantCreate)); } } if let Err(e) = shopping_cart_set_state( ShoppingCartSetState { id: msg.shopping_cart_id, state: ShoppingCartState::Closed, checkout_notes: msg.checkout_notes, }, t, ) .await { log::error!("{e:?}"); return Err(super::Error::AccountOrder(Error::CantCreate)); }; Ok(order) } #[derive(actix::Message)] #[rtype(result = "Result")] pub struct UpdateAccountOrder { pub id: OrderId, pub buyer_id: AccountId, pub status: OrderStatus, pub order_id: Option, } db_async_handler!(UpdateAccountOrder, update_account_order, Order); pub(crate) async fn update_account_order(msg: UpdateAccountOrder, db: PgPool) -> Result { sqlx::query_as( r#" UPDATE orders SET buyer_id = $2 AND status = $3 AND order_id = $4 WHERE id = $1 RETURNING id, buyer_id, status, order_ext_id, service_order_id, checkout_notes, address_id "#, ) .bind(msg.id) .bind(msg.buyer_id) .bind(msg.status) .bind(msg.order_id) .fetch_one(&db) .await .map_err(|e| { log::error!("{e:?}"); super::Error::AccountOrder(Error::CantCreate) }) } #[derive(actix::Message)] #[rtype(result = "Result")] pub struct UpdateAccountOrderByExt { pub order_ext_id: String, pub status: OrderStatus, } db_async_handler!(UpdateAccountOrderByExt, update_account_order_by_ext, Order); pub(crate) async fn update_account_order_by_ext( msg: UpdateAccountOrderByExt, db: PgPool, ) -> Result { sqlx::query_as( r#" UPDATE orders SET status = $2 WHERE order_ext_id = $1 RETURNING id, buyer_id, status, order_ext_id, service_order_id, checkout_notes, address_id "#, ) .bind(msg.order_ext_id) .bind(msg.status) .fetch_one(&db) .await .map_err(|e| { log::error!("{e:?}"); super::Error::AccountOrder(Error::CantCreate) }) } #[derive(actix::Message)] #[rtype(result = "Result")] pub struct FindAccountOrder { pub id: OrderId, } db_async_handler!(FindAccountOrder, find_account_order, Order); pub(crate) async fn find_account_order(msg: FindAccountOrder, db: PgPool) -> Result { sqlx::query_as( r#" SELECT id, buyer_id, status, order_ext_id, service_order_id, checkout_notes, address_id FROM orders WHERE id = $1 "#, ) .bind(msg.id) .fetch_one(&db) .await .map_err(|e| { log::error!("{e:?}"); super::Error::AccountOrder(Error::NotExists) }) } #[derive(actix::Message)] #[rtype(result = "Result")] pub struct SetOrderServiceId { pub id: OrderId, pub service_order_id: String, } db_async_handler!(SetOrderServiceId, set_order_service_id, Order); pub(crate) async fn set_order_service_id(msg: SetOrderServiceId, db: PgPool) -> Result { sqlx::query_as( r#" UPDATE orders SET service_order_id = $2 WHERE id = $1 RETURNING id, buyer_id, status, order_ext_id, service_order_id, checkout_notes, address_id "#, ) .bind(msg.id) .bind(msg.service_order_id) .fetch_one(&db) .await .map_err(|e| { log::error!("{e:?}"); super::Error::AccountOrder(Error::NotExists) }) }