Fix order, add non negative constructor
This commit is contained in:
parent
5354d909b3
commit
388bfd634a
@ -3,11 +3,13 @@ use sqlx::PgPool;
|
|||||||
|
|
||||||
pub use account_orders::*;
|
pub use account_orders::*;
|
||||||
pub use accounts::*;
|
pub use accounts::*;
|
||||||
|
pub use order_items::*;
|
||||||
pub use products::*;
|
pub use products::*;
|
||||||
pub use stocks::*;
|
pub use stocks::*;
|
||||||
|
|
||||||
mod account_orders;
|
mod account_orders;
|
||||||
mod accounts;
|
mod accounts;
|
||||||
|
mod order_items;
|
||||||
mod products;
|
mod products;
|
||||||
mod stocks;
|
mod stocks;
|
||||||
|
|
||||||
@ -37,6 +39,8 @@ pub enum Error {
|
|||||||
Product(products::Error),
|
Product(products::Error),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
Stock(stocks::Error),
|
Stock(stocks::Error),
|
||||||
|
#[error("{0}")]
|
||||||
|
OrderItem(order_items::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
@ -9,13 +9,13 @@ use super::Result;
|
|||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Can't create account")]
|
#[error("Can't create account order")]
|
||||||
CantCreate,
|
CantCreate,
|
||||||
#[error("Can't find account does to lack of identity")]
|
#[error("Can't find account order does to lack of identity")]
|
||||||
NoIdentity,
|
NoIdentity,
|
||||||
#[error("Account order does not exists")]
|
#[error("Account order does not exists")]
|
||||||
NotExists,
|
NotExists,
|
||||||
#[error("Failed to load all accounts")]
|
#[error("Failed to load all account orders")]
|
||||||
All,
|
All,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
93
api/src/actors/database/order_items.rs
Normal file
93
api/src/actors/database/order_items.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
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 order item")]
|
||||||
|
CantCreate,
|
||||||
|
#[error("Can't find order item does to lack of identity")]
|
||||||
|
NoIdentity,
|
||||||
|
#[error("Order item does not exists")]
|
||||||
|
NotExists,
|
||||||
|
#[error("Failed to load all order items")]
|
||||||
|
All,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(actix::Message)]
|
||||||
|
#[rtype(result = "Result<Vec<OrderItem>>")]
|
||||||
|
pub struct AllOrderItems;
|
||||||
|
|
||||||
|
async_handler!(AllOrderItems, all_order_items, Vec<OrderItem>);
|
||||||
|
|
||||||
|
pub async fn all_order_items(_msg: AllOrderItems, pool: PgPool) -> Result<Vec<OrderItem>> {
|
||||||
|
sqlx::query_as(
|
||||||
|
r#"
|
||||||
|
SELECT id, buyer_id, status
|
||||||
|
FROM order_items
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.fetch_all(&pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
log::error!("{e:?}");
|
||||||
|
super::Error::OrderItem(Error::All)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(actix::Message)]
|
||||||
|
#[rtype(result = "Result<OrderItem>")]
|
||||||
|
pub struct CreateOrderItem {
|
||||||
|
pub buyer_id: AccountId,
|
||||||
|
pub status: OrderStatus,
|
||||||
|
}
|
||||||
|
|
||||||
|
async_handler!(CreateOrderItem, create_order_item, OrderItem);
|
||||||
|
|
||||||
|
async fn create_order_item(msg: CreateOrderItem, db: PgPool) -> Result<OrderItem> {
|
||||||
|
sqlx::query_as(
|
||||||
|
r#"
|
||||||
|
INSERT INTO order_items (buyer_id, status)
|
||||||
|
VALUES ($1, $2)
|
||||||
|
RETURNING id, buyer_id, status
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(msg.buyer_id)
|
||||||
|
.bind(msg.status)
|
||||||
|
.fetch_one(&db)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
log::error!("{e:?}");
|
||||||
|
super::Error::OrderItem(Error::CantCreate)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(actix::Message)]
|
||||||
|
#[rtype(result = "Result<OrderItem>")]
|
||||||
|
pub struct FindOrderItem {
|
||||||
|
pub id: OrderItemId,
|
||||||
|
}
|
||||||
|
|
||||||
|
async_handler!(FindOrderItem, find_order_item, OrderItem);
|
||||||
|
|
||||||
|
async fn find_order_item(msg: FindOrderItem, db: PgPool) -> Result<OrderItem> {
|
||||||
|
sqlx::query_as(
|
||||||
|
r#"
|
||||||
|
SELECT id, buyer_id, status
|
||||||
|
FROM order_items
|
||||||
|
WHERE id = $1
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(msg.id)
|
||||||
|
.fetch_one(&db)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
log::error!("{e:?}");
|
||||||
|
super::Error::OrderItem(Error::NotExists)
|
||||||
|
})
|
||||||
|
}
|
@ -8,13 +8,13 @@ use crate::{database, model};
|
|||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Unable to load all products")]
|
#[error("Unable to load all stocks")]
|
||||||
All,
|
All,
|
||||||
#[error("Unable to create product")]
|
#[error("Unable to create stock")]
|
||||||
Create,
|
Create,
|
||||||
#[error("Unable to update product")]
|
#[error("Unable to update stock")]
|
||||||
Update,
|
Update,
|
||||||
#[error("Unable to delete product")]
|
#[error("Unable to delete stock")]
|
||||||
Delete,
|
Delete,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,9 +22,9 @@ pub enum Error {
|
|||||||
#[rtype(result = "Result<Vec<model::Stock>>")]
|
#[rtype(result = "Result<Vec<model::Stock>>")]
|
||||||
pub struct AllStocks;
|
pub struct AllStocks;
|
||||||
|
|
||||||
crate::async_handler!(AllStocks, all, Vec<Stock>);
|
crate::async_handler!(AllStocks, all_stocks, Vec<Stock>);
|
||||||
|
|
||||||
async fn all(_msg: AllStocks, pool: PgPool) -> Result<Vec<model::Stock>> {
|
async fn all_stocks(_msg: AllStocks, pool: PgPool) -> Result<Vec<model::Stock>> {
|
||||||
sqlx::query_as(
|
sqlx::query_as(
|
||||||
r#"
|
r#"
|
||||||
SELECT id, product_id, quantity, quantity_unit
|
SELECT id, product_id, quantity, quantity_unit
|
||||||
@ -47,9 +47,9 @@ pub struct CreateStock {
|
|||||||
pub quantity_unit: QuantityUnit,
|
pub quantity_unit: QuantityUnit,
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::async_handler!(CreateStock, create_product, Stock);
|
crate::async_handler!(CreateStock, create_stock, Stock);
|
||||||
|
|
||||||
async fn create_product(msg: CreateStock, pool: PgPool) -> Result<model::Stock> {
|
async fn create_stock(msg: CreateStock, pool: PgPool) -> Result<model::Stock> {
|
||||||
sqlx::query_as(
|
sqlx::query_as(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO stocks (product_id, quantity)
|
INSERT INTO stocks (product_id, quantity)
|
||||||
@ -77,9 +77,9 @@ pub struct UpdateStock {
|
|||||||
pub quantity_unit: QuantityUnit,
|
pub quantity_unit: QuantityUnit,
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::async_handler!(UpdateStock, update_product, Stock);
|
crate::async_handler!(UpdateStock, update_stock, Stock);
|
||||||
|
|
||||||
async fn update_product(msg: UpdateStock, pool: PgPool) -> Result<model::Stock> {
|
async fn update_stock(msg: UpdateStock, pool: PgPool) -> Result<model::Stock> {
|
||||||
sqlx::query_as(
|
sqlx::query_as(
|
||||||
r#"
|
r#"
|
||||||
UPDATE stocks
|
UPDATE stocks
|
||||||
@ -108,9 +108,9 @@ pub struct DeleteStock {
|
|||||||
pub stock_id: StockId,
|
pub stock_id: StockId,
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::async_handler!(DeleteStock, delete_product, Option<model::Stock>);
|
crate::async_handler!(DeleteStock, delete_stock, Option<model::Stock>);
|
||||||
|
|
||||||
async fn delete_product(msg: DeleteStock, pool: PgPool) -> Result<Option<Stock>> {
|
async fn delete_stock(msg: DeleteStock, pool: PgPool) -> Result<Option<Stock>> {
|
||||||
sqlx::query_as(
|
sqlx::query_as(
|
||||||
r#"
|
r#"
|
||||||
DELETE FROM stocks
|
DELETE FROM stocks
|
||||||
|
@ -5,7 +5,7 @@ use actix_session::{storage::RedisActorSessionStore, SessionMiddleware};
|
|||||||
use actix_web::cookie::Key;
|
use actix_web::cookie::Key;
|
||||||
use actix_web::middleware::Logger;
|
use actix_web::middleware::Logger;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use actix_web::{web, App, HttpResponse, HttpServer};
|
use actix_web::{App, HttpServer};
|
||||||
use gumdrop::Options;
|
use gumdrop::Options;
|
||||||
use password_hash::SaltString;
|
use password_hash::SaltString;
|
||||||
use validator::{validate_email, validate_length};
|
use validator::{validate_email, validate_length};
|
||||||
|
@ -4,6 +4,12 @@ use derive_more::{Deref, Display};
|
|||||||
use serde::de::{Error, Visitor};
|
use serde::de::{Error, Visitor};
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum TransformError {
|
||||||
|
#[error("Given value is below minimal value")]
|
||||||
|
BelowMinimal,
|
||||||
|
}
|
||||||
|
|
||||||
pub type RecordId = i32;
|
pub type RecordId = i32;
|
||||||
|
|
||||||
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
||||||
@ -41,6 +47,13 @@ pub enum QuantityUnit {
|
|||||||
Unit,
|
Unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
||||||
|
#[sqlx(rename_all = "lowercase")]
|
||||||
|
pub enum PaymentMethod {
|
||||||
|
PayU,
|
||||||
|
PaymentOnTheSpot,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
|
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
|
||||||
#[sqlx(transparent)]
|
#[sqlx(transparent)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
@ -56,6 +69,22 @@ pub struct PriceMinor(NonNegative);
|
|||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct Quantity(NonNegative);
|
pub struct Quantity(NonNegative);
|
||||||
|
|
||||||
|
impl TryFrom<NonNegative> for Quantity {
|
||||||
|
type Error = TransformError;
|
||||||
|
|
||||||
|
fn try_from(value: NonNegative) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<i32> for Quantity {
|
||||||
|
type Error = TransformError;
|
||||||
|
|
||||||
|
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self(value.try_into()?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(sqlx::Type, Deserialize, Serialize, Deref, Debug)]
|
#[derive(sqlx::Type, Deserialize, Serialize, Deref, Debug)]
|
||||||
#[sqlx(transparent)]
|
#[sqlx(transparent)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
@ -98,7 +127,19 @@ impl<'de> serde::Deserialize<'de> for Email {
|
|||||||
#[derive(sqlx::Type, Serialize, Deref)]
|
#[derive(sqlx::Type, Serialize, Deref)]
|
||||||
#[sqlx(transparent)]
|
#[sqlx(transparent)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct NonNegative(pub i32);
|
pub struct NonNegative(i32);
|
||||||
|
|
||||||
|
impl TryFrom<i32> for NonNegative {
|
||||||
|
type Error = TransformError;
|
||||||
|
|
||||||
|
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||||
|
if value < 0 {
|
||||||
|
return Err(TransformError::BelowMinimal);
|
||||||
|
} else {
|
||||||
|
Ok(Self(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'de> serde::Deserialize<'de> for NonNegative {
|
impl<'de> serde::Deserialize<'de> for NonNegative {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
@ -227,7 +268,7 @@ pub struct Stock {
|
|||||||
pub quantity_unit: QuantityUnit,
|
pub quantity_unit: QuantityUnit,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize)]
|
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
|
||||||
#[sqlx(transparent)]
|
#[sqlx(transparent)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct AccountOrderId(pub RecordId);
|
pub struct AccountOrderId(pub RecordId);
|
||||||
@ -238,3 +279,43 @@ pub struct AccountOrder {
|
|||||||
pub buyer_id: AccountId,
|
pub buyer_id: AccountId,
|
||||||
pub status: OrderStatus,
|
pub status: OrderStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
|
||||||
|
#[sqlx(transparent)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub struct OrderItemId(pub RecordId);
|
||||||
|
|
||||||
|
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
||||||
|
pub struct OrderItem {
|
||||||
|
pub id: OrderItemId,
|
||||||
|
pub product_id: ProductId,
|
||||||
|
pub order_id: OrderItemId,
|
||||||
|
pub quantity: Quantity,
|
||||||
|
pub quantity_unit: QuantityUnit,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
|
||||||
|
#[sqlx(transparent)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub struct ShoppingCartId(pub RecordId);
|
||||||
|
|
||||||
|
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
||||||
|
pub struct ShoppingCart {
|
||||||
|
pub id: ShoppingCartId,
|
||||||
|
pub buyer_id: AccountId,
|
||||||
|
pub payment_method: PaymentMethod,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
|
||||||
|
#[sqlx(transparent)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub struct ShoppingCartItemId(pub RecordId);
|
||||||
|
|
||||||
|
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
||||||
|
pub struct ShoppingCartItem {
|
||||||
|
pub id: ShoppingCartId,
|
||||||
|
pub product_id: ProductId,
|
||||||
|
pub shopping_cart_id: ShoppingCartId,
|
||||||
|
pub quantity: Quantity,
|
||||||
|
pub quantity_unit: QuantityUnit,
|
||||||
|
}
|
||||||
|
@ -68,7 +68,7 @@ CREATE TABLE order_items
|
|||||||
CONSTRAINT positive_quantity check ( quantity >= 0 )
|
CONSTRAINT positive_quantity check ( quantity >= 0 )
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE statistics
|
CREATE TABLE "statistics"
|
||||||
(
|
(
|
||||||
id serial not null primary key,
|
id serial not null primary key,
|
||||||
url varchar not null,
|
url varchar not null,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
CREATE TYPE "PaymentMethod" AS ENUM (
|
CREATE TYPE "PaymentMethod" AS ENUM (
|
||||||
'payu',
|
'pay_u',
|
||||||
'payment_on_the_spot'
|
'payment_on_the_spot'
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ CREATE TABLE shopping_cart_items
|
|||||||
(
|
(
|
||||||
id serial not null primary key,
|
id serial not null primary key,
|
||||||
product_id int references products (id) not null,
|
product_id int references products (id) not null,
|
||||||
order_id int references shopping_carts (id),
|
shopping_cart_id int references shopping_carts (id),
|
||||||
quantity int not null default 0,
|
quantity int not null default 0,
|
||||||
quantity_unit "QuantityUnit" not null,
|
quantity_unit "QuantityUnit" not null,
|
||||||
CONSTRAINT positive_quantity check ( quantity >= 0 )
|
CONSTRAINT positive_quantity check ( quantity >= 0 )
|
||||||
|
Loading…
Reference in New Issue
Block a user