Skip to main content

Documentation 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.

Core ERP Server Actions live in 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:
  1. Call requireAction(permission) to verify the authenticated user holds the required RBAC permission.
  2. Resolve the tenant UUID with getTenantId(tenantCode).
  3. Call validateTenantAccess(userId, role, tenantId) to enforce multi-tenant isolation.
  4. Query or mutate via supabaseAdmin (service-role client, bypasses RLS at the DB layer — isolation is enforced at step 3).

getTenantId

getTenantId(tenantCode?: string | null): Promise<string>
Resolves a tenant subdomain code to its internal UUID. Delegates to resolveTenantIdAsync() from the tenant resolver module. Used as the first step in every action that scopes data to a tenant.
tenantCode
string | null
The tenant subdomain code (e.g. "acme"). When null or undefined, the resolver falls back to the current session’s tenant context.
Returns Promise<string> — the tenant UUID.

Clients

getClients

getClients(tenantCode?: string | null): Promise<ClientListItem[]>
Returns all non-deleted clients for the tenant. For each client, computes totalInvoiced by summing total_amount across invoices with status EMITIDA, PARCIALMENTE_PAGADA, or PAGADA.
tenantCode
string | null
Tenant subdomain code. Resolved to UUID via getTenantId.
Returns Promise<ClientListItem[]> where each item has:
FieldTypeDescription
idstringClient UUID
taxIdstringTax identification number (tax_id)
namestringLegal name (legal_name)
segmentstringIndustry segment; defaults to "General"
totalInvoicednumberSum of all qualifying invoices in COP
status"ACTIVO" | "SUSPENDIDO" | "PENDIENTE"Mapped from DB status field
Throws if not authenticated or if Supabase returns an error.

createClient

createClient(
  tenantCode: string | null,
  clientData: {
    taxId: string;
    name: string;
    segment: string;
    email: string;
  }
): Promise<Client>
Creates a new client record for the tenant. Requires the clients.create RBAC permission.
tenantCode
string | null
required
Tenant subdomain code.
clientData.taxId
string
required
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.
clientData.name
string
required
Legal name stored in legal_name.
clientData.segment
string
required
Industry segment stored in industry.
clientData.email
string
required
Contact email address.
Returns 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

getJobs(tenantCode?: string | null): Promise<JobListItem[]>
Returns all jobs for the tenant ordered by creation date (newest first). DB priority values (HIGH / LOW / MEDIUM) are mapped to display strings (ALTA / BAJA / MEDIA). Status EN_EJECUCION is normalized to EN_PROGRESO.
tenantCode
string | null
Tenant subdomain code.
Returns Promise<JobListItem[]> where each item has:
FieldTypeDescription
idstringJob UUID
codestringJob code, e.g. JOB-2026-001
descriptionstringTitle of the job
assignedTechstringDerived from the tenant’s branding nombre_comercial
priority"BAJA" | "MEDIA" | "ALTA"Localized priority
startDatestringYYYY-MM-DD from planned_start_date
endDatestringYYYY-MM-DD from planned_end_date
status"PENDIENTE" | "EN_PROGRESO" | "COMPLETADA" | "CANCELADA"Normalized status
Throws if not authenticated or on Supabase error.

createJob

createJob(
  tenantCode: string | null,
  jobData: {
    description: string;
    assignedTech: string;
    priority: string;
    startDate: string;
    endDate: string;
  }
): Promise<Job>
Creates a new job (work order) for the tenant. Requires the jobs.create RBAC permission. Auto-generates a sequential job code in the format JOB-2026-NNN.
tenantCode
string | null
required
Tenant subdomain code.
jobData.description
string
required
Job title/description. Truncated to 100 characters for the title column; full text stored in description.
jobData.assignedTech
string
required
Assigned technician label. The action resolves the actual assigned_user_id to the tenant owner.
jobData.priority
string
required
Display priority string. Mapped back to DB values: ALTA → HIGH, BAJA → LOW, any other value → MEDIUM.
jobData.startDate
string
required
Planned start date in YYYY-MM-DD format.
jobData.endDate
string
required
Planned end date in YYYY-MM-DD format.
Returns 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

getInventoryStock(tenantCode?: string | null): Promise<StockItem[]>
Returns all inventory stock rows for the tenant, joining warehouse and item information.
tenantCode
string | null
Tenant subdomain code.
Returns Promise<StockItem[]> where each item has:
FieldTypeDescription
idstringComposite key: {warehouseId}-{itemId}
warehouseCodestringWarehouse code
warehouseNamestringWarehouse display name
itemCodestringItem/SKU code
itemNamestringItem display name
skustringAlias for itemCode
categorystringItem category
unitstringUnit of measure; defaults to "Unidad"
quantitynumberTotal quantity on hand
reservednumberReserved quantity
availablenumberAvailable quantity (quantity - reserved)

createInventoryMovement

createInventoryMovement(
  tenantCode: string | null,
  movement: {
    type: "Entrada" | "Salida" | "Transferencia";
    itemCode: string;
    quantity: number;
    notes: string;
    sourceWarehouse: string;
    destWarehouse?: string;
  }
): Promise<InventoryMovement>
Records an inventory movement. Requires the inventory.movement RBAC permission.
tenantCode
string | null
required
Tenant subdomain code.
movement.type
"Entrada" | "Salida" | "Transferencia"
required
Movement type. Salida and Transferencia trigger a stock availability check before insertion.
movement.itemCode
string
required
The item_code of the inventory item. Throws if not found in the tenant.
movement.quantity
number
required
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.
movement.notes
string
required
Free-text notes for the movement record.
movement.sourceWarehouse
string
required
warehouse_code of the source warehouse. Throws if not found.
movement.destWarehouse
string
warehouse_code of the destination warehouse. Required when type is "Transferencia". Throws if not found.
Returns 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

