Skip to main content

Migration

This guide covers replacing an existing wasabi_billing installation and optionally importing records from supported billing systems. Keep the public folder name and exports as wasabi_billing; there is no separate resource name to deploy for the replacement.

Back up before the first start

Back up the full database, existing billing folder, configuration, and inventory definitions. Test a restored copy in staging first. Schema setup and imports write to the database automatically when enabled; there is no interactive migration confirmation, automatic rollback, or write-fenced maintenance mode.

Replace an existing wasabi_billing installation​

  1. Schedule maintenance and stop invoice callers and the old billing resource. Keep players out while validating migration so no live payments race the replacement.
  2. Back up the wasabi_billing table and all related player/society balances.
  3. Replace the resource files, retaining the folder name wasabi_billing and the existing table.
  4. Reapply settings into the new shared/client/server configuration files. Do not copy the old monolithic config over them. Review the current defaults, especially automatic collection, reference prefix, providers, and language selection.
  5. Before starting, restore every billed society job name to Config.SocietiesSettings.allowedSocietiesToReceiveInvoices, including societies represented in historical invoices. This list is used to classify rows missing a receiver type.
  6. Leave Config.AutomaticAddDatabaseTables = true and Config.CompatImport = false. The import switch is for other products, not your existing wasabi_billing table.
  7. Start dependencies and billing, inspect SQL/module errors, and verify records and money paths before reopening the server.

What automatic setup changes​

Billing retains the table name wasabi_billing and existing invoice data. Standard setup:

  • Creates the table if absent.
  • Adds missing receiver_type, payment_method, and invoicer_identifier columns.
  • Adds missing idx_status_limit and idx_invoicer indexes.
  • Attempts to make idx_reference unique.
  • Backfills receiver classification using the configured society receive list.

Fresh-table fields include invoice/party identifiers and names, amount/VAT/total, status, payment method, and date strings. Dates remain string columns; the current deadline parser also accepts an ISO-style T separator. The setup does not generally resize every existing column or repair arbitrary customized schemas.

Receiver classification

If any row has receiver_type IS NULL, the backfill first sets null rows to personal, then sets all rows whose receiver identifier is in the society list to society. That second update is not restricted to only the previously null rows. Validate both historical society invoices and any existing explicit classifications before production use.

Duplicate references and verification​

When a non-unique idx_reference exists, duplicate reference values prevent conversion to a unique index. The resource logs a warning but does not repair or delete the duplicates for you.

Read-only checks after backup:

SELECT reference_id, COUNT(*) AS records
FROM wasabi_billing
GROUP BY reference_id
HAVING COUNT(*) > 1;

SHOW COLUMNS FROM wasabi_billing;
SHOW INDEX FROM wasabi_billing;

SELECT receiver_identifier, receiver_type, COUNT(*) AS records
FROM wasabi_billing
GROUP BY receiver_identifier, receiver_type;

Reconcile duplicate references deliberately with your integrations and item copies, then restart and confirm idx_reference is actually unique. Do not blindly delete duplicate rows. Startup continues after some setup failures, so verify the table itself rather than trusting a general startup message.

Check representative unpaid, paid, cancelled, overdue, personal, and society records. Existing decimal totals are floored during settlement, while payouts are derived from that same floored total. Historical rows without an issuing employee cannot deliver an employee commission to a missing identifier; do not assume the new column reconstructs missing history.

Replace another billing resource​

Three independent concerns must be handled:

  1. Stop the old system. Remove its startup entry and stop callers during migration.
  2. Compatibility APIs. Enable the particular adapters needed by your job scripts in Config.CompatExports.
  3. Historical records. Opt into a supported import with Config.CompatImport, if required.

The manifest provides okokBilling, esx_billing, and codem-billing independently of Lua switches. Turning a shim off does not remove those aliases or make running the original product alongside billing a supported configuration. Do not remove your separate banking resource.

API compatibility​

Replaced resourceServer settingSupported surfaces
okokBillingConfig.CompatExports.okokBilling = trueokokBilling:CreateCustomInvoice; client UI events okokBilling:ToggleMyInvoices and okokBilling:ToggleCreateInvoice
esx_billingConfig.CompatExports.esx_billing = trueesx_billing:sendBill
codem-billingConfig.CompatExports.codemBilling = trueServer exports createBilling and CheckBilling

