Skip to content

Examples ​

← BLN Society overview

Each example is one job. Copy the block, swap the ids, and wire it into your resource.

Related: API Β· Statebags Β· Events Β· Hooks


1. Register a society for your shop ​

Scenario: You run a shop script. Valentine General Store should be its own organization with its own account and members.

Goal: Create that organization on server boot and look it up later β€” without saving a society id in your database.

lua
-- server β€” run once when bln_society is ready
AddEventHandler('bln_society:ready', function()
    exports.bln_society:EnsureSociety({
        name = 'Valentine General Store',
        preset = 'business',
        fundingSource = Const.FUNDING.ACCOUNT,
        ownerResource = 'my_store',              -- your resource name
        externalKey = 'valentine_general_store', -- your config id for this shop
    })
end)

-- server β€” call this anywhere you need the shop's society
local function getStoreSociety(storeId)
    return exports.bln_society:SocietyByKey('my_store', storeId)
end

Result: First boot creates the society. Every boot after that finds the same one. getStoreSociety('valentine_general_store') gives you a handle β€” or nil if the society was deleted.


2. Send customer payment to the society account ​

Scenario: A player buys items at your shop. The money should go into the shop's society till, not disappear.

Goal: Credit the society balance when a sale completes. No permission check β€” the buyer is a customer, not a member.

lua
-- server β€” inside your purchase handler, after the player paid
RegisterNetEvent('my_store:purchaseComplete', function(storeId, transactionId, price)
    local society = exports.bln_society:SocietyByKey('my_store', storeId)
    if not society then return end

    society:AddMoney(price, {
        currency = 0,
        type = 'sale',
        reason = 'Cart sold',
        ref = ('my_store:sale:%s'):format(transactionId), -- unique β€” safe to retry
    })
end)

Result: The society balance goes up. The ledger records the sale. Calling again with the same ref does not double-credit.

Member restocking from the till is different β€” use Withdraw / Deposit so permissions and player pockets are handled. See API β€” Finance.


3. Block staff actions for players without permission ​

Scenario: A player tries to open your restock menu. Only store staff with the right permission should get in.

Goal: Check permission before your action runs. Reject everyone else.

lua
-- server β€” before opening restock or running any staff-only logic
RegisterNetEvent('my_store:tryRestock', function(storeId)
    local society = exports.bln_society:SocietyByKey('my_store', storeId)
    if not society then return end

    local charId = exports.bln_society:GetCharacterId(source)
    if not charId then return end

    if not society:HasPermission(charId, 'stores.restock') then
        -- notify player: no permission
        return
    end

    -- player passed β€” run your restock logic here
    TriggerClientEvent('my_store:openRestockUi', source, storeId)
end)

Result: Only members whose rank (or overrides) include stores.restock reach the restock UI. Everyone else is stopped here.

Register stores.restock in config/permissions.cfg.lua if it is not in the built-in list. Check permission names, not rank names like "Deputy".


4. Open the management menu from your own NPC ​

Scenario: Your shop already has a clerk NPC. You do not want a second BLN Society prompt on the same counter β€” you want your interaction to open the society menu.

Goal: Open the BLN Society management UI when the player talks to your NPC.

lua
-- server β€” triggered by your existing clerk / target / prompt
RegisterNetEvent('my_store:clerkTalk', function(storeId)
    local society = exports.bln_society:SocietyByKey('my_store', storeId)
    if not society then return end

    society:Open(source) -- opens the management menu for this player
end)

Result: The player sees the full society menu (members, finances, duty, etc.) without BLN Society placing its own world point.

Alternative β€” BLN Society draws the blip and prompt ​

Use this only when you have no clerk or interaction of your own:

lua
local society = exports.bln_society:SocietyByKey('my_store', storeId)
if not society then return end

society:SetPoint({
    coords = { x = -324.1, y = 776.5, z = 117.8, h = 90.0 },
    blip = { sprite = 'blip_shop_store', name = 'Valentine Store' },
})

Members see the blip and prompt at the coords. Strangers do not.


5. On the client: show a staff door only when on duty ​

Scenario: Your shop MLO has a back room. Only employees who are clocked in should see the enter prompt.

Goal: Read the local player's duty statebag and show or hide your prompt. No server callback.

lua
-- client
local STORE_SOCIETY_ID = 3 -- send this from your server payload when the player enters the shop

CreateThread(function()
    while not GlobalState['society:ready'] do Wait(100) end

    while true do
        local duty = LocalPlayer.state['society:duty']
        local onDutyForThisStore = duty and duty.id == STORE_SOCIETY_ID

        if onDutyForThisStore then
            ShowBackRoomPrompt()  -- your prompt / target / text UI
        else
            HideBackRoomPrompt()
        end

        Wait(500)
    end
end)

Result: The prompt appears only while the player is on duty for that society. Clock out and it disappears.

Your server already knows the society id β€” include it when the client loads the shop:

lua
-- server β€” in whatever payload you send when the player enters the store
TriggerClientEvent('my_store:enter', source, {
    storeId = storeId,
    societyId = society and society.id or nil,
})

For permission checks on the client, read LocalPlayer.state['society:memberships']. Bag shapes: Statebags. To refresh UI when duty changes without polling, use Events.