createInventoryItem(
  tenantCode: string | null,
  itemData: {
    itemCode: string;
    name: string;
    description: string;
    category: string;
    itemType: "Material" | "Herramienta" | "Equipo" | "Consumible" | "Repuesto";
    unit: string;
    minimumStock: number;
    maximumStock: number;
    reorderPoint: number;
    initialQuantity?: number;
    warehouseId?: string;
  }
): Promise<InventoryItem>
Creates a new inventory item. Requires the 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".
itemData.itemCode
string
required
Unique item/SKU code within the tenant.
itemData.name
string
required
Display name of the item.
itemData.description
string
required
Detailed description.
itemData.category
string
required
Item category (free text).
itemData.itemType
"Material" | "Herramienta" | "Equipo" | "Consumible" | "Repuesto"
required
Classification type stored in item_type.
itemData.unit
string
required
Unit of measure (e.g. "Unidad", "kg", "m").
itemData.minimumStock
number
required
Minimum stock threshold that triggers reorder alerts.
itemData.maximumStock
number
required
Maximum stock capacity for the item.
itemData.reorderPoint
number
required
Stock level at which a purchase order should be raised.
itemData.initialQuantity
number
If provided (and > 0), seeds initial stock in the specified warehouse.
itemData.warehouseId
string
UUID of the warehouse for the initial stock seed. Required when initialQuantity > 0.
Returns Promise<InventoryItem> — the full inserted row. Items are created with status: "Activo" and average_cost: 0. Required permission: items.manage

getWarehouses

getWarehouses(tenantCode?: string | null): Promise<WarehouseItem[]>
Returns all non-deleted warehouses for the tenant, ordered by name.
tenantCode
string | null
Tenant subdomain code.
Returns Promise<WarehouseItem[]> where each item has:
FieldTypeDescription
idstringWarehouse UUID
namestringDisplay name
codestringWarehouse code (warehouse_code)

Invoices

getInvoices

getInvoices(tenantCode?: string | null): Promise<InvoiceListItem[]>
Returns all non-deleted invoices for the tenant, ordered by creation date (newest first). Soft-deleted invoices (deleted_at IS NOT NULL) are excluded.
tenantCode
string | null
Tenant subdomain code.
Returns Promise<InvoiceListItem[]> where each item has:
FieldTypeDescription
idstringInvoice UUID
codestringInvoice code, e.g. FAC-2026-0001
clientNamestringClient’s legal_name; falls back to "Cliente General"
totalAmountnumberFull invoice amount
paidAmountnumberAmount paid so far
status"BORRADOR" | "EMITIDA" | "PARCIALMENTE_PAGADA" | "PAGADA" | "ANULADA"Invoice lifecycle status
datestringYYYY-MM-DD from invoice_date

createInvoice

createInvoice(
  tenantCode: string | null,
  invoiceData: {
    clientName: string;
    concept: string;
    amount: number;
  }
): Promise<Invoice>
Creates a new invoice with a single line item. Requires the invoices.manage RBAC permission.
tenantCode
string | null
required
Tenant subdomain code.
invoiceData.clientName
string
required
Matched against legal_name in the clients table. If no exact match is found, falls back to the first active client in the tenant.
invoiceData.concept
string
required
Line item description stored in invoice_items.description.
invoiceData.amount
number
required
Total invoice amount in COP. Used for subtotal, total_amount, and the single line item’s unit_price and line_total.
Returns Promise<Invoice> — the full inserted invoice row. The generated code follows the pattern FAC-2026-NNNN. New invoices are created with:
  • status: "EMITIDA"
  • due_date set to 30 days from the current date
  • discount_amount: 0, tax_amount: 0, paid_amount: 0
A corresponding invoice_items row is inserted automatically. Required permission: invoices.manage

Tenant Settings

getTenantSettings

getTenantSettings(tenantCode?: string | null): Promise<Record<string, any>>
Returns all settings for the authenticated tenant as a flat key-value record. Encrypted fields (where is_encrypted = true) are transparently decrypted via the get_tenant_setting Supabase RPC before being returned. Soft-deleted settings are excluded.
tenantCode
string | null
Tenant subdomain code.
Returns 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

getPublicTenantSettings(tenantCode?: string | null): Promise<Record<string, any>>
No-auth variant that returns only the nine public branding keys safe to expose to unauthenticated visitors. Does not call requireAction or getAuthContext.
tenantCode
string | null
Tenant subdomain code.
Returns Promise<Record<string, any>> containing any subset of these keys that exist in tenant_settings:
KeyDescription
nombre_comercialTrading name
razon_socialLegal company name
logo_urlPrimary logo URL
logo_secondary_urlSecondary / dark-mode logo URL
favicon_urlBrowser favicon URL
primary_colorBrand primary color (hex)
secondary_colorBrand secondary color (hex)
titulo_navegadorBrowser tab title
descripcion_sitioSite meta description
Returns an empty object {} on error rather than throwing.

updateTenantSettings

updateTenantSettings(
  tenantCode: string | null,
  module: string,
  key: string,
  value: any,
  isEncrypted?: boolean
): Promise<TenantSetting>
Upserts a single tenant setting. Requires the settings.manage RBAC permission. The upsert conflict target is (tenant_id, module, config_key).
tenantCode
string | null
required
Tenant subdomain code.
module
string
required
Settings module name (e.g. "EMPRESA", "IDENTIDAD", "LOCALIZACION", "DOCUMENTOS").
key
string
required
Configuration key (config_key) to upsert.
value
any
required
New value. Stored as JSONB in Supabase.
isEncrypted
boolean
When true, the value will be marked for encryption in the database. Defaults to false.
Returns 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

Build docs developers (and LLMs) love