Files
MarineInvoice/templates/company_form.html
T
alro65 35d460b127 Initial commit — MarineInvoice v1.0
Multi-tenant marine invoicing system: Stripe payments, PDF generation,
digital signatures, QR codes, SMTP email, bilingual templates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 01:54:08 -04:00

125 lines
8.8 KiB
HTML

{% extends "base.html" %}
{% block title %}{{ 'Editar' if company else 'Nueva' }} Compañía{% endblock %}
{% block content %}
<div class="flex items-center gap-3 mb-4">
<a href="/companies" class="btn btn-secondary btn-sm">← Volver</a>
<h1 class="page-title">{{ 'Editar' if company else 'Nueva' }} Compañía</h1>
</div>
<div class="card">
<form method="POST" enctype="multipart/form-data">
<p class="inv-section-title">Información General</p>
<div class="grid-2">
<div class="form-group"><label>Nombre *</label><input type="text" name="name" value="{{ company.name if company else '' }}" required placeholder="Ej: Prisa Yachts"></div>
<div class="form-group"><label>EIN / Tax ID</label><input type="text" name="ein" value="{{ company.ein if company else '' }}" placeholder="XX-XXXXXXX"></div>
</div>
<div class="grid-2">
<div class="form-group"><label>Licencia</label><input type="text" name="license" value="{{ company.license_num if company else '' }}" placeholder="Número de licencia"></div>
<div class="form-group"><label>Teléfono</label><input type="text" name="phone" value="{{ company.phone if company else '' }}" placeholder="(305) XXX-XXXX"></div>
</div>
<div class="form-group"><label>Dirección</label><input type="text" name="address" value="{{ company.address if company else '' }}" placeholder="Dirección"></div>
<div class="grid-2">
<div class="form-group"><label>Ciudad</label><input type="text" name="city" value="{{ company.city if company else '' }}" placeholder="Miami"></div>
<div class="form-group"><label>Estado / ZIP</label><input type="text" name="state" value="{{ company.state if company else '' }}" placeholder="FL 33010"></div>
</div>
<div class="grid-2">
<div class="form-group"><label>Email</label><input type="email" name="email" value="{{ company.email if company else '' }}" placeholder="info@empresa.com"></div>
<div class="form-group"><label>Website</label><input type="text" name="website" value="{{ company.website if company else '' }}" placeholder="www.empresa.com"></div>
</div>
<div class="grid-2">
<div class="form-group"><label>Gerente / Owner</label><input type="text" name="manager" value="{{ company.manager if company else '' }}" placeholder="Nombre completo"></div>
<div class="form-group"><label>Persona Autorizada</label><input type="text" name="authorized" value="{{ company.authorized if company else '' }}" placeholder="Nombre completo"></div>
</div>
<div class="grid-2">
<div class="form-group"><label>Sales Tax %</label><input type="number" name="tax_rate" value="{{ company.tax_rate if company else '7' }}" min="0" max="20" step="0.1"></div>
<div class="form-group">
<label>Logo</label>
{% if company and company.logo_path %}<img src="/static/{{ company.logo_path }}" style="height:44px;margin-bottom:6px;display:block;background:white;padding:3px;border-radius:5px;">{% endif %}
<input type="file" name="logo" accept="image/*" style="padding:7px;">
</div>
</div>
<div class="divider"></div>
<p class="inv-section-title">📋 Formato de Numeración Automática</p>
<div style="background:rgba(201,168,76,0.06);border:1px solid rgba(201,168,76,0.15);border-radius:10px;padding:12px 16px;font-size:12px;color:var(--gray);margin-bottom:16px;">
El número se genera como: <strong style="color:var(--gold)">PREFIJO-001-MMAAAA</strong> &nbsp;·&nbsp;
Ej: <code>IPY</code><strong style="color:var(--gold)">IPY-001-032026</strong> &nbsp;·&nbsp; <code>QPY</code><strong style="color:var(--gold)">QPY-001-032026</strong><br>
<span style="margin-top:4px;display:block;">El contador reinicia automáticamente cada mes. El usuario puede ajustar el número en el documento pero el contador interno no se altera.</span>
</div>
<div class="grid-2">
<div class="form-group">
<label>Prefijo de Invoice (solo letras)</label>
<input type="text" name="invoice_prefix" value="{{ company.invoice_prefix if company else 'INV' }}" placeholder="Ej: IPY" maxlength="8" style="text-transform:uppercase;" oninput="this.value=this.value.toUpperCase();updatePreview()">
<small style="color:var(--gray);font-size:11px;margin-top:4px;display:block;">Preview: <span id="inv-preview" style="color:var(--gold);font-weight:700;"></span></small>
</div>
<div class="form-group">
<label>Prefijo de Cotización (solo letras)</label>
<input type="text" name="quote_prefix" value="{{ company.quote_prefix if company else 'QUO' }}" placeholder="Ej: QPY" maxlength="8" style="text-transform:uppercase;" oninput="this.value=this.value.toUpperCase();updatePreview()">
<small style="color:var(--gray);font-size:11px;margin-top:4px;display:block;">Preview: <span id="quo-preview" style="color:var(--gold);font-weight:700;"></span></small>
</div>
</div>
<div class="divider"></div>
<p class="inv-section-title">📧 Servidor SMTP para envío de PDFs</p>
<div style="background:rgba(201,168,76,0.06);border:1px solid rgba(201,168,76,0.15);border-radius:10px;padding:12px 16px;font-size:12px;color:var(--gray);margin-bottom:14px;">
⚙️ Aquí solo se configura el <strong style="color:var(--gold)">servidor</strong> — es el mismo para todos.<br>
El email y contraseña de cada persona se configura en <strong style="color:var(--gold)">Usuarios</strong>.<br>
<span style="margin-top:4px;display:block;">Namecheap Private Email: <code>mail.privateemail.com</code> puerto <code>587</code></span>
</div>
<div class="grid-2">
<div class="form-group"><label>Servidor SMTP</label><input type="text" name="smtp_host" value="{{ company.smtp_host if company else '' }}" placeholder="mail.privateemail.com"></div>
<div class="form-group"><label>Puerto</label><input type="number" name="smtp_port" value="{{ company.smtp_port if company else '587' }}"></div>
</div>
<div class="divider"></div>
<p class="inv-section-title">💳 Stripe — Pagos con Tarjeta</p>
<div style="background:rgba(99,102,241,0.06);border:1px solid rgba(99,102,241,0.2);border-radius:10px;padding:12px 16px;font-size:12px;color:var(--gray);margin-bottom:14px;">
Cada compañía tiene sus propias claves. Obtén las claves en
<a href="https://dashboard.stripe.com/apikeys" target="_blank" style="color:#818cf8;">dashboard.stripe.com → Developers → API Keys</a>.<br>
<span style="margin-top:4px;display:block;">La Secret Key no se muestra después de guardada — déjala vacía si no quieres cambiarla.</span>
</div>
<div class="grid-2">
<div class="form-group">
<label>Publishable Key <span style="font-size:10px;color:var(--gray);">(pk_live_... o pk_test_...)</span></label>
<input type="text" name="stripe_publishable_key"
value="{{ company.stripe_publishable_key if company else '' }}"
placeholder="pk_live_...">
</div>
<div class="form-group">
<label>Secret Key <span style="font-size:10px;color:var(--gray);">(sk_live_... o sk_test_...)</span></label>
<input type="password" name="stripe_secret_key"
placeholder="{{ '••••••• (ya configurada — dejar vacío para no cambiar)' if company and company.stripe_secret_key else 'sk_live_...' }}">
</div>
</div>
<div class="divider"></div>
<div class="form-group">
<label>Notas para Invoices</label>
<textarea name="invoice_notes" rows="6" placeholder="Payment terms, methods of payment...">{{ company.invoice_notes if company else '' }}</textarea>
</div>
<div class="form-group">
<label>Notas para Cotizaciones</label>
<textarea name="quote_notes" rows="6" placeholder="Quotation validity, payment terms...">{{ company.quote_notes if company else '' }}</textarea>
</div>
<div class="flex gap-2 justify-between mt-3">
<a href="/companies" class="btn btn-secondary">Cancelar</a>
<button type="submit" class="btn btn-primary">💾 Guardar Compañía</button>
</div>
</form>
</div>
<style>
.inv-section-title { font-size:11px;text-transform:uppercase;letter-spacing:1px;color:var(--gray);margin-bottom:14px;padding-bottom:6px;border-bottom:1px solid rgba(255,255,255,0.08);font-weight:600; }
code { background:rgba(201,168,76,0.12);padding:2px 6px;border-radius:4px;font-size:11px; }
</style>
<script>
function updatePreview() {
const now = new Date();
const monthStr = String(now.getMonth()+1).padStart(2,'0')+String(now.getFullYear());
const ip = document.querySelector('[name="invoice_prefix"]').value||'INV';
const qp = document.querySelector('[name="quote_prefix"]').value||'QUO';
document.getElementById('inv-preview').textContent = ip+'-001-'+monthStr;
document.getElementById('quo-preview').textContent = qp+'-001-'+monthStr;
}
updatePreview();
</script>
{% endblock %}