@spottoai/types-package 1.0.2-dev1138.1 → 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 +80 -8
- package/dist/azure/financialAnalytics.d.ts.map +1 -1
- package/dist/azure/financialAnalyticsDelivery.d.ts +72 -3
- package/dist/azure/financialAnalyticsDelivery.d.ts.map +1 -1
- package/dist/azure/financialAnalyticsDelivery.js +7 -1
- package/dist/azure/financialAnalyticsDelivery.js.map +1 -1
- package/dist/azure/financialAnalyticsDeliveryValidation.d.ts +9 -1
- package/dist/azure/financialAnalyticsDeliveryValidation.d.ts.map +1 -1
- package/dist/azure/financialAnalyticsDeliveryValidation.js +190 -10
- package/dist/azure/financialAnalyticsDeliveryValidation.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 +101 -19
- 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 +45 -2
- package/dist/azure/financialDataflow.d.ts.map +1 -1
- package/dist/azure/financialDataflow.js.map +1 -1
- package/dist/azure/financialDataflowKernel.d.ts +31 -0
- package/dist/azure/financialDataflowKernel.d.ts.map +1 -0
- package/dist/azure/financialDataflowKernel.js +169 -0
- package/dist/azure/financialDataflowKernel.js.map +1 -0
- package/dist/azure/financialDataflowValidation.d.ts +5 -2
- package/dist/azure/financialDataflowValidation.d.ts.map +1 -1
- package/dist/azure/financialDataflowValidation.js +203 -30
- package/dist/azure/financialDataflowValidation.js.map +1 -1
- package/dist/azure/financialEvidenceAssessmentValidation.d.ts.map +1 -1
- package/dist/azure/financialEvidenceAssessmentValidation.js +7 -0
- package/dist/azure/financialEvidenceAssessmentValidation.js.map +1 -1
- package/dist/azure/financialPolicy.d.ts +19 -3
- package/dist/azure/financialPolicy.d.ts.map +1 -1
- package/dist/azure/financialPolicy.js.map +1 -1
- package/dist/azure/financialPolicyDelivery.d.ts +75 -1
- package/dist/azure/financialPolicyDelivery.d.ts.map +1 -1
- package/dist/azure/financialPolicyDelivery.js +5 -1
- package/dist/azure/financialPolicyDelivery.js.map +1 -1
- package/dist/azure/financialPolicyDeliveryValidation.d.ts +16 -2
- package/dist/azure/financialPolicyDeliveryValidation.d.ts.map +1 -1
- package/dist/azure/financialPolicyDeliveryValidation.js +238 -5
- package/dist/azure/financialPolicyDeliveryValidation.js.map +1 -1
- package/dist/azure/financialPolicyKernel.d.ts +38 -0
- package/dist/azure/financialPolicyKernel.d.ts.map +1 -0
- package/dist/azure/financialPolicyKernel.js +232 -0
- package/dist/azure/financialPolicyKernel.js.map +1 -0
- package/dist/azure/financialPolicyValidation.d.ts +1 -0
- package/dist/azure/financialPolicyValidation.d.ts.map +1 -1
- package/dist/azure/financialPolicyValidation.js +111 -16
- package/dist/azure/financialPolicyValidation.js.map +1 -1
- package/dist/azure/financialSavingsAuthority.d.ts +29 -0
- package/dist/azure/financialSavingsAuthority.d.ts.map +1 -1
- package/dist/azure/financialSavingsAuthority.js +2 -1
- package/dist/azure/financialSavingsAuthority.js.map +1 -1
- package/dist/azure/financialSavingsAuthorityValidation.d.ts.map +1 -1
- package/dist/azure/financialSavingsAuthorityValidation.js +3 -0
- package/dist/azure/financialSavingsAuthorityValidation.js.map +1 -1
- package/dist/azure/financialSavingsCoordinateValidation.d.ts.map +1 -1
- package/dist/azure/financialSavingsCoordinateValidation.js +36 -0
- package/dist/azure/financialSavingsCoordinateValidation.js.map +1 -1
- package/dist/azure/financialScope.d.ts +6 -0
- package/dist/azure/financialScope.d.ts.map +1 -1
- package/dist/azure/financialScope.js +6 -0
- package/dist/azure/financialScope.js.map +1 -1
- package/dist/azure/financialScopeBaseline.d.ts +8 -2
- package/dist/azure/financialScopeBaseline.d.ts.map +1 -1
- package/dist/azure/financialScopeBaseline.js +14 -1
- package/dist/azure/financialScopeBaseline.js.map +1 -1
- package/dist/azure/financialScopeBaselineValidation.d.ts.map +1 -1
- package/dist/azure/financialScopeBaselineValidation.js +15 -1
- package/dist/azure/financialScopeBaselineValidation.js.map +1 -1
- package/dist/azure/financialScopeEvidence.d.ts +1 -1
- package/dist/azure/financialScopeEvidence.d.ts.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 +21 -5
- package/dist/azure/views.d.ts.map +1 -1
- package/dist/azure/views.js.map +1 -1
- package/dist/esm/azure/financialAnalyticsDelivery.js +5 -0
- package/dist/esm/azure/financialAnalyticsDeliveryValidation.js +184 -11
- package/dist/esm/azure/financialAnalyticsDisplayKernel.js +139 -0
- package/dist/esm/azure/financialAnalyticsValidation.js +101 -19
- 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 +163 -0
- package/dist/esm/azure/financialDataflowValidation.js +199 -29
- package/dist/esm/azure/financialEvidenceAssessmentValidation.js +7 -0
- package/dist/esm/azure/financialPolicyDelivery.js +4 -0
- package/dist/esm/azure/financialPolicyDeliveryValidation.js +227 -7
- package/dist/esm/azure/financialPolicyKernel.js +225 -0
- package/dist/esm/azure/financialPolicyValidation.js +110 -16
- package/dist/esm/azure/financialSavingsAuthority.js +1 -0
- package/dist/esm/azure/financialSavingsAuthorityValidation.js +3 -0
- package/dist/esm/azure/financialSavingsCoordinateValidation.js +36 -0
- package/dist/esm/azure/financialScope.js +6 -0
- package/dist/esm/azure/financialScopeBaseline.js +12 -0
- package/dist/esm/azure/financialScopeBaselineValidation.js +15 -1
- package/dist/events/cost.d.ts +4 -0
- package/dist/events/cost.d.ts.map +1 -1
- package/package.json +3 -2
|
@@ -2,6 +2,9 @@ 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';
|
|
7
|
+
import { isCompleteFinancialBaselinePeriodV2 } from './financialScopeBaseline.js';
|
|
5
8
|
import { isFinancialScopeBaselineEnvelopeV2 } from './financialScopeBaselineValidation.js';
|
|
6
9
|
import { FINANCIAL_CURRENT_SPEND_COMPOSITION_CONTRACT_VERSION_V1, FINANCIAL_DATAFLOW_SCHEMA_VERSION_V1, } from './financialDataflow.js';
|
|
7
10
|
import { isFinancialBaselinePeriodV2 } from './financialScopeBaselineValidation.js';
|
|
@@ -141,6 +144,14 @@ export const isFinancialDataflowIdentityV1 = (value) => typeof value === 'string
|
|
|
141
144
|
export const isFinancialDataflowHashV1 = (value) => typeof value === 'string' && SHA256_ID.test(value);
|
|
142
145
|
export const isFinancialDataflowCurrencyV1 = (value) => typeof value === 'string' && CURRENCY.test(value);
|
|
143
146
|
export const isFinancialDataflowIsoInstantV1 = (value) => typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/.test(value) && Number.isFinite(Date.parse(value));
|
|
147
|
+
export const isFinancialDataflowJsonGzipArtifactDescriptorV1 = (value) => isFinancialDataflowRecordV1(value) &&
|
|
148
|
+
hasFinancialDataflowExactFieldsV1(value, ['path', 'sha256', 'byteCount', 'mediaType', 'contentEncoding']) &&
|
|
149
|
+
isFinancialDataflowIdentityV1(value.path) &&
|
|
150
|
+
isFinancialDataflowHashV1(value.sha256) &&
|
|
151
|
+
Number.isSafeInteger(value.byteCount) &&
|
|
152
|
+
Number(value.byteCount) > 0 &&
|
|
153
|
+
value.mediaType === 'application/json' &&
|
|
154
|
+
value.contentEncoding === 'gzip';
|
|
144
155
|
export const isFinancialDataflowCalendarDateV1 = (value) => {
|
|
145
156
|
if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(value))
|
|
146
157
|
return false;
|
|
@@ -310,9 +321,60 @@ export const isFinancialDataflowScopeV1 = (value) => isFinancialDataflowRecordV1
|
|
|
310
321
|
SCOPE_KINDS.has(value.kind) &&
|
|
311
322
|
isFinancialDataflowIdentityV1(value.scopeId) &&
|
|
312
323
|
isFinancialDataflowHashV1(value.scopeFingerprint);
|
|
324
|
+
export const isFinancialDataflowPeriodV1 = (value) => isFinancialDataflowRecordV1(value) &&
|
|
325
|
+
hasFinancialDataflowExactFieldsV1(value, ['windowKind', 'requested'], ['providerBillingPeriodId']) &&
|
|
326
|
+
isFinancialBaselinePeriodV2({ ...value, coverage: [], gaps: [] });
|
|
327
|
+
export const isFinancialDataflowScopeSelectorV1 = (value) => {
|
|
328
|
+
if (!isFinancialDataflowRecordV1(value) || typeof value.kind !== 'string' || !SCOPE_KINDS.has(value.kind))
|
|
329
|
+
return false;
|
|
330
|
+
if (value.kind === 'resource') {
|
|
331
|
+
return (hasFinancialDataflowExactFieldsV1(value, ['kind', 'resourceIds']) &&
|
|
332
|
+
isFinancialDataflowSortedUniqueStringsV1(value.resourceIds, FINANCIAL_DATAFLOW_LIMITS_V1.maximumMembers) &&
|
|
333
|
+
value.resourceIds.length === 1);
|
|
334
|
+
}
|
|
335
|
+
if (value.kind === 'resource-group') {
|
|
336
|
+
return (hasFinancialDataflowExactFieldsV1(value, ['kind', 'resourceGroupIds']) &&
|
|
337
|
+
isFinancialDataflowSortedUniqueStringsV1(value.resourceGroupIds, FINANCIAL_DATAFLOW_LIMITS_V1.maximumMembers) &&
|
|
338
|
+
value.resourceGroupIds.length === 1);
|
|
339
|
+
}
|
|
340
|
+
if (value.kind === 'subscription' || value.kind === 'multi-subscription') {
|
|
341
|
+
return (hasFinancialDataflowExactFieldsV1(value, ['kind', 'subscriptionIds']) &&
|
|
342
|
+
isFinancialDataflowSortedUniqueStringsV1(value.subscriptionIds, FINANCIAL_DATAFLOW_LIMITS_V1.maximumProviderAccounts) &&
|
|
343
|
+
value.subscriptionIds.length > 0 &&
|
|
344
|
+
(value.kind !== 'subscription' || value.subscriptionIds.length === 1));
|
|
345
|
+
}
|
|
346
|
+
if (!hasFinancialDataflowExactFieldsV1(value, ['kind', 'tags', 'tagMatch']) ||
|
|
347
|
+
(value.tagMatch !== 'any' && value.tagMatch !== 'all') ||
|
|
348
|
+
!Array.isArray(value.tags) ||
|
|
349
|
+
value.tags.length === 0 ||
|
|
350
|
+
value.tags.length > 256) {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
const keys = value.tags.map(tag => {
|
|
354
|
+
if (!isFinancialDataflowRecordV1(tag) ||
|
|
355
|
+
!hasFinancialDataflowExactFieldsV1(tag, ['key', 'value']) ||
|
|
356
|
+
!isFinancialDataflowIdentityV1(tag.key) ||
|
|
357
|
+
!isFinancialDataflowIdentityV1(tag.value)) {
|
|
358
|
+
return undefined;
|
|
359
|
+
}
|
|
360
|
+
return `${tag.key}\u0000${tag.value}`;
|
|
361
|
+
});
|
|
362
|
+
return keys.every((key) => key !== undefined) && keys.every((key, index) => index === 0 || keys[index - 1] < key);
|
|
363
|
+
};
|
|
313
364
|
export const isFinancialDataflowCoordinateV1 = (value) => {
|
|
314
365
|
if (!isFinancialDataflowRecordV1(value) ||
|
|
315
|
-
!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']) ||
|
|
316
378
|
!isFinancialDataflowIdentityV1(value.companyId) ||
|
|
317
379
|
value.provider !== 'azure' ||
|
|
318
380
|
!isFinancialDataflowSortedUniqueStringsV1(value.providerAccountRefs, FINANCIAL_DATAFLOW_LIMITS_V1.maximumProviderAccounts) ||
|
|
@@ -320,13 +382,18 @@ export const isFinancialDataflowCoordinateV1 = (value) => {
|
|
|
320
382
|
!isFinancialDataflowScopeV1(value.scope) ||
|
|
321
383
|
typeof value.periodRole !== 'string' ||
|
|
322
384
|
!PERIOD_ROLES.has(value.periodRole) ||
|
|
323
|
-
!
|
|
385
|
+
!isFinancialDataflowPeriodV1(value.period) ||
|
|
324
386
|
typeof value.costBasis !== 'string' ||
|
|
325
387
|
!COST_BASES.has(value.costBasis) ||
|
|
326
388
|
typeof value.estimateLens !== 'string' ||
|
|
327
389
|
!ESTIMATE_LENSES.has(value.estimateLens) ||
|
|
328
390
|
(value.requestedCurrencyCode !== undefined && !isFinancialDataflowCurrencyV1(value.requestedCurrencyCode)) ||
|
|
329
|
-
!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) {
|
|
330
397
|
return false;
|
|
331
398
|
}
|
|
332
399
|
if (value.accountingCurrency.status === 'resolved') {
|
|
@@ -354,7 +421,9 @@ const isMember = (value) => {
|
|
|
354
421
|
if (!isFinancialDataflowRecordV1(value) || !isFinancialDataflowIdentityV1(value.memberScopeId))
|
|
355
422
|
return false;
|
|
356
423
|
if (value.status === 'included') {
|
|
357
|
-
return hasFinancialDataflowExactFieldsV1(value, ['memberScopeId', 'baselineId', 'status']) &&
|
|
424
|
+
return (hasFinancialDataflowExactFieldsV1(value, ['memberScopeId', 'baselineId', 'chargeCompositionId', 'status']) &&
|
|
425
|
+
isFinancialDataflowHashV1(value.baselineId) &&
|
|
426
|
+
isFinancialDataflowHashV1(value.chargeCompositionId));
|
|
358
427
|
}
|
|
359
428
|
return (value.status === 'unavailable' &&
|
|
360
429
|
hasFinancialDataflowExactFieldsV1(value, ['memberScopeId', 'status', 'reasonCode']) &&
|
|
@@ -372,15 +441,7 @@ export const canonicalizeCurrentSpendMembershipV1 = (members) => {
|
|
|
372
441
|
export const createCurrentSpendMembershipDigestV1 = (members) => `sha256:${sha256Utf8(canonicalizeCurrentSpendMembershipV1(members))}`;
|
|
373
442
|
const isCompositionIdentity = (value) => {
|
|
374
443
|
if (!isFinancialDataflowRecordV1(value) ||
|
|
375
|
-
!hasFinancialDataflowExactFieldsV1(value, [
|
|
376
|
-
'schemaVersion',
|
|
377
|
-
'contractVersion',
|
|
378
|
-
'coordinate',
|
|
379
|
-
'members',
|
|
380
|
-
'amount',
|
|
381
|
-
'membershipDigest',
|
|
382
|
-
'algorithmVersion',
|
|
383
|
-
]) ||
|
|
444
|
+
!hasFinancialDataflowExactFieldsV1(value, ['schemaVersion', 'contractVersion', 'coordinate', 'members', 'amount', 'membershipDigest', 'algorithmVersion'], ['chargeSelection']) ||
|
|
384
445
|
value.schemaVersion !== FINANCIAL_DATAFLOW_SCHEMA_VERSION_V1 ||
|
|
385
446
|
value.contractVersion !== FINANCIAL_CURRENT_SPEND_COMPOSITION_CONTRACT_VERSION_V1 ||
|
|
386
447
|
!isFinancialDataflowCoordinateV1(value.coordinate) ||
|
|
@@ -396,11 +457,45 @@ const isCompositionIdentity = (value) => {
|
|
|
396
457
|
return false;
|
|
397
458
|
}
|
|
398
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
|
+
};
|
|
399
490
|
if (value.amount.status === 'available') {
|
|
400
491
|
return (currency !== undefined &&
|
|
401
492
|
hasFinancialDataflowExactFieldsV1(value.amount, ['status', 'amount', 'currencyCode']) &&
|
|
402
493
|
isCanonicalExactMoney({ amount: value.amount.amount, currencyCode: value.amount.currencyCode }) &&
|
|
403
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 &&
|
|
404
499
|
value.members.length > 0 &&
|
|
405
500
|
value.members.every(member => member.status === 'included'));
|
|
406
501
|
}
|
|
@@ -410,11 +505,17 @@ const isCompositionIdentity = (value) => {
|
|
|
410
505
|
isCanonicalExactMoney({ amount: value.amount.knownAmount, currencyCode: value.amount.currencyCode }) &&
|
|
411
506
|
value.amount.currencyCode === currency &&
|
|
412
507
|
isReasonCodes(value.amount.reasonCodes) &&
|
|
508
|
+
isChargeSelection(value.chargeSelection) &&
|
|
509
|
+
value.chargeSelection.currencyCode === currency &&
|
|
510
|
+
value.chargeSelection.includedAmount === value.amount.knownAmount &&
|
|
413
511
|
value.members.some(member => member.status === 'included') &&
|
|
414
|
-
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'));
|
|
415
515
|
}
|
|
416
516
|
const unresolvedCurrency = value.coordinate.accountingCurrency;
|
|
417
517
|
return (value.amount.status === 'unavailable' &&
|
|
518
|
+
value.chargeSelection === undefined &&
|
|
418
519
|
hasFinancialDataflowExactFieldsV1(value.amount, ['status', 'reasonCodes']) &&
|
|
419
520
|
isReasonCodes(value.amount.reasonCodes) &&
|
|
420
521
|
(currency !== undefined || (unresolvedCurrency.status === 'unresolved' && value.amount.reasonCodes.includes(unresolvedCurrency.reasonCode))));
|
|
@@ -431,6 +532,19 @@ export const canonicalizeCurrentSpendCompositionIdentityV1 = (value) => {
|
|
|
431
532
|
},
|
|
432
533
|
members: [...value.members].sort((left, right) => left.memberScopeId.localeCompare(right.memberScopeId)),
|
|
433
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
|
+
}),
|
|
434
548
|
};
|
|
435
549
|
return canonicalizeFinancialDataflowJsonV1(canonical);
|
|
436
550
|
};
|
|
@@ -447,7 +561,7 @@ export const isCurrentSpendCompositionV1 = (value) => {
|
|
|
447
561
|
'amount',
|
|
448
562
|
'membershipDigest',
|
|
449
563
|
'algorithmVersion',
|
|
450
|
-
])) {
|
|
564
|
+
], ['chargeSelection'])) {
|
|
451
565
|
return false;
|
|
452
566
|
}
|
|
453
567
|
const { compositionId, ...identity } = value;
|
|
@@ -462,62 +576,118 @@ const hasCompatibleBaselineCoordinate = (coordinate, baseline) => baseline.provi
|
|
|
462
576
|
toCanonicalEstimateLensV1(baseline.estimateLens) === coordinate.estimateLens &&
|
|
463
577
|
baseline.requestedCurrencyCode === coordinate.requestedCurrencyCode;
|
|
464
578
|
/** Proves that composition membership and money reconcile to exact V2 baseline envelopes. */
|
|
465
|
-
export const isCurrentSpendCompositionCompatibleV1 = (composition, baselines) => {
|
|
579
|
+
export const isCurrentSpendCompositionCompatibleV1 = (composition, baselines, chargeCompositions) => {
|
|
466
580
|
if (!isCurrentSpendCompositionV1(composition) ||
|
|
467
581
|
!Array.isArray(baselines) ||
|
|
468
582
|
baselines.length !== composition.members.length ||
|
|
469
583
|
baselines.length > FINANCIAL_DATAFLOW_LIMITS_V1.maximumMembers ||
|
|
470
|
-
!baselines.every(isFinancialScopeBaselineEnvelopeV2)
|
|
584
|
+
!baselines.every(isFinancialScopeBaselineEnvelopeV2) ||
|
|
585
|
+
!Array.isArray(chargeCompositions) ||
|
|
586
|
+
!chargeCompositions.every(isFinancialChargeCompositionV1)) {
|
|
471
587
|
return false;
|
|
472
588
|
}
|
|
473
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;
|
|
474
594
|
const baselineByScopeId = new Map(typedBaselines.map(baseline => [baseline.scopeId, baseline]));
|
|
475
595
|
if (baselineByScopeId.size !== typedBaselines.length ||
|
|
476
596
|
new Set(typedBaselines.filter(baseline => baseline.status === 'available').map(baseline => baseline.baselineId)).size !==
|
|
477
597
|
typedBaselines.filter(baseline => baseline.status === 'available').length) {
|
|
478
598
|
return false;
|
|
479
599
|
}
|
|
480
|
-
const
|
|
600
|
+
const includedSelections = [];
|
|
481
601
|
const expectedReasonCodes = new Set();
|
|
482
602
|
for (const member of composition.members) {
|
|
483
603
|
const baseline = baselineByScopeId.get(member.memberScopeId);
|
|
484
604
|
if (baseline === undefined || !hasCompatibleBaselineCoordinate(composition.coordinate, baseline))
|
|
485
605
|
return false;
|
|
486
606
|
if (member.status === 'included') {
|
|
487
|
-
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)
|
|
488
623
|
return false;
|
|
489
624
|
if (composition.coordinate.accountingCurrency.status === 'resolved' &&
|
|
490
625
|
baseline.total.currencyCode !== composition.coordinate.accountingCurrency.currencyCode) {
|
|
491
626
|
return false;
|
|
492
627
|
}
|
|
493
|
-
|
|
628
|
+
includedSelections.push(selectFinancialChargesV1(chargeComposition, composition.coordinate.chargeInclusionPolicyRef));
|
|
629
|
+
includedSelections[includedSelections.length - 1].reasonCodes?.forEach(reason => expectedReasonCodes.add(reason));
|
|
630
|
+
if (baseline.status === 'available' && !isCompleteFinancialBaselinePeriodV2(baseline.period)) {
|
|
631
|
+
expectedReasonCodes.add('coverage-incomplete');
|
|
632
|
+
}
|
|
494
633
|
continue;
|
|
495
634
|
}
|
|
496
|
-
if (baseline.status
|
|
497
|
-
|
|
498
|
-
|
|
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
|
+
}
|
|
499
648
|
}
|
|
500
649
|
if (composition.coordinate.accountingCurrency.status === 'unresolved') {
|
|
501
650
|
expectedReasonCodes.add(composition.coordinate.accountingCurrency.reasonCode);
|
|
502
651
|
}
|
|
652
|
+
if (typedChargeCompositions.length !== includedSelections.length)
|
|
653
|
+
return false;
|
|
503
654
|
const hasExpectedReasonCodes = (reasonCodes) => reasonCodes.length === expectedReasonCodes.size && reasonCodes.every(reasonCode => expectedReasonCodes.has(reasonCode));
|
|
504
655
|
if (composition.coordinate.accountingCurrency.status === 'unresolved') {
|
|
505
656
|
return composition.amount.status === 'unavailable' && hasExpectedReasonCodes(composition.amount.reasonCodes);
|
|
506
657
|
}
|
|
507
|
-
if (
|
|
658
|
+
if (includedSelections.length === 0) {
|
|
508
659
|
return composition.amount.status === 'unavailable' && hasExpectedReasonCodes(composition.amount.reasonCodes);
|
|
509
660
|
}
|
|
510
|
-
let
|
|
661
|
+
let aggregateSelection;
|
|
511
662
|
try {
|
|
512
|
-
|
|
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
|
+
};
|
|
513
680
|
}
|
|
514
681
|
catch {
|
|
515
682
|
return false;
|
|
516
683
|
}
|
|
517
|
-
|
|
518
|
-
|
|
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;
|
|
519
689
|
}
|
|
520
690
|
return (composition.amount.status === 'partial' &&
|
|
521
|
-
composition.amount.knownAmount ===
|
|
691
|
+
composition.amount.knownAmount === aggregateSelection.includedAmount &&
|
|
522
692
|
hasExpectedReasonCodes(composition.amount.reasonCodes));
|
|
523
693
|
};
|
|
@@ -12,6 +12,13 @@ const EVIDENCE_ROLES = new Set([
|
|
|
12
12
|
'retail-rate',
|
|
13
13
|
'commitment-quote',
|
|
14
14
|
'fx-conversion',
|
|
15
|
+
'commercial-arrangement',
|
|
16
|
+
'provider-access-observation',
|
|
17
|
+
'configuration-timeline',
|
|
18
|
+
'provider-price-schedule',
|
|
19
|
+
'pricing-function',
|
|
20
|
+
'charge-inclusion-policy',
|
|
21
|
+
'settlement-revision',
|
|
15
22
|
'eligibility-rule',
|
|
16
23
|
'recommendation-scenario-set',
|
|
17
24
|
'recommendation-lifecycle',
|
|
@@ -1,2 +1,6 @@
|
|
|
1
1
|
export const FINANCIAL_POLICY_READ_PROJECTION_CONTRACT_VERSION_V1 = 'financial-policy-read-projection/v1';
|
|
2
2
|
export const FINANCIAL_POLICY_ACTION_ATTEMPT_CONTRACT_VERSION_V1 = 'financial-policy-action-attempt/v1';
|
|
3
|
+
export const FINANCIAL_POLICY_DEFINITION_COMMAND_CONTRACT_VERSION_V1 = 'financial-policy-definition-command/v1';
|
|
4
|
+
export const FINANCIAL_POLICY_READ_CURRENT_POINTER_CONTRACT_VERSION_V1 = 'financial-policy-read-current-pointer/v1';
|
|
5
|
+
export const FINANCIAL_POLICY_ACTION_COMPLETION_CONTRACT_VERSION_V1 = 'financial-policy-action-completion/v1';
|
|
6
|
+
export const FINANCIAL_POLICY_READ_MANIFEST_CONTRACT_VERSION_V1 = 'financial-policy-read-manifest/v1';
|