Skip to main content

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

B2B Import ERP ships a pure, AI-free engineering calculation engine used across three surfaces: the public wizard form, the CRM diagnostic report, and the internal quoting tool. All functions are deterministic — given the same inputs they always return the same outputs — and carry zero side-effects. They do not call external APIs, touch the database, or require authentication. This makes them trivially testable with standard Jest unit tests. The engine consists of two primary modules:
  • src/utils/engineering.ts — airflow, volume, power, and noise calculations following ASHRAE standards.
  • src/utils/pricing.ts — COP/USD price estimation with urgency multipliers and volume-based scaling.
A third utility, src/utils/tenant.ts, provides CSS colour helpers used by the branding subsystem.

calculateRequiredCfm

Calculates the required airflow (in CFM — Cubic Feet per Minute) from the physical dimensions of a space and its operating environment, using ASHRAE Air Changes per Hour (ACH) norms.
// src/utils/engineering.ts
export function calculateRequiredCfm(
  dimensions: AreaDimensions,
  environment: string
): {
  cubicMeters: number;
  cubicFeet: number;
  ach: number;
  cfm: number;
}

Parameters

dimensions
AreaDimensions
required
Room dimensions in metres:
interface AreaDimensions {
  length: number; // metres
  width: number;  // metres
  height: number; // metres
}
environment
string
required
Operating environment key. Determines the ACH rate applied:
KeyACHCriticalityNotes
heavy_plant45ALTAHeavy manufacturing / smelting
fundicion45ALTAFoundry (alias for heavy_plant)
mecanico20MEDIAMechanical workshop
alimentos15BAJAFood processing
data_center / datacenter30ALTAServer rooms
miningNot in the ACH map; defaults to 10 ACH. Use heavy_plant for mining environments requiring 45 ACH.
warehouse / almacen8BAJAWarehouse / storage
default10BAJAGeneral purpose

Algorithm

volume_m3   = length × width × height
volume_ft3  = volume_m3 × 35.3147  (1 m³ = 35.3147 ft³)
ach         = ACH_BY_ENVIRONMENT[environment] ?? 10

# Pollutant factor adds +30% for heavy_plant and fundicion environments
pollutant_factor = (heavy_plant | fundicion) ? 1.3 : 1.0

cfm = round((volume_ft3 × ach / 60) × pollutant_factor)

Returns

{
  cubicMeters: number;  // rounded to 2 decimal places
  cubicFeet: number;    // rounded to 2 decimal places
  ach: number;          // air changes per hour used
  cfm: number;          // required airflow in CFM (integer)
}

Example

import { calculateRequiredCfm } from "@/utils/engineering";

const result = calculateRequiredCfm(
  { length: 30, width: 20, height: 8 },
  "data_center"
);
// result.cubicMeters  → 4800
// result.cfm          → ~85357  (4800 × 35.3147 × 30 / 60)
calculateRequiredCfm is a thin wrapper around generateEngineeringReport, which provides a richer DetailedEngineeringReport including power draw (HP and kW), noise level (dBA), equipment count, suggested distribution layout, and investment ranges. Use generateEngineeringReport directly when you need the full pre-engineering report.

getAchForEnvironment

Returns the Air Changes per Hour (ACH) rate for a given environment key, falling back to 10 (the default value) for unrecognised keys.
// src/utils/engineering.ts
export function getAchForEnvironment(environment: string): number
environment
string
required
An environment key from ACH_BY_ENVIRONMENT (see table in calculateRequiredCfm). Unknown keys return 10.
Returns a number — the ACH rate for the environment.

calculateAirDensity

Calculates corrected air density (kg/m³) for a given altitude and temperature using the standard pneumatic formula.
// src/utils/engineering.ts
export function calculateAirDensity(
  altitudeMsnm: number,  // altitude in metres above sea level
  tempCelsius: number    // ambient temperature in °C
): number
altitudeMsnm
number
required
Altitude in metres above sea level. 0 = sea level (standard density 1.204 kg/m³ at 20 °C).
tempCelsius
number
required
Ambient temperature in °C.
Returns air density in kg/m³, rounded to 3 decimal places. Lower altitudes and lower temperatures produce higher density values.

Formula

p0              = 1.204 kg/m³  (standard density at sea level, 20 °C)
tempCorrection  = 293.15 / (tempCelsius + 273.15)
altCorrection   = (1 − 2.2557×10⁻⁵ × altitudeMsnm)^5.25588
airDensity      = p0 × tempCorrection × altCorrection

generateEngineeringReport

