Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

The Power BI DataViz World Championships are on! With four chances to enter, you could win a spot in the LIVE Grand Finale in Las Vegas. Show off your skills.

Reply
JoeHeraty
Regular Visitor

Building a Fee payment table

Hi guys, 

New here, as struggling to find what I need anywhere online.  I'mlooking for some help in building a payment schedule for up to at least 12 months in advance, so I can predict dynamiclly and accurately what fees are coming in, in certain months, periods etc.

I have 3 fact fields, the payment frequency (monthly, Quarterly, Annual), the most recent paid date, and the amount.  I want for example the month names & year in columns and the values to populate the amount in the rows of the products.  I need a code to autopopulate based off the payment frequencys and the most recent payment date. 

The min date for the columns will be min date of the last issue date.  The max will vice versa.

Hope the community can help 🙂

Something to look similar to this: 

FrequencyAmountLast Payment DateJan-25Feb-25Mar-25Apr-25May-25
Monthly5001/01/202550505050 
Monthly7505/02/2025 757575 
Quarterly10001/01/2025100  100 
Quarterly15001/02/2025 150  150
Quarterly25020/01/2025250  250 
Annual40001/01/2025400    
1 ACCEPTED SOLUTION

Here is the code adjusted to display by week. (I have weeks starting on Monday.)

