forked from Simnation/Main
441 lines
17 KiB
Lua
441 lines
17 KiB
Lua
-- Initialize QBCore
|
|
local QBCore = exports['qb-core']:GetCoreObject()
|
|
|
|
-- Register callback for sending bills
|
|
lib.callback.register('billing:server:sendBill', function(source, data)
|
|
local src = source
|
|
local player = QBCore.Functions.GetPlayer(src)
|
|
local target = QBCore.Functions.GetPlayer(data.playerId)
|
|
|
|
if not player or not target then
|
|
return false
|
|
end
|
|
|
|
local senderName = player.PlayerData.charinfo.firstname .. ' ' .. player.PlayerData.charinfo.lastname
|
|
local description = data.reason .. ' (Von: ' .. senderName .. ')'
|
|
|
|
-- Create the bill
|
|
exports["ps-banking"]:createBill({
|
|
identifier = target.PlayerData.citizenid,
|
|
description = description,
|
|
type = "Invoice",
|
|
amount = data.amount,
|
|
})
|
|
|
|
-- Get the latest bill ID for this user (assuming it's the one we just created)
|
|
local result = MySQL.query.await('SELECT id FROM ps_banking_bills WHERE identifier = ? ORDER BY id DESC LIMIT 1', {
|
|
target.PlayerData.citizenid
|
|
})
|
|
|
|
local billId = result[1] and result[1].id or nil
|
|
|
|
-- Store additional data about the bill
|
|
MySQL.insert.await('INSERT INTO billing_accounts (bill_id, bill_description, sender_id, receiver_id, account_id, amount, created_at) VALUES (?, ?, ?, ?, ?, ?, NOW())', {
|
|
billId,
|
|
description,
|
|
player.PlayerData.citizenid,
|
|
target.PlayerData.citizenid,
|
|
data.account,
|
|
data.amount
|
|
})
|
|
|
|
-- Send payment prompt to target player
|
|
TriggerClientEvent('billing:client:showPaymentPrompt', data.playerId, {
|
|
billId = billId,
|
|
amount = data.amount,
|
|
reason = data.reason,
|
|
sender = senderName
|
|
})
|
|
|
|
-- Notify the sender
|
|
TriggerClientEvent('QBCore:Notify', src, 'Rechnung über $' .. data.amount .. ' an ' .. target.PlayerData.charinfo.firstname .. ' gesendet', 'success')
|
|
|
|
return true
|
|
end)
|
|
|
|
-- Add a callback to get bill status
|
|
lib.callback.register('billing:server:getBillStatus', function(source, billId)
|
|
local src = source
|
|
local player = QBCore.Functions.GetPlayer(src)
|
|
|
|
if not player then return nil end
|
|
|
|
local result = MySQL.query.await('SELECT * FROM billing_accounts WHERE bill_id = ?', {billId})
|
|
if result and #result > 0 then
|
|
return result[1]
|
|
end
|
|
|
|
return nil
|
|
end)
|
|
|
|
-- Add a callback to get all bill statuses for a player
|
|
lib.callback.register('billing:server:getAllBillStatuses', function(source)
|
|
local src = source
|
|
local player = QBCore.Functions.GetPlayer(src)
|
|
|
|
if not player then return nil end
|
|
|
|
local citizenId = player.PlayerData.citizenid
|
|
|
|
-- Get all bill statuses for this player
|
|
local result = MySQL.query.await('SELECT * FROM billing_accounts WHERE receiver_id = ?', {citizenId})
|
|
if result and #result > 0 then
|
|
return result
|
|
end
|
|
|
|
return {}
|
|
end)
|
|
|
|
-- Add a new callback for handling bill responses
|
|
lib.callback.register('billing:server:handleBillResponse', function(source, data)
|
|
local src = source
|
|
local player = QBCore.Functions.GetPlayer(src)
|
|
|
|
if not player then return false end
|
|
|
|
if data.action == 'pay' then
|
|
-- Process payment based on selected account
|
|
if data.accountId == 'personal' then
|
|
-- Pay from personal bank account
|
|
local billResult = MySQL.query.await('SELECT * FROM ps_banking_bills WHERE id = ?', {data.billId})
|
|
if not billResult or #billResult == 0 then return false end
|
|
|
|
local bill = billResult[1]
|
|
local amount = tonumber(bill.amount)
|
|
|
|
-- Check if player has enough money in their bank account
|
|
if player.PlayerData.money["bank"] < amount then
|
|
return false
|
|
end
|
|
|
|
-- Process payment manually instead of using callback to avoid issues
|
|
player.Functions.RemoveMoney("bank", amount, "bill-payment")
|
|
|
|
-- IMPORTANT: Delete the bill from ps_banking_bills table
|
|
MySQL.query.await('DELETE FROM ps_banking_bills WHERE id = ?', {data.billId})
|
|
|
|
-- Process the payment to the recipient's account
|
|
ProcessBillPayment(data.billId)
|
|
|
|
-- Notify the player
|
|
TriggerClientEvent('QBCore:Notify', src, 'Du hast die Rechnung über $' .. amount .. ' bezahlt', 'success')
|
|
|
|
return true
|
|
else
|
|
-- 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
|
|
MySQL.update.await('UPDATE billing_accounts SET declined = 1 WHERE bill_id = ?', {data.billId})
|
|
|
|
-- IMPORTANT: Delete the bill from ps_banking_bills table when declined
|
|
MySQL.query.await('DELETE FROM ps_banking_bills WHERE id = ?', {data.billId})
|
|
|
|
-- Find the sender to notify them
|
|
local billInfo = MySQL.query.await('SELECT * FROM billing_accounts WHERE bill_id = ?', {data.billId})
|
|
if billInfo and #billInfo > 0 then
|
|
local senderId = billInfo[1].sender_id
|
|
local sender = QBCore.Functions.GetPlayerByCitizenId(senderId)
|
|
|
|
if sender then
|
|
TriggerClientEvent('QBCore:Notify', sender.PlayerData.source, 'Deine Rechnung wurde abgelehnt', 'error')
|
|
end
|
|
end
|
|
|
|
-- Notify the player
|
|
TriggerClientEvent('QBCore:Notify', src, 'Du hast die Rechnung abgelehnt', 'info')
|
|
|
|
return true
|
|
elseif data.action == 'later' then
|
|
-- Simply close the prompt without any action
|
|
-- The bill will remain in the system as unpaid
|
|
|
|
-- Notify the player
|
|
TriggerClientEvent('QBCore:Notify', src, 'Die Rechnung wurde für später gespeichert', 'info')
|
|
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end)
|
|
|
|
-- 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 = tonumber(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
|
|
TriggerClientEvent('QBCore:Notify', src, 'Du hast keinen Zugriff auf dieses Konto', 'error')
|
|
return false
|
|
end
|
|
|
|
-- Check if account has enough balance
|
|
if tonumber(account.balance) < amount then
|
|
TriggerClientEvent('QBCore:Notify', src, 'Nicht genug Geld auf diesem Konto', 'error')
|
|
return false
|
|
end
|
|
|
|
-- Process payment
|
|
MySQL.update.await('UPDATE ps_banking_accounts SET balance = balance - ? WHERE id = ?', {amount, accountId})
|
|
|
|
-- IMPORTANT: Delete the bill from ps_banking_bills table
|
|
MySQL.query.await('DELETE FROM ps_banking_bills WHERE id = ?', {billId})
|
|
|
|
-- Process the payment to the recipient's account
|
|
ProcessBillPayment(billId)
|
|
|
|
-- Notify the player
|
|
TriggerClientEvent('QBCore:Notify', src, 'Du hast die Rechnung über $' .. amount .. ' vom Konto ' .. account.holder .. ' bezahlt', 'success')
|
|
|
|
return true
|
|
end
|
|
|
|
-- Add a callback for paying bill from selected account
|
|
lib.callback.register('billing:server:payBillFromAccount', function(source, data)
|
|
local src = source
|
|
local player = QBCore.Functions.GetPlayer(src)
|
|
|
|
if not player then return false end
|
|
|
|
if data.accountId == 'personal' then
|
|
-- Pay from personal bank account
|
|
local billResult = MySQL.query.await('SELECT * FROM ps_banking_bills WHERE id = ?', {data.billId})
|
|
if not billResult or #billResult == 0 then return false end
|
|
|
|
local bill = billResult[1]
|
|
local amount = tonumber(bill.amount)
|
|
|
|
-- Check if player has enough money in their bank account
|
|
if player.PlayerData.money["bank"] < amount then
|
|
TriggerClientEvent('QBCore:Notify', src, 'Nicht genug Geld auf deinem Konto', 'error')
|
|
return false
|
|
end
|
|
|
|
-- Process payment manually
|
|
player.Functions.RemoveMoney("bank", amount, "bill-payment")
|
|
|
|
-- IMPORTANT: Delete the bill from ps_banking_bills table
|
|
MySQL.query.await('DELETE FROM ps_banking_bills WHERE id = ?', {data.billId})
|
|
|
|
-- Process the payment to the recipient's account
|
|
ProcessBillPayment(data.billId)
|
|
|
|
-- Notify the player
|
|
TriggerClientEvent('QBCore:Notify', src, 'Du hast die Rechnung über $' .. amount .. ' bezahlt', 'success')
|
|
|
|
return true
|
|
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})
|
|
|
|
if billData and #billData > 0 then
|
|
local bill = billData[1]
|
|
local receiverId = bill.sender_id
|
|
local accountId = bill.account_id
|
|
local amount = tonumber(bill.amount)
|
|
|
|
-- If it's a personal account
|
|
if accountId == 'personal' then
|
|
local receiver = QBCore.Functions.GetPlayerByCitizenId(receiverId)
|
|
if receiver then
|
|
-- Add money directly to the receiver's bank account
|
|
receiver.Functions.AddMoney('bank', amount, 'bill-payment')
|
|
TriggerClientEvent('QBCore:Notify', receiver.PlayerData.source, 'Du hast $' .. amount .. ' von einer Rechnungszahlung erhalten', 'success')
|
|
else
|
|
-- Handle offline player
|
|
MySQL.insert.await('INSERT INTO offline_payments (citizen_id, amount, reason) VALUES (?, ?, ?)', {
|
|
receiverId,
|
|
amount,
|
|
'Rechnungszahlung'
|
|
})
|
|
end
|
|
else
|
|
-- Add money to the specified account
|
|
MySQL.update.await('UPDATE ps_banking_accounts SET balance = balance + ? WHERE id = ?', {
|
|
amount,
|
|
accountId
|
|
})
|
|
|
|
-- Try to notify the account owner if online
|
|
local accountResult = MySQL.query.await('SELECT * FROM ps_banking_accounts WHERE id = ?', {accountId})
|
|
if accountResult and #accountResult > 0 then
|
|
local account = accountResult[1]
|
|
local owner = json.decode(account.owner)
|
|
local ownerPlayer = QBCore.Functions.GetPlayerByCitizenId(owner.identifier)
|
|
|
|
if ownerPlayer then
|
|
TriggerClientEvent('QBCore:Notify', ownerPlayer.PlayerData.source, 'Das Konto ' .. account.holder .. ' hat $' .. amount .. ' von einer Rechnungszahlung erhalten', 'success')
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Update the bill status
|
|
MySQL.update.await('UPDATE billing_accounts SET paid = 1, paid_at = NOW() WHERE bill_id = ?', {billId})
|
|
end
|
|
end
|
|
|
|
-- Create the necessary database tables if they don't exist
|
|
MySQL.ready(function()
|
|
-- First check if the billing_accounts table exists
|
|
local tableExists = MySQL.query.await("SHOW TABLES LIKE 'billing_accounts'")
|
|
|
|
if #tableExists > 0 then
|
|
-- Table exists, check if the declined column exists
|
|
local columnExists = MySQL.query.await("SHOW COLUMNS FROM billing_accounts LIKE 'declined'")
|
|
|
|
if #columnExists == 0 then
|
|
-- Add the declined column if it doesn't exist
|
|
MySQL.query.await("ALTER TABLE billing_accounts ADD COLUMN declined TINYINT DEFAULT 0")
|
|
print("^2[nordi_billing] Added 'declined' column to billing_accounts table^7")
|
|
end
|
|
else
|
|
-- Create the table with all required columns
|
|
MySQL.query.await([[
|
|
CREATE TABLE IF NOT EXISTS billing_accounts (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
bill_id INT,
|
|
bill_description VARCHAR(255),
|
|
sender_id VARCHAR(50),
|
|
receiver_id VARCHAR(50),
|
|
account_id VARCHAR(50),
|
|
amount DECIMAL(10,2),
|
|
created_at DATETIME,
|
|
paid TINYINT DEFAULT 0,
|
|
declined TINYINT DEFAULT 0,
|
|
paid_at DATETIME
|
|
)
|
|
]])
|
|
print("^2[nordi_billing] Created billing_accounts table^7")
|
|
end
|
|
|
|
-- Create offline_payments table if it doesn't exist
|
|
MySQL.query.await([[
|
|
CREATE TABLE IF NOT EXISTS offline_payments (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
citizen_id VARCHAR(50),
|
|
amount DECIMAL(10,2),
|
|
reason VARCHAR(255),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
processed TINYINT DEFAULT 0
|
|
)
|
|
]])
|
|
print("^2[nordi_billing] Database tables initialized^7")
|
|
end) -- Added closing parenthesis here
|
|
|
|
|
|
|
|
-- Handle offline payments when a player logs in
|
|
RegisterNetEvent('QBCore:Server:PlayerLoaded', function()
|
|
local src = source
|
|
local player = QBCore.Functions.GetPlayer(src)
|
|
|
|
if not player then return end
|
|
|
|
local citizenId = player.PlayerData.citizenid
|
|
local offlinePayments = MySQL.query.await('SELECT * FROM offline_payments WHERE citizen_id = ? AND processed = 0', {citizenId})
|
|
|
|
if offlinePayments and #offlinePayments > 0 then
|
|
local totalAmount = 0
|
|
|
|
for _, payment in ipairs(offlinePayments) do
|
|
totalAmount = totalAmount + payment.amount
|
|
end
|
|
|
|
if totalAmount > 0 then
|
|
player.Functions.AddMoney('bank', totalAmount, 'offline-bill-payments')
|
|
TriggerClientEvent('QBCore:Notify', src, 'Du hast $' .. totalAmount .. ' von Rechnungszahlungen erhalten, während du offline warst', 'success')
|
|
|
|
-- Mark payments as processed
|
|
MySQL.update.await('UPDATE offline_payments SET processed = 1 WHERE citizen_id = ? AND processed = 0', {citizenId})
|
|
end
|
|
end
|
|
|
|
-- Check for unpaid bills
|
|
local unpaidBills = MySQL.query.await('SELECT COUNT(*) as count FROM ps_banking_bills WHERE identifier = ? AND isPaid = 0', {citizenId})
|
|
if unpaidBills and unpaidBills[1].count > 0 then
|
|
TriggerClientEvent('QBCore:Notify', src, 'Du hast ' .. unpaidBills[1].count .. ' unbezahlte Rechnungen. Tippe /bills um sie anzuzeigen.', 'info')
|
|
end
|
|
end)
|
|
|
|
-- Alternative hook method if you can't modify ps-banking
|
|
-- This listens for the MySQL query that deletes a bill (which happens when a bill is paid)
|
|
AddEventHandler('oxmysql:query', function(query, params)
|
|
if string.find(query, "DELETE FROM ps_banking_bills WHERE id = ?") then
|
|
-- This is likely a bill payment
|
|
local billId = params[1]
|
|
if billId then
|
|
-- Small delay to ensure the deletion completes
|
|
SetTimeout(100, function()
|
|
ProcessBillPayment(billId)
|
|
end)
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- Register a command to check bills
|
|
QBCore.Commands.Add('bills', 'Zeige deine unbezahlten Rechnungen an', {}, false, function(source)
|
|
TriggerClientEvent('QBCore:Notify', source, 'Öffne Rechnungsübersicht...', 'info')
|
|
-- This will trigger the client to open the bills menu
|
|
TriggerClientEvent('billing:client:openBillsMenu', source)
|
|
end)
|
|
|
|
-- Event handler for opening bills menu from command
|
|
RegisterNetEvent('billing:client:openBillsMenu', function()
|
|
-- This is handled on the client side
|
|
end)
|
|
|
|
-- Add a server event to notify bill sender when a bill is paid
|
|
RegisterServerEvent('billing:server:notifyBillPaid', function(senderId, amount, receiverName)
|
|
local sender = QBCore.Functions.GetPlayerByCitizenId(senderId)
|
|
if sender then
|
|
TriggerClientEvent('QBCore:Notify', sender.PlayerData.source, receiverName .. ' hat deine Rechnung über $' .. amount .. ' bezahlt', 'success')
|
|
end
|
|
end)
|
|
|
|
-- Add a server event to notify bill sender when a bill is declined
|
|
RegisterServerEvent('billing:server:notifyBillDeclined', function(senderId, amount, receiverName)
|
|
local sender = QBCore.Functions.GetPlayerByCitizenId(senderId)
|
|
if sender then
|
|
TriggerClientEvent('QBCore:Notify', sender.PlayerData.source, receiverName .. ' hat deine Rechnung über $' .. amount .. ' abgelehnt', 'error')
|
|
end
|
|
end)
|