Module:USASpending-by-category

From Defense Knowledge

Documentation for this module may be created at Module:USASpending-by-category/doc

local autoCreate = require('Module:AutoCreateWithPreload')

local p = {}

-- Get current language
local lang = mw.language.getContentLanguage()

-- Function to format number with two decimals and group separator
function formatNumberWithSeparator(num)

    local integerPart = math.floor(num)
    local decimalPart = string.format("%.2f", num - integerPart):sub(3)

    -- Format the integer part with group separators
    local formattedInteger = lang:formatNum(integerPart)

    -- Combine integer part and decimal part
    return formattedInteger .. "." .. decimalPart

end

function p.retrieveData(frame)

    -- Handle arguments
    local limit = frame.args.limit or 5
    local heading = frame.args.heading or ""
    local urlPath = frame.args.urlPath or ""
    local headingClass = frame.args.headingClass or "mt-5"
    -- Preload template for autocreated pages
    local acpTemplate = frame.args.acpTemplate or ""
    -- Get pagename
    local pageName = frame.args.page or mw.title.getCurrentTitle().text
    -- Set the API URL
    local baseUrl = 'https://api.usaspending.gov'
    local queryUrl = '/api/v2/search/spending_by_category/' .. urlPath
    local apiUrl = baseUrl .. queryUrl

    -- Handling the latest year period
    local dateTable = os.date("*t")
    local currentYear = dateTable.year
    local lastYear = currentYear - 1
    local yearAgo = {
        year = lastYear,
        month = dateTable.month,
        day = dateTable.day
    }
    local timestamp = os.time(yearAgo)
    local dateFrom = os.date("%Y-%m-%d", timestamp)
    local dateTo = os.date("%Y-%m-%d")

    -- Define POST data
    local postData = '{"filters":{"recipient_id":"' .. pageName .. '","time_period":[{"start_date":"' .. dateFrom .. '","end_date":"' .. dateTo .. '"}]},"limit":' .. limit .. '}'

    -- Fetch data from the API
    local data = mw.ext.externalData.getWebData {
        url = apiUrl,
        format = 'JSON',
        ['post data'] = postData,
        data = {code = 'code', name = 'name', amount = 'amount'},
        ['cache seconds'] = 86400
    }

    -- Assemble HTML output
    local output = {}

    -- Calculate total amount
    local totalAmount = 0
    local recordCount = 0

    if #data > 0 then
    for _, record in ipairs(data) do
        local amount = record.amount or 0
        totalAmount = totalAmount + amount
        recordCount = recordCount + 1
    end
    end
    if recordCount > 0 then

        -- Start building the table
        if heading ~= "" then
            table.insert(output, '<div class="h4 text-secondary border-bottom border-dark pb-2 ' .. headingClass .. '">' .. heading .. '</div>')
        end
        
        table.insert(output, '<table class="w-100 mt-0 wikitable sortable">')

        -- Add table headers
        table.insert(output, '<tr>')
        table.insert(output, '<th width="110">Code</th>')
        table.insert(output, '<th>Name</th>')
        table.insert(output, '<th width="190">Obligations</th>')
        table.insert(output, '<th width="190">% of Total</th>')
        table.insert(output, '</tr>')

        -- Add table rows
        for _, record in ipairs(data) do
            local percentage = (record.amount / totalAmount) * 100 or 0
            local code = record.code or "N/A"
            local name = record.name or "N/A"

            table.insert(output, '<tr>')
            table.insert(output, '<td>' .. code .. '</td>')
            if acpTemplate ~= "" then
                table.insert(output, '<td class="cell-overflow-hidden" title="' .. name .. '">[[' .. name .. ']]</td>')
            else
                table.insert(output, '<td class="cell-overflow-hidden" title="' .. name .. '">' .. name .. '</td>')
            end
            table.insert(output, '<td align="right" data-sort="' .. record.amount .. '">' .. formatNumberWithSeparator(record.amount) .. '</td>')
            if tostring(percentage) == "nan" then
                table.insert(output, '<td align="right" data-sort="--">--</td>') 
            else
                table.insert(output, '<td align="right" data-sort="' .. string.format("%.2f", percentage) .. '">' .. string.format("%.2f%%", percentage) .. '</td>') 
            end
            table.insert(output, '</tr>')

            -- Autocreate non-existing pages from links
            if acpTemplate ~= "" then
                table.insert(output, autoCreate.autoCreateWithPreload(frame, record.name, '{{' .. acpTemplate .. '}}'))
            end
        end

        -- Close the table
        table.insert(output, '</table>')

    end

    local result = table.concat(output, "\n")

    return result

end

return p