> For the complete documentation index, see [llms.txt](https://jota-dev-documentation.gitbook.io/jota-dev-docs-hidden/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jota-dev-documentation.gitbook.io/jota-dev-docs-hidden/basics/interactive-blocks/configuration/steps-to-configure-oculto.md).

# Steps to configure OCULTO

First, insert the items according to your framework

{% tabs %}
{% tab title="ESX" %}
If you are using esx, insert the items into the database

```sql
INSERT IGNORE INTO `items` (`name`, `label`, `weight`, `rare`, `can_remove`) VALUES
	('bill_1', '1$', 1, 0, 1),
	('bill_10', '10$', 1, 0, 1),
	('bill_100', '100$', 1, 0, 1),
	('bill_20', '20$', 1, 0, 1),
	('bill_5', '5$', 1, 0, 1),
	('bill_50', '50$', 1, 0, 1);
```

{% hint style="warning" %}
Important! Do not add this to the code without replacing the functions; you must replace the functions!
{% endhint %}

Go to the `es_extended/client/function.lua` folder and replace these function:

```lua
---@return table
function ESX.GetPlayerData()
    local data = ESX.PlayerData

    if data then
        data.money = exports['jc_real_money']:GetCash()
    end

    return data
end
```

Go to the `es_extended/server/classes/player.lua` folder and replaces these functions:

```lua
function self.setMoney(money)
    money = ESX.Math.Round(money)
    local current = exports['jc_real_money']:GetCashTotal(self.source)

    if money > current then
        exports['jc_real_money']:AddCash(self.source, money - current)
    elseif money < current then
        exports['jc_real_money']:PayCash(self.source, current - money)
    end
end

function self.getMoney()
    return exports['jc_real_money']:GetCashTotal(self.source)
end

function self.addMoney(money, reason)
    money = ESX.Math.Round(money)
    exports['jc_real_money']:AddCash(self.source, money)
end

function self.removeMoney(money, reason)
    money = ESX.Math.Round(money)
    return exports['jc_real_money']:PayCash(self.source, money)
end 

function self.getAccount(account)
    account = string.lower(account)

    if account == 'money' then
        return {
            name = 'money',
            label = 'Cash',
            money = exports['jc_real_money']:GetCashTotal(self.source),
            round = true,
            index = -1
        }
    end

    for i = 1, #self.accounts do
        if self.accounts[i].name == account then
            return self.accounts[i]
        end
    end

    return nil
end

function self.addAccountMoney(accountName, money, reason)
    reason = reason or "Unknown"
    if not tonumber(money) then
        error(("Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1"):format(accountName, self.playerId, money))
        return
    end
    if money > 0 then
        local account = self.getAccount(accountName)
        if account then
            money = account.round and ESX.Math.Round(money) or money
                
            if accountName == 'money' then
                exports['jc_real_money']:AddCash(self.source, money)
                return
            end

            self.accounts[account.index].money = self.accounts[account.index].money + money

            self.triggerEvent("esx:setAccountMoney", account)
            TriggerEvent("esx:addAccountMoney", self.source, accountName, money, reason)
        else
            error(("Tried To Set Add To Invalid Account ^5%s^1 For Player ^5%s^1!"):format(accountName, self.playerId))
        end
    else
        error(("Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1"):format(accountName, self.playerId, money))
    end
end

function self.removeAccountMoney(accountName, money, reason)
    reason = reason or "Unknown"
    if not tonumber(money) then
        error(("Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1"):format(accountName, self.playerId, money))
        return
    end
    if money > 0 then
        local account = self.getAccount(accountName)

        if account then
            money = account.round and ESX.Math.Round(money) or money

            if accountName == 'money' then
                exports['jc_real_money']:PayCash(self.source, money)
                return
            end

            if self.accounts[account.index].money - money > self.accounts[account.index].money then
                error(("Tried To Underflow Account ^5%s^1 For Player ^5%s^1!"):format(accountName, self.playerId))
                return
            end
            self.accounts[account.index].money = self.accounts[account.index].money - money

            self.triggerEvent("esx:setAccountMoney", account)
            TriggerEvent("esx:removeAccountMoney", self.source, accountName, money, reason)
        else
            error(("Tried To Set Add To Invalid Account ^5%s^1 For Player ^5%s^1!"):format(accountName, self.playerId))
        end
    else
        error(("Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1"):format(accountName, self.playerId, money))
    end
end
```

{% endtab %}

{% tab title="QB-Core" %}
Go to the `qb-core/shared/items.lua` folder and insert the items

```lua
['bill_1'] = {
    name = 'bill_1',
    label = '$1',
    weight = 1,
    type = 'item',
    image = 'bill_1.png',
    unique = false,
    useable = false,
    shouldClose = false,
    combinable = nil,
    description = '1$ bill'
},

['bill_5'] = {
    name = 'bill_5',
    label = '$5',
    weight = 1,
    type = 'item',
    image = 'bill_5.png',
    unique = false,
    useable = false,
    shouldClose = false,
    combinable = nil,
    description = '5$ bill'
},

['bill_10'] = {
    name = 'bill_10',
    label = '$10',
    weight = 1,
    type = 'item',
    image = 'bill_10.png',
    unique = false,
    useable = false,
    shouldClose = false,
    combinable = nil,
    description = '10 dollar bill'
},

['bill_20'] = {
    name = 'bill_20',
    label = '$20',
    weight = 1,
    type = 'item',
    image = 'bill_20.png',
    unique = false,
    useable = false,
    shouldClose = false,
    combinable = nil,
    description = '20$ bill'
},

['bill_50'] = {
    name = 'bill_50',
    label = '$50',
    weight = 1,
    type = 'item',
    image = 'bill_50.png',
    unique = false,
    useable = false,
    shouldClose = false,
    combinable = nil,
    description = '50$ bill'
},

['bill_100'] = {
    name = 'bill_100',
    label = '$100',
    weight = 1,
    type = 'item',
    image = 'bill_100.png',
    unique = false,
    useable = false,
    shouldClose = false,
    combinable = nil,
    description = '100$ bill'
},

```

{% hint style="warning" %}
Important! Do not add this to the code without replacing the functions; you must replace the functions!
{% endhint %}

Go to the `qb-core/client/functions.lua` folder and replace these function:

```lua
function QBCore.Functions.GetPlayerData(cb)
    if QBCore.PlayerData then
        local realCash = exports['jc_real_money']:GetCash()
        QBCore.PlayerData.cash = realCash
    end

    if not cb then
        return QBCore.PlayerData
    end

    cb(QBCore.PlayerData)
end
```

Go to the `qb-core/server/player.lua` folder and replaces these functions:

```lua
function self.Functions.UpdatePlayerData()
    if self.Offline then return end

    self.PlayerData.money.cash = exports['jc_real_money']:GetCashTotal(self.PlayerData.source)

    TriggerEvent('QBCore:Player:SetPlayerData', self.PlayerData)
    TriggerClientEvent('QBCore:Player:SetPlayerData', self.PlayerData.source, self.PlayerData)
end

function self.Functions.AddMoney(moneytype, amount, reason)
    reason = reason or 'unknown'
    moneytype = moneytype:lower()
    amount = tonumber(amount)
    if amount <= 0 then return false end

    if moneytype == 'cash' then
        exports['jc_real_money']:AddCash(self.PlayerData.source, amount)
        return true
    end

    if not self.PlayerData.money[moneytype] then return false end
    self.PlayerData.money[moneytype] += amount

    if not self.Offline then
        self.Functions.UpdatePlayerData()
        TriggerClientEvent('hud:client:OnMoneyChange', self.PlayerData.source, moneytype, amount, false)
        TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'add', reason)
        TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'add', reason)
    end

    return true
end

function self.Functions.RemoveMoney(moneytype, amount, reason)
    reason = reason or 'unknown'
    moneytype = moneytype:lower()
    amount = tonumber(amount)
    if amount <= 0 then return false end

    if moneytype == 'cash' then
        return exports['jc_real_money']:PayCash(self.PlayerData.source, amount)
    end

    if not self.PlayerData.money[moneytype] then return false end
    if self.PlayerData.money[moneytype] - amount < 0 then return false end

    self.PlayerData.money[moneytype] -= amount

    if not self.Offline then
        self.Functions.UpdatePlayerData()
        TriggerClientEvent('hud:client:OnMoneyChange', self.PlayerData.source, moneytype, amount, true)
        TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'remove', reason)
        TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'remove', reason)
    end

    return true
end

function self.Functions.GetMoney(moneytype)
    if not moneytype then return false end
    moneytype = moneytype:lower()

    if moneytype == 'cash' then
        return exports['jc_real_money']:GetCashTotal(self.PlayerData.source)
    end

    return self.PlayerData.money[moneytype]
end

function self.Functions.SetMoney(moneytype, amount, reason)
    reason = reason or 'unknown'
    moneytype = moneytype:lower()
    amount = tonumber(amount)
    if amount < 0 then return false end

    if moneytype == 'cash' then
        self.PlayerData.money.cash = exports['jc_real_money']:GetCashTotal(self.PlayerData.source)

        if not self.Offline then
            self.Functions.UpdatePlayerData()
        end

        return true
    end

    if not self.PlayerData.money[moneytype] then return false end
    self.PlayerData.money[moneytype] = amount

    if not self.Offline then
        self.Functions.UpdatePlayerData()
        TriggerClientEvent('QBCore:Client:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'set', reason)
        TriggerEvent('QBCore:Server:OnMoneyChange', self.PlayerData.source, moneytype, amount, 'set', reason)
    end

    return true
end

```

{% endtab %}

{% tab title="QBox" %}
Insert the items into `ox_intentory/data/items.lua`

```lua
	['bill_100'] = {
		label = '$100',
		weight = 1,
		stack = true,
	},

	['bill_50'] = {
		label = '$50',
		weight = 1,
		stack = true,
	},

	['bill_20'] = {
		label = '$20',
		weight = 1,
		stack = true,
	},

	['bill_10'] = {
		label = '$10',
		weight = 1,
		stack = true,
	},

	['bill_5'] = {
		label = '$5',
		weight = 1,
		stack = true,
	},

	['bill_1'] = {
		label = '$1',
		weight = 1,
		stack = true,
	},
```

{% hint style="warning" %}
Important! Do not add this to the code without replacing the functions; you must replace the functions!
{% endhint %}

Now go to `qbx_core/client/functions.lua` and replace the following functions:

```lua
function GetPlayerData()
    if QBX.PlayerData then
        QBX.PlayerData.cash = exports['jc_real_money']:GetCash()
    end

    return QBX.PlayerData
end
```

Now go to `qbx_core/server/player.lua` and replace the following functions:

```lua
---@param identifier Source | string
function UpdatePlayerData(identifier)
    local player = type(identifier) == 'string'
        and (GetPlayerByCitizenId(identifier) or GetOfflinePlayer(identifier))
        or GetPlayer(identifier)

    if not player or player.Offline then return end

    local realCash = exports.jc_real_money:GetCashTotal(player.PlayerData.source)
    player.PlayerData.money.cash = realCash

    TriggerEvent('QBCore:Player:SetPlayerData', player.PlayerData)
    TriggerClientEvent('QBCore:Player:SetPlayerData', player.PlayerData.source, player.PlayerData)
end

---@param source Source
---@param playerMoney table
---@param moneyType MoneyType
---@param amount number
---@param actionType 'add' | 'remove' | 'set'
---@param reason? string
---@param difference?  
local function emitMoneyEvents(source, playerMoney, moneyType, amount, actionType, reason, difference)
    local isSet = actionType == 'set'
    local isRemove = actionType == 'remove'

    TriggerClientEvent('hud:client:OnMoneyChange', source, moneyType, isSet and math.abs(difference) or amount, isSet and difference < 0 or isRemove, reason)
    TriggerClientEvent('QBCore:Client:OnMoneyChange', source, moneyType, amount, actionType, reason)
    TriggerEvent('QBCore:Server:OnMoneyChange', source, moneyType, amount, actionType, reason)

    if moneyType == 'bank' and isRemove then
        TriggerClientEvent('qb-phone:client:RemoveBankMoney', source, amount)
    end
end

---@param identifier Source | string
---@param moneyType MoneyType
---@param amount number
---@param reason? string
---@return boolean success if money was added
function AddMoney(identifier, moneyType, amount, reason)
    local player = type(identifier) == 'string'
        and (GetPlayerByCitizenId(identifier) or GetOfflinePlayer(identifier))
        or GetPlayer(identifier)

    if not player then return false end

    reason = reason or 'unknown'
    amount = qbx.math.round(tonumber(amount))

    if amount < 0 or not player.PlayerData.money[moneyType] then return false end

    if not triggerEventHooks('addMoney', {
        source = player.PlayerData.source,
        moneyType = moneyType,
        amount = amount
    }) then return false end

    player.PlayerData.money[moneyType] += amount

    if player.Offline then
        SaveOffline(player.PlayerData)
    else
        if moneyType == 'cash' then
            exports.jc_real_money:AddCash(player.PlayerData.source, amount)
        end

        UpdatePlayerData(identifier)

        local tags = amount > 100000 and config.logging.role or nil
        local resource = GetInvokingResource() or cache.resource

        logger.log({
            source = resource,
            webhook = config.logging.webhook['playermoney'],
            event = 'AddMoney',
            color = 'lightgreen',
            tags = tags,
            message = ('**%s (citizenid: %s | id: %s)** $%s (%s) added, new %s balance: $%s reason: %s'):format(
                GetPlayerName(player.PlayerData.source),
                player.PlayerData.citizenid,
                player.PlayerData.source,
                amount,
                moneyType,
                moneyType,
                player.PlayerData.money[moneyType],
                reason
            ),
        })

        emitMoneyEvents(player.PlayerData.source, player.PlayerData.money, moneyType, amount, 'add', reason)
    end

    return true
end

---@param identifier Source | string
---@param moneyType MoneyType
---@param amount number
---@param reason? string
---@return boolean success if money was removed
function RemoveMoney(identifier, moneyType, amount, reason)
    local player = type(identifier) == 'string'
        and (GetPlayerByCitizenId(identifier) or GetOfflinePlayer(identifier))
        or GetPlayer(identifier)

    if not player then return false end

    reason = reason or 'unknown'
    amount = qbx.math.round(tonumber(amount))

    if amount < 0 or not player.PlayerData.money[moneyType] then return false end

    if not triggerEventHooks('removeMoney', {
        source = player.PlayerData.source,
        moneyType = moneyType,
        amount = amount
    }) then return false end

    for _, mType in pairs(config.money.dontAllowMinus) do
        if mType == moneyType then
            if (player.PlayerData.money[moneyType] - amount) < 0 then
                return false
            end
        end
    end

    player.PlayerData.money[moneyType] -= amount

    if player.Offline then
        SaveOffline(player.PlayerData)
    else
        if moneyType == 'cash' then
            local success = exports.jc_real_money:PayCash(player.PlayerData.source, amount)
            if not success then
                return false
            end
        end

        UpdatePlayerData(identifier)

        local tags = amount > 100000 and config.logging.role or nil
        local resource = GetInvokingResource() or cache.resource

        logger.log({
            source = resource,
            webhook = config.logging.webhook['playermoney'],
            event = 'RemoveMoney',
            color = 'red',
            tags = tags,
            message = ('** %s (citizenid: %s | id: %s)** $%s (%s) removed, new %s balance: $%s reason: %s'):format(
                GetPlayerName(player.PlayerData.source),
                player.PlayerData.citizenid,
                player.PlayerData.source,
                amount,
                moneyType,
                moneyType,
                player.PlayerData.money[moneyType],
                reason
            ),
        })

        emitMoneyEvents(player.PlayerData.source, player.PlayerData.money, moneyType, amount, 'remove', reason)
    end

    return true
end

---@param identifier Source | string
---@param moneyType MoneyType
---@param amount number
---@param reason? string
---@return boolean success if money was set
function SetMoney(identifier, moneyType, amount, reason)
    local player = type(identifier) == 'string'
        and (GetPlayerByCitizenId(identifier) or GetOfflinePlayer(identifier))
        or GetPlayer(identifier)

    if not player then return false end

    reason = reason or 'unknown'
    amount = qbx.math.round(tonumber(amount))
    local oldAmount = player.PlayerData.money[moneyType]

    if amount < 0 or oldAmount == nil then return false end

    if not triggerEventHooks('setMoney', {
        source = player.PlayerData.source,
        moneyType = moneyType,
        amount = amount
    }) then return false end

    if player.Offline then
        player.PlayerData.money[moneyType] = amount
        SaveOffline(player.PlayerData)
        return true
    end

    if moneyType == 'cash' then
        player.PlayerData.money.cash = exports.jc_real_money:GetCashTotal(player.PlayerData.source)
    else
        player.PlayerData.money[moneyType] = amount
    end

    UpdatePlayerData(identifier)

    emitMoneyEvents(
        player.PlayerData.source,
        player.PlayerData.money,
        moneyType,
        amount,
        'set',
        reason,
        amount - oldAmount
    )

    return true
end

---@param identifier Source | string
---@param moneyType MoneyType
---@return boolean | number amount or false if moneytype does not exist
function GetMoney(identifier, moneyType)
    if not moneyType then return false end
    local player = type(identifier) == 'string' and (GetPlayerByCitizenId(identifier) or GetOfflinePlayer(identifier)) or GetPlayer(identifier)
    if not player then return false end

    if moneyType == 'cash' then
        return exports.jc_real_money:GetCashTotal(player.PlayerData.source)
    end

    return player.PlayerData.money[moneyType]
end
```

{% endtab %}
{% endtabs %}

Configure everything according to your inventory ->
