Commit Graph

419 Commits

Author SHA1 Message Date
Ali ae1d0a9782 fix(master-data): never let Item master-data abort migrate
On a bare/half-provisioned site (e.g. a distrobuilder base image where standard
UOMs like 'Litre' are not loaded yet), Item insert raised LinkValidationError
and the unhandled exception aborted the whole `bench migrate`, failing the
image build.

Isolate each Item insert in a savepoint and catch failures: roll back just that
item, log a visible SKIPPED line, and continue. Items are only inserted when
missing, so a later migrate on a fully provisioned site still creates them.
Adds a 'failed' counter to the summary line.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 15:28:55 +00:00
Ali 82ae160123 chore(i18n): stop tracking generated locale/*.po copies
az.po/ru.po are regenerated (overwritten) by the az_locale app on every
`bench migrate` via setup_locale, so tracking them dirtied the working tree and
blocked `git pull` ("local changes would be overwritten by merge"). Untrack them
and gitignore locale/*.po; main.pot (extraction template) stays tracked, and the
masters remain the source of truth in the az_locale repo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 10:38:12 +00:00
Ali e4ac3e328f feat(master-data): resolve Item Group root for groups too, and log results visibly
sync_item_groups now resolves the real tree root once and remaps the shipped
"All Item Groups" parent to it (via a new transform hook on sync_master_data),
so on localized sites (e.g. root "Bütün Element Qrupları") the tax groups nest
under the actual root instead of being orphaned.

Both sync_item_groups and sync_items now print explicit, always-visible lines
(resolved root, per-item creation, and a created/existed/skipped summary) so a
migrate run clearly shows whether the groups and items were created.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 09:52:48 +00:00
Ali 9b1f2b79e0 fix(master-data): import shipped Items ourselves, resolving the Item Group root by name
fixtures/item.json was imported blindly by Frappe's import_fixtures on every
migrate and hard-failed (skipping the whole file) on sites whose Item Group
tree root is not literally "All Item Groups" — e.g. the Azerbaijani-localized
"Bütün Element Qrupları" — so the fuel Items never got created and the reports
relying on them came up empty.

Move the file to master_data/ and import it via a new sync_items() in
after_migrate (after sync_item_groups). It resolves the root Item Group by
either known name (falling back to the structural root), remaps the shipped
root reference to whatever this site calls its root, and inserts only missing
items — existing items and their report data are never touched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 09:43:43 +00:00
Ali 5c96fe7836 push from mvp 2026-07-21 09:42:47 +00:00
Ali d81eb4eee9 fix(edv): compute 319.1-4 ƏDV at per-row rates to match e-taxes
Rows 319.1-319.4 (VAT refund on returned goods, Art. 165.5/165.6) have
their ƏDV auto-computed on the e-taxes portal from the paid amount at
distinct rates driven by the cash/non-cash cashback rules:
  319.1 = 18%, 319.2 = 17.1%, 319.3 = 14.85%, 319.4 = 12.6%
Parent 319 = Σ(319.1..319.4). Previously ours left the child ƏDV as manual
input, so 319 summed to 0 unless the accountant typed each cell.

Compute them in the controller and mark the cells read_only, mirroring the
grey (computed) cells on the site. Verified headless: paid 100/500/200/300
-> 18/85.5/29.7/37.8, 319 = 171.
2026-07-16 11:56:12 +00:00
Ali d11e32ac65 fix(vat): don't enter fill mode unless call completion is observable
Guard the frappe.call wrapper: only bump the pending counter / set fill mode when
the call actually returns a thenable. Otherwise a non-promise return would leave
fill mode stuck on and silently stop every recompute.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 15:57:56 +00:00
Ali 9e8732a676 perf(vat): drive the post-fill recompute off actual call completion, no timer
Instead of waiting a fixed delay after selecting dövr, wrap frappe.call to track
the fill calls (populate_vat_tables + formula_editor run_reports_batch): suppress
the per-write recompute while any is in flight and run it exactly once the moment
the last one resolves (deferred a tick so the apply lands first). User edits
recompute instantly. Robust regardless of how long the reports take.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 15:52:37 +00:00
Ali f45414e5ac perf(vat): make user-edit recompute instant; trim the post-fill wait
Drop the 300ms debounce on manual edits (the formula_editor storm it guarded
against is already handled by fill mode), so dependent cells update immediately.
Shorten the post-report-fill settle from 3s to 400ms — the one delay that must
stay, since recomputing during the hundreds-of-cells fill would freeze the form.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 15:33:18 +00:00
Ali 26e72c253e fix(vat): run the recompute once after the report-fill (dövr) settles
Selecting dövr triggers populate_vat_tables + formula_editor, which fill leaf
cells from reports but do not roll parents up (e.g. 301.1 = Σ 301.1.1..4). The
per-write recompute is suppressed during that storm; previously nothing ran
afterwards, so 301.1 (and other roll-ups / appendix→turnover passthrough) stayed
stale. Now "fill mode" runs the recompute ONCE, 3s after the fill settles.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 15:25:06 +00:00
Ali 67f258daf0 push from mvp 2026-07-15 15:14:46 +00:00
Ali ec3614a7bd refactor(vat): keep only calculations in doctype JS; row-creation stays Client Scripts
Revert the over-eager move: the default-row-creation scripts belong in Client
Scripts (restored to the fixture and DB). Only the column calculations
(VERIFIED CALC) stay inlined in declaration_of_value_added_tax.js. The
remove-client-script patch now targets just the calc script.

Result: rows are created once by the Client Scripts, calculations run from the
doctype JS; Formula Editor script unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 15:09:15 +00:00
Ali 619e7936f2 refactor(vat): move VAT calc + row-creation from Client Scripts into doctype JS
All computed-cell logic and default-row creation for "Declaration of value
added tax" now lives in declaration_of_value_added_tax.js (version-controlled)
instead of DB Client Scripts, so it no longer depends on fixture export/import
and can't be dropped by a stale-DB re-export.

- inline the VERIFIED CALC recompute + the 11 row-creating scripts (IIFE-wrapped)
- remove those 12 entries from the client_script.json fixture
- patch remove_vat_calc_client_scripts deletes them from existing DBs on migrate
  (fixture removal alone is upsert-only and would otherwise leave duplicates)

The Formula Editor script stays a Client Script (it is tool-generated).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 15:04:14 +00:00
Ali 32000dc718 fix(vat): restore VERIFIED CALC client script dropped by fixture re-export
The other machine re-exported client_script.json from its own DB (which
lacked this DB-only script) and the pull dropped it from the fixture.
Re-add only that entry (latest fill-mode version); no other script touched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 14:08:31 +00:00
Ali 85db866f92 push from mvp 2026-07-15 14:03:04 +00:00
Ali 1cfceb92a8 feat(vat): live column calculations + read-only for ƏDV declaration
Add a Client Script (fixture) that computes all derived cells of
"Declaration of value added tax" on manual edit, matching the e-taxes
form (verified against the live site):
- appendix roll-ups (parent = Σ children) for Əlavə 3/4/5 and debitor 307
- passthrough appendices → turnover (301.1←Əlavə3, 302←Əlavə4,
  303←Əlavə5, 301-2←agro sold); agro purchased = Σ Hissə 1
- rates (18/20%, Art.174.5 50% relief), %-share lines, clamps, 326/327 net
- Əlavə 1 / Əlavə 8 page totals

Mark every computed cell read-only (per-column, or per-row via
read_only_depends_on). Guard recompute against the formula_editor
report-fill storm ("fill mode") so selecting dövr no longer hangs.

Additive — existing scripts (formula_editor, row-creators) untouched.
Docs: edv_butun_dusturlar.md, edv_formulas.xlsx (formula reference).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 13:53:20 +00:00
Ali 770241a30e fix(tax-article): match 328-330 to the e-taxes wording
The accountant reads the Tax Article picker side by side with the cabinet, so
the two have to read identically. Three of the nine Əlavə 3.2 articles drifted:
328 carried a double space and the grammatically-tidied "Respublikasının" where
the form writes "Respublikasınını", 329 a double space, 330 spelled out "Vergi
Məcəlləsinin" where the form abbreviates to "VM-nin".

331 and 336 are left alone — Əlavə 3.2 is the reference wording for those two
and the articles already match it.

The nine already existed and were already mapped in the VAT allocation report;
only the wording moved. Tax Article is autoname:Prompt, so name is a stored id
rather than a slug of article_name — re-wording article_name alone would leave
the old text showing in every link picker. The name has to move too, and a moved
name is a different document, hence the delete-and-reinsert patch rather than a
rename_doc walk across a NestedSet. Nothing referenced the three (all ten Tax
Article link fields checked, zero rows).

The report's mapping keys move in lockstep. They are matched by exact string
against article_name, so a key left behind would not raise — it would silently
zero its column on a filed return. All 115 keys verified to resolve against the
live table afterwards.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 11:44:50 +00:00
Ali e8354516fb chore(i18n): sync az translations
Picked up by bench migrate — fills in msgstr values that were previously
empty. Unrelated to the tax-article cleanup; committed separately to keep
that change reviewable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 10:33:04 +00:00
Ali 294fcaf773 fix(tax-article): drop the aggregate VAT articles from the picker
301.1 (CƏMİ) and its two subtotals, the umbrella 165.1.3 article that sits
above the goods/services export ones, 308, 319.2 and 319.3 are ФНО summary
lines, not leaf articles an accountant should tag an invoice with. Tagging a
line with the umbrella 165.1.3 landed it in Əlavə 4 row 302.3 but not in the
302.3.1/302.3.2 breakdown underneath, so the total stopped reconciling with
its own parts.

Eight rows, not seven: 165.5 (NAĞD) shipped twice — Frappe truncates name at
140 chars, and the fixture carried both the full and the ellipsised spelling.
That was the only duplicate in the whole table.

Removing them from the fixture is not enough on its own: sync_fixtures imports
every json under fixtures/ regardless of the fixtures hook, and import_doc only
ever inserts or updates. Hence the patch as well — and it has to land before
sync_fixtures runs, which post_model_sync does.

No data referenced any of the eight (checked all ten Tax Article link fields,
including the ones jey_erp owns), so nothing on an invoice or asset moves.

Known follow-up, left deliberately: Əlavə 4 row 4 still resolves
report(VM-165.1.3) / report(VM-165.1.3-ödəniş), whose report columns are gone,
so it now yields 0 rather than 302.3.1 + 302.3.2. Handed to the accountant to
decide between summing the two survivors and filling the row by hand.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 10:33:04 +00:00
Ali 9d485c7ad4 feat(formulas): batch report resolution in a taxes_az-owned runtime
Selecting a period on a declaration fired one HTTP request per report reference
— 217 on a VAT return — and each one re-executed an entire Script Report just to
read a single column. Those 217 requests only ever ran 4 distinct reports: 120 of
VAT's 127 report fields read different columns out of the same report with the
same filters.

run_reports_batch groups the references by (report, filters) and executes each
report once, slicing every requested column out of the one result. The extraction
rule (take the report's total row, else sum every row) is ported verbatim — it
decides the figures that end up on a filed tax return.

The runtime lives here rather than in formula_editor because that app is a
design-time tool that gets removed from production machines; generated scripts no
longer reference it at all.

Errors are now surfaced instead of swallowed. A failed report used to yield 0 for
every field that asked for it, so a user without report permission got a
plausible-looking, fully-zeroed declaration and no hint anything was wrong.
Failing reports now contribute no values, the affected formulas are skipped rather
than zeroed, and the user is told which report failed and why.

Also fixes a Frappe core bug that threw on every declaration: Frappe writes the
active tab's fieldname into the URL hash, the URL API percent-encodes our
Azerbaijani fieldnames, and form.js then feeds that hash to jQuery as a CSS
selector.

Land tax and Property tax pointed js_parent_subtab at a parent tab that does not
exist in those doctypes, so their Əlavə tabs never nested.

VAT, one period change: 217 HTTP requests -> 1, 236 refresh_field -> 11, 4.5s -> 1.5s.
Verified identical output across all 426 formulas and all 337 report fields.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 12:28:43 +00:00
Ali e637a85a13 push from mvp 2026-07-13 09:59:03 +00:00
Ali ae2cc33966 fix(report): limit purchase invoice info to update-stock invoices
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 10:27:12 +00:00
Ali f333fa8826 fix(vat): widen counterparty name fields to Small Text
Data is varchar(140) and Frappe raises CharacterLengthExceededError rather
than truncating, so a long organisation name would block saving the
declaration. vöenadı is the tightest: it concatenates VÖEN + " / " + name,
leaving 127 characters for the name, and the longest supplier on record
already runs to 93.

Widen the four counterparty name fields to Small Text (TEXT column):
  - vöenadı                          (Əlavə 1 yeni)
  - sertifikattəqdimolunanşəxsinadı  (Əlavə 8 Tablo 1 and Tablo 2)
  - adı                              (Əlavə 2 Hissə 1)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 09:51:14 +00:00
Ali 6ee626dbe1 push from mvp 2026-07-10 09:42:57 +00:00
Ali 4e4a6517c9 feat(vat): auto-fill new Əlavə 1 tables and page totals
Fill the second Əlavə 1 tab (əlavə1_yeni) from the Purchase VAT offset
report (Cədvəl 22), whose columns map one-to-one onto the table and whose
vat_offset_line_code shares the 308/314/316 options of sətirkodu. The
report gained a posting_date key so the tarix column can be filled; its
visible columns are unchanged.

Also fill three summary targets that were left to manual entry:
  - əlavə_1_2      totals over Əlavə 1
  - əlavə1_2_yeni  totals per line code
  - sertifikat...səhifəsicəmi  page total of Əlavə 8 Tablo 2

The two summary tables already carry rows created by a client script, so
they are filled in place — fill_first_row and fill_rows_by_code never add
or remove rows. Rows are matched on the leading line code because the
stored sətirkodu carries a long description after it.

Widen the Int money fields to Float: paid VAT is proportional and was
truncating (106.78 -> 107). Invoice number becomes Data, matching the
report where it is a free-form string.

Note: the generated Formula Editor client script still writes əlavə_1_2
and əlavə1_2_yeni row 0 from report() grand totals. Those 6 formula blocks
are to be removed by hand; the Formula Editor record itself no longer
defines them, so they will not be regenerated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 09:39:00 +00:00
Ali 1aba387f87 fix(vat): map Əlavə 8 rows to real child fieldnames
populate_vat_tables built Əlavə 8 Tablo 2 rows with keys that do not exist
on "Declaration of value added tax Elave 8 2ci" (şəxsinadı, şəxsinvöeni,
sertifikatınseriyası, nsi, xidmətindəyəri). set_table() assigned them onto
the child object without error, so rows were created empty.

Map to the actual fieldnames. The doctype stores series and number in a
single "Sertifikatın seriya / nömrəsi" field, so cert_no is written whole
and _split_cert_no is dropped.

Also widen the two Int fields: the value column truncated decimals, and
VÖEN is an identifier that must not lose leading zeros — both now match
Elave 8 1ci.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 13:39:08 +00:00
Ali afd65ce302 fix(fno): run declaration calculations once per Dövr pick
Picking a period fired every recalculation twice. `frm.set_value()` schedules the
field's handlers asynchronously (frappe.model.set_value -> run_serially), so by
the time the first trigger ran, both `ay`/`rüb` and `il` were already set in
frm.doc — and each field's handler then did a full pass. In VAT that also meant
`populate_vat_tables` was called twice per pick.

Five declarations were affected, all of them via Formula_Editor_Script_* which
bind a handler to every field a formula depends on: Declaration of value added
tax, Declaration of mining tax, Road tax 2, Tax return withheld at source of
payment, Single declaration related to salaried and non-salaried work.

Those scripts are generated, so they can't be patched — the fix has to live in
the picker. Instead of two set_value() calls, write the fields directly, do what
set_value would have done (refresh_field, refresh_dependency, dirty) and fire the
handlers exactly once.

Firing only `il` is safe: for every affected declaration the period handler and
the `il` handler have byte-identical bodies once the trigger-field argument is
normalized (VAT 2750 lines each, single declaration 1202, mining tax 484, road
tax 2 128, tax withheld 4 — differing only in a comment), and
calculate_table_row_field() never reads its triggerField argument. A runtime
fallback triggers the period field instead when no `il` handler is bound.

Note this cannot be done with set_value("il", year) alone: frappe.model.set_value
skips both the trigger and dirty() when the value is unchanged, so changing only
the month within the same year would silently recalculate nothing.

Verified headless: one call per pick on both VAT (month) and Single declaration
(quarter), including a second pick within the same year.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 12:10:08 +00:00
Ali fd389d7b37 feat(fno): unified Dövr period picker across all declarations
Every declaration used to expose its reporting period as raw `ay` (month or
quarter Select), `il` (Int year) and/or `rüb` (quarter Select) fields, scattered
across the form. This adds a single `Dövr` field to all 23 declarations that
have a period, and hides the legacy fields.

Clicking `Dövr` opens an inline air-datepicker popup (the same widget Frappe
uses for Date fields, not a modal), restricted per declaration:

  month       -> month grid with Azerbaijani month names + year nav
  quarter_*   -> 2x2 grid of "1. Rüb".."4. Rüb"
  annual      -> year grid

The selection is written back into the hidden `ay`/`il`/`rüb` in their exact
original formats, so all downstream code (VAT appendix auto-fill, property tax
asset loading, single declaration, reports) keeps working untouched.

`dövr` deliberately carries no `read_only` docfield flag: with the site setting
`hide_empty_read_only_fields` enabled, Frappe hides empty read-only fields, which
made the picker invisible (and unopenable) on new documents. Keyboard input is
blocked from JS instead.

Also restores `ay` + `il` (hidden) on Declaration of value added tax: they were
deleted upstream while declaration_of_value_added_tax.{js,py} still read them,
which had silently broken the Əlavə auto-fill from reports.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 11:35:33 +00:00
Ali 682902a828 chore(property-tax): remove Property Tax Gov pilot doctypes
The Property Tax Gov family (parent + 10 child tables) was a duplicate of
Property tax return, used as a pilot for page-based declaration calc. It is
no longer needed; the original Property tax return is untouched and remains
the only property-tax declaration.

Both tables were empty (0 documents). `bench migrate` drops the orphaned
DocTypes; the empty `tabProperty Tax Gov*` tables were dropped manually since
migrate leaves them behind.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 11:35:18 +00:00
Ali 94c25e19e2 push from mvp 2026-07-09 11:02:04 +00:00
Ali 7cfae04159 feat(vat): Certificate VAT Report (Cədvəl 23) + auto-fill Əlavə 8
- New Script Report "Certificate VAT Report": one row per sales-invoice item
  certificate (cert no, VÖEN, taxpayer, value), full item amount per certificate
  with no splitting; filters company + date range, submitted invoices only.
- Auto-fill VAT declaration Əlavə 8 Table 2 (müəssisə_malın_dəyəri) from that
  report inside populate_vat_tables; split cert_no into series (letters, max 3)
  and number (digits).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 16:46:54 +00:00
Ali 71d9e303ce feat(report): add Purchase VAT offset report (Cədvəl 22)
Lists submitted Purchase Invoices flagged for VAT offset that have a VAT
offset line code: line code, VOEN/Name, e-taxes invoice series/number,
total, VAT (only the 521.3 ƏDV tax account), paid total (Grand Total -
Outstanding, Purchase Register logic) and proportional paid VAT.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 12:56:25 +00:00
Ali 93d7be9ee1 fix(vat): fill YGB date in Əlavə 1 (change field to Date)
ygbnintarixi was a Float field, so the YGB date could not be stored.
Change it to Date and map posting_date from the YGB report.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 14:56:50 +00:00
Ali d6488a68cf feat(vat): auto-fill VAT declaration appendices from reports
On selecting İl + Ay, the Declaration of value added tax fills three
appendices from the source reports' get_data:
- Əlavə 1            <- Purchase YGB VAT report
- Əlavə 2 Hissə 1    <- Purchase invoice info report (act_type mapped to AZ)
- Əlavə 2 Hissə 2    <- Agricultural goods stock report

Adds a whitelisted populate_vat_tables method + form trigger, and a
company filter to the purchase invoice info report.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 11:10:30 +00:00
Ali 8a430ae1b0 push from mvp 2026-06-26 11:09:32 +00:00
Ali 260205fd95 Reapply "chore(report): remove temporary source-document tracing"
This reverts commit b70a5bb371.
2026-06-25 11:03:42 +00:00
Ali b70a5bb371 Revert "chore(report): remove temporary source-document tracing"
This reverts commit 7505f286bd.
2026-06-25 10:49:07 +00:00
Ali 7505f286bd chore(report): remove temporary source-document tracing
Drop the temporary Source type / Source document columns and the per-voucher
detail rows used for tracing; the report returns the single summary row again.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 10:13:45 +00:00
Ali 70cb6da547 fix(report): count sale price only for stock-moving agricultural sales
Sold in period (sale price) now sums Sales Invoice items only when the
sale produced an outgoing Stock Ledger entry, so it stays consistent with
COGS/closing. A sale that does not update stock contributes 0 instead of
inflating the sale figure with no matching cost.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 10:04:07 +00:00
Ali bd61196c84 feat(report): add temporary source-document rows to agricultural stock report
Append detail rows listing the Stock Ledger entries (with a clickable link
to each source voucher) and sale prices behind opening/purchased/COGS/
closing, for tracing. The summary stays the first row. Also decide stock
direction by stock_value_difference so opening-stock reconciliations
(actual_qty = 0) are counted correctly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 09:31:18 +00:00
Ali beec3f4416 fix(report): Purchase YGB VAT report only lists documents with YGB
Replace the purchase_type/agricultural_goods gate with a YGB-presence
filter: a Purchase Invoice is included only when at least one of its YGB
fields (ygb / line_code) is filled.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 09:19:10 +00:00
Ali 2d743f2878 refactor(report): source agricultural stock report from Stock Ledger
Rebuild the report on Stock Ledger Entry instead of custom FIFO over
invoices. Opening/closing balances and COGS now come from ERPNext's stock
valuation (which already applies the company's method and includes opening
stock entered via Stock Reconciliation); sale price still comes from Sales
Invoices. Filtering is now item-level (Item.agricultural_goods) and all
amounts are net of VAT, so the trade-markup VAT is not double-counted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 08:43:09 +00:00
Ali f906536b7f fix(report): cost-based opening balance in agricultural stock report
Opening balance now subtracts sales before the period at their COGS
(via the company's FIFO/Moving Average method) instead of at sale price.
This keeps it consistent with the cost-based closing balance, so each
period's opening equals the previous period's closing and the value can
no longer go negative while stock remains.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 17:27:26 +00:00
Ali 18e55b7421 feat(report): add trade markup and its VAT to agricultural stock report
Closing balance is now cost-based (opening + purchased - COGS) so the
trade-markup identity holds. Adds two columns:
- Trade markup on goods sold = sold(sale) - (opening + purchased - closing)
- VAT on trade markup = trade markup * 18%

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 16:52:23 +00:00
Ali 72f8292bfe feat(report): add Purchase YGB VAT report
Per-document purchase report (Cədvəl 21 — ƏDV - YGB hesabat). A Purchase
Invoice qualifies when submitted and at least one of purchase_type /
agricultural_goods is set (items are not filtered). Columns: document,
date, line code, YGB, amount without VAT (net_total) and VAT amount.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 15:24:41 +00:00
Ali 97b8b4ed56 feat(report): item-level agricultural filter, FIFO/Average COGS column
Agricultural goods stock report now filters by the per-item agricultural
flag (only agro items inside agro documents count) and grosses up rows to
include VAT. Adds a single "Sold in period (purchase price)" column whose
costing method follows the company's Default Stock Valuation Method
(Moving Average -> weighted average, otherwise FIFO).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 14:45:00 +00:00
Ali 878d2bac83 feat(report): add Agricultural goods stock report
Period-based VAT agricultural goods movement report (Cədvəl 18(1)):
opening balance, purchased (Purchase Invoices), sold (Sales Invoices)
and closing balance for agricultural_goods documents. Amounts incl. VAT
(grand_total); closing = opening + purchased - sold. Formula-editor
friendly with Company/From/To filters.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 10:52:28 +00:00
Ali cd34b4ca87 fix(report): filter Purchase invoice info report by agricultural_goods
Switch the inclusion condition from purchase_type=1 to the newly added
agricultural_goods=1 flag on Purchase Invoice.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 10:41:37 +00:00
Ali 5d2a218087 feat(report): add Purchase invoice info report
New Script Report grouping purchase-type Purchase Invoices by Act Type,
showing counterparty (ФИО/company/country), VOEN/FIN, and amount.
Includes a link column to the source Purchase Invoice and optional
date-range filters; formula-editor friendly (no total row).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 09:47:04 +00:00
Ali aaa352098c push from mvp 2026-06-23 09:09:16 +00:00