Compare commits

..

331 Commits

Author SHA1 Message Date
Frappe PR Bot
d74a649016 chore(release): Bumped to Version 16.4.1
## [16.4.1](https://github.com/frappe/erpnext/compare/v16.4.0...v16.4.1) (2026-02-05)

### Bug Fixes

* stock balance report issue ([e009319](e0093199b1))
2026-02-05 10:52:48 +00:00
rohitwaghchaure
bc9928b32b Merge pull request #52464 from frappe/mergify/bp/version-16/pr-52461
fix: stock balance report issue (backport #52459) (backport #52461)
2026-02-05 16:20:53 +05:30
rohitwaghchaure
4305415ed9 chore: fix issue
(cherry picked from commit 1d24abf5dd)
2026-02-05 10:20:46 +00:00
Rohit Waghchaure
e0093199b1 fix: stock balance report issue
(cherry picked from commit 7e584dd84a)
(cherry picked from commit 62616ad9e1)
2026-02-05 10:20:45 +00:00
Frappe PR Bot
0312d58dca chore(release): Bumped to Version 16.4.0
# [16.4.0](https://github.com/frappe/erpnext/compare/v16.3.0...v16.4.0) (2026-02-04)

### Bug Fixes

* add precision to rejected batch no qty calculation ([b365444](b365444027))
* allow sales invoice to be renamed ([f7b915d](f7b915dfe6))
* **barcode:** failing request when item has both batch and serial ([e4cdd97](e4cdd971c8))
* batch selector not working if Use Legacy (Client side) Reactivity disabled ([2a3642b](2a3642b55a))
* better fix for aac39b2671 ([b8ab55f](b8ab55fee8))
* correct exchange gain loss in ppr ([e09406d](e09406d085))
* correct Sales Tax Template sidebar link to proper DocType ([4c14e74](4c14e74a12))
* correct spelling of Payment Reconciliation in Accounting ([c80b554](c80b554cd7))
* **credit-note:** set incoming rate as zero for expired batch ([0f9bf08](0f9bf08685))
* **demo:** removed toolbar eventlistener (backport [#52171](https://github.com/frappe/erpnext/issues/52171)) ([#52172](https://github.com/frappe/erpnext/issues/52172)) ([6608601](66086010fc))
* duplicate account number (Indonesia COA) (backport [#52080](https://github.com/frappe/erpnext/issues/52080)) ([#52317](https://github.com/frappe/erpnext/issues/52317)) ([81e6575](81e65757ee))
* failing test cases ([136b2cf](136b2cfba5))
* group item wise tax details by tax row ([45e4c04](45e4c04830))
* hide close button on WO if WO is completed ([0d1c30f](0d1c30f3f0))
* hide item_wise_tax_details table from print ([c619be9](c619be989b))
* include credit notes in project gross margin calculation ([e755a4a](e755a4ad98))
* item code not showing in report view ([af167f9](af167f91fe))
* journal auditing voucher print date to use posting_date ([7e5eab2](7e5eab261c))
* **journal-entry:** normalize exchange rate to float ([3f0032d](3f0032d793))
* js error if user does not have write permission for date field ([3944dfd](3944dfde31))
* lead time calculation for FG item ([5595602](5595602f24))
* make item name editable in RFQ ([dbe5846](dbe5846908))
* merge taxes in purchase receipt when get items from multiple purchase invoices ([#51422](https://github.com/frappe/erpnext/issues/51422)) ([d80c8d1](d80c8d14b0))
* missing depr_series causing error on jv creation (backport [#52085](https://github.com/frappe/erpnext/issues/52085)) ([#52206](https://github.com/frappe/erpnext/issues/52206)) ([78c4f01](78c4f01733))
* negative stock for purchase return ([220a528](220a528d7f))
* populate contact fields when creating quotation from customer ([55129e6](55129e697d))
* production plan not considering planning datetime when creating WO ([7e7b16b](7e7b16b23e))
* **profit and loss statement:** exclude non period columns ([28e8c40](28e8c40bfc))
* reset incoming rate in selling controller if there are changes in item ([024e7b0](024e7b01ac))
* **RFQ:** render email templates for preview and sending ([687a80d](687a80d74c))
* **stock:** add stock recon opening stock condition ([f9a8fc1](f9a8fc1f2d))
* **stock:** fetch batch wise valuation rate in get_items ([b132e3f](b132e3f22a))
* **stock:** ignore packing slip while cancelling the sales invoice ([f425f89](f425f89a26))
* **stock:** include subcontracting order qty while calculating the bin qty ([de244e0](de244e0af7))
* **stock:** remove is_return condition on pos batch qty calculation ([9dcaf38](9dcaf38142))
* **stock:** set incoming_rate with lcv rate for internal purchase ([f462639](f462639aa0))
* **subcontracting:** include item bom in supplied items grouping key ([95c4b8d](95c4b8de06))
* test cases ([e74389f](e74389f01c))
* validate over ordering of quotation ([e7ace8e](e7ace8e620))
* validation when more than one FG items in repack stock entry ([a2d302b](a2d302b3fa))
* zero valuation rate if returning from different warehouse ([8ce51b2](8ce51b2f80))

### Features

* clear demo data from desktop screen (backport [#52128](https://github.com/frappe/erpnext/issues/52128)) ([#52147](https://github.com/frappe/erpnext/issues/52147)) ([05e30dc](05e30dc011))
* **credit-note:** add checkbox to set valuation rate as zero for expired batch ([b84fd46](b84fd46841))
* **delivery-note:** add status indicator when document is partially billed ([6048add](6048add4c0))
* document naming rule will now use posting date of the document ([b03494b](b03494bb67))
* **Transaction Deletion Record:** Editable "DocTypes To Delete" List with CSV import/export ([#50592](https://github.com/frappe/erpnext/issues/50592)) ([4963261](4963261dc8))
2026-02-04 04:29:22 +00:00
ruthra kumar
e8e9fb25fe Merge pull request #52347 from frappe/version-16-hotfix
chore: release v16
2026-02-04 09:57:57 +05:30
rohitwaghchaure
4a7e2742ec Merge pull request #52388 from frappe/mergify/bp/version-16-hotfix/pr-51422
fix: merge taxes in purchase receipt when get items from multiple purchase invoices (backport #51422)
2026-02-03 22:53:40 +05:30
rohitwaghchaure
55d5d6535b Merge pull request #52391 from frappe/mergify/bp/version-16-hotfix/pr-51898
fix: group item wise tax details by tax row (backport #51898)
2026-02-03 22:52:37 +05:30
rohitwaghchaure
b8ac04fb54 Merge branch 'version-16' into version-16-hotfix 2026-02-03 22:50:07 +05:30
ravibharathi656
45e4c04830 fix: group item wise tax details by tax row
(cherry picked from commit 57bd1facf5)
2026-02-03 15:38:48 +00:00
NaviN
d80c8d14b0 fix: merge taxes in purchase receipt when get items from multiple purchase invoices (#51422)
* fix: merge taxes in purchase receipt when get items from multiple purchase invoices

* fix: make merge tax configurable

* chore: follow standard merge taxes method

* chore: follow standard merge taxes method

(cherry picked from commit 6fde0a6261)
2026-02-03 15:34:03 +00:00
mergify[bot]
66e47f5651 Merge pull request #52380 from frappe/mergify/bp/version-16-hotfix/pr-52278 2026-02-03 15:32:58 +00:00
ruthra kumar
a3e8af19a6 Merge pull request #52379 from frappe/mergify/bp/version-16-hotfix/pr-51651
fix: correct exchange gain loss in ppr (backport #51651)
2026-02-03 20:59:41 +05:30
Mihir Kandoi
9b498a8da8 Merge pull request #52385 from frappe/mergify/bp/version-16-hotfix/pr-52259
fix(stock): include subcontracting order qty while calculating the bin qty (backport #52259)
2026-02-03 20:48:37 +05:30
Mihir Kandoi
25389be340 Merge pull request #52382 from frappe/mergify/bp/version-16-hotfix/pr-52374
fix(stock): fetch batch wise valuation rate in get_items (backport #52374)
2026-02-03 20:34:37 +05:30
Sudharsanan11
de244e0af7 fix(stock): include subcontracting order qty while calculating the bin qty
(cherry picked from commit de8f8ef9f4)
2026-02-03 14:55:27 +00:00
kavin-114
b132e3f22a fix(stock): fetch batch wise valuation rate in get_items
(cherry picked from commit c5df570262)
2026-02-03 14:47:52 +00:00
ruthra kumar
670fd79e38 Merge pull request #52377 from frappe/mergify/bp/version-16-hotfix/pr-52314
fix(journal-entry): normalize exchange rate to float (backport #52314)
2026-02-03 20:10:03 +05:30
ravibharathi656
e09406d085 fix: correct exchange gain loss in ppr
(cherry picked from commit 02e96039ac)
2026-02-03 14:35:58 +00:00
rohitwaghchaure
3bc348d6f0 Merge pull request #52376 from frappe/mergify/bp/version-16-hotfix/pr-52375
fix: zero valuation rate if returning from different warehouse (backport #52369) (backport #52375)
2026-02-03 20:04:39 +05:30
Dharanidharan2813
3f0032d793 fix(journal-entry): normalize exchange rate to float
(cherry picked from commit be0040ddc7)
2026-02-03 14:17:24 +00:00
ruthra kumar
163b848455 Merge pull request #52368 from frappe/mergify/bp/version-16-hotfix/pr-52320
fix: correct Sales Tax Template sidebar link to proper DocType (backport #52320)
2026-02-03 19:44:26 +05:30
Rohit Waghchaure
8ce51b2f80 fix: zero valuation rate if returning from different warehouse
(cherry picked from commit 28929df0e8)
(cherry picked from commit eb2119e292)
2026-02-03 13:59:59 +00:00
ruthra kumar
422b37332e Merge pull request #52367 from frappe/mergify/bp/version-16-hotfix/pr-52279
fix(profit and loss statement): exclude non period columns (backport #52279)
2026-02-03 17:47:37 +05:30
Luis Mendoza
4c14e74a12 fix: correct Sales Tax Template sidebar link to proper DocType
(cherry picked from commit 06a7c85c93)
2026-02-03 12:05:37 +00:00
ravibharathi656
28e8c40bfc fix(profit and loss statement): exclude non period columns
(cherry picked from commit 6180e5eb53)
2026-02-03 12:00:00 +00:00
ruthra kumar
660fc8f76a Merge pull request #52365 from frappe/mergify/bp/version-16-hotfix/pr-52160
fix(stock): remove is_return condition on pos batch qty calculation (backport #52160)
2026-02-03 17:19:50 +05:30
ruthra kumar
22456a5857 Merge pull request #52362 from frappe/mergify/bp/version-16-hotfix/pr-51997
Add partially billed status indicator (backport #51997)
2026-02-03 17:19:31 +05:30
kavin-114
76e0eb00a5 test: add unit test case for pos reserved with return qty
(cherry picked from commit 12ec997027)
2026-02-03 11:11:50 +00:00
kavin-114
9dcaf38142 fix(stock): remove is_return condition on pos batch qty calculation
(cherry picked from commit 2c19c1fd06)
2026-02-03 11:11:50 +00:00
Dharanidharan2813
6048add4c0 feat(delivery-note): add status indicator when document is partially billed
(cherry picked from commit 7767000ccf)
2026-02-03 10:59:20 +00:00
rohitwaghchaure
0552b48328 Merge pull request #52356 from frappe/mergify/bp/version-16-hotfix/pr-52338
fix: negative stock for purchase return (backport #52338)
2026-02-03 16:16:28 +05:30
ruthra kumar
193b29d5fc Merge pull request #52350 from frappe/mergify/bp/version-16-hotfix/pr-52339
chore: rename icons (backport #52339)
2026-02-03 16:13:06 +05:30
Rohit Waghchaure
220a528d7f fix: negative stock for purchase return
(cherry picked from commit 77893933a2)
2026-02-03 10:25:10 +00:00
ruthra kumar
e087a8b179 Merge pull request #52353 from frappe/mergify/bp/version-16-hotfix/pr-52345
ci: skip svg (backport #52345)
2026-02-03 15:41:53 +05:30
ruthra kumar
d7067f6b7a ci: skip svg
(cherry picked from commit e565d2283e)
2026-02-03 10:11:12 +00:00
sokumon
e264d8e2d6 chore: rename icons
(cherry picked from commit 2d312bcfe8)
2026-02-03 10:02:54 +00:00
ruthra kumar
8b2559ab0c Merge pull request #52337 from frappe/mergify/bp/version-16-hotfix/pr-52280
fix(stock): ignore packing slip while cancelling the sales invoice (backport #52280)
2026-02-03 13:58:59 +05:30
Sudharsanan11
f425f89a26 fix(stock): ignore packing slip while cancelling the sales invoice
(cherry picked from commit c58887b44a)
2026-02-03 08:25:04 +00:00
ruthra kumar
e3bf84c572 Merge pull request #52321 from frappe/mergify/bp/version-16-hotfix/pr-50592
feat(Transaction Deletion Record): Editable "DocTypes To Delete" List with CSV import/export (backport #50592)
2026-02-03 13:50:00 +05:30
ruthra kumar
e2b88218ec Merge pull request #52330 from frappe/mergify/bp/version-16-hotfix/pr-51655
fix: include credit notes in project gross margin calculation (backport #51655)
2026-02-03 12:19:28 +05:30
ravibharathi656
e755a4ad98 fix: include credit notes in project gross margin calculation
(cherry picked from commit a378fee8e0)
2026-02-03 06:07:49 +00:00
ruthra kumar
d2ea428030 chore: resolve conflict 2026-02-03 10:38:39 +05:30
Mihir Kandoi
496956f08f Merge pull request #52324 from frappe/mergify/bp/version-16-hotfix/pr-52184
fix(subcontracting): include item bom in supplied items grouping key (backport #52184)
2026-02-03 09:24:00 +05:30
Sudharsanan11
a3190dd556 test(subcontracting): add test for consumed_qty calculation with similar finished goods
(cherry picked from commit 4d9412181c)
2026-02-03 03:40:18 +00:00
Sudharsanan11
95c4b8de06 fix(subcontracting): include item bom in supplied items grouping key
(cherry picked from commit 0d372a62a1)
2026-02-03 03:40:18 +00:00
Henning Wendtland
4963261dc8 feat(Transaction Deletion Record): Editable "DocTypes To Delete" List with CSV import/export (#50592)
* feat: add editable DocTypes To Delete list with import/export

Add user control over transaction deletion with reviewable and reusable deletion templates.

- New "DocTypes To Delete" table allows users to review and customize what will be deleted before submission
- Import/Export CSV templates for reusability across environments
- Company field rule: only filter by company if field is specifically named "company", otherwise delete all records
- Child tables (istable=1) automatically excluded from selection
- "Remove Zero Counts" helper button to clean up list
- Backward compatible with existing deletion records

* refactor: improve Transaction Deletion Record code quality

- Remove unnecessary chatty comments from AI-generated code
- Add concise docstrings to all new methods
- Remove redundant @frappe.whitelist() decorators from internal methods
- Improve CSV import validation (header check, child table filtering)
- Add better error feedback with consolidated skip messages
- Reorder form fields: To Delete list now appears before Excluded list
- Add conditional visibility for Summary table (legacy records only)
- Improve architectural clarity: single API entry point per feature

Technical improvements:
- export_to_delete_template_method and import_to_delete_template_method
  are now internal helpers without whitelist decorators
- CSV import now validates format and provides detailed skip reasons
- Summary table only shows for submitted records without To Delete list
- Maintains backward compatibility for existing deletion records

* fix: field order

* test: fix broken tests and add new ones

* fix: adapt create_transaction_deletion_request

* test: fix assertRaises trigger

* fix: conditionally execute Transaction Deletion pre-tasks based on selected DocTypes

* refactor: replace boolean task flags with status fields

* fix: remove UI comment

* fix: don't allow virtual doctype selection and improve protected Doctype List

* fix: replace outdated frappe.db.sql by frappe.qb

* feat: add support for multiple company fields

* fix: autofill comapny field, add docstrings, filter for company_field

* fix: add edge case handling for update_naming_series and add tests for prefix extraction

* fix: use redis for running deletion validation, check per doctype instead of company

(cherry picked from commit 0fb37ad792)

# Conflicts:
#	erpnext/patches.txt
2026-02-03 00:49:04 +00:00
mergify[bot]
81e65757ee fix: duplicate account number (Indonesia COA) (backport #52080) (#52317)
Co-authored-by: Apriliansyah Idris <apriliansyahidris@gmail.com>
fix: duplicate account number (Indonesia COA) (#52080)
2026-02-02 19:09:22 +00:00
rohitwaghchaure
78e581154b Merge pull request #52312 from frappe/mergify/bp/version-16-hotfix/pr-52303
fix: batch selector not working if Use Legacy (Client side) Reactivity disabled (backport #52303)
2026-02-02 23:32:40 +05:30
Rohit Waghchaure
2a3642b55a fix: batch selector not working if Use Legacy (Client side) Reactivity disabled
(cherry picked from commit d1cba1073f)
2026-02-02 16:32:18 +00:00
Mihir Kandoi
beaa76ca16 Merge pull request #52311 from frappe/mergify/bp/version-16-hotfix/pr-52246 2026-02-02 21:01:34 +05:30
Mihir Kandoi
9997185071 Merge pull request #52246 from mihir-kandoi/st58765
(cherry picked from commit 135a433018)
2026-02-02 15:15:38 +00:00
Mihir Kandoi
681c0b5917 Merge pull request #52308 from frappe/mergify/bp/version-16-hotfix/pr-52304
fix: populate contact fields when creating quotation from customer (backport #52304)
2026-02-02 20:36:19 +05:30
Mihir Kandoi
4a0e04ee20 Merge pull request #52306 from frappe/mergify/bp/version-16-hotfix/pr-52281
fix(stock): add stock recon opening stock condition (backport #52281)
2026-02-02 20:24:00 +05:30
Mihir Kandoi
55129e697d fix: populate contact fields when creating quotation from customer
(cherry picked from commit 75b2c2c83d)
2026-02-02 14:46:36 +00:00
kavin-114
f9a8fc1f2d fix(stock): add stock recon opening stock condition
(cherry picked from commit f3eb6c7078)
2026-02-02 14:37:36 +00:00
Mihir Kandoi
091ff81ae5 Merge pull request #52302 from frappe/mergify/bp/version-16-hotfix/pr-52286
fix: reset incoming rate in selling controller if there are changes i… (backport #52286)
2026-02-02 20:05:37 +05:30
Mihir Kandoi
024e7b01ac fix: reset incoming rate in selling controller if there are changes in item
(cherry picked from commit 2d6b43fd54)
2026-02-02 14:18:20 +00:00
ruthra kumar
a0156b61b8 Merge pull request #52284 from frappe/mergify/bp/version-16-hotfix/pr-52200
fix(accounts): correct date in Journal Auditing Voucher print format (backport #52200)
2026-02-02 12:55:41 +05:30
Tamal Majumdar
7e5eab261c fix: journal auditing voucher print date to use posting_date
(cherry picked from commit 43e2495df8)
2026-02-02 07:21:36 +00:00
ruthra kumar
63782e6355 Merge pull request #52282 from frappe/mergify/bp/version-16-hotfix/pr-51692
fix: correct spelling of Payment Reconciliation in Accounting (backport #51692)
2026-02-02 12:43:17 +05:30
nivithamerlin
c80b554cd7 fix: correct spelling of Payment Reconciliation in Accounting
(cherry picked from commit 35e53d28df)
2026-02-02 07:09:54 +00:00
Mihir Kandoi
7db88b210e Merge pull request #52276 from frappe/mergify/bp/version-16-hotfix/pr-52274 2026-02-02 10:24:07 +05:30
Mihir Kandoi
42d873f1d9 test: over ordering of quotation items
(cherry picked from commit 53e58f6678)
2026-02-02 04:38:13 +00:00
MochaMind
19c1dcc3dd chore: update POT file (#52264) 2026-02-01 15:07:28 +01:00
Mihir Kandoi
23e027b6be Merge pull request #52230 from frappe/mergify/bp/version-16-hotfix/pr-52222
fix: validate over ordering of quotation (backport #52222)
2026-01-31 20:26:44 +05:30
Mihir Kandoi
d91cfa76e6 Merge pull request #52257 from frappe/mergify/bp/version-16-hotfix/pr-52253 2026-01-31 20:19:18 +05:30
Mihir Kandoi
a29df7be67 chore: resolve conflicts 2026-01-31 20:13:26 +05:30
Mihir Kandoi
dbe5846908 fix: make item name editable in RFQ
(cherry picked from commit d9998a977c)
2026-01-31 14:34:24 +00:00
Mihir Kandoi
83fcb5d2d8 Merge pull request #52255 from frappe/mergify/bp/version-16-hotfix/pr-52252
fix: better fix for #51495 (backport #52252)
2026-01-31 19:52:45 +05:30
Mihir Kandoi
b8ab55fee8 fix: better fix for aac39b2671
(cherry picked from commit b24ae5e9a2)
2026-01-31 14:21:27 +00:00
rohitwaghchaure
4d03f4ebaa Merge pull request #52240 from frappe/mergify/bp/version-16-hotfix/pr-52232
fix: validation when more than one FG items in repack stock entry (backport #52232)
2026-01-31 17:54:08 +05:30
Rohit Waghchaure
a2d302b3fa fix: validation when more than one FG items in repack stock entry
(cherry picked from commit 6423ce2fa7)
2026-01-31 07:16:45 +00:00
Mihir Kandoi
b5321d42a3 Merge pull request #52234 from frappe/mergify/bp/version-16-hotfix/pr-52231
fix: item code not showing in report view (backport #52231)
2026-01-30 22:17:26 +05:30
UmakanthKaspa
af167f91fe fix: item code not showing in report view
(cherry picked from commit b20f57321f)
2026-01-30 16:46:26 +00:00
Mihir Kandoi
e74389f01c fix: test cases
(cherry picked from commit 36f1e3572c)
2026-01-30 14:00:52 +00:00
Mihir Kandoi
e7ace8e620 fix: validate over ordering of quotation
(cherry picked from commit 4cc306d2d8)

# Conflicts:
#	erpnext/patches.txt
2026-01-30 14:00:52 +00:00
Mihir Kandoi
e23e9b5d66 Merge pull request #52227 from frappe/mergify/bp/version-16-hotfix/pr-52226 2026-01-30 18:03:40 +05:30
Mihir Kandoi
136b2cfba5 fix: failing test cases
(cherry picked from commit d3f44a425c)
2026-01-30 12:18:10 +00:00
Mihir Kandoi
3b3738577d Merge pull request #52225 from frappe/mergify/bp/version-16-hotfix/pr-51433 2026-01-30 17:30:01 +05:30
Mihir Kandoi
1e646bd0ed Merge pull request #52224 from frappe/mergify/bp/version-16-hotfix/pr-52223
fix: allow sales invoice to be renamed (backport #52223)
2026-01-30 17:19:10 +05:30
Mihir Kandoi
02e6c49130 test: add test case
(cherry picked from commit e2c3d0fa94)
2026-01-30 11:41:46 +00:00
Mihir Kandoi
e9fa725030 chore: make feature opt in
(cherry picked from commit b8d4522ea1)
2026-01-30 11:41:46 +00:00
Mihir Kandoi
b03494bb67 feat: document naming rule will now use posting date of the document
(cherry picked from commit 22fd1a1cfd)
2026-01-30 11:41:45 +00:00
Mihir Kandoi
f7b915dfe6 fix: allow sales invoice to be renamed
(cherry picked from commit 95fdbe55f9)
2026-01-30 11:33:20 +00:00
Mihir Kandoi
0a5aac9ce7 Merge pull request #52218 from frappe/mergify/bp/version-16-hotfix/pr-52209
fix: add precision to rejected batch no qty calculation (backport #52209)
2026-01-30 12:21:50 +05:30
Mihir Kandoi
e3c62070d1 Merge pull request #52215 from frappe/mergify/bp/version-16-hotfix/pr-52213
fix: hide close button on WO if WO is completed (backport #52213)
2026-01-30 12:06:39 +05:30
Mihir Kandoi
b365444027 fix: add precision to rejected batch no qty calculation
(cherry picked from commit 838d245215)
2026-01-30 06:35:59 +00:00
Mihir Kandoi
0d1c30f3f0 fix: hide close button on WO if WO is completed
(cherry picked from commit 6e17ccf499)
2026-01-30 06:29:32 +00:00
Mihir Kandoi
d0b553dca3 Merge pull request #52212 from frappe/mergify/bp/version-16-hotfix/pr-52210
fix(barcode): failing request when item has both batch and serial (backport #52210)
2026-01-30 11:52:49 +05:30
Mihir Kandoi
e4cdd971c8 fix(barcode): failing request when item has both batch and serial
(cherry picked from commit 89f6f0f46f)
2026-01-30 06:17:41 +00:00
mergify[bot]
78c4f01733 fix: missing depr_series causing error on jv creation (backport #52085) (#52206)
fix: missing depr_series causing error on jv creation (#52085)

(cherry picked from commit b565dd3da8)

Co-authored-by: Dany Robert <rtdany10@gmail.com>
2026-01-29 23:30:29 +05:30
Mihir Kandoi
eac4978278 Merge pull request #52203 from frappe/mergify/bp/version-16-hotfix/pr-52201
fix: hide item_wise_tax_details table from print (backport #52201)
2026-01-29 21:58:37 +05:30
Mihir Kandoi
c619be989b fix: hide item_wise_tax_details table from print
(cherry picked from commit c38f884095)
2026-01-29 16:12:55 +00:00
rohitwaghchaure
64921fc1b5 Merge pull request #52197 from frappe/mergify/bp/version-16-hotfix/pr-52190
fix: lead time calculation for FG item (backport #52190)
2026-01-29 19:06:53 +05:30
rohitwaghchaure
6d8d502bbf Merge pull request #52192 from frappe/mergify/bp/version-16-hotfix/pr-52158
Add Landed Cost Voucher Amount in Internal Purchase Receipt (backport #52158)
2026-01-29 18:07:46 +05:30
Rohit Waghchaure
5595602f24 fix: lead time calculation for FG item
(cherry picked from commit 646688c291)
2026-01-29 12:29:39 +00:00
kavin-114
7042f2b8fb test: add unit test to check internal purchase with lcv
(cherry picked from commit dd4fd89ef8)
2026-01-29 12:02:50 +00:00
kavin-114
f462639aa0 fix(stock): set incoming_rate with lcv rate for internal purchase
(cherry picked from commit f0dccc3cd7)
2026-01-29 12:02:49 +00:00
Mihir Kandoi
14ba0f1cae Merge pull request #52183 from frappe/mergify/bp/version-16-hotfix/pr-52181
fix: js error if user does not have write permission for date field (backport #52181)
2026-01-29 15:42:29 +05:30
Mihir Kandoi
3944dfde31 fix: js error if user does not have write permission for date field
(cherry picked from commit 7f6f39f5e7)
2026-01-29 10:01:33 +00:00
ruthra kumar
16cc2b0a25 Merge pull request #52177 from frappe/mergify/bp/version-16-hotfix/pr-52173
New accounting icons (backport #52173)
2026-01-29 14:51:36 +05:30
Jacob Salvi
3394e1a126 refactor: new accounting icons (#52173)
* chore: new icons share-management

* chore: new accounting icons

* chore: trigger CI

---------

Co-authored-by: Soham Kulkarni <77533095+sokumon@users.noreply.github.com>
Co-authored-by: ruthra kumar <ruthra@erpnext.com>
(cherry picked from commit cdcf3fa593)
2026-01-29 09:13:39 +00:00
mergify[bot]
66086010fc fix(demo): removed toolbar eventlistener (backport #52171) (#52172)
Co-authored-by: Diptanil Saha <diptanil@frappe.io>
fix(demo): removed toolbar eventlistener (#52171)
2026-01-29 11:29:59 +05:30
Mihir Kandoi
195a2f3e74 Merge pull request #52168 from frappe/mergify/bp/version-16-hotfix/pr-52166
fix: production plan not considering planning datetime when creating WO (backport #52166)
2026-01-29 11:06:50 +05:30
Mihir Kandoi
7e7b16b23e fix: production plan not considering planning datetime when creating WO
(cherry picked from commit 4e19c7e8bd)
2026-01-29 05:20:59 +00:00
Aarol D'Souza
f4beb41df2 Merge pull request #52164 from frappe/mergify/bp/version-16-hotfix/pr-52092
fix(RFQ): render email templates for preview and sending (backport #52092)
2026-01-29 09:23:39 +05:30
AarDG10
4c4aa9bbdf ci: minor text correction
(cherry picked from commit 37cdae2f34)
2026-01-29 03:38:02 +00:00
AarDG10
687a80d74c fix(RFQ): render email templates for preview and sending
(cherry picked from commit 525b3960e1)
2026-01-29 03:38:01 +00:00
rohitwaghchaure
f01e0576b9 Merge pull request #52141 from frappe/mergify/bp/version-16-hotfix/pr-52007
Fix: Set Zero Rate for Standalone Credit Note with Expired Batch (backport #52007)
2026-01-28 19:46:10 +05:30
Frappe PR Bot
83a0d957ef chore(release): Bumped to Version 16.3.0
# [16.3.0](https://github.com/frappe/erpnext/compare/v16.2.0...v16.3.0) (2026-01-28)

### Features

* clear demo data from desktop screen (backport [#52128](https://github.com/frappe/erpnext/issues/52128))  ([#52150](https://github.com/frappe/erpnext/issues/52150)) ([554aeb9](554aeb94fd))
2026-01-28 12:51:32 +00:00
mergify[bot]
554aeb94fd feat: clear demo data from desktop screen (backport #52128) (#52150)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: Soham Kulkarni <77533095+sokumon@users.noreply.github.com>
2026-01-28 18:19:41 +05:30
mergify[bot]
05e30dc011 feat: clear demo data from desktop screen (backport #52128) (#52147)
Co-authored-by: Soham Kulkarni <77533095+sokumon@users.noreply.github.com>
2026-01-28 17:36:04 +05:30
kavin-114
40a3dabd30 test(credit-note): add unit test for zero valuation rate on expired batch
(cherry picked from commit 3460a7efb5)
2026-01-28 10:43:58 +00:00
kavin-114
0f9bf08685 fix(credit-note): set incoming rate as zero for expired batch
(cherry picked from commit e78c750b4e)
2026-01-28 10:43:58 +00:00
kavin-114
b84fd46841 feat(credit-note): add checkbox to set valuation rate as zero for expired batch
(cherry picked from commit 04cdf88715)
2026-01-28 10:43:58 +00:00
Frappe PR Bot
6209d633c2 chore(release): Bumped to Version 16.2.0
# [16.2.0](https://github.com/frappe/erpnext/compare/v16.1.0...v16.2.0) (2026-01-28)

### Bug Fixes

* **accounts:** correct base grand total and rounded total mismatch (backport [#51739](https://github.com/frappe/erpnext/issues/51739)) ([#52101](https://github.com/frappe/erpnext/issues/52101)) ([6115f8f](6115f8fb9a))
* **asset capitalization:** update total_asset_cost on asset capitalisation submission (backport [#52077](https://github.com/frappe/erpnext/issues/52077)) ([#52115](https://github.com/frappe/erpnext/issues/52115)) ([4f16956](4f1695616a))
* autofill warehouse for packed items ([881562f](881562fc37))
* Bin reserved qty for production for extra material transfer ([bf53133](bf53133f94))
* calculate weighted average rate for customer provided items in subcontracting inward order ([7120fbd](7120fbd14b))
* check the payment ledger entry has the dimension ([#51823](https://github.com/frappe/erpnext/issues/51823)) ([7342b25](7342b2551b))
* check the payment ledger entry has the dimension (backport [#51823](https://github.com/frappe/erpnext/issues/51823)) ([#52108](https://github.com/frappe/erpnext/issues/52108)) ([1927adb](1927adbd2e))
* create DN btn should not be shown if it cannot be created ([30e6b5d](30e6b5daac))
* **customer:** add customer group filters ([b1716bf](b1716bfeef))
* disable asset repair when status is fully depreciated ([13e4849](13e4849c43))
* Ensure paid_amount is always numeric before calling allocate_amount_to_references (backport [#50935](https://github.com/frappe/erpnext/issues/50935)) ([#52036](https://github.com/frappe/erpnext/issues/52036)) ([e9f3f0f](e9f3f0f445))
* force user to enter batch or serial for serial/batch items ([91199ea](91199ea9c9))
* handle parent level project change ([0b7684e](0b7684eccd))
* handle undefined bank_transaction_mapping in quick entry ([22a8d48](22a8d483e1))
* job cards should not be deleted on close of WO ([7c2bbe0](7c2bbe0d82))
* **journal-entry:** prevent submit failure due to double background queuing (backport [#52083](https://github.com/frappe/erpnext/issues/52083)) ([#52087](https://github.com/frappe/erpnext/issues/52087)) ([46e6096](46e6096fe3))
* negative stock for purchae return ([fb3fb8c](fb3fb8ca5e))
* not able to complete the job card ([f486071](f486071cf6))
* **payment entry:** update currency symbol (backport [#51956](https://github.com/frappe/erpnext/issues/51956)) ([#52094](https://github.com/frappe/erpnext/issues/52094)) ([b1b1f25](b1b1f25bb1))
* **project:** add missing counter to project update naming series ([37a237d](37a237dbb7))
* rejected qty in PR doesn't consider conversion factor ([c7c7a55](c7c7a55a58))
* **sales order:** set project at item level from parent ([27fe754](27fe754a7d))
* **shipment:** user contact validation to use full name ([0a56647](0a56647a61))
* show everything else besides other party specific item ([7575861](75758610dd))
* show message if image is removed from item description (backport [#52088](https://github.com/frappe/erpnext/issues/52088)) ([#52097](https://github.com/frappe/erpnext/issues/52097)) ([53b7375](53b73757ed))
* **stock:** use purchase UOM in Supplier Quotation items ([f97b850](f97b850077))
* strip whitespace in customer_name ([41e6687](41e6687b35))
* swedish_address_template ([cff09b7](cff09b71cc))
* tests ([6fa60d2](6fa60d2f1a))
* throw if item order field is not set in subcontracting controller ([264855e](264855e5e1))
* unable to split asset from capitalization (backport [#52020](https://github.com/frappe/erpnext/issues/52020)) ([#52114](https://github.com/frappe/erpnext/issues/52114)) ([c1cc1db](c1cc1dbd27)), closes [#52016](https://github.com/frappe/erpnext/issues/52016) [#52016](https://github.com/frappe/erpnext/issues/52016)
* UOM of item not fetching in BOM ([1b9a93f](1b9a93f90e))
* update country_wise_tax.json for Algerian Taxes (backport [#51878](https://github.com/frappe/erpnext/issues/51878)) ([#52038](https://github.com/frappe/erpnext/issues/52038)) ([8946f12](8946f12677))
* validation to check at-least one raw material for manufacture entry ([d067e37](d067e37ab6))
* warehouse permissions in MR incorrectly ignored ([504c84e](504c84e28a))

### Features

* **accounts:** retain filters when switching between financial statements (backport [#51668](https://github.com/frappe/erpnext/issues/51668)) ([#52117](https://github.com/frappe/erpnext/issues/52117)) ([9ed3801](9ed3801d06))
2026-01-28 04:15:59 +00:00
ruthra kumar
095fe65bef Merge pull request #52103 from frappe/version-16-hotfix
chore: release v16
2026-01-28 09:44:30 +05:30
Mihir Kandoi
b285548a46 Merge pull request #52124 from frappe/mergify/bp/version-16-hotfix/pr-51961
fix(sales order): set project at item level from parent (backport #51961)
2026-01-27 21:55:49 +05:30
SowmyaArunachalam
0b7684eccd fix: handle parent level project change
(cherry picked from commit 543b6e51c0)
2026-01-27 16:24:22 +00:00
SowmyaArunachalam
574460c009 chore: use frappe.model.set_value
(cherry picked from commit 3b27f49d79)
2026-01-27 16:24:22 +00:00
SowmyaArunachalam
27fe754a7d fix(sales order): set project at item level from parent
(cherry picked from commit 9e51701e2a)
2026-01-27 16:24:22 +00:00
Mihir Kandoi
531fe59a24 Merge pull request #52122 from frappe/mergify/bp/version-16-hotfix/pr-52084
fix(shipment): user contact validation to use full name (backport #52084)
2026-01-27 21:29:22 +05:30
harrishragavan
0a56647a61 fix(shipment): user contact validation to use full name
(cherry picked from commit 3c6eb9a531)
2026-01-27 15:57:22 +00:00
Soham Kulkarni
c2f666b7a3 Merge pull request #52120 from frappe/mergify/bp/version-16-hotfix/pr-52119 2026-01-27 21:11:42 +05:30
sokumon
c1bbe1104e chore: change color of icons in accounting folders
(cherry picked from commit 6f9cd8c261)
2026-01-27 15:15:16 +00:00
ruthra kumar
2c86327c7e Merge pull request #52112 from frappe/mergify/bp/version-16-hotfix/pr-52106
fix: show everything else besides other party specific item (backport #52106)
2026-01-27 20:08:54 +05:30
ruthra kumar
31385a1f91 Merge pull request #52118 from frappe/mergify/bp/version-16-hotfix/pr-51894
refactor: accounting workspace (backport #51894)
2026-01-27 20:08:29 +05:30
mergify[bot]
4f1695616a fix(asset capitalization): update total_asset_cost on asset capitalisation submission (backport #52077) (#52115)
fix(asset capitalization): update total_asset_cost on asset capitalisation submission (#52077)

fix(asset capitalization): update total_asset_cost on asset capitalization submission

(cherry picked from commit ec41f1b0f5)

Co-authored-by: NaviN <118178330+Navin-S-R@users.noreply.github.com>
2026-01-27 19:31:52 +05:30
mergify[bot]
9ed3801d06 feat(accounts): retain filters when switching between financial statements (backport #51668) (#52117) 2026-01-27 19:03:44 +05:30
ruthra kumar
61ad67ec29 refactor: reuse icon for invoicing
(cherry picked from commit f0332c4dc7)
2026-01-27 13:15:37 +00:00
ruthra kumar
735b9da6b1 refactor: rename Accounts to Accounting
(cherry picked from commit fb9656b975)
2026-01-27 13:15:36 +00:00
ruthra kumar
fe7a797156 refactor: link payments dashboard to sidebar
(cherry picked from commit f7abf9c1da)
2026-01-27 13:15:36 +00:00
ruthra kumar
f951dd180a refactor: payments dashboard
(cherry picked from commit 99406ccc15)
2026-01-27 13:15:36 +00:00
ruthra kumar
8e871796d4 refactor: shed duplicates from invoicing sidebar
(cherry picked from commit 1295d7aa30)
2026-01-27 13:15:36 +00:00
ruthra kumar
c88ee50c34 refactor: reorder accounts setup sidebar
(cherry picked from commit 5a680d5037)
2026-01-27 13:15:35 +00:00
ruthra kumar
e49f6f4f09 refactor: introduce setup icon and reorder
(cherry picked from commit 7528d42187)
2026-01-27 13:15:35 +00:00
ruthra kumar
72942e6b8c refactor: payments sidebar and icon
(cherry picked from commit cbdc945287)
2026-01-27 13:15:35 +00:00
ruthra kumar
fdcf037f1b chore: rename accounting to invoicing
(cherry picked from commit faf0dcb102)
2026-01-27 13:15:35 +00:00
ruthra kumar
9e0c606b95 chore: remove accounting icon
(cherry picked from commit 5e02b4009e)
2026-01-27 13:15:34 +00:00
ruthra kumar
6b9f2ddf83 refactor: invoicing icon
(cherry picked from commit 8125f9035c)
2026-01-27 13:15:34 +00:00
mergify[bot]
c1cc1dbd27 fix: unable to split asset from capitalization (backport #52020) (#52114)
fix: unable to split asset from capitalization (#52020)

* fix: Allow split asset from capitalized composite asset (fixes #52016)

* test: Add test case for splitting asset created via capitalization (fixes #52016)

* docs: Add docstring to before_submit method

* fix: Remove unused variable and fix UTF-8 encoding in asset files

* fix: Remove UTF-8 BOM from asset.py to fix linting

* fix: Fix test_split_asset_created_via_capitalization test parameters

* fix: Remove unused import create_item

* chore: remove unnecessary comments

Removed validation comments for composite asset capitalization in before_submit method.

---------


(cherry picked from commit 7e9647f3f0)

Co-authored-by: madelyngamble2 <madelyngamble2@gmail.com>
Co-authored-by: Khushi Rawat <142375893+khushi8112@users.noreply.github.com>
2026-01-27 18:04:19 +05:30
Mihir Kandoi
de584e2e8d test: fix tests
(cherry picked from commit 5eeebbde7f)
2026-01-27 10:57:40 +00:00
Mihir Kandoi
75758610dd fix: show everything else besides other party specific item
(cherry picked from commit 71371b0ba5)
2026-01-27 10:57:40 +00:00
ruthra kumar
1927adbd2e fix: check the payment ledger entry has the dimension (backport #51823) (#52108)
fix: check the payment ledger entry has the dimension (#51823)

* fix: check the payment ledger entry has the dimension

* fix: add project in payment ledger entry

(cherry picked from commit efa3973b77)

Co-authored-by: Vishnu Priya Baskaran <145791817+ervishnucs@users.noreply.github.com>
2026-01-27 16:25:33 +05:30
Vishnu Priya Baskaran
7342b2551b fix: check the payment ledger entry has the dimension (#51823)
* fix: check the payment ledger entry has the dimension

* fix: add project in payment ledger entry

(cherry picked from commit efa3973b77)
2026-01-27 10:27:23 +00:00
mergify[bot]
6115f8fb9a fix(accounts): correct base grand total and rounded total mismatch (backport #51739) (#52101)
Co-authored-by: Dharanidharan S <dharanidharans1328@gmail.com>
fix(accounts): correct base grand total and rounded total mismatch (#51739)
2026-01-27 14:23:10 +05:30
mergify[bot]
53b73757ed fix: show message if image is removed from item description (backport #52088) (#52097)
Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2026-01-27 14:09:02 +05:30
rohitwaghchaure
dee3357da2 Merge pull request #52075 from frappe/mergify/bp/version-16-hotfix/pr-52062
fix: not able to complete the job card (backport #52062)
2026-01-27 13:03:43 +05:30
mergify[bot]
b1b1f25bb1 fix(payment entry): update currency symbol (backport #51956) (#52094)
Co-authored-by: NaviN <118178330+Navin-S-R@users.noreply.github.com>
fix(payment entry): update currency symbol (#51956)
2026-01-27 06:34:19 +00:00
mergify[bot]
46e6096fe3 fix(journal-entry): prevent submit failure due to double background queuing (backport #52083) (#52087)
Co-authored-by: V Shankar <shankarv292002@gmail.com>
fix(journal-entry): prevent submit failure due to double background queuing (#52083)
2026-01-27 05:53:05 +00:00
Rohit Waghchaure
f486071cf6 fix: not able to complete the job card
(cherry picked from commit 696ea68f86)
2026-01-26 17:45:21 +00:00
Mihir Kandoi
b541fbbd60 Merge pull request #52066 from frappe/mergify/bp/version-16-hotfix/pr-52064
fix: strip whitespace in customer_name (backport #52064)
2026-01-26 15:32:27 +05:30
Shankarv19bcr
41e6687b35 fix: strip whitespace in customer_name
(cherry picked from commit e5ba0e6401)
2026-01-26 09:47:06 +00:00
MochaMind
55ce40de37 chore: update POT file (#52058) 2026-01-25 20:37:09 +01:00
ruthra kumar
6f21ab5d9a Merge pull request #52040 from frappe/mergify/bp/version-16-hotfix/pr-51670
fix: handle undefined bank_transaction_mapping in quick entry (backport #51670)
2026-01-25 13:11:28 +05:30
ruthra kumar
7c81672b36 Merge pull request #52041 from frappe/mergify/bp/version-16-hotfix/pr-51691
refactor: not warn when filter field is missing in FS reports (backport #51691)
2026-01-25 13:10:02 +05:30
ruthra kumar
d0faff09cb Merge pull request #52055 from frappe/mergify/bp/version-16-hotfix/pr-52050
fix: swedish_address_template (backport #52050)
2026-01-25 13:08:42 +05:30
mahsem
cff09b71cc fix: swedish_address_template
(cherry picked from commit 334e8ada30)
2026-01-25 05:22:41 +00:00
rohitwaghchaure
b180e3b78c Merge pull request #52053 from frappe/mergify/bp/version-16-hotfix/pr-52043
fix: UOM of item not fetching in BOM (backport #52043)
2026-01-25 10:50:38 +05:30
rohitwaghchaure
6ba2795043 Merge pull request #51905 from frappe/mergify/bp/version-16-hotfix/pr-51900
fix: validation to check at-least one raw material for manufacture entry (backport #51900)
2026-01-25 10:45:11 +05:30
Rohit Waghchaure
1b9a93f90e fix: UOM of item not fetching in BOM
(cherry picked from commit ba8eadda52)
2026-01-25 05:15:05 +00:00
rohitwaghchaure
1f1428f00a Merge branch 'version-16-hotfix' into mergify/bp/version-16-hotfix/pr-51900 2026-01-24 13:49:24 +05:30
Abdeali Chharchhoda
606ac2a91a refactor: not warn when filter field is missing in FS reports
(cherry picked from commit d905f78984)
2026-01-24 07:08:08 +00:00
Abdeali Chharchhoda
9a175757ac refactor: use console.error for error logging in Plaid integration
(cherry picked from commit 9322095786)
2026-01-24 07:07:48 +00:00
Abdeali Chharchhoda
22a8d483e1 fix: handle undefined bank_transaction_mapping in quick entry
(cherry picked from commit 8a1b8259bd)
2026-01-24 07:07:47 +00:00
Abdeali Chharchhoda
7abaaed957 refactor: remove redundant onload function for bank mapping table
(cherry picked from commit 7c7ba0154a)
2026-01-24 07:07:47 +00:00
mergify[bot]
8946f12677 fix: update country_wise_tax.json for Algerian Taxes (backport #51878) (#52038)
fix: update country_wise_tax.json for Algerian Taxes (#51878)

* Algeria chart of accounts

Algeria chart of accounts

* Update Algeria Chart Of Account

* Algeria chart of account

* Algeria Chart of Account

Algeria Chart of Account

* Modify Algeria tax entries in country_wise_tax.json

Updated tax rates and account names for Algeria.

* Rename account for Algeria tax from VAT to TVA

Rename account for Algeria tax from VAT to TVA

(cherry picked from commit e810cd8440)

Co-authored-by: HALFWARE <contact@half-ware.com>
2026-01-24 06:48:16 +00:00
mergify[bot]
e9f3f0f445 fix: Ensure paid_amount is always numeric before calling allocate_amount_to_references (backport #50935) (#52036)
fix: Ensure paid_amount is always numeric before calling allocate_amount_to_references (#50935)

fix: ensure paid_amount is not null in allocate_party_amount_against_ref_docs
(cherry picked from commit 50b3396064)

Co-authored-by: El-Shafei H. <el.shafei.developer@gmail.com>
2026-01-24 12:03:34 +05:30
ruthra kumar
ba38bc3eaf Merge pull request #52026 from frappe/mergify/bp/version-16-hotfix/pr-51756
fix: disable asset repair when status is fully depreciated (backport #51756)
2026-01-24 09:46:53 +05:30
rohitwaghchaure
b4572978f9 Merge pull request #52031 from frappe/mergify/bp/version-16-hotfix/pr-52024
fix: Bin reserved qty for production for extra material transfer (backport #52024)
2026-01-24 08:47:44 +05:30
Rohit Waghchaure
bf53133f94 fix: Bin reserved qty for production for extra material transfer
(cherry picked from commit f5378b6573)
2026-01-23 15:45:46 +00:00
Mihir Kandoi
23c902c317 Merge pull request #52022 from frappe/mergify/bp/version-16-hotfix/pr-51999
fix(stock): use purchase UOM in Supplier Quotation items (backport #51999)
2026-01-23 19:21:12 +05:30
SowmyaArunachalam
13e4849c43 fix: disable asset repair when status is fully depreciated
(cherry picked from commit 66fe1aa85d)
2026-01-23 11:38:39 +00:00
Bharathidhasan06
f97b850077 fix(stock): use purchase UOM in Supplier Quotation items
(cherry picked from commit 2606ca6fa9)
2026-01-23 08:34:36 +00:00
rohitwaghchaure
b3e12f9acb Merge pull request #52015 from frappe/mergify/bp/version-16-hotfix/pr-52006
fix: negative stock for purchase return (backport #52006)
2026-01-23 13:22:36 +05:30
Rohit Waghchaure
fb3fb8ca5e fix: negative stock for purchae return
(cherry picked from commit d68a04ad16)
2026-01-23 06:04:02 +00:00
rohitwaghchaure
e2232340dc Merge pull request #52005 from frappe/mergify/bp/version-16-hotfix/pr-51989
fix: autofill warehouse for packed items (backport #51989)
2026-01-22 23:56:30 +05:30
Sudharsanan11
881562fc37 fix: autofill warehouse for packed items
(cherry picked from commit 3f8a0a4833)
2026-01-22 17:28:22 +00:00
Mihir Kandoi
dcd6279d47 Merge pull request #51983 from frappe/mergify/bp/version-16-hotfix/pr-51908
fix: throw if item order field is not set in subcontracting controller (backport #51908)
2026-01-22 10:53:05 +05:30
Mihir Kandoi
041a7c5a57 Merge pull request #51982 from frappe/mergify/bp/version-16-hotfix/pr-51929
fix: calculate weighted average rate for customer provided items in subcontracting inward order (backport #51929)
2026-01-22 10:51:54 +05:30
Mihir Kandoi
27ffef41a7 Merge pull request #51980 from frappe/mergify/bp/version-16-hotfix/pr-51966
fix(customer): add customer group filters (backport #51966)
2026-01-22 10:42:45 +05:30
Mihir Kandoi
9038f19fb6 Merge pull request #51978 from frappe/mergify/bp/version-16-hotfix/pr-51967
fix(project): add missing counter to project update naming series (backport #51967)
2026-01-22 10:38:33 +05:30
ljain112
264855e5e1 fix: throw if item order field is not set in subcontracting controller
(cherry picked from commit d256365f4a)
2026-01-22 05:05:22 +00:00
ljain112
7120fbd14b fix: calculate weighted average rate for customer provided items in subcontracting inward order
(cherry picked from commit 37ee560eae)
2026-01-22 05:02:16 +00:00
SowmyaArunachalam
b1716bfeef fix(customer): add customer group filters
(cherry picked from commit 1e3db9f916)
2026-01-22 04:57:04 +00:00
ravibharathi656
37a237dbb7 fix(project): add missing counter to project update naming series
(cherry picked from commit 49e64f4e1c)
2026-01-22 04:53:10 +00:00
Mihir Kandoi
be9112b6fc Merge pull request #51972 from frappe/mergify/bp/version-16-hotfix/pr-51968 2026-01-22 09:04:25 +05:30
Mihir Kandoi
2f240f3553 Merge pull request #51970 from frappe/mergify/bp/version-16-hotfix/pr-51964
fix: create DN btn should not be shown if it cannot be created (backport #51964)
2026-01-21 22:54:50 +05:30
Mihir Kandoi
c7c7a55a58 fix: rejected qty in PR doesn't consider conversion factor
(cherry picked from commit 343ee9695b)
2026-01-21 17:21:00 +00:00
Mihir Kandoi
30e6b5daac fix: create DN btn should not be shown if it cannot be created
(cherry picked from commit 70ec977cb2)
2026-01-21 17:09:48 +00:00
Mihir Kandoi
0b5cc039b6 Merge pull request #51962 from frappe/mergify/bp/version-16-hotfix/pr-51958
fix!: force user to enter batch or serial for serial/batch items (backport #51958)
2026-01-21 16:38:31 +05:30
Mihir Kandoi
6fa60d2f1a fix: tests
(cherry picked from commit 035b3cb61e)
2026-01-21 10:53:46 +00:00
Mihir Kandoi
91199ea9c9 fix: force user to enter batch or serial for serial/batch items
(cherry picked from commit 7170a1bd78)
2026-01-21 10:53:46 +00:00
Mihir Kandoi
e23ba0e852 Merge pull request #51960 from frappe/mergify/bp/version-16-hotfix/pr-51947
fix: job cards should not be deleted on close of WO (backport #51947)
2026-01-21 16:03:09 +05:30
Mihir Kandoi
7c2bbe0d82 fix: job cards should not be deleted on close of WO
(cherry picked from commit c919b1de38)
2026-01-21 10:17:16 +00:00
Mihir Kandoi
0a2234a814 Merge pull request #51951 from frappe/mergify/bp/version-16-hotfix/pr-51948
fix: warehouse permissions in MR incorrectly ignored (backport #51948)
2026-01-21 14:05:14 +05:30
Mihir Kandoi
504c84e28a fix: warehouse permissions in MR incorrectly ignored
(cherry picked from commit 5bacb67d36)
2026-01-21 07:36:22 +00:00
ruthra kumar
bb2bada1fd Merge pull request #51945 from ruthra-kumar/reenable_auto_close
chore: reenable auto close
2026-01-21 10:16:58 +05:30
ruthra kumar
ca85ee33f5 chore: reenable auto close 2026-01-21 10:13:32 +05:30
ruthra kumar
21c1189e24 Merge pull request #51944 from ruthra-kumar/remove_junk_comment
chore: remove stray comment and disable auto close
2026-01-21 10:10:35 +05:30
ruthra kumar
7e7885b304 chore: remove stray comment and disable auto close 2026-01-21 10:09:03 +05:30
Frappe PR Bot
30238e3063 chore(release): Bumped to Version 16.1.0
# [16.1.0](https://github.com/frappe/erpnext/compare/v16.0.1...v16.1.0) (2026-01-20)

### Bug Fixes

* **accounts_controller:** make return message translatable ([621243c](621243c1d3))
* **accounts:** add missing accounting dimensions in advance taxes and charges ([673635e](673635e2c3))
* add below-0 column in ar/ap report (backport [#51673](https://github.com/frappe/erpnext/issues/51673)) ([#51780](https://github.com/frappe/erpnext/issues/51780)) ([5c93bf5](5c93bf5798))
* add company filters for warehouse ([ccab91b](ccab91b9ed))
* add other charges in total ([68c8dfb](68c8dfb24c))
* add uom js error ([a660ed0](a660ed061b))
* add validation for amount and hours ([ce421bb](ce421bb1d4))
* add validation for direct return ([bfd6375](bfd6375508))
* add validation for duplication ([84a749e](84a749e3d0))
* add validation for return against ([6dade11](6dade11d8f))
* allow creation of DN in SI for items not having DN reference ([fef6df7](fef6df709d))
* allow disassemble stock entry without work order (backport [#51761](https://github.com/frappe/erpnext/issues/51761)) ([#51836](https://github.com/frappe/erpnext/issues/51836)) ([c830bf6](c830bf6fc7))
* **bank_account:** validation for is_company_account ([5d5d208](5d5d208a49))
* **bom:** pass company warehouse filter ([3c533d0](3c533d04f5))
* **budget variance report:** check budget dimensions ([a3d860e](a3d860eabf))
* bugs ([accce1f](accce1fe59))
* calculate net profit amount from root node accounts ([89b44c4](89b44c41a2))
* change docfield type to render html format (backport [#51795](https://github.com/frappe/erpnext/issues/51795)) ([#51804](https://github.com/frappe/erpnext/issues/51804)) ([fcea760](fcea7603a8))
* common_party_path ([#51826](https://github.com/frappe/erpnext/issues/51826)) ([aeb2b60](aeb2b60450))
* continuous raw material consumption with bom validation (backport [#51914](https://github.com/frappe/erpnext/issues/51914)) ([#51919](https://github.com/frappe/erpnext/issues/51919)) ([c9d7c6c](c9d7c6cd42))
* docs_path ([86d5939](86d5939d91))
* dont show certain fields based on permissions ([d3dfed9](d3dfed909e))
* handle return cancellation ([65a1c70](65a1c7086b))
* include total hours validation in depends on ([cbfc137](cbfc13728b))
* **manufacturing:** consider process loss qty while validating the work order ([7b3f746](7b3f74609a))
* no attribute error on LCV ([fe59ace](fe59ace285))
* no attribute error on subcontracting receipt ([2131c7a](2131c7aadb))
* overproduction % not considered when making WO from SO ([fb669eb](fb669eb6f4))
* **pos:** reapply set warehouse during cart update ([6869115](686911546f))
* **postgres:** compute current month sales without DATE_FORMAT ([49760e4](49760e4542))
* prevent UOM from updating incorrectly while scanning barcode ([9d5a0e5](9d5a0e56a0))
* qty with serial no count ([ae6b3af](ae6b3af013))
* remove already transferred batch ([f1e41f4](f1e41f4a4f))
* setting process loss qty causes fg item qty to be incorrect ([cb2d455](cb2d4550af))
* Show non-SLE vouchers with GL entries in Stock vs Account Value Comparison report ([e64ae9a](e64ae9a8a9))
* **stock:** resolve quantity issue when adding items via barcode scan ([ab482ca](ab482caac9))
* **transaction.js:** use flt instead of cint for plc_conversion_rate ([8ba4701](8ba470160d))
* validation message in stock reco row idx ([176096b](176096bc5b))
* valuation rate for non batchwise valuation ([768c131](768c131073))

### Features

* add list_view status for partial billing ([9b88275](9b88275312))
* add new 2025 Charts of Accounts for France ([9cc9fa5](9cc9fa59be))
* Adding Item name in update item dialog box ([1da8ed2](1da8ed202b))
* modify field properties ([e49add2](e49add20b7))
* remove old French chart of accounts with code as nex 2025 is provided ([3bdaab1](3bdaab149b))
* support for serial item ([c4c2d35](c4c2d35565))
* **timesheet:** handle partial billing in sales invoice ([332673f](332673f260))

### Performance Improvements

* prevent duplicate reposting for the same item ([3ac431b](3ac431bd50))
2026-01-20 16:47:59 +00:00
ruthra kumar
35b3045b72 Merge pull request #51911 from frappe/version-16-hotfix
chore: release v16
2026-01-20 22:16:27 +05:30
Mihir Kandoi
cf130ff865 Merge pull request #51936 from frappe/mergify/bp/version-16-hotfix/pr-51934
fix: validation message in stock reco row idx (backport #51934)
2026-01-20 21:05:40 +05:30
Mihir Kandoi
176096bc5b fix: validation message in stock reco row idx
(cherry picked from commit 3960c01798)
2026-01-20 15:17:53 +00:00
rohitwaghchaure
e854eafc0b Merge pull request #51933 from frappe/mergify/bp/version-16-hotfix/pr-51930
Revert "perf: prevent duplicate reposting for the same item" (backport #51930)
2026-01-20 20:05:41 +05:30
rohitwaghchaure
72cdddbeda Revert "perf: prevent duplicate reposting for the same item"
(cherry picked from commit 6e4b90055f)
2026-01-20 14:19:47 +00:00
mergify[bot]
c9d7c6cd42 fix: continuous raw material consumption with bom validation (backport #51914) (#51919)
Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2026-01-20 12:56:27 +00:00
Diptanil Saha
8393c3c32d Merge pull request #51922 from frappe/mergify/bp/version-16-hotfix/pr-51887
fix(bank_account): `is_company_account` related validations (backport #51887)
2026-01-20 18:09:01 +05:30
Mihir Kandoi
5752d2e0a1 Merge pull request #51926 from frappe/mergify/bp/version-16-hotfix/pr-51909
fix: allow creation of DN in SI for items not having DN reference (backport #51909)
2026-01-20 18:03:35 +05:30
rohitwaghchaure
f25558b4d7 Merge pull request #51924 from frappe/mergify/bp/version-16-hotfix/pr-51920
perf: prevent duplicate reposting for the same item (backport #51920)
2026-01-20 18:01:21 +05:30
Mihir Kandoi
fef6df709d fix: allow creation of DN in SI for items not having DN reference
(cherry picked from commit b691de0147)
2026-01-20 12:14:59 +00:00
Rohit Waghchaure
3ac431bd50 perf: prevent duplicate reposting for the same item
(cherry picked from commit 7535931571)
2026-01-20 12:09:03 +00:00
diptanilsaha
5d5d208a49 fix(bank_account): validation for is_company_account
(cherry picked from commit 7532ab01d6)
2026-01-20 11:53:16 +00:00
ruthra kumar
9535f3d583 Merge pull request #51916 from frappe/mergify/bp/version-16-hotfix/pr-51671
fix(accounts): add missing accounting dimensions in advance taxes and charges (backport #51671)
2026-01-20 17:19:35 +05:30
Nikhil Kothari
673635e2c3 fix(accounts): add missing accounting dimensions in advance taxes and charges
(cherry picked from commit 22e9cb4cf4)

# Conflicts:
#	erpnext/patches.txt
2026-01-20 17:04:51 +05:30
Rohit Waghchaure
d067e37ab6 fix: validation to check at-least one raw material for manufacture entry
(cherry picked from commit f003b3c378)
2026-01-20 08:25:59 +00:00
Mihir Kandoi
37e241ba15 Merge pull request #51897 from frappe/mergify/bp/version-16-hotfix/pr-51895
fix: overproduction % not considered when making WO from SO (backport #51895)
2026-01-20 13:25:01 +05:30
Mihir Kandoi
fb669eb6f4 fix: overproduction % not considered when making WO from SO
(cherry picked from commit edba9efb5e)
2026-01-20 07:34:24 +00:00
ruthra kumar
232225d753 Merge pull request #51891 from frappe/mergify/bp/version-16-hotfix/pr-51561
fix: delete advance ledger entries  while reconciling payment entry (backport #51561)
2026-01-20 08:17:44 +05:30
ruthra kumar
80cbd851d1 Merge pull request #51893 from frappe/mergify/bp/version-16-hotfix/pr-51886
fix(accounts_controller): make return message translatable (backport #51886)
2026-01-20 08:13:12 +05:30
ruthra kumar
5474ac298d Merge pull request #51884 from frappe/mergify/bp/version-16-hotfix/pr-51830
fix(manufacturing): consider process loss qty while validating the work order (backport #51830)
2026-01-20 08:08:29 +05:30
ruthra kumar
7a9b10a05e Merge pull request #51861 from frappe/mergify/bp/version-16-hotfix/pr-51822
fix(budget variance report): check budget dimensions (backport #51822)
2026-01-20 07:56:49 +05:30
barredterra
621243c1d3 fix(accounts_controller): make return message translatable
(cherry picked from commit 0209f0fe29)
2026-01-20 02:26:48 +00:00
Lakshit Jain
efa5173964 Merge pull request #51561 from ljain112/fic-adv-ple-po
fix: delete advance ledger entries  while reconciling payment entry
(cherry picked from commit aea70c5ec1)
2026-01-20 02:21:34 +00:00
Sudharsanan11
7b3f74609a fix(manufacturing): consider process loss qty while validating the work order
(cherry picked from commit e6366e830c)
2026-01-19 16:18:36 +00:00
Mihir Kandoi
775f6d07b1 Merge pull request #51882 from frappe/mergify/bp/version-16-hotfix/pr-51880
fix: no attribute error on LCV (backport #51880)
2026-01-19 20:30:03 +05:30
Mihir Kandoi
e80ed14456 Merge pull request #51881 from frappe/mergify/bp/version-16-hotfix/pr-51879
fix: no attribute error on subcontracting receipt (backport #51879)
2026-01-19 20:15:55 +05:30
Mihir Kandoi
fe59ace285 fix: no attribute error on LCV
(cherry picked from commit ad11914fca)
2026-01-19 14:35:22 +00:00
Mihir Kandoi
2131c7aadb fix: no attribute error on subcontracting receipt
(cherry picked from commit fbac8b032e)
2026-01-19 14:30:08 +00:00
Diptanil Saha
b7284c7717 Merge pull request #51877 from frappe/mergify/bp/version-16-hotfix/pr-51595 2026-01-19 18:12:07 +05:30
Florian HENRY
6b9107c05c chore: re add older template
(cherry picked from commit b3efb3084f)
2026-01-19 12:23:31 +00:00
Florian HENRY
1ed8857d31 chore: fix bank account type
(cherry picked from commit 4fe1b214c1)
2026-01-19 12:23:31 +00:00
Florian HENRY
a195690bc8 chore: fix CASH acount type
(cherry picked from commit 6a876de838)
2026-01-19 12:23:31 +00:00
Florian HENRY
0c546c9e5a chore: fix bank acount type
(cherry picked from commit 765487a087)
2026-01-19 12:23:30 +00:00
Florian HENRY
11d9fd3dee chore: add Expenses Included In Valuation account
(cherry picked from commit c519cd0268)
2026-01-19 12:23:30 +00:00
Florian HENRY
3bdaab149b feat: remove old French chart of accounts with code as nex 2025 is provided
(cherry picked from commit bf430fce09)
2026-01-19 12:23:30 +00:00
Florian HENRY
ad4ac4e53c chore: Review PR #51595
(cherry picked from commit 6bdaeb983d)
2026-01-19 12:23:30 +00:00
Florian HENRY
9cc9fa59be feat: add new 2025 Charts of Accounts for France
(cherry picked from commit c81dee137f)
2026-01-19 12:23:30 +00:00
rohitwaghchaure
ab2aedd9a2 Merge pull request #51866 from frappe/mergify/bp/version-16-hotfix/pr-51769
fix(pos): reapply set warehouse during cart update (backport #51769)
2026-01-19 15:44:38 +05:30
ravibharathi656
686911546f fix(pos): reapply set warehouse during cart update
(cherry picked from commit 5a53c45321)
2026-01-19 10:07:50 +00:00
rohitwaghchaure
4f3078ab1a Merge pull request #51863 from frappe/mergify/bp/version-16-hotfix/pr-51690
feat: Adding Item name in update item dialog box (backport #51690)
2026-01-19 15:34:47 +05:30
rohitwaghchaure
a950adab79 Merge pull request #51864 from frappe/mergify/bp/version-16-hotfix/pr-51856
fix: qty with serial no count (backport #51856)
2026-01-19 15:34:23 +05:30
Rohit Waghchaure
ae6b3af013 fix: qty with serial no count
(cherry picked from commit 56e58ef301)
2026-01-19 10:00:35 +00:00
Nishka Gosalia
1da8ed202b feat: Adding Item name in update item dialog box
(cherry picked from commit e6133ad6d4)
2026-01-19 10:00:34 +00:00
ervishnucs
a3d860eabf fix(budget variance report): check budget dimensions
(cherry picked from commit cb696a8880)
2026-01-19 09:55:17 +00:00
rohitwaghchaure
adc9dc82ca Merge pull request #51848 from frappe/mergify/bp/version-16-hotfix/pr-51644
Refactor batch bundle get snos sle (backport #51644)
2026-01-19 15:15:20 +05:30
Rohit Waghchaure
79e04ea1fe chore: fix semantic commit message
(cherry picked from commit dfcbee9cc0)
2026-01-19 09:22:45 +00:00
krupalvora
0981b894dd refactor: Batch & Bundle get sle for snos - Added docstring
(cherry picked from commit 22dee50348)
2026-01-19 09:22:45 +00:00
krupalvora
380564a677 refactor: Batch & Bundle get Stock ledger for snos - added posting date in select
(cherry picked from commit 1ccc7365a7)
2026-01-19 09:22:45 +00:00
krupalvora
75deb180fb refactor: Batch & Bundle get Stock ledger for snos v2
(cherry picked from commit a074d81754)
2026-01-19 09:22:45 +00:00
krupalvora
839315752b refactor: Batch & Bundle get Stock ledger for snos
(cherry picked from commit c0149925ad)
2026-01-19 09:22:44 +00:00
Mihir Kandoi
2b4a547e23 Merge pull request #51847 from frappe/mergify/bp/version-16-hotfix/pr-51845
fix(bom): pass company warehouse filter (backport #51845)
2026-01-19 14:18:39 +05:30
22-poojashree
3c533d04f5 fix(bom): pass company warehouse filter
(cherry picked from commit 73bcfc4710)
2026-01-19 08:34:16 +00:00
ruthra kumar
1c214eec98 Merge pull request #51844 from frappe/mergify/bp/version-16-hotfix/pr-51826
fix: common_party_path (backport #51826)
2026-01-19 13:21:14 +05:30
mahsem
aeb2b60450 fix: common_party_path (#51826)
* fix: common_pary_path

* chore: remove non-existent anchor

---------

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
(cherry picked from commit 0c0f43f7f7)
2026-01-19 07:50:30 +00:00
ruthra kumar
1b3f5e1c96 Merge pull request #51841 from frappe/mergify/bp/version-16-hotfix/pr-51513
fix: calculate net profit amount from root node accounts (backport #51513)
2026-01-19 13:05:56 +05:30
mergify[bot]
c830bf6fc7 fix: allow disassemble stock entry without work order (backport #51761) (#51836)
fix: allow disassemble stock entry without work order (#51761)

* fix: allow disassemble stock entry without work order

* fix: use existing functionality to load fg item

* chore: better dict update

(cherry picked from commit 83919119f8)

Co-authored-by: Smit Vora <smitvora203@gmail.com>
2026-01-19 12:54:06 +05:30
ruthra kumar
e2b95da24d Merge pull request #51839 from frappe/mergify/bp/version-16-hotfix/pr-51787
fix: recalculate taxes when item tax template changes after discount (backport #51787)
2026-01-19 12:50:34 +05:30
Navin-S-R
89b44c41a2 fix: calculate net profit amount from root node accounts
(cherry picked from commit c84986d00e)
2026-01-19 07:15:50 +00:00
Lakshit Jain
181141b56a Merge pull request #51787 from ljain112/fix-taxes-disc
fix: recalculate taxes when item tax template changes after discount
(cherry picked from commit f00aeec9b4)
2026-01-19 07:01:52 +00:00
ruthra kumar
5742a5d86a Merge pull request #51834 from frappe/mergify/bp/version-16-hotfix/pr-51742
fix: add other charges in total (backport #51742)
2026-01-19 11:34:22 +05:30
SowmyaArunachalam
68c8dfb24c fix: add other charges in total
(cherry picked from commit 9406c07c42)
2026-01-19 05:45:20 +00:00
Mihir Kandoi
7f54de7926 Merge pull request #51829 from frappe/mergify/bp/version-16-hotfix/pr-51824
fix: setting process loss qty causes fg item qty to be incorrect (backport #51824)
2026-01-18 22:51:58 +05:30
Mihir Kandoi
cb2d4550af fix: setting process loss qty causes fg item qty to be incorrect
(cherry picked from commit 56f5df6847)
2026-01-18 17:21:03 +00:00
Mihir Kandoi
c22d7e16d1 Merge pull request #51821 from frappe/mergify/bp/version-16-hotfix/pr-51817
fix: prevent UOM from updating incorrectly while scanning barcode (backport #51817)
2026-01-18 15:10:56 +05:30
Pandiyan5273
9d5a0e56a0 fix: prevent UOM from updating incorrectly while scanning barcode
(cherry picked from commit 30263b26a5)
2026-01-18 09:36:44 +00:00
mergify[bot]
fcea7603a8 fix: change docfield type to render html format (backport #51795) (#51804)
fix: change docfield type to render html format (#51795)

(cherry picked from commit 3fe5b5c80d)

Co-authored-by: Sowmya <106989392+SowmyaArunachalam@users.noreply.github.com>
2026-01-17 15:12:57 +05:30
ruthra kumar
42ebb7446a Merge pull request #51797 from frappe/mergify/bp/version-16-hotfix/pr-51555
fix(postgres): compute current month sales without DATE_FORMAT (backport #51555)
2026-01-16 17:15:48 +05:30
Matt Howard
49760e4542 fix(postgres): compute current month sales without DATE_FORMAT
(cherry picked from commit 64f391adf7)
2026-01-16 11:29:08 +00:00
Mihir Kandoi
6e1f4d84b6 Merge pull request #51794 from frappe/mergify/bp/version-16-hotfix/pr-51790
fix(stock): resolve quantity issue when adding items via barcode scan (backport #51790)
2026-01-16 16:20:37 +05:30
Pandiyan5273
ab482caac9 fix(stock): resolve quantity issue when adding items via barcode scan
(cherry picked from commit f959b2c59a)
2026-01-16 10:49:36 +00:00
Mihir Kandoi
d8506fb2c0 Merge pull request #51792 from frappe/mergify/bp/version-16-hotfix/pr-51791
fix: dont show certain fields based on permissions (backport #51791)
2026-01-16 16:02:37 +05:30
Mihir Kandoi
d3dfed909e fix: dont show certain fields based on permissions
(cherry picked from commit b3db2981de)
2026-01-16 10:31:39 +00:00
Mihir Kandoi
ac31c5ca19 Merge pull request #51789 from frappe/mergify/bp/version-16-hotfix/pr-51784
fix: add company filters for warehouse (backport #51784)
2026-01-16 15:16:05 +05:30
SowmyaArunachalam
ccab91b9ed fix: add company filters for warehouse
(cherry picked from commit f952b92d71)
2026-01-16 09:44:42 +00:00
Mihir Kandoi
541a8b135a Merge pull request #51785 from frappe/mergify/bp/version-16-hotfix/pr-51693 2026-01-16 14:09:49 +05:30
Mihir Kandoi
c0a30a5302 chore: typo
(cherry picked from commit 8fd1d6aec8)
2026-01-16 08:25:03 +00:00
Mihir Kandoi
accce1fe59 fix: bugs
(cherry picked from commit 19ae405742)
2026-01-16 08:25:03 +00:00
Mihir Kandoi
f04221417e test: add test case
(cherry picked from commit b567184dd7)
2026-01-16 08:25:03 +00:00
Mihir Kandoi
c4c2d35565 feat: support for serial item
(cherry picked from commit 3d0f649411)
2026-01-16 08:25:02 +00:00
Mihir Kandoi
f1e41f4a4f fix: remove already transferred batch
(cherry picked from commit b54067e04d)
2026-01-16 08:25:02 +00:00
Mihir Kandoi
d9326d80de refactor: sample retention stock entry
(cherry picked from commit 8d188cd32b)
2026-01-16 08:25:02 +00:00
ruthra kumar
5c93bf5798 fix: add below-0 column in ar/ap report (backport #51673) (#51780)
Merge pull request #51673 from Jatin3128/ar/ap-future-range-fix

fix: add below-0 column in ar/ap report
(cherry picked from commit c5b0787de6)

Co-authored-by: Jatin3128 <140256508+Jatin3128@users.noreply.github.com>
2026-01-16 12:46:26 +05:30
Jatin3128
f62ad83d6f Merge pull request #51673 from Jatin3128/ar/ap-future-range-fix
fix: add below-0 column in ar/ap report
(cherry picked from commit c5b0787de6)
2026-01-16 06:37:34 +00:00
Ankush Menat
876e2d4e6e build: Update Frappe dependency (#51779) 2026-01-16 11:24:43 +05:30
rohitwaghchaure
4977e06c50 Merge pull request #51772 from frappe/mergify/bp/version-16-hotfix/pr-51768
fix: Show non-SLE vouchers with GL entries in Stock vs Account Value … (backport #51768)
2026-01-15 19:26:45 +05:30
Rohit Waghchaure
e64ae9a8a9 fix: Show non-SLE vouchers with GL entries in Stock vs Account Value Comparison report
(cherry picked from commit 1db9ce205f)
2026-01-15 12:20:36 +00:00
rohitwaghchaure
6ddf4eee15 Merge pull request #51752 from frappe/mergify/bp/version-16-hotfix/pr-51729
fix: valuation rate for non batchwise valuation (backport #51729)
2026-01-15 17:00:32 +05:30
Mihir Kandoi
d27a09cb9f Merge pull request #51755 from frappe/mergify/bp/version-16-hotfix/pr-51753
fix: docs_path (backport #51753)
2026-01-14 21:31:31 +05:30
mahsem
86d5939d91 fix: docs_path
(cherry picked from commit 7ef8c81caf)
2026-01-14 16:00:03 +00:00
Rohit Waghchaure
768c131073 fix: valuation rate for non batchwise valuation
(cherry picked from commit b6312bca9c)
2026-01-14 14:06:50 +00:00
Diptanil Saha
8f77223057 Merge pull request #51748 from frappe/mergify/bp/version-16-hotfix/pr-51730
fix(transaction.js): use flt instead of cint for plc_conversion_rate (backport #51730)
2026-01-14 15:55:13 +05:30
diptanilsaha
8ba470160d fix(transaction.js): use flt instead of cint for plc_conversion_rate
(cherry picked from commit 8b445e04e5)
2026-01-14 10:22:21 +00:00
Mihir Kandoi
1a6264d831 Merge pull request #51737 from frappe/mergify/bp/version-16-hotfix/pr-51684 2026-01-14 11:37:00 +05:30
Mihir Kandoi
19a90c0980 Merge pull request #51736 from frappe/mergify/bp/version-16-hotfix/pr-51295 2026-01-14 11:18:57 +05:30
Pandiyan5273
d57fc49896 test(stock-entry): manufacture entry without work order
(cherry picked from commit 784e338be4)
2026-01-14 05:34:40 +00:00
l0gesh29
fe0431a6d0 chore: modify error msg
(cherry picked from commit f7004aa8c3)
2026-01-14 05:33:39 +00:00
l0gesh29
bfd6375508 fix: add validation for direct return
(cherry picked from commit 8379b39aaf)
2026-01-14 05:33:38 +00:00
l0gesh29
6dade11d8f fix: add validation for return against
(cherry picked from commit ff9b936634)
2026-01-14 05:33:38 +00:00
Logesh Periyasamy
ce421bb1d4 fix: add validation for amount and hours
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
(cherry picked from commit 43d1d685c6)
2026-01-14 05:33:38 +00:00
l0gesh29
84a749e3d0 fix: add validation for duplication
(cherry picked from commit cda8a97f4a)
2026-01-14 05:33:37 +00:00
l0gesh29
65a1c7086b fix: handle return cancellation
(cherry picked from commit 50f73a5072)
2026-01-14 05:33:37 +00:00
l0gesh29
a04da71182 test: add test for partial billing and return
(cherry picked from commit ae594e81f9)
2026-01-14 05:33:37 +00:00
l0gesh29
cbfc13728b fix: include total hours validation in depends on
(cherry picked from commit 57d34ab146)
2026-01-14 05:33:37 +00:00
l0gesh29
9b88275312 feat: add list_view status for partial billing
(cherry picked from commit ff0b37055b)
2026-01-14 05:33:36 +00:00
l0gesh29
332673f260 feat(timesheet): handle partial billing in sales invoice
(cherry picked from commit c87b5d3132)
2026-01-14 05:33:36 +00:00
l0gesh29
e49add20b7 feat: modify field properties
(cherry picked from commit 38a4642479)
2026-01-14 05:33:36 +00:00
Mihir Kandoi
c3b0633eda Merge pull request #51734 from frappe/mergify/bp/version-16-hotfix/pr-51733
fix: add uom js error (backport #51733)
2026-01-14 10:28:24 +05:30
Mihir Kandoi
a660ed061b fix: add uom js error
(cherry picked from commit 6d3f6d73d0)
2026-01-14 04:55:22 +00:00
Frappe PR Bot
0b1c0c36b5 chore(release): Bumped to Version 16.0.1
## [16.0.1](https://github.com/frappe/erpnext/compare/v16.0.0...v16.0.1) (2026-01-13)

### Bug Fixes

* **asset value adjustment:** skip cancelling revaluation journal entry if already cancelled (backport [#51666](https://github.com/frappe/erpnext/issues/51666)) ([#51716](https://github.com/frappe/erpnext/issues/51716)) ([4b85d51](4b85d51257))
* Redirect to Desktop after signup ([#51696](https://github.com/frappe/erpnext/issues/51696)) ([0363b01](0363b01ab7))
* Redirect to Desktop after signup ([#51696](https://github.com/frappe/erpnext/issues/51696)) ([#51697](https://github.com/frappe/erpnext/issues/51697)) ([294fb27](294fb27dc8))
* Redirect to Desktop after signup (backport [#51696](https://github.com/frappe/erpnext/issues/51696)) ([#51714](https://github.com/frappe/erpnext/issues/51714)) ([2118321](211832104c))
* stock module not opened when no warehouses ([3420e21](3420e21d45))
* **tds:** correct tax logic for customer ([50ce61a](50ce61ae02))
2026-01-13 16:20:34 +00:00
Mihir Kandoi
d316ef2306 Merge pull request #51728 from frappe/trigger-release-v16 2026-01-13 21:44:48 +05:30
Mihir Kandoi
af3a7903b3 chore: trigger release 2026-01-13 21:43:30 +05:30
Mihir Kandoi
a66e114a71 Merge pull request #51727 from frappe/change-release-branch 2026-01-13 21:34:26 +05:30
Mihir Kandoi
631b9d3bb0 chore: update release branch from version-13 to version-16 2026-01-13 20:32:48 +05:30
Mihir Kandoi
eb03781718 Merge pull request #51713 from frappe/version-16-hotfix 2026-01-13 20:17:06 +05:30
rohitwaghchaure
eb7cebac91 Merge pull request #51720 from frappe/mergify/bp/version-16-hotfix/pr-51719
fix: stock module not opened when no warehouses (backport #51719)
2026-01-13 17:38:25 +05:30
Rohit Waghchaure
3420e21d45 fix: stock module not opened when no warehouses
(cherry picked from commit 9de3b07223)
2026-01-13 11:49:56 +00:00
Mihir Kandoi
211832104c fix: Redirect to Desktop after signup (backport #51696) (#51714)
Co-authored-by: Nabin Hait <nabinhait@gmail.com>
fix: Redirect to Desktop after signup (#51696)
2026-01-13 16:07:20 +05:30
mergify[bot]
4b85d51257 fix(asset value adjustment): skip cancelling revaluation journal entry if already cancelled (backport #51666) (#51716)
Co-authored-by: Navin-S-R <navin@aerele.in>
2026-01-13 16:05:14 +05:30
Nabin Hait
0363b01ab7 fix: Redirect to Desktop after signup (#51696)
(cherry picked from commit 3bc58fb46f)
2026-01-13 09:46:21 +00:00
Mihir Kandoi
fc517f7fa2 Merge pull request #51707 from mihir-kandoi/ci-patch-test-2 2026-01-13 15:11:37 +05:30
ruthra kumar
18451b69e6 Merge pull request #51703 from frappe/mergify/bp/version-16-hotfix/pr-51412
fix(tds): correct tax logic for customer (backport #51412)
2026-01-13 11:41:28 +05:30
ljain112
50ce61ae02 fix(tds): correct tax logic for customer
(cherry picked from commit 86b0f67dbc)
2026-01-13 05:37:32 +00:00
Nabin Hait
294fb27dc8 fix: Redirect to Desktop after signup (#51696) (#51697) 2026-01-12 19:22:24 +05:30
Rohit Waghchaure
c3fdb191b9 Merge branch 'develop' into version-16 2026-01-12 16:20:48 +05:30
Rohit Waghchaure
93db2ebd6f Merge branch 'develop' into version-16 2026-01-12 15:07:27 +05:30
rohitwaghchaure
2925f9a04e chore: weekly release for v16 2026-01-12 14:29:14 +05:30
rohitwaghchaure
c7bf103c0c chore: fix version 2026-01-12 14:04:45 +05:30
rohitwaghchaure
6dead8fd85 chore: fix version 2026-01-12 12:19:58 +05:30
1025 changed files with 149790 additions and 213605 deletions

View File

@@ -15,7 +15,7 @@ jobs:
strategy:
fail-fast: false
matrix:
branch: ["develop", "version-16-hotfix"]
branch: ["develop"]
permissions:
contents: write
@@ -30,11 +30,6 @@ jobs:
with:
python-version: "3.14"
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 24
- name: Run script to update POT file
run: |
bash ${GITHUB_WORKSPACE}/.github/helper/update_pot_file.sh

View File

@@ -8,8 +8,8 @@ permissions:
on:
schedule:
# 9:30 UTC => 3 PM IST
- cron: "30 9 * * 1,4"
# 9:30 UTC => 3 PM IST Tuesday
- cron: "30 9 * * 2"
workflow_dispatch:
jobs:
@@ -19,7 +19,7 @@ jobs:
strategy:
fail-fast: false
matrix:
version: ["15", "16"]
version: ["14", "15", "16"]
steps:
- uses: octokit/request-action@v2.x

View File

@@ -143,7 +143,6 @@ jobs:
}
update_to_version 15 3.13
update_to_version 16 3.14
echo "Updating to latest version"
git -C "apps/frappe" fetch --depth 1 upstream "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}"

View File

@@ -2,7 +2,7 @@ name: Generate Semantic Release
on:
push:
branches:
- version-13
- version-16
permissions:
contents: read

View File

@@ -4,8 +4,8 @@ on:
workflow_dispatch:
concurrency:
group: server-individual-tests-lightmode-develop
cancel-in-progress: true
group: server-individual-tests-develop-${{ github.event_name }}-${{ github.event.number || github.event_name == 'workflow_dispatch' && github.run_id || '' }}
cancel-in-progress: false
permissions:
contents: read
@@ -21,7 +21,7 @@ jobs:
- id: set-matrix
run: |
# Use grep and find to get the list of test files
matrix=$(find . -path '*/test_*.py' | xargs grep -l 'def test_' | sort | awk '{
matrix=$(find . -path '*/doctype/*/test_*.py' | xargs grep -l 'def test_' | awk '{
# Remove ./ prefix, file extension, and replace / with .
gsub(/^\.\//, "", $0)
gsub(/\.py$/, "", $0)
@@ -58,7 +58,6 @@ jobs:
strategy:
fail-fast: false
matrix: ${{fromJson(needs.discover.outputs.matrix)}}
max-parallel: 14
name: Test
@@ -131,13 +130,4 @@ jobs:
FRAPPE_BRANCH: ${{ github.event.inputs.branch }}
- name: Run Tests
run: |
site_name=$(echo "${{matrix.test}}" | sed -e 's/.*\.\(test_.*$\)/\1/')
echo "$site_name"
mkdir ~/frappe-bench/sites/$site_name
cp -r "${GITHUB_WORKSPACE}/.github/helper/site_config_mariadb.json" ~/frappe-bench/sites/$site_name/site_config.json
cd ~/frappe-bench/
bench --site $site_name reinstall --yes
bench --site $site_name set-config allow_tests true
bench --site $site_name run-tests --module ${{ matrix.test }} --lightmode
run: 'cd ~/frappe-bench/ && bench --site test_site run-tests --app erpnext --module ${{ matrix.test }}'

View File

@@ -129,7 +129,7 @@ jobs:
FRAPPE_BRANCH: ${{ github.event.client_payload.sha || github.event.inputs.branch }}
- name: Run Tests
run: 'cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --lightmode --app erpnext --total-builds ${{ strategy.job-total }} --build-number ${{ matrix.container }} --with-coverage'
run: 'cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --total-builds ${{ strategy.job-total }} --build-number ${{ matrix.container }} --with-coverage'
env:
TYPE: server

View File

@@ -50,13 +50,13 @@ pull_request_rules:
- version-15-hotfix
assignees:
- "{{ author }}"
- name: backport to version-16-hotfix
- name: backport to version-16-beta
conditions:
- label="backport version-16-hotfix"
- label="backport version-16-beta"
actions:
backport:
branches:
- version-16-hotfix
- version-16-beta
assignees:
- "{{ author }}"
- name: Automatic merge on CI success and review

View File

@@ -1,5 +1,5 @@
{
"branches": ["version-13"],
"branches": ["version-16"],
"plugins": [
"@semantic-release/commit-analyzer", {
"preset": "angular",
@@ -21,4 +21,4 @@
],
"@semantic-release/github"
]
}
}

View File

@@ -7,17 +7,17 @@ erpnext/accounts/ @ruthra-kumar
erpnext/assets/ @khushi8112
erpnext/regional @ruthra-kumar
erpnext/selling @ruthra-kumar
erpnext/support/ @ruthra-kumar
erpnext/buying/ @rohitwaghchaure @mihir-kandoi
erpnext/maintenance/ @rohitwaghchaure @mihir-kandoi
erpnext/maintenance/ @rohitwaghchaure
erpnext/manufacturing/ @rohitwaghchaure @mihir-kandoi
erpnext/quality_management/ @rohitwaghchaure @mihir-kandoi
erpnext/quality_management/ @rohitwaghchaure
erpnext/stock/ @rohitwaghchaure @mihir-kandoi
erpnext/subcontracting/ @mihir-kandoi
erpnext/projects/ @nishkagosalia
erpnext/subcontracting @mihir-kandoi
erpnext/controllers/ @ruthra-kumar @rohitwaghchaure @mihir-kandoi
erpnext/patches/ @ruthra-kumar @rohitwaghchaure @mihir-kandoi
erpnext/patches/ @ruthra-kumar
.github/ @ruthra-kumar @mihir-kandoi
.github/ @ruthra-kumar
pyproject.toml @ruthra-kumar

View File

@@ -75,48 +75,25 @@ It takes care of installation, setup, upgrades, monitoring, maintenance and supp
</div>
### Self-Hosted
#### Docker
See [Frappe Docker Documentation](https://github.com/frappe/frappe_docker) for full documentation & FAQ on docker setup
Prerequisites: docker, docker-compose, git. Refer [Docker Documentation](https://docs.docker.com) for more details on Docker setup.
#### Prerequisites
Run following commands:
- [Docker](https://docs.docker.com/get-docker/)
- [Docker Compose v2](https://docs.docker.com/compose/)
- [git](https://docs.github.com/en/get-started/getting-started-with-git/set-up-git)
> For Docker basics and best practices refer to Docker's [documentation](https://docs.docker.com)
#### Demo setup
The fastest way to try ERPNext is to play in an already set up sandbox, in your browser, click the button below:
<a href="https://labs.play-with-docker.com/?stack=https://raw.githubusercontent.com/frappe/frappe_docker/main/pwd.yml">
<img src="https://raw.githubusercontent.com/play-with-docker/stacks/master/assets/images/button.png" alt="Try in PWD"/>
</a>
### Try on your environment
> **⚠️ Disposable demo only**
>
> **This setup is intended for quick evaluation. Expect to throw the environment away.** You will not be able to install custom apps to this setup. For production deployments, custom configurations, and detailed explanations, see the full documentation.
First clone the repo:
```sh
```
git clone https://github.com/frappe/frappe_docker
cd frappe_docker
```
Then run:
```sh
docker compose -f pwd.yml up -d
```
Wait for a couple of minutes for ERPNext site to be created or check `create-site` container logs before opening browser on port `8080`. (username: `Administrator`, password: `admin`)
See [Frappe Docker](https://github.com/frappe/frappe_docker/blob/main/docs/01-getting-started/03-arm64.md) for ARM based docker setup
After a couple of minutes, site should be accessible on your localhost port: 8080. Use below default login credentials to access the site.
- Username: Administrator
- Password: admin
See [Frappe Docker](https://github.com/frappe/frappe_docker?tab=readme-ov-file#to-run-on-arm64-architecture-follow-this-instructions) for ARM based docker setup.
## Development Setup

View File

@@ -1,7 +1,7 @@
# Security Policy
The ERPNext team and community take security issues seriously. To report a security issue, please go through the information mentioned [here](https://frappe.io/security).
The ERPNext team and community take security issues seriously. To report a security issue, fill out the form at [https://erpnext.com/security/report](https://erpnext.com/security/report).
You can help us make ERPNext and all its users more secure by following the [Reporting guidelines](https://frappe.io/security).
You can help us make ERPNext and all it's users more secure by following the [Reporting guidelines](https://erpnext.com/security).
We appreciate your efforts to responsibly disclose your findings. We'll endeavor to respond quickly, and will keep you updated throughout the process.
We appreciate your efforts to responsibly disclose your findings. We'll endeavor to respond quickly, and will keep you updated throughout the process.

View File

@@ -6,7 +6,7 @@ import frappe
from frappe.model.document import Document
from frappe.utils.user import is_website_user
__version__ = "17.0.0-dev"
__version__ = "16.4.1"
def get_default_company(user=None):

View File

@@ -52,7 +52,7 @@ class ERPNextAddress(Address):
@frappe.whitelist()
def get_shipping_address(company: str, address: str | None = None):
def get_shipping_address(company, address=None):
filters = [
["Dynamic Link", "link_doctype", "=", "Company"],
["Dynamic Link", "link_name", "=", company],

View File

@@ -17,15 +17,6 @@ frappe.dashboards.chart_sources["Account Balance Timeline"] = {
fieldtype: "Link",
options: "Account",
reqd: 1,
default: locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"],
get_query: () => {
return {
filters: {
account_type: "Bank",
is_group: 0,
},
};
},
},
],
};

View File

@@ -4,7 +4,7 @@
import frappe
from frappe import _
from frappe.utils import add_to_date, formatdate, getdate, nowdate
from frappe.utils import add_to_date, formatdate, get_link_to_form, getdate, nowdate
from frappe.utils.dashboard import cache_source
from frappe.utils.dateutils import get_from_date_from_timespan, get_period_ending
from frappe.utils.nestedset import get_descendants_of
@@ -13,15 +13,15 @@ from frappe.utils.nestedset import get_descendants_of
@frappe.whitelist()
@cache_source
def get(
chart_name: str | None = None,
chart: str | dict | None = None,
no_cache: bool | None = None,
filters: str | dict | None = None,
from_date: str | None = None,
to_date: str | None = None,
timespan: str | None = None,
time_interval: str | None = None,
heatmap_year: str | None = None,
chart_name=None,
chart=None,
no_cache=None,
filters=None,
from_date=None,
to_date=None,
timespan=None,
time_interval=None,
heatmap_year=None,
):
if chart_name:
chart = frappe.get_doc("Dashboard Chart", chart_name)
@@ -37,14 +37,21 @@ def get(
filters = frappe.parse_json(filters) or frappe.parse_json(chart.filters_json)
account = filters.get("account")
company = filters.get("company")
filters.get("company")
if not company and not account:
frappe.throw(_("Company and account filters not set!"))
if not company:
frappe.throw(_("Company filter not set!"))
if not account:
frappe.throw(_("Account filter not set!"))
if not account and chart_name:
frappe.throw(
_("Account is not set for the dashboard chart {0}").format(
get_link_to_form("Dashboard Chart", chart_name)
)
)
if not frappe.db.exists("Account", account) and chart_name:
frappe.throw(
_("Account {0} does not exists in the dashboard chart {1}").format(
account, get_link_to_form("Dashboard Chart", chart_name)
)
)
if not to_date:
to_date = nowdate()

View File

@@ -7,6 +7,7 @@ from frappe.utils import (
cint,
date_diff,
flt,
formatdate,
get_first_day,
get_last_day,
get_link_to_form,
@@ -523,8 +524,7 @@ def make_gl_entries(
if gl_entries:
try:
make_gl_entries(gl_entries, cancel=(doc.docstatus == 2), merge_entries=True)
if not frappe.in_test:
frappe.db.commit()
frappe.db.commit()
except Exception as e:
if frappe.in_test:
doc.log_error(f"Error while processing deferred accounting for Invoice {doc.name}")
@@ -606,8 +606,7 @@ def book_revenue_via_journal_entry(
if submit:
journal_entry.submit()
if not frappe.in_test:
frappe.db.commit()
frappe.db.commit()
except Exception:
frappe.db.rollback()
doc.log_error(f"Error while processing deferred accounting for Invoice {doc.name}")

View File

@@ -471,7 +471,7 @@ class Account(NestedSet):
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_parent_account(doctype: str, txt: str, searchfield: str, start: int, page_len: int, filters: dict):
def get_parent_account(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql(
"""select name from tabAccount
where is_group = 1 and docstatus != 2 and company = {}
@@ -515,9 +515,7 @@ def get_account_autoname(account_number, account_name, company):
@frappe.whitelist()
def update_account_number(
name: str, account_name: str, account_number: str | None = None, from_descendant: bool = False
):
def update_account_number(name, account_name, account_number=None, from_descendant=False):
_ensure_idle_system()
account = frappe.get_cached_doc("Account", name)
if not account:
@@ -579,7 +577,7 @@ def update_account_number(
@frappe.whitelist()
def merge_account(old: str, new: str):
def merge_account(old, new):
_ensure_idle_system()
# Validate properties before merging
new_account = frappe.get_cached_doc("Account", new)
@@ -616,7 +614,7 @@ def merge_account(old: str, new: str):
@frappe.whitelist()
def get_root_company(company: str):
def get_root_company(company):
# return the topmost company in the hierarchy
ancestors = get_ancestors_of("Company", company, "lft asc")
return [ancestors[0]] if ancestors else []

View File

@@ -52,55 +52,60 @@ frappe.treeview_settings["Account"] = {
],
root_label: "Accounts",
get_tree_nodes: "erpnext.accounts.utils.get_children",
on_node_render: function (node, deep) {
const render_balances = () => {
for (let account of cur_tree.account_balance_data) {
const node = cur_tree.nodes && cur_tree.nodes[account.value];
if (!node || node.is_root) continue;
// show Dr if positive since balance is calculated as debit - credit else show Cr
const balance = account.balance_in_account_currency || account.balance;
const dr_or_cr = balance > 0 ? __("Dr") : __("Cr");
const format = (value, currency) => format_currency(Math.abs(value), currency);
if (account.balance !== undefined) {
node.parent && node.parent.find(".balance-area").remove();
$(
'<span class="balance-area pull-right">' +
(account.account_currency != account.company_currency
? format(account.balance_in_account_currency, account.account_currency) +
" / "
: "") +
format(account.balance, account.company_currency) +
" " +
dr_or_cr +
"</span>"
).insertBefore(node.$ul);
}
}
};
on_get_node: function (nodes, deep = false) {
if (frappe.boot.user.can_read.indexOf("GL Entry") == -1) return;
if (!cur_tree.account_balance_data) {
frappe.db.get_single_value("Accounts Settings", "show_balance_in_coa").then((value) => {
if (value) {
frappe.call({
method: "erpnext.accounts.utils.get_account_balances_coa",
args: {
company: cur_tree.args.company,
include_default_fb_balances: true,
},
callback: function (r) {
if (!r.message || r.message.length === 0) return;
cur_tree.account_balance_data = r.message || [];
render_balances();
},
});
}
});
let accounts = [];
if (deep) {
// in case of `get_all_nodes`
accounts = nodes.reduce((acc, node) => [...acc, ...node.data], []);
} else {
render_balances();
accounts = nodes;
}
frappe.db.get_single_value("Accounts Settings", "show_balance_in_coa").then((value) => {
if (value) {
const get_balances = frappe.call({
method: "erpnext.accounts.utils.get_account_balances",
args: {
accounts: accounts,
company: cur_tree.args.company,
include_default_fb_balances: true,
},
});
get_balances.then((r) => {
if (!r.message || r.message.length == 0) return;
for (let account of r.message) {
const node = cur_tree.nodes && cur_tree.nodes[account.value];
if (!node || node.is_root) continue;
// show Dr if positive since balance is calculated as debit - credit else show Cr
const balance = account.balance_in_account_currency || account.balance;
const dr_or_cr = balance > 0 ? __("Dr") : __("Cr");
const format = (value, currency) => format_currency(Math.abs(value), currency);
if (account.balance !== undefined) {
node.parent && node.parent.find(".balance-area").remove();
$(
'<span class="balance-area pull-right">' +
(account.balance_in_account_currency
? format(
account.balance_in_account_currency,
account.account_currency
) + " / "
: "") +
format(account.balance, account.company_currency) +
" " +
dr_or_cr +
"</span>"
).insertBefore(node.$ul);
}
}
});
}
});
},
add_tree_node: "erpnext.accounts.utils.add_ac",
menu_items: [

View File

@@ -99,7 +99,7 @@ def identify_is_group(child):
@frappe.whitelist()
def get_chart(chart_template: str | None, existing_company: str | None = None):
def get_chart(chart_template, existing_company=None):
chart = {}
if existing_company:
return get_account_tree_from_existing_company(existing_company)
@@ -132,7 +132,7 @@ def get_chart(chart_template: str | None, existing_company: str | None = None):
@frappe.whitelist()
def get_charts_for_country(country: str, with_standard: bool = False):
def get_charts_for_country(country, with_standard=False):
charts = []
def _get_chart_name(content):
@@ -225,7 +225,7 @@ def build_account_tree(tree, parent, all_accounts):
@frappe.whitelist()
def validate_bank_account(coa: str, bank_account: str):
def validate_bank_account(coa, bank_account):
accounts = []
chart = get_chart(coa)
@@ -244,9 +244,7 @@ def validate_bank_account(coa: str, bank_account: str):
@frappe.whitelist()
def build_tree_from_json(
chart_template: str, chart_data: dict | None = None, from_coa_importer: bool = False
):
def build_tree_from_json(chart_template, chart_data=None, from_coa_importer=False):
"""get chart template from its folder and parse the json to be rendered as tree"""
chart = chart_data or get_chart(chart_template)

View File

@@ -6,83 +6,64 @@
"Current Assets": {
"Accounts Receivable": {
"Debtors": {
"account_type": "Receivable",
"account_category": "Trade Receivables"
"account_type": "Receivable"
}
},
"Bank Accounts": {
"account_type": "Bank",
"is_group": 1,
"account_category": "Cash and Cash Equivalents"
"is_group": 1
},
"Cash In Hand": {
"Cash": {
"account_type": "Cash",
"account_category": "Cash and Cash Equivalents"
"account_type": "Cash"
},
"account_type": "Cash",
"account_category": "Cash and Cash Equivalents"
"account_type": "Cash"
},
"Loans and Advances (Assets)": {
"is_group": 1,
"account_category": "Other Receivables"
"is_group": 1
},
"Securities and Deposits": {
"Earnest Money": {
"account_category": "Other Current Assets"
}
"Earnest Money": {}
},
"Stock Assets": {
"Stock In Hand": {
"account_type": "Stock",
"account_category": "Stock Assets"
"account_type": "Stock"
},
"account_type": "Stock",
"account_category": "Stock Assets"
"account_type": "Stock"
},
"Tax Assets": {
"is_group": 1,
"account_category": "Other Current Assets"
"is_group": 1
}
},
"Fixed Assets": {
"Capital Equipment": {
"account_type": "Fixed Asset",
"account_category": "Tangible Assets"
"account_type": "Fixed Asset"
},
"Electronic Equipment": {
"account_type": "Fixed Asset",
"account_category": "Tangible Assets"
"account_type": "Fixed Asset"
},
"Furniture and Fixtures": {
"account_type": "Fixed Asset",
"account_category": "Tangible Assets"
"account_type": "Fixed Asset"
},
"Office Equipment": {
"account_type": "Fixed Asset",
"account_category": "Tangible Assets"
"account_type": "Fixed Asset"
},
"Plants and Machineries": {
"account_type": "Fixed Asset",
"account_category": "Tangible Assets"
"account_type": "Fixed Asset"
},
"Buildings": {
"account_type": "Fixed Asset",
"account_category": "Tangible Assets"
"account_type": "Fixed Asset"
},
"Accumulated Depreciations": {
"account_type": "Accumulated Depreciation",
"account_category": "Tangible Assets"
"account_type": "Accumulated Depreciation"
}
},
"Investments": {
"is_group": 1,
"account_category": "Long-term Investments"
"is_group": 1
},
"Temporary Accounts": {
"Temporary Opening": {
"account_type": "Temporary",
"account_category": "Other Non-current Assets"
"account_type": "Temporary"
}
},
"root_type": "Asset"
@@ -91,103 +72,55 @@
"Direct Expenses": {
"Stock Expenses": {
"Cost of Goods Sold": {
"account_type": "Cost of Goods Sold",
"account_category": "Cost of Goods Sold"
"account_type": "Cost of Goods Sold"
},
"Expenses Included In Valuation": {
"account_type": "Expenses Included In Valuation",
"account_category": "Other Direct Costs"
"account_type": "Expenses Included In Valuation"
},
"Stock Adjustment": {
"account_type": "Stock Adjustment",
"account_category": "Other Direct Costs"
"account_type": "Stock Adjustment"
}
}
},
"Indirect Expenses": {
"Administrative Expenses": {
"account_category": "Operating Expenses"
},
"Commission on Sales": {
"account_category": "Operating Expenses"
},
"Administrative Expenses": {},
"Commission on Sales": {},
"Depreciation": {
"account_type": "Depreciation",
"account_category": "Operating Expenses"
},
"Entertainment Expenses": {
"account_category": "Operating Expenses"
"account_type": "Depreciation"
},
"Entertainment Expenses": {},
"Freight and Forwarding Charges": {
"account_type": "Chargeable",
"account_category": "Operating Expenses"
},
"Legal Expenses": {
"account_category": "Operating Expenses"
},
"Marketing Expenses": {
"account_type": "Chargeable",
"account_category": "Operating Expenses"
},
"Miscellaneous Expenses": {
"account_type": "Chargeable",
"account_category": "Operating Expenses"
},
"Office Maintenance Expenses": {
"account_category": "Operating Expenses"
},
"Office Rent": {
"account_category": "Operating Expenses"
},
"Postal Expenses": {
"account_category": "Operating Expenses"
},
"Print and Stationery": {
"account_category": "Operating Expenses"
"account_type": "Chargeable"
},
"Legal Expenses": {},
"Marketing Expenses": {},
"Miscellaneous Expenses": {},
"Office Maintenance Expenses": {},
"Office Rent": {},
"Postal Expenses": {},
"Print and Stationery": {},
"Rounded Off": {
"account_type": "Round Off",
"account_category": "Operating Expenses"
"account_type": "Round Off"
},
"Salary": {
"account_category": "Operating Expenses"
},
"Sales Expenses": {
"account_category": "Operating Expenses"
},
"Telephone Expenses": {
"account_category": "Operating Expenses"
},
"Travel Expenses": {
"account_category": "Operating Expenses"
},
"Utility Expenses": {
"account_category": "Operating Expenses"
},
"Write Off": {
"account_category": "Operating Expenses"
},
"Exchange Gain/Loss": {
"account_category": "Operating Expenses"
},
"Gain/Loss on Asset Disposal": {
"account_category": "Other Operating Income"
},
"Impairment": {
"account_category": "Operating Expenses"
}
"Salary": {},
"Sales Expenses": {},
"Telephone Expenses": {},
"Travel Expenses": {},
"Utility Expenses": {},
"Write Off": {},
"Exchange Gain/Loss": {},
"Gain/Loss on Asset Disposal": {},
"Impairment": {}
},
"root_type": "Expense"
},
"Income": {
"Direct Income": {
"Sales": {
"account_type": "Income Account",
"account_category": "Revenue from Operations"
"account_type": "Income Account"
},
"Service": {
"account_type": "Income Account",
"account_category": "Revenue from Operations"
"account_type": "Income Account"
},
"account_type": "Income Account"
},
@@ -199,51 +132,31 @@
},
"Source of Funds (Liabilities)": {
"Capital Account": {
"Reserves and Surplus": {
"account_category": "Reserves and Surplus"
},
"Shareholders Funds": {
"account_category": "Share Capital"
},
"Revaluation Surplus": {
"account_category": "Reserves and Surplus"
}
"Reserves and Surplus": {},
"Shareholders Funds": {},
"Revaluation Surplus": {}
},
"Current Liabilities": {
"Accounts Payable": {
"Creditors": {
"account_type": "Payable",
"account_category": "Trade Payables"
"account_type": "Payable"
},
"Payroll Payable": {
"account_category": "Other Payables"
}
"Payroll Payable": {}
},
"Stock Liabilities": {
"Stock Received But Not Billed": {
"account_type": "Stock Received But Not Billed",
"account_category": "Trade Payables"
"account_type": "Stock Received But Not Billed"
}
},
"Duties and Taxes": {
"TDS": {
"account_type": "Tax",
"account_category": "Current Tax Liabilities"
},
"account_type": "Tax",
"is_group": 1,
"account_category": "Current Tax Liabilities"
"account_type": "Tax"
}
},
"Loans (Liabilities)": {
"Secured Loans": {
"account_category": "Long-term Borrowings"
},
"Unsecured Loans": {
"account_category": "Long-term Borrowings"
},
"Bank Overdraft Account": {
"account_category": "Short-term Borrowings"
}
"Secured Loans": {},
"Unsecured Loans": {},
"Bank Overdraft Account": {}
}
},
"root_type": "Liability"

View File

@@ -1,7 +1,9 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import unittest
import frappe
from frappe.tests import IntegrationTestCase
from frappe.utils import nowdate
from erpnext.accounts.doctype.account.account import (
@@ -10,10 +12,11 @@ from erpnext.accounts.doctype.account.account import (
update_account_number,
)
from erpnext.stock import get_company_default_inventory_account, get_warehouse_account
from erpnext.tests.utils import ERPNextTestSuite
EXTRA_TEST_RECORD_DEPENDENCIES = ["Company"]
class TestAccount(ERPNextTestSuite):
class TestAccount(IntegrationTestCase):
def test_rename_account(self):
if not frappe.db.exists("Account", "1210 - Debtors - _TC"):
acc = frappe.new_doc("Account")

View File

@@ -0,0 +1,6 @@
[
{
"doctype": "Account",
"name": "_Test Account 1"
}
]

View File

@@ -2,3 +2,19 @@
# See license.txt
# import frappe
from frappe.tests import IntegrationTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list
EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
class IntegrationTestAccountCategory(IntegrationTestCase):
"""
Integration tests for AccountCategory.
Use this class for testing interactions between multiple components.
"""
pass

View File

@@ -1,8 +1,8 @@
// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on("Account Closing Balance", {
refresh(frm) {
frm.page.btn_secondary.hide();
},
});
// frappe.ui.form.on("Account Closing Balance", {
// refresh(frm) {
// },
// });

View File

@@ -5,7 +5,6 @@
"doctype": "DocType",
"document_type": "Document",
"engine": "InnoDB",
"is_submittable": 1,
"field_order": [
"closing_date",
"account",

View File

@@ -2,9 +2,8 @@
# See license.txt
# import frappe
from erpnext.tests.utils import ERPNextTestSuite
from frappe.tests import IntegrationTestCase
class TestAccountClosingBalance(ERPNextTestSuite):
class TestAccountClosingBalance(IntegrationTestCase):
pass

View File

@@ -103,6 +103,10 @@ class AccountingDimension(Document):
if not self.fieldname:
self.fieldname = scrub(self.label)
def on_update(self):
frappe.flags.accounting_dimensions = None
frappe.flags.accounting_dimensions_details = None
def make_dimension_in_accounting_doctypes(doc, doclist=None):
if not doclist:
@@ -206,7 +210,7 @@ def delete_accounting_dimension(doc):
@frappe.whitelist()
def disable_dimension(doc: str):
def disable_dimension(doc):
if frappe.in_test:
toggle_disabling(doc=doc)
else:
@@ -237,26 +241,34 @@ def get_doctypes_with_dimensions():
return frappe.get_hooks("accounting_dimension_doctypes")
def get_accounting_dimensions(as_list=True):
accounting_dimensions = frappe.get_all(
"Accounting Dimension",
fields=["label", "fieldname", "disabled", "document_type"],
filters={"disabled": 0},
)
def get_accounting_dimensions(as_list=True, filters=None):
if not filters:
filters = {"disabled": 0}
if frappe.flags.accounting_dimensions is None:
frappe.flags.accounting_dimensions = frappe.get_all(
"Accounting Dimension",
fields=["label", "fieldname", "disabled", "document_type"],
filters=filters,
)
if as_list:
return [d.fieldname for d in accounting_dimensions]
return [d.fieldname for d in frappe.flags.accounting_dimensions]
else:
return accounting_dimensions
return frappe.flags.accounting_dimensions
def get_checks_for_pl_and_bs_accounts():
return frappe.db.sql(
"""SELECT p.label, p.disabled, p.fieldname, c.default_dimension, c.company, c.mandatory_for_pl, c.mandatory_for_bs
if frappe.flags.accounting_dimensions_details is None:
# nosemgrep
frappe.flags.accounting_dimensions_details = frappe.db.sql(
"""SELECT p.label, p.disabled, p.fieldname, c.default_dimension, c.company, c.mandatory_for_pl, c.mandatory_for_bs
FROM `tabAccounting Dimension`p ,`tabAccounting Dimension Detail` c
WHERE p.name = c.parent AND p.disabled = 0""",
as_dict=1,
)
as_dict=1,
)
return frappe.flags.accounting_dimensions_details
def get_dimension_with_children(doctype, dimensions):
@@ -274,7 +286,7 @@ def get_dimension_with_children(doctype, dimensions):
@frappe.whitelist()
def get_dimensions(with_cost_center_and_project: str | bool = False):
def get_dimensions(with_cost_center_and_project=False):
c = frappe.qb.DocType("Accounting Dimension Detail")
p = frappe.qb.DocType("Accounting Dimension")
dimension_filters = (

View File

@@ -1,14 +1,17 @@
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests import IntegrationTestCase
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.tests.utils import ERPNextTestSuite
EXTRA_TEST_RECORD_DEPENDENCIES = ["Cost Center", "Location", "Warehouse", "Department"]
class TestAccountingDimension(ERPNextTestSuite):
class TestAccountingDimension(IntegrationTestCase):
def setUp(self):
create_dimension()
@@ -77,6 +80,11 @@ class TestAccountingDimension(ERPNextTestSuite):
si.save()
self.assertRaises(frappe.ValidationError, si.submit)
def tearDown(self):
disable_dimension()
frappe.flags.accounting_dimensions_details = None
frappe.flags.dimension_filter_map = None
def create_dimension():
frappe.set_user("Administrator")

View File

@@ -3,7 +3,7 @@
import frappe
from frappe import _
from frappe import _, scrub
from frappe.model.document import Document
@@ -69,34 +69,37 @@ class AccountingDimensionFilter(Document):
def get_dimension_filter_map():
filters = frappe.db.sql(
"""
SELECT
a.applicable_on_account, d.dimension_value, p.accounting_dimension,
p.allow_or_restrict, p.fieldname, a.is_mandatory
FROM
`tabApplicable On Account` a,
`tabAccounting Dimension Filter` p
LEFT JOIN `tabAllowed Dimension` d ON d.parent = p.name
WHERE
p.name = a.parent
AND p.disabled = 0
""",
as_dict=1,
)
dimension_filter_map = {}
for f in filters:
build_map(
dimension_filter_map,
f.fieldname,
f.applicable_on_account,
f.dimension_value,
f.allow_or_restrict,
f.is_mandatory,
if not frappe.flags.get("dimension_filter_map"):
filters = frappe.db.sql(
"""
SELECT
a.applicable_on_account, d.dimension_value, p.accounting_dimension,
p.allow_or_restrict, p.fieldname, a.is_mandatory
FROM
`tabApplicable On Account` a,
`tabAccounting Dimension Filter` p
LEFT JOIN `tabAllowed Dimension` d ON d.parent = p.name
WHERE
p.name = a.parent
AND p.disabled = 0
""",
as_dict=1,
)
return dimension_filter_map
dimension_filter_map = {}
for f in filters:
build_map(
dimension_filter_map,
f.fieldname,
f.applicable_on_account,
f.dimension_value,
f.allow_or_restrict,
f.is_mandatory,
)
frappe.flags.dimension_filter_map = dimension_filter_map
return frappe.flags.dimension_filter_map
def build_map(map_object, dimension, account, filter_value, allow_or_restrict, is_mandatory):

View File

@@ -1,17 +1,21 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import (
create_dimension,
disable_dimension,
)
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError
from erpnext.tests.utils import ERPNextTestSuite
EXTRA_TEST_RECORD_DEPENDENCIES = ["Location", "Cost Center", "Department"]
class TestAccountingDimensionFilter(ERPNextTestSuite):
class TestAccountingDimensionFilter(unittest.TestCase):
def setUp(self):
create_dimension()
create_accounting_dimension_filter()
@@ -40,6 +44,17 @@ class TestAccountingDimensionFilter(ERPNextTestSuite):
self.assertRaises(MandatoryAccountDimensionError, si.submit)
self.invoice_list.append(si)
def tearDown(self):
disable_dimension_filter()
disable_dimension()
frappe.flags.accounting_dimensions_details = None
frappe.flags.dimension_filter_map = None
for si in self.invoice_list:
si.load_from_db()
if si.docstatus == 1:
si.cancel()
def create_accounting_dimension_filter():
if not frappe.db.get_value("Accounting Dimension Filter", {"accounting_dimension": "Cost Center"}):

View File

@@ -20,6 +20,7 @@
{
"fieldname": "period_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Period Name",
"reqd": 1,
"unique": 1
@@ -78,7 +79,7 @@
}
],
"links": [],
"modified": "2026-03-09 17:15:33.577217",
"modified": "2025-12-01 16:53:44.631299",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting Period",

View File

@@ -97,7 +97,7 @@ def validate_accounting_period_on_doc_save(doc, method=None):
if doc.doctype == "Bank Clearance":
return
elif doc.doctype == "Asset":
if doc.asset_type == "Existing Asset":
if doc.is_existing_asset:
return
else:
date = doc.available_for_use_date

View File

@@ -1,7 +1,9 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests import IntegrationTestCase
from frappe.utils import add_months, nowdate
from erpnext.accounts.doctype.accounting_period.accounting_period import (
@@ -9,10 +11,11 @@ from erpnext.accounts.doctype.accounting_period.accounting_period import (
OverlapError,
)
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.tests.utils import ERPNextTestSuite
EXTRA_TEST_RECORD_DEPENDENCIES = ["Item"]
class TestAccountingPeriod(ERPNextTestSuite):
class TestAccountingPeriod(IntegrationTestCase):
def test_overlap(self):
ap1 = create_accounting_period(
start_date="2018-04-01", end_date="2018-06-30", company="Wind Power LLC"
@@ -87,6 +90,10 @@ class TestAccountingPeriod(ERPNextTestSuite):
doc.submit() # Should not raise
self.assertEqual(doc.docstatus, 1)
def tearDown(self):
for d in frappe.get_all("Accounting Period"):
frappe.delete_doc("Accounting Period", d.name)
def create_accounting_period(**args):
args = frappe._dict(args)

View File

@@ -20,10 +20,6 @@
"enable_common_party_accounting",
"allow_multi_currency_invoices_against_single_party_account",
"confirm_before_resetting_posting_date",
"analytics_section",
"enable_accounting_dimensions",
"column_break_vtnr",
"enable_discounts_and_margin",
"journals_section",
"merge_similar_account_heads",
"deferred_accounting_settings_section",
@@ -55,16 +51,12 @@
"allow_pegged_currencies_exchange_rates",
"column_break_yuug",
"stale_days",
"payments_tab",
"section_break_jpd0",
"auto_reconcile_payments",
"auto_reconciliation_job_trigger",
"reconciliation_queue_size",
"column_break_resa",
"exchange_gain_loss_posting_date",
"payment_options_section",
"enable_loyalty_point_program",
"column_break_ctam",
"invoicing_settings_tab",
"accounts_transactions_settings_section",
"over_billing_allowance",
@@ -205,7 +197,7 @@
"description": "Payment Terms from orders will be fetched into the invoices as is",
"fieldname": "automatically_fetch_payment_terms",
"fieldtype": "Check",
"label": "Automatically Fetch Payment Terms from Order/Quotation"
"label": "Automatically Fetch Payment Terms from Order"
},
{
"description": "The percentage you are allowed to bill more against the amount ordered. For example, if the order value is $100 for an item and tolerance is set as 10%, then you are allowed to bill up to $110 ",
@@ -289,7 +281,7 @@
},
{
"default": "0",
"description": "Learn about <a href=\"https://docs.frappe.io/erpnext/user/manual/en/common_party_accounting\" rel=\"noopener noreferrer\">Common Party</a>",
"description": "Learn about <a href=\"https://docs.frappe.io/erpnext/user/manual/en/common_party_accounting\">Common Party</a>",
"fieldname": "enable_common_party_accounting",
"fieldtype": "Check",
"label": "Enable Common Party Accounting"
@@ -645,59 +637,16 @@
"fieldname": "budget_section",
"fieldtype": "Section Break",
"label": "Budget"
},
{
"fieldname": "analytics_section",
"fieldtype": "Section Break",
"label": "Analytical Accounting"
},
{
"fieldname": "column_break_vtnr",
"fieldtype": "Column Break"
},
{
"default": "0",
"description": "Apply discounts and margins on products",
"fieldname": "enable_discounts_and_margin",
"fieldtype": "Check",
"label": "Enable Discounts and Margin"
},
{
"fieldname": "payments_tab",
"fieldtype": "Tab Break",
"label": "Payments"
},
{
"fieldname": "payment_options_section",
"fieldtype": "Section Break",
"label": "Payment Options"
},
{
"default": "0",
"fieldname": "enable_loyalty_point_program",
"fieldtype": "Check",
"label": "Enable Loyalty Point Program"
},
{
"fieldname": "column_break_ctam",
"fieldtype": "Column Break"
},
{
"default": "0",
"description": "Enable cost center, projects and other custom accounting dimensions",
"fieldname": "enable_accounting_dimensions",
"fieldtype": "Check",
"label": "Enable Accounting Dimensions"
}
],
"grid_page_length": 50,
"hide_toolbar": 0,
"hide_toolbar": 1,
"icon": "icon-cog",
"idx": 1,
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2026-02-27 01:04:09.415288",
"modified": "2026-01-11 18:30:45.968531",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",

View File

@@ -12,28 +12,6 @@ from frappe.utils import cint
from erpnext.accounts.utils import sync_auto_reconcile_config
SELLING_DOCTYPES = [
"Sales Invoice",
"Sales Order",
"Delivery Note",
"Quotation",
"Sales Invoice Item",
"Sales Order Item",
"Delivery Note Item",
"Quotation Item",
"POS Invoice",
"POS Invoice Item",
]
BUYING_DOCTYPES = [
"Purchase Invoice",
"Purchase Order",
"Purchase Receipt",
"Purchase Invoice Item",
"Purchase Order Item",
"Purchase Receipt Item",
]
class AccountsSettings(Document):
# begin: auto-generated types
@@ -65,12 +43,9 @@ class AccountsSettings(Document):
default_ageing_range: DF.Data | None
delete_linked_ledger_entries: DF.Check
determine_address_tax_category_from: DF.Literal["Billing Address", "Shipping Address"]
enable_accounting_dimensions: DF.Check
enable_common_party_accounting: DF.Check
enable_discounts_and_margin: DF.Check
enable_fuzzy_matching: DF.Check
enable_immutable_ledger: DF.Check
enable_loyalty_point_program: DF.Check
enable_party_matching: DF.Check
exchange_gain_loss_posting_date: DF.Literal["Invoice", "Payment", "Reconciliation Date"]
fetch_valuation_rate_for_internal_transaction: DF.Check
@@ -123,18 +98,6 @@ class AccountsSettings(Document):
if old_doc.show_payment_schedule_in_print != self.show_payment_schedule_in_print:
self.enable_payment_schedule_in_print()
if old_doc.enable_accounting_dimensions != self.enable_accounting_dimensions:
toggle_accounting_dimension_sections(not self.enable_accounting_dimensions)
clear_cache = True
if old_doc.enable_discounts_and_margin != self.enable_discounts_and_margin:
toggle_sales_discount_section(not self.enable_discounts_and_margin)
clear_cache = True
if old_doc.enable_loyalty_point_program != self.enable_loyalty_point_program:
toggle_loyalty_point_program_section(not self.enable_loyalty_point_program)
clear_cache = True
if clear_cache:
frappe.clear_cache()
@@ -191,36 +154,3 @@ class AccountsSettings(Document):
frappe.db.sql(f"drop procedure if exists {InitSQLProceduresForAR.init_procedure_name}")
frappe.db.sql(f"drop procedure if exists {InitSQLProceduresForAR.allocate_procedure_name}")
def toggle_accounting_dimension_sections(hide):
accounting_dimension_doctypes = frappe.get_hooks("accounting_dimension_doctypes")
for doctype in accounting_dimension_doctypes:
create_property_setter_for_hiding_field(doctype, "accounting_dimensions_section", hide)
def toggle_sales_discount_section(hide):
for doctype in SELLING_DOCTYPES + BUYING_DOCTYPES:
meta = frappe.get_meta(doctype)
if meta.has_field("additional_discount_section"):
create_property_setter_for_hiding_field(doctype, "additional_discount_section", hide)
if meta.has_field("discount_and_margin"):
create_property_setter_for_hiding_field(doctype, "discount_and_margin", hide)
def toggle_loyalty_point_program_section(hide):
for doctype in SELLING_DOCTYPES:
meta = frappe.get_meta(doctype)
if meta.has_field("loyalty_points_redemption"):
create_property_setter_for_hiding_field(doctype, "loyalty_points_redemption", hide)
def create_property_setter_for_hiding_field(doctype, field_name, hide):
make_property_setter(
doctype,
field_name,
"hidden",
hide,
"Check",
validate_fields_for_doctype=False,
)

View File

@@ -1,9 +1,17 @@
import unittest
import frappe
from erpnext.tests.utils import ERPNextTestSuite
from frappe.tests import IntegrationTestCase
class TestAccountsSettings(ERPNextTestSuite):
class TestAccountsSettings(IntegrationTestCase):
def tearDown(self):
# Just in case `save` method succeeds, we need to take things back to default so that other tests
# don't break
cur_settings = frappe.get_doc("Accounts Settings", "Accounts Settings")
cur_settings.allow_stale = 1
cur_settings.save()
def test_stale_days(self):
cur_settings = frappe.get_doc("Accounts Settings", "Accounts Settings")
cur_settings.allow_stale = 0

View File

@@ -3,7 +3,6 @@
frappe.ui.form.on("Advance Payment Ledger Entry", {
refresh(frm) {
frm.page.btn_secondary.hide();
frm.set_currency_labels(["amount"], frm.doc.currency);
frm.set_currency_labels(["base_amount"], erpnext.get_currency(frm.doc.company));
},

View File

@@ -4,7 +4,6 @@
"creation": "2024-10-16 16:57:12.085072",
"doctype": "DocType",
"engine": "InnoDB",
"is_submittable": 1,
"field_order": [
"company",
"voucher_type",
@@ -51,7 +50,6 @@
"fieldname": "amount",
"fieldtype": "Currency",
"label": "Amount",
"options": "currency",
"read_only": 1
},
{

View File

@@ -2,6 +2,7 @@
# See license.txt
import frappe
from frappe.tests import IntegrationTestCase
from frappe.utils import nowdate, today
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
@@ -9,13 +10,14 @@ from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
# On ERPNextTestSuite, the doctype test records and all
# On IntegrationTestCase, the doctype test records and all
# link-field test record depdendencies are recursively loaded
# Use these module variables to add/remove to/from that list
from erpnext.tests.utils import ERPNextTestSuite
EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
class TestAdvancePaymentLedgerEntry(AccountsTestMixin, ERPNextTestSuite):
class TestAdvancePaymentLedgerEntry(AccountsTestMixin, IntegrationTestCase):
"""
Integration tests for AdvancePaymentLedgerEntry.
Use this class for testing interactions between multiple components.
@@ -28,6 +30,9 @@ class TestAdvancePaymentLedgerEntry(AccountsTestMixin, ERPNextTestSuite):
self.create_item()
self.clear_old_entries()
def tearDown(self):
frappe.db.rollback()
def create_sales_order(self, qty=1, rate=100, currency="INR", do_not_submit=False):
"""
Helper method

View File

@@ -1,8 +1,9 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
from erpnext.tests.utils import ERPNextTestSuite
from frappe.tests import IntegrationTestCase
class TestBank(ERPNextTestSuite):
class TestBank(IntegrationTestCase):
pass

View File

@@ -115,7 +115,7 @@ def get_default_company_bank_account(company, party_type, party):
@frappe.whitelist()
def get_bank_account_details(bank_account: str):
def get_bank_account_details(bank_account):
return frappe.get_cached_value(
"Bank Account", bank_account, ["account", "bank", "bank_account_no"], as_dict=1
)

View File

@@ -1,8 +1,11 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
from erpnext.tests.utils import ERPNextTestSuite
import frappe
from frappe import ValidationError
from frappe.tests import IntegrationTestCase
class TestBankAccount(ERPNextTestSuite):
class TestBankAccount(IntegrationTestCase):
pass

View File

@@ -1,8 +1,9 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
from erpnext.tests.utils import ERPNextTestSuite
from frappe.tests import IntegrationTestCase
class TestBankAccountSubtype(ERPNextTestSuite):
class TestBankAccountSubtype(IntegrationTestCase):
pass

View File

@@ -1,9 +1,10 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
import unittest
from erpnext.tests.utils import ERPNextTestSuite
from frappe.tests import IntegrationTestCase
class TestBankAccountType(ERPNextTestSuite):
class TestBankAccountType(IntegrationTestCase):
pass

View File

@@ -5,10 +5,8 @@
import frappe
from frappe import _, msgprint
from frappe.model.document import Document
from frappe.query_builder import Case
from frappe.query_builder.custom import ConstantColumn
from frappe.query_builder.functions import Coalesce, Sum
from frappe.utils import cint, flt, fmt_money, getdate
from frappe.utils import cint, flt, fmt_money, get_link_to_form, getdate
from pypika import Order
import erpnext
@@ -184,162 +182,65 @@ def get_payment_entries_for_bank_clearance(
):
entries = []
journal_entry = frappe.qb.DocType("Journal Entry")
journal_entry_account = frappe.qb.DocType("Journal Entry Account")
journal_entry_query = (
frappe.qb.from_(journal_entry_account)
.inner_join(journal_entry)
.on(journal_entry_account.parent == journal_entry.name)
.select(
ConstantColumn("Journal Entry").as_("payment_document"),
journal_entry.name.as_("payment_entry"),
journal_entry.cheque_no.as_("cheque_number"),
journal_entry.cheque_date,
Sum(journal_entry_account.debit_in_account_currency).as_("debit"),
Sum(journal_entry_account.credit_in_account_currency).as_("credit"),
journal_entry.posting_date,
journal_entry_account.against_account,
journal_entry.clearance_date,
journal_entry_account.account_currency,
)
.where(
(journal_entry_account.account == account)
& (journal_entry.docstatus == 1)
& (journal_entry.posting_date >= from_date)
& (journal_entry.posting_date <= to_date)
& (journal_entry.is_opening == "No")
)
)
condition = ""
pe_condition = ""
if not include_reconciled_entries:
journal_entry_query = journal_entry_query.where(
(journal_entry.clearance_date.isnull()) | (journal_entry.clearance_date == "0000-00-00")
)
condition = "and (clearance_date IS NULL or clearance_date='0000-00-00')"
pe_condition = "and (pe.clearance_date IS NULL or pe.clearance_date='0000-00-00')"
journal_entries = (
journal_entry_query.groupby(journal_entry_account.account, journal_entry.name)
.orderby(journal_entry.posting_date)
.orderby(journal_entry.name, order=Order.desc)
).run(as_dict=True)
pe = frappe.qb.DocType("Payment Entry")
company = frappe.qb.DocType("Company")
payment_entry_query = (
frappe.qb.from_(pe)
.join(company)
.on(pe.company == company.name)
.select(
ConstantColumn("Payment Entry").as_("payment_document"),
pe.name.as_("payment_entry"),
pe.reference_no.as_("cheque_number"),
pe.reference_date.as_("cheque_date"),
(
Case()
.when(
pe.paid_from == account,
(
pe.paid_amount
+ (
Case()
.when(
(pe.payment_type == "Pay")
& (company.default_currency == pe.paid_from_account_currency),
pe.base_total_taxes_and_charges,
)
.else_(pe.total_taxes_and_charges)
)
),
)
.else_(0)
).as_("credit"),
(
Case()
.when(pe.paid_from == account, 0)
.else_(
pe.received_amount
+ (
Case()
.when(
company.default_currency == pe.paid_to_account_currency,
pe.base_total_taxes_and_charges,
)
.else_(pe.total_taxes_and_charges)
)
)
).as_("debit"),
pe.posting_date,
Coalesce(pe.party, Case().when(pe.paid_from == account, pe.paid_to).else_(pe.paid_from)).as_(
"against_account"
),
pe.clearance_date,
(
Case()
.when(pe.paid_to == account, pe.paid_to_account_currency)
.else_(pe.paid_from_account_currency)
).as_("account_currency"),
)
.where(
((pe.paid_from == account) | (pe.paid_to == account))
& (pe.docstatus == 1)
& (pe.posting_date >= from_date)
& (pe.posting_date <= to_date)
)
journal_entries = frappe.db.sql(
f"""
select
"Journal Entry" as payment_document, t1.name as payment_entry,
t1.cheque_no as cheque_number, t1.cheque_date,
sum(t2.debit_in_account_currency) as debit, sum(t2.credit_in_account_currency) as credit,
t1.posting_date, t2.against_account, t1.clearance_date, t2.account_currency
from
`tabJournal Entry` t1, `tabJournal Entry Account` t2
where
t2.parent = t1.name and t2.account = %(account)s and t1.docstatus=1
and t1.posting_date >= %(from)s and t1.posting_date <= %(to)s
and ifnull(t1.is_opening, 'No') = 'No' {condition}
group by t2.account, t1.name
order by t1.posting_date ASC, t1.name DESC
""",
{"account": account, "from": from_date, "to": to_date},
as_dict=1,
)
if not include_reconciled_entries:
payment_entry_query = payment_entry_query.where(
(pe.clearance_date.isnull()) | (pe.clearance_date == "0000-00-00")
)
payment_entries = (payment_entry_query.orderby(pe.posting_date).orderby(pe.name, order=Order.desc)).run(
as_dict=True
payment_entries = frappe.db.sql(
f"""
select
"Payment Entry" as payment_document, pe.name as payment_entry,
pe.reference_no as cheque_number, pe.reference_date as cheque_date,
if(pe.paid_from=%(account)s, pe.paid_amount + if(pe.payment_type = 'Pay' and c.default_currency = pe.paid_from_account_currency, pe.base_total_taxes_and_charges, pe.total_taxes_and_charges) , 0) as credit,
if(pe.paid_from=%(account)s, 0, pe.received_amount + pe.total_taxes_and_charges) as debit,
pe.posting_date, ifnull(pe.party,if(pe.paid_from=%(account)s,pe.paid_to,pe.paid_from)) as against_account, pe.clearance_date,
if(pe.paid_to=%(account)s, pe.paid_to_account_currency, pe.paid_from_account_currency) as account_currency
from `tabPayment Entry` as pe
join `tabCompany` c on c.name = pe.company
where
(pe.paid_from=%(account)s or pe.paid_to=%(account)s) and pe.docstatus=1
and pe.posting_date >= %(from)s and pe.posting_date <= %(to)s
{pe_condition}
order by
pe.posting_date ASC, pe.name DESC
""",
{
"account": account,
"from": from_date,
"to": to_date,
},
as_dict=1,
)
acc = frappe.qb.DocType("Account")
pi = frappe.qb.DocType("Purchase Invoice")
paid_purchase_invoices_query = (
frappe.qb.from_(pi)
.inner_join(acc)
.on(pi.cash_bank_account == acc.name)
.select(
ConstantColumn("Purchase Invoice").as_("payment_document"),
pi.name.as_("payment_entry"),
pi.paid_amount.as_("credit"),
pi.posting_date,
pi.supplier.as_("against_account"),
pi.bill_no.as_("cheque_number"),
pi.clearance_date,
acc.account_currency,
ConstantColumn(0).as_("debit"),
)
.where(
(pi.docstatus == 1)
& (pi.is_paid == 1)
& (pi.cash_bank_account == account)
& (pi.posting_date >= from_date)
& (pi.posting_date <= to_date)
)
)
if not include_reconciled_entries:
paid_purchase_invoices_query = paid_purchase_invoices_query.where(
(pi.clearance_date.isnull()) | (pi.clearance_date == "0000-00-00")
)
paid_purchase_invoices = (
paid_purchase_invoices_query.orderby(pi.posting_date).orderby(pi.name, order=Order.desc)
).run(as_dict=True)
pos_sales_invoices = []
pos_sales_invoices, pos_purchase_invoices = [], []
if include_pos_transactions:
si_payment = frappe.qb.DocType("Sales Invoice Payment")
si = frappe.qb.DocType("Sales Invoice")
acc = frappe.qb.DocType("Account")
pos_sales_invoices_query = (
pos_sales_invoices = (
frappe.qb.from_(si_payment)
.inner_join(si)
.on(si_payment.parent == si.name)
@@ -362,22 +263,38 @@ def get_payment_entries_for_bank_clearance(
& (si.posting_date >= from_date)
& (si.posting_date <= to_date)
)
)
.orderby(si.posting_date)
.orderby(si.name, order=Order.desc)
).run(as_dict=True)
if not include_reconciled_entries:
pos_sales_invoices_query = pos_sales_invoices_query.where(
(si_payment.clearance_date.isnull()) | (si_payment.clearance_date == "0000-00-00")
pi = frappe.qb.DocType("Purchase Invoice")
pos_purchase_invoices = (
frappe.qb.from_(pi)
.inner_join(acc)
.on(pi.cash_bank_account == acc.name)
.select(
ConstantColumn("Purchase Invoice").as_("payment_document"),
pi.name.as_("payment_entry"),
pi.paid_amount.as_("credit"),
pi.posting_date,
pi.supplier.as_("against_account"),
pi.clearance_date,
acc.account_currency,
ConstantColumn(0).as_("debit"),
)
pos_sales_invoices = (
pos_sales_invoices_query.orderby(si.posting_date).orderby(si.name, order=Order.desc)
.where(
(pi.docstatus == 1)
& (pi.cash_bank_account == account)
& (pi.posting_date >= from_date)
& (pi.posting_date <= to_date)
)
.orderby(pi.posting_date)
.orderby(pi.name, order=Order.desc)
).run(as_dict=True)
entries = (
list(payment_entries)
+ list(journal_entries)
+ list(pos_sales_invoices)
+ list(paid_purchase_invoices)
list(payment_entries) + list(journal_entries) + list(pos_sales_invoices) + list(pos_purchase_invoices)
)
return entries

View File

@@ -1,7 +1,9 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests import IntegrationTestCase
from frappe.utils import add_months, getdate
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
@@ -13,12 +15,13 @@ from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.tests.utils import ERPNextTestSuite, if_lending_app_installed, if_lending_app_not_installed
from erpnext.tests.utils import if_lending_app_installed, if_lending_app_not_installed
class TestBankClearance(ERPNextTestSuite):
def setUp(self):
frappe.clear_cache()
class TestBankClearance(IntegrationTestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
create_warehouse(
warehouse_name="_Test Warehouse",
properties={"parent_warehouse": "All Warehouses - _TC"},

View File

@@ -1,8 +1,9 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
from erpnext.tests.utils import ERPNextTestSuite
from frappe.tests import IntegrationTestCase
class TestBankGuarantee(ERPNextTestSuite):
class TestBankGuarantee(IntegrationTestCase):
pass

View File

@@ -1,8 +1,8 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import json
from datetime import date
import frappe
from frappe import _
@@ -47,9 +47,7 @@ class BankReconciliationTool(Document):
@frappe.whitelist()
def get_bank_transactions(
bank_account: str, from_date: str | date | None = None, to_date: str | date | None = None
):
def get_bank_transactions(bank_account, from_date=None, to_date=None):
# returns bank transactions for a bank account
filters = []
filters.append(["bank_account", "=", bank_account])
@@ -59,7 +57,7 @@ def get_bank_transactions(
filters.append(["date", "<=", to_date])
if from_date:
filters.append(["date", ">=", from_date])
transactions = frappe.get_list(
transactions = frappe.get_all(
"Bank Transaction",
fields=[
"date",
@@ -82,9 +80,8 @@ def get_bank_transactions(
@frappe.whitelist()
def get_account_balance(bank_account: str, till_date: str | date, company: str):
def get_account_balance(bank_account, till_date, company):
# returns account balance till the specified date
frappe.has_permission("Bank Account", "read", bank_account, throw=True)
account = frappe.db.get_value("Bank Account", bank_account, "account")
filters = frappe._dict(
{
@@ -109,9 +106,7 @@ def get_account_balance(bank_account: str, till_date: str | date, company: str):
@frappe.whitelist()
def update_bank_transaction(
bank_transaction_name: str, reference_number: str, party_type: str | None = None, party: str | None = None
):
def update_bank_transaction(bank_transaction_name, reference_number, party_type=None, party=None):
# updates bank transaction based on the new parameters provided by the user from Vouchers
bank_transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
bank_transaction.reference_number = reference_number
@@ -140,16 +135,16 @@ def update_bank_transaction(
@frappe.whitelist()
def create_journal_entry_bts(
bank_transaction_name: str,
reference_number: str | None = None,
reference_date: str | None = None,
posting_date: str | date | None = None,
entry_type: str | None = None,
second_account: str | None = None,
mode_of_payment: str | None = None,
party_type: str | None = None,
party: str | None = None,
allow_edit: bool | None = None,
bank_transaction_name,
reference_number=None,
reference_date=None,
posting_date=None,
entry_type=None,
second_account=None,
mode_of_payment=None,
party_type=None,
party=None,
allow_edit=None,
):
# Create a new journal entry based on the bank transaction
bank_transaction = frappe.db.get_values(
@@ -299,17 +294,17 @@ def create_journal_entry_bts(
@frappe.whitelist()
def create_payment_entry_bts(
bank_transaction_name: str,
reference_number: str | None = None,
reference_date: str | None = None,
party_type: str | None = None,
party: str | None = None,
posting_date: str | None = None,
mode_of_payment: str | None = None,
project: str | None = None,
cost_center: str | None = None,
allow_edit: bool | None = None,
company_bank_account: str | None = None,
bank_transaction_name,
reference_number=None,
reference_date=None,
party_type=None,
party=None,
posting_date=None,
mode_of_payment=None,
project=None,
cost_center=None,
allow_edit=None,
company_bank_account=None,
):
# Create a new payment entry based on the bank transaction
bank_transaction = frappe.db.get_values(
@@ -376,12 +371,12 @@ def create_payment_entry_bts(
@frappe.whitelist()
def auto_reconcile_vouchers(
bank_account: str,
from_date: str | date | None = None,
to_date: str | date | None = None,
filter_by_reference_date: bool | None = None,
from_reference_date: bool | None = None,
to_reference_date: str | None = None,
bank_account,
from_date=None,
to_date=None,
filter_by_reference_date=None,
from_reference_date=None,
to_reference_date=None,
):
bank_transactions = get_bank_transactions(bank_account)
@@ -476,7 +471,7 @@ def get_auto_reconcile_message(partially_reconciled, reconciled):
@frappe.whitelist()
def reconcile_vouchers(bank_transaction_name: str, vouchers: str):
def reconcile_vouchers(bank_transaction_name, vouchers):
# updated clear date of all the vouchers based on the bank transaction
vouchers = json.loads(vouchers)
transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
@@ -492,13 +487,13 @@ def reconcile_vouchers(bank_transaction_name: str, vouchers: str):
@frappe.whitelist()
def get_linked_payments(
bank_transaction_name: str,
document_types: str | list[str] | None = None,
from_date: str | date | None = None,
to_date: str | date | None = None,
filter_by_reference_date: bool | None = None,
from_reference_date: bool | None = None,
to_reference_date: str | None = None,
bank_transaction_name,
document_types=None,
from_date=None,
to_date=None,
filter_by_reference_date=None,
from_reference_date=None,
to_reference_date=None,
):
# get all matching payments for a bank transaction
transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)

View File

@@ -4,6 +4,7 @@
import frappe
from frappe import qb
from frappe.tests import IntegrationTestCase
from frappe.utils import add_days, today
from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import (
@@ -12,10 +13,9 @@ from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool
)
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry
from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
from erpnext.tests.utils import ERPNextTestSuite
class TestBankReconciliationTool(AccountsTestMixin, ERPNextTestSuite):
class TestBankReconciliationTool(AccountsTestMixin, IntegrationTestCase):
def setUp(self):
self.create_company()
self.create_customer()
@@ -24,6 +24,9 @@ class TestBankReconciliationTool(AccountsTestMixin, ERPNextTestSuite):
qb.from_(bank_dt).delete().where(bank_dt.name == "HDFC").run()
self.create_bank_account()
def tearDown(self):
frappe.db.rollback()
def create_bank_account(self):
bank = frappe.get_doc(
{
@@ -40,7 +43,6 @@ class TestBankReconciliationTool(AccountsTestMixin, ERPNextTestSuite):
"bank": bank.name,
"is_company_account": True,
"account": self.bank, # account from Chart of Accounts
"company": self.company,
}
)
.insert()

View File

@@ -14,6 +14,7 @@ import openpyxl
from frappe import _
from frappe.core.doctype.data_import.data_import import DataImport
from frappe.core.doctype.data_import.importer import Importer, ImportFile
from frappe.query_builder.functions import Count
from frappe.utils.background_jobs import enqueue
from frappe.utils.file_manager import get_file, save_file
from frappe.utils.xlsxutils import ILLEGAL_CHARACTERS_RE, handle_html
@@ -143,7 +144,7 @@ def preprocess_mt940_content(content: str) -> str:
@frappe.whitelist()
def convert_mt940_to_csv(data_import: str, mt940_file_path: str):
def convert_mt940_to_csv(data_import, mt940_file_path):
doc = frappe.get_doc("Bank Statement Import", data_import)
_file_doc, content = get_file(mt940_file_path)
@@ -208,28 +209,26 @@ def convert_mt940_to_csv(data_import: str, mt940_file_path: str):
@frappe.whitelist()
def get_preview_from_template(
data_import: str, import_file: str | None = None, google_sheets_url: str | None = None
):
def get_preview_from_template(data_import, import_file=None, google_sheets_url=None):
return frappe.get_doc("Bank Statement Import", data_import).get_preview_from_template(
import_file, google_sheets_url
)
@frappe.whitelist()
def form_start_import(data_import: str):
def form_start_import(data_import):
job_id = frappe.get_doc("Bank Statement Import", data_import).start_import()
return job_id is not None
@frappe.whitelist()
def download_errored_template(data_import_name: str):
def download_errored_template(data_import_name):
data_import = frappe.get_doc("Bank Statement Import", data_import_name)
data_import.export_errored_rows()
@frappe.whitelist()
def download_import_log(data_import_name: str):
def download_import_log(data_import_name):
return frappe.get_doc("Bank Statement Import", data_import_name).download_import_log()
@@ -365,7 +364,7 @@ def write_xlsx(data, sheet_name, wb=None, column_widths=None, file_path=None):
@frappe.whitelist()
def get_import_status(docname: str):
def get_import_status(docname):
import_status = {}
data_import = frappe.get_doc("Bank Statement Import", docname)

View File

@@ -1,14 +1,15 @@
# Copyright (c) 2020, Frappe Technologies and Contributors
# See license.txt
import unittest
from erpnext.accounts.doctype.bank_statement_import.bank_statement_import import (
is_mt940_format,
preprocess_mt940_content,
)
from erpnext.tests.utils import ERPNextTestSuite
class TestBankStatementImport(ERPNextTestSuite):
class TestBankStatementImport(unittest.TestCase):
"""Unit tests for Bank Statement Import functions"""
def test_preprocess_mt940_content_with_long_statement_number(self):

View File

@@ -139,8 +139,6 @@ class BankTransaction(Document):
self.set_status()
def on_cancel(self):
self.ignore_linked_doctypes = ["GL Entry"]
for payment_entry in self.payment_entries:
self.delink_payment_entry(payment_entry)
@@ -375,12 +373,11 @@ def get_clearance_details(transaction, payment_entry, bt_allocations, gl_entries
("unallocated_amount", "bank_account"),
as_dict=True,
)
bt_bank_account = frappe.db.get_value("Bank Account", bt.bank_account, "account")
if bt_bank_account != gl_bank_account:
if bt.bank_account != gl_bank_account:
frappe.throw(
_("Bank Account {} in Bank Transaction {} is not matching with Bank Account {}").format(
bt_bank_account, payment_entry.payment_entry, gl_bank_account
bt.bank_account, payment_entry.payment_entry, gl_bank_account
)
)

View File

@@ -35,7 +35,7 @@ def upload_bank_statement():
@frappe.whitelist()
def create_bank_entries(columns: str, data: str, bank_account: str):
def create_bank_entries(columns, data, bank_account):
header_map = get_header_mapping(columns, bank_account)
success = 0

View File

@@ -2,20 +2,27 @@
# License: GNU General Public License v3. See license.txt
import frappe
from frappe.tests import IntegrationTestCase
from frappe.utils import nowdate
from erpnext.accounts.doctype.bank_transaction.test_bank_transaction import create_bank_account
from erpnext.tests.utils import ERPNextTestSuite
IBAN_1 = "DE02000000003716541159"
IBAN_2 = "DE02500105170137075030"
class TestAutoMatchParty(ERPNextTestSuite):
def setUp(self):
class TestAutoMatchParty(IntegrationTestCase):
@classmethod
def setUpClass(cls):
create_bank_account()
frappe.db.set_single_value("Accounts Settings", "enable_party_matching", 1)
frappe.db.set_single_value("Accounts Settings", "enable_fuzzy_matching", 1)
return super().setUpClass()
@classmethod
def tearDownClass(cls):
frappe.db.set_single_value("Accounts Settings", "enable_party_matching", 0)
frappe.db.set_single_value("Accounts Settings", "enable_fuzzy_matching", 0)
def test_match_by_account_number(self):
create_supplier_for_match(account_no=IBAN_1[11:])

View File

@@ -6,6 +6,7 @@ import json
import frappe
from frappe import utils
from frappe.model.docstatus import DocStatus
from frappe.tests import IntegrationTestCase
from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import (
get_linked_payments,
@@ -18,10 +19,12 @@ from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_paymen
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.tests.utils import ERPNextTestSuite, if_lending_app_installed
from erpnext.tests.utils import if_lending_app_installed
EXTRA_TEST_RECORD_DEPENDENCIES = ["Item", "Cost Center"]
class TestBankTransaction(ERPNextTestSuite):
class TestBankTransaction(IntegrationTestCase):
def setUp(self):
make_pos_profile()

View File

@@ -2,10 +2,8 @@
# See license.txt
# import frappe
from frappe.tests import IntegrationTestCase
from erpnext.tests.utils import ERPNextTestSuite
class TestBisectAccountingStatements(ERPNextTestSuite):
class TestBisectAccountingStatements(IntegrationTestCase):
pass

View File

@@ -2,10 +2,8 @@
# See license.txt
# import frappe
from frappe.tests import IntegrationTestCase
from erpnext.tests.utils import ERPNextTestSuite
class TestBisectNodes(ERPNextTestSuite):
class TestBisectNodes(IntegrationTestCase):
pass

View File

@@ -2,12 +2,14 @@
# For license information, please see license.txt
from datetime import date
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.query_builder.functions import Sum
from frappe.utils import add_months, flt, fmt_money, get_last_day, getdate
from frappe.utils.data import get_first_day
from frappe.utils import add_months, flt, fmt_money, get_last_day, getdate, month_diff
from frappe.utils.data import get_first_day, nowdate
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_accounting_dimensions,
@@ -845,7 +847,7 @@ def get_fiscal_year_date_range(from_fiscal_year, to_fiscal_year):
@frappe.whitelist()
def revise_budget(budget_name: str):
def revise_budget(budget_name):
old_budget = frappe.get_doc("Budget", budget_name)
if old_budget.docstatus == 1:

View File

@@ -1,8 +1,10 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.utils import flt, now_datetime, nowdate
from frappe.client import submit
from frappe.utils import add_days, flt, get_first_day, get_last_day, getdate, now_datetime, nowdate
from erpnext.accounts.doctype.budget.budget import (
BudgetError,
@@ -17,6 +19,12 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestBudget(ERPNextTestSuite):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.make_monthly_distribution()
cls.make_projects()
def setUp(self):
frappe.db.set_single_value("Accounts Settings", "use_legacy_budget_controller", False)
self.company = "_Test Company"

View File

@@ -1,8 +1,9 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
from erpnext.tests.utils import ERPNextTestSuite
from frappe.tests import IntegrationTestCase
class TestCashierClosing(ERPNextTestSuite):
class TestCashierClosing(IntegrationTestCase):
pass

View File

@@ -57,7 +57,7 @@ def validate_columns(data):
@frappe.whitelist()
def validate_company(company: str):
def validate_company(company):
parent_company, allow_account_creation_against_child_company = frappe.get_cached_value(
"Company", company, ["parent_company", "allow_account_creation_against_child_company"]
)
@@ -74,7 +74,7 @@ def validate_company(company: str):
@frappe.whitelist()
def import_coa(file_name: str, company: str):
def import_coa(file_name, company):
# delete existing data for accounts
unset_existing_data(company)
@@ -159,9 +159,7 @@ def generate_data_from_excel(file_doc, extension, as_dict=False):
@frappe.whitelist()
def get_coa(
doctype: str, parent: str, is_root: bool = False, file_name: str | None = None, for_validate: int = 0
):
def get_coa(doctype, parent, is_root=False, file_name=None, for_validate=0):
"""called by tree view (to fetch node's children)"""
file_doc, extension = get_file(file_name)
@@ -309,7 +307,7 @@ def build_response_as_excel(writer):
@frappe.whitelist()
def download_template(file_type: str, template_type: str, company: str):
def download_template(file_type, template_type, company):
writer = get_template(template_type, company)
if file_type == "CSV":
@@ -363,7 +361,7 @@ def get_sample_template(writer, company):
@frappe.whitelist()
def validate_accounts(file_doc: Document, extension: str):
def validate_accounts(file_doc, extension):
if extension == "csv":
accounts = generate_data_from_csv(file_doc, as_dict=True)
else:

View File

@@ -1,8 +1,9 @@
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
from erpnext.tests.utils import ERPNextTestSuite
from frappe.tests import IntegrationTestCase
class TestChartofAccountsImporter(ERPNextTestSuite):
class TestChartofAccountsImporter(IntegrationTestCase):
pass

View File

@@ -47,7 +47,7 @@ class ChequePrintTemplate(Document):
@frappe.whitelist()
def create_or_update_cheque_print_format(template_name: str):
def create_or_update_cheque_print_format(template_name):
if not frappe.db.exists("Print Format", template_name):
cheque_print = frappe.new_doc("Print Format")
cheque_print.update(

View File

@@ -1,8 +1,9 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
from erpnext.tests.utils import ERPNextTestSuite
from frappe.tests import IntegrationTestCase
class TestChequePrintTemplate(ERPNextTestSuite):
class TestChequePrintTemplate(IntegrationTestCase):
pass

View File

@@ -1,12 +1,12 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import unittest
import frappe
from erpnext.tests.utils import ERPNextTestSuite
from frappe.tests import IntegrationTestCase
class TestCostCenter(ERPNextTestSuite):
class TestCostCenter(IntegrationTestCase):
def test_cost_center_creation_against_child_node(self):
cost_center = frappe.get_doc(
{

View File

@@ -0,0 +1,23 @@
[
{
"company": "_Test Company",
"cost_center_name": "_Test Cost Center",
"doctype": "Cost Center",
"is_group": 0,
"parent_cost_center": "_Test Company - _TC"
},
{
"company": "_Test Company",
"cost_center_name": "_Test Cost Center 2",
"doctype": "Cost Center",
"is_group": 0,
"parent_cost_center": "_Test Company - _TC"
},
{
"company": "_Test Company",
"cost_center_name": "_Test Write Off Cost Center",
"doctype": "Cost Center",
"is_group": 0,
"parent_cost_center": "_Test Company - _TC"
}
]

View File

@@ -1,8 +1,10 @@
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.query_builder.functions import Sum
from frappe.tests import IntegrationTestCase
from frappe.utils import add_days, today
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
@@ -14,10 +16,9 @@ from erpnext.accounts.doctype.cost_center_allocation.cost_center_allocation impo
WrongPercentageAllocation,
)
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
from erpnext.tests.utils import ERPNextTestSuite
class TestCostCenterAllocation(ERPNextTestSuite):
class TestCostCenterAllocation(IntegrationTestCase):
def setUp(self):
cost_centers = [
"Main Cost Center 1",
@@ -190,7 +191,7 @@ class TestCostCenterAllocation(ERPNextTestSuite):
coa2.cancel()
jv.cancel()
@ERPNextTestSuite.change_settings("System Settings", {"rounding_method": "Commercial Rounding"})
@IntegrationTestCase.change_settings("System Settings", {"rounding_method": "Commercial Rounding"})
def test_debit_credit_on_cost_center_allocation_for_commercial_rounding(self):
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice

View File

@@ -1,10 +1,13 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests import IntegrationTestCase
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.tests.utils import ERPNextTestSuite
EXTRA_TEST_RECORD_DEPENDENCIES = ["Item"]
def test_create_test_data():
@@ -85,7 +88,6 @@ def test_create_test_data():
"partner_name": "_Test Coupon Partner",
"commission_rate": 2,
"referral_code": "COPART",
"territory": "All Territories",
}
)
sales_partner.insert()
@@ -108,10 +110,13 @@ def test_create_test_data():
coupon_code.insert()
class TestCouponCode(ERPNextTestSuite):
class TestCouponCode(IntegrationTestCase):
def setUp(self):
test_create_test_data()
def tearDown(self):
frappe.set_user("Administrator")
def test_sales_order_with_coupon_code(self):
frappe.db.set_value("Coupon Code", "SAVE30", "used", 0)

View File

@@ -101,11 +101,11 @@
"label": "Use HTTP Protocol"
}
],
"hide_toolbar": 0,
"hide_toolbar": 1,
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2026-03-16 13:28:21.075743",
"modified": "2026-01-02 18:19:02.873815",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Currency Exchange Settings",

View File

@@ -1,9 +1,10 @@
# Copyright (c) 2021, Wahni Green Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
import unittest
from erpnext.tests.utils import ERPNextTestSuite
from frappe.tests import IntegrationTestCase
class TestCurrencyExchangeSettings(ERPNextTestSuite):
class TestCurrencyExchangeSettings(IntegrationTestCase):
pass

View File

@@ -4,20 +4,37 @@ import json
import frappe
from frappe.model import mapper
from frappe.tests import IntegrationTestCase
from frappe.utils import add_days, nowdate, today
from erpnext import get_default_cost_center
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import (
unlink_payment_on_cancel_of_invoice,
)
from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
create_dunning as create_dunning_from_sales_invoice,
)
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import (
create_sales_invoice_against_cost_center,
)
from erpnext.tests.utils import ERPNextTestSuite
EXTRA_TEST_RECORD_DEPENDENCIES = ["Company", "Cost Center"]
class TestDunning(ERPNextTestSuite):
class TestDunning(IntegrationTestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
create_dunning_type("First Notice", fee=0.0, interest=0.0, is_default=1)
create_dunning_type("Second Notice", fee=10.0, interest=10.0, is_default=0)
unlink_payment_on_cancel_of_invoice()
@classmethod
def tearDownClass(cls):
unlink_payment_on_cancel_of_invoice(0)
super().tearDownClass()
def test_dunning_without_fees(self):
dunning = create_dunning(overdue_days=20)

View File

@@ -1,9 +1,10 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
import unittest
from erpnext.tests.utils import ERPNextTestSuite
from frappe.tests import IntegrationTestCase
class TestDunningType(ERPNextTestSuite):
class TestDunningType(IntegrationTestCase):
pass

View File

@@ -0,0 +1,36 @@
[
{
"doctype": "Dunning Type",
"dunning_type": "_Test First Notice",
"company": "_Test Company",
"is_default": 1,
"dunning_fee": 0.0,
"rate_of_interest": 0.0,
"dunning_letter_text": [
{
"language": "en",
"body_text": "We have still not received payment for our invoice",
"closing_text": "We kindly request that you pay the outstanding amount immediately, including interest and late fees."
}
],
"income_account": "Sales - _TC",
"cost_center": "_Test Cost Center - _TC"
},
{
"doctype": "Dunning Type",
"dunning_type": "_Test Second Notice",
"company": "_Test Company",
"is_default": 0,
"dunning_fee": 10.0,
"rate_of_interest": 10.0,
"dunning_letter_text": [
{
"language": "en",
"body_text": "We have still not received payment for our invoice",
"closing_text": "We kindly request that you pay the outstanding amount immediately, including interest and late fees."
}
],
"income_account": "Sales - _TC",
"cost_center": "_Test Cost Center - _TC"
}
]

View File

@@ -1,7 +1,6 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from datetime import date
import frappe
from frappe import _, qb
@@ -615,12 +614,7 @@ def calculate_exchange_rate_using_last_gle(company, account, party_type, party):
@frappe.whitelist()
def get_account_details(
company: str,
posting_date: str | date,
account: str,
party_type: str | None = None,
party: str | None = None,
rounding_loss_allowance: float = 0.0,
company, posting_date, account, party_type=None, party=None, rounding_loss_allowance: float | None = None
):
if not (company and posting_date):
frappe.throw(_("Company and Posting Date is mandatory"))

View File

@@ -5,15 +5,15 @@
import frappe
from frappe.query_builder import functions
from frappe.query_builder.utils import DocType
from frappe.tests import IntegrationTestCase
from frappe.utils import add_days, flt, today
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
from erpnext.tests.utils import ERPNextTestSuite
class TestExchangeRateRevaluation(AccountsTestMixin, ERPNextTestSuite):
class TestExchangeRateRevaluation(AccountsTestMixin, IntegrationTestCase):
def setUp(self):
self.create_company()
self.create_usd_receivable_account()
@@ -22,13 +22,14 @@ class TestExchangeRateRevaluation(AccountsTestMixin, ERPNextTestSuite):
self.clear_old_entries()
self.set_system_and_company_settings()
def tearDown(self):
frappe.db.rollback()
def set_system_and_company_settings(self):
# set number and currency precision
system_settings = frappe.get_doc("System Settings")
system_settings.float_precision = 2
system_settings.currency_precision = 2
system_settings.language = "en"
system_settings.time_zone = "Asia/Kolkata"
system_settings.save()
# Using Exchange Gain/Loss account for unrealized as well.
@@ -36,7 +37,7 @@ class TestExchangeRateRevaluation(AccountsTestMixin, ERPNextTestSuite):
company_doc.unrealized_exchange_gain_loss_account = company_doc.exchange_gain_loss_account
company_doc.save()
@ERPNextTestSuite.change_settings(
@IntegrationTestCase.change_settings(
"Accounts Settings",
{"allow_multi_currency_invoices_against_single_party_account": 1, "allow_stale": 0},
)
@@ -90,7 +91,7 @@ class TestExchangeRateRevaluation(AccountsTestMixin, ERPNextTestSuite):
)[0]
self.assertEqual(acc_balance.balance, 8500.0)
@ERPNextTestSuite.change_settings(
@IntegrationTestCase.change_settings(
"Accounts Settings",
{"allow_multi_currency_invoices_against_single_party_account": 1, "allow_stale": 0},
)
@@ -163,7 +164,7 @@ class TestExchangeRateRevaluation(AccountsTestMixin, ERPNextTestSuite):
self.assertEqual(acc_balance.balance, 0.0)
self.assertEqual(acc_balance.balance_in_account_currency, 0.0)
@ERPNextTestSuite.change_settings(
@IntegrationTestCase.change_settings(
"Accounts Settings",
{"allow_multi_currency_invoices_against_single_party_account": 1, "allow_stale": 0},
)
@@ -258,7 +259,7 @@ class TestExchangeRateRevaluation(AccountsTestMixin, ERPNextTestSuite):
self.assertEqual(flt(acc_balance.balance, precision), 0.0)
self.assertEqual(flt(acc_balance.balance_in_account_currency, precision), 0.0)
@ERPNextTestSuite.change_settings(
@IntegrationTestCase.change_settings(
"Accounts Settings",
{"allow_multi_currency_invoices_against_single_party_account": 1, "allow_stale": 0},
)

View File

@@ -1,13 +1,14 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests import IntegrationTestCase
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
from erpnext.tests.utils import ERPNextTestSuite
class TestFinanceBook(ERPNextTestSuite):
class TestFinanceBook(IntegrationTestCase):
def test_finance_book(self):
finance_book = create_finance_book()

View File

@@ -15,7 +15,7 @@ from frappe.database.operator_map import OPERATOR_MAP
from frappe.query_builder import Case
from frappe.query_builder.functions import Sum
from frappe.utils import cstr, date_diff, flt, getdate
from pypika.terms import Bracket, LiteralValue
from pypika.terms import LiteralValue
from erpnext import get_company_currency
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
@@ -541,7 +541,7 @@ class FinancialQueryBuilder:
.where(acb_table.period_closing_voucher == closing_voucher)
)
query = self._apply_standard_filters(query, acb_table, "Account Closing Balance")
query = self._apply_standard_filters(query, acb_table)
results = self._execute_with_permissions(query, "Account Closing Balance")
for row in results:
@@ -636,15 +636,12 @@ class FinancialQueryBuilder:
return self._execute_with_permissions(query, "GL Entry")
def _calculate_running_balances(self, balances_data: dict, gl_data: list[dict]) -> dict:
gl_dict = {row["account"]: row for row in gl_data}
accounts = set(balances_data.keys()) | set(gl_dict.keys())
for account in accounts:
for row in gl_data:
account = row["account"]
if account not in balances_data:
balances_data[account] = AccountData(account=account, **self._get_account_meta(account))
account_data: AccountData = balances_data[account]
gl_movement = gl_dict.get(account, {})
if account_data.has_periods():
first_period = account_data.get_period(self.periods[0]["key"])
@@ -654,13 +651,20 @@ class FinancialQueryBuilder:
for period in self.periods:
period_key = period["key"]
movement = gl_movement.get(period_key, 0.0)
movement = row.get(period_key, 0.0)
closing_balance = current_balance + movement
account_data.add_period(PeriodValue(period_key, current_balance, closing_balance, movement))
current_balance = closing_balance
# Accounts with no movements
for account_data in balances_data.values():
for period in self.periods:
period_key = period["key"]
if period_key not in account_data.period_values:
account_data.add_period(PeriodValue(period_key, 0.0, 0.0, 0.0))
def _handle_balance_accumulation(self, balances_data):
for account_data in balances_data.values():
account_data: AccountData
@@ -679,12 +683,12 @@ class FinancialQueryBuilder:
else:
account_data.unaccumulate_values()
def _apply_standard_filters(self, query, table, doctype: str = "GL Entry"):
def _apply_standard_filters(self, query, table):
if self.filters.get("ignore_closing_entries"):
if doctype == "GL Entry":
query = query.where(table.voucher_type != "Period Closing Voucher")
else:
if hasattr(table, "is_period_closing_voucher_entry"):
query = query.where(table.is_period_closing_voucher_entry == 0)
else:
query = query.where(table.voucher_type != "Period Closing Voucher")
if self.filters.get("project"):
projects = self.filters.get("project")
@@ -732,7 +736,7 @@ class FinancialQueryBuilder:
user_conditions = build_match_conditions(doctype)
if user_conditions:
query = query.where(Bracket(LiteralValue(user_conditions)))
query = query.where(LiteralValue(user_conditions))
return query.run(as_dict=True)

View File

@@ -5,6 +5,7 @@ import os
import shutil
import frappe
from frappe import _
from frappe.model.document import Document
from erpnext.accounts.doctype.account_category.account_category import import_account_categories

View File

@@ -1,15 +1,18 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import ast
import json
import re
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Any
from enum import Enum
from typing import Any, ClassVar
import frappe
from frappe import _
from frappe.database.operator_map import OPERATOR_MAP
from frappe.database.query import SQLFunctionParser
@dataclass

View File

@@ -5,16 +5,24 @@ import frappe
from frappe.utils import flt
from erpnext.accounts.doctype.financial_report_template.financial_report_engine import (
AccountData,
DataCollector,
DependencyResolver,
FilterExpressionParser,
FinancialQueryBuilder,
FormulaCalculator,
PeriodValue,
)
from erpnext.accounts.doctype.financial_report_template.test_financial_report_template import (
FinancialReportTemplateTestCase,
)
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
from erpnext.accounts.utils import get_currency_precision, get_fiscal_year
from erpnext.accounts.utils import get_currency_precision
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list
EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
class TestDependencyResolver(FinancialReportTemplateTestCase):
@@ -1664,360 +1672,3 @@ class TestFilterExpressionParser(FinancialReportTemplateTestCase):
mock_row_invalid = self._create_mock_report_row(invalid_formula)
condition = parser.build_condition(mock_row_invalid, account_table)
self.assertIsNone(condition)
class TestFinancialQueryBuilder(FinancialReportTemplateTestCase):
def test_fetch_balances_with_journal_entries(self):
company = "_Test Company"
cash_account = "_Test Cash - _TC"
bank_account = "_Test Bank - _TC"
# Create journal entries in different periods
# October: Transfer 1000 from Bank to Cash
jv_oct = make_journal_entry(
account1=cash_account,
account2=bank_account,
amount=1000,
posting_date="2024-10-15",
company=company,
submit=True,
)
# November: Transfer 500 from Bank to Cash
jv_nov = make_journal_entry(
account1=cash_account,
account2=bank_account,
amount=500,
posting_date="2024-11-20",
company=company,
submit=True,
)
# December: No transactions (test zero movement period)
try:
# Set up filters and periods for Q4 2024
filters = {
"company": company,
"from_fiscal_year": "2024",
"to_fiscal_year": "2024",
"period_start_date": "2024-10-01",
"period_end_date": "2024-12-31",
"filter_based_on": "Date Range",
"periodicity": "Monthly",
}
periods = [
{"key": "2024_oct", "from_date": "2024-10-01", "to_date": "2024-10-31"},
{"key": "2024_nov", "from_date": "2024-11-01", "to_date": "2024-11-30"},
{"key": "2024_dec", "from_date": "2024-12-01", "to_date": "2024-12-31"},
]
query_builder = FinancialQueryBuilder(filters, periods)
# Create account objects as expected by fetch_account_balances
accounts = [
frappe._dict({"name": cash_account, "account_name": "Cash", "account_number": "1001"}),
frappe._dict({"name": bank_account, "account_name": "Bank", "account_number": "1002"}),
]
# Fetch balances using the full workflow
balances_data = query_builder.fetch_account_balances(accounts)
# Verify Cash account balances
cash_data = balances_data.get(cash_account)
self.assertIsNotNone(cash_data, "Cash account should exist in results")
# October: movement = +1000 (debit)
oct_cash = cash_data.get_period("2024_oct")
self.assertIsNotNone(oct_cash, "October period should exist for cash")
self.assertEqual(oct_cash.movement, 1000.0, "October cash movement should be 1000")
# November: movement = +500
nov_cash = cash_data.get_period("2024_nov")
self.assertIsNotNone(nov_cash, "November period should exist for cash")
self.assertEqual(nov_cash.movement, 500.0, "November cash movement should be 500")
self.assertEqual(
nov_cash.opening, oct_cash.closing, "November opening should equal October closing"
)
# December: movement = 0 (no transactions)
dec_cash = cash_data.get_period("2024_dec")
self.assertIsNotNone(dec_cash, "December period should exist for cash")
self.assertEqual(dec_cash.movement, 0.0, "December cash movement should be 0")
self.assertEqual(
dec_cash.closing,
nov_cash.closing,
"December closing should equal November closing when no movement",
)
# Verify Bank account balances (opposite direction)
bank_data = balances_data.get(bank_account)
self.assertIsNotNone(bank_data, "Bank account should exist in results")
oct_bank = bank_data.get_period("2024_oct")
self.assertEqual(oct_bank.movement, -1000.0, "October bank movement should be -1000")
nov_bank = bank_data.get_period("2024_nov")
self.assertEqual(nov_bank.movement, -500.0, "November bank movement should be -500")
finally:
# Clean up: cancel journal entries
jv_nov.cancel()
jv_oct.cancel()
def test_opening_balance_from_previous_period_closing(self):
company = "_Test Company"
cash_account = "_Test Cash - _TC"
sales_account = "Sales - _TC"
posting_date_2023 = "2023-06-15"
# Create journal entry in prior period (2023)
# Cash Dr 5000, Sales Cr 5000
jv_2023 = make_journal_entry(
account1=cash_account,
account2=sales_account,
amount=5000,
posting_date=posting_date_2023,
company=company,
submit=True,
)
pcv = None
jv_2024 = None
original_pcv_setting = frappe.db.get_single_value(
"Accounts Settings", "use_legacy_controller_for_pcv"
)
try:
# Create Period Closing Voucher for 2023
# This will create Account Closing Balance entries
closing_account = frappe.db.get_value(
"Account",
{
"company": company,
"root_type": "Liability",
"is_group": 0,
"account_type": ["not in", ["Payable", "Receivable"]],
},
"name",
)
fy_2023 = get_fiscal_year(posting_date_2023, company=company)
frappe.db.set_single_value("Accounts Settings", "use_legacy_controller_for_pcv", 1)
pcv = frappe.get_doc(
{
"doctype": "Period Closing Voucher",
"transaction_date": "2023-12-31",
"period_start_date": fy_2023[1],
"period_end_date": fy_2023[2],
"company": company,
"fiscal_year": fy_2023[0],
"cost_center": "_Test Cost Center - _TC",
"closing_account_head": closing_account,
"remarks": "Test Period Closing",
}
)
pcv.insert()
pcv.submit()
pcv.reload()
# Now create a small transaction in 2024 to ensure the account appears
jv_2024 = make_journal_entry(
account1=cash_account,
account2=sales_account,
amount=100,
posting_date="2024-01-15",
company=company,
submit=True,
)
# Set up filters for Q1 2024 (after the period closing)
filters = {
"company": company,
"from_fiscal_year": "2024",
"to_fiscal_year": "2024",
"period_start_date": "2024-01-01",
"period_end_date": "2024-03-31",
"filter_based_on": "Date Range",
"periodicity": "Monthly",
"ignore_closing_entries": True, # Don't include PCV entries in movements
}
periods = [
{"key": "2024_jan", "from_date": "2024-01-01", "to_date": "2024-01-31"},
{"key": "2024_feb", "from_date": "2024-02-01", "to_date": "2024-02-29"},
{"key": "2024_mar", "from_date": "2024-03-01", "to_date": "2024-03-31"},
]
query_builder = FinancialQueryBuilder(filters, periods)
accounts = [
frappe._dict({"name": cash_account, "account_name": "Cash", "account_number": "1001"}),
]
balances_data = query_builder.fetch_account_balances(accounts)
# Verify Cash account has opening balance from 2023 transactions
cash_data = balances_data.get(cash_account)
self.assertIsNotNone(cash_data, "Cash account should exist in results")
jan_cash = cash_data.get_period("2024_jan")
self.assertIsNotNone(jan_cash, "January period should exist")
# Opening balance should be from prior period
# Cash had 5000 debit in 2023, so opening in 2024 should be >= 5000
# (may be higher if there were other test transactions)
self.assertEqual(
jan_cash.opening,
5000.0,
"January opening should equal to balance from 2023 (5000)",
)
# Verify running balance logic
# Movement in January is 100 (from jv_2024)
self.assertEqual(jan_cash.movement, 100.0, "January movement should be 100")
self.assertEqual(
jan_cash.closing, jan_cash.opening + jan_cash.movement, "Closing = Opening + Movement"
)
# February and March should have no movement but carry the balance
feb_cash = cash_data.get_period("2024_feb")
self.assertEqual(feb_cash.opening, jan_cash.closing, "Feb opening = Jan closing")
self.assertEqual(feb_cash.movement, 0.0, "February should have no movement")
self.assertEqual(feb_cash.closing, feb_cash.opening, "Feb closing = opening when no movement")
mar_cash = cash_data.get_period("2024_mar")
self.assertEqual(mar_cash.opening, feb_cash.closing, "Mar opening = Feb closing")
self.assertEqual(mar_cash.movement, 0.0, "March should have no movement")
self.assertEqual(mar_cash.closing, mar_cash.opening, "Mar closing = opening when no movement")
# Set up filters for Q2 2024
filters_q2 = {
"company": company,
"from_fiscal_year": "2024",
"to_fiscal_year": "2024",
"period_start_date": "2024-04-01",
"period_end_date": "2024-06-30",
"filter_based_on": "Date Range",
"periodicity": "Monthly",
"ignore_closing_entries": True,
}
periods_q2 = [
{"key": "2024_apr", "from_date": "2024-04-01", "to_date": "2024-04-30"},
{"key": "2024_may", "from_date": "2024-05-01", "to_date": "2024-05-31"},
{"key": "2024_jun", "from_date": "2024-06-01", "to_date": "2024-06-30"},
]
query_builder_q2 = FinancialQueryBuilder(filters_q2, periods_q2)
balances_data_q2 = query_builder_q2.fetch_account_balances(accounts)
# Verify Cash account in Q2
cash_data_q2 = balances_data_q2.get(cash_account)
self.assertIsNotNone(cash_data_q2, "Cash account should exist in Q2 results")
apr_cash = cash_data_q2.get_period("2024_apr")
self.assertIsNotNone(apr_cash, "April period should exist")
# Opening balance in April should equal closing in March
self.assertEqual(
apr_cash.opening,
mar_cash.closing,
"April opening should equal March closing balance",
)
self.assertEqual(apr_cash.closing, apr_cash.opening, "April closing = opening when no movement")
finally:
# Clean up
frappe.db.set_single_value(
"Accounts Settings", "use_legacy_controller_for_pcv", original_pcv_setting or 0
)
if jv_2024:
jv_2024.cancel()
if pcv:
pcv.reload()
if pcv.docstatus == 1:
pcv.cancel()
jv_2023.cancel()
def test_account_with_gl_entries_but_no_prior_closing_balance(self):
company = "_Test Company"
cash_account = "_Test Cash - _TC"
bank_account = "_Test Bank - _TC"
# Create journal entries WITHOUT any prior Period Closing Voucher
# This ensures the account exists in gl_dict but NOT in balances_data
jv = make_journal_entry(
account1=cash_account,
account2=bank_account,
amount=2500,
posting_date="2024-07-15",
company=company,
submit=True,
)
try:
# Set up filters - use a period with no prior PCV
filters = {
"company": company,
"from_fiscal_year": "2024",
"to_fiscal_year": "2024",
"period_start_date": "2024-07-01",
"period_end_date": "2024-09-30",
"filter_based_on": "Date Range",
"periodicity": "Monthly",
}
periods = [
{"key": "2024_jul", "from_date": "2024-07-01", "to_date": "2024-07-31"},
{"key": "2024_aug", "from_date": "2024-08-01", "to_date": "2024-08-31"},
{"key": "2024_sep", "from_date": "2024-09-01", "to_date": "2024-09-30"},
]
query_builder = FinancialQueryBuilder(filters, periods)
# Use accounts that have GL entries but may not have Account Closing Balance
accounts = [
frappe._dict({"name": cash_account, "account_name": "Cash", "account_number": "1001"}),
frappe._dict({"name": bank_account, "account_name": "Bank", "account_number": "1002"}),
]
balances_data = query_builder.fetch_account_balances(accounts)
# Verify accounts are present in results even without prior closing balance
cash_data = balances_data.get(cash_account)
self.assertIsNotNone(cash_data, "Cash account should exist in results")
bank_data = balances_data.get(bank_account)
self.assertIsNotNone(bank_data, "Bank account should exist in results")
# Verify July has the movement from journal entry
jul_cash = cash_data.get_period("2024_jul")
self.assertIsNotNone(jul_cash, "July period should exist for cash")
self.assertEqual(jul_cash.movement, 2500.0, "July cash movement should be 2500")
jul_bank = bank_data.get_period("2024_jul")
self.assertIsNotNone(jul_bank, "July period should exist for bank")
self.assertEqual(jul_bank.movement, -2500.0, "July bank movement should be -2500")
# Verify subsequent periods exist with zero movement
aug_cash = cash_data.get_period("2024_aug")
self.assertIsNotNone(aug_cash, "August period should exist for cash")
self.assertEqual(aug_cash.movement, 0.0, "August cash movement should be 0")
self.assertEqual(aug_cash.opening, jul_cash.closing, "August opening = July closing")
sep_cash = cash_data.get_period("2024_sep")
self.assertIsNotNone(sep_cash, "September period should exist for cash")
self.assertEqual(sep_cash.movement, 0.0, "September cash movement should be 0")
self.assertEqual(sep_cash.opening, aug_cash.closing, "September opening = August closing")
finally:
jv.cancel()

View File

@@ -2,16 +2,29 @@
# For license information, please see license.txt
import frappe
from frappe.tests import IntegrationTestCase
from frappe.tests.utils import make_test_records
from erpnext.tests.utils import ERPNextTestSuite
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list
EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
class FinancialReportTemplateTestCase(ERPNextTestSuite):
class TestFinancialReportTemplate(IntegrationTestCase):
pass
class FinancialReportTemplateTestCase(IntegrationTestCase):
"""Utility class with common setup and helper methods for all test classes"""
def setUp(self):
@classmethod
def setUpClass(cls):
"""Set up test data"""
self.create_test_template()
make_test_records("Company")
make_test_records("Fiscal Year")
cls.create_test_template()
@classmethod
def create_test_template(cls):

View File

@@ -4,7 +4,7 @@
import frappe
from dateutil.relativedelta import relativedelta
from frappe import _, cint
from frappe import _
from frappe.model.document import Document
from frappe.utils import add_days, add_years, cstr, getdate
@@ -33,11 +33,23 @@ class FiscalYear(Document):
self.validate_dates()
self.validate_overlap()
def on_update(self):
frappe.cache().delete_key("fiscal_years")
if not self.is_new():
year_start_end_dates = frappe.db.sql(
"""select year_start_date, year_end_date
from `tabFiscal Year` where name=%s""",
(self.name),
)
def on_trash(self):
frappe.cache().delete_key("fiscal_years")
if year_start_end_dates:
if (
getdate(self.year_start_date) != year_start_end_dates[0][0]
or getdate(self.year_end_date) != year_start_end_dates[0][1]
):
frappe.throw(
_(
"Cannot change Fiscal Year Start Date and Fiscal Year End Date once the Fiscal Year is saved."
)
)
def validate_dates(self):
self.validate_from_to_dates("year_start_date", "year_end_date")
@@ -54,20 +66,28 @@ class FiscalYear(Document):
frappe.exceptions.InvalidDates,
)
def on_update(self):
check_duplicate_fiscal_year(self)
frappe.cache().delete_value("fiscal_years")
def on_trash(self):
frappe.cache().delete_value("fiscal_years")
def validate_overlap(self):
fy = frappe.qb.DocType("Fiscal Year")
name = self.name or self.year
existing_fiscal_years = (
frappe.qb.from_(fy)
.select(fy.name)
.where(
(fy.year_start_date <= self.year_end_date)
& (fy.year_end_date >= self.year_start_date)
& (fy.name != name)
)
.run(as_dict=True)
existing_fiscal_years = frappe.db.sql(
"""select name from `tabFiscal Year`
where (
(%(year_start_date)s between year_start_date and year_end_date)
or (%(year_end_date)s between year_start_date and year_end_date)
or (year_start_date between %(year_start_date)s and %(year_end_date)s)
or (year_end_date between %(year_start_date)s and %(year_end_date)s)
) and name!=%(name)s""",
{
"year_start_date": self.year_start_date,
"year_end_date": self.year_end_date,
"name": self.name or "No Name",
},
as_dict=True,
)
if existing_fiscal_years:
@@ -90,30 +110,37 @@ class FiscalYear(Document):
frappe.throw(
_(
"Year start date or end date is overlapping with {0}. To avoid please set company"
).format(frappe.get_desk_link("Fiscal Year", existing.name, open_in_new_tab=True)),
).format(existing.name),
frappe.NameError,
)
def auto_create_fiscal_year():
fy = frappe.qb.DocType("Fiscal Year")
# Skipped auto-creating Short Year, as it has very rare use case.
# Reference: https://www.irs.gov/businesses/small-businesses-self-employed/tax-years (US)
follow_up_date = add_days(getdate(), days=3)
fiscal_year = (
frappe.qb.from_(fy)
.select(fy.name)
.where((fy.year_end_date == follow_up_date) & (fy.is_short_year == 0))
.run()
@frappe.whitelist()
def check_duplicate_fiscal_year(doc):
year_start_end_dates = frappe.db.sql(
"""select name, year_start_date, year_end_date from `tabFiscal Year` where name!=%s""",
(doc.name),
)
for fiscal_year, ysd, yed in year_start_end_dates:
if (getdate(doc.year_start_date) == ysd and getdate(doc.year_end_date) == yed) and (
not frappe.in_test
):
frappe.throw(
_(
"Fiscal Year Start Date and Fiscal Year End Date are already set in Fiscal Year {0}"
).format(fiscal_year)
)
for d in fiscal_year:
@frappe.whitelist()
def auto_create_fiscal_year():
for d in frappe.db.sql(
"""select name from `tabFiscal Year` where year_end_date = date_add(current_date, interval 3 day)"""
):
try:
current_fy = frappe.get_doc("Fiscal Year", d[0])
new_fy = frappe.new_doc("Fiscal Year")
new_fy.disabled = cint(current_fy.disabled)
new_fy = frappe.copy_doc(current_fy, ignore_no_copy=False)
new_fy.year_start_date = add_days(current_fy.year_end_date, 1)
new_fy.year_end_date = add_years(current_fy.year_end_date, 1)
@@ -121,10 +148,6 @@ def auto_create_fiscal_year():
start_year = cstr(new_fy.year_start_date.year)
end_year = cstr(new_fy.year_end_date.year)
new_fy.year = start_year if start_year == end_year else (start_year + "-" + end_year)
for row in current_fy.companies:
new_fy.append("companies", {"company": row.company})
new_fy.auto_created = 1
new_fy.insert(ignore_permissions=True)

View File

@@ -1,13 +1,15 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import unittest
import frappe
from frappe.tests import IntegrationTestCase
from frappe.utils import now_datetime
from erpnext.tests.utils import ERPNextTestSuite
IGNORE_TEST_RECORD_DEPENDENCIES = ["Company"]
class TestFiscalYear(ERPNextTestSuite):
class TestFiscalYear(IntegrationTestCase):
def test_extra_year(self):
if frappe.db.exists("Fiscal Year", "_Test Fiscal Year 2000"):
frappe.delete_doc("Fiscal Year", "_Test Fiscal Year 2000")

View File

@@ -15,22 +15,20 @@
"ignore_user_permissions": 1,
"in_list_view": 1,
"label": "Company",
"options": "Company",
"reqd": 1
"options": "Company"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2026-02-20 23:02:26.193606",
"modified": "2024-03-27 13:09:44.659251",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Fiscal Year Company",
"owner": "Administrator",
"permissions": [],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -14,7 +14,7 @@ class FiscalYearCompany(Document):
if TYPE_CHECKING:
from frappe.types import DF
company: DF.Link
company: DF.Link | None
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data

View File

@@ -5,7 +5,6 @@
"doctype": "DocType",
"document_type": "Document",
"engine": "InnoDB",
"is_submittable": 1,
"field_order": [
"dates_section",
"posting_date",

View File

@@ -1,15 +1,16 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import unittest
import frappe
from frappe.model.naming import parse_naming_series
from frappe.tests import IntegrationTestCase
from erpnext.accounts.doctype.gl_entry.gl_entry import rename_gle_sle_docs
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
from erpnext.tests.utils import ERPNextTestSuite
class TestGLEntry(ERPNextTestSuite):
class TestGLEntry(IntegrationTestCase):
def test_round_off_entry(self):
frappe.db.set_value("Company", "_Test Company", "round_off_account", "_Test Write Off - _TC")
frappe.db.set_value("Company", "_Test Company", "round_off_cost_center", "_Test Cost Center - _TC")

View File

@@ -317,7 +317,7 @@ class InvoiceDiscounting(AccountsController):
@frappe.whitelist()
def get_invoices(filters: str):
def get_invoices(filters):
filters = frappe._dict(json.loads(filters))
cond = []
if filters.customer:

View File

@@ -1,17 +1,18 @@
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests import IntegrationTestCase
from frappe.utils import add_days, flt, nowdate
from erpnext.accounts.doctype.account.test_account import create_account
from erpnext.accounts.doctype.journal_entry.journal_entry import get_payment_entry_against_invoice
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries
from erpnext.tests.utils import ERPNextTestSuite
class TestInvoiceDiscounting(ERPNextTestSuite):
class TestInvoiceDiscounting(IntegrationTestCase):
def setUp(self):
self.ar_credit = create_account(
account_name="_Test Accounts Receivable Credit",

View File

@@ -1,8 +1,9 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
from erpnext.tests.utils import ERPNextTestSuite
from frappe.tests import IntegrationTestCase
class TestItemTaxTemplate(ERPNextTestSuite):
class TestItemTaxTemplate(IntegrationTestCase):
pass

View File

@@ -0,0 +1,79 @@
[
{
"doctype": "Item Tax Template",
"title": "_Test Account Excise Duty @ 10",
"company": "_Test Company",
"taxes": [
{
"doctype": "Item Tax Template Detail",
"parentfield": "taxes",
"tax_rate": 10,
"tax_type": "_Test Account Excise Duty - _TC"
}
]
},
{
"doctype": "Item Tax Template",
"title": "_Test Account Excise Duty @ 12",
"company": "_Test Company",
"taxes": [
{
"doctype": "Item Tax Template Detail",
"parentfield": "taxes",
"tax_rate": 12,
"tax_type": "_Test Account Excise Duty - _TC"
}
]
},
{
"doctype": "Item Tax Template",
"title": "_Test Account Excise Duty @ 15",
"company": "_Test Company",
"taxes": [
{
"doctype": "Item Tax Template Detail",
"parentfield": "taxes",
"tax_rate": 15,
"tax_type": "_Test Account Excise Duty - _TC"
}
]
},
{
"doctype": "Item Tax Template",
"title": "_Test Account Excise Duty @ 20",
"company": "_Test Company",
"taxes": [
{
"doctype": "Item Tax Template Detail",
"parentfield": "taxes",
"tax_rate": 20,
"tax_type": "_Test Account Excise Duty - _TC"
}
]
},
{
"doctype": "Item Tax Template",
"title": "_Test Item Tax Template 1",
"company": "_Test Company",
"taxes": [
{
"doctype": "Item Tax Template Detail",
"parentfield": "taxes",
"tax_rate": 5,
"tax_type": "_Test Account Excise Duty - _TC"
},
{
"doctype": "Item Tax Template Detail",
"parentfield": "taxes",
"tax_rate": 10,
"tax_type": "_Test Account Education Cess - _TC"
},
{
"doctype": "Item Tax Template Detail",
"parentfield": "taxes",
"tax_rate": 15,
"tax_type": "_Test Account S&H Education Cess - _TC"
}
]
}
]

View File

@@ -277,21 +277,7 @@ frappe.ui.form.on("Journal Entry", {
var update_jv_details = function (doc, r) {
$.each(r, function (i, d) {
var row = frappe.model.add_child(doc, "Journal Entry Account", "accounts");
const {
idx,
name,
owner,
parent,
parenttype,
parentfield,
creation,
modified,
modified_by,
doctype,
docstatus,
...fields
} = d;
frappe.model.set_value(row.doctype, row.name, fields);
frappe.model.set_value(row.doctype, row.name, "account", d.account);
});
refresh_field("accounts");
};
@@ -303,6 +289,10 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
}
onload_post_render() {
this.frm.get_field("accounts").grid.set_multiple_add("account");
}
load_defaults() {
//this.frm.show_print_first = true;
if (this.frm.doc.__islocal && this.frm.doc.company) {

View File

@@ -9,16 +9,19 @@
"engine": "InnoDB",
"field_order": [
"entry_type_and_date",
"company",
"is_system_generated",
"title",
"voucher_type",
"column_break1",
"naming_series",
"process_deferred_accounting",
"reversal_of",
"column_break1",
"from_template",
"company",
"posting_date",
"multi_currency",
"finance_book",
"apply_tds",
"tax_withholding_category",
"is_system_generated",
"amended_from",
"section_break_tcvw",
"for_all_stock_asset_accounts",
"column_break_wpau",
@@ -27,60 +30,52 @@
"get_balance_for_periodic_accounting",
"2_add_edit_gl_entries",
"accounts",
"section_break_ouaq",
"total_debit",
"column_break_cixu",
"total_credit",
"difference",
"get_balance",
"section_break99",
"cheque_no",
"cheque_date",
"clearance_date",
"column_break_oizh",
"user_remark",
"subscription_section",
"auto_repeat",
"tax_withholding_tab",
"column_break99",
"total_debit",
"total_credit",
"difference",
"get_balance",
"multi_currency",
"total_amount_currency",
"total_amount",
"total_amount_in_words",
"section_tax_withholding_entry",
"tax_withholding_group",
"ignore_tax_withholding_threshold",
"override_tax_withholding_entries",
"tax_withholding_entries",
"more_info_tab",
"reference",
"clearance_date",
"remark",
"inter_company_journal_entry_reference",
"column_break98",
"bill_no",
"bill_date",
"due_date",
"column_break_isfa",
"inter_company_journal_entry_reference",
"process_deferred_accounting",
"reversal_of",
"payment_order",
"stock_entry",
"printing_settings",
"pay_to_recd_from",
"letter_head",
"select_print_heading",
"column_break_35",
"total_amount_currency",
"total_amount",
"total_amount_in_words",
"write_off",
"write_off_based_on",
"get_outstanding_invoices",
"column_break_30",
"write_off_amount",
"printing_settings",
"pay_to_recd_from",
"column_break_35",
"letter_head",
"select_print_heading",
"addtional_info",
"is_opening",
"finance_book",
"from_template",
"title",
"column_break3",
"remark",
"mode_of_payment",
"party_not_required"
"payment_order",
"party_not_required",
"column_break3",
"is_opening",
"stock_entry",
"subscription_section",
"auto_repeat",
"amended_from"
],
"fields": [
{
@@ -140,7 +135,6 @@
{
"fieldname": "company",
"fieldtype": "Link",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Company",
"oldfieldname": "company",
@@ -161,7 +155,6 @@
{
"fieldname": "2_add_edit_gl_entries",
"fieldtype": "Section Break",
"hide_border": 1,
"oldfieldtype": "Section Break",
"options": "fa fa-table"
},
@@ -182,6 +175,7 @@
"fieldname": "cheque_no",
"fieldtype": "Data",
"in_global_search": 1,
"in_list_view": 1,
"label": "Reference Number",
"mandatory_depends_on": "eval:doc.voucher_type == \"Bank Entry\"",
"no_copy": 1,
@@ -208,6 +202,10 @@
"oldfieldtype": "Small Text",
"print_hide": 1
},
{
"fieldname": "column_break99",
"fieldtype": "Column Break"
},
{
"fieldname": "total_debit",
"fieldtype": "Currency",
@@ -431,7 +429,7 @@
"collapsible": 1,
"fieldname": "addtional_info",
"fieldtype": "Section Break",
"label": "Additional Info",
"label": "More Information",
"oldfieldtype": "Section Break",
"options": "fa fa-file-text"
},
@@ -478,7 +476,7 @@
{
"fieldname": "subscription_section",
"fieldtype": "Section Break",
"label": "Subscription"
"label": "Subscription Section"
},
{
"allow_on_submit": 1,
@@ -595,10 +593,12 @@
"no_copy": 1
},
{
"collapsible": 1,
"collapsible_depends_on": "eval: doc.apply_tds && doc.docstatus == 0",
"depends_on": "eval: doc.apply_tds",
"fieldname": "section_tax_withholding_entry",
"fieldtype": "Section Break"
"fieldtype": "Section Break",
"label": "Tax Withholding Entry"
},
{
"fieldname": "tax_withholding_group",
@@ -624,33 +624,6 @@
"label": "Tax Withholding Entries",
"options": "Tax Withholding Entry",
"read_only_depends_on": "eval: !doc.override_tax_withholding_entries"
},
{
"fieldname": "more_info_tab",
"fieldtype": "Tab Break",
"label": "More Info"
},
{
"fieldname": "section_break_ouaq",
"fieldtype": "Section Break"
},
{
"fieldname": "column_break_cixu",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_oizh",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_isfa",
"fieldtype": "Column Break"
},
{
"depends_on": "eval: doc.apply_tds",
"fieldname": "tax_withholding_tab",
"fieldtype": "Tab Break",
"label": "Tax Withholding"
}
],
"icon": "fa fa-file-text",
@@ -665,7 +638,7 @@
"table_fieldname": "payment_entries"
}
],
"modified": "2026-03-09 17:15:26.569327",
"modified": "2025-11-13 17:54:14.542903",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",

View File

@@ -1,13 +1,12 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import json
from datetime import date
import frappe
from frappe import _, msgprint, scrub
from frappe.core.doctype.submission_queue.submission_queue import queue_submission
from frappe.model.document import Document
from frappe.utils import comma_and, cstr, flt, fmt_money, formatdate, get_link_to_form, nowdate
import erpnext
@@ -75,8 +74,8 @@ class JournalEntry(AccountsController):
mode_of_payment: DF.Link | None
multi_currency: DF.Check
naming_series: DF.Literal["ACC-JV-.YYYY.-"]
override_tax_withholding_entries: DF.Check
party_not_required: DF.Check
override_tax_withholding_entries: DF.Check
pay_to_recd_from: DF.Data | None
payment_order: DF.Link | None
periodic_entry_difference_account: DF.Link | None
@@ -294,8 +293,6 @@ class JournalEntry(AccountsController):
# References for this Journal are removed on the `on_cancel` event in accounts_controller
super().on_cancel()
from_doc_events = getattr(self, "ignore_linked_doctypes", ())
self.ignore_linked_doctypes = (
"GL Entry",
"Stock Ledger Entry",
@@ -309,10 +306,6 @@ class JournalEntry(AccountsController):
"Advance Payment Ledger Entry",
"Tax Withholding Entry",
)
if from_doc_events and from_doc_events != self.ignore_linked_doctypes:
self.ignore_linked_doctypes = self.ignore_linked_doctypes + from_doc_events
self.make_gl_entries(1)
JournalTaxWithholding(self).on_cancel()
self.unlink_advance_entry_reference()
@@ -1222,7 +1215,7 @@ class JournalEntry(AccountsController):
cancel_exchange_gain_loss_journal(frappe._dict(doctype=self.doctype, name=self.name))
@frappe.whitelist()
def get_balance(self, difference_account: str | None = None):
def get_balance(self, difference_account=None):
if not self.get("accounts"):
msgprint(_("'Entries' cannot be empty"), raise_exception=True)
else:
@@ -1328,12 +1321,7 @@ class JournalEntry(AccountsController):
@frappe.whitelist()
def get_default_bank_cash_account(
company: str,
account_type: str | None = None,
mode_of_payment: str | None = None,
account: str | None = None,
*,
fetch_balance: bool = True,
company, account_type=None, mode_of_payment=None, account=None, *, fetch_balance=True
):
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
@@ -1382,12 +1370,7 @@ def get_default_bank_cash_account(
@frappe.whitelist()
def get_payment_entry_against_order(
dt: str,
dn: str,
amount: float | None = None,
debit_in_account_currency: str | float | None = None,
journal_entry: bool = False,
bank_account: str | None = None,
dt, dn, amount=None, debit_in_account_currency=None, journal_entry=False, bank_account=None
):
ref_doc = frappe.get_doc(dt, dn)
@@ -1432,12 +1415,7 @@ def get_payment_entry_against_order(
@frappe.whitelist()
def get_payment_entry_against_invoice(
dt: str,
dn: str,
amount: float | None = None,
debit_in_account_currency: str | None = None,
journal_entry: bool = False,
bank_account: str | None = None,
dt, dn, amount=None, debit_in_account_currency=None, journal_entry=False, bank_account=None
):
ref_doc = frappe.get_doc(dt, dn)
if dt == "Sales Invoice":
@@ -1550,7 +1528,7 @@ def get_payment_entry(ref_doc, args):
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_against_jv(doctype: str, txt: str, searchfield: str, start: int, page_len: int, filters: dict):
def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
if not frappe.db.has_column("Journal Entry", searchfield):
return []
@@ -1581,7 +1559,7 @@ def get_against_jv(doctype: str, txt: str, searchfield: str, start: int, page_le
@frappe.whitelist()
def get_outstanding(args: str | dict):
def get_outstanding(args):
if not frappe.has_permission("Account"):
frappe.msgprint(_("No Permission"), raise_exception=1)
@@ -1641,7 +1619,7 @@ def get_outstanding(args: str | dict):
@frappe.whitelist()
def get_party_account_and_currency(company: str, party_type: str, party: str):
def get_party_account_and_currency(company, party_type, party):
if not frappe.has_permission("Account"):
frappe.msgprint(_("No Permission"), raise_exception=1)
@@ -1654,14 +1632,7 @@ def get_party_account_and_currency(company: str, party_type: str, party: str):
@frappe.whitelist()
def get_account_details_and_party_type(
account: str,
date: str,
company: str,
debit: float | str | None = None,
credit: float | str | None = None,
exchange_rate: float | str | None = None,
):
def get_account_details_and_party_type(account, date, company, debit=None, credit=None, exchange_rate=None):
"""Returns dict of account details and party type to be set in Journal Entry on selection of account."""
if not frappe.has_permission("Account"):
frappe.msgprint(_("No Permission"), raise_exception=1)
@@ -1710,15 +1681,15 @@ def get_account_details_and_party_type(
@frappe.whitelist()
def get_exchange_rate(
posting_date: str | date,
account: str | None = None,
account_currency: str | None = None,
company: str | None = None,
reference_type: str | None = None,
reference_name: str | None = None,
debit: float | str | None = None,
credit: float | str | None = None,
exchange_rate: str | float | None = None,
posting_date,
account=None,
account_currency=None,
company=None,
reference_type=None,
reference_name=None,
debit=None,
credit=None,
exchange_rate=None,
):
# Ensure exchange_rate is always numeric to avoid calculation errors
if isinstance(exchange_rate, str):
@@ -1755,7 +1726,7 @@ def get_exchange_rate(
@frappe.whitelist()
def get_average_exchange_rate(account: str):
def get_average_exchange_rate(account):
exchange_rate = 0
bank_balance_in_account_currency = get_balance_on(account)
if bank_balance_in_account_currency:
@@ -1766,7 +1737,7 @@ def get_average_exchange_rate(account: str):
@frappe.whitelist()
def make_inter_company_journal_entry(name: str, voucher_type: str, company: str):
def make_inter_company_journal_entry(name, voucher_type, company):
journal_entry = frappe.new_doc("Journal Entry")
journal_entry.voucher_type = voucher_type
journal_entry.company = company
@@ -1776,7 +1747,7 @@ def make_inter_company_journal_entry(name: str, voucher_type: str, company: str)
@frappe.whitelist()
def make_reverse_journal_entry(source_name: str, target_doc: str | Document | None = None):
def make_reverse_journal_entry(source_name, target_doc=None):
existing_reverse = frappe.db.exists("Journal Entry", {"reversal_of": source_name, "docstatus": 1})
if existing_reverse:
frappe.throw(

View File

@@ -2,20 +2,19 @@
# License: GNU General Public License v3. See license.txt
import frappe
from frappe.tests import IntegrationTestCase
from frappe.utils import flt, nowdate
from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.accounts.doctype.journal_entry.journal_entry import StockAccountInvalidTransaction
from erpnext.exceptions import InvalidAccountCurrency
from erpnext.selling.doctype.customer.test_customer import make_customer, set_credit_limit
from erpnext.tests.utils import ERPNextTestSuite
class TestJournalEntry(ERPNextTestSuite):
def setUp(self):
self.load_test_records("Journal Entry")
@ERPNextTestSuite.change_settings("Accounts Settings", {"unlink_payment_on_cancellation_of_invoice": 1})
class TestJournalEntry(IntegrationTestCase):
@IntegrationTestCase.change_settings(
"Accounts Settings", {"unlink_payment_on_cancellation_of_invoice": 1}
)
def test_journal_entry_with_against_jv(self):
jv_invoice = frappe.copy_doc(self.globalTestRecords["Journal Entry"][2])
base_jv = frappe.copy_doc(self.globalTestRecords["Journal Entry"][0])
@@ -150,6 +149,7 @@ class TestJournalEntry(ERPNextTestSuite):
if account_bal == stock_bal:
self.assertRaises(StockAccountInvalidTransaction, jv.save)
frappe.db.rollback()
else:
jv.submit()
jv.cancel()

View File

@@ -43,7 +43,7 @@
"fields": [
{
"bold": 1,
"columns": 4,
"columns": 2,
"fieldname": "account",
"fieldtype": "Link",
"in_global_search": 1,
@@ -185,19 +185,20 @@
"fieldtype": "Select",
"label": "Reference Type",
"no_copy": 1,
"options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees\nFull and Final Statement\nPayment Entry\nBank Transaction",
"options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees\nFull and Final Statement\nPayment Entry",
"search_index": 1
},
{
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"in_list_view": 1,
"label": "Reference Name",
"no_copy": 1,
"options": "reference_type",
"search_index": 1
},
{
"depends_on": "eval:doc.reference_type&&!in_list(doc.reference_type, ['Expense Claim', 'Asset', 'Employee Loan', 'Employee Advance', 'Bank Transaction'])",
"depends_on": "eval:doc.reference_type&&!in_list(doc.reference_type, ['Expense Claim', 'Asset', 'Employee Loan', 'Employee Advance'])",
"fieldname": "reference_due_date",
"fieldtype": "Date",
"label": "Reference Due Date",
@@ -293,7 +294,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2026-02-19 17:01:22.642454",
"modified": "2025-11-27 12:23:33.157655",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Account",

View File

@@ -55,7 +55,6 @@ class JournalEntryAccount(Document):
"Fees",
"Full and Final Statement",
"Payment Entry",
"Bank Transaction",
]
user_remark: DF.SmallText | None
# end: auto-generated types

View File

@@ -3,7 +3,6 @@
frappe.ui.form.on("Journal Entry Template", {
onload: function (frm) {
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
if (frm.is_new()) {
frappe.call({
type: "GET",
@@ -38,31 +37,6 @@ frappe.ui.form.on("Journal Entry Template", {
return { filters: filters };
});
frm.set_query("project", "accounts", function (doc, cdt, cdn) {
let row = frappe.get_doc(cdt, cdn);
let filters = {
company: doc.company,
};
if (row.party_type == "Customer") {
filters.customer = row.party;
}
return {
query: "erpnext.controllers.queries.get_project_name",
filters,
};
});
frm.set_query("party_type", "accounts", function (doc, cdt, cdn) {
const row = locals[cdt][cdn];
return {
query: "erpnext.setup.doctype.party_type.party_type.get_party_type",
filters: {
account: row.account,
},
};
});
},
voucher_type: function (frm) {
var add_accounts = function (doc, r) {

View File

@@ -3,7 +3,6 @@
import frappe
from frappe import _
from frappe.model.document import Document
@@ -43,29 +42,7 @@ class JournalEntryTemplate(Document):
]
# end: auto-generated types
def validate(self):
self.validate_party()
def validate_party(self):
"""
Loop over all accounts and see if party and party type is set correctly
"""
for account in self.accounts:
if account.party_type:
account_type = frappe.get_cached_value("Account", account.account, "account_type")
if account_type not in ["Receivable", "Payable"]:
frappe.throw(
_(
"Check row {0} for account {1}: Party Type is only allowed for Receivable or Payable accounts"
).format(account.idx, account.account)
)
if account.party and not account.party_type:
frappe.throw(
_("Check row {0} for account {1}: Party is only allowed if Party Type is set").format(
account.idx, account.account
)
)
pass
@frappe.whitelist()

Some files were not shown because too many files have changed in this diff Show More