Commit Graph

244 Commits

Author SHA1 Message Date
Ali c737884fae chore: stop tracking auto-generated translation_markers.py
Regenerated on every migrate (after_migrate hook), so its churn caused
'local changes would be overwritten' on git pull across machines.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 10:53:30 +00:00
Ali 8db8ff60a4 feat(purchase): restore Agricultural Goods checkbox on Purchase Invoice
Re-add the `agricultural_goods` Check field (was a manual, unversioned DB
custom field) next to `purchase_type`. The two checkboxes are mutually
exclusive (new purchase_invoice.js clears the other when one is set).

Agricultural Goods now reveals the same fields as Purchase Type:
act_type / agricultural_country / ygb / line_code on the parent, plus
tax_type and purchase_tax_amount on the items — all depends_on widened to
`purchase_type || agricultural_goods`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 10:38:44 +00:00
Ali dea23e1597 fix(purchase): rename YQB field to YGB
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 11:44:55 +00:00
Ali 00a543a1f3 feat(purchase): YQB + Line Code fields gated by purchase_type
Add YQB (Int, length 12) and Line Code (Select 310/311/314/316) custom
fields after Country on Purchase Order and Purchase Invoice, both shown
only when purchase_type is checked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 11:43:44 +00:00
Ali 575e0829b3 feat(sales-invoice): multi presented-certificate per item row
Add a "Sertifikatın seriyə / nömrəsi" multi-select cell to Sales Invoice
Item, mirroring the existing tax-article cell:

- new child DocType "Sales Invoice Certificate" (parent_row + certificate
  -> E-Taxes Presented Certificate), parent table custom_item_certificates,
  per-row display field custom_certificates_display; reuses the existing
  custom_si_row_key to link rows to certificates.
- sales_invoice_certificates.js: clicking an empty cell first asks
  "0% dərəcəsi ilə ƏDV-yə cəlb olunma haqqında sertifikatlar var?" (yes ->
  open the Table MultiSelect picker, no -> open nothing); rows that already
  have certificates open the picker directly.
- server hook sync_item_certificates: stable row keys, drop orphans,
  refresh the display label (not bound to the tax template).
- patch add_certificates_to_si_grid_views: inject the new column into saved
  per-user grid layouts.
- lock the tax-article cell (read-only) for any line that has a certificate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 15:58:50 +00:00
Ali 4926d5c637 feat(etaxes): classification code + explanation custom fields; quieter asset-category logs
Add read-only custom fields etaxes_classification_code (Təsnifat Kodu)
and etaxes_explanation on Journal Entry for E-Taxes VAT imports, with
matching translation markers.

Move asset-category creation logging from frappe.log_error (which spammed
the Error Log DocType) to a file logger; keep log_error only for real
creation failures. Drop the manual frappe.db.commit inside the
Company.on_update path so the framework keeps the save atomic.

Reuse the realtime progress-bar race fix in currency_exchange_list.js.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 16:19:22 +00:00
Ali 4e8a151851 feat(setup): enable default settings checkboxes on wizard complete
Add set_default_settings() to the setup_wizard_complete hook so fresh
installs get sane defaults after company creation:
- Global Defaults.disable_rounded_total = 1
- Accounts Settings.delete_linked_ledger_entries = 1

Uses get_single().save() (not db.set_value) so each doctype's
on_update/validate side effects run — disable_rounded_total in particular
is read via frappe.db.get_default, only populated in on_update. Idempotent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 12:36:12 +00:00
Ali 41ebed0c79 chore(payment-entry): drop legacy payment_entry_mod.js; rename boot patch entry
Remove the unused Payment Entry doctype_js (payment_entry_mod.js) and its
hook. Rename the boot_session entrypoint to apply_vat_boot_patches and drop
the obsolete party_account_types injection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 11:34:25 +00:00
Ali 0f7a86ff2b feat(bank-integration): rename Bank Statement Importer to Bank Integration Profile; excel import, list views, cleanup patches
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 17:52:41 +00:00
Ali e4d63cdc74 push from mvp 2026-06-08 12:49:37 +00:00
Ali 94257e12e3 chore(fixtures): export print formats, regenerate translation markers
- print_format.json: export Sales Invoice / Delivery Note / Purchase Order
  and related Jinja print formats
