Files
arrr-erp/app/modules/billing/templates/billing/settings.html
T
2026-06-20 15:01:44 +05:30

245 lines
17 KiB
HTML

{% extends "ui/templates/base/layout.html" %}
{% block content %}
<div class="space-y-6">
<div class="flex flex-col gap-3 md:flex-row md:items-start md:justify-between">
<div>
<p class="text-xs font-semibold uppercase tracking-[0.18em] text-brand-600">Phase 7R.1</p>
<h1 class="text-2xl font-bold text-slate-900">Firm Billing Settings</h1>
<p class="mt-1 text-sm text-slate-500">Configure firm GST, invoice numbering, payment details and invoice footer defaults.</p>
</div>
<div class="rounded-2xl border border-slate-200 bg-white px-4 py-3 text-sm shadow-sm">
<div class="font-semibold text-slate-900">{{ tenant_name }}</div>
<div class="text-xs text-slate-500">{% if branch_name %}Branch: {{ branch_name }}{% else %}Firm-wide default{% endif %}</div>
<div class="mt-2 text-xs text-slate-500">Next invoice preview</div>
<div class="font-mono text-sm font-semibold text-brand-700">{{ preview_invoice_no }}</div>
</div>
</div>
<div class="grid gap-6 lg:grid-cols-[minmax(0,1fr)_320px]">
<form method="post" action="/billing/settings" class="space-y-6">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
<section class="af-card p-5">
<div class="mb-4 flex items-center justify-between gap-3">
<div>
<h2 class="text-lg font-semibold text-slate-900">Scope</h2>
<p class="text-sm text-slate-500">Keep branch-specific settings for branch-wise invoice series, or use firm-wide default if you are working across branches.</p>
</div>
</div>
<div class="grid gap-4 md:grid-cols-2">
<label class="rounded-2xl border border-slate-200 p-4 text-sm">
<input type="radio" name="branch_scope" value="active" class="mr-2" {% if branch_scope != 'firm' %}checked{% endif %} />
Active branch settings
<div class="mt-1 text-xs text-slate-500">Recommended for branch-wise invoice numbering.</div>
</label>
<label class="rounded-2xl border border-slate-200 p-4 text-sm">
<input type="radio" name="branch_scope" value="firm" class="mr-2" {% if branch_scope == 'firm' %}checked{% endif %} />
Firm-wide default
<div class="mt-1 text-xs text-slate-500">Available when cross-branch billing permission is active.</div>
</label>
</div>
</section>
<section class="af-card p-5">
<h2 class="text-lg font-semibold text-slate-900">Firm GST & Contact Details</h2>
<div class="mt-4 grid gap-4 md:grid-cols-2">
<label class="text-sm font-medium text-slate-700">Legal / Billing Name
<input name="legal_name" value="{{ settings.legal_name or '' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700">GSTIN
<input name="gstin" value="{{ settings.gstin or '' }}" maxlength="15" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm uppercase" />
</label>
<label class="text-sm font-medium text-slate-700">PAN
<input name="pan" value="{{ settings.pan or '' }}" maxlength="10" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm uppercase" />
</label>
<label class="text-sm font-medium text-slate-700">State Code
<input name="state_code" value="{{ settings.state_code or '' }}" maxlength="2" placeholder="33" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700">Contact Email
<input name="contact_email" value="{{ settings.contact_email or '' }}" type="email" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700">Contact Mobile
<input name="contact_mobile" value="{{ settings.contact_mobile or '' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700 md:col-span-2">Website
<input name="website_url" value="{{ settings.website_url or '' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700 md:col-span-2">Billing Address
<textarea name="billing_address" rows="3" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">{{ settings.billing_address or '' }}</textarea>
</label>
</div>
</section>
<section class="af-card p-5">
<h2 class="text-lg font-semibold text-slate-900">Invoice Numbering & Tax Defaults</h2>
<div class="mt-4 grid gap-4 md:grid-cols-3">
<label class="text-sm font-medium text-slate-700">Invoice Title
<input name="invoice_title" value="{{ settings.invoice_title or 'Tax Invoice' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700">Prefix
<input name="invoice_prefix" value="{{ settings.invoice_prefix or 'INV' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm uppercase" />
</label>
<label class="text-sm font-medium text-slate-700">Next Number
<input name="next_invoice_no" value="{{ settings.next_invoice_no or 1 }}" type="number" min="1" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700">Padding
<input name="padding" value="{{ settings.padding or 4 }}" type="number" min="1" max="10" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700 md:col-span-2">Number Format
<input name="invoice_number_format" value="{{ settings.invoice_number_format or '{prefix}/{fy}/{number}' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 font-mono text-sm" />
<span class="mt-1 block text-xs text-slate-500">Tokens: {prefix}, {fy}, {number}, {branch_id}</span>
</label>
<label class="text-sm font-medium text-slate-700">Default Due Days
<input name="default_due_days" value="{{ settings.default_due_days or 15 }}" type="number" min="0" max="365" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700">Default GST Rate %
<input name="default_gst_rate" value="{{ settings.default_gst_rate or '18.00' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700">Default Tax Type
<select name="default_tax_type" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
{% for tax in tax_types %}<option value="{{ tax }}" {% if settings.default_tax_type == tax %}selected{% endif %}>{{ tax }}</option>{% endfor %}
</select>
</label>
<label class="text-sm font-medium text-slate-700">Default SAC Code
<input name="default_sac_code" value="{{ settings.default_sac_code or '' }}" placeholder="9982" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
</div>
</section>
<section class="af-card p-5">
<h2 class="text-lg font-semibold text-slate-900">Bank, UPI & Payment Details</h2>
<div class="mt-4 grid gap-4 md:grid-cols-2">
<label class="text-sm font-medium text-slate-700">Bank Name
<input name="bank_name" value="{{ settings.bank_name or '' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700">Account Name
<input name="bank_account_name" value="{{ settings.bank_account_name or '' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700">Account Number
<input name="bank_account_number" value="{{ settings.bank_account_number or '' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700">IFSC
<input name="bank_ifsc" value="{{ settings.bank_ifsc or '' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm uppercase" />
</label>
<label class="text-sm font-medium text-slate-700 md:col-span-2">UPI ID
<input name="upi_id" value="{{ settings.upi_id or '' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700 md:col-span-2">Additional Bank Details / Payment Instructions
<textarea name="bank_details" rows="3" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">{{ settings.bank_details or '' }}</textarea>
</label>
</div>
</section>
<section class="af-card p-5">
<h2 class="text-lg font-semibold text-slate-900">PayUMoney / PayU Online Payment Gateway</h2>
<p class="mt-1 text-sm text-slate-500">Enable this only after entering valid PayU/PayUMoney merchant credentials. Test mode posts to PayU test checkout.</p>
<div class="mt-4 grid gap-4 md:grid-cols-2">
<label class="flex items-center gap-3 rounded-2xl border border-slate-200 p-4 text-sm font-medium text-slate-700 md:col-span-2">
<input type="checkbox" name="payumoney_enabled" value="1" {% if settings.payumoney_enabled %}checked{% endif %} />
Enable PayUMoney / PayU Pay Now for client portal
</label>
<label class="text-sm font-medium text-slate-700">Mode
<select name="payumoney_mode" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
<option value="TEST" {% if settings.payumoney_mode != 'LIVE' %}selected{% endif %}>TEST / Sandbox</option>
<option value="LIVE" {% if settings.payumoney_mode == 'LIVE' %}selected{% endif %}>LIVE / Production</option>
</select>
</label>
<label class="text-sm font-medium text-slate-700">Merchant ID, optional
<input name="payumoney_merchant_id" value="{{ settings.payumoney_merchant_id or '' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700">Merchant Key
<input name="payumoney_merchant_key" value="{{ settings.payumoney_merchant_key or '' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" autocomplete="off" />
</label>
<label class="text-sm font-medium text-slate-700">Merchant Salt
<input name="payumoney_merchant_salt" value="{{ settings.payumoney_merchant_salt or '' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" autocomplete="off" />
</label>
<label class="text-sm font-medium text-slate-700 md:col-span-2">Product Info Label
<input name="payumoney_product_info" value="{{ settings.payumoney_product_info or 'Professional Services Invoice' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
</div>
<div class="mt-4 rounded-2xl border border-amber-200 bg-amber-50 p-4 text-xs leading-5 text-amber-900">
Store separate test and live credentials carefully. Do not enable LIVE until callback testing is completed from an accessible public URL.
</div>
</section>
<section class="af-card p-5">
<h2 class="text-lg font-semibold text-slate-900">Cashfree Online Payment Gateway</h2>
<p class="mt-1 text-sm text-slate-500">Enable Cashfree only after adding valid Cashfree PG credentials. Sandbox mode uses Cashfree sandbox APIs.</p>
<div class="mt-4 grid gap-4 md:grid-cols-2">
<label class="flex items-center gap-3 rounded-2xl border border-slate-200 p-4 text-sm font-medium text-slate-700 md:col-span-2">
<input type="checkbox" name="cashfree_enabled" value="1" {% if settings.cashfree_enabled %}checked{% endif %} />
Enable Cashfree Pay Now for client portal
</label>
<label class="text-sm font-medium text-slate-700">Mode
<select name="cashfree_mode" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
<option value="TEST" {% if settings.cashfree_mode != 'LIVE' %}selected{% endif %}>TEST / Sandbox</option>
<option value="LIVE" {% if settings.cashfree_mode == 'LIVE' %}selected{% endif %}>LIVE / Production</option>
</select>
</label>
<label class="text-sm font-medium text-slate-700">API Version
<input name="cashfree_api_version" value="{{ settings.cashfree_api_version or '2023-08-01' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
<label class="text-sm font-medium text-slate-700">Client ID / App ID
<input name="cashfree_client_id" value="{{ settings.cashfree_client_id or '' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" autocomplete="off" />
</label>
<label class="text-sm font-medium text-slate-700">Client Secret
<input name="cashfree_client_secret" value="{{ settings.cashfree_client_secret or '' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" autocomplete="off" />
</label>
<label class="text-sm font-medium text-slate-700 md:col-span-2">Order Note
<input name="cashfree_order_note" value="{{ settings.cashfree_order_note or 'Professional Services Invoice' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
</div>
<div class="mt-4 rounded-2xl border border-sky-200 bg-sky-50 p-4 text-xs leading-5 text-sky-900">
Cashfree checkout creates an order from the server and uses payment_session_id for hosted checkout. Webhook URL: <span class="font-mono">/client/billing/cashfree/webhook</span>
</div>
</section>
<section class="af-card p-5">
<h2 class="text-lg font-semibold text-slate-900">Invoice Notes, Terms & Signatory</h2>
<div class="mt-4 grid gap-4">
<label class="text-sm font-medium text-slate-700">Default Terms
<textarea name="terms" rows="3" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">{{ settings.terms or '' }}</textarea>
</label>
<label class="text-sm font-medium text-slate-700">Declaration
<textarea name="declaration" rows="3" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">{{ settings.declaration or '' }}</textarea>
</label>
<label class="text-sm font-medium text-slate-700">Invoice Footer Note
<textarea name="footer_note" rows="2" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">{{ settings.footer_note or '' }}</textarea>
</label>
<label class="text-sm font-medium text-slate-700">Authorised Signatory Name
<input name="authorised_signatory_name" value="{{ settings.authorised_signatory_name or '' }}" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" />
</label>
</div>
</section>
<div class="flex items-center justify-end gap-3">
<a href="/billing" class="af-btn af-btn-secondary">Back to Invoices</a>
{% if can_edit_settings %}
<button type="submit" class="af-btn af-btn-primary">Save Billing Settings</button>
{% else %}
<span class="text-sm text-slate-500">View-only access</span>
{% endif %}
</div>
</form>
<aside class="space-y-4">
<div class="af-card p-5">
<h3 class="font-semibold text-slate-900">Why this matters</h3>
<ul class="mt-3 space-y-2 text-sm text-slate-600">
<li>• GST invoice format will use these details in Phase 7R.2.</li>
<li>• Payment and receipt tracking will use bank/UPI details in Phase 7R.4.</li>
<li>• Client portal Pay Now uses UPI, PayUMoney and Cashfree settings from Phase 7R.5 / 7R.6 / 7R.6A.</li>
</ul>
</div>
<div class="af-card p-5">
<h3 class="font-semibold text-slate-900">Recommended invoice format</h3>
<p class="mt-2 rounded-xl bg-slate-50 px-3 py-2 font-mono text-sm text-slate-700">{prefix}/{fy}/{number}</p>
<p class="mt-2 text-xs text-slate-500">Example: INV/2026-27/0001</p>
</div>
</aside>
</div>
</div>
{% endblock %}