Compare commits

...

4 commits

Author SHA1 Message Date
6c5356ca46 fixed tenure
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m20s
2026-05-18 23:25:09 +07:00
5ea111a3c5 fixed cron job 2026-05-18 21:51:23 +07:00
d093953fbe แก้ไขการคำนวนระยะเวลาครองตำแหน่ง 2026-05-18 20:56:20 +07:00
f1c546ba8f fix store procedure 2026-05-18 17:37:43 +07:00
9 changed files with 1027 additions and 290 deletions

View file

@ -0,0 +1,140 @@
-- ====================================================================
-- Fix GetProfileEmployeeSalaryLevel to use calendar arithmetic
-- This changes from fixed formulas to actual calendar arithmetic,
-- matching calculateGovAge and GetProfileSalaryLevel behavior
-- ====================================================================
DELIMITER $$
DROP PROCEDURE IF EXISTS `GetProfileEmployeeSalaryLevel`$$
CREATE DEFINER=`root`@`%` PROCEDURE `GetProfileEmployeeSalaryLevel`(
IN personId VARCHAR(36),
IN _date DATE
)
BEGIN
WITH ordered AS (
SELECT *
FROM profileSalary
WHERE profileEmployeeId = personId
AND commandCode IN ('0','1','2','3','4','8','9','10','11','12','13','14','15','16','20')
),
work_session AS (
SELECT *,
COALESCE(
SUM(CASE WHEN commandCode IN (12,15,16) THEN 1 ELSE 0 END)
OVER (ORDER BY commandDateAffect, commandDateSign
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),
0) AS sessionId
FROM ordered
),
session_end AS (
SELECT sessionId, MAX(commandDateAffect) AS sessionEndDate
FROM work_session
GROUP BY sessionId
),
level_change AS (
SELECT *,
CASE
WHEN LAG(positionCee) OVER (ORDER BY commandDateAffect, commandDateSign) <=> positionCee
AND LAG(positionType) OVER (ORDER BY commandDateAffect, commandDateSign) <=> positionType
AND LAG(positionLevel) OVER (ORDER BY commandDateAffect, commandDateSign) <=> positionLevel
AND LAG(sessionId) OVER (ORDER BY commandDateAffect, commandDateSign) = sessionId
THEN 0
ELSE 1
END AS isNewLevel
FROM work_session
),
level_group AS (
SELECT *,
SUM(isNewLevel) OVER (ORDER BY commandDateAffect, commandDateSign) AS levelGroup
FROM level_change
),
first_rows AS (
SELECT * FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY levelGroup ORDER BY commandDateAffect, commandDateSign) AS rnLevel
FROM level_group
) t WHERE rnLevel = 1
),
rows_with_duration AS (
SELECT
fr.*,
CASE
WHEN LEAD(fr.commandDateAffect) OVER (ORDER BY fr.commandDateAffect, fr.commandDateSign) IS NULL
THEN NULL
WHEN LEAD(fr.sessionId) OVER (ORDER BY fr.commandDateAffect, fr.commandDateSign) <> fr.sessionId
THEN TIMESTAMPDIFF(DAY, fr.commandDateAffect, se.sessionEndDate) + 1
ELSE
TIMESTAMPDIFF(DAY, fr.commandDateAffect,
LEAD(fr.commandDateAffect) OVER (ORDER BY fr.commandDateAffect, fr.commandDateSign))
END AS duration_days
FROM first_rows fr
LEFT JOIN session_end se ON se.sessionId = fr.sessionId
),
resultWithDiff AS (
SELECT
*,
LAG(duration_days) OVER (ORDER BY commandDateAffect, commandDateSign) AS days_diff
FROM rows_with_duration
)
SELECT
r.commandDateAffect,
r.positionType,
r.positionLevel,
r.positionCee,
r.days_diff,
CASE
WHEN LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign) IS NOT NULL THEN
TIMESTAMPDIFF(YEAR, LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign), r.commandDateAffect)
ELSE 0
END AS Years,
CASE
WHEN LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign) IS NOT NULL THEN
TIMESTAMPDIFF(MONTH, LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign), r.commandDateAffect) % 12
ELSE 0
END AS Months,
CASE
WHEN LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign) IS NOT NULL THEN
DATEDIFF(r.commandDateAffect,
DATE_ADD(
DATE_ADD(LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign),
INTERVAL TIMESTAMPDIFF(YEAR, LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign), r.commandDateAffect) YEAR),
INTERVAL TIMESTAMPDIFF(MONTH, LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign), r.commandDateAffect) % 12 MONTH)
)
ELSE 0
END AS Days,
r.posNo,
r.positionExecutive,
r.orgRoot,
r.orgChild1,
r.orgChild2,
r.orgChild3,
r.orgChild4,
r.commandCode,
r.commandName,
r.commandNo,
r.commandYear,
r.remark
FROM resultWithDiff r
UNION ALL
SELECT
_date, NULL, NULL, NULL,
TIMESTAMPDIFF(DAY, MAX(commandDateAffect), _date) + 1,
TIMESTAMPDIFF(YEAR, MAX(commandDateAffect), _date),
TIMESTAMPDIFF(MONTH, MAX(commandDateAffect), _date) % 12,
DATEDIFF(_date,
DATE_ADD(
DATE_ADD(MAX(commandDateAffect),
INTERVAL TIMESTAMPDIFF(YEAR, MAX(commandDateAffect), _date) YEAR),
INTERVAL TIMESTAMPDIFF(MONTH, MAX(commandDateAffect), _date) % 12 MONTH)
),
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL
FROM resultWithDiff;
END$$
DELIMITER ;

