304 lines
11 KiB
JavaScript
304 lines
11 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ADDRESS_COVERAGE_EVIDENCE_SCHEMA_VERSION = void 0;
|
|
exports.isHeuristicCandidatesIntent = isHeuristicCandidatesIntent;
|
|
exports.isConfirmedBalanceIntent = isConfirmedBalanceIntent;
|
|
exports.resolveAddressAsOfDateBasis = resolveAddressAsOfDateBasis;
|
|
exports.resolveAddressRequestedResultMode = resolveAddressRequestedResultMode;
|
|
exports.resolveAddressCoverageEvidence = resolveAddressCoverageEvidence;
|
|
exports.attachAddressCoverageEvidence = attachAddressCoverageEvidence;
|
|
exports.toAddressCoverageEvidenceContract = toAddressCoverageEvidenceContract;
|
|
exports.ADDRESS_COVERAGE_EVIDENCE_SCHEMA_VERSION = "address_coverage_evidence_v1";
|
|
function toRecordObject(value) {
|
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
return null;
|
|
}
|
|
return value;
|
|
}
|
|
function toNonEmptyString(value) {
|
|
if (value === null || value === undefined) {
|
|
return null;
|
|
}
|
|
const text = String(value).trim();
|
|
return text.length > 0 ? text : null;
|
|
}
|
|
function normalizeIsoDateHint(value) {
|
|
if (typeof value !== "string") {
|
|
return null;
|
|
}
|
|
const trimmed = value.trim();
|
|
if (!trimmed) {
|
|
return null;
|
|
}
|
|
const match = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})(?:T.*)?$/);
|
|
if (!match) {
|
|
return null;
|
|
}
|
|
const year = Number(match[1]);
|
|
const month = Number(match[2]);
|
|
const day = Number(match[3]);
|
|
if (!Number.isFinite(year) || !Number.isFinite(month) || !Number.isFinite(day)) {
|
|
return null;
|
|
}
|
|
const candidate = new Date(Date.UTC(year, month - 1, day));
|
|
if (candidate.getUTCFullYear() !== year ||
|
|
candidate.getUTCMonth() + 1 !== month ||
|
|
candidate.getUTCDate() !== day) {
|
|
return null;
|
|
}
|
|
return `${match[1]}-${match[2]}-${match[3]}`;
|
|
}
|
|
function normalizeReasonCode(value) {
|
|
const normalized = value
|
|
.trim()
|
|
.replace(/[^\p{L}\p{N}_.:-]+/gu, "_")
|
|
.replace(/^_+|_+$/g, "")
|
|
.toLowerCase();
|
|
return normalized.length > 0 ? normalized.slice(0, 120) : null;
|
|
}
|
|
function pushReason(target, value) {
|
|
const text = toNonEmptyString(value);
|
|
if (!text) {
|
|
return;
|
|
}
|
|
const normalized = normalizeReasonCode(text);
|
|
if (normalized && !target.includes(normalized)) {
|
|
target.push(normalized);
|
|
}
|
|
}
|
|
function isResultMode(value) {
|
|
return value === "heuristic_candidates" || value === "confirmed_balance";
|
|
}
|
|
function isEvidenceStrength(value) {
|
|
return value === "weak" || value === "medium" || value === "strong";
|
|
}
|
|
function isCoverageStatus(value) {
|
|
return value === "full" || value === "partial" || value === "blocked";
|
|
}
|
|
function isAsOfDateBasis(value) {
|
|
return (value === "period_end" ||
|
|
value === "explicit_as_of_date" ||
|
|
value === "period_range" ||
|
|
value === "implicit_current_snapshot");
|
|
}
|
|
function isEvidenceBasis(value) {
|
|
return (value === "matched_rows" ||
|
|
value === "exact_negative" ||
|
|
value === "limited_response" ||
|
|
value === "heuristic_candidates" ||
|
|
value === "unknown");
|
|
}
|
|
function isHeuristicCandidatesIntent(intent) {
|
|
return (intent === "list_receivables_counterparties" ||
|
|
intent === "list_payables_counterparties" ||
|
|
intent === "list_open_contracts" ||
|
|
intent === "open_items_by_counterparty_or_contract");
|
|
}
|
|
function isConfirmedBalanceIntent(intent) {
|
|
return (intent === "account_balance_snapshot" ||
|
|
intent === "documents_forming_balance" ||
|
|
intent === "inventory_on_hand_as_of_date" ||
|
|
intent === "inventory_purchase_provenance_for_item" ||
|
|
intent === "inventory_purchase_documents_for_item" ||
|
|
intent === "inventory_sale_trace_for_item" ||
|
|
intent === "inventory_purchase_to_sale_chain" ||
|
|
intent === "open_contracts_confirmed_as_of_date" ||
|
|
intent === "payables_confirmed_as_of_date" ||
|
|
intent === "receivables_confirmed_as_of_date" ||
|
|
intent === "vat_payable_confirmed_as_of_date" ||
|
|
intent === "vat_liability_confirmed_for_tax_period");
|
|
}
|
|
function resolveAddressAsOfDateBasis(filters, semanticFrame) {
|
|
if (semanticFrame?.date_scope_kind === "implicit_current" &&
|
|
semanticFrame.date_basis_hint === "implicit_current_snapshot") {
|
|
return "implicit_current_snapshot";
|
|
}
|
|
const asOfDate = normalizeIsoDateHint(filters.as_of_date);
|
|
if (asOfDate) {
|
|
return "explicit_as_of_date";
|
|
}
|
|
if (semanticFrame?.date_basis_hint) {
|
|
return semanticFrame.date_basis_hint;
|
|
}
|
|
const periodFrom = normalizeIsoDateHint(filters.period_from);
|
|
const periodTo = normalizeIsoDateHint(filters.period_to);
|
|
if (periodFrom && periodTo) {
|
|
return "period_range";
|
|
}
|
|
if (!periodFrom && periodTo) {
|
|
return "period_end";
|
|
}
|
|
if (periodFrom) {
|
|
return "period_range";
|
|
}
|
|
return null;
|
|
}
|
|
function deriveAddressEvidenceStrength(input) {
|
|
if (isHeuristicCandidatesIntent(input.intent)) {
|
|
if (input.rowsMatched <= 0 || input.responseType === "LIMITED_WITH_REASON") {
|
|
return "weak";
|
|
}
|
|
if (input.selectedRecipe === "address_open_items_by_party_or_contract_v1") {
|
|
return "medium";
|
|
}
|
|
return "weak";
|
|
}
|
|
if (isConfirmedBalanceIntent(input.intent)) {
|
|
if (input.rowsMatched > 0) {
|
|
return "strong";
|
|
}
|
|
return input.responseType === "LIMITED_WITH_REASON" ? "weak" : "medium";
|
|
}
|
|
return null;
|
|
}
|
|
function resolveAddressRequestedResultMode(intent, filters, semanticFrame) {
|
|
if (isConfirmedBalanceIntent(intent)) {
|
|
return "confirmed_balance";
|
|
}
|
|
if (intent === "list_open_contracts") {
|
|
return "heuristic_candidates";
|
|
}
|
|
if (isHeuristicCandidatesIntent(intent)) {
|
|
const asOfDateBasis = resolveAddressAsOfDateBasis(filters, semanticFrame);
|
|
if (asOfDateBasis === "explicit_as_of_date" ||
|
|
asOfDateBasis === "period_end" ||
|
|
asOfDateBasis === "period_range" ||
|
|
asOfDateBasis === "implicit_current_snapshot") {
|
|
return "confirmed_balance";
|
|
}
|
|
return "heuristic_candidates";
|
|
}
|
|
return null;
|
|
}
|
|
function balanceConfirmedFrom(input) {
|
|
if (isHeuristicCandidatesIntent(input.intent)) {
|
|
return false;
|
|
}
|
|
if (isConfirmedBalanceIntent(input.intent)) {
|
|
return input.responseType !== "LIMITED_WITH_REASON";
|
|
}
|
|
return null;
|
|
}
|
|
function coverageStatusFrom(input) {
|
|
if (input.responseType === "LIMITED_WITH_REASON") {
|
|
return input.resultMode === "heuristic_candidates" ? "partial" : "blocked";
|
|
}
|
|
if (input.balanceConfirmed === false) {
|
|
return "partial";
|
|
}
|
|
if (input.rowsMatched > 0) {
|
|
return "full";
|
|
}
|
|
if (input.resultMode === "heuristic_candidates") {
|
|
return "partial";
|
|
}
|
|
if (input.resultMode === "confirmed_balance" && input.balanceConfirmed === true) {
|
|
return "full";
|
|
}
|
|
return "blocked";
|
|
}
|
|
function evidenceBasisFrom(input) {
|
|
if (input.responseType === "LIMITED_WITH_REASON") {
|
|
return "limited_response";
|
|
}
|
|
if (input.resultMode === "heuristic_candidates" || input.balanceConfirmed === false) {
|
|
return "heuristic_candidates";
|
|
}
|
|
if (input.rowsMatched > 0) {
|
|
return "matched_rows";
|
|
}
|
|
if (input.resultMode === "confirmed_balance") {
|
|
return "exact_negative";
|
|
}
|
|
return "unknown";
|
|
}
|
|
function resolveAddressCoverageEvidence(input) {
|
|
const requestedResultMode = resolveAddressRequestedResultMode(input.intent, input.filters, input.semanticFrame);
|
|
const resultMode = input.overrideResultMode ?? requestedResultMode;
|
|
const evidenceStrength = input.overrideEvidenceStrength ?? deriveAddressEvidenceStrength(input);
|
|
const balanceConfirmed = input.overrideBalanceConfirmed ?? balanceConfirmedFrom(input);
|
|
const asOfDateBasis = resolveAddressAsOfDateBasis(input.filters, input.semanticFrame);
|
|
const coverageStatus = coverageStatusFrom({
|
|
resultMode,
|
|
balanceConfirmed,
|
|
responseType: input.responseType,
|
|
rowsMatched: input.rowsMatched
|
|
});
|
|
const evidenceBasis = evidenceBasisFrom({
|
|
resultMode,
|
|
responseType: input.responseType,
|
|
rowsMatched: input.rowsMatched,
|
|
balanceConfirmed
|
|
});
|
|
const reasonCodes = [];
|
|
pushReason(reasonCodes, `coverage_status_${coverageStatus}`);
|
|
pushReason(reasonCodes, resultMode ? `result_mode_${resultMode}` : "result_mode_unknown");
|
|
pushReason(reasonCodes, evidenceStrength ? `evidence_strength_${evidenceStrength}` : "evidence_strength_none");
|
|
pushReason(reasonCodes, `evidence_basis_${evidenceBasis}`);
|
|
pushReason(reasonCodes, balanceConfirmed === true ? "balance_confirmed_true" : balanceConfirmed === false ? "balance_confirmed_false" : "balance_confirmed_unknown");
|
|
pushReason(reasonCodes, asOfDateBasis ? `as_of_date_basis_${asOfDateBasis}` : "as_of_date_basis_none");
|
|
return {
|
|
schema_version: exports.ADDRESS_COVERAGE_EVIDENCE_SCHEMA_VERSION,
|
|
policy_owner: "addressCoverageEvidencePolicy",
|
|
requested_result_mode: requestedResultMode,
|
|
result_mode: resultMode,
|
|
evidence_strength: evidenceStrength,
|
|
balance_confirmed: balanceConfirmed,
|
|
as_of_date_basis: asOfDateBasis,
|
|
coverage_status: coverageStatus,
|
|
evidence_basis: evidenceBasis,
|
|
reason_codes: reasonCodes.slice(0, 24)
|
|
};
|
|
}
|
|
function attachAddressCoverageEvidence(debugPayload, input) {
|
|
return {
|
|
...debugPayload,
|
|
address_coverage_evidence_v1: resolveAddressCoverageEvidence(input)
|
|
};
|
|
}
|
|
function toAddressCoverageEvidenceContract(value) {
|
|
const record = toRecordObject(value);
|
|
if (!record) {
|
|
return null;
|
|
}
|
|
const requestedResultMode = toNonEmptyString(record.requested_result_mode);
|
|
const resultMode = toNonEmptyString(record.result_mode);
|
|
const evidenceStrength = toNonEmptyString(record.evidence_strength);
|
|
const asOfDateBasis = toNonEmptyString(record.as_of_date_basis);
|
|
const coverageStatus = toNonEmptyString(record.coverage_status);
|
|
const evidenceBasis = toNonEmptyString(record.evidence_basis);
|
|
const balanceConfirmed = typeof record.balance_confirmed === "boolean" ? record.balance_confirmed : null;
|
|
if (!isCoverageStatus(coverageStatus) || !isEvidenceBasis(evidenceBasis)) {
|
|
return null;
|
|
}
|
|
if (requestedResultMode !== null && !isResultMode(requestedResultMode)) {
|
|
return null;
|
|
}
|
|
if (resultMode !== null && !isResultMode(resultMode)) {
|
|
return null;
|
|
}
|
|
if (evidenceStrength !== null && !isEvidenceStrength(evidenceStrength)) {
|
|
return null;
|
|
}
|
|
if (asOfDateBasis !== null && !isAsOfDateBasis(asOfDateBasis)) {
|
|
return null;
|
|
}
|
|
return {
|
|
schema_version: exports.ADDRESS_COVERAGE_EVIDENCE_SCHEMA_VERSION,
|
|
policy_owner: "addressCoverageEvidencePolicy",
|
|
requested_result_mode: requestedResultMode,
|
|
result_mode: resultMode,
|
|
evidence_strength: evidenceStrength,
|
|
balance_confirmed: balanceConfirmed,
|
|
as_of_date_basis: asOfDateBasis,
|
|
coverage_status: coverageStatus,
|
|
evidence_basis: evidenceBasis,
|
|
reason_codes: Array.isArray(record.reason_codes)
|
|
? record.reason_codes
|
|
.map((item) => toNonEmptyString(item))
|
|
.filter((item) => Boolean(item))
|
|
.slice(0, 24)
|
|
: []
|
|
};
|
|
}
|