# การเชื่อมต่อระบบ

cxg-tattoos เชื่อมต่อกับ framework ต่าง ๆ เพื่อเรียกเก็บเงินจากการซื้อและตรวจสอบสิทธิ์ผู้ดูแลได้ การเชื่อมต่อระบบรูปลักษณ์จะนำรอยสักที่บันทึกไว้กลับมาใช้เมื่อตัวละครโหลดหรือเปลี่ยน skin ตั้งค่าแต่ละส่วนแยกกัน

อ่านเพิ่มเติมได้ที่ [บทนำ](https://docs.cxgstudios.com/docs/th/01-cxg-tattoos/01-introduccion.md), [การติดตั้ง](https://docs.cxgstudios.com/docs/th/01-cxg-tattoos/02-instalacion.md), [การตั้งค่า](https://docs.cxgstudios.com/docs/th/01-cxg-tattoos/03-configuracion.md), [แคตตาล็อก](https://docs.cxgstudios.com/docs/th/01-cxg-tattoos/04-catalogo.md) และ [อินเทอร์เฟซ](https://docs.cxgstudios.com/docs/th/01-cxg-tattoos/06-interfaz.md)

## เฟรมเวิร์กที่รองรับ

| ระบบ | ตัวระบุการตั้งค่า | รีซอร์สเริ่มต้น | การชำระเงิน | สิทธิ์ |
| --- | --- | --- | --- | --- |
| Qbox | `qbx` | `qbx_core` | มี | มี |
| QBCore | `qbcore` | `qb-core` | มี | มี |
| ESX | `esx` | `es_extended` | มี | มี |
| ไม่มี framework | `standalone` | ไม่เกี่ยวข้อง | callback ของคุณเองหรือซื้อฟรี | ACE หรือการตรวจสอบของคุณเอง |

เมื่อใช้ `auto` รีซอร์สจะตรวจหา Qbox, QBCore หรือ ESX ที่เริ่มทำงานอยู่ หากไม่พบ จะใช้ `standalone` คุณกำหนด framework เองได้เมื่อเซิร์ฟเวอร์เปิดใช้หลาย framework หรือใช้ชื่อรีซอร์สอื่น:

```lua
Config.Purchases.framework = 'qbx' -- auto | qbx | qbcore | esx | standalone
Config.Purchases.resources.qbx = 'qbx_core'
Config.Purchases.accounts = { 'cash', 'bank' }
Config.Purchases.esxAccountMap.cash = 'money'
Config.Purchases.esxAccountMap.bank = 'bank'
Config.Purchases.allowFreePurchases = false
```

ระบบจะลองใช้บัญชีตามลำดับที่ระบุ การเรียกเก็บเงินจะใช้บัญชีเดียว หากยอดเงินในบัญชีนั้นไม่พอ จะลองบัญชีถัดไป ใน ESX `esxAccountMap` จะแปลง `cash` เป็นชื่อบัญชี `money`

`Config.Purchases.reason` และ `refundReason` ระบุเหตุผลของรายการเงินสำหรับ provider ที่รองรับ ค่าเริ่มต้นคือ `tattoo-purchase` และ `tattoo-purchase-refund` ตัวเลือก `allowFreePurchases` ใช้ข้ามการเรียกเก็บเงินใน adapter แบบ standalone; ตัวเลือกนี้ไม่ได้ทำให้การซื้อผ่าน framework อื่นฟรี

## การชำระเงินโดยไม่มี framework

ในโหมด `standalone` ให้เชื่อม `tryCharge` และ `refund` กับรีซอร์สระบบเศรษฐกิจของเซิร์ฟเวอร์ ต้องมี callbacks ทั้งสองรายการจึงจะรับการซื้อได้ เพราะการคืนเงินต้องคืนยอดที่เรียกเก็บไปแล้วหากบันทึกรอยสักไม่สำเร็จ

```lua
Config.Purchases.framework = 'standalone'
Config.Purchases.standalone.tryCharge = function(source, totalAmount, context)
    -- Sustituye esta llamada por la API de economía de tu servidor.
    local charged, receipt = MyEconomy.charge(source, totalAmount, context)
    if charged then
        return true, receipt
    end
    return false, 'No tienes saldo suficiente.'
end

Config.Purchases.standalone.refund = function(source, totalAmount, context, receiptData)
    -- Usa receiptData para devolver el mismo cobro aprobado.
    return MyEconomy.refund(source, totalAmount, receiptData) == true
end
```

`MyEconomy` เป็นตัวแทน API ของเซิร์ฟเวอร์ ให้เปลี่ยนเป็นชื่อและการเรียกใช้งานจริง หากต้องการอนุญาตให้ซื้อโดยไม่มีค่าใช้จ่าย ให้ตั้ง `allowFreePurchases = true` โดยตั้งใจ

adapter การชำระเงินมีเมธอด `isAvailable(settings)`, `charge(source, amount, context, settings)` และ `refund(source, amount, context, settings)` เมื่ออนุมัติการชำระเงินแล้ว ต้องเก็บใบรับเงินไว้ใน `context.paymentReceipt`; cxg-tattoos จะใช้ใบรับเงินนี้ส่งคำขอคืนเงินกลับไปยังระบบการชำระเงินเดิม สำหรับระบบเศรษฐกิจของคุณเอง ให้ใช้ callbacks `tryCharge` และ `refund` ของ `standalone` เป็นช่องทางตั้งค่าโดยตรง

## สิทธิ์ผู้ดูแล

ระบบตรวจสอบสิทธิ์บนเซิร์ฟเวอร์เมื่อต้องเปิดและใช้งานแผงผู้ดูแล การซ่อนหรือแก้ไขอินเทอร์เฟซของไคลเอนต์ไม่ได้ให้สิทธิ์เข้าถึง

ค่าเริ่มต้นใช้ framework ที่ตรวจพบและ ACE เป็นทางเลือกสำรอง:

```lua
Config.Permissions = {
    framework = 'auto', -- auto | qbx | qbcore | esx | standalone
    mode = 'hybrid',    -- framework | ace | hybrid | custom
    acePrefix = 'cxg-tattoos.',
    resources = {
        qbx = 'qbx_core',
        qbcore = 'qb-core',
        esx = 'es_extended',
    },
    bindings = {
        admin = {
            ace = { 'cxg-tattoos.admin', 'group.admin', 'admin' },
            qbx = { 'god', 'admin', 'group.admin' },
            qbcore = { 'god', 'admin', 'group.admin' },
            esx = { 'superadmin', 'admin' },
        },
    },
}
```

โหมด `framework` ตรวจสอบ roles ของ framework ส่วน `ace` ใช้รายการ ACE ใน binding และ `hybrid` อนุญาตให้ผ่านได้ด้วยวิธีใดวิธีหนึ่ง ใน `standalone` จะไม่มีการอนุญาตผ่าน framework ให้ตั้งค่า ACE หรือการตรวจสอบของคุณเอง

ตัวอย่างการอนุญาตสมาชิกของ ACE principal `group.admin`:

```cfg
add_ace group.admin cxg-tattoos.admin allow
```

หากต้องการให้ระบบของคุณเองตัดสินสิทธิ์ ให้ใช้ `mode = 'custom'` callback จะได้รับ id ผู้เล่น สิทธิ์ context ของการดำเนินการ และ binding ที่ตั้งค่าไว้ อนุญาตเฉพาะเมื่อค่าที่คืนเป็น boolean `true`:

```lua
Config.Permissions.mode = 'custom'
Config.Permissions.custom = {
    hasPermission = function(source, permission, context, binding)
        return exports.my_permissions:hasPermission(source, permission) == true
    end,
}
```

ปรับ `my_permissions` ให้ตรงกับ API ที่ติดตั้งบนเซิร์ฟเวอร์ หากไม่มี callback, callback ล้มเหลว หรือคืนค่าอื่น ระบบจะปฏิเสธการเข้าถึง

ตั้งค่าคำสั่งเปิดแผงได้เช่นกัน `permission` ต้องตรงกับ key ใน `Config.Permissions.bindings`:

```lua
Config.AdminCommand.enabled = true
Config.AdminCommand.name = 'tattooadmin'
Config.AdminCommand.permission = 'admin'
```

เมื่อใช้ค่าเหล่านี้ สิทธิ์ `admin` จะป้องกันคำสั่ง `/tattooadmin` และการดำเนินการของผู้ดูแล ตั้ง `enabled = false` เพื่อปิดคำสั่ง แต่ระบบยังตรวจสอบสิทธิ์ในช่องทางการจัดการอื่น

### ไฟล์เชื่อมต่อระบบที่แก้ไขได้

bridge ที่แก้ไขได้รวมการเชื่อมต่อกับระบบภายนอก หากต้องการกำหนดสิทธิ์หรือการชำระเงินเอง แนะนำให้ตั้งค่า callbacks ที่อธิบายไว้ก่อนหน้า หากปรับ bridge ที่มีอยู่ ให้คง contract ของมันไว้:

| ไฟล์หรือกลุ่ม | การใช้งาน | สัญญาของอะแดปเตอร์ |
| --- | --- | --- |
| `bridge/permissions/server.lua` | เลือก framework และใช้โหมด `framework`, `ace`, `hybrid` หรือ `custom` | `TattooPermissions.Has(source, permission, context)` คืน `true` เมื่ออนุญาตเท่านั้น |
| `bridge/permissions/registry.lua` | ลงทะเบียนและเครื่องมือสิทธิ์ที่ใช้ร่วมกัน | `TattooPermissionBridge.register(name, adapter)` |
| `bridge/permissions/qbx.lua`, `qbcore.lua`, `esx.lua`, `standalone.lua` | ตรวจสอบสิทธิ์แยกตาม framework หรือโหมดไม่มี framework | `isAvailable(settings)` และ `hasPermission(source, binding, settings, permission)`; รองรับ `context` เพิ่มเติมหากปรับใช้ |
| `bridge/payments/server.lua` | เลือก provider เรียกเก็บเงินและคืนเงิน | `Config.TryChargePlayer(source, totalAmount, context)` และ `Config.RefundPlayer(source, totalAmount, context)` |
| `bridge/payments/registry.lua` | ลงทะเบียนและเครื่องมือชำระเงินที่ใช้ร่วมกัน | `TattooPaymentBridge.register(name, adapter)` และเครื่องมือจัดการใบรับเงิน |
| `bridge/payments/qbx.lua`, `qbcore.lua`, `esx.lua`, `standalone.lua` | ดำเนินการชำระเงินผ่าน framework หรือ callbacks ของคุณเอง | `isAvailable(settings)`, `charge(...)` และ `refund(...)` |
| `bridge/appearance.lua` | เหตุการณ์โหลด skin และร้องขอรอยสักที่บันทึกไว้ | ขอรายการรอยสักของตัวละครและนำไปใช้เมื่อโหลดรูปลักษณ์เสร็จ |

callback สิทธิ์จะได้รับ `context` เป็นอาร์กิวเมนต์ที่ห้าเมื่อ bridge เรียกใช้ registry มี provider ที่รวมมาให้ (`qbx`, `qbcore`, `esx`, `standalone`); ตัวเลือกแบบกำหนดเองไม่ต้องเพิ่ม provider อีกตัว

ใน adapter การชำระเงิน ให้คงการลงทะเบียนใบรับเงินด้วย `TattooPaymentBridge.setReceipt(context, provider, account, amount, identifier, data)` การคืนเงินต้องตรวจ provider และจำนวนเงินเดียวกันด้วย `getReceipt(context, provider, amount)` และทำเครื่องหมายใบรับเงินว่าคืนแล้วหลังยืนยันการคืนเงิน ปรับไฟล์ provider ที่ใช้อยู่แล้ว หากทำ integration เองโดยไม่เปลี่ยน adapters ให้ใช้ callbacks standalone

## รูปลักษณ์และการโหลดตัวละคร

รีซอร์สรับฟังเหตุการณ์ทั่วไปจาก `illenium-appearance`, `fivem-appearance`, QBCore, ESX และ `spawnmanager`; จากนั้นจะเรียกคืนและนำรอยสักที่บันทึกไว้กลับมาใช้ ใน Qbox การตั้งค่าตัวอย่าง multicharacter ใช้ `playerskins.skin` เพื่อแสดงรอยสักที่บันทึกไว้ในหน้าจอเลือกตัวละคร

หากระบบรูปลักษณ์ของคุณใช้เหตุการณ์อื่น ให้ร้องขอการนำรอยสักมาใช้หลังโหลด skin เสร็จ:

```lua
TriggerServerEvent('cxg-tattoos:fetchMyTattoos')
```

เหตุการณ์นี้ส่งรอยสักของตัวละครปัจจุบันกลับไปยังไคลเอนต์ อย่าส่งรายการจากแหล่งข้อมูลที่ผู้เล่นเลือกเอง: เซิร์ฟเวอร์เป็นผู้ระบุและตรวจสอบเจ้าของข้อมูล

ตั้งค่าตัวอย่าง multicharacter ของ Qbox ได้ด้วยฟิลด์ต่อไปนี้:

```lua
Config.QbxMulticharacterPreview.enabled = true
Config.QbxMulticharacterPreview.resource = 'qbx_core'
Config.QbxMulticharacterPreview.playerskinsTable = 'playerskins'
Config.QbxMulticharacterPreview.playersTable = 'players'
Config.QbxMulticharacterPreview.syncExistingOnStart = true
```

`enabled` เปิด integration; `resource` ระบุชื่อรีซอร์ส Qbox ที่ติดตั้ง `playerskinsTable` และ `playersTable` ระบุตารางรูปลักษณ์และตัวละครที่การติดตั้งนั้นใช้ `syncExistingOnStart` ใช้ซิงก์รอยสักที่บันทึกไว้แล้วเมื่อ cxg-tattoos เริ่มทำงาน เพื่อให้แสดงในหน้าเลือก multicharacter ด้วย หากเซิร์ฟเวอร์เปลี่ยนชื่อตาราง ให้อัปเดตสองฟิลด์นี้ ไม่จำเป็นต้องแก้ `qbx_core`
