accounting workflows
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
session_start();
|
||||
require '../config.php';
|
||||
require '../include_header.php';
|
||||
|
||||
$ref_invoice_id = (int)($_GET['ref_invoice_id'] ?? 0);
|
||||
?>
|
||||
|
||||
<body>
|
||||
<?php require '../include_topbar.php'; ?>
|
||||
<?php require '../include_sidebar_ac.php'; ?>
|
||||
|
||||
<main id="content" class="content py-15">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="mb-6 d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h1 class="fs-3 mb-1">New Supplier Credit Note</h1>
|
||||
<p class="mb-0 text-muted">Accounting supplier credit note without stock movement</p>
|
||||
</div>
|
||||
<a href="<?php echo $server_url?>expense/purchase_invoice.php" class="btn btn-light">
|
||||
<i class="ti ti-arrow-left me-1"></i>Back
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-5">
|
||||
<div class="col-lg-8">
|
||||
<div class="card mb-5">
|
||||
<div class="card-body p-5">
|
||||
<h2 class="fs-5 mb-4">Supplier Credit Note Information</h2>
|
||||
<div class="row gx-5">
|
||||
<div class="mb-3 col-lg-6">
|
||||
<label class="form-label">Reference Purchase Invoice ID</label>
|
||||
<input type="number" id="ref_invoice_id" class="form-control"
|
||||
value="<?php echo $ref_invoice_id ?: ''; ?>" min="0" placeholder="Optional">
|
||||
</div>
|
||||
<div class="mb-3 col-lg-6">
|
||||
<label class="form-label">Supplier</label>
|
||||
<input type="text" id="contact" class="form-control contact_search"
|
||||
placeholder="Search supplier..." autocomplete="off">
|
||||
<input type="hidden" id="contact_id">
|
||||
</div>
|
||||
<div class="mb-3 col-lg-12">
|
||||
<label class="form-label">Reason / Notes</label>
|
||||
<textarea id="notes" class="form-control" rows="3"
|
||||
placeholder="Billing correction, returns credit, price adjustment..."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body p-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2 class="fs-5 mb-0">Credit Lines</h2>
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="add_item_row()">
|
||||
<i class="ti ti-plus me-1"></i>Add Line
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Description</th>
|
||||
<th style="width:100px;">Qty</th>
|
||||
<th style="width:130px;">Unit Price</th>
|
||||
<th style="width:80px;">Tax%</th>
|
||||
<th style="width:120px;" class="text-end">Total</th>
|
||||
<th style="width:40px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="item_tbody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-5">
|
||||
<div class="card-body p-4">
|
||||
<h2 class="fs-5 mb-3">Summary</h2>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Subtotal</span>
|
||||
<span id="summary_subtotal">0.00</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Tax</span>
|
||||
<span id="summary_tax">0.00</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<span class="text-muted small">Tax Adj.</span>
|
||||
<input type="number" id="tax_adjustment" class="form-control form-control-sm text-end"
|
||||
style="width:90px;" min="-0.3" max="0.3" step="0.01" value="0" oninput="recalc_totals()">
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between fw-bold fs-5">
|
||||
<span>Credit Total</span>
|
||||
<span id="summary_grand_total" class="text-info">0.00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body p-4 d-flex flex-column gap-2">
|
||||
<button class="btn btn-primary w-100" onclick="save_supplier_credit_note()">
|
||||
<i class="ti ti-device-floppy me-1"></i>Save Draft
|
||||
</button>
|
||||
<a href="<?php echo $server_url?>expense/purchase_invoice.php" class="btn btn-light w-100">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php require '../include_ending.php'; ?>
|
||||
|
||||
<script>
|
||||
var item_index = 0;
|
||||
|
||||
function add_item_row(item) {
|
||||
item = item || {};
|
||||
var idx = item_index++;
|
||||
var row = `<tr id="item_row_${idx}">
|
||||
<td>
|
||||
<input type="text" class="form-control form-control-sm item_desc"
|
||||
value="${escape_html(item.product_name || '')}" placeholder="Credit description">
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm item_qty"
|
||||
value="${item.quantity || 1}" min="0.0001" step="any" oninput="recalc_totals()">
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm item_price"
|
||||
value="${item.price || 0}" min="0" step="any" oninput="recalc_totals()">
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm item_tax_rate"
|
||||
value="${parseFloat(item.tax_rate || 0).toFixed(2)}" min="0" max="100" step="0.01" oninput="recalc_totals()">
|
||||
</td>
|
||||
<td class="item_total text-end align-middle">0.00</td>
|
||||
<td class="align-middle">
|
||||
<a href="javascript:void(0);" class="link-danger" onclick="remove_item(${idx})">
|
||||
<i class="ti ti-trash fs-5"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>`;
|
||||
$('#item_tbody').append(row);
|
||||
recalc_totals();
|
||||
}
|
||||
|
||||
function remove_item(idx) {
|
||||
$('#item_row_' + idx).remove();
|
||||
recalc_totals();
|
||||
}
|
||||
|
||||
function recalc_totals() {
|
||||
var subtotal = 0, tax_sum = 0;
|
||||
$('#item_tbody tr').each(function() {
|
||||
var qty = parseFloat($(this).find('.item_qty').val()) || 0;
|
||||
var price = parseFloat($(this).find('.item_price').val()) || 0;
|
||||
var tax_rate = parseFloat($(this).find('.item_tax_rate').val()) || 0;
|
||||
var total = qty * price;
|
||||
subtotal += total;
|
||||
tax_sum += total * tax_rate / 100;
|
||||
$(this).find('.item_total').text(format_number(total, 2));
|
||||
});
|
||||
var tax_adj = parseFloat($('#tax_adjustment').val()) || 0;
|
||||
var tax = round_dp(tax_sum, 2) + tax_adj;
|
||||
$('#summary_subtotal').text(format_number(subtotal, 2));
|
||||
$('#summary_tax').text(format_number(tax, 2));
|
||||
$('#summary_grand_total').text(format_number(subtotal + tax, 2));
|
||||
}
|
||||
|
||||
function collect_items() {
|
||||
var items = [];
|
||||
$('#item_tbody tr').each(function() {
|
||||
var desc = $(this).find('.item_desc').val().trim();
|
||||
var qty = parseFloat($(this).find('.item_qty').val()) || 0;
|
||||
var price = parseFloat($(this).find('.item_price').val()) || 0;
|
||||
var tax_rate = parseFloat($(this).find('.item_tax_rate').val()) || 0;
|
||||
if (!desc && qty <= 0) return;
|
||||
items.push({
|
||||
product_sku: '',
|
||||
product_name: desc,
|
||||
quantity: qty,
|
||||
price: price,
|
||||
tax_rate: tax_rate,
|
||||
tax_amount: round_dp(qty * price * tax_rate / 100, 4),
|
||||
total_price: round_dp(qty * price, 4),
|
||||
});
|
||||
});
|
||||
return items;
|
||||
}
|
||||
|
||||
function load_ref_invoice() {
|
||||
var ref_id = parseInt($('#ref_invoice_id').val()) || 0;
|
||||
if (!ref_id) return;
|
||||
|
||||
ajax_request({
|
||||
url: '<?php echo $server_url?>order/api/engine/retrieve_invoice.php',
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'read',
|
||||
data: { invoice_id: ref_id },
|
||||
onSuccess: function(res) {
|
||||
var inv = res.output || {};
|
||||
if (inv.doc_type !== 'purchase_invoice') return;
|
||||
$('#contact').val(inv.contact_name || '');
|
||||
$('#contact_id').val(inv.contact_id || 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function save_supplier_credit_note() {
|
||||
var items = collect_items();
|
||||
if (!items.length) {
|
||||
bootbox.alert('Please add at least one credit line.');
|
||||
return;
|
||||
}
|
||||
if (!$('#contact_id').val()) {
|
||||
bootbox.alert('Please select a supplier.');
|
||||
return;
|
||||
}
|
||||
if (!$('#notes').val().trim()) {
|
||||
bootbox.alert('Please enter the reason for this supplier credit note.');
|
||||
return;
|
||||
}
|
||||
|
||||
ajax_request({
|
||||
url: '<?php echo $server_url?>expense/api/engine/manage_supplier_credit_note.php',
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'create',
|
||||
data: {
|
||||
ref_invoice_id: $('#ref_invoice_id').val() || 0,
|
||||
contact_id: $('#contact_id').val() || 0,
|
||||
items: JSON.stringify(items),
|
||||
notes: $('#notes').val(),
|
||||
tax_adjustment: parseFloat($('#tax_adjustment').val()) || 0,
|
||||
},
|
||||
onSuccess: function(res) {
|
||||
if (res.new_id) {
|
||||
window.location.href = '<?php echo $server_url?>expense/manage_purchase_invoice.php?id=' + res.new_id;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('contact:selected', '#contact', function(e, contact) {
|
||||
$('#contact_id').val(contact.id);
|
||||
});
|
||||
|
||||
$(function() {
|
||||
add_item_row();
|
||||
load_ref_invoice();
|
||||
$('#ref_invoice_id').on('change', load_ref_invoice);
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user