Send journal lines, gl_id and list filters inside the ajax data payload where ajax_request reads them, select period when replacing a manual journal, and show ledger amounts to two decimals.
191 lines
7.2 KiB
PHP
191 lines
7.2 KiB
PHP
<?php
|
|
session_start();
|
|
require '../config.php';
|
|
require '../include_header.php';
|
|
?>
|
|
|
|
<body>
|
|
<?php require '../include_topbar.php'; ?>
|
|
<?php require '../include_master_sidebar.php'; ?>
|
|
|
|
<main id="content" class="content py-15">
|
|
<div class="container-fluid">
|
|
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="d-flex flex-column flex-md-row justify-content-between align-items-md-center mb-6 gap-3">
|
|
<div>
|
|
<h1 class="fs-3 mb-1">Posting Window</h1>
|
|
<p class="mb-0">Define the date range within which GL postings and approved inventory entries can be created, edited, voided, or reversed</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-5">
|
|
|
|
<!-- Window card -->
|
|
<div class="col-lg-6">
|
|
<div class="card">
|
|
<div class="card-body p-6">
|
|
|
|
<div class="d-flex align-items-center gap-3 mb-5">
|
|
<div class="icon-shape icon-lg bg-primary bg-opacity-10 text-primary rounded-2">
|
|
<i class="ti ti-calendar-event fs-4"></i>
|
|
</div>
|
|
<div>
|
|
<h5 class="mb-0 fw-semibold">Open Posting Window</h5>
|
|
<p class="mb-0 text-muted small">Dates outside this range are locked for GL and inventory movement</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Current status -->
|
|
<div id="window_display" class="alert alert-secondary mb-5">Loading...</div>
|
|
|
|
<div class="alert alert-info d-flex gap-2 mb-5">
|
|
<i class="ti ti-info-circle mt-1"></i>
|
|
<div>
|
|
This window applies to both accounting GL postings and approved inventory entries.
|
|
Draft inventory rows can still be edited or cancelled before they affect stock balance.
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Form -->
|
|
<div class="row g-3 mb-4">
|
|
<div class="col-sm-6">
|
|
<label class="form-label">Open From <span class="text-danger">*</span></label>
|
|
<input type="text" id="open_from" class="form-control">
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<label class="form-label">Open To <span class="text-danger">*</span></label>
|
|
<input type="text" id="open_to" class="form-control">
|
|
</div>
|
|
<div class="col-12">
|
|
<div class="form-text">Example: <code>01/01/2026</code> to <code>31/12/2026</code> opens all of 2026.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex gap-2">
|
|
<button class="btn btn-primary" onclick="save_window()">
|
|
<i class="ti ti-device-floppy me-1"></i>Save Window
|
|
</button>
|
|
<button class="btn btn-outline-secondary" onclick="clear_window()">
|
|
<i class="ti ti-lock-open me-1"></i>Remove Restrictions
|
|
</button>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Guide card -->
|
|
<div class="col-lg-6">
|
|
<div class="card border-0 bg-light h-100">
|
|
<div class="card-body p-5">
|
|
<h6 class="fw-semibold mb-3"><i class="ti ti-info-circle me-1"></i>How it works</h6>
|
|
<ul class="small mb-0 ps-3">
|
|
<li class="mb-2">Journal entries, GL postings, and approved inventory movements are only allowed if their date falls <strong>within</strong> the open window.</li>
|
|
<li class="mb-2">Dates <strong>before Open From</strong> or <strong>after Open To</strong> are rejected.</li>
|
|
<li class="mb-2">Inventory entries that already affected stock balance use the same window when they are voided, cancelled, or reversed.</li>
|
|
<li class="mb-2">To open a full year: set <strong>01/01/YYYY</strong> → <strong>31/12/YYYY</strong>.</li>
|
|
<li class="mb-2">To roll the window forward (e.g. close January): change Open From to <strong>01/02/YYYY</strong>.</li>
|
|
<li class="mb-2"><strong>Remove Restrictions</strong> clears both dates — all dates become postable.</li>
|
|
<li>Existing posted GL and approved inventory entries are not changed automatically — the window is checked when a user creates, edits, voids, cancels, or reverses them.</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<?php require '../include_ending.php'; ?>
|
|
|
|
<script>
|
|
var open_from_picker = null;
|
|
var open_to_picker = null;
|
|
|
|
function init_window_pickers() {
|
|
var config = {
|
|
dateFormat: 'Y-m-d',
|
|
altInput: true,
|
|
altFormat: 'd/m/Y',
|
|
allowInput: true,
|
|
onReady: function(_, __, fp) {
|
|
fp.altInput.classList.add('form-control');
|
|
}
|
|
};
|
|
|
|
open_from_picker = flatpickr('#open_from', config);
|
|
open_to_picker = flatpickr('#open_to', config);
|
|
}
|
|
|
|
function load_window() {
|
|
ajax_request({
|
|
url: server_url + 'accounting/api/engine/posting_window.php',
|
|
autoPrepare: true,
|
|
checkRequired: 0,
|
|
action: 'read',
|
|
onSuccess: function(res) {
|
|
var d = res.output;
|
|
if (open_from_picker) open_from_picker.setDate(d.open_from || '', false, 'Y-m-d');
|
|
if (open_to_picker) open_to_picker.setDate(d.open_to || '', false, 'Y-m-d');
|
|
render_display(d.open_from, d.open_to);
|
|
}
|
|
});
|
|
}
|
|
|
|
function render_display(from, to) {
|
|
var el = document.getElementById('window_display');
|
|
if (!from && !to) {
|
|
el.className = 'alert alert-success mb-5';
|
|
el.innerHTML = '<i class="ti ti-lock-open me-2"></i><strong>No restrictions</strong> — all dates are open for posting.';
|
|
} else {
|
|
el.className = 'alert alert-primary mb-5';
|
|
var f = from ? '<strong>' + escape_html(from) + '</strong>' : '<span class="text-muted">no lower limit</span>';
|
|
var t = to ? '<strong>' + escape_html(to) + '</strong>' : '<span class="text-muted">no upper limit</span>';
|
|
el.innerHTML = '<i class="ti ti-calendar-event me-2"></i>Posting open from ' + f + ' to ' + t;
|
|
}
|
|
}
|
|
|
|
function save_window() {
|
|
var from = document.getElementById('open_from').value;
|
|
var to = document.getElementById('open_to').value;
|
|
ajax_request({
|
|
url: server_url + 'accounting/api/engine/posting_window.php',
|
|
autoPrepare: true,
|
|
checkRequired: 0,
|
|
action: 'save',
|
|
// Inside `data`: as top-level options these were ignored, and the save
|
|
// only worked because autoPrepare happens to sweep the two inputs, whose
|
|
// ids match the field names.
|
|
data: { open_from: from, open_to: to },
|
|
onSuccess: function() {
|
|
render_display(from, to);
|
|
}
|
|
});
|
|
}
|
|
|
|
function clear_window() {
|
|
if (open_from_picker) open_from_picker.clear();
|
|
if (open_to_picker) open_to_picker.clear();
|
|
ajax_request({
|
|
url: server_url + 'accounting/api/engine/posting_window.php',
|
|
autoPrepare: true,
|
|
checkRequired: 0,
|
|
action: 'save',
|
|
data: { open_from: '', open_to: '' },
|
|
onSuccess: function() {
|
|
render_display('', '');
|
|
}
|
|
});
|
|
}
|
|
|
|
init_window_pickers();
|
|
load_window();
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|