Dữ liệu

Bảng lương

Số tổng phiếu lương đã chốt, đánh dấu đã chi.

Dùng token kết nối, dưới /v1/work. Dành cho tổ chức ghi sổ lương ở một hệ thống khác (phần mềm kế toán, ERP): mỗi phiếu lương đã chốt trong CTAS Work được mang sang dưới dạng số tổng, và hệ thống đó báo lại khi đã chi.

Ứng dụng làm theo luật của bảng lương CTAS Work, không có luật riêng. Chốt, duyệt, mở lại vẫn do người trong CTAS Work làm. Ứng dụng chỉ đọc, và chỉ đánh dấu đã chi cho phiếu đã được duyệt.

Bốn bước của một phiếu

stateNghĩa
closedđã chốt và gửi cho nhân viên; số đã cố định
verifiedquản lý đã duyệt
paidđã chi — xong hẳn, không mở lại được
reopenedđang mở lại để tính lại; totals là null, chờ chốt lại

Nhân viên xác nhận phiếu không chặn bước nào nên chỉ nằm ở confirmed_at. Phiếu đã duyệt có thể bị bỏ duyệt (thêm khoản cộng/trừ) hoặc mở lại cho đến khi đã chi.

Đọc phiếu

GET /payslips?period=2026-09&state=&member=&limit=&cursor= — quyền payroll:read. Mặc định trả mọi phiếu đã chốt của kỳ. GET /payslips/{id} — một phiếu, kể cả phiếu đang mở lại.

{ "id": "psl_…", "member_id": "mem_…", "department_id": "dep_…", "period": "2026-09",
  "pay_date": "2026-10-05", "state": "verified",
  "closed_at": "…", "confirmed_at": "…", "verified_at": "…", "paid_at": null, "paid_via": null,
  "currency": "VND",
  "totals": { "income": 9800000, "deductions": 50000, "insurance": 840000, "tax": 0,
              "advances": 1000000, "net": 7910000, "company_insurance": 1720000 } }
  • Không có từng dòng của phiếu. Mỗi dòng rơi vào đúng một nhóm nên luôn có income − deductions − insurance − tax − advances = net, khớp tới đồng.
  • tax là thuế TNCN đã khấu trừ, bằng 0 khi tổ chức chưa bật thuế. advances là tạm ứng thu hồi trong kỳ.
  • company_insurance là phần bảo hiểm công ty đóng, không nằm trong thực lĩnh.

Lương theo nơi làm

Mỗi phiếu kèm allocation: thu nhập, khoản trừ và BH công ty đóng theo phòng ban nơi tiền được làm ra — để hạch toán chi phí lương đúng cửa hàng.

"allocation": { "basis": "closed", "home_department_id": "dep_A",
  "departments": [
    { "department_id": "dep_A", "department_name": "Thăng Long", "home": true,  "income": 6400000, "deductions": 50000, "company_insurance": 840000,
      "days": null, "hours": null, "shifts": null },
    { "department_id": "dep_B", "department_name": "Bàn Cờ", "home": false, "income": 1600000, "deductions": 0, "company_insurance": 0,
      "days": 4, "hours": 32, "shifts": 4 } ] }
  • Ca được xếp ở phòng khác (nơi làm việc = phòng ban khác) tính về phòng đó: lương công/giờ của ngày đó, tăng ca, ca có giá riêng, khoản ghi trên ca.
  • Ở lại phòng của người: phụ cấp, thưởng, phạt theo kỳ, khoản thêm tay, ngày nghỉ có lương, lễ, công tác, BH công ty đóng. Chấm công ở nơi khác mà không xếp ca cũng tính về phòng của người.
  • Phần BH, thuế, tạm ứng của người lao động không chia (không phải chi phí của nơi nào).
  • Cộng các phòng luôn ra đúng totals.income, totals.deductions, totals.company_insurance.
  • basis = closed: chia lúc chốt, đóng băng cùng phiếu. recomputed: phiếu chốt trước 12/10/2026, tính lại sau theo lịch hiện có. allocation = null: chưa tính được (phiếu cũ chưa tính lại, hoặc đang mở lại).

Đánh dấu đã chi

POST /payslips/{id}/pay — quyền payroll:write. Chỉ cho phiếu đã duyệt:

LỗiKhi nào
409 PAYSLIP_NOT_VERIFIEDphiếu chưa được duyệt
409 PAYSLIP_REOPENEDphiếu đang mở lại

Gọi lại phiếu đã chi trả về phiếu như hiện tại (an toàn khi thử lại). Phiếu ghi paid_via là tên ứng dụng của bạn, nhân viên nhận thông báo "đã được chi" như khi chi trong CTAS Work. Kết nối của bạn không nhận payslip.paid cho chính lần đánh dấu này.

Sự kiện

payslip.closed, payslip.reopened, payslip.verified, payslip.unverified, payslip.paid, payslip.deleted.

{ "payslip_id": "psl_…", "member_id": "mem_…", "period": "2026-09", "state": "verified" }

Webhook không kèm số tiền: nhận sự kiện rồi đọc lại phiếu bằng GET /payslips/{id}. Cách đồng bộ gợi ý: nhận phiếu khi verified, gỡ khi unverified/reopened/deleted, ghi đã chi khi paid; định kỳ quét GET /payslips?period= để bù sự kiện lỡ.