Reorganiza repo como fuente de la verdad + propuesta v1.0 con emisión de facturas

- Estructura nueva: README maestro, bitacora/ (REGISTRO, PENDIENTES, plantillas),
  propuesta/, fuentes/; material superado a _archivado/
- Propuesta v1.0: MVP BIND-first con emisión asistida MXN/USD (dry-run +
  confirmación, timbra PAC de BIND), 112-136 h / $67,200-$81,600 + IVA,
  stack .NET 10 + EF Core + Angular 21 + PostgreSQL 17 sobre Azure
- Bitácora: historial de correos + 2 llamadas (incl. revisión 4-jun) y pendientes
- Prototipo y diagrama actualizados a v1.0; precios de Azure verificados
- Archivo ajeno (proyecto EOS) retirado del repo

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
JohannVelazquez
2026-06-04 10:57:27 -06:00
parent 404e6f3b89
commit 633d05e330
47 changed files with 32977 additions and 472 deletions
@@ -0,0 +1,261 @@
/**
* Datos sintéticos que imitan lo que BIND devolvería para una cuenta
* del tamaño de Balam (45 colaboradores + 5 freelancers, ~50 facturas/mes).
*
* Nada de esto es información real de Balam. Solo cumple con la *forma*
* del payload para que el cliente y los handlers se validen.
*/
import type {
Activity,
Customer,
Invoice,
InvoiceLine,
Payment,
Product,
} from "../../client/types.js";
export const customers: Customer[] = [
{
ID: "11111111-1111-1111-1111-111111111111",
Code: "ACU-001",
Name: "Acuntia México SA de CV",
TaxId: "ACU010203AB1",
Country: "MX",
Email: "facturacion@acuntia.example",
Currency: "MXN",
PaymentTerms: 30,
IsActive: true,
CreatedAt: "2024-01-15T10:00:00Z",
UpdatedAt: "2026-04-01T10:00:00Z",
},
{
ID: "22222222-2222-2222-2222-222222222222",
Code: "CLI-002",
Name: "TechMex Innovaciones SAPI",
TaxId: "TMI150301CD2",
Country: "MX",
Email: "ap@techmex.example",
Currency: "MXN",
PaymentTerms: 45,
IsActive: true,
CreatedAt: "2024-03-20T10:00:00Z",
UpdatedAt: "2026-04-15T10:00:00Z",
},
{
ID: "33333333-3333-3333-3333-333333333333",
Code: "CLI-003",
Name: "Norteamericana Logistics LLC",
TaxId: "98-7654321",
Country: "US",
Email: "billing@norteam.example",
Currency: "USD",
PaymentTerms: 60,
IsActive: true,
CreatedAt: "2025-02-10T10:00:00Z",
UpdatedAt: "2026-05-01T10:00:00Z",
},
{
ID: "44444444-4444-4444-4444-444444444444",
Code: "CLI-004",
Name: "Distribuidora del Golfo SA",
TaxId: "DGO180815EF3",
Country: "MX",
Email: "pagos@dgolfo.example",
Currency: "MXN",
PaymentTerms: 30,
IsActive: true,
CreatedAt: "2025-06-01T10:00:00Z",
UpdatedAt: "2026-05-10T10:00:00Z",
},
{
ID: "55555555-5555-5555-5555-555555555555",
Code: "CLI-005",
Name: "Servicios Estratégicos del Norte",
TaxId: "SEN200401GH4",
Country: "MX",
Email: "tesoreria@sen.example",
Currency: "MXN",
PaymentTerms: 15,
IsActive: false,
CreatedAt: "2025-08-12T10:00:00Z",
UpdatedAt: "2026-03-22T10:00:00Z",
},
];
export const products: Product[] = [
{
ID: "a1111111-1111-1111-1111-111111111111",
Code: "SVC-CONSULT",
Name: "Consultoría estratégica · hora",
UnitPrice: 1800,
Currency: "MXN",
SatCode: "80101504",
IsActive: true,
},
{
ID: "a2222222-2222-2222-2222-222222222222",
Code: "SVC-RECRUIT",
Name: "Búsqueda de talento ejecutivo",
UnitPrice: 45000,
Currency: "MXN",
SatCode: "80111501",
IsActive: true,
},
];
function line(product: Product, qty: number, taxRate: number): InvoiceLine {
const subtotal = round2(qty * product.UnitPrice);
const total = round2(subtotal * (1 + taxRate));
return {
ProductID: product.ID,
Description: product.Name,
Quantity: qty,
UnitPrice: product.UnitPrice,
TaxRate: taxRate,
Subtotal: subtotal,
Total: total,
};
}
export const invoices: Invoice[] = [
// 1) Pagada
{
ID: "f0000001-0000-0000-0000-000000000001",
Folio: "0001",
Serie: "A",
UUID: "AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAA0001",
CustomerID: customers[1]!.ID,
IssueDate: "2026-03-01T10:00:00Z",
DueDate: "2026-04-15T10:00:00Z",
Currency: "MXN",
ExchangeRate: null,
Subtotal: 90000,
Taxes: 14400,
Total: 104400,
Balance: 0,
Status: "paid",
Lines: [line(products[1]!, 2, 0.16)],
XmlUrl: "https://api.bind.com.mx/api/Invoices/f0000001/xml",
PdfUrl: "https://api.bind.com.mx/api/Invoices/f0000001/pdf",
},
// 2) Vigente
{
ID: "f0000002-0000-0000-0000-000000000002",
Folio: "0002",
Serie: "A",
UUID: "AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAA0002",
CustomerID: customers[3]!.ID,
IssueDate: "2026-05-10T10:00:00Z",
DueDate: "2026-06-09T10:00:00Z",
Currency: "MXN",
ExchangeRate: null,
Subtotal: 36000,
Taxes: 5760,
Total: 41760,
Balance: 41760,
Status: "issued",
Lines: [line(products[0]!, 20, 0.16)],
XmlUrl: null,
PdfUrl: null,
},
// 3) Vencida — caso cobranza
{
ID: "f0000003-0000-0000-0000-000000000003",
Folio: "0003",
Serie: "A",
UUID: "AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAA0003",
CustomerID: customers[1]!.ID,
IssueDate: "2026-02-15T10:00:00Z",
DueDate: "2026-04-01T10:00:00Z",
Currency: "MXN",
ExchangeRate: null,
Subtotal: 18000,
Taxes: 2880,
Total: 20880,
Balance: 20880,
Status: "overdue",
Lines: [line(products[0]!, 10, 0.16)],
XmlUrl: null,
PdfUrl: null,
},
// 4) USD a cliente Texas — sin IVA (exportación)
{
ID: "f0000004-0000-0000-0000-000000000004",
Folio: "0004",
Serie: "A",
UUID: "AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAA0004",
CustomerID: customers[2]!.ID,
IssueDate: "2026-05-20T10:00:00Z",
DueDate: "2026-07-19T10:00:00Z",
Currency: "USD",
ExchangeRate: 17.85,
Subtotal: 12500,
Taxes: 0,
Total: 12500,
Balance: 12500,
Status: "issued",
Lines: [
{
ProductID: products[1]!.ID,
Description: products[1]!.Name,
Quantity: 1,
UnitPrice: 12500,
TaxRate: 0,
Subtotal: 12500,
Total: 12500,
},
],
XmlUrl: null,
PdfUrl: null,
},
// 5) Cliente estratégico — ACUNTIA (no debe recibir recordatorio auto)
{
ID: "f0000005-0000-0000-0000-000000000005",
Folio: "0005",
Serie: "A",
UUID: "AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAA0005",
CustomerID: customers[0]!.ID,
IssueDate: "2026-04-20T10:00:00Z",
DueDate: "2026-05-20T10:00:00Z",
Currency: "MXN",
ExchangeRate: null,
Subtotal: 54000,
Taxes: 8640,
Total: 62640,
Balance: 62640,
Status: "overdue",
Lines: [line(products[0]!, 30, 0.16)],
XmlUrl: null,
PdfUrl: null,
},
];
export const payments: Payment[] = [
{
ID: "p0000001-0000-0000-0000-000000000001",
InvoiceID: invoices[0]!.ID,
PaymentDate: "2026-04-10T10:00:00Z",
Amount: 104400,
Currency: "MXN",
Method: "transfer",
Reference: "SPEI 7XX9-2026-04-10",
},
];
export const activities: Activity[] = [
{
ID: "ac000001-0000-0000-0000-000000000001",
CustomerID: customers[1]!.ID,
InvoiceID: invoices[2]!.ID,
Type: "reminder",
Subject: "Recordatorio enviado a TechMex (vencida 30 días)",
Notes: "Plantilla cobranza-vencida-30d",
CreatedAt: "2026-04-05T16:00:00Z",
CreatedBy: "balam-collections-bot",
},
];
function round2(n: number): number {
return Math.round(n * 100) / 100;
}