View file

@ -0,0 +1,137 @@
-- ====================================================================
-- Fix GetProfileEmployeeSalaryPosition to use calendar arithmetic
-- This changes from fixed formulas to actual calendar arithmetic,
-- matching calculateGovAge and GetProfileSalaryPosition behavior
-- ====================================================================
DELIMITER $$
DROP PROCEDURE IF EXISTS `GetProfileEmployeeSalaryPosition`$$
CREATE DEFINER=`root`@`%` PROCEDURE `GetProfileEmployeeSalaryPosition`(
IN personId VARCHAR(36),
IN _date DATE
)
BEGIN
WITH ordered AS (
SELECT * FROM profileSalary WHERE profileEmployeeId = personId AND commandCode IN ('0','1','2','3','4','8','9','10','11','12','13','14','15','16','20')
),
work_session AS (
SELECT *,
COALESCE(
SUM(CASE WHEN commandCode IN (12,15,16) THEN 1 ELSE 0 END)
OVER (ORDER BY commandDateAffect, commandDateSign
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),
0) AS sessionId
FROM ordered
),
session_end AS (
SELECT sessionId, MAX(commandDateAffect) AS sessionEndDate
FROM work_session
GROUP BY sessionId
),
position_change AS (
SELECT *,
CASE
WHEN LAG(positionName) OVER (ORDER BY commandDateAffect, commandDateSign) = positionName
AND LAG(sessionId) OVER (ORDER BY commandDateAffect, commandDateSign) = sessionId
THEN 0
ELSE 1
END AS isNewPosition
FROM work_session
),
position_group AS (
SELECT *,
SUM(isNewPosition) OVER (ORDER BY commandDateAffect, commandDateSign) AS posGroup
FROM position_change
),
first_rows AS (
SELECT * FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY posGroup ORDER BY commandDateAffect, commandDateSign) AS rnPos
FROM position_group
) t WHERE rnPos = 1
),
rows_with_duration AS (
SELECT
fr.*,
LEAD(fr.sessionId) OVER (ORDER BY fr.commandDateAffect, fr.commandDateSign) AS nextSessionId,
CASE
WHEN LEAD(fr.commandDateAffect) OVER (ORDER BY fr.commandDateAffect, fr.commandDateSign) IS NULL
THEN NULL
WHEN LEAD(fr.sessionId) OVER (ORDER BY fr.commandDateAffect, fr.commandDateSign) <> fr.sessionId
THEN TIMESTAMPDIFF(DAY, fr.commandDateAffect, se.sessionEndDate) + 1
ELSE
TIMESTAMPDIFF(DAY, fr.commandDateAffect,
LEAD(fr.commandDateAffect) OVER (ORDER BY fr.commandDateAffect, fr.commandDateSign))
END AS duration_days
FROM first_rows fr
LEFT JOIN session_end se ON se.sessionId = fr.sessionId
),
resultWithDiff AS (
SELECT
*,
LAG(duration_days) OVER (ORDER BY commandDateAffect, commandDateSign) AS days_diff
FROM rows_with_duration
)
SELECT
r.commandDateAffect,
r.positionName,
r.positionCee,
r.days_diff,
CASE
WHEN LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign) IS NOT NULL THEN
TIMESTAMPDIFF(YEAR, LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign), r.commandDateAffect)
ELSE 0
END AS Years,
CASE
WHEN LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign) IS NOT NULL THEN
TIMESTAMPDIFF(MONTH, LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign), r.commandDateAffect) % 12
ELSE 0
END AS Months,
CASE
WHEN LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign) IS NOT NULL THEN
TIMESTAMPDIFF(DAY,
DATE_ADD(
DATE_ADD(LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign),
INTERVAL TIMESTAMPDIFF(YEAR, LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign), r.commandDateAffect) YEAR),
INTERVAL TIMESTAMPDIFF(MONTH, LAG(commandDateAffect) OVER (ORDER BY commandDateAffect, commandDateSign), r.commandDateAffect) % 12 MONTH),
r.commandDateAffect)
ELSE 0
END AS Days,
r.posNo,
r.positionExecutive,
r.positionType,
r.positionLevel,
r.orgRoot,
r.orgChild1,
r.orgChild2,
r.orgChild3,
r.orgChild4,
r.commandCode,
r.commandName,
r.commandNo,
r.commandYear,
r.remark
FROM resultWithDiff r
UNION ALL
SELECT
_date, NULL, NULL,
TIMESTAMPDIFF(DAY, MAX(commandDateAffect), _date) + 1,
TIMESTAMPDIFF(YEAR, MAX(commandDateAffect), _date),
TIMESTAMPDIFF(MONTH, MAX(commandDateAffect), _date) % 12,
DATEDIFF(_date,
DATE_ADD(
DATE_ADD(MAX(commandDateAffect),
INTERVAL TIMESTAMPDIFF(YEAR, MAX(commandDateAffect), _date) YEAR),
INTERVAL TIMESTAMPDIFF(MONTH, MAX(commandDateAffect), _date) % 12 MONTH)
),
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL
FROM resultWithDiff;
END$$
DELIMITER ;

