diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/.fxap b/resources/[defaultmaps]/FM-AmmunationPUB/.fxap new file mode 100644 index 000000000..39b66b788 Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/.fxap differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/fxmanifest.lua b/resources/[defaultmaps]/FM-AmmunationPUB/fxmanifest.lua new file mode 100644 index 000000000..5827b6866 --- /dev/null +++ b/resources/[defaultmaps]/FM-AmmunationPUB/fxmanifest.lua @@ -0,0 +1,7 @@ +fx_version 'bodacious' +game 'gta5' +this_is_a_map 'yes' + + + +dependency '/assetpacks' \ No newline at end of file diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/readme.txt b/resources/[defaultmaps]/FM-AmmunationPUB/readme.txt new file mode 100644 index 000000000..94a8b76af --- /dev/null +++ b/resources/[defaultmaps]/FM-AmmunationPUB/readme.txt @@ -0,0 +1,23 @@ +In this file you will find a guide on how to solve problems you may have when using our map! + +--- The first thing we recommend you do is to ensure only our map and then start your maps one by one and you will find which one is causing this problem! --- + + +|This is a list of possible problems you may have| +-- In some cases we recommend removing the entire map containing the duplicate file! -- + +---- OLD INTERIOR ---- +Check this file in your resources folder searching for duplicated files, when you find the duplicated delete it! +In some cases we recommend removing the entire map containing the duplicate file! +File name - v_int_7.ytyp + +---- BUGGED COLLISIONS ---- +Check this file in your resources folder searching for duplicated files, when you find the duplicated delete it! +In some cases we recommend removing the entire map containing the duplicate file! +File name - v_gun.ybn +File name - hi@v_gun.ybn + + +If AFTER FOLLOWING THIS GUIDE the problem is still NOT SOLVED, join our discord and write in the support chat! +DISCORD LINK: https://discord.gg/TZeRjWeFKQ + diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/_manifestFMAmmunationPub.ymf b/resources/[defaultmaps]/FM-AmmunationPUB/stream/_manifestFMAmmunationPub.ymf new file mode 100644 index 000000000..47d29ba4d Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/_manifestFMAmmunationPub.ymf differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammu_texture.ytd b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammu_texture.ytd new file mode 100644 index 000000000..15df19c63 Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammu_texture.ytd differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucounter.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucounter.ydr new file mode 100644 index 000000000..2586aa9ec Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucounter.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucprops.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucprops.ydr new file mode 100644 index 000000000..b012092bc Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucprops.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucprops_02.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucprops_02.ydr new file mode 100644 index 000000000..652f356a5 Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucprops_02.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucprops_03.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucprops_03.ydr new file mode 100644 index 000000000..d4553d10e Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucprops_03.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucprops_04.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucprops_04.ydr new file mode 100644 index 000000000..4b8500482 Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammucprops_04.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudepz.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudepz.ydr new file mode 100644 index 000000000..424ba5c8f Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudepz.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudepz_02.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudepz_02.ydr new file mode 100644 index 000000000..43f166fbc Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudepz_02.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudepz_03.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudepz_03.ydr new file mode 100644 index 000000000..a5d882b19 Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudepz_03.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudetail.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudetail.ydr new file mode 100644 index 000000000..f02b4898b Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudetail.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudetail2.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudetail2.ydr new file mode 100644 index 000000000..276dd9375 Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudetail2.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudoor.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudoor.ydr new file mode 100644 index 000000000..636e1accd Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudoor.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudoor2.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudoor2.ydr new file mode 100644 index 000000000..ffd80766c Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammudoor2.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammugenfur.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammugenfur.ydr new file mode 100644 index 000000000..26baac0ad Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammugenfur.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammulights.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammulights.ydr new file mode 100644 index 000000000..a521acde7 Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammulights.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuoffice.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuoffice.ydr new file mode 100644 index 000000000..b080ed4d8 Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuoffice.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuposters.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuposters.ydr new file mode 100644 index 000000000..124bc060d Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuposters.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuprops_texture.ytd b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuprops_texture.ytd new file mode 100644 index 000000000..988d42a22 Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuprops_texture.ytd differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuref.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuref.ydr new file mode 100644 index 000000000..a5679ba95 Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuref.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammusdoor.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammusdoor.ydr new file mode 100644 index 000000000..6020c16ab Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammusdoor.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammushell_texture.ytd b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammushell_texture.ytd new file mode 100644 index 000000000..89ebf5e2d Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammushell_texture.ytd differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammushootr.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammushootr.ydr new file mode 100644 index 000000000..3de9be53f Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammushootr.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammutarg.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammutarg.ydr new file mode 100644 index 000000000..2e2d5bf4d Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammutarg.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuwalldet.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuwalldet.ydr new file mode 100644 index 000000000..3454b1446 Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/fm_ammuwalldet.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/hi@v_gun.ybn b/resources/[defaultmaps]/FM-AmmunationPUB/stream/hi@v_gun.ybn new file mode 100644 index 000000000..3ab63cdd9 Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/hi@v_gun.ybn differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/v_7_gc_shell.ydr b/resources/[defaultmaps]/FM-AmmunationPUB/stream/v_7_gc_shell.ydr new file mode 100644 index 000000000..5ea1c0dbd Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/v_7_gc_shell.ydr differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/v_gun.ybn b/resources/[defaultmaps]/FM-AmmunationPUB/stream/v_gun.ybn new file mode 100644 index 000000000..3d161c417 Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/v_gun.ybn differ diff --git a/resources/[defaultmaps]/FM-AmmunationPUB/stream/v_int_7.ytyp b/resources/[defaultmaps]/FM-AmmunationPUB/stream/v_int_7.ytyp new file mode 100644 index 000000000..9dad37e38 Binary files /dev/null and b/resources/[defaultmaps]/FM-AmmunationPUB/stream/v_int_7.ytyp differ diff --git a/resources/[tools]/nordi_billing/billing_client.lua b/resources/[tools]/nordi_billing/billing_client.lua index 084f11e47..72de33e94 100644 --- a/resources/[tools]/nordi_billing/billing_client.lua +++ b/resources/[tools]/nordi_billing/billing_client.lua @@ -169,6 +169,74 @@ function ShowBillingForm(selectedPlayer, accountOptions) end end +-- Function to show payment account selection +function ShowPaymentAccountSelection(billId, amount, description) + -- Get player's accounts for payment + local accounts = lib.callback.await('ps-banking:server:getAccounts', false) or {} + local accountOptions = {} + + -- Add default bank account + table.insert(accountOptions, { + value = 'personal', + label = 'Persönliches Bankkonto', + description = 'Bezahlen mit deinem Hauptkonto' + }) + + -- Add other accounts + for _, account in ipairs(accounts) do + table.insert(accountOptions, { + value = account.id, + label = account.holder .. ' - ' .. account.cardNumber, + description = 'Kontostand: $' .. account.balance + }) + end + + -- Register and show the account selection menu + lib.registerContext({ + id = 'payment_account_menu', + title = 'Wähle Zahlungskonto', + menu = 'billing_menu', -- Add back button to bills menu + options = accountOptions, + onExit = function() + ViewBills() -- Return to bills menu + end, + onSelect = function(selected) + local accountId = selected.value + + local confirm = lib.alertDialog({ + header = 'Rechnung bezahlen', + content = ('Möchtest du $%s für %s von diesem Konto bezahlen?'):format(amount, description), + centered = true, + cancel = true + }) + + if confirm == 'confirm' then + local success = lib.callback.await('billing:server:payBillFromAccount', false, { + billId = billId, + accountId = accountId + }) + + if success then + lib.notify({ + title = 'Billing System', + description = 'Rechnung erfolgreich bezahlt', + type = 'success' + }) + ViewBills() -- Refresh the list + else + lib.notify({ + title = 'Billing System', + description = 'Fehler beim Bezahlen der Rechnung. Unzureichendes Guthaben.', + type = 'error' + }) + end + end + end + }) + + lib.showContext('payment_account_menu') +end + -- Function to view received bills function ViewBills() local bills = lib.callback.await('ps-banking:server:getBills', false) @@ -213,30 +281,8 @@ function ViewBills() }, onSelect = function() if not bill.isPaid and not isDeclined then - local confirm = lib.alertDialog({ - header = 'Rechnung bezahlen', - content = ('Möchtest du $%s für %s bezahlen?'):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 = 'Rechnung erfolgreich bezahlt', - type = 'success' - }) - ViewBills() -- Refresh the list - else - lib.notify({ - title = 'Billing System', - description = 'Fehler beim Bezahlen der Rechnung. Unzureichendes Guthaben.', - type = 'error' - }) - end - end + -- Show account selection for payment + ShowPaymentAccountSelection(bill.id, bill.amount, bill.description) end end }) @@ -310,6 +356,68 @@ RegisterNetEvent('billing:client:showPaymentPrompt', function(data) -- Play a notification sound PlaySound(-1, "Event_Start_Text", "GTAO_FM_Events_Soundset", 0, 0, 1) + -- Get player's accounts for payment + local accounts = lib.callback.await('ps-banking:server:getAccounts', false) or {} + local accountOptions = {} + + -- Add default bank account + table.insert(accountOptions, { + title = 'Persönliches Bankkonto', + description = 'Bezahlen mit deinem Hauptkonto', + icon = 'credit-card', + onSelect = function() + local success = lib.callback.await('billing:server:handleBillResponse', false, { + action = 'pay', + billId = data.billId, + accountId = 'personal' + }) + + if success then + lib.notify({ + title = 'Rechnung bezahlt', + description = 'Du hast die Rechnung erfolgreich bezahlt', + type = 'success' + }) + else + lib.notify({ + title = 'Zahlung fehlgeschlagen', + description = 'Du hast nicht genug Geld auf deinem Konto', + type = 'error' + }) + end + end + }) + + -- Add other accounts + for _, account in ipairs(accounts) do + table.insert(accountOptions, { + title = account.holder .. ' - ' .. account.cardNumber, + description = 'Kontostand: $' .. account.balance, + icon = 'university', + onSelect = function() + local success = lib.callback.await('billing:server:handleBillResponse', false, { + action = 'pay', + billId = data.billId, + accountId = account.id + }) + + if success then + lib.notify({ + title = 'Rechnung bezahlt', + description = 'Du hast die Rechnung erfolgreich bezahlt', + type = 'success' + }) + else + lib.notify({ + title = 'Zahlung fehlgeschlagen', + description = 'Nicht genug Geld auf diesem Konto', + type = 'error' + }) + end + end + }) + end + -- Create the payment prompt lib.registerContext({ id = 'bill_payment_prompt', @@ -325,28 +433,9 @@ RegisterNetEvent('billing:client:showPaymentPrompt', function(data) }, { title = 'Bezahlen', - description = 'Rechnung sofort bezahlen', + description = 'Wähle ein Konto zum Bezahlen', icon = 'money-bill', - onSelect = function() - local success = lib.callback.await('billing:server:handleBillResponse', false, { - action = 'pay', - billId = data.billId - }) - - if success then - lib.notify({ - title = 'Rechnung bezahlt', - description = 'Du hast die Rechnung erfolgreich bezahlt', - type = 'success' - }) - else - lib.notify({ - title = 'Zahlung fehlgeschlagen', - description = 'Du hast nicht genug Geld auf deinem Konto', - type = 'error' - }) - end - end + menu = 'payment_account_selection' }, { title = 'Ablehnen', @@ -396,6 +485,14 @@ RegisterNetEvent('billing:client:showPaymentPrompt', function(data) } }) + -- Register the account selection submenu + lib.registerContext({ + id = 'payment_account_selection', + title = 'Wähle Zahlungskonto', + menu = 'bill_payment_prompt', + options = accountOptions + }) + -- Show the payment prompt lib.showContext('bill_payment_prompt') end) diff --git a/resources/[tools]/nordi_billing/billing_server.lua b/resources/[tools]/nordi_billing/billing_server.lua index 60fc19a6f..e41bb4f23 100644 --- a/resources/[tools]/nordi_billing/billing_server.lua +++ b/resources/[tools]/nordi_billing/billing_server.lua @@ -73,15 +73,15 @@ lib.callback.register('billing:server:handleBillResponse', function(source, data if not player then return false end if data.action == 'pay' then - -- Process payment - local success = lib.callback.await('ps-banking:server:payBill', src, data.billId) - - if success then - -- Payment successful - return true + -- Process payment based on selected account + if data.accountId == 'personal' then + -- Pay from personal bank account + local success = lib.callback.await('ps-banking:server:payBill', src, data.billId) + return success else - -- Payment failed (likely insufficient funds) - return false + -- Pay from shared account + local success = PayBillFromSharedAccount(src, data.billId, data.accountId) + return success end elseif data.action == 'decline' then -- Mark as declined in our system @@ -107,10 +107,72 @@ lib.callback.register('billing:server:handleBillResponse', function(source, data return false end) --- Event handler for when a bill is paid -RegisterNetEvent('ps-banking:server:billPaid', function(billId) +-- Function to pay bill from a shared account +function PayBillFromSharedAccount(source, billId, accountId) + local src = source + local player = QBCore.Functions.GetPlayer(src) + + if not player then return false end + + -- Get bill details + local billResult = MySQL.query.await('SELECT * FROM ps_banking_bills WHERE id = ?', {billId}) + if not billResult or #billResult == 0 then return false end + + local bill = billResult[1] + local amount = bill.amount + + -- Get account details + local accountResult = MySQL.query.await('SELECT * FROM ps_banking_accounts WHERE id = ?', {accountId}) + if not accountResult or #accountResult == 0 then return false end + + local account = accountResult[1] + + -- Check if player has access to this account + local hasAccess = false + local accountOwner = json.decode(account.owner) + local accountUsers = json.decode(account.users) + + if accountOwner.identifier == player.PlayerData.citizenid then + hasAccess = true + else + for _, user in ipairs(accountUsers) do + if user.identifier == player.PlayerData.citizenid then + hasAccess = true + break + end + end + end + + if not hasAccess then return false end + + -- Check if account has enough balance + if tonumber(account.balance) < tonumber(amount) then return false end + + -- Process payment + MySQL.update.await('UPDATE ps_banking_accounts SET balance = balance - ? WHERE id = ?', {amount, accountId}) + MySQL.query.await('DELETE FROM ps_banking_bills WHERE id = ?', {billId}) + + -- Process the payment to the recipient's account + ProcessBillPayment(billId) + + return true +end + +-- Add a callback for paying bill from selected account +lib.callback.register('billing:server:payBillFromAccount', function(source, data) local src = source + if data.accountId == 'personal' then + -- Pay from personal bank account + return lib.callback.await('ps-banking:server:payBill', src, data.billId) + else + -- Pay from shared account + return PayBillFromSharedAccount(src, data.billId, data.accountId) + end +end) + +-- Function to process bill payment to recipient +function ProcessBillPayment(billId) -- Find the bill in our custom table local billData = MySQL.query.await('SELECT * FROM billing_accounts WHERE bill_id = ?', {billId}) @@ -146,6 +208,11 @@ RegisterNetEvent('ps-banking:server:billPaid', function(billId) -- Update the bill status MySQL.update.await('UPDATE billing_accounts SET paid = 1, paid_at = NOW() WHERE bill_id = ?', {billId}) end +end + +-- Event handler for when a bill is paid +RegisterNetEvent('ps-banking:server:billPaid', function(billId) + ProcessBillPayment(billId) end) -- Create the necessary database tables if they don't exist @@ -214,7 +281,7 @@ AddEventHandler('oxmysql:query', function(query, params) if billId then -- Small delay to ensure the deletion completes SetTimeout(100, function() - TriggerEvent('ps-banking:server:billPaid', billId) + ProcessBillPayment(billId) end) end end