use anyhow::Result;
use rust_decimal::Decimal;
use sqlx::{PgPool, Row};
use uuid::Uuid;
use backbone_orm::company_scope::fetch_all_rows_scoped;
use crate::domain::entity::SalarySlipLine;
pub const TABLE_NAME: &str = "payroll.salary_slip_lines";
pub struct SalarySlipLineRepository(
backbone_orm::GenericCrudRepository<SalarySlipLine, backbone_orm::SoftDelete>,
);
impl std::ops::Deref for SalarySlipLineRepository {
type Target = backbone_orm::GenericCrudRepository<SalarySlipLine, backbone_orm::SoftDelete>;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl SalarySlipLineRepository {
pub fn new(pool: PgPool) -> Self {
Self(backbone_orm::GenericCrudRepository::new(pool, TABLE_NAME))
}
}
pub struct NewSlipLineRow<'a> {
pub id: Uuid,
pub salary_slip_id: Uuid,
pub name: &'a str,
pub component_type: &'a str,
pub is_statutory: bool,
pub amount: Decimal,
pub gl_account_id: Uuid,
pub source_kind: Option<&'static str>,
pub source_ref: Option<Uuid>,
}
pub struct DeductionGroupRow {
pub gl_account_id: Uuid,
pub amount: Decimal,
pub statutory: bool,
}
impl SalarySlipLineRepository {
pub async fn insert_line(
&self,
conn: &mut sqlx::PgConnection,
l: &NewSlipLineRow<'_>,
) -> Result<(), sqlx::Error> {
sqlx::query(
r#"INSERT INTO payroll.salary_slip_lines
(id, salary_slip_id, name, component_type, is_statutory, amount, gl_account_id,
source_kind, source_ref)
VALUES ($1,$2,$3,$4::component_type,$5,$6,$7,$8,$9)"#,
)
.bind(l.id).bind(l.salary_slip_id).bind(l.name).bind(l.component_type)
.bind(l.is_statutory).bind(l.amount).bind(l.gl_account_id)
.bind(l.source_kind).bind(l.source_ref)
.execute(conn)
.await?;
Ok(())
}
pub async fn group_deductions_by_account(
&self,
pool: &PgPool,
run_id: Uuid,
) -> Result<Vec<DeductionGroupRow>, sqlx::Error> {
let rows = fetch_all_rows_scoped(
pool,
sqlx::query(
r#"SELECT l.gl_account_id, SUM(l.amount) AS amt, bool_or(l.is_statutory) AS statutory
FROM payroll.salary_slip_lines l JOIN payroll.salary_slips s ON s.id = l.salary_slip_id
WHERE s.payroll_entry_id=$1 AND l.component_type='deduction'::component_type
AND (s.metadata->>'deleted_at') IS NULL
GROUP BY l.gl_account_id"#,
)
.bind(run_id),
)
.await?;
Ok(rows.iter().map(|r| DeductionGroupRow {
gl_account_id: r.get("gl_account_id"), amount: r.get("amt"), statutory: r.get("statutory"),
}).collect())
}
}
backbone_core::impl_crud_repository!(SalarySlipLineRepository, SalarySlipLine, soft_delete);