Tài liệu hướng dẫn tích hợp các API quy trình phê duyệt thông qua Mobile Gateway Transaction Codes (MBGW TranCode) dành cho Website Client và ứng dụng di động.
PENDING_APPROVAL, PENDING_REVIEW, DELEGATED, PROCESSED).pagination.totalItems) của tab tương ứng, cho phép Client tải song song các tab độc lập một cách tối ưu.
Authorization: Bearer <token>).
PENDING_APPROVAL: Mọi step APPROVE gán trực tiếp cho actor, chưa
PROCESSED và chưa soft-delete.
PENDING_REVIEW: Mọi step REVIEW gán trực tiếp cho actor, chưa
PROCESSED và chưa soft-delete.
DELEGATED: Mọi step chưa PROCESSED, chưa soft-delete có mapping uỷ
quyền của actor đang ACTIVE, chưa revoke và chưa hết validTo.PROCESSED: Mỗi proposal xuất hiện đúng 1 lần khi có step PROCESSED
được actor hiện tại hoàn tất (approval_step.updated_by là email actor).canProcess: Ba filter công việc
(PENDING_APPROVAL, PENDING_REVIEW, DELEGATED) trả
theo từng step, do đó cùng 1 proposal có thể xuất hiện nhiều dòng khi actor có nhiều step
liên quan; canProcess chỉ bằng true khi
stepStatus = PROCESSING. Filter PROCESSED trả mỗi proposal 1 dòng
và luôn có canProcess = false.
| Field | Type | Description |
|---|---|---|
filter |
String Required | Tab cần lọc: PENDING_APPROVAL, PENDING_REVIEW,
DELEGATED, PROCESSED.
|
keyword |
String Optional | Từ khóa tìm kiếm không phân biệt hoa thường trên Số tờ trình (number) và
Trích yếu (subjectMatter). |
currentPage |
Integer Optional | Trang hiện tại (mặc định: 1, số bản ghi mỗi trang cố định
perPage = 10).
|
{
"filter": "PENDING_APPROVAL",
"keyword": "0045/2026",
"currentPage": 1
}
{
"success": true,
"code": "200",
"message": "Lấy danh sách phê duyệt/review thành công.",
"data": {
"items": [
{
"proposalId": 45,
"stepId": 120,
"number": "0045/2026/TT",
"subjectMatter": "Rà soát chi phí hạ tầng máy chủ",
"proposalStatus": "UNDER_APPROVAL",
"stepType": "APPROVE",
"stepStatus": "PROCESSING",
"stepResult": null,
"assigneeEmail": "checker@example.com",
"assigneeName": "Người duyệt",
"isDelegated": false,
"canProcess": true,
"updatedAt": "2026-08-24T08:30:00+07:00"
}
],
"pagination": {
"currentPage": 1,
"perPage": 10,
"totalItems": 1,
"totalPages": 1,
"hasNext": false,
"hasPrev": false
}
}
}
steps và
bước con childSteps), danh sách các bước đang chờ xử lý (currentSteps) và các
hành động mà người dùng hiện tại được phép bấm (currentUserAllowedActions).
Authorization: Bearer <token>).
createdBy) hoặc người lập tờ trình
(makerEmail).coRequesters).assignee) của ít nhất một bước active
trong quy trình.delegatedApprover) của ít nhất một
bước trong quy trình.403 Forbidden.
steps chỉ chứa các bước gốc theo đúng thứ tự prevStepId /
nextStepId. Mỗi bước gốc có mảng childSteps chứa các bước review
con.
currentSteps luôn là danh sách toàn bộ các bước PROCESSING. Nhiều
bước processing chỉ hợp lệ khi tất cả là REVIEW và có cùng
parentStepId.
PROCESSING cùng lúc trong cùng tờ trình, API trả về lỗi
409 Conflict (do payload perform-action không truyền
stepId).
| Field | Type | Description |
|---|---|---|
proposalId |
Integer Required | ID của tờ trình cần lấy thông tin quy trình. Phải là số nguyên dương
(>= 1). |
{
"proposalId": 123
}
{
"success": true,
"code": "200",
"message": "Lấy thông tin quy trình và hành động được phép thành công.",
"data": {
"proposalId": 123,
"proposalStatus": "UNDER_APPROVAL",
"workflowCompleted": false,
"requesterPermissions": [
{ "permission": "PROPOSAL.CREATE", "granted": true },
{ "permission": "PROPOSAL.APPROVE", "granted": true },
{ "permission": "PROPOSAL.REVIEW", "granted": false }
],
"steps": [
{
"stepId": 1,
"proposalId": 123,
"nextStepId": 2,
"prevStepId": null,
"parentStepId": null,
"stepType": "APPROVE",
"status": "PROCESSED",
"result": "APPROVED",
"note": "Đồng ý phê duyệt",
"assignee": {
"email": "user1@example.com",
"name": "Nguyễn Văn A",
"title": "Trưởng phòng",
"department": "Phòng IT",
"company": "Công ty ABC"
},
"delegatedApprover": null,
"isCurrent": false,
"isAssignedToRequester": false,
"createdAt": "2026-08-24T08:00:00+07:00",
"createdBy": "creator@example.com",
"updatedAt": "2026-08-24T09:00:00+07:00",
"updatedBy": "user1@example.com",
"childSteps": []
},
{
"stepId": 2,
"proposalId": 123,
"nextStepId": null,
"prevStepId": 1,
"parentStepId": null,
"stepType": "APPROVE",
"status": "PROCESSING",
"result": null,
"note": null,
"assignee": {
"email": "user2@example.com",
"name": "Trần Thị B",
"title": "Phó Giám đốc",
"department": "Khối Vận hành",
"company": "Công ty ABC"
},
"delegatedApprover": null,
"isCurrent": true,
"isAssignedToRequester": true,
"createdAt": "2026-08-24T08:00:00+07:00",
"createdBy": "creator@example.com",
"updatedAt": "2026-08-24T09:00:00+07:00",
"updatedBy": "user1@example.com",
"childSteps": []
}
],
"currentSteps": [
{
"stepId": 2,
"proposalId": 123,
"stepType": "APPROVE",
"status": "PROCESSING",
"result": null,
"note": null,
"assignee": {
"email": "user2@example.com",
"name": "Trần Thị B",
"title": "Phó Giám đốc",
"department": "Khối Vận hành",
"company": "Công ty ABC"
},
"delegatedApprover": null,
"isCurrent": true,
"isAssignedToRequester": true,
"requiredPermission": "PROPOSAL.APPROVE",
"currentUserAllowedActions": [
"approve",
"reject",
"need_rework",
"need_review",
"need_checker",
"delegate_approver"
],
"createdAt": "2026-08-24T08:00:00+07:00",
"createdBy": "creator@example.com",
"updatedAt": "2026-08-24T09:00:00+07:00",
"updatedBy": "user1@example.com"
}
]
}
}
PROPOSAL.REVIEW trên hệ thống
IAM để phục vụ chức năng yêu cầu thêm người thẩm định (action need_review) trên màn hình
phê duyệt.
Authorization: Bearer <token>).
403 Forbidden.
REVIEW đối với module phê duyệt tờ trình.
API này không yêu cầu tham số
payload trong body (truyền JSON rỗng {} hoặc body trống).
{}
{
"success": true,
"code": "200",
"message": "Lấy danh sách reviewer hợp lệ thành công.",
"data": {
"items": [
{
"email": "reviewer1@example.com",
"name": "Đặng Thị Thảo",
"title": "Chuyên viên Thẩm định Rủi ro",
"department": "Ban Thẩm định",
"company": "Công ty ABC"
},
{
"email": "reviewer2@example.com",
"name": "Nguyễn Văn Hùng",
"title": "Trưởng nhóm Pháp chế",
"department": "Phòng Pháp chế",
"company": "Công ty ABC"
}
]
}
}
approve, reject, need_rework, need_review,
need_checker, reviewed, documents_request,
delegate_approver.data.noteTmp) cho bất kỳ hành động nào.
proposalId: Bắt buộc là số nguyên dương.action: Bắt buộc là 1 trong 8 hành động được hỗ trợ: approve,
reject, need_rework, need_review,
need_checker, reviewed, documents_request,
delegate_approver.
PROCESSING và chưa có kết quả (result == null). User phải là
effective assignee (hoặc người nhận ủy quyền hợp lệ).
409 Conflict.data chứa noteTmp để nối
thêm ghi chú vào bước hiện tại.note theo định dạng: [YYYY-MM-DD HH:mm] - <noteTmp> (tự động
xuống dòng nếu note cũ đã có nội dung).
need_review và
need_checker:
noteTmp: Ghi chú nối thêm vào bước phê duyệt hiện tại.note: Ghi chú khởi tạo giao cho reviewer/checker mới được thêm vào.
UNDER_APPROVAL.
403.createdBy) KHÔNG ĐƯỢC PHÉP thực hiện phê duyệt
(approve) tờ trình của chính mình. Vi phạm sẽ bị trả về mã lỗi 01.
REVIEW mới ngay TRƯỚC bước
Approve hiện tại, chuyển step Review sang PROCESSING, khóa step Approve sang
LOCKED và đưa proposal về PENDING_REVIEW. Reviewer phải có quyền
PROPOSAL.REVIEW trong IAM.
APPROVE mới ngay TRƯỚC bước
hiện tại, chuyển step mới sang PROCESSING, step hiện tại sang
LOCKED; proposal giữ nguyên UNDER_APPROVAL. Checker phải có quyền
PROPOSAL.APPROVE trong IAM và KHÔNG ĐƯỢC là người tạo tờ
trình.
APPROVE/PROCESSING mới được ủy quyền. Người nhận ủy
quyền không được ủy quyền tiếp.perpro_delegation_recipient của
actor, có quyền PROPOSAL.APPROVE trong IAM và KHÔNG ĐƯỢC là người tạo
tờ trình.| Field | Type | Description |
|---|---|---|
proposalId |
Integer Required | ID của tờ trình. Phải là số nguyên dương. |
action |
String Required | Loại hành động: approve, reject, need_rework,
need_review, need_checker, reviewed,
documents_request, delegate_approver.
|
data |
Object Conditional | Đối tượng dữ liệu đính kèm. Bắt buộc truyền khi action là
need_review, need_checker hoặc delegate_approver.
Tùy chọn truyền khi muốn gửi noteTmp cho các action khác.
|
approve (Phê duyệt){
"proposalId": 123,
"action": "approve",
"data": {
"noteTmp": "Đồng ý phê duyệt phần hạn mức bổ sung theo biên bản họp."
}
}
reject (Từ chối){
"proposalId": 123,
"action": "reject",
"data": {
"noteTmp": "Không đồng ý phê duyệt do rủi ro tài chính cao."
}
}
need_rework (Yêu cầu làm lại){
"proposalId": 123,
"action": "need_rework",
"data": {
"noteTmp": "Đề nghị bổ sung thêm tài liệu đánh giá rủi ro."
}
}
need_review (Yêu cầu thêm người thẩm định){
"proposalId": 123,
"action": "need_review",
"data": {
"reviewers": [
{ "email": "reviewer@example.com" }
],
"note": "Nhờ anh xem giúp phần đánh giá rủi ro và các cam kết tài chính.",
"noteTmp": "Chuyển thẩm định bổ sung trước khi phê duyệt."
}
}
need_checker (Yêu cầu thêm người phê duyệt){
"proposalId": 123,
"action": "need_checker",
"data": {
"checkers": [
{ "email": "checker@example.com" }
],
"note": "Nhờ anh duyệt bổ sung phần hạn mức tín dụng vượt thẩm quyền.",
"noteTmp": "Trình cấp phê duyệt trung gian."
}
}
reviewed (Đã thẩm định xong){
"proposalId": 123,
"action": "reviewed",
"data": {
"noteTmp": "Đã xem xét và đánh giá hồ sơ đầy đủ."
}
}
documents_request (Yêu cầu bổ sung hồ sơ){
"proposalId": 123,
"action": "documents_request",
"data": {
"noteTmp": "Bổ sung thêm bản sao kê tài khoản ngân hàng."
}
}
delegate_approver (Ủy quyền bước phê duyệt){
"proposalId": 123,
"action": "delegate_approver",
"data": {
"delegatedApprover": {
"email": "delegate@example.com"
},
"validTo": "2026-12-31T23:59:59+07:00",
"noteTmp": "Đồng ý ủy quyền xử lý bước phê duyệt hiện tại."
}
}
{
"success": true,
"code": "200",
"message": "Phê duyệt bước hiện tại thành công.",
"data": {
"proposalId": 123,
"performedAction": "approve",
"proposalStatus": "UNDER_APPROVAL",
"workflowCompleted": false,
"requesterPermissions": [
{ "permission": "PROPOSAL.CREATE", "granted": true },
{ "permission": "PROPOSAL.APPROVE", "granted": true },
{ "permission": "PROPOSAL.REVIEW", "granted": false }
],
"steps": [ "...danh sách các steps sau khi cập nhật..." ],
"currentSteps": [ "...danh sách các bước đang chờ xử lý tiếp theo..." ]
}
}
POST /api/v1/private/approval-steps/create (Hỗ trợ định dạng response list phẳng cho các
component Portal phiên bản cũ).
createdBy) mới được phép chỉnh sửa danh sách bước phê duyệt.DRAFT hoặc
LOCKED.
steps: Bắt buộc là một mảng JSON danh sách, có ít nhất 1 bước
(count >= 1).stepType = APPROVE.createdBy) KHÔNG
ĐƯỢC gán chính mình vào bất kỳ bước nào có stepType = APPROVE. Vi
phạm trả lỗi 01 ngay lập tức.| Field | Type | Description |
|---|---|---|
proposalId |
Integer Required | ID của tờ trình. |
steps |
Array Required | Danh sách các bước phê duyệt mới theo đúng thứ tự linked-list. Phải có ít nhất 1 bước. |
{
"proposalId": 20,
"steps": [
{
"stepId": 113,
"stepType": "REVIEW",
"assignee": {
"email": "reviewer@example.com"
},
"note": "Thẩm định hồ sơ ban đầu"
},
{
"stepId": null,
"stepType": "APPROVE",
"assignee": {
"email": "approver@example.com"
},
"note": "Phê duyệt tờ trình"
}
]
}
{
"success": true,
"code": "200",
"message": "Lưu danh sách quy trình phê duyệt thành công.",
"data": {
"proposalId": 20,
"modifiedStepCount": 2,
"deletedStepCount": 0,
"proposalStatus": "DRAFT",
"workflowCompleted": false,
"requesterPermissions": [
{ "permission": "PROPOSAL.CREATE", "granted": true },
{ "permission": "PROPOSAL.APPROVE", "granted": true },
{ "permission": "PROPOSAL.REVIEW", "granted": false }
],
"steps": [ "...danh sách steps sau khi lưu..." ],
"currentSteps": []
}
}
submit), gửi lại tờ trình sau khi đã chỉnh sửa
(rework-submit), hoặc gửi thông báo đã bổ sung tài liệu/chứng từ
(additional_documents_submit).
DRAFT.steps trong request.DRAFT và chưa có kết quả. Bước cuối cùng bắt buộc
là APPROVE.PROCESSING, các bước sau thành LOCKED;
proposal chuyển thành UNDER_APPROVAL (hoặc PENDING_REVIEW nếu bước
đầu là Review).REVISION_REQUIRED.steps chứa danh sách root steps
mới/chỉnh sửa.PENDING_DOCUMENTS.PROCESSING với kết quả
REQUEST_DOCUMENTS.
null (tiếp tục PROCESSING), chuyển tờ
trình về PENDING_REVIEW.submit (Gửi duyệt lần đầu){
"proposalId": 123,
"action": "submit"
}
rework-submit (Gửi lại sau khi chỉnh sửa){
"proposalId": 123,
"action": "rework-submit",
"steps": [
{
"stepId": 1,
"stepType": "APPROVE",
"assignee": { "email": "approver1@example.com" },
"note": "Phê duyệt bước 1"
},
{
"stepId": null,
"stepType": "APPROVE",
"assignee": { "email": "approver2@example.com" },
"note": "Phê duyệt bước 2"
}
]
}
additional_documents_submit (Gửi bổ sung chứng từ){
"proposalId": 123,
"action": "additional_documents_submit"
}
Danh mục 6 mã giao dịch trên
Mobile Gateway ánh xạ tới API PerPro Upstream (cấu hình trong mg_transaction,
mg_integration và mg_transaction_component theo migration
Version20260825171306.php):
MBGW TranCode (TRANSACTIONS.code) |
PerPro Upstream Endpoint | Tên Transaction & Chức năng nghiệp vụ |
|---|---|---|
| PP_PROPOSAL_CHECK_LIST | /api/v1/private/proposal-review-inbox/list |
Lấy danh sách tờ trình phê duyệt/review PerPro |
| PP_PROPOSAL_APPROVALS_AVAILABLE_ACTIONS | /api/v1/private/proposal-approvals/available-actions |
Lấy quy trình và thao tác phê duyệt khả dụng PerPro |
| PP_PROPOSAL_APPROVALS_ELIGIBLE_REVIEWERS | /api/v1/private/proposal-approvals/eligible-reviewers |
Lấy danh sách reviewer hợp lệ PerPro |
| PP_PROPOSAL_APPROVALS_PERFORM_ACTION | /api/v1/private/proposal-approvals/perform-action |
Thực hiện thao tác phê duyệt/review PerPro |
| PP_PROPOSAL_APPROVALS_MODIFY_STEPS | /api/v1/private/proposal-approvals/modify-steps |
Chỉnh sửa các bước phê duyệt PerPro |
| PP_PROPOSAL_APPROVALS_TRIGGER_STEP_FLOW | /api/v1/private/proposal-approvals/trigger-step-flow |
Khởi chạy quy trình phê duyệt PerPro |
Mọi lỗi phát sinh sau khi
request vào Controller đều trả HTTP Status 200 kèm mã lỗi tương ứng trong response envelope
code để Client dễ dàng xử lý:
| Mã lỗi (Code) | Tên lỗi | Mô tả chi tiết & Trường hợp xảy ra |
|---|---|---|
01 |
Creator Cannot Approve | Người tạo tờ trình vi phạm quy tắc chống tự phê duyệt (cố tình thực hiện duyệt, gán mình làm người duyệt hoặc nhận ủy quyền). |
400 |
Bad Request | Payload JSON không hợp lệ, thiếu trường bắt buộc, sai định dạng email/validTo, sai kiểu dữ liệu, hoặc assignee không có quyền IAM tương ứng. |
401 |
Unauthorized | Phiên đăng nhập không hợp lệ, thiếu Bearer Token hoặc token đã hết hạn. |
403 |
Forbidden | Người dùng không có quyền truy cập tờ trình, không phải người tạo tờ trình khi modify/submit, không được giao xử lý bước hiện tại, hoặc cấu hình ủy quyền trong danh bạ đã bị xóa/thu hồi. |
404 |
Not Found | Không tìm thấy tờ trình (Proposal ID không tồn tại hoặc đã bị soft-delete). |
409 |
Conflict | Xung đột trạng thái: Bước phê duyệt đã bị người khác xử lý trước đó, trạng thái tờ trình không phù hợp với hành động, user được giao nhiều hơn 1 bước processing, hoặc vi phạm tính liên tục của linked-list. |
503 |
Service Unavailable | Dịch vụ IAM tạm thời không khả dụng khi xác thực quyền của assignee/reviewer/checker. |
99 |
System Error | Lỗi hệ thống không xác định trong quá trình xử lý. |
| Action | Step Type | Trạng thái trước | Hành vi & Kết quả sau khi thực hiện |
|---|---|---|---|
approve |
APPROVE |
UNDER_APPROVAL |
Append note nếu có noteTmp; Current step thành
PROCESSED/APPROVED. Mở bước kế tiếp thành PROCESSING, hoặc
chuyển proposal thành APPROVED nếu là bước cuối cùng (kết thúc workflow).
|
reject |
APPROVE |
UNDER_APPROVAL |
Append note nếu có noteTmp; Tất cả các bước chưa xử lý thành
PROCESSED/REJECTED; Proposal chuyển sang REJECTED (kết thúc
quy trình).
|
need_rework |
APPROVE |
UNDER_APPROVAL |
Append note nếu có noteTmp; Current step giữ PROCESSING với
kết quả result = REWORK; Proposal chuyển sang
REVISION_REQUIRED để người tạo sửa lại.
|
need_review |
APPROVE |
UNDER_APPROVAL |
Append note vào step hiện tại; Chèn 1 root step REVIEW/PROCESSING mới ngay
trước step Approve hiện tại; Step Approve chuyển sang LOCKED; Proposal
chuyển sang PENDING_REVIEW. |
need_checker |
APPROVE |
UNDER_APPROVAL |
Append note vào step hiện tại; Chèn 1 root step APPROVE/PROCESSING mới ngay
trước step Approve hiện tại; Step Approve chuyển sang LOCKED; Proposal giữ
nguyên UNDER_APPROVAL. |
delegate_approver |
APPROVE |
UNDER_APPROVAL |
Append note nếu có noteTmp; Tạo mapping ủy quyền có hiệu lực trong bảng
perpro_approval_step_delegated_approver; Giữ nguyên trạng thái step và
proposal.
|
reviewed |
REVIEW |
PENDING_REVIEW |
Append note nếu có noteTmp; Current step thành
PROCESSED/REVIEWED; Mở lại bước Approve tiếp theo thành
PROCESSING; Proposal chuyển về UNDER_APPROVAL.
|
documents_request |
REVIEW |
PENDING_REVIEW |
Append note nếu có noteTmp; Current step giữ PROCESSING với
kết quả result = REQUEST_DOCUMENTS; Proposal chuyển sang
PENDING_DOCUMENTS để người tạo nộp thêm hồ sơ.
|
submit |
— | DRAFT |
Kích hoạt bước đầu tiên thành PROCESSING, các bước sau LOCKED;
Proposal chuyển sang UNDER_APPROVAL (hoặc PENDING_REVIEW nếu
bước 1 là Review). |
rework-submit |
— | REVISION_REQUIRED |
Thu hồi các ủy quyền cũ, cập nhật lại danh sách steps, reset kết quả; Bước 1 chuyển sang
PROCESSING; Proposal chuyển sang UNDER_APPROVAL (hoặc
PENDING_REVIEW).
|
additional_documents_submit |
— | PENDING_DOCUMENTS |
Reset kết quả của bước Review đang request documents về null (tiếp tục
PROCESSING); Proposal chuyển về PENDING_REVIEW.
|