Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: extract financing to it's own table & fix: Finance vehicle menu #64

Merged
merged 18 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions client/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ local function showFinancedVehiclesMenu()

if vehicles == nil or #vehicles == 0 then return exports.qbx_core:Notify(locale('error.nofinanced'), 'error') end
for _, v in pairs(vehicles) do
if v.balance ~= 0 then
if v.balance and v.balance > 0 then
local name = VEHICLES[v.vehicle].name
local plate = v.plate:upper()
ownedVehicles[#ownedVehicles + 1] = {
Expand Down Expand Up @@ -152,14 +152,18 @@ end
---@param targetShowroomVehicle integer vehicleName
---@param buyVehicle string model
local function openFinance(targetShowroomVehicle, buyVehicle)
local dialog = lib.inputDialog(VEHICLES[buyVehicle].name:upper()..' '..buyVehicle:upper()..' - $'..getVehPrice(targetShowroomVehicle), {
local dialog = lib.inputDialog(VEHICLES[buyVehicle].brand:upper()..' '..VEHICLES[buyVehicle].name:upper()..' - $'..getVehPrice(targetShowroomVehicle), {
{
type = 'number',
label = locale('menus.financesubmit_downpayment')..sharedConfig.finance.minimumDown..'%',
min = VEHICLES[buyVehicle].price * sharedConfig.finance.minimumDown / 100,
max = VEHICLES[buyVehicle].price
},
{
type = 'number',
label = locale('menus.financesubmit_totalpayment')..sharedConfig.finance.maximumPayments,
min = 2,
max = sharedConfig.finance.maximumPayments
}
})

Expand Down
4 changes: 3 additions & 1 deletion fxmanifest.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ files {
'locales/*.json'
}

dependency 'qbx_vehicles'

provide 'qb-vehicleshop'
lua54 'yes'
use_experimental_fxv2_oal 'yes'
use_experimental_fxv2_oal 'yes'
20 changes: 20 additions & 0 deletions migrate.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
CREATE TABLE IF NOT EXISTS `vehicle_financing` (
`vehicleId` int(11) NOT NULL,
`balance` int(11) DEFAULT NULL,
`paymentamount` int(11) DEFAULT NULL,
`paymentsleft` tinyint(4) DEFAULT NULL,
`financetime` int(11) DEFAULT NULL,
PRIMARY KEY (`vehicleId`),
FOREIGN KEY `vehicleId` (`vehicleId`) REFERENCES `player_vehicles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO vehicle_financing (vehicleId, balance, paymentamount, paymentsleft, financetime)
SELECT id, balance, paymentamount, paymentsleft, financetime
FROM player_vehicles
WHERE balance > 0 OR paymentamount > 0 OR paymentsleft > 0 OR financetime > 0;

ALTER TABLE player_vehicles
DROP COLUMN balance,
DROP COLUMN paymentamount,
DROP COLUMN paymentsleft,
DROP COLUMN financetime;
Manason marked this conversation as resolved.
Show resolved Hide resolved
43 changes: 24 additions & 19 deletions server/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ RegisterNetEvent('qbx_vehicleshop:server:removePlayer', function(citizenid)
if not financeTimer[citizenid] then return end

local playTime = financeTimer[citizenid]
local financetime = FetchVehicleEntitiesByCitizenId(citizenid)
for _, v in pairs(financetime) do
local vehicles = FetchFinancedVehicleEntitiesByCitizenId(citizenid)
for _, v in pairs(vehicles) do
if v.balance >= 1 then
local newTime = math.floor(v.financetime - (((os.time() - playTime) / 1000) / 60))
if newTime < 0 then newTime = 0 end
UpdateVehicleEntityFinanceTime(newTime, v.plate)
UpdateVehicleEntityFinanceTime(newTime, v.vehicleId)
end
end
financeTimer[citizenid] = nil
Expand All @@ -32,14 +32,14 @@ AddEventHandler('playerDropped', function()
local src = source
local license = GetPlayerIdentifierByType(src, 'license2') or GetPlayerIdentifierByType(src, 'license')
if not license then return end
local vehicles = FetchVehicleEntitiesByLicense(license)
local vehicles = FetchFinancedVehicleEntitiesByLicense(license)
if not vehicles then return end
for _, v in pairs(vehicles) do
local playTime = financeTimer[v.citizenid]
if v.balance >= 1 and playTime then
local newTime = math.floor(v.financetime - (((os.time() - playTime) / 1000) / 60))
if newTime < 0 then newTime = 0 end
UpdateVehicleEntityFinanceTime(newTime, v.plate)
UpdateVehicleEntityFinanceTime(newTime, v.vehicleId)
end
end
if vehicles[1] and financeTimer[vehicles[1].citizenid] then
Expand Down Expand Up @@ -94,6 +94,13 @@ lib.callback.register('qbx_vehicleshop:server:GetVehiclesByName', function(sourc
local player = exports.qbx_core:GetPlayer(src)
if not player then return end
local vehicles = FetchVehicleEntitiesByCitizenId(player.PlayerData.citizenid)
local financeVehicles = FetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid)
for _, v in pairs(financeVehicles) do
vehicles[v.vehicleId].balance = v.balance
vehicles[v.vehicleId].paymentamount = v.paymentamount
vehicles[v.vehicleId].paymentsleft = v.paymentsleft
vehicles[v.vehicleId].financetime = v.financetime
end
if vehicles[1] then
return vehicles
end
Expand Down Expand Up @@ -237,11 +244,9 @@ RegisterNetEvent('qbx_vehicleshop:server:buyShowroomVehicle', function(vehicle)
return
end

local cid = player.PlayerData.citizenid
local plate = generatePlate()
InsertVehicleEntity({
license = player.PlayerData.license,
citizenId = cid,
exports.qbx_vehicles:CreateVehicleEntity({
citizenId = player.PlayerData.citizenid,
model = vehicle,
plate = plate,
})
Expand Down Expand Up @@ -282,7 +287,6 @@ RegisterNetEvent('qbx_vehicleshop:server:financeVehicle', function(downPayment,

InsertVehicleEntityWithFinance({
insertVehicleEntityRequest = {
license = player.PlayerData.license,
citizenId = cid,
model = vehicle,
plate = plate,
Expand Down Expand Up @@ -343,8 +347,7 @@ RegisterNetEvent('qbx_vehicleshop:server:sellShowroomVehicle', function(data, pl

if not sellShowroomVehicleTransact(src, target, vehiclePrice, vehiclePrice) then return end

InsertVehicleEntity({
license = target.PlayerData.license,
exports.qbx_vehicles:CreateVehicleEntity({
citizenId = cid,
model = vehicle,
plate = plate
Expand Down Expand Up @@ -390,7 +393,6 @@ RegisterNetEvent('qbx_vehicleshop:server:sellfinanceVehicle', function(downPayme

InsertVehicleEntityWithFinance({
insertVehicleEntityRequest = {
license = target.PlayerData.license,
citizenId = cid,
model = vehicle,
plate = plate,
Expand Down Expand Up @@ -418,8 +420,8 @@ RegisterNetEvent('qbx_vehicleshop:server:checkFinance', function()
local vehicles = FetchFinancedVehicleEntitiesByCitizenId(player.PlayerData.citizenid)
for _, v in pairs(vehicles) do
local plate = v.plate
DeleteVehicleEntity(plate)
--MySQL.update('UPDATE player_vehicles SET citizenid = ? WHERE plate = ?', {'REPO-'..v.citizenid, plate}) -- Use this if you don't want them to be deleted
DeleteVehicleEntity(v.id)
--MySQL.update('UPDATE player_vehicles SET citizenid = ? WHERE id = ?', {'REPO-'..v.citizenid, v.id}) -- Use this if you don't want them to be deleted
exports.qbx_core:Notify(src, locale('error.repossessed', plate), 'error')
end
end)
Expand Down Expand Up @@ -457,8 +459,11 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl
local player = exports.qbx_core:GetPlayer(src)
local target = exports.qbx_core:GetPlayer(buyerId)
local row = FetchVehicleEntityByPlate(plate)
if config.finance.preventSelling and row.balance > 0 then
return exports.qbx_core:Notify(src, locale('error.financed'), 'error')
if config.finance.preventSelling then
local financeRow = FetchFinancedVehicleEntityById(row.id)
if financeRow.balance > 0 then
return exports.qbx_core:Notify(src, locale('error.financed'), 'error')
end
end
if row.citizenid ~= player.PlayerData.citizenid then
return exports.qbx_core:Notify(src, locale('error.notown'), 'error')
Expand Down Expand Up @@ -491,11 +496,11 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl
player.Functions.AddMoney(currencyType, sellAmount)
target.Functions.RemoveMoney(currencyType, sellAmount)
end
UpdateVehicleEntityOwner(targetcid, targetlicense, plate)
UpdateVehicleEntityOwner(targetcid, targetlicense, row.id)
TriggerClientEvent('vehiclekeys:client:SetOwner', buyerId, plate)
local sellerMessage = sellAmount > 0 and locale('success.soldfor') .. lib.math.groupdigits(sellAmount) or locale('success.gifted')
local buyerMessage = sellAmount > 0 and locale('success.boughtfor') .. lib.math.groupdigits(sellAmount) or locale('success.received_gift')
exports.qbx_core:Notify(src, sellerMessage, 'success')
exports.qbx_core:Notify(buyerId, buyerMessage, 'success')
end, GetEntityModel(vehicle), sellAmount)
end)
end)
80 changes: 38 additions & 42 deletions server/storage.lua
Original file line number Diff line number Diff line change
@@ -1,23 +1,8 @@
---@class InsertVehicleEntityRequest
---@field license string
---@field citizenId string
---@field model string
---@field plate string

---@param request InsertVehicleEntityRequest
function InsertVehicleEntity(request)
MySQL.insert('INSERT INTO player_vehicles (license, citizenid, vehicle, hash, mods, plate, garage, state) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', {
request.license,
request.citizenId,
request.model,
joaat(request.model),
'{}',
request.plate,
'pillboxgarage',
0
})
end

---@class VehicleFinanceServer
---@field balance number
---@field payment number
Expand All @@ -30,15 +15,13 @@ end

---@param request InsertVehicleEntityWithFinanceRequest
function InsertVehicleEntityWithFinance(request)
MySQL.insert('INSERT INTO player_vehicles (license, citizenid, vehicle, hash, mods, plate, garage, state, balance, paymentamount, paymentsleft, financetime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', {
request.insertVehicleEntityRequest.license,
request.insertVehicleEntityRequest.citizenId,
request.insertVehicleEntityRequest.model,
joaat(request.insertVehicleEntityRequest.model),
'{}',
request.insertVehicleEntityRequest.plate,
'pillboxgarage',
0,
local vehicleId = exports.qbx_vehicles:CreateVehicleEntity({
citizenId = request.insertVehicleEntityRequest.citizenId,
model = request.insertVehicleEntityRequest.model,
plate = request.insertVehicleEntityRequest.plate
})
MySQL.insert('INSERT INTO vehicle_financing (vehicleId, balance, paymentamount, paymentsleft, financetime) VALUES (?, ?, ?, ?, ?)', {
vehicleId,
request.vehicleFinance.balance,
request.vehicleFinance.payment,
request.vehicleFinance.paymentsLeft,
Expand All @@ -48,18 +31,19 @@ end

---@alias VehicleEntity table

---@class VehicleFinancingEntity
---@field vehicleId integer
---@field balance number
---@field paymentamount number
---@field paymentsleft integer
---@field financetime number

---@param citizenId string
---@return VehicleEntity[]
function FetchVehicleEntitiesByCitizenId(citizenId)
return MySQL.query.await('SELECT * FROM player_vehicles WHERE citizenid = ?', {citizenId})
end

---@param license string
---@return VehicleEntity[]
function FetchVehicleEntitiesByLicense(license)
return MySQL.query.await('SELECT * FROM player_vehicles WHERE license = ?', {license})
end

---@param plate string
---@return VehicleEntity
function FetchVehicleEntityByPlate(plate)
Expand All @@ -74,15 +58,15 @@ function DoesVehicleEntityExist(plate)
end

---@param time number
---@param plate string
function UpdateVehicleEntityFinanceTime(time, plate)
MySQL.update('UPDATE player_vehicles SET financetime = ? WHERE plate = ?', {time, plate})
---@param vehicleId integer
function UpdateVehicleEntityFinanceTime(time, vehicleId)
MySQL.update('UPDATE vehicle_financing SET financetime = ? WHERE vehicleId = ?', {time, vehicleId})
end

---@param vehicleFinance VehicleFinanceServer
---@param plate string
function UpdateVehicleFinance(vehicleFinance, plate)
MySQL.update('UPDATE player_vehicles SET balance = ?, paymentamount = ?, paymentsleft = ?, financetime = ? WHERE plate = ?', {
MySQL.update('UPDATE vehicle_financing AS vf INNER JOIN player_vehicles AS pv ON vf.vehicleId = pv.id SET vf.balance = ?, vf.paymentamount = ?, vf.paymentsleft = ?, vf.financetime = ? WHERE pv.plate = ?', {
vehicleFinance.balance,
vehicleFinance.payment,
vehicleFinance.paymentsLeft,
Expand All @@ -93,18 +77,30 @@ end

---@param citizenId string
---@param license string
---@param plate string
function UpdateVehicleEntityOwner(citizenId, license, plate)
MySQL.update('UPDATE player_vehicles SET citizenid = ?, license = ? WHERE plate = ?', {citizenId, license, plate})
---@param vehicleId integer
function UpdateVehicleEntityOwner(citizenId, license, vehicleId)
MySQL.update('UPDATE player_vehicles SET citizenid = ?, license = ? WHERE id = ?', {citizenId, license, vehicleId})
end

---@param id integer
---@return VehicleFinancingEntity
function FetchFinancedVehicleEntityById(id)
return MySQL.single.await('SELECT * FROM vehicle_financing WHERE vehicleId = ? AND balance > 0 AND financetime < 1', {id})
end

---@param citizenId string
---@return VehicleEntity[]
---@return VehicleFinancingEntity
function FetchFinancedVehicleEntitiesByCitizenId(citizenId)
return MySQL.query.await('SELECT * FROM player_vehicles WHERE citizenid = ? AND balance > 0 AND financetime < 1', {citizenId})
return MySQL.query.await('SELECT vehicle_financing.* FROM vehicle_financing INNER JOIN player_vehicles ON player_vehicles.citizenid = ? WHERE vehicle_financing.vehicleId = player_vehicles.id AND vehicle_financing.balance > 0 AND vehicle_financing.financetime > 1', {citizenId})
end

---@param plate string
function DeleteVehicleEntity(plate)
MySQL.query('DELETE FROM player_vehicles WHERE plate = ?', {plate})
---@param license string
---@return VehicleFinancingEntity
function FetchFinancedVehicleEntitiesByLicense(license)
return MySQL.query.await('SELECT vf.*, p.citizenid FROM vehicle_financing AS vf INNER JOIN players AS p ON p.citizenid = ? INNER JOIN player_vehicles AS pv ON pv.citizenid = p.citizenid AND vf.balance > 0 AND vf.financetime < 1', {license})
end

---@param vehicleId integer
function DeleteVehicleEntity(vehicleId)
exports.qbx_vehicles:DeleteEntityById(vehicleId)
end
47 changes: 9 additions & 38 deletions vehshop.sql
Original file line number Diff line number Diff line change
@@ -1,38 +1,9 @@
CREATE TABLE IF NOT EXISTS `player_vehicles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`license` varchar(50) DEFAULT NULL,
`citizenid` varchar(50) DEFAULT NULL,
`vehicle` varchar(50) DEFAULT NULL,
`hash` varchar(50) DEFAULT NULL,
`mods` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
`plate` varchar(15) NOT NULL,
`fakeplate` varchar(50) DEFAULT NULL,
`garage` varchar(50) DEFAULT 'pillboxgarage',
`fuel` int(11) DEFAULT 100,
`engine` float DEFAULT 1000,
`body` float DEFAULT 1000,
`state` int(11) DEFAULT 1,
`depotprice` int(11) NOT NULL DEFAULT 0,
`drivingdistance` int(50) DEFAULT NULL,
`status` text DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `plate` (`plate`),
KEY `citizenid` (`citizenid`),
KEY `license` (`license`)
) ENGINE=InnoDB AUTO_INCREMENT=1;

ALTER TABLE `player_vehicles`
ADD UNIQUE INDEX UK_playervehicles_plate (plate);

ALTER TABLE `player_vehicles`
ADD CONSTRAINT FK_playervehicles_players FOREIGN KEY (citizenid)
REFERENCES `players` (citizenid) ON DELETE CASCADE ON UPDATE CASCADE;

ALTER TABLE `player_vehicles`
ADD COLUMN `balance` int(11) NOT NULL DEFAULT 0;
ALTER TABLE `player_vehicles`
ADD COLUMN `paymentamount` int(11) NOT NULL DEFAULT 0;
ALTER TABLE `player_vehicles`
ADD COLUMN `paymentsleft` int(11) NOT NULL DEFAULT 0;
ALTER TABLE `player_vehicles`
ADD COLUMN `financetime` int(11) NOT NULL DEFAULT 0;
CREATE TABLE IF NOT EXISTS `vehicle_financing` (
`vehicleId` int(11) NOT NULL,
`balance` int(11) DEFAULT NULL,
`paymentamount` int(11) DEFAULT NULL,
`paymentsleft` int(11) DEFAULT NULL,
`financetime` int(11) DEFAULT NULL,
Manason marked this conversation as resolved.
Show resolved Hide resolved
PRIMARY KEY (`vehicleId`),
FOREIGN KEY `vehicleId` (`vehicleId`) REFERENCES `player_vehicles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Loading