Merge remote-tracking branch 'origin/main' into feature/crm-cumplimiento-pdf
Tres conflictos en frontend, todos por adiciones en el mismo punto: - crm/types.ts y sidebar/modules.ts: se conservan las dos partes. - crm/AccountFields.svelte: main pasó toda la pestaña fiscal a selects de crmCatalogs. Régimen fiscal y uso de CFDI se quedan con los catálogos del SAT (tax_regime_id / cfdi_use_id), que son las claves que viajan en el CFDI y que el PAC valida contra c_RegimenFiscal y c_UsoCFDI; el catálogo configurable del CRM no las garantiza. Método de pago, forma de pago y moneda sí toman la versión de main. Las tres resoluciones son idénticas a las de feature/AS-timbrado-cfdi-ingreso, donde este mismo merge ya se resolvió y se verificó, para que las dos ramas no diverjan de criterio. Además, un choque que git no detecta: las dos ramas salieron de d5e6f7a8b9c0 y crearon una migración con el mismo id, e6f7a8b9c0d1 —catálogos SAT aquí, catalog_items del CRM en main—. Los archivos se llaman distinto, así que el merge pasa limpio y el problema sólo aparece al arrancar Alembic, con la revisión duplicada y dos cabezas. Se renumera la de facturación a g1h2i3j4k5l6 y se encadena detrás del carril EFC (c5d6e7f8a9b0). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -120,6 +120,7 @@ class InvoiceResponse(InvoiceBase):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
case_id: int | None = None
|
||||
status: str
|
||||
subtotal: Decimal
|
||||
tax_amount: Decimal
|
||||
|
||||
@@ -26,6 +26,7 @@ class Invoice(Base, TenantScopedMixin, TimestampMixin):
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
||||
reference: Mapped[str | None] = mapped_column(String(40), nullable=True, index=True) # folio
|
||||
case_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("crm.cases.id"), nullable=True, index=True) # expediente
|
||||
shipment_id: Mapped[int | None] = mapped_column(
|
||||
Integer, ForeignKey("ops.shipments.id"), nullable=True, index=True
|
||||
)
|
||||
|
||||
@@ -6,6 +6,8 @@ from sqlalchemy import func
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from api.v1.modules.crm.accounts.models import Account
|
||||
from api.v1.modules.crm.cases import service as cases_service
|
||||
from api.v1.modules.crm.common.folios import next_folio
|
||||
from api.v1.modules.crm.quotes.models import Quote, QuoteItem
|
||||
from api.v1.modules.ops.shipments.models import Shipment
|
||||
|
||||
@@ -96,6 +98,15 @@ def create_invoice(db, payload: InvoiceCreate, tenant_id, company_id, user_id=No
|
||||
data = payload.model_dump()
|
||||
_validate_refs(db, data, tenant_id, company_id)
|
||||
obj = Invoice(**data, tenant_id=tenant_id, company_id=company_id, created_by=user_id, updated_by=user_id)
|
||||
# Folio F... auto-generado (mensual) si no viene uno explícito
|
||||
if not obj.reference:
|
||||
obj.reference = next_folio(db, tenant_id, company_id, "F", None, with_direction=False)
|
||||
# Expediente heredado del embarque (si la factura se genera de uno)
|
||||
if obj.shipment_id and not obj.case_id:
|
||||
sh = db.query(Shipment).filter(Shipment.id == obj.shipment_id).first()
|
||||
if sh:
|
||||
obj.case_id = sh.case_id
|
||||
cases_service.advance_stage(db, obj.case_id, "facturacion")
|
||||
db.add(obj)
|
||||
db.flush()
|
||||
_recompute(db, obj)
|
||||
@@ -282,6 +293,7 @@ def generate_from_shipment(db, shipment_id, tenant_id, company_id, user_id=None)
|
||||
|
||||
invoice = Invoice(
|
||||
reference=shipment.reference,
|
||||
case_id=shipment.case_id,
|
||||
shipment_id=shipment.id,
|
||||
quote_id=shipment.quote_id,
|
||||
account_id=shipment.account_id,
|
||||
@@ -295,6 +307,7 @@ def generate_from_shipment(db, shipment_id, tenant_id, company_id, user_id=None)
|
||||
)
|
||||
db.add(invoice)
|
||||
db.flush()
|
||||
cases_service.advance_stage(db, shipment.case_id, "facturacion")
|
||||
|
||||
if quote:
|
||||
q_items = db.query(QuoteItem).filter(QuoteItem.quote_id == quote.id, QuoteItem.deleted_at.is_(None)).all()
|
||||
|
||||
Reference in New Issue
Block a user