Full pre-engineering calculation engine. Extends the CFM calculation with altitude/temperature corrections, motor power sizing, noise estimation, equipment count, and investment range.
export function generateEngineeringReport(
  dimensions: AreaDimensions,
  environment: string,
  altitudeMsnm: number,   // altitude in metres above sea level
  tempCelsius: number,    // ambient temperature in °C
  hasDucts: boolean       // adds 1.5 inWG static pressure when true
): DetailedEngineeringReport
Returns:
interface DetailedEngineeringReport {
  cubicMeters: number;
  cubicFeet: number;
  ach: number;
  cfm: number;
  airDensity: number;          // kg/m³ corrected for altitude and temp
  staticPressure: number;      // inWG: 0.5 (no ducts) or 1.5 (with ducts)
  powerHp: number;             // HP = (CFM × SP) / 6356
  powerKw: number;             // kW = HP × 0.746 / 0.94 (IE4 efficiency)
  noiseDba: number;            // 68 dBA base + 10 × log10(eqCount)
  eqCount: number;             // ceil(cfm / 7500) — standard 7,500 CFM fans
  distribution: string;        // e.g. "4 Inyectores + 4 Extractores tipo Hongo"
  investmentRangeMinCop: number;
  investmentRangeMaxCop: number;
  investmentRangeMinUsd: number;
  investmentRangeMaxUsd: number;
  airVelocityFpm: number;
  criticality: "ALTA" | "MEDIA" | "BAJA";
}

estimatePrice

Generates a budgetary price range in COP and USD based on service type, urgency, and the physical volume of the installation.
// src/utils/pricing.ts
export function estimatePrice(
  serviceType: string,
  urgency: string,
  volumeCubicMeters: number
): PriceEstimation

Parameters

serviceType
string
required
Service category. Determines the base price in COP:
KeyBase Price (COP)
fabricacion$1,200,000
venta$800,000
reparacion$500,000
mantenimiento$300,000
default / otro$500,000
urgency
"baja" | "media" | "alta"
required
Urgency multiplier applied after the volume modifier:
KeyMultiplier
alta×1.35 (+35%)
media×1.10 (+10%)
baja×1.00 (no increment)
volumeCubicMeters
number
required
Volume of the installation in m³. Every 100 m³ adds 5% to the base price: volumeModifier = 1 + max(0, volume / 100) × 0.05.

Algorithm

base_price    = BASE_PRICE_BY_SERVICE[serviceType]
vol_modifier  = 1 + max(0, volume / 100) × 0.05
subtotal      = round(base_price × vol_modifier)
total_cop     = round(subtotal × urgency_multiplier)
total_usd     = round(total_cop / 4000, 2)    -- 1 USD = 4,000 COP

# ±15% deviation for commercial range
range_min_cop = round(total_cop × 0.85)
range_max_cop = round(total_cop × 1.15)

Returns

interface PriceEstimation {
  basePriceCop: number;
  urgencyMultiplier: number;
  subtotalCop: number;
  estimatedTotalCop: number;
  estimatedTotalUsd: number;
  rangeMinCop: number;
  rangeMaxCop: number;
  rangeMinUsd: number;
  rangeMaxUsd: number;
  rate: number;  // always 4000 (1 USD = 4,000 COP)
}

Example

import { estimatePrice } from "@/utils/pricing";

const estimate = estimatePrice("fabricacion", "alta", 500);
// basePriceCop       → 1,200,000
// urgencyMultiplier  → 1.35
// volumeModifier     → 1 + (500/100) × 0.05 = 1.25
// subtotalCop        → 1,500,000
// estimatedTotalCop  → 2,025,000
// rangeMinCop        → 1,721,250
// rangeMaxCop        → 2,328,750

parseToHslChannels

Converts any standard CSS colour (hex #RRGGBB, hsl(), hsla(), or already-formatted space-separated channels) into Tailwind CSS v4’s space-separated HSL channel format "H S% L%".
// src/utils/tenant.ts
export function parseToHslChannels(color: string): string
color
string
required
Input colour in any of these formats:
  • #0284c7 — 6-digit hex
  • #abc — 3-digit hex (expanded internally)
  • hsl(199, 89%, 48%) — CSS hsl()
  • hsla(199, 89%, 48%, 1) — CSS hsla()
  • "199 89% 48%" — already in channel format (returned as-is)
Returns "H S% L%" e.g. "199 89% 48%". Falls back to "240 5.9% 10%" for unrecognised formats.

Example

import { parseToHslChannels } from "@/utils/tenant";

parseToHslChannels("#0284c7");      // → "199 89% 48%"
parseToHslChannels("hsl(199, 89%, 48%)"); // → "199 89% 48%"
parseToHslChannels("199 89% 48%");  // → "199 89% 48%"  (no-op)

formatColorForDb

Converts space-separated HSL channel format back into a valid hsl() CSS string for storing in tenant_settings.config_value, which enforces a format constraint.
// src/utils/tenant.ts
export function formatColorForDb(color: string): string
color
string
required
Space-separated HSL channels: "H S% L%".
Returns "hsl(H, S%, L%)" — e.g. "hsl(199, 89%, 48%)". If the input doesn’t match the channel pattern it is returned unchanged.

Example

import { formatColorForDb } from "@/utils/tenant";

formatColorForDb("199 89% 48%"); // → "hsl(199, 89%, 48%)"
formatColorForDb("hsl(199, 89%, 48%)"); // → "hsl(199, 89%, 48%)"  (passthrough)
The branding save flow calls parseToHslChannels on user-input colours (which may come in any format from a colour picker), then calls formatColorForDb before writing to tenant_settings. This ensures consistency across both Tailwind CSS v4 CSS variable injection and database persistence.

Build docs developers (and LLMs) love