@chenchaolong/plugin-trade-compliance-workbench 1.0.76 → 1.0.77

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,7 +12,7 @@ import { finished } from 'node:stream/promises';
12
12
  import { createHash, randomUUID } from 'node:crypto';
13
13
  import { BankAccountSettings, CatalogReviewBlock, CompanySanctionMatch, CompanySettings, ControlledCatalogBatch, ControlledCatalogImportIssue, ControlledGoodsRecord, Customer, CustomerContract, CustomerContractAnalysisRun, CustomerContractClause, CustomerContractClauseAnalysis, DerivedSalesOrderManualData, GeneratedSalesFile, ImportTask, ManagedAsset, MonthlySafeExchangeRate, ProductComplianceMatch, ProfitRuleSettings, PurchaseOrder, PurchaseOrderLine, SanctionCatalogBatch, SanctionCatalogImportIssue, SanctionedCompanyAlias, SanctionedCompanyRecord, SettingsHistory, Supplier } from './entities/index.js';
14
14
  import { CATALOG_REVIEW_BATCH_LIMIT } from './constants.js';
15
- import { CatalogTypes, ClauseTypes, CustomerProfitRateStatuses, DomainError, DomainErrorCodes, RefundValidationMethods, SalesPaymentStatuses, SanctionHitStatuses, StalledCatalogImportDecisions } from './types.js';
15
+ import { CatalogTypes, ClauseTypes, CustomerProfitRateStatuses, DomainError, DomainErrorCodes, RefundValidationMethods, RiskLevels, SalesPaymentStatuses, SanctionHitStatuses, StalledCatalogImportDecisions } from './types.js';
16
16
  import { deriveSalesLine, assertReceivedAmount } from './domain/finance.js';
17
17
  import { parseCustomerContractNo, parsePurchaseContractNo } from './domain/contract-number.js';
18
18
  import { isProductNameMatch, normalizeExactName, normalizeForProductMatch, normalizeHsCode, normalizeSanctionSource } from './domain/normalization.js';
@@ -4220,16 +4220,49 @@ function normalizeCustomerContractDraftClause(value) {
4220
4220
  };
4221
4221
  }
4222
4222
  function normalizeCustomerContractDraftPayload(payload) {
4223
- if (!Array.isArray(payload.clauses))
4224
- return payload;
4225
- return {
4223
+ const normalized = {
4226
4224
  ...payload,
4227
- clauses: payload.clauses.map(clause => {
4225
+ clauses: Array.isArray(payload.clauses) ? payload.clauses.map(clause => {
4228
4226
  if (!clause || typeof clause !== 'object' || Array.isArray(clause))
4229
4227
  return clause;
4230
4228
  return normalizeCustomerContractDraftClause(clause);
4231
- })
4229
+ }) : payload.clauses
4232
4230
  };
4231
+ assertCustomerContractImportDraftPayload(normalized);
4232
+ return normalized;
4233
+ }
4234
+ function assertCustomerContractImportDraftPayload(payload) {
4235
+ const customer = payload.customer && typeof payload.customer === 'object' && !Array.isArray(payload.customer) ? payload.customer : {};
4236
+ const contract = payload.contract && typeof payload.contract === 'object' && !Array.isArray(payload.contract) ? payload.contract : {};
4237
+ const customerName = firstStringValue(customer, ['name', 'customerName']);
4238
+ if (!customerName)
4239
+ throw new DomainError(DomainErrorCodes.INVALID_INPUT, '客户名称为必填项');
4240
+ const contractNo = firstStringValue(contract, ['contractNo']);
4241
+ if (!contractNo)
4242
+ throw new DomainError(DomainErrorCodes.INVALID_INPUT, '客户合同编码为必填项');
4243
+ const clauses = Array.isArray(payload.clauses) ? payload.clauses : [];
4244
+ if (!clauses.length)
4245
+ throw new DomainError(DomainErrorCodes.INVALID_INPUT, '客户合同解析结果缺少可审核条款');
4246
+ const analyses = Array.isArray(payload.analyses) ? payload.analyses : [];
4247
+ let foundCount = 0;
4248
+ for (const clause of clauses) {
4249
+ if (!clause || typeof clause !== 'object' || Array.isArray(clause))
4250
+ throw new DomainError(DomainErrorCodes.INVALID_INPUT, '客户合同条款无效');
4251
+ const item = clause;
4252
+ if (!ClauseTypes.includes(item.clauseType))
4253
+ throw new DomainError(DomainErrorCodes.INVALID_INPUT, '客户合同条款类型无效');
4254
+ if (item.extractionStatus !== 'FOUND' && item.extractionStatus !== 'NOT_FOUND')
4255
+ throw new DomainError(DomainErrorCodes.INVALID_INPUT, '客户合同条款提取状态无效');
4256
+ if (item.extractionStatus !== 'FOUND')
4257
+ continue;
4258
+ foundCount += 1;
4259
+ const analysis = analyses.find(value => value && typeof value === 'object' && !Array.isArray(value) && value.clauseType === item.clauseType);
4260
+ if (!analysis || !RiskLevels.includes(analysis.riskLevel) || !firstStringValue(analysis, ['riskMessageZh']) || !firstStringValue(analysis, ['suggestionZh'])) {
4261
+ throw new DomainError(DomainErrorCodes.INVALID_INPUT, '已找到的关键条款缺少分析结果', { clauseType: item.clauseType });
4262
+ }
4263
+ }
4264
+ if (foundCount === 0)
4265
+ throw new DomainError(DomainErrorCodes.INVALID_INPUT, '客户合同解析结果缺少可审核条款');
4233
4266
  }
4234
4267
  function customerContractAnalysisInputChanged(currentByType, updates) {
4235
4268
  const seen = new Set();