-- Initialize QBCore local QBCore = exports['qb-core']:GetCoreObject() local isUiOpen = false local cooldown = false -- Command to open billing menu RegisterCommand('bill', function() OpenBillingMenu() end, false) -- Keybind registration RegisterKeyMapping('bill', 'Open Billing Menu', 'keyboard', 'F7') -- Default key is F7, can be changed in settings -- Function to open the billing menu function OpenBillingMenu() if cooldown then lib.notify({ title = 'Billing System', description = 'Please wait before using the billing system again', type = 'error' }) return end -- Get nearby players local players = GetNearbyPlayers() if #players == 0 then lib.notify({ title = 'Billing System', description = 'No players nearby to bill', type = 'error' }) return end -- Get player's accounts for receiving payment local accounts = lib.callback.await('ps-banking:server:getAccounts', false) or {} local accountOptions = {} -- Add default bank account table.insert(accountOptions, { value = 'personal', label = 'Personal Bank Account' }) -- Add other accounts for _, account in ipairs(accounts) do table.insert(accountOptions, { value = account.id, label = account.holder .. ' - ' .. account.cardNumber }) end -- Show the list of nearby players first local playerOptions = {} for _, player in ipairs(players) do table.insert(playerOptions, { title = player.name, description = 'ID: ' .. player.id, onSelect = function() -- When a player is selected, show the billing form ShowBillingForm(player, accountOptions) end }) end -- Register and show the player selection menu lib.registerContext({ id = 'nearby_players_menu', title = 'Select Player to Bill', options = playerOptions }) lib.showContext('nearby_players_menu') end -- Function to show the billing form after selecting a player function ShowBillingForm(selectedPlayer, accountOptions) local input = lib.inputDialog('Create Bill for ' .. selectedPlayer.name, { { type = 'number', label = 'Amount ($)', description = 'Enter the bill amount', icon = 'dollar-sign', required = true, min = 1, max = 100000 }, { type = 'input', label = 'Reason', description = 'Enter the reason for the bill', placeholder = 'Services provided...', required = true }, { type = 'select', label = 'Receiving Account', options = accountOptions, required = true } }) if not input then return end -- Play animation PlayBillingAnimation() -- Send the bill local success = lib.callback.await('billing:server:sendBill', false, { playerId = selectedPlayer.id, amount = input[1], reason = input[2], account = input[3] }) if success then lib.notify({ title = 'Billing System', description = 'Bill sent successfully to ' .. selectedPlayer.name, type = 'success' }) -- Set cooldown cooldown = true SetTimeout(5000, function() cooldown = false end) else lib.notify({ title = 'Billing System', description = 'Failed to send bill', type = 'error' }) end end -- Function to view received bills function ViewBills() local bills = lib.callback.await('ps-banking:server:getBills', false) if not bills or #bills == 0 then lib.notify({ title = 'Billing System', description = 'You have no unpaid bills', type = 'info' }) return end local billOptions = {} for _, bill in ipairs(bills) do local timestamp = os.date('%Y-%m-%d %H:%M', bill.date) table.insert(billOptions, { title = bill.description, description = ('Amount: $%s | Date: %s'):format(bill.amount, timestamp), metadata = { {label = 'Bill ID', value = bill.id}, {label = 'Type', value = bill.type}, {label = 'Status', value = bill.isPaid and 'Paid' or 'Unpaid'} }, onSelect = function() local confirm = lib.alertDialog({ header = 'Pay Bill', content = ('Do you want to pay $%s for %s?'):format(bill.amount, bill.description), centered = true, cancel = true }) if confirm == 'confirm' then local success = lib.callback.await('ps-banking:server:payBill', false, bill.id) if success then lib.notify({ title = 'Billing System', description = 'Bill paid successfully', type = 'success' }) ViewBills() -- Refresh the list else lib.notify({ title = 'Billing System', description = 'Failed to pay bill. Insufficient funds.', type = 'error' }) end end end }) end lib.registerContext({ id = 'billing_menu', title = 'Your Bills', options = billOptions }) lib.showContext('billing_menu') end -- Command to view bills RegisterCommand('bills', function() ViewBills() end, false) -- Helper function to get nearby players function GetNearbyPlayers() local playerPed = PlayerPedId() local playerCoords = GetEntityCoords(playerPed) local players = {} -- Get all players local allPlayers = GetActivePlayers() for _, player in ipairs(allPlayers) do local targetPed = GetPlayerPed(player) local targetCoords = GetEntityCoords(targetPed) local distance = #(playerCoords - targetCoords) if distance <= 5.0 and targetPed ~= playerPed then local targetId = GetPlayerServerId(player) local targetName = GetPlayerName(player) table.insert(players, {id = targetId, name = targetName}) end end return players end -- Animation function function PlayBillingAnimation() lib.requestAnimDict("cellphone@") -- Request the prop model local propModel = 'bzzz_prop_payment_terminal' lib.requestModel(propModel) -- Create prop local playerPed = PlayerPedId() local coords = GetEntityCoords(playerPed) local prop = CreateObject(GetHashKey(propModel), coords.x, coords.y, coords.z, true, true, true) -- Attach prop to player AttachEntityToEntity(prop, playerPed, GetPedBoneIndex(playerPed, 57005), 0.18, 0.01, 0.0, -54.0, 220.0, 43.0, true, true, false, true, 1, true) -- Play animation TaskPlayAnim(playerPed, "cellphone@", "cellphone_text_read_base", 2.0, 3.0, -1, 49, 0, false, false, false) -- Wait for animation to complete Wait(5000) -- Clear animation and delete prop ClearPedTasks(playerPed) DeleteEntity(prop) end