use rust_decimal::Decimal;
use sqlx::{PgPool, Row};
use uuid::Uuid;
use crate::domain::entity::StockMoveLine;
pub const TABLE_NAME: &str = "inventory.stock_move_lines";
pub struct StockMoveLineRepository(
backbone_orm::GenericCrudRepository<StockMoveLine, backbone_orm::SoftDelete>,
);
impl std::ops::Deref for StockMoveLineRepository {
type Target = backbone_orm::GenericCrudRepository<StockMoveLine, backbone_orm::SoftDelete>;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl StockMoveLineRepository {
pub fn new(pool: PgPool) -> Self {
Self(backbone_orm::GenericCrudRepository::new(pool, TABLE_NAME))
}
}
pub struct NewMoveLineRow<'a> {
pub id: Uuid,
pub quantity: Decimal,
pub lot_id: Option<Uuid>,
pub package_id: Option<Uuid>,
pub result_package_id: Option<Uuid>,
pub owner_id: Option<Uuid>,
pub move_id: Uuid,
pub picking_id: Option<Uuid>,
pub location_id: Uuid,
pub location_dest_id: Uuid,
pub item_id: Uuid,
pub state: &'a str,
}
pub struct MoveLineRow {
pub id: Uuid,
pub quantity: Decimal,
pub lot_id: Option<Uuid>,
pub package_id: Option<Uuid>,
pub result_package_id: Option<Uuid>,
pub owner_id: Option<Uuid>,
pub state: String,
pub move_id: Uuid,
pub location_id: Uuid,
pub location_dest_id: Uuid,
pub item_id: Uuid,
}
impl StockMoveLineRepository {
pub async fn insert_line(
&self,
conn: &mut sqlx::PgConnection,
l: &NewMoveLineRow<'_>,
) -> Result<(), sqlx::Error> {
sqlx::query(
r#"INSERT INTO inventory.stock_move_lines
(id, quantity, lot_id, package_id, result_package_id, owner_id, state, move_id,
picking_id, location_id, location_dest_id, item_id)
VALUES ($1,$2,$3,$4,$5,$6,$7::move_state,$8,$9,$10,$11,$12)"#,
)
.bind(l.id).bind(l.quantity).bind(l.lot_id).bind(l.package_id).bind(l.result_package_id)
.bind(l.owner_id).bind(l.state).bind(l.move_id).bind(l.picking_id)
.bind(l.location_id).bind(l.location_dest_id).bind(l.item_id)
.execute(conn)
.await?;
Ok(())
}
pub async fn retarget_picking(
&self,
conn: &mut sqlx::PgConnection,
move_id: Uuid,
picking_id: Uuid,
) -> Result<(), sqlx::Error> {
sqlx::query(
r#"UPDATE inventory.stock_move_lines
SET picking_id = $2
WHERE move_id = $1 AND (metadata->>'deleted_at') IS NULL"#,
)
.bind(move_id)
.bind(picking_id)
.execute(&mut *conn)
.await?;
Ok(())
}
pub async fn fetch_lines_for_move(
&self,
conn: &mut sqlx::PgConnection,
move_id: Uuid,
) -> Result<Vec<MoveLineRow>, sqlx::Error> {
let rows = sqlx::query(
r#"SELECT id, quantity, lot_id, package_id, result_package_id, owner_id,
state::text AS state, move_id, location_id, location_dest_id, item_id
FROM inventory.stock_move_lines
WHERE move_id=$1 AND (metadata->>'deleted_at') IS NULL
ORDER BY id"#,
)
.bind(move_id)
.fetch_all(&mut *conn)
.await?;
Ok(rows.into_iter().map(line_row_of).collect())
}
pub async fn fetch_line(
&self,
conn: &mut sqlx::PgConnection,
move_line_id: Uuid,
) -> Result<Option<MoveLineRow>, sqlx::Error> {
let row = sqlx::query(
r#"SELECT id, quantity, lot_id, package_id, result_package_id, owner_id,
state::text AS state, move_id, location_id, location_dest_id, item_id
FROM inventory.stock_move_lines
WHERE id=$1 AND (metadata->>'deleted_at') IS NULL"#,
)
.bind(move_line_id)
.fetch_optional(&mut *conn)
.await?;
Ok(row.map(line_row_of))
}
pub async fn sum_mirror_qty(
&self,
conn: &mut sqlx::PgConnection,
move_id: Uuid,
) -> Result<Decimal, sqlx::Error> {
let qty: Option<Decimal> = sqlx::query_scalar(
r#"SELECT SUM(quantity) FROM inventory.stock_move_lines
WHERE move_id=$1 AND (metadata->>'deleted_at') IS NULL"#,
)
.bind(move_id)
.fetch_one(&mut *conn)
.await?;
Ok(qty.unwrap_or(Decimal::ZERO))
}
pub async fn set_quantity(
&self,
conn: &mut sqlx::PgConnection,
line_id: Uuid,
quantity: Decimal,
) -> Result<(), sqlx::Error> {
sqlx::query(
r#"UPDATE inventory.stock_move_lines SET quantity=$2
WHERE id=$1 AND (metadata->>'deleted_at') IS NULL"#,
)
.bind(line_id).bind(quantity)
.execute(conn)
.await?;
Ok(())
}
pub async fn mirror_state(
&self,
conn: &mut sqlx::PgConnection,
move_id: Uuid,
state: &str,
) -> Result<(), sqlx::Error> {
sqlx::query(
r#"UPDATE inventory.stock_move_lines SET state=$2::move_state
WHERE move_id=$1 AND (metadata->>'deleted_at') IS NULL"#,
)
.bind(move_id).bind(state)
.execute(conn)
.await?;
Ok(())
}
}
fn line_row_of(r: sqlx::postgres::PgRow) -> MoveLineRow {
MoveLineRow {
id: r.get("id"),
quantity: r.get("quantity"),
lot_id: r.get("lot_id"),
package_id: r.get("package_id"),
result_package_id: r.get("result_package_id"),
owner_id: r.get("owner_id"),
state: r.get("state"),
move_id: r.get("move_id"),
location_id: r.get("location_id"),
location_dest_id: r.get("location_dest_id"),
item_id: r.get("item_id"),
}
}
backbone_core::impl_crud_repository!(StockMoveLineRepository, StockMoveLine, soft_delete);