Skip to content

Commit

Permalink
Merge pull request #8356 from ehuelsmann/fix/master/assembly-cogs
Browse files Browse the repository at this point in the history
Fix cogs calculation for assemblies
  • Loading branch information
ehuelsmann authored Sep 6, 2024
2 parents dcd0e71 + daf9d8d commit b5e65c9
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 19 deletions.
2 changes: 1 addition & 1 deletion lib/LedgerSMB/Report/Unapproved/Batch_Detail.pm
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,6 @@ sub run_report{
'1' => 'ap',
'2' => 'ar',
'3' => 'ap',
'5' => 'gl',
'6' => 'ar',
'8' => 'is',
'9' => 'ir',
Expand All @@ -273,6 +272,7 @@ sub run_report{
# This is different with batch class 8 and 9
$script = 'ir' if ($ref->{invoice} and $ref->{batch_class_id} == 3);
$script = 'is' if ($ref->{invoice} and $ref->{batch_class_id} == 6);
$script //= 'gl';

$ref->{reference_href_suffix} = "$script.pl?__action=edit&id=$ref->{transaction_id}"
if $script;
Expand Down
9 changes: 9 additions & 0 deletions sql/changes/1.10/migration-batch-class.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@


insert into
batch_class (id, class)
values (10, 'upgrade');

insert into
trans_type (code, description)
values ('up', 'The transaction is generated by a software upgrade');
192 changes: 192 additions & 0 deletions sql/changes/1.11/fix-assembly-cogs.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@


DO $$
DECLARE
t_corr record;
t_inv record;
t_closed_date date;
BEGIN
-- setup
select max(end_date) into t_closed_date
from account_checkpoint;

-- fix the negative sellprice values on assemblies
-- this fixes the historically incorrectly set values
-- (the fix in mfg_lot__commit() fixes the calculation
-- going forward)
update invoice i
set sellprice = sellprice * -1
where qty < 0
and sellprice < 0
and exists (select 1
from parts p
where p.id = i.parts_id
and p.assembly);

IF FOUND THEN
insert into batch (batch_class_id, control_code, default_date,
description)
values (10, 'UPG-ASSEMBLIES', now(),
'This batch has been generated by the upgrade procedure; it contains corrective transactions to fix COGS postings for assemblies');

create temporary sequence mig_ref_id;
create temporary table correction_lines as
select ac.*
from acc_trans ac
join ar
on ar.id = ac.trans_id
join invoice i
on ac.invoice_id = i.id
join account a
on a.id = ac.chart_id
where a.category in ('A', 'E') -- 'I' exists too, for sales
and not (ac.amount_bc = 0 and ac.amount_tc = 0)
and exists (select 1
from acc_trans
join account
on acc_trans.chart_id = account.id
where acc_trans.invoice_id = i.id
and account.category = 'E'
and ((ar.reverse and acc_trans.amount_bc < 0)
or (acc_trans.amount_bc > 0 and
ar.reverse is distinct from true)))
and exists (select 1
from parts p
where assembly
and p.id = i.parts_id);

alter table correction_lines
add column orig_transdate date,
add column corrected_monthend date,
add column correction_date date;

update correction_lines cl
set corrected_monthend = (select (date_trunc('month', transdate)
+ '1 month - 1 day'::interval)::date),
correction_date =
CASE WHEN transdate <= t_closed_date
THEN (select max(end_date)
from account_checkpoint) + '1 day'::interval
ELSE (select (date_trunc('month', transdate)
+ '1 month - 1 day'::interval)::date)
END;

alter table correction_lines
add column correction_shifted boolean; -- true if shifted due to closed period

update correction_lines
set correction_shifted = NOT (
date_trunc('month', corrected_monthend)
= date_trunc('month', correction_date));

for t_corr in
select distinct corrected_monthend, correction_date, correction_shifted
from correction_lines
loop
insert into gl (reference, transdate,
approved, trans_type_code,
description,
notes)
values ('upg/ac-' || nextval('mig_ref_id'), t_corr.correction_date,
false, 'up',
'Upgrade transaction fixing assembly COGS for '
|| extract('year' from t_corr.corrected_monthend)
|| '-' || lpad(extract('month' from t_corr.corrected_monthend)::text, 2, '0'),
''
|| CASE
WHEN t_corr.correction_shifted THEN
E'\n\nThe proposed posting date of this transaction was '
|| 'set to the first day of the current open period; '
|| 'the latest closing date being ' || t_closed_date
|| '. By reopening closed periods, the proposed date '
|| 'can be changed to the month the correction relates to.'
|| E'\n\nNOTE: Re-opening reported years may not be '
|| 'allowed in most jurisdictions; please consult an '
|| 'accountant on how to deal with such situations.'
ELSE
''
END);

insert into workflow (workflow_id, type, state)
values (nextval('workflow_seq')::int, 'GL', 'SAVED');
insert into workflow_context (workflow_id, context)
values (currval('workflow_seq')::int,
format('{"transdate": "%s", "batch-id": %s}',
t_corr.correction_date,
currval('batch_id_seq')::int)::jsonb);
update transactions
set workflow_id = currval('workflow_seq')::int
where id = currval('id')::int;

insert into voucher (trans_id, batch_id, batch_class)
values (currval('id')::int, currval('batch_id_seq')::int, 10);

insert into correction_lines (
trans_id, chart_id, transdate, source, cleared,
invoice_id, approved, voucher_id, entry_id,
amount_bc, amount_tc, curr,
memo)
select currval('id')::int, chart_id, t_corr.correction_date, null, false,
invoice_id, false, currval('voucher_id_seq')::int, entry_id,
-1*amount_bc, -1*amount_tc, curr,
'Corrected COGS for invoice ' || (select invnumber from ar where ar.id = correction_lines.trans_id)
from correction_lines
where corrected_monthend = t_corr.corrected_monthend;

-- this update works, because the insert above does not add
-- values for corrected_monthend
update correction_lines
set trans_id = currval('id')::int,
voucher_id = currval('voucher_id_seq')::int,
transdate = t_corr.correction_date,
approved = false,
cleared = false,
source = null,
amount_bc = amount_bc * -1,
amount_tc = amount_tc * -1,
memo = 'Reversing original COGS posting for invoice ' || (select invnumber from ar where ar.id = correction_lines.trans_id)
where corrected_monthend = t_corr.corrected_monthend;

for t_inv in
select distinct invoice_id
from correction_lines cl
loop
insert into invoice (
trans_id, parts_id, qty, allocated, sellprice, precision,
fxsellprice, discount, assemblyitem, unit, deliverydate,
serialnumber, vendor_sku,
description, notes)
select currval('id')::int, parts_id, 0, 0, sellprice, precision,
fxsellprice, discount, assemblyitem, unit, deliverydate,
serialnumber, vendor_sku,
'COGS-correction for invoice_id=' || t_inv.invoice_id, null
from invoice
where t_inv.invoice_id = invoice.id;

update correction_lines
set invoice_id = currval('invoice_id_seq')::int
where invoice_id = t_inv.invoice_id;
end loop;
end loop;

insert into acc_trans (
trans_id, chart_id, transdate, source, cleared,
invoice_id, approved, voucher_id, entry_id,
amount_bc, amount_tc, curr,
memo)
select trans_id, chart_id, transdate, source, cleared,
invoice_id, approved, voucher_id, nextval('acc_trans_entry_id_seq')::int,
amount_bc, amount_tc, curr,
memo
from correction_lines
order by invoice_id, memo desc, chart_id;


perform pg_notify(
'upgrade.' || current_database(),
$json${"type":"feedback","content":"Please review: A batch with corrections for Cost of Goods Sold (COGS) for assembly sales needs your (and potentially a licensed accountant's advice and) review under the menu Transaction Approval > Batch: assembly-related-COGS was posted as negative cost instead of regular cost.\n\nThis release fixes that and proposes transactions to correct any historically incorrect acccounting. Each transaction corrects for the assembly-related-COGS postings in a specific month. Transactions relating to postings in closed periods have been proposed for posting on the first day of the current open period, which may not be what you want. You can either Post the batch or Delete it; for other options, please contact the LedgerSMB community through its chat channel or mailing lists. For more information, please consult https://ledgersmb.org/content/cogs-assembly-fix"}$json$ -- '
);
END IF;
END;
$$ LANGUAGE plpgsql;

2 changes: 2 additions & 0 deletions sql/changes/LOADORDER
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ mc/delete-migration-validation-data.sql
1.10/missing-fkeys.sql
1.10/file-tranaction-cascade-delete.sql
1.10/fix-arap-approval-state.sql
1.10/migration-batch-class.sql
# 1.11 changes
1.11/menu-system-users.sql
1.11/country-config.sql
Expand All @@ -183,6 +184,7 @@ mc/delete-migration-validation-data.sql
1.11/rename-action-parameter.sql
1.11/gl-workflows.sql
1.11/workflow-for-aa-transactions.sql
1.11/fix-assembly-cogs.sql
# 1.12 changes
1.12/migrate_to_identity.sql
1.12/add-stored-order-quote-taxes.sql
Expand Down
23 changes: 15 additions & 8 deletions sql/modules/Goods.sql
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,31 @@ BEGIN

INSERT INTO invoice (trans_id, parts_id, qty, allocated, sellprice)
SELECT currval('id')::int, t_mfg_lot.parts_id, t_mfg_lot.qty * -1, 0,
sum(amount_bc) / t_mfg_lot.qty
-1*sum(amount_bc) / t_mfg_lot.qty
FROM acc_trans
WHERE amount_bc < 0 and trans_id = currval('id')::int;

PERFORM cogs__add_for_ap_line(currval('invoice_id_seq')::int);

-- move from reverse COGS.
-- move from COGS back into inventory
INSERT INTO acc_trans(trans_id, chart_id, transdate,
amount_bc, curr, amount_tc)
SELECT trans_id, chart_id, transdate, amount_bc * -1, curr, amount_tc * -1
amount_bc, curr, amount_tc,
invoice_id, memo)
SELECT trans_id, chart_id, transdate,
amount_bc * -1, curr, amount_tc * -1,
currval('invoice_id_seq')::int, 'Collect assembly parts costs from COGS'
FROM acc_trans
WHERE amount_bc < 0 and trans_id = currval('id')::int;

-- difference goes into inventory
INSERT INTO acc_trans(trans_id, transdate, amount_bc, curr, amount_tc,
chart_id)
SELECT trans_id, now(), sum(amount_bc) * -1, curr, sum(amount_tc) * -1,
(select inventory_accno_id from parts where id = t_mfg_lot.parts_id)
INSERT INTO acc_trans(trans_id, transdate, chart_id,
amount_bc, curr, amount_tc,
invoice_id, memo)
SELECT trans_id, now(), (select inventory_accno_id
from parts
where id = t_mfg_lot.parts_id),
sum(amount_bc) * -1, curr, sum(amount_tc) * -1,
currval('invoice_id_seq')::int, 'Post assembly parts cost in inventory'
FROM acc_trans
WHERE trans_id = currval('id')::int
GROUP BY trans_id, curr;
Expand Down
21 changes: 11 additions & 10 deletions sql/modules/Voucher.sql
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ $$
WHERE a.amount_bc > 0
AND v.batch_id = in_batch_id
AND v.batch_class IN (select id from batch_class
where class = 'gl')
where class in ('gl', 'upgrade'))
GROUP BY v.id, g.reference, g.description, v.batch_id,
v.trans_id, g.transdate
ORDER BY 7, 1
Expand Down Expand Up @@ -189,14 +189,15 @@ $$
SELECT b.id, c.class, b.control_code, b.description, u.username,
b.created_on, b.default_date,
sum(
CASE WHEN vc.id = 5 AND al.amount_bc < 0 -- GL
THEN al.amount_bc
WHEN vc.id = 1
THEN ap.amount_bc
WHEN vc.id = 2
THEN ar.amount_bc
ELSE 0
END) AS transaction_total,
CASE
WHEN vc.id = 1
THEN ap.amount_bc
WHEN vc.id = 2
THEN ar.amount_bc
WHEN al.amount_bc < 0 -- GL
THEN al.amount_bc
ELSE 0
END) AS transaction_total,
sum(
CASE WHEN alc.description = 'AR' AND vc.id IN (6, 7)
THEN al.amount_bc
Expand All @@ -214,7 +215,7 @@ $$
LEFT JOIN ar ON (vc.id = 2 AND v.trans_id = ar.id)
LEFT JOIN ap ON (vc.id = 1 AND v.trans_id = ap.id)
LEFT JOIN acc_trans al ON
((vc.id = 5 AND v.trans_id = al.trans_id) OR
((vc.id NOT IN (3, 4, 6, 7) AND v.trans_id = al.trans_id) OR
(vc.id IN (3, 4, 6, 7)
AND al.voucher_id = v.id))
LEFT JOIN account_link alc ON (al.chart_id = alc.account_id)
Expand Down

0 comments on commit b5e65c9

Please sign in to comment.