479 lines
24 KiB
HTML
479 lines
24 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
|
|
{% block title %}Export Bills{% endblock %}
|
|
|
|
{% block css %}
|
|
<link href="{% static 'assets/plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css' %}" rel="stylesheet" />
|
|
<link href="{% static 'assets/plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css' %}" rel="stylesheet" />
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div id="content" class="app-content">
|
|
<div class="container">
|
|
<ul class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'billing:bill_list' %}">Bills</a></li>
|
|
<li class="breadcrumb-item active">Export</li>
|
|
</ul>
|
|
|
|
<div class="row align-items-center mb-3">
|
|
<div class="col">
|
|
<h1 class="page-header">Export Bills</h1>
|
|
</div>
|
|
<div class="col-auto">
|
|
<button type="button" class="btn btn-success" onclick="startExport()" id="exportBtn">
|
|
<i class="fa fa-download me-2"></i>Start Export
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Export Configuration -->
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Export Configuration</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<form id="exportForm">
|
|
{% csrf_token %}
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Export Format</label>
|
|
<select name="format" class="form-select" required>
|
|
<option value="csv">CSV (Comma Separated)</option>
|
|
<option value="excel">Excel (.xlsx)</option>
|
|
<option value="pdf">PDF Report</option>
|
|
<option value="json">JSON Data</option>
|
|
<option value="xml">XML Format</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Date Range</label>
|
|
<div class="row">
|
|
<div class="col-6">
|
|
<input type="date" name="start_date" class="form-control" required>
|
|
<small class="form-text text-muted">From</small>
|
|
</div>
|
|
<div class="col-6">
|
|
<input type="date" name="end_date" class="form-control" required>
|
|
<small class="form-text text-muted">To</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Bill Status</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="status" value="draft" id="status_draft">
|
|
<label class="form-check-label" for="status_draft">Draft</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="status" value="pending" id="status_pending" checked>
|
|
<label class="form-check-label" for="status_pending">Pending</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="status" value="submitted" id="status_submitted" checked>
|
|
<label class="form-check-label" for="status_submitted">Submitted</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="status" value="paid" id="status_paid" checked>
|
|
<label class="form-check-label" for="status_paid">Paid</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="status" value="cancelled" id="status_cancelled">
|
|
<label class="form-check-label" for="status_cancelled">Cancelled</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Insurance Plans</label>
|
|
<select name="insurance_plans" class="form-select" multiple>
|
|
<option value="">All Insurance Plans</option>
|
|
{% for plan in insurance_plans %}
|
|
<option value="{{ plan.id }}">{{ plan.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<small class="form-text text-muted">Hold Ctrl to select multiple</small>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Amount Range</label>
|
|
<div class="row">
|
|
<div class="col-6">
|
|
<div class="input-group">
|
|
<span class="input-group-text">$</span>
|
|
<input type="number" name="min_amount" class="form-control" step="0.01" min="0">
|
|
</div>
|
|
<small class="form-text text-muted">Minimum</small>
|
|
</div>
|
|
<div class="col-6">
|
|
<div class="input-group">
|
|
<span class="input-group-text">$</span>
|
|
<input type="number" name="max_amount" class="form-control" step="0.01" min="0">
|
|
</div>
|
|
<small class="form-text text-muted">Maximum</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Fields to Include</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="fields" value="basic_info" id="fields_basic" checked>
|
|
<label class="form-check-label" for="fields_basic">Basic Information</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="fields" value="patient_info" id="fields_patient" checked>
|
|
<label class="form-check-label" for="fields_patient">Patient Details</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="fields" value="line_items" id="fields_items" checked>
|
|
<label class="form-check-label" for="fields_items">Line Items</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="fields" value="payments" id="fields_payments">
|
|
<label class="form-check-label" for="fields_payments">Payment History</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="fields" value="insurance" id="fields_insurance">
|
|
<label class="form-check-label" for="fields_insurance">Insurance Claims</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="fields" value="audit_trail" id="fields_audit">
|
|
<label class="form-check-label" for="fields_audit">Audit Trail</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Export Options</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="include_totals" id="include_totals" checked>
|
|
<label class="form-check-label" for="include_totals">Include Summary Totals</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="group_by_status" id="group_by_status">
|
|
<label class="form-check-label" for="group_by_status">Group by Status</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="include_charts" id="include_charts">
|
|
<label class="form-check-label" for="include_charts">Include Charts (PDF only)</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="compress_output" id="compress_output">
|
|
<label class="form-check-label" for="compress_output">Compress Output (.zip)</label>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-8">
|
|
<!-- Preview -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Export Preview</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="previewContent">
|
|
<div class="text-center text-muted py-4">
|
|
<i class="fa fa-search fa-3x mb-3"></i>
|
|
<div>Configure export settings to see preview</div>
|
|
<button type="button" class="btn btn-outline-primary mt-2" onclick="updatePreview()">
|
|
<i class="fa fa-refresh me-2"></i>Update Preview
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Export Status -->
|
|
<div class="card" id="exportStatus" style="display: none;">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Export Progress</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<div class="d-flex justify-content-between mb-1">
|
|
<span>Processing...</span>
|
|
<span id="progressPercent">0%</span>
|
|
</div>
|
|
<div class="progress">
|
|
<div class="progress-bar" id="progressBar" role="progressbar" style="width: 0%"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="exportMessages">
|
|
<div class="text-muted">
|
|
<i class="fa fa-info-circle me-2"></i>Initializing export process...
|
|
</div>
|
|
</div>
|
|
|
|
<div id="exportComplete" style="display: none;">
|
|
<div class="alert alert-success">
|
|
<i class="fa fa-check-circle me-2"></i>
|
|
<strong>Export Complete!</strong> Your file is ready for download.
|
|
</div>
|
|
<div class="text-center">
|
|
<a href="#" id="downloadLink" class="btn btn-success btn-lg">
|
|
<i class="fa fa-download me-2"></i>Download File
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Exports -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Recent Exports</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if recent_exports %}
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>Format</th>
|
|
<th>Records</th>
|
|
<th>Size</th>
|
|
<th>Status</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for export in recent_exports %}
|
|
<tr>
|
|
<td>{{ export.created_at|date:"M d, Y g:i A" }}</td>
|
|
<td>
|
|
<span class="badge bg-info">{{ export.format|upper }}</span>
|
|
</td>
|
|
<td>{{ export.record_count|default:"—" }}</td>
|
|
<td>{{ export.file_size|default:"—" }}</td>
|
|
<td>
|
|
{% if export.status == 'completed' %}
|
|
<span class="badge bg-success">Completed</span>
|
|
{% elif export.status == 'processing' %}
|
|
<span class="badge bg-warning">Processing</span>
|
|
{% elif export.status == 'failed' %}
|
|
<span class="badge bg-danger">Failed</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if export.status == 'completed' %}
|
|
<a href="{{ export.download_url }}" class="btn btn-outline-primary btn-sm">
|
|
<i class="fa fa-download"></i>
|
|
</a>
|
|
{% endif %}
|
|
<button type="button" class="btn btn-outline-danger btn-sm" onclick="deleteExport('{{ export.id }}')">
|
|
<i class="fa fa-trash"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<div class="text-center text-muted py-3">
|
|
<i class="fa fa-history fa-2x mb-2"></i>
|
|
<div>No recent exports</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script src="{% static 'assets/plugins/datatables.net/js/jquery.dataTables.min.js' %}"></script>
|
|
<script src="{% static 'assets/plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js' %}"></script>
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Set default dates
|
|
var today = new Date();
|
|
var firstDayOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
|
|
|
|
$('input[name="start_date"]').val(firstDayOfMonth.toISOString().split('T')[0]);
|
|
$('input[name="end_date"]').val(today.toISOString().split('T')[0]);
|
|
|
|
// Update preview when form changes
|
|
$('#exportForm').on('change', 'input, select', function() {
|
|
updatePreview();
|
|
});
|
|
|
|
// Initial preview
|
|
updatePreview();
|
|
});
|
|
|
|
function updatePreview() {
|
|
var formData = new FormData($('#exportForm')[0]);
|
|
|
|
// Show loading
|
|
$('#previewContent').html(`
|
|
<div class="text-center py-3">
|
|
<div class="spinner-border text-primary" role="status">
|
|
<span class="visually-hidden">Loading...</span>
|
|
</div>
|
|
<div class="mt-2">Generating preview...</div>
|
|
</div>
|
|
`);
|
|
|
|
// Simulate preview generation
|
|
setTimeout(function() {
|
|
var previewHtml = `
|
|
<div class="row mb-3">
|
|
<div class="col-md-3">
|
|
<div class="card text-center">
|
|
<div class="card-body">
|
|
<div class="fs-20px fw-600 text-primary">1,247</div>
|
|
<div class="text-muted small">Total Records</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card text-center">
|
|
<div class="card-body">
|
|
<div class="fs-20px fw-600 text-success">$2,847,392</div>
|
|
<div class="text-muted small">Total Amount</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card text-center">
|
|
<div class="card-body">
|
|
<div class="fs-20px fw-600 text-info">~2.5 MB</div>
|
|
<div class="text-muted small">Est. File Size</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card text-center">
|
|
<div class="card-body">
|
|
<div class="fs-20px fw-600 text-warning">~30s</div>
|
|
<div class="text-muted small">Est. Time</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-sm table-bordered">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Bill Number</th>
|
|
<th>Patient</th>
|
|
<th>Date</th>
|
|
<th>Amount</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>BILL-2024-001</td>
|
|
<td>John Smith</td>
|
|
<td>Jan 15, 2024</td>
|
|
<td>$1,250.00</td>
|
|
<td><span class="badge bg-success">Paid</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td>BILL-2024-002</td>
|
|
<td>Jane Doe</td>
|
|
<td>Jan 16, 2024</td>
|
|
<td>$850.00</td>
|
|
<td><span class="badge bg-warning">Pending</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td>BILL-2024-003</td>
|
|
<td>Bob Johnson</td>
|
|
<td>Jan 17, 2024</td>
|
|
<td>$2,100.00</td>
|
|
<td><span class="badge bg-primary">Submitted</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="5" class="text-center text-muted">
|
|
... and 1,244 more records
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
`;
|
|
|
|
$('#previewContent').html(previewHtml);
|
|
}, 1000);
|
|
}
|
|
|
|
function startExport() {
|
|
// Validate form
|
|
if (!$('#exportForm')[0].checkValidity()) {
|
|
$('#exportForm')[0].reportValidity();
|
|
return;
|
|
}
|
|
|
|
// Show export status
|
|
$('#exportStatus').show();
|
|
$('#exportBtn').prop('disabled', true);
|
|
|
|
// Simulate export process
|
|
var progress = 0;
|
|
var messages = [
|
|
'Validating export parameters...',
|
|
'Querying database records...',
|
|
'Processing bill data...',
|
|
'Generating export file...',
|
|
'Compressing output...',
|
|
'Finalizing export...'
|
|
];
|
|
|
|
var interval = setInterval(function() {
|
|
progress += Math.random() * 20;
|
|
if (progress > 100) progress = 100;
|
|
|
|
$('#progressBar').css('width', progress + '%');
|
|
$('#progressPercent').text(Math.round(progress) + '%');
|
|
|
|
if (progress < 100) {
|
|
var messageIndex = Math.floor((progress / 100) * messages.length);
|
|
if (messageIndex < messages.length) {
|
|
$('#exportMessages').html(`
|
|
<div class="text-muted">
|
|
<i class="fa fa-info-circle me-2"></i>${messages[messageIndex]}
|
|
</div>
|
|
`);
|
|
}
|
|
} else {
|
|
clearInterval(interval);
|
|
$('#exportComplete').show();
|
|
$('#downloadLink').attr('href', '/billing/exports/download/latest/');
|
|
$('#exportBtn').prop('disabled', false);
|
|
}
|
|
}, 500);
|
|
}
|
|
|
|
function deleteExport(exportId) {
|
|
if (confirm('Are you sure you want to delete this export?')) {
|
|
$.post('{% url "billing:delete_export" %}', {
|
|
'export_id': exportId,
|
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
}, function(data) {
|
|
if (data.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Failed to delete export: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
|