View file

@ -90,12 +90,12 @@ SELECT
END AS Months,
CASE
WHEN LAG(r.commandDateAffect) OVER (ORDER BY r.commandDateAffect, r.commandDateSign) IS NOT NULL THEN
TIMESTAMPDIFF(DAY,
DATEDIFF(r.commandDateAffect,
DATE_ADD(
DATE_ADD(LAG(r.commandDateAffect) OVER (ORDER BY r.commandDateAffect, r.commandDateSign),
INTERVAL TIMESTAMPDIFF(YEAR, LAG(r.commandDateAffect) OVER (ORDER BY r.commandDateAffect, r.commandDateSign), r.commandDateAffect) YEAR),
INTERVAL TIMESTAMPDIFF(MONTH, LAG(r.commandDateAffect) OVER (ORDER BY r.commandDateAffect, r.commandDateSign), r.commandDateAffect) MONTH),
r.commandDateAffect) + 1
INTERVAL TIMESTAMPDIFF(MONTH, LAG(r.commandDateAffect) OVER (ORDER BY r.commandDateAffect, r.commandDateSign), r.commandDateAffect) % 12 MONTH)
)
ELSE 0
END AS Days,
r.posNo,
@ -121,12 +121,12 @@ SELECT
TIMESTAMPDIFF(DAY, MAX(commandDateAffect), _date) + 1,
TIMESTAMPDIFF(YEAR, MAX(commandDateAffect), _date),
TIMESTAMPDIFF(MONTH, MAX(commandDateAffect), _date) % 12,
TIMESTAMPDIFF(DAY,
DATEDIFF(_date,
DATE_ADD(
DATE_ADD(MAX(commandDateAffect),
INTERVAL TIMESTAMPDIFF(YEAR, MAX(commandDateAffect), _date) YEAR),
INTERVAL TIMESTAMPDIFF(MONTH, MAX(commandDateAffect), _date) MONTH),
_date) + 1,
INTERVAL TIMESTAMPDIFF(MONTH, MAX(commandDateAffect), _date) % 12 MONTH)
),
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL
FROM resultWithDiff;

View file

@ -94,12 +94,12 @@ SELECT
END AS Months,
CASE
WHEN LAG(r.commandDateAffect) OVER (ORDER BY r.commandDateAffect, r.commandDateSign) IS NOT NULL THEN
TIMESTAMPDIFF(DAY,
DATEDIFF(r.commandDateAffect,
DATE_ADD(
DATE_ADD(LAG(r.commandDateAffect) OVER (ORDER BY r.commandDateAffect, r.commandDateSign),
INTERVAL TIMESTAMPDIFF(YEAR, LAG(r.commandDateAffect) OVER (ORDER BY r.commandDateAffect, r.commandDateSign), r.commandDateAffect) YEAR),
INTERVAL TIMESTAMPDIFF(MONTH, LAG(r.commandDateAffect) OVER (ORDER BY r.commandDateAffect, r.commandDateSign), r.commandDateAffect) MONTH),
r.commandDateAffect) + 1
INTERVAL TIMESTAMPDIFF(MONTH, LAG(r.commandDateAffect) OVER (ORDER BY r.commandDateAffect, r.commandDateSign), r.commandDateAffect) % 12 MONTH)
)
ELSE 0
END AS Days,
r.posNo,
@ -123,12 +123,12 @@ SELECT
TIMESTAMPDIFF(DAY, MAX(commandDateAffect), _date) + 1,
TIMESTAMPDIFF(YEAR, MAX(commandDateAffect), _date),
TIMESTAMPDIFF(MONTH, MAX(commandDateAffect), _date) % 12,
TIMESTAMPDIFF(DAY,
DATEDIFF(_date,
DATE_ADD(
DATE_ADD(MAX(commandDateAffect),
INTERVAL TIMESTAMPDIFF(YEAR, MAX(commandDateAffect), _date) YEAR),
INTERVAL TIMESTAMPDIFF(MONTH, MAX(commandDateAffect), _date) MONTH),
_date) + 1,
INTERVAL TIMESTAMPDIFF(MONTH, MAX(commandDateAffect), _date) % 12 MONTH)
),
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL
FROM resultWithDiff;

View file

@ -96,8 +96,8 @@ SELECT
DATE_ADD(
DATE_ADD(LAG(r.commandDateAffect) OVER (ORDER BY r.commandDateAffect, r.commandDateSign),
INTERVAL TIMESTAMPDIFF(YEAR, LAG(r.commandDateAffect) OVER (ORDER BY r.commandDateAffect, r.commandDateSign), r.commandDateAffect) YEAR),
INTERVAL TIMESTAMPDIFF(MONTH, LAG(r.commandDateAffect) OVER (ORDER BY r.commandDateAffect, r.commandDateSign), r.commandDateAffect) MONTH),
r.commandDateAffect) + 1
INTERVAL TIMESTAMPDIFF(MONTH, LAG(r.commandDateAffect) OVER (ORDER BY r.commandDateAffect, r.commandDateSign), r.commandDateAffect) % 12 MONTH),
r.commandDateAffect)
ELSE 0
END AS Days,
r.posNo,
@ -124,12 +124,12 @@ SELECT
TIMESTAMPDIFF(DAY, MAX(commandDateAffect), _date) + 1,
TIMESTAMPDIFF(YEAR, MAX(commandDateAffect), _date),
TIMESTAMPDIFF(MONTH, MAX(commandDateAffect), _date) % 12,
TIMESTAMPDIFF(DAY,
DATEDIFF(_date,
DATE_ADD(
DATE_ADD(MAX(commandDateAffect),
INTERVAL TIMESTAMPDIFF(YEAR, MAX(commandDateAffect), _date) YEAR),
INTERVAL TIMESTAMPDIFF(MONTH, MAX(commandDateAffect), _date) MONTH),
_date) + 1,
INTERVAL TIMESTAMPDIFF(MONTH, MAX(commandDateAffect), _date) % 12 MONTH)
),
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL
FROM resultWithDiff;

File diff suppressed because it is too large Load diff

View file

