2025-08-12 13:33:25 +03:00

484 lines
25 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 Information -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-user me-2"></i>Patient Information
</h5>
</div>
<div class="card-body">
<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.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>
</div>
</div>
<!-- Bill Details -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-file-invoice me-2"></i>Bill Details
</h5>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-md-4">
<div class="form-floating">
{{ form.bill_number }}
<label for="{{ form.bill_number.id_for_label }}">Bill Number *</label>
{% if form.bill_number.errors %}
<div class="invalid-feedback d-block">
{{ form.bill_number.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 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 class="col-md-6">
<div class="form-floating">
{{ form.status }}
<label for="{{ form.status.id_for_label }}">Status *</label>
{% if form.status.errors %}
<div class="invalid-feedback d-block">
{{ form.status.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 class="col-12">
<div class="form-floating">
{{ form.notes }}
<label for="{{ form.notes.id_for_label }}">Notes</label>
{% if form.notes.errors %}
<div class="invalid-feedback d-block">
{{ form.notes.errors.0 }}
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<!-- Line Items -->
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">
<i class="fas fa-list me-2"></i>Line Items
</h5>
<button type="button" class="btn btn-sm btn-primary" onclick="addLineItem()">
<i class="fas fa-plus me-1"></i>Add Item
</button>
</div>
<div class="card-body">
<div id="line-items-container">
<!-- Line items will be dynamically added here -->
{% if 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="card">
<div class="card-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>
</div>
<!-- Sidebar -->
<div class="col-lg-4">
<!-- Bill Summary -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-calculator me-2"></i>Bill Summary
</h5>
</div>
<div class="card-body">
<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>
</div>
</div>
<!-- Help Panel -->
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-question-circle me-2"></i>Help & Guidelines
</h5>
</div>
<div class="card-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 Status
</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>
</div>
</div>
</div>
</div>
</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 = {{ object.billlineitem_set.count|default:0 }};
function addLineItem() {
const template = document.getElementById('line-item-template');
const container = document.getElementById('line-items-container');
// Remove empty state if present
const emptyState = container.querySelector('.text-center.text-muted');
if (emptyState) {
emptyState.remove();
}
// Clone template
const clone = template.content.cloneNode(true);
// Update field names with counter
clone.querySelectorAll('input').forEach(input => {
input.name = input.name.replace('NEW', lineItemCounter);
});
container.appendChild(clone);
lineItemCounter++;
// Recalculate totals
calculateTotals();
}
function removeLineItem(button) {
const container = document.getElementById('line-items-container');
const lineItem = button.closest('.line-item-row');
lineItem.remove();
// Show empty state if no items left
if (container.children.length === 0) {
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>
`;
}
// Recalculate totals
calculateTotals();
}
function calculateTotals() {
let subtotal = 0;
document.querySelectorAll('.line-item-row').forEach(row => {
const quantity = parseFloat(row.querySelector('.quantity-input').value) || 0;
const unitPrice = parseFloat(row.querySelector('.unit-price-input').value) || 0;
subtotal += quantity * unitPrice;
});
const tax = subtotal * 0.0; // Adjust tax rate as needed
const discount = 0; // Add discount logic if needed
const total = subtotal + tax - discount;
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)}`;
}
// Auto-calculate totals when quantities or prices change
document.addEventListener('input', function(e) {
if (e.target.classList.contains('quantity-input') || e.target.classList.contains('unit-price-input')) {
calculateTotals();
}
});
// Initialize totals on page load
document.addEventListener('DOMContentLoaded', function() {
calculateTotals();
});
// Form validation
document.getElementById('billForm').addEventListener('submit', function(e) {
const lineItems = document.querySelectorAll('.line-item-row');
if (lineItems.length === 0) {
e.preventDefault();
alert('Please add at least one line item to the bill.');
return false;
}
// Validate line items
let hasErrors = false;
lineItems.forEach(row => {
const serviceCode = row.querySelector('input[name*="service_code"]').value.trim();
const description = row.querySelector('input[name*="description"]').value.trim();
const quantity = row.querySelector('.quantity-input').value;
const unitPrice = row.querySelector('.unit-price-input').value;
if (!serviceCode || !description || !quantity || !unitPrice) {
hasErrors = true;
}
});
if (hasErrors) {
e.preventDefault();
alert('Please fill in all required fields for each line item.');
return false;
}
});
</script>
{% endblock %}