Last active
July 18, 2025 22:41
-
-
Save ISKinGeR/2ea3077d338a8864f9636147d4468f14 to your computer and use it in GitHub Desktop.
Adding the Handling function for pending Shop Deposits for mythic framework (not professional but it work fine!)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- replace DoMerge & DoMove in ur inventory.lua | |
-- path: resources\[mythic]\mythic-inventory\server\inventory.lua | |
-- KR method <3 | |
-- DoMerge function | |
function DoMerge(source, data, cb) | |
CreateThread(function() | |
local player = Fetch:Source(source) | |
local char = player:GetData("Character") | |
local item = itemsDatabase[data.name] | |
local cash = char:GetData("Cash") | |
local entityFrom = LoadedEntitys[tonumber(data.invTypeFrom)] | |
local entityTo = LoadedEntitys[tonumber(data.invTypeTo)] | |
local invWeight = Inventory.Items:GetWeights(data.ownerTo, data.invTypeTo) | |
local totWeight = invWeight + (data.countTo * itemsDatabase[data.name].weight) | |
if data.ownerFrom == nil or data.slotFrom == nil or data.invTypeFrom == nil or data.ownerTo == nil or data.slotTo == nil or data.invTypeTo == nil then | |
cb({ reason = "Invalid Move Data" }) | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
return | |
end | |
if totWeight > getCapacity(data.invTypeTo, data.vehClassTo, data.vehModelTo, data.capacityOverrideTo) and data.ownerFrom ~= data.ownerTo then | |
cb({ reason = "Inventory Over Weight" }) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
return | |
end | |
if data.countTo <= 0 then | |
cb({ reason = "Can't Move 0 - Naughty Boy" }) | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
return | |
end | |
if entityFrom.shop then | |
local cost = math.ceil((item.price * tonumber(data.countTo))) | |
local paymentType = (cash >= cost and 'cash' or (Banking.Balance:Has(char:GetData("BankAccount"), cost) and 'bank' or nil)) | |
if entityFrom.free or paymentType ~= nil then | |
if -- Check if the item is either not a gun, or if it is that they have a Weapons license | |
(item.type ~= 2 | |
or ( | |
item.type == 2 | |
and (not item.requiresLicense or item.requiresLicense and Weapons:IsEligible(source)) | |
)) | |
and (not item.qualification or hasValue(char:GetData("Qualifications"), item.qualification)) | |
then | |
local paid = entityFrom.free | |
if not paid then | |
if paymentType == 'cash' then | |
paid = Wallet:Modify(source, -(math.abs(cost))) | |
else | |
paid = Banking.Balance:Charge(char:GetData("BankAccount"), cost, { | |
type = 'bill', | |
title = 'Store Purchase', | |
description = string.format('Bought x%s %s', data.countTo, item.label), | |
data = {} | |
}) | |
Phone.Notification:Add(source, "Bill Payment Successful", false, os.time() * 1000, 3000, "bank", {}) | |
end | |
if paid then | |
local isOwned = tonumber(data.ownerFrom:match("^shop:(%d+)$")) or false | |
local moneyShitForOwner = isOwned or entityFrom.id | |
local priceforStore = (cost * STORE_SHARE_AMOUNT) / tonumber(data.countTo) | |
local datatableForStore = string.format("%s %s ($%s/each)", data.countTo, data.name, priceforStore) | |
local function updateDeposit(accountKey, amount, isGov, shopName, itemCount, dataEntry) | |
pendingShopDeposits[accountKey] = pendingShopDeposits[accountKey] or { amount = 0, transactions = 0, itemsCount = 0, DATA = {} } | |
pendingShopDeposits[accountKey].amount += amount | |
pendingShopDeposits[accountKey].transactions += 1 | |
pendingShopDeposits[accountKey].itemsCount += itemCount | |
pendingShopDeposits[accountKey].shopname = shopName | |
pendingShopDeposits[accountKey].isGov = isGov or false | |
table.insert(pendingShopDeposits[accountKey].DATA, dataEntry) | |
end | |
local ownerAmount = math.floor(cost * STORE_SHARE_AMOUNT) | |
updateDeposit(storeBankAccounts[moneyShitForOwner], ownerAmount, false, data.ownerFrom, data.countTo, datatableForStore) | |
local govAmount = math.ceil(cost * (1.0 - STORE_SHARE_AMOUNT)) | |
updateDeposit(_govAccount, govAmount, true, data.ownerFrom, data.countTo, datatableForStore) | |
end | |
end | |
if paid then | |
local insData = Inventory:CreateItem(char:GetData("SID"), data.name, data.countTo, data.slotTo, {}, data.invTypeTo, false) | |
CreateStoreLog(data.ownerFrom, data.name, data.countTo or 1, char:GetData("SID"), insData.metadata, insData.id) | |
end | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
return cb({ success = true }) | |
else | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
cb({ reason = "Ineligible To Purchase Item" }) | |
end | |
else | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
cb({ reason = "Not Enough Cash" }) | |
end | |
else | |
local slotFrom = Inventory:GetSlot(data.ownerFrom, data.slotFrom, data.invTypeFrom) | |
local slotTo = Inventory:GetSlot(data.ownerTo, data.slotTo, data.invTypeTo) | |
if slotFrom == nil or slotTo == nil then | |
cb({ reason = "Item No Longer In That Slot" }) | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
return | |
end | |
MySQL.query.await('UPDATE inventory SET slot = ?, name = ?, dropped = ? WHERE name = ? AND slot = ? AND item_id = ?', { | |
data.slotTo, | |
string.format("%s-%s", data.ownerTo, data.invTypeTo), | |
data.invTypeTo == 10 and 1 or 0, | |
string.format("%s-%s", data.ownerFrom, data.invTypeFrom), | |
data.slotFrom, | |
data.name, | |
}) | |
if data.ownerFrom ~= data.ownerTo then | |
if data.invTypeFrom == 1 then | |
local plyr = Fetch:SID(data.ownerFrom) | |
if data.ownerFrom == data.ownerTo then | |
if item.type == 2 then | |
if (not item.isStackable and item.isStackable ~= -1) or data.countTo == slotFrom.Count then | |
TriggerClientEvent( | |
"Weapons:Client:Move", | |
plyr:GetData("Source"), | |
data.slotFrom, | |
data.slotTo | |
) | |
end | |
if item.isThrowable then | |
TriggerClientEvent( | |
"Weapons:Client:UpdateCount", | |
plyr:GetData("Source"), | |
data.slotFrom, | |
(slotFrom.Count - data.countTo) | |
) | |
TriggerClientEvent( | |
"Weapons:Client:UpdateCount", | |
plyr:GetData("Source"), | |
data.slotTo, | |
((slotTo?.Count or 0) + data.countTo) | |
) | |
end | |
elseif item.type == 10 then | |
TriggerClientEvent( | |
"Inventory:Container:Move", | |
plyr:GetData("Source"), | |
data.slotFrom, | |
data.slotTo | |
) | |
end | |
else | |
if not item.isStackable or data.countTo == slotFrom.Count then | |
if item.type == 2 then | |
TriggerClientEvent( | |
"Weapons:Client:Remove", | |
plyr:GetData("Source"), | |
slotFrom, | |
data.slotFrom, | |
{ | |
owner = data.ownerTo, | |
type = data.invTypeTo, | |
slot = data.slotTo, | |
} | |
) | |
elseif item.type == 10 then | |
TriggerClientEvent( | |
"Inventory:Container:Remove", | |
plyr:GetData("Source"), | |
slotFrom, | |
data.slotFrom | |
) | |
end | |
else | |
if item.isThrowable then | |
TriggerClientEvent( | |
"Weapons:Client:UpdateCount", | |
plyr:GetData("Source"), | |
data.slotFrom, | |
(slotFrom.Count - data.countTo) | |
) | |
end | |
end | |
end | |
end | |
if data.invTypeTo == 1 then | |
local plyr = Fetch:SID(data.ownerTo) | |
if item.isThrowable then | |
TriggerClientEvent( | |
"Weapons:Client:UpdateCount", | |
plyr:GetData("Source"), | |
data.slotTo, | |
((slotTo?.Count or 0) + data.countTo) | |
) | |
end | |
end | |
if data.inventory.position ~= nil then | |
CreateDZIfNotExist(source, data.inventory.position) | |
end | |
end | |
if data.ownerFrom ~= data.ownerTo and WEAPON_PROPS[item.name] ~= nil then | |
_refreshAttchs[data.ownerFrom] = source | |
_refreshAttchs[data.ownerTo] = source | |
end | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
return cb({ success = true }) | |
end | |
end) | |
end | |
-- DoMove function | |
function DoMove(source, data, cb) | |
CreateThread(function() | |
local player = Fetch:Source(source) | |
local char = player:GetData("Character") | |
local item = itemsDatabase[data.name] | |
local cash = char:GetData("Cash") | |
local entityFrom = LoadedEntitys[tonumber(data.invTypeFrom)] | |
local entityTo = LoadedEntitys[tonumber(data.invTypeTo)] | |
local invWeight = Inventory.Items:GetWeights(data.ownerTo, data.invTypeTo) | |
local totWeight = invWeight + (data.countTo * itemsDatabase[data.name].weight) | |
if data.ownerFrom == nil or data.slotFrom == nil or data.invTypeFrom == nil or data.ownerTo == nil or data.slotTo == nil or data.invTypeTo == nil then | |
cb({ reason = "Invalid Move Data" }) | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
return | |
end | |
if totWeight > getCapacity(data.invTypeTo, data.vehClassTo, data.vehModelTo, data.capacityOverrideTo) and data.ownerFrom ~= data.ownerTo then | |
cb({ reason = "Inventory Over Weight" }) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
return | |
end | |
if data.countTo <= 0 then | |
cb({ reason = "Can't Move 0 - Naughty Boy" }) | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
return | |
end | |
if entityFrom.shop then | |
local cost = math.ceil((item.price * tonumber(data.countTo))) | |
local paymentType = (cash >= cost and 'cash' or (Banking.Balance:Has(char:GetData("BankAccount"), cost) and 'bank' or nil)) | |
if entityFrom.free or paymentType ~= nil then | |
if -- Check if the item is either not a gun, or if it is that they have a Weapons license | |
(item.type ~= 2 | |
or ( | |
item.type == 2 | |
and (not item.requiresLicense or item.requiresLicense and Weapons:IsEligible(source)) | |
)) | |
and (not item.qualification or hasValue(char:GetData("Qualifications"), item.qualification)) | |
then | |
local paid = entityFrom.free | |
if not paid then | |
if paymentType == 'cash' then | |
paid = Wallet:Modify(source, -(math.abs(cost))) | |
else | |
paid = Banking.Balance:Charge(char:GetData("BankAccount"), cost, { | |
type = 'bill', | |
title = 'Store Purchase', | |
description = string.format('Bought x%s %s', data.countTo, item.label), | |
data = {} | |
}) | |
Phone.Notification:Add(source, "Bill Payment Successful", string.format('Bought x%s %s', data.countTo, item.label), os.time() * 1000, 3000, "bank", {}) | |
end | |
if paid then | |
local isOwned = tonumber(data.ownerFrom:match("^shop:(%d+)$")) or false | |
local moneyShitForOwner = isOwned or entityFrom.id | |
local priceforStore = (cost * STORE_SHARE_AMOUNT) / tonumber(data.countTo) | |
local datatableForStore = string.format("%s %s ($%s/each)", data.countTo, data.name, priceforStore) | |
local function updateDeposit(accountKey, amount, isGov, shopName, itemCount, dataEntry) | |
pendingShopDeposits[accountKey] = pendingShopDeposits[accountKey] or { amount = 0, transactions = 0, itemsCount = 0, DATA = {} } | |
pendingShopDeposits[accountKey].amount += amount | |
pendingShopDeposits[accountKey].transactions += 1 | |
pendingShopDeposits[accountKey].itemsCount += itemCount | |
pendingShopDeposits[accountKey].shopname = shopName | |
pendingShopDeposits[accountKey].isGov = isGov or false | |
table.insert(pendingShopDeposits[accountKey].DATA, dataEntry) | |
end | |
local ownerAmount = math.floor(cost * STORE_SHARE_AMOUNT) | |
updateDeposit(storeBankAccounts[moneyShitForOwner], ownerAmount, false, data.ownerFrom, data.countTo, datatableForStore) | |
local govAmount = math.ceil(cost * (1.0 - STORE_SHARE_AMOUNT)) | |
updateDeposit(_govAccount, govAmount, true, data.ownerFrom, data.countTo, datatableForStore) | |
end | |
end | |
if paid then | |
local insData = Inventory:CreateItem(char:GetData("SID"), data.name, data.countTo, data.slotTo, {}, data.invTypeTo, false) | |
CreateStoreLog(data.ownerFrom, data.name, data.countTo or 1, char:GetData("SID"), insData.metadata, insData.id) | |
end | |
if data.ownerFrom ~= data.ownerTo and WEAPON_PROPS[item.name] ~= nil then | |
_refreshAttchs[data.ownerFrom] = source | |
_refreshAttchs[data.ownerTo] = source | |
end | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
return cb({ success = true }) | |
else | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
cb({ reason = "Ineligible To Purchase Item" }) | |
end | |
else | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
cb({ reason = "Not Enough Cash" }) | |
end | |
else | |
local slotFrom = Inventory:GetSlot(data.ownerFrom, data.slotFrom, data.invTypeFrom) | |
local slotTo = Inventory:GetSlot(data.ownerTo, data.slotTo, data.invTypeTo) | |
if slotFrom == nil then | |
cb({ reason = "Item No Longer In That Slot" }) | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
return | |
end | |
if data.isSplit then | |
local itemIds = MySQL.query.await('SELECT id FROM inventory WHERE name = ? AND slot = ? AND item_id = ? ORDER BY id ASC LIMIT ?', { | |
string.format("%s-%s", data.ownerFrom, data.invTypeFrom), | |
data.slotFrom, | |
data.name, | |
data.countTo | |
}) | |
local params = {} | |
for k, v in ipairs(itemIds) do | |
table.insert(params, v.id) | |
end | |
MySQL.query.await(string.format('UPDATE inventory SET slot = ?, name = ?, dropped = ? WHERE id IN (%s)', table.concat(params, ',')), { | |
data.slotTo, | |
string.format("%s-%s", data.ownerTo, data.invTypeTo), | |
data.invTypeTo == 10 and 1 or 0 | |
}) | |
else | |
MySQL.query.await('UPDATE inventory SET slot = ?, name = ?, dropped = ? WHERE name = ? AND slot = "?" AND item_id = ?', { | |
data.slotTo, | |
string.format("%s-%s", data.ownerTo, data.invTypeTo), | |
(data.invTypeTo == 10 and 1 or 0), | |
string.format("%s-%s", data.ownerFrom, data.invTypeFrom), | |
data.slotFrom, | |
data.name, | |
}) | |
end | |
if data.ownerFrom ~= data.ownerTo then | |
if data.invTypeFrom == 1 then | |
local plyr = Fetch:SID(data.ownerFrom) | |
if data.ownerFrom == data.ownerTo then | |
if item.type == 2 then | |
if (not item.isStackable and item.isStackable ~= -1) or data.countTo == slotFrom.Count then | |
TriggerClientEvent( | |
"Weapons:Client:Move", | |
plyr:GetData("Source"), | |
data.slotFrom, | |
data.slotTo | |
) | |
end | |
if item.isThrowable then | |
TriggerClientEvent( | |
"Weapons:Client:UpdateCount", | |
plyr:GetData("Source"), | |
data.slotFrom, | |
(slotFrom.Count - data.countTo) | |
) | |
TriggerClientEvent( | |
"Weapons:Client:UpdateCount", | |
plyr:GetData("Source"), | |
data.slotTo, | |
((slotTo?.Count or 0) + data.countTo) | |
) | |
end | |
elseif item.type == 10 then | |
TriggerClientEvent( | |
"Inventory:Container:Move", | |
plyr:GetData("Source"), | |
data.slotFrom, | |
data.slotTo | |
) | |
end | |
else | |
if not item.isStackable or data.countTo == slotFrom.Count then | |
if item.type == 2 then | |
TriggerClientEvent( | |
"Weapons:Client:Remove", | |
plyr:GetData("Source"), | |
slotFrom, | |
data.slotFrom, | |
{ | |
owner = data.ownerTo, | |
type = data.invTypeTo, | |
slot = data.slotTo, | |
} | |
) | |
elseif item.type == 10 then | |
TriggerClientEvent( | |
"Inventory:Container:Remove", | |
plyr:GetData("Source"), | |
slotFrom, | |
data.slotFrom | |
) | |
end | |
else | |
if item.isThrowable then | |
TriggerClientEvent( | |
"Weapons:Client:UpdateCount", | |
plyr:GetData("Source"), | |
data.slotFrom, | |
(slotFrom.Count - data.countTo) | |
) | |
end | |
end | |
end | |
end | |
if data.invTypeTo == 1 then | |
local plyr = Fetch:SID(data.ownerTo) | |
if item.isThrowable then | |
TriggerClientEvent( | |
"Weapons:Client:UpdateCount", | |
plyr:GetData("Source"), | |
data.slotTo, | |
((slotTo?.Count or 0) + data.countTo) | |
) | |
end | |
end | |
if data.inventory.position ~= nil then | |
CreateDZIfNotExist(source, data.inventory.position) | |
end | |
end | |
if data.ownerFrom ~= data.ownerTo and WEAPON_PROPS[item.name] ~= nil then | |
_refreshAttchs[data.ownerFrom] = source | |
_refreshAttchs[data.ownerTo] = source | |
end | |
sendRefreshForClient(source, data.ownerFrom, data.invTypeFrom, data.slotFrom) | |
sendRefreshForClient(source, data.ownerTo, data.invTypeTo, data.slotTo) | |
return cb({ success = true }) | |
end | |
end) | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- put this in ur Startup.lua, not matter which line just put it there | |
-- path: resources\[mythic]\mythic-inventory\server\startup.lua | |
-- KR method <3 | |
Citizen.CreateThread(function() | |
while true do | |
local depositsToProcess = pendingShopDeposits | |
pendingShopDeposits = {} | |
if depositsToProcess and next(depositsToProcess) then | |
for accountId, depositData in pairs(depositsToProcess) do | |
local f = Banking.Accounts:Get(accountId) | |
if f ~= nil then | |
local description = string.format( | |
"%s - Sold %d items", | |
depositData.shopname or "Unknown", | |
depositData.itemsCount or 0 | |
) | |
local title = depositData.tax and "Shop Tax" or "Shop Earnings" | |
local dataDetails = {} | |
if depositData.DATA and type(depositData.DATA) == "table" then | |
for _, detail in ipairs(depositData.DATA) do | |
table.insert(dataDetails, detail) | |
end | |
end | |
Banking.Balance:Deposit(f.Account, tonumber(depositData.amount), { | |
type = "deposit", | |
title = title, | |
description = description, | |
data = dataDetails, | |
}, true) | |
else | |
Logger:Error("Banking", string.format("Account ID %s not found for pending deposit.", accountId)) | |
end | |
end | |
end | |
Citizen.Wait(60 * 1000 * 10) | |
end | |
end) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment