use sqlx::PgPool; use super::Result; use crate::database::{ create_order_item, shopping_cart_set_state, CreateOrderItem, Database, ShoppingCartSetState, }; use crate::db_async_handler; use crate::model::*; #[derive(Debug, thiserror::Error)] 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_account_orders, Vec); pub(crate) async fn all_account_orders( _msg: AllAccountOrders, pool: PgPool, ) -> Result> { sqlx::query_as( r#" SELECT id, buyer_id, status, order_id FROM account_orders "#, ) .fetch_all(&pool) .await .map_err(|e| { log::error!("{e:?}"); super::Error::AccountOrder(Error::All) }) } pub mod create_order { use crate::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, } db_async_handler!(CreateAccountOrder, create_account_order, AccountOrder); pub(crate) async fn create_account_order( msg: CreateAccountOrder, db: PgPool, ) -> Result { let mut t = db.begin().await?; let order: AccountOrder = match sqlx::query_as( r#" INSERT INTO account_orders (buyer_id, status) VALUES ($1, $2, $3) RETURNING id, buyer_id, status "#, ) .bind(msg.buyer_id) .bind(OrderStatus::Confirmed) .fetch_one(&mut t) .await { Ok(order) => order, Err(e) => { log::error!("{e:?}"); t.rollback().await.ok(); 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:?}"); t.rollback().await.ok(); return Err(super::Error::AccountOrder(Error::CantCreate)); } } if let Err(e) = shopping_cart_set_state( ShoppingCartSetState { id: msg.shopping_cart_id, state: ShoppingCartState::Closed, }, &mut t, ) .await { log::error!("{e:?}"); t.rollback().await.ok(); return Err(super::Error::AccountOrder(Error::CantCreate)); }; t.commit().await.ok(); Ok(order) } #[derive(actix::Message)] #[rtype(result = "Result")] pub struct UpdateAccountOrder { pub id: AccountOrderId, pub buyer_id: AccountId, pub status: OrderStatus, pub order_id: Option, } db_async_handler!(UpdateAccountOrder, update_account_order, AccountOrder); pub(crate) async fn update_account_order( msg: UpdateAccountOrder, db: PgPool, ) -> Result { sqlx::query_as( r#" UPDATE account_orders SET buyer_id = $2 AND status = $3 AND order_id = $4 WHERE id = $1 RETURNING id, buyer_id, status, order_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 FindAccountOrder { pub id: AccountOrderId, } db_async_handler!(FindAccountOrder, find_account_order, AccountOrder); pub(crate) async fn find_account_order(msg: FindAccountOrder, db: PgPool) -> Result { sqlx::query_as( r#" SELECT id, buyer_id, status, order_id FROM account_orders WHERE id = $1 "#, ) .bind(msg.id) .fetch_one(&db) .await .map_err(|e| { log::error!("{e:?}"); super::Error::AccountOrder(Error::NotExists) }) }