Marwan Alwali 23158e9fbf update
2025-09-08 03:00:23 +03:00

545 lines
24 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}{% if object %}Edit Bill{% else %}Create Bill{% endif %} - {{ block.super }}{% endblock %}
{% block content %}
<div class="container-fluid">
<!-- Page Header -->
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h1 class="h3 mb-1">{% if object %}Edit Medical Bill{% else %}Create Medical Bill{% endif %}</h1>
<nav aria-label="breadcrumb">
<ol class="breadcrumb mb-0">
<li class="breadcrumb-item"><a href="{% url 'billing:dashboard' %}">Billing</a></li>
<li class="breadcrumb-item"><a href="{% url 'billing:bill_list' %}">Medical Bills</a></li>
<li class="breadcrumb-item active">{% if object %}Edit{% else %}Create{% endif %}</li>
</ol>
</nav>
</div>
<div class="btn-group">
<a href="{% url 'billing:bill_list' %}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-2"></i>Back to List
</a>
{% if object %}
<a href="{% url 'billing:bill_detail' object.bill_id %}" class="btn btn-outline-primary">
<i class="fas fa-eye me-2"></i>View Details
</a>
{% endif %}
</div>
</div>
<form method="post"
id="billForm"
hx-post="{% if object %}{% url 'billing:bill_update' object.bill_id %}{% else %}{% url 'billing:bill_create' %}{% endif %}"
hx-target="#form-container">
{% csrf_token %}
<div class="row">
<!-- Main Form -->
<div class="col-lg-8">
<div id="form-container">
<!-- Patient & Context -->
<div class="panel panel-inverse mb-4">
<div class="panel-heading">
<h4 class="panel-title"><i class="fas fa-user me-2"></i>Patient & Context</h4>
<div class="panel-heading-btn">
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
{% if object %}
<div class="alert alert-secondary small d-flex justify-content-between align-items-center">
<div>
<strong>Bill #</strong> <code>{{ object.bill_number }}</code>
</div>
<div><strong>Created:</strong> {{ object.created_at|date:"M d, Y H:i" }}</div>
</div>
{% endif %}
<div class="row g-3">
<div class="col-md-6">
<div class="form-floating">
{{ form.patient }}
<label for="{{ form.patient.id_for_label }}">Patient *</label>
{% if form.patient.errors %}<div class="invalid-feedback d-block">{{ form.patient.errors.0 }}</div>{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-floating">
{{ form.bill_type }}
<label for="{{ form.bill_type.id_for_label }}">Bill Type *</label>
{% if form.bill_type.errors %}<div class="invalid-feedback d-block">{{ form.bill_type.errors.0 }}</div>{% endif %}
</div>
</div>
</div>
<div class="row g-3 mt-1">
<div class="col-md-6">
<div class="form-floating">
{{ form.encounter }}
<label for="{{ form.encounter.id_for_label }}">Related Encounter</label>
{% if form.encounter.errors %}<div class="invalid-feedback d-block">{{ form.encounter.errors.0 }}</div>{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-floating">
{{ form.admission }}
<label for="{{ form.admission.id_for_label }}">Admission</label>
{% if form.admission.errors %}<div class="invalid-feedback d-block">{{ form.admission.errors.0 }}</div>{% endif %}
</div>
</div>
</div>
<div class="row g-3 mt-1">
<div class="col-md-6">
<div class="form-floating">
{{ form.payment_terms }}
<label for="{{ form.payment_terms.id_for_label }}">Payment Terms</label>
{% if form.payment_terms.errors %}<div class="invalid-feedback d-block">{{ form.payment_terms.errors.0 }}</div>{% endif %}
</div>
</div>
</div>
</div>
</div>
<!-- Service & Dates -->
<div class="panel panel-inverse mb-4">
<div class="panel-heading">
<h4 class="panel-title"><i class="fas fa-calendar-alt me-2"></i>Service & Dates</h4>
<div class="panel-heading-btn">
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
<div class="row g-3">
<div class="col-md-4">
<div class="form-floating">
{{ form.service_date_from }}
<label for="{{ form.service_date_from.id_for_label }}">Service From *</label>
{% if form.service_date_from.errors %}<div class="invalid-feedback d-block">{{ form.service_date_from.errors.0 }}</div>{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating">
{{ form.service_date_to }}
<label for="{{ form.service_date_to.id_for_label }}">Service To *</label>
{% if form.service_date_to.errors %}<div class="invalid-feedback d-block">{{ form.service_date_to.errors.0 }}</div>{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating">
{{ form.bill_date }}
<label for="{{ form.bill_date.id_for_label }}">Bill Date *</label>
{% if form.bill_date.errors %}<div class="invalid-feedback d-block">{{ form.bill_date.errors.0 }}</div>{% endif %}
</div>
</div>
</div>
<div class="row g-3 mt-1">
<div class="col-md-4">
<div class="form-floating">
{{ form.due_date }}
<label for="{{ form.due_date.id_for_label }}">Due Date</label>
{% if form.due_date.errors %}<div class="invalid-feedback d-block">{{ form.due_date.errors.0 }}</div>{% endif %}
</div>
</div>
</div>
</div>
</div>
<!-- Providers & Insurance -->
<div class="panel panel-inverse mb-4">
<div class="panel-heading">
<h4 class="panel-title"><i class="fas fa-user-md me-2"></i>Providers & Insurance</h4>
<div class="panel-heading-btn">
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
<div class="row g-3">
<div class="col-md-6">
<div class="form-floating">
{{ form.attending_provider }}
<label for="{{ form.attending_provider.id_for_label }}">Attending Provider</label>
{% if form.attending_provider.errors %}<div class="invalid-feedback d-block">{{ form.attending_provider.errors.0 }}</div>{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-floating">
{{ form.billing_provider }}
<label for="{{ form.billing_provider.id_for_label }}">Billing Provider</label>
{% if form.billing_provider.errors %}<div class="invalid-feedback d-block">{{ form.billing_provider.errors.0 }}</div>{% endif %}
</div>
</div>
</div>
<div class="row g-3 mt-1">
<div class="col-md-6">
<div class="form-floating">
{{ form.primary_insurance }}
<label for="{{ form.primary_insurance.id_for_label }}">Primary Insurance</label>
{% if form.primary_insurance.errors %}<div class="invalid-feedback d-block">{{ form.primary_insurance.errors.0 }}</div>{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-floating">
{{ form.secondary_insurance }}
<label for="{{ form.secondary_insurance.id_for_label }}">Secondary Insurance</label>
{% if form.secondary_insurance.errors %}<div class="invalid-feedback d-block">{{ form.secondary_insurance.errors.0 }}</div>{% endif %}
</div>
</div>
</div>
</div>
</div>
<!-- Notes -->
<div class="panel panel-inverse mb-4">
<div class="panel-heading">
<h4 class="panel-title"><i class="fas fa-sticky-note me-2"></i>Notes</h4>
<div class="panel-heading-btn">
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
<div class="mb-0">
{{ form.notes }}
{% if form.notes.errors %}<div class="invalid-feedback d-block">{{ form.notes.errors.0 }}</div>{% endif %}
</div>
</div>
</div>
<!-- Line Items -->
<div class="panel panel-inverse mb-4">
<div class="panel-heading d-flex justify-content-between align-items-center">
<h4 class="panel-title"><i class="fas fa-list me-2"></i>Line Items</h4>
<div class="panel-heading-btn d-flex align-items-center gap-2">
<button type="button" class="btn btn-xs btn-primary" onclick="addLineItem()">
<i class="fas fa-plus me-1"></i>Add Item
</button>
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
<div id="line-items-container">
{% if object and object.billlineitem_set.all %}
{% for line_item in object.billlineitem_set.all %}
<div class="line-item-row border rounded p-3 mb-3">
<div class="row g-3">
<div class="col-md-3">
<div class="form-floating">
<input type="text" class="form-control" name="service_code_{{ forloop.counter0 }}" value="{{ line_item.service_code }}" placeholder="Service Code">
<label>Service Code</label>
</div>
</div>
<div class="col-md-4">
<div class="form-floating">
<input type="text" class="form-control" name="description_{{ forloop.counter0 }}" value="{{ line_item.description }}" placeholder="Description">
<label>Description</label>
</div>
</div>
<div class="col-md-2">
<div class="form-floating">
<input type="number" class="form-control quantity-input" name="quantity_{{ forloop.counter0 }}" value="{{ line_item.quantity }}" min="1" step="1" placeholder="Qty">
<label>Quantity</label>
</div>
</div>
<div class="col-md-2">
<div class="form-floating">
<input type="number" class="form-control unit-price-input" name="unit_price_{{ forloop.counter0 }}" value="{{ line_item.unit_price }}" min="0" step="0.01" placeholder="Unit Price">
<label>Unit Price</label>
</div>
</div>
<div class="col-md-1">
<button type="button" class="btn btn-outline-danger h-100 w-100" onclick="removeLineItem(this)">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
</div>
{% endfor %}
{% else %}
<div class="text-center text-muted py-4">
<i class="fas fa-list fa-2x mb-3 opacity-50"></i>
<p>No line items added yet. Click "Add Item" to get started.</p>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Form Actions -->
<div class="panel panel-inverse">
<div class="panel-body">
<div class="d-flex justify-content-between">
<div>
<a href="{% url 'billing:bill_list' %}" class="btn btn-outline-secondary">
<i class="fas fa-times me-2"></i>Cancel
</a>
</div>
<div class="btn-group">
<button type="submit" name="action" value="save_draft" class="btn btn-outline-primary">
<i class="fas fa-save me-2"></i>Save as Draft
</button>
<button type="submit" name="action" value="save_and_continue" class="btn btn-primary">
<i class="fas fa-check me-2"></i>{% if object %}Update{% else %}Create{% endif %} Bill
</button>
{% if not object %}
<button type="submit" name="action" value="save_and_submit" class="btn btn-success">
<i class="fas fa-paper-plane me-2"></i>Create & Submit
</button>
{% endif %}
</div>
</div>
</div>
</div>
</div> <!-- /#form-container -->
</div>
<!-- Sidebar -->
<div class="col-lg-4">
<!-- Bill Summary -->
<div class="panel panel-inverse mb-4">
<div class="panel-heading">
<h4 class="panel-title"><i class="fas fa-calculator me-2"></i>Bill Summary</h4>
<div class="panel-heading-btn">
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
<!-- Readout -->
<div class="d-flex justify-content-between mb-2">
<span>Subtotal:</span> <span id="subtotal-amount">$0.00</span>
</div>
<div class="d-flex justify-content-between mb-2">
<span>Tax:</span> <span id="tax-amount">$0.00</span>
</div>
<div class="d-flex justify-content-between mb-2">
<span>Discount:</span> <span id="discount-amount">$0.00</span>
</div>
<hr>
<div class="d-flex justify-content-between fw-bold">
<span>Total:</span> <span id="total-amount">$0.00</span>
</div>
<!-- Hidden bound fields so totals post to the form -->
<div class="d-none">
{{ form.subtotal }}
{{ form.tax_amount }}
{{ form.discount_amount }}
{{ form.adjustment_amount }}
</div>
</div>
</div>
<!-- Help Panel -->
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title"><i class="fas fa-question-circle me-2"></i>Help & Guidelines</h4>
<div class="panel-heading-btn">
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
<div class="accordion accordion-flush" id="helpAccordion">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#help-patient">
Patient Selection
</button>
</h2>
<div id="help-patient" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
<div class="accordion-body">
<ul class="list-unstyled mb-0">
<li><i class="fas fa-check text-success me-2"></i>Select the patient for this bill</li>
<li><i class="fas fa-check text-success me-2"></i>Link to a specific encounter if applicable</li>
<li><i class="fas fa-check text-success me-2"></i>Verify patient insurance information</li>
</ul>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#help-codes">
Service Codes
</button>
</h2>
<div id="help-codes" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
<div class="accordion-body">
<ul class="list-unstyled mb-0">
<li><i class="fas fa-info text-info me-2"></i>Use standard CPT/HCPCS codes</li>
<li><i class="fas fa-info text-info me-2"></i>Include modifier codes when applicable</li>
<li><i class="fas fa-info text-info me-2"></i>Verify codes with current fee schedule</li>
</ul>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#help-status">
Bill Lifecycle
</button>
</h2>
<div id="help-status" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
<div class="accordion-body">
<ul class="list-unstyled mb-0">
<li><strong>Draft:</strong> Bill is being prepared</li>
<li><strong>Pending:</strong> Ready for review</li>
<li><strong>Submitted:</strong> Sent to patient/insurance</li>
<li><strong>Paid:</strong> Payment received in full</li>
</ul>
</div>
</div>
</div>
</div> <!-- /accordion -->
</div>
</div>
</div>
</div> <!-- /.row -->
</form>
</div>
<!-- Line Item Template -->
<template id="line-item-template">
<div class="line-item-row border rounded p-3 mb-3">
<div class="row g-3">
<div class="col-md-3">
<div class="form-floating">
<input type="text" class="form-control" name="service_code_NEW" placeholder="Service Code">
<label>Service Code</label>
</div>
</div>
<div class="col-md-4">
<div class="form-floating">
<input type="text" class="form-control" name="description_NEW" placeholder="Description">
<label>Description</label>
</div>
</div>
<div class="col-md-2">
<div class="form-floating">
<input type="number" class="form-control quantity-input" name="quantity_NEW" value="1" min="1" step="1" placeholder="Qty">
<label>Quantity</label>
</div>
</div>
<div class="col-md-2">
<div class="form-floating">
<input type="number" class="form-control unit-price-input" name="unit_price_NEW" value="0.00" min="0" step="0.01" placeholder="Unit Price">
<label>Unit Price</label>
</div>
</div>
<div class="col-md-1">
<button type="button" class="btn btn-outline-danger h-100 w-100" onclick="removeLineItem(this)">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
</div>
</template>
<script>
let lineItemCounter = {% if object %}{{ object.billlineitem_set.count|default:0 }}{% else %}0{% endif %};
function addLineItem() {
const template = document.getElementById('line-item-template');
const container = document.getElementById('line-items-container');
const emptyState = container.querySelector('.text-center.text-muted');
if (emptyState) emptyState.remove();
const clone = template.content.cloneNode(true);
clone.querySelectorAll('input').forEach(input => {
input.name = input.name.replace('NEW', lineItemCounter);
});
container.appendChild(clone);
lineItemCounter++;
calculateTotals();
}
function removeLineItem(button) {
const container = document.getElementById('line-items-container');
const row = button.closest('.line-item-row');
if (row) row.remove();
if (!container.querySelector('.line-item-row')) {
container.innerHTML = `
<div class="text-center text-muted py-4">
<i class="fas fa-list fa-2x mb-3 opacity-50"></i>
<p>No line items added yet. Click "Add Item" to get started.</p>
</div>`;
}
calculateTotals();
}
function calculateTotals() {
let subtotal = 0;
document.querySelectorAll('.line-item-row').forEach(row => {
const q = parseFloat(row.querySelector('.quantity-input')?.value) || 0;
const p = parseFloat(row.querySelector('.unit-price-input')?.value) || 0;
subtotal += q * p;
});
// Adjust rates/logic as needed
const tax = subtotal * 0.00;
const discount = 0.00;
const total = subtotal + tax - discount;
// Visual readout
document.getElementById('subtotal-amount').textContent = `$${subtotal.toFixed(2)}`;
document.getElementById('tax-amount').textContent = `$${tax.toFixed(2)}`;
document.getElementById('discount-amount').textContent = `$${discount.toFixed(2)}`;
document.getElementById('total-amount').textContent = `$${total.toFixed(2)}`;
// Sync hidden bound fields
const subtotalInput = document.getElementById('id_subtotal');
const taxInput = document.getElementById('id_tax_amount');
const discountInput = document.getElementById('id_discount_amount');
const adjustInput = document.getElementById('id_adjustment_amount');
if (subtotalInput) subtotalInput.value = subtotal.toFixed(2);
if (taxInput) taxInput.value = tax.toFixed(2);
if (discountInput) discountInput.value = discount.toFixed(2);
if (adjustInput && !adjustInput.value) adjustInput.value = (0).toFixed(2);
}
document.addEventListener('input', e => {
if (e.target.classList.contains('quantity-input') || e.target.classList.contains('unit-price-input')) {
calculateTotals();
}
});
document.addEventListener('DOMContentLoaded', calculateTotals);
// Validate line items and ensure totals are synced before submit
document.getElementById('billForm').addEventListener('submit', function(e) {
const rows = document.querySelectorAll('.line-item-row');
if (!rows.length) {
e.preventDefault();
alert('Please add at least one line item to the bill.');
return false;
}
for (const row of rows) {
const code = (row.querySelector('input[name*="service_code"]')?.value || '').trim();
const desc = (row.querySelector('input[name*="description"]')?.value || '').trim();
const qty = row.querySelector('.quantity-input')?.value;
const price = row.querySelector('.unit-price-input')?.value;
if (!code || !desc || !qty || !price) {
e.preventDefault();
alert('Please fill in all required fields for each line item.');
return false;
}
}
// Make sure numbers are in the form
calculateTotals();
});
</script>
<style>
.badge { font-size: .75rem; }
.table-borderless td { padding: .5rem 0; }
.bg-gradient { background-image: linear-gradient(180deg, rgba(255,255,255,.15), rgba(255,255,255,0)); }
.line-item-row .btn-outline-danger:hover { transform: translateY(-1px); }
@media (max-width: 768px) {
.btn-group { display: flex; flex-direction: column; gap: .5rem; }
}
</style>
{% endblock %}