@spottoai/types-package 1.0.2-dev1138.2 → 1.0.2-dev1138.3
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.
- package/dist/azure/financialAnalytics.d.ts +68 -2
- package/dist/azure/financialAnalytics.d.ts.map +1 -1
- package/dist/azure/financialAnalyticsDelivery.d.ts +2 -0
- package/dist/azure/financialAnalyticsDelivery.d.ts.map +1 -1
- package/dist/azure/financialAnalyticsDelivery.js +4 -1
- package/dist/azure/financialAnalyticsDelivery.js.map +1 -1
- package/dist/azure/financialAnalyticsDisplayKernel.d.ts +12 -0
- package/dist/azure/financialAnalyticsDisplayKernel.d.ts.map +1 -0
- package/dist/azure/financialAnalyticsDisplayKernel.js +144 -0
- package/dist/azure/financialAnalyticsDisplayKernel.js.map +1 -0
- package/dist/azure/financialAnalyticsValidation.d.ts.map +1 -1
- package/dist/azure/financialAnalyticsValidation.js +61 -7
- package/dist/azure/financialAnalyticsValidation.js.map +1 -1
- package/dist/azure/financialAuthorityView.d.ts +4 -0
- package/dist/azure/financialAuthorityView.d.ts.map +1 -1
- package/dist/azure/financialAuthorityView.js.map +1 -1
- package/dist/azure/financialAuthorityViewValidation.d.ts.map +1 -1
- package/dist/azure/financialAuthorityViewValidation.js +39 -0
- package/dist/azure/financialAuthorityViewValidation.js.map +1 -1
- package/dist/azure/financialChargeComposition.d.ts +81 -0
- package/dist/azure/financialChargeComposition.d.ts.map +1 -0
- package/dist/azure/financialChargeComposition.js +41 -0
- package/dist/azure/financialChargeComposition.js.map +1 -0
- package/dist/azure/financialChargeCompositionKernel.d.ts +3 -0
- package/dist/azure/financialChargeCompositionKernel.d.ts.map +1 -0
- package/dist/azure/financialChargeCompositionKernel.js +49 -0
- package/dist/azure/financialChargeCompositionKernel.js.map +1 -0
- package/dist/azure/financialChargeCompositionValidation.d.ts +8 -0
- package/dist/azure/financialChargeCompositionValidation.d.ts.map +1 -0
- package/dist/azure/financialChargeCompositionValidation.js +164 -0
- package/dist/azure/financialChargeCompositionValidation.js.map +1 -0
- package/dist/azure/financialDataflow.d.ts +8 -1
- package/dist/azure/financialDataflow.d.ts.map +1 -1
- package/dist/azure/financialDataflow.js.map +1 -1
- package/dist/azure/financialDataflowKernel.d.ts +2 -0
- package/dist/azure/financialDataflowKernel.d.ts.map +1 -1
- package/dist/azure/financialDataflowKernel.js +59 -7
- package/dist/azure/financialDataflowKernel.js.map +1 -1
- package/dist/azure/financialDataflowValidation.d.ts +1 -1
- package/dist/azure/financialDataflowValidation.d.ts.map +1 -1
- package/dist/azure/financialDataflowValidation.js +146 -28
- package/dist/azure/financialDataflowValidation.js.map +1 -1
- package/dist/azure/financialPolicy.d.ts +3 -0
- package/dist/azure/financialPolicy.d.ts.map +1 -1
- package/dist/azure/financialPolicy.js.map +1 -1
- package/dist/azure/financialPolicyValidation.d.ts.map +1 -1
- package/dist/azure/financialPolicyValidation.js +5 -0
- package/dist/azure/financialPolicyValidation.js.map +1 -1
- package/dist/azure/financialScope.d.ts +4 -0
- package/dist/azure/financialScope.d.ts.map +1 -1
- package/dist/azure/financialScope.js +4 -0
- package/dist/azure/financialScope.js.map +1 -1
- package/dist/azure/metrics.d.ts +2 -2
- package/dist/azure/metrics.d.ts.map +1 -1
- package/dist/azure/prices.d.ts +16 -3
- package/dist/azure/prices.d.ts.map +1 -1
- package/dist/azure/recommendations.d.ts +12 -4
- package/dist/azure/recommendations.d.ts.map +1 -1
- package/dist/azure/reports.d.ts +3 -2
- package/dist/azure/reports.d.ts.map +1 -1
- package/dist/azure/reports.js.map +1 -1
- package/dist/azure/resources.d.ts +12 -0
- package/dist/azure/resources.d.ts.map +1 -1
- package/dist/azure/subscriptions.d.ts +4 -2
- package/dist/azure/subscriptions.d.ts.map +1 -1
- package/dist/azure/views.d.ts +7 -2
- package/dist/azure/views.d.ts.map +1 -1
- package/dist/azure/views.js.map +1 -1
- package/dist/esm/azure/financialAnalyticsDelivery.js +2 -0
- package/dist/esm/azure/financialAnalyticsDisplayKernel.js +139 -0
- package/dist/esm/azure/financialAnalyticsValidation.js +61 -7
- package/dist/esm/azure/financialAuthorityViewValidation.js +39 -0
- package/dist/esm/azure/financialChargeComposition.js +36 -0
- package/dist/esm/azure/financialChargeCompositionKernel.js +44 -0
- package/dist/esm/azure/financialChargeCompositionValidation.js +155 -0
- package/dist/esm/azure/financialDataflowKernel.js +59 -7
- package/dist/esm/azure/financialDataflowValidation.js +146 -28
- package/dist/esm/azure/financialPolicyValidation.js +5 -0
- package/dist/esm/azure/financialScope.js +4 -0
- package/package.json +3 -2
|
@@ -2,6 +2,8 @@ import { sha256Utf8 } from '../common/sha256.js';
|
|
|
2
2
|
import { formatExactDecimalValue, sumCanonicalDecimals } from '../common/exactDecimal.js';
|
|
3
3
|
import { toCanonicalEstimateLensV1 } from './costComposition.js';
|
|
4
4
|
import { isCanonicalExactMoney } from './financialValidationPrimitives.js';
|
|
5
|
+
import { AZURE_BILLED_ALL_CHARGES_POLICY_V1, resolveFinancialChargeInclusionPolicyV1, } from './financialChargeComposition.js';
|
|
6
|
+
import { isFinancialChargeCompositionV1, selectFinancialChargesV1 } from './financialChargeCompositionValidation.js';
|
|
5
7
|
import { isCompleteFinancialBaselinePeriodV2 } from './financialScopeBaseline.js';
|
|
6
8
|
import { isFinancialScopeBaselineEnvelopeV2 } from './financialScopeBaselineValidation.js';
|
|
7
9
|
import { FINANCIAL_CURRENT_SPEND_COMPOSITION_CONTRACT_VERSION_V1, FINANCIAL_DATAFLOW_SCHEMA_VERSION_V1, } from './financialDataflow.js';
|
|
@@ -361,7 +363,18 @@ export const isFinancialDataflowScopeSelectorV1 = (value) => {
|
|
|
361
363
|
};
|
|
362
364
|
export const isFinancialDataflowCoordinateV1 = (value) => {
|
|
363
365
|
if (!isFinancialDataflowRecordV1(value) ||
|
|
364
|
-
!hasFinancialDataflowExactFieldsV1(value, [
|
|
366
|
+
!hasFinancialDataflowExactFieldsV1(value, [
|
|
367
|
+
'companyId',
|
|
368
|
+
'provider',
|
|
369
|
+
'providerAccountRefs',
|
|
370
|
+
'scope',
|
|
371
|
+
'periodRole',
|
|
372
|
+
'period',
|
|
373
|
+
'costBasis',
|
|
374
|
+
'estimateLens',
|
|
375
|
+
'accountingCurrency',
|
|
376
|
+
'chargeInclusionPolicyRef',
|
|
377
|
+
], ['requestedCurrencyCode']) ||
|
|
365
378
|
!isFinancialDataflowIdentityV1(value.companyId) ||
|
|
366
379
|
value.provider !== 'azure' ||
|
|
367
380
|
!isFinancialDataflowSortedUniqueStringsV1(value.providerAccountRefs, FINANCIAL_DATAFLOW_LIMITS_V1.maximumProviderAccounts) ||
|
|
@@ -375,7 +388,12 @@ export const isFinancialDataflowCoordinateV1 = (value) => {
|
|
|
375
388
|
typeof value.estimateLens !== 'string' ||
|
|
376
389
|
!ESTIMATE_LENSES.has(value.estimateLens) ||
|
|
377
390
|
(value.requestedCurrencyCode !== undefined && !isFinancialDataflowCurrencyV1(value.requestedCurrencyCode)) ||
|
|
378
|
-
!isFinancialDataflowRecordV1(value.accountingCurrency)
|
|
391
|
+
!isFinancialDataflowRecordV1(value.accountingCurrency) ||
|
|
392
|
+
!isFinancialDataflowRecordV1(value.chargeInclusionPolicyRef) ||
|
|
393
|
+
!hasFinancialDataflowExactFieldsV1(value.chargeInclusionPolicyRef, ['policyId', 'policyDigest']) ||
|
|
394
|
+
!isFinancialDataflowIdentityV1(value.chargeInclusionPolicyRef.policyId) ||
|
|
395
|
+
!isFinancialDataflowHashV1(value.chargeInclusionPolicyRef.policyDigest) ||
|
|
396
|
+
resolveFinancialChargeInclusionPolicyV1(value.chargeInclusionPolicyRef) === undefined) {
|
|
379
397
|
return false;
|
|
380
398
|
}
|
|
381
399
|
if (value.accountingCurrency.status === 'resolved') {
|
|
@@ -403,7 +421,9 @@ const isMember = (value) => {
|
|
|
403
421
|
if (!isFinancialDataflowRecordV1(value) || !isFinancialDataflowIdentityV1(value.memberScopeId))
|
|
404
422
|
return false;
|
|
405
423
|
if (value.status === 'included') {
|
|
406
|
-
return hasFinancialDataflowExactFieldsV1(value, ['memberScopeId', 'baselineId', 'status']) &&
|
|
424
|
+
return (hasFinancialDataflowExactFieldsV1(value, ['memberScopeId', 'baselineId', 'chargeCompositionId', 'status']) &&
|
|
425
|
+
isFinancialDataflowHashV1(value.baselineId) &&
|
|
426
|
+
isFinancialDataflowHashV1(value.chargeCompositionId));
|
|
407
427
|
}
|
|
408
428
|
return (value.status === 'unavailable' &&
|
|
409
429
|
hasFinancialDataflowExactFieldsV1(value, ['memberScopeId', 'status', 'reasonCode']) &&
|
|
@@ -421,15 +441,7 @@ export const canonicalizeCurrentSpendMembershipV1 = (members) => {
|
|
|
421
441
|
export const createCurrentSpendMembershipDigestV1 = (members) => `sha256:${sha256Utf8(canonicalizeCurrentSpendMembershipV1(members))}`;
|
|
422
442
|
const isCompositionIdentity = (value) => {
|
|
423
443
|
if (!isFinancialDataflowRecordV1(value) ||
|
|
424
|
-
!hasFinancialDataflowExactFieldsV1(value, [
|
|
425
|
-
'schemaVersion',
|
|
426
|
-
'contractVersion',
|
|
427
|
-
'coordinate',
|
|
428
|
-
'members',
|
|
429
|
-
'amount',
|
|
430
|
-
'membershipDigest',
|
|
431
|
-
'algorithmVersion',
|
|
432
|
-
]) ||
|
|
444
|
+
!hasFinancialDataflowExactFieldsV1(value, ['schemaVersion', 'contractVersion', 'coordinate', 'members', 'amount', 'membershipDigest', 'algorithmVersion'], ['chargeSelection']) ||
|
|
433
445
|
value.schemaVersion !== FINANCIAL_DATAFLOW_SCHEMA_VERSION_V1 ||
|
|
434
446
|
value.contractVersion !== FINANCIAL_CURRENT_SPEND_COMPOSITION_CONTRACT_VERSION_V1 ||
|
|
435
447
|
!isFinancialDataflowCoordinateV1(value.coordinate) ||
|
|
@@ -445,11 +457,45 @@ const isCompositionIdentity = (value) => {
|
|
|
445
457
|
return false;
|
|
446
458
|
}
|
|
447
459
|
const currency = value.coordinate.accountingCurrency.status === 'resolved' ? value.coordinate.accountingCurrency.currencyCode : undefined;
|
|
460
|
+
const isChargeSelection = (selection) => {
|
|
461
|
+
if (!isFinancialDataflowRecordV1(selection) ||
|
|
462
|
+
!hasFinancialDataflowExactFieldsV1(selection, [
|
|
463
|
+
'status',
|
|
464
|
+
'includedAmount',
|
|
465
|
+
'excludedAmount',
|
|
466
|
+
'withheldAmount',
|
|
467
|
+
'forecastEligibleAmount',
|
|
468
|
+
'oneTimeAmount',
|
|
469
|
+
'unknownRecurrenceAmount',
|
|
470
|
+
'forecastStatus',
|
|
471
|
+
'currencyCode',
|
|
472
|
+
], ['reasonCodes', 'forecastReasonCodes']) ||
|
|
473
|
+
(selection.status !== 'available' && selection.status !== 'partial') ||
|
|
474
|
+
(selection.forecastStatus !== 'available' && selection.forecastStatus !== 'partial') ||
|
|
475
|
+
!isFinancialDataflowCurrencyV1(selection.currencyCode) ||
|
|
476
|
+
![
|
|
477
|
+
selection.includedAmount,
|
|
478
|
+
selection.excludedAmount,
|
|
479
|
+
selection.withheldAmount,
|
|
480
|
+
selection.forecastEligibleAmount,
|
|
481
|
+
selection.oneTimeAmount,
|
|
482
|
+
selection.unknownRecurrenceAmount,
|
|
483
|
+
].every(amount => isCanonicalExactMoney({ amount, currencyCode: selection.currencyCode })))
|
|
484
|
+
return false;
|
|
485
|
+
return ((selection.status === 'available' ? selection.reasonCodes === undefined : isReasonCodes(selection.reasonCodes)) &&
|
|
486
|
+
(selection.forecastStatus === 'available'
|
|
487
|
+
? selection.forecastReasonCodes === undefined
|
|
488
|
+
: isReasonCodes(selection.forecastReasonCodes)));
|
|
489
|
+
};
|
|
448
490
|
if (value.amount.status === 'available') {
|
|
449
491
|
return (currency !== undefined &&
|
|
450
492
|
hasFinancialDataflowExactFieldsV1(value.amount, ['status', 'amount', 'currencyCode']) &&
|
|
451
493
|
isCanonicalExactMoney({ amount: value.amount.amount, currencyCode: value.amount.currencyCode }) &&
|
|
452
494
|
value.amount.currencyCode === currency &&
|
|
495
|
+
isChargeSelection(value.chargeSelection) &&
|
|
496
|
+
value.chargeSelection.status === 'available' &&
|
|
497
|
+
value.chargeSelection.currencyCode === currency &&
|
|
498
|
+
value.chargeSelection.includedAmount === value.amount.amount &&
|
|
453
499
|
value.members.length > 0 &&
|
|
454
500
|
value.members.every(member => member.status === 'included'));
|
|
455
501
|
}
|
|
@@ -459,11 +505,17 @@ const isCompositionIdentity = (value) => {
|
|
|
459
505
|
isCanonicalExactMoney({ amount: value.amount.knownAmount, currencyCode: value.amount.currencyCode }) &&
|
|
460
506
|
value.amount.currencyCode === currency &&
|
|
461
507
|
isReasonCodes(value.amount.reasonCodes) &&
|
|
508
|
+
isChargeSelection(value.chargeSelection) &&
|
|
509
|
+
value.chargeSelection.currencyCode === currency &&
|
|
510
|
+
value.chargeSelection.includedAmount === value.amount.knownAmount &&
|
|
462
511
|
value.members.some(member => member.status === 'included') &&
|
|
463
|
-
(value.members.some(member => member.status === 'unavailable') ||
|
|
512
|
+
(value.members.some(member => member.status === 'unavailable') ||
|
|
513
|
+
value.amount.reasonCodes.includes('coverage-incomplete') ||
|
|
514
|
+
value.chargeSelection.status === 'partial'));
|
|
464
515
|
}
|
|
465
516
|
const unresolvedCurrency = value.coordinate.accountingCurrency;
|
|
466
517
|
return (value.amount.status === 'unavailable' &&
|
|
518
|
+
value.chargeSelection === undefined &&
|
|
467
519
|
hasFinancialDataflowExactFieldsV1(value.amount, ['status', 'reasonCodes']) &&
|
|
468
520
|
isReasonCodes(value.amount.reasonCodes) &&
|
|
469
521
|
(currency !== undefined || (unresolvedCurrency.status === 'unresolved' && value.amount.reasonCodes.includes(unresolvedCurrency.reasonCode))));
|
|
@@ -480,6 +532,19 @@ export const canonicalizeCurrentSpendCompositionIdentityV1 = (value) => {
|
|
|
480
532
|
},
|
|
481
533
|
members: [...value.members].sort((left, right) => left.memberScopeId.localeCompare(right.memberScopeId)),
|
|
482
534
|
amount: value.amount.status === 'available' ? value.amount : { ...value.amount, reasonCodes: [...value.amount.reasonCodes].sort() },
|
|
535
|
+
...(value.chargeSelection === undefined
|
|
536
|
+
? {}
|
|
537
|
+
: {
|
|
538
|
+
chargeSelection: {
|
|
539
|
+
...value.chargeSelection,
|
|
540
|
+
...(value.chargeSelection.reasonCodes === undefined
|
|
541
|
+
? {}
|
|
542
|
+
: { reasonCodes: [...value.chargeSelection.reasonCodes].sort() }),
|
|
543
|
+
...(value.chargeSelection.forecastReasonCodes === undefined
|
|
544
|
+
? {}
|
|
545
|
+
: { forecastReasonCodes: [...value.chargeSelection.forecastReasonCodes].sort() }),
|
|
546
|
+
},
|
|
547
|
+
}),
|
|
483
548
|
};
|
|
484
549
|
return canonicalizeFinancialDataflowJsonV1(canonical);
|
|
485
550
|
};
|
|
@@ -496,7 +561,7 @@ export const isCurrentSpendCompositionV1 = (value) => {
|
|
|
496
561
|
'amount',
|
|
497
562
|
'membershipDigest',
|
|
498
563
|
'algorithmVersion',
|
|
499
|
-
])) {
|
|
564
|
+
], ['chargeSelection'])) {
|
|
500
565
|
return false;
|
|
501
566
|
}
|
|
502
567
|
const { compositionId, ...identity } = value;
|
|
@@ -511,65 +576,118 @@ const hasCompatibleBaselineCoordinate = (coordinate, baseline) => baseline.provi
|
|
|
511
576
|
toCanonicalEstimateLensV1(baseline.estimateLens) === coordinate.estimateLens &&
|
|
512
577
|
baseline.requestedCurrencyCode === coordinate.requestedCurrencyCode;
|
|
513
578
|
/** Proves that composition membership and money reconcile to exact V2 baseline envelopes. */
|
|
514
|
-
export const isCurrentSpendCompositionCompatibleV1 = (composition, baselines) => {
|
|
579
|
+
export const isCurrentSpendCompositionCompatibleV1 = (composition, baselines, chargeCompositions) => {
|
|
515
580
|
if (!isCurrentSpendCompositionV1(composition) ||
|
|
516
581
|
!Array.isArray(baselines) ||
|
|
517
582
|
baselines.length !== composition.members.length ||
|
|
518
583
|
baselines.length > FINANCIAL_DATAFLOW_LIMITS_V1.maximumMembers ||
|
|
519
|
-
!baselines.every(isFinancialScopeBaselineEnvelopeV2)
|
|
584
|
+
!baselines.every(isFinancialScopeBaselineEnvelopeV2) ||
|
|
585
|
+
!Array.isArray(chargeCompositions) ||
|
|
586
|
+
!chargeCompositions.every(isFinancialChargeCompositionV1)) {
|
|
520
587
|
return false;
|
|
521
588
|
}
|
|
522
589
|
const typedBaselines = baselines;
|
|
590
|
+
const typedChargeCompositions = chargeCompositions;
|
|
591
|
+
const chargeCompositionById = new Map(typedChargeCompositions.map(value => [value.chargeCompositionId, value]));
|
|
592
|
+
if (chargeCompositionById.size !== typedChargeCompositions.length)
|
|
593
|
+
return false;
|
|
523
594
|
const baselineByScopeId = new Map(typedBaselines.map(baseline => [baseline.scopeId, baseline]));
|
|
524
595
|
if (baselineByScopeId.size !== typedBaselines.length ||
|
|
525
596
|
new Set(typedBaselines.filter(baseline => baseline.status === 'available').map(baseline => baseline.baselineId)).size !==
|
|
526
597
|
typedBaselines.filter(baseline => baseline.status === 'available').length) {
|
|
527
598
|
return false;
|
|
528
599
|
}
|
|
529
|
-
const
|
|
600
|
+
const includedSelections = [];
|
|
530
601
|
const expectedReasonCodes = new Set();
|
|
531
602
|
for (const member of composition.members) {
|
|
532
603
|
const baseline = baselineByScopeId.get(member.memberScopeId);
|
|
533
604
|
if (baseline === undefined || !hasCompatibleBaselineCoordinate(composition.coordinate, baseline))
|
|
534
605
|
return false;
|
|
535
606
|
if (member.status === 'included') {
|
|
536
|
-
if (baseline.status !== 'available' ||
|
|
607
|
+
if (baseline.status !== 'available' ||
|
|
608
|
+
baseline.baselineKind !== 'owner' ||
|
|
609
|
+
member.baselineId !== baseline.baselineId ||
|
|
610
|
+
canonicalizeFinancialDataflowJsonV1(baseline.chargeInclusionPolicyRef) !==
|
|
611
|
+
canonicalizeFinancialDataflowJsonV1(AZURE_BILLED_ALL_CHARGES_POLICY_V1.policyRef))
|
|
612
|
+
return false;
|
|
613
|
+
const chargeComposition = chargeCompositionById.get(member.chargeCompositionId);
|
|
614
|
+
if (chargeComposition === undefined ||
|
|
615
|
+
chargeComposition.baselineId !== baseline.baselineId ||
|
|
616
|
+
chargeComposition.ownerScopeId !== baseline.scopeId ||
|
|
617
|
+
chargeComposition.period.windowKind !== baseline.period.windowKind ||
|
|
618
|
+
canonicalizeFinancialDataflowJsonV1(chargeComposition.period.requested) !== canonicalizeFinancialDataflowJsonV1(baseline.period.requested) ||
|
|
619
|
+
chargeComposition.costBasis !== baseline.costBasis ||
|
|
620
|
+
chargeComposition.estimateLens !== baseline.estimateLens ||
|
|
621
|
+
chargeComposition.accountingCurrencyCode !== baseline.total.currencyCode ||
|
|
622
|
+
chargeComposition.reconciliation.sourceTotal !== baseline.total.amount)
|
|
537
623
|
return false;
|
|
538
624
|
if (composition.coordinate.accountingCurrency.status === 'resolved' &&
|
|
539
625
|
baseline.total.currencyCode !== composition.coordinate.accountingCurrency.currencyCode) {
|
|
540
626
|
return false;
|
|
541
627
|
}
|
|
542
|
-
|
|
628
|
+
includedSelections.push(selectFinancialChargesV1(chargeComposition, composition.coordinate.chargeInclusionPolicyRef));
|
|
629
|
+
includedSelections[includedSelections.length - 1].reasonCodes?.forEach(reason => expectedReasonCodes.add(reason));
|
|
543
630
|
if (baseline.status === 'available' && !isCompleteFinancialBaselinePeriodV2(baseline.period)) {
|
|
544
631
|
expectedReasonCodes.add('coverage-incomplete');
|
|
545
632
|
}
|
|
546
633
|
continue;
|
|
547
634
|
}
|
|
548
|
-
if (baseline.status
|
|
549
|
-
|
|
550
|
-
|
|
635
|
+
if (baseline.status === 'unavailable') {
|
|
636
|
+
if (member.reasonCode !== baseline.unavailableReason)
|
|
637
|
+
return false;
|
|
638
|
+
expectedReasonCodes.add(baseline.unavailableReason);
|
|
639
|
+
}
|
|
640
|
+
else {
|
|
641
|
+
const expectedDerivedReason = baseline.baselineKind === 'aggregate'
|
|
642
|
+
? 'charge-composition-requires-owner-baseline'
|
|
643
|
+
: 'charge-composition-unavailable';
|
|
644
|
+
if (member.reasonCode !== expectedDerivedReason)
|
|
645
|
+
return false;
|
|
646
|
+
expectedReasonCodes.add(expectedDerivedReason);
|
|
647
|
+
}
|
|
551
648
|
}
|
|
552
649
|
if (composition.coordinate.accountingCurrency.status === 'unresolved') {
|
|
553
650
|
expectedReasonCodes.add(composition.coordinate.accountingCurrency.reasonCode);
|
|
554
651
|
}
|
|
652
|
+
if (typedChargeCompositions.length !== includedSelections.length)
|
|
653
|
+
return false;
|
|
555
654
|
const hasExpectedReasonCodes = (reasonCodes) => reasonCodes.length === expectedReasonCodes.size && reasonCodes.every(reasonCode => expectedReasonCodes.has(reasonCode));
|
|
556
655
|
if (composition.coordinate.accountingCurrency.status === 'unresolved') {
|
|
557
656
|
return composition.amount.status === 'unavailable' && hasExpectedReasonCodes(composition.amount.reasonCodes);
|
|
558
657
|
}
|
|
559
|
-
if (
|
|
658
|
+
if (includedSelections.length === 0) {
|
|
560
659
|
return composition.amount.status === 'unavailable' && hasExpectedReasonCodes(composition.amount.reasonCodes);
|
|
561
660
|
}
|
|
562
|
-
let
|
|
661
|
+
let aggregateSelection;
|
|
563
662
|
try {
|
|
564
|
-
|
|
663
|
+
const reasonCodes = new Set(includedSelections.flatMap(selection => selection.reasonCodes ?? []));
|
|
664
|
+
const forecastReasonCodes = new Set(includedSelections.flatMap(selection => selection.forecastReasonCodes ?? []));
|
|
665
|
+
aggregateSelection = {
|
|
666
|
+
status: includedSelections.some(selection => selection.status === 'partial') ? 'partial' : 'available',
|
|
667
|
+
includedAmount: formatExactDecimalValue(sumCanonicalDecimals(includedSelections.map(selection => selection.includedAmount))),
|
|
668
|
+
excludedAmount: formatExactDecimalValue(sumCanonicalDecimals(includedSelections.map(selection => selection.excludedAmount))),
|
|
669
|
+
withheldAmount: formatExactDecimalValue(sumCanonicalDecimals(includedSelections.map(selection => selection.withheldAmount))),
|
|
670
|
+
forecastEligibleAmount: formatExactDecimalValue(sumCanonicalDecimals(includedSelections.map(selection => selection.forecastEligibleAmount))),
|
|
671
|
+
oneTimeAmount: formatExactDecimalValue(sumCanonicalDecimals(includedSelections.map(selection => selection.oneTimeAmount))),
|
|
672
|
+
unknownRecurrenceAmount: formatExactDecimalValue(sumCanonicalDecimals(includedSelections.map(selection => selection.unknownRecurrenceAmount))),
|
|
673
|
+
forecastStatus: includedSelections.some(selection => selection.forecastStatus === 'partial') ? 'partial' : 'available',
|
|
674
|
+
currencyCode: composition.coordinate.accountingCurrency.currencyCode,
|
|
675
|
+
...(reasonCodes.size === 0 ? {} : { reasonCodes: [...reasonCodes].sort() }),
|
|
676
|
+
...(forecastReasonCodes.size === 0
|
|
677
|
+
? {}
|
|
678
|
+
: { forecastReasonCodes: [...forecastReasonCodes].sort() }),
|
|
679
|
+
};
|
|
565
680
|
}
|
|
566
681
|
catch {
|
|
567
682
|
return false;
|
|
568
683
|
}
|
|
569
|
-
|
|
570
|
-
|
|
684
|
+
const sameSelection = canonicalizeFinancialDataflowJsonV1(composition.chargeSelection) === canonicalizeFinancialDataflowJsonV1(aggregateSelection);
|
|
685
|
+
if (!sameSelection)
|
|
686
|
+
return false;
|
|
687
|
+
if (includedSelections.length === composition.members.length && expectedReasonCodes.size === 0) {
|
|
688
|
+
return composition.amount.status === 'available' && composition.amount.amount === aggregateSelection.includedAmount;
|
|
571
689
|
}
|
|
572
690
|
return (composition.amount.status === 'partial' &&
|
|
573
|
-
composition.amount.knownAmount ===
|
|
691
|
+
composition.amount.knownAmount === aggregateSelection.includedAmount &&
|
|
574
692
|
hasExpectedReasonCodes(composition.amount.reasonCodes));
|
|
575
693
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { multiplyExactDecimalValues, parseCanonicalDecimal, subtractExactDecimalValues } from '../common/exactDecimal.js';
|
|
2
2
|
import { sha256Utf8 } from '../common/sha256.js';
|
|
3
3
|
import { isCanonicalExactMoney } from './financialValidationPrimitives.js';
|
|
4
|
+
import { isFinancialChargeInclusionPolicyRefV1 } from './financialChargeCompositionValidation.js';
|
|
4
5
|
import { FINANCIAL_POLICY_DEFINITION_CONTRACT_VERSION_V1, FINANCIAL_POLICY_EVALUATION_CONTRACT_VERSION_V1, } from './financialPolicy.js';
|
|
5
6
|
import { FINANCIAL_DATAFLOW_LIMITS_V1, canonicalizeFinancialDataflowJsonV1, canonicalizeFinancialDataflowCoordinateV1, hasFinancialDataflowExactFieldsV1, isFinancialDataflowCurrencyV1, createFinancialDataflowCoordinateIdV1, isFinancialDataflowHashV1, isFinancialDataflowIdentityV1, isFinancialDataflowIsoInstantV1, isFinancialDataflowRecordV1, isFinancialDataflowScopeSelectorV1, isFinancialDataflowSortedUniqueStringsV1, isFinancialDataflowValueWithinLimitsV1, } from './financialDataflowValidation.js';
|
|
6
7
|
import { isCurrentSpendCompositionV1 } from './financialDataflowValidation.js';
|
|
@@ -85,6 +86,7 @@ const isCoordinateRequest = (value, companyId) => isFinancialDataflowRecordV1(va
|
|
|
85
86
|
'period',
|
|
86
87
|
'costBasis',
|
|
87
88
|
'estimateLens',
|
|
89
|
+
'chargeInclusionPolicyRef',
|
|
88
90
|
'requiredAccountingCurrencyCode',
|
|
89
91
|
]) &&
|
|
90
92
|
value.provider === 'azure' &&
|
|
@@ -107,6 +109,7 @@ const isCoordinateRequest = (value, companyId) => isFinancialDataflowRecordV1(va
|
|
|
107
109
|
COST_BASES.has(value.costBasis) &&
|
|
108
110
|
typeof value.estimateLens === 'string' &&
|
|
109
111
|
ESTIMATE_LENSES.has(value.estimateLens) &&
|
|
112
|
+
isFinancialChargeInclusionPolicyRefV1(value.chargeInclusionPolicyRef) &&
|
|
110
113
|
isFinancialDataflowCurrencyV1(value.requiredAccountingCurrencyCode) &&
|
|
111
114
|
isFinancialDataflowIdentityV1(companyId);
|
|
112
115
|
const isCriteria = (value, currencyCode) => {
|
|
@@ -418,6 +421,8 @@ export const isFinancialPolicyEvaluationCompatibleV1 = (evaluation, definition,
|
|
|
418
421
|
request.scope.scopeId !== coordinate.scope.scopeId ||
|
|
419
422
|
request.costBasis !== coordinate.costBasis ||
|
|
420
423
|
request.estimateLens !== coordinate.estimateLens ||
|
|
424
|
+
canonicalizeFinancialDataflowJsonV1(request.chargeInclusionPolicyRef) !==
|
|
425
|
+
canonicalizeFinancialDataflowJsonV1(coordinate.chargeInclusionPolicyRef) ||
|
|
421
426
|
coordinate.requestedCurrencyCode !== request.requiredAccountingCurrencyCode ||
|
|
422
427
|
(currency === undefined
|
|
423
428
|
? currentSpendComposition.amount.status !== 'unavailable'
|
|
@@ -2,6 +2,9 @@ export * from './financialScopeEvidence.js';
|
|
|
2
2
|
export * from './financialScopeBaseline.js';
|
|
3
3
|
export * from './financialScopeBaselineIdentity.js';
|
|
4
4
|
export * from './financialScopeBaselineValidation.js';
|
|
5
|
+
export * from './financialChargeComposition.js';
|
|
6
|
+
export * from './financialChargeCompositionValidation.js';
|
|
7
|
+
export * from './financialChargeCompositionKernel.js';
|
|
5
8
|
export * from './financialEvidenceAssessmentValidation.js';
|
|
6
9
|
export * from './financialProjection.js';
|
|
7
10
|
export * from './financialProjectionValidation.js';
|
|
@@ -18,6 +21,7 @@ export * from './financialDataflowValidation.js';
|
|
|
18
21
|
export * from './financialDataflowKernel.js';
|
|
19
22
|
export * from './financialAnalytics.js';
|
|
20
23
|
export * from './financialAnalyticsValidation.js';
|
|
24
|
+
export * from './financialAnalyticsDisplayKernel.js';
|
|
21
25
|
export * from './financialAnalyticsDelivery.js';
|
|
22
26
|
export * from './financialAnalyticsDeliveryValidation.js';
|
|
23
27
|
export * from './financialPolicy.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spottoai/types-package",
|
|
3
|
-
"version": "1.0.2-dev1138.
|
|
3
|
+
"version": "1.0.2-dev1138.3",
|
|
4
4
|
"description": "Shared TypeScript interfaces for SpottoAI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -86,10 +86,11 @@
|
|
|
86
86
|
"check:financial-projection-contracts": "node scripts/check-financial-projection-contracts.mjs",
|
|
87
87
|
"check:financial-authority-view-contracts": "node scripts/check-financial-authority-view-contracts.mjs",
|
|
88
88
|
"check:financial-dataflow-contracts": "node scripts/check-financial-dataflow-contracts.mjs",
|
|
89
|
+
"check:financial-charge-composition-contracts": "node scripts/check-financial-charge-composition-contracts.mjs",
|
|
89
90
|
"check:capability-passport-contracts": "node scripts/check-capability-passport-contracts.mjs",
|
|
90
91
|
"check:commitments-planning": "node scripts/check-commitments-planning.mjs",
|
|
91
92
|
"prepublishOnly": "npm run clean && npm run build && npm test",
|
|
92
|
-
"test": "npm run build && npm run check:artifact-evidence-contracts && npm run check:billing-artifact-object-boundaries && npm run check:billing-cost-analysis-read-responses && npm run check:aws-examples && npm run check:plugin-public-artifacts && npm run check:portal-public-artifacts && npm run check:relationship-public-artifacts && npm run check:azure-view-set-contracts && npm run check:dev-1135-latest-contracts && npm run check:financial-scope-baseline-contracts && npm run check:financial-projection-contracts && npm run check:financial-authority-view-contracts && npm run check:financial-dataflow-contracts && npm run check:capability-passport-contracts && npm run check:commitments-planning && npm run check:packed-exports",
|
|
93
|
+
"test": "npm run build && npm run check:artifact-evidence-contracts && npm run check:billing-artifact-object-boundaries && npm run check:billing-cost-analysis-read-responses && npm run check:aws-examples && npm run check:plugin-public-artifacts && npm run check:portal-public-artifacts && npm run check:relationship-public-artifacts && npm run check:azure-view-set-contracts && npm run check:dev-1135-latest-contracts && npm run check:financial-scope-baseline-contracts && npm run check:financial-projection-contracts && npm run check:financial-authority-view-contracts && npm run check:financial-charge-composition-contracts && npm run check:financial-dataflow-contracts && npm run check:capability-passport-contracts && npm run check:commitments-planning && npm run check:packed-exports",
|
|
93
94
|
"lint": "eslint src --ext .ts",
|
|
94
95
|
"lint:fix": "eslint src --ext .ts --fix",
|
|
95
96
|
"format": "prettier --write \"src/**/*.{ts,js,json}\"",
|