diff --git a/Jenkinsfile b/Jenkinsfile
index 9c65d352..f89ff53e 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -112,7 +112,7 @@ pipeline {
sleep 2
done
if [ "$READY" != "1" ]; then
- echo "ERROR: Postgres no quedó listo a tiempo (30 intentos × 2s)."
+ echo "ERROR: Postgres no quedó listo a tiempo (30 intentos x 2s)."
exit 1
fi
docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" -v ON_ERROR_STOP=1 -c "
diff --git a/backend/api/v1/modules/a24/balance_movements/models.py b/backend/api/v1/modules/a24/balance_movements/models.py
index 2fd7fe84..d609d4c4 100644
--- a/backend/api/v1/modules/a24/balance_movements/models.py
+++ b/backend/api/v1/modules/a24/balance_movements/models.py
@@ -10,7 +10,7 @@ These 4 tables are ALL you need for balances:
a24.balance_movement ← the ledger (append-only, never UPDATE)
a24.discharge_header ← one discharge per export/SM/CTM event
- a24.discharge_detail ← one row per (export line × import lot consumed)
+ a24.discharge_detail ← one row per (export line x import lot consumed)
a24.discharge_scrap ← mermas, desperdicios, destrucciones
Design rules:
diff --git a/backend/api/v1/modules/a24/discharges/models.py b/backend/api/v1/modules/a24/discharges/models.py
index 2c8aed7f..47d5511a 100644
--- a/backend/api/v1/modules/a24/discharges/models.py
+++ b/backend/api/v1/modules/a24/discharges/models.py
@@ -10,7 +10,7 @@ These 4 tables are ALL you need for balances:
a24.balance_movement ← the ledger (append-only, never UPDATE)
a24.discharge_header ← one discharge per export/SM/CTM event
- a24.discharge_detail ← one row per (export line × import lot consumed)
+ a24.discharge_detail ← one row per (export line x import lot consumed)
a24.discharge_scrap ← mermas, desperdicios, destrucciones
Design rules:
@@ -156,7 +156,7 @@ class DischargeHeader(Base, TenantScopedMixin, TimestampMixin):
# The critical traceability link:
# "Export line X consumed Y units from import lot Z"
#
-# One row per (export_line × import_lot) pair.
+# One row per (export_line x import_lot) pair.
# A single export line can span multiple rows when PEPS pulls from
# more than one import lot.
#
@@ -168,7 +168,7 @@ class DischargeHeader(Base, TenantScopedMixin, TimestampMixin):
class DischargeDetail(Base, TenantScopedMixin, TimestampMixin):
"""
- One row per (export line × import lot consumed).
+ One row per (export line x import lot consumed).
This is the traceability record the SAT asks for:
"Show me which import pedimento covered this export line."
diff --git a/backend/api/v1/modules/a76/invoices/exports/docs/REPO_exports_diagramas.md b/backend/api/v1/modules/a76/invoices/exports/docs/REPO_exports_diagramas.md
index e61eb882..dcdc1dbe 100644
--- a/backend/api/v1/modules/a76/invoices/exports/docs/REPO_exports_diagramas.md
+++ b/backend/api/v1/modules/a76/invoices/exports/docs/REPO_exports_diagramas.md
@@ -22,7 +22,7 @@ flowchart TD
V5 --> V6{¿TC de la factura\n== TC del catálogo?}
V6 -- No --> E4([❌ Error\nTipo de cambio incorrecto])
V6 -- Sí --> V7[Marcar todas las partidas\ncomo sin descarga]
- V7 --> V8[Calcular valores por partida\nCosto × Cantidad × TC\nen pesos · dólares · moneda cuenta]
+ V7 --> V8[Calcular valores por partida\nCosto x Cantidad x TC\nen pesos · dólares · moneda cuenta]
V8 --> V9[Validar costo unitario · series · pesos]
V9 --> V10{¿Hay errores\nen partidas?}
V10 -- Sí --> E5([❌ Error\nCosto en cero o series faltantes])
diff --git a/backend/api/v1/modules/a76/invoices/exports/process/sub_process/assign_values.py b/backend/api/v1/modules/a76/invoices/exports/process/sub_process/assign_values.py
index aa401166..8a289d37 100644
--- a/backend/api/v1/modules/a76/invoices/exports/process/sub_process/assign_values.py
+++ b/backend/api/v1/modules/a76/invoices/exports/process/sub_process/assign_values.py
@@ -117,7 +117,7 @@ def _assign_costs_per_line(
line.financial.unit_cost_usd = cost_usd
line.financial.unit_cost_mxn = cost_usd * line_tc
- # Values are always: cost × qty
+ # Values are always: cost x qty
line.financial.value_mxn = (line.financial.unit_cost_mxn or Decimal(0)) * qty
line.financial.value_usd = (line.financial.unit_cost_usd or Decimal(0)) * qty
line.financial.value_mc = capture * qty
diff --git a/backend/api/v1/modules/a76/invoices/exports/process/sub_process/register_discharge_ledger.py b/backend/api/v1/modules/a76/invoices/exports/process/sub_process/register_discharge_ledger.py
index b48f4a8f..33484748 100644
--- a/backend/api/v1/modules/a76/invoices/exports/process/sub_process/register_discharge_ledger.py
+++ b/backend/api/v1/modules/a76/invoices/exports/process/sub_process/register_discharge_ledger.py
@@ -5,7 +5,7 @@ Creates the full Annex-24 discharge record for one export invoice:
1. ONE DischargeHeader (one per export event)
2. N BalanceMovement rows (type=CONSUMPTION, one per lot consumed)
- 3. N DischargeDetail rows (one per export-line × import-lot pair),
+ 3. N DischargeDetail rows (one per export-line x import-lot pair),
each referencing its BalanceMovement (design rule 3)
Design rules from a24.balance_movement (preserved here):
@@ -163,7 +163,7 @@ def register_discharge_ledger(
import_invoice_number_cache[lot.import_invoice_id] = origin_import_invoice
# ── 2. BalanceMovement (CONSUMPTION) ──────────────────────────
- # Proportional value: consume / lot_consumed_total × lot_value
+ # Proportional value: consume / lot_consumed_total x lot_value
# lot_consumed_total == consume for single-lot entries (most cases)
value_me = _proportional_value(consume, consume, lot.value_me)
value_mn = _proportional_value(consume, consume, lot.value_mn)
diff --git a/backend/api/v1/modules/a76/invoices/exports/process/sub_process/review_limits.py b/backend/api/v1/modules/a76/invoices/exports/process/sub_process/review_limits.py
index 163177ac..92424119 100644
--- a/backend/api/v1/modules/a76/invoices/exports/process/sub_process/review_limits.py
+++ b/backend/api/v1/modules/a76/invoices/exports/process/sub_process/review_limits.py
@@ -86,7 +86,7 @@ def limit_weight(lines: List[Any]) -> tuple[Decimal, Decimal]:
return total_qty, total_net_weight
def limit_value(lines: List[Any]) -> Decimal:
- """Sums (unit_cost_capture × quantity) across all line items."""
+ """Sums (unit_cost_capture x quantity) across all line items."""
total_value = Decimal(0)
for line in lines:
if line.financial and line.quantity:
diff --git a/backend/api/v1/modules/a76/invoices/imports/docs/REPO_imports_diagramas.md b/backend/api/v1/modules/a76/invoices/imports/docs/REPO_imports_diagramas.md
index 57af3fda..6864aaa8 100644
--- a/backend/api/v1/modules/a76/invoices/imports/docs/REPO_imports_diagramas.md
+++ b/backend/api/v1/modules/a76/invoices/imports/docs/REPO_imports_diagramas.md
@@ -21,7 +21,7 @@ flowchart TD
V2 --> V3{¿Errores en\nclases o fracciones?}
V3 -- Sí --> E4([❌ Error\nClase o fracción inválida])
V3 -- No --> V4[Validar pesos por partida\nKGS o LBS según configuración]
- V4 --> CALC[Calcular valores sin IVA\nCosto × Cantidad × TC\npesos · dólares · moneda cuenta]
+ V4 --> CALC[Calcular valores sin IVA\nCosto x Cantidad x TC\npesos · dólares · moneda cuenta]
CALC --> VL[Validar por cada partida\ncosto > 0 · clase activa\nparte activa · series · UMA]
VL --> VL2{¿Errores en\npartidas?}
VL2 -- Sí --> E5([❌ Error\nCosto cero · clase desactivada\nparte desactivada · series faltantes])
diff --git a/backend/api/v1/modules/a76/reports/movements/vencimiento/service.py b/backend/api/v1/modules/a76/reports/movements/vencimiento/service.py
index 8974f155..060485d6 100644
--- a/backend/api/v1/modules/a76/reports/movements/vencimiento/service.py
+++ b/backend/api/v1/modules/a76/reports/movements/vencimiento/service.py
@@ -327,7 +327,7 @@ def generate_vencimiento_csv(filters: VencimientoFilter, db: Session) -> bytes:
peso_saldo = peso_neto - peso_usado
# -- Valor según moneda (ME = foreign, MN = national) --
- # Legacy (UsarDescargos=1): ValorUsado = (CantUsada × ValorOrig) / CantOrig (proporcional, igual que peso)
+ # Legacy (UsarDescargos=1): ValorUsado = (CantUsada x ValorOrig) / CantOrig (proporcional, igual que peso)
if use_me:
valor_orig = _d(row["C22"])
else:
diff --git a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/class-dialog.svelte b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/class-dialog.svelte
index 3d091ec5..5ae270bb 100644
--- a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/class-dialog.svelte
+++ b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/class-dialog.svelte
@@ -3,9 +3,10 @@
import * as Table from '$lib/components/ui/table';
import { Input } from '$lib/components/ui/input';
import { Button } from '$lib/components/ui/button';
- import { Search, Loader2, Info } from 'lucide-svelte';
- import { toast } from 'svelte-sonner';
+ import { Search, Loader2, Info, AlertCircle } from 'lucide-svelte';
import { companyStore } from '$lib/stores/company.svelte';
+
+ let classesLoadError = $state('');
import { onMount } from 'svelte';
import { classesApi } from '$lib/api/dashboard/a76/classes';
@@ -57,7 +58,7 @@
currentPage = page;
} catch (error) {
console.error('Error fetching classes:', error);
- toast.error('Error al cargar clases');
+ classesLoadError = 'No se pudieron cargar las clases. Intenta de nuevo.';
if (page === 1) {
classes = [];
totalItems = 0;
@@ -133,6 +134,22 @@
+ {#if classesLoadError}
+
+
+
{classesLoadError}
+
+
+ {/if}
+
diff --git a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/part-number-dialog.svelte b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/part-number-dialog.svelte
index c60d96a6..f15141ff 100644
--- a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/part-number-dialog.svelte
+++ b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/part-number-dialog.svelte
@@ -3,10 +3,11 @@
import * as Table from '$lib/components/ui/table';
import { Input } from '$lib/components/ui/input';
import { Button } from '$lib/components/ui/button';
- import { Search, Loader2, Info, Package } from 'lucide-svelte';
- import { toast } from 'svelte-sonner';
+ import { Search, Loader2, Info, Package, AlertCircle } from 'lucide-svelte';
import { companyStore } from '$lib/stores/company.svelte';
+ let partsLoadError = $state('');
+
let {
open = $bindable(false),
onSelect
@@ -62,7 +63,7 @@
currentPage = page;
} catch (error) {
console.error('Error fetching parts:', error);
- toast.error('Error al cargar números de parte');
+ partsLoadError = 'No se pudieron cargar los números de parte. Intenta de nuevo.';
} finally {
isSearching = false;
isLoadingMore = false;
@@ -131,6 +132,22 @@
+ {#if partsLoadError}
+
+
+
{partsLoadError}
+
+
+ {/if}
+
diff --git a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/tab-series.svelte b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/tab-series.svelte
index 5ede683c..1cf364f5 100644
--- a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/tab-series.svelte
+++ b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/tab-series.svelte
@@ -4,12 +4,14 @@
import { Checkbox } from '$lib/components/ui/checkbox';
import { Label } from '$lib/components/ui/label';
import { Button } from '$lib/components/ui/button';
- import { Plus, Pencil, Trash2, CheckCircle2, AlertTriangle } from 'lucide-svelte';
+ import { Plus, Pencil, Trash2, CheckCircle2, AlertTriangle, AlertCircle } from 'lucide-svelte';
import { itemsApi, type Item, type LineDescriptions, type Serie } from '$lib/api/dashboard/a76/items';
import type { Invoice } from '$lib/api/dashboard/a76/invoices';
import { companyStore } from '$lib/stores/company.svelte';
import { toast } from 'svelte-sonner';
+ let seriesErrorMessage = $state('');
+
let {
descriptions = $bindable(),
series = $bindable(),
@@ -93,7 +95,7 @@
selectedSeriesIndex = null;
} catch (err) {
console.error('Error clearing series:', err);
- toast.error('Error al intentar borrar las series.');
+ seriesErrorMessage = 'No se pudieron borrar las series. Intenta de nuevo.';
}
}
@@ -171,6 +173,22 @@