use chrono::NaiveDate;
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use super::graph_properties::{GraphPropertyValue, ToNodeProperties};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum PayrollRunStatus {
#[default]
Draft,
Calculated,
Approved,
Posted,
Reversed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PayrollRun {
pub company_code: String,
pub payroll_id: String,
pub pay_period_start: NaiveDate,
pub pay_period_end: NaiveDate,
pub run_date: NaiveDate,
pub status: PayrollRunStatus,
#[serde(with = "crate::serde_decimal")]
pub total_gross: Decimal,
#[serde(with = "crate::serde_decimal")]
pub total_deductions: Decimal,
#[serde(with = "crate::serde_decimal")]
pub total_net: Decimal,
#[serde(with = "crate::serde_decimal")]
pub total_employer_cost: Decimal,
pub employee_count: u32,
pub currency: String,
pub posted_by: Option<String>,
pub approved_by: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PayrollLineItem {
pub payroll_id: String,
pub employee_id: String,
pub line_id: String,
#[serde(with = "crate::serde_decimal")]
pub gross_pay: Decimal,
#[serde(with = "crate::serde_decimal")]
pub base_salary: Decimal,
#[serde(with = "crate::serde_decimal")]
pub overtime_pay: Decimal,
#[serde(with = "crate::serde_decimal")]
pub bonus: Decimal,
#[serde(with = "crate::serde_decimal")]
pub tax_withholding: Decimal,
#[serde(with = "crate::serde_decimal")]
pub social_security: Decimal,
#[serde(with = "crate::serde_decimal")]
pub health_insurance: Decimal,
#[serde(with = "crate::serde_decimal")]
pub retirement_contribution: Decimal,
#[serde(with = "crate::serde_decimal")]
pub other_deductions: Decimal,
#[serde(with = "crate::serde_decimal")]
pub net_pay: Decimal,
pub hours_worked: f64,
pub overtime_hours: f64,
pub pay_date: NaiveDate,
pub cost_center: Option<String>,
pub department: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tax_withholding_label: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub social_security_label: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub health_insurance_label: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub retirement_contribution_label: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub employer_contribution_label: Option<String>,
}
impl ToNodeProperties for PayrollRun {
fn node_type_name(&self) -> &'static str {
"payroll_run"
}
fn node_type_code(&self) -> u16 {
330
}
fn to_node_properties(&self) -> HashMap<String, GraphPropertyValue> {
let mut p = HashMap::new();
p.insert(
"entityCode".into(),
GraphPropertyValue::String(self.company_code.clone()),
);
p.insert(
"payrollId".into(),
GraphPropertyValue::String(self.payroll_id.clone()),
);
p.insert(
"periodStart".into(),
GraphPropertyValue::Date(self.pay_period_start),
);
p.insert(
"periodEnd".into(),
GraphPropertyValue::Date(self.pay_period_end),
);
p.insert("runDate".into(), GraphPropertyValue::Date(self.run_date));
p.insert(
"status".into(),
GraphPropertyValue::String(format!("{:?}", self.status)),
);
p.insert(
"employeeCount".into(),
GraphPropertyValue::Int(self.employee_count as i64),
);
p.insert(
"grossPay".into(),
GraphPropertyValue::Decimal(self.total_gross),
);
p.insert("netPay".into(), GraphPropertyValue::Decimal(self.total_net));
p.insert(
"taxWithheld".into(),
GraphPropertyValue::Decimal(self.total_deductions),
);
p.insert(
"currency".into(),
GraphPropertyValue::String(self.currency.clone()),
);
p.insert(
"isApproved".into(),
GraphPropertyValue::Bool(matches!(
self.status,
PayrollRunStatus::Approved | PayrollRunStatus::Posted
)),
);
p
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum BenefitPlanType {
#[default]
Health,
Dental,
Vision,
Retirement401k,
StockPurchase,
LifeInsurance,
Disability,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum BenefitStatus {
#[default]
Active,
Pending,
Terminated,
OnLeave,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BenefitEnrollment {
pub id: String,
pub entity_code: String,
pub employee_id: String,
pub employee_name: String,
pub plan_type: BenefitPlanType,
pub plan_name: String,
pub enrollment_date: NaiveDate,
pub effective_date: NaiveDate,
pub period: String,
#[serde(with = "crate::serde_decimal")]
pub employee_contribution: Decimal,
#[serde(with = "crate::serde_decimal")]
pub employer_contribution: Decimal,
pub currency: String,
pub status: BenefitStatus,
pub is_active: bool,
}
impl BenefitEnrollment {
#[allow(clippy::too_many_arguments)]
pub fn new(
id: impl Into<String>,
entity_code: impl Into<String>,
employee_id: impl Into<String>,
employee_name: impl Into<String>,
plan_type: BenefitPlanType,
plan_name: impl Into<String>,
enrollment_date: NaiveDate,
effective_date: NaiveDate,
period: impl Into<String>,
employee_contribution: Decimal,
employer_contribution: Decimal,
currency: impl Into<String>,
status: BenefitStatus,
is_active: bool,
) -> Self {
Self {
id: id.into(),
entity_code: entity_code.into(),
employee_id: employee_id.into(),
employee_name: employee_name.into(),
plan_type,
plan_name: plan_name.into(),
enrollment_date,
effective_date,
period: period.into(),
employee_contribution,
employer_contribution,
currency: currency.into(),
status,
is_active,
}
}
}
impl ToNodeProperties for BenefitEnrollment {
fn node_type_name(&self) -> &'static str {
"benefit_enrollment"
}
fn node_type_code(&self) -> u16 {
333
}
fn to_node_properties(&self) -> HashMap<String, GraphPropertyValue> {
let mut p = HashMap::new();
p.insert(
"entityCode".into(),
GraphPropertyValue::String(self.entity_code.clone()),
);
p.insert(
"employeeId".into(),
GraphPropertyValue::String(self.employee_id.clone()),
);
p.insert(
"employeeName".into(),
GraphPropertyValue::String(self.employee_name.clone()),
);
p.insert(
"planType".into(),
GraphPropertyValue::String(format!("{:?}", self.plan_type)),
);
p.insert(
"planName".into(),
GraphPropertyValue::String(self.plan_name.clone()),
);
p.insert(
"enrollmentDate".into(),
GraphPropertyValue::Date(self.enrollment_date),
);
p.insert(
"effectiveDate".into(),
GraphPropertyValue::Date(self.effective_date),
);
p.insert(
"period".into(),
GraphPropertyValue::String(self.period.clone()),
);
p.insert(
"employeeContribution".into(),
GraphPropertyValue::Decimal(self.employee_contribution),
);
p.insert(
"employerContribution".into(),
GraphPropertyValue::Decimal(self.employer_contribution),
);
p.insert(
"currency".into(),
GraphPropertyValue::String(self.currency.clone()),
);
p.insert(
"status".into(),
GraphPropertyValue::String(format!("{:?}", self.status)),
);
p.insert("isActive".into(), GraphPropertyValue::Bool(self.is_active));
p
}
}