mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-29 08:01:36 +00:00
f79400a691
Includes the required banking configuration, SQL migration, and English locale entries.
185 lines
6.8 KiB
Lua
185 lines
6.8 KiB
Lua
Bridge.Database.AfterMigration("sky_phone", function()
|
|
|
|
local function valid_amount(value)
|
|
local amount = tonumber(value)
|
|
if not amount or amount ~= math.floor(amount) then
|
|
return nil
|
|
end
|
|
if amount < Config.Banking.MinimumAmount or amount > Config.Banking.MaximumAmount then
|
|
return nil
|
|
end
|
|
return amount
|
|
end
|
|
|
|
local function player_name(source)
|
|
local firstname = Sky.FW.GetFirstname(source)
|
|
local lastname = Sky.FW.GetLastname(source)
|
|
local name = ((firstname or "") .. " " .. (lastname or "")):match("^%s*(.-)%s*$")
|
|
if name == "" then
|
|
name = GetPlayerName(source) or ("Player %s"):format(source)
|
|
end
|
|
return name
|
|
end
|
|
|
|
local function require_banking_session(source)
|
|
local session, error_response = SkyPhone.RequireSession(source)
|
|
if not session then
|
|
return nil, error_response
|
|
end
|
|
local identifier = Sky.FW.GetIdentifier(source)
|
|
if type(identifier) ~= "string" or identifier == "" then
|
|
return nil, { success = false, error = "banking_unavailable" }
|
|
end
|
|
return identifier
|
|
end
|
|
|
|
local function transaction_dto(row)
|
|
return {
|
|
id = tonumber(row.id),
|
|
kind = row.kind,
|
|
amount = tonumber(row.amount) or 0,
|
|
label = row.label or "",
|
|
reference = row.reference or "",
|
|
createdAt = (tonumber(row.created_at_unix) or 0) * 1000,
|
|
}
|
|
end
|
|
|
|
local function transactions(identifier)
|
|
local rows = Bridge.Database.Query([[
|
|
SELECT `id`, `kind`, `amount`, `label`, `reference`,
|
|
UNIX_TIMESTAMP(`created_at`) AS `created_at_unix`
|
|
FROM `sky_phone_bank_transactions`
|
|
WHERE `owner_identifier` = ?
|
|
ORDER BY `id` DESC
|
|
LIMIT ?
|
|
]], { identifier, Config.Banking.HistoryLimit })
|
|
local result = {}
|
|
for _, row in ipairs(rows) do
|
|
result[#result + 1] = transaction_dto(row)
|
|
end
|
|
return result
|
|
end
|
|
|
|
local function overview(source, identifier)
|
|
return {
|
|
bank = math.max(0, tonumber(Sky.FW.GetAccountMoney(source, "bank")) or 0),
|
|
cash = math.max(0, tonumber(Sky.FW.GetAccountMoney(source, "cash")) or 0),
|
|
currency = Config.Banking.Currency,
|
|
playerId = source,
|
|
playerName = player_name(source),
|
|
transactions = transactions(identifier),
|
|
}
|
|
end
|
|
|
|
local function record_transaction(identifier, kind, amount, label, reference)
|
|
Bridge.Database.Query([[
|
|
INSERT INTO `sky_phone_bank_transactions`
|
|
(`owner_identifier`, `kind`, `amount`, `label`, `reference`)
|
|
VALUES (?, ?, ?, ?, ?)
|
|
]], { identifier, kind, amount, label or "", reference or "" })
|
|
end
|
|
|
|
local function notify_changed(source)
|
|
TriggerClientEvent("sky_phone:banking:changed", source)
|
|
end
|
|
|
|
Bridge.Callbacks.Register("sky_phone:banking:overview", function(source)
|
|
local identifier, error_response = require_banking_session(source)
|
|
if not identifier then
|
|
return error_response
|
|
end
|
|
return { success = true, data = overview(source, identifier) }
|
|
end)
|
|
|
|
Bridge.Callbacks.Register("sky_phone:banking:deposit", function(source, data)
|
|
if not SkyPhone.AllowOperation(source, "banking_transaction", Config.Banking.ActionsPerMinute, 60) then
|
|
return { success = false, error = "rate_limited" }
|
|
end
|
|
local identifier, error_response = require_banking_session(source)
|
|
if not identifier then
|
|
return error_response
|
|
end
|
|
local amount = valid_amount(data and data.amount)
|
|
if not amount then
|
|
return { success = false, error = "invalid_request" }
|
|
end
|
|
if not Sky.FW.RemoveAccountMoney(source, "cash", amount) then
|
|
return { success = false, error = "insufficient_funds" }
|
|
end
|
|
local added = pcall(Sky.FW.AddAccountMoney, source, "bank", amount)
|
|
if not added then
|
|
Sky.FW.AddAccountMoney(source, "cash", amount)
|
|
return { success = false, error = "transfer_failed" }
|
|
end
|
|
record_transaction(identifier, "deposit", amount, "", "cash-deposit")
|
|
return { success = true, data = overview(source, identifier) }
|
|
end)
|
|
|
|
Bridge.Callbacks.Register("sky_phone:banking:withdraw", function(source, data)
|
|
if not SkyPhone.AllowOperation(source, "banking_transaction", Config.Banking.ActionsPerMinute, 60) then
|
|
return { success = false, error = "rate_limited" }
|
|
end
|
|
local identifier, error_response = require_banking_session(source)
|
|
if not identifier then
|
|
return error_response
|
|
end
|
|
local amount = valid_amount(data and data.amount)
|
|
if not amount then
|
|
return { success = false, error = "invalid_request" }
|
|
end
|
|
if not Sky.FW.RemoveAccountMoney(source, "bank", amount) then
|
|
return { success = false, error = "insufficient_funds" }
|
|
end
|
|
local added = pcall(Sky.FW.AddAccountMoney, source, "cash", amount)
|
|
if not added then
|
|
Sky.FW.AddAccountMoney(source, "bank", amount)
|
|
return { success = false, error = "transfer_failed" }
|
|
end
|
|
record_transaction(identifier, "withdrawal", amount, "", "cash-withdrawal")
|
|
return { success = true, data = overview(source, identifier) }
|
|
end)
|
|
|
|
Bridge.Callbacks.Register("sky_phone:banking:transfer", function(source, data)
|
|
if not SkyPhone.AllowOperation(source, "banking_transaction", Config.Banking.ActionsPerMinute, 60) then
|
|
return { success = false, error = "rate_limited" }
|
|
end
|
|
local identifier, error_response = require_banking_session(source)
|
|
if not identifier then
|
|
return error_response
|
|
end
|
|
local amount = valid_amount(data and data.amount)
|
|
local target_value = tonumber(data and data.target)
|
|
if not amount
|
|
or not target_value
|
|
or target_value ~= math.floor(target_value)
|
|
or target_value <= 0
|
|
or target_value > 65535
|
|
then
|
|
return { success = false, error = "invalid_request" }
|
|
end
|
|
local target = math.floor(target_value)
|
|
if target == source then
|
|
return { success = false, error = "self_transfer" }
|
|
end
|
|
local target_identifier = Sky.FW.GetIdentifier(target)
|
|
if type(target_identifier) ~= "string" or target_identifier == "" then
|
|
return { success = false, error = "target_not_found" }
|
|
end
|
|
if not Sky.FW.RemoveAccountMoney(source, "bank", amount) then
|
|
return { success = false, error = "insufficient_funds" }
|
|
end
|
|
local added = pcall(Sky.FW.AddAccountMoney, target, "bank", amount)
|
|
if not added then
|
|
Sky.FW.AddAccountMoney(source, "bank", amount)
|
|
return { success = false, error = "transfer_failed" }
|
|
end
|
|
|
|
local reference = ("phone-transfer-%s-%s"):format(os.time(), source)
|
|
record_transaction(identifier, "transfer_out", amount, player_name(target), reference)
|
|
record_transaction(target_identifier, "transfer_in", amount, player_name(source), reference)
|
|
notify_changed(target)
|
|
return { success = true, data = overview(source, identifier) }
|
|
end)
|
|
|
|
end)
|