📝Configuration

Client Config

Config = {}

RegisterCommand('orgpanel', function()
    openPanel()
end)

Config.tabletEntity = nil -- DO NOT CHANGE
Config.tabletModel = "prop_cs_tablet"
Config.tabletDict = "amb@world_human_seat_wall_tablet@female@base"
Config.tabletAnim = "base"

Config.startTabletAnimation = function()
    lib.requestAnimDict(Config.tabletDict)
    if Config.tabletEntity then
        Config.stopTabletAnimation()
    end
    lib.requestModel(Config.tabletModel)
    Config.tabletEntity = CreateObject(GetHashKey(Config.tabletModel), 1.0, 1.0, 1.0, 1, 1, 0)
    AttachEntityToEntity(Config.tabletEntity, cache.ped, GetPedBoneIndex(cache.ped, 57005), 0.12, 0.10, -0.13, 25.0, 170.0, 160.0, true, true, false, true, 1, true)
    TaskPlayAnim(cache.ped, Config.tabletDict, Config.tabletAnim, 8.0, -8.0, -1, 50, 0, false, false, false)
end


Config.stopTabletAnimation = function()
	if Config.tabletEntity then
		StopAnimTask(cache.ped, Config.tabletDict, Config.tabletAnim ,8.0, -8.0, -1, 50, 0, false, false, false)
		DeleteEntity(Config.tabletEntity)
		Config.tabletEntity = nil
	end
end

Config.showNotification = function(msg)
    lib.notify({
        title = 'Organization Panel',
        description = msg,
        type = 'inform'
    })
end

Config.peds = { -- peds where you can create organization
    {
        coords = vec3(939.5922, -1490.5969, 30.0927),
        model = 'a_m_m_og_boss_01',
        heading = 180.0
    }
}

Config.pedinteraction = function(ped)
    exports.ox_target:addBoxZone({
        coords = ped.coords,
        size = vec3(1, 1, 2),
        rotation = 340,
        debug = drawZones,
        options = {
            {
                icon = 'fas fa-sitemap',
                label = 'Create an organization',
                distance = 2.0,
                onSelect = function(data)
                    Framework.TriggerServerCallback('pp-orgpanel:getorganization', function(isinorganization) 
                        Config.createOrganization(isinorganization)
                    end)
                end
            },
            {
                icon = 'fas fa-dollar-sign',
                label = "Deposit cash into the organization's account",
                distance = 2.0,
                onSelect = function(data)
                    Framework.TriggerServerCallback('pp-orgpanel:getorganization', function(isinorganization) 
                        Config.depositCash(isinorganization)
                    end)
                end
            },
        }
    })
end

Config.createOrganization = function(isinorganization)
    if isinorganization then
        return Config.showNotification('You are already in organization!')
    end
    local input = lib.inputDialog('Create organization', {
        {type = 'input', label = 'Organization name', description = 'Cost: 40.000$', required = true, max = 10},
    })
    if not input then return end
    TriggerServerEvent('pp-orgpanel:createneworg', input[1])
end

Config.depositCash = function(isinorganization)
    if not isinorganization then
        return Config.showNotification('You are not in any organization!')
    end
    local input = lib.inputDialog('Deposit cash', {
        {type = 'number', label = 'Deposit amount', required = true, min = 0},
    })
    if not input then return end
    TriggerServerEvent('pp-orgpanel:sendmoney', input[1])
end

lib.callback.register('rc-orgpanel:addmember', function(orgname, name)
    local alert = lib.alertDialog({
        header = 'Atention!',
        content = name .. ' invited you to join organization ' .. orgname .. ', do you want to join?',
        centered = true,
        cancel = true
    })
    return alert == 'confirm' and true or false
end)

Config.createStash = function(stash)
    exports.ox_target:addBoxZone({
        coords = stash.coords,
        size = stash.size,
        rotation = stash.rotation,
        debug = false,
        options = {
            {
                icon = 'fa-solid fa-hands',
                label = t('backend.open_stash'),
                distance = 2.0,
                onSelect = function()
                    exports.ox_inventory:openInventory('stash', 'orgstash_' .. stash.name)
                end
            }
        }
    })
end

Server Config

Config = {}

Config.ESXEvent = nil -- fill only when using older ESX version

Config.Locales = 'en'

Config.interiors = {
    enabled = true,
    registerstash = function(result)
        local szafki = {}
        for _, data in pairs(result) do
            local coords = json.decode(data.coords)
            local upgrades = data.upgrades and json.decode(data.upgrades) or {}

            local capacity = 100000
            local slots = 50

            if doesinteriorhaveupgrade(upgrades, 'weight') then
                capacity = 200000
            end
            if doesinteriorhaveupgrade(upgrades, 'slots2') then
                slots = 150
            elseif doesinteriorhaveupgrade(upgrades, 'slots') then
                slots = 100
            end


            table.insert(szafki, {coords = coords, name = data.name, slots = slots, capacity = capacity})
        end

        for _, stash in pairs(szafki) do
            exports.ox_inventory:RegisterStash('orgstash_' .. stash.name, 'Organization stash', stash.slots, stash.capacity, false)
        end
    end,
    stashes = { -- this is synced with database, removing any values here will remove them from the database as well
        ['interior1'] = {
            size = vec3(1.20000004768371, 0.60000002384185, 3.0),
            coords = vec3(746.5399780273438, -1781.989990234375, 36.54000091552734),
            rotation = 90,
            doorlock = 'interior1'
        }
    }
}

Config.levels = { -- progress levels on the home page
    [1] = {
        expMin = 0,
        expMax = 100,
    },
    [2] = {
        expMin = 101,
        expMax = 200,
    },
    [3] = {
        expMin = 201,
        expMax = 300,
    }
}

Config.managementAccess = function(src) -- specifies access to the management tab
    return false
end

Config.rankOrder = { -- grades in members tab
    ["Boss"] = 1,
    ["Deputy boss"] = 2,
    ["Senior member"] = 3,
    ["Member"] = 4,
    ["Beginner"] = 5
} 

Config.startMembers = 5 -- maximum members count when creating organization

Config.search = 'ssn' -- ssn | id (server id)

Config.OrgCreationCost = 40000 -- cost of creating organization (in cash)

Config.defaultWalletData = {bank = {value = 0, unit = '$'}} -- data in the wallet set when creating the organization

Config.GenerateAccountNumber = function()
    local first = math.random(100, 999)
    local second = math.random(100, 999)
    return first .. '-' .. second
end

Config.TransferFunction = function(src, identifier, amount, name)
    local export = exports.pefcl:addBankBalanceByIdentifier(src, { identifier = identifier, amount = amount, message = 'Transfer from ' .. name })
    if export and export.status and export.status == 'ok' then
        return true
    else
        return false
    end
end

Config.Queries = {
    ['identifierbyssn'] = 'SELECT identifier FROM users WHERE ssn = @ssn',
    ['namebyidentifier'] = 'SELECT firstname, lastname FROM users WHERE identifier = @identifier',
    ['nameandjoindate'] = 'SELECT u.firstname, u.lastname, om.join_date FROM organization_members om JOIN users u ON om.user_id = u.identifier WHERE om.org_id = @org_id',
    ['members'] = [[
        SELECT om.user_id, om.permissions, om.join_date, u.firstname, u.lastname, om.rank, 
        CASE WHEN o.owner_id = om.user_id THEN TRUE ELSE FALSE END AS isOwner
        FROM organization_members om
        INNER JOIN users u ON u.identifier = om.user_id
        LEFT JOIN organizations o ON o.id = om.org_id
        WHERE om.org_id = @org_id        
    ]],
    ['transactions'] = [[
        SELECT ot.*, u.firstname, u.lastname 
        FROM organization_transactions ot
        LEFT JOIN users u ON u.identifier = ot.user_id
        WHERE ot.org_id = @org_id ORDER BY ot.date DESC LIMIT 30
    ]]

}

Config.canCreateOrganization = function(orgname, ownerId, cb)
    cb({success = true, message = ''}) -- message is displaying as error in modal
end


Config.showNotification = function(source, msg)
    TriggerClientEvent('ox_lib:notify', source, {
        title = 'Organization Panel',
        description = msg,
        type = 'inform'
    })
end