All three server switches default to true. Only these specific surfaces are implemented; test each existing caller rather than assuming complete emulation of the replaced product. New integrations should use native Exports or the wasabi_billing: events.

The shipped Config.CompatExports table is defined only in config/server/config.lua. The two okokBilling client open-event handlers read that table on the client, so they are not enabled by the server default alone. If existing job menus still call those events, add Config.CompatExports = { okokBilling = true } in config/client/config.lua before its final module registration.

Import historical invoices​

Set one backend in config/server/config.lua:

Config.CompatImport = 'okokBilling'
-- Alternatively: Config.CompatImport = 'esx_billing'

The import is scheduled about five seconds after initialization. It reads the selected source table in the same database, inserts mapped rows into wasabi_billing, and adds/updates a marker column called wasabi_imported in the source table. This is not a read-only operation on the source table.

SettingSource tableReference mapping
'okokBilling'okokbillingokok- plus ref_id (or id when no ref_id)
'esx_billing'billingesx- plus the source id
falseNoneImport disabled, the default

There is no CodeM database importer. The CodeM export shim does not migrate its stored records.

okokBilling mapping​

The importer expects the documented source columns, including receiver/author identifiers and names, society, society_name, item, invoice_value, fees_amount, status, notes, and dates.

  • invoice_value becomes the pre-VAT amount and fees_amount the VAT portion; current configured VAT is not applied again.
  • A nonempty society value becomes the issuer identifier; otherwise the author identifier is used. The stored author identifier is also copied as invoicer_identifier.
  • Unlike the compatibility event adapter, this importer does not strip society_ from the stored society value. Check source society names against your banking account IDs before importing.
  • Receiver type is personal.
  • item becomes the reason, with nonblank notes appended; the resulting reason is truncated to 200 characters.
  • Only paid and unpaid statuses are retained verbatim. Other source statuses become unpaid; review these carefully before enabling collection.
  • Sent, deadline, and paid dates are copied. The reference prefix changes to the import mapping above, so old paper references or external links may need updating.

esx_billing mapping​

The importer expects id, identifier, sender, target_type, target, label, and amount.

  • The receiver is the character in identifier and receiver type is personal.
  • A society target uses target with society_ removed as the issuing society; otherwise sender is the author. sender is also copied into invoicer_identifier.
  • label becomes the reason, truncated to 200 characters.
  • Source amount becomes the total with zero VAT.
  • All imported rows are unpaid because standard ESX billing removes paid records.
  • Sent date is the import time; deadline is that time plus Config.MaxDaysToPayInvoice. Historical original dates cannot be reconstructed.

Import safeguards and limitations​

  • Rows already present under the mapped reference are skipped; positive amounts are floored and nonpositive amounts are skipped. Imported VAT is floored and clamped at zero; total is recomputed as amount plus VAT.
  • Source rows with wasabi_imported = 0 are considered. After a completed pass, remaining unmarked source rows are marked processed, including skipped rows. Do not assume a skip means the original row was imported correctly.
  • The source table is not dropped or emptied, but it is altered and marked. Keep the backup and source table until reconciliation is complete.
  • Import inserts do not use the normal creation side effects, so they do not issue item copies or send creation notifications.
  • This is not an atomic all-or-nothing migration or a schema-fingerprint validator. SQL errors can leave a partial import. Existing mapped references help avoid repeating completed inserts, but that is not an automatic rollback guarantee.
  • Keep automatic collection disabled during reconciliation, especially when source statuses or deadlines change meaning.

After import​

  1. Review the console's imported/skipped counts and any SQL errors.
  2. Compare source records with mapped references in wasabi_billing, including statuses, totals, society identifiers, dates, and skipped records.
  3. Test lookups, item behavior for newly created invoices, permissions, and payments against real provider accounts on staging.
  4. Set Config.CompatImport = false and restart after the import is verified. Leave the API compatibility switches enabled only where needed by existing callers.
  5. Retain backups. Delete an old source table only as a separate, deliberate database-maintenance decision after verification; billing never drops it for you.

Rollback planning​

There is no built-in rollback command. If verification fails, stop billing and invoice callers. Restore the matching resource/configuration and database backup under maintenance. If live payments have occurred since the backup, reconcile player and society balances as well as invoice rows before restoring service - rolling back invoice status alone can cause invoices to be collected twice.