Compare commits

...

670 Commits

Author SHA1 Message Date
Frappe PR Bot
0854333e42 chore(release): Bumped to Version 15.69.0
# [15.69.0](https://github.com/frappe/erpnext/compare/v15.68.0...v15.69.0) (2025-07-09)

### Features

* batch rate (valuation) in Batch-Wise Balance History report ([ba7e0b9](ba7e0b9506))
2025-07-09 15:16:52 +00:00
rohitwaghchaure
48e0ce1132 Merge pull request #48498 from frappe/mergify/bp/version-15/pr-48489
feat: batch rate (valuation) in Batch-Wise Balance History report (backport #48487) (backport #48489)
2025-07-09 20:44:29 +05:30
Rohit Waghchaure
ba7e0b9506 feat: batch rate (valuation) in Batch-Wise Balance History report
(cherry picked from commit 8a2a845a16)
(cherry picked from commit facd2027c3)
2025-07-09 14:16:27 +00:00
Frappe PR Bot
a94a13a7c1 chore(release): Bumped to Version 15.68.0
# [15.68.0](https://github.com/frappe/erpnext/compare/v15.67.0...v15.68.0) (2025-07-08)

### Bug Fixes

* add company field on POS Invoice Merge Log (backport [#48357](https://github.com/frappe/erpnext/issues/48357)) ([#48414](https://github.com/frappe/erpnext/issues/48414)) ([26db582](26db582499))
* Add company validation to company related fields in Process Statement Of Accounts ([5362648](536264896e))
* add not specified key for None respresented customer_group and territory ([8371daf](8371dafb1a))
* add selling price validation on update item ([a10e394](a10e3948b2))
* address not found when creating internal PR from DN ([f1621d1](f1621d15ff))
* consider empty string in previous doc validation ([b2de9cd](b2de9cdef2))
* cost center for payment entry against advance payment doctypes in accounts Payable/Receivable report ([3f004db](3f004db14f))
* duplicate items being created when fetching items from warehouse in stock reco ([818ddc0](818ddc0b8c))
* fetch from parent optional in inventory dimension ([ed77c15](ed77c15ebc))
* get fiscal year based on date ([177b23c](177b23c624))
* incorrect pending qty when creating PI from PO and PI rates differ from PO (backport [#48173](https://github.com/frappe/erpnext/issues/48173)) ([#48340](https://github.com/frappe/erpnext/issues/48340)) ([8eede1d](8eede1d266))
* item list and project not being set in work order when created from material request ([5cd36c3](5cd36c318b))
* job card material request/transfer buttons UI overlap ([09f8660](09f866022b))
* LCV from PR order mismatch ([74948aa](74948aabda))
* make labels in error message translatable (backport [#48327](https://github.com/frappe/erpnext/issues/48327)) ([#48436](https://github.com/frappe/erpnext/issues/48436)) ([6b41dc2](6b41dc2fed))
* multiple fixes related Deferred Accounting ([a4633d6](a4633d6e75))
* pos recent order display customer code and name (backport [#48379](https://github.com/frappe/erpnext/issues/48379)) ([#48388](https://github.com/frappe/erpnext/issues/48388)) ([f25097d](f25097da1d))
* **Quotation:** hide buttons if user cannot use them (backport [#48115](https://github.com/frappe/erpnext/issues/48115)) ([#48405](https://github.com/frappe/erpnext/issues/48405)) ([a2436e4](a2436e4b6e))
* rate not being fetched for product bundles in material request ([cfedaf5](cfedaf5dc1))
* rename journal entry title on update ([b7b5f6a](b7b5f6acf3))
* unnecessary primary button ([b1abcd5](b1abcd5577))
* update condition for blank tree fields in pricing rule ([f2d644b](f2d644ba29))
* update item reference in quality inspection ([65c277f](65c277fd27))
* update payment request outstanding on unreconciliation ([450061c](450061c7db))
* use default buying price list when price list is falsy ([a336e19](a336e19bb8))
* valuation rate of raw materials in subcontracting receipt ([4545213](4545213adc))

### Features

* add price list field to material request (backport [#48425](https://github.com/frappe/erpnext/issues/48425)) ([#48429](https://github.com/frappe/erpnext/issues/48429)) ([d4700e5](d4700e5560))
* add subject field to project ([#48368](https://github.com/frappe/erpnext/issues/48368)) ([9a538c6](9a538c6843))

### Reverts

* do not convert exchange gain/loss amount to foreign currency ([d0d1d63](d0d1d63d31))
* Revert "fix: stock reco qty with inventory dimension ([#47918](https://github.com/frappe/erpnext/issues/47918))" ([9a99ccc](9a99ccc166))
2025-07-08 13:01:14 +00:00
ruthra kumar
e573c6094a Merge pull request #48462 from frappe/version-15-hotfix
chore: release v15
2025-07-08 18:29:42 +05:30
ruthra kumar
524619e0b4 Merge pull request #48467 from frappe/mergify/bp/version-15-hotfix/pr-48259
fix: add not specified key for None respresented customer_group and t… (backport #48259)
2025-07-08 17:48:30 +05:30
ruthra kumar
5f5fa2f8e1 Merge pull request #48466 from frappe/mergify/bp/version-15-hotfix/pr-48378
fix: update item reference in quality inspection (backport #48378)
2025-07-08 17:48:17 +05:30
pugazhendhivelu
65c277fd27 fix: update item reference in quality inspection
(cherry picked from commit 9da5010265)

# Conflicts:
#	erpnext/public/js/controllers/transaction.js
2025-07-08 17:16:50 +05:30
l0gesh29
8371dafb1a fix: add not specified key for None respresented customer_group and territory
(cherry picked from commit 24cc711a70)

# Conflicts:
#	erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
2025-07-08 17:13:30 +05:30
ruthra kumar
f8bc0e47ff Merge pull request #48464 from frappe/mergify/bp/version-15-hotfix/pr-48402
fix: rename journal entry title on update (backport #48402)
2025-07-08 17:11:27 +05:30
ruthra kumar
d3a95f04cc Merge pull request #48470 from frappe/mergify/bp/version-15-hotfix/pr-48469
chore: better label for checkbox (backport #48469)
2025-07-08 17:10:50 +05:30
ruthra kumar
5f63794739 chore: better label for checkbox
(cherry picked from commit 8c2e40e291)
2025-07-08 11:40:08 +00:00
ruthra kumar
41bca34f6a Merge pull request #48468 from frappe/mergify/bp/version-15-hotfix/pr-48427
fix: Add company validation to company related fields in Process Statement Of Accounts (backport #48427)
2025-07-08 16:23:47 +05:30
ruthra kumar
f4b7093838 Merge pull request #48465 from frappe/mergify/bp/version-15-hotfix/pr-48359
fix: get fiscal year based on date (backport #48359)
2025-07-08 16:21:03 +05:30
ljain112
536264896e fix: Add company validation to company related fields in Process Statement Of Accounts
(cherry picked from commit 4e45e69247)
2025-07-08 10:37:17 +00:00
l0gesh29
177b23c624 fix: get fiscal year based on date
(cherry picked from commit efb8e7c0e4)
2025-07-08 10:26:26 +00:00
ravibharathi656
f81dba6380 chore: add none value
(cherry picked from commit 9e633bddef)
2025-07-08 10:25:18 +00:00
ravibharathi656
b7b5f6acf3 fix: rename journal entry title on update
(cherry picked from commit acb9829159)
2025-07-08 10:25:18 +00:00
ruthra kumar
d60d8a2625 Merge pull request #48457 from frappe/mergify/bp/version-15-hotfix/pr-48361
revert: do not convert exchange gain/loss amount to foreign currency (backport #48361)
2025-07-08 15:45:34 +05:30
ruthra kumar
e0efe922a6 Merge pull request #48459 from frappe/mergify/bp/version-15-hotfix/pr-48328
fix: update condition for blank tree fields in pricing rule (backport #48328)
2025-07-08 15:44:42 +05:30
mergify[bot]
500972e8aa refactor: remove do_reposting_for_each_stock_transaction feature (backport #48444) (#48452)
* refactor: remove do_reposting_for_each_stock_transaction feature

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-07-08 15:05:35 +05:30
Mihir Kandoi
b833dfab9d Merge pull request #48460 from frappe/mergify/bp/version-15-hotfix/pr-48456
fix: duplicate items being created when fetching items from warehouse in stock reco (backport #48456)
2025-07-08 15:05:11 +05:30
Mihir Kandoi
818ddc0b8c fix: duplicate items being created when fetching items from warehouse in stock reco
(cherry picked from commit 73f6c29559)
2025-07-08 09:01:47 +00:00
venkat102
d0d1d63d31 revert: do not convert exchange gain/loss amount to foreign currency
(cherry picked from commit c17ae703c7)

# Conflicts:
#	erpnext/accounts/report/general_ledger/test_general_ledger.py
2025-07-08 14:30:10 +05:30
ljain112
f2d644ba29 fix: update condition for blank tree fields in pricing rule
(cherry picked from commit 7e0e9db4d2)
2025-07-08 08:53:35 +00:00
ruthra kumar
9e831bbfc6 Merge pull request #48448 from frappe/mergify/bp/version-15-hotfix/pr-48326
fix: cost center for payment entry against advance payment doctypes in accounts payable/rece (backport #48326)
2025-07-08 14:06:28 +05:30
ruthra kumar
7690efa4f7 Merge pull request #48454 from frappe/mergify/bp/version-15-hotfix/pr-48416
refactor: remove duplicate reconciliation date logic (backport #48416)
2025-07-08 13:50:32 +05:30
ljain112
00669661e5 chore: resolve conflicts 2025-07-08 13:19:03 +05:30
ljain112
2ab1b42033 refactor: remove duplicate reconciliation date logic
(cherry picked from commit 398406082a)
2025-07-08 07:34:23 +00:00
ruthra kumar
2c156b58f0 Merge pull request #48453 from frappe/mergify/bp/version-15-hotfix/pr-48343
fix: consider empty string in previous doc validation (backport #48343)
2025-07-08 12:59:52 +05:30
Diptanil Saha
c617b343b3 Merge pull request #48449 from frappe/mergify/bp/version-15-hotfix/pr-48403
fix: add selling price validation on update item (backport #48403)
2025-07-08 12:41:58 +05:30
l0gesh29
b2de9cdef2 fix: consider empty string in previous doc validation
(cherry picked from commit dd43594ad6)
2025-07-08 07:11:51 +00:00
rohitwaghchaure
ae59908f0a Merge pull request #48443 from frappe/mergify/bp/version-15-hotfix/pr-48441
Revert "fix: stock reco qty with inventory dimension" (backport #48441)
2025-07-08 12:30:40 +05:30
l0gesh29
a10e3948b2 fix: add selling price validation on update item
(cherry picked from commit 327d067305)
2025-07-08 06:45:18 +00:00
Mihir Kandoi
fbe1f449d8 Merge pull request #48447 from frappe/mergify/bp/version-15-hotfix/pr-48332
fix: valuation rate of raw materials in subcontracting receipt (backport #48332)
2025-07-08 12:14:53 +05:30
Mihir Kandoi
b3fa0ac596 Merge pull request #48446 from frappe/mergify/bp/version-15-hotfix/pr-48445
fix: use default buying price list when price list is falsy (backport #48445)
2025-07-08 12:14:36 +05:30
ljain112
82d03e2617 refactor: function to fetch advance payment doctypes
(cherry picked from commit 48e8e85617)

# Conflicts:
#	erpnext/accounts/doctype/journal_entry/journal_entry.py
#	erpnext/accounts/doctype/payment_entry/payment_entry.py
#	erpnext/accounts/doctype/payment_request/payment_request.py
#	erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.py
#	erpnext/accounts/utils.py
#	erpnext/controllers/accounts_controller.py
2025-07-08 06:36:06 +00:00
ljain112
3f004db14f fix: cost center for payment entry against advance payment doctypes in accounts Payable/Receivable report
(cherry picked from commit 8f19f14004)
2025-07-08 06:36:06 +00:00
Mihir Kandoi
4545213adc fix: valuation rate of raw materials in subcontracting receipt
(cherry picked from commit 84ea6afd01)
2025-07-08 06:28:44 +00:00
Mihir Kandoi
a336e19bb8 fix: use default buying price list when price list is falsy
(cherry picked from commit 27c73cf9e9)
2025-07-08 06:26:09 +00:00
rohitwaghchaure
9a99ccc166 Revert "fix: stock reco qty with inventory dimension (#47918)"
This reverts commit 342cebc778.

(cherry picked from commit 8ba66c9833)
2025-07-08 05:08:04 +00:00
ruthra kumar
9935f04bde Merge pull request #48440 from frappe/mergify/bp/version-15-hotfix/pr-48324
fix: update payment request outstanding on unreconciliation (backport #48324)
2025-07-08 10:33:36 +05:30
ruthra kumar
cc5c4a3f9a chore: resolve conflict 2025-07-08 10:17:43 +05:30
rohitwaghchaure
0fefccc128 Merge pull request #48434 from frappe/mergify/bp/version-15-hotfix/pr-48432
fix: fetch from parent optional in inventory dimension (backport #48432)
2025-07-08 09:58:27 +05:30
ljain112
a8448f9e60 chore: fix test case for payment request
(cherry picked from commit 31d12517f0)
2025-07-08 04:16:41 +00:00
ljain112
450061c7db fix: update payment request outstanding on unreconciliation
(cherry picked from commit 8098229b55)

# Conflicts:
#	erpnext/accounts/doctype/payment_request/test_payment_request.py
2025-07-08 04:16:40 +00:00
rohitwaghchaure
5df8ad6ef1 chore: fix conflicts 2025-07-08 08:33:33 +05:30
mergify[bot]
6b41dc2fed fix: make labels in error message translatable (backport #48327) (#48436)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix: make labels in error message translatable (#48327)
2025-07-07 22:36:48 +02:00
Rohit Waghchaure
ed77c15ebc fix: fetch from parent optional in inventory dimension
(cherry picked from commit 8aac6a6b18)

# Conflicts:
#	erpnext/stock/doctype/inventory_dimension/inventory_dimension.json
2025-07-07 11:52:53 +00:00
mergify[bot]
d4700e5560 feat: add price list field to material request (backport #48425) (#48429)
* feat: add price list field to material request

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-07-07 15:50:04 +05:30
Mihir Kandoi
f4c9a6e59c Merge pull request #48430 from frappe/mergify/bp/version-15-hotfix/pr-48428
fix: address not found when creating internal PR from DN (backport #48428)
2025-07-07 15:43:22 +05:30
Mihir Kandoi
f1621d15ff fix: address not found when creating internal PR from DN
(cherry picked from commit 97c48ed6d2)
2025-07-07 09:51:19 +00:00
Mihir Kandoi
8638654c13 Merge pull request #48426 from frappe/mergify/bp/version-15-hotfix/pr-48424
fix: item list and project not being set in work order when created from material request (backport #48424)
2025-07-07 15:05:15 +05:30
Mihir Kandoi
5cd36c318b fix: item list and project not being set in work order when created from material request
(cherry picked from commit 099a5fbad9)
2025-07-07 08:49:26 +00:00
mergify[bot]
8eede1d266 fix: incorrect pending qty when creating PI from PO and PI rates differ from PO (backport #48173) (#48340)
* fix: incorrect pending qty when creating PI from PO and PI rates differ from PO

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-07-06 21:40:26 +05:30
mergify[bot]
26db582499 fix: add company field on POS Invoice Merge Log (backport #48357) (#48414)
* fix: add company field on POS Invoice Merge Log

(cherry picked from commit 109658731b)

# Conflicts:
#	erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json

* fix: patch for updating company name on existing pos merge log records

(cherry picked from commit d46b68230c)

# Conflicts:
#	erpnext/patches.txt

* fix: pass company on create_merge_logs

(cherry picked from commit b4b473185f)

* test: test company fetching from POS Closing Entry

(cherry picked from commit 9548f341bf)

# Conflicts:
#	erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py

* chore: remove conflicts

---------

Co-authored-by: Kavin <78342682+kavin0411@users.noreply.github.com>
Co-authored-by: diptanilsaha <diptanil@frappe.io>
2025-07-06 15:25:59 +05:30
ruthra kumar
89458f07c9 Merge pull request #48415 from frappe/mergify/bp/version-15-hotfix/pr-47805
fix: multiple fixes related Deferred Accounting (backport #47805)
2025-07-06 15:25:16 +05:30
Lakshit Jain
a4633d6e75 fix: multiple fixes related Deferred Accounting
(cherry picked from commit 277c1101fc)
2025-07-06 14:59:23 +05:30
Mihir Kandoi
dbe107345c Merge pull request #48404 from frappe/mergify/bp/version-15-hotfix/pr-48368
feat: add subject field to project (backport #48368)
2025-07-05 12:07:00 +05:30
mergify[bot]
a2436e4b6e fix(Quotation): hide buttons if user cannot use them (backport #48115) (#48405)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix(Quotation): hide buttons if user cannot use them (#48115)
2025-07-04 20:10:27 +02:00
Mihir Kandoi
9a538c6843 feat: add subject field to project (#48368)
* feat: add subject field to project

(cherry picked from commit 407fdab487)
2025-07-04 16:10:19 +00:00
Mihir Kandoi
d8f5924eb2 Merge pull request #48373 from mihir-kandoi/st42781
fix: LCV from PR order mismatch
2025-07-04 15:30:29 +05:30
Mihir Kandoi
9312a5b762 Merge pull request #48396 from frappe/mergify/bp/version-15-hotfix/pr-48372
fix: rate not being fetched for product bundles in material request (backport #48372)
2025-07-04 15:30:09 +05:30
Mihir Kandoi
edef03ac22 chore: resolve conflict 2025-07-04 12:49:45 +05:30
Mihir Kandoi
74948aabda fix: LCV from PR order mismatch 2025-07-04 12:48:15 +05:30
Mihir Kandoi
cfedaf5dc1 fix: rate not being fetched for product bundles in material request
(cherry picked from commit 45c7bac2d0)

# Conflicts:
#	erpnext/stock/doctype/packed_item/packed_item.py
2025-07-04 07:16:39 +00:00
mergify[bot]
f25097da1d fix: pos recent order display customer code and name (backport #48379) (#48388)
fix: pos recent order display customer code and name (#48379)

(cherry picked from commit 5f721f01d3)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-07-04 12:40:19 +05:30
mergify[bot]
3952f5d913 chore: fix flaky test in Tax Withholding Details (backport #48375) (#48394)
* chore: fix flaky test in Tax Withholding Details

(cherry picked from commit 14a2f98521)

* fix: sort tax withhodling details report by section code and transaction date

(cherry picked from commit 7ee2418f60)

* fix(test): flaky budget test case

(cherry picked from commit 704223e5d0)

* fix(test): import get_accumulated_monthly_budget

---------

Co-authored-by: ljain112 <ljain112@gmail.com>
Co-authored-by: ruthra kumar <ruthra@erpnext.com>
Co-authored-by: diptanilsaha <diptanil@frappe.io>
2025-07-04 12:05:55 +05:30
Mihir Kandoi
9d23199c25 Merge pull request #48377 from mihir-kandoi/fix-job-card-buttons-d
fix: job card material request/transfer buttons UI overlap
2025-07-04 11:22:46 +05:30
Mihir Kandoi
b1abcd5577 fix: unnecessary primary button 2025-07-04 08:29:29 +05:30
Mihir Kandoi
09f866022b fix: job card material request/transfer buttons UI overlap 2025-07-03 14:05:07 +05:30
Frappe PR Bot
f087da927a chore(release): Bumped to Version 15.67.0
# [15.67.0](https://github.com/frappe/erpnext/compare/v15.66.1...v15.67.0) (2025-07-01)

### Bug Fixes

* accounting entries for standalone credit notes ([cfc8c61](cfc8c610fa))
* better integration of Pick List with Delivery Note (backport [#47831](https://github.com/frappe/erpnext/issues/47831)) ([#48158](https://github.com/frappe/erpnext/issues/48158)) ([8f47505](8f47505604))
* customer section on pos item cart (backport [#48284](https://github.com/frappe/erpnext/issues/48284)) ([#48285](https://github.com/frappe/erpnext/issues/48285)) ([b6e0953](b6e09531d7))
* customer_group import from lead to customer ([#48266](https://github.com/frappe/erpnext/issues/48266)) ([5463a8b](5463a8b6cf))
* default UOMs by new stock Entry created by Stock Level section button ([f1062c6](f1062c61f6))
* disassemble qty calculation & max calculation to be allowed to create it ([bf78f61](bf78f6173c))
* failing test case ([bde63ed](bde63ed0e5))
* func parameters ([c69bb74](c69bb746ce))
* not able to save material request ([0e2bca4](0e2bca4b34))
* option to pick serial / batch for asset repair ([7de15b7](7de15b74d4))
* **pos invoice:** search using customer name (backport [#48279](https://github.com/frappe/erpnext/issues/48279)) ([#48323](https://github.com/frappe/erpnext/issues/48323)) ([ab20b96](ab20b965ca))
* saperated validations for each purpose of validation ([0c07dfa](0c07dfadfe))
* update salvage value after value adjustment (backport [#48228](https://github.com/frappe/erpnext/issues/48228)) ([#48248](https://github.com/frappe/erpnext/issues/48248)) ([ef202d7](ef202d7cd0))
* use company default currency in amount_eligible_for_commission ([9b8fffd](9b8fffd1d4))
* use gain_loss_posting_date instead of today ([ff36284](ff362843cb))
* use label "State/Province" for translatability (backport [#48273](https://github.com/frappe/erpnext/issues/48273)) ([#48286](https://github.com/frappe/erpnext/issues/48286)) ([af55ce0](af55ce0f6c))
* validate asset before repair ([a1eab1d](a1eab1db74))

### Features

* added Transfer and Issue option in purpose ([1f7eccd](1f7eccdac5))

### Performance Improvements

* use set_value for updating bank clearance_date ([a0db227](a0db227a7a))
2025-07-01 12:02:06 +00:00
ruthra kumar
171d86a3ab Merge pull request #48338 from frappe/version-15-hotfix
chore: release v15
2025-07-01 17:30:39 +05:30
ruthra kumar
58c6031c1f Merge pull request #48339 from frappe/mergify/bp/version-15-hotfix/pr-48244
fix: use gain_loss_posting_date instead of today (backport #48244)
2025-07-01 16:20:01 +05:30
ravibharathi656
ff362843cb fix: use gain_loss_posting_date instead of today
(cherry picked from commit 0585bc5aef)
2025-07-01 10:12:35 +00:00
rohitwaghchaure
86b14dd4be Merge pull request #48319 from frappe/mergify/bp/version-15-hotfix/pr-48298
fix: default UOMs by new Stock Entry created by Stock Level section button (when Item is batch or serial) (backport #48298)
2025-07-01 13:24:29 +05:30
ruthra kumar
037ef10fcb Merge pull request #48292 from ljain112/fix-bank-cleareance-v15
perf: use set_value for updating bank clearance_date
2025-07-01 11:58:13 +05:30
mergify[bot]
ab20b965ca fix(pos invoice): search using customer name (backport #48279) (#48323)
* fix(pos invoice): search using customer name

(cherry picked from commit 20fd071c4e)

# Conflicts:
#	erpnext/selling/page/point_of_sale/point_of_sale.py

* refactor: use or_filters for customer and customer_name

(cherry picked from commit 6a401bcfbb)

# Conflicts:
#	erpnext/selling/page/point_of_sale/point_of_sale.py

* refactor: refactored for version 15

---------

Co-authored-by: ravibharathi656 <ravibharathi656@gmail.com>
Co-authored-by: diptanilsaha <diptanil@frappe.io>
2025-06-30 14:51:47 +05:30
rohitwaghchaure
e1a726bdd4 Merge pull request #48294 from frappe/mergify/bp/version-15-hotfix/pr-48293
fix: option to pick serial / batch for asset repair (backport #48293)
2025-06-30 13:27:29 +05:30
rohitwaghchaure
221e5a2190 Merge pull request #48320 from frappe/mergify/bp/version-15-hotfix/pr-48184
fix: Disassembly order items calculation in stock entry & track it in work order (backport #48184)
2025-06-30 13:16:30 +05:30
rohitwaghchaure
f0724f2f04 Merge pull request #48317 from frappe/mergify/bp/version-15-hotfix/pr-48240
refactor: bom stock report (backport #48240)
2025-06-30 13:15:37 +05:30
rohitwaghchaure
c404faaa6d chore: fix issue 2025-06-30 12:46:52 +05:30
rohitwaghchaure
abfe3c8365 chore: fix conflicts 2025-06-30 12:45:04 +05:30
iamkhanraheel
61f4547860 test: added test case for disassembly order
(cherry picked from commit aee26c3550)
2025-06-30 06:57:52 +00:00
iamkhanraheel
c69bb746ce fix: func parameters
(cherry picked from commit ce6ace4b8a)
2025-06-30 06:57:51 +00:00
iamkhanraheel
bf78f6173c fix: disassemble qty calculation & max calculation to be allowed to create it
(cherry picked from commit 3e4d160626)

# Conflicts:
#	erpnext/manufacturing/doctype/work_order/work_order.json
#	erpnext/stock/doctype/stock_entry/stock_entry.py
2025-06-30 06:57:51 +00:00
ruthra kumar
e628a37b99 Merge pull request #48318 from frappe/mergify/bp/version-15-hotfix/pr-48304
chore: fix translation message (backport #48304)
2025-06-30 12:22:58 +05:30
Florian HENRY
f1062c61f6 fix: default UOMs by new stock Entry created by Stock Level section button
(cherry picked from commit e7da4992f3)
2025-06-30 05:40:15 +00:00
Abdallah A. Zaqout
f479675ce6 chore: fix translation message
(cherry picked from commit bc002937ad)
2025-06-30 05:34:05 +00:00
Mihir Kandoi
ce7dbf3090 refactor: bom stock report
(cherry picked from commit ee4e0c646d)
2025-06-30 05:32:04 +00:00
rohitwaghchaure
ac587b9c94 chore: fix conflicts 2025-06-30 10:55:56 +05:30
ruthra kumar
1ea3daeb17 Merge pull request #48267 from frappe/mergify/bp/version-15-hotfix/pr-48266
fix: customer_group import from lead to customer (backport #48266)
2025-06-30 10:48:20 +05:30
ruthra kumar
b2f6fed42c Merge pull request #48315 from frappe/mergify/bp/version-15-hotfix/pr-48271
fix: use company default currency in amount_eligible_for_commission (backport #48271)
2025-06-30 10:34:49 +05:30
rohitwaghchaure
352642096e chore: fix conflicts 2025-06-30 10:12:54 +05:30
rohitwaghchaure
ab61b46a01 chore: fix conflicts 2025-06-30 10:09:59 +05:30
ravibharathi656
9b8fffd1d4 fix: use company default currency in amount_eligible_for_commission
(cherry picked from commit 7c7b392789)
2025-06-30 04:39:08 +00:00
rohitwaghchaure
46243fdb5f Merge pull request #48314 from frappe/mergify/bp/version-15-hotfix/pr-48310
fix: accounting entries for standalone credit notes (backport #48310)
2025-06-30 10:07:36 +05:30
Rohit Waghchaure
cfc8c610fa fix: accounting entries for standalone credit notes
(cherry picked from commit 52177cffcd)
2025-06-30 04:09:56 +00:00
Khushi Rawat
d73ff810d9 Merge pull request #48312 from frappe/mergify/bp/version-15-hotfix/pr-48311
fix: validate asset status for repair (backport #48311)
2025-06-30 01:31:45 +05:30
Khushi Rawat
2b37287b19 chore: resolved conflicts 2025-06-30 01:04:54 +05:30
Khushi Rawat
f31b008502 chore: resolved conflicts 2025-06-30 01:03:49 +05:30
khushi8112
6f24c02121 test: asset status validation
(cherry picked from commit cfe04a2aaf)

# Conflicts:
#	erpnext/assets/doctype/asset_repair/test_asset_repair.py
2025-06-29 19:26:03 +00:00
khushi8112
a1eab1db74 fix: validate asset before repair
(cherry picked from commit c6baa34812)

# Conflicts:
#	erpnext/assets/doctype/asset_repair/asset_repair.json
2025-06-29 19:26:03 +00:00
Frappe PR Bot
fcf9f82092 chore(release): Bumped to Version 15.66.1
## [15.66.1](https://github.com/frappe/erpnext/compare/v15.66.0...v15.66.1) (2025-06-27)

### Bug Fixes

* not able to save material request ([a49026e](a49026e9d2))
2025-06-27 12:28:50 +00:00
rohitwaghchaure
e817561dce Merge pull request #48300 from frappe/mergify/bp/version-15/pr-48297
fix: not able to save material request (backport #48296) (backport #48297)
2025-06-27 17:57:24 +05:30
Rohit Waghchaure
a49026e9d2 fix: not able to save material request
(cherry picked from commit c5e36eb323)
(cherry picked from commit 0e2bca4b34)
2025-06-27 11:18:10 +00:00
rohitwaghchaure
7574069af2 Merge pull request #48297 from frappe/mergify/bp/version-15-hotfix/pr-48296
fix: not able to save material request (backport #48296)
2025-06-27 16:47:17 +05:30
Rohit Waghchaure
0e2bca4b34 fix: not able to save material request
(cherry picked from commit c5e36eb323)
2025-06-27 10:55:48 +00:00
Rohit Waghchaure
7de15b74d4 fix: option to pick serial / batch for asset repair
(cherry picked from commit ae77c609ff)

# Conflicts:
#	erpnext/assets/doctype/asset_repair/asset_repair.py
#	erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json
2025-06-27 09:59:22 +00:00
ljain112
a0db227a7a perf: use set_value for updating bank clearance_date 2025-06-27 14:12:14 +05:30
mergify[bot]
af55ce0f6c fix: use label "State/Province" for translatability (backport #48273) (#48286)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix: use label "State/Province" for translatability (#48273)
2025-06-26 20:49:06 +02:00
0xD0M1M0
894bb703f6 chore: improve some german translations (#48283) 2025-06-26 20:23:35 +02:00
mergify[bot]
b6e09531d7 fix: customer section on pos item cart (backport #48284) (#48285)
* fix: customer section on pos item cart (#48284)

* fix: customer recent transactions

* fix: pos customer section display customer_name instead of customer name

(cherry picked from commit e1d9f863c6)

# Conflicts:
#	erpnext/public/scss/point-of-sale.scss
#	erpnext/selling/page/point_of_sale/point_of_sale.py
#	erpnext/selling/page/point_of_sale/pos_item_cart.js

* chore: resolve conflict

* chore: resolve conflict

* chore: resolve conflict

---------

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-06-26 23:20:38 +05:30
mergify[bot]
8f47505604 fix: better integration of Pick List with Delivery Note (backport #47831) (#48158)
* fix: better integration of Pick List with Delivery Note (#47831)

Co-authored-by: priyanshshah2442 <priyanshshah2442@gmail.com>
(cherry picked from commit 527cfe9c7d)

# Conflicts:
#	erpnext/patches.txt
#	erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
#	erpnext/stock/doctype/pick_list/pick_list.py
#	erpnext/stock/doctype/pick_list_item/pick_list_item.json

* chore: resolve conflicts

* fix: setting status correctly as per v15 utility

* fix: get items from Pick List to DN even if not linked to Sales Order

---------

Co-authored-by: Smit Vora <smitvora203@gmail.com>
Co-authored-by: Priyansh Shah <108476017+priyanshshah2442@users.noreply.github.com>
2025-06-26 18:25:53 +05:30
0xD0M1M0
5463a8b6cf fix: customer_group import from lead to customer (#48266)
In case customization happens and the lead has the field "customer_group", the get_mapped_doc function would fail and be overwritten by the default value.

(cherry picked from commit 1b18105bce)
2025-06-25 21:26:40 +00:00
Khushi Rawat
b8a773e3e1 Merge pull request #48253 from frappe/mergify/bp/version-15-hotfix/pr-47901
feat: Asset Transfer and Issue in single asset movement record (backport #47901)
2025-06-25 15:23:54 +05:30
khushi8112
dc642fbc41 chore: linters check 2025-06-25 15:04:17 +05:30
Khushi Rawat
ddbdcbb026 chore: resolved conflicts 2025-06-25 14:47:47 +05:30
Khushi Rawat
df938f24d4 chore: resolved conflicts 2025-06-25 14:47:00 +05:30
Khushi Rawat
bde63ed0e5 fix: failing test case
(cherry picked from commit 7d3bec8ef8)
2025-06-25 09:08:24 +00:00
Khushi Rawat
1c3ac9c1fd refactor: split set_latest_location_and_custodian_in_asset into smaller functions
(cherry picked from commit 7e52cb2856)
2025-06-25 09:08:24 +00:00
Khushi Rawat
0c07dfadfe fix: saperated validations for each purpose of validation
(cherry picked from commit 07d1a0ed9c)

# Conflicts:
#	erpnext/assets/doctype/asset_movement/asset_movement.py
2025-06-25 09:08:24 +00:00
Khushi Rawat
1f7eccdac5 feat: added Transfer and Issue option in purpose
(cherry picked from commit f5e5146021)

# Conflicts:
#	erpnext/assets/doctype/asset_movement/asset_movement.json
2025-06-25 09:08:23 +00:00
Khushi Rawat
ef202d7cd0 fix: update salvage value after value adjustment (backport #48228) (#48248)
fix: update salvage value after value adjustment
2025-06-25 11:43:18 +05:30
Frappe PR Bot
de03618b09 chore(release): Bumped to Version 15.66.0
# [15.66.0](https://github.com/frappe/erpnext/compare/v15.65.4...v15.66.0) (2025-06-25)

### Bug Fixes

* add descendants item groups to fetch the barcode items ([5cabdbf](5cabdbfe06))
* add is_group filter for warehouse ([ad0819f](ad0819feee))
* add party and party_name columns to trend reports ([ceab26d](ceab26d5f1))
* add validation for exchange gain/loss entries ([153ed04](153ed04161))
* **asset-invoice:** handle asset invoice cancellation ([d3daeaf](d3daeaf475))
* auto append_taxes_from_item_tax_template in backend ([2bf8dff](2bf8dffb60))
* coa reset root_type on unchecking is_group on new_node (backport [#48156](https://github.com/frappe/erpnext/issues/48156)) ([#48160](https://github.com/frappe/erpnext/issues/48160)) ([7c2bf02](7c2bf026ef))
* contract autoname ([1223f55](1223f5551f))
* fallback expense account and cost center in subcontracting receipt ([ac22c42](ac22c422c8))
* get already billed amount from current doc instead of database ([#48079](https://github.com/frappe/erpnext/issues/48079)) ([c2c5e45](c2c5e45bc6))
* incoming rate for the stand-alone credit note ([ad40bfe](ad40bfe4ea))
* modify query to fetch valid return qty ([764c71d](764c71d3e1))
* naming series field in bank transaction (backport [#48121](https://github.com/frappe/erpnext/issues/48121)) ([#48149](https://github.com/frappe/erpnext/issues/48149)) ([f0ddf1b](f0ddf1b223))
* **open_opportunity:** remove company=null filter (backport [#48222](https://github.com/frappe/erpnext/issues/48222)) ([#48224](https://github.com/frappe/erpnext/issues/48224)) ([2d7a7d9](2d7a7d9988))
* permission issue during reposting ([6896216](6896216276))
* pos item details fetch uoms on stock settings allow_uom_with_conversion_rate_defined_in_item configuration (backport [#48178](https://github.com/frappe/erpnext/issues/48178)) ([#48179](https://github.com/frappe/erpnext/issues/48179)) ([991ddfe](991ddfe187))
* pos item price in get_item and item search (backport [#47925](https://github.com/frappe/erpnext/issues/47925)) ([#48217](https://github.com/frappe/erpnext/issues/48217)) ([f8cfbda](f8cfbda4e0))
* resolved conflicts ([881dcf8](881dcf817f))
* SABB validation during the LCV ([b3d337a](b3d337a45b))
* setup wizard load chart of accounts and fiscal year on change of country (backport [#48125](https://github.com/frappe/erpnext/issues/48125)) ([#48128](https://github.com/frappe/erpnext/issues/48128)) ([f85b08d](f85b08d2f5))
* stock adjustment entry to make stock balance zero (backport [#48245](https://github.com/frappe/erpnext/issues/48245)) ([#48247](https://github.com/frappe/erpnext/issues/48247)) ([41d22d0](41d22d0255))
* stock reconciliation validation for serial and batch ([89376dd](89376ddf8d))
* target inventory dimension for stock entry ([4e70005](4e70005937))
* Update indexing to populate correct values in trends report chart ([24f892d](24f892d582))
* update journal entry title on amend ([4341ac7](4341ac7e7a))
* Update transaction currency to company currency to show correct currency symbol ([651b952](651b9521b9))
* use currency from opportunity while creating quotation ([#45540](https://github.com/frappe/erpnext/issues/45540)) ([a6c5738](a6c5738f4b))
* use set_query on sales_order link field in work order ([b33bec4](b33bec4dad))

### Features

* add naming series for Contract Doctype ([b3c43e8](b3c43e8527))
* add search field for contract doctype ([27b5d94](27b5d9493a))
2025-06-25 04:48:04 +00:00
ruthra kumar
ecd30c5809 Merge pull request #48229 from frappe/version-15-hotfix
chore: release v15
2025-06-25 10:16:37 +05:30
mergify[bot]
41d22d0255 fix: stock adjustment entry to make stock balance zero (backport #48245) (#48247)
fix: stock adjustment entry to make stock balance zero (#48245)

(cherry picked from commit 66eeda6410)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-06-24 22:16:24 +05:30
ruthra kumar
a913cfea7e Merge pull request #48239 from frappe/mergify/bp/version-15-hotfix/pr-45540
fix: use currency from opportunity while creating quotation (backport #45540)
2025-06-24 19:35:10 +05:30
Sugesh G
a6c5738f4b fix: use currency from opportunity while creating quotation (#45540)
(cherry picked from commit d748b491ee)
2025-06-24 12:10:24 +00:00
ruthra kumar
3a6956ba05 Merge pull request #48230 from frappe/mergify/bp/version-15-hotfix/pr-47627
fix: auto append_taxes_from_item_tax_template in backend (backport #47627)
2025-06-24 17:38:14 +05:30
ruthra kumar
1deadb8daa Merge pull request #48236 from frappe/mergify/bp/version-15-hotfix/pr-48226
Trends reports (backport #48226)
2025-06-24 17:36:44 +05:30
ruthra kumar
463ad0a163 Merge pull request #48235 from frappe/mergify/bp/version-15-hotfix/pr-48079
fix: get already billed amount from current doc instead of database (backport #48079)
2025-06-24 17:35:37 +05:30
ljain112
f6bb86574e chore: fix test case for auto tax appending 2025-06-24 16:45:41 +05:30
Khushi Rawat
889a14b557 Merge pull request #48120 from aerele/fix/asset-invoice-cancel-validation
fix(asset-invoice): handle asset invoice cancellation
2025-06-24 16:24:18 +05:30
ljain112
0b96e1e3ef chore: resolve conflicts 2025-06-24 15:52:24 +05:30
Karuppasamy923
24f892d582 fix: Update indexing to populate correct values in trends report chart
(cherry picked from commit b08d66113c)
2025-06-24 10:18:44 +00:00
Karuppasamy923
651b9521b9 fix: Update transaction currency to company currency to show correct currency symbol
(cherry picked from commit b0e201a332)
2025-06-24 10:18:44 +00:00
Lakshit Jain
c2c5e45bc6 fix: get already billed amount from current doc instead of database (#48079)
* fix: get already billed amount from current doc instead of database

* fix: throw overbilling validation for all items in single call

* refactor: minor fixes

---------

Co-authored-by: Sagar Vora <16315650+sagarvora@users.noreply.github.com>
(cherry picked from commit 47c3c4808e)
2025-06-24 10:11:43 +00:00
ljain112
1ccdb67c55 chore: resolve conflicts 2025-06-24 15:31:34 +05:30
ljain112
2bf8dffb60 fix: auto append_taxes_from_item_tax_template in backend
(cherry picked from commit 4cb1fa2b6b)

# Conflicts:
#	erpnext/controllers/accounts_controller.py
#	erpnext/controllers/tests/test_accounts_controller.py
2025-06-24 09:48:21 +00:00
mergify[bot]
6511eb4c7c refactor: track completed app setup wizards and re-run the setup wizard upon new app installation. (backport #47691) (#48223)
* refactor: track completed app setup wizards and re-run the setup wizard upon new app installation. (#47691)

(cherry picked from commit 75b5ba6e67)

# Conflicts:
#	erpnext/hooks.py
#	erpnext/setup/install.py

* chore: fix conflicts

* chore: fix conflicts

* chore: fix conflicts

* fix: permission issue

* fix: space

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-06-24 14:51:15 +05:30
Mihir Kandoi
5aed023434 Merge pull request #48225 from frappe/mergify/bp/version-15-hotfix/pr-48078
fix: fallback expense account and cost center in subcontracting receipt (backport #48078)
2025-06-24 12:14:28 +05:30
rohitwaghchaure
764c81a146 Merge pull request #48215 from frappe/mergify/bp/version-15-hotfix/pr-48195
fix: incoming rate for the stand-alone credit note (backport #48195)
2025-06-24 12:02:17 +05:30
mergify[bot]
2d7a7d9988 fix(open_opportunity): remove company=null filter (backport #48222) (#48224)
* fix(open_opportunity): remove company=null filter (#48222)

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
(cherry picked from commit c8c1c96298)

# Conflicts:
#	erpnext/crm/number_card/open_opportunity/open_opportunity.json

* chore: resolve conflicts

---------

Co-authored-by: Akhil Narang <me@akhilnarang.dev>
2025-06-24 11:56:08 +05:30
Mihir Kandoi
ac22c422c8 fix: fallback expense account and cost center in subcontracting receipt
(cherry picked from commit cf1d4362e5)
2025-06-24 06:20:50 +00:00
rohitwaghchaure
f560286610 chore: fix conflicts 2025-06-24 11:34:04 +05:30
ruthra kumar
19a6ce3605 Merge pull request #48220 from frappe/mergify/bp/version-15-hotfix/pr-48180
fix: update journal entry title on amend (backport #48180)
2025-06-24 10:11:28 +05:30
ravibharathi656
4341ac7e7a fix: update journal entry title on amend
(cherry picked from commit 4a3ee4df29)
2025-06-24 04:04:04 +00:00
ruthra kumar
866780b383 Merge pull request #48212 from frappe/mergify/bp/version-15-hotfix/pr-48162
fix: add validation for exchange gain/loss entries (backport #48162)
2025-06-24 09:19:14 +05:30
ruthra kumar
ca2f4e801e Merge pull request #48213 from frappe/mergify/bp/version-15-hotfix/pr-48053
fix: add descendants item groups to fetch the barcode items (backport #48053)
2025-06-24 09:18:19 +05:30
mergify[bot]
f8cfbda4e0 fix: pos item price in get_item and item search (backport #47925) (#48217)
fix: pos item price in get_item and item search (#47925)

* fix: pos get item and item search

* refactor: resolved linter issue and renamed variables

* fix: uom on get_item

* fix: incorrect item quantity on pos selector

* refactor: remove unused import

(cherry picked from commit 919684a787)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-06-23 22:42:47 +05:30
Rohit Waghchaure
ad40bfe4ea fix: incoming rate for the stand-alone credit note
(cherry picked from commit b06eca8dcb)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
2025-06-23 15:40:49 +00:00
pugazhendhivelu
5cabdbfe06 fix: add descendants item groups to fetch the barcode items
(cherry picked from commit 4b82fe2611)
2025-06-23 14:01:23 +00:00
i-am-vimal
153ed04161 fix: add validation for exchange gain/loss entries
(cherry picked from commit 5c9eddd31e)
2025-06-23 14:00:09 +00:00
ruthra kumar
78013d3d8f Merge pull request #48209 from frappe/mergify/bp/version-15-hotfix/pr-48200
chore: better label and desciption for pegged currency flag (backport #48200)
2025-06-23 19:29:40 +05:30
ruthra kumar
b6dda08290 chore: better label and desciption for pegged currency flag
(cherry picked from commit c5cd7d91c4)
2025-06-23 12:14:42 +00:00
ruthra kumar
1ea876bc7a Merge pull request #48199 from frappe/mergify/bp/version-15-hotfix/pr-48096
fix: add party and party_name columns to trend reports (backport #48096)
2025-06-23 15:58:34 +05:30
ruthra kumar
b92662a095 Merge pull request #48197 from frappe/mergify/bp/version-15-hotfix/pr-48186
fix: add is_group filter for warehouse (backport #48186)
2025-06-23 15:44:29 +05:30
Karuppasamy923
ceab26d5f1 fix: add party and party_name columns to trend reports
(cherry picked from commit d05204a960)
2025-06-23 10:12:18 +00:00
Karuppasamy923
ad0819feee fix: add is_group filter for warehouse
(cherry picked from commit a29ae9cf90)
2025-06-23 10:07:10 +00:00
rohitwaghchaure
c5bf889391 Merge pull request #48182 from frappe/mergify/bp/version-15-hotfix/pr-48181
fix: SABB validation during the LCV (backport #48181)
2025-06-22 12:17:04 +05:30
Khushi Rawat
7303ee4bea Merge pull request #48175 from frappe/mergify/bp/version-15-hotfix/pr-48151
fix: duplicate naming issue in contract doctype (backport #48151)
2025-06-22 00:47:47 +05:30
Rohit Waghchaure
b3d337a45b fix: SABB validation during the LCV
(cherry picked from commit e958f886d3)
2025-06-20 15:55:02 +00:00
mergify[bot]
991ddfe187 fix: pos item details fetch uoms on stock settings allow_uom_with_conversion_rate_defined_in_item configuration (backport #48178) (#48179)
fix: pos item details fetch uoms on stock settings allow_uom_with_conversion_rate_defined_in_item configuration (#48178)

(cherry picked from commit 4aa4942a17)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-06-20 16:23:42 +05:30
Khushi Rawat
881dcf817f fix: resolved conflicts 2025-06-20 14:23:02 +05:30
khushi8112
c07d5b6dec chore: remove unused import
(cherry picked from commit a1c0727d7b)
2025-06-20 07:29:35 +00:00
khushi8112
4c2f555379 refactor: remove test case
(cherry picked from commit 4a027125bc)
2025-06-20 07:29:35 +00:00
khushi8112
27b5d9493a feat: add search field for contract doctype
(cherry picked from commit 0665691b88)
2025-06-20 07:29:35 +00:00
khushi
b3c43e8527 feat: add naming series for Contract Doctype
(cherry picked from commit bf56c73c6c)

# Conflicts:
#	erpnext/crm/doctype/contract/contract.json
2025-06-20 07:29:35 +00:00
khushi
1005ee64cd refactor: remove autoname
(cherry picked from commit a4bb7c4e95)
2025-06-20 07:29:34 +00:00
khushi
8150638519 chore: linters check
(cherry picked from commit f7e63936a9)
2025-06-20 07:29:34 +00:00
khushi
194e15fe6e chore: test contract autoname
(cherry picked from commit b55d1e61c7)
2025-06-20 07:29:34 +00:00
khushi
1223f5551f fix: contract autoname
(cherry picked from commit e13e2bffe2)
2025-06-20 07:29:33 +00:00
mergify[bot]
f0ddf1b223 fix: naming series field in bank transaction (backport #48121) (#48149)
fix: naming series field in bank transaction (#48121)

* fix: naming series field in bank transaction

* fix: default naming_series

(cherry picked from commit c94764ab52)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-06-20 11:52:53 +05:30
Frappe PR Bot
bd128d3b3a chore(release): Bumped to Version 15.65.4
## [15.65.4](https://github.com/frappe/erpnext/compare/v15.65.3...v15.65.4) (2025-06-19)

### Bug Fixes

* target inventory dimension for stock entry ([0958a3b](0958a3b643))
2025-06-19 16:33:57 +00:00
rohitwaghchaure
42460980b2 Merge pull request #48167 from frappe/mergify/bp/version-15/pr-48166
fix: target inventory dimension for stock entry (backport #48165) (backport #48166)
2025-06-19 22:02:27 +05:30
Rohit Waghchaure
0958a3b643 fix: target inventory dimension for stock entry
(cherry picked from commit d65cb56d66)
(cherry picked from commit 4e70005937)
2025-06-19 15:13:19 +00:00
rohitwaghchaure
f5adfe3f0f Merge pull request #48166 from frappe/mergify/bp/version-15-hotfix/pr-48165
fix: target inventory dimension for stock entry (backport #48165)
2025-06-19 20:41:35 +05:30
Rohit Waghchaure
4e70005937 fix: target inventory dimension for stock entry
(cherry picked from commit d65cb56d66)
2025-06-19 14:24:39 +00:00
rohitwaghchaure
4eff2b58e6 Merge pull request #48159 from frappe/mergify/bp/version-15-hotfix/pr-48131
fix: permission issue during reposting (backport #48131)
2025-06-19 18:08:10 +05:30
mergify[bot]
7c2bf026ef fix: coa reset root_type on unchecking is_group on new_node (backport #48156) (#48160)
fix: coa reset root_type on unchecking is_group on new_node (#48156)

(cherry picked from commit 2f8893439f)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-06-19 17:54:08 +05:30
Rohit Waghchaure
6896216276 fix: permission issue during reposting
(cherry picked from commit dcc9fc2fec)
2025-06-19 12:14:44 +00:00
mergify[bot]
bf61014fe5 test: purchase invoice provisional accounting entry (backport #48112) (#48134)
test: purchase invoice provisional accounting entry (#48112)

* test: fixed purchase invoice provisional accounting entry

* test: added tests for multi currency

(cherry picked from commit 80f992c87f)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-06-19 13:01:51 +05:30
Frappe PR Bot
e0ca060475 chore(release): Bumped to Version 15.65.3
## [15.65.3](https://github.com/frappe/erpnext/compare/v15.65.2...v15.65.3) (2025-06-19)

### Bug Fixes

* stock reconciliation validation for serial and batch ([3057f6c](3057f6ce35))
* use set_query on sales_order link field in work order ([6a6130e](6a6130e06c))
2025-06-19 05:30:19 +00:00
rohitwaghchaure
84d348b3d4 Merge pull request #48145 from frappe/mergify/bp/version-15/pr-48107
fix: use set_query on sales_order link field in work order (backport #48077) (backport #48107)
2025-06-19 10:58:59 +05:30
rohitwaghchaure
a63457e5b0 Merge pull request #48144 from frappe/mergify/bp/version-15/pr-48113
fix: stock reconciliation validation for serial nos (backport #47988) (backport #48113)
2025-06-19 10:58:43 +05:30
Mihir Kandoi
6a6130e06c fix: use set_query on sales_order link field in work order
(cherry picked from commit 6def182e1a)
(cherry picked from commit b33bec4dad)
2025-06-19 04:37:39 +00:00
Rohit Waghchaure
3057f6ce35 fix: stock reconciliation validation for serial and batch
(cherry picked from commit 69d54d2e0f)
(cherry picked from commit 89376ddf8d)
2025-06-19 04:36:35 +00:00
rohitwaghchaure
7fbefef72a Merge pull request #48135 from aerele/handle-return-qty
fix: modify query to fetch valid return qty
2025-06-18 20:24:46 +05:30
Bhavan23
ea3015a450 test(sales-invoice): add test case for asset invoice cancellation 2025-06-18 19:21:14 +05:30
ravibharathi656
9146bd95a4 test: update import for change_settings 2025-06-18 18:41:01 +05:30
ravibharathi656
4576fcd96f test: add test for validating sales invoice qty after return 2025-06-18 18:16:06 +05:30
ravibharathi656
764c71d3e1 fix: modify query to fetch valid return qty 2025-06-18 18:16:06 +05:30
mergify[bot]
f85b08d2f5 fix: setup wizard load chart of accounts and fiscal year on change of country (backport #48125) (#48128)
fix: setup wizard load chart of accounts and fiscal year on change of country (#48125)

(cherry picked from commit 14f0569a39)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-06-18 17:26:55 +05:30
Mihir Kandoi
f0ae90011b Merge pull request #48107 from frappe/mergify/bp/version-15-hotfix/pr-48077 2025-06-18 11:08:43 +05:30
Bhavan23
d3daeaf475 fix(asset-invoice): handle asset invoice cancellation 2025-06-18 10:54:24 +05:30
rohitwaghchaure
79a9d583d9 Merge pull request #48113 from frappe/mergify/bp/version-15-hotfix/pr-47988
fix: stock reconciliation validation for serial nos (backport #47988)
2025-06-17 23:18:24 +05:30
Rohit Waghchaure
89376ddf8d fix: stock reconciliation validation for serial and batch
(cherry picked from commit 69d54d2e0f)
2025-06-17 17:31:05 +00:00
Frappe PR Bot
d2ac603fd7 chore(release): Bumped to Version 15.65.2
## [15.65.2](https://github.com/frappe/erpnext/compare/v15.65.1...v15.65.2) (2025-06-17)

### Bug Fixes

* add validation for calculate ageing with filter for summary and other reports ([23db22a](23db22ac0b))
* add validation for exchange gain/loss entries ([97f1304](97f13049ee))
* add validation for party type ([baa08ce](baa08ce496))
* batch page length ([994454b](994454bfc3))
* budget naming series (backport [#48075](https://github.com/frappe/erpnext/issues/48075)) ([#48080](https://github.com/frappe/erpnext/issues/48080)) ([4d18fd0](4d18fd0e80))
* do not allow capitalization from connection tab for submitted asset ([7b5e2a6](7b5e2a6af0))
* do not reset party account for return doc ([ad5421a](ad5421a413))
* float division by zero ([40504b8](40504b8da2))
* incorrect condition for setting party account on change of company ([f2b9e73](f2b9e73819))
* incorrect warehouse set from SO to MR ([e9365d7](e9365d7272))
* pos invoice consolidation row refer issue (backport [#48057](https://github.com/frappe/erpnext/issues/48057)) ([#48058](https://github.com/frappe/erpnext/issues/48058)) ([db9f0b6](db9f0b6f38))
* prevent saving negative quantity in BOM ([1c9032a](1c9032a4c2))
* unpack non-iterable NoneType object error ([dd39d24](dd39d24da0))
* update asset status after making asset value adjustment record ([ee30357](ee30357835))
2025-06-17 14:51:34 +00:00
ruthra kumar
3340b19c5d Merge pull request #48100 from frappe/version-15-hotfix
chore: release v15
2025-06-17 20:20:01 +05:30
Mihir Kandoi
b33bec4dad fix: use set_query on sales_order link field in work order
(cherry picked from commit 6def182e1a)
2025-06-17 12:09:08 +00:00
Sagar Vora
4d1022182d Merge pull request #48105 from frappe/mergify/bp/version-15-hotfix/pr-48104
fix: incorrect condition for setting party account on change of company (backport #48104)
2025-06-17 11:26:35 +00:00
ljain112
f2b9e73819 fix: incorrect condition for setting party account on change of company
(cherry picked from commit 20565f5f19)
2025-06-17 11:26:13 +00:00
ruthra kumar
31cb78e3f3 Merge pull request #48101 from frappe/mergify/bp/version-15-hotfix/pr-47898
Pegged currency (backport #47898)
2025-06-17 16:00:54 +05:30
ruthra kumar
789cd20d2d Merge pull request #48102 from frappe/mergify/bp/version-15-hotfix/pr-48098
fix: do not reset party account for return doc (backport #48098)
2025-06-17 15:42:32 +05:30
Karuppasamy
cb58d05777 Merge pull request #47898 from aerele/pegged-currency
Pegged currency

(cherry picked from commit cec0ffad06)

# Conflicts:
#	erpnext/accounts/doctype/accounts_settings/accounts_settings.json
#	erpnext/patches.txt
#	erpnext/setup/install.py
2025-06-17 15:32:36 +05:30
ljain112
ad5421a413 fix: do not reset party account for return doc
(cherry picked from commit 7e758a9d5b)
2025-06-17 09:59:44 +00:00
ruthra kumar
84f9a1fb2d Merge pull request #48094 from frappe/mergify/bp/version-15-hotfix/pr-48082
fix:add validation for party type (backport #48082)
2025-06-17 15:14:34 +05:30
ruthra kumar
7d88b8bbb9 Merge pull request #48093 from frappe/mergify/bp/version-15-hotfix/pr-47879
fix: add validation for exchange gain/loss entries (backport #47879)
2025-06-17 13:59:08 +05:30
AlcinSnowlina
baa08ce496 fix: add validation for party type
(cherry picked from commit 7c9d6aaae2)
2025-06-17 08:26:07 +00:00
ruthra kumar
7031a5033c Merge pull request #48092 from frappe/mergify/bp/version-15-hotfix/pr-48076
fix: Prevent saving negative quantity in BOM (backport #48076)
2025-06-17 13:47:20 +05:30
l0gesh29
1f1e88d52e test: add test for debit/credit calculations in exchange gain/loss account filter in GL
(cherry picked from commit 6ea32a8762)

# Conflicts:
#	erpnext/accounts/report/general_ledger/test_general_ledger.py
2025-06-17 13:42:02 +05:30
l0gesh29
97f13049ee fix: add validation for exchange gain/loss entries
(cherry picked from commit d992f67658)
2025-06-17 08:04:57 +00:00
iamkhanraheel
1c9032a4c2 fix: prevent saving negative quantity in BOM
(cherry picked from commit e52d83e756)
2025-06-17 07:50:27 +00:00
Khushi Rawat
323a91ddd7 Merge pull request #48090 from khushi8112/update-asset-status-after-revaluation-v15-backport
fix: update asset status after making asset value adjustment record
2025-06-17 13:06:50 +05:30
Khushi Rawat
ee30357835 fix: update asset status after making asset value adjustment record 2025-06-17 12:35:44 +05:30
mergify[bot]
4d18fd0e80 fix: budget naming series (backport #48075) (#48080)
* fix: budget naming series (#48075)

(cherry picked from commit c4bdf2a721)

# Conflicts:
#	erpnext/accounts/doctype/budget/budget.json

* chore: resolve conflict

---------

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-06-17 11:21:54 +05:30
rohitwaghchaure
d054486495 Merge pull request #48065 from frappe/mergify/bp/version-15-hotfix/pr-48061
fix: incorrect warehouse set from SO to MR (backport #48061)
2025-06-16 14:52:44 +05:30
Rohit Waghchaure
e9365d7272 fix: incorrect warehouse set from SO to MR
(cherry picked from commit 0da8d9c869)
2025-06-16 04:42:27 +00:00
ruthra kumar
b3578ecf09 Merge pull request #48063 from frappe/mergify/bp/version-15-hotfix/pr-48036
fix: add validation for calculate ageing with filter for summary and … (backport #48036)
2025-06-16 09:52:37 +05:30
l0gesh29
23db22ac0b fix: add validation for calculate ageing with filter for summary and other reports
(cherry picked from commit c630aa9fe8)
2025-06-16 03:10:11 +00:00
rohitwaghchaure
85099a3a68 Merge pull request #48044 from frappe/mergify/bp/version-15-hotfix/pr-48037
fix: float division by zero (backport #48037)
2025-06-15 18:29:02 +05:30
mergify[bot]
db9f0b6f38 fix: pos invoice consolidation row refer issue (backport #48057) (#48058)
fix: pos invoice consolidation row refer issue (#48057)

(cherry picked from commit 4178d9e2a1)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-06-13 20:08:22 +05:30
mergify[bot]
56311e6e1e build(deps): bump rapidfuzz (backport #47503) (#48051)
build(deps): bump rapidfuzz (#47503)


(cherry picked from commit c275c55d6c)

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
Co-authored-by: Akhil Narang <me@akhilnarang.dev>
2025-06-13 16:01:08 +05:30
Rohit Waghchaure
40504b8da2 fix: float division by zero
(cherry picked from commit 59cbe85817)
2025-06-13 02:50:28 +00:00
rohitwaghchaure
379def5f0f Merge pull request #48022 from frappe/mergify/bp/version-15-hotfix/pr-48018
fix: batch page length (backport #48018)
2025-06-12 15:47:24 +05:30
Khushi Rawat
ab6a534df2 Merge pull request #48032 from frappe/mergify/bp/version-15-hotfix/pr-48031
fix: do not allow capitalization from connection tab for submitted asset (backport #48031)
2025-06-12 15:22:06 +05:30
Khushi Rawat
7b5e2a6af0 fix: do not allow capitalization from connection tab for submitted asset
(cherry picked from commit 27bec4cde5)
2025-06-12 09:48:10 +00:00
Rohit Waghchaure
994454bfc3 fix: batch page length
(cherry picked from commit 338256b799)
2025-06-11 14:33:13 +00:00
Frappe PR Bot
9febca2981 chore(release): Bumped to Version 15.65.1
## [15.65.1](https://github.com/frappe/erpnext/compare/v15.65.0...v15.65.1) (2025-06-11)

### Bug Fixes

* unpack non-iterable NoneType object error ([f92b5b9](f92b5b9a2e))
2025-06-11 12:51:34 +00:00
Sagar Vora
62efd09f2f Merge pull request #48021 from frappe/mergify/bp/version-15/pr-48019
fix: unpack non-iterable NoneType object error in patch (backport #48019)
2025-06-11 12:50:06 +00:00
Sagar Vora
b8f1c8f6b1 Merge pull request #48020 from frappe/mergify/bp/version-15-hotfix/pr-48019
fix: unpack non-iterable NoneType object error in patch (backport #48019)
2025-06-11 12:49:27 +00:00
priyanshshah2442
f92b5b9a2e fix: unpack non-iterable NoneType object error
(cherry picked from commit 7d940faa4f)
2025-06-11 12:49:17 +00:00
priyanshshah2442
dd39d24da0 fix: unpack non-iterable NoneType object error
(cherry picked from commit 7d940faa4f)
2025-06-11 12:49:05 +00:00
Frappe PR Bot
dc8bb792d7 chore(release): Bumped to Version 15.65.0
# [15.65.0](https://github.com/frappe/erpnext/compare/v15.64.1...v15.65.0) (2025-06-10)

### Bug Fixes

* add .length in list validation ([#47974](https://github.com/frappe/erpnext/issues/47974)) ([66f41d4](66f41d44c4))
* add change log for bug fix in Additional Discount functionality ([f27e591](f27e591d88))
* add draft transactions also in calculated mismatch report ([23b5d2d](23b5d2db2c))
* add user permission while fetching ple ([a2cdd91](a2cdd91a0d))
* **asset:** make purchase date mandatory ([a5e5553](a5e5553520))
* AttributeError due to incorrect object ([43d4e26](43d4e26ac5))
* available qty in BOM Stock Report ([84b2f87](84b2f871ba))
* better description of tab name ([#44697](https://github.com/frappe/erpnext/issues/44697)) ([d05b49b](d05b49b0f8))
* changes in report ([78c6386](78c63869e0))
* changes to report and patch ([5237ff8](5237ff8d94))
* conflicts ([aa29c5d](aa29c5dde2))
* consider expired batches in the stock reco (backport [#47909](https://github.com/frappe/erpnext/issues/47909)) ([#47919](https://github.com/frappe/erpnext/issues/47919)) ([2e78e14](2e78e14c7e))
* consider user permission while populating the data ([617b065](617b0658b8))
* do not create repeat work orders ([795108c](795108c1dd))
* do not remove item which has zero qty and zero valuation ([ef77791](ef77791bd6))
* ensure proper float conversion for discount values ([d24c2c4](d24c2c4cca))
* fetch correct item tax template on item rate update ([#47973](https://github.com/frappe/erpnext/issues/47973)) ([f88e682](f88e68230a))
* fieldtype to Currency for discount amounts ([59dd5fe](59dd5fee26))
* incorrect warehouse in MR ([8156d89](8156d89903))
* key-error for COGS By Item Group report (backport [#47914](https://github.com/frappe/erpnext/issues/47914)) ([#47915](https://github.com/frappe/erpnext/issues/47915)) ([996fb75](996fb7552a))
* patch to set discount percentange in case of mismatch ([039c47e](039c47e3f2))
* pos permission error on strict permission (backport [#47896](https://github.com/frappe/erpnext/issues/47896)) ([#47897](https://github.com/frappe/erpnext/issues/47897)) ([0314a39](0314a39fab))
* Project argument is passed correctly for MR creation ([e98ad4c](e98ad4ce27))
* remove currency col ([35035c2](35035c2a31))
* remove use sales invoice check ([#47908](https://github.com/frappe/erpnext/issues/47908)) ([1b15507](1b1550708d))
* **report:** include descendants when filtering by parent item group ([d21bfa2](d21bfa219d))
* **sales order:** error message on creation of work order from sales order ([129cd7a](129cd7ae8a))
* stock adjustment entry during reposting (backport [#47878](https://github.com/frappe/erpnext/issues/47878)) ([#47883](https://github.com/frappe/erpnext/issues/47883)) ([e5d06f8](e5d06f8c86))
* stock reco qty with inventory dimension (backport [#47918](https://github.com/frappe/erpnext/issues/47918)) ([#47922](https://github.com/frappe/erpnext/issues/47922)) ([6d2c14c](6d2c14c75e))
* test case to verify correct setting of discount amount and percentage ([06ea957](06ea957ae5))
* throw permission error ([#47976](https://github.com/frappe/erpnext/issues/47976)) ([9167d2e](9167d2ef64))
* typo ([8b4824f](8b4824fef5))
* update currency based on transaction ([eaeb18c](eaeb18c651))
* zero division error in purchase receipt ([b99f8fd](b99f8fd021))

### Features

* Add hook to update gl dict by apps ([76c2477](76c2477d23))
* add validation for inter company transactions ([9a47c50](9a47c507c0))
* populate Timer dialog project field from Timesheet parent_project (backport [#47971](https://github.com/frappe/erpnext/issues/47971)) ([#48001](https://github.com/frappe/erpnext/issues/48001)) ([66b0426](66b0426155))
* report to verify discount amount mismatch ([b3eb49d](b3eb49d39d))

### Performance Improvements

* Batch GLE/SLE rename commits (backport [#47950](https://github.com/frappe/erpnext/issues/47950)) ([#47951](https://github.com/frappe/erpnext/issues/47951)) ([f490de9](f490de9285))

### Reverts

* Revert "fix: calculate discount percentage if discount amount is specified (#…" ([5a5449c](5a5449c60c))
2025-06-10 14:33:55 +00:00
ruthra kumar
bd11146f02 Merge pull request #47996 from frappe/version-15-hotfix
chore: release v15
2025-06-10 20:02:19 +05:30
rohitwaghchaure
33f1d7a5fe Merge pull request #48004 from frappe/mergify/bp/version-15-hotfix/pr-47998
fix: incorrect warehouse in MR (backport #47998)
2025-06-10 18:41:17 +05:30
rohitwaghchaure
60de0474a1 chore: fix conflicts 2025-06-10 18:19:27 +05:30
Rohit Waghchaure
8156d89903 fix: incorrect warehouse in MR
(cherry picked from commit 2b9ca79291)

# Conflicts:
#	erpnext/manufacturing/doctype/production_plan/production_plan.py
2025-06-10 12:41:26 +00:00
mergify[bot]
66b0426155 feat: populate Timer dialog project field from Timesheet parent_project (backport #47971) (#48001)
feat: populate Timer dialog project field from Timesheet parent_project (#47971)

* feat: default parent project in timer dialog > project

* chore: fix formatting

* fix: remove unnecessary or condition

---------


(cherry picked from commit bc87609264)

Co-authored-by: Rahul Agrawal <12agrawalrahul@gmail.com>
Co-authored-by: Rahul Agrawal <deathstarconsole@Rahuls-MacBook-Air.local>
2025-06-10 18:07:28 +05:30
rohitwaghchaure
60b12b8319 Merge pull request #47992 from frappe/mergify/bp/version-15-hotfix/pr-47969
fix: do not create repeat work orders (backport #47969)
2025-06-10 16:40:54 +05:30
ruthra kumar
112d40db22 Merge pull request #47994 from frappe/mergify/bp/version-15-hotfix/pr-47981
refactor(Work Order): query_sales_order (backport #47981)
2025-06-10 15:01:09 +05:30
ruthra kumar
0d0b05bf6c Merge pull request #47991 from frappe/mergify/bp/version-15-hotfix/pr-47923
fix: update currency based on transaction (backport #47923)
2025-06-10 14:42:05 +05:30
rohitwaghchaure
c2d7e8c471 chore: fix conflicts 2025-06-10 14:38:18 +05:30
rohitwaghchaure
ccb0f7ac42 chore: fix conflicts 2025-06-10 14:36:31 +05:30
rohitwaghchaure
781b66e252 chore: fix conflicts 2025-06-10 14:35:23 +05:30
barredterra
efd3b1c966 refactor(Work Order): query_sales_order
- Use `get_list` instead of `db.sql_list`

    The method is used for setting link options in the frontend and the Link field doesn't ignore permissions, so get_list should be fine here.

- Added type hints to enable argument validation

(cherry picked from commit 2dbdacf905)
2025-06-10 09:03:18 +00:00
Rohit Waghchaure
795108c1dd fix: do not create repeat work orders
(cherry picked from commit 384f4e120a)

# Conflicts:
#	erpnext/manufacturing/doctype/production_plan/production_plan.js
#	erpnext/manufacturing/doctype/production_plan/test_production_plan.py
#	erpnext/manufacturing/doctype/production_plan_sub_assembly_item/production_plan_sub_assembly_item.json
2025-06-10 09:00:27 +00:00
rohitwaghchaure
7348778220 Merge pull request #47941 from frappe/mergify/bp/version-15-hotfix/pr-47888
fix: do not remove item which has zero qty and zero valuation (backport #47888)
2025-06-10 14:29:54 +05:30
DHINESH00
eaeb18c651 fix: update currency based on transaction
(cherry picked from commit fc4f38eed1)
2025-06-10 08:56:37 +00:00
rohitwaghchaure
78607b5812 Merge pull request #47987 from frappe/mergify/bp/version-15-hotfix/pr-47942
fix: available qty in BOM Stock Report (backport #47942)
2025-06-10 14:02:43 +05:30
Sagar Vora
823cfeaf4f Merge pull request #47978 from frappe/mergify/bp/version-15-hotfix/pr-47976
fix: throw permission error (backport #47976)
2025-06-10 07:37:10 +00:00
Sagar Vora
aa29c5dde2 fix: conflicts 2025-06-10 13:05:37 +05:30
ruthra kumar
713b17c3a5 Merge pull request #47990 from frappe/mergify/bp/version-15-hotfix/pr-47989
fix: Include draft transactions in the `Calculated Discount Mismatch` report (backport #47989)
2025-06-10 12:58:05 +05:30
priyanshshah2442
23b5d2db2c fix: add draft transactions also in calculated mismatch report
(cherry picked from commit 4e1abc1814)
2025-06-10 07:12:03 +00:00
Rohit Waghchaure
84b2f871ba fix: available qty in BOM Stock Report
(cherry picked from commit ea689bbe3f)
2025-06-10 06:50:51 +00:00
Sagar Vora
ac78bfb55b Merge pull request #47985 from frappe/mergify/bp/version-15-hotfix/pr-47946
fix: patch and report for incorrect discount values (backport #47946)
2025-06-10 06:10:23 +00:00
priyanshshah2442
59dd5fee26 fix: fieldtype to Currency for discount amounts
(cherry picked from commit f781a39dbe)
2025-06-10 06:04:09 +00:00
Sagar Vora
35035c2a31 fix: remove currency col
(cherry picked from commit 9bf9b34ac4)
2025-06-10 06:04:08 +00:00
Sagar Vora
78c63869e0 fix: changes in report
(cherry picked from commit 33e793354c)
2025-06-10 06:04:08 +00:00
priyanshshah2442
06ea957ae5 fix: test case to verify correct setting of discount amount and percentage
(cherry picked from commit 3f0c5be5d9)
2025-06-10 06:04:08 +00:00
priyanshshah2442
f27e591d88 fix: add change log for bug fix in Additional Discount functionality
(cherry picked from commit 9120927a65)
2025-06-10 06:04:08 +00:00
priyanshshah2442
d24c2c4cca fix: ensure proper float conversion for discount values
(cherry picked from commit 3dcb801a37)
2025-06-10 06:04:07 +00:00
Sagar Vora
5237ff8d94 fix: changes to report and patch
(cherry picked from commit daad6137f8)
2025-06-10 06:04:07 +00:00
priyanshshah2442
b3eb49d39d feat: report to verify discount amount mismatch
(cherry picked from commit 62dd6df24f)
2025-06-10 06:04:07 +00:00
priyanshshah2442
039c47e3f2 fix: patch to set discount percentange in case of mismatch
(cherry picked from commit f7eda8a156)
2025-06-10 06:04:06 +00:00
ruthra kumar
7ecb4d3d6f Merge pull request #47968 from aerele/validate-intercompany-rate
Add validation for inter company transactions rate
2025-06-10 11:12:26 +05:30
ruthra kumar
76a9e45ff8 Merge pull request #47982 from frappe/mergify/bp/version-15-hotfix/pr-47974
fix: add .length in list validation (backport #47974)
2025-06-10 10:25:21 +05:30
ruthra kumar
c69a0f150d Merge pull request #47934 from thomasantony12/so_bug_on_wo
fix(sales order): error message on creation of work order from sales order
2025-06-10 10:19:33 +05:30
l0gesh29
66f41d44c4 fix: add .length in list validation (#47974)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
(cherry picked from commit c8cec8cedf)
2025-06-09 23:16:36 +00:00
Khushi Rawat
7393a9f470 Merge pull request #47980 from frappe/mergify/bp/version-15-hotfix/pr-47979
fix: AttributeError due to incorrect object (backport #47979)
2025-06-10 00:31:45 +05:30
Khushi Rawat
43d4e26ac5 fix: AttributeError due to incorrect object
(cherry picked from commit 351796bce6)
2025-06-09 18:46:03 +00:00
Aayush Dalal
9167d2ef64 fix: throw permission error (#47976)
Co-authored-by: Sagar Vora <16315650+sagarvora@users.noreply.github.com>
(cherry picked from commit 8b6a8d0c4f)

# Conflicts:
#	erpnext/stock/utils.py
2025-06-09 17:29:58 +00:00
Diptanil Saha
f88e68230a fix: fetch correct item tax template on item rate update (#47973) 2025-06-09 19:23:33 +05:30
ravibharathi656
3aee14176c test: pass sales invoice name instead of doc 2025-06-09 19:12:51 +05:30
ravibharathi656
d6796da464 test: add unit test for inter company transaction rate validation 2025-06-09 19:12:51 +05:30
ravibharathi656
9a47c507c0 feat: add validation for inter company transactions 2025-06-09 19:12:51 +05:30
ruthra kumar
95d1d7047d Merge pull request #47967 from frappe/mergify/bp/version-15-hotfix/pr-47865
fix: consider user permission while populating the data (backport #47865)
2025-06-09 15:41:37 +05:30
l0gesh29
a2cdd91a0d fix: add user permission while fetching ple
(cherry picked from commit 1a4bb30923)
2025-06-09 09:53:13 +00:00
l0gesh29
617b0658b8 fix: consider user permission while populating the data
(cherry picked from commit 074dc6d7dd)
2025-06-09 09:53:13 +00:00
Khushi Rawat
d8e9ed417d Merge pull request #47943 from frappe/mergify/bp/version-15-hotfix/pr-47547
fix(asset): make purchase date mandatory (backport #47547)
2025-06-09 14:48:57 +05:30
ruthra kumar
eb7eadc16f Merge pull request #47590 from FathihMohammed/show_descedants
fix(report): include descendants when filtering by parent item group
2025-06-09 13:31:41 +05:30
FATHIH MOHAMMED
d21bfa219d fix(report): include descendants when filtering by parent item group 2025-06-09 11:54:32 +05:30
ruthra kumar
198089cac1 Merge pull request #47958 from frappe/mergify/bp/version-15-hotfix/pr-44697
fix: better description of tab name (backport #44697)
2025-06-09 10:17:31 +05:30
mahsem
d05b49b0f8 fix: better description of tab name (#44697)
(cherry picked from commit 6119d4384a)
2025-06-08 20:15:11 +00:00
mergify[bot]
f490de9285 perf: Batch GLE/SLE rename commits (backport #47950) (#47951)
perf: Batch GLE/SLE rename commits (#47950)

(cherry picked from commit bb693c0a4f)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2025-06-06 21:00:49 +05:30
RAVIBHARATHI P C
a5e5553520 fix(asset): make purchase date mandatory
(cherry picked from commit e6f47be4b0)
2025-06-06 12:10:43 +00:00
rohitwaghchaure
ea393ef008 chore: fix conflicts 2025-06-06 15:38:10 +05:30
Rohit Waghchaure
ef77791bd6 fix: do not remove item which has zero qty and zero valuation
(cherry picked from commit 86e4a658a5)

# Conflicts:
#	erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
2025-06-06 10:03:14 +00:00
Frappe PR Bot
63d165c48a chore(release): Bumped to Version 15.64.1
## [15.64.1](https://github.com/frappe/erpnext/compare/v15.64.0...v15.64.1) (2025-06-06)

### Reverts

* Revert "fix: calculate discount percentage if discount amount is specified (#…" ([29d7593](29d7593fa7))
2025-06-06 07:07:12 +00:00
thomasantony12
129cd7ae8a fix(sales order): error message on creation of work order from sales order 2025-06-06 12:36:30 +05:30
Sagar Vora
83a57909d3 Merge pull request #47933 from frappe/mergify/bp/version-15/pr-47927
fix: calculate discount percentage if discount amount is specified" (backport #47927)
2025-06-06 07:05:40 +00:00
Sagar Vora
29d7593fa7 Revert "fix: calculate discount percentage if discount amount is specified (#…"
This reverts commit bb474f4f42.

(cherry picked from commit 27dc0f5b70)
2025-06-06 07:05:26 +00:00
Sagar Vora
a8e1c4f6cd Merge pull request #47928 from frappe/mergify/bp/version-15-hotfix/pr-47927
fix: calculate discount percentage if discount amount is specified" (backport #47927)
2025-06-06 06:07:35 +00:00
Sagar Vora
5a5449c60c Revert "fix: calculate discount percentage if discount amount is specified (#…"
This reverts commit bb474f4f42.

(cherry picked from commit 27dc0f5b70)
2025-06-06 06:07:15 +00:00
mergify[bot]
6d2c14c75e fix: stock reco qty with inventory dimension (backport #47918) (#47922)
fix: stock reco qty with inventory dimension (#47918)

(cherry picked from commit 342cebc778)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-06-06 09:51:23 +05:30
mergify[bot]
2e78e14c7e fix: consider expired batches in the stock reco (backport #47909) (#47919)
fix: consider expired batches in the stock reco (#47909)

(cherry picked from commit 8fa3473945)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-06-05 17:35:23 +05:30
mergify[bot]
996fb7552a fix: key-error for COGS By Item Group report (backport #47914) (#47915)
fix: key-error for COGS By Item Group report (#47914)

fix: keyerror for COGS By Item Group report
(cherry picked from commit 997ce4eaa7)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-06-05 17:18:30 +05:30
Deepesh Garg
04349b61bd Merge pull request #47917 from frappe/mergify/bp/version-15-hotfix/pr-47907
feat: Add hook to update gl dict by apps (backport #47907)
2025-06-05 16:51:20 +05:30
Deepesh Garg
d3202068d9 style: Linting issues
(cherry picked from commit c4aecb15ce)
2025-06-05 11:03:52 +00:00
Deepesh Garg
76c2477d23 feat: Add hook to update gl dict by apps
(cherry picked from commit 10ff369ff2)
2025-06-05 11:03:51 +00:00
Diptanil Saha
1b1550708d fix: remove use sales invoice check (#47908) 2025-06-05 14:08:37 +05:30
ruthra kumar
425674e164 Merge pull request #47906 from frappe/mergify/bp/version-15-hotfix/pr-47665
fix: Project argument is not passed correctly for MR creation (backport #47665)
2025-06-05 11:53:22 +05:30
Syed Mujeer Hashmi
e98ad4ce27 fix: Project argument is passed correctly for MR creation
(cherry picked from commit 9eab434ae8)
2025-06-05 06:21:32 +00:00
mergify[bot]
0314a39fab fix: pos permission error on strict permission (backport #47896) (#47897)
fix: pos permission error on strict permission (#47896)

(cherry picked from commit bb903a4bef)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-06-04 16:11:07 +05:30
mergify[bot]
e5d06f8c86 fix: stock adjustment entry during reposting (backport #47878) (#47883)
fix: stock adjustment entry during reposting (#47878)

fix: stock adjustment entry
(cherry picked from commit cbcd580daa)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-06-04 12:51:10 +05:30
ruthra kumar
fb5d60eeb6 Merge pull request #47873 from frappe/mergify/bp/version-15-hotfix/pr-47872
fix: typo (backport #47872)
2025-06-03 19:49:47 +05:30
Mihir Kandoi
8d7be8a536 Merge pull request #47876 from frappe/mergify/bp/version-15-hotfix/pr-47874 2025-06-03 19:09:52 +05:30
Mihir Kandoi
b99f8fd021 fix: zero division error in purchase receipt
(cherry picked from commit 32229fb646)
2025-06-03 13:09:28 +00:00
Ayush Marhatta
8b4824fef5 fix: typo
(cherry picked from commit a243abb5fd)
2025-06-03 12:09:06 +00:00
Frappe PR Bot
916511ef1a chore(release): Bumped to Version 15.64.0
# [15.64.0](https://github.com/frappe/erpnext/compare/v15.63.0...v15.64.0) (2025-06-03)

### Bug Fixes

* Accounts receivable shouldn't fetch DN for employees ([9f5cfdd](9f5cfdd65b))
* add company filter to cost center and project in process statement of accounts ([5ebf1b9](5ebf1b9cc4))
* add internal link field in Sales Order connections for internal transactions ([3c697e9](3c697e90a3))
* calculate discount percentage if discount amount is specified ([#47806](https://github.com/frappe/erpnext/issues/47806)) ([ba8a316](ba8a316b06))
* cash flow report fixes ([4a1966c](4a1966c680))
* check return_against exists before api call ([8623a56](8623a5650b))
* decimal issue ([#47839](https://github.com/frappe/erpnext/issues/47839)) ([34b62d2](34b62d226c))
* ensure backend response is awaited before saving ([5a23d7c](5a23d7cdca))
* GL entries for rejected returned materials ([#47612](https://github.com/frappe/erpnext/issues/47612)) ([5bac652](5bac652b5f))
* Handle duplicate Items qty in Quotation ([4c1b415](4c1b415b9d))
* improved indexing for SLE queries. (backport [#47194](https://github.com/frappe/erpnext/issues/47194)) ([#47822](https://github.com/frappe/erpnext/issues/47822)) ([3879cbd](3879cbd86d))
* incorrect actual qty in product bundle balance report (backport [#47791](https://github.com/frappe/erpnext/issues/47791)) ([#47814](https://github.com/frappe/erpnext/issues/47814)) ([9df3b9b](9df3b9b059))
* **Timesheet:** Only update to_time if it's more than 1 second off ([#47702](https://github.com/frappe/erpnext/issues/47702)) ([470534a](470534af78))
* use `query.walk() `for escaping special chars in receiable/payable report ([2e3ebec](2e3ebec53c))
* use user default for company instead of global default in purchase order analysis report ([7d828dc](7d828dc17e))

### Features

* add column "Item Name" to "BOM Stock Report" (backport [#47116](https://github.com/frappe/erpnext/issues/47116)) ([#47485](https://github.com/frappe/erpnext/issues/47485)) ([9192913](9192913832))
* allow to set valuation rate for Rejected Materials (backport [#47582](https://github.com/frappe/erpnext/issues/47582)) ([#47869](https://github.com/frappe/erpnext/issues/47869)) ([3582b32](3582b32f03))
* show item name for raw materials in BOM creator ([0c612be](0c612be6fe))
* specify expense account and cost center for raw materials in Su… (backport [#47756](https://github.com/frappe/erpnext/issues/47756)) ([#47861](https://github.com/frappe/erpnext/issues/47861)) ([01dd733](01dd7337a2))
2025-06-03 11:54:42 +00:00
ruthra kumar
c614ff419b Merge pull request #47868 from frappe/version-15-hotfix
chore: release v15
2025-06-03 17:23:19 +05:30
ruthra kumar
d5163ed502 Merge pull request #47870 from frappe/mergify/bp/version-15-hotfix/pr-47612
fix: GL entries for rejected returned materials (backport #47612)
2025-06-03 16:45:02 +05:30
rohitwaghchaure
5bac652b5f fix: GL entries for rejected returned materials (#47612)
(cherry picked from commit 3e098da01f)
2025-06-03 10:57:14 +00:00
mergify[bot]
3582b32f03 feat: allow to set valuation rate for Rejected Materials (backport #47582) (#47869)
feat: allow to set valuation rate for Rejected Materials (#47582)

(cherry picked from commit ca0e53dd78)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-06-03 16:25:53 +05:30
ruthra kumar
2815a0d827 Merge pull request #47864 from frappe/mergify/bp/version-15-hotfix/pr-47854
fix: use user default for company instead of global default in purchase order analysis report (backport #47854)
2025-06-03 13:22:23 +05:30
Ayush Marhatta
7d828dc17e fix: use user default for company instead of global default in purchase order analysis report
(cherry picked from commit 49f23513e0)
2025-06-03 07:48:19 +00:00
mergify[bot]
01dd7337a2 feat: specify expense account and cost center for raw materials in Su… (backport #47756) (#47861) 2025-06-03 12:28:12 +05:30
Marc Ramser
470534af78 fix(Timesheet): Only update to_time if it's more than 1 second off (#47702)
* Fix: Only update to_time if it's more than 1 second off

Before, to_time was updated even when it was almost the same as the expected time (like 17:20 vs 17:19:59.998). This causes problems because of small rounding errors and caused valid times like 17:20 to be reset. Now, to_time is only updated if the difference is greater than 1 second.

To reproduce the current error:
* From Time 09:00:00
* To Time 17:20:00
Save 
To Time is 17:19:59

* Update erpnext/projects/doctype/timesheet/timesheet.py

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>

* Update timesheet.py

---------

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2025-06-03 11:59:13 +05:30
ruthra kumar
a4fe89f65c Merge pull request #47860 from frappe/mergify/bp/version-15-hotfix/pr-47809
fix: cash flow report fixes (backport #47809)
2025-06-03 11:47:50 +05:30
Lakshit Jain
4a1966c680 fix: cash flow report fixes
(cherry picked from commit 20b87512d1)
2025-06-03 05:53:23 +00:00
ruthra kumar
cd7462dd87 Merge pull request #47852 from frappe/mergify/bp/version-15-hotfix/pr-47780
fix: add internal link field in Sales Order connections for internal … (backport #47780)
2025-06-03 09:59:31 +05:30
Karuppasamy923
3c697e90a3 fix: add internal link field in Sales Order connections for internal transactions
(cherry picked from commit e3e6503076)
2025-06-02 11:17:45 +00:00
ruthra kumar
6dde327713 Merge pull request #47849 from frappe/mergify/bp/version-15-hotfix/pr-47502
fix: Handle duplicate Items qty in Quotation (backport #47502)
2025-06-02 15:11:46 +05:30
ruthra kumar
16b10274cf Merge pull request #47840 from frappe/mergify/bp/version-15-hotfix/pr-47839
fix: decimal issue (backport #47839)
2025-06-02 14:51:08 +05:30
Abdeali Chharchhodawala
4c1b415b9d fix: Handle duplicate Items qty in Quotation
fix: Handle duplicate Items qty in Quotation
(cherry picked from commit 39f6d8ffb6)
2025-06-02 09:20:41 +00:00
ruthra kumar
d7124779bf Merge pull request #47842 from frappe/mergify/bp/version-15-hotfix/pr-47821
Accounts receivable show delivery note (backport #47821)
2025-06-02 14:02:05 +05:30
ruthra kumar
053a5b93ca Merge pull request #47844 from frappe/mergify/bp/version-15-hotfix/pr-47781
fix: add company filter to cost center and project in process statement of accounts (backport #47781)
2025-06-02 13:41:21 +05:30
l0gesh29
9f5cfdd65b fix: Accounts receivable shouldn't fetch DN for employees
* fix: reorder function call

* fix: Add condition to fetch return entries for specific party types

(cherry picked from commit c8e052f3c6)
2025-06-02 13:40:20 +05:30
ljain112
5ebf1b9cc4 fix: add company filter to cost center and project in process statement of accounts
(cherry picked from commit 14313b162a)
2025-06-02 08:08:42 +00:00
rohitwaghchaure
34b62d226c fix: decimal issue (#47839)
(cherry picked from commit 0dbd9efc91)
2025-06-02 07:55:28 +00:00
Mihir Kandoi
9bf8904c80 Merge pull request #47832 from frappe/mergify/bp/version-15-hotfix/pr-47806 2025-05-31 21:18:29 +05:30
Mihir Kandoi
ba8a316b06 fix: calculate discount percentage if discount amount is specified (#47806)
(cherry picked from commit bb474f4f42)
2025-05-31 15:23:21 +00:00
mergify[bot]
3879cbd86d fix: improved indexing for SLE queries. (backport #47194) (#47822)
* fix: improved indexing for SLE queries. (#47194)

(cherry picked from commit b49a835b4c)

# Conflicts:
#	erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-30 15:36:51 +05:30
mergify[bot]
9df3b9b059 fix: incorrect actual qty in product bundle balance report (backport #47791) (#47814)
fix: incorrect actual qty in product bundle balance report (#47791)

(cherry picked from commit c544c3e018)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-30 14:01:32 +05:30
ruthra kumar
0131800df2 Merge pull request #47808 from frappe/mergify/bp/version-15-hotfix/pr-47794
fix: use `query.walk() `for escaping special chars in receiable/payable report (backport #47794)
2025-05-29 14:07:34 +05:30
ljain112
2e3ebec53c fix: use query.walk() for escaping special chars in receiable/payable report
(cherry picked from commit a0a51b5074)
2025-05-29 08:21:18 +00:00
mergify[bot]
ef9ccd7a57 chore: removed orphaned function (backport #47796) (#47804)
chore: removed orphaned function (#47796)

(cherry picked from commit cb9e6f6655)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-29 12:25:08 +05:30
Mihir Kandoi
903d9b50fe Merge pull request #47798 from frappe/mergify/bp/version-15-hotfix/pr-47792
feat: show item name for raw materials in BOM creator (backport #47792)
2025-05-28 20:28:51 +05:30
Mihir Kandoi
0c612be6fe feat: show item name for raw materials in BOM creator
(cherry picked from commit 90ba4ad1e1)
2025-05-28 14:23:24 +00:00
ruthra kumar
893a86e173 Merge pull request #47777 from frappe/mergify/bp/version-15-hotfix/pr-47041
fix: Check `return_against` and Await API Call (backport #47041)
2025-05-28 10:57:56 +05:30
Sanket322
5a23d7cdca fix: ensure backend response is awaited before saving
(cherry picked from commit c48db0b7c0)
2025-05-28 03:56:00 +00:00
Sanket322
8623a5650b fix: check return_against exists before api call
(cherry picked from commit 00b6b97197)
2025-05-28 03:56:00 +00:00
mergify[bot]
73bc57f53e Revert "fix: translate_pos_buttons" (backport #47773) (#47774)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix: translate_pos_buttons" (#47773)
2025-05-27 21:11:49 +02:00
mergify[bot]
9192913832 feat: add column "Item Name" to "BOM Stock Report" (backport #47116) (#47485)
Co-authored-by: Patrick Eißler <77415730+PatrickDEissler@users.noreply.github.com>
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2025-05-27 19:21:41 +02:00
Frappe PR Bot
f59093c6b7 chore(release): Bumped to Version 15.63.0
# [15.63.0](https://github.com/frappe/erpnext/compare/v15.62.0...v15.63.0) (2025-05-27)

### Bug Fixes

* absence of rounding causing discrepancy in the valuation rate calculation (backport [#47700](https://github.com/frappe/erpnext/issues/47700)) ([#47711](https://github.com/frappe/erpnext/issues/47711)) ([f41bcc6](f41bcc6fec))
* add no_copy for lost reasons ([db97dbd](db97dbd394))
* create Quality Inspection button not showing (backport [#47746](https://github.com/frappe/erpnext/issues/47746)) ([#47750](https://github.com/frappe/erpnext/issues/47750)) ([60dfe36](60dfe36195))
* display stock value in currency format in chart warehouse wise stock value ([ba009f4](ba009f4626))
* do not update same field twice ([63ba27e](63ba27e359))
* exchange rate not being fetched when creating supplier quotation from MR ([2c22615](2c22615b6b))
* filter of item for manufacture type material request (backport [#47712](https://github.com/frappe/erpnext/issues/47712)) ([#47717](https://github.com/frappe/erpnext/issues/47717)) ([2961e59](2961e595c2))
* handle multiselect filters for tree doctypes in Customer Ledger Summary Report ([f783bf6](f783bf60a4))
* Headline rendered twice on first save ([f94a14c](f94a14c06a))
* include rejected amount in PI/PR overbilling validation logic ([#47572](https://github.com/frappe/erpnext/issues/47572)) ([cd1c10a](cd1c10a43f))
* incorrect inventory dimension for material transfer (backport [#47592](https://github.com/frappe/erpnext/issues/47592)) ([#47644](https://github.com/frappe/erpnext/issues/47644)) ([9a78283](9a78283ecb))
* incorrect valuation rate due to positive qty (backport [#47686](https://github.com/frappe/erpnext/issues/47686)) ([#47688](https://github.com/frappe/erpnext/issues/47688)) ([62aa1cd](62aa1cdb33))
* linter ([c44493f](c44493fd7e))
* Linter (due to conflicts resolved on gh) ([37f4cf5](37f4cf5367))
* Linters ([91e167f](91e167fe72))
* made changes specifically for value adjustment entry ([74e29f1](74e29f1218))
* Merge conflicts ([3deb11e](3deb11e5b2))
* only include advances within the tcs period ([a2f5975](a2f5975133))
* party account based on party type's account type ([d3d22f6](d3d22f699e))
* patch to rename group_by filter in custom reports (backport [#47709](https://github.com/frappe/erpnext/issues/47709)) ([#47730](https://github.com/frappe/erpnext/issues/47730)) ([a137944](a137944955))
* patch to set status cancelled for already cancelled pos invoices (backport [#47725](https://github.com/frappe/erpnext/issues/47725)) ([#47759](https://github.com/frappe/erpnext/issues/47759)) ([4fd1af2](4fd1af2118))
* **portal:** User cannot create 0 qty SQ from RFQ ([f95a3f5](f95a3f5b8b))
* pos invoice status not updating on cancel (backport [#47556](https://github.com/frappe/erpnext/issues/47556)) ([#47657](https://github.com/frappe/erpnext/issues/47657)) ([db318a4](db318a4e9b))
* prettier ([0f22646](0f2264658f))
* prettier ([2c8db09](2c8db092a0))
* Relabel unit price settings for more clarity ([8891f46](8891f46a22))
* setting paid amount to 0 when is_paid is unchecked in purchase invoice ([895231a](895231a8a7))
* show general ledger in doc currency in Process Statement Of Accounts ([b3cbbf2](b3cbbf2ce3))
* skip drop ship items (backport [#47670](https://github.com/frappe/erpnext/issues/47670)) ([#47718](https://github.com/frappe/erpnext/issues/47718)) ([e058885](e05888502f))
* skip last purchase rate for free item (backport [#47693](https://github.com/frappe/erpnext/issues/47693)) ([#47696](https://github.com/frappe/erpnext/issues/47696)) ([f17b7b5](f17b7b5ee9))
* space ([fe78bb6](fe78bb60c4))
* space ([194e41a](194e41a2d9))
* translate_pos_buttons ([01b0d10](01b0d1057e))
* Treat rows as Unit Price rows only until the qty is 0 ([d963601](d9636018f5))
* typo in TREE_DOCTYPES list "Terrirtory" should be "Territory" ([3d2d1ba](3d2d1ba072))
* updated value after depreciation after value adjustment ([8ed6e98](8ed6e98565))
* use pypika object `LiteralValue` for adding match conditions ([fb2df77](fb2df77da2))

### Features

* add validation for Item Tax Template on rate change ([92d5e91](92d5e91e1f))
* Unit Price Contract ([33366fc](33366fce6c))
* Unit Price Items in Buying (RFQ, SQ, PO) ([f8fa775](f8fa775af3))
2025-05-27 14:56:33 +00:00
ruthra kumar
7ede5392bd Merge pull request #47758 from frappe/version-15-hotfix
chore: release v15
2025-05-27 20:24:59 +05:30
ruthra kumar
0f5c7d95a0 Merge pull request #47772 from frappe/mergify/bp/version-15-hotfix/pr-47766
fix: handle multiselect filters for tree doctypes in Customer Ledger Summary Report (backport #47766)
2025-05-27 20:09:05 +05:30
ljain112
f783bf60a4 fix: handle multiselect filters for tree doctypes in Customer Ledger Summary Report
(cherry picked from commit 536f7d5ff8)
2025-05-27 14:24:08 +00:00
ruthra kumar
4c49ab19d6 Merge pull request #47769 from frappe/mergify/bp/version-15-hotfix/pr-47765
fix: use pypika object `LiteralValue` for adding match conditions (backport #47765)
2025-05-27 19:52:20 +05:30
ruthra kumar
de1afee75a Merge pull request #47770 from frappe/mergify/bp/version-15-hotfix/pr-47767
fix: add no_copy for lost reasons (backport #47767)
2025-05-27 19:52:04 +05:30
l0gesh29
db97dbd394 fix: add no_copy for lost reasons
(cherry picked from commit 98e889a516)
2025-05-27 12:33:50 +00:00
ljain112
fb2df77da2 fix: use pypika object LiteralValue for adding match conditions
(cherry picked from commit 9093e5e363)
2025-05-27 12:31:16 +00:00
ruthra kumar
260073f14a Merge pull request #47764 from frappe/mergify/bp/version-15-hotfix/pr-47763
feat: add validation for Item Tax Template on rate change (backport #47763)
2025-05-27 17:14:54 +05:30
Karuppasamy923
92d5e91e1f feat: add validation for Item Tax Template on rate change
(cherry picked from commit a9a957edc7)
2025-05-27 11:30:15 +00:00
mergify[bot]
4fd1af2118 fix: patch to set status cancelled for already cancelled pos invoices (backport #47725) (#47759)
* fix: patch to set status cancelled for already cancelled pos invoices (#47725)

(cherry picked from commit 4d1d66e579)

# Conflicts:
#	erpnext/patches.txt

* chore: resolve conflict

---------

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-05-27 15:55:40 +05:30
Khushi Rawat
5997e37454 Merge pull request #47754 from khushi8112/asset-value-adjustment-of-zero-cost
fix: updated value after depreciation after value adjustment
2025-05-27 15:28:11 +05:30
Khushi Rawat
63ba27e359 fix: do not update same field twice 2025-05-27 15:10:51 +05:30
ruthra kumar
fd19f284c4 Merge pull request #47755 from frappe/mergify/bp/version-15-hotfix/pr-47679
fix: setting paid amount to 0 when is_paid is unchecked in purchase invoice (backport #47679)
2025-05-27 14:37:21 +05:30
Khushi Rawat
74e29f1218 fix: made changes specifically for value adjustment entry 2025-05-27 14:14:30 +05:30
ruthra kumar
5dee1d40ac Merge pull request #47753 from frappe/mergify/bp/version-15-hotfix/pr-47736
fix: only include advances within the tcs period (backport #47736)
2025-05-27 14:11:01 +05:30
ljain112
895231a8a7 fix: setting paid amount to 0 when is_paid is unchecked in purchase invoice
(cherry picked from commit e358a9e53f)
2025-05-27 08:32:33 +00:00
Khushi Rawat
8ed6e98565 fix: updated value after depreciation after value adjustment 2025-05-27 13:34:03 +05:30
ruthra kumar
70f9c13f3c Merge pull request #47751 from frappe/mergify/bp/version-15-hotfix/pr-47737
fix: party account based on party type's account type (backport #47737)
2025-05-27 13:31:39 +05:30
ljain112
a2f5975133 fix: only include advances within the tcs period
(cherry picked from commit 477ec9fdcc)
2025-05-27 07:49:19 +00:00
ljain112
d3d22f699e fix: party account based on party type's account type
(cherry picked from commit 19b1650522)
2025-05-27 07:44:13 +00:00
mergify[bot]
60dfe36195 fix: create Quality Inspection button not showing (backport #47746) (#47750)
fix: create Quality Inspection button not showing (#47746)

(cherry picked from commit d8cb073eaf)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-27 13:06:32 +05:30
ruthra kumar
b9698366c3 Merge pull request #47747 from frappe/mergify/bp/version-15-hotfix/pr-47654
fix: show general ledger in doc currency in Process Statement Of Accounts (backport #47654)
2025-05-27 12:01:48 +05:30
ruthra kumar
1fb4ac44fe Merge pull request #47748 from frappe/mergify/bp/version-15-hotfix/pr-47659
fix: translate_pos_buttons (backport #47659)
2025-05-27 11:52:27 +05:30
mahsem
0f2264658f fix: prettier
(cherry picked from commit 2839fc9460)
2025-05-27 06:12:19 +00:00
mahsem
fe78bb60c4 fix: space
(cherry picked from commit 50a5b51909)
2025-05-27 06:12:19 +00:00
mahsem
194e41a2d9 fix: space
(cherry picked from commit a442ec4e80)
2025-05-27 06:12:19 +00:00
mahsem
2c8db092a0 fix: prettier
(cherry picked from commit 1953c8489c)
2025-05-27 06:12:19 +00:00
mahsem
c44493fd7e fix: linter
(cherry picked from commit 4a6b5b9993)
2025-05-27 06:12:18 +00:00
mahsem
01b0d1057e fix: translate_pos_buttons
(cherry picked from commit ce45d1664d)
2025-05-27 06:12:18 +00:00
ljain112
9d2f396d75 chore: update test case because currency is auto set to system currency
(cherry picked from commit 22a94d6817)
2025-05-27 06:11:09 +00:00
ljain112
b3cbbf2ce3 fix: show general ledger in doc currency in Process Statement Of Accounts
(cherry picked from commit 998f6a29a4)
2025-05-27 06:11:09 +00:00
ruthra kumar
0cbb7223be Merge pull request #47742 from frappe/mergify/bp/version-15-hotfix/pr-47697
refactor: Fetch party name for contract (backport #47697)
2025-05-26 19:56:31 +05:30
ruthra kumar
c09b258d57 chore: resolve conflicts 2025-05-26 17:48:11 +05:30
ruthra kumar
d5d1a51b92 refactor: patch old contract with full party name
(cherry picked from commit 8e2221178b)

# Conflicts:
#	erpnext/patches.txt
2025-05-26 12:11:31 +00:00
ruthra kumar
9abac4c6df refactor: fetch party name on selection
(cherry picked from commit 752024e222)
2025-05-26 12:11:31 +00:00
ruthra kumar
48f786e493 refactor: full name field in contract
(cherry picked from commit 016924361a)

# Conflicts:
#	erpnext/crm/doctype/contract/contract.json
2025-05-26 12:11:30 +00:00
mergify[bot]
a137944955 fix: patch to rename group_by filter in custom reports (backport #47709) (#47730)
* fix: patch to rename group_by filter in custom reports

(cherry picked from commit 0d19c18c06)

# Conflicts:
#	erpnext/patches.txt

* fix: using python instead of sql query

(cherry picked from commit 48eccb1f73)

* chore: resolve conflict

---------

Co-authored-by: diptanilsaha <diptanil@frappe.io>
2025-05-26 13:29:41 +05:30
ruthra kumar
bb54bebe94 Merge pull request #47726 from frappe/mergify/bp/version-15-hotfix/pr-47253
fix: display stock value in currency format in chart warehouse wise stock value (backport #47253)
2025-05-26 11:35:46 +05:30
Prateek Karamchandani
ba009f4626 fix: display stock value in currency format in chart warehouse wise stock value
(cherry picked from commit 7a5cbc759c)
2025-05-26 05:49:56 +00:00
mergify[bot]
e05888502f fix: skip drop ship items (backport #47670) (#47718)
fix: skip drop ship items (#47670)

(cherry picked from commit 67c86ec028)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-26 07:53:55 +05:30
mergify[bot]
2961e595c2 fix: filter of item for manufacture type material request (backport #47712) (#47717)
fix: filter of item for manufacture type material request (#47712)

(cherry picked from commit 874750f9ce)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-25 20:51:14 +05:30
mergify[bot]
f41bcc6fec fix: absence of rounding causing discrepancy in the valuation rate calculation (backport #47700) (#47711)
fix: absence of rounding causing discrepancy in the valuation rate calculation (#47700)

(cherry picked from commit 1e8ed22421)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-24 17:27:20 +05:30
Marica
a6b1bdc78b Merge pull request #47410 from frappe/mergify/bp/version-15-hotfix/pr-46214
feat: Unit Price Items (backport #46214)
2025-05-23 17:42:33 +02:00
mergify[bot]
f17b7b5ee9 fix: skip last purchase rate for free item (backport #47693) (#47696)
fix: skip last purchase rate for free item (#47693)

(cherry picked from commit c3b17024bd)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-23 09:49:51 +05:30
ruthra kumar
5529a17831 Merge pull request #47685 from frappe/mergify/bp/version-15-hotfix/pr-47675
fix: typo in TREE_DOCTYPES list "Terrirtory" should be "Territory" (backport #47675)
2025-05-22 16:25:15 +05:30
mergify[bot]
62aa1cdb33 fix: incorrect valuation rate due to positive qty (backport #47686) (#47688)
fix: incorrect valuation rate due to positive qty (#47686)

(cherry picked from commit 6ed97b5fda)

Co-authored-by: Khushi Rawat <142375893+khushi8112@users.noreply.github.com>
2025-05-22 16:17:18 +05:30
ljain112
3d2d1ba072 fix: typo in TREE_DOCTYPES list "Terrirtory" should be "Territory"
(cherry picked from commit 51162cb1a3)
2025-05-22 10:27:05 +00:00
Mihir Kandoi
f3bc80c89d Merge pull request #47678 from frappe/mergify/bp/version-15-hotfix/pr-47658
fix: exchange rate not being fetched when creating supplier quotation… (backport #47658)
2025-05-22 14:36:37 +05:30
Mihir Kandoi
6892994ef6 Merge pull request #47677 from frappe/mergify/bp/version-15-hotfix/pr-47572
fix: include rejected amount in PI/PR overbilling validation logic (backport #47572)
2025-05-22 14:36:19 +05:30
Mihir Kandoi
2c22615b6b fix: exchange rate not being fetched when creating supplier quotation from MR
(cherry picked from commit 9d12ae071a)
2025-05-22 07:26:50 +00:00
Mihir Kandoi
cd1c10a43f fix: include rejected amount in PI/PR overbilling validation logic (#47572)
* fix: include rejected amount in PI/PR overbilling validation logic

* fix: add check if amount is 0

* fix: unneccessary condition

(cherry picked from commit 8d9888b1b6)
2025-05-22 07:23:46 +00:00
mergify[bot]
db318a4e9b fix: pos invoice status not updating on cancel (backport #47556) (#47657)
fix: pos invoice status not updating on cancel (#47556)

(cherry picked from commit 8c86def018)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-05-21 15:09:48 +05:30
mergify[bot]
9a78283ecb fix: incorrect inventory dimension for material transfer (backport #47592) (#47644)
fix: incorrect inventory dimension for material transfer (#47592)

(cherry picked from commit 738cb6a0c1)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-20 20:46:57 +05:30
Frappe PR Bot
52a5cd9702 chore(release): Bumped to Version 15.62.0
# [15.62.0](https://github.com/frappe/erpnext/compare/v15.61.1...v15.62.0) (2025-05-20)

### Bug Fixes

* alias name and parent to prevent child row mapping issues ([612fa7c](612fa7c672))
* allow FG as RM by default (backport [#47543](https://github.com/frappe/erpnext/issues/47543)) ([#47550](https://github.com/frappe/erpnext/issues/47550)) ([9355782](9355782397))
* asset cancellation issue (backport [#47639](https://github.com/frappe/erpnext/issues/47639)) ([#47641](https://github.com/frappe/erpnext/issues/47641)) ([ce9da48](ce9da48a5e))
* asset image field updation issue (backport [#47615](https://github.com/frappe/erpnext/issues/47615)) ([#47617](https://github.com/frappe/erpnext/issues/47617)) ([35c7af1](35c7af1b9d))
* better validation message with solution for BOM recursion (backport [#47472](https://github.com/frappe/erpnext/issues/47472)) ([#47477](https://github.com/frappe/erpnext/issues/47477)) ([a450f4c](a450f4ce64))
* Broken test + use `super()` appropriately ([5b50d5a](5b50d5abf2))
* Conflicts ([9cede83](9cede83de1))
* correct expense amount in party ledger summary. ([09a46fc](09a46fcf0e))
* date formatting in process_statement_of_accounts accounts_receivable print format ([cf354c0](cf354c0da3))
* include only invoices with update_stock = 0  for billed amt in delivery note. ([70e190d](70e190dbbb))
* incorrect qty during reset (backport [#47593](https://github.com/frappe/erpnext/issues/47593)) ([#47595](https://github.com/frappe/erpnext/issues/47595)) ([72ae80e](72ae80e2e3))
* mapping of dispatch address when creating PO from SO (backport [#47552](https://github.com/frappe/erpnext/issues/47552)) ([#47553](https://github.com/frappe/erpnext/issues/47553)) ([30ec69c](30ec69c977))
* POS Invoice can't use Loyalty Points when Global Rounded Total is Disabled (backport [#47491](https://github.com/frappe/erpnext/issues/47491)) ([#47564](https://github.com/frappe/erpnext/issues/47564)) ([926c0c5](926c0c5cf4))
* pos item group filter fetching wrong items (backport [#47545](https://github.com/frappe/erpnext/issues/47545)) ([#47546](https://github.com/frappe/erpnext/issues/47546)) ([5a3eff0](5a3eff05a1))
* **quotation:** use `Text Editor` field in alternative items dialog for item description ([32eeeda](32eeedac24))
* remove hardcoded doctype in `make_return_doc` ([1a69d81](1a69d8137f))
* removed invalid child param to prevent callback failure ([073d06c](073d06c44f))
* **SalesAnalytics:** Ignore opening entries ([be280a4](be280a408e))
* set no_copy to party_balance field in Payment Entry ([da4ed5c](da4ed5cc18))
* set no_copy to party_balance field in Payment Entry ([52cab02](52cab02a5c))
* validate inter-company transaction address links ([86aa072](86aa072235))
* validation message format (backport [#47542](https://github.com/frappe/erpnext/issues/47542)) ([#47549](https://github.com/frappe/erpnext/issues/47549)) ([f225e19](f225e1986e))

### Features

* add checbox for validating time logs in job card ([80c7661](80c76618ae))
* add option to calculate ageing based on report date or today date ([69337cf](69337cf18b))
2025-05-20 13:54:53 +00:00
ruthra kumar
f3052a446f Merge pull request #47636 from frappe/version-15-hotfix
chore: release v15
2025-05-20 19:23:12 +05:30
mergify[bot]
ce9da48a5e fix: asset cancellation issue (backport #47639) (#47641)
fix: asset cancellation issue (#47639)

(cherry picked from commit 33ab64dec2)

Co-authored-by: Khushi Rawat <142375893+khushi8112@users.noreply.github.com>
2025-05-20 17:21:48 +05:30
mergify[bot]
a450f4ce64 fix: better validation message with solution for BOM recursion (backport #47472) (#47477)
fix: better validation message with solution for BOM recursion

(cherry picked from commit 7103cdd84a)

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
2025-05-20 16:15:23 +05:30
ruthra kumar
a029f2e8a3 Merge pull request #47633 from frappe/mergify/bp/version-15-hotfix/pr-47632
fix(quotation): use `Text Editor` field in alternative items dialog (backport #47632)
2025-05-20 14:25:10 +05:30
Akhil Narang
32eeedac24 fix(quotation): use Text Editor field in alternative items dialog for item description
`Data` causes text to overflow - the field is originally a `Text Editor` field

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
(cherry picked from commit c7ea91073e)
2025-05-20 08:52:05 +00:00
ruthra kumar
ecb2bab70f Merge pull request #47631 from frappe/mergify/bp/version-15-hotfix/pr-47629
fix: date formatting in process_statement_of_accounts accounts_receivable print format (backport #47629)
2025-05-20 14:06:20 +05:30
ljain112
cf354c0da3 fix: date formatting in process_statement_of_accounts accounts_receivable print format
(cherry picked from commit 67c32ce3c9)

# Conflicts:
#	erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html
2025-05-20 13:57:47 +05:30
ruthra kumar
73fc8c374f Merge pull request #47628 from frappe/mergify/bp/version-15-hotfix/pr-47580
feat: add option to calculate ageing based on report date or today's date (backport #47580)
2025-05-20 13:53:04 +05:30
ruthra kumar
8c4ce03f44 Merge pull request #47623 from frappe/mergify/bp/version-15-hotfix/pr-47486
fix(SalesAnalytics): Ignore opening entries (backport #47486)
2025-05-20 13:21:36 +05:30
l0gesh29
69337cf18b feat: add option to calculate ageing based on report date or today date
(cherry picked from commit c67ba2d49b)
2025-05-20 07:48:39 +00:00
ruthra kumar
b773b494a0 Merge pull request #47625 from frappe/mergify/bp/version-15-hotfix/pr-47559
fix: include only invoices with update_stock = 0  for billed amt in delivery note. (backport #47559)
2025-05-20 11:25:06 +05:30
ljain112
70e190dbbb fix: include only invoices with update_stock = 0 for billed amt in delivery note.
(cherry picked from commit 6dc459db58)
2025-05-20 05:31:56 +00:00
l0gesh29
be280a408e fix(SalesAnalytics): Ignore opening entries
(cherry picked from commit 6d269b4409)
2025-05-20 05:20:43 +00:00
ruthra kumar
9584c80857 Merge pull request #47622 from frappe/mergify/bp/version-15-hotfix/pr-47614
fix: remove hardcoded doctype in `make_return_doc` (backport #47614)
2025-05-20 10:14:57 +05:30
barredterra
1a69d8137f fix: remove hardcoded doctype in make_return_doc
(cherry picked from commit 45a5c19dd4)
2025-05-20 04:30:11 +00:00
mergify[bot]
35c7af1b9d fix: asset image field updation issue (backport #47615) (#47617)
fix: asset image field updation issue (#47615)

(cherry picked from commit ff2ccf9bce)

Co-authored-by: Khushi Rawat <142375893+khushi8112@users.noreply.github.com>
2025-05-20 01:28:45 +05:30
ruthra kumar
da4ed5cc18 fix: set no_copy to party_balance field in Payment Entry 2025-05-19 16:15:16 +05:30
ruthra kumar
927d0f686f Merge pull request #47600 from frappe/mergify/bp/version-15-hotfix/pr-47505
fix: validate inter company transaction address links (backport #47505)
2025-05-19 13:25:08 +05:30
Bhavan23
8ee9a46d96 test: add test case to validate inter-company transaction address links
(cherry picked from commit 0caa757dd6)
2025-05-19 07:39:50 +00:00
Bhavan23
86aa072235 fix: validate inter-company transaction address links
(cherry picked from commit aed46ad5b9)
2025-05-19 07:39:50 +00:00
mergify[bot]
72ae80e2e3 fix: incorrect qty during reset (backport #47593) (#47595)
fix: incorrect qty during reset (#47593)

(cherry picked from commit a058fe7319)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-19 12:02:29 +05:30
Mihir Kandoi
829550cd99 Merge pull request #47577 from frappe/mergify/bp/version-15-hotfix/pr-47570
feat: add checkbox for validating time logs in job card (backport #47570)
2025-05-17 00:34:56 +05:30
Mihir Kandoi
249d18962c chore: resolve conflicts 2025-05-17 00:08:39 +05:30
Khushi Rawat
b9f12ed4c7 Merge pull request #47576 from frappe/mergify/bp/version-15-hotfix/pr-47573
fix: alias 'name' and 'parent' to prevent child row mapping issues (backport #47573)
2025-05-16 15:52:37 +05:30
Mihir Kandoi
80c76618ae feat: add checbox for validating time logs in job card
(cherry picked from commit 2d9a6a4de8)

# Conflicts:
#	erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json
2025-05-16 10:05:52 +00:00
Khushi Rawat
073d06c44f fix: removed invalid child param to prevent callback failure
(cherry picked from commit 1ca51e4f14)
2025-05-16 10:05:51 +00:00
Khushi Rawat
612fa7c672 fix: alias name and parent to prevent child row mapping issues
(cherry picked from commit a418e377f4)
2025-05-16 10:05:51 +00:00
marination
e7dc31191c Merge branch 'version-15-hotfix' into mergify/bp/version-15-hotfix/pr-46214 2025-05-15 18:50:58 +02:00
mergify[bot]
926c0c5cf4 fix: POS Invoice can't use Loyalty Points when Global Rounded Total is Disabled (backport #47491) (#47564)
fix: POS Invoice can't use Loyalty Points when Global Rounded Total is Disabled (#47491)

(cherry picked from commit b541b536c3)

Co-authored-by: Kitti U. @ Ecosoft <kittiu@gmail.com>
2025-05-15 19:35:03 +05:30
ljain112
52cab02a5c fix: set no_copy to party_balance field in Payment Entry 2025-05-15 18:03:25 +05:30
Frappe PR Bot
31fa1c9a58 chore(release): Bumped to Version 15.61.1
## [15.61.1](https://github.com/frappe/erpnext/compare/v15.61.0...v15.61.1) (2025-05-15)

### Bug Fixes

* correct expense amount in party ledger summary. ([67741f1](67741f1a21))
2025-05-15 06:05:18 +00:00
ruthra kumar
631a9bfa7c Merge pull request #47557 from frappe/mergify/bp/version-15/pr-47541
fix: correct expense amount in party ledger summary. (backport #47541)
2025-05-15 11:33:53 +05:30
ljain112
67741f1a21 fix: correct expense amount in party ledger summary.
(cherry picked from commit 09a46fcf0e)
2025-05-15 05:47:32 +00:00
mergify[bot]
f225e1986e fix: validation message format (backport #47542) (#47549)
fix: validation message format (#47542)

(cherry picked from commit a18e1cffa7)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-15 10:31:28 +05:30
mergify[bot]
9355782397 fix: allow FG as RM by default (backport #47543) (#47550)
fix: allow FG as RM by default (#47543)

(cherry picked from commit 4241bfd4bc)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-15 10:31:12 +05:30
mergify[bot]
30ec69c977 fix: mapping of dispatch address when creating PO from SO (backport #47552) (#47553)
fix: mapping of dispatch address when creating PO from SO (#47552)

* fix: mapping of dispatch address when creating PO from SO

* fix: add to default supplier function as well

(cherry picked from commit 82161e9cb5)

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-05-14 20:52:04 +05:30
ruthra kumar
b22831bd94 Merge pull request #47541 from ljain112/fix-cls
fix: correct expense amount in party ledger summary.
2025-05-14 17:56:22 +05:30
mergify[bot]
5a3eff05a1 fix: pos item group filter fetching wrong items (backport #47545) (#47546)
fix: pos item group filter fetching wrong items (#47545)

(cherry picked from commit 5c28e01590)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-05-14 17:41:36 +05:30
ljain112
09a46fcf0e fix: correct expense amount in party ledger summary. 2025-05-14 12:38:38 +05:30
marination
37f4cf5367 fix: Linter (due to conflicts resolved on gh) 2025-05-13 17:18:40 +02:00
marination
f95a3f5b8b fix(portal): User cannot create 0 qty SQ from RFQ
- The portal uses `create_supplier_quotation` for SQ creation which excludes 0 qty items
2025-05-13 17:13:41 +02:00
marination
0286788e97 chore: Relabel according to review changes 2025-05-13 17:13:41 +02:00
marination
8891f46a22 fix: Relabel unit price settings for more clarity 2025-05-13 17:13:41 +02:00
Marica
890ce4a676 Merge branch 'version-15-hotfix' into mergify/bp/version-15-hotfix/pr-46214 2025-05-13 17:07:43 +02:00
Marica
2960d0dce1 Merge pull request #47537 from frappe/mergify/bp/version-15-hotfix/pr-38530
refactor: Consolidate duplicate zero-quantity Items checks for transactions. (backport #38530)
2025-05-13 16:55:54 +02:00
Frappe PR Bot
6e699178ae chore(release): Bumped to Version 15.61.0
# [15.61.0](https://github.com/frappe/erpnext/compare/v15.60.2...v15.61.0) (2025-05-13)

### Bug Fixes

* accumulate values for all the fiscal years in Profit And Loss Statement ([6dbdc36](6dbdc36af9))
* added PR/PI overbilling validation (backport [#47385](https://github.com/frappe/erpnext/issues/47385)) ([#47497](https://github.com/frappe/erpnext/issues/47497)) ([309ea7b](309ea7b9cf))
* broken test suite due to incorrect OR filter ([4a37f2a](4a37f2a925))
* condition for advance_account assignment ([b6e5e33](b6e5e3347d))
* do not mandate depreciation accounts for non depreciable asset category ([a75931c](a75931c90f))
* dont auto-fetch latest exchange rate ([0adb715](0adb7156cd))
* error while making SABB for backdated stock reco ([7ba7d1a](7ba7d1a2a4))
* ignore "Account Closing Balance" doctype on Period Closing Voucher cancellation ([39c0291](39c029133f))
* only depreciable category assets are allowed for depreciation ([242a119](242a119f95))
* **payment-reconciliation:** use reconciliation_takes_effect_on from company ([25fabda](25fabda40a))
* POS non-stock item mistakenly hidden as unavailable (backport [#47493](https://github.com/frappe/erpnext/issues/47493)) ([#47506](https://github.com/frappe/erpnext/issues/47506)) ([b18692c](b18692c120))
* resolved conflicts ([dcfae61](dcfae61a7a))
* timesheet portal showing total billing hours ([64ae4e1](64ae4e1fec))
* typo ([d61a85e](d61a85e316))
* typo in event.js ([67d24e9](67d24e9635))
* warning message for COGS account in the stock entry ([7abe199](7abe199e2a))

### Features

* add non depreciable category checkbox in asset category ([96d3bfd](96d3bfd2d9))
* add routing/sequencing to work order operations (backport [#46975](https://github.com/frappe/erpnext/issues/46975)) ([#47534](https://github.com/frappe/erpnext/issues/47534)) ([56d0357](56d0357f6f))

### Performance Improvements

* Skip link checking on repost's remove_attached_file (backport [#45061](https://github.com/frappe/erpnext/issues/45061)) ([#47450](https://github.com/frappe/erpnext/issues/47450)) ([09e7bfb](09e7bfbacb))
2025-05-13 14:04:07 +00:00
ruthra kumar
0f350ef24d Merge pull request #47528 from frappe/version-15-hotfix
chore: release v15
2025-05-13 19:32:35 +05:30
mergify[bot]
56d0357f6f feat: add routing/sequencing to work order operations (backport #46975) (#47534)
* feat: add routing/sequencing to work order operations (#46975)

* feat: add routing/sequencing to work order operations

* fix: add validation and remove reorderin for non sequence id operations

* chore: readability

* fix: logical error

* fix: logical error

* chore: added row number in error message

(cherry picked from commit f1159b6ea6)

# Conflicts:
#	erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json

* chore: resolve conflicts

---------

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-05-13 19:02:01 +05:30
marination
5b50d5abf2 fix: Broken test + use super() appropriately
- test: Remove `test_bom_qty`. It had invalid code. Its been removed from develop. There wasn't a strong case being tested.
2025-05-13 14:42:57 +02:00
marination
9cede83de1 fix: Conflicts 2025-05-13 14:26:54 +02:00
Bernd Oliver Sünderhauf
a8b982dd0a chore: Adapt translations to reworded message.
(cherry picked from commit 3688d9412e)

# Conflicts:
#	erpnext/translations/tr.csv
2025-05-13 12:13:56 +00:00
Bernd Oliver Sünderhauf
cf45ffdabe refactor: Consolidate duplicate zero-quantity transaction Items checks.
(cherry picked from commit 4918aeb4c6)

# Conflicts:
#	erpnext/stock/doctype/stock_entry/stock_entry.py
2025-05-13 12:13:47 +00:00
Bernd Oliver Sünderhauf
e91a0acbb3 test: Add, expand and refine test-cases for zero-quantity transactions.
(cherry picked from commit b2d8a44199)

# Conflicts:
#	erpnext/selling/doctype/sales_order/test_sales_order.py
#	erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
#	erpnext/stock/doctype/stock_entry/stock_entry.py
2025-05-13 12:13:46 +00:00
Khushi Rawat
fbbae80f92 Merge pull request #47533 from frappe/mergify/bp/version-15-hotfix/pr-47530
feat: non depreciable asset category (backport #47530)
2025-05-13 17:23:09 +05:30
Khushi Rawat
dcfae61a7a fix: resolved conflicts 2025-05-13 17:07:14 +05:30
marination
3deb11e5b2 fix: Merge conflicts 2025-05-13 13:35:19 +02:00
Khushi Rawat
242a119f95 fix: only depreciable category assets are allowed for depreciation
(cherry picked from commit d715db1226)
2025-05-13 11:34:35 +00:00
Khushi Rawat
a75931c90f fix: do not mandate depreciation accounts for non depreciable asset category
(cherry picked from commit 32cb7d6388)
2025-05-13 11:34:35 +00:00
Khushi Rawat
96d3bfd2d9 feat: add non depreciable category checkbox in asset category
(cherry picked from commit fbbfd6531b)

# Conflicts:
#	erpnext/assets/doctype/asset_category/asset_category.json
2025-05-13 11:34:35 +00:00
ruthra kumar
165a4fcef6 Merge pull request #47527 from frappe/mergify/bp/version-15-hotfix/pr-47520
fix: ignore "Account Closing Balance" doctype on Period Closing Voucher cancellation (backport #47520)
2025-05-13 15:10:13 +05:30
ruthra kumar
29b35d6eb0 Merge pull request #47522 from frappe/mergify/bp/version-15-hotfix/pr-47468
fix(payment-reconciliation): use reconciliation_takes_effect_on from company (backport #47468)
2025-05-13 15:03:59 +05:30
ljain112
39c029133f fix: ignore "Account Closing Balance" doctype on Period Closing Voucher cancellation
(cherry picked from commit d6602d63fc)
2025-05-13 09:21:31 +00:00
ruthra kumar
7f55d59a7b chore: drop redundant patch 2025-05-13 14:45:51 +05:30
ruthra kumar
95f21e5ecd Merge pull request #47523 from frappe/mergify/bp/version-15-hotfix/pr-47521
fix: condition for advance_account assignment (backport #47521)
2025-05-13 14:31:29 +05:30
Bhavan23
bafd9ed15e chore: simplify repeated condition checks
(cherry picked from commit 7bc62cedc6)
2025-05-13 14:14:13 +05:30
Bhavan23
25fabda40a fix(payment-reconciliation): use reconciliation_takes_effect_on from company
(cherry picked from commit 19f1ffbdc2)
2025-05-13 14:14:10 +05:30
ljain112
b6e5e3347d fix: condition for advance_account assignment
(cherry picked from commit ded46ce3d8)
2025-05-13 08:43:18 +00:00
ruthra kumar
2868446292 Merge pull request #47517 from frappe/mergify/bp/version-15-hotfix/pr-47367
fix: Use `Currency` instead of `Float` in GL report to show details (backport #47367)
2025-05-13 13:08:32 +05:30
Abdeali Chharchhodawala
811fe4fee6 Merge pull request #47367 from Abdeali099/gl-report-field-float-to-currency
fix: Use `Currency` instead of `Float` in GL report to show details
(cherry picked from commit e4e0bb68ec)
2025-05-13 05:57:49 +00:00
mergify[bot]
b6bf13ff02 refactor: available serial no report (backport #47333) (#47500)
* refactor: available serial no report

(cherry picked from commit 74eb611563)

* chore: further optimizations

(cherry picked from commit 653e0a2e3a)

---------

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-05-12 23:29:51 +05:30
ruthra kumar
b82e2585d5 Merge pull request #47508 from frappe/mergify/bp/version-15-hotfix/pr-47243
fix: accumulate values for all the fiscal years in Profit And Loss Statement (backport #47243)
2025-05-12 17:09:57 +05:30
ruthra kumar
9ca96a63c3 refactor(test): don't default to accumulate
(cherry picked from commit 54e4e7918e)
2025-05-12 16:54:14 +05:30
ruthra kumar
98cb9c6b96 test: accumulate filter on P&L report
(cherry picked from commit afff6b84ce)
2025-05-12 16:54:09 +05:30
ruthra kumar
d61a85e316 fix: typo
(cherry picked from commit 61d13ce232)
2025-05-12 11:17:32 +00:00
ljain112
6dbdc36af9 fix: accumulate values for all the fiscal years in Profit And Loss Statement
(cherry picked from commit 6851322361)
2025-05-12 11:17:32 +00:00
mergify[bot]
b18692c120 fix: POS non-stock item mistakenly hidden as unavailable (backport #47493) (#47506)
fix: POS non-stock item mistakenly hidden as unavailable (#47493)

(cherry picked from commit 57f3489dfa)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-05-12 15:10:11 +05:30
mergify[bot]
309ea7b9cf fix: added PR/PI overbilling validation (backport #47385) (#47497)
* fix: added PR/PI overbilling validation

(cherry picked from commit f4ffc57b51)

* test: added test

(cherry picked from commit b406ec724b)

* fix: linter error

(cherry picked from commit 27e842ba02)

---------

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-05-11 14:31:46 +05:30
Mihir Kandoi
775b2432ab Merge pull request #47494 from frappe/mergify/bp/version-15-hotfix/pr-47481
fix: timesheet portal showing total billing hours (backport #47481)
2025-05-10 12:04:04 +05:30
Mihir Kandoi
64ae4e1fec fix: timesheet portal showing total billing hours
(cherry picked from commit b04a07fda0)
2025-05-10 06:09:25 +00:00
ruthra kumar
005014ef6a Merge pull request #47482 from frappe/mergify/bp/version-15-hotfix/pr-47380
fix: broken CI - uae vat 201 tests failing (backport #47380)
2025-05-09 15:00:55 +05:30
ruthra kumar
4a37f2a925 fix: broken test suite due to incorrect OR filter
(cherry picked from commit 37d74e387d)
2025-05-09 09:13:26 +00:00
ruthra kumar
870be7a79b Merge pull request #47467 from frappe/mergify/bp/version-15-hotfix/pr-47462
Update event.js (backport #47462)
2025-05-08 14:13:19 +05:30
Yaiphalemba Mangshatabam
67d24e9635 fix: typo in event.js
"Sales Partners" -> "Sales Partner"

(cherry picked from commit edee75c757)
2025-05-08 08:40:56 +00:00
rohitwaghchaure
3ba7bb3ab7 Merge pull request #47454 from frappe/mergify/bp/version-15-hotfix/pr-47452
fix: warning message for COGS account in the stock entry (backport #47452)
2025-05-08 13:58:08 +05:30
rohitwaghchaure
72ec3f3d18 Merge pull request #47458 from frappe/mergify/bp/version-15-hotfix/pr-47457
fix: error while making SABB for backdated stock reco (backport #47457)
2025-05-08 13:57:43 +05:30
Rohit Waghchaure
7ba7d1a2a4 fix: error while making SABB for backdated stock reco
(cherry picked from commit ad25636afb)
2025-05-07 15:49:10 +00:00
Rohit Waghchaure
7abe199e2a fix: warning message for COGS account in the stock entry
(cherry picked from commit bba6b0ff45)
2025-05-07 10:50:21 +00:00
mergify[bot]
09e7bfbacb perf: Skip link checking on repost's remove_attached_file (backport #45061) (#47450)
perf: Skip link checking on repost's remove_attached_file (#45061)

This is internal detail, doesn't need to do horrible link checks in
framework.

(cherry picked from commit 4f690affc9)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2025-05-07 14:04:12 +05:30
ruthra kumar
ef7b09fc11 Merge pull request #47448 from frappe/mergify/bp/version-15-hotfix/pr-47447
fix: dont auto-fetch latest exchange rate (backport #47447)
2025-05-07 11:22:50 +05:30
ruthra kumar
0adb7156cd fix: dont auto-fetch latest exchange rate
- also use correct currency field for comparison

(cherry picked from commit 4ccd0a7407)
2025-05-07 05:47:33 +00:00
Frappe PR Bot
7fb557197a chore(release): Bumped to Version 15.60.2
## [15.60.2](https://github.com/frappe/erpnext/compare/v15.60.1...v15.60.2) (2025-05-06)

### Bug Fixes

* 'time to resolve: failed' on issue (backport [#47406](https://github.com/frappe/erpnext/issues/47406)) ([#47407](https://github.com/frappe/erpnext/issues/47407)) ([21612fc](21612fc230))
* backward compatibility for renamed group_by filter on reports (backport [#47362](https://github.com/frappe/erpnext/issues/47362)) ([#47403](https://github.com/frappe/erpnext/issues/47403)) ([0e5c709](0e5c709f7b))
* change shipping address fetching condition ([0aabe4f](0aabe4fd1e))
* completed transactions showing in the list (backport [#47374](https://github.com/frappe/erpnext/issues/47374)) ([#47379](https://github.com/frappe/erpnext/issues/47379)) ([1ef7da8](1ef7da837f))
* do not allocate amount when ref's doctype or name are not set ([c2e36da](c2e36daa32))
* do not mandate depreciation account for assets without depreciation (backport [#47427](https://github.com/frappe/erpnext/issues/47427)) ([#47428](https://github.com/frappe/erpnext/issues/47428)) ([01e975b](01e975b481))
* not able to submit the stock entry ([#47383](https://github.com/frappe/erpnext/issues/47383)) ([035394a](035394ae6a))
* party name in Ledger Summary ([4fc14b3](4fc14b3097))
* precision issue ([b6908a7](b6908a79bd))
* rename unchanged group_by filter related to general ledger report (backport [#47366](https://github.com/frappe/erpnext/issues/47366)) ([#47405](https://github.com/frappe/erpnext/issues/47405)) ([8d1e855](8d1e855dc8))
* renaming group by fieldname and value in reports (backport [#47352](https://github.com/frappe/erpnext/issues/47352)) ([#47360](https://github.com/frappe/erpnext/issues/47360)) ([85a8adf](85a8adf804))
* show party type in due date exceeding message ([f73e99e](f73e99e9d2))
* stock reco recalculate qty not works for opening stock reco ([2bd30e3](2bd30e3c46))
* update accounts on change of mode of payment in sales invoice payment (backport [#47381](https://github.com/frappe/erpnext/issues/47381)) ([#47400](https://github.com/frappe/erpnext/issues/47400)) ([afb44a6](afb44a677c))
* validation for difference account ([f4a43d0](f4a43d07b0))
* warning message before changing the valuation method (backport [#47340](https://github.com/frappe/erpnext/issues/47340)) ([#47342](https://github.com/frappe/erpnext/issues/47342)) ([4ef2b77](4ef2b77973))
2025-05-06 14:11:12 +00:00
ruthra kumar
7733e417a4 Merge pull request #47429 from frappe/version-15-hotfix
chore: release v15
2025-05-06 19:39:35 +05:30
rohitwaghchaure
d8fb11009f Merge pull request #47440 from frappe/mergify/bp/version-15-hotfix/pr-47435
fix: stock reco recalculate qty not works for opening stock reco (backport #47435)
2025-05-06 18:45:43 +05:30
Rohit Waghchaure
2bd30e3c46 fix: stock reco recalculate qty not works for opening stock reco
(cherry picked from commit 97095c7d24)
2025-05-06 12:57:56 +00:00
rohitwaghchaure
fb56db1166 Merge pull request #47437 from frappe/mergify/bp/version-15-hotfix/pr-47397
fix: precision issue (backport #47397)
2025-05-06 17:50:26 +05:30
Rohit Waghchaure
b6908a79bd fix: precision issue
(cherry picked from commit 69bee93bfd)
2025-05-06 11:59:50 +00:00
mergify[bot]
f4551bb918 feat!: configure which rate is used to auto-update price list (backport #47417)
Co-authored-by: Sagar Vora <16315650+sagarvora@users.noreply.github.com>
2025-05-06 17:00:03 +05:30
mergify[bot]
01e975b481 fix: do not mandate depreciation account for assets without depreciation (backport #47427) (#47428)
fix: do not mandate depreciation account for assets without depreciation (#47427)

(cherry picked from commit 51ea33e743)

Co-authored-by: Khushi Rawat <142375893+khushi8112@users.noreply.github.com>
2025-05-06 15:21:14 +05:30
ruthra kumar
91cbf2ec4f Merge pull request #47426 from frappe/mergify/bp/version-15-hotfix/pr-47337
fix: do not allocate amount when ref's doctype or name are not set (backport #47337)
2025-05-06 15:00:46 +05:30
Abdeali Chharchhoda
c2e36daa32 fix: do not allocate amount when ref's doctype or name are not set
(cherry picked from commit b9a02b466b)
2025-05-06 09:04:52 +00:00
ruthra kumar
74caf8134c Merge pull request #47416 from frappe/mergify/bp/version-15-hotfix/pr-47408
fix: show party type in due date exceeding message (backport #47408)
2025-05-06 14:32:52 +05:30
ruthra kumar
40faa7f7b9 chore: resolve conflicts and pass all parameters 2025-05-06 14:14:41 +05:30
Abdeali Chharchhoda
f73e99e9d2 fix: show party type in due date exceeding message
(cherry picked from commit b6d9134014)

# Conflicts:
#	erpnext/accounts/party.py
2025-05-06 06:28:48 +00:00
ruthra kumar
2d77e056bc Merge pull request #47414 from frappe/mergify/bp/version-15-hotfix/pr-47358
fix: change shipping address fetching condition (backport #47358)
2025-05-06 11:28:56 +05:30
Vimal
0aabe4fd1e fix: change shipping address fetching condition
(cherry picked from commit 0b4add2f2b)
2025-05-06 05:29:00 +00:00
marination
f94a14c06a fix: Headline rendered twice on first save
- `refresh` gets triggered twice and that renders the note twice
- Remove any existing note before rendering

(cherry picked from commit bf62f9ad57)
2025-05-05 16:59:18 +00:00
marination
d9636018f5 fix: Treat rows as Unit Price rows only until the qty is 0
- The unit price check should depend on the row qty being 0
- Once the row ceases to be 0, it is treated as an ordinary row
- test: PO, SO and Quotation

(cherry picked from commit 0447c7be0a)

# Conflicts:
#	erpnext/selling/doctype/quotation/test_quotation.py
#	erpnext/selling/doctype/sales_order/test_sales_order.py
2025-05-05 16:59:17 +00:00
marination
2d96a62530 test: Sales Order + fix: Mapping of Items from Quotation & SO
(cherry picked from commit 55981c8358)

# Conflicts:
#	erpnext/selling/doctype/sales_order/test_sales_order.py
2025-05-05 16:59:17 +00:00
marination
eba73df88e test: Purchase Order with Unit Price Items
- chore: Fix error message in accounts controller

(cherry picked from commit eea758f5b2)

# Conflicts:
#	erpnext/buying/doctype/purchase_order/test_purchase_order.py
#	erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py
2025-05-05 16:59:16 +00:00
marination
c19065e675 test: Zero Qty in RFQ and Supplier Quotation
(cherry picked from commit 8f96c0b546)

# Conflicts:
#	erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py
#	erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py
2025-05-05 16:59:16 +00:00
marination
f8fa775af3 feat: Unit Price Items in Buying (RFQ, SQ, PO)
- chore: Extract `set_unit_price_items_note` into a util

(cherry picked from commit e403d3f153)

# Conflicts:
#	erpnext/buying/doctype/buying_settings/buying_settings.json
#	erpnext/buying/doctype/purchase_order/purchase_order.json
#	erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
#	erpnext/selling/doctype/quotation/quotation.json
#	erpnext/selling/doctype/selling_settings/selling_settings.json
2025-05-05 16:59:16 +00:00
marination
91e167fe72 fix: Linters
(cherry picked from commit 71f65bab5e)

# Conflicts:
#	erpnext/selling/doctype/sales_order/sales_order.py
2025-05-05 16:59:15 +00:00
marination
33366fce6c feat: Unit Price Contract
(cherry picked from commit c1e4e7af28)

# Conflicts:
#	erpnext/controllers/accounts_controller.py
#	erpnext/selling/doctype/quotation/quotation.json
#	erpnext/selling/doctype/sales_order/sales_order.py
#	erpnext/selling/doctype/selling_settings/selling_settings.json
2025-05-05 16:59:15 +00:00
mergify[bot]
8d1e855dc8 fix: rename unchanged group_by filter related to general ledger report (backport #47366) (#47405)
fix: rename unchanged group_by filter related to general ledger report (#47366)

(cherry picked from commit 3de249dcba)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-05-05 18:01:51 +05:30
mergify[bot]
0e5c709f7b fix: backward compatibility for renamed group_by filter on reports (backport #47362) (#47403)
fix: backward compatibility for renamed group_by filter on reports (#47362)

* fix: backward compatibility for renamed group_by filter in general ledger report

* fix: backward compatibility for renamed group_by filter in supplier quotation comparison report

(cherry picked from commit d4ffa54136)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-05-05 18:01:29 +05:30
mergify[bot]
21612fc230 fix: 'time to resolve: failed' on issue (backport #47406) (#47407)
fix: 'time to resolve: failed' on issue (#47406)

* fix: 'time to resolve: failed' on issue

* fix: sla_resolution_date

(cherry picked from commit 45393d51a2)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-05-05 17:50:36 +05:30
mergify[bot]
afb44a677c fix: update accounts on change of mode of payment in sales invoice payment (backport #47381) (#47400)
* fix: update accounts on change of mode of payment in sales invoice payment (#47381)

* fix: update accounts on change of mode of payment in sales invoice payment

* test: fixed tests

(cherry picked from commit 8067799692)

# Conflicts:
#	erpnext/accounts/doctype/mode_of_payment/test_mode_of_payment.py
#	erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
#	erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py

* chore: resolve conflict

* chore: remove unused library

* chore: resolve conflict

* chore: resolve conflict

* chore: resolve linter issue

---------

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-05-05 16:35:31 +05:30
ruthra kumar
4f6aee3f22 Merge pull request #47399 from frappe/mergify/bp/version-15-hotfix/pr-47145
refactor: make AR / AP report more memory efficient (backport #47145)
2025-05-05 16:03:36 +05:30
ruthra kumar
fc1b1ca5e2 chore: resolve conflict 2025-05-05 15:47:39 +05:30
ruthra kumar
f69b8d7e2d refactor: set default for fetch methods
(cherry picked from commit ca1e81e1b5)
2025-05-05 10:14:49 +00:00
ruthra kumar
2147441e64 refactor: use fetch method based on configuration
(cherry picked from commit b5bb6f3508)
2025-05-05 10:14:49 +00:00
ruthra kumar
5e5cf68b32 refactor: configurable fetch method for AR / AP report
(cherry picked from commit 66fd639b52)

# Conflicts:
#	erpnext/accounts/doctype/accounts_settings/accounts_settings.json
2025-05-05 10:14:49 +00:00
ruthra kumar
7c8245d299 refactor: use unbuffered cursor for fetching
(cherry picked from commit 08903459c2)
2025-05-05 10:14:48 +00:00
rohitwaghchaure
a4c9707fdf Merge pull request #47390 from frappe/mergify/bp/version-15-hotfix/pr-47376
fix: validation for difference account (backport #47376)
2025-05-05 14:11:07 +05:30
Rohit Waghchaure
f4a43d07b0 fix: validation for difference account
(cherry picked from commit fb819c558e)
2025-05-03 07:52:58 +00:00
Frappe PR Bot
c1ed750bcb chore(release): Bumped to Version 15.60.1
## [15.60.1](https://github.com/frappe/erpnext/compare/v15.60.0...v15.60.1) (2025-05-02)

### Bug Fixes

* not able to submit the stock entry ([#47383](https://github.com/frappe/erpnext/issues/47383)) ([73a418a](73a418a2bd))
2025-05-02 13:44:13 +00:00
rohitwaghchaure
1d139eb94a Merge pull request #47384 from frappe/mergify/bp/version-15/pr-47383
fix: not able to submit the stock entry (backport #47383)
2025-05-02 19:12:43 +05:30
rohitwaghchaure
73a418a2bd fix: not able to submit the stock entry (#47383)
(cherry picked from commit 035394ae6a)
2025-05-02 13:06:32 +00:00
rohitwaghchaure
035394ae6a fix: not able to submit the stock entry (#47383) 2025-05-02 18:34:47 +05:30
mergify[bot]
1ef7da837f fix: completed transactions showing in the list (backport #47374) (#47379)
fix: completed transactions showing in the list (#47374)

(cherry picked from commit 97db9da10e)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-02 15:28:45 +05:30
mergify[bot]
85a8adf804 fix: renaming group by fieldname and value in reports (backport #47352) (#47360)
* fix: renaming group by fieldname and value in reports (#47352)

* fix: renaming in general ledger report

* fix: renaming in supplier quotation comparison report

* fix: renaming group by to categorize by in process statement of accounts

* fix: added patch

* fix: patch update to all documents

* chore: added patches to patch.txt

* chore: removing patch from v14

(cherry picked from commit 13a84e7f82)

# Conflicts:
#	erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json

* chore: resolve conflict

---------

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-04-30 17:19:43 +05:30
Mihir Kandoi
d3445b3079 Merge pull request #47357 from frappe/mergify/bp/version-15-hotfix/pr-47336
refactor: portal query in timesheet.py (backport #47336)
2025-04-30 16:35:11 +05:30
Mihir Kandoi
ada7821a49 refactor: portal query in timesheet.py (#47336)
* refactor: portal query in timesheet.py

* fix: use criterion.any to fix query

(cherry picked from commit 4fc7a8b71d)
2025-04-30 10:45:02 +00:00
Nihantra C. Patel
3f7dcedf3d Merge pull request #47354 from frappe/mergify/bp/version-15-hotfix/pr-47351
fix: party name in Ledger Summary (backport #47351)
2025-04-30 14:05:47 +05:30
Nihantra Patel
4fc14b3097 fix: party name in Ledger Summary
(cherry picked from commit 70bc86a4c6)
2025-04-30 08:13:52 +00:00
mergify[bot]
4ef2b77973 fix: warning message before changing the valuation method (backport #47340) (#47342)
fix: warning message before changing the valuation method (#47340)

(cherry picked from commit ffdc4347e8)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-04-30 08:45:39 +05:30
Frappe PR Bot
96996bd8a9 chore(release): Bumped to Version 15.60.0
# [15.60.0](https://github.com/frappe/erpnext/compare/v15.59.0...v15.60.0) (2025-04-29)

### Bug Fixes

* add transaction_date in field_no_map when creating PO from SQ (backport [#47257](https://github.com/frappe/erpnext/issues/47257)) ([#47313](https://github.com/frappe/erpnext/issues/47313)) ([afb67f1](afb67f1f0c))
* allow selling asset at zero rate (backport [#47326](https://github.com/frappe/erpnext/issues/47326)) ([#47332](https://github.com/frappe/erpnext/issues/47332)) ([171b687](171b687611))
* allow to change valuation method from FIFO to Moving Average ([b2294ed](b2294ed6e3))
* allow to make quality inspection after Purchase / Delivery ([e0cea49](e0cea49236))
* cancel pos closing entry failure for return pos invoices (backport [#47248](https://github.com/frappe/erpnext/issues/47248)) ([#47249](https://github.com/frappe/erpnext/issues/47249)) ([10d843e](10d843e490))
* commas in rfq portal js ([954fec1](954fec16f4))
* compare total debit/credit with precision for Inter Company Journal Entry ([0927155](0927155171))
* consolidating pos invoices on the basis of accounting dimensions (backport [#46961](https://github.com/frappe/erpnext/issues/46961)) ([#47265](https://github.com/frappe/erpnext/issues/47265)) ([f8da159](f8da1599bb))
* correct query for dispatch_address; remove unnecessary code; increase reusability; ([ac3b2ba](ac3b2ba003))
* do not check for permission if values are not changed in employee doctype ([#47238](https://github.com/frappe/erpnext/issues/47238)) ([0caba9f](0caba9f70d))
* enable use serial / batch fields on batch selection ([925cc40](925cc40efa))
* enhance dispatch address query logic and add supplier address query ([290f0b9](290f0b94e5))
* fix sub assembly qty calculation in production plan when bom level >= 1 (backport [#47296](https://github.com/frappe/erpnext/issues/47296)) ([#47315](https://github.com/frappe/erpnext/issues/47315)) ([d15b7ca](d15b7ca9af))
* make asset quantity and amount editable (backport [#47226](https://github.com/frappe/erpnext/issues/47226)) ([#47227](https://github.com/frappe/erpnext/issues/47227)) ([c140fd0](c140fd0f12))
* map dispatch address correctly for inter company transactions ([d8c0e71](d8c0e7156e))
* missing else statement ([8a30a31](8a30a31302))
* **payment request:** get advance amount based on transaction currency ([c2235e2](c2235e2d17))
* **PE:** Set account types in get_payment_entry (backport [#47246](https://github.com/frappe/erpnext/issues/47246)) ([#47266](https://github.com/frappe/erpnext/issues/47266)) ([3e733f6](3e733f6ba1))
* prevent cancellation of last asset movement (backport [#47291](https://github.com/frappe/erpnext/issues/47291)) ([#47312](https://github.com/frappe/erpnext/issues/47312)) ([2edd12b](2edd12b26d))
* price currency in supplier quotation comparison ([6b1b30a](6b1b30a4a6))
* prohibit consolidated sales invoice return (backport [#47251](https://github.com/frappe/erpnext/issues/47251)) ([#47252](https://github.com/frappe/erpnext/issues/47252)) ([4bcea55](4bcea55563))
* QI reference not set if 'Action If Quality Inspection Is Not Sub… (backport [#47294](https://github.com/frappe/erpnext/issues/47294)) ([#47295](https://github.com/frappe/erpnext/issues/47295)) ([b0399fe](b0399fe948))
* Re-insert missing "Serial No Warranty Expiry" Report ([727c32d](727c32d789))
* remove invalid email account creation (backport [#47318](https://github.com/frappe/erpnext/issues/47318)) ([#47323](https://github.com/frappe/erpnext/issues/47323)) ([fc8a8b5](fc8a8b5433))
* remove use of cur_frm ([5c300b8](5c300b893b))
* **Rename Tool:** allow more than 500 rows (backport [#47117](https://github.com/frappe/erpnext/issues/47117)) ([#47225](https://github.com/frappe/erpnext/issues/47225)) ([c0ae133](c0ae1336f4))
* require email OR phone in shipment doctype not both (backport [#47300](https://github.com/frappe/erpnext/issues/47300)) ([#47330](https://github.com/frappe/erpnext/issues/47330)) ([0056fb1](0056fb1d0f))
* set billing hours to hours ([0763a8d](0763a8d42d))
* set billing hours to hours in timesheet (backport [#47289](https://github.com/frappe/erpnext/issues/47289)) ([#47290](https://github.com/frappe/erpnext/issues/47290)) ([74bdc82](74bdc82bfa))
* update additional cost and total asset cost after asset repair (backport [#47233](https://github.com/frappe/erpnext/issues/47233)) ([#47235](https://github.com/frappe/erpnext/issues/47235)) ([4a29a54](4a29a54804))
* update billing hours when hours is changed ([a9df1f5](a9df1f5f6b))
* update quantity validation using asset quantity field instead of… (backport [#46731](https://github.com/frappe/erpnext/issues/46731)) ([#47284](https://github.com/frappe/erpnext/issues/47284)) ([2e6112f](2e6112f21b))
* validate if from and to time are present on submission of job card ([#47325](https://github.com/frappe/erpnext/issues/47325)) ([d640c79](d640c79c1c))
* validation if no stock ledger entries against stock reco (backport [#47292](https://github.com/frappe/erpnext/issues/47292)) ([#47293](https://github.com/frappe/erpnext/issues/47293)) ([91bcefe](91bcefef8c))

### Features

* add dispatch address fields to purchase doctypes ([5f101e7](5f101e7635))
* add dispatch address support in party details and controllers ([1fe1563](1fe1563dab))
* add display dispatch address when dispatch address is selected ([93ea2f9](93ea2f93b6))
* change sabb qty automatically incase of internal transfer PR if sabb only has 1 batch ([#47256](https://github.com/frappe/erpnext/issues/47256)) ([9495a2a](9495a2ac9d))
2025-04-29 13:12:18 +00:00
ruthra kumar
a9e40bc0d8 Merge pull request #47328 from frappe/version-15-hotfix
chore: release v15
2025-04-29 18:40:46 +05:30
mergify[bot]
d15b7ca9af fix: fix sub assembly qty calculation in production plan when bom level >= 1 (backport #47296) (#47315)
* fix: fix sub assembly qty calculation in production plan when bom level >= 1

(cherry picked from commit bfc4ce1d5d)

* fix: logical error

(cherry picked from commit ee10afc074)

---------

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-04-29 18:12:36 +05:30
mergify[bot]
171b687611 fix: allow selling asset at zero rate (backport #47326) (#47332)
fix: allow selling asset at zero rate (#47326)

(cherry picked from commit 05afad78fc)

Co-authored-by: Khushi Rawat <142375893+khushi8112@users.noreply.github.com>
2025-04-29 17:12:51 +05:30
ruthra kumar
cc8418b7e4 Merge pull request #47329 from frappe/mergify/bp/version-15-hotfix/pr-47325
fix: validate if from and to time are present on submission of job card (backport #47325)
2025-04-29 16:46:34 +05:30
mergify[bot]
0056fb1d0f fix: require email OR phone in shipment doctype not both (backport #47300) (#47330)
fix: require email OR phone in shipment doctype not both (#47300)

(cherry picked from commit fc02a6510e)

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-04-29 16:27:56 +05:30
Mihir Kandoi
d640c79c1c fix: validate if from and to time are present on submission of job card (#47325)
(cherry picked from commit 7499c25a3c)
2025-04-29 10:52:56 +00:00
mergify[bot]
2edd12b26d fix: prevent cancellation of last asset movement (backport #47291) (#47312)
fix: prevent cancellation of last asset movement (#47291)

* fix: prevent cancellation of last asset movement

* test: movement cancellation

* fix: allow cancellation of asset movement when cancelling asset

(cherry picked from commit 9dee4ac891)

Co-authored-by: Khushi Rawat <142375893+khushi8112@users.noreply.github.com>
2025-04-29 12:51:18 +05:30
ruthra kumar
71482261c7 Merge pull request #47324 from frappe/mergify/bp/version-15-hotfix/pr-47241
fix: compare total debit/credit with precision for Inter Company Journal Entry (backport #47241)
2025-04-29 12:43:42 +05:30
Mihir Kandoi
9df5727ea4 Merge pull request #47317 from frappe/mergify/bp/version-15-hotfix/pr-47256
feat: change sabb qty automatically incase of internal transfer PR if… (backport #47256)
2025-04-29 12:40:53 +05:30
mergify[bot]
fc8a8b5433 fix: remove invalid email account creation (backport #47318) (#47323)
fix: remove invalid email account creation (#47318)

(cherry picked from commit 7423e4187f)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-04-29 12:40:45 +05:30
Mihir Kandoi
409831183b Merge pull request #47314 from frappe/mergify/bp/version-15-hotfix/pr-47234
fix: price currency in supplier quotation comparison (backport #47234)
2025-04-29 12:40:31 +05:30
mergify[bot]
afb67f1f0c fix: add transaction_date in field_no_map when creating PO from SQ (backport #47257) (#47313)
* fix: add transaction_date in field_no_map when creating PO from SQ

(cherry picked from commit 3790c6c551)

* fix: test case

(cherry picked from commit acd1529780)

# Conflicts:
#	erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py

* fix: remove unused import

(cherry picked from commit 9e640341fd)

# Conflicts:
#	erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py

* chore: fix conflicts

* chore: remove unused imports

---------

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-04-29 12:40:10 +05:30
ruthra kumar
7bc39349b0 Merge pull request #47321 from frappe/mergify/bp/version-15-hotfix/pr-47231
fix(payment request): get advance amount based on transaction currency (backport #47231)
2025-04-29 12:25:54 +05:30
ljain112
0927155171 fix: compare total debit/credit with precision for Inter Company Journal Entry
(cherry picked from commit 5fe247557e)
2025-04-29 06:48:08 +00:00
venkat102
c2235e2d17 fix(payment request): get advance amount based on transaction currency
(cherry picked from commit b570d97b4d)
2025-04-29 06:37:54 +00:00
Mihir Kandoi
9495a2ac9d feat: change sabb qty automatically incase of internal transfer PR if sabb only has 1 batch (#47256)
* feat: change sabb qty automatically incase of internal transfer PR if sabb only has 1 batch

* fix: prevent creation of SABB on every save

* perf: optimize code

* fix: remove unnecessary conditon

* refactor: change if to elif

* fix: remove dn_item_qty and set to item.qty

* test: added test

(cherry picked from commit 47927b38a9)
2025-04-29 06:17:04 +00:00
Mihir Kandoi
cb61e0bd18 Merge pull request #47316 from frappe/mergify/bp/version-15-hotfix/pr-47302
fix: commas in rfq portal js (backport #47302)
2025-04-29 11:46:31 +05:30
Mihir Kandoi
954fec16f4 fix: commas in rfq portal js
(cherry picked from commit bd727e069b)
2025-04-29 06:07:50 +00:00
Mihir Kandoi
6b1b30a4a6 fix: price currency in supplier quotation comparison
(cherry picked from commit 88926eb2a7)
2025-04-29 06:06:38 +00:00
mergify[bot]
b0399fe948 fix: QI reference not set if 'Action If Quality Inspection Is Not Sub… (backport #47294) (#47295)
fix: QI reference not set if 'Action If Quality Inspection Is Not Sub… (#47294)

fix: qi reference not set if 'Action If Quality Inspection Is Not Submitted' is blank
(cherry picked from commit 0701a8cf5a)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-04-28 22:01:57 +05:30
mergify[bot]
91bcefef8c fix: validation if no stock ledger entries against stock reco (backport #47292) (#47293)
fix: validation if no stock ledger entries against stock reco (#47292)

(cherry picked from commit 3d36d0b1df)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-04-28 19:38:27 +05:30
mergify[bot]
74bdc82bfa fix: set billing hours to hours in timesheet (backport #47289) (#47290)
* fix: set billing hours to hours

(cherry picked from commit 0763a8d42d)

* fix: update billing hours when hours is changed

(cherry picked from commit a9df1f5f6b)

* fix: missing else statement

(cherry picked from commit 8a30a31302)

---------

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-04-28 16:33:40 +05:30
rohitwaghchaure
5b32bb7468 Merge pull request #47289 from frappe/st37102-2
fix: set billing hours to hours in timesheet
2025-04-28 16:27:33 +05:30
Mihir Kandoi
8a30a31302 fix: missing else statement 2025-04-28 16:08:40 +05:30
Mihir Kandoi
a9df1f5f6b fix: update billing hours when hours is changed 2025-04-28 16:07:54 +05:30
Mihir Kandoi
0763a8d42d fix: set billing hours to hours 2025-04-28 15:43:13 +05:30
rohitwaghchaure
c02a4a4591 Merge pull request #47286 from frappe/mergify/bp/version-15-hotfix/pr-47285
fix: allow to make quality inspection after Purchase / Delivery (backport #47285)
2025-04-28 15:29:16 +05:30
ruthra kumar
1cbcf7532c Merge pull request #47281 from frappe/mergify/bp/version-15-hotfix/pr-46993
feat: add dispatch address fields to purchase doctypes (backport #46993)
2025-04-28 14:47:02 +05:30
Rohit Waghchaure
e0cea49236 fix: allow to make quality inspection after Purchase / Delivery
(cherry picked from commit fad1a32e63)
2025-04-28 09:00:14 +00:00
mergify[bot]
2e6112f21b fix: update quantity validation using asset quantity field instead of… (backport #46731) (#47284)
* fix: update quantity validation using asset quantity field instead of… (#46731)

* fix: update quantity validation using asset quantity field instead of total records

* fix: update throw message

(cherry picked from commit eae08bc619)

# Conflicts:
#	erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py

* chore: resolved conflicts

---------

Co-authored-by: l0gesh29 <logeshperiyasamy24@gmail.com>
Co-authored-by: Khushi Rawat <142375893+khushi8112@users.noreply.github.com>
2025-04-28 14:18:51 +05:30
ruthra kumar
feb4038c06 chore: resolve conflicts 2025-04-28 11:36:24 +05:30
Smit Vora
d8c0e7156e fix: map dispatch address correctly for inter company transactions
(cherry picked from commit ceaba4220b)
2025-04-28 05:28:20 +00:00
Smit Vora
7baa8f50fb refactor: set address details for transactions
(cherry picked from commit fb3b7d8c34)
2025-04-28 05:28:20 +00:00
Smit Vora
62261a276f refactor: address field position
(cherry picked from commit 8ccd7a3e61)

# Conflicts:
#	erpnext/public/scss/erpnext.scss
2025-04-28 05:28:20 +00:00
Karm Soni
ac3b2ba003 fix: correct query for dispatch_address; remove unnecessary code; increase reusability;
(cherry picked from commit 999ffe86a7)
2025-04-28 05:28:19 +00:00
Karm Soni
93ea2f93b6 feat: add display dispatch address when dispatch address is selected
(cherry picked from commit d12998e524)
2025-04-28 05:28:19 +00:00
Karm Soni
5c300b893b fix: remove use of cur_frm
(cherry picked from commit c4bd3123fb)
2025-04-28 05:28:19 +00:00
Karm Soni
290f0b94e5 fix: enhance dispatch address query logic and add supplier address query
(cherry picked from commit 9a859e54b6)
2025-04-28 05:28:18 +00:00
Karm Soni
1fe1563dab feat: add dispatch address support in party details and controllers
(cherry picked from commit 53d0b7be23)
2025-04-28 05:28:18 +00:00
Karm Soni
5f101e7635 feat: add dispatch address fields to purchase doctypes
(cherry picked from commit 54b5205221)

# Conflicts:
#	erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
#	erpnext/buying/doctype/purchase_order/purchase_order.json
2025-04-28 05:28:18 +00:00
mergify[bot]
3e733f6ba1 fix(PE): Set account types in get_payment_entry (backport #47246) (#47266)
Co-authored-by: Corentin Forler <10946971+cogk@users.noreply.github.com>
fix(PE): Set account types in get_payment_entry (#47246)
2025-04-27 15:24:59 +02:00
rohitwaghchaure
5c4dc7a16e Merge pull request #47277 from frappe/mergify/bp/version-15-hotfix/pr-47259
fix: enable use serial / batch fields on batch selection (backport #47259)
2025-04-27 18:41:32 +05:30
Rohit Waghchaure
925cc40efa fix: enable use serial / batch fields on batch selection
(cherry picked from commit a4471865a9)
2025-04-27 13:06:21 +00:00
rohitwaghchaure
d947beec88 Merge pull request #47276 from frappe/mergify/bp/version-15-hotfix/pr-47268
fix: allow to change valuation method from FIFO to Moving Average (backport #47268)
2025-04-27 18:23:16 +05:30
Rohit Waghchaure
b2294ed6e3 fix: allow to change valuation method from FIFO to Moving Average
(cherry picked from commit b454ed4b8f)
2025-04-27 12:16:36 +00:00
mergify[bot]
f8da1599bb fix: consolidating pos invoices on the basis of accounting dimensions (backport #46961) (#47265)
fix: consolidating pos invoices on the basis of accounting dimensions (#46961)

* fix: consolidating pos invoices on the basis of accounting dimensions

* fix: project field

(cherry picked from commit c85edc3346)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-04-25 17:59:15 +05:30
Marica
636e9e0998 Merge pull request #47261 from frappe/mergify/bp/version-15-hotfix/pr-47232
fix: Re-insert missing "Serial No Warranty Expiry" Report (backport #47232)
2025-04-25 15:13:55 +05:30
marination
727c32d789 fix: Re-insert missing "Serial No Warranty Expiry" Report
(cherry picked from commit deefac0abf)
2025-04-25 09:28:36 +00:00
mergify[bot]
4bcea55563 fix: prohibit consolidated sales invoice return (backport #47251) (#47252)
fix: prohibit consolidated sales invoice return (#47251)

(cherry picked from commit 483c4a3271)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-04-25 11:33:04 +05:30
mergify[bot]
10d843e490 fix: cancel pos closing entry failure for return pos invoices (backport #47248) (#47249)
fix: cancel pos closing entry failure for return pos invoices (#47248)

(cherry picked from commit c8ee5d9a4e)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-04-24 23:23:08 +05:30
Lakshit Jain
0caba9f70d fix: do not check for permission if values are not changed in employee doctype (#47238) 2025-04-24 17:03:30 +02:00
mergify[bot]
4a29a54804 fix: update additional cost and total asset cost after asset repair (backport #47233) (#47235)
fix: update additional cost and total asset cost after asset repair (#47233)

* fix: add consumed stock's cost to the asset value after repair

* fix: do not copy additional cost and total asset cost

(cherry picked from commit ed8a8532e1)

Co-authored-by: Khushi Rawat <142375893+khushi8112@users.noreply.github.com>
2025-04-24 16:36:53 +05:30
mergify[bot]
c140fd0f12 fix: make asset quantity and amount editable (backport #47226) (#47227)
fix: make asset quantity and amount editable (#47226)

(cherry picked from commit 0d53e6ed7c)

Co-authored-by: Khushi Rawat <142375893+khushi8112@users.noreply.github.com>
2025-04-24 11:36:18 +05:30
mergify[bot]
c0ae1336f4 fix(Rename Tool): allow more than 500 rows (backport #47117) (#47225)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix(Rename Tool): allow more than 500 rows (#47117)
2025-04-23 20:26:03 +02:00
Frappe PR Bot
4c3044cd70 chore(release): Bumped to Version 15.59.0
# [15.59.0](https://github.com/frappe/erpnext/compare/v15.58.2...v15.59.0) (2025-04-22)

### Bug Fixes

* `TypeError` in group field filter in supplier ledger summary ([3b349f4](3b349f44b1))
* add group by after user permission condition ([f07c3d9](f07c3d9124))
* backslash in url ([f6edd5a](f6edd5aa7d))
* change get_url_to_form to get_link_to_form ([982a68b](982a68b71a))
* cherry pick ([20aba54](20aba541c4))
* consider per_ordered instead of per_billed when creating PO from MR ([be154a4](be154a469f))
* correct error message in validate_internal_transfer_qty ([b8a7f6d](b8a7f6dac1))
* create default warehouse (backport [#47125](https://github.com/frappe/erpnext/issues/47125)) ([#47131](https://github.com/frappe/erpnext/issues/47131)) ([ad177e0](ad177e08b8))
* disbaled UOM showing in the list ([3d4f3e1](3d4f3e1be7))
* distributed discounts on si ([ad05e6d](ad05e6dec2))
* **Employee:** remove User Permissions if create_user_permission is unchecked ([7ab81b7](7ab81b7e54))
* expense account in stock entry ([2f1f229](2f1f229144))
* get total without rounding off tax amounts for distributing discount (backport [#47155](https://github.com/frappe/erpnext/issues/47155)) ([8050e65](8050e653ab))
* group sub assemblies in production plan ([73683b2](73683b2754))
* import error ([924e9b9](924e9b94b6))
* keep per_billed 100 for billed delivery note after return ([680c221](680c221f05))
* linter ([c58800a](c58800a929))
* logic and added test case ([b3e852a](b3e852adfc))
* Modify .json from desk to change `modified` ([1dc9812](1dc98124dc))
* only update User Permissions if a relevant field has changed ([b0f3d62](b0f3d62dd0))
* pos disable customer selection at payment (backport [#47169](https://github.com/frappe/erpnext/issues/47169)) ([#47170](https://github.com/frappe/erpnext/issues/47170)) ([7adba1f](7adba1f0f3))
* provision to recalculate the qty in the Bin ([5535eb4](5535eb4817))
* rate based on posting date in Tax Withholding Report ([9184c40](9184c40371))
* remove invalid parameter ([2431141](2431141062))
* remove unused import ([4fba4d4](4fba4d49d2))
* respect field "ignore_user_permissions" property in employee query ([a450ce2](a450ce25b9))
* respect mapped accounting dimensions ([846b24b](846b24ba52))
* revert unintended changes ([a09ab90](a09ab902e5))
* set correct paid/receive amount if doc currency is different from party account currency ([5dc63f9](5dc63f97a1))
* set default company address in Sales Doctype on change of company ([05d4c1e](05d4c1e6ca))
* show button only when RFQ is submitted ([9655bfa](9655bfa199))
* test cases ([dedb19e](dedb19e3e9))
* test cases error ([13d3b27](13d3b27a1f))
* update country wise fiscal year (backport [#47141](https://github.com/frappe/erpnext/issues/47141)) ([#47176](https://github.com/frappe/erpnext/issues/47176)) ([390780d](390780d871))
* use get_url_to_form instead ([ad35021](ad35021666))

### Features

* add button to show request for comparison report directly from RFQ ([cb2b956](cb2b9563e0))
* add unit tests for distributed_discount_amount ([6f6574c](6f6574c5ac))

### Reverts

* disable customer if creating from opportunity ([99735e0](99735e0af4))
2025-04-22 13:47:39 +00:00
ruthra kumar
f7efd006c2 Merge pull request #47204 from frappe/version-15-hotfix
chore: release v15
2025-04-22 19:16:15 +05:30
mergify[bot]
8050e653ab fix: get total without rounding off tax amounts for distributing discount (backport #47155)
Co-authored-by: Sagar Vora <16315650+sagarvora@users.noreply.github.com>
2025-04-22 17:53:10 +05:30
ruthra kumar
2ba6c78e5e Merge pull request #47210 from frappe/mergify/bp/version-15-hotfix/pr-47178
fix: keep per_billed 100 for billed delivery note after return (backport #47178)
2025-04-22 17:30:33 +05:30
Sugesh393
04a1578b53 refactor: update base_outstanding calculation
(cherry picked from commit 02356029a8)
2025-04-22 11:42:13 +00:00
Sugesh393
2b05ccfa6f test: add new unit test to keep per_billed 100 for billed delivery note
(cherry picked from commit fe5898a151)
2025-04-22 11:42:12 +00:00
Sugesh393
680c221f05 fix: keep per_billed 100 for billed delivery note after return
(cherry picked from commit 8290a83591)
2025-04-22 11:42:12 +00:00
ruthra kumar
bbbbb4da55 Merge pull request #47209 from frappe/mergify/bp/version-15-hotfix/pr-47183
fix: backslash in url (backport #47183)
2025-04-22 17:07:23 +05:30
ruthra kumar
e2f8ca5f87 chore: resolve conflict 2025-04-22 16:46:57 +05:30
ruthra kumar
6671f4df41 Merge pull request #47208 from frappe/mergify/bp/version-15-hotfix/pr-46717
fix: respect field "ignore_user_permissions" property in employee query (backport #46717)
2025-04-22 16:40:28 +05:30
Mihir Kandoi
4fba4d49d2 fix: remove unused import
(cherry picked from commit c3d172fac3)
2025-04-22 10:46:37 +00:00
Mihir Kandoi
982a68b71a fix: change get_url_to_form to get_link_to_form
(cherry picked from commit 5d07beee61)
2025-04-22 10:46:37 +00:00
Mihir Kandoi
a09ab902e5 fix: revert unintended changes
(cherry picked from commit eaaf34cda6)

# Conflicts:
#	erpnext/stock/doctype/material_request/material_request.json
2025-04-22 10:46:37 +00:00
Mihir Kandoi
ad35021666 fix: use get_url_to_form instead
(cherry picked from commit 7a82b37f76)
2025-04-22 10:46:36 +00:00
Mihir Kandoi
f6edd5aa7d fix: backslash in url
(cherry picked from commit ecf15130ba)

# Conflicts:
#	erpnext/stock/doctype/material_request/material_request.json
2025-04-22 10:46:36 +00:00
ljain112
e752f3f914 chore: added test case for employee query with user permissions
(cherry picked from commit 4be975f87c)

# Conflicts:
#	erpnext/controllers/tests/test_queries.py
2025-04-22 16:00:00 +05:30
ruthra kumar
31af933c1c Merge pull request #47207 from frappe/mergify/bp/version-15-hotfix/pr-47171
fix: set correct paid/receive amount if doc currency is different from party account currency (backport #47171)
2025-04-22 15:58:28 +05:30
ljain112
a450ce25b9 fix: respect field "ignore_user_permissions" property in employee query
(cherry picked from commit 91d7bc55be)
2025-04-22 10:12:30 +00:00
Soham Kulkarni
e152c72a7b Merge pull request #47201 from frappe/mergify/bp/version-15-hotfix/pr-47175
fix: add grand_total to show correct status in quick list widget (backport #47175)
2025-04-22 15:41:49 +05:30
ljain112
5dc63f97a1 fix: set correct paid/receive amount if doc currency is different from party account currency
(cherry picked from commit 9612521894)
2025-04-22 10:07:17 +00:00
rohitwaghchaure
8bc00ffbb4 Merge pull request #47206 from frappe/mergify/bp/version-15-hotfix/pr-47184
feat: add button to view Supplier Quotation Comparison directly from RFQ (backport #47184)
2025-04-22 15:16:01 +05:30
Mihir Kandoi
9655bfa199 fix: show button only when RFQ is submitted
(cherry picked from commit ef57d2b328)
2025-04-22 09:43:41 +00:00
Mihir Kandoi
cb2b9563e0 feat: add button to show request for comparison report directly from RFQ
(cherry picked from commit b4aa88b59b)
2025-04-22 09:43:41 +00:00
ruthra kumar
bb71b91d4a Merge pull request #47203 from frappe/mergify/bp/version-15-hotfix/pr-47180
fix: set default company address in selling Doctype on change of company (backport #47180)
2025-04-22 15:12:20 +05:30
ljain112
05d4c1e6ca fix: set default company address in Sales Doctype on change of company
(cherry picked from commit a31075692c)
2025-04-22 08:59:04 +00:00
Soham Kulkarni
d7556069e4 Merge pull request #47175 from sokumon/purchase-receipt-quick-list
fix: add grand_total to show correct status in quick list widget
(cherry picked from commit 68ca4a77c9)
2025-04-22 08:52:51 +00:00
ruthra kumar
a3821cf182 Merge pull request #47199 from frappe/mergify/bp/version-15-hotfix/pr-47138
fix: rate based on posting date in Tax Withholding Report (backport #47138)
2025-04-22 14:07:08 +05:30
ruthra kumar
18e3171cc9 Merge pull request #47197 from frappe/mergify/bp/version-15-hotfix/pr-47191
fix: expense account in stock entry (backport #47191)
2025-04-22 13:34:01 +05:30
ljain112
1f8fce253d chore: added test case for date period in multiple tax withholding rules
(cherry picked from commit 515fe340a8)

# Conflicts:
#	erpnext/accounts/report/tax_withholding_details/test_tax_withholding_details.py
2025-04-22 13:31:28 +05:30
ljain112
9184c40371 fix: rate based on posting date in Tax Withholding Report
(cherry picked from commit a32a79e90a)
2025-04-22 07:59:58 +00:00
Rohit Waghchaure
2f1f229144 fix: expense account in stock entry
(cherry picked from commit 75874b4986)
2025-04-22 07:46:37 +00:00
ruthra kumar
393e4462f8 Merge pull request #47195 from frappe/mergify/bp/version-15-hotfix/pr-47124
fix: `TypeError` in group field filter in supplier ledger summary (backport #47124)
2025-04-22 12:44:05 +05:30
ljain112
3b349f44b1 fix: TypeError in group field filter in supplier ledger summary
(cherry picked from commit 872e94a316)
2025-04-22 06:51:57 +00:00
rohitwaghchaure
c430ce96b3 Merge pull request #47185 from frappe/mergify/bp/version-15-hotfix/pr-47144
fix: provision to recalculate the qty in the Bin (backport #47144)
2025-04-22 12:20:46 +05:30
rohitwaghchaure
7b5297bb7f Merge pull request #47188 from frappe/mergify/bp/version-15-hotfix/pr-47186
fix: disabled UOM showing in the list (backport #47186)
2025-04-22 12:20:34 +05:30
Rohit Waghchaure
3d4f3e1be7 fix: disbaled UOM showing in the list
(cherry picked from commit 3745825052)
2025-04-21 16:43:17 +00:00
Rohit Waghchaure
5535eb4817 fix: provision to recalculate the qty in the Bin
(cherry picked from commit 36081413d8)
2025-04-21 15:49:11 +00:00
ruthra kumar
af35e43555 Merge pull request #47095 from frappe/mergify/bp/version-15-hotfix/pr-47007
chore: Fix typo "Item Wise Tax Detail " (backport #47007)
2025-04-21 16:50:22 +05:30
ruthra kumar
f53a45cfef chore: resolve conflict 2025-04-21 16:30:20 +05:30
ruthra kumar
19045bcace Merge pull request #47177 from frappe/mergify/bp/version-15-hotfix/pr-47067
fix: correct error message in validate_internal_transfer_qty (backport #47067)
2025-04-21 16:24:11 +05:30
ljain112
b8a7f6dac1 fix: correct error message in validate_internal_transfer_qty
(cherry picked from commit 5063f1174e)
2025-04-21 10:28:27 +00:00
ruthra kumar
f2c3150687 Merge pull request #47013 from frappe/mergify/bp/version-15-hotfix/pr-45924
fix(Employee): remove User Permissions if create_user_permission is unchecked (backport #45924)
2025-04-21 15:55:03 +05:30
mergify[bot]
390780d871 fix: update country wise fiscal year (backport #47141) (#47176)
fix: update country wise fiscal year (#47141)

(cherry picked from commit cb2ad4acdb)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-04-21 14:26:47 +05:30
mergify[bot]
7adba1f0f3 fix: pos disable customer selection at payment (backport #47169) (#47170)
fix: pos disable customer selection at payment (#47169)

(cherry picked from commit f52cbf6165)

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-04-21 11:56:54 +05:30
Sagar Vora
d6d042868d Merge pull request #43067 from frappe/mergify/bp/version-15-hotfix/pr-41721
fix: distributed discounts on si (backport #41721)
2025-04-19 16:35:12 +05:30
Sagar Vora
f764b9713b Merge branch 'version-15-hotfix' into mergify/bp/version-15-hotfix/pr-41721 2025-04-19 16:18:37 +05:30
Sagar Vora
16877fade8 Merge pull request #47157 from frappe/mergify/bp/version-15-hotfix/pr-47154
fix: respect mapped accounting dimensions (backport #47154)
2025-04-19 13:04:01 +05:30
Sagar Vora
846b24ba52 fix: respect mapped accounting dimensions
(cherry picked from commit 7dbe27da19)
2025-04-19 07:22:45 +00:00
mergify[bot]
451b1a19a8 chore: migrate pre-commit config (backport #47132) (#47134)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2025-04-17 14:18:00 +02:00
mergify[bot]
ad177e08b8 fix: create default warehouse (backport #47125) (#47131)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix: create default warehouse (#47125)
2025-04-17 13:40:05 +02:00
Frappe PR Bot
00a8503dd7 chore(release): Bumped to Version 15.58.2
## [15.58.2](https://github.com/frappe/erpnext/compare/v15.58.1...v15.58.2) (2025-04-17)

### Bug Fixes

* add group by after user permission condition ([0287f34](0287f34928))
2025-04-17 10:54:22 +00:00
ruthra kumar
76a2eb69a0 Merge pull request #47127 from frappe/mergify/bp/version-15/pr-47118
fix: add group by after user permission condition (backport #47118)
2025-04-17 16:22:18 +05:30
ruthra kumar
673694ae48 Merge pull request #47128 from frappe/mergify/bp/version-15-hotfix/pr-47118
fix: add group by after user permission condition (backport #47118)
2025-04-17 16:22:07 +05:30
venkat102
0287f34928 fix: add group by after user permission condition
(cherry picked from commit 756d496235)
2025-04-17 10:36:57 +00:00
venkat102
f07c3d9124 fix: add group by after user permission condition
(cherry picked from commit 756d496235)
2025-04-17 10:36:57 +00:00
rohitwaghchaure
d18266d839 Merge pull request #47048 from frappe/mergify/bp/version-15-hotfix/pr-46938
fix: group sub assemblies in production plan (backport #46938)
2025-04-17 15:31:08 +05:30
rohitwaghchaure
0c714e2bd9 Merge pull request #47114 from frappe/mergify/bp/version-15-hotfix/pr-47050
fix: consider per_ordered instead of per_billed when creating PO from MR (backport #47050)
2025-04-16 22:49:24 +05:30
Mihir Kandoi
20aba541c4 fix: cherry pick 2025-04-16 20:32:05 +05:30
Mihir Kandoi
be154a469f fix: consider per_ordered instead of per_billed when creating PO from MR
(cherry picked from commit 5a524854de)

# Conflicts:
#	erpnext/stock/doctype/material_request/material_request.js
2025-04-16 10:58:52 +00:00
Frappe PR Bot
741f29e57a chore(release): Bumped to Version 15.58.1
## [15.58.1](https://github.com/frappe/erpnext/compare/v15.58.0...v15.58.1) (2025-04-16)

### Bug Fixes

* revert [#46903](https://github.com/frappe/erpnext/issues/46903) - disable changing customer on opportunity ([5c04d18](5c04d183bf))
2025-04-16 05:15:20 +00:00
ruthra kumar
5090108718 Merge pull request #47110 from frappe/mergify/bp/version-15/pr-47108
revert: disable customer if creating from opportunity (backport #47108)
2025-04-16 10:44:01 +05:30
Shariq Ansari
5c04d183bf fix: revert #46903 - disable changing customer on opportunity
(cherry picked from commit fc16199a49)
2025-04-16 10:38:17 +05:30
Shariq Ansari
bb6d6c3edf Merge pull request #47109 from frappe/mergify/bp/version-15-hotfix/pr-47108 2025-04-16 10:22:33 +05:30
Shariq Ansari
99735e0af4 revert: disable customer if creating from opportunity
(cherry picked from commit fc16199a49)
2025-04-16 04:51:33 +00:00
marination
1dc98124dc fix: Modify .json from desk to change modified
(cherry picked from commit be556167b1)

# Conflicts:
#	erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json
2025-04-15 11:32:47 +00:00
Himanshu Shivhare
5cb8e5dfbd chore: Fix typo "Item Wise Tax Detail "
(cherry picked from commit 9624d56abd)
2025-04-15 11:32:46 +00:00
Mihir Kandoi
c58800a929 fix: linter 2025-04-14 13:33:48 +05:30
Mihir Kandoi
924e9b94b6 fix: import error 2025-04-14 13:28:06 +05:30
Mihir Kandoi
13d3b27a1f fix: test cases error
(cherry picked from commit 8df18762a9)
2025-04-14 06:41:28 +00:00
Mihir Kandoi
dedb19e3e9 fix: test cases
(cherry picked from commit a7394329ca)
2025-04-14 06:41:27 +00:00
Mihir Kandoi
b3e852adfc fix: logic and added test case
(cherry picked from commit f071255340)
2025-04-14 06:41:27 +00:00
Mihir Kandoi
73683b2754 fix: group sub assemblies in production plan
(cherry picked from commit f58abed935)
2025-04-14 06:41:27 +00:00
barredterra
2431141062 fix: remove invalid parameter 2025-04-11 13:07:44 +02:00
Patrick Eissler
b0e8f85a27 refactor: make linter happy 2025-04-11 12:25:58 +02:00
Patrick Eissler
b0f3d62dd0 fix: only update User Permissions if a relevant field has changed 2025-04-11 12:25:26 +02:00
Patrick Eissler
e47d07d98c chore: use existing utility function 2025-04-11 12:24:25 +02:00
Patrick Eissler
7ab81b7e54 fix(Employee): remove User Permissions if create_user_permission is unchecked 2025-04-11 12:24:04 +02:00
David (aider)
6f6574c5ac feat: add unit tests for distributed_discount_amount
(cherry picked from commit a464bd861b)
2024-09-05 10:08:39 +00:00
David
ad05e6dec2 fix: distributed discounts on si
(cherry picked from commit 0bab6f34c1)

# Conflicts:
#	erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
#	erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json
#	erpnext/selling/doctype/quotation_item/quotation_item.json
#	erpnext/selling/doctype/sales_order_item/sales_order_item.json
#	erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
2024-09-05 10:08:39 +00:00
400 changed files with 10803 additions and 5262 deletions

View File

@@ -1,5 +1,5 @@
exclude: 'node_modules|.git'
default_stages: [commit]
default_stages: [pre-commit]
fail_fast: false

View File

@@ -4,7 +4,7 @@ import inspect
import frappe
from frappe.utils.user import is_website_user
__version__ = "15.58.0"
__version__ = "15.69.0"
def get_default_company(user=None):

View File

@@ -138,6 +138,11 @@ frappe.treeview_settings["Account"] = {
description: __(
"Further accounts can be made under Groups, but entries can be made against non-Groups"
),
onchange: function () {
if (!this.value) {
this.layout.set_value("root_type", "");
}
},
},
{
fieldtype: "Select",

View File

@@ -22,4 +22,21 @@ frappe.ui.form.on("Accounts Settings", {
}
);
},
add_taxes_from_taxes_and_charges_template(frm) {
toggle_tax_settings(frm, "add_taxes_from_taxes_and_charges_template");
},
add_taxes_from_item_tax_template(frm) {
toggle_tax_settings(frm, "add_taxes_from_item_tax_template");
},
});
function toggle_tax_settings(frm, field_name) {
if (frm.doc[field_name]) {
const other_field =
field_name === "add_taxes_from_item_tax_template"
? "add_taxes_from_taxes_and_charges_template"
: "add_taxes_from_item_tax_template";
frm.set_value(other_field, 0);
}
}

View File

@@ -31,6 +31,7 @@
"determine_address_tax_category_from",
"column_break_19",
"add_taxes_from_item_tax_template",
"add_taxes_from_taxes_and_charges_template",
"book_tax_discount_loss",
"round_row_wise_tax",
"print_settings",
@@ -38,8 +39,14 @@
"show_taxes_as_table_in_print",
"column_break_12",
"show_payment_schedule_in_print",
"item_price_settings_section",
"maintain_same_internal_transaction_rate",
"column_break_feyo",
"maintain_same_rate_action",
"role_to_override_stop_action",
"currency_exchange_section",
"allow_stale",
"allow_pegged_currencies_exchange_rates",
"column_break_yuug",
"stale_days",
"section_break_jpd0",
@@ -77,9 +84,12 @@
"reports_tab",
"remarks_section",
"general_ledger_remarks_length",
"ignore_is_opening_check_for_reporting",
"column_break_lvjk",
"receivable_payable_remarks_length",
"accounts_receivable_payable_tuning_section",
"receivable_payable_fetch_method",
"legacy_section",
"ignore_is_opening_check_for_reporting",
"payment_request_settings",
"create_pr_in_draft_status"
],
@@ -532,6 +542,73 @@
"fieldtype": "Select",
"label": "Posting Date Inheritance for Exchange Gain / Loss",
"options": "Invoice\nPayment\nReconciliation Date"
},
{
"fieldname": "column_break_xrnd",
"fieldtype": "Column Break"
},
{
"default": "Buffered Cursor",
"fieldname": "receivable_payable_fetch_method",
"fieldtype": "Select",
"label": "Data Fetch Method",
"options": "Buffered Cursor\nUnBuffered Cursor"
},
{
"fieldname": "accounts_receivable_payable_tuning_section",
"fieldtype": "Section Break",
"label": "Accounts Receivable / Payable Tuning"
},
{
"fieldname": "legacy_section",
"fieldtype": "Section Break",
"label": "Legacy Fields"
},
{
"default": "0",
"fieldname": "maintain_same_internal_transaction_rate",
"fieldtype": "Check",
"label": "Maintain Same Rate Throughout Internal Transaction"
},
{
"default": "Stop",
"depends_on": "maintain_same_internal_transaction_rate",
"fieldname": "maintain_same_rate_action",
"fieldtype": "Select",
"label": "Action if Same Rate is Not Maintained Throughout Internal Transaction",
"mandatory_depends_on": "maintain_same_internal_transaction_rate",
"options": "Stop\nWarn"
},
{
"depends_on": "eval: doc.maintain_same_internal_transaction_rate && doc.maintain_same_rate_action == 'Stop'",
"fieldname": "role_to_override_stop_action",
"fieldtype": "Link",
"label": "Role Allowed to Override Stop Action",
"options": "Role"
},
{
"fieldname": "item_price_settings_section",
"fieldtype": "Section Break",
"label": "Item Price Settings"
},
{
"fieldname": "column_break_feyo",
"fieldtype": "Column Break"
},
{
"default": "0",
"description": "System will do an implicit conversion using the pegged currency. <br>\nEx: Instead of AED -&gt; INR, system will do AED -&gt; USD -&gt; INR using the pegged exchange rate of AED against USD.",
"documentation_url": "/app/pegged-currencies/Pegged Currencies",
"fieldname": "allow_pegged_currencies_exchange_rates",
"fieldtype": "Check",
"label": "Allow Implicit Pegged Currency Conversion"
},
{
"default": "0",
"description": "If no taxes are set, and Taxes and Charges Template is selected, the system will automatically apply the taxes from the chosen template.",
"fieldname": "add_taxes_from_taxes_and_charges_template",
"fieldtype": "Check",
"label": "Automatically Add Taxes from Taxes and Charges Template"
}
],
"icon": "icon-cog",
@@ -539,7 +616,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2025-01-23 13:15:44.077853",
"modified": "2025-06-23 15:55:33.346398",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
@@ -568,4 +645,4 @@
"sort_order": "ASC",
"states": [],
"track_changes": 1
}
}

View File

@@ -25,7 +25,9 @@ class AccountsSettings(Document):
acc_frozen_upto: DF.Date | None
add_taxes_from_item_tax_template: DF.Check
add_taxes_from_taxes_and_charges_template: DF.Check
allow_multi_currency_invoices_against_single_party_account: DF.Check
allow_pegged_currencies_exchange_rates: DF.Check
allow_stale: DF.Check
auto_reconcile_payments: DF.Check
auto_reconciliation_job_trigger: DF.Int
@@ -50,13 +52,17 @@ class AccountsSettings(Document):
general_ledger_remarks_length: DF.Int
ignore_account_closing_balance: DF.Check
ignore_is_opening_check_for_reporting: DF.Check
maintain_same_internal_transaction_rate: DF.Check
maintain_same_rate_action: DF.Literal["Stop", "Warn"]
make_payment_via_journal_entry: DF.Check
merge_similar_account_heads: DF.Check
over_billing_allowance: DF.Currency
post_change_gl_entries: DF.Check
receivable_payable_fetch_method: DF.Literal["Buffered Cursor", "UnBuffered Cursor"]
receivable_payable_remarks_length: DF.Int
reconciliation_queue_size: DF.Int
role_allowed_to_over_bill: DF.Link | None
role_to_override_stop_action: DF.Link | None
round_row_wise_tax: DF.Check
show_balance_in_coa: DF.Check
show_inclusive_tax_in_print: DF.Check
@@ -69,6 +75,7 @@ class AccountsSettings(Document):
# end: auto-generated types
def validate(self):
self.validate_auto_tax_settings()
old_doc = self.get_doc_before_save()
clear_cache = False
@@ -135,3 +142,13 @@ class AccountsSettings(Document):
if self.has_value_changed("reconciliation_queue_size"):
if cint(self.reconciliation_queue_size) < 5 or cint(self.reconciliation_queue_size) > 100:
frappe.throw(_("Queue Size should be between 5 and 100"))
def validate_auto_tax_settings(self):
if self.add_taxes_from_item_tax_template and self.add_taxes_from_taxes_and_charges_template:
frappe.throw(
_("You cannot enable both the settings '{0}' and '{1}'.").format(
frappe.bold(_(self.meta.get_label("add_taxes_from_item_tax_template"))),
frappe.bold(_(self.meta.get_label("add_taxes_from_taxes_and_charges_template"))),
),
title=_("Auto Tax Settings Error"),
)

View File

@@ -118,8 +118,9 @@ class BankClearance(Document):
else:
# using db_set to trigger notification
payment_entry = frappe.get_doc(d.payment_document, d.payment_entry)
payment_entry.db_set("clearance_date", d.clearance_date)
frappe.db.set_value(
d.payment_document, d.payment_entry, "clearance_date", d.clearance_date
)
clearance_date_updated = True

View File

@@ -7,6 +7,9 @@ import frappe
from frappe.utils import add_months, getdate
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
from erpnext.accounts.doctype.mode_of_payment.test_mode_of_payment import (
set_default_account_for_mode_of_payment,
)
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
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
@@ -191,11 +194,13 @@ def make_pos_sales_invoice():
customer = make_customer(customer="_Test Customer")
mode_of_payment = frappe.get_doc("Mode of Payment", "Wire Transfer")
set_default_account_for_mode_of_payment(mode_of_payment, "_Test Company", "_Test Bank Clearance - _TC")
si = create_sales_invoice(customer=customer, item="_Test Item", is_pos=1, qty=1, rate=1000, do_not_save=1)
si.set("payments", [])
si.append(
"payments", {"mode_of_payment": "Cash", "account": "_Test Bank Clearance - _TC", "amount": 1000}
)
si.append("payments", {"mode_of_payment": "Wire Transfer", "amount": 1000})
si.insert()
si.submit()

View File

@@ -277,7 +277,7 @@ def get_import_status(docname):
@frappe.whitelist()
def get_import_logs(docname: str):
frappe.has_permission("Bank Statement Import")
frappe.has_permission("Bank Statement Import", throw=True)
return frappe.get_all(
"Data Import Log",

View File

@@ -1,6 +1,7 @@
import frappe
from frappe.utils import flt
from rapidfuzz import fuzz, process
from rapidfuzz.utils import default_process
class AutoMatchParty:
@@ -132,6 +133,7 @@ class AutoMatchbyPartyNameDescription:
query=self.get(field),
choices={row.get("name"): row.get("party_name") for row in names},
scorer=fuzz.token_set_ratio,
processor=default_process,
)
party_name, skip = self.process_fuzzy_result(result)

View File

@@ -45,7 +45,6 @@
"default": "ACC-BTN-.YYYY.-",
"fieldname": "naming_series",
"fieldtype": "Select",
"hidden": 1,
"label": "Series",
"no_copy": 1,
"options": "ACC-BTN-.YYYY.-",
@@ -236,9 +235,10 @@
"fieldtype": "Column Break"
}
],
"grid_page_length": 50,
"is_submittable": 1,
"links": [],
"modified": "2023-11-18 18:32:47.203694",
"modified": "2025-06-18 17:24:57.044666",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Transaction",
@@ -287,9 +287,10 @@
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "date",
"sort_order": "DESC",
"states": [],
"title_field": "bank_account",
"track_changes": 1
}
}

View File

@@ -12,6 +12,9 @@ from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool
get_linked_payments,
reconcile_vouchers,
)
from erpnext.accounts.doctype.mode_of_payment.test_mode_of_payment import (
set_default_account_for_mode_of_payment,
)
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
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
@@ -434,15 +437,13 @@ def add_vouchers(gl_account="_Test Bank - _TC"):
except frappe.DuplicateEntryError:
pass
mode_of_payment = frappe.get_doc({"doctype": "Mode of Payment", "name": "Cash"})
mode_of_payment = frappe.get_doc({"doctype": "Mode of Payment", "name": "Wire Transfer"})
if not frappe.db.get_value("Mode of Payment Account", {"company": "_Test Company", "parent": "Cash"}):
mode_of_payment.append("accounts", {"company": "_Test Company", "default_account": gl_account})
mode_of_payment.save()
set_default_account_for_mode_of_payment(mode_of_payment, "_Test Company", gl_account)
si = create_sales_invoice(customer="Fayva", qty=1, rate=109080, do_not_save=1)
si.is_pos = 1
si.append("payments", {"mode_of_payment": "Cash", "account": gl_account, "amount": 109080})
si.append("payments", {"mode_of_payment": "Wire Transfer", "amount": 109080})
si.insert()
si.submit()

View File

@@ -7,10 +7,10 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"naming_series",
"budget_against",
"company",
"cost_center",
"naming_series",
"project",
"fiscal_year",
"column_break_3",
@@ -195,19 +195,19 @@
},
{
"fieldname": "naming_series",
"fieldtype": "Data",
"hidden": 1,
"fieldtype": "Select",
"label": "Series",
"no_copy": 1,
"options": "BUDGET-.YYYY.-",
"print_hide": 1,
"read_only": 1,
"reqd": 1,
"set_only_once": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2022-10-10 22:14:36.361509",
"modified": "2025-06-16 15:57:13.114981",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Budget",
@@ -235,4 +235,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -48,7 +48,7 @@ class Budget(Document):
cost_center: DF.Link | None
fiscal_year: DF.Link
monthly_distribution: DF.Link | None
naming_series: DF.Data | None
naming_series: DF.Literal["BUDGET-.YYYY.-"]
project: DF.Link | None
# end: auto-generated types
@@ -136,9 +136,6 @@ class Budget(Document):
):
self.applicable_on_booking_actual_expenses = 1
def before_naming(self):
self.naming_series = f"{{{frappe.scrub(self.budget_against)}}}./.{self.fiscal_year}/.###"
def validate_expense_against_budget(args, expense_amount=0):
args = frappe._dict(args)

View File

@@ -6,7 +6,11 @@ import unittest
import frappe
from frappe.utils import now_datetime, nowdate
from erpnext.accounts.doctype.budget.budget import BudgetError, get_actual_expense
from erpnext.accounts.doctype.budget.budget import (
BudgetError,
get_accumulated_monthly_budget,
get_actual_expense,
)
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
from erpnext.accounts.utils import get_fiscal_year
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
@@ -96,6 +100,10 @@ class TestBudget(unittest.TestCase):
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
frappe.db.set_value("Budget", budget.name, "fiscal_year", fiscal_year)
accumulated_limit = get_accumulated_monthly_budget(
budget.monthly_distribution, nowdate(), budget.fiscal_year, budget.accounts[0].budget_amount
)
mr = frappe.get_doc(
{
"doctype": "Material Request",
@@ -109,7 +117,7 @@ class TestBudget(unittest.TestCase):
"uom": "_Test UOM",
"warehouse": "_Test Warehouse - _TC",
"schedule_date": nowdate(),
"rate": 100000,
"rate": accumulated_limit + 1,
"expense_account": "_Test Account Cost for Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC",
}

View File

@@ -7,7 +7,7 @@ from frappe import _
from frappe.model.document import Document
from frappe.model.meta import get_field_precision
from frappe.model.naming import set_name_from_naming_options
from frappe.utils import flt, fmt_money, now
from frappe.utils import create_batch, flt, fmt_money, now
import erpnext
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
@@ -451,12 +451,15 @@ def rename_gle_sle_docs():
def rename_temporarily_named_docs(doctype):
"""Rename temporarily named docs using autoname options"""
docs_to_rename = frappe.get_all(doctype, {"to_rename": "1"}, order_by="creation", limit=50000)
for doc in docs_to_rename:
oldname = doc.name
set_name_from_naming_options(frappe.get_meta(doctype).autoname, doc)
newname = doc.name
frappe.db.sql(
f"UPDATE `tab{doctype}` SET name = %s, to_rename = 0, modified = %s where name = %s",
(newname, now(), oldname),
auto_commit=True,
)
autoname = frappe.get_meta(doctype).autoname
for batch in create_batch(docs_to_rename, 100):
for doc in batch:
oldname = doc.name
set_name_from_naming_options(autoname, doc)
newname = doc.name
frappe.db.sql(
f"UPDATE `tab{doctype}` SET name = %s, to_rename = 0, modified = %s where name = %s",
(newname, now(), oldname),
)
frappe.db.commit()

View File

@@ -197,7 +197,7 @@ frappe.ui.form.on("Invoice Discounting", {
from_date: frm.doc.posting_date,
to_date: moment(frm.doc.modified).format("YYYY-MM-DD"),
company: frm.doc.company,
group_by: "Group by Voucher (Consolidated)",
categorize_by: "Categorize by Voucher (Consolidated)",
show_cancelled_entries: frm.doc.docstatus === 2,
};
frappe.set_route("query-report", "General Ledger");

View File

@@ -35,7 +35,7 @@ frappe.ui.form.on("Journal Entry", {
to_date: moment(frm.doc.modified).format("YYYY-MM-DD"),
company: frm.doc.company,
finance_book: frm.doc.finance_book,
group_by: "",
categorize_by: "",
show_cancelled_entries: frm.doc.docstatus === 2,
};
frappe.set_route("query-report", "General Ledger");

View File

@@ -24,6 +24,7 @@ from erpnext.accounts.party import get_party_account
from erpnext.accounts.utils import (
cancel_exchange_gain_loss_journal,
get_account_currency,
get_advance_payment_doctypes,
get_balance_on,
get_stock_accounts,
get_stock_and_account_balance,
@@ -146,8 +147,7 @@ class JournalEntry(AccountsController):
if self.docstatus == 0:
self.apply_tax_withholding()
if not self.title:
if self.is_new() or not self.title:
self.title = self.get_title()
def validate_advance_accounts(self):
@@ -239,9 +239,10 @@ class JournalEntry(AccountsController):
def update_advance_paid(self):
advance_paid = frappe._dict()
advance_payment_doctypes = get_advance_payment_doctypes()
for d in self.get("accounts"):
if d.is_advance:
if d.reference_type in frappe.get_hooks("advance_payment_doctypes"):
if d.reference_type in advance_payment_doctypes:
advance_paid.setdefault(d.reference_type, []).append(d.reference_name)
for voucher_type, order_list in advance_paid.items():
@@ -250,11 +251,20 @@ class JournalEntry(AccountsController):
def validate_inter_company_accounts(self):
if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
doc = frappe.get_doc("Journal Entry", self.inter_company_journal_entry_reference)
doc = frappe.db.get_value(
"Journal Entry",
self.inter_company_journal_entry_reference,
["company", "total_debit", "total_credit"],
as_dict=True,
)
account_currency = frappe.get_cached_value("Company", self.company, "default_currency")
previous_account_currency = frappe.get_cached_value("Company", doc.company, "default_currency")
if account_currency == previous_account_currency:
if self.total_credit != doc.total_debit or self.total_debit != doc.total_credit:
credit_precision = self.precision("total_credit")
debit_precision = self.precision("total_debit")
if (flt(self.total_credit, credit_precision) != flt(doc.total_debit, debit_precision)) or (
flt(self.total_debit, debit_precision) != flt(doc.total_credit, credit_precision)
):
frappe.throw(_("Total Credit/ Debit Amount should be same as linked Journal Entry"))
def validate_depr_entry_voucher_type(self):
@@ -1034,7 +1044,9 @@ class JournalEntry(AccountsController):
def set_print_format_fields(self):
bank_amount = party_amount = total_amount = 0.0
currency = bank_account_currency = party_account_currency = pay_to_recd_from = None
currency = (
bank_account_currency
) = party_account_currency = pay_to_recd_from = self.pay_to_recd_from = None
party_type = None
for d in self.get("accounts"):
if d.party_type in ["Customer", "Supplier"] and d.party:

View File

@@ -168,8 +168,9 @@ def validate_loyalty_points(ref_doc, points_to_redeem):
loyalty_amount = flt(points_to_redeem * loyalty_program_details.conversion_factor)
if loyalty_amount > ref_doc.rounded_total:
frappe.throw(_("You can't redeem Loyalty Points having more value than the Rounded Total."))
total_amount = ref_doc.grand_total if ref_doc.is_rounded_total_disabled() else ref_doc.rounded_total
if loyalty_amount > total_amount:
frappe.throw(_("You can't redeem Loyalty Points having more value than the Total Amount."))
if not ref_doc.loyalty_amount and ref_doc.loyalty_amount != loyalty_amount:
ref_doc.loyalty_amount = loyalty_amount

View File

@@ -3,8 +3,25 @@
import unittest
# test_records = frappe.get_test_records('Mode of Payment')
import frappe
class TestModeofPayment(unittest.TestCase):
pass
def set_default_account_for_mode_of_payment(mode_of_payment, company, account):
mode_of_payment.reload()
if frappe.db.exists(
"Mode of Payment Account", {"parent": mode_of_payment.mode_of_payment, "company": company}
):
frappe.db.set_value(
"Mode of Payment Account",
{"parent": mode_of_payment.mode_of_payment, "company": company},
"default_account",
account,
)
return
mode_of_payment.append("accounts", {"company": company, "default_account": account})
mode_of_payment.save()

View File

@@ -411,7 +411,7 @@ frappe.ui.form.on("Payment Entry", {
from_date: frm.doc.posting_date,
to_date: moment(frm.doc.modified).format("YYYY-MM-DD"),
company: frm.doc.company,
group_by: "",
categorize_by: "",
show_cancelled_entries: frm.doc.docstatus === 2,
};
frappe.set_route("query-report", "General Ledger");

View File

@@ -21,7 +21,6 @@
"party_name",
"book_advance_payments_in_separate_party_account",
"reconcile_on_advance_payment_date",
"advance_reconciliation_takes_effect_on",
"column_break_11",
"bank_account",
"party_bank_account",
@@ -229,6 +228,7 @@
"fieldname": "party_balance",
"fieldtype": "Currency",
"label": "Party Balance",
"no_copy": 1,
"print_hide": 1,
"read_only": 1
},
@@ -786,18 +786,9 @@
"options": "No\nYes",
"print_hide": 1,
"search_index": 1
},
{
"default": "Oldest Of Invoice Or Advance",
"fetch_from": "company.reconciliation_takes_effect_on",
"fieldname": "advance_reconciliation_takes_effect_on",
"fieldtype": "Select",
"hidden": 1,
"label": "Advance Reconciliation Takes Effect On",
"no_copy": 1,
"options": "Advance Payment Date\nOldest Of Invoice Or Advance\nReconciliation Date"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [
@@ -809,7 +800,7 @@
"table_fieldname": "payment_entries"
}
],
"modified": "2025-03-24 16:18:19.920701",
"modified": "2025-05-15 18:01:04.013025",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",
@@ -849,6 +840,7 @@
"write": 1
}
],
"row_format": "Dynamic",
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",

View File

@@ -46,8 +46,10 @@ from erpnext.accounts.party import (
from erpnext.accounts.utils import (
cancel_exchange_gain_loss_journal,
get_account_currency,
get_advance_payment_doctypes,
get_balance_on,
get_outstanding_invoices,
get_reconciliation_effect_date,
)
from erpnext.controllers.accounts_controller import (
AccountsController,
@@ -568,7 +570,7 @@ class PaymentEntry(AccountsController):
def validate_mandatory(self):
for field in ("paid_amount", "received_amount", "source_exchange_rate", "target_exchange_rate"):
if not self.get(field):
frappe.throw(_("{0} is mandatory").format(self.meta.get_label(field)))
frappe.throw(_("{0} is mandatory").format(_(self.meta.get_label(field))))
def validate_reference_documents(self):
valid_reference_doctypes = self.get_valid_reference_doctypes()
@@ -1028,7 +1030,7 @@ class PaymentEntry(AccountsController):
def calculate_base_allocated_amount_for_reference(self, d) -> float:
base_allocated_amount = 0
if d.reference_doctype in frappe.get_hooks("advance_payment_doctypes"):
if d.reference_doctype in get_advance_payment_doctypes():
# When referencing Sales/Purchase Order, use the source/target exchange rate depending on payment type.
# This is so there are no Exchange Gain/Loss generated for such doctypes
@@ -1308,8 +1310,7 @@ class PaymentEntry(AccountsController):
if not self.party_account:
return
advance_payment_doctypes = frappe.get_hooks("advance_payment_doctypes")
advance_payment_doctypes = get_advance_payment_doctypes()
if self.payment_type == "Receive":
against_account = self.paid_to
else:
@@ -1492,20 +1493,7 @@ class PaymentEntry(AccountsController):
else:
# For backwards compatibility
# Supporting reposting on payment entries reconciled before select field introduction
if self.advance_reconciliation_takes_effect_on == "Advance Payment Date":
posting_date = self.posting_date
elif self.advance_reconciliation_takes_effect_on == "Oldest Of Invoice Or Advance":
date_field = "posting_date"
if invoice.reference_doctype in ["Sales Order", "Purchase Order"]:
date_field = "transaction_date"
posting_date = frappe.db.get_value(
invoice.reference_doctype, invoice.reference_name, date_field
)
if getdate(posting_date) < getdate(self.posting_date):
posting_date = self.posting_date
elif self.advance_reconciliation_takes_effect_on == "Reconciliation Date":
posting_date = nowdate()
posting_date = get_reconciliation_effect_date(invoice, self.company, self.posting_date)
frappe.db.set_value("Payment Entry Reference", invoice.name, "reconcile_effect_on", posting_date)
dr_or_cr, account = self.get_dr_and_account_for_advances(invoice)
@@ -1696,12 +1684,15 @@ class PaymentEntry(AccountsController):
return flt(gl_dict.get(field, 0) / (conversion_rate or 1))
def update_advance_paid(self):
if self.payment_type in ("Receive", "Pay") and self.party:
for d in self.get("references"):
if d.allocated_amount and d.reference_doctype in frappe.get_hooks("advance_payment_doctypes"):
frappe.get_doc(
d.reference_doctype, d.reference_name, for_update=True
).set_total_advance_paid()
if self.payment_type not in ("Receive", "Pay") or not self.party:
return
advance_payment_doctypes = get_advance_payment_doctypes()
for d in self.get("references"):
if d.allocated_amount and d.reference_doctype in advance_payment_doctypes:
frappe.get_doc(
d.reference_doctype, d.reference_name, for_update=True
).set_total_advance_paid()
def on_recurring(self, reference_doc, auto_repeat_doc):
self.reference_no = reference_doc.name
@@ -1994,7 +1985,7 @@ class PaymentEntry(AccountsController):
# Re allocate amount to those references which have PR set (Higher priority)
for ref in self.references:
if not ref.payment_request:
if not (ref.reference_doctype and ref.reference_name and ref.payment_request):
continue
# fetch outstanding_amount of `Reference` (Payment Term) and `Payment Request` to allocate new amount
@@ -2045,7 +2036,7 @@ class PaymentEntry(AccountsController):
)
# Re allocate amount to those references which have no PR (Lower priority)
for ref in self.references:
if ref.payment_request:
if ref.payment_request or not (ref.reference_doctype and ref.reference_name):
continue
key = (ref.reference_doctype, ref.reference_name, ref.get("payment_term"))
@@ -2361,7 +2352,7 @@ def get_outstanding_reference_documents(args, validate=False):
accounts = get_party_account(
args.get("party_type"), args.get("party"), args.get("company"), include_advance=True
)
advance_account = accounts[1] if len(accounts) >= 1 else None
advance_account = accounts[1] if len(accounts) > 1 else None
if party_account == advance_account:
party_account = accounts[0]
@@ -2941,6 +2932,8 @@ def get_payment_entry(
party_account_currency if payment_type == "Receive" else bank.account_currency
)
pe.paid_to_account_currency = party_account_currency if payment_type == "Pay" else bank.account_currency
pe.paid_from_account_type = frappe.db.get_value("Account", pe.paid_from, "account_type")
pe.paid_to_account_type = frappe.db.get_value("Account", pe.paid_to, "account_type")
pe.paid_amount = paid_amount
pe.received_amount = received_amount
pe.letter_head = doc.get("letter_head")
@@ -3300,26 +3293,25 @@ def set_paid_amount_and_received_amount(
if party_account_currency == bank.account_currency:
paid_amount = received_amount = abs(outstanding_amount)
else:
company_currency = frappe.get_cached_value("Company", doc.get("company"), "default_currency")
if payment_type == "Receive":
paid_amount = abs(outstanding_amount)
if bank_amount:
received_amount = bank_amount
else:
if bank and company_currency != bank.account_currency:
received_amount = paid_amount / doc.get("conversion_rate", 1)
else:
received_amount = paid_amount * doc.get("conversion_rate", 1)
# settings if it is for receive
paid_amount = abs(outstanding_amount)
if bank_amount:
received_amount = bank_amount
else:
received_amount = abs(outstanding_amount)
if bank_amount:
paid_amount = bank_amount
company_currency = frappe.get_cached_value("Company", doc.get("company"), "default_currency")
if bank and company_currency != bank.account_currency:
# doc currency can be different from bank currency
posting_date = doc.get("posting_date") or doc.get("transaction_date")
conversion_rate = get_exchange_rate(
bank.account_currency, party_account_currency, posting_date
)
received_amount = paid_amount / conversion_rate
else:
if bank and company_currency != bank.account_currency:
paid_amount = received_amount / doc.get("conversion_rate", 1)
else:
# if party account currency and bank currency is different then populate paid amount as well
paid_amount = received_amount * doc.get("conversion_rate", 1)
received_amount = paid_amount * doc.get("conversion_rate", 1)
# if payment type is pay, then paid amount and received amount are swapped
if payment_type == "Pay":
paid_amount, received_amount = received_amount, paid_amount
return paid_amount, received_amount

View File

@@ -589,7 +589,7 @@ class PaymentReconciliation(Document):
def check_mandatory_to_fetch(self):
for fieldname in ["company", "party_type", "party", "receivable_payable_account"]:
if not self.get(fieldname):
frappe.throw(_("Please select {0} first").format(self.meta.get_label(fieldname)))
frappe.throw(_("Please select {0} first").format(_(self.meta.get_label(fieldname))))
def validate_entries(self):
if not self.get("invoices"):
@@ -826,7 +826,7 @@ def reconcile_dr_cr_note(dr_cr_notes, company, active_dimensions=None):
create_gain_loss_journal(
company,
today(),
inv.difference_posting_date,
inv.party_type,
inv.party,
inv.account,

View File

@@ -670,7 +670,12 @@ def get_amount(ref_doc, payment_account=None):
dt = ref_doc.doctype
if dt in ["Sales Order", "Purchase Order"]:
grand_total = (flt(ref_doc.rounded_total) or flt(ref_doc.grand_total)) - ref_doc.advance_paid
advance_amount = flt(ref_doc.advance_paid)
if ref_doc.party_account_currency != ref_doc.currency:
advance_amount = flt(flt(ref_doc.advance_paid) / ref_doc.conversion_rate)
grand_total = (flt(ref_doc.rounded_total) or flt(ref_doc.grand_total)) - advance_amount
elif dt in ["Sales Invoice", "Purchase Invoice"]:
if (
dt == "Sales Invoice"
@@ -824,8 +829,7 @@ def update_payment_requests_as_per_pe_references(references=None, cancel=False):
if not references:
return
precision = references[0].precision("allocated_amount")
precision = frappe.get_precision("Payment Entry Reference", "allocated_amount")
referenced_payment_requests = frappe.get_all(
"Payment Request",
filters={"name": ["in", {row.payment_request for row in references if row.payment_request}]},

View File

@@ -630,29 +630,58 @@ class TestPaymentRequest(FrappeTestCase):
pr = make_payment_request(dt="Sales Invoice", dn=si.name, mute_email=1)
self.assertEqual(pr.grand_total, si.outstanding_amount)
def test_partial_paid_invoice_with_submitted_payment_entry(self):
pi = make_purchase_invoice(currency="INR", qty=1, rate=5000)
pi.save()
pi.submit()
def test_partial_paid_invoice_with_submitted_payment_entry(self):
pi = make_purchase_invoice(currency="INR", qty=1, rate=5000)
pi.save()
pi.submit()
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe.reference_no = "PURINV0001"
pe.reference_date = frappe.utils.nowdate()
pe.paid_amount = 2500
pe.references[0].allocated_amount = 2500
pe.save()
pe.submit()
pe.cancel()
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe.reference_no = "PURINV0001"
pe.reference_date = frappe.utils.nowdate()
pe.paid_amount = 2500
pe.references[0].allocated_amount = 2500
pe.save()
pe.submit()
pe.cancel()
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe.reference_no = "PURINV0002"
pe.reference_date = frappe.utils.nowdate()
pe.paid_amount = 2500
pe.references[0].allocated_amount = 2500
pe.save()
pe.submit()
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe.reference_no = "PURINV0002"
pe.reference_date = frappe.utils.nowdate()
pe.paid_amount = 2500
pe.references[0].allocated_amount = 2500
pe.save()
pe.submit()
pi.load_from_db()
pr = make_payment_request(dt="Purchase Invoice", dn=pi.name, mute_email=1)
self.assertEqual(pr.grand_total, pi.outstanding_amount)
pi.load_from_db()
pr = make_payment_request(dt="Purchase Invoice", dn=pi.name, mute_email=1)
self.assertEqual(pr.grand_total, pi.outstanding_amount)
def test_payment_request_on_unreconcile(self):
pi = make_purchase_invoice(currency="INR", qty=1, rate=500)
pi.submit()
pr = make_payment_request(
dt=pi.doctype,
dn=pi.name,
mute_email=1,
submit_doc=True,
return_doc=True,
)
self.assertEqual(pr.grand_total, pi.outstanding_amount)
pe = pr.create_payment_entry()
unreconcile = frappe.get_doc(
{
"doctype": "Unreconcile Payment",
"company": pe.company,
"voucher_type": pe.doctype,
"voucher_no": pe.name,
}
)
unreconcile.add_references()
unreconcile.submit()
pi.load_from_db()
pr.load_from_db()
self.assertEqual(pr.grand_total, pi.outstanding_amount)

View File

@@ -0,0 +1,8 @@
// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
// frappe.ui.form.on("Pegged Currencies", {
// refresh(frm) {
// },
// });

View File

@@ -0,0 +1,47 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-05-30 11:47:03.670913",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"pegged_currencies_item_section",
"pegged_currency_item"
],
"fields": [
{
"fieldname": "pegged_currencies_item_section",
"fieldtype": "Section Break"
},
{
"fieldname": "pegged_currency_item",
"fieldtype": "Table",
"options": "Pegged Currency Details"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2025-06-02 11:46:31.936714",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pegged Currencies",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}

View File

@@ -0,0 +1,22 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class PeggedCurrencies(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.pegged_currencies.pegged_currencies import PeggedCurrencies
pegged_currency_item: DF.Table[PeggedCurrencies]
# end: auto-generated types
pass

View File

@@ -0,0 +1,9 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
from frappe.tests.utils import FrappeTestCase
class TestPeggedCurrencies(FrappeTestCase):
pass

View File

@@ -0,0 +1,49 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-05-30 11:59:28.219277",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"source_currency",
"pegged_against",
"pegged_exchange_rate"
],
"fields": [
{
"fieldname": "source_currency",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Currency",
"options": "Currency"
},
{
"fieldname": "pegged_exchange_rate",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Exchange Rate"
},
{
"fieldname": "pegged_against",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Pegged Against",
"options": "Currency"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-06-17 14:11:16.521193",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pegged Currency Details",
"owner": "Administrator",
"permissions": [],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}

View File

@@ -0,0 +1,25 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class PeggedCurrencyDetails(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
pegged_against: DF.Link | None
pegged_exchange_rate: DF.Data | None
source_currency: DF.Link | None
# end: auto-generated types
pass

View File

@@ -47,7 +47,7 @@ frappe.ui.form.on("Period Closing Voucher", {
from_date: frm.doc.posting_date,
to_date: moment(frm.doc.modified).format("YYYY-MM-DD"),
company: frm.doc.company,
group_by: "",
categorize_by: "",
show_cancelled_entries: frm.doc.docstatus === 2,
};
frappe.set_route("query-report", "General Ledger");

View File

@@ -133,7 +133,12 @@ class PeriodClosingVoucher(AccountsController):
self.make_gl_entries()
def on_cancel(self):
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Payment Ledger Entry")
self.ignore_linked_doctypes = (
"GL Entry",
"Stock Ledger Entry",
"Payment Ledger Entry",
"Account Closing Balance",
)
self.block_if_future_closing_voucher_exists()
self.db_set("gle_processing_status", "In Progress")
self.cancel_gl_entries()

View File

@@ -323,3 +323,15 @@ frappe.ui.form.on("POS Invoice", {
});
},
});
frappe.ui.form.on("Sales Invoice Payment", {
mode_of_payment: function (frm) {
frappe.call({
doc: frm.doc,
method: "set_account_for_mode_of_payment",
callback: function (r) {
refresh_field("payments");
},
});
},
});

View File

@@ -273,6 +273,8 @@ class POSInvoice(SalesInvoice):
against_psi_doc.delete_loyalty_point_entry()
against_psi_doc.make_loyalty_point_entry()
self.db_set("status", "Cancelled")
if self.coupon_code:
from erpnext.accounts.doctype.pricing_rule.utils import update_coupon_code_count

View File

@@ -7,6 +7,9 @@ import unittest
import frappe
from frappe import _
from erpnext.accounts.doctype.mode_of_payment.test_mode_of_payment import (
set_default_account_for_mode_of_payment,
)
from erpnext.accounts.doctype.pos_invoice.pos_invoice import PartialPaymentValidationError, make_sales_return
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
@@ -31,6 +34,8 @@ class TestPOSInvoice(unittest.TestCase):
cls.test_user, cls.pos_profile = init_user_and_profile()
create_opening_entry(cls.pos_profile, cls.test_user)
mode_of_payment = frappe.get_doc("Mode of Payment", "Bank Draft")
set_default_account_for_mode_of_payment(mode_of_payment, "_Test Company", "_Test Bank - _TC")
def tearDown(self):
if frappe.session.user != "Administrator":
@@ -233,12 +238,8 @@ class TestPOSInvoice(unittest.TestCase):
pos = create_pos_invoice(qty=10, do_not_save=True)
pos.set("payments", [])
pos.append(
"payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - _TC", "amount": 500}
)
pos.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 500, "default": 1}
)
pos.append("payments", {"mode_of_payment": "Bank Draft", "amount": 500})
pos.append("payments", {"mode_of_payment": "Cash", "amount": 500, "default": 1})
pos.insert()
pos.submit()
@@ -276,9 +277,7 @@ class TestPOSInvoice(unittest.TestCase):
do_not_save=1,
)
pos.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 1000, "default": 1}
)
pos.append("payments", {"mode_of_payment": "Cash", "amount": 1000, "default": 1})
pos.insert()
pos.submit()
@@ -318,9 +317,7 @@ class TestPOSInvoice(unittest.TestCase):
do_not_save=1,
)
pos.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 2000, "default": 1}
)
pos.append("payments", {"mode_of_payment": "Cash", "amount": 2000, "default": 1})
pos.insert()
pos.submit()
@@ -331,9 +328,7 @@ class TestPOSInvoice(unittest.TestCase):
# partial return 1
pos_return1.get("items")[0].qty = -1
pos_return1.set("payments", [])
pos_return1.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": -1000, "default": 1}
)
pos_return1.append("payments", {"mode_of_payment": "Cash", "amount": -1000, "default": 1})
pos_return1.paid_amount = -1000
pos_return1.submit()
pos_return1.reload()
@@ -350,9 +345,7 @@ class TestPOSInvoice(unittest.TestCase):
# partial return 2
pos_return2 = make_sales_return(pos.name)
pos_return2.set("payments", [])
pos_return2.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": -1000, "default": 1}
)
pos_return2.append("payments", {"mode_of_payment": "Cash", "amount": -1000, "default": 1})
pos_return2.paid_amount = -1000
pos_return2.submit()
@@ -372,10 +365,8 @@ class TestPOSInvoice(unittest.TestCase):
)
pos.set("payments", [])
pos.append("payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - _TC", "amount": 50})
pos.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 60, "default": 1}
)
pos.append("payments", {"mode_of_payment": "Bank Draft", "amount": 50})
pos.append("payments", {"mode_of_payment": "Cash", "amount": 60, "default": 1})
pos.insert()
pos.submit()
@@ -393,7 +384,7 @@ class TestPOSInvoice(unittest.TestCase):
pos_inv = create_pos_invoice(rate=10000, do_not_save=1)
pos_inv.append(
"payments",
{"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 9000},
{"mode_of_payment": "Cash", "amount": 9000},
)
pos_inv.insert()
self.assertRaises(PartialPaymentValidationError, pos_inv.submit)
@@ -424,9 +415,7 @@ class TestPOSInvoice(unittest.TestCase):
do_not_save=1,
)
pos.append(
"payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - _TC", "amount": 1000}
)
pos.append("payments", {"mode_of_payment": "Bank Draft", "amount": 1000})
pos.insert()
pos.submit()
@@ -445,9 +434,7 @@ class TestPOSInvoice(unittest.TestCase):
do_not_save=1,
)
pos2.append(
"payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - _TC", "amount": 1000}
)
pos2.append("payments", {"mode_of_payment": "Bank Draft", "amount": 1000})
pos2.insert()
self.assertRaises(frappe.ValidationError, pos2.submit)
@@ -496,9 +483,7 @@ class TestPOSInvoice(unittest.TestCase):
do_not_save=1,
)
pos2.append(
"payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - _TC", "amount": 1000}
)
pos2.append("payments", {"mode_of_payment": "Bank Draft", "amount": 1000})
pos2.insert()
self.assertRaises(frappe.ValidationError, pos2.submit)
@@ -561,9 +546,7 @@ class TestPOSInvoice(unittest.TestCase):
)
pos.get("items")[0].has_serial_no = 1
pos.set("payments", [])
pos.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 1000, "default": 1}
)
pos.append("payments", {"mode_of_payment": "Cash", "amount": 1000, "default": 1})
pos = pos.save().submit()
# make a return
@@ -609,7 +592,7 @@ class TestPOSInvoice(unittest.TestCase):
inv = create_pos_invoice(customer="Test Loyalty Customer", rate=10000, do_not_save=1)
inv.append(
"payments",
{"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 10000},
{"mode_of_payment": "Cash", "amount": 10000},
)
inv.insert()
inv.submit()
@@ -641,7 +624,7 @@ class TestPOSInvoice(unittest.TestCase):
pos_inv = create_pos_invoice(customer="Test Loyalty Customer", rate=10000, do_not_save=1)
pos_inv.append(
"payments",
{"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 10000},
{"mode_of_payment": "Cash", "amount": 10000},
)
pos_inv.paid_amount = 10000
pos_inv.submit()
@@ -656,7 +639,7 @@ class TestPOSInvoice(unittest.TestCase):
inv.loyalty_amount = inv.loyalty_points * before_lp_details.conversion_factor
inv.append(
"payments",
{"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 10000 - inv.loyalty_amount},
{"mode_of_payment": "Cash", "amount": 10000 - inv.loyalty_amount},
)
inv.paid_amount = 10000
inv.submit()
@@ -677,12 +660,12 @@ class TestPOSInvoice(unittest.TestCase):
frappe.db.sql("delete from `tabPOS Invoice`")
test_user, pos_profile = init_user_and_profile()
pos_inv = create_pos_invoice(rate=300, additional_discount_percentage=10, do_not_submit=1)
pos_inv.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 270})
pos_inv.append("payments", {"mode_of_payment": "Cash", "amount": 270})
pos_inv.save()
pos_inv.submit()
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200})
pos_inv2.append("payments", {"mode_of_payment": "Cash", "amount": 3200})
pos_inv2.save()
pos_inv2.submit()
@@ -703,7 +686,7 @@ class TestPOSInvoice(unittest.TestCase):
frappe.db.sql("delete from `tabPOS Invoice`")
test_user, pos_profile = init_user_and_profile()
pos_inv = create_pos_invoice(rate=300, do_not_submit=1)
pos_inv.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 300})
pos_inv.append("payments", {"mode_of_payment": "Cash", "amount": 300})
pos_inv.append(
"taxes",
{
@@ -720,7 +703,7 @@ class TestPOSInvoice(unittest.TestCase):
pos_inv2 = create_pos_invoice(rate=300, qty=2, do_not_submit=1)
pos_inv2.additional_discount_percentage = 10
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 540})
pos_inv2.append("payments", {"mode_of_payment": "Cash", "amount": 540})
pos_inv2.append(
"taxes",
{
@@ -758,7 +741,7 @@ class TestPOSInvoice(unittest.TestCase):
frappe.db.sql("delete from `tabPOS Invoice`")
test_user, pos_profile = init_user_and_profile()
pos_inv = create_pos_invoice(item=item, rate=300, do_not_submit=1)
pos_inv.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 300})
pos_inv.append("payments", {"mode_of_payment": "Cash", "amount": 300})
pos_inv.append(
"taxes",
{
@@ -773,7 +756,7 @@ class TestPOSInvoice(unittest.TestCase):
self.assertRaises(frappe.ValidationError, pos_inv.submit)
pos_inv2 = create_pos_invoice(item=item, rate=400, do_not_submit=1)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 400})
pos_inv2.append("payments", {"mode_of_payment": "Cash", "amount": 400})
pos_inv2.append(
"taxes",
{
@@ -818,7 +801,7 @@ class TestPOSInvoice(unittest.TestCase):
pos_inv1 = create_pos_invoice(item="_BATCH ITEM Test For Reserve", rate=300, qty=15, do_not_save=1)
pos_inv1.append(
"payments",
{"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 4500},
{"mode_of_payment": "Cash", "amount": 4500},
)
pos_inv1.items[0].batch_no = batch_no
pos_inv1.save()
@@ -839,7 +822,7 @@ class TestPOSInvoice(unittest.TestCase):
)
pos_inv2.append(
"payments",
{"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3000},
{"mode_of_payment": "Cash", "amount": 3000},
)
pos_inv2.save()
pos_inv2.submit()
@@ -879,7 +862,7 @@ class TestPOSInvoice(unittest.TestCase):
)
pos_inv1.append(
"payments",
{"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 300},
{"mode_of_payment": "Cash", "amount": 300},
)
pos_inv1.save()
pos_inv1.submit()

View File

@@ -37,6 +37,7 @@
"column_break_19",
"discount_percentage",
"discount_amount",
"distributed_discount_amount",
"base_rate_with_margin",
"section_break1",
"rate",
@@ -847,11 +848,17 @@
{
"fieldname": "column_break_ciit",
"fieldtype": "Column Break"
},
{
"fieldname": "distributed_discount_amount",
"fieldtype": "Currency",
"label": "Distributed Discount Amount",
"options": "currency"
}
],
"istable": 1,
"links": [],
"modified": "2024-05-07 15:56:53.343317",
"modified": "2024-05-07 15:56:54.343317",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice Item",

View File

@@ -39,6 +39,7 @@ class POSInvoiceItem(Document):
description: DF.TextEditor
discount_amount: DF.Currency
discount_percentage: DF.Percent
distributed_discount_amount: DF.Currency
dn_detail: DF.Data | None
enable_deferred_revenue: DF.Check
expense_account: DF.Link | None

View File

@@ -5,6 +5,7 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"company",
"posting_date",
"posting_time",
"merge_invoices_based_on",
@@ -113,12 +114,22 @@
"label": "Posting Time",
"no_copy": 1,
"reqd": 1
},
{
"fieldname": "company",
"fieldtype": "Link",
"in_standard_filter": 1,
"label": "Company",
"options": "Company",
"print_hide": 1,
"remember_last_selected_value": 1,
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2022-08-01 11:36:42.456429",
"modified": "2025-07-02 17:08:04.747202",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice Merge Log",
@@ -179,8 +190,9 @@
"write": 1
}
],
"sort_field": "modified",
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -2,6 +2,7 @@
# For license information, please see license.txt
import hashlib
import json
import frappe
@@ -27,11 +28,10 @@ class POSInvoiceMergeLog(Document):
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.pos_invoice_reference.pos_invoice_reference import (
POSInvoiceReference,
)
from erpnext.accounts.doctype.pos_invoice_reference.pos_invoice_reference import POSInvoiceReference
amended_from: DF.Link | None
company: DF.Link
consolidated_credit_note: DF.Link | None
consolidated_invoice: DF.Link | None
customer: DF.Link
@@ -257,6 +257,7 @@ class POSInvoiceMergeLog(Document):
if not found:
tax.charge_type = "Actual"
tax.idx = idx
tax.row_id = None
idx += 1
tax.included_in_print_rate = 0
tax.tax_amount = tax.tax_amount_after_discount_amount
@@ -302,10 +303,17 @@ class POSInvoiceMergeLog(Document):
accounting_dimensions = get_checks_for_pl_and_bs_accounts()
accounting_dimensions_fields = [d.fieldname for d in accounting_dimensions]
dimension_values = frappe.db.get_value(
"POS Profile", {"name": invoice.pos_profile}, accounting_dimensions_fields, as_dict=1
"POS Profile",
{"name": invoice.pos_profile},
[*accounting_dimensions_fields, "cost_center", "project"],
as_dict=1,
)
for dimension in accounting_dimensions:
dimension_value = dimension_values.get(dimension.fieldname)
dimension_value = (
data[0].get(dimension.fieldname)
if data[0].get(dimension.fieldname)
else dimension_values.get(dimension.fieldname)
)
if not dimension_value and (dimension.mandatory_for_pl or dimension.mandatory_for_bs):
frappe.throw(
@@ -317,6 +325,14 @@ class POSInvoiceMergeLog(Document):
invoice.set(dimension.fieldname, dimension_value)
invoice.set(
"cost_center",
data[0].get("cost_center") if data[0].get("cost_center") else dimension_values.get("cost_center"),
)
invoice.set(
"project", data[0].get("project") if data[0].get("project") else dimension_values.get("project")
)
if self.merge_invoices_based_on == "Customer Group":
invoice.flags.ignore_pos_profile = True
invoice.pos_profile = ""
@@ -336,7 +352,7 @@ class POSInvoiceMergeLog(Document):
for doc in invoice_docs:
doc.load_from_db()
inv = sales_invoice
if doc.is_return:
if doc.is_return and credit_notes:
for key, value in credit_notes.items():
if doc.name in value:
inv = key
@@ -446,9 +462,34 @@ def get_invoice_customer_map(pos_invoices):
pos_invoice_customer_map.setdefault(customer, [])
pos_invoice_customer_map[customer].append(invoice)
for customer, invoices in pos_invoice_customer_map.items():
pos_invoice_customer_map[customer] = split_invoices_by_accounting_dimension(invoices)
return pos_invoice_customer_map
def split_invoices_by_accounting_dimension(pos_invoices):
# pos_invoices = {
# {'dim_field1': 'dim_field1_value1', 'dim_field2': 'dim_field2_value1'}: [],
# {'dim_field1': 'dim_field1_value2', 'dim_field2': 'dim_field2_value1'}: []
# }
pos_invoice_accounting_dimensions_map = {}
for invoice in pos_invoices:
dimension_fields = [d.fieldname for d in get_checks_for_pl_and_bs_accounts()]
accounting_dimensions = frappe.db.get_value(
"POS Invoice", invoice.pos_invoice, [*dimension_fields, "cost_center", "project"], as_dict=1
)
accounting_dimensions_dic_hash = hashlib.sha256(
json.dumps(accounting_dimensions).encode()
).hexdigest()
pos_invoice_accounting_dimensions_map.setdefault(accounting_dimensions_dic_hash, [])
pos_invoice_accounting_dimensions_map[accounting_dimensions_dic_hash].append(invoice)
return pos_invoice_accounting_dimensions_map
def consolidate_pos_invoices(pos_invoices=None, closing_entry=None):
invoices = pos_invoices or (closing_entry and closing_entry.get("pos_transactions"))
if frappe.flags.in_test and not invoices:
@@ -532,20 +573,22 @@ def split_invoices(invoices):
def create_merge_logs(invoice_by_customer, closing_entry=None):
try:
for customer, invoices in invoice_by_customer.items():
for _invoices in split_invoices(invoices):
merge_log = frappe.new_doc("POS Invoice Merge Log")
merge_log.posting_date = (
getdate(closing_entry.get("posting_date")) if closing_entry else nowdate()
)
merge_log.posting_time = (
get_time(closing_entry.get("posting_time")) if closing_entry else nowtime()
)
merge_log.customer = customer
merge_log.pos_closing_entry = closing_entry.get("name") if closing_entry else None
merge_log.set("pos_invoices", _invoices)
merge_log.save(ignore_permissions=True)
merge_log.submit()
for customer, invoices_acc_dim in invoice_by_customer.items():
for invoices in invoices_acc_dim.values():
for _invoices in split_invoices(invoices):
merge_log = frappe.new_doc("POS Invoice Merge Log")
merge_log.posting_date = (
getdate(closing_entry.get("posting_date")) if closing_entry else nowdate()
)
merge_log.posting_time = (
get_time(closing_entry.get("posting_time")) if closing_entry else nowtime()
)
merge_log.company = closing_entry.get("company") if closing_entry else None
merge_log.customer = customer
merge_log.pos_closing_entry = closing_entry.get("name") if closing_entry else None
merge_log.set("pos_invoices", _invoices)
merge_log.save(ignore_permissions=True)
merge_log.submit()
if closing_entry:
closing_entry.set_status(update=True, status="Submitted")
closing_entry.db_set("error_message", "")

View File

@@ -455,3 +455,58 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
frappe.set_user("Administrator")
frappe.db.sql("delete from `tabPOS Profile`")
frappe.db.sql("delete from `tabPOS Invoice`")
def test_separate_consolidated_invoice_for_different_accounting_dimensions(self):
"""
Creating 3 POS Invoices where first POS Invoice has different Cost Center than the other two.
Consolidate the Invoices.
Check whether the first POS Invoice is consolidated with a separate Sales Invoice than the other two.
Check whether the second and third POS Invoice are consolidated with the same Sales Invoice.
"""
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
frappe.db.sql("delete from `tabPOS Invoice`")
create_cost_center(cost_center_name="_Test POS Cost Center 1", is_group=0)
create_cost_center(cost_center_name="_Test POS Cost Center 2", is_group=0)
try:
test_user, pos_profile = init_user_and_profile()
pos_inv = create_pos_invoice(rate=300, do_not_submit=1)
pos_inv.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 300})
pos_inv.cost_center = "_Test POS Cost Center 1 - _TC"
pos_inv.save()
pos_inv.submit()
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200})
pos_inv.cost_center = "_Test POS Cost Center 2 - _TC"
pos_inv2.save()
pos_inv2.submit()
pos_inv3 = create_pos_invoice(rate=2300, do_not_submit=1)
pos_inv3.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 2300})
pos_inv.cost_center = "_Test POS Cost Center 2 - _TC"
pos_inv3.save()
pos_inv3.submit()
consolidate_pos_invoices()
pos_inv.load_from_db()
self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv.consolidated_invoice))
pos_inv2.load_from_db()
self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv2.consolidated_invoice))
self.assertFalse(pos_inv.consolidated_invoice == pos_inv3.consolidated_invoice)
pos_inv3.load_from_db()
self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv3.consolidated_invoice))
self.assertTrue(pos_inv2.consolidated_invoice == pos_inv3.consolidated_invoice)
finally:
frappe.set_user("Administrator")
frappe.db.sql("delete from `tabPOS Profile`")
frappe.db.sql("delete from `tabPOS Invoice`")

View File

@@ -169,7 +169,7 @@ class PricingRule(Document):
tocheck = frappe.scrub(self.get("applicable_for", ""))
if tocheck and not self.get(tocheck):
throw(_("{0} is required").format(self.meta.get_label(tocheck)), frappe.MandatoryError)
throw(_("{0} is required").format(_(self.meta.get_label(tocheck))), frappe.MandatoryError)
if self.apply_rule_on_other:
o_field = "other_" + frappe.scrub(self.apply_rule_on_other)

View File

@@ -205,6 +205,56 @@ class TestPricingRule(FrappeTestCase):
details = get_item_details(args)
self.assertEqual(details.get("discount_percentage"), 10)
def test_unset_group_condition(self):
"""
If args are not set for group condition, then pricing rule should not be applied.
"""
from erpnext.stock.get_item_details import get_item_details
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule",
"apply_on": "Item Code",
"items": [{"item_code": "_Test Item"}],
"currency": "USD",
"selling": 1,
"rate_or_discount": "Discount Percentage",
"rate": 0,
"discount_percentage": 10,
"applicable_for": "Territory",
"territory": "All Territories",
"company": "_Test Company",
}
frappe.get_doc(test_record.copy()).insert()
args = frappe._dict(
{
"item_code": "_Test Item",
"company": "_Test Company",
"price_list": "_Test Price List",
"currency": "_Test Currency",
"doctype": "Sales Order",
"conversion_rate": 1,
"price_list_currency": "_Test Currency",
"plc_conversion_rate": 1,
"order_type": "Sales",
"customer": "_Test Customer",
"name": None,
}
)
# without territory in customer
customer = frappe.get_doc("Customer", "_Test Customer")
territory = customer.territory
customer.territory = None
customer.save()
details = get_item_details(args)
self.assertEqual(details.get("discount_percentage"), 0)
customer.territory = territory
customer.save()
def test_pricing_rule_for_variants(self):
from erpnext.stock.get_item_details import get_item_details

View File

@@ -223,6 +223,10 @@ def _get_tree_conditions(args, parenttype, table, allow_blank=True):
)
frappe.flags.tree_conditions[key] = condition
elif allow_blank:
condition = f"ifnull({table}.{field}, '') = ''"
return condition

View File

@@ -40,6 +40,13 @@ class TestProcessDeferredAccounting(unittest.TestCase):
si.save()
si.submit()
original_gle = [
["Debtors - _TC", 3000.0, 0, "2023-07-01"],
[deferred_account, 0.0, 3000, "2023-07-01"],
]
check_gl_entries(self, si.name, original_gle, "2023-07-01")
process_deferred_accounting = frappe.get_doc(
dict(
doctype="Process Deferred Accounting",
@@ -63,6 +70,12 @@ class TestProcessDeferredAccounting(unittest.TestCase):
]
check_gl_entries(self, si.name, expected_gle, "2023-07-01")
# cancel the process deferred accounting document
process_deferred_accounting.cancel()
# check if gl entries are cancelled
check_gl_entries(self, si.name, original_gle, "2023-07-01")
change_acc_settings()
def test_pda_submission_and_cancellation(self):

View File

@@ -54,6 +54,29 @@ frappe.ui.form.on("Process Statement Of Accounts", {
};
});
frm.set_query("account", function () {
if (!frm.doc.company) {
frappe.throw(__("Please set Company"));
}
return {
filters: {
company: frm.doc.company,
},
};
});
frm.set_query("cost_center", function () {
if (!frm.doc.company) {
frappe.throw(__("Please set Company"));
}
return {
filters: {
company: frm.doc.company,
},
};
});
frm.set_query("project", function () {
if (!frm.doc.company) {
frappe.throw(__("Please set Company"));
}
return {
filters: {
company: frm.doc.company,
@@ -65,6 +88,11 @@ frappe.ui.form.on("Process Statement Of Accounts", {
frm.set_value("to_date", frappe.datetime.get_today());
}
},
company: function (frm) {
frm.set_value("account", "");
frm.set_value("cost_center", "");
frm.set_value("project", "");
},
report: function (frm) {
let filters = {
company: frm.doc.company,

View File

@@ -12,7 +12,7 @@
"posting_date",
"company",
"account",
"group_by",
"categorize_by",
"cost_center",
"territory",
"ignore_exchange_rate_revaluation_journals",
@@ -174,14 +174,6 @@
"fieldtype": "Date",
"label": "Start Date"
},
{
"default": "Group by Voucher (Consolidated)",
"depends_on": "eval:(doc.report == 'General Ledger');",
"fieldname": "group_by",
"fieldtype": "Select",
"label": "Group By",
"options": "\nGroup by Voucher\nGroup by Voucher (Consolidated)"
},
{
"depends_on": "eval: (doc.report == 'General Ledger');",
"fieldname": "currency",
@@ -384,7 +376,7 @@
"default": "0",
"fieldname": "ignore_exchange_rate_revaluation_journals",
"fieldtype": "Check",
"label": "Ignore Exchange Rate Revaluation Journals"
"label": "Ignore Exchange Rate Revaluation and Gain / Loss Journals"
},
{
"default": "0",
@@ -397,10 +389,18 @@
"fieldname": "show_remarks",
"fieldtype": "Check",
"label": "Show Remarks"
},
{
"default": "Categorize by Voucher (Consolidated)",
"depends_on": "eval:(doc.report == 'General Ledger');",
"fieldname": "categorize_by",
"fieldtype": "Select",
"label": "Categorize By",
"options": "\nCategorize by Voucher\nCategorize by Voucher (Consolidated)"
}
],
"links": [],
"modified": "2024-12-11 12:11:13.543134",
"modified": "2025-07-08 16:52:12.602384",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",
@@ -436,4 +436,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -44,6 +44,7 @@ class ProcessStatementOfAccounts(Document):
ageing_based_on: DF.Literal["Due Date", "Posting Date"]
based_on_payment_terms: DF.Check
body: DF.TextEditor | None
categorize_by: DF.Literal["", "Categorize by Voucher", "Categorize by Voucher (Consolidated)"]
cc_to: DF.TableMultiSelect[ProcessStatementOfAccountsCC]
collection_name: DF.DynamicLink | None
company: DF.Link
@@ -56,7 +57,6 @@ class ProcessStatementOfAccounts(Document):
finance_book: DF.Link | None
frequency: DF.Literal["Weekly", "Monthly", "Quarterly"]
from_date: DF.Date | None
group_by: DF.Literal["", "Group by Voucher", "Group by Voucher (Consolidated)"]
ignore_cr_dr_notes: DF.Check
ignore_exchange_rate_revaluation_journals: DF.Check
include_ageing: DF.Check
@@ -82,6 +82,10 @@ class ProcessStatementOfAccounts(Document):
# end: auto-generated types
def validate(self):
self.validate_account()
self.validate_company_for_table("Cost Center")
self.validate_company_for_table("Project")
if not self.subject:
self.subject = "Statement Of Accounts for {{ customer.customer_name }}"
if not self.body:
@@ -104,6 +108,43 @@ class ProcessStatementOfAccounts(Document):
self.to_date = self.start_date
self.from_date = add_months(self.to_date, -1 * self.filter_duration)
def validate_account(self):
if not self.account:
return
if self.company != frappe.get_cached_value("Account", self.account, "company"):
frappe.throw(
_("Account {0} doesn't belong to Company {1}").format(
frappe.bold(self.account),
frappe.bold(self.company),
)
)
def validate_company_for_table(self, doctype):
field = frappe.scrub(doctype)
if not self.get(field):
return
fieldname = field + "_name"
values = set(d.get(fieldname) for d in self.get(field))
invalid_values = frappe.db.get_all(
doctype, filters={"name": ["in", values], "company": ["!=", self.company]}, pluck="name"
)
if invalid_values:
msg = _("<p>Following {0}s doesn't belong to Company {1} :</p>").format(
doctype, frappe.bold(self.company)
)
msg += (
"<ul>"
+ "".join(_("<li>{}</li>").format(frappe.bold(row)) for row in invalid_values)
+ "</ul>"
)
frappe.throw(_(msg))
def get_report_pdf(doc, consolidated=True):
statement_dict = get_statement_dict(doc)
@@ -129,8 +170,8 @@ def get_statement_dict(doc, get_statement_dict=False):
tax_id = frappe.get_doc("Customer", entry.customer).tax_id
presentation_currency = (
get_party_account_currency("Customer", entry.customer, doc.company)
or doc.currency
doc.currency
or get_party_account_currency("Customer", entry.customer, doc.company)
or get_company_currency(doc.company)
)
@@ -204,7 +245,7 @@ def get_gl_filters(doc, entry, tax_id, presentation_currency):
"party": [entry.customer],
"party_name": [entry.customer_name] if entry.customer_name else None,
"presentation_currency": presentation_currency,
"group_by": doc.group_by,
"categorize_by": doc.categorize_by,
"currency": doc.currency,
"project": [p.project_name for p in doc.project],
"show_opening_entries": 0,

View File

@@ -211,7 +211,7 @@
<tr>
{% if(report.report_name == "Accounts Receivable" or report.report_name == "Accounts Payable") %}
{% if(data[i]["party"]) %}
<td>{{ (data[i]["posting_date"]) }}</td>
<td>{{ frappe.format((data[i]["posting_date"]), 'Date') }}</td>
<td style="text-align: right">{{ data[i]["age"] }}</td>
<td>
{% if not(filters.show_future_payments) %}

View File

@@ -97,6 +97,7 @@ def create_process_soa(**args):
company=args.company or "_Test Company",
customers=args.customers or [{"customer": "_Test Customer"}],
enable_auto_email=1 if args.enable_auto_email else 0,
currency=args.currency or "",
frequency=args.frequency or "Weekly",
report=args.report or "General Ledger",
from_date=args.from_date or getdate(today()),

View File

@@ -425,6 +425,8 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
this.frm.set_value("is_paid", 0);
frappe.msgprint(__("Please specify Company to proceed"));
}
} else {
this.frm.set_value("paid_amount", 0);
}
this.calculate_outstanding_amount();
this.frm.refresh_fields();

View File

@@ -143,8 +143,10 @@
"contact_mobile",
"contact_email",
"company_shipping_address_section",
"shipping_address",
"dispatch_address",
"dispatch_address_display",
"column_break_126",
"shipping_address",
"shipping_address_display",
"company_billing_address_section",
"billing_address",
@@ -1546,7 +1548,7 @@
{
"fieldname": "company_shipping_address_section",
"fieldtype": "Section Break",
"label": "Company Shipping Address"
"label": "Shipping Address"
},
{
"fieldname": "column_break_126",
@@ -1627,13 +1629,28 @@
"fieldname": "update_outstanding_for_self",
"fieldtype": "Check",
"label": "Update Outstanding for Self"
},
{
"fieldname": "dispatch_address_display",
"fieldtype": "Text Editor",
"label": "Dispatch Address",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "dispatch_address",
"fieldtype": "Link",
"label": "Select Dispatch Address ",
"options": "Address",
"print_hide": 1
}
],
"grid_page_length": 50,
"icon": "fa fa-file-text",
"idx": 204,
"is_submittable": 1,
"links": [],
"modified": "2025-01-14 11:39:04.564610",
"modified": "2025-04-09 16:49:22.175081",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
@@ -1688,6 +1705,7 @@
"write": 1
}
],
"row_format": "Dynamic",
"search_fields": "posting_date, supplier, bill_no, base_grand_total, outstanding_amount",
"show_name_in_global_search": 1,
"sort_field": "modified",

View File

@@ -117,6 +117,8 @@ class PurchaseInvoice(BuyingController):
currency: DF.Link | None
disable_rounded_total: DF.Check
discount_amount: DF.Currency
dispatch_address: DF.Link | None
dispatch_address_display: DF.TextEditor | None
due_date: DF.Date | None
from_date: DF.Date | None
grand_total: DF.Currency
@@ -1224,7 +1226,7 @@ class PurchaseInvoice(BuyingController):
pr_items = frappe.get_all(
"Purchase Receipt Item",
filters={"parent": ("in", linked_purchase_receipts)},
fields=["name", "provisional_expense_account", "qty", "base_rate"],
fields=["name", "provisional_expense_account", "qty", "base_rate", "rate"],
)
default_provisional_account = self.get_company_default("default_provisional_account")
provisional_accounts = set(
@@ -1252,6 +1254,7 @@ class PurchaseInvoice(BuyingController):
"provisional_account": item.provisional_expense_account or default_provisional_account,
"qty": item.qty,
"base_rate": item.base_rate,
"rate": item.rate,
"has_provisional_entry": item.name in rows_with_provisional_entries,
}
@@ -1268,7 +1271,10 @@ class PurchaseInvoice(BuyingController):
self.posting_date,
pr_item.get("provisional_account"),
reverse=1,
item_amount=(min(item.qty, pr_item.get("qty")) * pr_item.get("base_rate")),
item_amount=(
(min(item.qty, pr_item.get("qty")) * pr_item.get("rate"))
* purchase_receipt_doc.get("conversion_rate")
),
)
def update_gross_purchase_amount_for_linked_assets(self, item):
@@ -1330,17 +1336,12 @@ class PurchaseInvoice(BuyingController):
warehouse_debit_amount = stock_amount
elif self.is_return and self.update_stock and self.is_internal_supplier and warehouse_debit_amount:
elif self.is_return and self.update_stock and (self.is_internal_supplier or not self.return_against):
net_rate = item.base_net_amount
if item.sales_incoming_rate: # for internal transfer
net_rate = item.qty * item.sales_incoming_rate
stock_amount = (
net_rate
+ item.item_tax_amount
+ flt(item.landed_cost_voucher_amount)
+ flt(item.get("amount_difference_with_purchase_invoice"))
)
stock_amount = net_rate + item.item_tax_amount + flt(item.landed_cost_voucher_amount)
if flt(stock_amount, net_amt_precision) != flt(warehouse_debit_amount, net_amt_precision):
cost_of_goods_sold_account = self.get_company_default("default_expense_account")

View File

@@ -16,7 +16,7 @@ from erpnext.buying.doctype.purchase_order.test_purchase_order import (
create_purchase_order,
)
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
from erpnext.controllers.accounts_controller import get_payment_terms
from erpnext.controllers.accounts_controller import InvalidQtyError, get_payment_terms
from erpnext.controllers.buying_controller import QtyMismatchError
from erpnext.exceptions import InvalidCurrency
from erpnext.projects.doctype.project.test_project import make_project
@@ -55,6 +55,16 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
def tearDown(self):
frappe.db.rollback()
def test_purchase_invoice_qty(self):
pi = make_purchase_invoice(qty=0, do_not_save=True)
with self.assertRaises(InvalidQtyError):
pi.save()
# No error with qty=1
pi.items[0].qty = 1
pi.save()
self.assertEqual(pi.items[0].qty, 1)
def test_purchase_invoice_received_qty(self):
"""
1. Test if received qty is validated against accepted + rejected
@@ -1653,7 +1663,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
pi = create_purchase_invoice_from_receipt(pr.name)
pi.set_posting_time = 1
pi.posting_date = add_days(pr.posting_date, -1)
pi.posting_date = add_days(pr.posting_date, 1)
pi.items[0].expense_account = "Cost of Goods Sold - _TC"
pi.save()
pi.submit()
@@ -1662,30 +1672,38 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
# Check GLE for Purchase Invoice
expected_gle = [
["Cost of Goods Sold - _TC", 250, 0, add_days(pr.posting_date, -1)],
["Creditors - _TC", 0, 250, add_days(pr.posting_date, -1)],
["Cost of Goods Sold - _TC", 250, 0, add_days(pr.posting_date, 1)],
["Creditors - _TC", 0, 250, add_days(pr.posting_date, 1)],
]
check_gl_entries(self, pi.name, expected_gle, pi.posting_date)
expected_gle_for_purchase_receipt = [
["Provision Account - _TC", 250, 0, pr.posting_date],
["_Test Account Cost for Goods Sold - _TC", 0, 250, pr.posting_date],
["Provision Account - _TC", 0, 250, pi.posting_date],
["_Test Account Cost for Goods Sold - _TC", 250, 0, pi.posting_date],
["_Test Account Cost for Goods Sold - _TC", 250, 0, pr.posting_date],
["Provision Account - _TC", 0, 250, pr.posting_date],
["_Test Account Cost for Goods Sold - _TC", 0, 250, pi.posting_date],
["Provision Account - _TC", 250, 0, pi.posting_date],
]
check_gl_entries(self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date)
check_gl_entries(
self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date, voucher_type="Purchase Receipt"
)
# Cancel purchase invoice to check reverse provisional entry cancellation
pi.cancel()
expected_gle_for_purchase_receipt_post_pi_cancel = [
["Provision Account - _TC", 0, 250, pi.posting_date],
["_Test Account Cost for Goods Sold - _TC", 250, 0, pi.posting_date],
["Provision Account - _TC", 0, 250, pi.posting_date],
]
check_gl_entries(self, pr.name, expected_gle_for_purchase_receipt_post_pi_cancel, pr.posting_date)
check_gl_entries(
self,
pr.name,
expected_gle_for_purchase_receipt_post_pi_cancel,
pi.posting_date,
voucher_type="Purchase Receipt",
)
toggle_provisional_accounting_setting()
@@ -1695,6 +1713,9 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
# Configure Buying Settings to allow rate change
frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 0)
# Configure Accounts Settings to allow 300% over billing
frappe.db.set_single_value("Accounts Settings", "over_billing_allowance", 300)
# Create PR: rate = 1000, qty = 5
pr = make_purchase_receipt(
item_code="_Test Non Stock Item", rate=1000, posting_date=add_days(nowdate(), -2)
@@ -1703,7 +1724,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
# Overbill PR: rate = 2000, qty = 10
pi = create_purchase_invoice_from_receipt(pr.name)
pi.set_posting_time = 1
pi.posting_date = add_days(pr.posting_date, -1)
pi.posting_date = add_days(pr.posting_date, 1)
pi.items[0].qty = 10
pi.items[0].rate = 2000
pi.items[0].expense_account = "Cost of Goods Sold - _TC"
@@ -1711,30 +1732,38 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
pi.submit()
expected_gle = [
["Cost of Goods Sold - _TC", 20000, 0, add_days(pr.posting_date, -1)],
["Creditors - _TC", 0, 20000, add_days(pr.posting_date, -1)],
["Cost of Goods Sold - _TC", 20000, 0, add_days(pr.posting_date, 1)],
["Creditors - _TC", 0, 20000, add_days(pr.posting_date, 1)],
]
check_gl_entries(self, pi.name, expected_gle, pi.posting_date)
expected_gle_for_purchase_receipt = [
["Provision Account - _TC", 5000, 0, pr.posting_date],
["_Test Account Cost for Goods Sold - _TC", 0, 5000, pr.posting_date],
["Provision Account - _TC", 0, 5000, pi.posting_date],
["_Test Account Cost for Goods Sold - _TC", 5000, 0, pi.posting_date],
["_Test Account Cost for Goods Sold - _TC", 5000, 0, pr.posting_date],
["Provision Account - _TC", 0, 5000, pr.posting_date],
["_Test Account Cost for Goods Sold - _TC", 0, 5000, pi.posting_date],
["Provision Account - _TC", 5000, 0, pi.posting_date],
]
check_gl_entries(self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date)
check_gl_entries(
self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date, voucher_type="Purchase Receipt"
)
# Cancel purchase invoice to check reverse provisional entry cancellation
pi.cancel()
expected_gle_for_purchase_receipt_post_pi_cancel = [
["Provision Account - _TC", 0, 5000, pi.posting_date],
["_Test Account Cost for Goods Sold - _TC", 5000, 0, pi.posting_date],
["Provision Account - _TC", 0, 5000, pi.posting_date],
]
check_gl_entries(self, pr.name, expected_gle_for_purchase_receipt_post_pi_cancel, pr.posting_date)
check_gl_entries(
self,
pr.name,
expected_gle_for_purchase_receipt_post_pi_cancel,
pi.posting_date,
voucher_type="Purchase Receipt",
)
toggle_provisional_accounting_setting()
@@ -1767,13 +1796,76 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
check_gl_entries(self, pi.name, expected_gle, pi.posting_date)
expected_gle_for_purchase_receipt = [
["Provision Account - _TC", 5000, 0, pr.posting_date],
["_Test Account Cost for Goods Sold - _TC", 0, 5000, pr.posting_date],
["Provision Account - _TC", 0, 1000, pi.posting_date],
["_Test Account Cost for Goods Sold - _TC", 1000, 0, pi.posting_date],
["_Test Account Cost for Goods Sold - _TC", 5000, 0, pr.posting_date],
["Provision Account - _TC", 0, 5000, pr.posting_date],
["_Test Account Cost for Goods Sold - _TC", 0, 1000, pi.posting_date],
["Provision Account - _TC", 1000, 0, pi.posting_date],
]
check_gl_entries(self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date)
check_gl_entries(
self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date, voucher_type="Purchase Receipt"
)
toggle_provisional_accounting_setting()
def test_provisional_accounting_entry_multi_currency(self):
setup_provisional_accounting()
pr = make_purchase_receipt(
item_code="_Test Non Stock Item",
posting_date=add_days(nowdate(), -2),
qty=1000,
rate=111.11,
currency="USD",
do_not_save=1,
supplier="_Test Supplier USD",
)
pr.conversion_rate = 0.014783000
pr.save()
pr.submit()
pi = create_purchase_invoice_from_receipt(pr.name)
pi.set_posting_time = 1
pi.posting_date = add_days(pr.posting_date, 1)
pi.items[0].expense_account = "Cost of Goods Sold - _TC"
pi.save()
pi.submit()
self.assertEqual(pr.items[0].provisional_expense_account, "Provision Account - _TC")
# Check GLE for Purchase Invoice
expected_gle = [
["_Test Payable USD - _TC", 0, 1642.54, add_days(pr.posting_date, 1)],
["Cost of Goods Sold - _TC", 1642.54, 0, add_days(pr.posting_date, 1)],
]
check_gl_entries(self, pi.name, expected_gle, pi.posting_date)
expected_gle_for_purchase_receipt = [
["_Test Account Cost for Goods Sold - _TC", 1642.54, 0, pr.posting_date],
["Provision Account - _TC", 0, 1642.54, pr.posting_date],
["_Test Account Cost for Goods Sold - _TC", 0, 1642.54, pi.posting_date],
["Provision Account - _TC", 1642.54, 0, pi.posting_date],
]
check_gl_entries(
self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date, voucher_type="Purchase Receipt"
)
# Cancel purchase invoice to check reverse provisional entry cancellation
pi.cancel()
expected_gle_for_purchase_receipt_post_pi_cancel = [
["_Test Account Cost for Goods Sold - _TC", 1642.54, 0, pi.posting_date],
["Provision Account - _TC", 0, 1642.54, pi.posting_date],
]
check_gl_entries(
self,
pr.name,
expected_gle_for_purchase_receipt_post_pi_cancel,
pi.posting_date,
voucher_type="Purchase Receipt",
)
toggle_provisional_accounting_setting()
@@ -2688,13 +2780,13 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
To test if after applying discount on grand total,
the grand total is calculated correctly without any rounding errors
"""
invoice = make_purchase_invoice(qty=2, rate=100, do_not_save=True, do_not_submit=True)
invoice = make_purchase_invoice(qty=3, rate=100, do_not_save=True, do_not_submit=True)
invoice.append(
"items",
{
"item_code": "_Test Item",
"qty": 1,
"rate": 21.39,
"qty": 3,
"rate": 50.3,
},
)
invoice.append(
@@ -2703,18 +2795,19 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
"charge_type": "On Net Total",
"account_head": "_Test Account VAT - _TC",
"description": "VAT",
"rate": 15.5,
"rate": 15,
},
)
# the grand total here will be 255.71
# the grand total here will be 518.54
invoice.disable_rounded_total = 1
# apply discount on grand total to adjust the grand total to 255
invoice.discount_amount = 0.71
# apply discount on grand total to adjust the grand total to 518
invoice.discount_amount = 0.54
invoice.save()
# check if grand total is 496 and not something like 254.99 due to rounding errors
self.assertEqual(invoice.grand_total, 255)
# check if grand total is 518 and not something like 517.99 due to rounding errors
self.assertEqual(invoice.grand_total, 518)
def test_apply_discount_on_grand_total_with_previous_row_total_tax(self):
"""
@@ -2755,6 +2848,54 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
self.assertEqual(invoice.grand_total, 300)
def test_pr_pi_over_billing(self):
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
make_purchase_invoice as make_purchase_invoice_from_pr,
)
# Configure Buying Settings to allow rate change
frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 0)
pr = make_purchase_receipt(qty=10, rate=10)
pi = make_purchase_invoice_from_pr(pr.name)
pi.items[0].rate = 12
# Test 1 - This will fail because over billing is not allowed
self.assertRaises(frappe.ValidationError, pi.submit)
frappe.db.set_single_value("Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 1)
# Test 2 - This will now submit because over billing allowance is ignored when set_landed_cost_based_on_purchase_invoice_rate is checked
pi.submit()
frappe.db.set_single_value("Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 0)
frappe.db.set_single_value("Accounts Settings", "over_billing_allowance", 20)
pi.cancel()
pi = make_purchase_invoice_from_pr(pr.name)
pi.items[0].rate = 12
# Test 3 - This will now submit because over billing is allowed upto 20%
pi.submit()
pi.reload()
pi.cancel()
pi = make_purchase_invoice_from_pr(pr.name)
pi.items[0].rate = 13
# Test 4 - Since this PI is overbilled by 130% and only 120% is allowed, it will fail
self.assertRaises(frappe.ValidationError, pi.submit)
def test_discount_percentage_not_set_when_amount_is_manually_set(self):
pi = make_purchase_invoice(do_not_save=True)
discount_amount = 7
pi.discount_amount = discount_amount
pi.save()
self.assertEqual(pi.additional_discount_percentage, None)
pi.set_posting_time = 1
pi.posting_date = add_days(today(), -1)
pi.save()
self.assertEqual(pi.discount_amount, discount_amount)
def set_advance_flag(company, flag, default_account):
frappe.db.set_value(
@@ -2864,7 +3005,7 @@ def make_purchase_invoice(**args):
bundle_id = None
if not args.use_serial_batch_fields and (args.get("batch_no") or args.get("serial_no")):
batches = {}
qty = args.qty or 5
qty = args.qty if args.qty is not None else 5
item_code = args.item or args.item_code or "_Test Item"
if args.get("batch_no"):
batches = frappe._dict({args.batch_no: qty})
@@ -2893,7 +3034,7 @@ def make_purchase_invoice(**args):
"item_code": args.item or args.item_code or "_Test Item",
"item_name": args.item_name,
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"qty": args.qty or 5,
"qty": args.qty if args.qty is not None else 5,
"received_qty": args.received_qty or 0,
"rejected_qty": args.rejected_qty or 0,
"rate": args.rate or 50,

View File

@@ -38,6 +38,7 @@
"column_break_30",
"discount_percentage",
"discount_amount",
"distributed_discount_amount",
"base_rate_with_margin",
"sec_break2",
"rate",
@@ -840,7 +841,7 @@
},
{
"collapsible": 1,
"collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount",
"collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount || doc.distributed_discount_amount",
"fieldname": "section_break_26",
"fieldtype": "Section Break",
"label": "Discount and Margin"
@@ -971,12 +972,18 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1
},
{
"fieldname": "distributed_discount_amount",
"fieldtype": "Currency",
"label": "Distributed Discount Amount",
"options": "currency"
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2025-03-12 16:33:12.453290",
"modified": "2025-03-12 16:33:13.453290",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",

View File

@@ -34,6 +34,7 @@ class PurchaseInvoiceItem(Document):
description: DF.TextEditor | None
discount_amount: DF.Currency
discount_percentage: DF.Percent
distributed_discount_amount: DF.Currency
enable_deferred_expense: DF.Check
expense_account: DF.Link | None
from_warehouse: DF.Link | None

View File

@@ -196,7 +196,7 @@
"fieldname": "item_wise_tax_detail",
"fieldtype": "Code",
"hidden": 1,
"label": "Item Wise Tax Detail ",
"label": "Item Wise Tax Detail",
"oldfieldname": "item_wise_tax_detail",
"oldfieldtype": "Small Text",
"print_hide": 1,
@@ -235,10 +235,11 @@
"read_only": 1
}
],
"grid_page_length": 50,
"idx": 1,
"istable": 1,
"links": [],
"modified": "2024-04-08 19:51:36.678551",
"modified": "2025-04-15 13:14:48.936047",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Taxes and Charges",

View File

@@ -782,24 +782,6 @@ frappe.ui.form.on("Sales Invoice", {
};
};
},
// When multiple companies are set up. in case company name is changed set default company address
company: function (frm) {
if (frm.doc.company) {
frappe.call({
method: "erpnext.setup.doctype.company.company.get_default_company_address",
args: { name: frm.doc.company, existing_address: frm.doc.company_address || "" },
debounce: 2000,
callback: function (r) {
if (r.message) {
frm.set_value("company_address", r.message);
} else {
frm.set_value("company_address", "");
}
},
});
}
},
onload: function (frm) {
frm.redemption_conversion_factor = null;
},
@@ -1102,6 +1084,18 @@ frappe.ui.form.on("Sales Invoice Timesheet", {
},
});
frappe.ui.form.on("Sales Invoice Payment", {
mode_of_payment: function (frm) {
frappe.call({
doc: frm.doc,
method: "set_account_for_mode_of_payment",
callback: function (r) {
refresh_field("payments");
},
});
},
});
var set_timesheet_detail_rate = function (cdt, cdn, currency, timelog) {
frappe.call({
method: "erpnext.projects.doctype.timesheet.timesheet.get_timesheet_detail_rate",

View File

@@ -2024,6 +2024,7 @@
"fieldname": "amount_eligible_for_commission",
"fieldtype": "Currency",
"label": "Amount Eligible for Commission",
"options": "Company:company:default_currency",
"read_only": 1
},
{
@@ -2188,7 +2189,7 @@
"link_fieldname": "consolidated_invoice"
}
],
"modified": "2025-03-17 19:32:31.809658",
"modified": "2025-06-26 14:06:56.773552",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -751,10 +751,10 @@ class SalesInvoice(SellingController):
self.paid_amount = paid_amount
self.base_paid_amount = base_paid_amount
@frappe.whitelist()
def set_account_for_mode_of_payment(self):
for payment in self.payments:
if not payment.account:
payment.account = get_bank_cash_account(payment.mode_of_payment, self.company).get("account")
payment.account = get_bank_cash_account(payment.mode_of_payment, self.company).get("account")
def validate_time_sheets_are_submitted(self):
for data in self.timesheets:
@@ -1348,7 +1348,7 @@ class SalesInvoice(SellingController):
)
for item in self.get("items"):
if flt(item.base_net_amount, item.precision("base_net_amount")):
if flt(item.base_net_amount, item.precision("base_net_amount")) or item.is_fixed_asset:
# Do not book income for transfer within same company
if self.is_internal_transfer():
continue
@@ -1356,7 +1356,9 @@ class SalesInvoice(SellingController):
if item.is_fixed_asset:
asset = self.get_asset(item)
if self.is_return:
if (self.docstatus == 2 and not self.is_return) or (
self.docstatus == 1 and self.is_return
):
fixed_asset_gl_entries = get_gl_entries_on_asset_regain(
asset,
item.base_net_amount,
@@ -1369,8 +1371,10 @@ class SalesInvoice(SellingController):
add_asset_activity(asset.name, _("Asset returned"))
if asset.calculate_depreciation:
posting_date = frappe.db.get_value(
"Sales Invoice", self.return_against, "posting_date"
posting_date = (
frappe.db.get_value("Sales Invoice", self.return_against, "posting_date")
if self.is_return
else self.posting_date
)
reverse_depreciation_entry_made_after_disposal(asset, posting_date)
notes = _(
@@ -1467,8 +1471,10 @@ class SalesInvoice(SellingController):
return self._enable_discount_accounting
def set_asset_status(self, asset):
if self.is_return:
if self.is_return and not self.docstatus == 2:
asset.set_status()
elif self.is_return and self.docstatus == 2:
asset.set_status("Sold")
else:
asset.set_status("Sold" if self.docstatus == 1 else None)
@@ -2286,6 +2292,18 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
set_purchase_references(target)
def update_details(source_doc, target_doc, source_parent):
def _validate_address_link(address, link_doctype, link_name):
return frappe.db.get_value(
"Dynamic Link",
{
"parent": address,
"parenttype": "Address",
"link_doctype": link_doctype,
"link_name": link_name,
},
"parent",
)
target_doc.inter_company_invoice_reference = source_doc.name
if target_doc.doctype in ["Purchase Invoice", "Purchase Order"]:
currency = frappe.db.get_value("Supplier", details.get("party"), "default_currency")
@@ -2296,13 +2314,34 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
target_doc.buying_price_list = source_doc.selling_price_list
# Invert Addresses
update_address(target_doc, "supplier_address", "address_display", source_doc.company_address)
update_address(
target_doc, "shipping_address", "shipping_address_display", source_doc.customer_address
)
update_address(
target_doc, "billing_address", "billing_address_display", source_doc.customer_address
)
if source_doc.company_address and _validate_address_link(
source_doc.company_address, "Supplier", details.get("party")
):
update_address(target_doc, "supplier_address", "address_display", source_doc.company_address)
if source_doc.dispatch_address_name and _validate_address_link(
source_doc.dispatch_address_name, "Company", details.get("company")
):
update_address(
target_doc,
"dispatch_address",
"dispatch_address_display",
source_doc.dispatch_address_name,
)
if source_doc.shipping_address_name and _validate_address_link(
source_doc.shipping_address_name, "Company", details.get("company")
):
update_address(
target_doc,
"shipping_address",
"shipping_address_display",
source_doc.shipping_address_name,
)
if source_doc.customer_address and _validate_address_link(
source_doc.customer_address, "Company", details.get("company")
):
update_address(
target_doc, "billing_address", "billing_address_display", source_doc.customer_address
)
if currency:
target_doc.currency = currency
@@ -2323,13 +2362,22 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
target_doc.customer = details.get("party")
target_doc.selling_price_list = source_doc.buying_price_list
update_address(
target_doc, "company_address", "company_address_display", source_doc.supplier_address
)
update_address(
target_doc, "shipping_address_name", "shipping_address", source_doc.shipping_address
)
update_address(target_doc, "customer_address", "address_display", source_doc.shipping_address)
if source_doc.supplier_address and _validate_address_link(
source_doc.supplier_address, "Company", details.get("company")
):
update_address(
target_doc, "company_address", "company_address_display", source_doc.supplier_address
)
if source_doc.shipping_address and _validate_address_link(
source_doc.shipping_address, "Customer", details.get("party")
):
update_address(
target_doc, "shipping_address_name", "shipping_address", source_doc.shipping_address
)
if source_doc.shipping_address and _validate_address_link(
source_doc.shipping_address, "Customer", details.get("party")
):
update_address(target_doc, "customer_address", "address_display", source_doc.shipping_address)
if currency:
target_doc.currency = currency

View File

@@ -12,6 +12,9 @@ from frappe.utils import add_days, flt, format_date, getdate, nowdate, today
import erpnext
from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account
from erpnext.accounts.doctype.mode_of_payment.test_mode_of_payment import (
set_default_account_for_mode_of_payment,
)
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import WarehouseMissingError
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import (
@@ -24,7 +27,7 @@ from erpnext.assets.doctype.asset.test_asset import create_asset, create_asset_d
from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
get_depr_schedule,
)
from erpnext.controllers.accounts_controller import update_invoice_status
from erpnext.controllers.accounts_controller import InvalidQtyError, update_invoice_status
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
from erpnext.selling.doctype.customer.test_customer import get_customer_dict
@@ -54,8 +57,33 @@ class TestSalesInvoice(FrappeTestCase):
create_items(["_Test Internal Transfer Item"], uoms=[{"uom": "Box", "conversion_factor": 10}])
create_internal_parties()
setup_accounts()
mode_of_payment = frappe.get_doc("Mode of Payment", "Bank Draft")
set_default_account_for_mode_of_payment(mode_of_payment, "_Test Company", "_Test Bank - _TC")
set_default_account_for_mode_of_payment(
mode_of_payment, "_Test Company with perpetual inventory", "_Test Bank - TCP1"
)
frappe.db.set_single_value("Accounts Settings", "acc_frozen_upto", None)
@change_settings(
"Accounts Settings",
{"maintain_same_internal_transaction_rate": 1, "maintain_same_rate_action": "Stop"},
)
def test_invalid_rate_without_override(self):
from frappe import ValidationError
from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_purchase_invoice
si = create_sales_invoice(
customer="_Test Internal Customer 3", company="_Test Company", is_internal_customer=1, rate=100
)
pi = make_inter_company_purchase_invoice(si.name)
pi.items[0].rate = 120
with self.assertRaises(ValidationError) as e:
pi.insert()
pi.submit()
self.assertIn("Rate must be same", str(e.exception))
def tearDown(self):
frappe.db.rollback()
@@ -74,6 +102,16 @@ class TestSalesInvoice(FrappeTestCase):
def tearDownClass(self):
unlink_payment_on_cancel_of_invoice(0)
def test_sales_invoice_qty(self):
si = create_sales_invoice(qty=0, do_not_save=True)
with self.assertRaises(InvalidQtyError):
si.save()
# No error with qty=1
si.items[0].qty = 1
si.save()
self.assertEqual(si.items[0].qty, 1)
def test_timestamp_change(self):
w = frappe.copy_doc(test_records[0])
w.docstatus = 0
@@ -798,6 +836,10 @@ class TestSalesInvoice(FrappeTestCase):
w = self.make()
self.assertEqual(w.outstanding_amount, w.base_rounded_total)
@change_settings(
"Accounts Settings",
{"add_taxes_from_item_tax_template": 0, "add_taxes_from_taxes_and_charges_template": 0},
)
def test_rounded_total_with_cash_discount(self):
si = frappe.copy_doc(test_records[2])
@@ -964,10 +1006,8 @@ class TestSalesInvoice(FrappeTestCase):
pos.is_pos = 1
pos.update_stock = 1
pos.append(
"payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - TCP1", "amount": 50}
)
pos.append("payments", {"mode_of_payment": "Cash", "account": "Cash - TCP1", "amount": 50})
pos.append("payments", {"mode_of_payment": "Bank Draft", "amount": 50})
pos.append("payments", {"mode_of_payment": "Cash", "amount": 50})
taxes = get_taxes_and_charges()
pos.taxes = []
@@ -996,10 +1036,8 @@ class TestSalesInvoice(FrappeTestCase):
pos.is_pos = 1
pos.pos_profile = pos_profile.name
pos.append(
"payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - _TC", "amount": 500}
)
pos.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 500})
pos.append("payments", {"mode_of_payment": "Bank Draft", "amount": 500})
pos.append("payments", {"mode_of_payment": "Cash", "amount": 500})
pos.insert()
pos.submit()
@@ -1042,10 +1080,8 @@ class TestSalesInvoice(FrappeTestCase):
pos.is_pos = 1
pos.update_stock = 1
pos.append(
"payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - TCP1", "amount": 50}
)
pos.append("payments", {"mode_of_payment": "Cash", "account": "Cash - TCP1", "amount": 60})
pos.append("payments", {"mode_of_payment": "Bank Draft", "amount": 50})
pos.append("payments", {"mode_of_payment": "Cash", "amount": 60})
pos.write_off_outstanding_amount_automatically = 1
pos.insert()
@@ -1085,10 +1121,8 @@ class TestSalesInvoice(FrappeTestCase):
pos.is_pos = 1
pos.update_stock = 1
pos.append(
"payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - TCP1", "amount": 50}
)
pos.append("payments", {"mode_of_payment": "Cash", "account": "Cash - TCP1", "amount": 40})
pos.append("payments", {"mode_of_payment": "Bank Draft", "amount": 50})
pos.append("payments", {"mode_of_payment": "Cash", "amount": 40})
pos.write_off_outstanding_amount_automatically = 1
pos.insert()
@@ -1102,7 +1136,7 @@ class TestSalesInvoice(FrappeTestCase):
pos = create_sales_invoice(do_not_save=True)
pos.is_pos = 1
pos.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 100})
pos.append("payments", {"mode_of_payment": "Cash", "amount": 100})
pos.save().submit()
self.assertEqual(pos.outstanding_amount, 0.0)
self.assertEqual(pos.status, "Paid")
@@ -1173,10 +1207,8 @@ class TestSalesInvoice(FrappeTestCase):
for tax in taxes:
pos.append("taxes", tax)
pos.append(
"payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - TCP1", "amount": 50}
)
pos.append("payments", {"mode_of_payment": "Cash", "account": "Cash - TCP1", "amount": 60})
pos.append("payments", {"mode_of_payment": "Bank Draft", "amount": 50})
pos.append("payments", {"mode_of_payment": "Cash", "amount": 60})
pos.insert()
pos.submit()
@@ -2465,6 +2497,10 @@ class TestSalesInvoice(FrappeTestCase):
for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
@change_settings(
"Accounts Settings",
{"book_deferred_entries_based_on": "Days", "book_deferred_entries_via_journal_entry": 0},
)
def test_deferred_revenue(self):
deferred_account = create_account(
account_name="Deferred Revenue",
@@ -2519,6 +2555,10 @@ class TestSalesInvoice(FrappeTestCase):
self.assertRaises(frappe.ValidationError, si.save)
@change_settings(
"Accounts Settings",
{"book_deferred_entries_based_on": "Months", "book_deferred_entries_via_journal_entry": 0},
)
def test_fixed_deferred_revenue(self):
deferred_account = create_account(
account_name="Deferred Revenue",
@@ -2526,10 +2566,6 @@ class TestSalesInvoice(FrappeTestCase):
company="_Test Company",
)
acc_settings = frappe.get_doc("Accounts Settings", "Accounts Settings")
acc_settings.book_deferred_entries_based_on = "Months"
acc_settings.save()
item = create_item("_Test Item for Deferred Accounting")
item.enable_deferred_revenue = 1
item.deferred_revenue_account = deferred_account
@@ -2569,9 +2605,61 @@ class TestSalesInvoice(FrappeTestCase):
check_gl_entries(self, si.name, expected_gle, "2019-01-30")
acc_settings = frappe.get_doc("Accounts Settings", "Accounts Settings")
acc_settings.book_deferred_entries_based_on = "Days"
acc_settings.save()
def test_validate_inter_company_transaction_address_links(self):
def _validate_address_link(address, link_doctype, link_name):
return frappe.db.get_value(
"Dynamic Link",
{
"parent": address,
"parenttype": "Address",
"link_doctype": link_doctype,
"link_name": link_name,
},
"parent",
)
si = create_sales_invoice(
company="Wind Power LLC",
customer="_Test Internal Customer",
debit_to="Debtors - WP",
warehouse="Stores - WP",
income_account="Sales - WP",
expense_account="Cost of Goods Sold - WP",
cost_center="Main - WP",
currency="USD",
do_not_save=1,
)
si.selling_price_list = "_Test Price List Rest of the World"
si.submit()
target_doc = make_inter_company_transaction("Sales Invoice", si.name)
target_doc.items[0].update(
{
"expense_account": "Cost of Goods Sold - _TC1",
"cost_center": "Main - _TC1",
"warehouse": "Stores - _TC1",
}
)
target_doc.save()
if target_doc.doctype in ["Purchase Invoice", "Purchase Order"]:
for details in [
("supplier_address", "Supplier", target_doc.supplier),
("dispatch_address", "Company", target_doc.company),
("shipping_address", "Company", target_doc.company),
("billing_address", "Company", target_doc.company),
]:
if address := target_doc.get(details[0]):
self.assertEqual(address, _validate_address_link(address, details[1], details[2]))
else:
for details in [
("company_address", "Company", target_doc.company),
("shipping_address_name", "Customer", target_doc.customer),
("customer_address", "Customer", target_doc.customer),
]:
if address := target_doc.get(details[0]):
self.assertEqual(address, _validate_address_link(address, details[1], details[2]))
def test_inter_company_transaction(self):
si = create_sales_invoice(
@@ -2765,7 +2853,9 @@ class TestSalesInvoice(FrappeTestCase):
self.assertEqual(si.items[0].rate, rate)
self.assertEqual(target_doc.items[0].rate, rate)
check_gl_entries(self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1))
check_gl_entries(
self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1), voucher_type="Purchase Invoice"
)
def test_internal_transfer_gl_precision_issues(self):
# Make a stock queue of an item with two valuations
@@ -3051,6 +3141,65 @@ class TestSalesInvoice(FrappeTestCase):
self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
self.assertEqual(schedule.journal_entry, schedule.journal_entry)
def test_depreciation_on_cancel_invoice(self):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
create_asset_data()
asset = create_asset(
item_code="Macbook Pro",
purchase_date="2020-01-01",
available_for_use_date="2023-01-01",
depreciation_start_date="2023-04-01",
calculate_depreciation=1,
submit=1,
)
post_depreciation_entries()
si = create_sales_invoice(
item_code="Macbook Pro", asset=asset.name, qty=1, rate=10000, posting_date=getdate("2025-05-01")
)
return_si = make_return_doc("Sales Invoice", si.name)
return_si.posting_date = getdate("2025-05-01")
return_si.submit()
return_si.reload()
return_si.cancel()
asset.load_from_db()
# Check if the asset schedule is updated while cancel the return invoice
expected_values = [
["2023-04-01", 4986.30, 4986.30, True],
["2024-04-01", 20000.0, 24986.30, True],
["2025-04-01", 20000.0, 44986.30, True],
["2025-05-01", 1643.84, 46630.14, True],
]
for i, schedule in enumerate(get_depr_schedule(asset.name, "Active")):
self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
self.assertEqual(schedule.journal_entry, schedule.journal_entry)
si.reload()
si.cancel()
asset.load_from_db()
# Check if the asset schedule is updated while cancel the sales invoice
expected_values = [
["2023-04-01", 4986.30, 4986.30, True],
["2024-04-01", 20000.0, 24986.30, True],
["2025-04-01", 20000.0, 44986.30, True],
["2026-04-01", 20000.0, 64986.30, False],
["2027-04-01", 20000.0, 84986.30, False],
["2028-01-01", 15013.70, 100000.0, False],
]
for i, schedule in enumerate(get_depr_schedule(asset.name, "Active")):
self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
self.assertEqual(schedule.journal_entry, schedule.journal_entry)
def test_sales_invoice_against_supplier(self):
from erpnext.accounts.doctype.opening_invoice_creation_tool.test_opening_invoice_creation_tool import (
make_customer,
@@ -3345,6 +3494,7 @@ class TestSalesInvoice(FrappeTestCase):
si.posting_date = getdate()
si.submit()
@change_settings("Accounts Settings", {"over_billing_allowance": 0})
def test_over_billing_case_against_delivery_note(self):
"""
Test a case where duplicating the item with qty = 1 in the invoice
@@ -3352,24 +3502,23 @@ class TestSalesInvoice(FrappeTestCase):
"""
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
over_billing_allowance = frappe.db.get_single_value("Accounts Settings", "over_billing_allowance")
frappe.db.set_single_value("Accounts Settings", "over_billing_allowance", 0)
dn = create_delivery_note()
dn.submit()
si = make_sales_invoice(dn.name)
# make a copy of first item and add it to invoice
item_copy = frappe.copy_doc(si.items[0])
si.save()
si.items = [] # Clear existing items
si.append("items", item_copy)
si.save()
si.append("items", item_copy)
with self.assertRaises(frappe.ValidationError) as err:
si.submit()
si.save()
self.assertTrue("cannot overbill" in str(err.exception).lower())
frappe.db.set_single_value("Accounts Settings", "over_billing_allowance", over_billing_allowance)
dn.cancel()
@change_settings(
"Accounts Settings",
@@ -3904,10 +4053,8 @@ class TestSalesInvoice(FrappeTestCase):
pos = create_sales_invoice(qty=10, do_not_save=True)
pos.is_pos = 1
pos.pos_profile = pos_profile.name
pos.append(
"payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - _TC", "amount": 500}
)
pos.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 500})
pos.append("payments", {"mode_of_payment": "Bank Draft", "amount": 500})
pos.append("payments", {"mode_of_payment": "Cash", "amount": 500})
pos.save().submit()
pos_return = make_sales_return(pos.name)
@@ -4278,7 +4425,7 @@ class TestSalesInvoice(FrappeTestCase):
pos.is_pos = 1
pos.pos_profile = pos_profile.name
pos.debit_to = "_Test Receivable USD - _TC"
pos.append("payments", {"mode_of_payment": "Cash", "account": "_Test Bank - _TC", "amount": 20.35})
pos.append("payments", {"mode_of_payment": "Cash", "amount": 20.35})
pos.save().submit()
pos_return = make_sales_return(pos.name)
@@ -4327,6 +4474,94 @@ class TestSalesInvoice(FrappeTestCase):
self.assertRaises(StockOverReturnError, return_doc.save)
def test_stand_alone_credit_note_valuation(self):
from erpnext.stock.doctype.item.test_item import make_item
item_code = "_Test Item for Credit Note Valuation"
make_item_for_si(
item_code,
{
"is_stock_item": 1,
"has_batch_no": 1,
"create_new_batch": 1,
"batch_number_series": "BATCH-TCNV.####",
},
)
si = create_sales_invoice(
item=item_code,
qty=-2,
rate=1200,
is_return=1,
update_stock=1,
)
stock_ledger_entry = frappe.db.get_value(
"Stock Ledger Entry",
{
"voucher_type": "Sales Invoice",
"voucher_no": si.name,
"item_code": item_code,
"warehouse": "_Test Warehouse - _TC",
},
["incoming_rate", "valuation_rate", "actual_qty as qty", "stock_value_difference"],
as_dict=True,
)
self.assertEqual(stock_ledger_entry.incoming_rate, 1200.0)
self.assertEqual(stock_ledger_entry.valuation_rate, 1200.0)
self.assertEqual(stock_ledger_entry.qty, 2.0)
self.assertEqual(stock_ledger_entry.stock_value_difference, 2400.0)
def test_stand_alone_credit_note_zero_valuation(self):
from erpnext.stock.doctype.item.test_item import make_item
item_code = "_Test Item for Credit Note Zero Valuation"
make_item_for_si(
item_code,
{
"is_stock_item": 1,
"has_batch_no": 1,
"create_new_batch": 1,
"batch_number_series": "BATCH-TCNZV.####",
},
)
si = create_sales_invoice(
item=item_code,
qty=-2,
rate=1200,
is_return=1,
update_stock=1,
allow_zero_valuation_rate=1,
)
stock_ledger_entry = frappe.db.get_value(
"Stock Ledger Entry",
{
"voucher_type": "Sales Invoice",
"voucher_no": si.name,
"item_code": item_code,
"warehouse": "_Test Warehouse - _TC",
},
["incoming_rate", "valuation_rate", "actual_qty as qty", "stock_value_difference"],
as_dict=True,
)
self.assertEqual(stock_ledger_entry.incoming_rate, 0.0)
self.assertEqual(stock_ledger_entry.valuation_rate, 0.0)
self.assertEqual(stock_ledger_entry.qty, 2.0)
self.assertEqual(stock_ledger_entry.stock_value_difference, 0.0)
def make_item_for_si(item_code, properties=None):
from erpnext.stock.doctype.item.test_item import make_item
item = make_item(item_code, properties=properties)
item.is_stock_item = 1
item.save()
return item
def set_advance_flag(company, flag, default_account):
frappe.db.set_value(
@@ -4354,6 +4589,8 @@ def check_gl_entries(doc, voucher_no, expected_gle, posting_date, voucher_type="
)
gl_entries = q.run(as_dict=True)
doc.assertGreater(len(gl_entries), 0)
for i, gle in enumerate(gl_entries):
doc.assertEqual(expected_gle[i][0], gle.account)
doc.assertEqual(expected_gle[i][1], gle.debit)
@@ -4379,11 +4616,12 @@ def create_sales_invoice(**args):
si.conversion_rate = args.conversion_rate or 1
si.naming_series = args.naming_series or "T-SINV-"
si.cost_center = args.parent_cost_center
si.is_internal_customer = args.is_internal_customer or 0
bundle_id = None
if si.update_stock and (args.get("batch_no") or args.get("serial_no")):
batches = {}
qty = args.qty or 1
qty = args.qty if args.qty is not None else 1
item_code = args.item or args.item_code or "_Test Item"
if args.get("batch_no"):
batches = frappe._dict({args.batch_no: qty})
@@ -4415,7 +4653,7 @@ def create_sales_invoice(**args):
"description": args.description or "_Test Item",
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"target_warehouse": args.target_warehouse,
"qty": args.qty or 1,
"qty": args.qty if args.qty is not None else 1,
"uom": args.uom or "Nos",
"stock_uom": args.uom or "Nos",
"rate": args.rate if args.get("rate") is not None else 100,
@@ -4429,6 +4667,7 @@ def create_sales_invoice(**args):
"conversion_factor": args.get("conversion_factor", 1),
"incoming_rate": args.incoming_rate or 0,
"serial_and_batch_bundle": bundle_id,
"allow_zero_valuation_rate": args.allow_zero_valuation_rate or 0,
},
)
@@ -4581,6 +4820,12 @@ def create_internal_parties():
allowed_to_interact_with="_Test Company with perpetual inventory",
)
create_internal_supplier(
supplier_name="_Test Internal Supplier 3",
represents_company="_Test Company",
allowed_to_interact_with="_Test Company",
)
def create_internal_supplier(supplier_name, represents_company, allowed_to_interact_with):
if not frappe.db.exists("Supplier", supplier_name):

View File

@@ -37,6 +37,7 @@
"column_break_19",
"discount_percentage",
"discount_amount",
"distributed_discount_amount",
"base_rate_with_margin",
"section_break1",
"rate",
@@ -259,7 +260,7 @@
},
{
"collapsible": 1,
"collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount",
"collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount || doc.distributed_discount_amount",
"fieldname": "discount_and_margin",
"fieldtype": "Section Break",
"label": "Discount and Margin"
@@ -932,6 +933,12 @@
"fieldname": "column_break_ytgd",
"fieldtype": "Column Break"
},
{
"fieldname": "distributed_discount_amount",
"fieldtype": "Currency",
"label": "Distributed Discount Amount",
"options": "currency"
},
{
"fieldname": "available_quantity_section",
"fieldtype": "Section Break",
@@ -976,7 +983,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2025-03-12 16:33:52.503777",
"modified": "2025-03-12 16:33:55.503777",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",

View File

@@ -40,6 +40,7 @@ class SalesInvoiceItem(Document):
discount_account: DF.Link | None
discount_amount: DF.Currency
discount_percentage: DF.Percent
distributed_discount_amount: DF.Currency
dn_detail: DF.Data | None
enable_deferred_revenue: DF.Check
expense_account: DF.Link | None

View File

@@ -671,6 +671,7 @@ def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers):
conditions.append(ple.party.isin(parties))
conditions.append(ple.voucher_no == ple.against_voucher_no)
conditions.append(ple.company == inv.company)
conditions.append(ple.posting_date[tax_details.from_date : tax_details.to_date])
advance_amt = (
qb.from_(ple).select(Abs(Sum(ple.amount))).where(Criterion.all(conditions)).run()[0][0] or 0.0

View File

@@ -288,17 +288,18 @@ class TestTaxWithholdingCategory(FrappeTestCase):
frappe.db.set_value(
"Customer", "Test TCS Customer", "tax_withholding_category", "Cumulative Threshold TCS"
)
fiscal_year = get_fiscal_year(today(), company="_Test Company")
vouchers = []
# create advance payment
pe = create_payment_entry(
pe1 = create_payment_entry(
payment_type="Receive", party_type="Customer", party="Test TCS Customer", paid_amount=20000
)
pe.paid_from = "Debtors - _TC"
pe.paid_to = "Cash - _TC"
pe.submit()
vouchers.append(pe)
pe1.paid_from = "Debtors - _TC"
pe1.paid_to = "Cash - _TC"
pe1.submit()
vouchers.append(pe1)
# create invoice
si1 = create_sales_invoice(customer="Test TCS Customer", rate=5000)
@@ -320,6 +321,17 @@ class TestTaxWithholdingCategory(FrappeTestCase):
# make another invoice
# sum of unallocated amount from payment entry and this sales invoice will breach cumulative threashold
# TDS should be calculated
# this payment should not be considered for TCS calculation as it is outside of fiscal year
pe2 = create_payment_entry(
payment_type="Receive", party_type="Customer", party="Test TCS Customer", paid_amount=10000
)
pe2.paid_from = "Debtors - _TC"
pe2.paid_to = "Cash - _TC"
pe2.posting_date = add_days(fiscal_year[1], -10)
pe2.submit()
vouchers.append(pe2)
si2 = create_sales_invoice(customer="Test TCS Customer", rate=15000)
si2.submit()
vouchers.append(si2)

View File

@@ -12,6 +12,7 @@ from frappe.utils.data import comma_and
from erpnext.accounts.utils import (
cancel_exchange_gain_loss_journal,
get_advance_payment_doctypes,
unlink_ref_doc_from_payment_entries,
update_voucher_outstanding,
)
@@ -84,7 +85,7 @@ class UnreconcilePayment(Document):
update_voucher_outstanding(
alloc.reference_doctype, alloc.reference_name, alloc.account, alloc.party_type, alloc.party
)
if doc.doctype in frappe.get_hooks("advance_payment_doctypes"):
if doc.doctype in get_advance_payment_doctypes():
doc.set_total_advance_paid()
frappe.db.set_value("Unreconcile Payment Entries", alloc.name, "unlinked", True)

View File

@@ -692,7 +692,18 @@ def make_reverse_gl_entries(
query.run()
else:
if not immutable_ledger_enabled:
set_as_cancel(gl_entries[0]["voucher_type"], gl_entries[0]["voucher_no"])
gle_names = [x.get("name") for x in gl_entries]
# if names are available, cancel only that set of entries
if not all(gle_names):
set_as_cancel(gl_entries[0]["voucher_type"], gl_entries[0]["voucher_no"])
else:
frappe.db.sql(
"""UPDATE `tabGL Entry` SET is_cancelled = 1,
modified=%s, modified_by=%s
where name in %s and is_cancelled = 0""",
(now(), frappe.session.user, tuple(gle_names)),
)
for entry in gl_entries:
new_gle = copy.deepcopy(entry)

View File

@@ -71,6 +71,7 @@ def get_party_details(
party_address=None,
company_address=None,
shipping_address=None,
dispatch_address=None,
pos_profile=None,
):
if not party:
@@ -92,6 +93,7 @@ def get_party_details(
party_address,
company_address,
shipping_address,
dispatch_address,
pos_profile,
)
@@ -111,6 +113,7 @@ def _get_party_details(
party_address=None,
company_address=None,
shipping_address=None,
dispatch_address=None,
pos_profile=None,
):
party_details = frappe._dict(
@@ -134,6 +137,7 @@ def _get_party_details(
party_address,
company_address,
shipping_address,
dispatch_address,
ignore_permissions=ignore_permissions,
)
set_contact_details(party_details, party, party_type)
@@ -191,34 +195,51 @@ def set_address_details(
party_address=None,
company_address=None,
shipping_address=None,
dispatch_address=None,
*,
ignore_permissions=False,
):
billing_address_field = (
# party_billing
party_billing_field = (
"customer_address" if party_type in ["Lead", "Prospect"] else party_type.lower() + "_address"
)
party_details[billing_address_field] = party_address or get_default_address(party_type, party.name)
party_details[party_billing_field] = party_address or get_default_address(party_type, party.name)
if doctype:
party_details.update(
get_fetch_values(doctype, billing_address_field, party_details[billing_address_field])
get_fetch_values(doctype, party_billing_field, party_details[party_billing_field])
)
# address display
party_details.address_display = render_address(
party_details[billing_address_field], check_permissions=not ignore_permissions
)
# shipping address
if party_type in ["Customer", "Lead"]:
party_details.shipping_address_name = shipping_address or get_party_shipping_address(
party_type, party.name
)
party_details.shipping_address = render_address(
party_details["shipping_address_name"], check_permissions=not ignore_permissions
)
if doctype:
party_details.update(
get_fetch_values(doctype, "shipping_address_name", party_details.shipping_address_name)
)
party_details.address_display = render_address(
party_details[party_billing_field], check_permissions=not ignore_permissions
)
# party_shipping
if party_type in ["Customer", "Lead"]:
party_shipping_field = "shipping_address_name"
party_shipping_display = "shipping_address"
default_shipping = shipping_address
else:
# Supplier
party_shipping_field = "dispatch_address"
party_shipping_display = "dispatch_address_display"
default_shipping = dispatch_address
party_details[party_shipping_field] = default_shipping or get_party_shipping_address(
party_type, party.name
)
party_details[party_shipping_display] = render_address(
party_details[party_shipping_field], check_permissions=not ignore_permissions
)
if doctype:
party_details.update(
get_fetch_values(doctype, party_shipping_field, party_details[party_shipping_field])
)
# company_address
if company_address:
party_details.company_address = company_address
else:
@@ -256,22 +277,20 @@ def set_address_details(
**get_fetch_values(doctype, "shipping_address", party_details.billing_address),
)
party_address, shipping_address = (
party_details.get(billing_address_field),
party_details.shipping_address_name,
party_billing, party_shipping = (
party_details.get(party_billing_field),
party_details.get(party_shipping_field),
)
party_details["tax_category"] = get_address_tax_category(
party.get("tax_category"),
party_address,
shipping_address if party_type != "Supplier" else party_address,
party.get("tax_category"), party_billing, party_shipping
)
if doctype in TRANSACTION_TYPES:
with temporary_flag("company", company):
get_regional_address_details(party_details, doctype, company)
return party_address, shipping_address
return party_billing, party_shipping
@erpnext.allow_regional
@@ -405,6 +424,8 @@ def get_party_account(party_type, party=None, company=None, include_advance=Fals
Will first search in party (Customer / Supplier) record, if not found,
will search in group (Customer Group / Supplier Group),
finally will return default."""
if not party_type:
frappe.throw(_("Party Type is mandatory"))
if not company:
frappe.throw(_("Please select a Company"))
@@ -441,6 +462,12 @@ def get_party_account(party_type, party=None, company=None, include_advance=Fals
if (account and account_currency != existing_gle_currency) or not account:
account = get_party_gle_account(party_type, party, company)
# get default account on the basis of party type
if not account:
account_type = frappe.get_cached_value("Party Type", party_type, "account_type")
default_account_name = "default_" + account_type.lower() + "_account"
account = frappe.get_cached_value("Company", company, default_account_name)
if include_advance and party_type in ["Customer", "Supplier", "Student"]:
advance_account = get_party_advance_account(party_type, party, company)
if advance_account:
@@ -638,34 +665,34 @@ def get_due_date_from_template(template_name, posting_date, bill_date):
return due_date
def validate_due_date(posting_date, due_date, bill_date=None, template_name=None):
def validate_due_date(posting_date, due_date, bill_date=None, template_name=None, doctype=None):
if getdate(due_date) < getdate(posting_date):
frappe.throw(_("Due Date cannot be before Posting / Supplier Invoice Date"))
else:
if not template_name:
return
validate_due_date_with_template(posting_date, due_date, bill_date, template_name, doctype)
default_due_date = get_due_date_from_template(template_name, posting_date, bill_date).strftime(
"%Y-%m-%d"
)
if not default_due_date:
return
def validate_due_date_with_template(posting_date, due_date, bill_date, template_name, doctype=None):
if not template_name:
return
if default_due_date != posting_date and getdate(due_date) > getdate(default_due_date):
is_credit_controller = (
frappe.db.get_single_value("Accounts Settings", "credit_controller") in frappe.get_roles()
default_due_date = format(get_due_date_from_template(template_name, posting_date, bill_date))
if not default_due_date:
return
if default_due_date != posting_date and getdate(due_date) > getdate(default_due_date):
if frappe.db.get_single_value("Accounts Settings", "credit_controller") in frappe.get_roles():
party_type = "supplier" if doctype == "Purchase Invoice" else "customer"
msgprint(
_("Note: Due Date exceeds allowed {0} credit days by {1} day(s)").format(
party_type, date_diff(due_date, default_due_date)
)
)
if is_credit_controller:
msgprint(
_("Note: Due / Reference Date exceeds allowed customer credit days by {0} day(s)").format(
date_diff(due_date, default_due_date)
)
)
else:
frappe.throw(
_("Due / Reference Date cannot be after {0}").format(formatdate(default_due_date))
)
else:
frappe.throw(_("Due / Reference Date cannot be after {0}").format(formatdate(default_due_date)))
@frappe.whitelist()
@@ -912,12 +939,16 @@ def get_party_shipping_address(doctype: str, name: str) -> str | None:
["is_shipping_address", "=", 1],
["address_type", "=", "Shipping"],
],
pluck="name",
limit=1,
fields=["name", "is_shipping_address"],
order_by="is_shipping_address DESC",
)
return shipping_addresses[0] if shipping_addresses else None
if shipping_addresses and shipping_addresses[0].is_shipping_address == 1:
return shipping_addresses[0].name
if len(shipping_addresses) == 1:
return shipping_addresses[0].name
else:
return None
def get_partywise_advanced_payment_amount(

View File

@@ -60,6 +60,13 @@ frappe.query_reports["Accounts Payable"] = {
options: "Posting Date\nDue Date\nSupplier Invoice Date",
default: "Due Date",
},
{
fieldname: "calculate_ageing_with",
label: __("Calculate Ageing With"),
fieldtype: "Select",
options: "Report Date\nToday Date",
default: "Report Date",
},
{
fieldname: "range",
label: __("Ageing Range"),

View File

@@ -185,7 +185,7 @@
{% if(!filters.show_future_payments) { %}
<td>
{% if(!(filters.party)) { %}
{% if(!filters.party?.length) { %}
{%= data[i]["party"] %}
{% if(data[i]["customer_name"] && data[i]["customer_name"] != data[i]["party"]) { %}
<br> {%= data[i]["customer_name"] %}
@@ -258,7 +258,7 @@
{% if(data[i]["party"]|| "&nbsp;") { %}
{% if(!data[i]["is_total_row"]) { %}
<td>
{% if(!(filters.party)) { %}
{% if(!filters.party?.length) { %}
{%= data[i]["party"] %}
{% if(data[i]["customer_name"] && data[i]["customer_name"] != data[i]["party"]) { %}
<br> {%= data[i]["customer_name"] %}

View File

@@ -89,6 +89,13 @@ frappe.query_reports["Accounts Receivable"] = {
options: "Posting Date\nDue Date",
default: "Due Date",
},
{
fieldname: "calculate_ageing_with",
label: __("Calculate Ageing With"),
fieldtype: "Select",
options: "Report Date\nToday Date",
default: "Report Date",
},
{
fieldname: "range",
label: __("Ageing Range"),

View File

@@ -6,6 +6,7 @@ from collections import OrderedDict
import frappe
from frappe import _, qb, query_builder, scrub
from frappe.desk.reportview import build_match_conditions
from frappe.query_builder import Criterion
from frappe.query_builder.functions import Date, Substring, Sum
from frappe.utils import cint, cstr, flt, getdate, nowdate
@@ -14,7 +15,11 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_accounting_dimensions,
get_dimension_with_children,
)
from erpnext.accounts.utils import get_currency_precision, get_party_types_from_account_type
from erpnext.accounts.utils import (
get_advance_payment_doctypes,
get_currency_precision,
get_party_types_from_account_type,
)
# This report gives a summary of all Outstanding Invoices considering the following
@@ -47,13 +52,21 @@ class ReceivablePayableReport:
self.ple = qb.DocType("Payment Ledger Entry")
self.filters.report_date = getdate(self.filters.report_date or nowdate())
self.age_as_on = (
getdate(nowdate()) if self.filters.report_date > getdate(nowdate()) else self.filters.report_date
getdate(nowdate())
if "calculate_ageing_with" not in self.filters
or self.filters.calculate_ageing_with == "Today Date"
else self.filters.report_date
)
if not self.filters.range:
self.filters.range = "30, 60, 90, 120"
self.ranges = [num.strip() for num in self.filters.range.split(",") if num.strip().isdigit()]
self.range_numbers = [num for num in range(1, len(self.ranges) + 2)]
self.ple_fetch_method = (
frappe.db.get_single_value("Accounts Settings", "receivable_payable_fetch_method")
or "Buffered Cursor"
) # Fail Safe
self.advance_payment_doctypes = get_advance_payment_doctypes()
def run(self, args):
self.filters.update(args)
@@ -77,6 +90,7 @@ class ReceivablePayableReport:
self.party_details = {}
self.invoices = set()
self.skip_total_row = 0
self.advance_payment_doctypes = get_advance_payment_doctypes()
if self.filters.get("group_by_party"):
self.previous_party = ""
@@ -90,13 +104,7 @@ class ReceivablePayableReport:
self.skip_total_row = 1
def get_data(self):
self.get_ple_entries()
self.get_sales_invoices_or_customers_based_on_sales_person()
self.voucher_balance = OrderedDict()
self.init_voucher_balance() # invoiced, paid, credit_note, outstanding
# Build delivery note map against all sales invoices
self.build_delivery_note_map()
# Get invoice details like bill_no, due_date etc for all invoices
self.get_invoice_details()
@@ -105,17 +113,51 @@ class ReceivablePayableReport:
self.get_future_payments()
# Get return entries
self.get_return_entries()
if not self.filters.party_type or self.filters.party_type in ["Customer", "Supplier"]:
self.get_return_entries()
# Get Exchange Rate Revaluations
self.get_exchange_rate_revaluations()
self.prepare_ple_query()
self.data = []
self.voucher_balance = OrderedDict()
if self.ple_fetch_method == "Buffered Cursor":
self.fetch_ple_in_buffered_cursor()
elif self.ple_fetch_method == "UnBuffered Cursor":
self.fetch_ple_in_unbuffered_cursor()
# Build delivery note map against all sales invoices
self.build_delivery_note_map()
self.build_data()
def fetch_ple_in_buffered_cursor(self):
query, param = self.ple_query
self.ple_entries = frappe.db.sql(query, param, as_dict=True)
for ple in self.ple_entries:
self.init_voucher_balance(ple) # invoiced, paid, credit_note, outstanding
# This is unavoidable. Initialization and allocation cannot happen in same loop
for ple in self.ple_entries:
self.update_voucher_balance(ple)
self.build_data()
delattr(self, "ple_entries")
def fetch_ple_in_unbuffered_cursor(self):
self.ple_entries = []
query, param = self.ple_query
with frappe.db.unbuffered_cursor():
for ple in frappe.db.sql(query, param, as_dict=True, as_iterator=True):
self.init_voucher_balance(ple) # invoiced, paid, credit_note, outstanding
self.ple_entries.append(ple)
# This is unavoidable. Initialization and allocation cannot happen in same loop
for ple in self.ple_entries:
self.update_voucher_balance(ple)
delattr(self, "ple_entries")
def build_voucher_dict(self, ple):
return frappe._dict(
@@ -136,26 +178,25 @@ class ReceivablePayableReport:
outstanding_in_account_currency=0.0,
)
def init_voucher_balance(self):
# build all keys, since we want to exclude vouchers beyond the report date
for ple in self.ple_entries:
# get the balance object for voucher_type
def init_voucher_balance(self, ple):
if self.filters.get("ignore_accounts"):
key = (ple.voucher_type, ple.voucher_no, ple.party)
else:
key = (ple.account, ple.voucher_type, ple.voucher_no, ple.party)
if self.filters.get("ignore_accounts"):
key = (ple.voucher_type, ple.voucher_no, ple.party)
else:
key = (ple.account, ple.voucher_type, ple.voucher_no, ple.party)
if key not in self.voucher_balance:
self.voucher_balance[key] = self.build_voucher_dict(ple)
if key not in self.voucher_balance:
self.voucher_balance[key] = self.build_voucher_dict(ple)
if (ple.voucher_type == ple.against_voucher_type and ple.voucher_no == ple.against_voucher_no) or (
ple.voucher_type in ("Payment Entry", "Journal Entry")
and ple.against_voucher_type in self.advance_payment_doctypes
):
self.voucher_balance[key].cost_center = ple.cost_center
if ple.voucher_type == ple.against_voucher_type and ple.voucher_no == ple.against_voucher_no:
self.voucher_balance[key].cost_center = ple.cost_center
self.get_invoices(ple)
self.get_invoices(ple)
if self.filters.get("group_by_party"):
self.init_subtotal_row(ple.party)
if self.filters.get("group_by_party"):
self.init_subtotal_row(ple.party)
if self.filters.get("group_by_party") and not self.filters.get("in_party_currency"):
self.init_subtotal_row("Total")
@@ -419,16 +460,14 @@ class ReceivablePayableReport:
self.invoice_details = frappe._dict()
if self.account_type == "Receivable":
# nosemgrep
si_list = frappe.db.sql(
"""
select name, due_date, po_no
from `tabSales Invoice`
where posting_date <= %s
and company = %s
and docstatus = 1
""",
(self.filters.report_date, self.filters.company),
as_dict=1,
si_list = frappe.get_list(
"Sales Invoice",
filters={
"posting_date": ("<=", self.filters.report_date),
"company": self.filters.company,
"docstatus": 1,
},
fields=["name", "due_date", "po_no"],
)
for d in si_list:
self.invoice_details.setdefault(d.name, d)
@@ -451,33 +490,29 @@ class ReceivablePayableReport:
if self.account_type == "Payable":
# nosemgrep
for pi in frappe.db.sql(
"""
select name, due_date, bill_no, bill_date
from `tabPurchase Invoice`
where
posting_date <= %s
and company = %s
and docstatus = 1
""",
(self.filters.report_date, self.filters.company),
as_dict=1,
):
invoices = frappe.get_list(
"Purchase Invoice",
filters={
"posting_date": ("<=", self.filters.report_date),
"company": self.filters.company,
"docstatus": 1,
},
fields=["name", "due_date", "bill_no", "bill_date"],
)
for pi in invoices:
self.invoice_details.setdefault(pi.name, pi)
# Invoices booked via Journal Entries
# nosemgrep
journal_entries = frappe.db.sql(
"""
select name, due_date, bill_no, bill_date
from `tabJournal Entry`
where
posting_date <= %s
and company = %s
and docstatus = 1
""",
(self.filters.report_date, self.filters.company),
as_dict=1,
journal_entries = frappe.get_list(
"Journal Entry",
filters={
"posting_date": ("<=", self.filters.report_date),
"company": self.filters.company,
"docstatus": 1,
},
fields=["name", "due_date", "bill_no", "bill_date"],
)
for je in journal_entries:
@@ -759,7 +794,7 @@ class ReceivablePayableReport:
self.get_ageing_data(entry_date, row)
# ageing buckets should not have amounts if due date is not reached
if getdate(entry_date) > getdate(self.filters.report_date):
if getdate(entry_date) > getdate(self.age_as_on):
[setattr(row, f"range{i}", 0.0) for i in self.range_numbers]
row.total_due = sum(row[f"range{i}"] for i in self.range_numbers)
@@ -778,7 +813,7 @@ class ReceivablePayableReport:
)
row["range" + str(index + 1)] = row.outstanding
def get_ple_entries(self):
def prepare_ple_query(self):
# get all the GL entries filtered by the given filters
self.prepare_conditions()
@@ -826,12 +861,18 @@ class ReceivablePayableReport:
else:
query = query.select(ple.remarks)
if self.filters.get("group_by_party"):
query = query.orderby(self.ple.party, self.ple.posting_date)
else:
query = query.orderby(self.ple.posting_date, self.ple.party)
query, param = query.walk()
self.ple_entries = query.run(as_dict=True)
match_conditions = build_match_conditions("Payment Ledger Entry")
if match_conditions:
query += " AND " + match_conditions
if self.filters.get("group_by_party"):
query += f" ORDER BY `{self.ple.party.name}`, `{self.ple.posting_date.name}`"
else:
query += f" ORDER BY `{self.ple.posting_date.name}`, `{self.ple.party.name}`"
self.ple_query = (query, param)
def get_sales_invoices_or_customers_based_on_sales_person(self):
if self.filters.get("sales_person"):

View File

@@ -0,0 +1,13 @@
// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
// frappe.query_reports["Calculated Discount Mismatch"] = {
// filters: [
// {
// "fieldname": "my_filter",
// "label": __("My Filter"),
// "fieldtype": "Data",
// "reqd": 1,
// },
// ],
// };

View File

@@ -0,0 +1,38 @@
{
"add_total_row": 0,
"add_translate_data": 0,
"columns": [],
"creation": "2025-06-06 17:09:50.681090",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 0,
"is_standard": "Yes",
"letter_head": "",
"letterhead": null,
"modified": "2025-06-06 18:09:18.221911",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Calculated Discount Mismatch",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Version",
"report_name": "Calculated Discount Mismatch",
"report_type": "Script Report",
"roles": [
{
"role": "System Manager"
},
{
"role": "Administrator"
},
{
"role": "Accounts Manager"
},
{
"role": "Accounts User"
}
],
"timeout": 0
}

View File

@@ -0,0 +1,173 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import json
import frappe
from frappe import _
from frappe.query_builder import Order, Tuple
from frappe.utils.formatters import format_value
AFFECTED_DOCTYPES = frozenset(
(
"POS Invoice",
"Purchase Invoice",
"Sales Invoice",
"Purchase Order",
"Supplier Quotation",
"Quotation",
"Sales Order",
"Delivery Note",
"Purchase Receipt",
)
)
LAST_MODIFIED_DATE_THRESHOLD = "2025-05-30"
def execute(filters=None):
columns = get_columns()
data = get_data()
return columns, data
def get_columns():
return [
{
"fieldname": "doctype",
"label": _("Transaction Type"),
"fieldtype": "Link",
"options": "DocType",
"width": 120,
},
{
"fieldname": "docname",
"label": _("Transaction Name"),
"fieldtype": "Dynamic Link",
"options": "doctype",
"width": 150,
},
{
"fieldname": "actual_discount_percentage",
"label": _("Discount Percentage in Transaction"),
"fieldtype": "Percent",
"width": 180,
},
{
"fieldname": "actual_discount_amount",
"label": _("Discount Amount in Transaction"),
"fieldtype": "Currency",
"width": 180,
},
{
"fieldname": "suspected_discount_amount",
"label": _("Suspected Discount Amount"),
"fieldtype": "Currency",
"width": 180,
},
]
def get_data():
transactions_with_discount_percentage = {}
for doctype in AFFECTED_DOCTYPES:
transactions = get_transactions_with_discount_percentage(doctype)
for transaction in transactions:
transactions_with_discount_percentage[(doctype, transaction.name)] = transaction
if not transactions_with_discount_percentage:
return []
VERSION = frappe.qb.DocType("Version")
versions = (
frappe.qb.from_(VERSION)
.select(VERSION.ref_doctype, VERSION.docname, VERSION.data)
.where(VERSION.creation > LAST_MODIFIED_DATE_THRESHOLD)
.where(Tuple(VERSION.ref_doctype, VERSION.docname).isin(list(transactions_with_discount_percentage)))
.where(
VERSION.data.like('%"discount\\_amount"%')
| VERSION.data.like('%"additional\\_discount\\_percentage"%')
)
.orderby(VERSION.creation, order=Order.desc)
.run(as_dict=True)
)
if not versions:
return []
version_map = {}
for version in versions:
key = (version.ref_doctype, version.docname)
if key not in version_map:
version_map[key] = []
version_map[key].append(version.data)
data = []
discount_amount_field_map = {
doctype: frappe.get_meta(doctype).get_field("discount_amount") for doctype in AFFECTED_DOCTYPES
}
for doc, versions in version_map.items():
for version_data in versions:
if '"additional_discount_percentage"' in version_data:
# don't consider doc if additional_discount_percentage is changed in newest version
break
version_data = json.loads(version_data)
changed_values = version_data.get("changed")
if not changed_values:
continue
discount_values = next((row for row in changed_values if row[0] == "discount_amount"), None)
if not discount_values:
continue
old = discount_values[1]
new = discount_values[2]
doctype = doc[0]
doc_values = transactions_with_discount_percentage.get(doc)
formatted_discount_amount = format_value(
doc_values.discount_amount,
df=discount_amount_field_map[doctype],
currency=doc_values.currency,
)
if new != formatted_discount_amount:
# if the discount amount in the version is not equal to the current value, skip
break
data.append(
{
"doctype": doctype,
"docname": doc_values.name,
"actual_discount_percentage": doc_values.additional_discount_percentage,
"actual_discount_amount": new,
"suspected_discount_amount": old,
}
)
break
return data
def get_transactions_with_discount_percentage(doctype):
transactions = frappe.get_all(
doctype,
fields=[
"name",
"currency",
"additional_discount_percentage",
"discount_amount",
],
filters={
"docstatus": ["<", 2],
"additional_discount_percentage": [">", 0],
"discount_amount": ["!=", 0],
"modified": [">", LAST_MODIFIED_DATE_THRESHOLD],
},
)
return transactions

View File

@@ -75,7 +75,11 @@ def execute(filters=None):
# add first net income in operations section
if net_profit_loss:
net_profit_loss.update(
{"indent": 1, "parent_section": cash_flow_sections[0]["section_header"]}
{
"indent": 1,
"parent_section": cash_flow_sections[0]["section_header"],
"section": net_profit_loss["account"],
}
)
data.append(net_profit_loss)
section_data.append(net_profit_loss)

View File

@@ -8,6 +8,7 @@ from frappe.query_builder import Criterion, Tuple
from frappe.query_builder.functions import IfNull
from frappe.utils import getdate, nowdate
from frappe.utils.nestedset import get_descendants_of
from pypika.terms import LiteralValue
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_accounting_dimensions,
@@ -15,7 +16,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
)
TREE_DOCTYPES = frozenset(
["Customer Group", "Terrirtory", "Supplier Group", "Sales Partner", "Sales Person", "Cost Center"]
["Customer Group", "Territory", "Supplier Group", "Sales Partner", "Sales Person", "Cost Center"]
)
@@ -77,13 +78,12 @@ class PartyLedgerSummaryReport:
from frappe.desk.reportview import build_match_conditions
query, params = query.walk()
match_conditions = build_match_conditions(party_type)
if match_conditions:
query += "and" + match_conditions
query = query.where(LiteralValue(match_conditions))
party_details = frappe.db.sql(query, params, as_dict=True)
party_details = query.run(as_dict=True)
for row in party_details:
self.parties.append(row.party)
@@ -100,7 +100,7 @@ class PartyLedgerSummaryReport:
conditions.append(doctype.territory.isin(self.filters.territory))
if self.filters.get(group_field):
conditions.append(doctype.get(group_field).isin(self.filters.get(group_field)))
conditions.append(doctype[group_field].isin(self.filters.get(group_field)))
if self.filters.payment_terms_template:
conditions.append(doctype.payment_terms == self.filters.payment_terms_template)
@@ -144,10 +144,10 @@ class PartyLedgerSummaryReport:
if self.party_naming_by == "Naming Series":
columns.append(
{
"label": _(self.filters.party_type + "Name"),
"label": _(self.filters.party_type + " Name"),
"fieldtype": "Data",
"fieldname": "party_name",
"width": 110,
"width": 150,
}
)
@@ -252,12 +252,13 @@ class PartyLedgerSummaryReport:
self.party_data = frappe._dict({})
for gle in self.gl_entries:
party_details = self.party_details.get(gle.party)
party_name = party_details.get(f"{scrub(self.filters.party_type)}_name", "")
self.party_data.setdefault(
gle.party,
frappe._dict(
{
**party_details,
"party_name": gle.party,
"party_name": party_name,
"opening_balance": 0,
"invoiced_amount": 0,
"paid_amount": 0,
@@ -404,7 +405,9 @@ class PartyLedgerSummaryReport:
gl = qb.DocType("GL Entry")
query = (
qb.from_(gl)
.select(gl.voucher_type, gl.voucher_no)
.select(
gl.posting_date, gl.account, gl.party, gl.voucher_type, gl.voucher_no, gl.debit, gl.credit
)
.where(
(gl.docstatus < 2)
& (gl.is_cancelled == 0)
@@ -455,9 +458,16 @@ class PartyLedgerSummaryReport:
def get_children(doctype, value):
children = get_descendants_of(doctype, value)
if not isinstance(value, list):
value = [d.strip() for d in value.strip().split(",") if d]
return [value, *children]
all_children = []
for d in value:
all_children += get_descendants_of(doctype, value)
all_children.append(d)
return list(set(all_children))
def execute(filters=None):

View File

@@ -79,6 +79,14 @@ class Deferred_Item:
return - estimated amount to post for given period
Calculated based on already booked amount and item service period
"""
if self.filters.book_deferred_entries_based_on == "Months":
# if the deferred entries are based on service period, use service start and end date
return self.calculate_monthly_amount(start_date, end_date)
else:
return self.calculate_days_amount(start_date, end_date)
def calculate_monthly_amount(self, start_date, end_date):
total_months = (
(self.service_end_date.year - self.service_start_date.year) * 12
+ (self.service_end_date.month - self.service_start_date.month)
@@ -105,6 +113,19 @@ class Deferred_Item:
return base_amount
def calculate_days_amount(self, start_date, end_date):
base_amount = 0
total_days = date_diff(self.service_end_date, self.service_start_date) + 1
total_booking_days = date_diff(end_date, start_date) + 1
already_booked_amount = self.get_item_total()
base_amount = flt(self.base_net_amount * total_booking_days / flt(total_days))
if base_amount + already_booked_amount > self.base_net_amount:
base_amount = self.base_net_amount - already_booked_amount
return base_amount
def make_dummy_gle(self, name, date, amount):
"""
return - frappe._dict() of a dummy gle entry
@@ -245,6 +266,10 @@ class Deferred_Revenue_and_Expense_Report:
else:
self.filters = frappe._dict(filters)
self.filters.book_deferred_entries_based_on = frappe.db.get_singles_value(
"Accounts Settings", "book_deferred_entries_based_on"
)
self.period_list = None
self.deferred_invoices = []
# holds period wise total for report
@@ -289,7 +314,11 @@ class Deferred_Revenue_and_Expense_Report:
.join(inv)
.on(inv.name == inv_item.parent)
.left_join(gle)
.on((inv_item.name == gle.voucher_detail_no) & (deferred_account_field == gle.account))
.on(
(inv_item.name == gle.voucher_detail_no)
& (deferred_account_field == gle.account)
& (gle.is_cancelled == 0)
)
.select(
inv.name.as_("doc"),
inv.posting_date,

View File

@@ -47,12 +47,12 @@
{% for(let j=0, k=data.length; j<k; j++) { %}
{%
var row = data[j];
var row_class = data[j].parent_account ? "" : "financial-statements-important";
row_class += data[j].account_name ? "" : " financial-statements-blank-row";
var row_class = data[j].parent_account || data[j].parent_section ? "" : "financial-statements-important";
row_class += data[j].account_name || data[j].section ? "" : " financial-statements-blank-row";
%}
<tr class="{%= row_class %}">
<td>
<span style="padding-left: {%= cint(data[j].indent) * 2 %}em">{%= row.account_name %}</span>
<span style="padding-left: {%= cint(data[j].indent) * 2 %}em">{%= row.account_name || row.section %}</span>
</td>
{% for(let i=1, l=report_columns.length; i<l; i++) { %}
<td class="text-right">

View File

@@ -9,7 +9,7 @@ import re
import frappe
from frappe import _
from frappe.query_builder.functions import Sum
from frappe.query_builder.functions import Max, Min, Sum
from frappe.utils import add_days, add_months, cint, cstr, flt, formatdate, get_first_day, getdate
from pypika.terms import ExistsCriterion
@@ -109,14 +109,19 @@ def get_period_list(
def get_fiscal_year_data(from_fiscal_year, to_fiscal_year):
fiscal_year = frappe.db.sql(
"""select min(year_start_date) as year_start_date,
max(year_end_date) as year_end_date from `tabFiscal Year` where
name between %(from_fiscal_year)s and %(to_fiscal_year)s""",
{"from_fiscal_year": from_fiscal_year, "to_fiscal_year": to_fiscal_year},
as_dict=1,
from_year_start_date = frappe.get_cached_value("Fiscal Year", from_fiscal_year, "year_start_date")
to_year_end_date = frappe.get_cached_value("Fiscal Year", to_fiscal_year, "year_end_date")
fy = frappe.qb.DocType("Fiscal Year")
query = (
frappe.qb.from_(fy)
.select(Min(fy.year_start_date).as_("year_start_date"), Max(fy.year_end_date).as_("year_end_date"))
.where(fy.year_start_date >= from_year_start_date)
.where(fy.year_end_date <= to_year_end_date)
)
fiscal_year = query.run(as_dict=True)
return fiscal_year[0] if fiscal_year else {}
@@ -519,9 +524,6 @@ def get_accounting_entries(
.where(gl_entry.company == filters.company)
)
if group_by_account:
query = query.groupby(gl_entry.account)
ignore_is_opening = frappe.db.get_single_value(
"Accounts Settings", "ignore_is_opening_check_for_reporting"
)
@@ -551,6 +553,9 @@ def get_accounting_entries(
if match_conditions:
query += "and" + match_conditions
if group_by_account:
query += " GROUP BY `account`"
return frappe.db.sql(query, params, as_dict=True)

View File

@@ -49,7 +49,7 @@ frappe.query_reports["General Ledger"] = {
label: __("Voucher No"),
fieldtype: "Data",
on_change: function () {
frappe.query_report.set_filter_value("group_by", "Group by Voucher (Consolidated)");
frappe.query_report.set_filter_value("categorize_by", "Categorize by Voucher (Consolidated)");
},
},
{
@@ -112,29 +112,29 @@ frappe.query_reports["General Ledger"] = {
hidden: 1,
},
{
fieldname: "group_by",
label: __("Group by"),
fieldname: "categorize_by",
label: __("Categorize by"),
fieldtype: "Select",
options: [
"",
{
label: __("Group by Voucher"),
value: "Group by Voucher",
label: __("Categorize by Voucher"),
value: "Categorize by Voucher",
},
{
label: __("Group by Voucher (Consolidated)"),
value: "Group by Voucher (Consolidated)",
label: __("Categorize by Voucher (Consolidated)"),
value: "Categorize by Voucher (Consolidated)",
},
{
label: __("Group by Account"),
value: "Group by Account",
label: __("Categorize by Account"),
value: "Categorize by Account",
},
{
label: __("Group by Party"),
value: "Group by Party",
label: __("Categorize by Party"),
value: "Categorize by Party",
},
],
default: "Group by Voucher (Consolidated)",
default: "Categorize by Voucher (Consolidated)",
},
{
fieldname: "tax_id",
@@ -209,7 +209,7 @@ frappe.query_reports["General Ledger"] = {
},
{
fieldname: "ignore_err",
label: __("Ignore Exchange Rate Revaluation Journals"),
label: __("Ignore Exchange Rate Revaluation and Gain / Loss Journals"),
fieldtype: "Check",
},
{

View File

@@ -63,13 +63,17 @@ def validate_filters(filters, account_details):
if not account_details.get(account):
frappe.throw(_("Account {0} does not exists").format(account))
if filters.get("account") and filters.get("group_by") == "Group by Account":
if not filters.get("categorize_by") and filters.get("group_by"):
filters["categorize_by"] = filters["group_by"]
filters["categorize_by"] = filters["categorize_by"].replace("Group by", "Categorize by")
if filters.get("account") and filters.get("categorize_by") == "Categorize by Account":
filters.account = frappe.parse_json(filters.get("account"))
for account in filters.account:
if account_details[account].is_group == 0:
frappe.throw(_("Can not filter based on Child Account, if grouped by Account"))
if filters.get("voucher_no") and filters.get("group_by") in ["Group by Voucher"]:
if filters.get("voucher_no") and filters.get("categorize_by") in ["Categorize by Voucher"]:
frappe.throw(_("Can not filter based on Voucher No, if grouped by Voucher"))
if filters.from_date > filters.to_date:
@@ -163,9 +167,9 @@ def get_gl_entries(filters, accounting_dimensions):
if filters.get("include_dimensions"):
order_by_statement = "order by posting_date, creation"
if filters.get("group_by") == "Group by Voucher":
if filters.get("categorize_by") == "Categorize by Voucher":
order_by_statement = "order by posting_date, voucher_type, voucher_no"
if filters.get("group_by") == "Group by Account":
if filters.get("categorize_by") == "Categorize by Account":
order_by_statement = "order by account, posting_date, creation"
if filters.get("include_default_book_entries"):
@@ -260,7 +264,7 @@ def get_conditions(filters):
if filters.get("voucher_no_not_in"):
conditions.append("voucher_no not in %(voucher_no_not_in)s")
if filters.get("group_by") == "Group by Party" and not filters.get("party_type"):
if filters.get("categorize_by") == "Categorize by Party" and not filters.get("party_type"):
conditions.append("party_type in ('Customer', 'Supplier')")
if filters.get("party_type"):
@@ -272,7 +276,7 @@ def get_conditions(filters):
if not (
filters.get("account")
or filters.get("party")
or filters.get("group_by") in ["Group by Account", "Group by Party"]
or filters.get("categorize_by") in ["Categorize by Account", "Categorize by Party"]
):
if not ignore_is_opening:
conditions.append("(posting_date >=%(from_date)s or is_opening = 'Yes')")
@@ -374,26 +378,26 @@ def get_data_with_opening_closing(filters, account_details, accounting_dimension
# Opening for filtered account
data.append(totals.opening)
if filters.get("group_by") != "Group by Voucher (Consolidated)":
if filters.get("categorize_by") != "Categorize by Voucher (Consolidated)":
for _acc, acc_dict in gle_map.items():
# acc
if acc_dict.entries:
# opening
data.append({"debit_in_transaction_currency": None, "credit_in_transaction_currency": None})
if (not filters.get("group_by") and not filters.get("voucher_no")) or (
filters.get("group_by") and filters.get("group_by") != "Group by Voucher"
if (not filters.get("categorize_by") and not filters.get("voucher_no")) or (
filters.get("categorize_by") and filters.get("categorize_by") != "Categorize by Voucher"
):
data.append(acc_dict.totals.opening)
data += acc_dict.entries
# totals
if filters.get("group_by") or not filters.voucher_no:
if filters.get("categorize_by") or not filters.voucher_no:
data.append(acc_dict.totals.total)
# closing
if (not filters.get("group_by") and not filters.get("voucher_no")) or (
filters.get("group_by") and filters.get("group_by") != "Group by Voucher"
if (not filters.get("categorize_by") and not filters.get("voucher_no")) or (
filters.get("categorize_by") and filters.get("categorize_by") != "Categorize by Voucher"
):
data.append(acc_dict.totals.closing)
@@ -430,9 +434,9 @@ def get_totals_dict():
def group_by_field(group_by):
if group_by == "Group by Party":
if group_by == "Categorize by Party":
return "party"
elif group_by in ["Group by Voucher (Consolidated)", "Group by Account"]:
elif group_by in ["Categorize by Voucher (Consolidated)", "Categorize by Account"]:
return "account"
else:
return "voucher_no"
@@ -440,7 +444,7 @@ def group_by_field(group_by):
def initialize_gle_map(gl_entries, filters, totals_dict):
gle_map = OrderedDict()
group_by = group_by_field(filters.get("group_by"))
group_by = group_by_field(filters.get("categorize_by"))
for gle in gl_entries:
gle_map.setdefault(gle.get(group_by), _dict(totals=copy.deepcopy(totals_dict), entries=[]))
@@ -450,8 +454,8 @@ def initialize_gle_map(gl_entries, filters, totals_dict):
def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map, totals):
entries = []
consolidated_gle = OrderedDict()
group_by = group_by_field(filters.get("group_by"))
group_by_voucher_consolidated = filters.get("group_by") == "Group by Voucher (Consolidated)"
group_by = group_by_field(filters.get("categorize_by"))
group_by_voucher_consolidated = filters.get("categorize_by") == "Categorize by Voucher (Consolidated)"
if filters.get("show_net_values_in_party_account"):
account_type_map = get_account_type_map(filters.get("company"))
@@ -559,17 +563,20 @@ def get_account_type_map(company):
def get_result_as_list(data, filters):
balance, _balance_in_account_currency = 0, 0
balance = 0
for d in data:
if not d.get("posting_date"):
balance, _balance_in_account_currency = 0, 0
balance = 0
balance = get_balance(d, balance, "debit", "credit")
d["balance"] = balance
d["account_currency"] = filters.account_currency
d["presentation_currency"] = filters.presentation_currency
return data
@@ -595,11 +602,8 @@ def get_columns(filters):
if filters.get("presentation_currency"):
currency = filters["presentation_currency"]
else:
if filters.get("company"):
currency = get_company_currency(filters["company"])
else:
company = get_default_company()
currency = get_company_currency(company)
company = filters.get("company") or get_default_company()
filters["presentation_currency"] = currency = get_company_currency(company)
columns = [
{
@@ -620,19 +624,22 @@ def get_columns(filters):
{
"label": _("Debit ({0})").format(currency),
"fieldname": "debit",
"fieldtype": "Float",
"fieldtype": "Currency",
"options": "presentation_currency",
"width": 130,
},
{
"label": _("Credit ({0})").format(currency),
"fieldname": "credit",
"fieldtype": "Float",
"fieldtype": "Currency",
"options": "presentation_currency",
"width": 130,
},
{
"label": _("Balance ({0})").format(currency),
"fieldname": "balance",
"fieldtype": "Float",
"fieldtype": "Currency",
"options": "presentation_currency",
"width": 130,
},
]

View File

@@ -3,7 +3,7 @@
import frappe
from frappe import qb
from frappe.tests.utils import FrappeTestCase
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import flt, today
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
@@ -155,7 +155,7 @@ class TestGeneralLedger(FrappeTestCase):
"from_date": today(),
"to_date": today(),
"account": [account.name],
"group_by": "Group by Voucher (Consolidated)",
"categorize_by": "Categorize by Voucher (Consolidated)",
}
)
)
@@ -246,7 +246,7 @@ class TestGeneralLedger(FrappeTestCase):
"from_date": today(),
"to_date": today(),
"account": [account.name],
"group_by": "Group by Voucher (Consolidated)",
"categorize_by": "Categorize by Voucher (Consolidated)",
"ignore_err": True,
}
)
@@ -261,7 +261,7 @@ class TestGeneralLedger(FrappeTestCase):
"from_date": today(),
"to_date": today(),
"account": [account.name],
"group_by": "Group by Voucher (Consolidated)",
"categorize_by": "Categorize by Voucher (Consolidated)",
"ignore_err": False,
}
)
@@ -308,7 +308,7 @@ class TestGeneralLedger(FrappeTestCase):
"from_date": si.posting_date,
"to_date": si.posting_date,
"account": [si.debit_to],
"group_by": "Group by Voucher (Consolidated)",
"categorize_by": "Categorize by Voucher (Consolidated)",
"ignore_cr_dr_notes": False,
}
)
@@ -325,7 +325,7 @@ class TestGeneralLedger(FrappeTestCase):
"from_date": si.posting_date,
"to_date": si.posting_date,
"account": [si.debit_to],
"group_by": "Group by Voucher (Consolidated)",
"categorize_by": "Categorize by Voucher (Consolidated)",
"ignore_cr_dr_notes": True,
}
)

View File

@@ -5,12 +5,14 @@
import frappe
from frappe import _
from frappe.model.meta import get_field_precision
from frappe.query_builder import functions as fn
from frappe.utils import cstr, flt
from frappe.utils.nestedset import get_descendants_of
from frappe.utils.xlsxutils import handle_html
from pypika import Order
from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
from erpnext.accounts.report.utils import get_query_columns, get_values_for_columns
from erpnext.accounts.report.utils import get_values_for_columns
from erpnext.selling.report.item_wise_sales_history.item_wise_sales_history import (
get_customer_details,
)
@@ -375,7 +377,12 @@ def apply_conditions(query, si, sii, filters, additional_conditions=None):
query = query.where(sii.item_code == filters.get("item_code"))
if filters.get("item_group"):
query = query.where(sii.item_group == filters.get("item_group"))
if frappe.db.get_value("Item Group", filters.get("item_group"), "is_group"):
item_groups = get_descendants_of("Item Group", filters.get("item_group"))
item_groups.append(filters.get("item_group"))
query = query.where(sii.item_group.isin(item_groups))
else:
query = query.where(sii.item_group == filters.get("item_group"))
if filters.get("income_account"):
query = query.where(
@@ -427,7 +434,7 @@ def get_items(filters, additional_query_columns, additional_conditions=None):
si.is_internal_customer,
si.customer,
si.remarks,
si.territory,
fn.IfNull(si.territory, "Not Specified").as_("territory"),
si.company,
si.base_net_total,
sii.project,
@@ -450,7 +457,7 @@ def get_items(filters, additional_query_columns, additional_conditions=None):
sii.base_net_rate,
sii.base_net_amount,
si.customer_name,
si.customer_group,
fn.IfNull(si.customer_group, "Not Specified").as_("customer_group"),
sii.so_detail,
si.update_stock,
sii.uom,

View File

@@ -35,7 +35,6 @@ def execute(filters=None):
filters=filters,
accumulated_values=filters.accumulated_values,
ignore_closing_entries=True,
ignore_accumulated_values_for_fy=True,
)
expense = get_data(
@@ -46,7 +45,6 @@ def execute(filters=None):
filters=filters,
accumulated_values=filters.accumulated_values,
ignore_closing_entries=True,
ignore_accumulated_values_for_fy=True,
)
net_profit_loss = get_net_profit_loss(

View File

@@ -2,8 +2,9 @@
# MIT License. See license.txt
import frappe
from frappe.desk.query_report import export_query
from frappe.tests.utils import FrappeTestCase
from frappe.utils import getdate, today
from frappe.utils import add_days, getdate, today
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.report.financial_statements import get_period_list
@@ -57,7 +58,7 @@ class TestProfitAndLossStatement(AccountsTestMixin, FrappeTestCase):
period_end_date=fy.year_end_date,
filter_based_on="Fiscal Year",
periodicity="Monthly",
accumulated_vallues=True,
accumulated_values=False,
)
def test_profit_and_loss_output_and_summary(self):
@@ -90,3 +91,82 @@ class TestProfitAndLossStatement(AccountsTestMixin, FrappeTestCase):
with self.subTest(current_period_key=current_period_key):
self.assertEqual(acc[current_period_key], 150)
self.assertEqual(acc["total"], 150)
def test_p_and_l_export(self):
self.create_sales_invoice(qty=1, rate=150)
filters = self.get_report_filters()
frappe.local.form_dict = frappe._dict(
{
"report_name": "Profit and Loss Statement",
"file_format_type": "CSV",
"filters": filters,
"visible_idx": [0, 1, 2, 3, 4, 5, 6],
}
)
export_query()
contents = frappe.response["filecontent"].decode()
sales_account = frappe.db.get_value("Company", self.company, "default_income_account")
self.assertIn(sales_account, contents)
def test_accumulate_filter(self):
# ensure 2 fiscal years
cur_fy = self.get_fiscal_year()
find_for = add_days(cur_fy.year_start_date, -1)
_x = frappe.db.get_all(
"Fiscal Year",
filters={"disabled": 0, "year_start_date": ("<=", find_for), "year_end_date": (">=", find_for)},
)[0]
prev_fy = frappe.get_doc("Fiscal Year", _x.name)
prev_fy.append("companies", {"company": self.company})
prev_fy.save()
# make SI on both of them
prev_fy_si = self.create_sales_invoice(qty=1, rate=450, do_not_submit=True)
prev_fy_si.posting_date = add_days(prev_fy.year_end_date, -1)
prev_fy_si.save().submit()
income_acc = prev_fy_si.items[0].income_account
self.create_sales_invoice(qty=1, rate=120)
# Unaccumualted
filters = frappe._dict(
company=self.company,
from_fiscal_year=prev_fy.name,
to_fiscal_year=cur_fy.name,
period_start_date=prev_fy.year_start_date,
period_end_date=cur_fy.year_end_date,
filter_based_on="Date Range",
periodicity="Yearly",
accumulated_values=False,
)
result = execute(filters)
columns = [result[0][2], result[0][3]]
expected = {
"account": income_acc,
columns[0].get("fieldname"): 450.0,
columns[1].get("fieldname"): 120.0,
}
actual = [x for x in result[1] if x.get("account") == income_acc]
self.assertEqual(len(actual), 1)
actual = actual[0]
for key in expected.keys():
with self.subTest(key=key):
self.assertEqual(expected.get(key), actual.get(key))
# accumualted
filters.update({"accumulated_values": True})
expected = {
"account": income_acc,
columns[0].get("fieldname"): 450.0,
columns[1].get("fieldname"): 570.0,
}
result = execute(filters)
columns = [result[0][2], result[0][3]]
actual = [x for x in result[1] if x.get("account") == income_acc]
self.assertEqual(len(actual), 1)
actual = actual[0]
for key in expected.keys():
with self.subTest(key=key):
self.assertEqual(expected.get(key), actual.get(key))

View File

@@ -59,3 +59,33 @@ class TestSupplierLedgerSummary(FrappeTestCase, AccountsTestMixin):
for field in expected:
with self.subTest(field=field):
self.assertEqual(report_output[0].get(field), expected.get(field))
def test_supplier_ledger_summary_with_filters(self):
self.create_purchase_invoice()
supplier_group = frappe.db.get_value("Supplier", self.supplier, "supplier_group")
filters = {
"company": self.company,
"from_date": today(),
"to_date": today(),
"supplier_group": supplier_group,
}
expected = {
"party": "_Test Supplier",
"party_name": "_Test Supplier",
"opening_balance": 0,
"invoiced_amount": 300.0,
"paid_amount": 0,
"return_amount": 0,
"closing_balance": 300.0,
"currency": "INR",
"supplier_name": "_Test Supplier",
}
report_output = execute(filters)[1]
self.assertEqual(len(report_output), 1)
for field in expected:
with self.subTest(field=field):
self.assertEqual(report_output[0].get(field), expected.get(field))

View File

@@ -4,6 +4,7 @@
import frappe
from frappe import _
from frappe.utils import getdate
def execute(filters=None):
@@ -33,6 +34,7 @@ def execute(filters=None):
def validate_filters(filters):
"""Validate if dates are properly set"""
filters = frappe._dict(filters or {})
if filters.from_date > filters.to_date:
frappe.throw(_("From Date must be before To Date"))
@@ -68,7 +70,7 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_
if not tax_withholding_category:
tax_withholding_category = party_map.get(party, {}).get("tax_withholding_category")
rate = tax_rate_map.get(tax_withholding_category)
rate = get_tax_withholding_rates(tax_rate_map.get(tax_withholding_category, []), posting_date)
if net_total_map.get((voucher_type, name)):
if voucher_type == "Journal Entry" and tax_amount and rate:
# back calcalute total amount from rate and tax_amount
@@ -119,7 +121,7 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_
)
out.append(row)
out.sort(key=lambda x: x["section_code"])
out.sort(key=lambda x: (x["section_code"], x["transaction_date"]))
return out
@@ -435,12 +437,22 @@ def get_doc_info(vouchers, doctype, tax_category_map, net_total_map=None):
def get_tax_rate_map(filters):
rate_map = frappe.get_all(
"Tax Withholding Rate",
filters={
"from_date": ("<=", filters.get("from_date")),
"to_date": (">=", filters.get("to_date")),
},
fields=["parent", "tax_withholding_rate"],
as_list=1,
filters={"from_date": ("<=", filters.to_date), "to_date": (">=", filters.from_date)},
fields=["parent", "tax_withholding_rate", "from_date", "to_date"],
)
return frappe._dict(rate_map)
rate_list = frappe._dict()
for rate in rate_map:
rate_list.setdefault(rate.parent, []).append(frappe._dict(rate))
return rate_list
def get_tax_withholding_rates(tax_withholding, posting_date):
# returns the row that matches with the fiscal year from posting date
for rate in tax_withholding:
if getdate(rate.from_date) <= getdate(posting_date) <= getdate(rate.to_date):
return rate.tax_withholding_rate
return 0

View File

@@ -3,7 +3,7 @@
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import today
from frappe.utils import add_to_date, today
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
@@ -60,6 +60,58 @@ class TestTaxWithholdingDetails(AccountsTestMixin, FrappeTestCase):
]
self.check_expected_values(result, expected_values)
def test_date_filters_in_multiple_tax_withholding_rules(self):
create_tax_category("TDS - 3", rate=10, account="TDS - _TC", cumulative_threshold=1)
# insert new rate in same fiscal year
fiscal_year = get_fiscal_year(today(), company="_Test Company")
mid_year = add_to_date(fiscal_year[1], months=6)
tds_doc = frappe.get_doc("Tax Withholding Category", "TDS - 3")
tds_doc.rates[0].to_date = mid_year
from_date = add_to_date(mid_year, days=1)
tds_doc.append(
"rates",
{
"tax_withholding_rate": 20,
"from_date": from_date,
"to_date": fiscal_year[2],
"single_threshold": 1,
"cumulative_threshold": 1,
},
)
tds_doc.save()
inv_1 = make_purchase_invoice(
rate=1000, posting_date=add_to_date(fiscal_year[1], days=1), do_not_save=True, do_not_submit=True
)
inv_1.set_posting_time = 1
inv_1.apply_tds = 1
inv_1.tax_withholding_category = tds_doc.name
inv_1.save()
inv_1.submit()
inv_2 = make_purchase_invoice(rate=1000, posting_date=from_date, do_not_save=True, do_not_submit=True)
inv_2.set_posting_time = 1
inv_2.apply_tds = 1
inv_2.tax_withholding_category = tds_doc.name
inv_2.save()
inv_2.submit()
result = execute(
frappe._dict(
company="_Test Company",
party_type="Supplier",
from_date=fiscal_year[1],
to_date=fiscal_year[2],
)
)[1]
expected_values = [
[inv_1.name, "TDS - 3", 10.0, 5000, 500, 4500],
[inv_2.name, "TDS - 3", 20.0, 5000, 1000, 4000],
]
self.check_expected_values(result, expected_values)
def check_expected_values(self, result, expected_values):
for i in range(len(result)):
voucher = frappe._dict(result[i])

View File

@@ -12,8 +12,8 @@ DEFAULT_FILTERS = {
REPORT_FILTER_TEST_CASES: list[tuple[ReportName, ReportFilters]] = [
("General Ledger", {"group_by": "Group by Voucher (Consolidated)"}),
("General Ledger", {"group_by": "Group by Voucher (Consolidated)", "include_dimensions": 1}),
("General Ledger", {"categorize_by": "Categorize by Voucher (Consolidated)"}),
("General Ledger", {"categorize_by": "Categorize by Voucher (Consolidated)", "include_dimensions": 1}),
("Accounts Payable", {"range": "30, 60, 90, 120"}),
("Accounts Receivable", {"range": "30, 60, 90, 120"}),
("Consolidated Financial Statement", {"report": "Balance Sheet"}),

View File

@@ -169,7 +169,7 @@ def validate_fiscal_year(date, fiscal_year, company, label="Date", doc=None):
if doc:
doc.fiscal_year = years[0]
else:
throw(_("{0} '{1}' not in Fiscal Year {2}").format(label, formatdate(date), fiscal_year))
throw(_("{0} '{1}' not in Fiscal Year {2}").format(_(label), formatdate(date), fiscal_year))
@frappe.whitelist()
@@ -629,6 +629,7 @@ def update_reference_in_journal_entry(d, journal_entry, do_not_save=False):
# Update Advance Paid in SO/PO since they might be getting unlinked
update_advance_paid = []
if jv_detail.get("reference_type") in ["Sales Order", "Purchase Order"]:
update_advance_paid.append((jv_detail.reference_type, jv_detail.reference_name))
@@ -714,19 +715,7 @@ def update_reference_in_payment_entry(
# Update Reconciliation effect date in reference
if payment_entry.book_advance_payments_in_separate_party_account:
if payment_entry.advance_reconciliation_takes_effect_on == "Advance Payment Date":
reconcile_on = payment_entry.posting_date
elif payment_entry.advance_reconciliation_takes_effect_on == "Oldest Of Invoice Or Advance":
date_field = "posting_date"
if d.against_voucher_type in ["Sales Order", "Purchase Order"]:
date_field = "transaction_date"
reconcile_on = frappe.db.get_value(d.against_voucher_type, d.against_voucher, date_field)
if getdate(reconcile_on) < getdate(payment_entry.posting_date):
reconcile_on = payment_entry.posting_date
elif payment_entry.advance_reconciliation_takes_effect_on == "Reconciliation Date":
reconcile_on = nowdate()
reconcile_on = get_reconciliation_effect_date(d, payment_entry.company, payment_entry.posting_date)
reference_details.update({"reconcile_effect_on": reconcile_on})
if d.voucher_detail_no:
@@ -780,6 +769,28 @@ def update_reference_in_payment_entry(
return row, update_advance_paid
def get_reconciliation_effect_date(reference, company, posting_date):
reconciliation_takes_effect_on = frappe.get_cached_value(
"Company", company, "reconciliation_takes_effect_on"
)
if reconciliation_takes_effect_on == "Advance Payment Date":
reconcile_on = posting_date
elif reconciliation_takes_effect_on == "Oldest Of Invoice Or Advance":
date_field = "posting_date"
if reference.against_voucher_type in ["Sales Order", "Purchase Order"]:
date_field = "transaction_date"
reconcile_on = frappe.db.get_value(
reference.against_voucher_type, reference.against_voucher, date_field
)
if getdate(reconcile_on) < getdate(posting_date):
reconcile_on = posting_date
elif reconciliation_takes_effect_on == "Reconciliation Date":
reconcile_on = nowdate()
return reconcile_on
def cancel_exchange_gain_loss_journal(
parent_doc: dict | object, referenced_dt: str | None = None, referenced_dn: str | None = None
) -> None:
@@ -994,58 +1005,79 @@ def remove_ref_doc_link_from_pe(
per = qb.DocType("Payment Entry Reference")
pay = qb.DocType("Payment Entry")
linked_pe = (
query = (
qb.from_(per)
.select(per.parent)
.where((per.reference_doctype == ref_type) & (per.reference_name == ref_no) & (per.docstatus.lt(2)))
.run(as_list=1)
)
linked_pe = convert_to_list(linked_pe)
# remove reference only from specified payment
linked_pe = [x for x in linked_pe if x == payment_name] if payment_name else linked_pe
if linked_pe:
update_query = (
qb.update(per)
.set(per.allocated_amount, 0)
.set(per.modified, now())
.set(per.modified_by, frappe.session.user)
.where(per.docstatus.lt(2) & (per.reference_doctype == ref_type) & (per.reference_name == ref_no))
.select("*")
.where(
(per.reference_doctype == ref_type)
& (per.reference_name == ref_no)
& (per.docstatus.lt(2))
& (per.parenttype == "Payment Entry")
)
)
if payment_name:
update_query = update_query.where(per.parent == payment_name)
# update reference only from specified payment
if payment_name:
query = query.where(per.parent == payment_name)
update_query.run()
reference_rows = query.run(as_dict=True)
for pe in linked_pe:
try:
pe_doc = frappe.get_doc("Payment Entry", pe)
pe_doc.set_amounts()
if not reference_rows:
return
# Call cancel on only removed reference
references = [
x
for x in pe_doc.references
if x.reference_doctype == ref_type and x.reference_name == ref_no
]
[pe_doc.make_advance_gl_entries(x, cancel=1) for x in references]
linked_pe = set()
row_names = set()
pe_doc.clear_unallocated_reference_document_rows()
pe_doc.validate_payment_type_with_outstanding()
except Exception:
msg = _("There were issues unlinking payment entry {0}.").format(pe_doc.name)
msg += "<br>"
msg += _("Please cancel payment entry manually first")
frappe.throw(msg, exc=PaymentEntryUnlinkError, title=_("Payment Unlink Error"))
for row in reference_rows:
linked_pe.add(row.parent)
row_names.add(row.name)
qb.update(pay).set(pay.total_allocated_amount, pe_doc.total_allocated_amount).set(
pay.base_total_allocated_amount, pe_doc.base_total_allocated_amount
).set(pay.unallocated_amount, pe_doc.unallocated_amount).set(pay.modified, now()).set(
pay.modified_by, frappe.session.user
).where(pay.name == pe).run()
from erpnext.accounts.doctype.payment_request.payment_request import (
update_payment_requests_as_per_pe_references,
)
frappe.msgprint(_("Payment Entries {0} are un-linked").format("\n".join(linked_pe)))
# Update payment request amount
update_payment_requests_as_per_pe_references(reference_rows, cancel=True)
# Update allocated amounts and modified fields in one go
(
qb.update(per)
.set(per.allocated_amount, 0)
.set(per.modified, now())
.set(per.modified_by, frappe.session.user)
.where(per.name.isin(row_names))
.where(per.parenttype == "Payment Entry")
.run()
)
for pe in linked_pe:
try:
pe_doc = frappe.get_doc("Payment Entry", pe)
pe_doc.set_amounts()
# Call cancel on only removed reference
references = [x for x in pe_doc.references if x.name in row_names]
[pe_doc.make_advance_gl_entries(x, cancel=1) for x in references]
pe_doc.clear_unallocated_reference_document_rows()
pe_doc.validate_payment_type_with_outstanding()
except Exception:
msg = _("There were issues unlinking payment entry {0}.").format(pe_doc.name)
msg += "<br>"
msg += _("Please cancel payment entry manually first")
frappe.throw(msg, exc=PaymentEntryUnlinkError, title=_("Payment Unlink Error"))
(
qb.update(pay)
.set(pay.total_allocated_amount, pe_doc.total_allocated_amount)
.set(pay.base_total_allocated_amount, pe_doc.base_total_allocated_amount)
.set(pay.unallocated_amount, pe_doc.unallocated_amount)
.set(pay.modified, now())
.set(pay.modified_by, frappe.session.user)
.where(pay.name == pe)
.run()
)
frappe.msgprint(_("Payment Entries {0} are un-linked").format("\n".join(linked_pe)))
@frappe.whitelist()
@@ -2232,6 +2264,15 @@ def get_party_types_from_account_type(account_type):
return frappe.db.get_all("Party Type", {"account_type": account_type}, pluck="name")
def get_advance_payment_doctypes():
"""
Get list of advance payment doctypes based on type.
:param type: Optional, can be "receivable" or "payable". If not provided, returns both.
"""
return frappe.get_hooks("advance_payment_doctypes")
def run_ledger_health_checks():
health_monitor_settings = frappe.get_doc("Ledger Health Monitor")
if health_monitor_settings.enable_health_monitor:

View File

@@ -72,6 +72,12 @@ frappe.ui.form.on("Asset", {
filters: { item_code: doc.item_code },
};
});
if (frm.doc.docstatus == 1) {
frm.custom_make_buttons = {
"Asset Capitalization": "Asset Capitalization",
};
}
},
refresh: function (frm) {
@@ -658,10 +664,6 @@ frappe.ui.form.on("Asset", {
} else {
frm.set_value("purchase_invoice_item", data.purchase_invoice_item);
}
let is_editable = !data.is_multiple_items; // if multiple items, then fields should be read-only
frm.set_df_property("gross_purchase_amount", "read_only", is_editable);
frm.set_df_property("asset_quantity", "read_only", is_editable);
}
},
});

View File

@@ -154,6 +154,7 @@
{
"allow_on_submit": 1,
"fetch_from": "item_code.image",
"fetch_if_empty": 1,
"fieldname": "image",
"fieldtype": "Attach Image",
"hidden": 1,
@@ -204,8 +205,8 @@
"fieldname": "purchase_date",
"fieldtype": "Date",
"label": "Purchase Date",
"mandatory_depends_on": "eval:!doc.is_existing_asset && !doc.is_composite_asset",
"read_only_depends_on": "eval:!doc.is_existing_asset && !doc.is_composite_asset"
"read_only_depends_on": "eval:!doc.is_existing_asset && !doc.is_composite_asset",
"reqd": 1
},
{
"fieldname": "disposal_date",
@@ -512,6 +513,7 @@
"fieldname": "total_asset_cost",
"fieldtype": "Currency",
"label": "Total Asset Cost",
"no_copy": 1,
"options": "Company:company:default_currency",
"read_only": 1
},
@@ -520,6 +522,7 @@
"fieldname": "additional_asset_cost",
"fieldtype": "Currency",
"label": "Additional Asset Cost",
"no_copy": 1,
"options": "Company:company:default_currency",
"read_only": 1
},
@@ -593,7 +596,7 @@
"link_fieldname": "target_asset"
}
],
"modified": "2025-04-15 16:33:17.189524",
"modified": "2025-05-20 00:44:06.229177",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",

View File

@@ -42,16 +42,15 @@ from erpnext.controllers.accounts_controller import AccountsController
class Asset(AccountsController):
# begin: auto-generated types
# ruff: noqa
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from erpnext.assets.doctype.asset_finance_book.asset_finance_book import AssetFinanceBook
from frappe.types import DF
from erpnext.assets.doctype.asset_finance_book.asset_finance_book import AssetFinanceBook
additional_asset_cost: DF.Currency
amended_from: DF.Link | None
asset_category: DF.Link | None
@@ -94,7 +93,7 @@ class Asset(AccountsController):
opening_number_of_booked_depreciations: DF.Int
policy_number: DF.Data | None
purchase_amount: DF.Currency
purchase_date: DF.Date | None
purchase_date: DF.Date
purchase_invoice: DF.Link | None
purchase_invoice_item: DF.Data | None
purchase_receipt: DF.Link | None
@@ -118,10 +117,10 @@ class Asset(AccountsController):
total_asset_cost: DF.Currency
total_number_of_depreciations: DF.Int
value_after_depreciation: DF.Currency
# ruff: noqa
# end: auto-generated types
def validate(self):
self.validate_category()
self.validate_precision()
self.set_purchase_doc_row_item()
self.validate_asset_values()
@@ -343,6 +342,17 @@ class Asset(AccountsController):
title=_("Missing Finance Book"),
)
def validate_category(self):
non_depreciable_category = frappe.db.get_value(
"Asset Category", self.asset_category, "non_depreciable_category"
)
if self.calculate_depreciation and non_depreciable_category:
frappe.throw(
_(
"This asset category is marked as non-depreciable. Please disable depreciation calculation or choose a different category."
)
)
def validate_precision(self):
if self.gross_purchase_amount:
self.gross_purchase_amount = flt(
@@ -1169,7 +1179,6 @@ def get_values_from_purchase_doc(purchase_doc_name, item_code, doctype):
frappe.throw(_(f"Selected {doctype} does not contain the Item Code {item_code}"))
first_item = matching_items[0]
is_multiple_items = len(matching_items) > 1
return {
"company": purchase_doc.company,
@@ -1178,7 +1187,6 @@ def get_values_from_purchase_doc(purchase_doc_name, item_code, doctype):
"asset_quantity": first_item.qty,
"cost_center": first_item.cost_center or purchase_doc.get("cost_center"),
"asset_location": first_item.get("asset_location"),
"is_multiple_items": is_multiple_items,
"purchase_receipt_item": first_item.name if doctype == "Purchase Receipt" else None,
"purchase_invoice_item": first_item.name if doctype == "Purchase Invoice" else None,
}

View File

@@ -330,45 +330,6 @@ def _make_journal_entry_for_depreciation(
row.db_update()
def get_depreciation_accounts(asset_category, company):
fixed_asset_account = accumulated_depreciation_account = depreciation_expense_account = None
accounts = frappe.db.get_value(
"Asset Category Account",
filters={"parent": asset_category, "company_name": company},
fieldname=[
"fixed_asset_account",
"accumulated_depreciation_account",
"depreciation_expense_account",
],
as_dict=1,
)
if accounts:
fixed_asset_account = accounts.fixed_asset_account
accumulated_depreciation_account = accounts.accumulated_depreciation_account
depreciation_expense_account = accounts.depreciation_expense_account
if not accumulated_depreciation_account or not depreciation_expense_account:
accounts = frappe.get_cached_value(
"Company", company, ["accumulated_depreciation_account", "depreciation_expense_account"]
)
if not accumulated_depreciation_account:
accumulated_depreciation_account = accounts[0]
if not depreciation_expense_account:
depreciation_expense_account = accounts[1]
if not fixed_asset_account or not accumulated_depreciation_account or not depreciation_expense_account:
frappe.throw(
_("Please set Depreciation related Accounts in Asset Category {0} or Company {1}").format(
asset_category, company
)
)
return fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account
def get_credit_and_debit_accounts(accumulated_depreciation_account, depreciation_expense_account):
root_type = frappe.get_value("Account", depreciation_expense_account, "root_type")
@@ -718,16 +679,15 @@ def get_gl_entries_on_asset_disposal(
def get_asset_details(asset, finance_book=None):
value_after_depreciation = asset.get_value_after_depreciation(finance_book)
accumulated_depr_amount = flt(asset.gross_purchase_amount) - flt(value_after_depreciation)
fixed_asset_account, accumulated_depr_account, _ = get_depreciation_accounts(
asset.asset_category, asset.company
)
disposal_account, depreciation_cost_center = get_disposal_account_and_cost_center(asset.company)
depreciation_cost_center = asset.cost_center or depreciation_cost_center
value_after_depreciation = asset.get_value_after_depreciation(finance_book)
accumulated_depr_amount = flt(asset.gross_purchase_amount) - flt(value_after_depreciation)
return (
fixed_asset_account,
asset,
@@ -739,6 +699,52 @@ def get_asset_details(asset, finance_book=None):
)
def get_depreciation_accounts(asset_category, company):
fixed_asset_account = accumulated_depreciation_account = depreciation_expense_account = None
non_depreciable_category = frappe.db.get_value(
"Asset Category", asset_category, "non_depreciable_category"
)
accounts = frappe.db.get_value(
"Asset Category Account",
filters={"parent": asset_category, "company_name": company},
fieldname=[
"fixed_asset_account",
"accumulated_depreciation_account",
"depreciation_expense_account",
],
as_dict=1,
)
if accounts:
fixed_asset_account = accounts.fixed_asset_account
accumulated_depreciation_account = accounts.accumulated_depreciation_account
depreciation_expense_account = accounts.depreciation_expense_account
if not fixed_asset_account:
frappe.throw(_("Please set Fixed Asset Account in Asset Category {0}").format(asset_category))
if not non_depreciable_category:
accounts = frappe.get_cached_value(
"Company", company, ["accumulated_depreciation_account", "depreciation_expense_account"]
)
if not accumulated_depreciation_account:
accumulated_depreciation_account = accounts[0]
if not depreciation_expense_account:
depreciation_expense_account = accounts[1]
if not accumulated_depreciation_account or not depreciation_expense_account:
frappe.throw(
_("Please set Depreciation related Accounts in Asset Category {0} or Company {1}").format(
asset_category, company
)
)
return fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account
def get_profit_gl_entries(
asset, profit_amount, gl_entries, disposal_account, depreciation_cost_center, date=None
):
@@ -792,7 +798,7 @@ def get_value_after_depreciation_on_disposal_date(asset, disposal_date, finance_
idx = 1
if finance_book:
for d in asset.finance_books:
for d in asset_doc.finance_books:
if d.finance_book == finance_book:
idx = d.idx
break

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