Add customer contract clearance console

This commit is contained in:
xz
2026-09-01 14:38:42 +08:00
parent 1d4154dd20
commit 5849705d1e
19 changed files with 2431 additions and 25 deletions
+42
View File
@@ -19,6 +19,8 @@ const deliveryDraftVersion = `portal-draft-${runId}`;
const batchId = `smoke-portal-batch-${runId}`;
const deliveryLabel = `smoke-portal-delivery-${runId}`;
const draftDeliveryLabel = `smoke-portal-draft-${runId}`;
const customerId = `cust-portal-${runId}`;
const contractId = `contract-portal-${runId}`;
const auditTargetIds = new Set();
const accessLinkIds = [];
const releaseIds = [];
@@ -89,6 +91,40 @@ const crossOrganizationHeaders = {
const producerUser = dbGet("SELECT id FROM users WHERE email = ?", ["producer@local.test"]);
assert.ok(producerUser?.id, "producer user must exist");
function seedContractClearance() {
const timestamp = new Date().toISOString();
dbRun(
"INSERT OR IGNORE INTO customers(id, organization_id, name, legal_name, code, customer_type, status, industry, region, billing_email, tax_id, notes, tags_json, metadata_json, created_by, created_at, updated_at) VALUES (?, ?, ?, ?, ?, 'distributor', 'active', 'AI 短剧发行', 'CN', 'portal@example.local', '', 'delivery portal smoke customer', '[\"smoke\",\"portal\"]', '{}', ?, ?, ?)",
[customerId, organizationId, `门户烟测客户 ${runId}`, `门户烟测客户 ${runId} 有限公司`, `PORTAL-${runId}`, producerUser.id, timestamp, timestamp]
);
dbRun(
"INSERT OR IGNORE INTO production_contracts(id, organization_id, customer_id, contract_number, title, contract_type, status, approval_status, effective_at, expires_at, signed_at, currency, amount, license_scope_json, rights_json, delivery_terms_json, evidence_json, risk_json, approval_note, created_by, updated_by, created_at, updated_at) VALUES (?, ?, ?, ?, ?, 'production_license', 'active', 'approved', ?, ?, ?, 'CNY', 0, ?, ?, ?, ?, ?, 'smoke portal contract', ?, ?, ?, ?)",
[
contractId,
organizationId,
customerId,
`PORTAL-CTR-${runId}`,
`门户烟测授权 ${runId}`,
new Date(Date.now() - 86400000).toISOString(),
new Date(Date.now() + 365 * 86400000).toISOString(),
timestamp,
JSON.stringify({ channels: ["local-file", "private-delivery-portal"], territories: ["CN"], deliverables: ["vertical-video", "delivery-manifest"], platforms: ["private-preview", "internal-review"], exclusive: false, commercialUse: true, language: ["zh-CN"] }),
JSON.stringify({ originalStory: true, derivativeProduction: true, aiGeneratedAssetsAllowed: true, voiceCloneAllowed: false, fixedVoiceRequired: true, singleFramePolicyRequired: true }),
JSON.stringify({ customerPortalAllowed: true, requireClearanceCertificate: true, maxAccessDays: 7 }),
JSON.stringify({ contractRef: `smoke://portal-contract/${runId}`, rightsEvidenceRef: `smoke://portal-rights/${runId}`, signedCopyPath: `storage/contracts/smoke-portal/${runId}.json` }),
JSON.stringify({ paidCloudAllowed: false, publicModelAllowed: false, rightsReview: "passed" }),
producerUser.id,
producerUser.id,
timestamp,
timestamp
]
);
dbRun(
"INSERT OR IGNORE INTO contract_project_bindings(id, organization_id, workspace_id, project_id, contract_id, customer_id, usage_mode, status, notes, created_by, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, 'primary-license', 'active', 'delivery portal smoke binding', ?, ?, ?)",
[`contract-binding-portal-${runId}`, organizationId, workspaceId, projectId, contractId, customerId, producerUser.id, timestamp, timestamp]
);
}
let channelId = "";
let publishedReleaseId = "";
let primaryToken = "";
@@ -144,6 +180,7 @@ try {
dbRun("UPDATE deliveries SET status = 'approved', active_batch_id = ?, approved_by = ?, approved_at = ?, updated_at = ? WHERE id = ?", [batchId, producerUser.id, timestamp, timestamp, delivery.delivery.id]);
expectOk(await request("/api/production/reviews", { headers: producerHeaders }), "ensure portal QA reviews");
dbRun("UPDATE reviews SET status = 'approved', score = 100, decision_by = ?, decision_at = ?, evidence_json = ?, updated_at = ? WHERE project_id = ?", [producerUser.id, timestamp, JSON.stringify({ source: "smoke-delivery-portal", checkedAt: timestamp }), timestamp, projectId]);
seedContractClearance();
seeded = true;
const release = expectStatus(await request(`/api/production/deliveries/${encodeURIComponent(delivery.delivery.id)}/releases`, {
@@ -260,6 +297,11 @@ try {
assert.ok(Number(eventCount?.count || 0) >= 6, "portal view/download/rejection activity must be audited");
console.log(`delivery portal smoke passed: ${publishedReleaseId} / ${accessLinkIds.length} links`);
} finally {
dbRun("DELETE FROM contract_license_events WHERE contract_id = ? OR customer_id = ? OR project_id = ?", [contractId, customerId, projectId]);
dbRun("DELETE FROM contract_project_bindings WHERE contract_id = ? OR project_id = ?", [contractId, projectId]);
dbRun("DELETE FROM production_contracts WHERE id = ?", [contractId]);
dbRun("DELETE FROM customer_contacts WHERE customer_id = ?", [customerId]);
dbRun("DELETE FROM customers WHERE id = ?", [customerId]);
for (const targetId of auditTargetIds) dbRun("DELETE FROM audit_logs WHERE target_id = ?", [targetId]);
for (const linkId of accessLinkIds) dbRun("DELETE FROM delivery_access_events WHERE link_id = ?", [linkId]);
for (const linkId of accessLinkIds) dbRun("DELETE FROM delivery_access_links WHERE id = ?", [linkId]);