Accounting GL: vendor checks relieve A/P; Village Grove payments direct-to-bank

- post_transaction_gl: a vendor money-out (check) now posts Dr A/P / Cr Bank
  instead of re-debiting the coded expense account. Fixes double-counted expense
  and checks showing as P&L debits (bill already recognized the expense).
- post_payment_gl: Village Grove owner payments post straight to HOLII COGENT
  Checking instead of Undeposited Funds (scoped; others unchanged).

Both applied to the live DB; Ashley Manor's affected transactions re-posted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-08 14:45:04 -04:00
parent 5aa03d1cd6
commit fdb9174c45
2 changed files with 72 additions and 0 deletions
@@ -0,0 +1,41 @@
-- Fix: vendor (money-out) bank transactions were re-debiting the expense account
-- when coded to one, double-counting expense (the bill already recognized it) and
-- never relieving Accounts Payable — so checks showed as P&L debits. Make vendor
-- payments relieve A/P; the coded account is only used for non-vendor/non-customer
-- transactions.
create or replace function accounting.post_transaction_gl(_txn_id uuid)
returns void
language plpgsql
security definer
set search_path to 'public', 'accounting'
as $function$
declare t accounting.transactions%rowtype; _counter uuid; _je uuid; _amt numeric;
begin
select * into t from accounting.transactions where id=_txn_id;
if not found then return; end if;
perform accounting._gl_clear(t.company_id, 'acmacc_txn', t.id::text);
if not accounting.gl_managed(t.company_id) then return; end if;
if t.transfer_id is not null or t.deposit_id is not null then return; end if;
if t.account_id is null then return; end if;
_amt := coalesce(t.amount,0);
if _amt = 0 then return; end if;
_counter := case
when t.customer_id is not null then accounting.coa_ar(t.company_id)
when t.vendor_id is not null then accounting.coa_ap(t.company_id)
when t.coa_account_id is not null then t.coa_account_id
else null end;
if _counter is null then return; end if;
insert into accounting.journal_entries (company_id, date, description, reference, external_source, external_id)
values (t.company_id, t.date, coalesce(nullif(t.description,''), 'Bank transaction'), t.reference, 'acmacc_txn', t.id::text)
returning id into _je;
if t.type = 'credit' then
insert into accounting.journal_entry_lines (journal_entry_id, account_id, debit, credit, description) values
(_je, t.account_id, _amt, 0, t.description),
(_je, _counter, 0, _amt, t.description);
else
insert into accounting.journal_entry_lines (journal_entry_id, account_id, debit, credit, description) values
(_je, _counter, _amt, 0, t.description),
(_je, t.account_id, 0, _amt, t.description);
end if;
end$function$;
@@ -0,0 +1,31 @@
-- Village Grove at La Cita: post owner payments directly to the operating
-- checking account (HOLII COGENT Checking XX2814) instead of Undeposited Funds.
-- Scoped to this one company per request; all others keep the Undeposited flow.
-- (Interim hardcoded routing until a per-company "operating/deposit account"
-- setting exists.)
create or replace function accounting.post_payment_gl(_payment_id uuid)
returns void
language plpgsql
security definer
set search_path to 'public', 'accounting'
as $function$
declare p accounting.payments_received%rowtype; _ar uuid; _dest uuid; _je uuid;
begin
select * into p from accounting.payments_received where id=_payment_id;
if not found then return; end if;
perform accounting._gl_clear(p.company_id, 'acmacc_pay', p.id::text);
if not accounting.gl_managed(p.company_id) then return; end if;
if coalesce(p.amount,0) = 0 then return; end if;
if p.company_id = '3216c404-496f-4d98-b6fe-36d0f9b1278a' then
_dest := 'db656b9e-f27a-4c0f-be2a-dc1fa793be49'; -- HOLII COGENT Checking -- XX2814
else
_dest := accounting.coa_undeposited(p.company_id);
end if;
_ar := accounting.coa_ar(p.company_id);
insert into accounting.journal_entries (company_id, date, description, reference, external_source, external_id)
values (p.company_id, p.payment_date, coalesce(nullif(p.memo,''), 'Payment received'), p.reference, 'acmacc_pay', p.id::text)
returning id into _je;
insert into accounting.journal_entry_lines (journal_entry_id, account_id, debit, credit, description) values
(_je, _dest, p.amount, 0, 'Payment received'),
(_je, _ar, 0, p.amount, 'Payment received');
end$function$;