use anyhow::Result;
use rust_decimal::Decimal;
use sqlx::{PgPool, Row};
use uuid::Uuid;
use backbone_orm::company_scope::fetch_one_row_scoped;
use crate::domain::entity::SalarySlip;
pub const TABLE_NAME: &str = "payroll.salary_slips";
pub struct SalarySlipRepository(
backbone_orm::GenericCrudRepository<SalarySlip, backbone_orm::SoftDelete>,
);
impl std::ops::Deref for SalarySlipRepository {
type Target = backbone_orm::GenericCrudRepository<SalarySlip, backbone_orm::SoftDelete>;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl SalarySlipRepository {
pub fn new(pool: PgPool) -> Self {
Self(backbone_orm::GenericCrudRepository::new(pool, TABLE_NAME))
}
}
pub struct NewSalarySlipRow {
pub id: Uuid,
pub payroll_entry_id: Uuid,
pub employee_id: Uuid,
pub structure_id: Uuid,
pub working_days: Decimal,
pub unpaid_days: Decimal,
pub gross_pay: Decimal,
pub total_deductions: Decimal,
pub net_pay: Decimal,
pub overtime_hours: Option<Decimal>,
pub tax_method: Option<String>,
}
pub struct SlipTotalsRow {
pub total_gross: Decimal,
pub total_deductions: Decimal,
pub total_net: Decimal,
pub count: i64,
}
impl SalarySlipRepository {
pub async fn insert_slip(
&self,
conn: &mut sqlx::PgConnection,
s: &NewSalarySlipRow,
) -> Result<(), sqlx::Error> {
sqlx::query(
r#"INSERT INTO payroll.salary_slips
(id, payroll_entry_id, employee_id, structure_id, working_days, unpaid_days,
gross_pay, total_deductions, net_pay, overtime_hours, tax_method)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)"#,
)
.bind(s.id).bind(s.payroll_entry_id).bind(s.employee_id).bind(s.structure_id)
.bind(s.working_days).bind(s.unpaid_days).bind(s.gross_pay).bind(s.total_deductions).bind(s.net_pay)
.bind(s.overtime_hours).bind(s.tax_method.clone())
.execute(conn)
.await?;
Ok(())
}
pub async fn sum_totals_by_run(
&self,
pool: &PgPool,
run_id: Uuid,
) -> Result<SlipTotalsRow, sqlx::Error> {
let row = fetch_one_row_scoped(
pool,
sqlx::query(
r#"SELECT COALESCE(SUM(gross_pay),0) AS g, COALESCE(SUM(total_deductions),0) AS d,
COALESCE(SUM(net_pay),0) AS n, count(*) AS c
FROM payroll.salary_slips WHERE payroll_entry_id=$1 AND (metadata->>'deleted_at') IS NULL"#,
)
.bind(run_id),
)
.await?;
Ok(SlipTotalsRow {
total_gross: row.get("g"), total_deductions: row.get("d"), total_net: row.get("n"),
count: row.get("c"),
})
}
}
backbone_core::impl_crud_repository!(SalarySlipRepository, SalarySlip, soft_delete);