UnAuthorized Leave Salary Deduction Issue As Per Setup Parameter has been Fixed Correction

This commit is contained in:
Shahadat Hossain 2026-11-09 16:31:55 +06:00
parent cb1cbfa5eb
commit af24bc0b4a
2 changed files with 57 additions and 35 deletions

57
CLAUDE.md Normal file
View File

@ -0,0 +1,57 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Overview
CEL Payroll is a .NET Framework 4.5 WinForms desktop payroll/HR application (C#) backed by SQL Server. Solution: `CEL Payroll.sln` (VS 2019 format; folder name refers to the original VS2015 port). There are no test projects and no linter.
## Build
Build from Visual Studio, or with MSBuild from a Developer Command Prompt:
```bash
msbuild "CEL Payroll.sln" /p:Configuration=Debug
```
Startup project is `Payroll.UI` (WinExe, entry `Payroll.UI/Payroll.UI/Program.cs` → `frmMain`). Third-party and in-house framework assemblies (`Ease.CoreV35`, `Ease.Controls`, `Ease.Report`, ReportViewer, NPOI, ClosedXML, iTextSharp, etc.) are checked in as binaries under `Library/` and referenced by HintPath, not NuGet. Crystal Reports 10.5 runtime must be installed for `Payroll.Report` to build.
## Architecture
Layered, with project dependencies flowing downward:
- **Payroll.UI** — WinForms screens, grouped by module folder (Salary, Tax, Bonus, Leave, PF, Gratuity, FinalSettlement, …).
- **Payroll.Report** — report classes (`Class/rpt*.cs`), the report viewer (`UI/fReportViewer.cs`), typed datasets (`PayrollDataSet`), and `.rdlc` files under `RDLC/` (plus some Crystal reports).
- **Ease.UICreator** — generic, config-driven master/detail form generator used for simple setup screens.
- **Payroll.Controls** — shared custom WinForms controls.
- **Payroll.Service** — service implementations + data access (SQL).
- **Payroll.BO** — business objects and the service interfaces.
- **Ease.SvcHost** — Windows service exposing `Payroll.Service` over .NET Remoting (TCP) for a 3-tier deployment.
- **Payroll.NotifProcessInterface** — console exe that runs notification/mail processing.
### BO / Service / DA pattern
Each entity spans three files that share a module folder name across projects, e.g. Bonus:
1. `Payroll.BO/Bonus/Bonus.cs` — class deriving from `BasicBaseObject` (or similar Ease.CoreV35 base), properties call `OnPropertyChange`, static `Get(...)`/instance `Save()`/`Delete()` methods that use a per-type `Cache` and delegate to `Service`. The **service interface (`IBonusService`) is declared at the bottom of the same BO file**. `Service` is resolved via `Services.Factory.CreateService<IBonusService>(...)`.
2. `Payroll.Service/Bonus/Service/BonusService.cs` — `ServiceTemplate` subclass implementing the interface. Every method wraps work in `TransactionContext.Begin()` / `tc.End()`, with `tc.HandleError()` + `ExceptionLog.Write(e)` + `throw new ServiceException(...)` in the catch. `MapObject` maps `DataReader` columns to BO properties and sets `ObjectState.Saved`.
3. `Payroll.Service/Bonus/DA/BonusDA.cs` — `internal static` class of raw SQL. Queries use Ease's placeholder formatting, not SqlParameters: `%n` number, `%s` string, `%d` date (e.g. `tc.ExecuteNonQuery("UPDATE Bonus SET code=%s WHERE BonusID=%n", ...)`).
Adding a method to an entity means touching all three: interface + BO wrapper, service implementation, DA query. IDs use the Ease `ID` type (`.Integer` for the int value). Many queries are scoped by `SystemInformation.CurrentSysInfo.PayrollTypeID`.
Service location is controlled by `serviceHandler` in `Payroll.UI/Payroll.UI/App.config`: `Payroll.Service.dll/conn` loads the services in-process using the `conn` entry in `<dbSettings>`; a `host:port/Payroll.Service` value goes through `Ease.SvcHost` remoting instead.
### Menus and forms
The main menu is driven by `Payroll.UI/Payroll.UI/Menu.xml`. Each `<permissioninfo>` names a `<formname>` and `<showfunction>`; `frmMain` resolves the form type by reflection (`Payroll.UI.<formname>` unless the name is assembly-qualified) and invokes the parameterless show method. Simple setup screens use `BasicUIForms` (`CreateUI.cs`), whose `show*` methods build forms through `Ease.UICreator`. Adding a screen to the menu means adding a Menu.xml entry whose names match exactly.
### Reports
RDLC files are compiled as **EmbeddedResource** in `Payroll.Report.csproj` and loaded by manifest name, e.g. `"Payroll.Report.RDLC.BankAdvice.rdlc"` (see `Class/rptBankAdvice.cs`, `UI/fReportViewer.cs`). A new `.rdlc` must be added to the csproj as an EmbeddedResource, and its dataset fields must match the `DataTable` passed in (typed datasets live in `PayrollDataSet`).
## Repository conventions
- Branching: work on `dev_shahadat`, PRs into `devqc` (Gitea-hosted).
- Commit messages are prefixed with the ticket ID in the form `YYYYMMDD-NNNN <description>`, e.g. `20260929-3216 Bank advice Salary Report Modification`.
- Release commits typically bump `AssemblyVersion`/`AssemblyFileVersion` in `Payroll.UI/Payroll.UI/Properties/AssemblyInfo.cs` to a date-based `YY.M.DD.0` value.
- `App.config` contains live DB connection strings and is frequently changed per environment; don't commit connection-string changes unless intended.

View File

@ -1512,41 +1512,6 @@ namespace Payroll.BO
if (Param.Details.Count > 0) if (Param.Details.Count > 0)
this.AddDetail(salary, EnumSalaryGroup.Miscellaneous, EnumSalaryItemCode.Tot_UnauthLeave_Days, Param.UnAhuthorizeLeaveID.Integer, 0, "UnAuthorized Leave Days", item.BasicCurrentDeduct); this.AddDetail(salary, EnumSalaryGroup.Miscellaneous, EnumSalaryItemCode.Tot_UnauthLeave_Days, Param.UnAhuthorizeLeaveID.Integer, 0, "UnAuthorized Leave Days", item.BasicCurrentDeduct);
#region Deduct all allowances for unauthorized leave
// Same days and daily-rate formula as Basic; allowances already set in the parameter are skipped to avoid double deduction
if (item.BasicCurrentDeduct > 0)
{
List<SalaryMonthlyDetail> allowances = salary.Details.FindAll(delegate(SalaryMonthlyDetail dtl)
{
return dtl.itemGroupCode == EnumSalaryGroup.Gross && dtl.ItemCode == EnumSalaryItemCode.Allowance;
});
foreach (SalaryMonthlyDetail allowance in allowances)
{
bool isInParam = Param.Details.Exists(delegate(UnAuthorizeLeaveParamDetail pd)
{
return pd.Type == EnumSalaryComponent.Allowance && pd.AllowanceID.Integer == allowance.ItemID;
});
if (isInParam) continue;
nAmount = allowance.CalculatedAmount;
if (salary.Employee.JoiningDate > GlobalFunctions.FirstDateOfMonth(_processMonth))
{
double ndays = Ease.CoreV35.Utility.Global.DateFunctions.DateDiff("d", salary.Employee.JoiningDate, _processMonth) + 1;
nAmount = nAmount / ndays;
nAmount = nAmount * _processMonth.Day;
}
nAmount = GlobalFunctions.ConevrtToDlyRateofMonth(nAmount, _processMonth) * item.BasicCurrentDeduct;
nAmount = GlobalFunctions.Round(nAmount);
if (nAmount <= 0) continue;
this.AddDetail(salary, EnumSalaryGroup.UnauthLeave, EnumSalaryItemCode.Allowance,
allowance.ItemID, allowance.SupportID.Integer, allowance.Description, nAmount);
}
}
#endregion
//} //}
//item.currentDeduct = nUnpaidDays; //item.currentDeduct = nUnpaidDays;