Schema (packages/database/prisma/schema.prisma): - Add SenaeCategory, B2BRequestStatus, NotificationChannel enums - Add Package fields: lengthCm, widthCm, heightCm, hasDiscrepancy, photos[], senaeCategory, senaeAuthNumber, senaeDeclarationId - Add userId field to PreAlert - Add RefreshToken model (JWT auth — Fase 1) - Add Tariff model (configurable rates: pricePerLb, insurancePct, etc.) - Add B2BRequest model (heavy cargo imports — doc §13) - Add Notification model (multi-channel: email, whatsapp, sms, push — doc §16) - Add userAgent to AuditLog API (apps/api): - Add CalculatorModule: calculates SENAE cost breakdown (flete, seguro, FODINFA, arancel, IVA) per formulas in doc §15 - Add TrackingModule: public GET /api/tracking/:id endpoint (doc §07) - Register both modules in AppModule - Add Jest config + test scripts (test, test:watch, test:cov, test:ci) Tests (80 tests, 97.45% coverage): - calculator.util.spec.ts: 35 tests — SENAE formulas, volumetric weight, 4x4 regime, tariff rates, error validation, breakdown - tracking-id.util.spec.ts: 13 tests — format, uniqueness, validation - suite-code.util.spec.ts: 13 tests — generation, parsing, address builder - health.controller.spec.ts: 5 tests — ok/degraded/timestamp - calculator.spec.ts: 8 tests — controller + service unit tests - tracking.controller.spec.ts: 9 tests — public search, 404, no sensitive data Web (apps/web): - page.tsx: Full landing page matching documentation (Hero, Services, 8 Modules, Tracking states, SENAE calculator preview, 6 Roles, Companies) - /calculadora: SENAE categories + API usage guide - /tracking: Tracking ID format + 11 states reference Seed (packages/database/prisma/seed.ts): - Creates all 6 roles (SUPER_ADMIN, ADMIN_EMPRESA, OPERADOR_BODEGA, AGENTE_ADUANERO, CLIENTE, SOPORTE) - Assigns Suite EC-00001 to demo client - Creates demo Package EC-20260506-000001 with status history - Creates demo PreAlert and B2BRequest .env.example: Added all 9 integrations from doc §18: Amazon SP-API, SENAE WebService, Stripe/PayPhone, WhatsApp Business API, SendGrid/SES, SMS/Twilio, FedEx/DHL/UPS couriers, S3/MinIO, Sentry migration.sql: Updated to reflect all new models and fields turbo.json + package.json: Added test, test:cov, test:ci tasks + db:seed script
87 lines
4.1 KiB
TypeScript
87 lines
4.1 KiB
TypeScript
import type { Metadata } from "next";
|
||
|
||
export const metadata: Metadata = {
|
||
title: "Calculadora de Envíos SENAE — Moraworld Imports",
|
||
description: "Calcula el costo total de tu envío desde EE.UU. a Ecuador incluyendo FODINFA, IVA, arancel y flete. Sin registro.",
|
||
};
|
||
|
||
export default function CalculadoraPage() {
|
||
const apiUrl = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:3001";
|
||
|
||
return (
|
||
<main style={{ minHeight: "100vh", background: "#F3F4F6", padding: "40px 20px" }}>
|
||
<div style={{ maxWidth: 700, margin: "0 auto" }}>
|
||
<div style={{ marginBottom: 32 }}>
|
||
<h1 style={{ fontSize: "1.8rem", fontWeight: 800, marginBottom: 8 }}>
|
||
Calculadora SENAE
|
||
</h1>
|
||
<p style={{ color: "#6B7280" }}>
|
||
Sin necesidad de registro. Conoce el costo total antes de comprar.
|
||
</p>
|
||
</div>
|
||
|
||
{/* Nota: el formulario interactivo se implementa en Fase 1 con client component */}
|
||
<div style={{
|
||
background: "#fff", borderRadius: 16, padding: 32,
|
||
border: "1px solid #E5E7EB", marginBottom: 24,
|
||
}}>
|
||
<h2 style={{ fontWeight: 700, marginBottom: 16, fontSize: "1rem" }}>
|
||
Ingresa los datos de tu paquete
|
||
</h2>
|
||
<p style={{ color: "#6B7280", fontSize: ".88rem", marginBottom: 20 }}>
|
||
El formulario interactivo se habilitará en la Fase 1. Por ahora puedes usar el
|
||
endpoint de la API directamente:
|
||
</p>
|
||
<div style={{
|
||
background: "#0D1117", borderRadius: 10, padding: "16px 20px",
|
||
fontFamily: "monospace", fontSize: ".8rem", color: "#A5B4FC",
|
||
lineHeight: 2,
|
||
}}>
|
||
<div style={{ color: "rgba(255,255,255,.3)", marginBottom: 8 }}>{`// GET /api/calculator`}</div>
|
||
<div>
|
||
<span style={{ color: "#6EE7B7" }}>GET</span>{" "}
|
||
{apiUrl}/api/calculator?<span style={{ color: "#FCD34D" }}>value</span>=150&
|
||
<span style={{ color: "#FCD34D" }}>weight</span>=2&
|
||
<span style={{ color: "#FCD34D" }}>category</span>=REGIMEN_4X4
|
||
</div>
|
||
<div style={{ marginTop: 12, color: "rgba(255,255,255,.3)" }}>
|
||
{`// Parámetros: value, weight, category, length, width, height, shipments`}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Categorías SENAE informativas */}
|
||
<div style={{
|
||
background: "#fff", borderRadius: 16, padding: 32,
|
||
border: "1px solid #E5E7EB",
|
||
}}>
|
||
<h2 style={{ fontWeight: 700, marginBottom: 20, fontSize: "1rem" }}>
|
||
Categorías SENAE aplicables
|
||
</h2>
|
||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
|
||
{[
|
||
{ name: "Régimen 4×4", rate: "0%", color: "#10B981", bg: "#D1FAE5", desc: "Hasta $400 · 4 kg · 4 envíos/año" },
|
||
{ name: "Categoría B", rate: "10%", color: "#1D4ED8", bg: "#DBEAFE", desc: "Bienes generales" },
|
||
{ name: "Categoría C", rate: "20%", color: "#FF6B00", bg: "#FFEDD5", desc: "Textiles, calzado, hogar" },
|
||
{ name: "Categoría D", rate: "0–15%", color: "#8B5CF6", bg: "#EDE9FE", desc: "Electrónicos · puede requerir INEN" },
|
||
].map((c) => (
|
||
<div key={c.name} style={{
|
||
background: c.bg, borderRadius: 10, padding: 16, textAlign: "center",
|
||
}}>
|
||
<div style={{ fontWeight: 800, marginBottom: 4 }}>{c.name}</div>
|
||
<div style={{ fontSize: "1.8rem", fontWeight: 900, color: c.color, lineHeight: 1, marginBottom: 6 }}>{c.rate}</div>
|
||
<div style={{ fontSize: ".75rem", color: "#4B5563" }}>{c.desc}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
<div style={{ marginTop: 20, padding: 16, background: "#F3F4F6", borderRadius: 8 }}>
|
||
<p style={{ fontSize: ".82rem", color: "#6B7280", lineHeight: 1.6 }}>
|
||
<strong>Fórmula:</strong> Flete (Peso × $3.50/lb) + Seguro (2%) + FODINFA (0.5%) + Arancel (% categoría) + IVA (15%)
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
);
|
||
}
|