backbone-inventory 0.17.2

Inventory: stock ledger of record (SLE) + moving-average valuation; emits COGS/asset AccountingPost (Delivery/Receipt -> GL)
Documentation
//! Repository for StockEntry entities
//!
//! Originally generated by metaphor-schema; now **user-owned** — this exact path is declared under
//! `user_owned` in `metaphor.codegen.yaml`, so the generator skips it wholesale. The custom methods
//! below hold the hand-written StockEntry (transfer) SQL
//! (4-layer rule: services orchestrate, repositories hold the SQL).
//!
//! Thin newtype over `backbone_orm::GenericCrudRepository<StockEntry, backbone_orm::SoftDelete>`.
//! All standard CRUD methods are available via `Deref`.

use anyhow::Result;
use rust_decimal::Decimal;
use sqlx::PgPool;
use uuid::Uuid;

use crate::domain::entity::StockEntry;

/// Table name for StockEntry entities
pub const TABLE_NAME: &str = "inventory.stock_entries";

/// Repository for StockEntry entities.
///
/// All standard CRUD, soft-delete, pagination, and bulk methods are
/// provided automatically via `Deref` to `backbone_orm::GenericCrudRepository`.
pub struct StockEntryRepository(
    backbone_orm::GenericCrudRepository<StockEntry, backbone_orm::SoftDelete>,
);

impl std::ops::Deref for StockEntryRepository {
    type Target = backbone_orm::GenericCrudRepository<StockEntry, backbone_orm::SoftDelete>;
    fn deref(&self) -> &Self::Target { &self.0 }
}

impl StockEntryRepository {
    /// Create a new repository instance.
    pub fn new(pool: PgPool) -> Self {
        Self(backbone_orm::GenericCrudRepository::new(pool, TABLE_NAME))
    }
}

/// The exact row a transfer Stock Entry header insert writes.
///
/// Mirrors the raw column shape rather than the `StockEntry` entity: `stock_entry_type`, `status`
/// and `posting_state` are literal casts. A transfer is submitted immediately and is value-neutral,
/// so its posting_state is `not_applicable` — there is no GL post to reconcile.
pub struct NewTransferRow<'a> {
    pub id: Uuid,
    pub entry_number: &'a str,
    pub from_warehouse_id: Uuid,
    pub to_warehouse_id: Uuid,
    pub posting_date: chrono::NaiveDate,
}

/// Hand-written StockEntry SQL. Lives here per the module's 4-layer rule.
impl StockEntryRepository {
    /// Insert the transfer header.
    ///
    /// Takes the CALLER'S connection so the header, its items, and BOTH bins' movements commit as one
    /// unit — a transfer that half-committed would create or destroy value. The caller has already
    /// relayed the ambient org scope onto it — don't re-bind here.
    ///
    /// Returns the raw `sqlx::Error` deliberately: the caller inspects it for a unique violation to
    /// turn a duplicate entry number into `DuplicateNumber`.
    pub async fn insert_transfer(
        &self,
        conn: &mut sqlx::PgConnection,
        t: &NewTransferRow<'_>,
    ) -> Result<(), sqlx::Error> {
        sqlx::query(
            r#"INSERT INTO inventory.stock_entries
                (id, entry_number, stock_entry_type, from_warehouse_id, to_warehouse_id,
                 posting_date, status, posting_state)
               VALUES ($1,$2,'transfer'::stock_entry_type,$3,$4,$5,'submitted'::doc_status,'not_applicable'::gl_posting_state)"#,
        )
        .bind(t.id).bind(t.entry_number).bind(t.from_warehouse_id)
        .bind(t.to_warehouse_id).bind(t.posting_date)
        .execute(conn)
        .await?;
        Ok(())
    }
}

backbone_core::impl_crud_repository!(StockEntryRepository, StockEntry, soft_delete);