cmc-sales/go-app/templates/documents/view.html

502 lines
20 KiB
HTML
Raw Normal View History

2025-07-02 05:04:36 -07:00
{{define "content"}}
<div class="container">
<div class="columns">
<div class="column">
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li><a href="/documents">Documents</a></li>
<li class="is-active"><a href="#" aria-current="page">{{.Document.Type}} #{{.Document.ID}}</a></li>
</ul>
</nav>
</div>
</div>
<!-- Include document type specific view -->
{{if eq .DocType "quote"}}
{{template "document-quote-view" .}}
{{else if eq .DocType "invoice"}}
{{template "document-invoice-view" .}}
{{else if eq .DocType "purchaseOrder"}}
{{template "document-purchase-order-view" .}}
{{else if eq .DocType "orderAck"}}
{{template "document-orderack-view" .}}
{{else if eq .DocType "packingList"}}
{{template "document-packinglist-view" .}}
{{else}}
<div class="notification is-warning">
Unknown document type: {{.DocType}}
</div>
{{end}}
<!-- Line Items Section -->
<div class="box mt-5">
<h2 class="title is-4">Line Items</h2>
<div id="line-items-table">
<table class="table is-fullwidth is-striped">
<thead>
<tr>
<th>Item #</th>
<th>Title</th>
<th>Description</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Total Price</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="line-items-tbody">
{{if .LineItems}}
{{range .LineItems}}
<tr id="line-item-{{.ID}}">
<td>{{.ItemNumber}}</td>
<td>{{.Title}}</td>
<td>{{.Description}}</td>
<td>{{.Quantity}}</td>
<td>
{{if .GrossUnitPrice.Valid}}
${{.GrossUnitPrice.String}}
{{else if .UnitPriceString.Valid}}
{{.UnitPriceString.String}}
{{else}}
-
{{end}}
</td>
<td>
{{if .GrossPrice.Valid}}
${{.GrossPrice.String}}
{{else if .GrossPriceString.Valid}}
{{.GrossPriceString.String}}
{{else}}
-
{{end}}
</td>
<td>
<button class="button is-small is-primary" onclick="editLineItem({{.ID}})">
<span class="icon">
<i class="fas fa-edit"></i>
</span>
<span>Edit</span>
</button>
<button class="button is-small is-danger" onclick="deleteLineItem({{.ID}})">
<span class="icon">
<i class="fas fa-trash"></i>
</span>
<span>Delete</span>
</button>
</td>
</tr>
{{end}}
{{else}}
<tr id="no-line-items">
<td colspan="7" class="has-text-centered has-text-grey">
No line items yet
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
<button class="button is-primary" onclick="showAddLineItemForm()">
<span class="icon">
<i class="fas fa-plus"></i>
</span>
<span>Add Line Item</span>
</button>
</div>
<!-- Add Line Item Modal -->
<div class="modal" id="add-line-item-modal">
<div class="modal-background" onclick="hideAddLineItemForm()"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Add Line Item</p>
<button class="delete" aria-label="close" onclick="hideAddLineItemForm()"></button>
</header>
<section class="modal-card-body">
<form id="add-line-item-form">
<input type="hidden" name="document_id" value="{{.Document.ID}}">
<div class="field">
<label class="label">Title</label>
<div class="control">
<input class="input" type="text" name="title" placeholder="Line item title" required>
</div>
</div>
<div class="field">
<label class="label">Description</label>
<div class="control">
<textarea class="textarea" name="description" placeholder="Line item description" required></textarea>
</div>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label">Quantity</label>
<div class="control">
<input class="input" type="text" name="quantity" placeholder="1.00" required>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label">Unit Price</label>
<div class="control">
<input class="input" type="text" name="gross_unit_price" placeholder="0.00">
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label">Total Price</label>
<div class="control">
<input class="input" type="text" name="gross_price" placeholder="0.00">
</div>
</div>
</div>
</div>
<div class="field">
<div class="control">
<label class="checkbox">
<input type="checkbox" name="option" value="1">
Optional item
</label>
</div>
</div>
</form>
</section>
<footer class="modal-card-foot">
<button class="button is-primary" onclick="submitLineItem()">Add Line Item</button>
<button class="button" onclick="hideAddLineItemForm()">Cancel</button>
</footer>
</div>
</div>
<!-- Edit Line Item Modal -->
<div class="modal" id="edit-line-item-modal">
<div class="modal-background" onclick="hideEditLineItemForm()"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Edit Line Item</p>
<button class="delete" aria-label="close" onclick="hideEditLineItemForm()"></button>
</header>
<section class="modal-card-body">
<form id="edit-line-item-form">
<input type="hidden" name="id" id="edit-line-item-id">
<input type="hidden" name="document_id" value="{{.Document.ID}}">
<div class="field">
<label class="label">Item Number</label>
<div class="control">
<input class="input" type="text" name="item_number" id="edit-item-number" placeholder="1.00" required>
</div>
</div>
<div class="field">
<label class="label">Title</label>
<div class="control">
<input class="input" type="text" name="title" id="edit-title" placeholder="Line item title" required>
</div>
</div>
<div class="field">
<label class="label">Description</label>
<div class="control">
<textarea class="textarea" name="description" id="edit-description" placeholder="Line item description" required></textarea>
</div>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label">Quantity</label>
<div class="control">
<input class="input" type="text" name="quantity" id="edit-quantity" placeholder="1.00" required oninput="calculateEditTotal()">
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label">Unit Price</label>
<div class="control">
<input class="input" type="text" name="gross_unit_price" id="edit-unit-price" placeholder="0.00" oninput="calculateEditTotal()">
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label">Total Price</label>
<div class="control">
<input class="input" type="text" name="gross_price" id="edit-total-price" placeholder="0.00">
</div>
</div>
</div>
</div>
<div class="field">
<div class="control">
<label class="checkbox">
<input type="checkbox" name="option" id="edit-option" value="1">
Optional item
</label>
</div>
</div>
</form>
</section>
<footer class="modal-card-foot">
<button class="button is-primary" onclick="submitEditLineItem()">Update Line Item</button>
<button class="button" onclick="hideEditLineItemForm()">Cancel</button>
</footer>
</div>
</div>
<!-- Attachments Section -->
<div class="box mt-5">
<h2 class="title is-4">Attachments</h2>
<div id="attachments-table">
<table class="table is-fullwidth is-striped">
<thead>
<tr>
<th>Filename</th>
<th>Name</th>
<th>Description</th>
<th>Size</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="5" class="has-text-centered has-text-grey">
No attachments yet
</td>
</tr>
</tbody>
</table>
</div>
<button class="button is-info" onclick="addAttachment()">
<span class="icon">
<i class="fas fa-paperclip"></i>
</span>
<span>Add Attachment</span>
</button>
</div>
</div>
<script>
function showAddLineItemForm() {
document.getElementById('add-line-item-modal').classList.add('is-active');
}
function hideAddLineItemForm() {
document.getElementById('add-line-item-modal').classList.remove('is-active');
document.getElementById('add-line-item-form').reset();
}
function hideEditLineItemForm() {
document.getElementById('edit-line-item-modal').classList.remove('is-active');
document.getElementById('edit-line-item-form').reset();
}
function submitEditLineItem() {
const form = document.getElementById('edit-line-item-form');
const formData = new FormData(form);
fetch('/line_items/ajax_edit', {
method: 'POST',
body: formData
})
.then(response => response.text())
.then(data => {
if (data === 'SUCCESS') {
hideEditLineItemForm();
refreshLineItemsTable();
showNotification('Line item updated successfully', 'is-success');
} else {
showNotification('Failed to update line item', 'is-danger');
}
})
.catch(error => {
console.error('Error:', error);
showNotification('Error updating line item', 'is-danger');
});
}
function submitLineItem() {
const form = document.getElementById('add-line-item-form');
const formData = new FormData(form);
fetch('/line_items/ajax_add', {
method: 'POST',
body: formData
})
.then(response => response.text())
.then(data => {
if (data === 'SUCCESS') {
hideAddLineItemForm();
refreshLineItemsTable();
showNotification('Line item added successfully', 'is-success');
} else {
showNotification('Failed to add line item', 'is-danger');
}
})
.catch(error => {
console.error('Error:', error);
showNotification('Error adding line item', 'is-danger');
});
}
function editLineItem(id) {
// Fetch line item data
fetch(`/api/v1/line-items/${id}`)
.then(response => response.json())
.then(data => {
// Populate the edit form
document.getElementById('edit-line-item-id').value = data.id;
document.getElementById('edit-item-number').value = data.item_number;
document.getElementById('edit-title').value = data.title;
document.getElementById('edit-description').value = data.description;
document.getElementById('edit-quantity').value = data.quantity;
// Handle price fields - check both numeric and string versions
if (data.gross_unit_price && data.gross_unit_price.Valid) {
document.getElementById('edit-unit-price').value = data.gross_unit_price.String;
} else {
document.getElementById('edit-unit-price').value = '';
}
if (data.gross_price && data.gross_price.Valid) {
document.getElementById('edit-total-price').value = data.gross_price.String;
} else {
document.getElementById('edit-total-price').value = '';
}
// Set checkbox
document.getElementById('edit-option').checked = data.option;
// Show the modal
document.getElementById('edit-line-item-modal').classList.add('is-active');
})
.catch(error => {
console.error('Error fetching line item:', error);
showNotification('Error loading line item data', 'is-danger');
});
}
function deleteLineItem(id) {
if (confirm('Are you sure you want to delete this line item?')) {
fetch(`/line_items/ajax_delete/${id}`, {
method: 'POST'
})
.then(response => response.text())
.then(data => {
if (data === 'SUCCESS') {
document.getElementById(`line-item-${id}`).remove();
// Check if there are no more line items
const tbody = document.getElementById('line-items-tbody');
if (tbody.children.length === 0) {
tbody.innerHTML = '<tr id="no-line-items"><td colspan="7" class="has-text-centered has-text-grey">No line items yet</td></tr>';
}
showNotification('Line item deleted successfully', 'is-success');
} else {
showNotification('Failed to delete line item', 'is-danger');
}
})
.catch(error => {
console.error('Error:', error);
showNotification('Error deleting line item', 'is-danger');
});
}
}
function refreshLineItemsTable() {
const documentId = {{.Document.ID}};
fetch(`/line_items/get_table/${documentId}`, {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.text())
.then(html => {
// The response is already the tbody content
document.getElementById('line-items-tbody').innerHTML = html;
})
.catch(error => {
console.error('Error refreshing line items:', error);
});
}
function showNotification(message, type) {
// Create notification element
const notification = document.createElement('div');
notification.className = `notification ${type} is-light`;
notification.innerHTML = `
<button class="delete" onclick="this.parentElement.remove()"></button>
${message}
`;
// Add to page
const container = document.querySelector('.container');
container.insertBefore(notification, container.firstChild);
// Auto-remove after 5 seconds
setTimeout(() => {
if (notification.parentElement) {
notification.remove();
}
}, 5000);
}
function addAttachment() {
// TODO: Implement attachment modal
alert('Add attachment functionality coming soon');
}
function generatePDF() {
const documentId = {{.Document.ID}};
const currentUrl = window.location.href;
// Show loading state
const buttons = document.querySelectorAll('button');
const originalTexts = new Map();
buttons.forEach(btn => {
if (btn.onclick && btn.onclick.toString().includes('generatePDF')) {
originalTexts.set(btn, btn.innerHTML);
btn.innerHTML = '<span class="icon"><i class="fas fa-spinner fa-spin"></i></span><span>Generating PDF...</span>';
btn.disabled = true;
}
});
// Call PDF generation endpoint
window.location.href = `/documents/pdf/${documentId}`;
// Reset button state after a delay (in case user stays on page)
setTimeout(() => {
buttons.forEach(btn => {
if (originalTexts.has(btn)) {
btn.innerHTML = originalTexts.get(btn);
btn.disabled = false;
}
});
}, 3000);
}
function emailDocument() {
// TODO: Implement email functionality
alert('Email functionality coming soon');
}
function calculateEditTotal() {
const quantity = parseFloat(document.getElementById('edit-quantity').value) || 0;
const unitPrice = parseFloat(document.getElementById('edit-unit-price').value) || 0;
const total = quantity * unitPrice;
if (total > 0) {
document.getElementById('edit-total-price').value = total.toFixed(2);
}
}
</script>
{{end}}