diff --git a/docs-mslearn/toolkit/changelog.md b/docs-mslearn/toolkit/changelog.md index e168935bc..fba31eafb 100644 --- a/docs-mslearn/toolkit/changelog.md +++ b/docs-mslearn/toolkit/changelog.md @@ -83,6 +83,13 @@ _Released June 2026_ ### [Power BI reports](power-bi/reports.md) v15 +- **Added** + - Added the new FOCUS 1.3 and 1.4 columns to the Costs table in KQL and storage reports: `AllocatedMethodDetails`, `AllocatedMethodId`, `AllocatedResourceId`, `AllocatedResourceName`, `AllocatedTags`, `CommitmentProgramEligibilityDetails`, `ContractApplied`, the 12 `ContractCommitment*` columns, `HostProviderName`, `InvoiceDetailId`, and `ServiceProviderName` ([#2120](https://github.com/microsoft/finops-toolkit/issues/2120)). +- **Changed** + - Updated KQL reports to use the FinOps hubs `v1_4` schema (`Costs_v1_4()` and `Recommendations_v1_4()`) for FOCUS 1.4 ([#2120](https://github.com/microsoft/finops-toolkit/issues/2120)). + - Updated storage reports to align FOCUS 1.0-1.4 exports to the FOCUS 1.4 schema and to detect FOCUS 1.4 data when identifying the source version. +- **Deprecated** + - Deprecated the `ProviderName` and `PublisherName` columns in the Costs table. Both columns are retained for backward compatibility and are populated from the FOCUS 1.3 replacements, `HostProviderName` and `ServiceProviderName`, when not available in the source data. - **Fixed** - Fixed Power BI storage report refresh errors caused by ISO 8601 duration `x_SkuTerm` values (like `P3Y`) and empty strings in cost exports ([#2174](https://github.com/microsoft/finops-toolkit/issues/2174)). diff --git a/docs-mslearn/toolkit/hubs/compatibility.md b/docs-mslearn/toolkit/hubs/compatibility.md index dadbf0e04..62d47f538 100644 --- a/docs-mslearn/toolkit/hubs/compatibility.md +++ b/docs-mslearn/toolkit/hubs/compatibility.md @@ -3,7 +3,7 @@ title: Compatibility guide description: Learn which Power BI report versions are compatible with each FinOps hubs version to ensure seamless upgrades and data integrity. author: flanakin ms.author: micflan -ms.date: 04/01/2026 +ms.date: 07/16/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit @@ -33,7 +33,8 @@ The Power BI version refers to the Power BI reports made available within that s | Cost Management exports | FinOps hubs | Storage path | Power BI | Notes | | ----------------------------------------- | ----------- | ---------------------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | -| FOCUS costs, prices, reservation datasets | 12+ | {dataset}/{yyyy}/{MM}/{scope} | 12+² | KQL reports use the FinOps hubs v1_2 schema for FOCUS 1.2 | +| FOCUS costs, prices, reservation datasets | 15+ | {dataset}/{yyyy}/{MM}/{scope} | 15+² | KQL reports use the FinOps hubs v1_4 schema for FOCUS 1.4 | +| FOCUS costs, prices, reservation datasets | 12+ | {dataset}/{yyyy}/{MM}/{scope} | 12-14² | KQL reports use the FinOps hubs v1_2 schema for FOCUS 1.2 | | FOCUS costs, prices, reservation datasets | 0.8+ | {dataset}/{yyyy}/{MM}/{scope} | 0.7-0.11² | | | FOCUS costs, prices, reservation datasets | 0.7 | {dataset}/{yyyy}/{MM}/{scope}¹ | 0.7+² | Storage path updated to new dataset names that support joining multiple related datasets together | | FOCUS costs, prices, reservation datasets | 0.6 | {export-type}/{yyyy}/{MM}/{scope} | 0.6+ | Reservation recommendations pulled from hub storage | diff --git a/src/power-bi/kql/Shared.Dataset/definition/tables/Costs.tmdl b/src/power-bi/kql/Shared.Dataset/definition/tables/Costs.tmdl index cb665ee6f..893bea1bf 100644 --- a/src/power-bi/kql/Shared.Dataset/definition/tables/Costs.tmdl +++ b/src/power-bi/kql/Shared.Dataset/definition/tables/Costs.tmdl @@ -1848,6 +1848,210 @@ table Costs annotation SummarizationSetBy = Automatic + column AllocatedMethodDetails + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: 55113e62-acbf-4acb-b0e1-41854cefeadc + summarizeBy: none + sourceColumn: AllocatedMethodDetails + + annotation SummarizationSetBy = Automatic + + column AllocatedMethodId + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: 8256f9c9-1499-49ff-9d84-e528dc8dd3b5 + summarizeBy: none + sourceColumn: AllocatedMethodId + + annotation SummarizationSetBy = Automatic + + column AllocatedResourceId + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: ce5ffa08-514d-41c4-b3f9-ad22054d5b6e + summarizeBy: none + sourceColumn: AllocatedResourceId + + annotation SummarizationSetBy = Automatic + + column AllocatedResourceName + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: 505ecaae-5603-46a4-9c7d-c2a93f84350f + summarizeBy: none + sourceColumn: AllocatedResourceName + + annotation SummarizationSetBy = Automatic + + column AllocatedTags + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: 0c09f14d-e1b7-48a3-a51d-dbe9c65c7a4e + summarizeBy: none + sourceColumn: AllocatedTags + + annotation SummarizationSetBy = Automatic + + column CommitmentProgramEligibilityDetails + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: e0a419cd-689a-4667-96e7-848817cf3140 + summarizeBy: none + sourceColumn: CommitmentProgramEligibilityDetails + + annotation SummarizationSetBy = Automatic + + column ContractApplied + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: 8e7d2334-99f6-4b4f-8683-2c3c9a535719 + summarizeBy: none + sourceColumn: ContractApplied + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentBenefitCategory + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: c1b085bd-8b41-4947-adf8-3f7b295f7b02 + summarizeBy: none + sourceColumn: ContractCommitmentBenefitCategory + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentCreated + dataType: dateTime + formatString: General Date + sourceProviderType: datetimeoffset + lineageTag: b881035d-76ff-43bc-83ab-72f7c9ff9912 + summarizeBy: none + sourceColumn: ContractCommitmentCreated + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentDiscountPercentage + dataType: double + sourceProviderType: decimal + lineageTag: 3acab673-4552-4996-aa7e-8b04a05f8ea3 + summarizeBy: none + sourceColumn: ContractCommitmentDiscountPercentage + + annotation SummarizationSetBy = Automatic + + annotation PBI_FormatHint = {"isGeneralNumber":true} + + column ContractCommitmentDurationType + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: 495b8505-e715-47fc-a27e-4834d2a1e3f6 + summarizeBy: none + sourceColumn: ContractCommitmentDurationType + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentFulfillmentInterval + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: 0b54f930-ae2b-4efd-8422-fa6e56971946 + summarizeBy: none + sourceColumn: ContractCommitmentFulfillmentInterval + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentLastUpdated + dataType: dateTime + formatString: General Date + sourceProviderType: datetimeoffset + lineageTag: 58258b25-f8e3-45f8-862d-86e433720454 + summarizeBy: none + sourceColumn: ContractCommitmentLastUpdated + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentLifecycleStatus + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: b09906a8-b301-4cdb-920a-dd91fcb40e1b + summarizeBy: none + sourceColumn: ContractCommitmentLifecycleStatus + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentModel + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: f79edd03-14c9-4a89-a877-fe9bcf3e6c8a + summarizeBy: none + sourceColumn: ContractCommitmentModel + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentOfferCategory + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: d2bc0b21-e86c-4ff2-9085-bb4fdd816e6b + summarizeBy: none + sourceColumn: ContractCommitmentOfferCategory + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentPaymentInterval + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: 4e174c85-2d67-4a8a-a8fb-63b1bdd9de4b + summarizeBy: none + sourceColumn: ContractCommitmentPaymentInterval + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentPaymentModel + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: 9ec28b52-c4c7-499e-abc8-62254bd7a94d + summarizeBy: none + sourceColumn: ContractCommitmentPaymentModel + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentPaymentUpfrontPercentage + dataType: double + sourceProviderType: decimal + lineageTag: a7a0be0e-0f44-4c34-b313-0ae2a2e692a0 + summarizeBy: none + sourceColumn: ContractCommitmentPaymentUpfrontPercentage + + annotation SummarizationSetBy = Automatic + + annotation PBI_FormatHint = {"isGeneralNumber":true} + + column HostProviderName + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: 5b7f174f-09d5-4c7b-9f51-4486012cf9d3 + summarizeBy: none + sourceColumn: HostProviderName + + annotation SummarizationSetBy = Automatic + + column InvoiceDetailId + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: f338213d-a52c-4fbd-8865-8f9e2ced5907 + summarizeBy: none + sourceColumn: InvoiceDetailId + + annotation SummarizationSetBy = Automatic + + column ServiceProviderName + dataType: string + sourceProviderType: nvarchar(max) + lineageTag: d3d89090-75d9-4695-9df3-1758ab163a73 + summarizeBy: none + sourceColumn: ServiceProviderName + + annotation SummarizationSetBy = Automatic + hierarchy 'Service Hierarchy' lineageTag: 039a7b6d-f19d-4a79-91b3-a05fbc778704 @@ -1886,7 +2090,11 @@ table Costs Source = AzureDataExplorer.Contents(#"Cluster URL", "Hub", " - Costs_v1_2 + Costs_v1_4 + // + // Deprecated columns -- Removed from FOCUS in 1.3; retained for backward compatibility with existing visuals and custom reports + | extend ProviderName = HostProviderName + | extend PublisherName = ServiceProviderName // // Apply summarization settings | where ChargePeriodStart >= monthsago(" & lookback & ") @@ -1952,6 +2160,10 @@ table Costs ) ) else "") & " // + | extend AllocatedMethodDetails = tostring(AllocatedMethodDetails) + | extend AllocatedTags = tostring(AllocatedTags) + | extend CommitmentProgramEligibilityDetails = tostring(CommitmentProgramEligibilityDetails) + | extend ContractApplied = tostring(ContractApplied) | extend SkuPriceDetails = tostring(SkuPriceDetails) | extend Tags = tostring(Tags) | extend x_SkuDetails = tostring(x_SkuDetails) diff --git a/src/power-bi/kql/Shared.Dataset/definition/tables/ReservationRecommendations.tmdl b/src/power-bi/kql/Shared.Dataset/definition/tables/ReservationRecommendations.tmdl index 9cdde158b..ba836269c 100644 --- a/src/power-bi/kql/Shared.Dataset/definition/tables/ReservationRecommendations.tmdl +++ b/src/power-bi/kql/Shared.Dataset/definition/tables/ReservationRecommendations.tmdl @@ -226,7 +226,7 @@ table ReservationRecommendations let Source = AzureDataExplorer.Contents(#"Cluster URL", "Hub", " - Recommendations_v1_2 + Recommendations_v1_4 | where x_SourceProvider == 'Microsoft' and x_SourceType == 'ReservationRecommendations' | extend RegionId = tostring(x_RecommendationDetails.RegionId) | extend RegionName = tostring(x_RecommendationDetails.RegionName) diff --git a/src/power-bi/storage/Shared.Dataset/definition/expressions.tmdl b/src/power-bi/storage/Shared.Dataset/definition/expressions.tmdl index 69c6f549c..d071fabce 100644 --- a/src/power-bi/storage/Shared.Dataset/definition/expressions.tmdl +++ b/src/power-bi/storage/Shared.Dataset/definition/expressions.tmdl @@ -326,7 +326,11 @@ expression ftk_Storage = ``` "x_SourceType", each data), "x_SourceVersion", // TODO: Extract from the manifest - each if data = "focuscost" then (if Table.HasColumns(FilterRowsByDate, {"ChargeSubcategory"}) and [ChargeSubcategory] <> null then "1.0-preview(v1)" else "1.0") + each if data = "focuscost" then ( + if Table.HasColumns(FilterRowsByDate, {"ServiceProviderName"}) and [ServiceProviderName] <> null then "1.4" + else if Table.HasColumns(FilterRowsByDate, {"ChargeSubcategory"}) and [ChargeSubcategory] <> null then "1.0-preview(v1)" + else if Table.HasColumns(FilterRowsByDate, {"InvoiceId"}) and [InvoiceId] <> null then "1.2" + else "1.0") else if data = "pricesheet" then "2023-05-01" else if data = "reservationdetails" then "2023-03-01" else if data = "reservationtransactions" then "2023-05-01" diff --git a/src/power-bi/storage/Shared.Dataset/definition/tables/Costs.tmdl b/src/power-bi/storage/Shared.Dataset/definition/tables/Costs.tmdl index 75880048f..35f1c099e 100644 --- a/src/power-bi/storage/Shared.Dataset/definition/tables/Costs.tmdl +++ b/src/power-bi/storage/Shared.Dataset/definition/tables/Costs.tmdl @@ -1390,6 +1390,188 @@ table Costs annotation SummarizationSetBy = Automatic + column AllocatedMethodDetails + dataType: string + lineageTag: 9402c4c8-c505-464e-931e-751668d3ba83 + summarizeBy: none + sourceColumn: AllocatedMethodDetails + + annotation SummarizationSetBy = Automatic + + column AllocatedMethodId + dataType: string + lineageTag: 26e34a2c-3d0d-47cf-a116-4c861bc62286 + summarizeBy: none + sourceColumn: AllocatedMethodId + + annotation SummarizationSetBy = Automatic + + column AllocatedResourceId + dataType: string + lineageTag: 55d64b52-5560-47f1-9f2b-eb5a04ae0a2e + summarizeBy: none + sourceColumn: AllocatedResourceId + + annotation SummarizationSetBy = Automatic + + column AllocatedResourceName + dataType: string + lineageTag: c9863af0-538a-44cd-b03f-53a4004b9a4e + summarizeBy: none + sourceColumn: AllocatedResourceName + + annotation SummarizationSetBy = Automatic + + column AllocatedTags + dataType: string + lineageTag: 1e7ec40d-2d57-4c62-ab98-a4c9eb577ada + summarizeBy: none + sourceColumn: AllocatedTags + + annotation SummarizationSetBy = Automatic + + column CommitmentProgramEligibilityDetails + dataType: string + lineageTag: 52986e67-2e71-4413-bca2-1e37333d5908 + summarizeBy: none + sourceColumn: CommitmentProgramEligibilityDetails + + annotation SummarizationSetBy = Automatic + + column ContractApplied + dataType: string + lineageTag: f12cd4d2-2ede-4553-9814-57fa0757112c + summarizeBy: none + sourceColumn: ContractApplied + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentBenefitCategory + dataType: string + lineageTag: ae3d4177-9814-4879-9bb7-9c84f0b127d2 + summarizeBy: none + sourceColumn: ContractCommitmentBenefitCategory + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentCreated + dataType: dateTime + formatString: General Date + lineageTag: 6aaa2b8d-7950-4b5f-8e7d-fdbff15a60e2 + summarizeBy: none + sourceColumn: ContractCommitmentCreated + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentDiscountPercentage + dataType: double + lineageTag: 251a216b-4954-4f84-a972-2c9bd9593573 + summarizeBy: none + sourceColumn: ContractCommitmentDiscountPercentage + + annotation SummarizationSetBy = Automatic + + annotation PBI_FormatHint = {"isGeneralNumber":true} + + column ContractCommitmentDurationType + dataType: string + lineageTag: f246de01-ff20-4373-b3b5-58e8c6705543 + summarizeBy: none + sourceColumn: ContractCommitmentDurationType + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentFulfillmentInterval + dataType: string + lineageTag: 08022da8-18a2-4d1a-884f-a03615f90b29 + summarizeBy: none + sourceColumn: ContractCommitmentFulfillmentInterval + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentLastUpdated + dataType: dateTime + formatString: General Date + lineageTag: ed6b0f99-e25f-4861-885f-b1becb81e17d + summarizeBy: none + sourceColumn: ContractCommitmentLastUpdated + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentLifecycleStatus + dataType: string + lineageTag: 1abe7929-75b4-4ccd-abdc-7980ea71132a + summarizeBy: none + sourceColumn: ContractCommitmentLifecycleStatus + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentModel + dataType: string + lineageTag: abb04100-9b6a-491f-90af-9a4d06b760e0 + summarizeBy: none + sourceColumn: ContractCommitmentModel + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentOfferCategory + dataType: string + lineageTag: 94666530-e96d-47b0-8af0-6472b3f97e2b + summarizeBy: none + sourceColumn: ContractCommitmentOfferCategory + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentPaymentInterval + dataType: string + lineageTag: 5850c014-27a3-4b6f-8499-4263ac860da4 + summarizeBy: none + sourceColumn: ContractCommitmentPaymentInterval + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentPaymentModel + dataType: string + lineageTag: 0f9d97a4-b773-47b8-8190-b25d9c4545c8 + summarizeBy: none + sourceColumn: ContractCommitmentPaymentModel + + annotation SummarizationSetBy = Automatic + + column ContractCommitmentPaymentUpfrontPercentage + dataType: double + lineageTag: 0e58352c-4239-4152-9e5d-4296d4fc3e1c + summarizeBy: none + sourceColumn: ContractCommitmentPaymentUpfrontPercentage + + annotation SummarizationSetBy = Automatic + + annotation PBI_FormatHint = {"isGeneralNumber":true} + + column HostProviderName + dataType: string + lineageTag: 4ed42b42-c9bc-4566-b586-50b914d500d6 + summarizeBy: none + sourceColumn: HostProviderName + + annotation SummarizationSetBy = Automatic + + column InvoiceDetailId + dataType: string + lineageTag: 5d3f426f-21d9-4e8b-bd21-187dc5f16dbb + summarizeBy: none + sourceColumn: InvoiceDetailId + + annotation SummarizationSetBy = Automatic + + column ServiceProviderName + dataType: string + lineageTag: 357cda7a-59a0-4992-aa90-39422f7a6764 + summarizeBy: none + sourceColumn: ServiceProviderName + + annotation SummarizationSetBy = Automatic + hierarchy 'Service Hierarchy' lineageTag: 039a7b6d-f19d-4a79-91b3-a05fbc778704 @@ -1432,6 +1614,7 @@ table Costs HasPreview = Table.HasColumns(RawData, {"ChargeSubcategory"}), Has10 = Table.HasColumns(RawData, {"ChargeClass"}), Has12 = Table.HasColumns(RawData, {"InvoiceId"}), + Has14 = Table.HasColumns(RawData, {"ServiceProviderName"}), HandlePeview = if HasPreview = false then RawData else if PerformDeprecatedOptimizations = false then error "LegacyFocusVersion: Please enable the 'Perform Extra Query Optimizations' parameter" else ( @@ -1477,11 +1660,26 @@ table Costs null, each [PricingCurrency], Replacer.ReplaceValue, {"x_PricingCurrency"}), null, each [SkuMeter], Replacer.ReplaceValue, {"x_SkuMeterName"}), + // Handle columns added in FOCUS 1.3/1.4 gracefully -- Create missing columns so all FOCUS versions expose the same schema + Ensure14Cols = List.Accumulate( + {"AllocatedMethodDetails", "AllocatedMethodId", "AllocatedResourceId", "AllocatedResourceName", "AllocatedTags", "CommitmentProgramEligibilityDetails", "ContractApplied", "ContractCommitmentBenefitCategory", "ContractCommitmentCreated", "ContractCommitmentDiscountPercentage", "ContractCommitmentDurationType", "ContractCommitmentFulfillmentInterval", "ContractCommitmentLastUpdated", "ContractCommitmentLifecycleStatus", "ContractCommitmentModel", "ContractCommitmentOfferCategory", "ContractCommitmentPaymentInterval", "ContractCommitmentPaymentModel", "ContractCommitmentPaymentUpfrontPercentage", "HostProviderName", "InvoiceDetailId", "ServiceProviderName", "ProviderName", "PublisherName"}, + Align12, + (t, col) => if Table.HasColumns(t, col) then t else Table.AddColumn(t, col, each null) + ), + // Backfill the FOCUS 1.3 provider columns from the deprecated ProviderName/PublisherName columns (removed in FOCUS 1.3) for older data + AlignNewProviders = Table.ReplaceValue(Table.ReplaceValue(Ensure14Cols, + null, each [ProviderName], Replacer.ReplaceValue, {"HostProviderName"}), + null, each if [PublisherName] <> null then [PublisherName] else [ProviderName], Replacer.ReplaceValue, {"ServiceProviderName"}), + // Backfill the deprecated ProviderName/PublisherName columns from the FOCUS 1.3 replacements for backward compatibility + Align14 = if Has14 = false then AlignNewProviders else Table.ReplaceValue(Table.ReplaceValue(AlignNewProviders, + null, each [HostProviderName], Replacer.ReplaceValue, {"ProviderName"}), + null, each [ServiceProviderName], Replacer.ReplaceValue, {"PublisherName"}), + // Fix known bugs and set data types Fixes = Table.TransformColumnTypes( Table.ReplaceValue(Table.ReplaceValue( // Create AvailabilityZone column if missing to support non-Microsoft clouds - if Table.HasColumns(Align12, {"AvailabilityZone"}) then Align12 else Table.AddColumn(Align12, "AvailabilityZone", each null), + if Table.HasColumns(Align14, {"AvailabilityZone"}) then Align14 else Table.AddColumn(Align14, "AvailabilityZone", each null), // Fix savings plan purchases -- Cost Management fix pending as of Dec 8, 2024 each [EffectiveCost], each if [ChargeCategory] = "Purchase" and [CommitmentDiscountId] <> "" and [CommitmentDiscountId] <> null then 0.0 else [EffectiveCost], Replacer.ReplaceValue, {"EffectiveCost"}), // Fix PricingCategory values -- Remove after Oct 1, 2025 @@ -1492,6 +1690,8 @@ table Costs {"BillingPeriodStart", type datetimezone}, {"ChargePeriodEnd", type datetimezone}, {"ChargePeriodStart", type datetimezone}, + {"ContractCommitmentCreated", type datetimezone}, + {"ContractCommitmentLastUpdated", type datetimezone}, {"x_BillingExchangeRateDate", type datetimezone}, {"x_ServicePeriodStart", type datetimezone}, {"x_ServicePeriodEnd", type datetimezone}, @@ -1509,6 +1709,8 @@ table Costs {"x_EffectiveUnitPrice", type number}, // Other columns {"ConsumedQuantity", type number}, + {"ContractCommitmentDiscountPercentage", type number}, + {"ContractCommitmentPaymentUpfrontPercentage", type number}, {"PricingQuantity", type number}, {"x_BillingExchangeRate", type number}, {"x_PartnerCreditRate", type number},