use anyhow::Result;
use rust_decimal::Decimal;
use sqlx::{PgPool, Row};
use uuid::Uuid;
use backbone_orm::company_scope::fetch_one_scalar_scoped;
use crate::domain::entity::PosCashMovement;
pub const TABLE_NAME: &str = "pos.pos_cash_movements";
pub struct PosCashMovementRepository(
backbone_orm::GenericCrudRepository<PosCashMovement, backbone_orm::SoftDelete>,
);
impl std::ops::Deref for PosCashMovementRepository {
type Target = backbone_orm::GenericCrudRepository<PosCashMovement, backbone_orm::SoftDelete>;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl PosCashMovementRepository {
pub fn new(pool: PgPool) -> Self {
Self(backbone_orm::GenericCrudRepository::new(pool, TABLE_NAME))
}
}
pub struct NewCashMovementRow<'a> {
pub id: Uuid,
pub pos_profile_id: Uuid,
pub opening_entry_id: Uuid,
pub cashier_party_id: Uuid,
pub movement_type: &'a str,
pub amount: Decimal,
pub reason: Option<&'a str>,
pub moved_at: chrono::NaiveDateTime,
}
impl PosCashMovementRepository {
pub async fn insert_movement(
&self,
conn: &mut sqlx::PgConnection,
m: &NewCashMovementRow<'_>,
) -> Result<(), sqlx::Error> {
sqlx::query(
r#"INSERT INTO pos.pos_cash_movements
(id, pos_profile_id, opening_entry_id, cashier_party_id, movement_type, amount, reason, moved_at)
VALUES ($1,$2,$3,$4,$5::pos_cash_movement_type,$6,$7,$8)"#,
)
.bind(m.id).bind(m.pos_profile_id).bind(m.opening_entry_id).bind(m.cashier_party_id)
.bind(m.movement_type).bind(m.amount).bind(m.reason).bind(m.moved_at)
.execute(conn)
.await?;
Ok(())
}
pub async fn net_for_session(
&self,
pool: &PgPool,
opening_entry_id: Uuid,
) -> Result<Decimal, sqlx::Error> {
fetch_one_scalar_scoped(
pool,
sqlx::query_scalar(
r#"SELECT COALESCE(SUM(CASE movement_type
WHEN 'pay_in' THEN amount
WHEN 'pay_out' THEN -amount
WHEN 'drop' THEN -amount
ELSE 0 END), 0)
FROM pos.pos_cash_movements
WHERE opening_entry_id=$1 AND (metadata->>'deleted_at') IS NULL"#,
)
.bind(opening_entry_id),
)
.await
}
}
backbone_core::impl_crud_repository!(PosCashMovementRepository, PosCashMovement, soft_delete);