Payroll / Timesheet — Case thường gặp
Tab Payroll không hiện trong Finance Settings
Kiểm tra STAFF_ROSTER cho BU hiện tại. Tab chỉ render khi BU bật Staff Roster; route /settings/finance/payroll bảo vệ cùng quy tắc.
Ví dụ thực tế: Admin không thấy tab Payroll sau Subsidy Settings. → BU chưa bật Staff Roster / thiếu
STAFF_ROSTER. → Tab không render đúng config, không sửa UI.
Lưu payroll settings sai value
Label map backend cố định: Rostered Hours = 0, Actual Hours = 1. Save giá trị khác 0/1 → reject/normalize; không lưu label thô.
Ví dụ thực tế: Admin chọn
Actual Hours. → Lưu value1, không phải label. →DefaultPaidHoursOptionId = 1; load lại vẫn hiệnActual Hours.
Export chỉ có CSV, không có xlsx/PDF
Export luôn là CSV duy nhất; hệ thống không cung cấp variant khác. Browser không được assemble file — mọi định dạng do backend + jsReport dựng.
Ví dụ thực tế: User tải export nhận CSV thay vì xlsx như cũ. → Hành vi mới của server-side render. → CSV tải về, tên file theo khoảng ngày, nội dung từ dataset backend.
Export reject vì id ngoài scope
Id dòng (ca hay leave-only) ngoài BU/org scope của caller → reject toàn bộ request, không thu hẹp kết quả. Thiếu Timesheet permission cũng reject, không đánh dấu dòng.
Ví dụ thực tế: Caller gửi id thuộc org khác BU. → Không trả file thiếu dòng. → Cả request fail, không dòng nào được đánh dấu exported.
Render thất bại nhưng không đánh dấu exported
Mark exported chỉ sau khi render thành công; Reporting Server lỗi → request fail, mọi dòng giữ nguyên. Un-export vẫn xóa cờ để dòng chọn lại được.
Ví dụ thực tế: jsReport render lỗi giữa chừng. → Không để dòng bị "exported" dù chưa có file. → Không dòng nào bị đánh dấu; retry sau khi server ổn.
Cột Leave Hours sai nguồn
Leave Hours = overlap giữa interval leave và interval ca — không phải total hours của absence. Leave Tracking Code = tracking code của leave, không phải code của ca.
Ví dụ thực tế: Ca
09:00–17:00, leave07:00–11:00(total 4h, codeAL). →Leave Hours = 2, codeAL. → Hiện4hayOT→ sai nguồn, không sửa bằng UI.
Nhiều leave trùng một ca
Export gộp vào cùng 1 shift row, các giá trị giữ thứ tự overlap start time; không nhân dòng ca.
Ví dụ thực tế: Ca overlap 2 leave (hours
1/2, codeAL/SICK). → Export 1 dòng cho ca. → CellLeave Hours=1và2; leaveTracking Code=ALvàSICK.
Dòng leave-only thiếu cột
Dòng nghỉ không ca dùng đúng bộ cột của dòng ca: Date/Name có giá trị, Org trống, cột giờ ca trống, Leave Hours/Tracking Code từ chính absence.
Ví dụ thực tế: Leave-only
09:00–13:00codeAL. → File cóLeave Hours = 4.00, codeAL,Orgvà cột giờ ca rỗng. → Dòng vẫn parse đủ field như dòng ca.
Approve dòng leave-only kéo theo duyệt leave
Trạng thái timesheet độc lập với lifecycle duyệt của leave: approve dòng trên Timesheet không đổi status/approver/thời gian của leave và ngược lại.
Ví dụ thực tế: Admin approve dòng leave-only draft. → Không được làm đơn nghỉ thành "approved". → Chỉ
EmployeeAbsence.TimesheetStatusIdđổi; lifecycle leave giữ nguyên.
Leave trùng ca không tạo dòng riêng
Leave overlap một ca rostered → không sinh leave-only row; nó nằm trong cột leave của shift row, không approve/export độc lập.
Ví dụ thực tế: Staff có ca và approved leave cùng ngày trùng giờ. → Không nhân đôi thành 2 dòng. → Chỉ hiện trong shift row's leave column; approve/export theo dòng ca.
Mode grouped gộp nhầm staff trùng tên
Gộp theo staff identity, không theo tên hiển thị; 2 staff cùng tên vẫn là 2 record riêng, giờ không cộng chung.
Ví dụ thực tế: Hai nhân viên đều tên "Hoa" cùng trong selection. → Không gộp giờ của 2 người. → CSV có 2 record riêng, mỗi record tổng giờ đúng từng người, sort theo tên.
Leave-only row bị khóa chọn khi đã exported
Dòng đã exported không chọn được; action un-export xóa cờ và cho chọn lại.
Ví dụ thực tế: Dòng leave-only đã export vào kỳ trước vẫn hiện trong grid. → Không export trùng lần nữa. → Selection control disabled; chọn Un-export để mở khóa và chọn lại.