let
    endYear = 2026,
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45W8s3PK8nIqVTSUTI1ABKG+ob6RgZGpkqxOshy5qZAwkjfFCEXWJpYVJJaBJY1NMDQiiINNtkIl7QR1GIjA4S8Y15eaWIOUNgEzehYAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Frequency = _t, Amount = _t, #"Last Payment Date" = _t]),
    set_types = Table.TransformColumnTypes(Source,{{"Frequency", type text}, {"Amount", Int64.Type}, {"Last Payment Date", type date}}),
    add_freq_months = Table.AddColumn(set_types, "Frequency Months", each if [Frequency] = "Monthly" then 1 else if [Frequency] = "Quarterly" then 3 else if [Frequency] = "Annual" then 12 else 0, Int64.Type),
    generate_paid_months = Table.AddColumn(add_freq_months, "Dates", each let freq = [Frequency Months], startDate = Date.StartOfMonth([Last Payment Date]), amount = [Amount] in List.Generate(()=> startDate, each _ <= #date(endYear,12,1), each Date.AddMonths(_, freq), each "Week " & Number.ToText(Date.WeekOfYear(_, Day.Monday))&"|"&Number.ToText(amount))),
    convert_list_to_table = Table.TransformColumns(generate_paid_months, {{"Dates", each Table.FromList(_, Splitter.SplitTextByDelimiter("|"), {"Date", "Amount"})}}),
    transpose_nested_tables = Table.TransformColumns(convert_list_to_table, {{"Dates", each Table.PromoteHeaders(Table.Transpose(_))}}),
    minPaymentWeek = Date.WeekOfYear(Date.StartOfMonth(List.Min(transpose_nested_tables[Last Payment Date])), Day.Monday),
    generatedDatesList = List.Generate(()=> minPaymentWeek, each _ <= Date.WeekOfYear(#date(endYear,12,1), Day.Monday), each _ + 1, each "Week " & Number.ToText(_)),
    expand_nested_tables = Table.ExpandTableColumn(transpose_nested_tables, "Dates", generatedDatesList),
    remove_freq_months = Table.RemoveColumns(expand_nested_tables,{"Frequency Months"})
in
    remove_freq_months




Did I answer your question? Mark my post as a solution!

Proud to be a Super User!





View solution in original post

9 REPLIES 9
dufoq3
Super User
Super User

Hi @JoeHeraty, I've created another query for you:

 

you can select DateType and WeekType

dufoq3_3-1737836901224.png

 

Output if you select Date = 1 (only weeks with payments)

dufoq3_0-1737836143618.png

 

Output if you select Date = 0 (full year)

dufoq3_2-1737836660849.png

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45W8s3PK8nIqVTSUTI1ABIGhvpAZGRgZKoUq4Msa24KkjXVNzBCyAaWJhaVpBaB5Q0NsGhHUQA3H4cJRmAFRgYoJjjm5ZUm5gDFTTDMjwUA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Frequency = _t, Amount = _t, #"Last Payment Date" = _t]),
    ChangedType = Table.TransformColumnTypes(Source,{{"Amount", Currency.Type}, {"Last Payment Date", type date}}, "sk-SK"),
    __Select__ = [ 
        DateType = 0,   // 0 = Full year,   1 = Use only weeks with payments
        WeekType = 0    // 1 = Ordinary,    1 = ISO
  ],
    D = [ firstDate = if (__Select__[DateType] ?? 0) = 0 then Date.StartOfYear(List.Min(ChangedType[Last Payment Date])) else List.Min(ChangedType[Last Payment Date]),
    lastDate = Date.EndOfYear(firstDate),
    weeks = Record.Combine(List.Generate(()=> firstDate, each _ <= lastDate, each Date.AddDays(_, 7), each Record.AddField([], Date.ToText(firstDate, "yyyy") & "-W" & Text.PadStart(Text.From(Date.WeekOfYear(_)), 2, "0"), null))) ],
    Fn_Week = (Data as date) =>
            let
                Weekday = Date.DayOfWeek(Data) + 1,
                Part1 = Number.From(Data) - Weekday + 11,
                Part2 = Number.From(#date(Date.Year(Date.From(Number.From(Data) + 4 - Weekday)),1,1)),
                Part3 = (Part1 - Part2) / 7,
                Tranc = Part3 - Number.Mod(Part3, 1),
                Output = Date.ToText(D[firstDate], "yyyy") & "-W" &
                                ( if __Select__[WeekType] = 1
                                  then Text.PadStart(Text.From(Tranc), 2, "0")
                                  else Text.PadStart(Text.From(Date.WeekOfYear(Data)), 2, "0")
                                )
            in
                Output,
    StepBack = ChangedType,
    Ad_Weeks = Table.AddColumn(StepBack, "Weeks", each 
        [ a = if [Frequency] = "Annual" then {Record.AddField([], Fn_Week([Last Payment Date]), [Amount])} else List.Generate(
                    ()=> D[firstDate],
                    (x)=> x <= D[lastDate],
                    (x)=> if [Frequency] = "Weekly" then Date.AddDays(x, 7) else
                            if [Frequency] = "Monthly" then Date.AddMonths(x, 1)
                            else Date.AddQuarters(x, 1),
                    (x)=> Record.AddField([], Fn_Week(x), [Amount])),
          b = _ & Record.Combine(a)
        ][b]
    , type table),
    UsedSelectedDate = [ fn = each Table.Skip(Table.Combine(List.Transform(_[Weeks], (x)=> Table.FromRecords({x})))),
    a = Table.InsertRows(Ad_Weeks, 0, { Ad_Weeks{0} & [Weeks = Record.Combine(List.Transform(List.RemoveMatchingItems(Table.ColumnNames(Ad_Weeks), {"Weeks"}), (x)=> Record.AddField([], x, null))) & D[weeks]] }),
    b = if __Select__[DateType] = 1 then fn(Ad_Weeks) else fn(a)
  ][b],
    ChangedType2 = Value.ReplaceType(
        UsedSelectedDate,
        Value.Type(Table.FirstN(ChangedType, 0) &
          [ a = List.Difference(Table.ColumnNames(UsedSelectedDate), Table.ColumnNames(ChangedType)),
            b = Table.PromoteHeaders(Table.FromRows({a})),
            c = Table.TransformColumnTypes(b, List.Transform(a, (x)=> {x, Currency.Type}))
          ][c] ))
in
    ChangedType2

 


Note: Check this link to learn how to use my query.
Check this link if you don't know how to provide sample data.

Hi dufoq, thank you very much! This is awesome!

You're welcome @JoeHeraty. Enjoy 😉


Note: Check this link to learn how to use my query.
Check this link if you don't know how to provide sample data.

v-mdharahman
Community Support
Community Support

Hi @JoeHeraty,
Thanks for reaching out to the Microsoft fabric community forum.

It looks like the issue you were having has been solved by @jgeddes. Please accept it as solution if you are satisfied with the solution.

 

If I misunderstand your needs or you still have problems on it, please feel free to let us know.
Best Regards,
Hammad.
Community Support Team

If this post helps then please mark it as a solution, so that other members find it more quickly.
Thank you.

AlienSx
Super User
Super User

let
    // fact_table is your original table
    fx_schedule = (row) => ((sequence) => Record.FromList(List.Repeat({row[Amount]}, List.Count(sequence)), sequence))
        (List.Generate(
            () => row[Last Payment Date], 
            (x) => x <= last_month, 
            (x) => Function.Invoke(Record.Field(freq, row[Frequency]), {x, 1}),
            (x) => Date.ToText(x, "MMM-yy")
        )),
    freq = [Monthly = Date.AddMonths, Quarterly = Date.AddQuarters, Annual = Date.AddYears],
    last_month = Date.AddMonths(Date.EndOfMonth(Date.From(DateTime.FixedLocalNow())), 12), 
    headers = List.Generate(
        () => List.Min(fact_table[Last Payment Date]), 
        (x) => x <= last_month, 
        (x) => Date.AddMonths(x, 1),
        (x) => Date.ToText(x, "MMM-yy")
    ),
    schedule = Table.AddColumn(fact_table, "expand_me", fx_schedule), 
    xpand = Table.ExpandRecordColumn(schedule, "expand_me", headers)
in
    xpand
jgeddes
Super User
Super User

Here is an example code that shows one way to do this.
You can change the endYear value to lengthen or shorthen the forecast period.

let
    endYear = 2026,
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45W8s3PK8nIqVTSUTI1ABKG+ob6RgZGpkqxOshy5qZAwkjfFCEXWJpYVJJaBJY1NMDQiiINNtkIl7QR1GIjA4S8Y15eaWIOUNgEzehYAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Frequency = _t, Amount = _t, #"Last Payment Date" = _t]),
    set_types = Table.TransformColumnTypes(Source,{{"Frequency", type text}, {"Amount", Int64.Type}, {"Last Payment Date", type date}}),
    add_freq_months = Table.AddColumn(set_types, "Frequency Months", each if [Frequency] = "Monthly" then 1 else if [Frequency] = "Quarterly" then 3 else if [Frequency] = "Annual" then 12 else 0, Int64.Type),
    generate_paid_months = Table.AddColumn(add_freq_months, "Dates", each let freq = [Frequency Months], startDate = Date.StartOfMonth([Last Payment Date]), amount = [Amount] in List.Generate(()=> startDate, each _ <= #date(endYear,12,1), each Date.AddMonths(_, freq), each Date.ToText(_)&"|"&Number.ToText(amount))),
    convert_list_to_table = Table.TransformColumns(generate_paid_months, {{"Dates", each Table.FromList(_, Splitter.SplitTextByDelimiter("|"), {"Date", "Amount"})}}),
    transpose_nested_tables = Table.TransformColumns(convert_list_to_table, {{"Dates", each Table.PromoteHeaders(Table.Transpose(_))}}),
    minPaymentMonth = Date.StartOfMonth(List.Min(transpose_nested_tables[Last Payment Date])),
    minFrequencyMonths = List.Min(transpose_nested_tables[Frequency Months]),
    generatedDatesList = List.Generate(()=> minPaymentMonth, each _ <= #date(endYear,12,1), each Date.AddMonths(_, 1), each Date.ToText(_)),
    expand_nested_tables = Table.ExpandTableColumn(transpose_nested_tables, "Dates", generatedDatesList),
    remove_freq_months = Table.RemoveColumns(expand_nested_tables,{"Frequency Months"})
in
    remove_freq_months

Using your example data...

jgeddes_0-1737139899548.png

You end up with...

jgeddes_1-1737139932123.png

Hope this gets you pointed in the right direction.





Did I answer your question? Mark my post as a solution!

Proud to be a Super User!





Thank you very much! This is exactly what I needed!  Where in the code could I alter to get column headers as Week Number and values to fill in the week periods, or would this need complete new code?

Here is the code adjusted to display by week. (I have weeks starting on Monday.)

let
    endYear = 2026,
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45W8s3PK8nIqVTSUTI1ABKG+ob6RgZGpkqxOshy5qZAwkjfFCEXWJpYVJJaBJY1NMDQiiINNtkIl7QR1GIjA4S8Y15eaWIOUNgEzehYAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Frequency = _t, Amount = _t, #"Last Payment Date" = _t]),
    set_types = Table.TransformColumnTypes(Source,{{"Frequency", type text}, {"Amount", Int64.Type}, {"Last Payment Date", type date}}),
    add_freq_months = Table.AddColumn(set_types, "Frequency Months", each if [Frequency] = "Monthly" then 1 else if [Frequency] = "Quarterly" then 3 else if [Frequency] = "Annual" then 12 else 0, Int64.Type),
    generate_paid_months = Table.AddColumn(add_freq_months, "Dates", each let freq = [Frequency Months], startDate = Date.StartOfMonth([Last Payment Date]), amount = [Amount] in List.Generate(()=> startDate, each _ <= #date(endYear,12,1), each Date.AddMonths(_, freq), each "Week " & Number.ToText(Date.WeekOfYear(_, Day.Monday))&"|"&Number.ToText(amount))),
    convert_list_to_table = Table.TransformColumns(generate_paid_months, {{"Dates", each Table.FromList(_, Splitter.SplitTextByDelimiter("|"), {"Date", "Amount"})}}),
    transpose_nested_tables = Table.TransformColumns(convert_list_to_table, {{"Dates", each Table.PromoteHeaders(Table.Transpose(_))}}),
    minPaymentWeek = Date.WeekOfYear(Date.StartOfMonth(List.Min(transpose_nested_tables[Last Payment Date])), Day.Monday),
    generatedDatesList = List.Generate(()=> minPaymentWeek, each _ <= Date.WeekOfYear(#date(endYear,12,1), Day.Monday), each _ + 1, each "Week " & Number.ToText(_)),
    expand_nested_tables = Table.ExpandTableColumn(transpose_nested_tables, "Dates", generatedDatesList),
    remove_freq_months = Table.RemoveColumns(expand_nested_tables,{"Frequency Months"})
in
    remove_freq_months




Did I answer your question? Mark my post as a solution!

Proud to be a Super User!





Jgeddes, this is brilliant thank you very much!

Helpful resources

Announcements
Feb2025 Sticker Challenge

Join our Community Sticker Challenge 2025

If you love stickers, then you will definitely want to check out our Community Sticker Challenge!

Jan NL Carousel

Fabric Community Update - January 2025

Find out what's new and trending in the Fabric community.

Top Solution Authors
Top Kudoed Authors