Core ERP Server Actions live inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/ency07/B2B/llms.txt
Use this file to discover all available pages before exploring further.
src/erp/actions/core.ts. All actions are marked "use server" and run exclusively on the server. Every authenticated action calls requireAction() for RBAC enforcement and validateTenantAccess() for tenant isolation before querying Supabase.
Common action pattern — All ERP actions follow the same four-step guard sequence before touching the database:
- Call
requireAction(permission)to verify the authenticated user holds the required RBAC permission. - Resolve the tenant UUID with
getTenantId(tenantCode). - Call
validateTenantAccess(userId, role, tenantId)to enforce multi-tenant isolation. - Query or mutate via
supabaseAdmin(service-role client, bypasses RLS at the DB layer — isolation is enforced at step 3).
getTenantId
resolveTenantIdAsync() from the tenant resolver module. Used as the first step in every action that scopes data to a tenant.
The tenant subdomain code (e.g.
"acme"). When null or undefined, the resolver falls back to the current session’s tenant context.Promise<string> — the tenant UUID.
Clients
getClients
totalInvoiced by summing total_amount across invoices with status EMITIDA, PARCIALMENTE_PAGADA, or PAGADA.
Tenant subdomain code. Resolved to UUID via
getTenantId.Promise<ClientListItem[]> where each item has:
| Field | Type | Description |
|---|---|---|
id | string | Client UUID |
taxId | string | Tax identification number (tax_id) |
name | string | Legal name (legal_name) |
segment | string | Industry segment; defaults to "General" |
totalInvoiced | number | Sum of all qualifying invoices in COP |
status | "ACTIVO" | "SUSPENDIDO" | "PENDIENTE" | Mapped from DB status field |
createClient
clients.create RBAC permission.
Tenant subdomain code.
Tax ID (NIT). Must be unique within the tenant — throws
"Ya existe un cliente con este NIT para este tenant." if a non-deleted client with the same tax_id already exists.Legal name stored in
legal_name.Industry segment stored in
industry.Contact email address.
Promise<Client> — the full inserted row. New clients are created with client_type: "Empresa", country: "México", status: "ACTIVO", and assigned_user_id set to the tenant owner.
Required permission: clients.create
Jobs
getJobs
HIGH / LOW / MEDIUM) are mapped to display strings (ALTA / BAJA / MEDIA). Status EN_EJECUCION is normalized to EN_PROGRESO.
Tenant subdomain code.
Promise<JobListItem[]> where each item has:
| Field | Type | Description |
|---|---|---|
id | string | Job UUID |
code | string | Job code, e.g. JOB-2026-001 |
description | string | Title of the job |
assignedTech | string | Derived from the tenant’s branding nombre_comercial |
priority | "BAJA" | "MEDIA" | "ALTA" | Localized priority |
startDate | string | YYYY-MM-DD from planned_start_date |
endDate | string | YYYY-MM-DD from planned_end_date |
status | "PENDIENTE" | "EN_PROGRESO" | "COMPLETADA" | "CANCELADA" | Normalized status |
createJob
jobs.create RBAC permission. Auto-generates a sequential job code in the format JOB-2026-NNN.
Tenant subdomain code.
Job title/description. Truncated to 100 characters for the
title column; full text stored in description.Assigned technician label. The action resolves the actual
assigned_user_id to the tenant owner.Display priority string. Mapped back to DB values:
ALTA → HIGH, BAJA → LOW, any other value → MEDIUM.Planned start date in
YYYY-MM-DD format.Planned end date in
YYYY-MM-DD format.Promise<Job> — the full inserted row. New jobs are created with status: "PENDIENTE" and the tenant owner set as created_by.
Required permission: jobs.create
Inventory
getInventoryStock
Tenant subdomain code.
Promise<StockItem[]> where each item has:
| Field | Type | Description |
|---|---|---|
id | string | Composite key: {warehouseId}-{itemId} |
warehouseCode | string | Warehouse code |
warehouseName | string | Warehouse display name |
itemCode | string | Item/SKU code |
itemName | string | Item display name |
sku | string | Alias for itemCode |
category | string | Item category |
unit | string | Unit of measure; defaults to "Unidad" |
quantity | number | Total quantity on hand |
reserved | number | Reserved quantity |
available | number | Available quantity (quantity - reserved) |
createInventoryMovement
inventory.movement RBAC permission.
Tenant subdomain code.
Movement type.
Salida and Transferencia trigger a stock availability check before insertion.The
item_code of the inventory item. Throws if not found in the tenant.Quantity to move. For
Salida and Transferencia, throws "Stock insuficiente en bodega origen" if the source warehouse’s available_quantity is less than this value.Free-text notes for the movement record.
warehouse_code of the source warehouse. Throws if not found.warehouse_code of the destination warehouse. Required when type is "Transferencia". Throws if not found.Promise<InventoryMovement> — the full inserted row with auto-generated code MOV-2026-NNNN. Movements are automatically set to status: "Aplicado".
Required permission: inventory.movement
createInventoryItem
items.manage RBAC permission. If initialQuantity and warehouseId are both provided, seeds an inventory_stock row and records an "Entrada" movement with notes "Carga inicial de inventario".
Unique item/SKU code within the tenant.
Display name of the item.
Detailed description.
Item category (free text).
Classification type stored in
item_type.Unit of measure (e.g.
"Unidad", "kg", "m").Minimum stock threshold that triggers reorder alerts.
Maximum stock capacity for the item.
Stock level at which a purchase order should be raised.
If provided (and
> 0), seeds initial stock in the specified warehouse.UUID of the warehouse for the initial stock seed. Required when
initialQuantity > 0.Promise<InventoryItem> — the full inserted row. Items are created with status: "Activo" and average_cost: 0.
Required permission: items.manage
getWarehouses
Tenant subdomain code.
Promise<WarehouseItem[]> where each item has:
| Field | Type | Description |
|---|---|---|
id | string | Warehouse UUID |
name | string | Display name |
code | string | Warehouse code (warehouse_code) |
Invoices
getInvoices
deleted_at IS NOT NULL) are excluded.
Tenant subdomain code.
Promise<InvoiceListItem[]> where each item has:
| Field | Type | Description |
|---|---|---|
id | string | Invoice UUID |
code | string | Invoice code, e.g. FAC-2026-0001 |
clientName | string | Client’s legal_name; falls back to "Cliente General" |
totalAmount | number | Full invoice amount |
paidAmount | number | Amount paid so far |
status | "BORRADOR" | "EMITIDA" | "PARCIALMENTE_PAGADA" | "PAGADA" | "ANULADA" | Invoice lifecycle status |
date | string | YYYY-MM-DD from invoice_date |
createInvoice
invoices.manage RBAC permission.
Tenant subdomain code.
Matched against
legal_name in the clients table. If no exact match is found, falls back to the first active client in the tenant.Line item description stored in
invoice_items.description.Total invoice amount in COP. Used for
subtotal, total_amount, and the single line item’s unit_price and line_total.Promise<Invoice> — the full inserted invoice row. The generated code follows the pattern FAC-2026-NNNN. New invoices are created with:
status: "EMITIDA"due_dateset to 30 days from the current datediscount_amount: 0,tax_amount: 0,paid_amount: 0
invoice_items row is inserted automatically.
Required permission: invoices.manage
Tenant Settings
getTenantSettings
is_encrypted = true) are transparently decrypted via the get_tenant_setting Supabase RPC before being returned. Soft-deleted settings are excluded.
Tenant subdomain code.
Promise<Record<string, any>> — object keyed by config_key. Values for encrypted fields are the decrypted plaintext; if decryption fails, the raw ciphertext is returned as a fallback.
Requires authentication. Throws "No autenticado" if no session is present.
getPublicTenantSettings
requireAction or getAuthContext.
Tenant subdomain code.
Promise<Record<string, any>> containing any subset of these keys that exist in tenant_settings:
| Key | Description |
|---|---|
nombre_comercial | Trading name |
razon_social | Legal company name |
logo_url | Primary logo URL |
logo_secondary_url | Secondary / dark-mode logo URL |
favicon_url | Browser favicon URL |
primary_color | Brand primary color (hex) |
secondary_color | Brand secondary color (hex) |
titulo_navegador | Browser tab title |
descripcion_sitio | Site meta description |
{} on error rather than throwing.
updateTenantSettings
settings.manage RBAC permission. The upsert conflict target is (tenant_id, module, config_key).
Tenant subdomain code.
Settings module name (e.g.
"EMPRESA", "IDENTIDAD", "LOCALIZACION", "DOCUMENTOS").Configuration key (
config_key) to upsert.New value. Stored as JSONB in Supabase.
When
true, the value will be marked for encryption in the database. Defaults to false.Promise<TenantSetting> — the upserted row. updated_at is automatically set to the current timestamp and updated_by to the tenant owner’s user ID.
Required permission: settings.manage