Facturapi: fix legal payload (name/legal_name/tax_system, address, no tax_id), reuse local org, status via user key; add fiscal address fields; embed Carta Manifiesto iframe
This commit is contained in:
@@ -761,6 +761,12 @@ def get_business():
|
|||||||
'regimen_fiscal': cfg.get('tenant_regimen_fiscal', ''),
|
'regimen_fiscal': cfg.get('tenant_regimen_fiscal', ''),
|
||||||
'cp': cfg.get('tenant_cp', ''),
|
'cp': cfg.get('tenant_cp', ''),
|
||||||
'direccion': cfg.get('tenant_direccion', ''),
|
'direccion': cfg.get('tenant_direccion', ''),
|
||||||
|
'numero_exterior': cfg.get('tenant_numero_exterior', ''),
|
||||||
|
'numero_interior': cfg.get('tenant_numero_interior', ''),
|
||||||
|
'colonia': cfg.get('tenant_colonia', ''),
|
||||||
|
'ciudad': cfg.get('tenant_ciudad', ''),
|
||||||
|
'municipio': cfg.get('tenant_municipio', ''),
|
||||||
|
'estado': cfg.get('tenant_estado', ''),
|
||||||
'telefono': cfg.get('tenant_telefono', ''),
|
'telefono': cfg.get('tenant_telefono', ''),
|
||||||
'email': cfg.get('tenant_email', ''),
|
'email': cfg.get('tenant_email', ''),
|
||||||
})
|
})
|
||||||
@@ -778,6 +784,12 @@ def update_business():
|
|||||||
'regimen_fiscal': 'tenant_regimen_fiscal',
|
'regimen_fiscal': 'tenant_regimen_fiscal',
|
||||||
'cp': 'tenant_cp',
|
'cp': 'tenant_cp',
|
||||||
'direccion': 'tenant_direccion',
|
'direccion': 'tenant_direccion',
|
||||||
|
'numero_exterior': 'tenant_numero_exterior',
|
||||||
|
'numero_interior': 'tenant_numero_interior',
|
||||||
|
'colonia': 'tenant_colonia',
|
||||||
|
'ciudad': 'tenant_ciudad',
|
||||||
|
'municipio': 'tenant_municipio',
|
||||||
|
'estado': 'tenant_estado',
|
||||||
'telefono': 'tenant_telefono',
|
'telefono': 'tenant_telefono',
|
||||||
'email': 'tenant_email',
|
'email': 'tenant_email',
|
||||||
# Tax params (also keep cfdi_* aliases in sync)
|
# Tax params (also keep cfdi_* aliases in sync)
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ def _get_issuer_config(cur, branch_id=None):
|
|||||||
"razon_social": config.get("tenant_razon_social", ""),
|
"razon_social": config.get("tenant_razon_social", ""),
|
||||||
"regimen_fiscal": config.get("cfdi_regimen_fiscal") or config.get("tenant_regimen_fiscal", "601"),
|
"regimen_fiscal": config.get("cfdi_regimen_fiscal") or config.get("tenant_regimen_fiscal", "601"),
|
||||||
"cp": config.get("tenant_cp", "00000"),
|
"cp": config.get("tenant_cp", "00000"),
|
||||||
|
"direccion": config.get("tenant_direccion", ""),
|
||||||
|
"exterior": config.get("tenant_numero_exterior", ""),
|
||||||
|
"interior": config.get("tenant_numero_interior", ""),
|
||||||
|
"colonia": config.get("tenant_colonia", ""),
|
||||||
|
"ciudad": config.get("tenant_ciudad", ""),
|
||||||
|
"municipio": config.get("tenant_municipio", ""),
|
||||||
|
"estado": config.get("tenant_estado", ""),
|
||||||
"serie": config.get("cfdi_serie") or config.get("invoice_serie", "A"),
|
"serie": config.get("cfdi_serie") or config.get("invoice_serie", "A"),
|
||||||
"facturapi_key": config.get("cfdi_facturapi_key", ""),
|
"facturapi_key": config.get("cfdi_facturapi_key", ""),
|
||||||
"facturapi_org_id": config.get("cfdi_facturapi_org_id", ""),
|
"facturapi_org_id": config.get("cfdi_facturapi_org_id", ""),
|
||||||
|
|||||||
@@ -216,8 +216,18 @@ def create_organization(tenant_config: dict) -> dict:
|
|||||||
rfc = (tenant_config.get("rfc") or "").upper().strip()
|
rfc = (tenant_config.get("rfc") or "").upper().strip()
|
||||||
name = tenant_config.get("razon_social") or tenant_config.get("name") or rfc or "Nexus"
|
name = tenant_config.get("razon_social") or tenant_config.get("name") or rfc or "Nexus"
|
||||||
|
|
||||||
# First try to find existing org by RFC
|
# 1) Reuse the organization already stored locally, if it still exists in Facturapi.
|
||||||
existing = find_organization_by_rfc(tenant_config) if rfc else None
|
local_org_id = _get_org_id(tenant_config)
|
||||||
|
if local_org_id:
|
||||||
|
try:
|
||||||
|
get_organization(local_org_id, user_key)
|
||||||
|
org_id = local_org_id
|
||||||
|
except FacturapiError:
|
||||||
|
local_org_id = None
|
||||||
|
|
||||||
|
# 2) Try to find an existing organization by RFC (legacy / Horux-style lookup).
|
||||||
|
if not local_org_id and rfc:
|
||||||
|
existing = find_organization_by_rfc(tenant_config)
|
||||||
if existing:
|
if existing:
|
||||||
org_id = existing["id"]
|
org_id = existing["id"]
|
||||||
else:
|
else:
|
||||||
@@ -226,6 +236,12 @@ def create_organization(tenant_config: dict) -> dict:
|
|||||||
org_id = org.get("id")
|
org_id = org.get("id")
|
||||||
if not org_id:
|
if not org_id:
|
||||||
raise FacturapiError("Could not create organization: no id returned")
|
raise FacturapiError("Could not create organization: no id returned")
|
||||||
|
elif not local_org_id:
|
||||||
|
payload = {"name": name}
|
||||||
|
org = _request("POST", "/organizations", user_key, json_payload=payload, timeout=60)
|
||||||
|
org_id = org.get("id")
|
||||||
|
if not org_id:
|
||||||
|
raise FacturapiError("Could not create organization: no id returned")
|
||||||
|
|
||||||
# Configure fiscal/legal data (required before Live mode can be used)
|
# Configure fiscal/legal data (required before Live mode can be used)
|
||||||
try:
|
try:
|
||||||
@@ -245,27 +261,49 @@ def create_organization(tenant_config: dict) -> dict:
|
|||||||
|
|
||||||
|
|
||||||
def _build_legal_payload(tenant_config: dict) -> dict:
|
def _build_legal_payload(tenant_config: dict) -> dict:
|
||||||
"""Build Facturapi /organizations/{id}/legal payload from tenant config."""
|
"""Build Facturapi /organizations/{id}/legal payload from tenant config.
|
||||||
|
|
||||||
|
Facturapi expects `name`, `legal_name`, `tax_system` and an `address` object
|
||||||
|
with at least `street` and `exterior` non-empty. `tax_id` is not accepted
|
||||||
|
by this endpoint (it is set from the CSD or from the organization profile).
|
||||||
|
"""
|
||||||
rfc = (tenant_config.get("rfc") or "").upper().strip()
|
rfc = (tenant_config.get("rfc") or "").upper().strip()
|
||||||
legal_name = (tenant_config.get("razon_social") or "").strip()
|
legal_name = (tenant_config.get("razon_social") or "").strip()
|
||||||
tax_system = (tenant_config.get("regimen_fiscal") or "").strip() or "601"
|
tax_system = (tenant_config.get("regimen_fiscal") or "").strip() or "601"
|
||||||
zip_code = (tenant_config.get("cp") or tenant_config.get("tenant_cp") or "").strip() or "00000"
|
zip_code = (tenant_config.get("cp") or "").strip() or "00000"
|
||||||
if not rfc or not legal_name:
|
if not rfc or not legal_name:
|
||||||
raise FacturapiError("RFC y Razón Social son obligatorios para configurar la organización en Facturapi")
|
raise FacturapiError("RFC y Razón Social son obligatorios para configurar la organización en Facturapi")
|
||||||
|
|
||||||
|
name = legal_name or rfc or "Nexus"
|
||||||
|
street = (tenant_config.get("direccion") or "").strip() or "No especificada"
|
||||||
|
exterior = (
|
||||||
|
(tenant_config.get("exterior") or "").strip()
|
||||||
|
or (tenant_config.get("numero_exterior") or "").strip()
|
||||||
|
or "S/N"
|
||||||
|
)
|
||||||
|
|
||||||
|
address = {
|
||||||
|
"zip": zip_code,
|
||||||
|
"street": street,
|
||||||
|
"exterior": exterior,
|
||||||
|
}
|
||||||
|
|
||||||
|
optional_address_fields = {
|
||||||
|
"interior": (tenant_config.get("interior") or tenant_config.get("numero_interior") or "").strip(),
|
||||||
|
"neighborhood": (tenant_config.get("colonia") or "").strip(),
|
||||||
|
"city": (tenant_config.get("ciudad") or "").strip(),
|
||||||
|
"municipality": (tenant_config.get("municipio") or "").strip(),
|
||||||
|
"state": (tenant_config.get("estado") or "").strip(),
|
||||||
|
}
|
||||||
|
for key, value in optional_address_fields.items():
|
||||||
|
if value:
|
||||||
|
address[key] = value
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"tax_id": rfc,
|
"name": name,
|
||||||
"legal_name": legal_name,
|
"legal_name": legal_name,
|
||||||
"tax_system": tax_system,
|
"tax_system": tax_system,
|
||||||
"address": {
|
"address": address,
|
||||||
"zip": zip_code,
|
|
||||||
"street": (tenant_config.get("direccion") or "").strip(),
|
|
||||||
"exterior": "",
|
|
||||||
"interior": "",
|
|
||||||
"neighborhood": "",
|
|
||||||
"city": "",
|
|
||||||
"municipality": "",
|
|
||||||
"state": "",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -279,6 +317,22 @@ def update_organization_legal(tenant_config: dict, org_id: str) -> dict:
|
|||||||
return _request("PUT", f"/organizations/{org_id}/legal", user_key, json_payload=payload, timeout=60)
|
return _request("PUT", f"/organizations/{org_id}/legal", user_key, json_payload=payload, timeout=60)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_status_key(tenant_config: dict) -> str | None:
|
||||||
|
"""Return the best key for read-only organization status checks.
|
||||||
|
|
||||||
|
Prefer the Facturapi user key because the live secret key cannot read
|
||||||
|
organization metadata until the org is production-ready.
|
||||||
|
"""
|
||||||
|
user = _get_user_key()
|
||||||
|
if user:
|
||||||
|
return user
|
||||||
|
for key in ("facturapi_key", "cfdi_facturapi_key"):
|
||||||
|
tenant_key = (tenant_config.get(key) or "").strip()
|
||||||
|
if tenant_key.startswith("sk_user_"):
|
||||||
|
return tenant_key
|
||||||
|
return _get_secret_key(tenant_config)
|
||||||
|
|
||||||
|
|
||||||
def get_org_status(tenant_config: dict) -> dict:
|
def get_org_status(tenant_config: dict) -> dict:
|
||||||
result = {
|
result = {
|
||||||
"configured": False,
|
"configured": False,
|
||||||
@@ -292,12 +346,12 @@ def get_org_status(tenant_config: dict) -> dict:
|
|||||||
"error": None,
|
"error": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
has_secret = bool(_get_secret_key(tenant_config))
|
||||||
api_key = get_api_key(tenant_config)
|
has_user = bool(_get_user_key_for_tenant(tenant_config))
|
||||||
result["has_key"] = True
|
if not has_secret and not has_user:
|
||||||
except FacturapiError as e:
|
result["error"] = "Facturapi not configured. Set FACTURAPI_USER_KEY env or tenant_config.facturapi_secret_key"
|
||||||
result["error"] = str(e)
|
|
||||||
return result
|
return result
|
||||||
|
result["has_key"] = True
|
||||||
|
|
||||||
org_id = _get_org_id(tenant_config)
|
org_id = _get_org_id(tenant_config)
|
||||||
if not org_id:
|
if not org_id:
|
||||||
@@ -307,6 +361,11 @@ def get_org_status(tenant_config: dict) -> dict:
|
|||||||
result["has_org_id"] = True
|
result["has_org_id"] = True
|
||||||
result["org_id"] = org_id
|
result["org_id"] = org_id
|
||||||
|
|
||||||
|
api_key = _get_status_key(tenant_config)
|
||||||
|
if not api_key:
|
||||||
|
result["error"] = "No Facturapi key available"
|
||||||
|
return result
|
||||||
|
|
||||||
def _fetch():
|
def _fetch():
|
||||||
org = get_organization(org_id, api_key)
|
org = get_organization(org_id, api_key)
|
||||||
legal = org.get("legal", {})
|
legal = org.get("legal", {})
|
||||||
|
|||||||
@@ -397,6 +397,13 @@ const Invoicing = (() => {
|
|||||||
const cpEl = document.getElementById('cp-fiscal');
|
const cpEl = document.getElementById('cp-fiscal');
|
||||||
const razonEl = document.getElementById('razon-social');
|
const razonEl = document.getElementById('razon-social');
|
||||||
const regimenEl = document.getElementById('regimen-fiscal');
|
const regimenEl = document.getElementById('regimen-fiscal');
|
||||||
|
const direccionEl = document.getElementById('direccion-fiscal');
|
||||||
|
const exteriorEl = document.getElementById('numero-exterior');
|
||||||
|
const interiorEl = document.getElementById('numero-interior');
|
||||||
|
const coloniaEl = document.getElementById('colonia-fiscal');
|
||||||
|
const ciudadEl = document.getElementById('ciudad-fiscal');
|
||||||
|
const municipioEl = document.getElementById('municipio-fiscal');
|
||||||
|
const estadoEl = document.getElementById('estado-fiscal');
|
||||||
if (!rfcEl || !cpEl || !razonEl || !regimenEl) return;
|
if (!rfcEl || !cpEl || !razonEl || !regimenEl) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -406,6 +413,13 @@ const Invoicing = (() => {
|
|||||||
rfcEl.value = data.rfc || '';
|
rfcEl.value = data.rfc || '';
|
||||||
cpEl.value = data.cp || '';
|
cpEl.value = data.cp || '';
|
||||||
razonEl.value = data.razon_social || '';
|
razonEl.value = data.razon_social || '';
|
||||||
|
if (direccionEl) direccionEl.value = data.direccion || '';
|
||||||
|
if (exteriorEl) exteriorEl.value = data.numero_exterior || '';
|
||||||
|
if (interiorEl) interiorEl.value = data.numero_interior || '';
|
||||||
|
if (coloniaEl) coloniaEl.value = data.colonia || '';
|
||||||
|
if (ciudadEl) ciudadEl.value = data.ciudad || '';
|
||||||
|
if (municipioEl) municipioEl.value = data.municipio || '';
|
||||||
|
if (estadoEl) estadoEl.value = data.estado || '';
|
||||||
const regimen = data.regimen_fiscal || '601';
|
const regimen = data.regimen_fiscal || '601';
|
||||||
regimenEl.value = regimen + ' — ' + (regimenEl.querySelector('option[value^="' + regimen + '"')?.textContent.split('—')[1]?.trim() || '');
|
regimenEl.value = regimen + ' — ' + (regimenEl.querySelector('option[value^="' + regimen + '"')?.textContent.split('—')[1]?.trim() || '');
|
||||||
// If exact value not matched, leave first option selected by SAT code prefix
|
// If exact value not matched, leave first option selected by SAT code prefix
|
||||||
@@ -425,6 +439,13 @@ const Invoicing = (() => {
|
|||||||
const razon_social = (document.getElementById('razon-social')?.value || '').trim();
|
const razon_social = (document.getElementById('razon-social')?.value || '').trim();
|
||||||
const regimenValue = document.getElementById('regimen-fiscal')?.value || '601';
|
const regimenValue = document.getElementById('regimen-fiscal')?.value || '601';
|
||||||
const regimen_fiscal = regimenValue.split('—')[0].trim();
|
const regimen_fiscal = regimenValue.split('—')[0].trim();
|
||||||
|
const direccion = (document.getElementById('direccion-fiscal')?.value || '').trim();
|
||||||
|
const numero_exterior = (document.getElementById('numero-exterior')?.value || '').trim();
|
||||||
|
const numero_interior = (document.getElementById('numero-interior')?.value || '').trim();
|
||||||
|
const colonia = (document.getElementById('colonia-fiscal')?.value || '').trim();
|
||||||
|
const ciudad = (document.getElementById('ciudad-fiscal')?.value || '').trim();
|
||||||
|
const municipio = (document.getElementById('municipio-fiscal')?.value || '').trim();
|
||||||
|
const estado = (document.getElementById('estado-fiscal')?.value || '').trim();
|
||||||
const statusEl = document.getElementById('emisor-save-status');
|
const statusEl = document.getElementById('emisor-save-status');
|
||||||
|
|
||||||
if (!rfc || !razon_social || !cp) {
|
if (!rfc || !razon_social || !cp) {
|
||||||
@@ -436,7 +457,11 @@ const Invoicing = (() => {
|
|||||||
const res = await fetch('/pos/api/config/business', {
|
const res = await fetch('/pos/api/config/business', {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: headers(),
|
headers: headers(),
|
||||||
body: JSON.stringify({ rfc, razon_social, regimen_fiscal, cp, cfdi_regimen_fiscal: regimen_fiscal, cfdi_serie: 'A' })
|
body: JSON.stringify({
|
||||||
|
rfc, razon_social, regimen_fiscal, cp,
|
||||||
|
direccion, numero_exterior, numero_interior, colonia, ciudad, municipio, estado,
|
||||||
|
cfdi_regimen_fiscal: regimen_fiscal, cfdi_serie: 'A'
|
||||||
|
})
|
||||||
});
|
});
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const err = await res.json().catch(() => ({ error: res.statusText }));
|
const err = await res.json().catch(() => ({ error: res.statusText }));
|
||||||
@@ -483,6 +508,13 @@ const Invoicing = (() => {
|
|||||||
document.getElementById('csd-key-label').textContent = 'Subir llave privada .key';
|
document.getElementById('csd-key-label').textContent = 'Subir llave privada .key';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reloadManifiesto() {
|
||||||
|
const iframe = document.getElementById('manifiesto-iframe');
|
||||||
|
if (iframe) {
|
||||||
|
iframe.src = iframe.src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateFileLabels() {
|
function updateFileLabels() {
|
||||||
const cer = document.getElementById('csd-cer');
|
const cer = document.getElementById('csd-cer');
|
||||||
const key = document.getElementById('csd-key');
|
const key = document.getElementById('csd-key');
|
||||||
@@ -836,7 +868,7 @@ const Invoicing = (() => {
|
|||||||
showDetail, showCancelModal, confirmCancel, processQueue,
|
showDetail, showCancelModal, confirmCancel, processQueue,
|
||||||
showNewInvoiceModal, closeNewInvoiceModal, submitNewInvoice, notaCreditoPlaceholder,
|
showNewInvoiceModal, closeNewInvoiceModal, submitNewInvoice, notaCreditoPlaceholder,
|
||||||
openGlobalInvoiceModal, previewGlobalInvoice, generateGlobalInvoice, setupFacturapi,
|
openGlobalInvoiceModal, previewGlobalInvoice, generateGlobalInvoice, setupFacturapi,
|
||||||
uploadCsd, resetCsdForm,
|
uploadCsd, resetCsdForm, reloadManifiesto,
|
||||||
filterFacturas, exportFacturasCSV, exportNotasCSV,
|
filterFacturas, exportFacturasCSV, exportNotasCSV,
|
||||||
newCreditNote, newPaymentComplement,
|
newCreditNote, newPaymentComplement,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
// The fetch handler normalizes static asset URLs (strips ?v= query strings)
|
// The fetch handler normalizes static asset URLs (strips ?v= query strings)
|
||||||
// so templates can use cache-busting query params freely.
|
// so templates can use cache-busting query params freely.
|
||||||
|
|
||||||
const VERSION = 41;
|
const VERSION = 43;
|
||||||
const CACHE_NAME = 'nexus-pos-v' + VERSION;
|
const CACHE_NAME = 'nexus-pos-v' + VERSION;
|
||||||
|
|
||||||
const APP_SHELL = [
|
const APP_SHELL = [
|
||||||
|
|||||||
@@ -757,6 +757,41 @@
|
|||||||
<span class="form-hint">Régimen del emisor según el SAT</span>
|
<span class="form-hint">Régimen del emisor según el SAT</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-field form-field--span2">
|
||||||
|
<label class="form-label" for="direccion-fiscal">Calle</label>
|
||||||
|
<input class="form-input" id="direccion-fiscal" type="text" value="" placeholder="Ej: Av. Insurgentes Sur" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-field">
|
||||||
|
<label class="form-label" for="numero-exterior">Número Exterior</label>
|
||||||
|
<input class="form-input" id="numero-exterior" type="text" value="" placeholder="Ej: 123" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-field">
|
||||||
|
<label class="form-label" for="numero-interior">Número Interior</label>
|
||||||
|
<input class="form-input" id="numero-interior" type="text" value="" placeholder="Ej: 4B" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-field">
|
||||||
|
<label class="form-label" for="colonia-fiscal">Colonia</label>
|
||||||
|
<input class="form-input" id="colonia-fiscal" type="text" value="" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-field">
|
||||||
|
<label class="form-label" for="ciudad-fiscal">Ciudad</label>
|
||||||
|
<input class="form-input" id="ciudad-fiscal" type="text" value="" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-field">
|
||||||
|
<label class="form-label" for="municipio-fiscal">Municipio / Alcaldía</label>
|
||||||
|
<input class="form-input" id="municipio-fiscal" type="text" value="" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-field">
|
||||||
|
<label class="form-label" for="estado-fiscal">Estado</label>
|
||||||
|
<input class="form-input" id="estado-fiscal" type="text" value="" />
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="margin-top:var(--space-4);display:flex;justify-content:flex-end;gap:var(--space-3);align-items:center;">
|
<div style="margin-top:var(--space-4);display:flex;justify-content:flex-end;gap:var(--space-3);align-items:center;">
|
||||||
@@ -867,6 +902,44 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- CARTA MANIFIESTO -->
|
||||||
|
<div class="config-section" style="grid-column: span 2;">
|
||||||
|
<div class="config-section__header">
|
||||||
|
<svg viewBox="0 0 24 24">
|
||||||
|
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||||||
|
<polyline points="14 2 14 8 20 8"/>
|
||||||
|
<line x1="16" y1="13" x2="8" y2="13"/>
|
||||||
|
<line x1="16" y1="17" x2="8" y2="17"/>
|
||||||
|
<polyline points="10 9 9 9 8 9"/>
|
||||||
|
</svg>
|
||||||
|
<span class="config-section__title">Carta Manifiesto (SAT)</span>
|
||||||
|
</div>
|
||||||
|
<div class="config-section__body" id="manifiesto-panel">
|
||||||
|
<p style="color:var(--color-text-muted); margin-bottom:var(--space-3);">
|
||||||
|
Firma la carta manifiesto con tu <strong>FIEL</strong> (e.firma) para autorizar a Facturapi a timbrar CFDI ante el SAT.
|
||||||
|
Si no la ves, usa el botón para abrirla en una pestaña nueva.
|
||||||
|
</p>
|
||||||
|
<div style="border:1px solid var(--color-border); border-radius:var(--radius-md); overflow:hidden; background:var(--color-bg-base);">
|
||||||
|
<iframe
|
||||||
|
id="manifiesto-iframe"
|
||||||
|
src="https://www.facturapi.io/embedded/manifiesto"
|
||||||
|
title="Firma de Carta Manifiesto"
|
||||||
|
style="width:100%; height:720px; border:0; display:block;"
|
||||||
|
loading="lazy"
|
||||||
|
allow="fullscreen"
|
||||||
|
></iframe>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:var(--space-3); display:flex; gap:var(--space-3); justify-content:flex-end;">
|
||||||
|
<a class="btn btn--ghost btn--sm" href="https://www.facturapi.io/manifiesto" target="_blank" rel="noopener">
|
||||||
|
Abrir portal de firma
|
||||||
|
</a>
|
||||||
|
<button type="button" class="btn btn--secondary btn--sm" onclick="Invoicing.reloadManifiesto()">
|
||||||
|
Recargar firma
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- CONFIGURACIÓN DE SERIES — full width -->
|
<!-- CONFIGURACIÓN DE SERIES — full width -->
|
||||||
<div class="config-section" style="grid-column: span 2;">
|
<div class="config-section" style="grid-column: span 2;">
|
||||||
<div class="config-section__header">
|
<div class="config-section__header">
|
||||||
|
|||||||
Reference in New Issue
Block a user