Skip to content

[Backport version-15] feat: book port expenses to a work in progress account - #485

Merged
av-dev2 merged 7 commits into
version-15from
backport-484-to-version-15
Sep 23, 2026
Merged

av-dev2 merged 7 commits into
version-15from
backport-484-to-version-15

Conversation

@github-actions

Copy link
Copy Markdown

Backport of #484 to version-15.


Why

Port expenses are bought against a container and carried on the ICD Container, ICD Master BL and Manifest dimensions, but they post straight to an expense account, so the cost hits the profit and loss before the container has been invoiced. The ICD wants them held in work in progress and released to cost of goods sold when the container is billed.

This is the first half — holding them on WIP. The release to COGS is a separate change.

Settings

A new Expense Accounting section at the top of the Expenses tab in ICD TZ Settings:

field behaviour
enable_wip_for_expensesEnable WIP for Port Expenses Check, off by default
wip_account Link to Account, shown and mandatory only while the check is on
cogs_account Link to Account, shown and mandatory only while the check is on

The form offers only postable accounts of the user's company. The server refuses a save where either account is missing, is a group account, where the two are the same (releasing an expense would post it to itself), or where they belong to different companies — because the form filter does not reach an import, a patch or the API, and a group account otherwise fails far later at posting time.

Purchase Order

build_purchase_order resolves the account once and every line carries it.

setting expense account on the saved line
off Cost of Goods Sold - _TC7 — whatever ERPNext chooses
on Expenses Included In Asset Valuation - _TC7 — the WIP account

With the setting off the field is left unset, which is indistinguishable from how it behaved before: ERPNext fills it from the item and company defaults.

Purchase Invoice

expense_account already copies from order to invoice — frappe's mapper copies same-named fields — but an invoice raised on its own has none, and any invoice can be edited afterwards. A line that slipped onto another account would never be released.

A before_validate hook holds the line on WIP. Verified: an invoice raised on its own, with its line starting on another account, was moved onto WIP.

Only a configured port expense item on a container line is touched. A container can be tagged on any purchase, and the rest of that invoice is ERPNext's to account for — a stock item under perpetual inventory above all, whose Stock Received But Not Billed account must not be overwritten. Running before validate also leaves ERPNext's own assignments intact and lets against_expense_account name what the invoice actually posts to.

Multi-company

An account belongs to one company and the settings hold one account. Another company's documents are therefore left alone rather than made unsavable — they keep ERPNext's default. The exception is where the ICD is deliberately creating a port expense order: there a configured account that cannot serve the company is reported, because silence would send the expense to the default and it would never be released.

If expenses are genuinely booked in more than one company, the accounts need to be held per company. Worth settling alongside the COGS release.

Worth knowing before this is enabled

cogs_account is captured but nothing reads it yet. Until the release is built, ticking this accumulates a WIP balance that nothing clears.

Testing

icd_tz/tests/test_expense_wip_account.py — the account chosen and left alone by the setting; an order refused when the configured account cannot serve its company while an incidental document is left alone; the settings refusing a missing, group, repeated or cross-company account; an order line carrying the account and carrying none when off; and an invoice holding only a configured expense line on a container, leaving a non-expense item, a line with no container, and everything else alone.

Also checked end to end on a saved Purchase Order and an invoice, not only in memory.

Full suite: 310 passing. pre-commit run --all-files and ruff check green.

An Expense Accounting section on the Expenses tab: a checkbox, and the WIP and
COGS accounts, which are only shown and only mandatory once it is ticked.

The COGS account is held for releasing the expense when the container is
invoiced, which is not built yet, so ticking this accumulates a WIP balance
nothing clears.

(cherry picked from commit 5f50a22)
mandatory_depends_on and the form filters reach the form only, not an import, a
patch or the API. A group account, or an account of another company, fails far
later at posting time, and two identical accounts would release an expense by
posting it to itself.

(cherry picked from commit ae9a043)
Both account fields list the postable accounts of the user company, so a group
account or another company's account is not offered in the first place.

(cherry picked from commit 2d0cb25)
Each order line carries the WIP account while the ICD books expenses there. It
is left unset otherwise, so ERPNext keeps choosing the account from the item and
company defaults exactly as before.

An account belongs to one company and the settings hold one account, so another
company is left alone rather than made unsavable. Where the ICD is deliberately
creating a port expense order, a configured account that cannot serve the
company is said out loud instead, since silence would send the expense back to
the default and it would never be released.

(cherry picked from commit 1caf6ec)
The mapper copies the account from the order the invoice was made from, but an
invoice raised on its own has none and any invoice can be edited afterwards. A
line that slipped onto another account would never be released to cost of goods
sold.

Only a configured port expense item on a container line is held. A container can
be tagged on any purchase, and the rest of the invoice is ERPNext's to account
for, a stock item under perpetual inventory above all. It runs before validate
so ERPNext still has its say on every other line.

(cherry picked from commit 4b36991)
Before validate rather than after, so ERPNext still assigns the accounts it owns
and the against expense account it derives names what the invoice posts to.

(cherry picked from commit 484fc9d)
Covers the account chosen and left alone by the setting, an order refused when
the configured account cannot serve its company while an incidental document is
left alone, the settings refusing a missing, group, repeated or cross company
account, and an invoice holding only a configured expense line on a container.

(cherry picked from commit 38d662b)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant