Compare commits

...

427 Commits

Author SHA1 Message Date
mergify[bot]
bd7e5b3e05 refactor: use consistent report column names (backport #54451) (backport #54478) (#54506)
* refactor: use consistent report column names

(cherry picked from commit 7630c01e40)

# Conflicts:
#	erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py
(cherry picked from commit ab188c4404)

* refactor: better label for entity type

(cherry picked from commit 8e12bda108)
(cherry picked from commit e1ff203f95)

* fix: add party_type for dynamic link and add it to grouping key

(cherry picked from commit a3ad1fb163)
(cherry picked from commit 6eb2868a15)

* fix: use key consistently

(cherry picked from commit 8f9a5e6c0c)
(cherry picked from commit 32d46b3e88)

* chore: resolve conflicts

(cherry picked from commit 34e94d6e7a)

* chore: translate values correctly

(cherry picked from commit 83fd655042)

---------

Co-authored-by: Smit Vora <smitvora203@gmail.com>
2026-04-24 20:01:36 +05:30
Frappe PR Bot
adf92a8292 chore(release): Bumped to Version 14.92.14
## [14.92.14](https://github.com/frappe/erpnext/compare/v14.92.13...v14.92.14) (2026-04-10)

### Bug Fixes

* added exception handling on service level agreement apply hook ([#50096](https://github.com/frappe/erpnext/issues/50096)) ([#54192](https://github.com/frappe/erpnext/issues/54192)) ([12b2788](12b27883f6))
2026-04-10 11:53:37 +00:00
diptanilsaha
df6dc540f8 Merge pull request #54202 from frappe/mergify/bp/version-14/pr-54192
fix: added exception handling on service level agreement apply hook (#50096) (backport #54192)
2026-04-10 17:22:07 +05:30
diptanilsaha
12b27883f6 fix: added exception handling on service level agreement apply hook (#50096) (#54192)
Co-authored-by: Ankush Menat <ankush@frappe.io>
(cherry picked from commit 21311dab86)
2026-04-10 11:33:06 +00:00
Frappe PR Bot
5bbfb79cdc chore(release): Bumped to Version 14.92.13
## [14.92.13](https://github.com/frappe/erpnext/compare/v14.92.12...v14.92.13) (2026-03-21)

### Bug Fixes

* allow zero valuation rate ([7a98e13](7a98e13d7d))
2026-03-21 08:34:35 +00:00
rohitwaghchaure
266ac2d5be Merge pull request #53637 from frappe/mergify/bp/version-14/pr-53635
fix: allow zero valuation rate (backport #53635)
2026-03-21 14:03:04 +05:30
Rohit Waghchaure
7a98e13d7d fix: allow zero valuation rate
(cherry picked from commit a6eadb18c9)
2026-03-19 08:32:50 +00:00
rohitwaghchaure
aeee42e857 Merge pull request #52349 from frappe/version-14-hotfix
chore: release v14
2026-02-03 22:48:16 +05:30
Mihir Kandoi
e1674d2017 Merge pull request #51658 from mihir-kandoi/eol-msg 2026-01-30 17:09:28 +05:30
Mihir Kandoi
65d7c6b882 chore: rename filename 2026-01-30 17:08:48 +05:30
Frappe PR Bot
966f262e38 chore(release): Bumped to Version 14.92.12
## [14.92.12](https://github.com/frappe/erpnext/compare/v14.92.11...v14.92.12) (2026-01-27)

### Bug Fixes

* **stock:** remove limit filter while fetching batch and bin ([07ac93d](07ac93d06a))
2026-01-27 14:42:02 +00:00
ruthra kumar
44f81092b6 Merge pull request #52105 from frappe/version-14-hotfix
chore: release v14
2026-01-27 20:09:29 +05:30
rohitwaghchaure
6f1616bc95 Merge pull request #51939 from aerele/fix/pick-list-qty-validation
fix(stock): remove limit filter while fetching batch and bin
2026-01-23 19:36:54 +05:30
Sudharsanan11
07ac93d06a fix(stock): remove limit filter while fetching batch and bin 2026-01-20 23:12:13 +05:30
Frappe PR Bot
34499d7f77 chore(release): Bumped to Version 14.92.11
## [14.92.11](https://github.com/frappe/erpnext/compare/v14.92.10...v14.92.11) (2026-01-20)

### Bug Fixes

* Show non-SLE vouchers with GL entries in Stock vs Account Value Comparison report ([6e03d45](6e03d45034))
* **transaction.js:** use flt instead of cint for plc_conversion_rate ([d09de53](d09de53d1d))
2026-01-20 16:37:18 +00:00
ruthra kumar
2967de1999 Merge pull request #51910 from frappe/version-14-hotfix
chore: release v14
2026-01-20 22:05:36 +05:30
ruthra kumar
824beaa893 Merge pull request #51837 from frappe/mergify/bp/version-14-hotfix/pr-51787
fix: recalculate taxes when item tax template changes after discount (backport #51787)
2026-01-19 14:37:18 +05:30
ljain112
b4dc1be5ed chore: resolve conflicts 2026-01-19 13:45:11 +05:30
Lakshit Jain
cf49c32b94 Merge pull request #51787 from ljain112/fix-taxes-disc
fix: recalculate taxes when item tax template changes after discount
(cherry picked from commit f00aeec9b4)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
#	erpnext/controllers/taxes_and_totals.py
2026-01-19 07:01:36 +00:00
rohitwaghchaure
d54f45469a Merge pull request #51770 from frappe/mergify/bp/version-14-hotfix/pr-51768
fix: Show non-SLE vouchers with GL entries in Stock vs Account Value … (backport #51768)
2026-01-15 20:59:58 +05:30
rohitwaghchaure
ad5181c52f chore: fix conflicts 2026-01-15 19:28:44 +05:30
Rohit Waghchaure
6e03d45034 fix: Show non-SLE vouchers with GL entries in Stock vs Account Value Comparison report
(cherry picked from commit 1db9ce205f)

# Conflicts:
#	erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py
2026-01-15 12:20:32 +00:00
Diptanil Saha
7a18f86dd5 Merge pull request #51746 from frappe/mergify/bp/version-14-hotfix/pr-51730
fix(transaction.js): use flt instead of cint for plc_conversion_rate (backport #51730)
2026-01-14 15:56:06 +05:30
Diptanil Saha
39e1bddce6 chore: resolve conflict 2026-01-14 15:53:18 +05:30
diptanilsaha
d09de53d1d fix(transaction.js): use flt instead of cint for plc_conversion_rate
(cherry picked from commit 8b445e04e5)

# Conflicts:
#	erpnext/public/js/controllers/transaction.js
2026-01-14 10:22:04 +00:00
Frappe PR Bot
8035940263 chore(release): Bumped to Version 14.92.10
## [14.92.10](https://github.com/frappe/erpnext/compare/v14.92.9...v14.92.10) (2026-01-13)

### Bug Fixes

* don't duplicate default income account to Item ([#50413](https://github.com/frappe/erpnext/issues/50413)) ([55d2a54](55d2a54785)), closes [#48231](https://github.com/frappe/erpnext/issues/48231)
* negative stock issue for higher precision ([21d1385](21d13859a0))
2026-01-13 14:44:57 +00:00
ruthra kumar
c69f3d330a Merge pull request #51712 from frappe/version-14-hotfix
chore: release v14
2026-01-13 20:13:30 +05:30
Mihir Kandoi
90d88b1c26 chore: fix grammar 2026-01-13 11:00:42 +05:30
Mihir Kandoi
22eec09175 chore: update links 2026-01-13 10:52:51 +05:30
ruthra kumar
dbfd4ea4d3 Merge pull request #51331 from frappe/mergify/bp/version-14-hotfix/pr-50413
fix: don't duplicate default income account to Item (backport #50413)
2026-01-12 20:34:03 +05:30
barredterra
8d28dcb18b chore: resolve conflicts 2026-01-11 17:59:27 +01:00
Mihir Kandoi
3f186b24f3 chore: EOL announcement for v14 2026-01-10 22:44:44 +05:30
rohitwaghchaure
4b0ddbf73a Merge pull request #51591 from frappe/mergify/bp/version-14-hotfix/pr-51588
fix: negative stock issue for higher precision (backport #51586) (backport #51588)
2026-01-08 16:11:20 +05:30
rohitwaghchaure
cddf1e1ee5 chore: fix conflicts
Refactor delivery note tests to improve clarity and organization. Remove redundant test cases and ensure proper valuation checks for batch and serial items.
2026-01-08 15:18:53 +05:30
rohitwaghchaure
22e5aba02b chore: fix conflicts
Refactor test cases for delivery notes to handle negative stock and higher precision.

(cherry picked from commit 5193dbba9b)
2026-01-08 09:35:44 +00:00
Rohit Waghchaure
21d13859a0 fix: negative stock issue for higher precision
(cherry picked from commit 87be020c78)

# Conflicts:
#	erpnext/stock/doctype/delivery_note/test_delivery_note.py
(cherry picked from commit 1bbeecff12)

# Conflicts:
#	erpnext/stock/doctype/delivery_note/test_delivery_note.py
2026-01-08 09:35:44 +00:00
Frappe PR Bot
18fbe69892 chore(release): Bumped to Version 14.92.9
## [14.92.9](https://github.com/frappe/erpnext/compare/v14.92.8...v14.92.9) (2026-01-07)

### Bug Fixes

* update filters on period closing voucher ([6499a1d](6499a1dae0))
2026-01-07 04:58:04 +00:00
ruthra kumar
f2043baf36 Merge pull request #51539 from frappe/version-14-hotfix
chore: release v14
2026-01-07 10:26:40 +05:30
ruthra kumar
6267b9aea5 Merge pull request #51486 from frappe/mergify/bp/version-14-hotfix/pr-51467
fix: update filters on period closing voucher (backport #51467)
2026-01-05 10:53:20 +05:30
SowmyaArunachalam
6499a1dae0 fix: update filters on period closing voucher
(cherry picked from commit 7ab1e1f677)
2026-01-05 05:20:31 +00:00
Sagar Vora
478992812f Merge pull request #51410 from frappe/revert-51302-pin-urllib3 2025-12-31 13:22:41 +05:30
Sagar Vora
634dd11d72 Revert "fix(deps): pin urllib3" 2025-12-31 13:18:09 +05:30
Frappe PR Bot
29134db5b4 chore(release): Bumped to Version 14.92.8
## [14.92.8](https://github.com/frappe/erpnext/compare/v14.92.7...v14.92.8) (2025-12-30)

### Bug Fixes

* **stock:** update last incoming rate in serial no doctype ([5e12937](5e129374b9))
2025-12-30 13:33:09 +00:00
ruthra kumar
a2597c9608 Merge pull request #51390 from frappe/version-14-hotfix
chore: release v14
2025-12-30 19:01:44 +05:30
rohitwaghchaure
0e6586734a Merge pull request #51365 from aerele/fix/serial-item-incoming-rate
fix(stock): update last incoming rate in serial no doctype
2025-12-29 23:31:07 +05:30
Sudharsanan11
5e129374b9 fix(stock): update last incoming rate in serial no doctype 2025-12-29 16:54:09 +05:30
Raffael Meyer
55d2a54785 fix: don't duplicate default income account to Item (#50413)
* fix: don't duplicate default income account to Item

Only store _Default Income Account_ in **Item** if it's different from the **Company**'s  _Default Income Account_.

Resolves #48231

* refactor: move db call out of loop

* docs: add docstring

(cherry picked from commit b6cb9d4799)

# Conflicts:
#	erpnext/controllers/selling_controller.py
2025-12-25 09:23:09 +00:00
Frappe PR Bot
b3bf456ea2 chore(release): Bumped to Version 14.92.7
## [14.92.7](https://github.com/frappe/erpnext/compare/v14.92.6...v14.92.7) (2025-12-24)

### Bug Fixes

* available qty not fetched on selection of batch ([9841438](98414385e5))
* **deps:** pin urllib3<2 ([1dee100](1dee10077c))
* disable uv ([d713f39](d713f39fce))
* **patch:** fallback for frankfurter settings v14 patch ([5c9e0bb](5c9e0bba2f))

### Performance Improvements

* optimize company monthly sales query using date range ([#48942](https://github.com/frappe/erpnext/issues/48942)) ([e9c1d0a](e9c1d0ad52))
2025-12-24 08:23:59 +00:00
rohitwaghchaure
932dc66871 Merge pull request #51279 from frappe/version-14-hotfix
chore: release v14
2025-12-24 13:52:30 +05:30
Akhil Narang
3a6d056fd3 Merge pull request #51302 from akhilnarang/pin-urllib3
fix(deps): pin urllib3
2025-12-24 12:52:26 +05:30
Akhil Narang
d713f39fce fix: disable uv
Seems to cause an issue with dependency resolution when installation dev dependencies

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2025-12-24 12:29:21 +05:30
Akhil Narang
1dee10077c fix(deps): pin urllib3<2
v2 has breaking changes, and some other ERPNext dependencies pull in newer requests, which has urllib3<3 mentioned.

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2025-12-24 11:26:39 +05:30
ruthra kumar
c86cf5b9c6 Merge pull request #51291 from frappe/mergify/bp/version-14-hotfix/pr-51285
fix(patch): handle currency exchange settings frankfurter api update for older versions (backport #51285)
2025-12-23 20:46:16 +05:30
diptanilsaha
5c9e0bba2f fix(patch): fallback for frankfurter settings v14 patch
(cherry picked from commit 50bb1ce31d)
2025-12-23 12:11:25 +00:00
rohitwaghchaure
793688710a Merge pull request #51261 from rohitwaghchaure/fixed-support-53592
fix: available qty not fetched on selection of batch
2025-12-22 16:52:30 +05:30
Rohit Waghchaure
98414385e5 fix: available qty not fetched on selection of batch 2025-12-22 16:47:38 +05:30
Diptanil Saha
33f7b742ec Merge pull request #51147 from frappe/mergify/bp/version-14-hotfix/pr-48942 2025-12-17 11:57:24 +05:30
Yash Chaubey
e9c1d0ad52 perf: optimize company monthly sales query using date range (#48942)
* perf: optimize company monthly sales query using date range instead of DATE_FORMAT

* perf: optimize company monthly sales query using date range

(cherry picked from commit 4ede97ae2b)
2025-12-17 06:07:27 +00:00
Frappe PR Bot
e733b41ab3 chore(release): Bumped to Version 14.92.6
## [14.92.6](https://github.com/frappe/erpnext/compare/v14.92.5...v14.92.6) (2025-12-16)

### Bug Fixes

* **asset:** calculate depreciation amount for non prorata based schedules ([8de0d60](8de0d60581))
* **asset:** prorata daily depr amount calculation ([bc58fd1](bc58fd1fa4))
* **currency exchange settings:** added backward compatibility for frankfurter api ([a15b010](a15b010868))
* **share balance:** use currency field instead of int for rate and amount ([a299392](a299392128))
* Short circuit guest perm checks ([6f6cbb7](6f6cbb717e))
* **transaction-deletion:** Add virtual doctypes to the list of ignored doctypes (backport [#51063](https://github.com/frappe/erpnext/issues/51063)) ([#51086](https://github.com/frappe/erpnext/issues/51086)) ([67c0d08](67c0d08569))
* update expected schedules on test case test_schedule_for_straight_line_method_for_existing_asset ([6ea7393](6ea7393f7d))
2025-12-16 15:12:25 +00:00
ruthra kumar
39fd4a827c Merge pull request #51125 from frappe/version-14-hotfix
chore: release v14
2025-12-16 20:40:57 +05:30
mergify[bot]
67c0d08569 fix(transaction-deletion): Add virtual doctypes to the list of ignored doctypes (backport #51063) (#51086)
* fix: Add virtual doctypes to the list of ignored doctypes in transaction deletion

(cherry picked from commit c7a7cb2b90)

* refactor: switch to `or_filters` so the query hits the DB only once

(cherry picked from commit 45a7195abe)

* refactor: remove redundant assignment of doctypes_to_be_ignored_list

(cherry picked from commit 0f7d89f4d1)

---------

Co-authored-by: KerollesFathy <kerollesfhabib@gmail.com>
2025-12-14 14:31:02 +05:30
Ankush Menat
6f6cbb717e fix: Short circuit guest perm checks 2025-12-14 12:12:35 +05:30
Diptanil Saha
387657fa92 Merge pull request #51044 from frappe/mergify/bp/version-14-hotfix/pr-51037
fix(currency exchange settings): added backward compatibility for frankfurter api (backport #51037)
2025-12-11 16:27:54 +05:30
Diptanil Saha
ef03d90a08 chore: resolve conflict 2025-12-11 15:58:30 +05:30
diptanilsaha
a15b010868 fix(currency exchange settings): added backward compatibility for frankfurter api
(cherry picked from commit 5c2bb66028)

# Conflicts:
#	erpnext/patches.txt
2025-12-11 10:26:17 +00:00
Khushi Rawat
9d00afe1b1 Merge pull request #50964 from aerele/daily-prorata-depr-amount-calculation
fix(asset): prorata daily depr amount calculation
2025-12-10 14:22:17 +05:30
Navin-S-R
6ea7393f7d fix: update expected schedules on test case test_schedule_for_straight_line_method_for_existing_asset 2025-12-10 13:35:57 +05:30
Navin-S-R
8de0d60581 fix(asset): calculate depreciation amount for non prorata based schedules 2025-12-10 12:38:27 +05:30
Diptanil Saha
a67092894f Merge pull request #51002 from frappe/mergify/bp/version-14-hotfix/pr-51001
fix(share balance): use currency field instead of int for rate and amount (backport #51001)
2025-12-10 10:38:26 +05:30
Diptanil Saha
77b9044d8d chore: resolve conflict 2025-12-10 09:56:15 +05:30
Diptanil Saha
ba9f571886 chore: resolve conflict 2025-12-10 09:52:37 +05:30
diptanilsaha
a299392128 fix(share balance): use currency field instead of int for rate and amount
(cherry picked from commit 2fe5fad884)

# Conflicts:
#	erpnext/accounts/doctype/share_balance/share_balance.json
#	erpnext/accounts/doctype/share_balance/share_balance.py
2025-12-10 04:21:05 +00:00
Navin-S-R
bc58fd1fa4 fix(asset): prorata daily depr amount calculation 2025-12-08 15:38:48 +05:30
Frappe PR Bot
1920259180 chore(release): Bumped to Version 14.92.5
## [14.92.5](https://github.com/frappe/erpnext/compare/v14.92.4...v14.92.5) (2025-12-03)

### Bug Fixes

* **Job Card:** avoid Type Error when completed_qty is None (backport [#50447](https://github.com/frappe/erpnext/issues/50447)) ([#50760](https://github.com/frappe/erpnext/issues/50760)) ([5e05873](5e05873226))
* update uom when item changes ([a3b120b](a3b120b3b2))
2025-12-03 05:43:40 +00:00
Diptanil Saha
ea1ca7111d Merge pull request #50867 from frappe/version-14-hotfix 2025-12-03 11:12:16 +05:30
rohitwaghchaure
10f1c9c3ac Merge pull request #50763 from aerele/support-52987
fix: update uom when item changes
2025-11-26 23:42:32 +05:30
Pugazhendhi Velu
a3b120b3b2 fix: update uom when item changes 2025-11-26 16:07:27 +00:00
mergify[bot]
5e05873226 fix(Job Card): avoid Type Error when completed_qty is None (backport #50447) (#50760)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix(Job Card): avoid Type Error when completed_qty is None (#50447)
2025-11-26 14:55:53 +01:00
ruthra kumar
14a7ab71b4 Merge pull request #50747 from frappe/version-14-hotfix
chore: release v14
2025-11-26 10:17:16 +05:30
mergify[bot]
db828c08b6 chore: switched frankfurter domain from frankfurter.app to frankfurter.dev (backport #50734) (#50739)
Co-authored-by: diptanilsaha <diptanil@frappe.io>
2025-11-25 15:49:37 +05:30
Frappe PR Bot
993890116b chore(release): Bumped to Version 14.92.4
## [14.92.4](https://github.com/frappe/erpnext/compare/v14.92.3...v14.92.4) (2025-11-18)

### Bug Fixes

* current qty in stock reco ([5979683](5979683e8e))
* **process statement of accounts:** use date instead of formatted date ([1ef9471](1ef9471c79))
2025-11-18 13:09:28 +00:00
Diptanil Saha
cd437b5a26 Merge pull request #50594 from frappe/version-14-hotfix 2025-11-18 18:37:55 +05:30
Diptanil Saha
e6f505ef81 Merge pull request #50523 from frappe/mergify/bp/version-14-hotfix/pr-49086
fix(process statement of accounts): use date instead of formatted date (backport #49086)
2025-11-13 22:16:06 +05:30
ravibharathi656
1ef9471c79 fix(process statement of accounts): use date instead of formatted date
(cherry picked from commit aa3f50ab77)
2025-11-13 16:24:05 +00:00
rohitwaghchaure
304aad6745 Merge pull request #50490 from frappe/mergify/bp/version-14-hotfix/pr-50487
fix: current qty in stock reconciliation  (backport #50487)
2025-11-12 22:49:37 +05:30
rohitwaghchaure
c80fed8b2f chore: fix conflicts 2025-11-12 13:57:00 +05:30
Rohit Waghchaure
5979683e8e fix: current qty in stock reco
(cherry picked from commit 58315bc963)

# Conflicts:
#	erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
2025-11-12 08:25:59 +00:00
Frappe PR Bot
457a81123b chore(release): Bumped to Version 14.92.3
## [14.92.3](https://github.com/frappe/erpnext/compare/v14.92.2...v14.92.3) (2025-11-11)

### Bug Fixes

* set company before creating asset movement to avoid permission error ([8dc80c9](8dc80c948e))
2025-11-11 14:42:37 +00:00
Diptanil Saha
d7966183be Merge pull request #50474 from frappe/version-14-hotfix 2025-11-11 20:11:02 +05:30
Khushi Rawat
367bd58e76 Merge pull request #50378 from frappe/mergify/bp/version-14-hotfix/pr-50367
fix: set company before creating asset movement to avoid permission error (backport #50367)
2025-11-06 10:03:10 +05:30
rehansari26
8dc80c948e fix: set company before creating asset movement to avoid permission error
(cherry picked from commit 8c49c9e500)
2025-11-05 21:50:18 +00:00
Diptanil Saha
0e3cc120dc Merge pull request #50334 from frappe/version-14-hotfix
chore: release v14
2025-11-04 18:00:16 +05:30
ruthra kumar
b54c5f61d6 Merge pull request #50308 from frappe/mergify/bp/version-14-hotfix/pr-50297
chore:there is no company field in bank (backport #50297)
2025-11-03 14:04:23 +05:30
Nihal Roshan
c51a9025b3 refactor: remove company filter
'Bank' doctype has no 'company' field.

(cherry picked from commit f1682ea90e)
2025-11-03 08:31:53 +00:00
Frappe PR Bot
616448f9c9 chore(release): Bumped to Version 14.92.2
## [14.92.2](https://github.com/frappe/erpnext/compare/v14.92.1...v14.92.2) (2025-10-21)

### Bug Fixes

* do reposting of first transfer entry based on item-wh combination ([85c509e](85c509ea69))
* handle flt conversion for prev_ordered_qty ([9460568](94605687c7))
2025-10-21 12:45:22 +00:00
Diptanil Saha
70a8c64ea4 Merge pull request #50181 from frappe/version-14-hotfix
chore: release v14
2025-10-21 18:13:40 +05:30
mergify[bot]
00a75d4984 refactor: simplify expression (backport #50168) (#50169)
Co-authored-by: barredterra <14891507+barredterra@users.noreply.github.com>
2025-10-19 23:59:31 +02:00
rohitwaghchaure
8b826c2369 Merge pull request #50121 from frappe/mergify/bp/version-14-hotfix/pr-50061
fix: do reposting of first transfer entry based on item-wh combination (backport #50061)
2025-10-16 15:02:52 +05:30
rohitwaghchaure
210786119d chore: fix conflicts 2025-10-16 00:17:50 +05:30
Rohit Waghchaure
85c509ea69 fix: do reposting of first transfer entry based on item-wh combination
(cherry picked from commit 2f25b445ab)

# Conflicts:
#	erpnext/stock/stock_ledger.py
2025-10-15 18:44:46 +00:00
Mihir Kandoi
6e35b6b6b3 Merge pull request #50105 from frappe/mergify/bp/version-14-hotfix/pr-50078
fix: handle flt conversion for prev_ordered_qty (backport #50078)
2025-10-15 00:15:14 +05:30
Kavin
94605687c7 fix: handle flt conversion for prev_ordered_qty
(cherry picked from commit 77c35ef47f)
2025-10-14 18:10:27 +00:00
Frappe PR Bot
e27518b2d4 chore(release): Bumped to Version 14.92.1
## [14.92.1](https://github.com/frappe/erpnext/compare/v14.92.0...v14.92.1) (2025-10-14)

### Bug Fixes

* sanitize projects field in tasks webform ([#50089](https://github.com/frappe/erpnext/issues/50089)) ([aadc83d](aadc83d0d9))
2025-10-14 14:18:29 +00:00
Diptanil Saha
cf71178af6 Merge pull request #50099 from frappe/version-14-hotfix
chore: release v14
2025-10-14 19:46:52 +05:30
ruthra kumar
002575244f Merge pull request #50097 from frappe/mergify/bp/version-14-hotfix/pr-50089
fix: sanitize projects field in tasks webform (backport #50089)
2025-10-14 19:22:52 +05:30
Akhil Narang
aadc83d0d9 fix: sanitize projects field in tasks webform (#50089)
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
(cherry picked from commit f8b50d3ffa)
2025-10-14 13:08:25 +00:00
Frappe PR Bot
66f1e2a076 chore(release): Bumped to Version 14.92.0
# [14.92.0](https://github.com/frappe/erpnext/compare/v14.91.3...v14.92.0) (2025-10-07)

### Bug Fixes

* **Common Code:** fetch canonical URI from Code List (backport [#49882](https://github.com/frappe/erpnext/issues/49882)) ([#49883](https://github.com/frappe/erpnext/issues/49883)) ([9b5183e](9b5183e0e5))
* do not fetch disabled item tax template ([dcae024](dcae024fd2))
* linter; dont change doc after DB update (backport [#49907](https://github.com/frappe/erpnext/issues/49907)) ([#49909](https://github.com/frappe/erpnext/issues/49909)) ([30a6fe5](30a6fe55ca))
* resolved conflict ([2c383a6](2c383a69f9))
* Set paid amount automatically only if return entry validated and has negative grand total ([#49829](https://github.com/frappe/erpnext/issues/49829)) ([b7d76d8](b7d76d8fad))

### Features

* dynamic due date in payment terms when fetched from order (backport [#48864](https://github.com/frappe/erpnext/issues/48864)) ([#49937](https://github.com/frappe/erpnext/issues/49937)) ([d82106c](d82106cb76))
2025-10-07 13:18:52 +00:00
ruthra kumar
1d5935a10f chore: release v14 (#49943)
* refactor(Supplier): custom buttons call make methods (backport #49840) (#49841)

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

* fix(Common Code): fetch canonical URI from Code List (backport #49882) (#49883)

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix(Common Code): fetch canonical URI from Code List (#49882)

* fix: Set paid amount automatically only if return entry validated and has negative grand total (#49829)

(cherry picked from commit dcbcc596f2)

# Conflicts:
#	erpnext/public/js/controllers/taxes_and_totals.js

* fix: resolved conflict

* fix: linter; dont change doc after DB update (backport #49907) (#49909)

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
Co-authored-by: ruthra kumar <ruthra@erpnext.com>
fix: linter; dont change doc after DB update (#49907)

* fix: do not fetch disabled item tax template

(cherry picked from commit b10cf4a928)

# Conflicts:
#	erpnext/public/js/controllers/transaction.js
#	erpnext/stock/get_item_details.py

* chore: fix conflicts

* chore: fix conflicts

* chore: fix linters issue

* feat: dynamic due date in payment terms when fetched from order (backport #48864) (#49937)

* feat: dynamic due date in payment terms when fetched from order (#48864)

* fix: dynamic due date when payment terms are fetched from order

* fix(test): use change_settings decorator for settings enable and disable

* fix(test): compare schedule for due_date dynamically

* fix: save conditions for due date at invoice level

* fix: make fields read only and on change of date unset the date condition fields

* fix: remove fetch_form

* fix: correct field assingment

* fix: revert unwanted changes

* refactor: streamline payment term field assignments and enhance discount date handling

* refactor: remove payment_term from fields_to_copy and optimize currency handling in transaction callback

* refactor: ensure default values for payment schedule and discount validity fields

(cherry picked from commit 3c70cbbaf8)

# Conflicts:
#	erpnext/accounts/doctype/payment_schedule/payment_schedule.json
#	erpnext/accounts/doctype/payment_schedule/payment_schedule.py
#	erpnext/public/js/controllers/transaction.js
#	erpnext/selling/doctype/sales_order/test_sales_order.py
#	erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py

* chore: resolve conflicts

---------

Co-authored-by: Lakshit Jain <ljain112@gmail.com>

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
Co-authored-by: Nabin Hait <nabinhait@gmail.com>
Co-authored-by: ruthra kumar <ruthra@erpnext.com>
Co-authored-by: ljain112 <ljain112@gmail.com>
Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-10-07 18:47:23 +05:30
mergify[bot]
d82106cb76 feat: dynamic due date in payment terms when fetched from order (backport #48864) (#49937)
* feat: dynamic due date in payment terms when fetched from order (#48864)

* fix: dynamic due date when payment terms are fetched from order

* fix(test): use change_settings decorator for settings enable and disable

* fix(test): compare schedule for due_date dynamically

* fix: save conditions for due date at invoice level

* fix: make fields read only and on change of date unset the date condition fields

* fix: remove fetch_form

* fix: correct field assingment

* fix: revert unwanted changes

* refactor: streamline payment term field assignments and enhance discount date handling

* refactor: remove payment_term from fields_to_copy and optimize currency handling in transaction callback

* refactor: ensure default values for payment schedule and discount validity fields

(cherry picked from commit 3c70cbbaf8)

# Conflicts:
#	erpnext/accounts/doctype/payment_schedule/payment_schedule.json
#	erpnext/accounts/doctype/payment_schedule/payment_schedule.py
#	erpnext/public/js/controllers/transaction.js
#	erpnext/selling/doctype/sales_order/test_sales_order.py
#	erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py

* chore: resolve conflicts

---------

Co-authored-by: Lakshit Jain <ljain112@gmail.com>
2025-10-07 14:10:46 +05:30
rohitwaghchaure
03aeac6c9b Merge pull request #49931 from frappe/mergify/bp/version-14-hotfix/pr-49702
fix: do not fetch disabled item tax template (backport #49702)
2025-10-07 11:54:19 +05:30
rohitwaghchaure
014f5bff5c chore: fix linters issue 2025-10-07 11:24:49 +05:30
rohitwaghchaure
819667ab24 chore: fix conflicts 2025-10-07 11:00:45 +05:30
rohitwaghchaure
aa20e224fb chore: fix conflicts 2025-10-07 11:00:02 +05:30
ljain112
dcae024fd2 fix: do not fetch disabled item tax template
(cherry picked from commit b10cf4a928)

# Conflicts:
#	erpnext/public/js/controllers/transaction.js
#	erpnext/stock/get_item_details.py
2025-10-07 05:26:09 +00:00
mergify[bot]
30a6fe55ca fix: linter; dont change doc after DB update (backport #49907) (#49909)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
Co-authored-by: ruthra kumar <ruthra@erpnext.com>
fix: linter; dont change doc after DB update (#49907)
2025-10-06 13:34:24 +02:00
ruthra kumar
57f9894f41 Merge pull request #49892 from frappe/mergify/bp/version-14-hotfix/pr-49829
fix: Set paid amount automatically only if return entry validated and has negative grand total (backport #49829)
2025-10-06 12:58:55 +05:30
Nabin Hait
2c383a69f9 fix: resolved conflict 2025-10-06 12:19:22 +05:30
Nabin Hait
b7d76d8fad fix: Set paid amount automatically only if return entry validated and has negative grand total (#49829)
(cherry picked from commit dcbcc596f2)

# Conflicts:
#	erpnext/public/js/controllers/taxes_and_totals.js
2025-10-06 05:58:16 +00:00
mergify[bot]
9b5183e0e5 fix(Common Code): fetch canonical URI from Code List (backport #49882) (#49883)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix(Common Code): fetch canonical URI from Code List (#49882)
2025-10-04 19:22:04 +02:00
mergify[bot]
0b43d518af refactor(Supplier): custom buttons call make methods (backport #49840) (#49841)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2025-10-02 00:16:20 +02:00
Frappe PR Bot
a6b490e4b3 chore(release): Bumped to Version 14.91.3
## [14.91.3](https://github.com/frappe/erpnext/compare/v14.91.2...v14.91.3) (2025-09-30)

### Performance Improvements

* reposting for backdated transactions ([3d51c1b](3d51c1b363))
2025-09-30 13:07:25 +00:00
ruthra kumar
a5d33d5665 Merge pull request #49802 from frappe/version-14-hotfix
chore: release v14
2025-09-30 18:36:03 +05:30
Frappe PR Bot
48c3c80383 chore(release): Bumped to Version 14.91.2
## [14.91.2](https://github.com/frappe/erpnext/compare/v14.91.1...v14.91.2) (2025-09-25)

### Performance Improvements

* reposting for backdated transactions ([f3da431](f3da431f1f))
2025-09-25 14:45:52 +00:00
rohitwaghchaure
a9a68f2523 Merge pull request #49726 from frappe/mergify/bp/version-14/pr-49723
perf: reposting for backdated transactions (backport #49720) (backport #49723)
2025-09-25 20:14:23 +05:30
Rohit Waghchaure
f3da431f1f perf: reposting for backdated transactions
(cherry picked from commit 1b0fc0541b)
(cherry picked from commit 3d51c1b363)
2025-09-25 13:22:15 +00:00
rohitwaghchaure
14e92d589f Merge pull request #49723 from frappe/mergify/bp/version-14-hotfix/pr-49720
perf: reposting for backdated transactions (backport #49720)
2025-09-25 18:50:18 +05:30
Rohit Waghchaure
3d51c1b363 perf: reposting for backdated transactions
(cherry picked from commit 1b0fc0541b)
2025-09-25 12:16:23 +00:00
Frappe PR Bot
825ef415ef chore(release): Bumped to Version 14.91.1
## [14.91.1](https://github.com/frappe/erpnext/compare/v14.91.0...v14.91.1) (2025-09-23)

### Bug Fixes

* add condition for name ([0c7911d](0c7911d0fe))
2025-09-23 13:35:10 +00:00
ruthra kumar
f6148c4352 chore: release v14 (#49696)
* fix: add condition for name

(cherry picked from commit cf5a2d6351)

* test: add test to validate user permission in qb

(cherry picked from commit a5b881ea74)

# Conflicts:
#	erpnext/setup/doctype/employee/test_employee.py

---------

Co-authored-by: venkat102 <venkatesharunachalam659@gmail.com>
Co-authored-by: ruthra kumar <ruthra@erpnext.com>
2025-09-23 19:03:40 +05:30
ruthra kumar
3c408ff66b Merge pull request #49616 from frappe/mergify/bp/version-14-hotfix/pr-49467
fix: add condition for name (backport #49467)
2025-09-22 10:49:01 +05:30
venkat102
f6bc9fc505 test: add test to validate user permission in qb
(cherry picked from commit a5b881ea74)

# Conflicts:
#	erpnext/setup/doctype/employee/test_employee.py
2025-09-18 16:47:10 +05:30
venkat102
0c7911d0fe fix: add condition for name
(cherry picked from commit cf5a2d6351)
2025-09-18 11:12:13 +00:00
Frappe PR Bot
b8ecc4274f chore(release): Bumped to Version 14.91.0
# [14.91.0](https://github.com/frappe/erpnext/compare/v14.90.1...v14.91.0) (2025-09-16)

### Bug Fixes

* duplicate items being created when fetching items from warehouse in stock reco ([646de0b](646de0bec1))
* remove ignore_permissions ([180f406](180f406917))

### Features

* add permission check for custom button ([42b38b7](42b38b7998))
2025-09-16 14:41:37 +00:00
ruthra kumar
a9b7bc1385 Merge pull request #49565 from frappe/version-14-hotfix
chore: release v14
2025-09-16 20:08:58 +05:30
Mihir Kandoi
d062e50f35 Merge pull request #49515 from frappe/mergify/bp/version-14-hotfix/pr-48456 2025-09-10 10:06:48 +05:30
Mihir Kandoi
646de0bec1 fix: duplicate items being created when fetching items from warehouse in stock reco
(cherry picked from commit 73f6c29559)
2025-09-10 03:01:06 +00:00
Raffael Meyer
02de47c673 Merge pull request #49434 from frappe/mergify/bp/version-14-hotfix/pr-49374
fix: improve permission handling for party link creation (backport #49374)
2025-09-03 17:12:27 +02:00
Marc-Constantin Enke
42b38b7998 feat: add permission check for custom button
(cherry picked from commit 00fd1d2f26)
2025-09-02 17:20:31 +00:00
Marc-Constantin Enke
180f406917 fix: remove ignore_permissions
(cherry picked from commit 7f55f421ab)
2025-09-02 17:20:31 +00:00
Frappe PR Bot
90803b852e chore(release): Bumped to Version 14.90.1
## [14.90.1](https://github.com/frappe/erpnext/compare/v14.90.0...v14.90.1) (2025-09-02)

### Bug Fixes

* add is_cancelled in condition ([b9f9be3](b9f9be3d88))
* ignore cancelled gl and add company filter ([6b29c06](6b29c06511))
* set missing due date in Purchase Invoice and POS Invoice ([#49232](https://github.com/frappe/erpnext/issues/49232)) ([2b6b0b3](2b6b0b32a7))
2025-09-02 13:48:57 +00:00
ruthra kumar
4cbde47ac4 Merge pull request #49424 from frappe/version-14-hotfix
chore: release v14
2025-09-02 19:17:38 +05:30
ruthra kumar
0b3215cd42 Merge pull request #49416 from frappe/mergify/bp/version-14-hotfix/pr-49379
fix: add is_cancelled in condition (backport #49379)
2025-09-02 11:16:44 +05:30
l0gesh29
b9f9be3d88 fix: add is_cancelled in condition
(cherry picked from commit 77a9cf6398)
2025-09-02 05:27:23 +00:00
ruthra kumar
faeedb01a8 Merge pull request #49411 from frappe/mergify/bp/version-14-hotfix/pr-49366
fix(trial-balance-simple): ignore cancelled gl and add company filter (backport #49366)
2025-09-02 10:42:36 +05:30
Raffael Meyer
a2402ddf52 Merge pull request #49233 from frappe/mergify/bp/version-14-hotfix/pr-49232
fix: set missing due date in Purchase Invoice and POS Invoice (backport #49232)
2025-09-02 00:49:37 +02:00
l0gesh29
6b29c06511 fix: ignore cancelled gl and add company filter
(cherry picked from commit afb067ce50)
2025-09-01 11:16:22 +00:00
Frappe PR Bot
2cedd455d9 chore(release): Bumped to Version 14.90.0
# [14.90.0](https://github.com/frappe/erpnext/compare/v14.89.2...v14.90.0) (2025-08-26)

### Bug Fixes

* **dunning:** include accounting dimension upon gl creation ([4fccef0](4fccef0636))
* **payment_entry:** clear party_type when switching to Internal Transfer to avoid 'Supplier None not found' ([e27dd64](e27dd64044))
* **Supplier:** add make_method for Pricing Rule (backport [#49282](https://github.com/frappe/erpnext/issues/49282)) ([#49283](https://github.com/frappe/erpnext/issues/49283)) ([7986e69](7986e69839))

### Features

* add make methods for Bank Account (backport [#49000](https://github.com/frappe/erpnext/issues/49000)) ([#49274](https://github.com/frappe/erpnext/issues/49274)) ([836545b](836545bdb4))
2025-08-26 11:35:26 +00:00
ruthra kumar
ba31f685f8 Merge pull request #49327 from frappe/version-14-hotfix
chore: release v14
2025-08-26 17:01:27 +05:30
ruthra kumar
507d27d509 Merge pull request #49309 from niyati34/fix/payment-entry-clear-party-type-v14hotfix
Fix/payment entry clear party type v14hotfix
2025-08-26 13:27:38 +05:30
niyati34
e27dd64044 fix(payment_entry): clear party_type when switching to Internal Transfer to avoid 'Supplier None not found' 2025-08-25 19:49:05 +05:30
ruthra kumar
7f617a54d1 Merge pull request #49278 from aerele/dunning-accouting-dimension
fix(dunning): include accounting dimension upon gl creation
2025-08-25 16:56:35 +05:30
mergify[bot]
7986e69839 fix(Supplier): add make_method for Pricing Rule (backport #49282) (#49283)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix(Supplier): add make_method for Pricing Rule (#49282)
2025-08-22 19:26:10 +02:00
mergify[bot]
836545bdb4 feat: add make methods for Bank Account (backport #49000) (#49274)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2025-08-22 19:17:44 +02:00
ravibharathi656
4fccef0636 fix(dunning): include accounting dimension upon gl creation 2025-08-22 12:34:39 +05:30
Raffael Meyer
2b6b0b32a7 fix: set missing due date in Purchase Invoice and POS Invoice (#49232)
(cherry picked from commit 77478303fe)
2025-08-19 12:30:46 +00:00
Frappe PR Bot
dac192a210 chore(release): Bumped to Version 14.89.2
## [14.89.2](https://github.com/frappe/erpnext/compare/v14.89.1...v14.89.2) (2025-08-19)

### Bug Fixes

* formatted string for disabled filter in get_income_account ([1c24bed](1c24bedaf6))
* handle empty loyalty point details ([0d6be69](0d6be69ce5))
* include missing cint import ([ea454ef](ea454ef770))
* sanitize column name for inventory_dimensions in get_stock_balance ([c3ebc39](c3ebc39f3b))
* use query builder instead of raw SQL in get_blanket_orders ([9d06e09](9d06e093a6))
* use query builder instead of raw SQL in get_loyalty_details ([64e6d65](64e6d65c00))
* use query builder instead of raw SQL in get_material_requests_based_on_supplier ([5a0e690](5a0e690307))
* use query builder instead of raw SQL in get_rfq_containing_supplier ([4b643fe](4b643feb92))
* use query builder instead of raw SQL in get_timesheet_detail_rate ([22d7bbb](22d7bbb081))
* use query builder instead of raw SQL in unset_existing_data ([06f04ca](06f04cad3e))
2025-08-19 11:53:42 +00:00
ruthra kumar
8421e09a95 Merge pull request #49226 from frappe/version-14-hotfix
chore: release v14
2025-08-19 17:22:16 +05:30
Diptanil Saha
43a723546d Merge pull request #49220 from frappe/mergify/bp/version-14-hotfix/pr-49192
fix: improve queries with query builder and input sanitization (backport #49192)
2025-08-19 11:51:32 +05:30
diptanilsaha
ea454ef770 fix: include missing cint import 2025-08-19 11:27:55 +05:30
diptanilsaha
0d6be69ce5 fix: handle empty loyalty point details
(cherry picked from commit 1231ca17c9)
2025-08-19 05:25:23 +00:00
diptanilsaha
22d7bbb081 fix: use query builder instead of raw SQL in get_timesheet_detail_rate
(cherry picked from commit e563ed0c75)
2025-08-19 05:25:23 +00:00
diptanilsaha
4b643feb92 fix: use query builder instead of raw SQL in get_rfq_containing_supplier
(cherry picked from commit 7f2a52ff71)
2025-08-19 05:25:22 +00:00
diptanilsaha
06f04cad3e fix: use query builder instead of raw SQL in unset_existing_data
(cherry picked from commit 7fa4ed6139)
2025-08-19 05:25:22 +00:00
diptanilsaha
c3ebc39f3b fix: sanitize column name for inventory_dimensions in get_stock_balance
(cherry picked from commit eb22794f14)
2025-08-19 05:25:22 +00:00
diptanilsaha
9d06e093a6 fix: use query builder instead of raw SQL in get_blanket_orders
(cherry picked from commit 1db135262d)
2025-08-19 05:25:22 +00:00
diptanilsaha
1c24bedaf6 fix: formatted string for disabled filter in get_income_account
(cherry picked from commit 6320f7290f)
2025-08-19 05:25:21 +00:00
diptanilsaha
5a0e690307 fix: use query builder instead of raw SQL in get_material_requests_based_on_supplier
(cherry picked from commit de919568b4)
2025-08-19 05:25:21 +00:00
diptanilsaha
64e6d65c00 fix: use query builder instead of raw SQL in get_loyalty_details
(cherry picked from commit 8696ba2f5d)
2025-08-19 05:25:21 +00:00
Frappe PR Bot
e7915b31ce chore(release): Bumped to Version 14.89.1
## [14.89.1](https://github.com/frappe/erpnext/compare/v14.89.0...v14.89.1) (2025-08-12)

### Bug Fixes

* add condition to fetch active accounts ([8fc8aa2](8fc8aa2dfd))
* nonetype error on applying presentation_currency filter on financial statements and trial balance report ([89d00ee](89d00ee4a2))
* **purchase invoice:** filter only enabled account ([e0d9a47](e0d9a47ff7))
* **tax withholding details:** avoid voucher duplication ([92ee871](92ee871b79))
* timeout while submitting purchase receipt ([06c3839](06c3839abc))
2025-08-12 12:02:50 +00:00
ruthra kumar
b4200c5453 Merge pull request #49117 from frappe/version-14-hotfix
chore: release v14
2025-08-12 17:31:29 +05:30
ruthra kumar
2f4bfa77b2 Merge pull request #48998 from frappe/mergify/bp/version-14-hotfix/pr-48761
fix: prevent gain or loss entry cancellation upon reposting (backport #48761)
2025-08-12 16:44:09 +05:30
Vignesh S
5eeaaf4757 chore: fix text case failure casued by mergify 2025-08-12 16:25:59 +05:30
ruthra kumar
8faabb8110 Merge pull request #49115 from frappe/mergify/bp/version-14-hotfix/pr-48909
fix(tax withholding details): avoid voucher duplication (backport #48909)
2025-08-12 16:07:00 +05:30
ravibharathi656
92ee871b79 fix(tax withholding details): avoid voucher duplication
(cherry picked from commit 8837016243)
2025-08-12 09:31:36 +00:00
MochaMind
67dad765dc chore: release v14 (#49057)
* fix: timeout while submitting purchase receipt

(cherry picked from commit c433943c46)

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

* chore: fix conflicts

* fix: nonetype error on applying presentation_currency filter on financial statements and trial balance report

(cherry picked from commit d7e22de44c)

* fix(purchase invoice): filter only enabled account

(cherry picked from commit c3111db6e2)

* fix: add condition to fetch active accounts

(cherry picked from commit 7c8dd86a35)

* chore: add back filter

(cherry picked from commit 23308f6d10)

---------

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
Co-authored-by: diptanilsaha <diptanil@frappe.io>
Co-authored-by: mithili <mithili15602@gamil.com>
Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-08-11 11:50:29 +05:30
Mihir Kandoi
25ff9e0a4d Merge pull request #49048 from frappe/mergify/bp/version-14-hotfix/pr-48813
fix(purchase invoice): filter only enabled account (backport #48813)
2025-08-08 12:00:55 +05:30
mithili
a230a0d94c chore: add back filter
(cherry picked from commit 23308f6d10)
2025-08-08 05:25:01 +00:00
mithili
8fc8aa2dfd fix: add condition to fetch active accounts
(cherry picked from commit 7c8dd86a35)
2025-08-08 05:25:01 +00:00
mithili
e0d9a47ff7 fix(purchase invoice): filter only enabled account
(cherry picked from commit c3111db6e2)
2025-08-08 05:25:01 +00:00
rohitwaghchaure
9d0034f0a4 Merge pull request #49018 from frappe/mergify/bp/version-14-hotfix/pr-49010
fix: timeout while submitting purchase receipt (backport #49010)
2025-08-07 12:28:30 +05:30
Diptanil Saha
f3d780c5bc Merge pull request #49024 from frappe/mergify/bp/version-14-hotfix/pr-49023
fix: NoneType error on applying presentation_currency filter on financial statements and trial balance report (backport #49023)
2025-08-07 02:31:03 +05:30
diptanilsaha
89d00ee4a2 fix: nonetype error on applying presentation_currency filter on financial statements and trial balance report
(cherry picked from commit d7e22de44c)
2025-08-06 20:41:33 +00:00
rohitwaghchaure
22e63099ee chore: fix conflicts 2025-08-06 22:24:45 +05:30
Rohit Waghchaure
06c3839abc fix: timeout while submitting purchase receipt
(cherry picked from commit c433943c46)

# Conflicts:
#	erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
2025-08-06 14:35:43 +00:00
Frappe PR Bot
a7d13d580c chore(release): Bumped to Version 14.89.0
# [14.89.0](https://github.com/frappe/erpnext/compare/v14.88.4...v14.89.0) (2025-08-06)

### Bug Fixes

* add doctype fieldname in condition ([c263e6d](c263e6d67e))
* add flt to prevent NoneType errors ([2c98081](2c98081be6))
* closing balance being added twice to fifo queue ([7abc4c4](7abc4c4022))
* do not split round off when there is a cost center allocation ([388b5fb](388b5fb8f6))
* payment ledger voucher seperator row currencies ([0de4477](0de4477ddf))
* provide company for outstanding record. ([235f271](235f271729))
* provide missing `company` in report records that require reference to `Company:company:default_currency` ([d38fd07](d38fd0779c))
* Use correct Attachments folder in code list import ([f415bc3](f415bc3d14))

### Features

* add show_amount_in_company_currency in gl report ([eb69122](eb691226d5))
2025-08-06 02:35:47 +00:00
ruthra kumar
dd9dc29fe5 Merge pull request #48980 from frappe/version-14-hotfix
chore: release v14
2025-08-06 08:04:22 +05:30
Logesh Periyasamy
b3035ec7d4 Merge pull request #48761 from aerele/exchange-gain-or-loss-on-repost
fix: prevent gain or loss entry cancellation upon reposting
(cherry picked from commit a8d17b7590)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
2025-08-06 07:44:42 +05:30
ruthra kumar
0ecc056a3f Merge pull request #48996 from frappe/mergify/bp/version-14-hotfix/pr-48901
fix: do not split round off when there is a cost center allocation (backport #48901)
2025-08-05 20:55:34 +05:30
ravibharathi656
7a9150aac0 test: add test for cost center allocation commercial rounding
(cherry picked from commit dd24cce509)

# Conflicts:
#	erpnext/accounts/doctype/cost_center_allocation/test_cost_center_allocation.py
2025-08-05 20:35:21 +05:30
venkat102
388b5fb8f6 fix: do not split round off when there is a cost center allocation
(cherry picked from commit f0df41d521)
2025-08-05 20:35:18 +05:30
ruthra kumar
96a1a4a8b8 Merge pull request #48984 from frappe/mergify/bp/version-14-hotfix/pr-48798
feat: add show_amount_in_company_currency in gl report (backport #48798)
2025-08-05 17:44:27 +05:30
l0gesh29
eb691226d5 feat: add show_amount_in_company_currency in gl report
(cherry picked from commit 468e5e9b2e)

# Conflicts:
#	erpnext/accounts/report/general_ledger/general_ledger.js
2025-08-05 17:11:33 +05:30
Mihir Kandoi
00e61a531a Merge pull request #48986 from mihir-kandoi/st45290
fix: closing balance being added twice to fifo queue in stock ageing report
2025-08-05 15:48:38 +05:30
Mihir Kandoi
7abc4c4022 fix: closing balance being added twice to fifo queue 2025-08-05 15:25:25 +05:30
Mihir Kandoi
1ae3fd3e27 Merge pull request #48966 from frappe/mergify/bp/version-14-hotfix/pr-48693
fix: Use correct Attachments folder in code list import (backport #48693)
2025-08-05 14:29:16 +05:30
ruthra kumar
ade44fbdb4 Merge pull request #48970 from frappe/mergify/bp/version-14-hotfix/pr-48861
chore: correct description for `consider_party_ledger_amount` in Tax Withholding Category (backport #48861)
2025-08-05 14:26:25 +05:30
ljain112
82e8fb8a5e chore: correct description for consider_party_ledger_amount in Tax Withholding Category
(cherry picked from commit f619bca2d6)

# Conflicts:
#	erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
2025-08-05 14:24:38 +05:30
Corentin Forler
f415bc3d14 fix: Use correct Attachments folder in code list import
(cherry picked from commit bc2cb1737a)
2025-08-05 08:34:37 +00:00
ruthra kumar
5bc3273460 Merge pull request #48963 from frappe/mergify/bp/version-14-hotfix/pr-48860
fix: add doctype fieldname in condition (backport #48860)
2025-08-05 13:09:37 +05:30
l0gesh29
c263e6d67e fix: add doctype fieldname in condition
(cherry picked from commit e2d63e4c32)

# Conflicts:
#	erpnext/accounts/utils.py
2025-08-05 12:16:33 +05:30
ruthra kumar
11b5a81170 Merge pull request #48927 from pps190/backport/version-14-hotfix/48926
fix: provide missing company in report records that require reference to Company:company:default_currency (Backport #48926)
2025-08-04 10:29:49 +05:30
Mihir Kandoi
27485b9472 Merge pull request #48329 from pps190/backport/version-14-hotfix/34909
Get incoming rate v14 fix (Backport #34909)
2025-08-02 22:09:30 +05:30
Devin Slauenwhite
0de4477ddf fix: payment ledger voucher seperator row currencies 2025-08-02 12:29:52 -04:00
Devin Slauenwhite
235f271729 fix: provide company for outstanding record. 2025-08-02 12:23:32 -04:00
Devin Slauenwhite
d38fd0779c fix: provide missing company in report records that require reference to Company:company:default_currency 2025-08-02 12:03:40 -04:00
Mihir Kandoi
093c6bb17e Merge pull request #48907 from frappe/st45332
fix: add flt to prevent NoneType errors
2025-08-01 17:07:50 +05:30
Mihir Kandoi
2c98081be6 fix: add flt to prevent NoneType errors 2025-08-01 16:39:56 +05:30
Frappe PR Bot
e5c821a822 chore(release): Bumped to Version 14.88.4
## [14.88.4](https://github.com/frappe/erpnext/compare/v14.88.3...v14.88.4) (2025-07-29)

### Bug Fixes

* import get_link_to_form from utils ([b43fbf2](b43fbf2a7d))
* include empty values in user permission ([4d12ae0](4d12ae069e))
* incorrect GL entries ([493c8ce](493c8ce04e))
* post gl entry on completion date of asset repair ([80ae982](80ae9820f0))
* resolved conflicts ([6cdc781](6cdc7811b8))
* resolved conflicts ([4524c74](4524c74968))
2025-07-29 15:11:30 +00:00
ruthra kumar
500ffbab09 Merge pull request #48831 from frappe/version-14-hotfix
chore: release v14
2025-07-29 20:40:08 +05:30
ruthra kumar
451326fdeb Merge pull request #48846 from frappe/mergify/bp/version-14-hotfix/pr-48835
fix: include empty values in user permission (backport #48835)
2025-07-29 20:17:18 +05:30
l0gesh29
4d12ae069e fix: include empty values in user permission
(cherry picked from commit f13d98fc7c)
2025-07-29 14:26:33 +00:00
Khushi Rawat
4297c58e5e Merge pull request #48834 from frappe/mergify/bp/version-14-hotfix/pr-48833
fix: post gl entry on completion date of asset repair (backport #48833)
2025-07-29 16:57:02 +05:30
Khushi Rawat
b43fbf2a7d fix: import get_link_to_form from utils 2025-07-29 15:48:41 +05:30
Khushi Rawat
6cdc7811b8 fix: resolved conflicts 2025-07-29 15:42:00 +05:30
Khushi Rawat
59ac7aeb23 chore: resolved conflicts 2025-07-29 15:41:20 +05:30
Khushi Rawat
4524c74968 fix: resolved conflicts 2025-07-29 15:39:10 +05:30
khushi8112
80ae9820f0 fix: post gl entry on completion date of asset repair
(cherry picked from commit 5a82b723c2)

# Conflicts:
#	erpnext/assets/doctype/asset_repair/asset_repair.json
#	erpnext/assets/doctype/asset_repair/asset_repair.py
#	erpnext/assets/doctype/asset_repair/test_asset_repair.py
2025-07-29 10:07:22 +00:00
rohitwaghchaure
5d92f38bbe Merge pull request #48807 from frappe/mergify/bp/version-14-hotfix/pr-48801
fix: incorrect GL entries (backport #48801)
2025-07-28 17:54:00 +05:30
rohitwaghchaure
a944eaf054 chore: fix conflicts 2025-07-28 16:35:39 +05:30
Rohit Waghchaure
493c8ce04e fix: incorrect GL entries
(cherry picked from commit 4c273fcc99)

# Conflicts:
#	erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
2025-07-28 10:58:37 +00:00
Frappe PR Bot
a711cd7a18 chore(release): Bumped to Version 14.88.3
## [14.88.3](https://github.com/frappe/erpnext/compare/v14.88.2...v14.88.3) (2025-07-23)

### Bug Fixes

* add validation for account key ([360f3b7](360f3b7c25))
* calculate due date based on payment term ([#46416](https://github.com/frappe/erpnext/issues/46416)) ([9e7a5bb](9e7a5bb1bb))
* performance issue while submitting the purchase invoice ([4fe09fd](4fe09fd7e8))
* **period closing voucher:** closing account head debit and debit in account currency should be equal ([76a233e](76a233e1b7))
* **production plan:** add company filter to sub assembly warehouse ([8934adf](8934adfef4))
* show amount for exchange gain or loss account ([581221f](581221f1ec))
2025-07-23 02:50:52 +00:00
ruthra kumar
942aca31f2 Merge pull request #48746 from frappe/version-14-hotfix
chore: release v14
2025-07-23 08:19:35 +05:30
ruthra kumar
77ea06dc7d Merge pull request #48740 from frappe/mergify/bp/version-14-hotfix/pr-48665
fix: show amount for exchange gain or loss account (backport #48665)
2025-07-22 12:56:31 +05:30
l0gesh29
360f3b7c25 fix: add validation for account key
(cherry picked from commit b6da350c20)
2025-07-22 06:44:03 +00:00
l0gesh29
581221f1ec fix: show amount for exchange gain or loss account
(cherry picked from commit 4f90f50eb2)
2025-07-22 06:44:03 +00:00
rohitwaghchaure
e0be83caa5 Merge pull request #48728 from frappe/mergify/bp/version-14-hotfix/pr-48704
fix(production plan): add company filter to sub assembly warehouse (backport #48704)
2025-07-21 20:04:07 +05:30
ravibharathi656
8934adfef4 fix(production plan): add company filter to sub assembly warehouse
(cherry picked from commit 1728a95111)
2025-07-21 14:27:40 +00:00
Frappe PR Bot
259251dfab chore(release): Bumped to Version 14.88.2
## [14.88.2](https://github.com/frappe/erpnext/compare/v14.88.1...v14.88.2) (2025-07-17)

### Bug Fixes

* calculate due date based on payment term ([#46416](https://github.com/frappe/erpnext/issues/46416)) ([9ce357f](9ce357f3bf))
2025-07-17 11:18:43 +00:00
rohitwaghchaure
f8c54f0a9b Merge pull request #48660 from frappe/mergify/bp/version-14/pr-48638
fix: calculate due date based on payment term (backport #46416) (backport #48638)
2025-07-17 16:47:21 +05:30
Sudharsanan Ashok
9ce357f3bf fix: calculate due date based on payment term (#46416)
(cherry picked from commit 9e808c832f)
(cherry picked from commit 9e7a5bb1bb)
2025-07-17 10:45:07 +00:00
Marica
2d6f4740be Merge pull request #48638 from frappe/mergify/bp/version-14-hotfix/pr-46416
fix: calculate due date based on payment term (backport #46416)
2025-07-16 17:18:04 +02:00
Frappe PR Bot
a3b38d9a91 chore(release): Bumped to Version 14.88.1
## [14.88.1](https://github.com/frappe/erpnext/compare/v14.88.0...v14.88.1) (2025-07-16)

### Bug Fixes

* **period closing voucher:** closing account head debit and debit in account currency should be equal ([18eea34](18eea3425c))
2025-07-16 15:09:51 +00:00
ruthra kumar
ed2e8c2cc6 Merge pull request #48640 from frappe/mergify/bp/version-14/pr-48615
fix(period closing voucher): closing account head debit and debit in account currency should be equal (backport #48615)
2025-07-16 20:38:16 +05:30
venkat102
18eea3425c fix(period closing voucher): closing account head debit and debit in account currency should be equal
(cherry picked from commit 76a233e1b7)
2025-07-16 14:46:15 +00:00
ruthra kumar
7aaea9f5b6 Merge pull request #48615 from aerele/backport-48612
fix(period closing voucher): closing account head debit and debit in account currency should be equal
2025-07-16 20:13:11 +05:30
Sudharsanan Ashok
9e7a5bb1bb fix: calculate due date based on payment term (#46416)
(cherry picked from commit 9e808c832f)
2025-07-16 14:40:15 +00:00
rohitwaghchaure
27105501fb Merge pull request #48636 from frappe/mergify/bp/version-14-hotfix/pr-48633
fix: performance issue while submitting the purchase invoice (backport #48633)
2025-07-16 17:10:28 +05:30
Rohit Waghchaure
4fe09fd7e8 fix: performance issue while submitting the purchase invoice
(cherry picked from commit 47979871de)
2025-07-16 11:16:37 +00:00
venkat102
76a233e1b7 fix(period closing voucher): closing account head debit and debit in account currency should be equal 2025-07-15 18:24:54 +05:30
Frappe PR Bot
bda447f20a chore(release): Bumped to Version 14.88.0
# [14.88.0](https://github.com/frappe/erpnext/compare/v14.87.0...v14.88.0) (2025-07-15)

### Bug Fixes

* **Employee:** add context to status in List View (backport [#48576](https://github.com/frappe/erpnext/issues/48576)) ([#48578](https://github.com/frappe/erpnext/issues/48578)) ([9dad082](9dad08274a))

### Features

* parent item group support in Stock Projected Qty report ([3b36be2](3b36be214f))
* update the modified date of the SLE after reposting ([8966c95](8966c956d5))
2025-07-15 12:50:14 +00:00
ruthra kumar
7db420cf9f Merge pull request #48601 from frappe/version-14-hotfix
chore: release v14
2025-07-15 18:18:44 +05:30
ruthra kumar
5ddfe3ce1d Merge pull request #48585 from frappe/mergify/bp/version-14-hotfix/pr-47892
refactor: use sql for building voucher balance in Receivable report (backport #47892)
2025-07-15 08:23:20 +05:30
ruthra kumar
ff998572e7 chore: resolve conflicts 2025-07-15 08:03:48 +05:30
ruthra kumar
f364a41490 chore: rename method
(cherry picked from commit fc8ca7d82c)

# Conflicts:
#	erpnext/accounts/report/accounts_receivable/accounts_receivable.py
2025-07-15 01:52:45 +00:00
ruthra kumar
804edad233 refactor: build and pass match conditions as qb criterion
(cherry picked from commit 7efeed54de)

# Conflicts:
#	erpnext/accounts/report/accounts_receivable/accounts_receivable.py
#	erpnext/accounts/utils.py
2025-07-15 01:52:45 +00:00
ruthra kumar
e533158a1c chore: drop unused utility method
(cherry picked from commit 52c0df24e3)
2025-07-15 01:52:45 +00:00
ruthra kumar
5bcf642dff refactor: dynamic DB field types
(cherry picked from commit 9d0ebe3427)

# Conflicts:
#	erpnext/accounts/report/accounts_receivable/accounts_receivable.py
2025-07-15 01:52:44 +00:00
ruthra kumar
d7822f493b refactor: better variable name
(cherry picked from commit 1a90c0d031)
2025-07-15 01:52:44 +00:00
ruthra kumar
5188745c53 refactor: prefix-ed names for easy distinction
(cherry picked from commit c5e35cc330)
2025-07-15 01:52:44 +00:00
ruthra kumar
006a8c71fd refactor: utility to drop existing procedures and include cost center
(cherry picked from commit da32bb5f51)

# Conflicts:
#	erpnext/accounts/doctype/accounts_settings/accounts_settings.js
#	erpnext/accounts/doctype/accounts_settings/accounts_settings.json
#	erpnext/accounts/doctype/accounts_settings/accounts_settings.py
2025-07-15 01:52:44 +00:00
ruthra kumar
ba25d334b1 refactor: order by posting date
(cherry picked from commit 7b7440d44a)
2025-07-15 01:52:43 +00:00
ruthra kumar
dd1020ccfb refactor: call procedures based on config
(cherry picked from commit e90c6a33bd)

# Conflicts:
#	erpnext/accounts/report/accounts_receivable/accounts_receivable.py
2025-07-15 01:52:43 +00:00
ruthra kumar
de2f80811f refactor: introduce sql option for data fetch
(cherry picked from commit 8cf8f6abad)

# Conflicts:
#	erpnext/accounts/doctype/accounts_settings/accounts_settings.py
2025-07-15 01:52:43 +00:00
ruthra kumar
12eaa64572 refactor: better readability
(cherry picked from commit 097e74979f)
2025-07-15 01:52:42 +00:00
ruthra kumar
da1dcb8b21 refactor: using sql procedures for AR report
- dynamic filters are passed

(cherry picked from commit e5920c57aa)

# Conflicts:
#	erpnext/accounts/report/accounts_receivable/accounts_receivable.py
2025-07-15 01:52:42 +00:00
mergify[bot]
9dad08274a fix(Employee): add context to status in List View (backport #48576) (#48578)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix(Employee): add context to status in List View (#48576)
2025-07-14 15:53:42 +02:00
rohitwaghchaure
d8d53bc43e Merge pull request #48496 from frappe/mergify/bp/version-14-hotfix/pr-48490
feat: update the modified date of the SLE after reposting (backport #48490)
2025-07-09 19:45:26 +05:30
Rohit Waghchaure
8966c956d5 feat: update the modified date of the SLE after reposting
(cherry picked from commit c2cd4934e7)
2025-07-09 13:52:11 +00:00
rohitwaghchaure
a518fc080a Merge pull request #48491 from frappe/mergify/bp/version-14-hotfix/pr-48488
feat: parent item group support in Stock Projected Qty report (backport #48488)
2025-07-09 18:59:55 +05:30
Rohit Waghchaure
3b36be214f feat: parent item group support in Stock Projected Qty report
(cherry picked from commit 6e80d89d13)
2025-07-09 11:19:41 +00:00
Frappe PR Bot
20af226947 chore(release): Bumped to Version 14.87.0
# [14.87.0](https://github.com/frappe/erpnext/compare/v14.86.5...v14.87.0) (2025-07-08)

### Bug Fixes

* fetch from parent optional in inventory dimension ([bb901ca](bb901cab88))
* incorrect backport ([94a17b6](94a17b6ec2))

### Features

* Period-wise closing entries for TB (backport [#39712](https://github.com/frappe/erpnext/issues/39712)) ([#48386](https://github.com/frappe/erpnext/issues/48386)) ([711e06b](711e06b537))

### Reverts

* do not convert exchange gain/loss amount to foreign currency ([083402e](083402e9a8))
* Revert "fix: stock reco qty with inventory dimension ([#47918](https://github.com/frappe/erpnext/issues/47918))" ([9207d79](9207d79ce6))
2025-07-08 12:54:12 +00:00
ruthra kumar
7f26b1d5a2 Merge pull request #48461 from frappe/version-14-hotfix
chore: release v14
2025-07-08 18:22:45 +05:30
ruthra kumar
c332fcdeff Merge pull request #48458 from frappe/mergify/bp/version-14-hotfix/pr-48361
revert: do not convert exchange gain/loss amount to foreign currency (backport #48361)
2025-07-08 15:45:19 +05:30
mergify[bot]
51adea3b89 refactor: remove do_reposting_for_each_stock_transaction feature (backport #48444) (#48451)
* refactor: remove do_reposting_for_each_stock_transaction feature

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
2025-07-08 15:06:00 +05:30
venkat102
083402e9a8 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:26:24 +05:30
rohitwaghchaure
1116a0fc8e Merge pull request #48442 from frappe/mergify/bp/version-14-hotfix/pr-48441
Revert "fix: stock reco qty with inventory dimension" (backport #48441)
2025-07-08 12:30:58 +05:30
rohitwaghchaure
b15d7e573e chore: fix conflicts 2025-07-08 10:45:49 +05:30
rohitwaghchaure
9207d79ce6 Revert "fix: stock reco qty with inventory dimension (#47918)"
This reverts commit 342cebc778.

(cherry picked from commit 8ba66c9833)

# Conflicts:
#	erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
2025-07-08 05:07:53 +00:00
rohitwaghchaure
33eb72035b Merge pull request #48433 from frappe/mergify/bp/version-14-hotfix/pr-48432
fix: fetch from parent optional in inventory dimension (backport #48432)
2025-07-08 10:13:56 +05:30
rohitwaghchaure
2c6099e051 Merge pull request #48438 from rohitwaghchaure/fixed-sales-incoming-rate-issue
fix: incorrect backport
2025-07-08 09:55:06 +05:30
rohitwaghchaure
5f4aaed5a0 chore: fix conflicts 2025-07-08 08:34:16 +05:30
Rohit Waghchaure
94a17b6ec2 fix: incorrect backport 2025-07-08 08:32:12 +05:30
Rohit Waghchaure
bb901cab88 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
Diptanil Saha
711e06b537 feat: Period-wise closing entries for TB (backport #39712) (#48386)
feat: Period-wise closing entries for TB

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2025-07-03 22:47:28 +05:30
Diptanil Saha
c54b65acc2 chore: fix flaky test in Tax Withholding Details (backport #48375) (#48387)
* fix(test): flaky budget test case

* chore(test): import get_accumulated_monthly_budget

* fix(test): tds_payable_monthly tests

---------

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
2025-07-03 22:09:19 +05:30
Frappe PR Bot
179b8c7c61 chore(release): Bumped to Version 14.86.5
## [14.86.5](https://github.com/frappe/erpnext/compare/v14.86.4...v14.86.5) (2025-07-01)

### Bug Fixes

* accounting entries for standalone credit notes ([15ae019](15ae0196c6))
* add validation for exchange gain/loss entries ([b98cce8](b98cce8b9a))
* do not allow backdated transactions against serial numbers. ([#48281](https://github.com/frappe/erpnext/issues/48281)) ([945bdab](945bdabebb))
2025-07-01 11:59:12 +00:00
ruthra kumar
b107387dda Merge pull request #48337 from frappe/version-14-hotfix
chore: release v14
2025-07-01 17:27:40 +05:30
ruthra kumar
9fcca18bf3 Merge pull request #48334 from frappe/mergify/bp/version-14-hotfix/pr-48162
fix: add validation for exchange gain/loss entries (backport #48162)
2025-07-01 16:20:45 +05:30
i-am-vimal
b98cce8b9a fix: add validation for exchange gain/loss entries
(cherry picked from commit 5c9eddd31e)

# Conflicts:
#	erpnext/accounts/report/utils.py
2025-07-01 15:36:51 +05:30
Hossein Yousefian
bd9655a781 get_incoming_rate_voucher_no_fix 2025-06-30 17:11:04 -04:00
Hossein Yousefian
1df3b608ec get_incoming_rate_zero_in_rate_fix 2025-06-30 17:11:04 -04:00
rohitwaghchaure
62b7a8d21a Merge pull request #48313 from frappe/mergify/bp/version-14-hotfix/pr-48310
fix: accounting entries for standalone credit notes (backport #48310)
2025-06-30 10:09:23 +05:30
rohitwaghchaure
6b31e54891 chore: fix conflicts 2025-06-30 09:42:13 +05:30
Rohit Waghchaure
15ae0196c6 fix: accounting entries for standalone credit notes
(cherry picked from commit 52177cffcd)

# Conflicts:
#	erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
2025-06-30 04:09:39 +00:00
Frappe PR Bot
a06d705d75 chore(release): Bumped to Version 14.86.4
## [14.86.4](https://github.com/frappe/erpnext/compare/v14.86.3...v14.86.4) (2025-06-27)

### Bug Fixes

* do not allow backdated transactions against serial numbers. ([#48281](https://github.com/frappe/erpnext/issues/48281)) ([1393100](1393100a62))
2025-06-27 06:27:09 +00:00
rohitwaghchaure
9e3e3182f2 Merge pull request #48290 from frappe/mergify/bp/version-14/pr-48281
fix: do not allow backdated transactions against serial numbers. (backport #48281)
2025-06-27 11:55:38 +05:30
rohitwaghchaure
1393100a62 fix: do not allow backdated transactions against serial numbers. (#48281)
(cherry picked from commit 945bdabebb)
2025-06-27 06:03:52 +00:00
rohitwaghchaure
945bdabebb fix: do not allow backdated transactions against serial numbers. (#48281) 2025-06-27 11:33:03 +05:30
Frappe PR Bot
f07594b863 chore(release): Bumped to Version 14.86.3
## [14.86.3](https://github.com/frappe/erpnext/compare/v14.86.2...v14.86.3) (2025-06-24)

### Bug Fixes

* get already billed amount from current doc instead of database ([#48079](https://github.com/frappe/erpnext/issues/48079)) ([0790db7](0790db79fd))
2025-06-24 14:08:14 +00:00
ruthra kumar
25a382ec24 Merge pull request #48241 from frappe/version-14-hotfix
chore: release v14
2025-06-24 19:36:37 +05:30
ruthra kumar
d7c47e8ea5 Merge pull request #48234 from frappe/mergify/bp/version-14-hotfix/pr-48079
fix: get already billed amount from current doc instead of database (backport #48079)
2025-06-24 17:36:05 +05:30
ljain112
2627fb10ce chore: resolve conflicts 2025-06-24 16:14:24 +05:30
Lakshit Jain
0790db79fd 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)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
2025-06-24 10:11:43 +00:00
Frappe PR Bot
0dad2acfc8 chore(release): Bumped to Version 14.86.2
## [14.86.2](https://github.com/frappe/erpnext/compare/v14.86.1...v14.86.2) (2025-06-17)

### Bug Fixes

* incorrect warehouse set from SO to MR ([fbfc6a6](fbfc6a6f62))
2025-06-17 14:36:59 +00:00
ruthra kumar
193042ef07 Merge pull request #48099 from frappe/version-14-hotfix
chore: release v14
2025-06-17 20:05:31 +05:30
rohitwaghchaure
8208a9ec27 Merge pull request #48064 from frappe/mergify/bp/version-14-hotfix/pr-48061
fix: incorrect warehouse set from SO to MR (backport #48061)
2025-06-16 14:52:54 +05:30
Rohit Waghchaure
fbfc6a6f62 fix: incorrect warehouse set from SO to MR
(cherry picked from commit 0da8d9c869)
2025-06-16 04:42:26 +00:00
Frappe PR Bot
e9f9eaa2d0 chore(release): Bumped to Version 14.86.1
## [14.86.1](https://github.com/frappe/erpnext/compare/v14.86.0...v14.86.1) (2025-06-10)

### Bug Fixes

* available qty in BOM Stock Report ([186173a](186173a21e))
* incorrect warehouse in MR ([2cac05e](2cac05e56c))
* key-error for COGS By Item Group report (backport [#47914](https://github.com/frappe/erpnext/issues/47914)) ([#47916](https://github.com/frappe/erpnext/issues/47916)) ([f5ef376](f5ef376486))
* stock adjustment entry during reposting (backport [#47878](https://github.com/frappe/erpnext/issues/47878)) ([#47882](https://github.com/frappe/erpnext/issues/47882)) ([c9eeca2](c9eeca22f5))
* stock reco qty with inventory dimension (backport [#47918](https://github.com/frappe/erpnext/issues/47918)) ([#47921](https://github.com/frappe/erpnext/issues/47921)) ([6397c36](6397c366fd))
* throw permission error ([#47976](https://github.com/frappe/erpnext/issues/47976)) ([96c937b](96c937bf6a))
2025-06-10 14:31:53 +00:00
ruthra kumar
08d40ddb9b Merge pull request #47997 from frappe/version-14-hotfix
chore: release v14
2025-06-10 20:00:21 +05:30
rohitwaghchaure
d60ab92082 Merge pull request #48003 from frappe/mergify/bp/version-14-hotfix/pr-47998
fix: incorrect warehouse in MR (backport #47998)
2025-06-10 18:54:18 +05:30
rohitwaghchaure
85a0581145 chore: fix conflicts 2025-06-10 18:20:28 +05:30
Rohit Waghchaure
2cac05e56c fix: incorrect warehouse in MR
(cherry picked from commit 2b9ca79291)

# Conflicts:
#	erpnext/manufacturing/doctype/production_plan/production_plan.py
2025-06-10 12:41:16 +00:00
ruthra kumar
10e4e610db Merge pull request #47993 from frappe/mergify/bp/version-14-hotfix/pr-47981
refactor(Work Order): query_sales_order (backport #47981)
2025-06-10 15:01:22 +05:30
barredterra
9ab80cfd6c 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:13 +00:00
rohitwaghchaure
8f2b83d434 Merge pull request #47986 from frappe/mergify/bp/version-14-hotfix/pr-47942
fix: available qty in BOM Stock Report (backport #47942)
2025-06-10 14:03:06 +05:30
Sagar Vora
7f0ebb37da Merge pull request #47977 from frappe/mergify/bp/version-14-hotfix/pr-47976
fix: throw permission error (backport #47976)
2025-06-10 07:39:53 +00:00
Sagar Vora
1d42c4a305 chore: fix conflicts 2025-06-10 13:08:39 +05:30
Rohit Waghchaure
186173a21e fix: available qty in BOM Stock Report
(cherry picked from commit ea689bbe3f)
2025-06-10 06:50:51 +00:00
Aayush Dalal
96c937bf6a fix: throw permission error (#47976)
Co-authored-by: Sagar Vora <16315650+sagarvora@users.noreply.github.com>
(cherry picked from commit 8b6a8d0c4f)

# Conflicts:
#	erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
#	erpnext/stock/utils.py
2025-06-09 17:29:42 +00:00
rohitwaghchaure
52aafc9410 Merge pull request #47932 from rohitwaghchaure/fixed-sabb-cond
chore: incorrect condition
2025-06-06 13:13:54 +05:30
Rohit Waghchaure
3232310c0f chore: incorrect condition 2025-06-06 12:30:03 +05:30
mergify[bot]
6397c366fd fix: stock reco qty with inventory dimension (backport #47918) (#47921)
fix: stock reco qty with inventory dimension (#47918)

(cherry picked from commit 342cebc778)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-06-06 09:50:20 +05:30
mergify[bot]
f5ef376486 fix: key-error for COGS By Item Group report (backport #47914) (#47916)
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:22 +05:30
mergify[bot]
c9eeca22f5 fix: stock adjustment entry during reposting (backport #47878) (#47882)
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:22 +05:30
Frappe PR Bot
b145638eca chore(release): Bumped to Version 14.86.0
# [14.86.0](https://github.com/frappe/erpnext/compare/v14.85.10...v14.86.0) (2025-06-03)

### Bug Fixes

* filter of item for manufacture type material request (backport [#47712](https://github.com/frappe/erpnext/issues/47712)) ([#47716](https://github.com/frappe/erpnext/issues/47716)) ([69463b4](69463b4798))
* incorrect actual qty in product bundle balance report (backport [#47791](https://github.com/frappe/erpnext/issues/47791)) ([#47813](https://github.com/frappe/erpnext/issues/47813)) ([df779bb](df779bb7dd))
* use `query.walk() `for escaping special chars in receiable/payable report ([ca48583](ca4858318e))

### Features

* add column "Item Name" to "BOM Stock Report" (backport [#47116](https://github.com/frappe/erpnext/issues/47116)) ([#47484](https://github.com/frappe/erpnext/issues/47484)) ([b664781](b664781fae))
2025-06-03 11:52:06 +00:00
ruthra kumar
b46fdc2645 Merge pull request #47867 from frappe/version-14-hotfix
chore: release v14
2025-06-03 17:20:36 +05:30
mergify[bot]
df779bb7dd fix: incorrect actual qty in product bundle balance report (backport #47791) (#47813)
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:49 +05:30
ruthra kumar
20f701ff0b Merge pull request #47807 from frappe/mergify/bp/version-14-hotfix/pr-47794
fix: use `query.walk() `for escaping special chars in receiable/payable report (backport #47794)
2025-05-29 14:58:45 +05:30
ljain112
ca4858318e fix: use query.walk() for escaping special chars in receiable/payable report
(cherry picked from commit a0a51b5074)
2025-05-29 08:21:15 +00:00
mergify[bot]
b664781fae feat: add column "Item Name" to "BOM Stock Report" (backport #47116) (#47484)
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:20 +02:00
mergify[bot]
69463b4798 fix: filter of item for manufacture type material request (backport #47712) (#47716)
* fix: filter of item for manufacture type material request (#47712)

(cherry picked from commit 874750f9ce)

# Conflicts:
#	erpnext/stock/doctype/material_request/material_request.js

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-27 21:56:36 +05:30
Frappe PR Bot
caf0f2cd19 chore(release): Bumped to Version 14.85.10
## [14.85.10](https://github.com/frappe/erpnext/compare/v14.85.9...v14.85.10) (2025-05-27)

### Bug Fixes

* incorrect status in the serial no ([#47740](https://github.com/frappe/erpnext/issues/47740)) ([d37b12f](d37b12f385))
* incorrect valuation rate due to positive qty (backport [#47686](https://github.com/frappe/erpnext/issues/47686)) ([#47687](https://github.com/frappe/erpnext/issues/47687)) ([d5d4b3a](d5d4b3a7f3))
* only include advances within the tcs period ([43aeff3](43aeff38aa))
* patch to rename group_by filter in custom reports (backport [#47709](https://github.com/frappe/erpnext/issues/47709)) ([#47729](https://github.com/frappe/erpnext/issues/47729)) ([70bcfb4](70bcfb4748))
* rate changing while making PR (negative discount) (backport [#40539](https://github.com/frappe/erpnext/issues/40539)) ([#47735](https://github.com/frappe/erpnext/issues/47735)) ([70e6ea6](70e6ea6b3f))
* remove public access to list items (backport [#45838](https://github.com/frappe/erpnext/issues/45838)) ([5d9be73](5d9be7366b))
* skip last purchase rate for free item (backport [#47693](https://github.com/frappe/erpnext/issues/47693)) ([#47695](https://github.com/frappe/erpnext/issues/47695)) ([1f1cb33](1f1cb338fe))
* validation message format (backport [#47542](https://github.com/frappe/erpnext/issues/47542)) ([#47549](https://github.com/frappe/erpnext/issues/47549)) ([792f3af](792f3afa1b))
2025-05-27 11:46:57 +00:00
ruthra kumar
1cfb002de8 Merge pull request #47757 from frappe/version-14-hotfix
chore: release v14
2025-05-27 17:15:22 +05:30
ruthra kumar
3b686827e9 Merge pull request #47752 from frappe/mergify/bp/version-14-hotfix/pr-47736
fix: only include advances within the tcs period (backport #47736)
2025-05-27 14:10:45 +05:30
rohitwaghchaure
d37b12f385 fix: incorrect status in the serial no (#47740) 2025-05-27 13:23:40 +05:30
ljain112
43aeff38aa fix: only include advances within the tcs period
(cherry picked from commit 477ec9fdcc)
2025-05-27 07:49:16 +00:00
ruthra kumar
ad13dcd695 Merge pull request #47745 from frappe/mergify/bp/version-14-hotfix/pr-47549
fix: validation message format (backport #47542) (backport #47549)
2025-05-27 12:03:44 +05:30
mergify[bot]
792f3afa1b fix: validation message format (backport #47542) (#47549)
fix: validation message format (#47542)

(cherry picked from commit a18e1cffa7)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
(cherry picked from commit f225e1986e)
2025-05-27 06:04:55 +00:00
ruthra kumar
43dda4a5d2 Merge pull request #47741 from frappe/mergify/bp/version-14-hotfix/pr-47697
refactor: Fetch party name for contract (backport #47697)
2025-05-26 19:56:16 +05:30
ruthra kumar
274ce10329 chore: resolve conflicts 2025-05-26 17:46:42 +05:30
ruthra kumar
caf145e3ca refactor: patch old contract with full party name
(cherry picked from commit 8e2221178b)

# Conflicts:
#	erpnext/patches.txt
2025-05-26 12:11:25 +00:00
ruthra kumar
05911ad563 refactor: fetch party name on selection
(cherry picked from commit 752024e222)
2025-05-26 12:11:24 +00:00
ruthra kumar
de937a6bad refactor: full name field in contract
(cherry picked from commit 016924361a)

# Conflicts:
#	erpnext/crm/doctype/contract/contract.json
#	erpnext/crm/doctype/contract/contract.py
2025-05-26 12:11:24 +00:00
mergify[bot]
70e6ea6b3f fix: rate changing while making PR (negative discount) (backport #40539) (#47735)
fix: rate changing while making PR (negative discount) (#40539)

(cherry picked from commit 8136954484)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-26 16:02:06 +05:30
mergify[bot]
70bcfb4748 fix: patch to rename group_by filter in custom reports (backport #47709) (#47729)
* fix: patch to rename group_by filter in custom reports

(cherry picked from commit 0d19c18c06)

# Conflicts:
#	erpnext/patches.txt
#	erpnext/patches/v14_0/rename_group_by_to_categorize_by_in_custom_reports.py

* 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:28 +05:30
mergify[bot]
1f1cb338fe fix: skip last purchase rate for free item (backport #47693) (#47695)
fix: skip last purchase rate for free item (#47693)

(cherry picked from commit c3b17024bd)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-24 17:17:09 +05:30
mergify[bot]
d5d4b3a7f3 fix: incorrect valuation rate due to positive qty (backport #47686) (#47687)
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:42 +05:30
mergify[bot]
5d9be7366b fix: remove public access to list items (backport #45838)
* fix: remove public access to list items

(cherry picked from commit 2bd596ee3d)

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

* fix: resolve conflict

---------

Co-authored-by: CaseSolved <richard@casesolved.co.uk>
Co-authored-by: Sagar Vora <16315650+sagarvora@users.noreply.github.com>
2025-05-21 23:12:40 +05:30
Frappe PR Bot
79a4b597d4 chore(release): Bumped to Version 14.85.9
## [14.85.9](https://github.com/frappe/erpnext/compare/v14.85.8...v14.85.9) (2025-05-20)

### Bug Fixes

* asset image field updation issue (backport [#47615](https://github.com/frappe/erpnext/issues/47615)) ([d88feec](d88feecf46))
* better validation message with solution for BOM recursion (backport [#47472](https://github.com/frappe/erpnext/issues/47472)) ([#47476](https://github.com/frappe/erpnext/issues/47476)) ([537c917](537c917bfc))
* include only invoices with update_stock = 0  for billed amt in delivery note. ([54197ff](54197ff760))
* remove hardcoded doctype in `make_return_doc` ([9ce86b1](9ce86b135b))
2025-05-20 13:53:32 +00:00
ruthra kumar
0b0944cc06 Merge pull request #47635 from frappe/version-14-hotfix
chore: release v14
2025-05-20 19:22:04 +05:30
mergify[bot]
537c917bfc fix: better validation message with solution for BOM recursion (backport #47472) (#47476)
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:40 +05:30
ruthra kumar
13f393c59a Merge pull request #47624 from frappe/mergify/bp/version-14-hotfix/pr-47559
fix: include only invoices with update_stock = 0  for billed amt in delivery note. (backport #47559)
2025-05-20 11:24:52 +05:30
ljain112
54197ff760 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
ruthra kumar
6f1109226d Merge pull request #47621 from frappe/mergify/bp/version-14-hotfix/pr-47614
fix: remove hardcoded doctype in `make_return_doc` (backport #47614)
2025-05-20 10:37:00 +05:30
barredterra
9ce86b135b fix: remove hardcoded doctype in make_return_doc
(cherry picked from commit 45a5c19dd4)

# Conflicts:
#	erpnext/controllers/sales_and_purchase_return.py
2025-05-20 10:11:21 +05:30
mergify[bot]
d88feecf46 fix: asset image field updation issue (backport #47615) 2025-05-20 10:08:26 +05:30
Frappe PR Bot
271d0a301f chore(release): Bumped to Version 14.85.8
## [14.85.8](https://github.com/frappe/erpnext/compare/v14.85.7...v14.85.8) (2025-05-13)

### Bug Fixes

* broken test suite due to incorrect OR filter ([949ed59](949ed59f84))
* ignore "Account Closing Balance" doctype on Period Closing Voucher cancellation ([a04feff](a04feff264))
* typo in event.js ([2389fd5](2389fd5145))
* warning message for COGS account in the stock entry ([1bbbd26](1bbbd261cb))
2025-05-13 14:02:11 +00:00
ruthra kumar
9d36166616 Merge pull request #47529 from frappe/version-14-hotfix
chore: release v14
2025-05-13 19:30:41 +05:30
ruthra kumar
00407cd0ee Merge pull request #47526 from frappe/mergify/bp/version-14-hotfix/pr-47520
fix: ignore "Account Closing Balance" doctype on Period Closing Voucher cancellation (backport #47520)
2025-05-13 15:22:32 +05:30
ljain112
a04feff264 fix: ignore "Account Closing Balance" doctype on Period Closing Voucher cancellation
(cherry picked from commit d6602d63fc)

# Conflicts:
#	erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
2025-05-13 15:00:36 +05:30
ruthra kumar
d6f5ac90b1 Merge pull request #47516 from frappe/mergify/bp/version-14-hotfix/pr-47367
fix: Use `Currency` instead of `Float` in GL report to show details (backport #47367)
2025-05-13 13:08:20 +05:30
Abdeali Chharchhodawala
c6c1b00559 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 12:49:52 +05:30
ruthra kumar
b86dc294f1 Merge pull request #47518 from frappe/mergify/bp/version-14-hotfix/pr-47380
fix: broken CI - uae vat 201 tests failing (backport #47380)
2025-05-13 12:45:41 +05:30
ruthra kumar
949ed59f84 fix: broken test suite due to incorrect OR filter
(cherry picked from commit 37d74e387d)
2025-05-13 06:39:22 +00:00
ruthra kumar
558225b027 Merge pull request #47466 from frappe/mergify/bp/version-14-hotfix/pr-47462
Update event.js (backport #47462)
2025-05-08 14:12:55 +05:30
Yaiphalemba Mangshatabam
2389fd5145 fix: typo in event.js
"Sales Partners" -> "Sales Partner"

(cherry picked from commit edee75c757)
2025-05-08 08:40:37 +00:00
rohitwaghchaure
d66a34411c Merge pull request #47453 from frappe/mergify/bp/version-14-hotfix/pr-47452
fix: warning message for COGS account in the stock entry (backport #47452)
2025-05-08 13:58:23 +05:30
Rohit Waghchaure
1bbbd261cb fix: warning message for COGS account in the stock entry
(cherry picked from commit bba6b0ff45)
2025-05-07 10:50:18 +00:00
Frappe PR Bot
182b9892fc chore(release): Bumped to Version 14.85.7
## [14.85.7](https://github.com/frappe/erpnext/compare/v14.85.6...v14.85.7) (2025-05-06)

### Bug Fixes

* backward compatibility for renamed group_by filter on reports (backport [#47362](https://github.com/frappe/erpnext/issues/47362)) ([#47402](https://github.com/frappe/erpnext/issues/47402)) ([378821d](378821d9e6))
* change shipping address fetching condition ([8e0bd97](8e0bd976c3))
* completed transactions showing in the list (backport [#47374](https://github.com/frappe/erpnext/issues/47374)) ([#47378](https://github.com/frappe/erpnext/issues/47378)) ([b507e63](b507e63375))
* do not allocate amount when ref's doctype or name are not set ([f278120](f278120aa0))
* rename unchanged group_by filter related to general ledger report (backport [#47366](https://github.com/frappe/erpnext/issues/47366)) ([#47404](https://github.com/frappe/erpnext/issues/47404)) ([d41fec7](d41fec7d2b))
* renaming group by fieldname and value in reports (backport [#47352](https://github.com/frappe/erpnext/issues/47352)) ([#47359](https://github.com/frappe/erpnext/issues/47359)) ([27a8856](27a8856dca))
* show party type in due date exceeding message ([4376fbc](4376fbc3ed))
* validation for difference account ([150cc5a](150cc5a664))
* warning message before changing the valuation method (backport [#47340](https://github.com/frappe/erpnext/issues/47340)) ([#47341](https://github.com/frappe/erpnext/issues/47341)) ([b13e0a6](b13e0a6b9f))
2025-05-06 14:13:22 +00:00
ruthra kumar
015525599f Merge pull request #47430 from frappe/version-14-hotfix
chore: release v14
2025-05-06 19:41:49 +05:30
mergify[bot]
3993525bf6 feat!: configure which rate is used to auto-update price list (backport #47417) (#47433)
* feat!: configure which rate is used to auto-update price list

(cherry picked from commit 3ebde4526a)

# Conflicts:
#	erpnext/selling/doctype/sales_order/test_sales_order.py
#	erpnext/setup/setup_wizard/operations/defaults_setup.py
#	erpnext/setup/setup_wizard/operations/install_fixtures.py
#	erpnext/stock/doctype/stock_settings/stock_settings.json
#	erpnext/stock/doctype/stock_settings/stock_settings.py
#	erpnext/stock/get_item_details.py

* fix: merge conflicts

---------

Co-authored-by: Sagar Vora <16315650+sagarvora@users.noreply.github.com>
2025-05-06 18:43:27 +05:30
ruthra kumar
8343c92ac5 Merge pull request #47425 from frappe/mergify/bp/version-14-hotfix/pr-47337
fix: do not allocate amount when ref's doctype or name are not set (backport #47337)
2025-05-06 15:01:05 +05:30
Abdeali Chharchhoda
f278120aa0 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
862e6330ac Merge pull request #47415 from frappe/mergify/bp/version-14-hotfix/pr-47408
fix: show party type in due date exceeding message (backport #47408)
2025-05-06 14:32:58 +05:30
ruthra kumar
bd395e2406 chore: resolve conflicts and pass all parameters 2025-05-06 14:12:44 +05:30
Abdeali Chharchhoda
4376fbc3ed fix: show party type in due date exceeding message
(cherry picked from commit b6d9134014)

# Conflicts:
#	erpnext/accounts/party.py
2025-05-06 06:28:47 +00:00
ruthra kumar
c49ee563fd Merge pull request #47413 from frappe/mergify/bp/version-14-hotfix/pr-47358
fix: change shipping address fetching condition (backport #47358)
2025-05-06 11:29:16 +05:30
Vimal
8e0bd976c3 fix: change shipping address fetching condition
(cherry picked from commit 0b4add2f2b)
2025-05-06 05:28:40 +00:00
rohitwaghchaure
d66e8e8597 Merge pull request #47389 from frappe/mergify/bp/version-14-hotfix/pr-47376
fix: validation for difference account (backport #47376)
2025-05-05 18:39:04 +05:30
mergify[bot]
d41fec7d2b fix: rename unchanged group_by filter related to general ledger report (backport #47366) (#47404)
* fix: rename unchanged group_by filter related to general ledger report (#47366)

(cherry picked from commit 3de249dcba)

# Conflicts:
#	erpnext/accounts/doctype/payment_entry/payment_entry.js
#	erpnext/accounts/test/test_reports.py
#	erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js

* chore: resolve conflict

* chore: resolve conflict

* chore: resolve conflict

---------

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-05-05 18:18:23 +05:30
mergify[bot]
378821d9e6 fix: backward compatibility for renamed group_by filter on reports (backport #47362) (#47402)
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:06 +05:30
ruthra kumar
698e260526 Merge pull request #47146 from frappe/mergify/copy/version-14-hotfix/pr-47145
refactor: make AR / AP report more memory efficient (copy #47145)
2025-05-05 15:43:33 +05:30
ruthra kumar
fc793f0f25 refactor: set default for fetch methods 2025-05-05 15:04:48 +05:30
ruthra kumar
204d1d6a53 refactor: use fetch method based on configuration 2025-05-05 15:04:48 +05:30
ruthra kumar
aee917b790 refactor: configurable fetch method for AR / AP report 2025-05-05 15:04:45 +05:30
ruthra kumar
892d3980d3 refactor: use unbuffered cursor for fetching 2025-05-05 14:59:24 +05:30
rohitwaghchaure
e743d5f66b chore: fix linters issue 2025-05-05 14:19:20 +05:30
rohitwaghchaure
9adb863787 chore: fix linters issue 2025-05-05 14:12:07 +05:30
Rohit Waghchaure
150cc5a664 fix: validation for difference account
(cherry picked from commit fb819c558e)
2025-05-03 07:52:53 +00:00
mergify[bot]
b507e63375 fix: completed transactions showing in the list (backport #47374) (#47378)
* fix: completed transactions showing in the list (#47374)

(cherry picked from commit 97db9da10e)

# Conflicts:
#	erpnext/stock/doctype/stock_entry/stock_entry.js

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-05-02 15:29:10 +05:30
mergify[bot]
27a8856dca fix: renaming group by fieldname and value in reports (backport #47352) (#47359)
* 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
#	erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
#	erpnext/accounts/report/general_ledger/general_ledger.py
#	erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py
#	erpnext/patches.txt
#	erpnext/patches/v14_0/rename_group_by_to_categorize_by.py

* chore: resolve conflict

* chore: resolve conflict

* chore: resolve conflict

* chore: resolve conflict

* chore: resolve conflict

* chore: resolve conflict

* chore: fixed path for patch file

---------

Co-authored-by: Diptanil Saha <diptanil@frappe.io>
2025-04-30 18:22:59 +05:30
mergify[bot]
b13e0a6b9f fix: warning message before changing the valuation method (backport #47340) (#47341)
fix: warning message before changing the valuation method (#47340)

(cherry picked from commit ffdc4347e8)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2025-04-30 12:54:15 +05:30
Frappe PR Bot
04bb4f8415 chore(release): Bumped to Version 14.85.6
## [14.85.6](https://github.com/frappe/erpnext/compare/v14.85.5...v14.85.6) (2025-04-29)

### Bug Fixes

* allow to change valuation method from FIFO to Moving Average ([7130e5c](7130e5ccfb))
* calculate useful days of asset's life correctly for existing asset ([#47066](https://github.com/frappe/erpnext/issues/47066)) ([0bc3bc4](0bc3bc4851))
* item code not showing in the error message ([48748e7](48748e7142))
* remove invalid email account creation (backport [#47318](https://github.com/frappe/erpnext/issues/47318)) ([#47322](https://github.com/frappe/erpnext/issues/47322)) ([0c5c344](0c5c34409e))
2025-04-29 13:08:31 +00:00
ruthra kumar
6735ba0ab6 Merge pull request #47327 from frappe/version-14-hotfix
chore: release v14
2025-04-29 18:36:51 +05:30
mergify[bot]
0c5c34409e fix: remove invalid email account creation (backport #47318) (#47322)
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:25 +05:30
rohitwaghchaure
9dbc1cc5fb Merge pull request #47287 from frappe/mergify/bp/version-14-hotfix/pr-47268
fix: allow to change valuation method from FIFO to Moving Average (backport #47268)
2025-04-28 15:28:53 +05:30
Rohit Waghchaure
7130e5ccfb fix: allow to change valuation method from FIFO to Moving Average
(cherry picked from commit b454ed4b8f)
2025-04-28 09:06:30 +00:00
rohitwaghchaure
0e42516977 Merge pull request #47258 from rohitwaghchaure/fixed-support-46933
fix: item code not showing in the error message
2025-04-25 14:38:38 +05:30
Rohit Waghchaure
48748e7142 fix: item code not showing in the error message 2025-04-25 14:08:38 +05:30
Khushi Rawat
0bc3bc4851 fix: calculate useful days of asset's life correctly for existing asset (#47066)
* fix: calculate useful days of asset's life correctly for existing asset

* fix: test

* fix: test case correction
2025-04-23 12:30:59 +05:30
Frappe PR Bot
d791108649 chore(release): Bumped to Version 14.85.5
## [14.85.5](https://github.com/frappe/erpnext/compare/v14.85.4...v14.85.5) (2025-04-22)

### Bug Fixes

* create default warehouse ([#47125](https://github.com/frappe/erpnext/issues/47125)) ([a766aa0](a766aa0837))
* rate based on posting date in Tax Withholding Report ([17dc87a](17dc87a2df))
* respect mapped accounting dimensions ([e4c2442](e4c2442ba2))
2025-04-22 13:45:53 +00:00
ruthra kumar
0d84059fde Merge pull request #47205 from frappe/version-14-hotfix
chore: release v14
2025-04-22 19:14:23 +05:30
ruthra kumar
6868da5f6a Merge pull request #47198 from frappe/mergify/bp/version-14-hotfix/pr-47138
fix: rate based on posting date in Tax Withholding Report (backport #47138)
2025-04-22 14:07:19 +05:30
ljain112
f906568fea chore: added test case for date period in multiple tax withholding rules
(cherry picked from commit 515fe340a8)

# Conflicts:
#	erpnext/accounts/report/tds_payable_monthly/test_tds_payable_monthly.py
2025-04-22 13:33:16 +05:30
ljain112
17dc87a2df fix: rate based on posting date in Tax Withholding Report
(cherry picked from commit a32a79e90a)
2025-04-22 07:59:50 +00:00
Sagar Vora
522597d22b Merge pull request #47156 from frappe/mergify/bp/version-14-hotfix/pr-47154
fix: respect mapped accounting dimensions (backport #47154)
2025-04-19 13:03:56 +05:30
Sagar Vora
e4c2442ba2 fix: respect mapped accounting dimensions
(cherry picked from commit 7dbe27da19)
2025-04-19 07:22:23 +00:00
mergify[bot]
0d9bc4424c chore: migrate pre-commit config (backport #47132) (#47133)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2025-04-17 14:22:23 +02:00
Raffael Meyer
35c9375f0d Merge pull request #47130 from frappe/mergify/bp/version-14-hotfix/pr-47125
fix: create default warehouse (backport #47125)
2025-04-17 13:56:56 +02:00
barredterra
f04c73b9c2 ci: update linters
copy config from version-15
2025-04-17 13:38:19 +02:00
Raffael Meyer
a766aa0837 fix: create default warehouse (#47125) 2025-04-17 13:38:10 +02:00
Frappe PR Bot
3248415667 chore(release): Bumped to Version 14.85.4
## [14.85.4](https://github.com/frappe/erpnext/compare/v14.85.3...v14.85.4) (2025-04-16)

### Bug Fixes

* correct doctype in item_wise_purchase register ([6ec33c0](6ec33c0098))
* go for lower case "on" because we already have translations for that ([056cc35](056cc35379))
* make report's "printed on" translatable ([f1a8643](f1a864349e))
* **Payment Entry:** set account type if missing (backport [#47069](https://github.com/frappe/erpnext/issues/47069)) (backport [#47070](https://github.com/frappe/erpnext/issues/47070)) ([#47072](https://github.com/frappe/erpnext/issues/47072)) ([b88f6c1](b88f6c1252))
* remove redundant letter head ([033fa09](033fa09eb4))
* revert [#46900](https://github.com/frappe/erpnext/issues/46900) - against_voucher filter in general ledger ([5844aaf](5844aafd12))
* serial no validation for stock reconciliation ([a3d4d34](a3d4d34454))
* stock entry repack amount calculation ([253a067](253a067592))
* update the modified date in for SLEs and GLs after rename ([8801584](8801584c8d))

### Performance Improvements

* stock ageing report generation ([7a74dac](7a74dac2c2))
2025-04-16 04:02:43 +00:00
ruthra kumar
4fb12754ce Merge pull request #47090 from frappe/version-14-hotfix
chore: release v14
2025-04-16 09:31:20 +05:30
ruthra kumar
503b89a764 Merge pull request #46952 from frappe/mergify/bp/version-14-hotfix/pr-46949
fix: improve translatability of query report print formats (backport #46913) (backport #46949)
2025-04-15 15:59:10 +05:30
mergify[bot]
b88f6c1252 fix(Payment Entry): set account type if missing (backport #47069) (backport #47070) (#47072)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
fix(Payment Entry): set account type if missing (backport #47069) (#47070)
fix(Payment Entry): set account type if missing (#47069)
2025-04-14 19:19:50 +02:00
rohitwaghchaure
e5156e6666 Merge pull request #47068 from frappe/mergify/bp/version-14-hotfix/pr-46997
fix: update the modified date in for SLEs and GLs after rename (backport #46997)
2025-04-14 21:06:08 +05:30
Rohit Waghchaure
8801584c8d fix: update the modified date in for SLEs and GLs after rename
(cherry picked from commit dc5a5ef258)
2025-04-14 15:02:22 +00:00
rohitwaghchaure
55ac96ff09 Merge pull request #47062 from frappe/mergify/bp/version-14-hotfix/pr-46853
fix: stock entry repack amount calculation (backport #46853)
2025-04-14 20:30:38 +05:30
rohitwaghchaure
3f3fb323cf chore: fix conflicts 2025-04-14 18:02:24 +05:30
Rohit Waghchaure
253a067592 fix: stock entry repack amount calculation
(cherry picked from commit 544ceb93cd)

# Conflicts:
#	erpnext/stock/stock_ledger.py
2025-04-14 12:30:21 +00:00
Frappe PR Bot
d8f301f1db chore(release): Bumped to Version 14.85.3
## [14.85.3](https://github.com/frappe/erpnext/compare/v14.85.2...v14.85.3) (2025-04-14)

### Bug Fixes

* revert [#46900](https://github.com/frappe/erpnext/issues/46900) - against_voucher filter in general ledger ([27ecd3a](27ecd3a21b))
2025-04-14 08:24:00 +00:00
ruthra kumar
6d65c967da Merge pull request #47056 from frappe/mergify/bp/version-14/pr-47049
Revert "fix: remove against_voucher and against_voucher_type column from General Ledger Report" (backport #47049)
2025-04-14 13:52:35 +05:30
ruthra kumar
4ac5c7e5e7 Merge pull request #47054 from frappe/mergify/bp/version-14-hotfix/pr-47049
Revert "fix: remove against_voucher and against_voucher_type column from General Ledger Report" (backport #47049)
2025-04-14 13:51:45 +05:30
ruthra kumar
911014a54e chore: resolve conflict 2025-04-14 13:27:13 +05:30
ruthra kumar
694f158fc8 chore: resolve conflict 2025-04-14 13:25:36 +05:30
ruthra kumar
27ecd3a21b fix: revert #46900 - against_voucher filter in general ledger
(cherry picked from commit adb331ef71)

# Conflicts:
#	erpnext/accounts/report/general_ledger/general_ledger.py
2025-04-14 07:50:45 +00:00
ruthra kumar
5844aafd12 fix: revert #46900 - against_voucher filter in general ledger
(cherry picked from commit adb331ef71)

# Conflicts:
#	erpnext/accounts/report/general_ledger/general_ledger.py
2025-04-14 07:49:35 +00:00
ruthra kumar
98ffbfb432 Merge pull request #47032 from frappe/mergify/bp/version-14-hotfix/pr-47012
fix: correct doctype in item_wise_purchase register (backport #47012)
2025-04-12 07:29:28 +05:30
ljain112
6ec33c0098 fix: correct doctype in item_wise_purchase register
(cherry picked from commit b8b8dce733)
2025-04-12 01:41:16 +00:00
rohitwaghchaure
a2595350f6 Merge pull request #46971 from rohitwaghchaure/fixed-support-35746
fix: serial no validation for stock reconciliation
2025-04-10 11:05:45 +05:30
rohitwaghchaure
ac7700dff0 Merge pull request #46983 from rohitwaghchaure/fixed-stock-ageing-report
perf: stock ageing report generation
2025-04-10 11:03:40 +05:30
Rohit Waghchaure
7a74dac2c2 perf: stock ageing report generation 2025-04-10 10:10:09 +05:30
Rohit Waghchaure
a3d4d34454 fix: serial no validation for stock reconciliation 2025-04-09 17:14:40 +05:30
barredterra
443ed5b2ce chore: add missing german translation
(cherry picked from commit d94ebd0c78)
2025-04-08 14:12:41 +00:00
barredterra
033fa09eb4 fix: remove redundant letter head
(cherry picked from commit 7896f8a855)
2025-04-08 14:12:41 +00:00
barredterra
056cc35379 fix: go for lower case "on" because we already have translations for that
(cherry picked from commit 7cf83ffce7)
2025-04-08 14:12:40 +00:00
barredterra
f1a864349e fix: make report's "printed on" translatable
(cherry picked from commit 18e9a9881c)
2025-04-08 14:12:40 +00:00
160 changed files with 2531 additions and 1001 deletions

View File

@@ -9,15 +9,16 @@ jobs:
name: linters
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: pip
- name: Install and Run Pre-commit
uses: pre-commit/action@v2.0.3
uses: pre-commit/action@v3.0.0
- name: Download Semgrep rules
run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules

View File

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

View File

@@ -3,7 +3,7 @@ import inspect
import frappe
__version__ = "14.85.2"
__version__ = "14.92.14"
def get_default_company(user=None):

View File

@@ -3,4 +3,14 @@
frappe.ui.form.on("Accounts Settings", {
refresh: function (frm) {},
drop_ar_procedures: function (frm) {
frm.call({
doc: frm.doc,
method: "drop_ar_sql_procedures",
callback: function (r) {
frappe.show_alert(__("Procedures dropped"), 5);
},
});
},
});

View File

@@ -73,9 +73,14 @@
"reports_tab",
"remarks_section",
"general_ledger_remarks_length",
"ignore_is_opening_check_for_reporting",
"column_break_lvjk",
"receivable_payable_remarks_length"
"receivable_payable_remarks_length",
"accounts_receivable_payable_tuning_section",
"receivable_payable_fetch_method",
"column_break_ntmi",
"drop_ar_procedures",
"legacy_section",
"ignore_is_opening_check_for_reporting"
],
"fields": [
{
@@ -479,6 +484,34 @@
"fieldname": "ignore_is_opening_check_for_reporting",
"fieldtype": "Check",
"label": "Ignore Is Opening check for reporting"
},
{
"default": "Buffered Cursor",
"fieldname": "receivable_payable_fetch_method",
"fieldtype": "Select",
"label": "Data Fetch Method",
"options": "Buffered Cursor\nUnBuffered Cursor\nRaw SQL"
},
{
"fieldname": "accounts_receivable_payable_tuning_section",
"fieldtype": "Section Break",
"label": "Accounts Receivable / Payable Tuning"
},
{
"fieldname": "legacy_section",
"fieldtype": "Section Break",
"label": "Legacy Fields"
},
{
"fieldname": "column_break_ntmi",
"fieldtype": "Column Break"
},
{
"depends_on": "eval:doc.receivable_payable_fetch_method == \"Raw SQL\"",
"description": "Drops existing SQL Procedures and Function setup by Accounts Receivable report",
"fieldname": "drop_ar_procedures",
"fieldtype": "Button",
"label": "Drop Procedures"
}
],
"icon": "icon-cog",
@@ -486,7 +519,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2025-01-23 13:15:44.077853",
"modified": "2025-05-05 12:29:38.302027",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
@@ -515,4 +548,4 @@
"sort_order": "ASC",
"states": [],
"track_changes": 1
}
}

View File

@@ -65,3 +65,11 @@ class AccountsSettings(Document):
def validate_pending_reposts(self):
if self.acc_frozen_upto:
check_pending_reposting(self.acc_frozen_upto)
@frappe.whitelist()
def drop_ar_sql_procedures(self):
from erpnext.accounts.report.accounts_receivable.accounts_receivable import InitSQLProceduresForAR
frappe.db.sql(f"drop function if exists {InitSQLProceduresForAR.genkey_function_name}")
frappe.db.sql(f"drop procedure if exists {InitSQLProceduresForAR.init_procedure_name}")
frappe.db.sql(f"drop procedure if exists {InitSQLProceduresForAR.allocate_procedure_name}")

View File

@@ -9,13 +9,6 @@ cur_frm.add_fetch("bank", "swift_number", "swift_number");
frappe.ui.form.on("Bank Guarantee", {
setup: function (frm) {
frm.set_query("bank", function () {
return {
filters: {
company: frm.doc.company,
},
};
});
frm.set_query("bank_account", function () {
return {
filters: {

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

@@ -448,9 +448,8 @@ def unset_existing_data(company):
"Sales Taxes and Charges Template",
"Purchase Taxes and Charges Template",
]:
frappe.db.sql(
f'''delete from `tab{doctype}` where `company`="%s"''' % (company) # nosec
)
dt = frappe.qb.DocType(doctype)
frappe.qb.from_(dt).where(dt.company == company).delete().run()
def set_default_accounts(company):

View File

@@ -4,6 +4,8 @@
import unittest
import frappe
from frappe.query_builder.functions import Sum
from frappe.tests.utils import change_settings
from frappe.utils import add_days, today
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
@@ -190,6 +192,31 @@ class TestCostCenterAllocation(unittest.TestCase):
coa2.cancel()
jv.cancel()
@change_settings("System Settings", {"rounding_method": "Commercial Rounding"})
def test_debit_credit_on_cost_center_allocation_for_commercial_rounding(self):
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
cca = create_cost_center_allocation(
"_Test Company",
"Main Cost Center 1 - _TC",
{"Sub Cost Center 2 - _TC": 50, "Sub Cost Center 3 - _TC": 50},
)
si = create_sales_invoice(rate=145.65, cost_center="Main Cost Center 1 - _TC")
gl_entry = frappe.qb.DocType("GL Entry")
gl_entries = (
frappe.qb.from_(gl_entry)
.select(Sum(gl_entry.credit).as_("cr"), Sum(gl_entry.debit).as_("dr"))
.where(gl_entry.voucher_type == "Sales Invoice")
.where(gl_entry.voucher_no == si.name)
).run(as_dict=1)
self.assertEqual(gl_entries[0].cr, gl_entries[0].dr)
si.cancel()
cca.cancel()
def create_cost_center_allocation(
company,

View File

@@ -19,7 +19,7 @@ frappe.ui.form.on("Currency Exchange Settings", {
to: "{to_currency}",
};
add_param(frm, r.message, params, result);
} else if (frm.doc.service_provider == "frankfurter.app") {
} else if (["frankfurter.app", "frankfurter.dev"].includes(frm.doc.service_provider)) {
let result = ["rates", "{to_currency}"];
let params = {
base: "{from_currency}",

View File

@@ -78,7 +78,7 @@
"fieldname": "service_provider",
"fieldtype": "Select",
"label": "Service Provider",
"options": "frankfurter.app\nexchangerate.host\nCustom",
"options": "frankfurter.dev\nexchangerate.host\nCustom",
"reqd": 1
},
{
@@ -104,7 +104,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2024-03-18 08:32:26.895076",
"modified": "2025-11-25 13:03:41.896424",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Currency Exchange Settings",
@@ -141,8 +141,9 @@
"write": 1
}
],
"sort_field": "modified",
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -35,7 +35,7 @@ class CurrencyExchangeSettings(Document):
self.append("req_params", {"key": "date", "value": "{transaction_date}"})
self.append("req_params", {"key": "from", "value": "{from_currency}"})
self.append("req_params", {"key": "to", "value": "{to_currency}"})
elif self.service_provider == "frankfurter.app":
elif self.service_provider in ("frankfurter.dev", "frankfurter.app"):
self.set("result_key", [])
self.set("req_params", [])
@@ -80,11 +80,13 @@ class CurrencyExchangeSettings(Document):
@frappe.whitelist()
def get_api_endpoint(service_provider: str | None = None, use_http: bool = False):
if service_provider and service_provider in ["exchangerate.host", "frankfurter.app"]:
if service_provider and service_provider in ["exchangerate.host", "frankfurter.dev", "frankfurter.app"]:
if service_provider == "exchangerate.host":
api = "api.exchangerate.host/convert"
elif service_provider == "frankfurter.app":
api = "api.frankfurter.app/{transaction_date}"
elif service_provider == "frankfurter.dev":
api = "api.frankfurter.dev/v1/{transaction_date}"
protocol = "https://"
if use_http:

View File

@@ -55,46 +55,46 @@ class Dunning(AccountsController):
"conversion_rate",
"cost_center",
]
inv = frappe.db.get_value("Sales Invoice", self.sales_invoice, invoice_fields, as_dict=1)
accounting_dimensions = get_accounting_dimensions()
invoice_fields.extend(accounting_dimensions)
inv = frappe.db.get_value("Sales Invoice", self.sales_invoice, invoice_fields, as_dict=1)
dunning_in_company_currency = flt(self.dunning_amount * inv.conversion_rate)
default_cost_center = frappe.get_cached_value("Company", self.company, "cost_center")
gl_entries.append(
self.get_gl_dict(
{
"account": inv.debit_to,
"party_type": "Customer",
"party": self.customer,
"due_date": self.due_date,
"against": self.income_account,
"debit": dunning_in_company_currency,
"debit_in_account_currency": self.dunning_amount,
"against_voucher": self.name,
"against_voucher_type": "Dunning",
"cost_center": inv.cost_center or default_cost_center,
"project": inv.project,
},
inv.party_account_currency,
item=inv,
)
)
gl_entries.append(
self.get_gl_dict(
{
"account": self.income_account,
"against": self.customer,
"credit": dunning_in_company_currency,
"cost_center": inv.cost_center or default_cost_center,
"credit_in_account_currency": self.dunning_amount,
"project": inv.project,
},
item=inv,
)
)
debit = {
"account": inv.debit_to,
"party_type": "Customer",
"party": self.customer,
"due_date": self.due_date,
"against": self.income_account,
"debit": dunning_in_company_currency,
"debit_in_account_currency": self.dunning_amount,
"against_voucher": self.name,
"against_voucher_type": "Dunning",
"cost_center": inv.cost_center or default_cost_center,
"project": inv.project,
}
credit = {
"account": self.income_account,
"against": self.customer,
"credit": dunning_in_company_currency,
"credit_in_account_currency": self.dunning_amount,
"cost_center": inv.cost_center or default_cost_center,
"project": inv.project,
}
for dimension in accounting_dimensions:
if val := inv.get(dimension):
debit[dimension] = credit[dimension] = val
gl_entries = [
self.get_gl_dict(debit, inv.party_account_currency, item=inv),
self.get_gl_dict(credit, item=inv),
]
make_gl_entries(
gl_entries, cancel=(self.docstatus == 2), update_outstanding="No", merge_entries=False
)

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
from frappe.utils import flt, fmt_money, now
import erpnext
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
@@ -261,7 +261,7 @@ def validate_balance_type(account, adv_adj=False):
if balance_must_be:
balance = frappe.db.sql(
"""select sum(debit) - sum(credit)
from `tabGL Entry` where account = %s""",
from `tabGL Entry` where is_cancelled = 0 and account = %s""",
account,
)[0][0]
@@ -405,7 +405,7 @@ def rename_temporarily_named_docs(doctype):
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 where name = %s",
(newname, oldname),
f"UPDATE `tab{doctype}` SET name = %s, to_rename = 0, modified = %s where name = %s",
(newname, now(), oldname),
auto_commit=True,
)

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

@@ -34,7 +34,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

@@ -5,6 +5,7 @@
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.query_builder.functions import Sum
from frappe.utils import flt, today
@@ -18,22 +19,30 @@ def get_loyalty_details(
if not expiry_date:
expiry_date = today()
condition = ""
if company:
condition = " and company=%s " % frappe.db.escape(company)
if not include_expired_entry:
condition += " and expiry_date>='%s' " % expiry_date
LoyaltyPointEntry = frappe.qb.DocType("Loyalty Point Entry")
loyalty_point_details = frappe.db.sql(
f"""select sum(loyalty_points) as loyalty_points,
sum(purchase_amount) as total_spent from `tabLoyalty Point Entry`
where customer=%s and loyalty_program=%s and posting_date <= %s
{condition}
group by customer""",
(customer, loyalty_program, expiry_date),
as_dict=1,
query = (
frappe.qb.from_(LoyaltyPointEntry)
.select(
Sum(LoyaltyPointEntry.loyalty_points).as_("loyalty_points"),
Sum(LoyaltyPointEntry.purchase_amount).as_("total_spent"),
)
.where(
(LoyaltyPointEntry.customer == customer)
& (LoyaltyPointEntry.loyalty_program == loyalty_program)
& (LoyaltyPointEntry.posting_date <= expiry_date)
)
.groupby(LoyaltyPointEntry.customer)
)
if company:
query = query.where(LoyaltyPointEntry.company == company)
if not include_expired_entry:
query = query.where(LoyaltyPointEntry.expiry_date >= expiry_date)
loyalty_point_details = query.run(as_dict=True)
if loyalty_point_details:
return loyalty_point_details[0]
else:

View File

@@ -60,6 +60,6 @@ def create_party_link(primary_role, primary_party, secondary_party):
party_link.secondary_role = "Customer" if primary_role == "Supplier" else "Supplier"
party_link.secondary_party = secondary_party
party_link.save(ignore_permissions=True)
party_link.save()
return party_link

View File

@@ -319,7 +319,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");
@@ -330,7 +330,7 @@ frappe.ui.form.on('Payment Entry', {
payment_type: function(frm) {
set_default_party_type(frm);
if(frm.doc.payment_type == "Internal Transfer") {
$.each(["party", "party_balance", "paid_from", "paid_to",
$.each(["party", "party_type", "party_balance", "paid_from", "paid_to",
"references", "total_allocated_amount"], function(i, field) {
frm.set_value(field, null);
});

View File

@@ -350,15 +350,25 @@ class PaymentEntry(AccountsController):
self.set(self.party_account_field, party_account)
self.party_account = party_account
if self.paid_from and not (self.paid_from_account_currency or self.paid_from_account_balance):
if self.paid_from and (
not self.paid_from_account_currency
or not self.paid_from_account_balance
or not self.paid_from_account_type
):
acc = get_account_details(self.paid_from, self.posting_date, self.cost_center)
self.paid_from_account_currency = acc.account_currency
self.paid_from_account_balance = acc.account_balance
self.paid_from_account_type = acc.account_type
if self.paid_to and not (self.paid_to_account_currency or self.paid_to_account_balance):
if self.paid_to and (
not self.paid_to_account_currency
or not self.paid_to_account_balance
or not self.paid_to_account_type
):
acc = get_account_details(self.paid_to, self.posting_date, self.cost_center)
self.paid_to_account_currency = acc.account_currency
self.paid_to_account_balance = acc.account_balance
self.paid_to_account_type = acc.account_type
self.party_account_currency = (
self.paid_from_account_currency
@@ -1580,7 +1590,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
@@ -1631,7 +1641,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"))

View File

@@ -10,14 +10,19 @@
"description",
"section_break_4",
"due_date",
"invoice_portion",
"mode_of_payment",
"column_break_5",
"invoice_portion",
"due_date_based_on",
"credit_days",
"credit_months",
"section_break_6",
"discount_type",
"discount_date",
"column_break_9",
"discount",
"discount_type",
"column_break_9",
"discount_validity_based_on",
"discount_validity",
"section_break_9",
"payment_amount",
"outstanding",
@@ -155,12 +160,50 @@
"fieldtype": "Currency",
"label": "Payment Amount (Company Currency)",
"options": "Company:company:default_currency"
},
{
"fieldname": "due_date_based_on",
"fieldtype": "Select",
"label": "Due Date Based On",
"options": "\nDay(s) after invoice date\nDay(s) after the end of the invoice month\nMonth(s) after the end of the invoice month",
"read_only": 1
},
{
"depends_on": "eval:in_list(['Day(s) after invoice date', 'Day(s) after the end of the invoice month'], doc.due_date_based_on)",
"fieldname": "credit_days",
"fieldtype": "Int",
"label": "Credit Days",
"non_negative": 1,
"read_only": 1
},
{
"depends_on": "eval:doc.due_date_based_on=='Month(s) after the end of the invoice month'",
"fieldname": "credit_months",
"fieldtype": "Int",
"label": "Credit Months",
"non_negative": 1,
"read_only": 1
},
{
"depends_on": "discount",
"fieldname": "discount_validity_based_on",
"fieldtype": "Select",
"label": "Discount Validity Based On",
"options": "\nDay(s) after invoice date\nDay(s) after the end of the invoice month\nMonth(s) after the end of the invoice month",
"read_only": 1
},
{
"depends_on": "discount_validity_based_on",
"fieldname": "discount_validity",
"fieldtype": "Int",
"label": "Discount Validity",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2022-09-16 13:57:06.382859",
"modified": "2025-07-31 08:38:25.820701",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Schedule",
@@ -171,4 +214,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -161,4 +161,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}
}

View File

@@ -11,9 +11,9 @@ frappe.ui.form.on("Period Closing Voucher", {
return {
filters: [
["Account", "company", "=", frm.doc.company],
["Account", "is_group", "=", "0"],
["Account", "is_group", "=", 0],
["Account", "freeze_account", "=", "No"],
["Account", "root_type", "in", "Liability, Equity"],
["Account", "root_type", "in", ["Liability", "Equity"]],
],
};
});
@@ -29,7 +29,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

@@ -32,8 +32,13 @@ class PeriodClosingVoucher(AccountsController):
def on_cancel(self):
self.validate_future_closing_vouchers()
self.ignore_linked_doctypes = (
"GL Entry",
"Stock Ledger Entry",
"Payment Ledger Entry",
"Account Closing Balance",
)
self.db_set("gle_processing_status", "In Progress")
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Payment Ledger Entry")
gle_count = frappe.db.count(
"GL Entry",
{"voucher_type": "Period Closing Voucher", "voucher_no": self.name, "is_cancelled": 0},
@@ -201,6 +206,9 @@ class PeriodClosingVoucher(AccountsController):
return gl_entry
def get_gle_for_closing_account(self, acc):
debit = abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0
credit = abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) < 0 else 0
gl_entry = self.get_gl_dict(
{
"company": self.company,
@@ -209,16 +217,10 @@ class PeriodClosingVoucher(AccountsController):
"cost_center": acc.cost_center,
"finance_book": acc.finance_book,
"account_currency": acc.account_currency,
"debit_in_account_currency": abs(flt(acc.bal_in_account_currency))
if flt(acc.bal_in_account_currency) > 0
else 0,
"debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0,
"credit_in_account_currency": abs(flt(acc.bal_in_account_currency))
if flt(acc.bal_in_account_currency) < 0
else 0,
"credit": abs(flt(acc.bal_in_company_currency))
if flt(acc.bal_in_company_currency) < 0
else 0,
"debit_in_account_currency": debit,
"debit": debit,
"credit_in_account_currency": credit,
"credit": credit,
"is_period_closing_voucher_entry": 1,
},
item=acc,

View File

@@ -560,7 +560,13 @@ class POSInvoice(SalesInvoice):
"Account", self.debit_to, "account_currency", cache=True
)
if not self.due_date and self.customer:
self.due_date = get_due_date(self.posting_date, "Customer", self.customer, self.company)
self.due_date = get_due_date(
self.posting_date,
"Customer",
self.customer,
self.company,
template_name=self.payment_terms_template,
)
super(SalesInvoice, self).set_missing_values(for_validate)

View File

@@ -12,7 +12,7 @@
"posting_date",
"company",
"account",
"group_by",
"categorize_by",
"cost_center",
"territory",
"ignore_exchange_rate_revaluation_journals",
@@ -172,14 +172,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",
@@ -395,10 +387,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-10-18 17:51:39.108481",
"modified": "2025-04-30 14:43:23.643006",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",
@@ -433,4 +433,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}
}

View File

@@ -145,7 +145,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,
@@ -449,7 +449,7 @@ def send_auto_email():
selected = frappe.get_list(
"Process Statement Of Accounts",
filters={"enable_auto_email": 1},
or_filters={"to_date": format_date(today()), "posting_date": format_date(today())},
or_filters={"to_date": today(), "posting_date": today()},
)
for entry in selected:
send_emails(entry.name, from_scheduler=True)

View File

@@ -29,7 +29,10 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
this.frm.set_query("expense_account", "items", function () {
return {
query: "erpnext.controllers.queries.get_expense_account",
filters: { company: doc.company },
filters: {
company: doc.company,
disabled: 0,
},
};
});
}

View File

@@ -173,7 +173,12 @@ class PurchaseInvoice(BuyingController):
)
if not self.due_date:
self.due_date = get_due_date(
self.posting_date, "Supplier", self.supplier, self.company, self.bill_date
self.posting_date,
"Supplier",
self.supplier,
self.company,
self.bill_date,
template_name=self.payment_terms_template,
)
tds_category = frappe.db.get_value("Supplier", self.supplier, "tax_withholding_category")
@@ -781,7 +786,7 @@ class PurchaseInvoice(BuyingController):
self.get_provisional_accounts()
for item in self.get("items"):
if flt(item.base_net_amount):
if flt(item.base_net_amount) or (self.get("update_stock") and item.valuation_rate):
account_currency = get_account_currency(item.expense_account)
if item.item_code:
frappe.get_cached_value("Item", item.item_code, "asset_category")
@@ -1016,6 +1021,9 @@ class PurchaseInvoice(BuyingController):
def get_provisional_accounts(self):
self.provisional_accounts = frappe._dict()
linked_purchase_receipts = set([d.purchase_receipt for d in self.items if d.purchase_receipt])
if not linked_purchase_receipts:
return
pr_items = frappe.get_all(
"Purchase Receipt Item",
filters={"parent": ("in", linked_purchase_receipts)},
@@ -1124,6 +1132,30 @@ class PurchaseInvoice(BuyingController):
warehouse_debit_amount = stock_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
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")
stock_adjustment_amt = stock_amount - warehouse_debit_amount
gl_entries.append(
self.get_gl_dict(
{
"account": cost_of_goods_sold_account,
"against": item.expense_account,
"debit": stock_adjustment_amt,
"debit_in_transaction_currency": stock_adjustment_amt / self.conversion_rate,
"remarks": self.get("remarks") or _("Stock Adjustment"),
"cost_center": item.cost_center,
"project": item.project or self.project,
},
account_currency,
item=item,
)
)
return warehouse_debit_amount
def make_tax_gl_entries(self, gl_entries):

View File

@@ -1816,19 +1816,16 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
rate = flt(sle.stock_value_difference) / flt(sle.actual_qty)
self.assertAlmostEqual(rate, 500)
@change_settings("Accounts Settings", {"automatically_fetch_payment_terms": 1})
def test_payment_allocation_for_payment_terms(self):
from erpnext.buying.doctype.purchase_order.test_purchase_order import (
create_pr_against_po,
create_purchase_order,
)
from erpnext.selling.doctype.sales_order.test_sales_order import (
automatically_fetch_payment_terms,
)
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
make_purchase_invoice as make_pi_from_pr,
)
automatically_fetch_payment_terms()
frappe.db.set_value(
"Payment Terms Template",
"_Test Payment Term Template",
@@ -1854,7 +1851,6 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
pi = make_pi_from_pr(pr.name)
self.assertEqual(pi.payment_schedule[0].payment_amount, 1000)
automatically_fetch_payment_terms(enable=0)
frappe.db.set_value(
"Payment Terms Template",
"_Test Payment Term Template",

View File

@@ -151,7 +151,7 @@ def start_repost(account_repost_doc=str) -> None:
if doc.doctype in ["Sales Invoice", "Purchase Invoice"]:
if not repost_doc.delete_cancelled_entries:
doc.docstatus = 2
doc.make_gl_entries_on_cancel()
doc.make_gl_entries_on_cancel(from_repost=True)
doc.docstatus = 1
if doc.doctype == "Sales Invoice":
@@ -163,7 +163,7 @@ def start_repost(account_repost_doc=str) -> None:
elif doc.doctype == "Purchase Receipt":
if not repost_doc.delete_cancelled_entries:
doc.docstatus = 2
doc.make_gl_entries_on_cancel()
doc.make_gl_entries_on_cancel(from_repost=True)
doc.docstatus = 1
doc.make_gl_entries(from_repost=True)

View File

@@ -498,7 +498,13 @@ class SalesInvoice(SellingController):
"Account", self.debit_to, "account_currency", cache=True
)
if not self.due_date and self.customer:
self.due_date = get_due_date(self.posting_date, "Customer", self.customer, self.company)
self.due_date = get_due_date(
self.posting_date,
"Customer",
self.customer,
self.company,
template_name=self.payment_terms_template,
)
super().set_missing_values(for_validate)
@@ -1019,7 +1025,6 @@ class SalesInvoice(SellingController):
self.make_exchange_gain_loss_journal()
elif self.docstatus == 2:
cancel_exchange_gain_loss_journal(frappe._dict(doctype=self.doctype, name=self.name))
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
if update_outstanding == "No":

View File

@@ -2828,6 +2828,60 @@ class TestSalesInvoice(FrappeTestCase):
self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 10 - _TC")
self.assertEqual(sales_invoice.items[0].item_tax_rate, item_tax_map)
def test_item_tax_template_change_with_grand_total_discount(self):
"""
Test that when item tax template changes due to discount on Grand Total,
the tax calculations are consistent.
"""
item = create_item("Test Item With Multiple Tax Templates")
item.set("taxes", [])
item.append(
"taxes",
{
"item_tax_template": "_Test Account Excise Duty @ 10 - _TC",
"minimum_net_rate": 0,
"maximum_net_rate": 500,
},
)
item.append(
"taxes",
{
"item_tax_template": "_Test Account Excise Duty @ 12 - _TC",
"minimum_net_rate": 501,
"maximum_net_rate": 1000,
},
)
item.save()
si = create_sales_invoice(item=item.name, rate=700, do_not_save=True)
si.append(
"taxes",
{
"charge_type": "On Net Total",
"account_head": "_Test Account Excise Duty - _TC",
"cost_center": "_Test Cost Center - _TC",
"description": "Excise Duty",
"rate": 0,
},
)
si.insert()
self.assertEqual(si.items[0].item_tax_template, "_Test Account Excise Duty @ 12 - _TC")
si.apply_discount_on = "Grand Total"
si.discount_amount = 300
si.save()
# Verify template changed to 10%
self.assertEqual(si.items[0].item_tax_template, "_Test Account Excise Duty @ 10 - _TC")
self.assertEqual(si.taxes[0].tax_amount, 70) # 10% of 700
self.assertEqual(si.grand_total, 470) # 700 + 70 - 300
si.submit()
@change_settings("Selling Settings", {"enable_discount_accounting": 1})
def test_sales_invoice_with_discount_accounting_enabled(self):
discount_account = create_account(
@@ -3287,6 +3341,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
@@ -3294,24 +3349,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_value("Accounts Settings", None, "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_value("Accounts Settings", None, "over_billing_allowance", over_billing_allowance)
dn.cancel()
@change_settings(
"Accounts Settings",
@@ -3889,6 +3943,60 @@ class TestSalesInvoice(FrappeTestCase):
self.assertEqual(invoice.outstanding_amount, 0)
def test_system_generated_exchange_gain_or_loss_je_after_repost(self):
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
from erpnext.accounts.doctype.repost_accounting_ledger.test_repost_accounting_ledger import (
update_repost_settings,
)
update_repost_settings()
si = create_sales_invoice(
customer="_Test Customer USD",
debit_to="_Test Receivable USD - _TC",
currency="USD",
conversion_rate=80,
)
pe = get_payment_entry("Sales Invoice", si.name)
pe.reference_no = "10"
pe.reference_date = nowdate()
pe.paid_from_account_currency = si.currency
pe.paid_to_account_currency = "INR"
pe.source_exchange_rate = 85
pe.target_exchange_rate = 1
pe.paid_amount = si.outstanding_amount
pe.received_amount = 8500
pe.insert()
pe.submit()
ral = frappe.new_doc("Repost Accounting Ledger")
ral.company = si.company
ral.append("vouchers", {"voucher_type": si.doctype, "voucher_no": si.name})
ral.save()
ral.submit()
je = frappe.qb.DocType("Journal Entry")
jea = frappe.qb.DocType("Journal Entry Account")
q = (
(
frappe.qb.from_(je)
.join(jea)
.on(je.name == jea.parent)
.select(je.docstatus)
.where(
(je.voucher_type == "Exchange Gain Or Loss")
& (jea.reference_name == si.name)
& (jea.reference_type == "Sales Invoice")
& (je.is_system_generated == 1)
)
)
.limit(1)
.run()
)
self.assertEqual(q[0][0], 1)
def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
gl_entries = frappe.db.sql(

View File

@@ -80,7 +80,7 @@
"collapsible": 0,
"columns": 0,
"fieldname": "rate",
"fieldtype": "Int",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -102,7 +102,7 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -199,7 +199,7 @@
"collapsible": 0,
"columns": 0,
"fieldname": "amount",
"fieldtype": "Int",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -221,7 +221,7 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -324,7 +324,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-01-10 18:32:36.201124",
"modified": "2025-12-10 08:06:40.611761",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Share Balance",
@@ -339,4 +339,4 @@
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}
}

View File

@@ -75,7 +75,7 @@
},
{
"default": "0",
"description": "Even invoices with apply tax withholding unchecked will be considered for checking cumulative threshold breach",
"description": "Only payment entries with apply tax withholding unchecked will be considered for checking cumulative threshold breach",
"fieldname": "consider_party_ledger_amount",
"fieldtype": "Check",
"label": "Consider Entire Party Ledger Amount",
@@ -102,10 +102,11 @@
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-07-27 21:47:34.396071",
"modified": "2025-07-30 07:13:51.785735",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Withholding Category",
"naming_rule": "Set by user",
"owner": "Administrator",
"permissions": [
{
@@ -148,4 +149,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}
}

View File

@@ -622,6 +622,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

@@ -243,17 +243,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)
@@ -275,6 +276,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

@@ -179,6 +179,15 @@ def process_gl_map(gl_map, merge_entries=True, precision=None):
def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None):
round_off_account, default_currency = frappe.get_cached_value(
"Company", gl_map[0].company, ["round_off_account", "default_currency"]
)
if not precision:
precision = get_field_precision(
frappe.get_meta("GL Entry").get_field("debit"),
currency=default_currency,
)
new_gl_map = []
for d in gl_map:
cost_center = d.get("cost_center")
@@ -192,6 +201,11 @@ def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None):
new_gl_map.append(d)
continue
if d.account == round_off_account:
d.cost_center = cost_center_allocation[0][0]
new_gl_map.append(d)
continue
for sub_cost_center, percentage in cost_center_allocation:
gle = copy.deepcopy(d)
gle.cost_center = sub_cost_center

View File

@@ -552,12 +552,13 @@ def validate_party_accounts(doc):
@frappe.whitelist()
def get_due_date(posting_date, party_type, party, company=None, bill_date=None):
def get_due_date(posting_date, party_type, party, company=None, bill_date=None, template_name=None):
"""Get due date from `Payment Terms Template`"""
due_date = None
if (bill_date or posting_date) and party:
due_date = bill_date or posting_date
template_name = get_payment_terms_template(party, party_type, company)
if not template_name:
template_name = get_payment_terms_template(party, party_type, company)
if template_name:
due_date = get_due_date_from_template(template_name, posting_date, bill_date).strftime("%Y-%m-%d")
@@ -597,35 +598,34 @@ def get_due_date_from_template(template_name, posting_date, bill_date):
def validate_due_date(
posting_date, due_date, party_type, party, company=None, bill_date=None, template_name=None
posting_date, due_date, party_type, party, company=None, 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 Date cannot be after {0}").format(formatdate(default_due_date)))
@frappe.whitelist()
@@ -903,12 +903,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

@@ -282,4 +282,4 @@
{% } %}
</tbody>
</table>
<p class="text-right text-muted">{{ __("Printed On ") }}{%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}</p>
<p class="text-right text-muted">{%= __("Printed on {0}", [frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string())]) %}</p>

View File

@@ -6,6 +6,7 @@ from collections import OrderedDict
import frappe
from frappe import _, qb, query_builder, scrub
from frappe.database.schema import get_definition
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,10 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_accounting_dimensions,
get_dimension_with_children,
)
from erpnext.accounts.utils import get_currency_precision
from erpnext.accounts.utils import (
build_qb_match_conditions,
get_currency_precision,
)
# This report gives a summary of all Outstanding Invoices considering the following
@@ -49,6 +53,10 @@ class ReceivablePayableReport:
self.age_as_on = (
getdate(nowdate()) if self.filters.report_date > getdate(nowdate()) else self.filters.report_date
)
self.ple_fetch_method = (
frappe.db.get_single_value("Accounts Settings", "receivable_payable_fetch_method")
or "Buffered Cursor"
) # Fail Safe
def run(self, args):
self.filters.update(args)
@@ -85,13 +93,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,12 +107,45 @@ class ReceivablePayableReport:
# 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()
elif self.ple_fetch_method == "Raw SQL":
self.fetch_ple_in_sql_procedures()
# Build delivery note map against all sales invoices
self.build_delivery_note_map()
self.build_data()
def fetch_ple_in_buffered_cursor(self):
self.ple_entries = self.ple_query.run(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 = []
with frappe.db.unbuffered_cursor():
for ple in self.ple_query.run(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(
@@ -131,26 +166,22 @@ 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:
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")
@@ -272,6 +303,79 @@ class ReceivablePayableReport:
row.paid -= amount
row.paid_in_account_currency -= amount_in_account_currency
def fetch_ple_in_sql_procedures(self):
self.proc = InitSQLProceduresForAR()
build_balance = f"""
begin not atomic
declare done boolean default false;
declare rec1 row type of `{self.proc._row_def_table_name}`;
declare ple cursor for {self.ple_query.get_sql()};
declare continue handler for not found set done = true;
open ple;
fetch ple into rec1;
while not done do
call {self.proc.init_procedure_name}(rec1);
fetch ple into rec1;
end while;
close ple;
set done = false;
open ple;
fetch ple into rec1;
while not done do
call {self.proc.allocate_procedure_name}(rec1);
fetch ple into rec1;
end while;
close ple;
end;
"""
frappe.db.sql(build_balance)
balances = frappe.db.sql(
f"""select
name,
voucher_type,
voucher_no,
party,
party_account `account`,
posting_date,
account_currency,
cost_center,
sum(invoiced) `invoiced`,
sum(paid) `paid`,
sum(credit_note) `credit_note`,
sum(invoiced) - sum(paid) - sum(credit_note) `outstanding`,
sum(invoiced_in_account_currency) `invoiced_in_account_currency`,
sum(paid_in_account_currency) `paid_in_account_currency`,
sum(credit_note_in_account_currency) `credit_note_in_account_currency`,
sum(invoiced_in_account_currency) - sum(paid_in_account_currency) - sum(credit_note_in_account_currency) `outstanding_in_account_currency`
from `{self.proc._voucher_balance_name}` group by name order by posting_date;""",
as_dict=True,
)
for x in balances:
if self.filters.get("ignore_accounts"):
key = (x.voucher_type, x.voucher_no, x.party)
else:
key = (x.account, x.voucher_type, x.voucher_no, x.party)
_d = self.build_voucher_dict(x)
for field in [
"invoiced",
"paid",
"credit_note",
"outstanding",
"invoiced_in_account_currency",
"paid_in_account_currency",
"credit_note_in_account_currency",
"outstanding_in_account_currency",
"cost_center",
]:
_d[field] = x.get(field)
self.voucher_balance[key] = _d
def update_sub_total_row(self, row, party):
total_row = self.total_row_map.get(party)
@@ -764,7 +868,7 @@ class ReceivablePayableReport:
index = 4
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()
@@ -812,12 +916,15 @@ class ReceivablePayableReport:
else:
query = query.select(ple.remarks)
if match_conditions := build_qb_match_conditions("Payment Ledger Entry"):
query = query.where(Criterion.all(match_conditions))
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)
self.ple_entries = query.run(as_dict=True)
self.ple_query = query
def get_sales_invoices_or_customers_based_on_sales_person(self):
if self.filters.get("sales_person"):
@@ -1204,3 +1311,134 @@ def get_customer_group_with_children(customer_groups):
frappe.throw(_("Customer Group: {0} does not exist").format(d))
return list(set(all_customer_groups))
class InitSQLProceduresForAR:
"""
Initialize SQL Procedures, Functions and Temporary tables to build Receivable / Payable report
"""
_varchar_type = get_definition("Data")
_currency_type = get_definition("Currency")
# Temporary Tables
_voucher_balance_name = "_ar_voucher_balance"
_voucher_balance_definition = f"""
create temporary table `{_voucher_balance_name}`(
name {_varchar_type},
voucher_type {_varchar_type},
voucher_no {_varchar_type},
party {_varchar_type},
party_account {_varchar_type},
posting_date date,
account_currency {_varchar_type},
cost_center {_varchar_type},
invoiced {_currency_type},
paid {_currency_type},
credit_note {_currency_type},
invoiced_in_account_currency {_currency_type},
paid_in_account_currency {_currency_type},
credit_note_in_account_currency {_currency_type}) engine=memory;
"""
_row_def_table_name = "_ar_ple_row"
_row_def_table_definition = f"""
create temporary table `{_row_def_table_name}`(
name {_varchar_type},
account {_varchar_type},
voucher_type {_varchar_type},
voucher_no {_varchar_type},
against_voucher_type {_varchar_type},
against_voucher_no {_varchar_type},
party_type {_varchar_type},
cost_center {_varchar_type},
party {_varchar_type},
posting_date date,
due_date date,
account_currency {_varchar_type},
amount {_currency_type},
amount_in_account_currency {_currency_type}) engine=memory;
"""
# Function
genkey_function_name = "ar_genkey"
genkey_function_sql = f"""
create function `{genkey_function_name}`(rec row type of `{_row_def_table_name}`, allocate bool) returns char(40)
begin
if allocate then
return sha1(concat_ws(',', rec.account, rec.against_voucher_type, rec.against_voucher_no, rec.party));
else
return sha1(concat_ws(',', rec.account, rec.voucher_type, rec.voucher_no, rec.party));
end if;
end
"""
# Procedures
init_procedure_name = "ar_init_tmp_table"
init_procedure_sql = f"""
create procedure ar_init_tmp_table(in ple row type of `{_row_def_table_name}`)
begin
if not exists (select name from `{_voucher_balance_name}` where name = `{genkey_function_name}`(ple, false))
then
insert into `{_voucher_balance_name}` values (`{genkey_function_name}`(ple, false), ple.voucher_type, ple.voucher_no, ple.party, ple.account, ple.posting_date, ple.account_currency, ple.cost_center, 0, 0, 0, 0, 0, 0);
end if;
end;
"""
allocate_procedure_name = "ar_allocate_to_tmp_table"
allocate_procedure_sql = f"""
create procedure ar_allocate_to_tmp_table(in ple row type of `{_row_def_table_name}`)
begin
declare invoiced {_currency_type} default 0;
declare invoiced_in_account_currency {_currency_type} default 0;
declare paid {_currency_type} default 0;
declare paid_in_account_currency {_currency_type} default 0;
declare credit_note {_currency_type} default 0;
declare credit_note_in_account_currency {_currency_type} default 0;
if ple.amount > 0 then
if (ple.voucher_type in ("Journal Entry", "Payment Entry") and (ple.voucher_no != ple.against_voucher_no)) then
set paid = -1 * ple.amount;
set paid_in_account_currency = -1 * ple.amount_in_account_currency;
else
set invoiced = ple.amount;
set invoiced_in_account_currency = ple.amount_in_account_currency;
end if;
else
if ple.voucher_type in ("Sales Invoice", "Purchase Invoice") then
if (ple.voucher_no = ple.against_voucher_no) then
set paid = -1 * ple.amount;
set paid_in_account_currency = -1 * ple.amount_in_account_currency;
else
set credit_note = -1 * ple.amount;
set credit_note_in_account_currency = -1 * ple.amount_in_account_currency;
end if;
else
set paid = -1 * ple.amount;
set paid_in_account_currency = -1 * ple.amount_in_account_currency;
end if;
end if;
insert into `{_voucher_balance_name}` values (`{genkey_function_name}`(ple, true), ple.against_voucher_type, ple.against_voucher_no, ple.party, ple.account, ple.posting_date, ple.account_currency,'', invoiced, paid, 0, invoiced_in_account_currency, paid_in_account_currency, 0);
end;
"""
def __init__(self):
existing_procedures = frappe.db.get_routines()
if self.genkey_function_name not in existing_procedures:
frappe.db.sql(self.genkey_function_sql)
if self.init_procedure_name not in existing_procedures:
frappe.db.sql(self.init_procedure_sql)
if self.allocate_procedure_name not in existing_procedures:
frappe.db.sql(self.allocate_procedure_sql)
frappe.db.sql(f"drop table if exists `{self._voucher_balance_name}`")
frappe.db.sql(self._voucher_balance_definition)
frappe.db.sql(f"drop table if exists `{self._row_def_table_name}`")
frappe.db.sql(self._row_def_table_definition)

View File

@@ -1,6 +1,3 @@
<div style="margin-bottom: 7px;">
{%= frappe.boot.letter_heads[frappe.defaults.get_default("letter_head")] %}
</div>
<h2 class="text-center">{%= __("Bank Reconciliation Statement") %}</h2>
<h4 class="text-center">{%= filters.account && (filters.account + ", "+filters.report_date) || "" %} {%= filters.company %}</h4>
<hr>
@@ -46,4 +43,4 @@
{% } %}
</tbody>
</table>
<p class="text-right text-muted">Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}</p>
<p class="text-right text-muted">{%= __("Printed on {0}", [frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string())]) %}</p>

View File

@@ -67,5 +67,5 @@
</tbody>
</table>
<p class="text-right text-muted">
Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}
{%= __("Printed on {0}", [frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string())]) %}
</p>

View File

@@ -78,4 +78,4 @@
{% } %}
</tbody>
</table>
<p class="text-right text-muted">Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}</p>
<p class="text-right text-muted">{%= __("Printed on {0}", [frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string())]) %}</p>

View File

@@ -49,9 +49,14 @@ 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)");
},
},
{
fieldname: "against_voucher_no",
label: __("Against Voucher No"),
fieldtype: "Data",
},
{
fieldtype: "Break",
},
@@ -107,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",
@@ -192,6 +197,11 @@ frappe.query_reports["General Ledger"] = {
label: __("Show Net Values in Party Account"),
fieldtype: "Check",
},
{
fieldname: "show_amount_in_company_currency",
label: __("Show Credit / Debit in Company Currency"),
fieldtype: "Check",
},
{
fieldname: "show_remarks",
label: __("Show Remarks"),

View File

@@ -72,13 +72,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:
@@ -172,9 +176,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"):
@@ -201,7 +205,7 @@ def get_gl_entries(filters, accounting_dimensions):
)
if filters.get("presentation_currency"):
return convert_to_presentation_currency(gl_entries, currency_map)
return convert_to_presentation_currency(gl_entries, currency_map, filters)
else:
return gl_entries
@@ -225,6 +229,9 @@ def get_conditions(filters):
if filters.get("voucher_no"):
conditions.append("voucher_no=%(voucher_no)s")
if filters.get("against_voucher_no"):
conditions.append("against_voucher=%(against_voucher_no)s")
if filters.get("ignore_err"):
err_journals = frappe.db.get_all(
"Journal Entry",
@@ -258,7 +265,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"):
@@ -270,7 +277,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')")
@@ -365,13 +372,13 @@ 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({})
if filters.get("group_by") != "Group by Voucher":
if filters.get("categorize_by") != "Categorize by Voucher":
data.append(acc_dict.totals.opening)
data += acc_dict.entries
@@ -380,7 +387,7 @@ def get_data_with_opening_closing(filters, account_details, accounting_dimension
data.append(acc_dict.totals.total)
# closing
if filters.get("group_by") != "Group by Voucher":
if filters.get("categorize_by") != "Categorize by Voucher":
data.append(acc_dict.totals.closing)
data.append({})
else:
@@ -413,9 +420,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"
@@ -423,7 +430,7 @@ def group_by_field(group_by):
def initialize_gle_map(gl_entries, filters):
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=get_totals_dict(), entries=[]))
@@ -434,8 +441,8 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map):
totals = get_totals_dict()
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"))
@@ -468,6 +475,9 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map):
data[key][rev_dr_or_cr] = 0
data[key][rev_dr_or_cr + "_in_account_currency"] = 0
if data[key].against_voucher and gle.against_voucher:
data[key].against_voucher += ", " + gle.against_voucher
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
show_opening_entries = filters.get("show_opening_entries")
@@ -528,17 +538,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
@@ -564,11 +577,21 @@ 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)
company_currency = get_company_currency(filters.get("company") or get_default_company())
if (
filters.get("show_amount_in_company_currency")
and filters["presentation_currency"] != company_currency
):
frappe.throw(
_("Presentation Currency cannot be {0} , When {1} is enabled.").format(
frappe.bold(filters["presentation_currency"]),
frappe.bold("Show Credit / Debit in Company Currency"),
)
)
columns = [
{
@@ -589,19 +612,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,
},
{"label": _("Voucher Type"), "fieldname": "voucher_type", "width": 120},
@@ -630,6 +656,14 @@ def get_columns(filters):
columns.extend(
[
{"label": _("Against Voucher Type"), "fieldname": "against_voucher_type", "width": 100},
{
"label": _("Against Voucher"),
"fieldname": "against_voucher",
"fieldtype": "Dynamic Link",
"options": "against_voucher_type",
"width": 100,
},
{"label": _("Supplier Invoice No"), "fieldname": "bill_no", "fieldtype": "Data", "width": 100},
]
)

View File

@@ -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

@@ -46,6 +46,7 @@ class PaymentLedger:
against_voucher_no=ple.against_voucher_no,
amount=ple.amount,
currency=ple.account_currency,
company=ple.company,
)
if self.filters.include_account_currency:
@@ -77,6 +78,7 @@ class PaymentLedger:
against_voucher_no="Outstanding:",
amount=total,
currency=voucher_data[0].currency,
company=voucher_data[0].company,
)
if self.filters.include_account_currency:
@@ -85,7 +87,12 @@ class PaymentLedger:
voucher_data.append(entry)
# empty row
voucher_data.append(frappe._dict())
voucher_data.append(
frappe._dict(
currency=voucher_data[0].currency,
company=voucher_data[0].company,
)
)
self.data.extend(voucher_data)
def build_conditions(self):

View File

@@ -52,28 +52,25 @@ def group_by_party_and_category(data, filters):
party_category_wise_map = {}
for row in data:
key = (row.get("party_type"), row.get("party"), row.get("tax_withholding_category"))
party_category_wise_map.setdefault(
(row.get("party"), row.get("section_code")),
key,
{
"pan": row.get("pan"),
"tax_id": row.get("tax_id"),
"party": row.get("party"),
"party_type": row.get("party_type"),
"party_name": row.get("party_name"),
"section_code": row.get("section_code"),
"entity_type": row.get("entity_type"),
"tax_withholding_category": row.get("tax_withholding_category"),
"party_entity_type": row.get("party_entity_type"),
"rate": row.get("rate"),
"total_amount": 0.0,
"tax_amount": 0.0,
},
)
party_category_wise_map.get((row.get("party"), row.get("section_code")))["total_amount"] += row.get(
"total_amount", 0.0
)
party_category_wise_map.get((row.get("party"), row.get("section_code")))["tax_amount"] += row.get(
"tax_amount", 0.0
)
party_category_wise_map.get(key)["total_amount"] += row.get("total_amount", 0.0)
party_category_wise_map.get(key)["tax_amount"] += row.get("tax_amount", 0.0)
final_result = get_final_result(party_category_wise_map)
@@ -114,13 +111,18 @@ def get_columns(filters):
columns.extend(
[
{
"label": _("Section Code"),
"label": _("Tax Withholding Category"),
"options": "Tax Withholding Category",
"fieldname": "section_code",
"fieldname": "tax_withholding_category",
"fieldtype": "Link",
"width": 180,
},
{"label": _("Entity Type"), "fieldname": "entity_type", "fieldtype": "Data", "width": 180},
{
"label": _("{0} Type").format(_(filters.get("party_type", "Party"))),
"fieldname": "party_entity_type",
"fieldtype": "Data",
"width": 180,
},
{
"label": _("TDS Rate %") if filters.get("party_type") == "Supplier" else _("TCS Rate %"),
"fieldname": "rate",

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"))
@@ -43,6 +45,7 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_
gle_map = get_gle_map(tds_docs)
out = []
entries = {}
for name, details in gle_map.items():
for entry in details:
tax_amount, total_amount, grand_total, base_total = 0, 0, 0, 0
@@ -68,7 +71,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
@@ -103,8 +106,8 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_
row.update(
{
"section_code": tax_withholding_category or "",
"entity_type": party_map.get(party, {}).get(party_type),
"tax_withholding_category": tax_withholding_category or "",
"party_entity_type": party_map.get(party, {}).get(party_type),
"rate": rate,
"total_amount": total_amount,
"grand_total": grand_total,
@@ -117,9 +120,14 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_
"supplier_invoice_date": bill_date,
}
)
out.append(row)
out.sort(key=lambda x: x["section_code"])
key = entry.voucher_no
if key in entries:
entries[key]["tax_amount"] += tax_amount
else:
entries[key] = row
out = list(entries.values())
out.sort(key=lambda x: (x["tax_withholding_category"], x["transaction_date"], x["ref_no"]))
return out
@@ -169,9 +177,9 @@ def get_columns(filters):
pan = "pan" if frappe.db.has_column(filters.party_type, "pan") else "tax_id"
columns = [
{
"label": _("Section Code"),
"label": _("Tax Withholding Category"),
"options": "Tax Withholding Category",
"fieldname": "section_code",
"fieldname": "tax_withholding_category",
"fieldtype": "Link",
"width": 90,
},
@@ -200,7 +208,12 @@ def get_columns(filters):
columns.extend(
[
{"label": _("Entity Type"), "fieldname": "entity_type", "fieldtype": "Data", "width": 100},
{
"label": _("{0} Type").format(_(filters.get("party_type", "Party"))),
"fieldname": "party_entity_type",
"fieldtype": "Data",
"width": 100,
},
]
)
if filters.party_type == "Supplier":
@@ -435,12 +448,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,13 +60,65 @@ class TestTdsPayableMonthly(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])
voucher_expected_values = expected_values[i]
voucher_actual_values = (
voucher.ref_no,
voucher.section_code,
voucher.tax_withholding_category,
voucher.rate,
voucher.base_total,
voucher.tax_amount,

View File

@@ -79,8 +79,14 @@ frappe.require("assets/erpnext/js/financial_statements.js", function () {
options: erpnext.get_presentation_currency_list(),
},
{
fieldname: "with_period_closing_entry",
label: __("Period Closing Entry"),
fieldname: "with_period_closing_entry_for_opening",
label: __("With Period Closing Entry For Opening Balances"),
fieldtype: "Check",
default: 1,
},
{
fieldname: "with_period_closing_entry_for_current_period",
label: __("Period Closing Entry For Current Period"),
fieldtype: "Check",
default: 1,
},

View File

@@ -120,7 +120,7 @@ def get_data(filters):
max_rgt,
filters,
gl_entries_by_account,
ignore_closing_entries=not flt(filters.with_period_closing_entry),
ignore_closing_entries=not flt(filters.with_period_closing_entry_for_current_period),
ignore_opening_entries=True,
)
@@ -274,7 +274,7 @@ def get_opening_balance(
):
opening_balance = opening_balance.where(closing_balance.posting_date >= filters.year_start_date)
if not flt(filters.with_period_closing_entry):
if not flt(filters.with_period_closing_entry_for_opening):
if doctype == "Account Closing Balance":
opening_balance = opening_balance.where(closing_balance.is_period_closing_voucher_entry == 0)
else:

View File

@@ -4,15 +4,25 @@
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"mandatory": 1,
"options": "Company",
"wildcard_filter": 0
}
],
"idx": 0,
"is_standard": "Yes",
"modified": "2019-01-17 17:20:42.374958",
"modified": "2025-08-28 19:06:54.273322",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Trial Balance (Simple)",
"owner": "Administrator",
"prepared_report": 0,
"query": "select fiscal_year as \"Fiscal Year:Data:80\",\n\tcompany as \"Company:Data:220\",\n\tposting_date as \"Posting Date:Date:100\",\n\taccount as \"Account:Data:380\",\n\tsum(debit) as \"Debit:Currency:140\",\n\tsum(credit) as \"Credit:Currency:140\",\n\tfinance_book as \"Finance Book:Link/Finance Book:140\"\nfrom `tabGL Entry`\ngroup by fiscal_year, company, posting_date, account\norder by fiscal_year, company, posting_date, account",
"query": "select fiscal_year as \"Fiscal Year:Data:80\",\n\tcompany as \"Company:Data:220\",\n\tposting_date as \"Posting Date:Date:100\",\n\taccount as \"Account:Data:380\",\n\tsum(debit) as \"Debit:Currency:140\",\n\tsum(credit) as \"Credit:Currency:140\",\n\tfinance_book as \"Finance Book:Link/Finance Book:140\"\nfrom `tabGL Entry`\nwhere is_cancelled = 0 and company = %(company)s\ngroup by fiscal_year, company, posting_date, account\norder by fiscal_year, company, posting_date, account",
"ref_doctype": "GL Entry",
"report_name": "Trial Balance (Simple)",
"report_type": "Query Report",

View File

@@ -86,7 +86,7 @@ def get_rate_as_at(date, from_currency, to_currency):
return rate
def convert_to_presentation_currency(gl_entries, currency_info):
def convert_to_presentation_currency(gl_entries, currency_info, filters=None):
"""
Take a list of GL Entries and change the 'debit' and 'credit' values to currencies
in `currency_info`.
@@ -99,6 +99,13 @@ def convert_to_presentation_currency(gl_entries, currency_info):
company_currency = currency_info["company_currency"]
account_currencies = list(set(entry["account_currency"] for entry in gl_entries))
exchange_gain_or_loss = False
if filters and isinstance(filters.get("account"), list):
account_filter = filters.get("account")
gain_loss_account = frappe.db.get_value("Company", filters.company, "exchange_gain_loss_account")
exchange_gain_or_loss = len(account_filter) == 1 and account_filter[0] == gain_loss_account
for entry in gl_entries:
debit = flt(entry["debit"])
@@ -107,7 +114,11 @@ def convert_to_presentation_currency(gl_entries, currency_info):
credit_in_account_currency = flt(entry["credit_in_account_currency"])
account_currency = entry["account_currency"]
if len(account_currencies) == 1 and account_currency == presentation_currency:
if (
len(account_currencies) == 1
and account_currency == presentation_currency
and not exchange_gain_or_loss
) and not (filters and filters.get("show_amount_in_company_currency")):
entry["debit"] = debit_in_account_currency
entry["credit"] = credit_in_account_currency
else:

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", {"range1": 30, "range2": 60, "range3": 90, "range4": 120}),
("Accounts Receivable", {"range1": 30, "range2": 60, "range3": 90, "range4": 120}),
("Consolidated Financial Statement", {"report": "Balance Sheet"}),

View File

@@ -2,12 +2,14 @@
# License: GNU General Public License v3. See license.txt
from collections import defaultdict
from json import loads
from typing import TYPE_CHECKING, Optional
import frappe
import frappe.defaults
from frappe import _, qb, throw
from frappe.desk.reportview import build_match_conditions
from frappe.model.meta import get_field_precision
from frappe.query_builder import AliasedQuery, Criterion, Table
from frappe.query_builder.functions import Round, Sum
@@ -26,6 +28,7 @@ from frappe.utils import (
nowdate,
)
from pypika import Order
from pypika.functions import Coalesce
from pypika.terms import ExistsCriterion
import erpnext
@@ -2191,3 +2194,44 @@ def run_ledger_health_checks():
doc.general_and_payment_ledger_mismatch = True
doc.checked_on = run_date
doc.save()
def get_link_fields_grouped_by_option(doctype):
meta = frappe.get_meta(doctype)
link_fields_map = defaultdict(list)
for df in meta.fields:
if df.fieldtype == "Link" and df.options and not df.ignore_user_permissions:
link_fields_map[df.options].append(df.fieldname)
return link_fields_map
def build_qb_match_conditions(doctype, user=None) -> list:
match_filters = build_match_conditions(doctype, user, False)
link_fields_map = get_link_fields_grouped_by_option(doctype)
criterion = []
apply_strict_user_permissions = frappe.get_system_settings("apply_strict_user_permissions")
if match_filters:
_dt = qb.DocType(doctype)
for filter in match_filters:
for link_option, allowed_values in filter.items():
fieldnames = link_fields_map.get(link_option, [])
cond = None
if link_option == doctype:
cond = _dt["name"].isin(allowed_values)
for fieldname in fieldnames:
field = _dt[fieldname]
cond = field.isin(allowed_values)
if not apply_strict_user_permissions:
cond = (Coalesce(field, "") == "") | cond
if cond:
criterion.append(cond)
return criterion

View File

@@ -152,6 +152,7 @@
{
"allow_on_submit": 1,
"fetch_from": "item_code.image",
"fetch_if_empty": 1,
"fieldname": "image",
"fieldtype": "Attach Image",
"hidden": 1,
@@ -582,7 +583,7 @@
"link_fieldname": "target_asset"
}
],
"modified": "2024-01-15 17:35:49.226603",
"modified": "2025-05-20 00:44:06.229177",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",

View File

@@ -313,6 +313,7 @@ class Asset(AccountsController):
"asset_name": self.asset_name,
"target_location": self.location,
"to_employee": self.custodian,
"company": self.company,
}
]
asset_movement = frappe.get_doc(
@@ -635,38 +636,44 @@ class Asset(AccountsController):
return add_days(self.available_for_use_date, -1)
# if it returns True, depreciation_amount will not be equal for the first and last rows
def check_is_pro_rata(self, row, wdv_or_dd_non_yearly=False):
def check_is_pro_rata(asset_doc, row, wdv_or_dd_non_yearly=False):
has_pro_rata = False
# if not existing asset, from_date = available_for_use_date
# otherwise, if number_of_depreciations_booked = 2, available_for_use_date = 01/01/2020 and frequency_of_depreciation = 12
# from_date = 01/01/2022
from_date = self.get_modified_available_for_use_date(row, wdv_or_dd_non_yearly)
days = date_diff(row.depreciation_start_date, from_date) + 1
if wdv_or_dd_non_yearly:
total_days = get_total_days(row.depreciation_start_date, 12)
if row.depreciation_method in ("Straight Line", "Manual"):
prev_depreciation_start_date = get_last_day(
add_months(
row.depreciation_start_date,
(row.frequency_of_depreciation * -1) * asset_doc.number_of_depreciations_booked,
)
)
from_date = asset_doc.available_for_use_date
days = date_diff(prev_depreciation_start_date, from_date) + 1
total_days = get_total_days(prev_depreciation_start_date, row.frequency_of_depreciation)
else:
# if frequency_of_depreciation is 12 months, total_days = 365
from_date = _get_modified_available_for_use_date(asset_doc, row, wdv_or_dd_non_yearly=False)
days = date_diff(row.depreciation_start_date, from_date) + 1
total_days = get_total_days(row.depreciation_start_date, row.frequency_of_depreciation)
if days <= 0:
frappe.throw(
_(
"""Error: This asset already has {0} depreciation periods booked.
The `depreciation start` date must be at least {1} periods after the `available for use` date.
Please correct the dates accordingly."""
).format(
asset_doc.number_of_depreciations_booked,
asset_doc.number_of_depreciations_booked,
)
)
if days < total_days:
has_pro_rata = True
return has_pro_rata
def get_modified_available_for_use_date(self, row, wdv_or_dd_non_yearly=False):
if wdv_or_dd_non_yearly:
return add_months(
self.available_for_use_date,
(self.number_of_depreciations_booked * 12),
)
else:
return add_months(
self.available_for_use_date,
(self.number_of_depreciations_booked * row.frequency_of_depreciation),
)
def validate_asset_finance_books(self, row):
if flt(row.expected_value_after_useful_life) >= flt(self.gross_purchase_amount):
frappe.throw(
@@ -1290,6 +1297,28 @@ def get_item_details(item_code, asset_category, gross_purchase_amount):
return books
def _get_modified_available_for_use_date(asset_doc, row, wdv_or_dd_non_yearly=False):
"""
if Asset has opening booked depreciations = 9,
available for use date = 17-07-2023,
depreciation start date = 30-04-2024
then from date should be 01-04-2024
"""
if asset_doc.number_of_depreciations_booked > 0:
from_date = add_months(
asset_doc.available_for_use_date,
(asset_doc.number_of_depreciations_booked * row.frequency_of_depreciation) - 1,
)
if is_last_day_of_the_month(row.depreciation_start_date):
return add_days(get_last_day(from_date), 1)
# get from date when depreciation start date is not last day of the month
months_difference = month_diff(row.depreciation_start_date, from_date) - 1
return add_days(add_months(row.depreciation_start_date, -1 * months_difference), 1)
else:
return asset_doc.available_for_use_date
def get_asset_account(account_name, asset=None, asset_category=None, company=None):
account = None
if asset:
@@ -1503,11 +1532,7 @@ def get_straight_line_or_manual_depr_amount(asset, row, schedule_idx, number_of_
# if the Depreciation Schedule is being prepared for the first time
else:
if row.daily_prorata_based:
amount = (
flt(asset.gross_purchase_amount)
- flt(asset.opening_accumulated_depreciation)
- flt(row.expected_value_after_useful_life)
)
amount = flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
total_days = (
date_diff(
get_last_day(
@@ -1519,7 +1544,11 @@ def get_straight_line_or_manual_depr_amount(asset, row, schedule_idx, number_of_
),
add_days(
get_last_day(
add_months(row.depreciation_start_date, -1 * row.frequency_of_depreciation)
add_months(
row.depreciation_start_date,
(row.frequency_of_depreciation * (asset.number_of_depreciations_booked + 1))
* -1,
),
),
1,
),
@@ -1542,11 +1571,9 @@ def get_straight_line_or_manual_depr_amount(asset, row, schedule_idx, number_of_
return daily_depr_amount * (date_diff(to_date, from_date) + 1)
else:
return (
flt(asset.gross_purchase_amount)
- flt(asset.opening_accumulated_depreciation)
- flt(row.expected_value_after_useful_life)
) / flt(row.total_number_of_depreciations - asset.number_of_depreciations_booked)
return (flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life)) / flt(
row.total_number_of_depreciations
)
def get_shift_depr_amount(asset, row, schedule_idx):

View File

@@ -660,7 +660,7 @@ class TestDepreciationMethods(AssetSetup):
available_for_use_date="2030-06-06",
is_existing_asset=1,
number_of_depreciations_booked=2,
opening_accumulated_depreciation=47095.89,
opening_accumulated_depreciation=47178.08,
expected_value_after_useful_life=10000,
depreciation_start_date="2032-12-31",
total_number_of_depreciations=3,
@@ -668,7 +668,7 @@ class TestDepreciationMethods(AssetSetup):
)
self.assertEqual(asset.status, "Draft")
expected_schedules = [["2032-12-31", 42904.11, 90000.0]]
expected_schedules = [["2032-12-31", 30000.0, 77178.08], ["2033-06-06", 12821.92, 90000.0]]
schedules = [
[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount]
for d in asset.get("schedules")
@@ -1451,7 +1451,7 @@ class TestDepreciationBasics(AssetSetup):
affects `value_after_depreciation`
"""
asset = create_asset(calculate_depreciation=1)
asset = create_asset(calculate_depreciation=1, depreciation_start_date="2021-12-31")
asset.opening_accumulated_depreciation = 2000
asset.number_of_depreciations_booked = 1

View File

@@ -380,7 +380,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
args: {
item_code: item.item_code,
warehouse: cstr(item.warehouse),
qty: flt(item.stock_qty),
qty: -1 * flt(item.stock_qty),
serial_no: item.serial_no,
posting_date: me.frm.doc.posting_date,
posting_time: me.frm.doc.posting_time,

View File

@@ -76,6 +76,7 @@
"fieldname": "completion_date",
"fieldtype": "Datetime",
"label": "Completion Date",
"mandatory_depends_on": "eval:doc.repair_status==\"Completed\"",
"no_copy": 1
},
{
@@ -264,7 +265,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2022-08-16 15:55:25.023471",
"modified": "2025-07-29 15:14:34.044564",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
@@ -302,10 +303,11 @@
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"title_field": "asset_name",
"track_changes": 1,
"track_seen": 1
}
}

View File

@@ -3,7 +3,7 @@
import frappe
from frappe import _
from frappe.utils import add_months, cint, flt, getdate, time_diff_in_hours
from frappe.utils import add_months, cint, flt, get_link_to_form, getdate, time_diff_in_hours
import erpnext
from erpnext.accounts.general_ledger import make_gl_entries
@@ -20,6 +20,20 @@ class AssetRepair(AccountsController):
self.set_stock_items_cost()
self.calculate_total_repair_cost()
def validate_asset(self):
if self.asset_doc.status in ("Sold", "Fully Depreciated", "Scrapped"):
frappe.throw(
_("Asset {0} is in {1} status and cannot be repaired.").format(
get_link_to_form("Asset", self.asset), self.asset_doc.status
)
)
def validate_dates(self):
if self.completion_date and (getdate(self.failure_date) > getdate(self.completion_date)):
frappe.throw(
_("Completion Date can not be before Failure Date. Please adjust the dates accordingly.")
)
def update_status(self):
if self.repair_status == "Pending":
frappe.db.set_value("Asset", self.asset, "status", "Out of Order")
@@ -195,7 +209,7 @@ class AssetRepair(AccountsController):
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
"posting_date": getdate(),
"posting_date": self.completion_date,
"against_voucher_type": "Purchase Invoice",
"against_voucher": self.purchase_invoice,
"company": self.company,
@@ -214,7 +228,7 @@ class AssetRepair(AccountsController):
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
"posting_date": getdate(),
"posting_date": self.completion_date,
"company": self.company,
},
item=self,
@@ -248,7 +262,7 @@ class AssetRepair(AccountsController):
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
"posting_date": getdate(),
"posting_date": self.completion_date,
"company": self.company,
},
item=self,
@@ -265,7 +279,7 @@ class AssetRepair(AccountsController):
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
"posting_date": getdate(),
"posting_date": self.completion_date,
"against_voucher_type": "Stock Entry",
"against_voucher": self.stock_entry,
"company": self.company,

View File

@@ -4,7 +4,7 @@
import unittest
import frappe
from frappe.utils import flt, nowdate
from frappe.utils import add_days, flt, nowdate
from erpnext.assets.doctype.asset.asset import (
get_asset_account,
@@ -288,6 +288,7 @@ def create_asset_repair(**args):
if args.submit:
asset_repair.repair_status = "Completed"
asset_repair.completion_date = add_days(args.failure_date, 1)
asset_repair.cost_center = frappe.db.get_value("Company", asset.company, "cost_center")
if args.stock_consumption:

View File

@@ -456,9 +456,8 @@ class PurchaseOrder(BuyingController):
if not self.is_against_so():
return
for item in removed_items:
prev_ordered_qty = (
prev_ordered_qty = flt(
frappe.get_cached_value("Sales Order Item", item.get("sales_order_item"), "ordered_qty")
or 0.0
)
frappe.db.set_value(

View File

@@ -526,12 +526,8 @@ class TestPurchaseOrder(FrappeTestCase):
self.assertRaises(frappe.ValidationError, pr.submit)
self.assertRaises(frappe.ValidationError, pi.submit)
@change_settings("Accounts Settings", {"automatically_fetch_payment_terms": 1})
def test_make_purchase_invoice_with_terms(self):
from erpnext.selling.doctype.sales_order.test_sales_order import (
automatically_fetch_payment_terms,
)
automatically_fetch_payment_terms()
po = create_purchase_order(do_not_save=True)
self.assertRaises(frappe.ValidationError, make_pi_from_po, po.name)
@@ -555,7 +551,6 @@ class TestPurchaseOrder(FrappeTestCase):
self.assertEqual(getdate(pi.payment_schedule[0].due_date), getdate(po.transaction_date))
self.assertEqual(pi.payment_schedule[1].payment_amount, 2500.0)
self.assertEqual(getdate(pi.payment_schedule[1].due_date), add_days(getdate(po.transaction_date), 30))
automatically_fetch_payment_terms(enable=0)
def test_warehouse_company_validation(self):
from erpnext.stock.utils import InvalidWarehouseCompany
@@ -703,6 +698,7 @@ class TestPurchaseOrder(FrappeTestCase):
)
self.assertEqual(due_date, "2023-03-31")
@change_settings("Accounts Settings", {"automatically_fetch_payment_terms": 0})
def test_terms_are_not_copied_if_automatically_fetch_payment_terms_is_unchecked(self):
po = create_purchase_order(do_not_save=1)
po.payment_terms_template = "_Test Payment Term Template"
@@ -834,18 +830,16 @@ class TestPurchaseOrder(FrappeTestCase):
bo.load_from_db()
self.assertEqual(bo.items[0].ordered_qty, 5)
@change_settings("Accounts Settings", {"automatically_fetch_payment_terms": 1})
def test_payment_terms_are_fetched_when_creating_purchase_invoice(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import (
create_payment_terms_template,
)
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.selling.doctype.sales_order.test_sales_order import (
automatically_fetch_payment_terms,
compare_payment_schedules,
)
automatically_fetch_payment_terms()
po = create_purchase_order(qty=10, rate=100, do_not_save=1)
create_payment_terms_template()
po.payment_terms_template = "Test Receivable Template"
@@ -859,8 +853,6 @@ class TestPurchaseOrder(FrappeTestCase):
# self.assertEqual(po.payment_terms_template, pi.payment_terms_template)
compare_payment_schedules(self, po, pi)
automatically_fetch_payment_terms(enable=0)
def test_internal_transfer_flow(self):
from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
make_inter_company_purchase_invoice,

View File

@@ -9,6 +9,7 @@ from frappe import _
from frappe.core.doctype.communication.email import make
from frappe.desk.form.load import get_attachments
from frappe.model.mapper import get_mapped_doc
from frappe.query_builder import Order
from frappe.utils import get_url
from frappe.utils.print_format import download_pdf
from frappe.utils.user import get_user_fullname
@@ -502,35 +503,32 @@ def get_supplier_tag():
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_rfq_containing_supplier(doctype, txt, searchfield, start, page_len, filters):
conditions = ""
if txt:
conditions += "and rfq.name like '%%" + txt + "%%' "
rfq = frappe.qb.DocType("Request for Quotation")
rfq_supplier = frappe.qb.DocType("Request for Quotation Supplier")
if filters.get("transaction_date"):
conditions += "and rfq.transaction_date = '{}'".format(filters.get("transaction_date"))
rfq_data = frappe.db.sql(
f"""
select
distinct rfq.name, rfq.transaction_date,
rfq.company
from
`tabRequest for Quotation` rfq, `tabRequest for Quotation Supplier` rfq_supplier
where
rfq.name = rfq_supplier.parent
and rfq_supplier.supplier = %(supplier)s
and rfq.docstatus = 1
and rfq.company = %(company)s
{conditions}
order by rfq.transaction_date ASC
limit %(page_len)s offset %(start)s """,
{
"page_len": page_len,
"start": start,
"company": filters.get("company"),
"supplier": filters.get("supplier"),
},
as_dict=1,
query = (
frappe.qb.from_(rfq)
.from_(rfq_supplier)
.select(rfq.name)
.distinct()
.select(rfq.transaction_date, rfq.company)
.where(
(rfq.name == rfq_supplier.parent)
& (rfq_supplier.supplier == filters.get("supplier"))
& (rfq.docstatus == 1)
& (rfq.company == filters.get("company"))
)
.orderby(rfq.transaction_date, order=Order.asc)
.limit(page_len)
.offset(start)
)
if txt:
query = query.where(rfq.name.like(f"%%{txt}%%"))
if filters.get("transaction_date"):
query = query.where(rfq.transaction_date == filters.get("transaction_date"))
rfq_data = query.run(as_dict=1)
return rfq_data

View File

@@ -42,6 +42,11 @@ frappe.ui.form.on("Supplier", {
},
};
});
frm.make_methods = {
"Bank Account": () => erpnext.utils.make_bank_account(frm.doc.doctype, frm.doc.name),
"Pricing Rule": () => erpnext.utils.make_pricing_rule(frm.doc.doctype, frm.doc.name),
};
},
refresh: function (frm) {
@@ -84,21 +89,9 @@ frappe.ui.form.on("Supplier", {
__("View")
);
frm.add_custom_button(
__("Bank Account"),
function () {
erpnext.utils.make_bank_account(frm.doc.doctype, frm.doc.name);
},
__("Create")
);
frm.add_custom_button(__("Bank Account"), () => frm.make_methods["Bank Account"](), __("Create"));
frm.add_custom_button(
__("Pricing Rule"),
function () {
erpnext.utils.make_pricing_rule(frm.doc.doctype, frm.doc.name);
},
__("Create")
);
frm.add_custom_button(__("Pricing Rule"), () => frm.make_methods["Pricing Rule"](), __("Create"));
frm.add_custom_button(
__("Get Supplier Group Details"),
@@ -108,7 +101,10 @@ frappe.ui.form.on("Supplier", {
__("Actions")
);
if (cint(frappe.defaults.get_default("enable_common_party_accounting"))) {
if (
cint(frappe.defaults.get_default("enable_common_party_accounting")) &&
frappe.model.can_create("Party Link")
) {
frm.add_custom_button(
__("Link with Customer"),
function () {

View File

@@ -94,9 +94,6 @@
</script>
</head>
<div style="margin-bottom: 7px;" class="text-center">
{%= frappe.boot.letter_heads[frappe.defaults.get_default("letter_head")] %}
</div>
<h2 class="text-center">{%= __(report.report_name) %}</h2>
<h4 class="text-center">{%= filters.item %} </h4>
@@ -124,9 +121,7 @@
</tbody>
</table>
<h4 class="text-center"> Analysis Chart </h4>
<h4 class="text-center">{%= __("Analysis Chart") %}</h4>
<div id="chart_div"></div>
<p class="text-right text-muted">Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}</p>
<p class="text-right text-muted">{%= __("Printed on {0}", [frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string())]) %}</p>

View File

@@ -76,14 +76,14 @@ frappe.query_reports["Supplier Quotation Comparison"] = {
},
},
{
fieldname: "group_by",
label: __("Group by"),
fieldname: "categorize_by",
label: __("Categorize by"),
fieldtype: "Select",
options: [
{ label: __("Group by Supplier"), value: "Group by Supplier" },
{ label: __("Group by Item"), value: "Group by Item" },
{ label: __("Categorize by Supplier"), value: "Categorize by Supplier" },
{ label: __("Categorize by Item"), value: "Categorize by Item" },
],
default: __("Group by Supplier"),
default: __("Categorize by Supplier"),
},
{
fieldtype: "Check",

View File

@@ -15,6 +15,8 @@ def execute(filters=None):
if not filters:
return [], []
validate_filters(filters)
columns = get_columns(filters)
supplier_quotation_data = get_data(filters)
@@ -24,6 +26,12 @@ def execute(filters=None):
return columns, data, message, chart_data
def validate_filters(filters):
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")
def get_data(filters):
sq = frappe.qb.DocType("Supplier Quotation")
sq_item = frappe.qb.DocType("Supplier Quotation Item")
@@ -82,7 +90,9 @@ def prepare_data(supplier_quotation_data, filters):
group_wise_map = defaultdict(list)
supplier_qty_price_map = {}
group_by_field = "supplier_name" if filters.get("group_by") == "Group by Supplier" else "item_code"
group_by_field = (
"supplier_name" if filters.get("categorize_by") == "Categorize by Supplier" else "item_code"
)
company_currency = frappe.db.get_default("currency")
float_precision = cint(frappe.db.get_default("float_precision")) or 2
@@ -274,7 +284,7 @@ def get_columns(filters):
},
]
if filters.get("group_by") == "Group by Item":
if filters.get("categorize_by") == "Categorize by Item":
group_by_columns.reverse()
columns[0:0] = group_by_columns # add positioned group by columns to the report

View File

@@ -20,6 +20,9 @@ def update_last_purchase_rate(doc, is_submit) -> None:
this_purchase_date = getdate(doc.get("posting_date") or doc.get("transaction_date"))
for d in doc.get("items"):
if d.get("is_free_item"):
continue
# get last purchase details
last_purchase_details = get_last_purchase_details(d.item_code, doc.name)

View File

@@ -0,0 +1,11 @@
# End of Life reached
With the release of ERPNext version 16, version 14 has reached its end of life.
This means that version 14 of ERPNext (which is running on this site) will no longer receive critical bug fixes and is no longer covered under Frappe Support.
We highly recommend that you update to version 16 to get the latest bug fixes, features and other improvements.
[Click here to know more about version 16](https://frappe.io/erpnext/version-16)
If you're on [Frappe Cloud](https://frappe.io/cloud), [click here to learn how to update to v16](https://docs.frappe.io/cloud/sites/version-upgrade)

View File

@@ -213,6 +213,11 @@ class AccountsController(TransactionBase):
self.validate_date_with_fiscal_year()
self.validate_party_accounts()
if self.doctype in ["Sales Invoice", "Purchase Invoice"]:
if self.is_return:
self.validate_qty()
else:
self.validate_deferred_start_and_end_date()
self.validate_inter_company_reference()
@@ -258,11 +263,6 @@ class AccountsController(TransactionBase):
self.set_advance_gain_or_loss()
if self.is_return:
self.validate_qty()
else:
self.validate_deferred_start_and_end_date()
self.validate_deferred_income_expense_account()
self.set_inter_company_account()
@@ -684,7 +684,9 @@ class AccountsController(TransactionBase):
"Customer",
self.customer,
self.company,
None,
self.payment_terms_template,
self.doctype,
)
elif self.doctype == "Purchase Invoice":
validate_due_date(
@@ -695,6 +697,7 @@ class AccountsController(TransactionBase):
self.company,
self.bill_date,
self.payment_terms_template,
self.doctype,
)
def set_price_list_currency(self, buying_or_selling):
@@ -1739,69 +1742,50 @@ class AccountsController(TransactionBase):
def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on):
from erpnext.controllers.status_updater import get_allowance_for
item_allowance = {}
global_qty_allowance, global_amount_allowance = None, None
ref_wise_billed_amount = self.get_reference_wise_billed_amt(ref_dt, item_ref_dn, based_on)
role_allowed_to_over_bill = frappe.get_cached_value(
"Accounts Settings", None, "role_allowed_to_over_bill"
)
user_roles = frappe.get_roles()
if not ref_wise_billed_amount:
return
total_overbilled_amt = 0.0
overbilled_items = []
precision = self.precision(based_on, "items")
precision_allowance = 1 / (10**precision)
reference_names = [d.get(item_ref_dn) for d in self.get("items") if d.get(item_ref_dn)]
reference_details = self.get_billing_reference_details(reference_names, ref_dt + " Item", based_on)
role_allowed_to_overbill = frappe.get_cached_value(
"Accounts Settings", None, "role_allowed_to_over_bill"
)
is_overbilling_allowed = role_allowed_to_overbill in frappe.get_roles()
for item in self.get("items"):
if not item.get(item_ref_dn):
continue
for row in ref_wise_billed_amount.values():
total_billed_amt = row.billed_amt
allowance = get_allowance_for(row.item_code, {}, None, None, "amount")[0]
ref_amt = flt(reference_details.get(item.get(item_ref_dn)), self.precision(based_on, item))
based_on_amt = flt(item.get(based_on))
if not ref_amt:
if based_on_amt: # Skip warning for free items
frappe.msgprint(
_(
"System will not check over billing since amount for Item {0} in {1} is zero"
).format(item.item_code, ref_dt),
title=_("Warning"),
indicator="orange",
)
continue
already_billed = self.get_billed_amount_for_item(item, item_ref_dn, based_on)
total_billed_amt = flt(flt(already_billed) + based_on_amt, self.precision(based_on, item))
allowance, item_allowance, global_qty_allowance, global_amount_allowance = get_allowance_for(
item.item_code, item_allowance, global_qty_allowance, global_amount_allowance, "amount"
)
max_allowed_amt = flt(ref_amt * (100 + allowance) / 100)
max_allowed_amt = flt(row.ref_amt * (100 + allowance) / 100)
if total_billed_amt < 0 and max_allowed_amt < 0:
# while making debit note against purchase return entry(purchase receipt) getting overbill error
total_billed_amt = abs(total_billed_amt)
max_allowed_amt = abs(max_allowed_amt)
total_billed_amt, max_allowed_amt = abs(total_billed_amt), abs(max_allowed_amt)
overbill_amt = total_billed_amt - max_allowed_amt
row["max_allowed_amt"] = max_allowed_amt
total_overbilled_amt += overbill_amt
if overbill_amt > 0.01 and role_allowed_to_over_bill not in user_roles:
if self.doctype != "Purchase Invoice":
self.throw_overbill_exception(item, max_allowed_amt)
elif not cint(
if overbill_amt > precision_allowance and not is_overbilling_allowed:
if self.doctype != "Purchase Invoice" or not cint(
frappe.db.get_single_value(
"Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice"
)
):
self.throw_overbill_exception(item, max_allowed_amt)
overbilled_items.append(row)
if role_allowed_to_over_bill in user_roles and total_overbilled_amt > 0.1:
if overbilled_items:
self.throw_overbill_exception(overbilled_items, precision)
if is_overbilling_allowed and total_overbilled_amt > 0.1:
frappe.msgprint(
_("Overbilling of {} ignored because you have {} role.").format(
total_overbilled_amt, role_allowed_to_over_bill
total_overbilled_amt, role_allowed_to_overbill
),
indicator="orange",
alert=True,
@@ -1817,55 +1801,88 @@ class AccountsController(TransactionBase):
)
)
def get_billed_amount_for_item(self, item, item_ref_dn, based_on):
def get_reference_wise_billed_amt(self, ref_dt, item_ref_dn, based_on):
"""
Returns Sum of Amount of
Sales/Purchase Invoice Items
that are linked to `item_ref_dn` (`dn_detail` / `pr_detail`)
that are submitted OR not submitted but are under current invoice
"""
reference_names = [d.get(item_ref_dn) for d in self.items if d.get(item_ref_dn)]
from frappe.query_builder import Criterion
from frappe.query_builder.functions import Sum
if not reference_names:
return
item_doctype = frappe.qb.DocType(item.doctype)
ref_wise_billed_amount = {}
precision = self.precision(based_on, "items")
reference_details = self.get_billing_reference_details(reference_names, ref_dt + " Item", based_on)
already_billed = self.get_already_billed_amount(reference_names, item_ref_dn, based_on)
for item in self.items:
key = item.get(item_ref_dn)
if not key:
continue
ref_amt = flt(reference_details.get(key), precision)
current_amount = flt(item.get(based_on), precision)
if not ref_amt:
if current_amount: # Skip warning for free items
frappe.msgprint(
_(
"System will not check over billing since amount for Item {0} in {1} is zero"
).format(item.item_code, ref_dt),
title=_("Warning"),
indicator="orange",
)
continue
ref_wise_billed_amount.setdefault(
key,
frappe._dict(item_code=item.item_code, billed_amt=0.0, ref_amt=ref_amt, rows=[]),
)
ref_wise_billed_amount[key]["rows"].append(item.idx)
ref_wise_billed_amount[key]["ref_amt"] = ref_amt
ref_wise_billed_amount[key]["billed_amt"] += current_amount
if key in already_billed:
ref_wise_billed_amount[key]["billed_amt"] += flt(already_billed.pop(key, 0), precision)
return ref_wise_billed_amount
def get_already_billed_amount(self, reference_names, item_ref_dn, based_on):
item_doctype = frappe.qb.DocType(self.items[0].doctype)
based_on_field = frappe.qb.Field(based_on)
join_field = frappe.qb.Field(item_ref_dn)
result = (
frappe.qb.from_(item_doctype)
.select(Sum(based_on_field))
.where(join_field == item.get(item_ref_dn))
.where(
Criterion.any(
[ # select all items from other invoices OR current invoices
Criterion.all(
[ # for selecting items from other invoices
item_doctype.docstatus == 1,
item_doctype.parent != self.name,
]
),
Criterion.all(
[ # for selecting items from current invoice, that are linked to same reference
item_doctype.docstatus == 0,
item_doctype.parent == self.name,
item_doctype.name != item.name,
]
),
]
)
)
).run()
return result[0][0] if result else 0
def throw_overbill_exception(self, item, max_allowed_amt):
frappe.throw(
_(
"Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set allowance in Accounts Settings"
).format(item.item_code, item.idx, max_allowed_amt)
return frappe._dict(
(
frappe.qb.from_(item_doctype)
.select(join_field, Sum(based_on_field))
.where(join_field.isin(reference_names))
.where((item_doctype.docstatus == 1) & (item_doctype.parent != self.name))
.groupby(join_field)
).run()
)
def throw_overbill_exception(self, overbilled_items, precision):
message = (
_("<p>Cannot overbill for the following Items:</p>")
+ "<ul>"
+ "".join(
_("<li>Item {0} in row(s) {1} billed more than {2}</li>").format(
frappe.bold(item.item_code),
", ".join(str(x) for x in item.rows),
frappe.bold(fmt_money(item.max_allowed_amt, precision=precision, currency=self.currency)),
)
for item in overbilled_items
)
+ "</ul>"
)
message += _("<p>To allow over-billing, please set allowance in Accounts Settings.</p>")
frappe.throw(_(message))
def get_company_default(self, fieldname, ignore_validation=False):
from erpnext.accounts.utils import get_company_default
@@ -2222,6 +2239,7 @@ class AccountsController(TransactionBase):
self.payment_schedule = []
self.payment_terms_template = po_or_so.payment_terms_template
posting_date = self.get("bill_date") or self.get("posting_date") or self.get("transaction_date")
for schedule in po_or_so.payment_schedule:
payment_schedule = {
@@ -2234,6 +2252,17 @@ class AccountsController(TransactionBase):
}
if automatically_fetch_payment_terms:
if schedule.due_date_based_on:
payment_schedule["due_date"] = get_due_date(schedule, posting_date)
payment_schedule["due_date_based_on"] = schedule.due_date_based_on
payment_schedule["credit_days"] = cint(schedule.credit_days)
payment_schedule["credit_months"] = cint(schedule.credit_months)
if schedule.discount_validity_based_on:
payment_schedule["discount_date"] = get_discount_date(schedule, posting_date)
payment_schedule["discount_validity_based_on"] = schedule.discount_validity_based_on
payment_schedule["discount_validity"] = cint(schedule.discount_validity)
payment_schedule["payment_amount"] = flt(
grand_total * flt(payment_schedule["invoice_portion"]) / 100,
schedule.precision("payment_amount"),
@@ -2721,9 +2750,7 @@ def set_balance_in_account_currency(
_("Account: {0} with currency: {1} can not be selected").format(gl_dict.account, account_currency)
)
gl_dict["account_currency"] = (
company_currency if account_currency == company_currency else account_currency
)
gl_dict["account_currency"] = account_currency
# set debit/credit in account currency if not provided
if flt(gl_dict.debit) and not flt(gl_dict.debit_in_account_currency):
@@ -2970,14 +2997,26 @@ def get_payment_term_details(
term = frappe.get_doc("Payment Term", term)
else:
term_details.payment_term = term.payment_term
term_details.description = term.description
term_details.invoice_portion = term.invoice_portion
fields_to_copy = [
"description",
"invoice_portion",
"discount_type",
"discount",
"mode_of_payment",
"due_date_based_on",
"credit_days",
"credit_months",
"discount_validity_based_on",
"discount_validity",
]
for field in fields_to_copy:
term_details[field] = term.get(field)
term_details.payment_amount = flt(term.invoice_portion) * flt(grand_total) / 100
term_details.base_payment_amount = flt(term.invoice_portion) * flt(base_grand_total) / 100
term_details.discount_type = term.discount_type
term_details.discount = term.discount
term_details.outstanding = term_details.payment_amount
term_details.mode_of_payment = term.mode_of_payment
if bill_date:
term_details.due_date = get_due_date(term, bill_date)
@@ -2996,11 +3035,11 @@ def get_due_date(term, posting_date=None, bill_date=None):
due_date = None
date = bill_date or posting_date
if term.due_date_based_on == "Day(s) after invoice date":
due_date = add_days(date, term.credit_days)
due_date = add_days(date, cint(term.credit_days))
elif term.due_date_based_on == "Day(s) after the end of the invoice month":
due_date = add_days(get_last_day(date), term.credit_days)
due_date = add_days(get_last_day(date), cint(term.credit_days))
elif term.due_date_based_on == "Month(s) after the end of the invoice month":
due_date = get_last_day(add_months(date, term.credit_months))
due_date = get_last_day(add_months(date, cint(term.credit_months)))
return due_date
@@ -3008,11 +3047,11 @@ def get_discount_date(term, posting_date=None, bill_date=None):
discount_validity = None
date = bill_date or posting_date
if term.discount_validity_based_on == "Day(s) after invoice date":
discount_validity = add_days(date, term.discount_validity)
discount_validity = add_days(date, cint(term.discount_validity))
elif term.discount_validity_based_on == "Day(s) after the end of the invoice month":
discount_validity = add_days(get_last_day(date), term.discount_validity)
discount_validity = add_days(get_last_day(date), cint(term.discount_validity))
elif term.discount_validity_based_on == "Month(s) after the end of the invoice month":
discount_validity = get_last_day(add_months(date, term.discount_validity))
discount_validity = get_last_day(add_months(date, cint(term.discount_validity)))
return discount_validity

View File

@@ -6,7 +6,7 @@ import json
from collections import defaultdict
import frappe
from frappe import qb, scrub
from frappe import cint, qb, scrub
from frappe.desk.reportview import get_filters_cond, get_match_cond
from frappe.query_builder import Criterion, CustomFunction
from frappe.query_builder.functions import Locate
@@ -528,21 +528,27 @@ def get_account_list(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_blanket_orders(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql(
"""select distinct bo.name, bo.blanket_order_type, bo.to_date
from `tabBlanket Order` bo, `tabBlanket Order Item` boi
where
boi.parent = bo.name
and boi.item_code = {item_code}
and bo.blanket_order_type = '{blanket_order_type}'
and bo.company = {company}
and bo.docstatus = 1""".format(
item_code=frappe.db.escape(filters.get("item")),
blanket_order_type=filters.get("blanket_order_type"),
company=frappe.db.escape(filters.get("company")),
bo = frappe.qb.DocType("Blanket Order")
bo_item = frappe.qb.DocType("Blanket Order Item")
blanket_orders = (
frappe.qb.from_(bo)
.from_(bo_item)
.select(bo.name)
.distinct()
.select(bo.blanket_order_type, bo.to_date)
.where(
(bo_item.parent == bo.name)
& (bo_item.item_code == filters.get("item"))
& (bo.blanket_order_type == filters.get("blanket_order_type"))
& (bo.company == filters.get("company"))
& (bo.docstatus == 1)
)
.run()
)
return blanket_orders
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
@@ -560,7 +566,7 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters):
if filters.get("company"):
condition += "and tabAccount.company = %(company)s"
condition += f"and tabAccount.disabled = {filters.get('disabled', 0)}"
condition += " and tabAccount.disabled = %(disabled)s"
return frappe.db.sql(
f"""select tabAccount.name from `tabAccount`
@@ -570,7 +576,11 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters):
and tabAccount.`{searchfield}` LIKE %(txt)s
{condition} {get_match_cond(doctype)}
order by idx desc, name""",
{"txt": "%" + txt + "%", "company": filters.get("company", "")},
{
"txt": "%" + txt + "%",
"company": filters.get("company", ""),
"disabled": cint(filters.get("disabled", 0)),
},
)
@@ -646,7 +656,7 @@ def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
where (tabAccount.report_type = "Profit and Loss"
or tabAccount.account_type in ("Expense Account", "Fixed Asset", "Temporary", "Asset Received But Not Billed", "Capital Work in Progress"))
and tabAccount.is_group=0
and tabAccount.docstatus!=2
and tabAccount.disabled = 0
and tabAccount.{searchfield} LIKE %(txt)s
{condition} {get_match_cond(doctype)}""",
{"company": filters.get("company", ""), "txt": "%" + txt + "%"},

View File

@@ -368,7 +368,7 @@ def make_return_doc(doctype: str, source_name: str, target_doc=None):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
company = frappe.db.get_value("Delivery Note", source_name, "company")
company = frappe.db.get_value(doctype, source_name, "company")
default_warehouse_for_sales_return = frappe.get_cached_value(
"Company", company, "default_warehouse_for_sales_return"
)

View File

@@ -728,7 +728,16 @@ class SellingController(StockController):
def set_default_income_account_for_item(obj):
for d in obj.get("items"):
if d.item_code:
if getattr(d, "income_account", None):
set_item_default(d.item_code, obj.company, "income_account", d.income_account)
"""Set income account as default for items in the transaction.
Updates the item default income account for each item in the transaction
if it differs from the company's default income account.
Args:
obj: Transaction document containing items table with income_account field
"""
company_default = frappe.get_cached_value("Company", obj.company, "default_income_account")
for d in obj.get("items", default=[]):
income_account = getattr(d, "income_account", None)
if d.item_code and income_account and income_account != company_default:
set_item_default(d.item_code, obj.company, "income_account", income_account)

View File

@@ -520,8 +520,9 @@ class StockController(AccountsController):
make_sl_entries(sl_entries, allow_negative_stock, via_landed_cost_voucher)
def make_gl_entries_on_cancel(self):
cancel_exchange_gain_loss_journal(frappe._dict(doctype=self.doctype, name=self.name))
def make_gl_entries_on_cancel(self, from_repost=False):
if not from_repost:
cancel_exchange_gain_loss_journal(frappe._dict(doctype=self.doctype, name=self.name))
if frappe.db.sql(
"""select name from `tabGL Entry` where voucher_type=%s
and voucher_no=%s""",
@@ -1027,12 +1028,7 @@ def is_reposting_pending():
)
def future_sle_exists(args, sl_entries=None, allow_force_reposting=True):
if allow_force_reposting and frappe.db.get_single_value(
"Stock Reposting Settings", "do_reposting_for_each_stock_transaction"
):
return True
def future_sle_exists(args, sl_entries=None):
key = (args.voucher_type, args.voucher_no)
if not hasattr(frappe.local, "future_sle"):
frappe.local.future_sle = {}

View File

@@ -42,17 +42,23 @@ class calculate_taxes_and_totals:
items = list(filter(lambda item: not item.get("is_alternative"), self.doc.get("items")))
return items
def calculate(self):
def calculate(self, ignore_tax_template_validation=False):
if not len(self._items):
return
self.discount_amount_applied = False
self.need_recomputation = False
self.ignore_tax_template_validation = ignore_tax_template_validation
self._calculate()
if self.doc.meta.get_field("discount_amount"):
self.set_discount_amount()
self.apply_discount_amount()
if not ignore_tax_template_validation and self.need_recomputation:
return self.calculate(ignore_tax_template_validation=True)
# Update grand total as per cash and non trade discount
if self.doc.apply_discount_on == "Grand Total" and self.doc.get("is_cash_or_non_trade_discount"):
self.doc.grand_total -= self.doc.discount_amount
@@ -96,6 +102,9 @@ class calculate_taxes_and_totals:
self.doc.base_tax_withholding_net_total = sum_base_net_amount
def validate_item_tax_template(self):
if self.ignore_tax_template_validation:
return
if self.doc.get("is_return") and self.doc.get("return_against"):
return
@@ -136,6 +145,10 @@ class calculate_taxes_and_totals:
)
)
# For correct tax_amount calculation re-computation is required
if self.discount_amount_applied and self.doc.apply_discount_on == "Grand Total":
self.need_recomputation = True
def update_item_tax_map(self):
for item in self.doc.items:
item.item_tax_rate = get_item_tax_map(

View File

@@ -29,4 +29,10 @@ frappe.ui.form.on("Contract", {
});
}
},
party_name: function (frm) {
let field = frm.doc.party_type.toLowerCase() + "_name";
frappe.db.get_value(frm.doc.party_type, frm.doc.party_name, field, (r) => {
frm.set_value("party_full_name", r[field]);
});
},
});

View File

@@ -14,6 +14,7 @@
"party_user",
"status",
"fulfilment_status",
"party_full_name",
"sb_terms",
"start_date",
"cb_date",
@@ -244,11 +245,18 @@
"fieldname": "authorised_by_section",
"fieldtype": "Section Break",
"label": "Authorised By"
},
{
"fieldname": "party_full_name",
"fieldtype": "Data",
"label": "Party Full Name",
"read_only": 1
}
],
"grid_page_length": 50,
"is_submittable": 1,
"links": [],
"modified": "2020-12-07 11:15:58.385521",
"modified": "2025-05-23 13:54:03.346537",
"modified_by": "Administrator",
"module": "CRM",
"name": "Contract",
@@ -315,9 +323,10 @@
"write": 1
}
],
"row_format": "Dynamic",
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 1
}
}

View File

@@ -23,10 +23,17 @@ class Contract(Document):
self.name = _(name)
def validate(self):
self.set_missing_values()
self.validate_dates()
self.update_contract_status()
self.update_fulfilment_status()
def set_missing_values(self):
if not self.party_full_name:
field = self.party_type.lower() + "_name"
if res := frappe.db.get_value(self.party_type, self.party_name, field):
self.party_full_name = res
def before_submit(self):
self.signed_by_company = frappe.session.user

View File

@@ -60,7 +60,7 @@ def import_genericode():
"doctype": "File",
"attached_to_doctype": "Code List",
"attached_to_name": code_list.name,
"folder": "Home/Attachments",
"folder": frappe.db.get_value("File", {"is_attachments_folder": 1}),
"file_name": frappe.local.uploaded_filename,
"file_url": frappe.local.uploaded_file_url,
"is_private": 1,

View File

@@ -6,6 +6,7 @@
"engine": "InnoDB",
"field_order": [
"code_list",
"canonical_uri",
"title",
"common_code",
"description",
@@ -71,10 +72,17 @@
"in_list_view": 1,
"label": "Description",
"max_height": "60px"
},
{
"fetch_from": "code_list.canonical_uri",
"fieldname": "canonical_uri",
"fieldtype": "Data",
"label": "Canonical URI"
}
],
"grid_page_length": 50,
"links": [],
"modified": "2024-11-06 07:46:17.175687",
"modified": "2025-10-04 17:22:28.176155",
"modified_by": "Administrator",
"module": "EDI",
"name": "Common Code",
@@ -94,10 +102,11 @@
"write": 1
}
],
"row_format": "Dynamic",
"search_fields": "common_code,description",
"show_title_field_in_link": 1,
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"title_field": "title"
}
}

View File

@@ -22,6 +22,7 @@ class CommonCode(Document):
additional_data: DF.Code | None
applies_to: DF.Table[DynamicLink]
canonical_uri: DF.Data | None
code_list: DF.Link
common_code: DF.Data
description: DF.SmallText | None

View File

@@ -7,7 +7,7 @@ from collections import deque
from operator import itemgetter
import frappe
from frappe import _
from frappe import _, bold
from frappe.core.doctype.version.version import get_diff
from frappe.model.mapper import get_mapped_doc
from frappe.utils import cint, cstr, flt, today
@@ -554,9 +554,16 @@ class BOM(WebsiteGenerator):
def check_recursion(self, bom_list=None):
"""Check whether recursion occurs in any bom"""
def _throw_error(bom_name):
def _throw_error(bom_name, production_item=None):
msg = _("BOM recursion: {1} cannot be parent or child of {0}").format(self.name, bom_name)
if production_item and bom_name != self.name:
msg += "<br><br>"
msg += _(
"Note: If you want to use the finished good {0} as a raw material, then enable the 'Do Not Explode' checkbox in the Items table against the same raw material."
).format(bold(production_item))
frappe.throw(
_("BOM recursion: {1} cannot be parent or child of {0}").format(self.name, bom_name),
msg,
exc=BOMRecursionError,
)
@@ -573,7 +580,7 @@ class BOM(WebsiteGenerator):
if self.item == item.item_code and item.bom_no:
# Same item but with different BOM should not be allowed.
# Same item can appear recursively once as long as it doesn't have BOM.
_throw_error(item.bom_no)
_throw_error(item.bom_no, self.item)
if self.name in {d.bom_no for d in self.items}:
_throw_error(self.name)

View File

@@ -443,7 +443,7 @@ class JobCard(Document):
op_row.employee.append(time_log.employee)
if time_log.time_in_mins:
op_row.completed_time += time_log.time_in_mins
op_row.completed_qty += time_log.completed_qty
op_row.completed_qty += flt(time_log.completed_qty)
for row in self.sub_operations:
operation_deatils = operation_wise_completed_time.get(row.sub_operation)

View File

@@ -37,6 +37,14 @@ frappe.ui.form.on("Production Plan", {
};
});
frm.set_query("sub_assembly_warehouse", function (doc) {
return {
filters: {
company: doc.company,
},
};
});
frm.set_query("material_request", "material_requests", function () {
return {
filters: {

View File

@@ -1048,6 +1048,7 @@ def get_exploded_items(item_details, company, bom_no, include_non_stock_items, p
item.purchase_uom,
item_uom.conversion_factor,
item.safety_stock,
bom.item.as_("main_bom_item"),
)
.where(
(bei.docstatus < 2)
@@ -1115,6 +1116,7 @@ def get_subitems(
item_default.default_warehouse,
item.purchase_uom,
item_uom.conversion_factor,
bom.item.as_("main_bom_item"),
)
.where(
(bom.name == bom_no)
@@ -1228,6 +1230,7 @@ def get_material_request_items(
"sales_order": sales_order,
"description": row.get("description"),
"uom": row.get("purchase_uom") or row.get("stock_uom"),
"main_bom_item": row.get("main_bom_item"),
}
@@ -1757,6 +1760,7 @@ def get_raw_materials_of_sub_assembly_items(
item.purchase_uom,
item_uom.conversion_factor,
item.safety_stock,
bom.item.as_("main_bom_item"),
)
.where(
(bei.docstatus == 1)

View File

@@ -1322,20 +1322,20 @@ def stop_unstop(work_order, status):
@frappe.whitelist()
def query_sales_order(production_item):
out = frappe.db.sql_list(
"""
select distinct so.name from `tabSales Order` so, `tabSales Order Item` so_item
where so_item.parent=so.name and so_item.item_code=%s and so.docstatus=1
union
select distinct so.name from `tabSales Order` so, `tabPacked Item` pi_item
where pi_item.parent=so.name and pi_item.item_code=%s and so.docstatus=1
""",
(production_item, production_item),
def query_sales_order(production_item: str) -> list[str]:
return frappe.get_list(
"Sales Order",
filters=[
["Sales Order", "docstatus", "=", 1],
],
or_filters=[
["Sales Order Item", "item_code", "=", production_item],
["Packed Item", "item_code", "=", production_item],
],
pluck="name",
distinct=True,
)
return out
@frappe.whitelist()
def make_job_card(work_order, operations):

View File

@@ -23,6 +23,7 @@ def get_columns():
"""return columns"""
columns = [
_("Item") + ":Link/Item:150",
_("Item Name") + "::240",
_("Description") + "::300",
_("BOM Qty") + ":Float:160",
_("BOM UoM") + "::160",
@@ -73,11 +74,12 @@ def get_bom_stock(filters):
.on((BOM_ITEM.item_code == BIN.item_code) & (CONDITIONS))
.select(
BOM_ITEM.item_code,
BOM_ITEM.item_name,
BOM_ITEM.description,
BOM_ITEM.stock_qty,
BOM_ITEM.stock_uom,
BOM_ITEM.stock_qty * qty_to_produce / BOM.quantity,
Sum(BIN.actual_qty).as_("actual_qty"),
BIN.actual_qty.as_("actual_qty"),
Sum(Floor(BIN.actual_qty / (BOM_ITEM.stock_qty * qty_to_produce / BOM.quantity))),
)
.where((BOM_ITEM.parent == filters.get("bom")) & (BOM_ITEM.parenttype == "BOM"))

View File

@@ -94,6 +94,7 @@ def get_expected_data(bom, warehouse, qty_to_produce, show_exploded_view=False):
expected_data.append(
[
item.item_code,
item.item_name,
item.description,
item.stock_qty,
item.stock_uom,

View File

@@ -372,3 +372,9 @@ erpnext.patches.v14_0.disable_add_row_in_gross_profit
execute:frappe.db.set_single_value("Accounts Settings", "exchange_gain_loss_posting_date", "Payment")
erpnext.patches.v14_0.update_posting_datetime
erpnext.stock.doctype.stock_ledger_entry.patches.ensure_sle_indexes
erpnext.patches.v14_0.rename_group_by_to_categorize_by
execute:frappe.db.set_single_value("Accounts Settings", "receivable_payable_fetch_method", "Buffered Cursor")
erpnext.patches.v14_0.set_update_price_list_based_on
erpnext.patches.v14_0.rename_group_by_to_categorize_by_in_custom_reports
erpnext.patches.v14_0.update_full_name_in_contract
erpnext.patches.v16_0.update_currency_exchange_settings_for_frankfurter #2025-12-11

View File

@@ -0,0 +1,20 @@
import frappe
from frappe.model.utils.rename_field import rename_field
def execute():
rename_field("Process Statement Of Accounts", "group_by", "categorize_by")
frappe.db.sql(
"""
UPDATE
`tabProcess Statement Of Accounts`
SET
categorize_by = CASE
WHEN categorize_by = 'Group by Voucher (Consolidated)' THEN 'Categorize by Voucher (Consolidated)'
WHEN categorize_by = 'Group by Voucher' THEN 'Categorize by Voucher'
END
WHERE
categorize_by IN ('Group by Voucher (Consolidated)', 'Group by Voucher')
"""
)

View File

@@ -0,0 +1,24 @@
import json
import frappe
def execute():
custom_reports = frappe.get_all(
"Report",
filters={
"report_type": "Custom Report",
"reference_report": ["in", ["General Ledger", "Supplier Quotation Comparison"]],
},
fields=["name", "json"],
)
for report in custom_reports:
report_json = json.loads(report.json)
if "filters" in report_json and "group_by" in report_json["filters"]:
report_json["filters"]["categorize_by"] = (
report_json["filters"].pop("group_by").replace("Group", "Categorize")
)
frappe.db.set_value("Report", report.name, "json", json.dumps(report_json))

View File

@@ -0,0 +1,14 @@
import frappe
from frappe.utils import cint
def execute():
frappe.db.set_single_value(
"Stock Settings",
"update_price_list_based_on",
(
"Price List Rate"
if cint(frappe.db.get_single_value("Selling Settings", "editable_price_list_rate"))
else "Rate"
),
)

View File

@@ -2,6 +2,15 @@ import frappe
def execute():
try:
from erpnext.patches.v16_0.update_currency_exchange_settings_for_frankfurter import execute
execute()
except ImportError:
update_frankfurter_app_parameter_and_result()
def update_frankfurter_app_parameter_and_result():
settings = frappe.get_doc("Currency Exchange Settings")
if settings.service_provider != "frankfurter.app":
return

View File

@@ -0,0 +1,15 @@
import frappe
from frappe import qb
def execute():
con = qb.DocType("Contract")
for c in (
qb.from_(con)
.select(con.name, con.party_type, con.party_name)
.where(con.party_full_name.isnull())
.run(as_dict=True)
):
field = c.party_type.lower() + "_name"
if res := frappe.db.get_value(c.party_type, c.party_name, field):
frappe.db.set_value("Contract", c.name, "party_full_name", res)

View File

@@ -0,0 +1,17 @@
import frappe
def execute():
settings_meta = frappe.get_meta("Currency Exchange Settings")
settings = frappe.get_doc("Currency Exchange Settings")
if (
"frankfurter.dev" not in settings_meta.get_options("service_provider").split("\n")
or settings.service_provider != "frankfurter.app"
):
return
settings.service_provider = "frankfurter.dev"
settings.set_parameters_and_result()
settings.flags.ignore_validate = True
settings.save()

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