Update cart and items, add cart state
This commit is contained in:
parent
160c1f2563
commit
5d757e84d5
@ -5,6 +5,7 @@ pub use account_orders::*;
|
||||
pub use accounts::*;
|
||||
pub use order_items::*;
|
||||
pub use products::*;
|
||||
pub use shopping_cart_items::*;
|
||||
pub use shopping_carts::*;
|
||||
pub use stocks::*;
|
||||
|
||||
@ -12,6 +13,7 @@ mod account_orders;
|
||||
mod accounts;
|
||||
mod order_items;
|
||||
mod products;
|
||||
mod shopping_cart_items;
|
||||
mod shopping_carts;
|
||||
mod stocks;
|
||||
|
||||
@ -45,6 +47,8 @@ pub enum Error {
|
||||
OrderItem(order_items::Error),
|
||||
#[error("{0}")]
|
||||
ShoppingCart(shopping_carts::Error),
|
||||
#[error("{0}")]
|
||||
ShoppingCartItem(shopping_cart_items::Error),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
201
api/src/actors/database/shopping_cart_items.rs
Normal file
201
api/src/actors/database/shopping_cart_items.rs
Normal file
@ -0,0 +1,201 @@
|
||||
use crate::async_handler;
|
||||
use actix::{Handler, ResponseActFuture, WrapFuture};
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::database::Database;
|
||||
use crate::model::*;
|
||||
|
||||
use super::Result;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("Can't create shopping cart item")]
|
||||
CantCreate,
|
||||
#[error("Can't update shopping cart item")]
|
||||
CantUpdate(ShoppingCartItemId),
|
||||
#[error("Shopping cart does not exists")]
|
||||
NotExists,
|
||||
#[error("Failed to load all shopping cart items")]
|
||||
All,
|
||||
#[error("Failed to load account shopping cart items")]
|
||||
AccountCarts,
|
||||
#[error("Failed to load items for shopping cart {0}")]
|
||||
CartItems(ShoppingCartId),
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<Vec<ShoppingCartItem>>")]
|
||||
pub struct AllShoppingCartItems;
|
||||
|
||||
async_handler!(AllShoppingCartItems, all_shopping_cart_items, Vec<ShoppingCartItem>);
|
||||
|
||||
pub async fn all_shopping_cart_items(
|
||||
_msg: AllShoppingCartItems,
|
||||
pool: PgPool,
|
||||
) -> Result<Vec<ShoppingCartItem>> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, product_id, shopping_cart_id, quantity, quantity_unit
|
||||
FROM shopping_cart_items
|
||||
"#,
|
||||
)
|
||||
.fetch_all(&pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
super::Error::ShoppingCartItem(Error::All)
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<Vec<ShoppingCartItem>>")]
|
||||
pub struct AccountShoppingCartItems {
|
||||
pub account_id: AccountId,
|
||||
}
|
||||
|
||||
async_handler!(AccountShoppingCartItems, account_shopping_cart_items, Vec<ShoppingCartItem>);
|
||||
|
||||
pub async fn account_shopping_cart_items(
|
||||
msg: AccountShoppingCartItems,
|
||||
pool: PgPool,
|
||||
) -> Result<Vec<ShoppingCartItem>> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, product_id, shopping_cart_id, quantity, quantity_unit
|
||||
FROM shopping_cart_items
|
||||
WHERE buyer_id = $1
|
||||
"#,
|
||||
)
|
||||
.bind(msg.account_id)
|
||||
.fetch_all(&pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
super::Error::ShoppingCartItem(Error::AccountCarts)
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<ShoppingCartItem>")]
|
||||
pub struct CreateShoppingCartItem {
|
||||
pub product_id: ProductId,
|
||||
pub shopping_cart_id: ShoppingCartId,
|
||||
pub quantity: Quantity,
|
||||
pub quantity_unit: QuantityUnit,
|
||||
}
|
||||
|
||||
async_handler!(CreateShoppingCartItem, create_shopping_cart_item, ShoppingCartItem);
|
||||
|
||||
async fn create_shopping_cart_item(
|
||||
msg: CreateShoppingCartItem,
|
||||
db: PgPool,
|
||||
) -> Result<ShoppingCartItem> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
INSERT INTO shopping_cart_items (product_id, shopping_cart_id, quantity, quantity_unit)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING id, product_id, shopping_cart_id, quantity, quantity_unit
|
||||
"#,
|
||||
)
|
||||
.bind(msg.product_id)
|
||||
.bind(msg.shopping_cart_id)
|
||||
.bind(msg.quantity)
|
||||
.bind(msg.quantity_unit)
|
||||
.fetch_one(&db)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
super::Error::ShoppingCartItem(Error::CantCreate)
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<ShoppingCartItem>")]
|
||||
pub struct UpdateShoppingCartItem {
|
||||
pub id: ShoppingCartItemId,
|
||||
pub product_id: ProductId,
|
||||
pub shopping_cart_id: ShoppingCartId,
|
||||
pub quantity: Quantity,
|
||||
pub quantity_unit: QuantityUnit,
|
||||
}
|
||||
|
||||
async_handler!(UpdateShoppingCartItem, update_shopping_cart_item, ShoppingCartItem);
|
||||
|
||||
async fn update_shopping_cart_item(
|
||||
msg: UpdateShoppingCartItem,
|
||||
db: PgPool,
|
||||
) -> Result<ShoppingCartItem> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
UPDATE shopping_cart_items
|
||||
SET product_id = $2 AND shopping_cart_id = $3 AND quantity = $4 AND quantity_unit = $5
|
||||
WHERE id = $1
|
||||
RETURNING id, product_id, shopping_cart_id, quantity, quantity_unit
|
||||
"#,
|
||||
)
|
||||
.bind(msg.id)
|
||||
.bind(msg.product_id)
|
||||
.bind(msg.shopping_cart_id)
|
||||
.bind(msg.quantity)
|
||||
.bind(msg.quantity_unit)
|
||||
.fetch_one(&db)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
super::Error::ShoppingCartItem(Error::CantUpdate(msg.id))
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<ShoppingCartItem>")]
|
||||
pub struct FindShoppingCartItem {
|
||||
pub id: ShoppingCartItemId,
|
||||
}
|
||||
|
||||
async_handler!(FindShoppingCartItem, find_shopping_cart_item, ShoppingCartItem);
|
||||
|
||||
async fn find_shopping_cart_item(
|
||||
msg: FindShoppingCartItem,
|
||||
db: PgPool,
|
||||
) -> Result<ShoppingCartItem> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, product_id, shopping_cart_id, quantity, quantity_unit
|
||||
FROM shopping_cart_items
|
||||
WHERE id = $1
|
||||
"#,
|
||||
)
|
||||
.bind(msg.id)
|
||||
.fetch_one(&db)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
super::Error::ShoppingCartItem(Error::NotExists)
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<Vec<ShoppingCartItem>>")]
|
||||
pub struct CartItems {
|
||||
pub shopping_cart_id: ShoppingCartId,
|
||||
}
|
||||
|
||||
async_handler!(CartItems, cart_items, Vec<ShoppingCartItem>);
|
||||
|
||||
async fn cart_items(msg: CartItems, pool: PgPool) -> Result<Vec<ShoppingCartItem>> {
|
||||
let shopping_cart_id = msg.shopping_cart_id;
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, product_id, shopping_cart_id, quantity, quantity_unit
|
||||
FROM shopping_cart_items
|
||||
WHERE shopping_cart_id = $1
|
||||
"#,
|
||||
)
|
||||
.bind(msg.shopping_cart_id)
|
||||
.fetch_all(&pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
super::Error::ShoppingCartItem(Error::CartItems(shopping_cart_id))
|
||||
})
|
||||
}
|
@ -11,8 +11,8 @@ use super::Result;
|
||||
pub enum Error {
|
||||
#[error("Can't create shopping cart")]
|
||||
CantCreate,
|
||||
#[error("Can't find shopping cart does to lack of identity")]
|
||||
NoIdentity,
|
||||
#[error("Can't update shopping cart {0}")]
|
||||
CantUpdate(ShoppingCartId),
|
||||
#[error("Shopping cart does not exists")]
|
||||
NotExists,
|
||||
#[error("Failed to load all shopping carts")]
|
||||
@ -30,7 +30,7 @@ async_handler!(AllShoppingCarts, all_shopping_carts, Vec<ShoppingCart>);
|
||||
pub async fn all_shopping_carts(_msg: AllShoppingCarts, pool: PgPool) -> Result<Vec<ShoppingCart>> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, buyer_id, payment_method
|
||||
SELECT id, buyer_id, payment_method, state
|
||||
FROM shopping_carts
|
||||
"#,
|
||||
)
|
||||
@ -56,12 +56,12 @@ pub async fn account_shopping_carts(
|
||||
) -> Result<Vec<ShoppingCart>> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, buyer_id, payment_method
|
||||
SELECT id, buyer_id, payment_method, state
|
||||
FROM shopping_carts
|
||||
WHERE buyer_id = $1
|
||||
"#,
|
||||
)
|
||||
.bind(msg.acocunt_id)
|
||||
.bind(msg.account_id)
|
||||
.fetch_all(&pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
@ -84,7 +84,7 @@ async fn create_shopping_cart(msg: CreateShoppingCart, db: PgPool) -> Result<Sho
|
||||
r#"
|
||||
INSERT INTO shopping_carts (buyer_id, payment_method)
|
||||
VALUES ($1, $2)
|
||||
RETURNING id, buyer_id, payment_method
|
||||
RETURNING id, buyer_id, payment_method, state
|
||||
"#,
|
||||
)
|
||||
.bind(msg.buyer_id)
|
||||
@ -97,6 +97,38 @@ RETURNING id, buyer_id, payment_method
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<ShoppingCart>")]
|
||||
pub struct UpdateShoppingCart {
|
||||
pub id: ShoppingCartId,
|
||||
pub buyer_id: AccountId,
|
||||
pub payment_method: PaymentMethod,
|
||||
pub state: ShoppingCartState,
|
||||
}
|
||||
|
||||
async_handler!(UpdateShoppingCart, update_shopping_cart, ShoppingCart);
|
||||
|
||||
async fn update_shopping_cart(msg: UpdateShoppingCart, db: PgPool) -> Result<ShoppingCart> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
UPDATE shopping_carts
|
||||
SET buyer_id = $2 AND payment_method = $2 AND state = $4
|
||||
WHERE id = $1
|
||||
RETURNING id, buyer_id, payment_method, state
|
||||
"#,
|
||||
)
|
||||
.bind(msg.id)
|
||||
.bind(msg.buyer_id)
|
||||
.bind(msg.payment_method)
|
||||
.bind(msg.state)
|
||||
.fetch_one(&db)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
super::Error::ShoppingCart(Error::CantUpdate(msg.id))
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<ShoppingCart>")]
|
||||
pub struct FindShoppingCart {
|
||||
@ -108,7 +140,7 @@ async_handler!(FindShoppingCart, find_shopping_cart, ShoppingCart);
|
||||
async fn find_shopping_cart(msg: FindShoppingCart, db: PgPool) -> Result<ShoppingCart> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, buyer_id, payment_method
|
||||
SELECT id, buyer_id, payment_method, state
|
||||
FROM shopping_carts
|
||||
WHERE id = $1
|
||||
"#,
|
||||
|
@ -161,7 +161,7 @@ async fn server(opts: ServerOpts) -> Result<()> {
|
||||
App::new()
|
||||
.wrap(Logger::default())
|
||||
.wrap(actix_web::middleware::Compress::default())
|
||||
.wrap(actix_web::middleware::NormalizePath::default())
|
||||
.wrap(actix_web::middleware::NormalizePath::trim())
|
||||
.wrap(SessionMiddleware::new(
|
||||
RedisActorSessionStore::new(redis_connection_string),
|
||||
secret_key.clone(),
|
||||
|
@ -54,6 +54,13 @@ pub enum PaymentMethod {
|
||||
PaymentOnTheSpot,
|
||||
}
|
||||
|
||||
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
||||
#[sqlx(rename_all = "lowercase")]
|
||||
pub enum ShoppingCartState {
|
||||
Active,
|
||||
Closed,
|
||||
}
|
||||
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
|
||||
#[sqlx(transparent)]
|
||||
#[serde(transparent)]
|
||||
@ -280,7 +287,7 @@ pub struct AccountOrder {
|
||||
pub status: OrderStatus,
|
||||
}
|
||||
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Copy, Clone, Deref)]
|
||||
#[sqlx(transparent)]
|
||||
#[serde(transparent)]
|
||||
pub struct OrderItemId(pub RecordId);
|
||||
@ -294,7 +301,7 @@ pub struct OrderItem {
|
||||
pub quantity_unit: QuantityUnit,
|
||||
}
|
||||
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Copy, Clone, Deref, Display, Debug)]
|
||||
#[sqlx(transparent)]
|
||||
#[serde(transparent)]
|
||||
pub struct ShoppingCartId(pub RecordId);
|
||||
@ -304,9 +311,10 @@ pub struct ShoppingCart {
|
||||
pub id: ShoppingCartId,
|
||||
pub buyer_id: AccountId,
|
||||
pub payment_method: PaymentMethod,
|
||||
pub state: ShoppingCartState,
|
||||
}
|
||||
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Copy, Clone, Deref, Display, Debug)]
|
||||
#[sqlx(transparent)]
|
||||
#[serde(transparent)]
|
||||
pub struct ShoppingCartItemId(pub RecordId);
|
||||
|
10
db/migrate/202204161233_add_cart_state.sql
Normal file
10
db/migrate/202204161233_add_cart_state.sql
Normal file
@ -0,0 +1,10 @@
|
||||
CREATE TYPE "ShoppingCartState" AS ENUM (
|
||||
'active',
|
||||
'closed'
|
||||
);
|
||||
|
||||
ALTER TABLE shopping_carts
|
||||
ADD COLUMN "state" "ShoppingCartState" NOT NULL DEFAULT 'active';
|
||||
|
||||
ALTER TABLE shopping_carts
|
||||
ADD CONSTRAINT single_active_cart UNIQUE (buyer_id, "state");
|
Loading…
Reference in New Issue
Block a user