@ -27,7 +27,7 @@ import { Profile } from "../entities/Profile";
import { In, LessThan, IsNull, MoreThan } from "typeorm";
import permission from "../interfaces/permission";
import { setLogDataDiff } from "../interfaces/utils";
import { calculateTenure } from "../utils/tenure";
import { normalizeDurationSumSimple } from "../utils/tenure";
import { Command } from "../entities/Command";
import { OrgRoot } from "../entities/OrgRoot";
import Extension from "../interfaces/extension";
@ -161,6 +161,14 @@ export class ProfileSalaryEmployeeController extends Controller {
_position.length > 1
? _position.slice(1).map((curr: any, index: number) => ({
days: curr.days_diff ? Number(curr.days_diff) : 0,
// Use stored procedure's calculated values (calendar arithmetic)
year:
curr.Years !== null && curr.Years !== undefined ? Math.floor(Number(curr.Years)) : 0,
month:
curr.Months !== null && curr.Months !== undefined
? Math.floor(Number(curr.Months))
: 0,
day: curr.Days !== null && curr.Days !== undefined ? Math.floor(Number(curr.Days)) : 0,
name: _position[index]?.positionName,
}))
: [];
@ -171,15 +179,25 @@ export class ProfileSalaryEmployeeController extends Controller {
if (existing) {
existing.days += curr.days;
existing.year += curr.year;
existing.month += curr.month;
existing.day += curr.day;
} else {
existing = { name: curr.name, days: curr.days };
existing = {
name: curr.name,
days: curr.days,
year: curr.year,
month: curr.month,
day: curr.day,
};
acc.push(existing);
}
const { year, month, day } = calculateTenure(existing.days);
existing.year = year;
existing.month = month;
existing.day = day;
// Normalize the summed values using calendar arithmetic
const normalized = normalizeDurationSumSimple(existing.year, existing.month, existing.day);
existing.year = normalized.years;
existing.month = normalized.months;
existing.day = normalized.days;
return acc;
},
@ -195,6 +213,14 @@ export class ProfileSalaryEmployeeController extends Controller {
_posLevel.length > 1
? _posLevel.slice(1).map((curr: any, index: number) => ({
days: curr.days_diff ? Number(curr.days_diff) : 0,
// Use stored procedure's calculated values (calendar arithmetic)
year:
curr.Years !== null && curr.Years !== undefined ? Math.floor(Number(curr.Years)) : 0,
month:
curr.Months !== null && curr.Months !== undefined
? Math.floor(Number(curr.Months))
: 0,
day: curr.Days !== null && curr.Days !== undefined ? Math.floor(Number(curr.Days)) : 0,
name:
!_posLevel[index]?.positionType && _posLevel[index]?.positionCee
? `ระดับ ${_posLevel[index]?.positionCee.trim()}`
@ -208,15 +234,25 @@ export class ProfileSalaryEmployeeController extends Controller {
if (existing) {
existing.days += curr.days;
existing.year += curr.year;
existing.month += curr.month;
existing.day += curr.day;
} else {
existing = { name: curr.name, days: curr.days };
existing = {
name: curr.name,
days: curr.days,
year: curr.year,
month: curr.month,
day: curr.day,
};
acc.push(existing);
}
const { year, month, day } = calculateTenure(existing.days);
existing.year = year;
existing.month = month;
existing.day = day;
// Normalize the summed values using calendar arithmetic
const normalized = normalizeDurationSumSimple(existing.year, existing.month, existing.day);
existing.year = normalized.years;
existing.month = normalized.months;
existing.day = normalized.days;
return acc;
},
@ -254,6 +290,14 @@ export class ProfileSalaryEmployeeController extends Controller {
_position.length > 1
? _position.slice(1).map((curr: any, index: number) => ({
days: curr.days_diff ? Number(curr.days_diff) : 0,
// Use stored procedure's calculated values (calendar arithmetic)
year:
curr.Years !== null && curr.Years !== undefined ? Math.floor(Number(curr.Years)) : 0,
month:
curr.Months !== null && curr.Months !== undefined
? Math.floor(Number(curr.Months))
: 0,
day: curr.Days !== null && curr.Days !== undefined ? Math.floor(Number(curr.Days)) : 0,
name: _position[index]?.positionName,
}))
: [];
@ -264,15 +308,25 @@ export class ProfileSalaryEmployeeController extends Controller {
if (existing) {
existing.days += curr.days;
existing.year += curr.year;
existing.month += curr.month;
existing.day += curr.day;
} else {
existing = { name: curr.name, days: curr.days };
existing = {
name: curr.name,
days: curr.days,
year: curr.year,
month: curr.month,
day: curr.day,
};
acc.push(existing);
}
const { year, month, day } = calculateTenure(existing.days);
existing.year = year;
existing.month = month;
existing.day = day;
// Normalize the summed values using calendar arithmetic
const normalized = normalizeDurationSumSimple(existing.year, existing.month, existing.day);
existing.year = normalized.years;
existing.month = normalized.months;
existing.day = normalized.days;
return acc;
},
@ -288,6 +342,14 @@ export class ProfileSalaryEmployeeController extends Controller {
_posLevel.length > 1
? _posLevel.slice(1).map((curr: any, index: number) => ({
days: curr.days_diff ? Number(curr.days_diff) : 0,
// Use stored procedure's calculated values (calendar arithmetic)
year:
curr.Years !== null && curr.Years !== undefined ? Math.floor(Number(curr.Years)) : 0,
month:
curr.Months !== null && curr.Months !== undefined
? Math.floor(Number(curr.Months))
: 0,
day: curr.Days !== null && curr.Days !== undefined ? Math.floor(Number(curr.Days)) : 0,
name:
!_posLevel[index]?.positionType && _posLevel[index]?.positionCee
? `ระดับ ${_posLevel[index]?.positionCee.trim()}`
@ -301,15 +363,25 @@ export class ProfileSalaryEmployeeController extends Controller {
if (existing) {
existing.days += curr.days;
existing.year += curr.year;
existing.month += curr.month;
existing.day += curr.day;
} else {
existing = { name: curr.name, days: curr.days };
existing = {
name: curr.name,
days: curr.days,
year: curr.year,
month: curr.month,
day: curr.day,
};
acc.push(existing);
}
const { year, month, day } = calculateTenure(existing.days);
existing.year = year;
existing.month = month;
existing.day = day;
// Normalize the summed values using calendar arithmetic
const normalized = normalizeDurationSumSimple(existing.year, existing.month, existing.day);
existing.year = normalized.years;
existing.month = normalized.months;
existing.day = normalized.days;
return acc;
},

View file

@ -74,7 +74,7 @@ export class TenureLevelEmployee extends EntityBase {
positionLevel: string;
}
export class CreateTenureLevelOfficer {
export class CreateTenureLevelEmployee {
profileEmployeeId: string;
positionCee: string | null;
days_diff: number | null;

View file

@ -1,18 +1,37 @@
/**
*
* Stored Procedure GetProfileSalaryPosition
* @param totalDays
* @returns { year, month, day }
* Normalize a duration sum using calendar arithmetic
* Converts excess days to months using average month length (30.4375 days)
* and excess months to years. Matches the logic used in stored procedures.
*
* @param years Total years from sum
* @param months Total months from sum
* @param days Total days from sum
* @returns Normalized { years, months, days }
*/
export function calculateTenure(totalDays: number) {
// Match stored procedure formula:
// days_diff / 365.2524 AS Years
// (days_diff / 30.4375) % 12 AS Months
// days_diff % 30.4375 AS Days
export function normalizeDurationSumSimple(
years: number,
months: number,
days: number,
): { years: number; months: number; days: number } {
const DAYS_PER_MONTH = 30.4375; // Average days per month in Gregorian calendar
const year = Math.floor(totalDays / 365.2524);
const month = Math.floor((totalDays / 30.4375) % 12);
const day = Math.floor(totalDays % 30.4375);
let totalMonths = months;
let totalDays = days;
return { year, month, day };
// Convert excess days to months
if (totalDays >= DAYS_PER_MONTH) {
const additionalMonths = Math.floor(totalDays / DAYS_PER_MONTH);
totalMonths += additionalMonths;
totalDays = totalDays - additionalMonths * DAYS_PER_MONTH;
}
// Convert excess months to years
let totalYears = years;
if (totalMonths >= 12) {
const additionalYears = Math.floor(totalMonths / 12);
totalYears += additionalYears;
totalMonths = totalMonths % 12;
}
return { years: totalYears, months: Math.floor(totalMonths), days: Math.floor(totalDays) };
}