Next.js Server Actions (introduced in Next.js 14 and stabilised in 16) let you define async functions that run exclusively on the server and can be called directly from React components without building a separate API layer. In B2B Import ERP every Server Action is declared with theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/ency07/B2B-import/llms.txt
Use this file to discover all available pages before exploring further.
"use server" directive, resolves the caller’s tenant via getTenantId(), and performs all database mutations through supabaseAdmin — the Supabase service-role client — so that Row-Level Security is never a bottleneck for trusted back-end operations.
Common Pattern
Every action follows the same three-step scaffold:- Resolve the tenant — call
getTenantId(tenantCode)to turn a human-readable slug ("apex",nullfor the default tenant, etc.) into a stable UUID. - Execute the query — use
supabaseAdminto read or write the resolved tenant’s data. - Return typed data or throw — on Supabase error, the action throws an
Errorwhose message is safe to surface to the client.
getTenantId implementation
The current implementation uses deterministic UUID constants for the two demo tenants. In a production multi-tenant deployment, replace this with a database lookup against the
tenants table using the tenant_code column.Clients & Contacts
Actions live insrc/app/actions.ts.
getClients
Returns all active clients for a tenant, enriched with their total invoiced amount.
The tenant slug (e.g.
"apex"). Pass null or omit to use the default tenant.deleted_at IS NULL are returned. Invoices are filtered to statuses EMITIDA, PARCIALMENTE_PAGADA, and PAGADA.
createClient
Creates a new client record for the tenant. Checks for a duplicate tax_id within the same tenant before inserting.
The tenant slug.
RFC / NIT / tax identifier. Must be unique within the tenant.
Legal name (
legal_name).Industry segment, stored in the
industry column.Primary contact email.
"Ya existe un cliente con este RFC para este tenant." when the tax_id already exists.
Jobs
Actions live insrc/app/actions.ts.
getJobs
Returns all work orders for the tenant, ordered newest-first. Priority and status values are mapped to display-friendly labels.
Tenant slug.
createJob
Creates a new work order, auto-generating a JOB-2026-XXX code and resolving default client, requirement, site, and area references from the tenant.
Work order description (also used as
title; truncated to 100 chars)."ALTA", "MEDIA", or "BAJA".ISO date string for planned start (
YYYY-MM-DD).ISO date string for planned end (
YYYY-MM-DD).Inventory
Actions live insrc/app/actions.ts.
getInventoryStock
Returns all warehouse stock positions for the tenant, joined with warehouse and item metadata.
createInventoryMovement
Creates a stock movement record (Entrada, Salida, or Transferencia) and sets status to Aplicado.
Movement direction.
Transferencia requires destWarehouse.The
item_code of the inventory_items record.The
warehouse_code of the source warehouse.Required when
type is "Transferencia".Invoices
Actions live insrc/app/actions.ts.
getInvoices
Returns all invoices for the tenant, newest-first, with the linked client’s legal_name joined.
createInvoice
Creates an invoice header in EMITIDA status, adding a single line item for the concept amount. Matches the client by legal_name; falls back to the first active client if no match is found.
Legal name of the client. Used to look up
clients.legal_name.Line item description.
Total amount in COP. Used as both
subtotal_amount and total_amount.Tenant Settings
Actions live insrc/app/actions.ts.
getTenantSettings
Fetches all settings for the tenant as a flat key-value map, decrypting any encrypted fields via the get_tenant_setting RPC.
config_key and each value is the resolved (and decrypted where applicable) config_value.
updateTenantSettings
Upserts a single setting key within a given module. If the row exists it is updated; otherwise a new row is inserted.
Logical grouping:
"EMPRESA", "LOCALIZACION", "IDENTIDAD", "DOCUMENTOS", etc.The
config_key to set (e.g. "color_primario").Any JSON-serialisable value.
Defaults to
false. When true, the value is stored with is_encrypted = true and decrypted via RPC on read.Leads
Actions live insrc/app/actions/leads.ts.
calculateLeadScore
Pure scoring function — no database writes. Computes a 0–100 priority score and assigns a Spanish-language risk level.
Contact email. Public domains (gmail, yahoo, etc.) incur a −20-point penalty. Disposable domains (yopmail, mailinator, tempmail) force
SPAM classification.Professional role. Decision-maker roles (
"Director de Planta", "Gerente de Mantenimiento", "Supervisor de HVAC / Operaciones") add 40 points. Mid-level roles add 25 points.Urgency level.
alta adds 40 points, media adds 20, baja adds 5.createLeadWithScore
Scores the lead and persists it to the leads table with status = "NUEVO".
Tenant slug.
UUID of the existing
clients record.UUID of the existing
client_contacts record.Contact’s professional role — fed to
calculateLeadScore.Urgency level — fed to
calculateLeadScore.Contact email — fed to
calculateLeadScore.submitContactForm
Registers a lead originating from the B2B landing page contact form, without requiring an existing clients record. Scores the lead using calculateLeadScore with role "Otro".
Full name of the contact.
Company name — stored in
leads.company_name.Urgency level fed to
calculateLeadScore.Free-text message — stored in
leads.notes.This action writes directly to the
leads table using the extended columns added by migration 20260619000036_fix_leads_schema.sql (name, company_name, phone, email, urgency, lead_score). Unlike createLeadWithScore, no client_id or contact_id is required.Requirements
Actions live insrc/app/actions/requirements.ts.
getRequirements
Returns all requirements for the tenant, ordered newest-first, with the linked client’s legal_name and city joined.
Tenant slug.
RequirementRow[] where each row includes:
createRequirement
Inserts a new requirement in BORRADOR status.
Short descriptive title.
UUID of the parent client.
Service category (e.g.
"fabricacion", "mantenimiento").Priority level:
"LOW", "MEDIUM", or "HIGH".updateRequirementStatus
Updates the status (and optionally other fields) of an existing requirement. Used to advance requirements through the workflow.
UUID of the requirement to update.
New status value:
"BORRADOR", "NUEVO", "EN_REVISION", "DIAGNOSTICO", "COTIZACION", "COMPLETADO", or "CANCELADO".Optional additional column values to patch on the same row (e.g.
{ engineering_user_id: "..." }).Quotes
Actions live insrc/app/actions/quotes.ts.
getQuotes
Returns all quotes for the tenant, newest-first, with the linked client’s legal_name joined.
Tenant slug.
QuoteRow[]:
createQuote
Creates a new quote header in BORRADOR status.
UUID of the client.
Optional UUID of a linked requirement.
ISO date string for the quote expiry date (
YYYY-MM-DD).getQuoteItems
Returns all line items for a specific quote, ordered by item_order.
UUID of the parent quote.
addQuoteItem
Adds a single line item to an existing quote.
UUID of the parent quote.
Type label for the line item (e.g.
"PRODUCTO", "SERVICIO").Integer display order for this line within the quote.
updateQuoteStatus
Updates the status of an existing quote.
UUID of the quote.
New status:
"BORRADOR", "EN_REVISION", "ENVIADA", "APROBADA", "RECHAZADA", or "VENCIDA".Wizard
Actions live insrc/app/actions/wizard.ts.
submitWizardData
The wizard is the main public-facing intake form. This single action orchestrates the entire lead-capture pipeline: engineering calculations → client upsert → contact upsert → lead scoring → diagnostic report creation.
Tenant slug for the landing page the visitor came from.
Full submission from the multi-step wizard form:
calculateRequiredCfm()computes airflow from room dimensions + environment.estimatePrice()produces a COP/USD price range.- Client is upserted by
legal_name— existing clients are reused, not duplicated. - Contact is upserted by
emailwithin the client — reused if already present. createLeadWithScore()scores the lead and persists it.- A
diagnostic_reportsrecord is created, linking all calculated data to the lead.
WizardResult:
Payments
Actions live insrc/app/actions/payments.ts.
getPaymentGateway
Fetches the active Wompi gateway configuration for the tenant.
null (never throws) when no active gateway is configured, so callers should guard for the null case before attempting checkout.
createWompiCheckout
Creates a payment_transactions record, stamps the invoice with a payment link, and returns the checkout URL.
UUID of the invoice being paid.
Amount in COP (Colombian Peso).
Payer email — stored on the transaction record.
Payer display name.
"Pasarela de pagos no configurada para este tenant." when no active gateway exists.
processWompiWebhook
Called by POST /api/webhooks/wompi. Finds the matching transaction by reference_id, maps the Wompi status, and — when APPROVED — creates a payments record, updates the invoice balance, and creates a payment_reconciliations entry.
revalidatePath("/portal") and revalidatePath("/dashboard/invoices") to invalidate Next.js caches.
getPaymentHistory
Returns the 50 most recent applied payments for the tenant, ordered by payment date descending.
Catalog
Actions live insrc/app/actions/catalog.ts.
getIndustrialCatalog
Fetches the full five-level product hierarchy for the tenant: Category → Subcategory → Family → Series → Products. Each product includes specifications, images, documents, CAD files, and SEO metadata.
Tenant slug.
CatalogCategory[] tree:
This function issues sequential waterfall queries for each level of the hierarchy. For large catalogs consider caching the result with
unstable_cache or implementing a single recursive SQL view.getProductDetail
Fetches the full detail for a single product including specifications, images, documents, CAD files, and SEO metadata.
addProductImage
Inserts a media asset record into media_assets and links it to a product via product_images.
UUID of the product to attach the image to.
Supabase Storage path (e.g.
"products/abc123/hero.png").saveProduct
Creates or updates a product and replaces its specifications in a single operation. Pass product.id to update; omit it to insert.
UUID of the
product_series record this product belongs to.Key-value map of technical specifications. Existing specs are deleted and replaced on every save.
deleteProduct
Soft-deletes a product by setting deleted_at.
saveCategory
Creates or updates a product category. Pass category.id to update; omit it to insert.
deleteCategory
Soft-deletes a product category by setting deleted_at.
Branding
Actions live insrc/app/actions/branding.ts.
getTenantBranding
Returns the merged branding configuration: hardcoded defaults from getBrandingDefaults() are overridden by any keys stored in tenant_settings for modules EMPRESA, LOCALIZACION, IDENTIDAD, and DOCUMENTOS.
Tenant slug. Affects which defaults are applied (
"apex" vs AeroMax).BrandingConfig object (50+ keys covering company info, logos, colours, typography, localization, email/PDF templates, and portal labels). See src/utils/branding-defaults.ts for the complete interface.