use anyhow::Result;
use rust_decimal::Decimal;
use sqlx::{PgPool, Row};
use uuid::Uuid;
use backbone_orm::org_scope;
use super::gl_voucher_repository::GlSettlementState;
use crate::domain::entity::StockReconciliation;
pub const TABLE_NAME: &str = "inventory.stock_reconciliations";
pub struct StockReconciliationRepository(
backbone_orm::GenericCrudRepository<StockReconciliation, backbone_orm::SoftDelete>,
);
impl std::ops::Deref for StockReconciliationRepository {
type Target = backbone_orm::GenericCrudRepository<StockReconciliation, backbone_orm::SoftDelete>;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl StockReconciliationRepository {
pub fn new(pool: PgPool) -> Self {
Self(backbone_orm::GenericCrudRepository::new(pool, TABLE_NAME))
}
}
pub struct NewReconciliationRow<'a> {
pub id: Uuid,
pub recon_number: &'a str,
pub warehouse_id: Uuid,
pub posting_date: chrono::NaiveDate,
pub currency: &'a str,
pub inventory_account_id: Uuid,
pub adjustment_account_id: Uuid,
}
pub struct ReconRepostHeaderRow {
pub recon_number: String,
pub posting_date: chrono::NaiveDate,
pub currency: String,
pub net_difference: Decimal,
pub inventory_account_id: Uuid,
pub adjustment_account_id: Uuid,
pub gl: GlSettlementState,
}
impl StockReconciliationRepository {
pub async fn insert_submitted(
&self,
conn: &mut sqlx::PgConnection,
r: &NewReconciliationRow<'_>,
) -> Result<(), sqlx::Error> {
sqlx::query(
r#"INSERT INTO inventory.stock_reconciliations
(id, recon_number, warehouse_id, posting_date, currency, net_difference,
inventory_account_id, adjustment_account_id, status, posting_state)
VALUES ($1,$2,$3,$4,$5,0,$6,$7,'submitted'::doc_status,'pending'::gl_posting_state)"#,
)
.bind(r.id).bind(r.recon_number).bind(r.warehouse_id).bind(r.posting_date)
.bind(r.currency)
.bind(r.inventory_account_id).bind(r.adjustment_account_id)
.execute(conn)
.await?;
Ok(())
}
pub async fn update_net_difference(
&self,
conn: &mut sqlx::PgConnection,
id: Uuid,
net_difference: Decimal,
) -> Result<(), sqlx::Error> {
sqlx::query("UPDATE inventory.stock_reconciliations SET net_difference=$2 WHERE id=$1")
.bind(id).bind(net_difference)
.execute(conn)
.await?;
Ok(())
}
pub async fn mark_not_applicable(
&self,
pool: &PgPool,
id: Uuid,
) -> Result<(), sqlx::Error> {
org_scope::execute_scoped(
pool,
sqlx::query("UPDATE inventory.stock_reconciliations SET posting_state='not_applicable'::gl_posting_state WHERE id=$1")
.bind(id),
)
.await?;
Ok(())
}
pub async fn fetch_repost_header(
&self,
pool: &PgPool,
id: Uuid,
) -> Result<Option<ReconRepostHeaderRow>, sqlx::Error> {
let row = org_scope::fetch_optional_row_scoped(
pool,
sqlx::query(
r#"SELECT recon_number, posting_date, currency, net_difference,
inventory_account_id, adjustment_account_id,
posting_state::text AS ps, journal_id, accounting_post_id
FROM inventory.stock_reconciliations WHERE id=$1 AND (metadata->>'deleted_at') IS NULL"#,
)
.bind(id),
)
.await?;
Ok(row.map(|h| ReconRepostHeaderRow {
recon_number: h.get("recon_number"),
posting_date: h.get("posting_date"), currency: h.get("currency"),
net_difference: h.get("net_difference"),
inventory_account_id: h.get("inventory_account_id"),
adjustment_account_id: h.get("adjustment_account_id"),
gl: GlSettlementState {
posting_state: h.get("ps"), journal_id: h.get("journal_id"),
accounting_post_id: h.get("accounting_post_id"),
},
}))
}
}
backbone_core::impl_crud_repository!(StockReconciliationRepository, StockReconciliation, soft_delete);