Config.upgrades = {
    {
        name = 'unlocked_wallet', -- name (not seen by players)
        title = 'Wallet', 
        description = 'Unlocks the wallet panel.', 
        icon = 'fas fa-wallet', -- fontawesome icon (https://fontawesome.com/search?o=r&m=free)
        --cost = {value =  100, type = 'crypto'}, -- organization wallet
        canBuy = function(source) 
            local count = exports.ox_inventory:Search(source, 'count', 'pendrive_wlt')
            if count == 0 then
                return {success = false, message = "You don't have required item."}
            else
                return {success = true, message = ''}
            end
        end,
        onBuy = function(orgid, src, cb)
            local count = exports.ox_inventory:Search(src, 'count', 'pendrive_wlt')
            if count == 0 then
                cb({success = false, message = "You don't have required item."})
            else
                local success, info = exports.ox_inventory:RemoveItem(src, 'pendrive_wlt', 1)
                cb({success = true, message = ''})
            end
        end
    },
    {
        name = 'members_upgrade_10',
        title = 'Members',
        description = 'Increases the maximum number of members from 5 to 10.',
        icon = 'fas fa-user',
        cost = {value =  25, type = 'bank'},
        onBuy = function(orgId, src, cb)
            maxmembers(orgId, 10, cb)
        end
    },
    {
        name = 'members_upgrade_15',
        title = 'Members v2',
        description = 'Increases the maximum number of members from 10 to 15.',
        icon = 'fas fa-user',
        cost = {value =  50, type = 'SectoCoin'},
        onBuy = function(orgId, src, cb)
            maxmembers(orgId, 15, cb)
        end,
        disabled = function(orgId, cb)
            doesOrgHaveUpgrade(orgId, 'members_upgrade_10', function(hasUpgrade)
                if not hasUpgrade then
                    cb({disabled = true, message = 'To purchase this upgrade, you must have the "Members" upgrade.'})
                else
                    cb({disabled = false})
                end
            end)
        end,
    },
    {
        name = 'members_upgrade_20',
        title = 'Members v3',
        description = 'Increases the maximum number of members from 15 to 20.',
        icon = 'fas fa-user',
        cost = {value =  60, type = 'SectoCoin'},
        onBuy = function(orgId, src, cb)
            maxmembers(orgId, 20, cb)
        end,
        disabled = function(orgId, cb)
            doesOrgHaveUpgrade(orgId, 'members_upgrade_15', function(hasUpgrade15)
                doesOrgHaveUpgrade(orgId, 'members_upgrade_10', function(hasUpgrade10)
                    if not hasUpgrade10 or not hasUpgrade15 then
                        cb({disabled = true, message = 'To purchase this upgrade, you must have the "Members v2" upgrade.'})
                    else
                        cb({success = false})
                    end
                end)
            end)
        end
    },
    {
        name = 'interior_slots',
        title = 'Slots in the stash',
        description = 'Increases the maximum slots in an organization stash to 100.',
        icon = 'fas fa-arrow-up-1-9',
        cost = {value = 50, type = 'SectoCoin'},
        disabled = function(orgid, cb)
            doesorghaveinterior(orgid, function(hasinterior)
                if not hasinterior then
                    cb({disabled = true, message = 'The organization has no registered property.'})
                else
                    cb({success = false})
                end
            end)
        end,
        onBuy = function(orgid, src, cb)
            local xPlayer = Framework.getPlayerFromId(src)
            MySQL.Async.fetchAll('SELECT * FROM organization_interiors WHERE org_id = @org_id', { 
                ['@org_id'] = orgid 
            }, function(interiorsResult)
                if interiorsResult and #interiorsResult > 0 then
                    local upgradesJSON = interiorsResult[1].upgrades
                    local upgradesFromDB = json.decode(upgradesJSON) or {}
                    
                    table.insert(upgradesFromDB, 'slots')
        
                    local updatedUpgradesJSON = json.encode(upgradesFromDB)
        
                    MySQL.Async.execute('UPDATE organization_interiors SET upgrades = @upgrades WHERE org_id = @org_id', {
                        ['@upgrades'] = updatedUpgradesJSON,
                        ['@org_id'] = orgid
                    }, function(rowsChanged)
                        if rowsChanged > 0 then
                            if xPlayer then
                                Config.showNotification(Framework.getSource(xPlayer), 'Attention! The changes will be visible after the next server restart.')
                            end
                            cb({success = true, message = 'Upgrades updated correctly.'})
                        else
                            cb({success = false, message = 'Failed to update upgrades.'})
                        end
                    end)
                else
                    cb({success = false, message = "The organization's properties were not found."})
                end
            end)
        end
    },

}