feat(hrms): reconcile custom fields + add Employee/Exit Interview/Asset Assignment missing fields (TETRA-1354) #5

Merged
tant merged 1 commit from feat/TETRA-1354-reconcile-custom-fields into develop 2026-04-22 14:25:52 +07:00
Owner

Mục tiêu

Gom Frappe custom field fixtures từ Layer 2 (apps/api/src/modules/recruitment/migrations/*.json trong tetra repo) về vhrms làm single source of truth — xem TETRA-1354.

Đồng thời thêm các custom field mà NestJS API đang query nhưng chưa có trong vhrms (phát hiện trong TETRA-1352).

Thay đổi

Custom Fields mới

DocType Field Fieldtype Nguồn
Job Applicant previous_status, custom_rejection_reason Data Layer 2 JSON
Job Applicant talent_pool, talent_pool_level, talent_pool_notes, talent_pool_date, talent_pool_skills, talent_pool_suitable_positions Check/Select/Text/Date/Small Text Layer 2 JSON (Story 22.11)
Interview custom_interview_mode Select Layer 2 JSON
Interview custom_meeting_location, custom_video_call_link Data Layer 2 JSON
Interview custom_applicant_instructions Small Text Layer 2 JSON
Interview custom_interviewer_employee_ids Small Text (hidden) Layer 2 JSON
Exit Interview custom_interviewer_id Data Mới (TETRA-1354)
Exit Interview custom_location Data Mới
Exit Interview custom_notes, custom_suggestions Long Text Mới
Exit Interview custom_nps_score Int Mới
Exit Interview custom_skip_reason Small Text Mới
Asset Assignment custom_returned Check Mới (skip nếu DocType không tồn tại)
Asset Assignment custom_returned_date Date Mới
Asset Assignment custom_return_condition Select (good/fair/broken/missing) Mới
Asset Assignment custom_return_notes Long Text Mới
Employee custom_gross_salary Currency Mới
Employee custom_is_pregnant Check Mới
Employee custom_pregnancy_status Data Mới
Job Offer Term custom_notes Small Text Mới (child table)

Lý do chọn kiểu dữ liệu (field gây nhầm lẫn)

  • Employee.custom_pregnancy_statusData (không Select): separation.service.ts:242 chỉ truthy-check, test dùng giá trị 'pregnant' — Data đủ linh hoạt để thêm post_maternity, v.v. mà không phải edit lại custom_fields.
  • Employee.custom_gross_salaryCurrency: match với Job Offer.custom_gross_salary đã có trong vhrms (consistency + auto format VND).
  • Exit Interview.custom_interviewer_idData (không Link Employee/User): interviewer là Tetra eOffice user UUID, có thể chưa sync về HRMS — dùng Link sẽ báo LinkValidationError.
  • Asset Assignment.custom_return_conditionSelect với 4 giá trị cố định (good/fair/broken/missing): khớp với AssetReturnDto + default good trong separation.service.ts:1208.

Property Setters (TETRA-1354)

  • Job Applicant.status options → 9 giá trị: Open | Screening | Interview | Offer | Offer Accepted | Hired | Hold | Rejected | Cancelled (default Frappe chỉ có 4).
  • Interview.scheduled_on / from_time / to_time: set_only_once = 0 → cho phép HR reschedule.

Wiring hooks

  • setup/property_setters.py: thêm ensure_job_applicant_property_setters(), ensure_interview_property_setters(), entry point ensure_all_property_setters().
  • setup/__init__.py: gọi ensure_all_property_setters() trong cả after_installafter_migrate.

Side note — Asset Assignment

Asset Assignment không phải DocType mặc định của ERPNext/HRMS. NestJS (separation.service.ts:1160) có query doctype này nhưng bọc try/catch trả [] khi fail. Tạm thời ta skip provisioning field khi DocType chưa có, sẽ tự provision khi team enable module Asset.

Verification local

  • Copy WIP vhrms vào container tetra-eoffice-hrms-backend, chạy create_custom_fields(get_custom_fields(), ignore_validate=True) + ensure_all_property_setters() thành công.
  • MariaDB count trước/sau:
    • Employee: 123 → 126 (+3)
    • Exit Interview: 0 → 6 (+6)
    • Job Offer Term: 0 → 1 (+1)
    • Interview, Job Applicant, Job Offer, Job Opening, Job Requisition, Employee Separation: không đổi (đã có đủ)
  • 3 endpoint TETRA-1352 vẫn trả HTTP 200: GET /api/v1/recruitment/offers, GET /api/v1/hrms/separations?status=pending_cancellation, GET /api/v1/hrms/separations/compliance-alerts.

Tiếp theo

Sau khi PR này merge, tetra repo sẽ:

  1. rsync vendor/vhrms/ với vhrms develop HEAD.
  2. Delete Layer 2 files + npm scripts + thêm bench migrate vào configure.sh (PR riêng).

Refs: TETRA-1354, TETRA-1352

## Mục tiêu Gom Frappe custom field fixtures từ Layer 2 (`apps/api/src/modules/recruitment/migrations/*.json` trong tetra repo) về vhrms làm single source of truth — xem [TETRA-1354](https://tetravn.atlassian.net/browse/TETRA-1354). Đồng thời thêm các custom field mà NestJS API đang query nhưng chưa có trong vhrms (phát hiện trong TETRA-1352). ## Thay đổi ### Custom Fields mới | DocType | Field | Fieldtype | Nguồn | |---|---|---|---| | Job Applicant | `previous_status`, `custom_rejection_reason` | Data | Layer 2 JSON | | Job Applicant | `talent_pool`, `talent_pool_level`, `talent_pool_notes`, `talent_pool_date`, `talent_pool_skills`, `talent_pool_suitable_positions` | Check/Select/Text/Date/Small Text | Layer 2 JSON (Story 22.11) | | Interview | `custom_interview_mode` | Select | Layer 2 JSON | | Interview | `custom_meeting_location`, `custom_video_call_link` | Data | Layer 2 JSON | | Interview | `custom_applicant_instructions` | Small Text | Layer 2 JSON | | Interview | `custom_interviewer_employee_ids` | Small Text (hidden) | Layer 2 JSON | | Exit Interview | `custom_interviewer_id` | Data | Mới (TETRA-1354) | | Exit Interview | `custom_location` | Data | Mới | | Exit Interview | `custom_notes`, `custom_suggestions` | Long Text | Mới | | Exit Interview | `custom_nps_score` | Int | Mới | | Exit Interview | `custom_skip_reason` | Small Text | Mới | | Asset Assignment | `custom_returned` | Check | Mới (skip nếu DocType không tồn tại) | | Asset Assignment | `custom_returned_date` | Date | Mới | | Asset Assignment | `custom_return_condition` | Select (good/fair/broken/missing) | Mới | | Asset Assignment | `custom_return_notes` | Long Text | Mới | | Employee | `custom_gross_salary` | Currency | Mới | | Employee | `custom_is_pregnant` | Check | Mới | | Employee | `custom_pregnancy_status` | Data | Mới | | Job Offer Term | `custom_notes` | Small Text | Mới (child table) | ### Lý do chọn kiểu dữ liệu (field gây nhầm lẫn) - **`Employee.custom_pregnancy_status`** → `Data` (không `Select`): `separation.service.ts:242` chỉ truthy-check, test dùng giá trị `'pregnant'` — Data đủ linh hoạt để thêm `post_maternity`, v.v. mà không phải edit lại custom_fields. - **`Employee.custom_gross_salary`** → `Currency`: match với `Job Offer.custom_gross_salary` đã có trong vhrms (consistency + auto format VND). - **`Exit Interview.custom_interviewer_id`** → `Data` (không `Link Employee/User`): interviewer là Tetra eOffice user UUID, có thể chưa sync về HRMS — dùng Link sẽ báo LinkValidationError. - **`Asset Assignment.custom_return_condition`** → `Select` với 4 giá trị cố định (good/fair/broken/missing): khớp với `AssetReturnDto` + default `good` trong `separation.service.ts:1208`. ### Property Setters (TETRA-1354) - **Job Applicant.status** options → 9 giá trị: `Open | Screening | Interview | Offer | Offer Accepted | Hired | Hold | Rejected | Cancelled` (default Frappe chỉ có 4). - **Interview.scheduled_on / from_time / to_time**: `set_only_once = 0` → cho phép HR reschedule. ### Wiring hooks - `setup/property_setters.py`: thêm `ensure_job_applicant_property_setters()`, `ensure_interview_property_setters()`, entry point `ensure_all_property_setters()`. - `setup/__init__.py`: gọi `ensure_all_property_setters()` trong cả `after_install` và `after_migrate`. ## Side note — Asset Assignment `Asset Assignment` không phải DocType mặc định của ERPNext/HRMS. NestJS (`separation.service.ts:1160`) có query doctype này nhưng bọc try/catch trả `[]` khi fail. Tạm thời ta skip provisioning field khi DocType chưa có, sẽ tự provision khi team enable module Asset. ## Verification local - Copy WIP vhrms vào container `tetra-eoffice-hrms-backend`, chạy `create_custom_fields(get_custom_fields(), ignore_validate=True)` + `ensure_all_property_setters()` thành công. - MariaDB count trước/sau: - `Employee`: 123 → 126 (+3) - `Exit Interview`: 0 → 6 (+6) - `Job Offer Term`: 0 → 1 (+1) - `Interview`, `Job Applicant`, `Job Offer`, `Job Opening`, `Job Requisition`, `Employee Separation`: không đổi (đã có đủ) - 3 endpoint TETRA-1352 vẫn trả HTTP 200: `GET /api/v1/recruitment/offers`, `GET /api/v1/hrms/separations?status=pending_cancellation`, `GET /api/v1/hrms/separations/compliance-alerts`. ## Tiếp theo Sau khi PR này merge, tetra repo sẽ: 1. rsync `vendor/vhrms/` với vhrms develop HEAD. 2. Delete Layer 2 files + npm scripts + thêm `bench migrate` vào `configure.sh` (PR riêng). Refs: TETRA-1354, TETRA-1352
Gom Frappe custom field fixtures từ Layer 2 (apps/api/src/modules/
recruitment/migrations/*.json trong tetra repo) về vhrms làm single
source of truth. Đồng thời thêm các custom field mà NestJS API đang
query nhưng chưa có trong vhrms (phát hiện trong TETRA-1352).

Job Applicant (+8 fields, previously in Layer 2):
- previous_status, custom_rejection_reason
- talent_pool, talent_pool_level, talent_pool_notes, talent_pool_date,
  talent_pool_skills, talent_pool_suitable_positions (Story 22.11)

Interview (+5 fields, previously in Layer 2):
- custom_interview_mode, custom_meeting_location, custom_video_call_link,
  custom_applicant_instructions, custom_interviewer_employee_ids

Exit Interview (+6 fields, newly discovered):
- custom_interviewer_id (Data — lưu Tetra user UUID, không phải Employee
  link vì interviewer có thể là user eOffice không có Employee doc)
- custom_location (Data), custom_notes (Long Text),
- custom_nps_score (Int), custom_suggestions (Long Text),
- custom_skip_reason (Small Text)

Asset Assignment (+4 fields, newly discovered — DocType chưa có trên
site mặc định, filter ở cuối get_custom_fields để skip an toàn):
- custom_returned (Check), custom_returned_date (Date),
- custom_return_condition (Select: good/fair/broken/missing),
- custom_return_notes (Long Text)

Employee (+3 fields, newly discovered):
- custom_gross_salary (Currency) — fallback khi không có Salary Slip
  (separation.service.ts tính trợ cấp Điều 46 BLLĐ 2019)
- custom_is_pregnant (Check), custom_pregnancy_status (Data) — bảo
  vệ lao động nữ Điều 137/138 BLLĐ 2019 (cấm OT, cấm đơn phương
  chấm dứt HĐLĐ)

Job Offer Term (+1 child table field):
- custom_notes (Small Text) — offers.service.ts ghi/đọc per-term notes

Property Setters (TETRA-1354, consolidated từ Layer 2):
- Job Applicant.status options → 9-state pipeline (Open, Screening,
  Interview, Offer, Offer Accepted, Hired, Hold, Rejected, Cancelled)
- Interview.scheduled_on / from_time / to_time: set_only_once = 0
  (cho phép HR reschedule interview)

Wiring:
- property_setters.py: thêm ensure_job_applicant_property_setters(),
  ensure_interview_property_setters(), và entry point
  ensure_all_property_setters() — gọi trong after_install và
  after_migrate của setup/__init__.py.

Refs: TETRA-1354
Refs: TETRA-1352

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tant merged commit d3bcec523b into develop 2026-04-22 14:25:52 +07:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
tant/vhrms!5
No description provided.