diff --git a/app/accounting/posting_window.php b/app/accounting/posting_window.php index 1afe4c7..ed4b4c9 100644 --- a/app/accounting/posting_window.php +++ b/app/accounting/posting_window.php @@ -157,8 +157,10 @@ autoPrepare: true, checkRequired: 0, action: 'save', - open_from: from, - open_to: to, + // 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); } @@ -173,8 +175,7 @@ autoPrepare: true, checkRequired: 0, action: 'save', - open_from: '', - open_to: '', + data: { open_from: '', open_to: '' }, onSuccess: function() { render_display('', ''); } diff --git a/app/assets/utils/classes_ac/GlManager.php b/app/assets/utils/classes_ac/GlManager.php index ddb408d..8354b02 100644 --- a/app/assets/utils/classes_ac/GlManager.php +++ b/app/assets/utils/classes_ac/GlManager.php @@ -81,7 +81,11 @@ class GlManager $now = date('Y-m-d H:i:s'); $sth = $this->pdo->prepare( - "SELECT id, current_version, formula_id, history + // `period` is read below as $old_period to reverse the old ETL + // totals. It was missing from this list, so it was always null and + // upsertEtl(string $period) threw a TypeError — every edit of a + // manual journal ended in HTTP 500. + "SELECT id, current_version, formula_id, history, period FROM td_gl WHERE company_id = :cid AND id = :gl_id AND source_type = 'manual' FOR UPDATE" diff --git a/app/journal/index.php b/app/journal/index.php index 404aa85..bb128c8 100644 --- a/app/journal/index.php +++ b/app/journal/index.php @@ -117,16 +117,32 @@ }; function load_listing() { - var period = document.getElementById('f_period').value; + var period = document.getElementById('f_period').value; // "YYYY-MM" var source = document.getElementById('f_source').value; + // The engine filters on a date range, not a period, so turn the chosen + // month into its first and last day. + var date_from = '', date_to = ''; + if (/^\d{4}-\d{2}$/.test(period)) { + var ym = period.split('-'); + var last_day = new Date(parseInt(ym[0]), parseInt(ym[1]), 0).getDate(); + date_from = period + '-01'; + date_to = period + '-' + ('0' + last_day).slice(-2); + } + + // Payload fields must go inside `data` — ajax_request() ignores unknown + // top-level options, so as siblings of `url` these were never sent and the + // month / source filters silently did nothing. ajax_request({ url: server_url + 'accounting/api/engine/get_journal_listing.php', autoPrepare: true, checkRequired: 0, action: 'read', - period: period, - source_type: source, + data: { + source_type: source, + date_from: date_from, + date_to: date_to + }, onSuccess: function(res) { var rows = res.output || []; document.getElementById('jl_badge').textContent = rows.length + ' entries'; @@ -146,8 +162,8 @@ '' + escape_html(label) + '' + '' + escape_html(r.contact_name || '—') + '' + '' + escape_html(r.period) + '' + - '' + format_number(r.total_debit) + '' + - '' + format_number(r.total_credit) + '' + + '' + format_number(r.total_debit, 2) + '' + + '' + format_number(r.total_credit, 2) + '' + '' + escape_html(r.posted_at) + '' + '' + (r.source_type === 'manual' ? ' ' : '') + @@ -169,7 +185,9 @@ autoPrepare: true, checkRequired: 0, action: 'read', - gl_id: gl_id, + // Inside `data`, or it is never sent and the engine answers + // "gl_id is required." for every row. + data: { gl_id: gl_id }, onSuccess: function(res) { var d = res.output; var h = d.header; @@ -180,8 +198,8 @@ '' + escape_html(l.account_code) + '' + '' + escape_html(l.account_name) + '' + '' + escape_html(l.description || '—') + '' + - '' + (parseFloat(l.debit) ? format_number(l.debit) : '—') + '' + - '' + (parseFloat(l.credit) ? format_number(l.credit) : '—') + '' + + '' + (parseFloat(l.debit) ? format_number(l.debit, 2) : '—') + '' + + '' + (parseFloat(l.credit) ? format_number(l.credit, 2) : '—') + '' + ''; }).join(''); diff --git a/app/journal/new.php b/app/journal/new.php index 5ad4719..9a67953 100644 --- a/app/journal/new.php +++ b/app/journal/new.php @@ -216,11 +216,17 @@ autoPrepare: true, checkRequired: 0, action: 'manage', - gl_id: document.getElementById('gl_id').value || 0, - journal_date: jdate, - reference: document.getElementById('reference').value, - description: document.getElementById('description').value, - lines: JSON.stringify(lines), + // Payload fields must go inside `data` — ajax_request() ignores unknown + // top-level options. As siblings of `url`, `lines` was never sent (it is + // not a form field, so autoPrepare could not pick it up either) and every + // save was refused with "At least two journal lines are required." + data: { + gl_id: document.getElementById('gl_id').value || 0, + journal_date: jdate, + reference: document.getElementById('reference').value, + description: document.getElementById('description').value, + lines: JSON.stringify(lines) + }, onSuccess: function() { window.location.href = server_url + 'journal/index.php'; } @@ -238,7 +244,7 @@ autoPrepare: true, checkRequired: 0, action: 'read', - gl_id: , + data: { gl_id: }, onSuccess: function(res) { var d = res.output; var h = d.header;