fix: 补齐候选诊断环境与证据保护(09-06-release-gate-integrity)
这个提交包含在:
@@ -263,6 +263,47 @@ create_and_bind_invoice() {
|
||||
echo "$invoice_id"
|
||||
}
|
||||
|
||||
set_non_positive_item_fixture() {
|
||||
DATABASE_URL="$DATABASE_URL" node - "$1" <<'NODE'
|
||||
const reimbursementId = process.argv[2];
|
||||
const { createPrismaClient } = require('./src/prismaClient');
|
||||
|
||||
(async () => {
|
||||
const { prisma, pool } = createPrismaClient();
|
||||
await prisma.$connect();
|
||||
try {
|
||||
const itemId = await prisma.$transaction(async (tx) => {
|
||||
const items = await tx.reimbursementItem.findMany({
|
||||
where: { reimbursement_id: reimbursementId },
|
||||
select: { id: true },
|
||||
});
|
||||
if (items.length !== 1) throw new Error('non_positive_item_fixture_requires_one_item');
|
||||
const item = await tx.reimbursementItem.update({
|
||||
where: { id: items[0].id },
|
||||
data: { amount: '-1.00' },
|
||||
select: { id: true, amount: true },
|
||||
});
|
||||
const aggregate = await tx.reimbursementItem.aggregate({
|
||||
where: { reimbursement_id: reimbursementId },
|
||||
_sum: { amount: true },
|
||||
});
|
||||
if (item.amount.toFixed(2) !== '-1.00' || aggregate._sum.amount?.toFixed(2) !== '-1.00') {
|
||||
throw new Error('non_positive_item_fixture_not_persisted');
|
||||
}
|
||||
return item.id;
|
||||
});
|
||||
process.stdout.write(itemId);
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
await pool.end();
|
||||
}
|
||||
})().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
NODE
|
||||
}
|
||||
|
||||
set_reimbursement_total_amount() {
|
||||
local reimbursement_id="$1"
|
||||
local total_amount="$2"
|
||||
@@ -988,16 +1029,21 @@ withdraw_reimbursement "$EMPLOYEE_TOKEN" "$RID_PERM" "cleanup after PERM_002" "$
|
||||
assert_instance_status "$INSTANCE_PERM" "cancelled" "PERM_002 cleanup"
|
||||
assert_reimbursement_status_db "$RID_PERM" "draft" "PERM_002 cleanup"
|
||||
|
||||
echo "[6/23] negative_not_allowed: submit blocked when total_amount < 0"
|
||||
RID_NEGATIVE="$(create_reimbursement "$EMPLOYEE_TOKEN" "$TMP_DIR/negative-create.json")"
|
||||
create_and_bind_invoice "$EMPLOYEE_TOKEN" "$RID_NEGATIVE" "negative" >/dev/null
|
||||
set_reimbursement_total_amount "$RID_NEGATIVE" "-1.00"
|
||||
echo "[6/23] items_positive_amount_required: submit blocked for a negative item"
|
||||
RID_NON_POSITIVE_ITEM="$(create_reimbursement "$EMPLOYEE_TOKEN" "$TMP_DIR/non-positive-item-create.json")"
|
||||
create_and_bind_invoice "$EMPLOYEE_TOKEN" "$RID_NON_POSITIVE_ITEM" "non-positive-item" >/dev/null
|
||||
NON_POSITIVE_ITEM_ID="$(set_non_positive_item_fixture "$RID_NON_POSITIVE_ITEM")"
|
||||
|
||||
negative_submit_status="$(api_json_auth POST "$BASE_URL/api/reimbursements/$RID_NEGATIVE/submit" "$EMPLOYEE_TOKEN" "$TMP_DIR/negative-submit.json" '{}')"
|
||||
assert_status "$negative_submit_status" "400" "negative_not_allowed submit" "$TMP_DIR/negative-submit.json"
|
||||
assert_error_code "$TMP_DIR/negative-submit.json" "VALID_001" "negative_not_allowed submit"
|
||||
assert_error_detail "$TMP_DIR/negative-submit.json" '.error.details.total_amount' "negative_not_allowed" "negative_not_allowed submit"
|
||||
assert_no_workflow_instance "$RID_NEGATIVE" "negative_not_allowed"
|
||||
non_positive_submit_status="$(api_json_auth POST "$BASE_URL/api/reimbursements/$RID_NON_POSITIVE_ITEM/submit" "$EMPLOYEE_TOKEN" "$TMP_DIR/non-positive-item-submit.json" '{}')"
|
||||
assert_status "$non_positive_submit_status" "400" "items_positive_amount_required submit" "$TMP_DIR/non-positive-item-submit.json"
|
||||
assert_error_code "$TMP_DIR/non-positive-item-submit.json" "VALID_001" "items_positive_amount_required submit"
|
||||
assert_error_detail "$TMP_DIR/non-positive-item-submit.json" '.error.details.items' "positive_amount_required" "items_positive_amount_required submit"
|
||||
assert_error_detail "$TMP_DIR/non-positive-item-submit.json" '.error.details.reasonCode' "reimbursement.items_positive_amount_required" "items_positive_amount_required submit"
|
||||
if ! jq -e --arg item_id "$NON_POSITIVE_ITEM_ID" '.error.details.itemIds == [$item_id]' "$TMP_DIR/non-positive-item-submit.json" >/dev/null; then
|
||||
echo "[ERROR] items_positive_amount_required must identify exactly the injected item" >&2
|
||||
exit 1
|
||||
fi
|
||||
assert_no_workflow_instance "$RID_NON_POSITIVE_ITEM" "items_positive_amount_required"
|
||||
|
||||
echo "[7/23] Prepare manager-missing context"
|
||||
set_employee_direct_manager "$EMPLOYEE_ID" "__NULL__"
|
||||
@@ -1338,7 +1384,7 @@ echo "- reject reimbursementId: $RID_REJECT"
|
||||
echo "- return reimbursementId: $RID_RETURN"
|
||||
echo "- withdraw reimbursementId: $RID_WITHDRAW"
|
||||
echo "- perm reimbursementId: $RID_PERM"
|
||||
echo "- negative reimbursementId: $RID_NEGATIVE"
|
||||
echo "- non-positive item reimbursementId: $RID_NON_POSITIVE_ITEM"
|
||||
echo "- manager-skip reimbursementId: $RID_SKIP"
|
||||
echo "- no-actionable reimbursementId: $RID_NO_ACTIONABLE"
|
||||
echo "- transfer-ok reimbursementId: $RID_TRANSFER_OK"
|
||||
|
||||
在新工单中引用
屏蔽一个用户