- translation_markers.py: drop the old tax_article marker, add the deprecated
  single-field description marker

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 12:46:13 +00:00
Ali fe8d016148 feat(tax-article): extend tax_article coverage to new VAT-turnover groups
- Payment Entry: add the two new Əlavə 3 groups (ƏDV tutulan dövriyyə /
  ƏDV tutulan əməliyyat sayılmayan dövriyyə) to the tax_article link filter
- Sales Invoice: allow tax articles on ƏDV 18% lines, filtered to
  "ƏDV tutulan dövriyyə barədə məlumat" (301.x). ƏDV daxil 18% stays excluded
  (its prefix doesn't match "ƏDV 18%").

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 12:44:51 +00:00
Ali e4e5746301 docs(custom-fields): fix stale description on legacy tax_article
It is no longer auto-synced (mirror was removed); mark it deprecated and point
to the custom_item_tax_articles multi-select.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:35:41 +00:00
Ali 6f0758d90b refactor(patch): make Tax Articles grid-column injection additive
Insert custom_tax_articles_display into saved layouts independently instead of
replacing the legacy tax_article column (which is still used by other flows).
Position it after item_tax_template; leave legacy untouched. Idempotent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:30:48 +00:00
Ali 9c4e075527 fix(sales-invoice): inject Tax Articles column into saved grid layouts
Per-user grid layouts (GridView in __UserSettings) saved before this feature
list the legacy tax_article column but not custom_tax_articles_display. Frappe
renders the saved list verbatim and ignores the new in_list_view field, so the
'Tax Articles' cell never appears for those users until added via the grid gear
-- which is why it showed on a fresh user (Administrator) but not on machines
where the user had a saved layout.

Patch replaces the legacy tax_article entry with custom_tax_articles_display in
every saved Sales Invoice Item layout that lacks it. Idempotent; runs on migrate
so every machine converges automatically.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:24:27 +00:00
Ali 647f940328 fix(sales-invoice): force-unhide Tax Articles grid column across sites
create_custom_fields() applies only the properties present in each field
def (cf.update(df)). The custom_tax_articles_display def listed
in_list_view=1 but omitted 'hidden', so a site where the field had
hidden=1 would never converge on migrate -> the column showed on one
machine and stayed hidden on another. Make hidden=0 explicit so migrate
force-applies it everywhere.

Verified: forcing hidden=1 then running create_custom_fields() now resets
it to hidden=0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:09:55 +00:00
Ali 3a87334f3c chore(sales-invoice): clarify tax-article comments (drop stale TEST/mirror notes)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 13:57:42 +00:00
Ali ea8818d07f feat(sales-invoice): multiple Tax Articles per item row + Payment Entry multi-select
Per-row multi-select of Tax Article records on Sales Invoice item rows
(VAT 0% / VAT-exempt, codes 302.x/303.x) via a parent child table linked
by a stable row key; Tax Article multi-select on Payment Entry. Legacy
single tax_article demoted to hidden/read-only.

- custom_fields.py: new fields + section; legacy tax_article -> primary
- custom/sales_invoice_tax_articles.py: validate hook (row keys + display)
- doctype/{sales_invoice,payment_entry}_tax_article: child tables (0%/exempt)
- public/js: Table MultiSelect dialog + vat_calculator SI refresh-chain fix
- patches: backfill row keys + historic single-article values

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 12:25:24 +00:00
Ali 4c1f582db9 feat(in_words): native Azerbaijani format for in_words / base_in_words
Frappe's money_in_words() produces "AZN Dörd Min Doqquz Yüz yalnız." for
1234.00 AZN — grammatically gettext-friendly but not how Azerbaijani
documents actually look. Native convention is "Min iki yüz otuz dörd
manat 56 qəpik": sentence-case number, lowercase currency word, fraction
as digits, no "only" suffix.

format_in_words_az is hooked as a validate doc_event on every doctype
that carries in_words / base_in_words (11 in total: Sales/Purchase Order,
Sales/Purchase Invoice, Quotation, Delivery Note, etc.). Runs after the
controller's own set_total_in_words has populated the field, then
overwrites it. No-op for any language other than az.

Uses grand_total (not rounded_total) to preserve qəpik precision, since
ERPNext's Rounded Total can round to whole manat per the Currency's
rounding_method.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 16:47:23 +00:00
Ali 30c46e2feb added new translations for custom fields 2026-05-25 13:32:29 +00:00
Ali e88ab56df0 chore(bank-integration): remove completed standard_field code migration
migrate_standard_field_codes_to_labels() rewrote Bank Integration Excel Column
Mapping.standard_field from old machine codes to human-readable labels — a
one-time compatibility fix after the storage format changed. The migration has
done its job: the preset fixture already ships labels, and new sites create
mappings via the UI dropdown (labels from the start), so old codes can only
exist on databases that predate the format change. Drop the function, its
code->label map, and the after_migrate call.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 17:06:09 +00:00
Ali 3e2f9d7c66 chore(custom-fields): remove dead 'Setting up VAT calculation hooks' print
The last line of create_custom_fields() was a print() with no code under it —
a leftover heading for setup that was never written. It only produced a
misleading line in the migrate log; VAT calculation is actually wired up by
patch_sales_documents(), an unrelated function.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 16:58:05 +00:00
Ali 89bb5dd1f0 fix(bt-import): swap show_progress for freeze to avoid stuck backdrop
Importing Bank Transactions via "Import From → Load from Excel" left
the screen darkened and unresponsive after the job finished. Root cause
was the show_progress Bootstrap modal: closing it from JS (we had a
hand-rolled _closeProgress that called .modal('hide').remove() and then
removed .modal-backdrop manually) interrupted Bootstrap's hide animation
mid-flight, leaving the dimmed overlay stuck. Opening a msgprint right
after made it worse — the two modals fought over the same backdrop
node.

Switched to frappe.dom.freeze / unfreeze: a single full-page overlay
managed by Frappe core, with no Bootstrap modal/backdrop juggling. The
freeze message is updated in place as progress events arrive (writes
to #freeze .freeze-message directly to avoid stacking the freeze
counter, which would break unfreeze pairing). unfreeze on completion
cleans up reliably, so the msgprint that opens immediately after lands
on a clean page.

Removed the now-unused _closeProgress helper.
2026-05-18 14:34:54 +00:00
Ali a7686eadc6 refactor: drop unused Account Mappings from Bank Statement Importer
Bank Account is chosen explicitly in the Import dialog before the
parser runs, so the IBAN→Bank Account child table never carried weight
in this flow. Unlike kapital_bank — where the API hands over raw IBANs
and needs a lookup table — jey_erp's Excel import fixes one Bank
Account per file from the dialog and applies it to every row.

Removed surface:
- Bank Statement Importer JSON: Account Mappings subtab (Mappings group)
  and Accounts subtab (Data group), plus their child table field
- Bank Integration Account Mapping DocType folder
- matching.py: match_similar_accounts
- creation.py: create_unmapped_accounts
- import_api.py: "accounts" branch of get_bi_reference_data_list
- bank_statement_importer.js: Match/Create buttons in the Accounts
  group, _bi_render_accounts renderer, and its load_tab line

Added post_model_sync patch drop_bank_integration_account_mapping that
deletes the DocType and its `tab<Name>` table from existing databases.
2026-05-18 14:26:22 +00:00
Ali 37dbc2be48 fix(create-accounts): set is_company_account=1 on auto-created Bank Accounts
Bank Accounts created via the "Create Bank Accounts" button represent
the user's own accounts at the bank — not counterparty accounts — so
they need is_company_account=1. Without it, ERPNext treats them as
external and they don't appear in Bank Reconciliation Tool or as
selectable paid_from/paid_to in Payment Entry / Journal Entry.
2026-05-18 14:17:33 +00:00
Ali c198574f6c fix(cascade-delete): override frm.savetrash so stock confirm never runs
Previous approach replaced the Menu Delete item's jQuery click handler,
but Frappe wires the same item through its own event chain that bypassed
.off('click') — both our cascade dialog AND the stock "Permanently
delete X?" prompt fired in sequence.

Form's Delete menu item ends up calling frm.savetrash(); overriding that
method directly is the single point that intercepts every code path that
reaches it. Removed the brittle DOM-walking wireMenuItem helper.
2026-05-18 14:00:54 +00:00
Ali 31d93fb887 feat(bank-statement-importer): cascade delete with confirmation
Stock delete on Bank Statement Importer hits Frappe's link-check
(registry rows + Bank Account dynamic-link) and refuses to proceed,
leaving users unable to remove an importer they no longer need without
hand-cleaning every dependent row.

New flow:
- cascade_delete.py adds two whitelisted endpoints: get_dependents
  (counts) and cascade_delete (unlink Bank Accounts → delete Customer/
  Supplier/Purpose registry rows → delete the importer)
- bank_statement_importer.js overrides the Menu → Delete action: shows
  a confirm dialog listing exactly how many records will be deleted vs
  just unlinked, with a red primary button to drive the choice home.
  After success the user is sent to the list view.

Bank Accounts are intentionally unlinked rather than deleted — they hold
business data (Bank Transactions, reconciliations) that has nothing to
do with the importer being removed.
2026-05-18 13:50:03 +00:00
Ali 5bff95501f refactor(bank-statement-importer): drop redundant Default Company field
System is single-company; Default Company on Bank Statement Importer
duplicated what ERPNext already exposes via Global Defaults. Removed
the field and replaced bi.default_company with erpnext.get_default_company()
at the two usage sites (Bank Account creation, Bank Transaction bulk
import). Existing column on tabBank Statement Importer is left in place
— Frappe just ignores it.
2026-05-18 13:40:53 +00:00
Ali 1492573fac revert: drop adaptive workflow guide
The 4-step workflow stepper added in 83a2cb6 was experimental and
turned out to be visual noise on top of the form. Reverting back to
the tab layout speaking for itself.
2026-05-18 13:28:22 +00:00
Ali 83a2cb6259 feat(bank-statement-importer): adaptive workflow guide above tabs
Users had no way to know the setup is ordered — they would land on
Match/Create buttons before the registries had anything to match, or
go to Load Data before configuring the file format.

A small four-step indicator now sits at the top of the form, with the
current step highlighted and a one-line hint pointing at the next
action. State is read off the form itself (column_mappings filled? any
mapping tables populated?), so the guide moves forward as the user
makes progress and disappears once setup is done as much as the form
can tell.

The four steps:
  1. Configure format    → File Format tab + sample file
  2. Load registries     → Load Data button
  3. Match & Create      → Data tab + Match/Create toolbar buttons
  4. Import statements   → Bank Transaction list → Import From
2026-05-18 13:20:57 +00:00
Ali a27e9b08f5 fix(file-format): offer to re-run auto-detect on sample re-upload
Previously a re-upload (clear → re-attach) just refreshed the Excel
Column dropdown and silently kept the existing mapping rows — pointing
the user at the new file but leaving the table tied to the old one. Now
the form asks before overwriting: empty table still auto-detects
silently, populated table prompts with a Confirm dialog before clearing
and re-running.
2026-05-18 13:10:22 +00:00
Ali d87da25417 fix(bank-statement-importer): drop premature File Format validation
The validate() hook threw "Amount Mode 'X' requires these Standard
Fields: Reference Number, Debit, Credit" as soon as the user uploaded a
sample file — auto-detect made the form dirty, and any later save
ran into a setup the user hadn't finished yet. The dialog interrupted
the very flow it was supposed to support.

Removed the entire _validate_file_format hook. The same check already
lives in excel_parser.parse_excel — it fires only when the user actually
tries to import a statement, which is the right moment to demand that
the format be complete. Saving a half-configured form is fine: users
can come back and finish later.
2026-05-18 13:03:13 +00:00
Ali 0e52ec16b6 fix(column-mappings): make Standard Field optional
Auto-detect inserts a row for every header found in the sample file,
including ones it couldn't match against the synonym list — those rows
went in with an empty standard_field. With Standard Field marked
reqd=1, any subsequent action that triggered a save (Match accounts,
Create customers, etc. routed through the "save first?" prompt) failed
with "Mandatory fields required in table Column Mappings, Row N".

The reqd was already redundant: excel_parser skips column_mappings rows
without a standard_field, and Bank Statement Importer.validate enforces
the actual required-minimum set (Date / Reference + Debit/Credit or
Amount) at the parent level based on amount_mode. Dropping reqd from
the child lets unmapped rows coexist in the table for visibility.
2026-05-18 12:59:55 +00:00
Ali ded4946c75 refactor(synonyms): move synonym data to JSON, keep matcher in Python
The header → Standard Field dictionary is data, not code, so it now
lives in header_synonyms.json next to its loader. Editing a synonym list
no longer requires touching Python — open the JSON, append a string,
done.

header_synonyms.py is now a thin loader (reads the JSON once at import
time) plus the matcher and the Azərbaycan→Latin transliteration table,
which stay in Python because they're behaviour, not data.
2026-05-18 12:54:25 +00:00
Ali 357305a687 refactor(excel-parser): extract header synonyms to its own module
The _HEADER_SYNONYMS dict, the Azərbaycan-to-Latin translation table, and
the matcher helpers were sitting in the middle of excel_parser.py making
the file harder to scan. Moved them to a dedicated header_synonyms.py
with a docstring explaining how to extend it.

Public API of the new module is just guess_standard_field(header) and
HEADER_SYNONYMS — that's the surface excel_parser actually uses.
2026-05-18 12:51:55 +00:00
Ali 381aebdbdb fix(file-format): auto-detect columns on sample upload, quiet alerts
Two changes that drop the manual step from the column-mapping setup:

- Auto-detect now runs implicitly when the user attaches a Sample Excel
  File. The Auto-detect Columns Button field is removed (Preview Sample
  stays — it answers a different question). Auto-detect only fires when
  the Column Mappings table is empty; a user-edited table is never
  overwritten silently.
- Replaced the modal "Auto-detect Complete" / "Sample File Error" /
  "Empty Header Row" msgprints with small bottom-right show_alert
  toasts. The result is one line — "Auto-mapped 9 of 11 columns" —
  with green/orange/red indicator instead of a full-screen dialog.

The synonym dictionary used by detection lives in code at
jey_erp/bank_integration/excel_parser.py (_HEADER_SYNONYMS).
2026-05-18 12:50:31 +00:00
Ali 54ac6288fd fix(file-format): move Preview/Auto-detect buttons into the tab body
The two helpers used to live in the form toolbar under a 'File Format'
group, which added noise to the already busy header (Match/Create
buttons for accounts/customers/suppliers/purposes plus Load Data are
also there).

They are now native Button fields inside the File Format tab, sitting in
a two-column row directly under the Sample Excel File attach widget:

  [ Sample Excel File: ... ]
  [ Preview Sample ]   [ Auto-detect Columns ]
  [ Format / Column Mappings sections ]

Both buttons are gated by depends_on=sample_file, so they only appear
when there's actually a file to operate on — same gating as before, just
contextually placed next to the upload instead of in the global toolbar.
2026-05-18 12:45:35 +00:00
Ali 7f24bd6b2a fix(file-format): hide rarely-used 'Use Currency From File' toggle
Multi-currency Bank Accounts (one account holding several currencies in
parallel) exist with some western banks like Revolut/Wise, but in AZ the
convention is one Bank Account per currency. The toggle was extra noise
on the File Format tab for every user.

Kept the field and the underlying parse/import logic intact (hidden=1
only). Removing the hidden flag re-exposes it if a real multi-currency
case ever shows up.
2026-05-18 12:42:57 +00:00
Ali 408102117c fix(workspace): insert importer link into ERPNext Invoicing Banking card
Replaces the standalone Bank Statements workspace (incorrect approach —
ERPNext doesn't expose top-level apps as tiles automatically) with a
runtime insertion of a single 'Bank Statement Importer' link into the
existing 'Banking' card on the ERPNext-owned Invoicing workspace.

Editing the workspace at runtime via after_migrate (not by overriding
its JSON) is intentional: ERPNext resyncs that JSON on every `bench
migrate`, so a file-level patch would be reverted. after_migrate runs
AFTER the resync, so the inserted link stays.

The insert is idempotent — it skips when the link is already present,
when the Banking card break isn't there, or when Bank Statement Importer
DocType doesn't exist yet.
2026-05-18 12:24:53 +00:00
Ali c6c1394af6 fix(workspace): nest Bank Statements under Accounting
User feedback: a standalone top-level workspace doesn't surface inside
the existing ERPNext module tiles. Putting it under Accounting (next to
Financial Reports) matches user mental model — bank statement work is
already a financial activity.

After migrate, Bank Statements shows up as a sub-page in the Accounting
sidebar group, alongside Financial Reports.
2026-05-18 12:05:27 +00:00
Ali 5e434c9113 feat(workspace): add Bank Statements workspace
A discoverable home for the import flow — until now Bank Statement
Importer, the registries, and the BRT had no workspace entry and were
only reachable by typing URLs.

The workspace groups everything into three cards:
  Setup       — Bank Statement Importer, Bank, Bank Account
  Daily Use   — Bank Transaction, Bank Reconciliation Tool
  Registry    — Counterparties (Customers/Suppliers), Purpose Keywords

Plus three coloured shortcut tiles for the most-used entry points.
2026-05-18 11:55:42 +00:00
Ali 6f8e9d40a2 refactor(bank-integration): rename DocType to Bank Statement Importer
The original "Bank Integration" name was too broad — this is specifically
a configurable Excel statement importer, not a generic bank API
integration. The new name lines up with the per-bank, per-format profile
the doctype actually represents.

Scope is narrow on purpose: only the main DocType is renamed. The
internal mapping/registry doctypes (Bank Integration Customer, Supplier,
Purpose, Customer Mapping, Supplier Mapping, Transaction Mapping,
Account Mapping, Standard Field, Excel Preset, Excel Column Mapping)
keep their tech names — they are not directly user-facing and renaming
them would multiply the migration surface for no UX gain.

Changes:
- Folder bank_integration/ moved to bank_statement_importer/, files
  renamed alongside; Python class is now BankStatementImporter
- All Python callers (excel_parser, import_api, create_reconcile,
  creation, matching, migrations) call frappe.get_doc("Bank Statement
  Importer", …); the parenttype string in child-table queries follows
- JS form handler, both list views (Bank Transaction, BRT) updated,
  including the "BiType::Name" mapping-source key used by BRT
- Registry doctypes (Customer, Supplier, Purpose) updated to link to
  Bank Statement Importer in their parent_bank_integration field
- Bank Account.bank_integration_type custom field options now offer
  "Bank Statement Importer"
- pre_model_sync patch renames the existing DocType, rewrites Bank
  Account.bank_integration_type stored values, and patches the Custom
  Field options in-place so the rest of the migrate run is consistent.
  Idempotent: skips when the new name already exists or the old one
  doesn't.

The Python module path jey_erp.bank_integration.* is intentionally
unchanged so existing imports (and any external integrations) keep
working without touching every from-import statement.
2026-05-18 11:54:41 +00:00
Ali 05ee98cc0e feat(bank-integration): inline preview and auto-detect for File Format
Two new helpers on the Bank Integration form, shown when a Sample File
is attached:

- "Preview Sample" opens a modal with the header row + first 20 data
  rows, with badges on each column showing the currently mapped Standard
  Field (or "unmapped"). Helps spot wrong Header Row / column drift
  before importing real statements.
- "Auto-detect Columns" reads the sample headers and replaces the
  Column Mappings table with a best-effort guess based on a multilingual
  synonym list (English, Azərbaycan, Russian). Reports how many of the
  total columns matched and lists unmapped headers so the user can fill
  the rest manually. Asks for confirmation before overwriting an
  existing table.

Both helpers are backed by new whitelisted endpoints
parse_sample_preview and auto_detect_column_mappings in excel_parser.py.
2026-05-18 11:47:49 +00:00
Ali 04b16a6eea refactor(bank-integration): merge Excel Preset into File Format tab
File format settings (header row, amount mode, column mappings, sample
file, direction values, custom date format, currency-from-file) now live
on the Bank Integration record itself under a new "File Format" tab,
removing the extra hop through Bank Integration Excel Preset.

- Bank Integration JSON gains the File Format tab and column_mappings child
- Excel parser and import API read format from Bank Integration directly,
  drop the preset_name argument from public endpoints
- Load Data dialog (on Bank Integration) and Load From Excel dialog (on
  Bank Transaction list) drop the preset Link field; the chosen Bank
  Integration provides everything needed
- after_migrate patch copies fields and column mappings from an existing
  preset into each Bank Integration whose File Format is still empty
- Bank Integration Excel Preset doctype kept around for rollback but
  marked deprecated (System Manager only, in-form warning), removed from
  the fixtures list so fresh installs don't ship the Generic preset
2026-05-18 11:45:56 +00:00
Ali 4f0c26208b Drop Obligation Pacts section from Company custom fields
The E-Taxes Obligation Pact doctype is being removed; the in-form
list section + HTML field that hosted it on Company are no longer
needed. Cleanup of leftover Custom Field rows on existing sites is
handled by jey_wizard's v0_1_27 patch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:07:09 +00:00
Ali e81f4bc8e8 chore(sales-invoice): remove Won/Lost checkboxes
Drop the conditional Won/Lost Custom Fields and their JS/Python plumbing —
they should never be shown again. Adds a post-migrate patch to delete the
existing Custom Field records (and any stray Property Setters) from the DB.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 15:06:08 +00:00
Ali 1a6bd5649b chore: use native Azərbaycan spelling in user-facing strings
Replaces "Azeri" / "Azerbaijani" / "Azerbaijan" with the native form
"Azərbaycan" in labels, descriptions, comments, app description, and
docs. Field names and Python identifiers are unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 10:56:52 +00:00
Ali a3ae46b978 fix(bank-integration): symmetric Azeri translit + VOEN-first dedup
Two related correctness fixes:

1. Asymmetric Azerbaijani normalization.
   consider_azeri_chars was only honoured by match_similar_customers/suppliers
   when populating registries. At Create & Reconcile time both the party-name
   lookup and the fuzzy purpose matcher compared raw lowercased strings, so a
   party matched via "Şirkət" ↔ "Sirket" translit at registry time would not
   resolve when the BT arrived, and a purpose rule keyed on "Mədaxil" would
   fall short of fuzzy threshold against "Medaxil".

   - name_to_party now indexes each row under strict / lowercase / translit /
     translit+lowercase variants based on its effective Case Mode + Azeri
     Translit (new per-row Select fields that override the globals, same
     pattern as case sensitivity).
   - _find_mapping_for_txn takes an `az` flag and applies translit to both
     keyword cache and txn purpose/party before comparison.

2. Customer / Supplier dedup ignored VOEN.
   create_unmapped_customers / create_unmapped_suppliers checked only by
   customer_name / supplier_name, so a registry record sharing a VOEN with an
   existing party under a slightly different name would create a duplicate.
   Now: tax_id is checked first, name as fallback; when an existing party is
   found, the mapping row is linked to it (instead of silently `continue`ing
   without linking). Response includes linked_count alongside created_count.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 10:45:39 +00:00
Ali 70215e200c fix(bank-integration): preview XSS, header completeness, ref-number safeguards, per-file currency
- Escape t.ref_no / t.counterparty / t.purpose / error fields with
  escape_html when rendering the preview and error-detail dialogs. A
  malicious bank statement (or counterparty-supplied purpose text)
  containing HTML could otherwise execute in the importer's session.
- Parser now refuses to proceed if any standard field required by the
  selected Amount Mode is missing from the file headers — instead of
  silently dropping every row with reason "amount" / "date".
- Reference Number is now a required mapping for all Amount Modes,
  preventing a class of silent duplication on re-import. parse_excel_for_
  preview also returns empty_ref_count and the preview surfaces a warning
  about future duplicate risk when some rows have an empty Reference
  Number on disk.
- Add 'Use Currency From File' checkbox on Excel Preset (default off).
  When on, BT.currency uses the parsed Currency column with fallback to
  the Bank Account's currency. import_bulk_bt now takes preset_name and
  the background job reads the flag.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 16:52:34 +00:00
Ali 5dd1296221 refactor(bank-integration): cleanup + robust amount parsing
- Delete mapping_resolver.py: dead code (nothing imports it; create_reconcile
  builds the indexes it needs directly).
- Simplify _create_journal_entry_for_brt: the if is_pay / else branches were
  identical because the matching transaction mapping is scoped by payment_type,
  so paid_from / paid_to already encode direction (from = credit side, to =
  debit side for both Pay and Receive). Removed the dead conditional, kept a
  comment explaining why no swap is needed.
- Add _parse_amount helper in excel_parser: handles currency text in the cell
  ('AZN 250', '250 AZN'), comma decimals ('250,00'), mixed thousands+decimal
  ('1,200.50' / '1.200,50'), accounting-style brackets ('(45.50)' → -45.50),
  and trailing minus ('250-'). Used for amount/debit/credit cells.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 16:40:50 +00:00