backbone-payroll 0.3.47

Payroll: salary structures, payroll runs and computed salary slips over effective-dated statutory tables, plus compensation changes
Documentation
//! Repository for SalaryStructure 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 SalaryStructure SQL (4-layer rule: services orchestrate, repos hold SQL).
//!
//! Thin newtype over `backbone_orm::GenericCrudRepository<SalaryStructure, backbone_orm::SoftDelete>`.
//! All standard CRUD methods are available via `Deref`.

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

use crate::domain::entity::SalaryStructure;

/// Table name for SalaryStructure entities
pub const TABLE_NAME: &str = "payroll.salary_structures";

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

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

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

/// The exact row a structure definition writes. Mirrors the raw column shape, not the
/// `SalaryStructure` entity: the insert hard-codes `status = 'active'`, so that column is not a
/// parameter.
pub struct NewStructureRow<'a> {
    pub id: Uuid,
    pub name: &'a str,
}

/// Hand-written SalaryStructure SQL. Lives here (not in the write service) per the module's 4-layer
/// rule: services orchestrate and own the unit of work, repositories hold the SQL.
impl SalaryStructureRepository {
    /// Define a salary structure, active from the start.
    ///
    /// Takes the CALLER'S connection so the structure and its components commit as ONE unit. The
    /// caller has already relayed the ambient org request scope onto it (`bind_org_scope_on`,
    /// ADR-0029) so this passes the tenancy RLS fence — don't re-bind here.
    pub async fn insert_structure(
        &self,
        conn: &mut sqlx::PgConnection,
        s: &NewStructureRow<'_>,
    ) -> Result<(), sqlx::Error> {
        sqlx::query(
            r#"INSERT INTO payroll.salary_structures (id, name, status)
               VALUES ($1,$2,'active')"#,
        )
        .bind(s.id).bind(s.name)
        .execute(conn)
        .await?;
        Ok(())
    }
}

backbone_core::impl_crud_repository!(SalaryStructureRepository, SalaryStructure, soft_delete);