Compare commits

...

672 Commits

Author SHA1 Message Date
Frappe PR Bot
c79088f46a chore(release): Bumped to Version 14.72.2
## [14.72.2](https://github.com/frappe/erpnext/compare/v14.72.1...v14.72.2) (2024-08-21)

### Bug Fixes

* disable rename from warehouse ([ed568fb](ed568fb01d))
* disable rename from warehouse ([a520d06](a520d06c3f))
* **patch:** replace repost with direct sql to update 'against_voucher ([c98ab15](c98ab15a44))
2024-08-21 05:21:14 +00:00
ruthra kumar
d5896cd8a0 Merge pull request #42833 from frappe/version-14-hotfix
chore: release v14
2024-08-21 10:49:56 +05:30
Frappe PR Bot
79edcb2a94 chore(release): Bumped to Version 14.72.1
## [14.72.1](https://github.com/frappe/erpnext/compare/v14.72.0...v14.72.1) (2024-08-16)

### Bug Fixes

* **patch:** replace repost with direct sql to update 'against_voucher ([f6f341a](f6f341ad58))
2024-08-16 11:09:57 +00:00
ruthra kumar
bd2f408f00 Merge pull request #42795 from frappe/mergify/bp/version-14/pr-42791
fix(patch): Use sql to update 'against_voucher' rather than reposting (backport #42791)
2024-08-16 16:38:39 +05:30
ruthra kumar
3b02f80a4e chore: resolve conflict 2024-08-16 16:04:52 +05:30
ruthra kumar
bebd1a0426 chore: update patches.txt
(cherry picked from commit 1721175a20)

# Conflicts:
#	erpnext/patches.txt
2024-08-16 10:26:22 +00:00
ruthra kumar
f6f341ad58 fix(patch): replace repost with direct sql to update 'against_voucher
(cherry picked from commit 13bb48434f)
2024-08-16 10:26:22 +00:00
ruthra kumar
752f93c630 Merge pull request #42793 from frappe/mergify/bp/version-14-hotfix/pr-42791
fix(patch): Use sql to update 'against_voucher' rather than reposting (backport #42791)
2024-08-16 15:55:22 +05:30
ruthra kumar
d14e386e18 chore: resolve conflict 2024-08-16 15:34:48 +05:30
ruthra kumar
9f687eee4e chore: update patches.txt
(cherry picked from commit 1721175a20)

# Conflicts:
#	erpnext/patches.txt
2024-08-16 10:02:34 +00:00
ruthra kumar
c98ab15a44 fix(patch): replace repost with direct sql to update 'against_voucher
(cherry picked from commit 13bb48434f)
2024-08-16 10:02:33 +00:00
Nihantra C. Patel
54815b44e7 Merge pull request #42770 from frappe/mergify/bp/version-14-hotfix/pr-42769
fix: disable rename from warehouse (backport #42769)
2024-08-14 17:15:39 +05:30
Nihantra C. Patel
ed568fb01d fix: disable rename from warehouse 2024-08-14 16:35:34 +05:30
Nihantra C. Patel
a520d06c3f fix: disable rename from warehouse
(cherry picked from commit c1812f74e8)

# Conflicts:
#	erpnext/stock/doctype/warehouse/warehouse.json
2024-08-14 11:03:41 +00:00
Frappe PR Bot
2796aa8b57 chore(release): Bumped to Version 14.72.0
# [14.72.0](https://github.com/frappe/erpnext/compare/v14.71.0...v14.72.0) (2024-08-14)

### Bug Fixes

* dimensions in common party journal entry ([b73df8f](b73df8f5f0))
* expense causing p&l test case to fail ([a9fa9e8](a9fa9e86ea))
* force fetch updates for subcription ([f35bc43](f35bc43242))
* german translation of exit ([db27dd8](db27dd8702))
* ledger entries for pos return with update outstanding for self ([714a432](714a432c1c))
* Maintain same rate on qty change on Quotation to Sales Order ([29449cb](29449cbaf9))
* missing def expense if no exp in first month ([7cd6deb](7cd6debd0e))
* patch to fix incorrect against_voucher references in ledger ([5473546](54735469c1))
* pre-commit for better code formatting ([8f19832](8f19832aa5))
* Sort lists before calling itertools.groupby ([29cfb7c](29cfb7cf25))
* test case for zero deferred expense ([186701b](186701b54f))
* text color in sales funnel report based on theme ([2509618](25096185c9))
* typeerror on payment entry ([c4c001b](c4c001b6f9))
* update 'Paid Amount' on forex payment request ([365ef6b](365ef6b88a))
* warning message for negative stock (backport [#42683](https://github.com/frappe/erpnext/issues/42683)) ([#42709](https://github.com/frappe/erpnext/issues/42709)) ([e44daf7](e44daf73fb))

### Features

* changes in opportunity.py to show contacts and addresses from referenced and opportunities ([8d7e150](8d7e150afb))
2024-08-14 08:00:58 +00:00
ruthra kumar
a5ca5b5081 Merge pull request #42744 from frappe/version-14-hotfix
chore: release v14
2024-08-14 13:29:41 +05:30
ruthra kumar
695297b917 Merge pull request #42760 from frappe/mergify/bp/version-14-hotfix/pr-42720
fix: incorrect 'against_voucher' for Pos return with 'Update Outstanding for Self' disabled. (backport #42720)
2024-08-14 12:27:13 +05:30
ruthra kumar
8882b85888 chore: resolve conflict 2024-08-14 12:04:30 +05:30
ruthra kumar
1cddb4ff39 refactor: move patch to v14 and update patches.txt
(cherry picked from commit da2286802a)

# Conflicts:
#	erpnext/patches.txt
2024-08-14 06:26:35 +00:00
ruthra kumar
aaa6d66666 test: against_voucher for pos_returns without updating for self
(cherry picked from commit 3fb0858321)
2024-08-14 06:26:35 +00:00
ruthra kumar
fa44b0d745 refactor: update patches.txt
(cherry picked from commit 4dc0d3a003)

# Conflicts:
#	erpnext/patches.txt
2024-08-14 06:26:35 +00:00
ruthra kumar
54735469c1 fix: patch to fix incorrect against_voucher references in ledger
(cherry picked from commit 487d0a55f5)

# Conflicts:
#	erpnext/patches/v14_0/update_pos_return_ledger_entries.py
2024-08-14 06:26:34 +00:00
ruthra kumar
714a432c1c fix: ledger entries for pos return with update outstanding for self
(cherry picked from commit 2cd9b28e5b)
2024-08-14 06:26:34 +00:00
ruthra kumar
367b4177c6 Merge pull request #42748 from frappe/mergify/bp/version-14-hotfix/pr-42221
fix: Force Fetching updates on Subscriptions (backport #42221)
2024-08-13 17:24:50 +05:30
ruthra kumar
2d0dca943a chore: resolve conflict 2024-08-13 16:54:35 +05:30
ruthra kumar
456f5b644b Merge pull request #42740 from frappe/mergify/bp/version-14-hotfix/pr-42726
fix: text color in sales funnel report based on theme (backport #42726)
2024-08-13 16:49:01 +05:30
ruthra kumar
cca5aa8a96 chore: resolve conflict 2024-08-13 16:28:07 +05:30
ruthra kumar
366f383d1f refactor: test for force-fetch on future subscription
(cherry picked from commit fd680380bb)

# Conflicts:
#	erpnext/accounts/doctype/subscription/test_subscription.py
2024-08-13 10:53:15 +00:00
ruthra kumar
7752de3a1c chore: minor naming change
(cherry picked from commit d8b6767697)
2024-08-13 10:53:14 +00:00
ruthra kumar
f0f663e552 refactor: don't process future subscriptions
(cherry picked from commit 3a11577411)
2024-08-13 10:53:14 +00:00
ruthra kumar
f35bc43242 fix: force fetch updates for subcription
(cherry picked from commit 1ef890db73)

# Conflicts:
#	erpnext/accounts/doctype/subscription/subscription.js
2024-08-13 10:53:14 +00:00
ruthra kumar
b0b5b25a53 chore: resolve conflict 2024-08-13 14:38:44 +05:30
ljain112
25096185c9 fix: text color in sales funnel report based on theme
(cherry picked from commit 61bc0925d5)

# Conflicts:
#	erpnext/selling/page/sales_funnel/sales_funnel.js
2024-08-13 08:36:21 +00:00
ruthra kumar
a5b5b5e62c Merge pull request #42734 from frappe/mergify/bp/version-14-hotfix/pr-42733
refactor: add a new filter flag in Process Statement of Accounts (backport #42733)
2024-08-13 11:49:19 +05:30
ruthra kumar
e421e16fdc chore: resolve conflicts 2024-08-13 11:22:52 +05:30
ruthra kumar
cef3573d79 refactor: pass filter to General Ledger
(cherry picked from commit 90880c8c01)
2024-08-13 05:41:19 +00:00
ruthra kumar
1ebcc33cdd refactor: cr and dr note filter in Statement of Accounts
(cherry picked from commit 0cf478c4c2)

# 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
2024-08-13 05:41:19 +00:00
ruthra kumar
a9871e379a refactor: combine vouchers from both ignore
(cherry picked from commit 4cc5cd5a71)
2024-08-13 05:41:19 +00:00
ruthra kumar
34662e6e3c Merge pull request #42724 from frappe/mergify/bp/version-14-hotfix/pr-42672
fix: update 'Paid Amount' on forex payment request (backport #42672)
2024-08-12 16:36:28 +05:30
ruthra kumar
1844cb60a4 chore: resolve conflict 2024-08-12 16:14:29 +05:30
ruthra kumar
71416902f6 test: currency conversion on foreign currency account
(cherry picked from commit f913c0fde1)
2024-08-12 10:38:33 +00:00
ruthra kumar
e289793308 test: make use of test fixture
(cherry picked from commit d6d0a1b38d)

# Conflicts:
#	erpnext/accounts/doctype/payment_request/test_payment_request.py
2024-08-12 10:38:33 +00:00
ruthra kumar
365ef6b88a fix: update 'Paid Amount' on forex payment request
(cherry picked from commit 7b0dfb2a05)
2024-08-12 10:38:33 +00:00
mergify[bot]
e44daf73fb fix: warning message for negative stock (backport #42683) (#42709)
* fix: warning message for negative stock (#42683)

(cherry picked from commit deccb007c1)

# Conflicts:
#	erpnext/stock/stock_ledger.py

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-12 11:20:44 +05:30
ruthra kumar
a43136da5d Merge pull request #42694 from frappe/mergify/bp/version-14-hotfix/pr-42428
fix: Sort lists before calling itertools.groupby (backport #42428)
2024-08-09 12:44:24 +05:30
ruthra kumar
d0fbb4d532 Merge pull request #42692 from frappe/mergify/bp/version-14-hotfix/pr-42691
fix: typeerror on payment entry (backport #42691)
2024-08-09 11:55:49 +05:30
Corentin Forler
29cfb7cf25 fix: Sort lists before calling itertools.groupby
(cherry picked from commit 45a6ecbd38)
2024-08-09 06:23:57 +00:00
ruthra kumar
c4c001b6f9 fix: typeerror on payment entry
(cherry picked from commit 9cdca0d662)
2024-08-09 11:53:35 +05:30
Raffael Meyer
93d8e3f3b0 Merge pull request #42687 from frappe/mergify/bp/version-14-hotfix/pr-42684
fix: german translation of exit (backport #42684)
2024-08-08 23:25:58 +02:00
barredterra
db27dd8702 fix: german translation of exit
(cherry picked from commit a2df276880)
2024-08-08 21:15:03 +00:00
ruthra kumar
cc97d4e869 Merge pull request #42651 from frappe/mergify/bp/version-14-hotfix/pr-40865
fix: missing def expense if no exp in first month (backport #40865)
2024-08-08 14:37:39 +05:30
ruthra kumar
eb26610d54 Merge pull request #42677 from frappe/mergify/bp/version-14-hotfix/pr-42673
fix: Maintain same rate on qty change on Quotation to Sales Order (backport #42673)
2024-08-08 13:37:48 +05:30
ruthra kumar
29449cbaf9 fix: Maintain same rate on qty change on Quotation to Sales Order
(cherry picked from commit 91ce9fce9b)
2024-08-08 08:03:37 +00:00
Shariq Ansari
f29cad695a Merge pull request #42667 from frappe/mergify/bp/version-14-hotfix/pr-42596
fix: changes in opportunity.py to show contacts and addresses created from opportunity (backport #42596)
2024-08-08 11:39:47 +05:30
Dietmar Fischer
8f19832aa5 fix: pre-commit for better code formatting
(cherry picked from commit 511a0b9f37)
2024-08-07 14:29:48 +00:00
Dietmar Fischer
8d7e150afb feat: changes in opportunity.py to show contacts and addresses from referenced and opportunities
(cherry picked from commit 61576ca030)
2024-08-07 14:29:48 +00:00
ruthra kumar
4a77653e94 Merge pull request #42660 from frappe/mergify/bp/version-14-hotfix/pr-42578
fix: dimensions in common party journal entry (backport #42578)
2024-08-07 16:23:45 +05:30
ruthra kumar
fa74efc1fc test: dimension inheritance on Exc Gain/Loss JV on Common party
(cherry picked from commit 8040544216)
2024-08-07 10:33:23 +00:00
ljain112
b73df8f5f0 fix: dimensions in common party journal entry
(cherry picked from commit ac629ede79)
2024-08-07 10:33:22 +00:00
Frappe PR Bot
a8a8a033a1 chore(release): Bumped to Version 14.71.0
# [14.71.0](https://github.com/frappe/erpnext/compare/v14.70.14...v14.71.0) (2024-08-07)

### Bug Fixes

* 'undefined' in PL and BS report summary on Consolidated report ([a5e1432](a5e14324da))
* company filter for filtring tax withheld vouchers ([b7731c8](b7731c8fd7))
* do not update item price and last purchase rate for inter transf… (backport [#42616](https://github.com/frappe/erpnext/issues/42616)) ([#42632](https://github.com/frappe/erpnext/issues/42632)) ([5c5349e](5c5349ed16))
* filter condition in item-wise purchase register ([bc9b461](bc9b46126b))
* fixed depreciation calculation as per income tax act ([8df1079](8df1079618))
* item_code filter in item-wise sales register ([f0f8a2f](f0f8a2f01b))
* min height for rows in sales funnel ([7086a96](7086a96462))
* set query filters for sales / purchase tax template on PE ([c8d8536](c8d85364b9))
* slowness in reposting dependent vouchers. (backport [#42282](https://github.com/frappe/erpnext/issues/42282)) ([#42569](https://github.com/frappe/erpnext/issues/42569)) ([3fb6f97](3fb6f97f66))

### Features

* expiry date column in Available Batch Report (backport [#42628](https://github.com/frappe/erpnext/issues/42628)) ([#42641](https://github.com/frappe/erpnext/issues/42641)) ([83928bb](83928bbf78))
2024-08-07 09:27:57 +00:00
ruthra kumar
f0230b2dfd Merge pull request #42648 from frappe/version-14-hotfix
chore: release v14
2024-08-07 14:56:41 +05:30
Khushi Rawat
f4811c3846 Merge pull request #42629 from khushi8112/depreciation-adjustment-issue-when-field-for-income-tax-enabled
fix: depreciation calculation as per income tax act
2024-08-06 19:15:03 +05:30
Dany Robert
a9fa9e86ea fix: expense causing p&l test case to fail
(cherry picked from commit 01888c98bc)
2024-08-06 11:01:41 +00:00
Dany Robert
c67be05280 chore: semgrep
(cherry picked from commit 581af4eced)
2024-08-06 11:01:41 +00:00
Dany Robert
186701b54f fix: test case for zero deferred expense
(cherry picked from commit 7ef4dbcaf6)
2024-08-06 11:01:41 +00:00
Dany Robert
7cd6debd0e fix: missing def expense if no exp in first month
(cherry picked from commit 5c9ce575f6)
2024-08-06 11:01:41 +00:00
Nihantra C. Patel
f8fd354d75 Merge pull request #42650 from Nihantra-Patel/fix_item_sales_purchase_register
fix: item_code filter in item-wise sales-purchase register v14
2024-08-06 16:19:16 +05:30
Nihantra Patel
bc9b46126b fix: filter condition in item-wise purchase register 2024-08-06 15:56:00 +05:30
Nihantra Patel
f0f8a2f01b fix: item_code filter in item-wise sales register 2024-08-06 15:54:05 +05:30
mergify[bot]
83928bbf78 feat: expiry date column in Available Batch Report (backport #42628) (#42641)
* feat: expiry date column in Available Batch Report (#42628)

(cherry picked from commit faff84c6e5)

# Conflicts:
#	erpnext/stock/report/available_batch_report/available_batch_report.py

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-06 15:24:37 +05:30
ruthra kumar
bc50512c97 Merge pull request #42645 from frappe/mergify/bp/version-14-hotfix/pr-42592
fix: company filter for filtring tax withheld vouchers (backport #42592)
2024-08-06 13:39:17 +05:30
ljain112
b7731c8fd7 fix: company filter for filtring tax withheld vouchers
(cherry picked from commit cfe2ae604b)
2024-08-06 07:47:21 +00:00
ruthra kumar
8667bcd86b Merge pull request #42643 from frappe/mergify/bp/version-14-hotfix/pr-42545
fix: min height for rows in sales funnel (backport #42545)
2024-08-06 13:09:39 +05:30
ljain112
7086a96462 fix: min height for rows in sales funnel
(cherry picked from commit fd71d8af52)
2024-08-06 07:33:07 +00:00
ruthra kumar
2a38e14cca Merge pull request #42637 from frappe/mergify/bp/version-14-hotfix/pr-42636
refactor: posting date should not be considered for ignore filters in GL (backport #42636)
2024-08-06 11:43:54 +05:30
ruthra kumar
f4ba879203 refactor: posting date is not considered for ignore filters in GL
(cherry picked from commit c930f8ba9d)
2024-08-06 05:26:26 +00:00
mergify[bot]
5c5349ed16 fix: do not update item price and last purchase rate for inter transf… (backport #42616) (#42632)
fix: do not update item price and last purchase rate for inter transf… (#42616)

fix: do not update item price and last purchase rate for inter transfer transaction
(cherry picked from commit c8af544ef3)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-06 08:19:46 +05:30
Khushi Rawat
8df1079618 fix: fixed depreciation calculation as per income tax act 2024-08-05 18:04:06 +05:30
Khushi Rawat
38739bec45 Merge pull request #42630 from khushi8112/fix-semgrep
ci: fix semgrep version in linters
2024-08-05 18:01:50 +05:30
Khushi Rawat
6ceb3476a6 ci: fix semgrep version in linters 2024-08-05 17:37:29 +05:30
ruthra kumar
6cba69c7da Merge pull request #42625 from frappe/mergify/bp/version-14-hotfix/pr-42555
refactor: date filters should be mandatory in Sales Pipeline Analytics report (backport #42555)
2024-08-05 15:32:28 +05:30
ruthra kumar
ffd3aea07e refactor(test): use test fixture and supply from and to dates
(cherry picked from commit 4253caf910)
2024-08-05 09:39:27 +00:00
ruthra kumar
989ef52f59 refactor: consider empty-string as Not Assigned
(cherry picked from commit 213b2ba942)
2024-08-05 09:39:27 +00:00
ruthra kumar
baa36c6d5e refactor: report columns should be based on from and to dates
(cherry picked from commit 751a25c4b7)
2024-08-05 09:39:27 +00:00
ruthra kumar
f7f191fe50 refactor: make 'from_date' and 'to_date' mandatory
(cherry picked from commit 3617b41b95)
2024-08-05 09:39:27 +00:00
ruthra kumar
703f58ceac refactor: date filters should be explicit
(cherry picked from commit 40c166a0a0)
2024-08-05 09:39:27 +00:00
ruthra kumar
e1da019fe7 Merge pull request #42613 from frappe/mergify/bp/version-14-hotfix/pr-42597
refactor: filter to ignore system generated cr / dr reconciliation journals on general ledger (backport #42597)
2024-08-05 13:20:25 +05:30
ruthra kumar
f0bdc41a94 refactor(test): clear old records 2024-08-05 12:58:21 +05:30
ruthra kumar
392ba36dcf refactor(test): filter and reconcile concerned vouchers
(cherry picked from commit 9ade269b7a)
2024-08-05 05:43:50 +00:00
ruthra kumar
1b6539c3c5 test: clear old data
(cherry picked from commit 991069bfbc)
2024-08-05 05:43:50 +00:00
ruthra kumar
1da744dc4d refactor: make use of date filters on ignore filterss
(cherry picked from commit 03f3ab522f)
2024-08-05 05:43:50 +00:00
ruthra kumar
ac763f8c19 test: ignore filter for system generated cr / dr note journals
(cherry picked from commit 3ffac73598)
2024-08-05 05:43:50 +00:00
ruthra kumar
0a83c8b00c refactor: ignore system generated cr / dr notes on general ledger
(cherry picked from commit bb8c9b5a58)
2024-08-05 05:43:50 +00:00
ruthra kumar
b20b15af74 refactor: ignore filter in general ledger for cr / dr notes
(cherry picked from commit 59d5beee20)
2024-08-05 05:43:50 +00:00
Frappe PR Bot
4089af5a7b chore(release): Bumped to Version 14.70.14
## [14.70.14](https://github.com/frappe/erpnext/compare/v14.70.13...v14.70.14) (2024-08-01)

### Bug Fixes

* slowness in reposting dependent vouchers. (backport [#42282](https://github.com/frappe/erpnext/issues/42282)) ([#42569](https://github.com/frappe/erpnext/issues/42569)) ([cccfbf1](cccfbf193e))
2024-08-01 09:12:20 +00:00
rohitwaghchaure
06c73ef2da Merge pull request #42570 from frappe/mergify/bp/version-14/pr-42569
fix: slowness in reposting dependent vouchers. (backport #42282) (backport #42569)
2024-08-01 14:40:58 +05:30
mergify[bot]
cccfbf193e fix: slowness in reposting dependent vouchers. (backport #42282) (#42569)
fix: slowness in reposting dependent vouchers. (#42282)

(cherry picked from commit b17696a8ae)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
(cherry picked from commit 3fb6f97f66)
2024-08-01 07:52:46 +00:00
mergify[bot]
3fb6f97f66 fix: slowness in reposting dependent vouchers. (backport #42282) (#42569)
fix: slowness in reposting dependent vouchers. (#42282)

(cherry picked from commit b17696a8ae)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-01 13:21:37 +05:30
ruthra kumar
35f6657bae Merge pull request #42565 from frappe/mergify/bp/version-14-hotfix/pr-42563
fix: set query filters for sales / purchase tax template on PE (backport #42563)
2024-07-31 17:28:45 +05:30
ruthra kumar
e82c441326 chore: resolve conflict 2024-07-31 17:14:26 +05:30
ruthra kumar
c8d85364b9 fix: set query filters for sales / purchase tax template on PE
(cherry picked from commit 9fe47ac101)

# Conflicts:
#	erpnext/accounts/doctype/payment_entry/payment_entry.js
2024-07-31 11:39:09 +00:00
ruthra kumar
64234a571e Merge pull request #42559 from frappe/mergify/bp/version-14-hotfix/pr-42558
fix: 'undefined' in PL and BS report summary on Consolidated report (backport #42558)
2024-07-31 16:19:17 +05:30
ruthra kumar
a5e14324da fix: 'undefined' in PL and BS report summary on Consolidated report
(cherry picked from commit dd5a5e4919)
2024-07-31 10:03:56 +00:00
Frappe PR Bot
37a7da3371 chore(release): Bumped to Version 14.70.13
## [14.70.13](https://github.com/frappe/erpnext/compare/v14.70.12...v14.70.13) (2024-07-31)

### Bug Fixes

* builtins.KeyError: ('ABC', 'Store - CP') (backport [#42505](https://github.com/frappe/erpnext/issues/42505)) ([#42508](https://github.com/frappe/erpnext/issues/42508)) ([0256c64](0256c64634))
* consider payment entries for checking if tds is deducted ([e7432fc](e7432fc60d))
* dynamic condition in the pricing rule not working (backport [#42467](https://github.com/frappe/erpnext/issues/42467)) ([#42543](https://github.com/frappe/erpnext/issues/42543)) ([53034c3](53034c332b))
* **gross profit:** incorrect valuation rate on different warehouses ([1a7efbb](1a7efbb654))
* ignore duplicates while creating default templates ([99bc8e8](99bc8e849c))
* incorrect cost_center on AR/AP report ([0e2abbd](0e2abbd08e))
* keep status as In Progress for RIV for Timeout Error (backport [#42274](https://github.com/frappe/erpnext/issues/42274)) ([#42504](https://github.com/frappe/erpnext/issues/42504)) ([8e8d0c7](8e8d0c7bd0))
* parenttype in item wise purchase and sales register ([97f2e88](97f2e88f4c))
* performance issue for the report Purchase Order Analysis report (backport [#42503](https://github.com/frappe/erpnext/issues/42503)) ([#42506](https://github.com/frappe/erpnext/issues/42506)) ([f42f1bb](f42f1bb35f))
* price_list_currency not found error (backport [#42534](https://github.com/frappe/erpnext/issues/42534)) ([#42538](https://github.com/frappe/erpnext/issues/42538)) ([3ba6f40](3ba6f40063))
* warehouse filter in Product Bundle Balance (backport [#42532](https://github.com/frappe/erpnext/issues/42532)) ([#42536](https://github.com/frappe/erpnext/issues/42536)) ([0441984](0441984405))
2024-07-31 06:00:37 +00:00
ruthra kumar
81c362dbe4 Merge pull request #42542 from frappe/version-14-hotfix
chore: release v14
2024-07-31 11:29:23 +05:30
mergify[bot]
53034c332b fix: dynamic condition in the pricing rule not working (backport #42467) (#42543)
fix: dynamic condition in the pricing rule not working (#42467)

(cherry picked from commit 0e817f42ef)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-07-30 17:01:24 +05:30
mergify[bot]
0441984405 fix: warehouse filter in Product Bundle Balance (backport #42532) (#42536)
fix: warehouse filter in Product Bundle Balance (#42532)

(cherry picked from commit 0ecfa709d8)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-07-30 14:53:31 +05:30
mergify[bot]
3ba6f40063 fix: price_list_currency not found error (backport #42534) (#42538)
fix: price_list_currency not found error (#42534)

(cherry picked from commit 23fed831a0)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-07-30 14:52:45 +05:30
mergify[bot]
8e8d0c7bd0 fix: keep status as In Progress for RIV for Timeout Error (backport #42274) (#42504)
* fix: keep status as In Progress for RIV for Timeout Error (#42274)

(cherry picked from commit 10280d6140)

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

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-07-30 14:25:51 +05:30
mergify[bot]
f42f1bb35f fix: performance issue for the report Purchase Order Analysis report (backport #42503) (#42506)
* fix: performance issue for the report Purchase Order Analysis report (#42503)

(cherry picked from commit cb522f8f22)

# Conflicts:
#	erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-07-30 14:25:23 +05:30
mergify[bot]
0256c64634 fix: builtins.KeyError: ('ABC', 'Store - CP') (backport #42505) (#42508)
fix: builtins.KeyError: ('ABC', 'Store - CP') (#42505)

(cherry picked from commit 25dac1f18e)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-07-30 14:25:01 +05:30
ruthra kumar
e4f583d25a Merge pull request #42529 from frappe/mergify/bp/version-14-hotfix/pr-42528
chore: button name should reflect what it creates (backport #42528)
2024-07-30 12:12:32 +05:30
ruthra kumar
7259c0fe30 chore: button name should reflect what it creates
(cherry picked from commit 0b6e7f83cd)
2024-07-30 06:31:17 +00:00
ruthra kumar
02547115e5 Merge pull request #42335 from frappe/mergify/bp/version-14-hotfix/pr-42330
fix: incorrect valuation rate for items from different warehouses in Gross Profit (backport #42330)
2024-07-29 10:17:04 +05:30
ruthra kumar
0bc9825238 Merge pull request #42491 from frappe/mergify/bp/version-14-hotfix/pr-42477
fix: incorrect cost_center on AR/AP report (backport #42477)
2024-07-26 20:10:43 +05:30
ruthra kumar
bb66126dfa test: invoice cost center reported in AR/AP report
(cherry picked from commit 9a0894fd65)
2024-07-26 14:14:32 +00:00
ruthra kumar
0e2abbd08e fix: incorrect cost_center on AR/AP report
(cherry picked from commit 3e19041fa3)
2024-07-26 14:14:32 +00:00
Smit Vora
ff78fab176 Merge pull request #42483 from frappe/mergify/bp/version-14-hotfix/pr-42305
fix: consider payment entries for checking if tds is deducted (backport #42305)
2024-07-26 15:17:05 +05:30
Smit Vora
04840762dd Merge pull request #42481 from frappe/mergify/bp/version-14-hotfix/pr-42444
fix: parenttype in purchase and sales item query (backport #42444)
2024-07-26 15:16:44 +05:30
ljain112
e7432fc60d fix: consider payment entries for checking if tds is deducted
(cherry picked from commit 40b59de4cd)
2024-07-26 09:11:50 +00:00
ljain112
97f2e88f4c fix: parenttype in item wise purchase and sales register
(cherry picked from commit 35981b8730)
2024-07-26 08:56:42 +00:00
ruthra kumar
37f24ae763 Merge pull request #42473 from frappe/mergify/bp/version-14-hotfix/pr-42472
refactor: index on Purchase Invoice 'release_date' (backport #42472)
2024-07-25 21:51:16 +05:30
ruthra kumar
25b9127bae refactor: index on Purchase Invoice 'release_date'
(cherry picked from commit 764dd12b10)
2024-07-25 15:57:59 +00:00
ruthra kumar
6e74e6f314 Merge pull request #42464 from frappe/mergify/bp/version-14-hotfix/pr-42462
refactor: provision for re-evaluating Exchange Rates in monthly frequency (backport #42462)
2024-07-24 22:11:22 +05:30
ruthra kumar
240118ee8b chore: resolve conflict 2024-07-24 18:48:32 +05:30
ruthra kumar
c1fd95ac66 refactor: hooks for monthly re-evaluation jobs
(cherry picked from commit fc4e5f165c)

# Conflicts:
#	erpnext/hooks.py
2024-07-24 13:15:15 +00:00
ruthra kumar
8e340bb7fd refactor: provision for monthly re-evaluation
(cherry picked from commit ce2b9e0f1a)

# Conflicts:
#	erpnext/setup/doctype/company/company.json
#	erpnext/setup/doctype/company/company.py
2024-07-24 13:15:15 +00:00
ruthra kumar
96a6172999 Merge pull request #42455 from frappe/mergify/bp/version-14-hotfix/pr-42390
refactor: cleaning up stale code related to reposting (backport #42390)
2024-07-24 17:35:24 +05:30
Smit Vora
d0d587432d Merge pull request #42439 from frappe/mergify/bp/version-14-hotfix/pr-42377
fix: ignore duplicates while creating default templates (backport #42377)
2024-07-24 14:25:46 +05:30
ruthra kumar
07509b5e99 chore: resolve conflicts 2024-07-24 13:07:15 +05:30
ruthra kumar
99d5b6dc71 chore: resolve conflicts 2024-07-24 13:04:57 +05:30
ruthra kumar
56b1582027 refactor(test): remove assert on 'repost_required'
(cherry picked from commit e71cb4eab7)
2024-07-24 07:29:10 +00:00
ruthra kumar
149109649d refactor: remove attribute check on 'repost_required'
(cherry picked from commit 07fc952a43)

# Conflicts:
#	erpnext/accounts/doctype/journal_entry/journal_entry.py
#	erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
#	erpnext/accounts/doctype/sales_invoice/sales_invoice.py
2024-07-24 07:29:09 +00:00
ruthra kumar
0284328e2c refactor: repost without checking on flag
(cherry picked from commit 09f429ffba)
2024-07-24 07:29:09 +00:00
ruthra kumar
a243873ab0 chore: remove stale UI code related to repost
(cherry picked from commit fe46e1d089)

# Conflicts:
#	erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
2024-07-24 07:29:09 +00:00
ruthra kumar
197e043fc9 chore: remove 'repost_required' from Journal Entry
(cherry picked from commit e81373bb6a)

# Conflicts:
#	erpnext/accounts/doctype/journal_entry/journal_entry.json
#	erpnext/accounts/doctype/journal_entry/journal_entry.py
2024-07-24 07:29:09 +00:00
ruthra kumar
925a164101 chore: remove 'repost_required' from purchase invoice
(cherry picked from commit a467888a67)

# Conflicts:
#	erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
#	erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
2024-07-24 07:29:08 +00:00
ruthra kumar
8f1a4b9717 chore: remove stale 'repost_required' flag from sales invoice
(cherry picked from commit 06c5334f2a)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/sales_invoice.json
#	erpnext/accounts/doctype/sales_invoice/sales_invoice.py
2024-07-24 07:29:08 +00:00
ruthra kumar
67d4020241 chore: remove stale code from sales invoice
(cherry picked from commit f3fda9ce98)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/sales_invoice.js
2024-07-24 07:29:08 +00:00
Frappe PR Bot
fe4b2e36cc chore(release): Bumped to Version 14.70.12
## [14.70.12](https://github.com/frappe/erpnext/compare/v14.70.11...v14.70.12) (2024-07-24)

### Bug Fixes

* missing cr/dr notes on payment reconciliation ([90ee21f](90ee21f868))
* remove proprietorship and update it with individual (backport [#42307](https://github.com/frappe/erpnext/issues/42307)) ([8c1f619](8c1f6196b8))
* set pos data if not return doc ([6ecb064](6ecb064264))
* Show the rows in AR/AP report where outstanding equals to 0.01 ([2936988](2936988cc6))
2024-07-24 07:26:52 +00:00
ruthra kumar
6759b90f85 Merge pull request #42448 from frappe/version-14-hotfix
chore: release v14
2024-07-24 12:55:36 +05:30
Smit Vora
99bc8e849c fix: ignore duplicates while creating default templates
(cherry picked from commit cf55c2ab3d)
2024-07-23 04:56:31 +00:00
ruthra kumar
7a25d33547 Merge pull request #42408 from frappe/mergify/bp/version-14-hotfix/pr-42407
test: basic test case for item-wise purchase register (backport #42407)
2024-07-21 20:08:19 +05:30
ruthra kumar
2466e28bf5 test: basic test case for item-wise purchase register
(cherry picked from commit c3c5d3f615)
2024-07-19 11:21:08 +00:00
ruthra kumar
1096528bb9 Merge pull request #42401 from frappe/mergify/bp/version-14-hotfix/pr-42386
fix: set pos data if not return doc (backport #42386)
2024-07-19 10:57:20 +05:30
ljain112
6ecb064264 fix: set pos data if not return doc
(cherry picked from commit 65d672da65)
2024-07-19 04:56:26 +00:00
ruthra kumar
92300b27c9 Merge pull request #42384 from frappe/mergify/bp/version-14-hotfix/pr-42374
fix: Show the rows in AR/AP report where outstanding equals to 0.01 (backport #42374)
2024-07-18 15:08:55 +05:30
ruthra kumar
4fa9626de0 chore: resolve conflict 2024-07-18 14:41:09 +05:30
ruthra kumar
9b828b829a test: AR/AP report on miniscule outstanding
(cherry picked from commit bb9e42cce2)
2024-07-18 08:15:39 +00:00
Nabin Hait
2936988cc6 fix: Show the rows in AR/AP report where outstanding equals to 0.01
(cherry picked from commit e1dedc5402)

# Conflicts:
#	erpnext/patches.txt
2024-07-18 08:15:38 +00:00
ruthra kumar
9fca232578 Merge pull request #42382 from frappe/mergify/bp/version-14-hotfix/pr-42369
fix: missing cr/dr notes on payment reconciliation (backport #42369)
2024-07-18 13:43:36 +05:30
ruthra kumar
fac22e93d0 chore: resolve conflict 2024-07-18 12:44:34 +05:30
ruthra kumar
3109efaf09 test: payment filter should not affect dr/cr notes
(cherry picked from commit 2d686c06ea)

# Conflicts:
#	erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py
2024-07-18 07:12:45 +00:00
ruthra kumar
90ee21f868 fix: missing cr/dr notes on payment reconciliation
(cherry picked from commit a30af68e9e)
2024-07-18 07:12:45 +00:00
Smit Vora
36c46bb344 Merge pull request #42366 from vorasmit/update-prop-backport
fix: remove redundant proprietorship field from customer type and supplier type (backport #42307)
2024-07-17 18:55:40 +05:30
Sanket322
8c1f6196b8 fix: remove proprietorship and update it with individual (backport #42307) 2024-07-17 14:03:52 +05:30
Frappe PR Bot
12a31de25a chore(release): Bumped to Version 14.70.11
## [14.70.11](https://github.com/frappe/erpnext/compare/v14.70.10...v14.70.11) (2024-07-17)

### Bug Fixes

* missing discount on POS Credit Notes ([ac48c3d](ac48c3d4e7))
2024-07-17 05:11:39 +00:00
ruthra kumar
3b9400755e Merge pull request #42353 from frappe/version-14-hotfix
chore: release v14
2024-07-17 10:40:24 +05:30
ruthra kumar
2ce7300c3c Merge pull request #42337 from frappe/mergify/bp/version-14-hotfix/pr-42294
refactor: make reposting implicit (backport #42294)
2024-07-15 15:41:23 +05:30
ruthra kumar
b96b3b51b6 chore: resolve conflicts 2024-07-15 15:22:06 +05:30
ruthra kumar
8f03769bf2 chore: contextual comments
(cherry picked from commit 794a62aecb)
2024-07-15 09:41:56 +00:00
ruthra kumar
d20f3ab492 refactor(test): reposting happens implicitly
(cherry picked from commit c283cda169)
2024-07-15 09:41:56 +00:00
ruthra kumar
980ca1d8c5 refactor(test): no need to assert repost_required flag
Reposting happens implicitly upon 'Update After Submit'

(cherry picked from commit 8f135e9859)

# Conflicts:
#	erpnext/accounts/doctype/journal_entry/test_journal_entry.py
2024-07-15 09:41:56 +00:00
ruthra kumar
4668a2d7d8 refactor: make reposting implicit
(cherry picked from commit 722ef92324)

# Conflicts:
#	erpnext/accounts/doctype/journal_entry/journal_entry.py
2024-07-15 09:41:56 +00:00
ruthra kumar
1a7efbb654 fix(gross profit): incorrect valuation rate on different warehouses
(cherry picked from commit f9d2dd0a62)
2024-07-15 08:50:15 +00:00
ruthra kumar
ccc2a47e73 Merge pull request #42290 from frappe/mergify/bp/version-14-hotfix/pr-42192
refactor: tests for item wise sales register report (backport #42192)
2024-07-12 09:28:05 +05:30
ruthra kumar
f98716cc2a refactor(test): clear old records 2024-07-11 21:03:29 +05:30
ruthra kumar
7903e8d669 refactor(test): use each instance UOM for assertion
(cherry picked from commit cf4fbfb601)
2024-07-11 12:34:13 +00:00
ruthra kumar
9a50a0a129 refactor: test suite for item-wise sales register
(cherry picked from commit 3aaa22e672)
2024-07-11 12:34:12 +00:00
ruthra kumar
1646517dc4 chore: rename test suite for payable report
(cherry picked from commit 9474f72776)
2024-07-11 12:34:12 +00:00
ruthra kumar
38811e792c Merge pull request #42288 from frappe/mergify/bp/version-14-hotfix/pr-42287
fix: missing discount on POS Credit Notes (backport #42287)
2024-07-11 17:33:26 +05:30
ruthra kumar
edfb408464 chore: resolve conflict 2024-07-11 17:31:20 +05:30
ruthra kumar
ac48c3d4e7 fix: missing discount on POS Credit Notes
(cherry picked from commit 1049550951)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/sales_invoice.js
2024-07-11 11:58:57 +00:00
Frappe PR Bot
1d66b7e5a3 chore(release): Bumped to Version 14.70.10
## [14.70.10](https://github.com/frappe/erpnext/compare/v14.70.9...v14.70.10) (2024-07-10)

### Bug Fixes

* add missing german translations ([d5c1c62](d5c1c62622))
* empty item-wise sales/purchase register reports on initial load ([13895fa](13895fa060))
* fetch expence account from asset category ([4d6a71a](4d6a71ab4b))
* group by in item-wise purchase register ([62ad466](62ad466a3b))
* **Holiday List:** sort holidays on save to avoid disorienting the user (backport [#42236](https://github.com/frappe/erpnext/issues/42236)) ([#42251](https://github.com/frappe/erpnext/issues/42251)) ([fcf6500](fcf6500144))
* manual pick allow to pick more than available stock (backport [#42155](https://github.com/frappe/erpnext/issues/42155)) ([#42158](https://github.com/frappe/erpnext/issues/42158)) ([454e147](454e147592))
* multiple free items on same Item Group ([701dd9e](701dd9e19b))
* removed max discount validation for sales return ([4195c50](4195c50f02))
* stock qty validation in SCR (backport [#42124](https://github.com/frappe/erpnext/issues/42124)) ([#42224](https://github.com/frappe/erpnext/issues/42224)) ([e2f8e02](e2f8e02c73))
* tax on stock_rbnb on repost of Purchase Receipt ([106c154](106c154a16))
* **tds:** use doctype reference when mapping keys across multiple doctypes ([51cbbee](51cbbee4ca))
* updated logic for calculating tax_withholding_net_total in payment entry ([49e5066](49e50662b6))
* use standard method to get `_doc_before_save` ([9fde733](9fde7330e0))
2024-07-10 10:43:56 +00:00
ruthra kumar
ab9bde86f9 Merge pull request #42254 from frappe/version-14-hotfix
chore: release v14
2024-07-10 16:12:40 +05:30
ruthra kumar
5c75bb8775 Merge pull request #42271 from frappe/mergify/bp/version-14-hotfix/pr-42247
fix: don't merge tax into stock account on purchase receipt repost (backport #42247)
2024-07-10 15:52:00 +05:30
ruthra kumar
115a0123ed chore: resolve conflict 2024-07-10 15:30:24 +05:30
ruthra kumar
fdf1dfe46e test: tax account heads on PR report without LCV
(cherry picked from commit 9562628ed6)

# Conflicts:
#	erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
2024-07-10 09:58:30 +00:00
ruthra kumar
106c154a16 fix: tax on stock_rbnb on repost of Purchase Receipt
(cherry picked from commit 8633080dff)
2024-07-10 09:58:30 +00:00
Smit Vora
00e8b862dd Merge pull request #42264 from frappe/mergify/bp/version-14-hotfix/pr-42127
fix: removed max discount validation for sales return (backport #42127)
2024-07-10 15:22:51 +05:30
ljain112
4195c50f02 fix: removed max discount validation for sales return
(cherry picked from commit db807d433b)
2024-07-10 07:01:54 +00:00
Smit Vora
fdb8e5b379 Merge pull request #42262 from ljain112/fix-tds-backport
fix(tds): use doctype reference when mapping keys across multiple doctype (backport #42258)
2024-07-10 12:27:28 +05:30
ljain112
51cbbee4ca fix(tds): use doctype reference when mapping keys across multiple doctypes 2024-07-10 11:55:35 +05:30
Sagar Vora
5000c09759 Merge pull request #42261 from frappe/mergify/bp/version-14-hotfix/pr-42060
fix: updated logic for calculating tax_withholding_net_total in payment entry (backport #42060)
2024-07-10 11:24:31 +05:30
ljain112
49e50662b6 fix: updated logic for calculating tax_withholding_net_total in payment entry
(cherry picked from commit c8a34cde7f)
2024-07-10 05:53:37 +00:00
ruthra kumar
f2f1f32826 Merge pull request #42163 from frappe/mergify/bp/version-14-hotfix/pr-42162
refactor: remove obsolete function call (backport #42162)
2024-07-10 10:28:37 +05:30
mergify[bot]
fcf6500144 fix(Holiday List): sort holidays on save to avoid disorienting the user (backport #42236) (#42251)
* fix(Holiday List): sort holidays on save to avoid disorienting the user (#42236)

fix: sort holidays on save to avoid disorienting the user
(cherry picked from commit ad137250fc)

# Conflicts:
#	erpnext/setup/doctype/holiday_list/holiday_list.py

* chore: fix conflicts

---------

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2024-07-09 18:44:08 +05:30
Raffael Meyer
f2d5a69af4 Merge pull request #42237 from frappe/mergify/bp/version-14-hotfix/pr-42235
fix: add missing german translations (backport #42235)
2024-07-08 19:53:18 +02:00
barredterra
d5c1c62622 fix: add missing german translations
(cherry picked from commit 2f89461ace)
2024-07-08 17:51:41 +00:00
mergify[bot]
e2f8e02c73 fix: stock qty validation in SCR (backport #42124) (#42224)
* fix: stock qty validation in SCR (#42124)

(cherry picked from commit 99f2735ad3)

# Conflicts:
#	erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-07-08 17:06:23 +05:30
Frappe PR Bot
30cba7ee2c chore(release): Bumped to Version 14.70.9
## [14.70.9](https://github.com/frappe/erpnext/compare/v14.70.8...v14.70.9) (2024-07-05)

### Bug Fixes

* blank item-wise sales/purchase register reports on first load ([0f275a9](0f275a9ff0))
* group by in item-wise purchase register ([1840267](18402677da))
2024-07-05 02:47:14 +00:00
ruthra kumar
21a60c9927 Merge pull request #42190 from frappe/mergify/bp/version-14/pr-41975
fix: group by in item-wise purchase register (backport #41975)
2024-07-05 08:15:53 +05:30
ruthra kumar
0f275a9ff0 fix: blank item-wise sales/purchase register reports on first load 2024-07-05 07:50:37 +05:30
Nihantra C. Patel
18402677da fix: group by in item-wise purchase register
(cherry picked from commit 3fab00135b)
2024-07-05 02:05:26 +00:00
ruthra kumar
e9357c193d Merge pull request #42184 from frappe/mergify/bp/version-14-hotfix/pr-42183
fix: empty item-wise sales/purchase register reports on initial load (backport #42183)
2024-07-04 15:10:30 +05:30
ruthra kumar
13895fa060 fix: empty item-wise sales/purchase register reports on initial load
(cherry picked from commit ee862126e4)
2024-07-04 09:36:58 +00:00
ruthra kumar
64f8498576 Merge pull request #42180 from frappe/mergify/bp/version-14-hotfix/pr-41975
fix: group by in item-wise purchase register (backport #41975)
2024-07-04 14:59:50 +05:30
Nihantra C. Patel
62ad466a3b fix: group by in item-wise purchase register
(cherry picked from commit 3fab00135b)
2024-07-04 09:09:07 +00:00
Khushi Rawat
45899b3017 Merge pull request #42174 from khushi8112/fetch-expence-account-from-asset-category
fix: fetch expense account from asset category
2024-07-04 13:14:39 +05:30
ruthra kumar
d92a042bf7 Merge pull request #42172 from frappe/mergify/bp/version-14-hotfix/pr-42143
refactor: validation to prevent recursion with mixed conditions (backport #42143)
2024-07-04 09:20:35 +05:30
Khushi Rawat
4d6a71ab4b fix: fetch expence account from asset category 2024-07-04 01:45:01 +05:30
ruthra kumar
d5fa968078 chore: resolve conflicts 2024-07-03 20:59:27 +05:30
ruthra kumar
71cbebd31b test: validation on mixed condition and recursion on pricing rule
(cherry picked from commit eb4af58bf0)

# Conflicts:
#	erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
2024-07-03 15:26:56 +00:00
ruthra kumar
99317768f6 test: validation on mixed condition with recursion
(cherry picked from commit 9bd4e7b709)

# Conflicts:
#	erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
2024-07-03 15:26:56 +00:00
ruthra kumar
9fde7330e0 fix: use standard method to get _doc_before_save
(cherry picked from commit 9d7be293ae)
2024-07-03 15:26:56 +00:00
ruthra kumar
49fb6bec6a refactor: validation to prevent recursion with mixed conditions
(cherry picked from commit 406dfd528f)
2024-07-03 15:26:55 +00:00
ruthra kumar
0f1f5b6f3d Merge pull request #42169 from frappe/mergify/bp/version-14-hotfix/pr-42165
fix: multiple free items on same Item Group (backport #42165)
2024-07-03 20:55:34 +05:30
mergify[bot]
454e147592 fix: manual pick allow to pick more than available stock (backport #42155) (#42158)
* fix: manual pick allow to pick more than available stock (#42155)

(cherry picked from commit 938dd4b2aa)

# Conflicts:
#	erpnext/stock/doctype/pick_list/test_pick_list.py

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-07-03 19:28:18 +05:30
ruthra kumar
701dd9e19b fix: multiple free items on same Item Group
(cherry picked from commit c4ae0d283f)
2024-07-03 12:28:35 +00:00
Markus Lobedann
2cf82561f6 refactor: remove obsolete function call (#42162)
(cherry picked from commit 4512432816)
2024-07-03 10:22:23 +00:00
Frappe PR Bot
f2d113dcf2 chore(release): Bumped to Version 14.70.8
## [14.70.8](https://github.com/frappe/erpnext/compare/v14.70.7...v14.70.8) (2024-07-03)

### Bug Fixes

* always post to tax account heads if LCV is booked ([650b25f](650b25fc23))
* asset value correction in fixed asset register ([#41943](https://github.com/frappe/erpnext/issues/41943)) ([a2ee463](a2ee4631cc))
* consistent query field name in item wise purchase register with item wise sales register ([9665212](9665212607))
* **Delivery Note:** only show permitted actions ([0aa246c](0aa246c39e))
* dynamic_link for party in customer and supplier dashboard ([6de7a8d](6de7a8de10))
* incorrect against_account upon reposting ([6028a19](6028a19e6b))
* Re-open allows SO's to be over credit limit ([952a7b4](952a7b46d5))
* **Sales Order:** only show permitted actions ([5468a3b](5468a3b0b7))
* timeout while cancelling LCV ([#42030](https://github.com/frappe/erpnext/issues/42030)) ([21bf7fd](21bf7fd1f8))
2024-07-03 05:02:59 +00:00
ruthra kumar
97e4495f1f Merge pull request #42141 from frappe/version-14-hotfix
chore: release v14
2024-07-03 10:31:45 +05:30
ruthra kumar
26c99351fd Merge pull request #42150 from frappe/mergify/bp/version-14-hotfix/pr-42073
fix: always post to tax account heads if LCV is booked (backport #42073)
2024-07-03 07:44:36 +05:30
ruthra kumar
4d99449aa8 chore: resolve conflict 2024-07-03 07:16:08 +05:30
ruthra kumar
72b93805fd refactor(test): fix flaky test
(cherry picked from commit 0e256b8b29)
2024-07-03 01:34:50 +00:00
ruthra kumar
f31ed75578 refactor(test): cleanup test data
(cherry picked from commit 6ba6b5aa33)
2024-07-03 01:34:50 +00:00
ruthra kumar
003d7e9f3e test: Repost should not merge expense accounts from LCV
(cherry picked from commit fa56555150)

# Conflicts:
#	erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
2024-07-03 01:34:49 +00:00
ruthra kumar
650b25fc23 fix: always post to tax account heads if LCV is booked
(cherry picked from commit 0fcd5d5130)
2024-07-03 01:34:49 +00:00
ruthra kumar
d5366c5873 Merge pull request #42131 from frappe/mergify/bp/version-14-hotfix/pr-42126
fix: Re-open allows SO's to be over credit limit (backport #42126)
2024-07-01 17:25:50 +05:30
ruthra kumar
bf36b4fa11 chore: resolve conflict 2024-07-01 17:05:56 +05:30
ruthra kumar
f4fc26b52e test: credit check on Sales Order re-open
(cherry picked from commit 60694e09c4)

# Conflicts:
#	erpnext/selling/doctype/sales_order/test_sales_order.py
2024-07-01 11:33:36 +00:00
ruthra kumar
952a7b46d5 fix: Re-open allows SO's to be over credit limit
(cherry picked from commit 5eed781263)
2024-07-01 11:33:35 +00:00
Smit Vora
cc9857affd Merge pull request #42064 from frappe/mergify/bp/version-14-hotfix/pr-41979
fix: dynamic_link for party in customer and supplier dashboard (backport #41979)
2024-06-28 13:04:35 +05:30
ljain112
6de7a8de10 fix: dynamic_link for party in customer and supplier dashboard
(cherry picked from commit c0a8800832)
2024-06-28 06:35:17 +00:00
Frappe PR Bot
b593f57637 chore: release v14 (#42023)
* fix(Sales Order): only show permitted actions

(cherry picked from commit c29d955371)

# Conflicts:
#	erpnext/selling/doctype/sales_order/sales_order.js

* fix(Delivery Note): only show permitted actions

(cherry picked from commit 418bdc1dcc)

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

* fix: consistent query field name in item wise purchase register with item wise sales register

* chore: resolve conflicts

* refactor: remove use of can_create for Payment Request (#41647)

(cherry picked from commit 47bc5691a1)

* fix: incorrect against_account upon reposting

(cherry picked from commit 20c4098399)

* fix: asset value correction in fixed asset register (#41943)

* fix: timeout while cancelling LCV (#42030)

fix: timeout while canelling LCV

---------

Co-authored-by: barredterra <14891507+barredterra@users.noreply.github.com>
Co-authored-by: ljain112 <ljain112@gmail.com>
Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
Co-authored-by: ruthra kumar <ruthra@erpnext.com>
Co-authored-by: Khushi Rawat <142375893+khushi8112@users.noreply.github.com>
2024-06-26 18:02:23 +05:30
rohitwaghchaure
21bf7fd1f8 fix: timeout while cancelling LCV (#42030)
fix: timeout while canelling LCV
2024-06-25 17:38:03 +05:30
Khushi Rawat
a2ee4631cc fix: asset value correction in fixed asset register (#41943) 2024-06-25 16:04:20 +05:30
ruthra kumar
92ca6c6538 Merge pull request #41983 from frappe/mergify/bp/version-14-hotfix/pr-41981
fix: incorrect against_account upon reposting (backport #41981)
2024-06-21 19:10:41 +05:30
ruthra kumar
6028a19e6b fix: incorrect against_account upon reposting
(cherry picked from commit 20c4098399)
2024-06-21 12:30:39 +00:00
Raffael Meyer
87dc586543 Merge pull request #41440 from frappe/mergify/bp/version-14-hotfix/pr-41384
fix(SO, DN): only show permitted actions (backport #41384)
2024-06-20 15:51:18 +02:00
barredterra
22216b275c refactor: remove use of can_create for Payment Request (#41647)
(cherry picked from commit 47bc5691a1)
2024-06-20 14:21:30 +02:00
barredterra
0e6edf763e chore: resolve conflicts 2024-06-20 14:15:26 +02:00
barredterra
e77534ba2b Merge remote-tracking branch 'upstream/version-14-hotfix' into mergify/bp/version-14-hotfix/pr-41384 2024-06-20 13:47:58 +02:00
rohitwaghchaure
ae14b86a8c Merge pull request #41954 from ljain112/fix-41927
fix: consistent query field name in item wise purchase register with …
2024-06-20 14:03:12 +05:30
ljain112
9665212607 fix: consistent query field name in item wise purchase register with item wise sales register 2024-06-20 11:11:43 +05:30
Frappe PR Bot
5ae9ec2657 chore(release): Bumped to Version 14.70.7
## [14.70.7](https://github.com/frappe/erpnext/compare/v14.70.6...v14.70.7) (2024-06-19)

### Bug Fixes

* add LCV flag to determine negative expenses ([20b8ee1](20b8ee1e90))
* allow Auditor to read a Fiscal Year ([b1a911a](b1a911aa9c))
* allow Auditor to select a company ([18b6d50](18b6d50a31))
* allow Employee role to select Department (backport [#41877](https://github.com/frappe/erpnext/issues/41877)) ([#41880](https://github.com/frappe/erpnext/issues/41880)) ([245c6d8](245c6d8672))
* migrate lead notes ([8f5278e](8f5278e3d4))
* only show user and date if available ([598c581](598c581623))
* parameters for PI references ([d484553](d48455393e))
* regional overide for updating item valution ([6441bc7](6441bc7862))
* reposting validation related PCV ([bcfc83d](bcfc83d8d5))
* reset perpetual inventory flag after test ([eae5f27](eae5f27ec8))
2024-06-19 06:25:45 +00:00
ruthra kumar
890289563a Merge pull request #41942 from frappe/version-14-hotfix
chore: release v14
2024-06-19 11:54:25 +05:30
Raffael Meyer
ee49e83020 Merge pull request #41944 from frappe/mergify/bp/version-14-hotfix/pr-41421
fix: migrate lead notes (backport #41421)
2024-06-19 01:17:48 +02:00
barredterra
598c581623 fix: only show user and date if available
(cherry picked from commit 895aede590)
2024-06-18 22:57:20 +00:00
barredterra
8f5278e3d4 fix: migrate lead notes
(cherry picked from commit 382d0ff453)
2024-06-18 22:57:19 +00:00
Raffael Meyer
aa38f69a67 Merge pull request #40543 from frappe/mergify/bp/version-14-hotfix/pr-40542 2024-06-18 12:51:55 +02:00
ruthra kumar
57a81c4012 Merge pull request #41937 from frappe/mergify/bp/version-14-hotfix/pr-41900
refactor: ignore unreconcile doc for PO and SO on cancel/delete (backport #41900)
2024-06-18 11:57:27 +05:30
ruthra kumar
2fabcb0c50 chore: resolve conflicts 2024-06-18 10:43:07 +05:30
ljain112
f833923f2f refactor: ignore unreconcile doc for PO and SO on cancel/delete
(cherry picked from commit b618d685c6)

# Conflicts:
#	erpnext/buying/doctype/purchase_order/purchase_order.js
#	erpnext/selling/doctype/sales_order/sales_order.js
2024-06-18 04:57:52 +00:00
rohitwaghchaure
077cb9e983 Merge pull request #41934 from frappe/mergify/bp/version-14-hotfix/pr-41931
fix: reposting validation related PCV (backport #41931)
2024-06-18 09:41:58 +05:30
Rohit Waghchaure
bcfc83d8d5 fix: reposting validation related PCV
(cherry picked from commit 194f1dc674)
2024-06-17 12:22:00 +00:00
ruthra kumar
a5d1feef02 Merge pull request #41912 from frappe/mergify/bp/version-14-hotfix/pr-40187
fix: valuation tax entries on LCV after billing PR (backport #40187)
2024-06-17 13:54:06 +05:30
ruthra kumar
b050110544 chore: resolve conflicts 2024-06-17 07:12:51 +05:30
Gursheen Anand
e8f5c45751 chore: resolve conflicts
(cherry picked from commit 54a58e9205)
2024-06-15 15:12:23 +00:00
Gursheen Anand
eae5f27ec8 fix: reset perpetual inventory flag after test
(cherry picked from commit 0b36cbe307)
2024-06-15 15:12:23 +00:00
Gursheen Anand
d48455393e fix: parameters for PI references
(cherry picked from commit 8b3d46610e)
2024-06-15 15:12:23 +00:00
Gursheen Anand
7c699c8a38 test: LCV entries after billing
(cherry picked from commit 53642e7417)

# Conflicts:
#	erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
2024-06-15 15:12:23 +00:00
Gursheen Anand
20b8ee1e90 fix: add LCV flag to determine negative expenses
(cherry picked from commit baa3fee1bf)

# Conflicts:
#	erpnext/controllers/stock_controller.py
2024-06-15 15:12:22 +00:00
Smit Vora
f9a7bb0544 Merge pull request #41889 from frappe/mergify/bp/version-14-hotfix/pr-41842
fix: regional overide for updating item valution (backport #41842)
2024-06-15 09:16:18 +05:30
ljain112
6441bc7862 fix: regional overide for updating item valution
(cherry picked from commit 1a10f0bcbd)
2024-06-13 08:09:01 +00:00
Raffael Meyer
a5df0f2c94 Merge pull request #41660 from frappe/mergify/bp/version-14-hotfix/pr-41659
fix: Auditor permissions (backport #41659)
2024-06-12 17:47:30 +02:00
mergify[bot]
e33416a4a7 Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-41659 2024-06-12 12:13:11 +00:00
mergify[bot]
245c6d8672 fix: allow Employee role to select Department (backport #41877) (#41880)
* fix: allow Employee role to select Department (#41877)

(cherry picked from commit 56082f5a29)

# Conflicts:
#	erpnext/setup/doctype/department/department.json

* chore: fix conflicts

---------

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2024-06-12 17:19:16 +05:30
Frappe PR Bot
32fba94b2a chore(release): Bumped to Version 14.70.6
## [14.70.6](https://github.com/frappe/erpnext/compare/v14.70.5...v14.70.6) (2024-06-11)

### Bug Fixes

* Add additional condition application ([e79e9e9](e79e9e94d0))
* fixing Item-wise sales register ([5d97c7c](5d97c7cff9))
* fixing Item-wise sales register [#41373](https://github.com/frappe/erpnext/issues/41373) ([ab90b81](ab90b815e3))
* fixing Item-wise sales register and purchase register [#41373](https://github.com/frappe/erpnext/issues/41373) ([ee47440](ee47440063))
* Item-wise Sales and Purchase register with no item codes [#41373](https://github.com/frappe/erpnext/issues/41373) ([bc24e75](bc24e75c24))
* terms and conditions for material request (backport [#41834](https://github.com/frappe/erpnext/issues/41834)) ([#41836](https://github.com/frappe/erpnext/issues/41836)) ([7234625](7234625d65))
2024-06-11 13:07:24 +00:00
rohitwaghchaure
a6ed10b712 Merge pull request #41853 from frappe/version-14-hotfix
chore: release v14
2024-06-11 18:36:07 +05:30
mergify[bot]
7234625d65 fix: terms and conditions for material request (backport #41834) (#41836)
fix: terms and conditions for material request (#41834)

(cherry picked from commit 4b026d66dc)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-06-10 15:17:06 +05:30
Frappe PR Bot
0c4a2af9ab chore(release): Bumped to Version 14.70.5
## [14.70.5](https://github.com/frappe/erpnext/compare/v14.70.4...v14.70.5) (2024-06-10)

### Bug Fixes

* Add additional condition application ([810378c](810378c899))
* fixing Item-wise sales register ([3823e0e](3823e0e494))
* fixing Item-wise sales register [#41373](https://github.com/frappe/erpnext/issues/41373) ([e8286d7](e8286d7b3c))
* fixing Item-wise sales register and purchase register [#41373](https://github.com/frappe/erpnext/issues/41373) ([fd73a8a](fd73a8a348))
* Item-wise Sales and Purchase register with no item codes [#41373](https://github.com/frappe/erpnext/issues/41373) ([91de469](91de46922d))
2024-06-10 04:55:25 +00:00
Deepesh Garg
5ba0082bc7 Merge pull request #41832 from frappe/mergify/bp/version-14/pr-41829
fix: Item-wise Sales and Purchase register with no item codes (#41424)
2024-06-10 10:24:04 +05:30
Deepesh Garg
47b3e96a37 chore: resolve conflicts
(cherry picked from commit e9b7d00afb)
2024-06-10 04:53:29 +00:00
Deepesh Garg
810378c899 fix: Add additional condition application
(cherry picked from commit 8ec364df6f)

# Conflicts:
#	erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
(cherry picked from commit e79e9e94d0)
2024-06-10 04:53:29 +00:00
Deepesh Garg
bdf198c94f chore: update condition queries in qb
(cherry picked from commit d2af36e1eb)

# Conflicts:
#	erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
#	erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
(cherry picked from commit e94e15259b)
2024-06-10 04:53:29 +00:00
Poorvi-R-Bhat
e8286d7b3c fix: fixing Item-wise sales register #41373
(cherry picked from commit eafa88b8e9)

# Conflicts:
#	erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
(cherry picked from commit ab90b815e3)
2024-06-10 04:53:29 +00:00
Poorvi-R-Bhat
fd73a8a348 fix: fixing Item-wise sales register and purchase register #41373
(cherry picked from commit 76073ae228)

# Conflicts:
#	erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
(cherry picked from commit ee47440063)
2024-06-10 04:53:29 +00:00
Poorvi-R-Bhat
91de46922d fix: Item-wise Sales and Purchase register with no item codes #41373
(cherry picked from commit 1b45ecfcae)

# Conflicts:
#	erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
#	erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
(cherry picked from commit bc24e75c24)
2024-06-10 04:53:29 +00:00
Poorvi
3823e0e494 fix: fixing Item-wise sales register
(cherry picked from commit c90185f533)
(cherry picked from commit 5d97c7cff9)
2024-06-10 04:53:28 +00:00
Deepesh Garg
625aa4ef6b Merge pull request #41829 from frappe/mergify/bp/version-14-hotfix/pr-41424
fix: Item-wise Sales and Purchase register with no item codes (#41424)
2024-06-09 22:38:15 +05:30
Deepesh Garg
e9b7d00afb chore: resolve conflicts 2024-06-09 22:17:30 +05:30
Deepesh Garg
e79e9e94d0 fix: Add additional condition application
(cherry picked from commit 8ec364df6f)

# Conflicts:
#	erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
2024-06-09 14:13:27 +00:00
Deepesh Garg
e94e15259b chore: update condition queries in qb
(cherry picked from commit d2af36e1eb)

# Conflicts:
#	erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
#	erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
2024-06-09 14:13:27 +00:00
Poorvi-R-Bhat
ab90b815e3 fix: fixing Item-wise sales register #41373
(cherry picked from commit eafa88b8e9)

# Conflicts:
#	erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
2024-06-09 14:13:25 +00:00
Poorvi-R-Bhat
ee47440063 fix: fixing Item-wise sales register and purchase register #41373
(cherry picked from commit 76073ae228)

# Conflicts:
#	erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
2024-06-09 14:13:24 +00:00
Poorvi-R-Bhat
bc24e75c24 fix: Item-wise Sales and Purchase register with no item codes #41373
(cherry picked from commit 1b45ecfcae)

# Conflicts:
#	erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
#	erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
2024-06-09 14:13:23 +00:00
Poorvi
5d97c7cff9 fix: fixing Item-wise sales register
(cherry picked from commit c90185f533)
2024-06-09 14:13:23 +00:00
ruthra kumar
e38383a757 Merge pull request #41806 from frappe/mergify/bp/version-14-hotfix/pr-41804
chore: repost settings permission overhaul (backport #41804)
2024-06-06 16:34:18 +05:30
ruthra kumar
a5bda0180e chore: repost settings permission overhaul
(cherry picked from commit 458d8f5ed8)
2024-06-06 16:13:55 +05:30
Frappe PR Bot
b6648eebfa chore(release): Bumped to Version 14.70.4
## [14.70.4](https://github.com/frappe/erpnext/compare/v14.70.3...v14.70.4) (2024-06-05)

### Bug Fixes

* Filters in account balance report ([570985f](570985f40e))
* get assets received but not billed account only if any asset item is received ([#41734](https://github.com/frappe/erpnext/issues/41734)) ([39885b2](39885b2b01))
* Ignore disabling default currency field while creating new company (backport [#41699](https://github.com/frappe/erpnext/issues/41699)) ([#41760](https://github.com/frappe/erpnext/issues/41760)) ([5ab5bd1](5ab5bd138f))
* payment term when creating PO from SO (backport [#41376](https://github.com/frappe/erpnext/issues/41376)) ([#41743](https://github.com/frappe/erpnext/issues/41743)) ([dc32657](dc3265751c))
2024-06-05 01:17:52 +00:00
ruthra kumar
faa3c7c3a4 Merge pull request #41774 from frappe/version-14-hotfix
chore: release v14
2024-06-05 06:46:34 +05:30
mergify[bot]
5ab5bd138f fix: Ignore disabling default currency field while creating new company (backport #41699) (#41760)
fix: Ignore disabling default currency field while creating new company (#41699)

(cherry picked from commit 80f6228d45)

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
2024-06-04 11:55:42 +05:30
mergify[bot]
dc3265751c fix: payment term when creating PO from SO (backport #41376) (#41743)
fix: payment term when creating PO from SO (#41376)

* fix: payment term when creating PO from SO

* fix: payment term when creating PO from SO

* fix: payment term when creating PO from SO

* fix: payment term when creating PO from SO

(cherry picked from commit 441596f795)

Co-authored-by: Nihantra C. Patel <141945075+Nihantra-Patel@users.noreply.github.com>
2024-06-03 18:37:26 +05:30
ruthra kumar
cf8f0e4096 Merge pull request #41745 from frappe/mergify/bp/version-14-hotfix/pr-41742
chore: System Manager should have  submit permission for repost doctypes (backport #41742)
2024-06-03 18:33:55 +05:30
ruthra kumar
8c09968e1b chore: Sys Manager shluld have submit permission for repost doctypes
(cherry picked from commit 4558f64c0f)
2024-06-03 12:20:56 +00:00
Nabin Hait
39885b2b01 fix: get assets received but not billed account only if any asset item is received (#41734)
fix: get assets received but not billed account only if any asset item received
2024-06-03 14:05:57 +05:30
Deepesh Garg
6a6a6971ba Merge pull request #41679 from frappe/mergify/bp/version-14-hotfix/pr-41676
fix: Filters in account balance report (#41676)
2024-05-31 20:02:35 +05:30
Frappe PR Bot
13dfbe3d80 chore(release): Bumped to Version 14.70.3
## [14.70.3](https://github.com/frappe/erpnext/compare/v14.70.2...v14.70.3) (2024-05-29)

### Bug Fixes

* add in some indices to speed up Purchase Order deletion ([c16c41e](c16c41ee59))
* Add to Cart button width for Mobile/Tablet ([819ced4](819ced4cb3))
* cost center filter according to the company in project ([7035969](7035969db7))
* cost center filter according to the company in project ([0cf97f2](0cf97f2559))
* cost center filter according to the company in project ([459d136](459d136368))
* dict can not be used as parameter ([#41598](https://github.com/frappe/erpnext/issues/41598)) ([649c192](649c192abe))
* Fetch outstanding and total amount for reference journal entry ([50f6afd](50f6afd588))
* set expense account as Assets RBNB only if it is booked in linked PR ([#41368](https://github.com/frappe/erpnext/issues/41368)) ([014486d](014486de39))
* Update depreciation schedule via asset repair ([#41344](https://github.com/frappe/erpnext/issues/41344)) ([eb418e8](eb418e8659))
2024-05-29 07:52:36 +00:00
ruthra kumar
7e3c15e0b6 Merge pull request #41665 from frappe/version-14-hotfix
chore: release v14
2024-05-29 13:21:18 +05:30
Deepesh Garg
570985f40e fix: Filters in account balance report
(cherry picked from commit 1c9fe691ea)
2024-05-29 07:20:48 +00:00
Nabin Hait
eb418e8659 fix: Update depreciation schedule via asset repair (#41344)
* fix: Update depreciation schedule via asset repair

* fix: test cases related to modified depreciation schedule
2024-05-29 11:07:03 +05:30
Nabin Hait
014486de39 fix: set expense account as Assets RBNB only if it is booked in linked PR (#41368)
* fix: set expense account as Assets RBNB only if it is booked in linked PR

* fix: broken translations
2024-05-29 10:46:06 +05:30
barredterra
a53a80f01d chore: resolve conflicts 2024-05-27 18:54:17 +02:00
barredterra
b1a911aa9c fix: allow Auditor to read a Fiscal Year
(cherry picked from commit eaa4efbc45)

# Conflicts:
#	erpnext/accounts/doctype/fiscal_year/fiscal_year.json
2024-05-27 16:50:26 +00:00
barredterra
18b6d50a31 fix: allow Auditor to select a company
(cherry picked from commit 06401cc84f)

# Conflicts:
#	erpnext/setup/doctype/company/company.json
2024-05-27 16:50:26 +00:00
Akhil Narang
fcb2f4f084 Merge pull request #41624 from frappe/mergify/bp/version-14-hotfix/pr-41601
fix: add in some indices to speed up Purchase Order deletion (backport #41601)
2024-05-27 13:31:51 +05:30
Akhil Narang
308f200793 Merge pull request #41610 from frappe/mergify/bp/version-14-hotfix/pr-41609
refactor: use `json` directly instead of using `frappe.json` (backport #41609)
2024-05-27 13:31:29 +05:30
Akhil Narang
4fcfbe6e9f Merge pull request #41597 from frappe/mergify/bp/version-14-hotfix/pr-41576
chore: sync ruff config with framework (backport #41576)
2024-05-27 13:31:22 +05:30
Akhil Narang
5b2c13dacf refactor: use json directly instead of using frappe.json (#41609)
(cherry picked from commit 3f06f1905f)
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-05-27 07:26:24 +00:00
Ankush Menat
76b7884fb7 ci: ruff only fix imports
(cherry picked from commit 85b1a8001b)
2024-05-27 07:26:14 +00:00
Ankush Menat
518dad8ecb ci: dont auto apply fixes
I've personally encountered ~5 instances of bad auto fixes, let
developers apply the fixes.

(cherry picked from commit 3b4913ec81)
2024-05-27 07:26:14 +00:00
Akhil Narang
220ae118e8 chore: resolve conflicts 2024-05-27 07:25:29 +00:00
Akhil Narang
f1f2f6e338 chore: resolve conflicts 2024-05-27 07:25:29 +00:00
Akhil Narang
c16c41ee59 fix: add in some indices to speed up Purchase Order deletion
`tabSales Order`.`inter_company_order_reference`
`tabSales Invoice Item`.`purchase_order`

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

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
#	erpnext/selling/doctype/sales_order/sales_order.json
2024-05-27 07:25:29 +00:00
ruthra kumar
dcffb3886b Merge pull request #41648 from frappe/mergify/bp/version-14-hotfix/pr-41401
fix: cost center filter according to the company in project (backport #41401)
2024-05-27 10:41:59 +05:30
Nihantra C. Patel
7035969db7 fix: cost center filter according to the company in project
(cherry picked from commit 501c6aa126)
2024-05-27 04:41:12 +00:00
Nihantra C. Patel
0cf97f2559 fix: cost center filter according to the company in project
(cherry picked from commit cfde8088b4)
2024-05-27 04:41:12 +00:00
Nihantra C. Patel
459d136368 fix: cost center filter according to the company in project
(cherry picked from commit 249e8264dd)
2024-05-27 04:41:11 +00:00
ruthra kumar
a2bfe31876 Merge pull request #40289 from Nihantra-Patel/fix_button_size_for_add_to_cart
fix: Add to Cart button width for Mobile/Tablet
2024-05-24 10:57:15 +05:30
ruthra kumar
75b021dc23 Merge pull request #41604 from frappe/mergify/bp/version-14-hotfix/pr-41603
refactor: remove 'format:' based naming in internal doctypes (backport #41603)
2024-05-24 10:54:45 +05:30
ruthra kumar
b2e2e951da Merge pull request #41606 from frappe/mergify/bp/version-14-hotfix/pr-41594
refactor: 'Payment Period Based On Invoice Date' report (backport #41594)
2024-05-24 10:54:07 +05:30
ruthra kumar
0f9b5074a6 chore: resolve conflicts 2024-05-23 17:47:47 +05:30
ruthra kumar
190900cd1b refactor: replace against_voucher with against_voucher_no
(cherry picked from commit c4e2abb973)
2024-05-23 12:16:41 +00:00
ruthra kumar
3512f7d528 refactor: remove debit and credit
(cherry picked from commit 014b542cf3)
2024-05-23 12:16:40 +00:00
ruthra kumar
0dc2f78a2e refactor: query payment ledger for payments
(cherry picked from commit cb3c20dcd3)
2024-05-23 12:16:40 +00:00
ruthra kumar
c834a9de85 refactor: remove 'format:' based naming in internal doctypes
(cherry picked from commit e2ec3e453a)

# Conflicts:
#	erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json
#	erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json
2024-05-23 12:15:21 +00:00
Frappe PR Bot
c910b8ab03 chore(release): Bumped to Version 14.70.2
## [14.70.2](https://github.com/frappe/erpnext/compare/v14.70.1...v14.70.2) (2024-05-23)

### Bug Fixes

* Fetch outstanding and total amount for reference journal entry ([94c3ee6](94c3ee645d))
2024-05-23 11:01:54 +00:00
ruthra kumar
b9ebb50a02 Merge pull request #41600 from frappe/mergify/bp/version-14/pr-40957
fix: Fetch correct outstanding and total amount for reference journal entry (backport #40920) (backport #40957)
2024-05-23 16:30:31 +05:30
ruthra kumar
38cc28a4c3 chore: resolve conflicts
(cherry picked from commit 5230d411bf)
2024-05-23 10:39:16 +00:00
ruthra kumar
bbb9b9e3b6 chore: remove unused imports
(cherry picked from commit a6bf7c1ebd)
2024-05-23 10:39:15 +00:00
Nabin Hait
94c3ee645d fix: Fetch outstanding and total amount for reference journal entry
(cherry picked from commit f331f9b15c)

# Conflicts:
#	erpnext/accounts/doctype/payment_entry/payment_entry.js
#	erpnext/accounts/doctype/payment_entry/payment_entry.py
(cherry picked from commit 50f6afd588)
2024-05-23 10:39:15 +00:00
ruthra kumar
4d8c35aa5d Merge pull request #40957 from frappe/mergify/bp/version-14-hotfix/pr-40920
fix: Fetch correct outstanding and total amount for reference journal entry (backport #40920)
2024-05-23 16:08:14 +05:30
ruthra kumar
5230d411bf chore: resolve conflicts 2024-05-23 15:42:34 +05:30
ruthra kumar
a6bf7c1ebd chore: remove unused imports 2024-05-23 15:42:34 +05:30
Nabin Hait
50f6afd588 fix: Fetch outstanding and total amount for reference journal entry
(cherry picked from commit f331f9b15c)

# Conflicts:
#	erpnext/accounts/doctype/payment_entry/payment_entry.js
#	erpnext/accounts/doctype/payment_entry/payment_entry.py
2024-05-23 15:42:34 +05:30
rohitwaghchaure
649c192abe fix: dict can not be used as parameter (#41598) 2024-05-23 15:37:00 +05:30
Frappe PR Bot
b7d6a54bed chore(release): Bumped to Version 14.70.1
## [14.70.1](https://github.com/frappe/erpnext/compare/v14.70.0...v14.70.1) (2024-05-22)

### Bug Fixes

* minor Dr and Cr between Purchase Receipt and Purchase Invoice ([82d206b](82d206b709))
* possible sql error on General Ledger ([dfb4c47](dfb4c47089))
* print format bold for field "total" ([89d507e](89d507e07e))
* priority not working for multiple pricing rules (backport [#41516](https://github.com/frappe/erpnext/issues/41516)) ([#41524](https://github.com/frappe/erpnext/issues/41524)) ([97fdda8](97fdda8a7c))
* typerror on hide_fields ([331a743](331a743d69))
* validate reorder group warehouse (backport [#41478](https://github.com/frappe/erpnext/issues/41478)) ([#41479](https://github.com/frappe/erpnext/issues/41479)) ([2659535](26595351cc))
2024-05-22 08:46:30 +00:00
ruthra kumar
05e4dae1b8 Merge pull request #41575 from frappe/version-14-hotfix
chore: release v14
2024-05-22 14:15:11 +05:30
mergify[bot]
97fdda8a7c fix: priority not working for multiple pricing rules (backport #41516) (#41524)
* fix: priority not working for multiple pricing rules (#41516)

(cherry picked from commit 5cf5b18aea)

# Conflicts:
#	erpnext/accounts/doctype/pricing_rule/pricing_rule.json
#	erpnext/accounts/doctype/pricing_rule/pricing_rule.py
#	erpnext/patches.txt

* chore: fix conflicts

* chore: fix conflicts

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-05-20 13:39:39 +05:30
ruthra kumar
9802333397 Merge pull request #41527 from frappe/mergify/bp/version-14-hotfix/pr-41523
fix: minor Dr and Cr between Purchase Receipt and Purchase Invoice (backport #41523)
2024-05-20 08:32:24 +05:30
ruthra kumar
82d206b709 fix: minor Dr and Cr between Purchase Receipt and Purchase Invoice
This applies for Provisional Accounting for Non-stock items

(cherry picked from commit 1c0a24424a)
2024-05-17 12:21:28 +00:00
ruthra kumar
80810c2ebb Merge pull request #41518 from frappe/mergify/bp/version-14-hotfix/pr-41517
fix: typerror on hide_fields (backport #41517)
2024-05-17 14:54:06 +05:30
ruthra kumar
331a743d69 fix: typerror on hide_fields
(cherry picked from commit deb9766f2a)
2024-05-17 14:51:57 +05:30
ruthra kumar
32a1fea8f0 Merge pull request #41512 from frappe/mergify/bp/version-14-hotfix/pr-41511
fix: possible sql error on General Ledger (backport #41511)
2024-05-17 11:17:24 +05:30
ruthra kumar
dfb4c47089 fix: possible sql error on General Ledger
(cherry picked from commit 76131f8e10)
2024-05-17 05:26:54 +00:00
mergify[bot]
0cbf049608 chore(BOM Explorer): display items in the same order as in the BOM (backport #41496) (#41510)
chore(BOM Explorer): display items in the same order as in the BOM (#41496)

(cherry picked from commit bd381cc0c6)

Co-authored-by: Samuel Danieli <23150094+scdanieli@users.noreply.github.com>
2024-05-17 09:37:03 +05:30
ruthra kumar
3f0cb47464 Merge pull request #41500 from frappe/mergify/bp/version-14-hotfix/pr-40072
fix: print format bold for field "total" (backport #40072)
2024-05-16 15:35:48 +05:30
Nihantra C. Patel
89d507e07e fix: print format bold for field "total"
(cherry picked from commit 3c9640df27)
2024-05-16 10:04:03 +00:00
mergify[bot]
26595351cc fix: validate reorder group warehouse (backport #41478) (#41479)
fix: validate reorder group warehouse (#41478)

(cherry picked from commit 0363afcfd0)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-05-15 15:15:41 +05:30
Frappe PR Bot
dfaca93292 chore(release): Bumped to Version 14.70.0
# [14.70.0](https://github.com/frappe/erpnext/compare/v14.69.1...v14.70.0) (2024-05-15)

### Bug Fixes

* "Based on" field always has the value "Not applicable" ([1078a98](1078a98cce))
* address filter and quotation to for prospect ([c9e7f45](c9e7f450c5))
* address filter and quotation to for prospect ([6902780](690278042d))
* address filter and quotation to for prospect ([754e193](754e193c76))
* consistent use of "Address & Contact" (backport [#41386](https://github.com/frappe/erpnext/issues/41386)) ([#41387](https://github.com/frappe/erpnext/issues/41387)) ([256d6a4](256d6a47ac))
* data getting override in delivery trip (backport [#41431](https://github.com/frappe/erpnext/issues/41431)) ([#41432](https://github.com/frappe/erpnext/issues/41432)) ([5366356](5366356400))
* Default dates in report ([c3244f0](c3244f009b))
* default fiscal year ([7a380f5](7a380f584d))
* Duplicate party name column in AR/AP report ([a8be5f0](a8be5f0789))
* PSOA ageing ([e69e540](e69e5404d3))

### Features

* allow to pick manually qty / batches / serial nos (backport [#40723](https://github.com/frappe/erpnext/issues/40723)) ([#41435](https://github.com/frappe/erpnext/issues/41435)) ([7b28d7d](7b28d7d2b8))
2024-05-15 05:12:14 +00:00
Deepesh Garg
40de3f3481 Merge pull request #41458 from frappe/version-14-hotfix
chore: release v14
2024-05-15 10:40:58 +05:30
Deepesh Garg
fc2614612b Merge pull request #41466 from frappe/mergify/bp/version-14-hotfix/pr-41258
fix: PSOA ageing (#41258)
2024-05-14 21:19:17 +05:30
Deepesh Garg
e69e5404d3 fix: PSOA ageing
(cherry picked from commit fed2d11905)
2024-05-14 14:40:36 +00:00
Nabin Hait
14ec6351ae Merge pull request #41448 from frappe/mergify/bp/version-14-hotfix/pr-41412
fix: Duplicate party name column in AR/AP report (backport #41412)
2024-05-14 20:02:56 +05:30
Deepesh Garg
a8be5f0789 fix: Duplicate party name column in AR/AP report
(cherry picked from commit 7501fe8ebd)
2024-05-14 02:53:49 +00:00
Deepesh Garg
42312c5bba Merge pull request #41170 from deepeshgarg007/default_dates_in_reports
fix: Default dates in report
2024-05-14 08:21:51 +05:30
mergify[bot]
7b28d7d2b8 feat: allow to pick manually qty / batches / serial nos (backport #40723) (#41435)
* feat: allow to pick manually qty / batches / serial nos

(cherry picked from commit 50dd9fa8a3)

# Conflicts:
#	erpnext/stock/doctype/pick_list/pick_list.json
#	erpnext/stock/doctype/pick_list/pick_list.py

* chore: fix conflicts

* chore: fix conflicts

---------

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
2024-05-13 21:37:13 +05:30
barredterra
0aa246c39e fix(Delivery Note): only show permitted actions
(cherry picked from commit 418bdc1dcc)

# Conflicts:
#	erpnext/stock/doctype/delivery_note/delivery_note.js
2024-05-13 13:43:07 +00:00
barredterra
5468a3b0b7 fix(Sales Order): only show permitted actions
(cherry picked from commit c29d955371)

# Conflicts:
#	erpnext/selling/doctype/sales_order/sales_order.js
2024-05-13 13:43:07 +00:00
mergify[bot]
5366356400 fix: data getting override in delivery trip (backport #41431) (#41432)
fix: data getting override in delivery trip (#41431)

fix: data getting override
(cherry picked from commit 663fcb374d)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-05-13 16:31:34 +05:30
Deepesh Garg
7a380f584d fix: default fiscal year 2024-05-11 17:51:53 +05:30
mergify[bot]
256d6a47ac fix: consistent use of "Address & Contact" (backport #41386) (#41387)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix: consistent use of "Address & Contact" (#41386)
2024-05-10 17:42:27 +02:00
Akhil Narang
67e06615a3 Merge pull request #41406 from frappe/mergify/bp/version-14-hotfix/pr-37031
fix: "Based on" field always has the value "Not applicable" (backport #37031)
2024-05-10 16:44:33 +05:30
HarryPaulo
1078a98cce fix: "Based on" field always has the value "Not applicable"
(cherry picked from commit fae640c56f)
2024-05-10 11:13:03 +00:00
ruthra kumar
d87ffae03f Merge pull request #41394 from frappe/mergify/bp/version-14-hotfix/pr-41040
fix: address filter and quotation to for prospect (backport #41040)
2024-05-09 12:48:48 +05:30
ruthra kumar
0404941fb2 chore: resolve conflict 2024-05-09 12:21:29 +05:30
ruthra kumar
c4dfcbec96 refactor: make use of doc.quotation_to
(cherry picked from commit 754c7f6d1c)

# Conflicts:
#	erpnext/selling/doctype/quotation/quotation.js
2024-05-09 06:45:53 +00:00
Nihantra Patel
c9e7f450c5 fix: address filter and quotation to for prospect
(cherry picked from commit 2896e3666c)
2024-05-09 06:45:53 +00:00
Nihantra Patel
690278042d fix: address filter and quotation to for prospect
(cherry picked from commit 24a68a79df)
2024-05-09 06:45:52 +00:00
Nihantra Patel
754e193c76 fix: address filter and quotation to for prospect
(cherry picked from commit fe5b88522e)

# Conflicts:
#	erpnext/selling/doctype/quotation/quotation.js
2024-05-09 06:45:52 +00:00
Frappe PR Bot
9d5e4b3b3a chore(release): Bumped to Version 14.69.1
## [14.69.1](https://github.com/frappe/erpnext/compare/v14.69.0...v14.69.1) (2024-05-09)

### Bug Fixes

* added brand column in Warehouse wise Item Balance Age and Value … (backport [#41280](https://github.com/frappe/erpnext/issues/41280)) ([#41281](https://github.com/frappe/erpnext/issues/41281)) ([d727c52](d727c52421))
* Cost center not getting saved in PSOA ([e82ea12](e82ea12cbc))
* filter validation for batch-wise balance history report (backport [#41356](https://github.com/frappe/erpnext/issues/41356)) ([#41360](https://github.com/frappe/erpnext/issues/41360)) ([339256b](339256bc71))
* incorrect query for Purchase Invoice rate in GP ([93b30d9](93b30d9f11))
* missing Item Name on Save for Quotation created from Item (backport [#41233](https://github.com/frappe/erpnext/issues/41233)) ([#41303](https://github.com/frappe/erpnext/issues/41303)) ([a26ae64](a26ae64385))
* pricing rule rounding ([d2ce927](d2ce927891))
* reset rate for serial batch supplied items ([#41293](https://github.com/frappe/erpnext/issues/41293)) ([cd33199](cd33199da2))

### Performance Improvements

* index on item code for the Pick List Item doctype (backport [#41357](https://github.com/frappe/erpnext/issues/41357)) ([#41362](https://github.com/frappe/erpnext/issues/41362)) ([4647ec8](4647ec8892))
2024-05-09 05:30:06 +00:00
ruthra kumar
d7709cf4e4 Merge pull request #41354 from frappe/version-14-hotfix
chore: release v14
2024-05-09 10:58:39 +05:30
mergify[bot]
4647ec8892 perf: index on item code for the Pick List Item doctype (backport #41357) (#41362)
* perf: index on item code for the Pick List Item doctype (#41357)

(cherry picked from commit 0887161f2a)

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

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-05-08 11:38:02 +05:30
mergify[bot]
339256bc71 fix: filter validation for batch-wise balance history report (backport #41356) (#41360)
fix: filter validation for batch-wise balance history report (#41356)

fix: filter validation for batchwise balance history report
(cherry picked from commit 544fc60093)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-05-08 00:15:33 +05:30
ruthra kumar
c3d567b291 Merge pull request #41348 from frappe/mergify/bp/version-14-hotfix/pr-41288
fix: pricing rule rounding (backport #41288)
2024-05-07 10:32:20 +05:30
ruthra kumar
e068bec212 refactor(test): test floor based rounding
(cherry picked from commit c41a037174)
2024-05-07 04:32:04 +00:00
ruthra kumar
d2ce927891 fix: pricing rule rounding
Consider a pricing rule of 20:1 with recursion enabled, free items
should follow the below progression

|   Qty | Free item qty |
|-------+---------------|
|  0-19 |             0 |
| 20-39 |             1 |
| 40-59 |             2 |

(cherry picked from commit 9bf37426c1)
2024-05-07 04:32:03 +00:00
mergify[bot]
a26ae64385 fix: missing Item Name on Save for Quotation created from Item (backport #41233) (#41303)
fix: missing Item Name on Save for Quotation created from Item (#41233)

* fix: missing Item Name on Save for Quotation created from Item

* fix: missing Item Name on Save for Quotation created from Item

(cherry picked from commit c8e92cb1b2)

Co-authored-by: HENRY Florian <florian.henry@open-concept.pro>
2024-05-06 21:46:18 +05:30
s-aga-r
cd33199da2 fix: reset rate for serial batch supplied items (#41293) 2024-05-06 21:37:27 +05:30
ruthra kumar
27100401aa Merge pull request #41336 from frappe/mergify/bp/version-14-hotfix/pr-41334
fix: incorrect query for Purchase Invoice rate in GP (backport #41334)
2024-05-06 13:17:58 +05:30
ruthra kumar
93b30d9f11 fix: incorrect query for Purchase Invoice rate in GP
(cherry picked from commit bd8382c592)
2024-05-06 07:24:49 +00:00
Deepesh Garg
904f369e99 Merge pull request #41324 from frappe/mergify/bp/version-14-hotfix/pr-41318
fix: Cost center not getting saved in PSOA (#41318)
2024-05-06 12:25:14 +05:30
Deepesh Garg
7b9c22775c chore: resolve conflicts 2024-05-06 11:52:26 +05:30
Deepesh Garg
6aa8d5fb4b chore: resolve conflicts 2024-05-06 11:29:53 +05:30
Deepesh Garg
e82ea12cbc fix: Cost center not getting saved in PSOA
(cherry picked from commit 58f7039630)

# Conflicts:
#	erpnext/accounts/doctype/psoa_cost_center/psoa_cost_center.json
#	erpnext/accounts/doctype/psoa_cost_center/psoa_cost_center.py
2024-05-04 08:26:55 +00:00
mergify[bot]
d727c52421 fix: added brand column in Warehouse wise Item Balance Age and Value … (backport #41280) (#41281)
fix: added brand column in Warehouse wise Item Balance Age and Value … (#41280)

fix: added brand coulmn in Warehouse wise Item Balance Age and Value report
(cherry picked from commit 1cbc200770)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-05-03 17:53:52 +05:30
Frappe PR Bot
5ae29655f9 chore(release): Bumped to Version 14.69.0
# [14.69.0](https://github.com/frappe/erpnext/compare/v14.68.2...v14.69.0) (2024-05-02)

### Bug Fixes

* 'NoneType' object has no attribute '_read_rowdata_packet_unbuffered' ([949aa93](949aa9346c))
* args when get the delivery note in delivery trip ([abe64aa](abe64aa1ab))
* args when get the delivery note in delivery trip ([1a7b3c4](1a7b3c437d))
* display term name for single term invoices ([58b68b7](58b68b7597))
* duplicate column in the stock ledger report ([3fcdcef](3fcdcef178))
* handle stock balance unbuffered_cursor error (backport [#41186](https://github.com/frappe/erpnext/issues/41186)) ([#41187](https://github.com/frappe/erpnext/issues/41187)) ([59010c9](59010c9a61))
* incorrectly applying TDS when Advance is in previous FY ([eb22fb9](eb22fb9326))
* mode of payment has precedance ([33d38ba](33d38ba3a7))
* multiple pricing rules with discount amount and discount percentage not working ([#41211](https://github.com/frappe/erpnext/issues/41211)) ([54313b5](54313b5db9))
* negative stock qty error for stock reconciliation ([#41283](https://github.com/frappe/erpnext/issues/41283)) ([9aa054c](9aa054c400))
* permission issue when user permission restricts on company ([45c4167](45c4167c86))
* validation to prevent overallocation ([8318286](8318286865))

### Features

* allow to do reposting for all stock transactions (audit) (backport [#41165](https://github.com/frappe/erpnext/issues/41165)) ([#41205](https://github.com/frappe/erpnext/issues/41205)) ([1e13193](1e1319351d))

### Performance Improvements

* timeout issue while submitting purchase receipt (v14) ([113351e](113351e850))
2024-05-02 04:31:43 +00:00
ruthra kumar
81a99309d8 Merge pull request #41264 from frappe/version-14-hotfix
chore: release v14
2024-05-02 09:59:30 +05:30
rohitwaghchaure
9aa054c400 fix: negative stock qty error for stock reconciliation (#41283)
fix: negative stock qty error for stock reco
2024-05-02 09:38:33 +05:30
ruthra kumar
82b2675aa8 Merge pull request #41269 from frappe/mergify/bp/version-14-hotfix/pr-41268
fix: validation to prevent overallocation (backport #41268)
2024-04-30 18:40:47 +05:30
ruthra kumar
8318286865 fix: validation to prevent overallocation
(cherry picked from commit bf755fab55)
2024-04-30 17:48:55 +05:30
ruthra kumar
f87411f40d Merge pull request #41254 from frappe/mergify/bp/version-14-hotfix/pr-41252
fix: permission issue when user permission restricts on company (backport #41252)
2024-04-30 14:19:39 +05:30
ruthra kumar
45c4167c86 fix: permission issue when user permission restricts on company 2024-04-30 12:24:32 +05:30
ruthra kumar
e0d1f2f6eb Merge pull request #41248 from frappe/mergify/bp/version-14-hotfix/pr-41240
fix: display term name for single term invoices in AR/AP (backport #41240)
2024-04-30 07:42:33 +05:30
ruthra kumar
ba45ea42f8 Merge pull request #41246 from frappe/mergify/bp/version-14-hotfix/pr-41194
fix: TDS incorrectly applied when Advance is in previous FY (backport #41194)
2024-04-30 07:42:23 +05:30
ruthra kumar
58b68b7597 fix: display term name for single term invoices
(cherry picked from commit 5fa4cfee04)
2024-04-30 01:40:17 +00:00
ruthra kumar
4d56c46446 test: TDS deduction across fiscal year
(cherry picked from commit 2f9a144023)
2024-04-30 07:04:21 +05:30
ruthra kumar
eb22fb9326 fix: incorrectly applying TDS when Advance is in previous FY
(cherry picked from commit b195f519e2)
2024-04-30 01:27:56 +00:00
rohitwaghchaure
54313b5db9 fix: multiple pricing rules with discount amount and discount percentage not working (#41211) 2024-04-29 20:53:10 +05:30
mergify[bot]
866b0c6ac7 chore: delete invalid translations (backport #41227) (#41228)
chore: delete invalid translations (#41227)

(cherry picked from commit 067419b7cd)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2024-04-29 10:41:54 +05:30
mergify[bot]
1e1319351d feat: allow to do reposting for all stock transactions (audit) (backport #41165) (#41205)
* feat: allow to do reposting for all transactions (audit)

(cherry picked from commit aefbe21b46)

# Conflicts:
#	erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json
#	erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.py

* chore: fix conflicts

* chore: fix conflicts

---------

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
2024-04-26 14:25:51 +05:30
rohitwaghchaure
6b2874694e Merge pull request #41204 from rohitwaghchaure/fixed-unbuffered_cursor
fix: 'NoneType' object has no attribute '_read_rowdata_packet_unbuffe…
2024-04-26 13:50:07 +05:30
rohitwaghchaure
ff37706bef Merge pull request #41200 from frappe/mergify/bp/version-14-hotfix/pr-41185
fix: args when get the delivery note in delivery trip (backport #41185)
2024-04-26 13:36:14 +05:30
Rohit Waghchaure
949aa9346c fix: 'NoneType' object has no attribute '_read_rowdata_packet_unbuffered' 2024-04-26 13:25:46 +05:30
rohitwaghchaure
2f6fee9877 chore: fix conflicts 2024-04-26 13:15:32 +05:30
Nihantra Patel
abe64aa1ab fix: args when get the delivery note in delivery trip
(cherry picked from commit ca577f7aaa)
2024-04-26 07:40:32 +00:00
Nihantra Patel
1a7b3c437d fix: args when get the delivery note in delivery trip
(cherry picked from commit 2f359e201d)

# Conflicts:
#	erpnext/stock/doctype/delivery_note/delivery_note.py
2024-04-26 07:40:31 +00:00
rohitwaghchaure
da69b1e71b Merge pull request #41196 from frappe/mergify/bp/version-14-hotfix/pr-41192
fix: duplicate column in the stock ledger report (backport #41192)
2024-04-26 12:49:35 +05:30
Frappe PR Bot
d160f5b61a chore(release): Bumped to Version 14.68.2
## [14.68.2](https://github.com/frappe/erpnext/compare/v14.68.1...v14.68.2) (2024-04-26)

### Performance Improvements

* timeout issue while submitting purchase receipt (v14) ([c93840e](c93840eb56))
2024-04-26 06:53:19 +00:00
Rohit Waghchaure
3fcdcef178 fix: duplicate column in the stock ledger report
(cherry picked from commit be7fd6bfb4)
2024-04-26 06:53:08 +00:00
rohitwaghchaure
40ece3f5da Merge pull request #41193 from frappe/mergify/bp/version-14/pr-41174
perf: timeout issue while submitting purchase receipt (v14) (backport #41174)
2024-04-26 12:21:59 +05:30
Rohit Waghchaure
c93840eb56 perf: timeout issue while submitting purchase receipt (v14)
(cherry picked from commit 113351e850)
2024-04-26 05:27:47 +00:00
rohitwaghchaure
7656fe4bfc Merge pull request #41174 from rohitwaghchaure/fixed-performance-issue-for-serial-no-creation
perf: timeout issue while submitting purchase receipt (v14)
2024-04-26 10:56:28 +05:30
mergify[bot]
59010c9a61 fix: handle stock balance unbuffered_cursor error (backport #41186) (#41187)
fix: handle stock balance unbuffered_cursor error (#41186)

(cherry picked from commit 341fb6d8f3)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2024-04-25 17:26:29 +05:30
Rohit Waghchaure
113351e850 perf: timeout issue while submitting purchase receipt (v14) 2024-04-25 12:10:29 +05:30
Frappe PR Bot
2026c986ba chore(release): Bumped to Version 14.68.1
## [14.68.1](https://github.com/frappe/erpnext/compare/v14.68.0...v14.68.1) (2024-04-25)

### Bug Fixes

* mode of payment has precedance ([7e52f72](7e52f72bed))
2024-04-25 03:43:28 +00:00
ruthra kumar
91c202f172 Merge pull request #41179 from frappe/mergify/bp/version-14/pr-41142
fix: mode of payment has precedance in Payment Entry (backport #41142)
2024-04-25 09:12:14 +05:30
ruthra kumar
7e52f72bed fix: mode of payment has precedance
Mode of Payment is given precedence over company/party bank account

(cherry picked from commit 4aef969879)
2024-04-25 09:06:04 +05:30
ruthra kumar
b9d28fc1ad Merge pull request #41178 from frappe/mergify/bp/version-14-hotfix/pr-41142
fix: mode of payment has precedance in Payment Entry (backport #41142)
2024-04-25 09:02:37 +05:30
ruthra kumar
33d38ba3a7 fix: mode of payment has precedance
Mode of Payment is given precedence over company/party bank account

(cherry picked from commit 4aef969879)
2024-04-25 08:58:01 +05:30
Deepesh Garg
ff8dba1cb7 Merge branch 'version-14-hotfix' of https://github.com/frappe/erpnext into default_dates_in_reports 2024-04-24 17:20:55 +05:30
Deepesh Garg
c3244f009b fix: Default dates in report 2024-04-24 16:59:51 +05:30
Frappe PR Bot
30b2cac423 chore(release): Bumped to Version 14.68.0
# [14.68.0](https://github.com/frappe/erpnext/compare/v14.67.2...v14.68.0) (2024-04-24)

### Bug Fixes

* account and stock manager read perm ([03ce9ee](03ce9ee321))
* allow Employee role to select cost center & project (accounting dimensions) (backport [#41160](https://github.com/frappe/erpnext/issues/41160)) ([#41161](https://github.com/frappe/erpnext/issues/41161)) ([bb48440](bb48440591))
* do not add actual expense twice for validating budget ([ec4f07f](ec4f07fd60))
* don't attempt to set gender from salutation (backport [#40997](https://github.com/frappe/erpnext/issues/40997)) ([#41072](https://github.com/frappe/erpnext/issues/41072)) ([5d05bf8](5d05bf8d4e))
* Missing args while fetching items from delivery note ([0df80ad](0df80ad923))
* Multiple partial payment requests against Purchase Invoice ([f1b75e8](f1b75e8c54))
* Party type in Payment Order ([a2e1d13](a2e1d132df))
* Permission for lower dedcution certificate ([a22be6f](a22be6f9b9))
* Test case ([5aef9d2](5aef9d2ef2))
* validate uom is integer for PR item (backport [#41074](https://github.com/frappe/erpnext/issues/41074)) ([#41076](https://github.com/frappe/erpnext/issues/41076)) ([9d0c1dc](9d0c1dc46f))

### Features

* Available batches report as on specific date ([8868cb1](8868cb147d))
* show expense breakup ([f087ec8](f087ec8df5))

### Performance Improvements

* stock ageing and batch-wise balance history report ([6017e7a](6017e7ac3e))
2024-04-24 07:32:43 +00:00
Deepesh Garg
67be2ba9dc Merge pull request #41151 from frappe/version-14-hotfix
chore: release v14
2024-04-24 13:01:19 +05:30
Deepesh Garg
3e81f0f578 Merge pull request #41100 from frappe/mergify/bp/version-14-hotfix/pr-41085
fix: Permission for lower deduction certificate (#41085)
2024-04-24 12:00:13 +05:30
mergify[bot]
bb48440591 fix: allow Employee role to select cost center & project (accounting dimensions) (backport #41160) (#41161)
* fix: allow Employee role to select cost center & project (accounting dimensions)

(cherry picked from commit d0d496a515)

# Conflicts:
#	erpnext/accounts/doctype/cost_center/cost_center.json
#	erpnext/projects/doctype/project/project.json

* chore: fix conflicts

---------

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2024-04-24 11:43:33 +05:30
Deepesh Garg
35230a9692 chore: Resolve conflicts 2024-04-24 11:33:34 +05:30
Nabin Hait
df3ff1097c Merge pull request #41140 from frappe/mergify/bp/version-14-hotfix/pr-41136
fix: Missing args while fetching items from delivery note in Installation Note (backport #41136)
2024-04-24 10:59:16 +05:30
rohitwaghchaure
521bf31fe3 Merge pull request #41154 from rohitwaghchaure/feat-new-batch-report-v14
feat: Available batches report as on specific date
2024-04-23 17:17:26 +05:30
Rohit Waghchaure
8868cb147d feat: Available batches report as on specific date 2024-04-23 17:10:05 +05:30
Deepesh Garg
0dfae12f14 Merge pull request #41130 from frappe/mergify/bp/version-14-hotfix/pr-40797
fix: Party type in Payment Order (#40797)
2024-04-23 12:05:25 +05:30
Nabin Hait
0df80ad923 fix: Missing args while fetching items from delivery note
(cherry picked from commit bbe323fbb4)
2024-04-23 04:55:02 +00:00
rohitwaghchaure
c71d1118a9 Merge pull request #41138 from rohitwaghchaure/fixed-performance-for-stock-reports
perf: stock ageing and batch-wise balance history report
2024-04-23 10:12:19 +05:30
Rohit Waghchaure
6017e7ac3e perf: stock ageing and batch-wise balance history report 2024-04-23 06:56:41 +05:30
Deepesh Garg
d5784cc629 Merge pull request #41126 from frappe/mergify/bp/version-14-hotfix/pr-40812
fix: Multiple partial payment requests against Purchase Invoice (#40812)
2024-04-22 11:36:30 +05:30
Deepesh Garg
a2e1d132df fix: Party type in Payment Order
(cherry picked from commit 91fa41c9ec)
2024-04-22 06:05:12 +00:00
Gursheen Kaur Anand
3e912993e1 Merge pull request #41123 from frappe/mergify/bp/version-14-hotfix/pr-40769
fix: budget validation for purchase orders (backport #40769)
2024-04-21 18:57:52 +05:30
Deepesh Garg
5aef9d2ef2 fix: Test case
(cherry picked from commit 071e5ed648)
2024-04-21 11:50:38 +00:00
Deepesh Garg
f1b75e8c54 fix: Multiple partial payment requests against Purchase Invoice
(cherry picked from commit 45d5f6e00a)
2024-04-21 11:50:38 +00:00
Gursheen Anand
5b1c5e3fea refactor: show list for expense breakup
(cherry picked from commit 9a12376e29)
2024-04-21 11:26:19 +00:00
Gursheen Anand
f087ec8df5 feat: show expense breakup
(cherry picked from commit 59292a09c4)
2024-04-21 11:26:19 +00:00
Gursheen Anand
ec4f07fd60 fix: do not add actual expense twice for validating budget
(cherry picked from commit af26ac96e9)
2024-04-21 11:26:19 +00:00
Deepesh Garg
a22be6f9b9 fix: Permission for lower dedcution certificate
(cherry picked from commit f6f118855b)

# Conflicts:
#	erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
2024-04-19 10:11:41 +00:00
Gursheen Kaur Anand
e8accd0256 Merge pull request #41094 from frappe/mergify/bp/version-14-hotfix/pr-41093
fix: accounts manager perm for FY (backport #41093)
2024-04-19 14:08:19 +05:30
Gursheen Kaur Anand
de3a423618 chore: resolve conflicts 2024-04-19 13:32:39 +05:30
Gursheen Anand
03ce9ee321 fix: account and stock manager read perm
(cherry picked from commit 572e844a91)

# Conflicts:
#	erpnext/accounts/doctype/fiscal_year/fiscal_year.json
2024-04-19 08:00:48 +00:00
mergify[bot]
9d0c1dc46f fix: validate uom is integer for PR item (backport #41074) (#41076)
* fix: validate uom is integer for PR item

(cherry picked from commit 9a290fdfc9)

# Conflicts:
#	erpnext/controllers/subcontracting_controller.py

* chore: `conflicts`

---------

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2024-04-18 07:53:33 +05:30
mergify[bot]
5d05bf8d4e fix: don't attempt to set gender from salutation (backport #40997) (#41072)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix: don't attempt to set gender from salutation (#40997)
2024-04-17 17:54:03 +02:00
Frappe PR Bot
84789b7407 chore(release): Bumped to Version 14.67.2
## [14.67.2](https://github.com/frappe/erpnext/compare/v14.67.1...v14.67.2) (2024-04-17)

### Bug Fixes

* barcode not fetched on selection of item (backport [#40814](https://github.com/frappe/erpnext/issues/40814)) ([#41027](https://github.com/frappe/erpnext/issues/41027)) ([0bee921](0bee921d40))
* Delayed Order Report not working (backport [#41037](https://github.com/frappe/erpnext/issues/41037)) ([#41038](https://github.com/frappe/erpnext/issues/41038)) ([e956dbb](e956dbbf68))
* Don't call get_fiscal_year if setup is not done yet ([59cea9f](59cea9f4dd))
* Don't set delivery date as today while making SO from Quotation ([b47e224](b47e224a1c))
* exclude some query builder lines from ruff rules ([2425119](2425119b5e))
* expense account set as COGS for stock entry Material Issue (backport [#41026](https://github.com/frappe/erpnext/issues/41026)) ([#41028](https://github.com/frappe/erpnext/issues/41028)) ([153e0ba](153e0ba81b))
* get address if multiple companies ([c2b6b64](c2b6b64e2e))
* get address if multiple companies ([0493872](04938726d9))
* **gp:** SLEs not fetched for correct warehouse ([97e7b3f](97e7b3f3d3))
* incorrect exc gain/loss for PE against JE for payable accounts ([50a74ee](50a74ee7fe))
* Resolve merge conflicts ([cc925ae](cc925ae938))
* Subcontracting Receipt GL Entries (backport [#40773](https://github.com/frappe/erpnext/issues/40773)) ([#40978](https://github.com/frappe/erpnext/issues/40978)) ([c2c4548](c2c4548cc0))
* test cases ([79e23da](79e23dad2c))
* **treewide:** manual ruff fixes ([b087fb3](b087fb3d54))
* use 'eq' and isnull() on qb conditions ([b4ed2d2](b4ed2d2c16))
2024-04-17 06:12:30 +00:00
rohitwaghchaure
cd70c6c1b2 Merge pull request #41032 from frappe/version-14-hotfix
chore: release v14
2024-04-17 11:41:15 +05:30
ruthra kumar
4cc0a5851b Merge pull request #40854 from frappe/mergify/bp/version-14-hotfix/pr-40786
fix(gp): SLEs not fetched for correct warehouse (backport #40786)
2024-04-17 10:36:52 +05:30
ruthra kumar
6e9da0a729 Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-40786 2024-04-17 10:16:55 +05:30
Dany Robert
97e7b3f3d3 fix(gp): SLEs not fetched for correct warehouse
(cherry picked from commit f958e8be06)
2024-04-17 10:15:29 +05:30
mergify[bot]
e956dbbf68 fix: Delayed Order Report not working (backport #41037) (#41038)
fix: Delayed Order Report not working (#41037)

(cherry picked from commit d69a18b826)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-04-16 18:24:45 +05:30
rohitwaghchaure
ebf5f13447 Merge branch 'version-14' into version-14-hotfix 2024-04-16 17:59:35 +05:30
ruthra kumar
9404dea97e Merge pull request #41034 from frappe/mergify/bp/version-14-hotfix/pr-40373
fix: get address if multiple companies (backport #40373)
2024-04-16 16:41:26 +05:30
ruthra kumar
ee06448f0d chore: resolve conflict 2024-04-16 16:38:32 +05:30
Nihantra C. Patel
c2b6b64e2e fix: get address if multiple companies
(cherry picked from commit 655a1797be)
2024-04-16 11:01:59 +00:00
Nihantra Patel
04938726d9 fix: get address if multiple companies
(cherry picked from commit c6cf1bec76)

# Conflicts:
#	erpnext/selling/doctype/sales_order/sales_order.js
2024-04-16 11:01:58 +00:00
mergify[bot]
153e0ba81b fix: expense account set as COGS for stock entry Material Issue (backport #41026) (#41028)
fix: expense account set as COGS for stock entry Material Issue (#41026)

(cherry picked from commit 03231e99ef)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-04-16 14:22:53 +05:30
mergify[bot]
0bee921d40 fix: barcode not fetched on selection of item (backport #40814) (#41027)
* fix: barcode not fetched on selection of item

(cherry picked from commit b0730293e2)

# Conflicts:
#	erpnext/stock/get_item_details.py

* chore: fix conflicts

* chore: fix test case

---------

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
2024-04-16 14:22:32 +05:30
ruthra kumar
9d3c861766 Merge pull request #41022 from frappe/mergify/bp/version-14-hotfix/pr-41020
fix: incorrect exc gain/loss for PE against JE for payable accounts (backport #41020)
2024-04-16 11:31:40 +05:30
ruthra kumar
e8d05517c5 chore: resolve conflict 2024-04-16 11:07:39 +05:30
ruthra kumar
2ebdd93a83 test: exc gain/loss journals booking in Payable accounts
(cherry picked from commit 8821c98625)
2024-04-16 05:29:49 +00:00
ruthra kumar
50a74ee7fe fix: incorrect exc gain/loss for PE against JE for payable accounts
(cherry picked from commit 81b574053f)

# Conflicts:
#	erpnext/controllers/accounts_controller.py
2024-04-16 05:29:49 +00:00
Nabin Hait
da1c317c6c Merge pull request #41006 from frappe/mergify/bp/version-14-hotfix/pr-40858
fix: Don't set delivery date as today while making SO from Quotation (backport #40858)
2024-04-15 13:05:21 +05:30
Nabin Hait
79e23dad2c fix: test cases
(cherry picked from commit 65c74fa3c7)
2024-04-15 07:03:42 +00:00
Nabin Hait
b47e224a1c fix: Don't set delivery date as today while making SO from Quotation
(cherry picked from commit fec20decc1)
2024-04-15 07:03:42 +00:00
Deepesh Garg
3310358d36 Merge pull request #40947 from frappe/mergify/bp/version-14-hotfix/pr-40931
fix: Don't call get_fiscal_year if setup is not done yet (backport #40931)
2024-04-15 11:18:06 +05:30
Frappe PR Bot
7a6c0e5283 chore(release): Bumped to Version 14.67.1
## [14.67.1](https://github.com/frappe/erpnext/compare/v14.67.0...v14.67.1) (2024-04-12)

### Bug Fixes

* Subcontracting Receipt GL Entries (backport [#40773](https://github.com/frappe/erpnext/issues/40773)) (backport [#40978](https://github.com/frappe/erpnext/issues/40978)) ([#40982](https://github.com/frappe/erpnext/issues/40982)) ([4672f59](4672f59599))
2024-04-12 10:01:51 +00:00
mergify[bot]
4672f59599 fix: Subcontracting Receipt GL Entries (backport #40773) (backport #40978) (#40982)
* fix: Subcontracting Receipt GL Entries (backport #40773) (#40978)

* fix: Subcontracting Receipt GL Entries

(cherry picked from commit 9808ae92a4)

* chore: linter

---------

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
(cherry picked from commit c2c4548cc0)

# Conflicts:
#	erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py

* chore: `conflicts`

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2024-04-12 15:30:27 +05:30
mergify[bot]
c2c4548cc0 fix: Subcontracting Receipt GL Entries (backport #40773) (#40978)
* fix: Subcontracting Receipt GL Entries

(cherry picked from commit 9808ae92a4)

* chore: linter

---------

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2024-04-12 14:50:12 +05:30
Deepesh Garg
cc925ae938 fix: Resolve merge conflicts 2024-04-12 12:10:55 +05:30
Akhil Narang
f0ecc627fb Merge pull request #40943 from akhilnarang/v14-ruff
chore: backport ruff linting/formatting
2024-04-12 11:01:43 +05:30
Akhil Narang
cf3c26d80c chore: gitignore ruff format
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-04-12 11:01:32 +05:30
Corentin Flr
59cea9f4dd fix: Don't call get_fiscal_year if setup is not done yet
(cherry picked from commit c203fafb1b)

# Conflicts:
#	erpnext/public/js/utils.js
2024-04-10 15:17:44 +00:00
Frappe PR Bot
cc6bacb190 chore(release): Bumped to Version 14.67.0
# [14.67.0](https://github.com/frappe/erpnext/compare/v14.66.4...v14.67.0) (2024-04-10)

### Bug Fixes

* Get pro-rata depr amount based on correct days ([10d7600](10d760089e))
* group warehouse added in the stock reconciliation ([9dea6d3](9dea6d3393))
* ignore dimension validation for cancelled entries ([9745724](9745724d41))
* incorrect currency symbol in General Ledger print ([5896e75](5896e755bf))
* incorrect operator causing incorrect validation ([7e1ab75](7e1ab75b38))
* query_report.trigger_refresh is not a function ([a6145fa](a6145fa13c))
* translatable web footer ([#40834](https://github.com/frappe/erpnext/issues/40834)) ([b55d859](b55d8597e8))
* use reference type name to update exc rate ([09cda60](09cda60bdf))

### Features

* ledger health doctype ([b667a02](b667a02470))
* new hook `fields_for_group_similar_items` to group additional fields for print formats ([#40831](https://github.com/frappe/erpnext/issues/40831)) ([0172880](0172880fd3))

### Performance Improvements

* memory consumption for the Batch-Wise Balance History report ([3165682](3165682d7a))
2024-04-10 14:22:01 +00:00
Deepesh Garg
cebde2662d Merge pull request #40919 from frappe/version-14-hotfix
chore: release v14
2024-04-10 19:50:19 +05:30
ruthra kumar
b4ed2d2c16 fix: use 'eq' and isnull() on qb conditions
(cherry picked from commit eee86d2e4b)
(cherry picked from commit 22689958da)
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-04-10 17:13:31 +05:30
Akhil Narang
2425119b5e fix: exclude some query builder lines from ruff rules
`== None` and `== True` are intentional here

(cherry picked from commit ac69513f60)
(cherry picked from commit 41d7c03cbb)
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-04-10 17:13:31 +05:30
Akhil Narang
b087fb3d54 fix(treewide): manual ruff fixes
(cherry picked from commit f63396ef47)
(cherry picked from commit 7828eee014)
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-04-10 17:13:31 +05:30
Akhil Narang
4d34b1ead7 refactor(treewide): formatting and ruff fixes, + manually enabled F401
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-04-10 17:13:31 +05:30
barredterra
c28d19cf7f chore: switch to ruff for python formatting/linting
(cherry picked from commit 8afb7790de)
(cherry picked from commit 9eeedd8515)
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-04-10 17:07:51 +05:30
ruthra kumar
73d2595aa6 Merge pull request #40937 from frappe/mergify/bp/version-14-hotfix/pr-40936
fix: ignore dimension validation for cancelled entries (backport #40936)
2024-04-10 15:28:00 +05:30
ruthra kumar
9745724d41 fix: ignore dimension validation for cancelled entries
(cherry picked from commit 971c867f29)
2024-04-10 08:28:35 +00:00
ruthra kumar
a31b2e17f5 Merge pull request #40929 from frappe/mergify/bp/version-14-hotfix/pr-40695
feat: Periodically monitor ledger health (backport #40695)
2024-04-10 07:17:29 +05:30
ruthra kumar
46c76b166d chore: resolve conflicts 2024-04-09 19:59:09 +05:30
ruthra kumar
6079c5636e Merge pull request #40927 from frappe/mergify/bp/version-14-hotfix/pr-40926
fix: incorrect currency symbol in General Ledger print (backport #40926)
2024-04-09 19:54:29 +05:30
ruthra kumar
5808feaccf chore: use super() instead of super(__class__, self)
(cherry picked from commit 24d37d22a3)
2024-04-09 12:25:55 +00:00
ruthra kumar
98ad034b21 chore: make ledger health doctype read_only
(cherry picked from commit dc79213bb3)
2024-04-09 12:25:55 +00:00
ruthra kumar
277717a2e0 test: ledger monitoring function
(cherry picked from commit 4776d660b5)
2024-04-09 12:25:55 +00:00
ruthra kumar
0591f72e01 chore: schedule job to run daily
(cherry picked from commit f96cf111ed)
2024-04-09 12:25:54 +00:00
ruthra kumar
1af6b4256f chore: permission and UI changes
(cherry picked from commit 1a43ed763b)
2024-04-09 12:25:53 +00:00
ruthra kumar
6273a31b8c refactor: only run checks on specified companies
(cherry picked from commit 00eeacd06a)

# Conflicts:
#	erpnext/accounts/utils.py
2024-04-09 12:25:53 +00:00
ruthra kumar
f86c035f88 refactor: make health check configurable for companies
(cherry picked from commit 704925549b)
2024-04-09 12:25:52 +00:00
ruthra kumar
9981a900b2 refactor: control monitoring through settings page
(cherry picked from commit a42482ce35)

# Conflicts:
#	erpnext/accounts/utils.py
2024-04-09 12:25:52 +00:00
ruthra kumar
7a6ffccecc chore: settings page for health monitor
(cherry picked from commit b2fb7843d1)
2024-04-09 12:25:47 +00:00
ruthra kumar
58698c9aa4 refactor: barebones method to run checks
(cherry picked from commit 8c8d9be810)

# Conflicts:
#	erpnext/accounts/utils.py
2024-04-09 12:25:47 +00:00
ruthra kumar
bbe4ca7d74 refactor: flag for general and payment ledger mismatch
(cherry picked from commit d620b9eae8)
2024-04-09 12:25:46 +00:00
ruthra kumar
153fc91478 refactor: date on which vouchers was reported
(cherry picked from commit 402ffc6d27)
2024-04-09 12:25:45 +00:00
ruthra kumar
b667a02470 feat: ledger health doctype
(cherry picked from commit 9ed74dd8cc)
2024-04-09 12:25:45 +00:00
ruthra kumar
5896e755bf fix: incorrect currency symbol in General Ledger print
(cherry picked from commit 429e036e8c)
2024-04-09 12:16:41 +00:00
rohitwaghchaure
dd6c53df96 Merge pull request #40910 from rohitwaghchaure/fixed-perf-issue-for-batchwise-balance-history
perf: memory consumption for the Batch-Wise Balance History report
2024-04-09 17:36:43 +05:30
Rohit Waghchaure
3165682d7a perf: memory consumption for the Batch-Wise Balance History report 2024-04-08 19:03:48 +05:30
ruthra kumar
aff71970e5 Merge pull request #40904 from frappe/mergify/bp/version-14-hotfix/pr-40878
refactor: merge taxes from delivery note to Sales Invoice (backport #40878)
2024-04-08 16:18:48 +05:30
Sagar Vora
2b5ae1dbae Merge pull request #40906 from frappe/mergify/bp/version-14-hotfix/pr-40831 2024-04-08 10:22:43 +00:00
Sagar Vora
24709ab400 chore: fix conflict 2024-04-08 15:50:58 +05:30
Smit Vora
0172880fd3 feat: new hook fields_for_group_similar_items to group additional fields for print formats (#40831)
(cherry picked from commit f7c9e1538b)

# Conflicts:
#	erpnext/hooks.py
2024-04-08 10:18:15 +00:00
ruthra kumar
b76c00de68 chore: resolve conflict 2024-04-08 15:44:13 +05:30
ruthra kumar
ae1858f465 test: tax merging from 2 Delivery Note to Sales Invoice
(cherry picked from commit 39a48a2e2a)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
2024-04-08 09:09:36 +00:00
ruthra kumar
22b16a6b0e refactor: merge taxes from delivery note to Sales Invoice
(cherry picked from commit 550cbbd91c)
2024-04-08 09:09:34 +00:00
Frappe PR Bot
8d8feadeae chore(release): Bumped to Version 14.66.4
## [14.66.4](https://github.com/frappe/erpnext/compare/v14.66.3...v14.66.4) (2024-04-07)

### Bug Fixes

* incorrect operator causing incorrect validation ([60ba62e](60ba62e882))
2024-04-07 12:34:56 +00:00
rohitwaghchaure
5629ad21d2 Merge pull request #40898 from frappe/mergify/bp/version-14/pr-40893
fix: incorrect operator causing incorrect validation (backport #40883) (backport #40893)
2024-04-07 18:03:33 +05:30
Nabin Hait
1eb720a7b0 Merge pull request #40897 from nabinhait/pro-rata-depr-fix
fix: Get pro-rata depr amount based on correct days
2024-04-07 15:23:42 +05:30
rohitwaghchaure
c4e950f6b5 Merge pull request #40835 from frappe/mergify/bp/version-14-hotfix/pr-40834
fix: translatable web footer (backport #40834)
2024-04-07 14:35:45 +05:30
rohitwaghchaure
d4313f7109 Merge pull request #40859 from frappe/mergify/bp/version-14-hotfix/pr-40848
fix: group warehouse added in the stock reconciliation (backport #40848)
2024-04-07 14:34:33 +05:30
Rohit Waghchaure
60ba62e882 fix: incorrect operator causing incorrect validation
(cherry picked from commit 6b317b0c0d)
(cherry picked from commit 7e1ab75b38)
2024-04-07 09:04:00 +00:00
rohitwaghchaure
26d7354973 Merge pull request #40893 from frappe/mergify/bp/version-14-hotfix/pr-40883
fix: incorrect operator causing incorrect validation (backport #40883)
2024-04-07 14:33:10 +05:30
Nabin Hait
10d760089e fix: Get pro-rata depr amount based on correct days 2024-04-07 14:08:45 +05:30
Rohit Waghchaure
7e1ab75b38 fix: incorrect operator causing incorrect validation
(cherry picked from commit 6b317b0c0d)
2024-04-07 06:34:07 +00:00
rohitwaghchaure
0f9af4b82c Merge pull request #40888 from frappe/mergify/bp/version-14-hotfix/pr-40887
fix: query_report.trigger_refresh is not a function (backport #40887)
2024-04-07 12:02:16 +05:30
Rohit Waghchaure
a6145fa13c fix: query_report.trigger_refresh is not a function
(cherry picked from commit 30bbb58ca1)
2024-04-07 06:27:49 +00:00
ruthra kumar
cc2f861bca Merge pull request #40868 from frappe/mergify/bp/version-14-hotfix/pr-40856
fix: unwanted Exc Gain/Loss journals on Payment against Journal entry (backport #40856)
2024-04-05 11:01:48 +05:30
ruthra kumar
8f2fd5dec9 test: payment against JE reconciliation with different rates
(cherry picked from commit fe84558b77)
2024-04-05 05:03:56 +00:00
ruthra kumar
09cda60bdf fix: use reference type name to update exc rate
(cherry picked from commit c15690e475)
2024-04-05 05:03:56 +00:00
Rohit Waghchaure
9dea6d3393 fix: group warehouse added in the stock reconciliation
(cherry picked from commit 8f53bc0096)
2024-04-04 10:09:55 +00:00
Frappe PR Bot
fb076d34b1 chore(release): Bumped to Version 14.66.3
## [14.66.3](https://github.com/frappe/erpnext/compare/v14.66.2...v14.66.3) (2024-04-03)

### Bug Fixes

* cost center shouldn't update debit/credit in Exc gain/loss JV ([f66b53b](f66b53b2c1))
* do not fetch received items in purchase receipt ([e778d7e](e778d7e690))
* linter issues ([515f933](515f933362))
* markdown to text editor set for supplier quotation ([b5629d2](b5629d2d4e))
* payment_order_status should be no_copy ([8dff18e](8dff18eab4))
* Priority not copied from project template ([4f4470b](4f4470b9d2))
* show currency symbol in base currency in fixed asset register report ([cfe5f00](cfe5f009f6))
* show future payments allocated sales returns is considered as payment ([803ed90](803ed904a9))
* Warehouse linked company name in multicompany setup (backport [#40779](https://github.com/frappe/erpnext/issues/40779)) ([#40780](https://github.com/frappe/erpnext/issues/40780)) ([ceac42d](ceac42dfaa))
2024-04-03 10:32:43 +00:00
Deepesh Garg
fba888fe94 Merge pull request #40821 from frappe/version-14-hotfix
chore: release v14
2024-04-03 16:01:29 +05:30
Raffael Meyer
b55d8597e8 fix: translatable web footer (#40834)
(cherry picked from commit f3bcdbe5bd)
2024-04-02 15:16:18 +00:00
Nabin Hait
81081663c4 Merge pull request #40826 from frappe/mergify/bp/version-14-hotfix/pr-40584
fix: show currency symbol in base currency in fixed asset register report (backport #40584)
2024-04-02 18:29:58 +05:30
rohitwaghchaure
2f66542d71 Merge pull request #40824 from rohitwaghchaure/fixed-remove-enqueue-submit-cancel
chore: remove enqueue submit and cancel from the stock entry
2024-04-02 16:34:57 +05:30
Rohit Waghchaure
abc0294cbf chore: remove enqueue submit and cancel from stock entry 2024-04-02 16:10:28 +05:30
Nabin Hait
515f933362 fix: linter issues
(cherry picked from commit 21a40a2236)
2024-04-02 10:27:57 +00:00
Nabin Hait
cfe5f009f6 fix: show currency symbol in base currency in fixed asset register report
(cherry picked from commit 8b6220efd8)
2024-04-02 10:27:56 +00:00
ruthra kumar
cf74f8312e Merge pull request #40803 from frappe/mergify/bp/version-14-hotfix/pr-40181
fix: show future payments consider allocated sales returns (backport #40181)
2024-04-01 14:13:59 +05:30
Devin Slauenwhite
803ed904a9 fix: show future payments allocated sales returns is considered as payment
(cherry picked from commit 3381d0d945)
2024-04-01 07:34:41 +00:00
Devin Slauenwhite
72db656054 test: show future payments allocated sales returns is considered as payment
(cherry picked from commit daaa00bd4a)
2024-04-01 07:34:40 +00:00
rohitwaghchaure
44b72e7fc8 Merge pull request #40737 from frappe/mergify/bp/version-14-hotfix/pr-40731
fix: markdown to text editor set for supplier quotation (backport #40731)
2024-03-31 21:14:38 +05:30
rohitwaghchaure
31017774f6 chore: fix conflicts 2024-03-31 11:42:05 +05:30
rohitwaghchaure
9b8bb4d6a2 chore: fix conflicts 2024-03-31 11:41:44 +05:30
mergify[bot]
ceac42dfaa fix: Warehouse linked company name in multicompany setup (backport #40779) (#40780)
fix: Warehouse linked company name in multicompany setup (#40779)

(cherry picked from commit 679aea607b)

Co-authored-by: jeshani <56191568+jeshani@users.noreply.github.com>
2024-03-30 10:18:16 +05:30
ruthra kumar
998cc0a966 Merge pull request #40668 from frappe/mergify/bp/version-14-hotfix/pr-40634
refactor: better pop up message for Internal Customer validation (backport #40634)
2024-03-29 13:50:35 +05:30
ruthra kumar
e722c9a34a Merge pull request #40766 from frappe/mergify/bp/version-14-hotfix/pr-40758
fix: payment_order_status should be no_copy (backport #40758)
2024-03-29 13:49:08 +05:30
Ashish Shah
8dff18eab4 fix: payment_order_status should be no_copy
payment_order_status should be no_copy

(cherry picked from commit adee2ba541)
2024-03-29 07:57:03 +00:00
ruthra kumar
7363884ab3 Merge pull request #40762 from frappe/mergify/bp/version-14-hotfix/pr-40760
fix: cost center shouldn't update debit/credit in Exc gain/loss JV (backport #40760)
2024-03-29 11:47:05 +05:30
ruthra kumar
f66b53b2c1 fix: cost center shouldn't update debit/credit in Exc gain/loss JV
(cherry picked from commit 398d3022ef)
2024-03-29 06:13:47 +00:00
Frappe PR Bot
c1a95c05bc chore(release): Bumped to Version 14.66.2
## [14.66.2](https://github.com/frappe/erpnext/compare/v14.66.1...v14.66.2) (2024-03-29)

### Bug Fixes

* use sql to clear comments ([0322c1a](0322c1a36e))
2024-03-29 05:41:39 +00:00
ruthra kumar
db56d259cc Merge pull request #40747 from frappe/mergify/bp/version-14/pr-40739
refactor: use sql to clear comments (backport #40739)
2024-03-29 11:10:22 +05:30
ruthra kumar
0322c1a36e fix: use sql to clear comments
(cherry picked from commit 1f46c1530e)
2024-03-29 10:50:05 +05:30
ruthra kumar
bb35c334c0 Merge pull request #40744 from frappe/mergify/bp/version-14-hotfix/pr-40739
refactor: use sql to clear comments (backport #40739)
2024-03-28 19:42:02 +05:30
ruthra kumar
4d6fad26f3 refactor: use sql to clear comments
(cherry picked from commit 1f46c1530e)
2024-03-28 12:12:12 +00:00
Nihantra Patel
b5629d2d4e fix: markdown to text editor set for supplier quotation
(cherry picked from commit 9828d34b19)

# Conflicts:
#	erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
#	erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
2024-03-28 07:16:11 +00:00
rohitwaghchaure
b1105fb0ab Merge pull request #40721 from frappe/mergify/bp/version-14-hotfix/pr-40718
fix: do not fetch received items in purchase receipt (backport #40718)
2024-03-27 23:01:12 +05:30
Rohit Waghchaure
e778d7e690 fix: do not fetch received items in purchase receipt
(cherry picked from commit 5bff434902)
2024-03-27 17:11:25 +00:00
Frappe PR Bot
5827bdcbc2 chore(release): Bumped to Version 14.66.1
## [14.66.1](https://github.com/frappe/erpnext/compare/v14.66.0...v14.66.1) (2024-03-27)

### Bug Fixes

* Priority not copied from project template ([af6dd3b](af6dd3bcfb))
2024-03-27 11:21:16 +00:00
rohitwaghchaure
94f15797f5 Merge pull request #40712 from frappe/mergify/bp/version-14/pr-40710
fix: Priority not copied from project template (backport #40708) (backport #40710)
2024-03-27 16:50:07 +05:30
Rohit Waghchaure
af6dd3bcfb fix: Priority not copied from project template
(cherry picked from commit 33fd7b8a1f)
(cherry picked from commit 4f4470b9d2)
2024-03-27 10:49:11 +00:00
rohitwaghchaure
e947d65cb2 Merge pull request #40710 from frappe/mergify/bp/version-14-hotfix/pr-40708
fix: Priority not copied from project template (backport #40708)
2024-03-27 16:17:57 +05:30
Rohit Waghchaure
4f4470b9d2 fix: Priority not copied from project template
(cherry picked from commit 33fd7b8a1f)
2024-03-27 10:18:21 +00:00
Frappe PR Bot
4ea3876f30 chore(release): Bumped to Version 14.66.0
# [14.66.0](https://github.com/frappe/erpnext/compare/v14.65.8...v14.66.0) (2024-03-27)

### Bug Fixes

* achieved targets for sales partners ([f9ab763](f9ab763cc8))
* Add default finance book check in P&L statement ([4485121](4485121255))
* incorrect total qty in job card ([fb252ec](fb252ec29a))
* pass empty string email content of pos invoice ([ee7bd98](ee7bd98878))
* permissions during bulk transaction logs ([99faafb](99faafb5be))
* rate not fetching from the item price ([9b3c4ac](9b3c4ac575))
* rate reset to zero ([2f839fb](2f839fbf6d))
* remove microsecond from posting datetime ([#40017](https://github.com/frappe/erpnext/issues/40017)) ([c3f9338](c3f9338430))
* show correct variance for durations with no vouchers ([fe3bee4](fe3bee44e2))
* style for tax breakup ([e922ac7](e922ac7c31))
* use Text Editor for rendering tax breakup table ([bba1ac5](bba1ac5735))
* validate gl for previous fiscal year ([82b6133](82b613353b))
* wrong buying amount if delivered and billed qty varies ([2b31113](2b311131ba))

### Features

* bisect doctype ([5ad3918](5ad3918232))
* nodes doctype ([6afb6ff](6afb6ff4df))

### Performance Improvements

* add in some indexes (backport [#40590](https://github.com/frappe/erpnext/issues/40590)) ([#40604](https://github.com/frappe/erpnext/issues/40604)) ([390d3a6](390d3a6a9f))
* new column posting datetime in SLE to optimize stock ledger related queries ([5e68ebd](5e68ebd030))
2024-03-27 03:27:23 +00:00
Deepesh Garg
bd3b1bbbb8 Merge pull request #40677 from frappe/version-14-hotfix
chore: release v14
2024-03-27 08:56:10 +05:30
rohitwaghchaure
4a1cd943bd Merge pull request #40687 from frappe/mergify/bp/version-14-hotfix/pr-40684
fix: incorrect total qty in job card (backport #40684)
2024-03-26 19:54:15 +05:30
Rohit Waghchaure
fb252ec29a fix: incorrect total qty in job card
(cherry picked from commit c3546cf8e2)
2024-03-26 14:03:40 +00:00
Wolfram Schmidt
2834d25ce3 refactor: better pop message for Internal Customer validation
-added more meaningful description to message when using "internal Customer" scenario

(cherry picked from commit b132892b25)
2024-03-26 09:55:04 +05:30
Deepesh Garg
208a46fbe4 Merge pull request #40505 from frappe/mergify/bp/version-14-hotfix/pr-40503
fix: achieved targets for territory / partners bpv15 (#40503)
2024-03-26 09:03:14 +05:30
Deepesh Garg
2723e1f614 Merge pull request #40652 from frappe/mergify/bp/version-14-hotfix/pr-40640
fix: Add default finance book check-in P&L statement (#40640)
2024-03-25 17:08:57 +05:30
Deepesh Garg
4485121255 fix: Add default finance book check in P&L statement
(cherry picked from commit 5be3417fdf)
2024-03-25 09:14:41 +00:00
Frappe PR Bot
cf770e784d chore(release): Bumped to Version 14.65.8
## [14.65.8](https://github.com/frappe/erpnext/compare/v14.65.7...v14.65.8) (2024-03-25)

### Bug Fixes

* reset update outstanding flag for old records ([73c534c](73c534cf1a))
2024-03-25 02:57:34 +00:00
ruthra kumar
fda9c03d4d Merge pull request #40644 from frappe/mergify/bp/version-14/pr-40622
fix: reset update_outstanding_for_self flag for old records (backport #40622)
2024-03-25 08:26:21 +05:30
ruthra kumar
adec93de18 refactor: hide on print formats
(cherry picked from commit fdcdc8a56e)
2024-03-25 07:47:20 +05:30
ruthra kumar
73c534cf1a fix: reset update outstanding flag for old records
(cherry picked from commit a88bf8419e)
2024-03-25 07:47:16 +05:30
ruthra kumar
0ec1a88748 Merge pull request #40625 from frappe/mergify/bp/version-14-hotfix/pr-40622
refactor: reset update_outstanding_for_self flag for old records (backport #40622)
2024-03-24 16:24:37 +05:30
rohitwaghchaure
91400e1371 Merge pull request #40628 from frappe/mergify/bp/version-14-hotfix/pr-40017
fix: remove microsecond from posting datetime (backport #40017)
2024-03-23 18:39:04 +05:30
mergify[bot]
39711df27c Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-40503 2024-03-23 09:10:52 +00:00
Deepesh Garg
03eb4d77ce Merge pull request #40514 from mmdanny89/email-point-of-sale
fix: pass empty string email content of pos invoice
2024-03-23 14:39:58 +05:30
rohitwaghchaure
c3f9338430 fix: remove microsecond from posting datetime (#40017)
(cherry picked from commit 0b04d04da3)
2024-03-23 03:07:37 +00:00
ruthra kumar
dbb4391f1e refactor: hide on print formats
(cherry picked from commit fdcdc8a56e)
2024-03-22 14:54:03 +00:00
ruthra kumar
22cec21c6f refactor: reset flag for old records
(cherry picked from commit a88bf8419e)
2024-03-22 14:54:03 +00:00
ruthra kumar
ab7f80625b Merge pull request #40615 from frappe/mergify/bp/version-14-hotfix/pr-38496
feat: utility to debug financial reports - Bisect Accounting Statements (backport #38496)
2024-03-22 16:23:22 +05:30
rohitwaghchaure
a4ddc4ee1b Merge pull request #40036 from frappe/mergify/bp/version-14-hotfix/pr-39800
perf: new column Posting Datetime in SLE to optimize stock ledger related queries (backport #39800)
2024-03-22 16:06:53 +05:30
rohitwaghchaure
07929d20aa Merge pull request #40618 from frappe/mergify/bp/version-14-hotfix/pr-40616
fix: rate reset to zero (backport #40616)
2024-03-22 15:41:07 +05:30
Rohit Waghchaure
2f839fbf6d fix: rate reset to zero
(cherry picked from commit 6821baa850)
2024-03-22 09:50:51 +00:00
ruthra kumar
9f3b6d21c3 chore: resolve JS linter issue 2024-03-22 14:42:57 +05:30
ruthra kumar
4eb1fbfe42 chore: resolve linter issues
(cherry picked from commit 0890b414b1)
2024-03-22 08:51:33 +00:00
ruthra kumar
3a38aacc30 refactor: cache results
(cherry picked from commit 14c8c8c33d)
2024-03-22 08:51:33 +00:00
ruthra kumar
48bfb9d315 refactor: flag to differentiate generated and default values
(cherry picked from commit 0925706d5e)
2024-03-22 08:51:33 +00:00
ruthra kumar
5d90b0fd1d refactor: save results in node
(cherry picked from commit ca14ae8f1b)
2024-03-22 08:51:32 +00:00
ruthra kumar
3cab242e9f chore: restrict only to administrator and type info
(cherry picked from commit 90c6d4dc85)
2024-03-22 08:51:32 +00:00
ruthra kumar
54e7f303e9 chore: change data type for summary fields
(cherry picked from commit 228aa1a244)
2024-03-22 08:51:32 +00:00
ruthra kumar
cd0a7fed41 refactor: adding labels to important section
(cherry picked from commit 993e2bfbf9)
2024-03-22 08:51:32 +00:00
ruthra kumar
84609abd65 chore: UI cleanup
(cherry picked from commit ea3071db66)
2024-03-22 08:51:31 +00:00
ruthra kumar
a76d19fe8f chore: add screen freeze on wait
(cherry picked from commit 395299803f)
2024-03-22 08:51:31 +00:00
ruthra kumar
ebea0fd203 chore: code cleanup
(cherry picked from commit 5e2d21c033)
2024-03-22 08:51:31 +00:00
ruthra kumar
f9c30968bf chore: hide internal variables section
(cherry picked from commit c4c3090f46)
2024-03-22 08:51:31 +00:00
ruthra kumar
a9a510547e chore: rename btree and remove debugging statements
(cherry picked from commit 6492019383)
2024-03-22 08:51:31 +00:00
ruthra kumar
c2f6f9d37f chore: hide internal fields and better painting logic for heatmap
(cherry picked from commit f6831fba13)
2024-03-22 08:51:30 +00:00
ruthra kumar
9d5c010071 refactor: working heatmap
(cherry picked from commit 16db6c2f47)
2024-03-22 08:51:30 +00:00
ruthra kumar
3cfc778bdb chore: hide some internal fields
(cherry picked from commit bd3dc6482e)
2024-03-22 08:51:30 +00:00
ruthra kumar
f06014afc3 refactor: calculate summary on tree navigation
(cherry picked from commit f7b7b2b438)
2024-03-22 08:51:30 +00:00
ruthra kumar
bee5744309 refactor: use DB to store tree and state
(cherry picked from commit 99fbd8ad18)
2024-03-22 08:51:30 +00:00
ruthra kumar
bc1f25b897 chore: use doctype as btree
(cherry picked from commit 9d20256366)
2024-03-22 08:51:30 +00:00
ruthra kumar
6afb6ff4df feat: nodes doctype
(cherry picked from commit 85f2a6dd54)
2024-03-22 08:51:29 +00:00
ruthra kumar
609ecbe804 chore: remove unwanted code
(cherry picked from commit de2eba0d98)
2024-03-22 08:51:29 +00:00
ruthra kumar
674d822985 refactor: add basic navigation
1. remove unnecessary columns
2. added basic tree navigation

(cherry picked from commit 705ef4f5a3)
2024-03-22 08:51:29 +00:00
ruthra kumar
66fae6466f refactor: ability to build and load tree from DB
(cherry picked from commit b2dde55f2c)
2024-03-22 08:51:29 +00:00
ruthra kumar
81f456bdc7 refactor: introduce node class
(cherry picked from commit d53b34c0ce)
2024-03-22 08:51:29 +00:00
ruthra kumar
a177137d6d refactor: more buttons
(cherry picked from commit a427029151)
2024-03-22 08:51:28 +00:00
ruthra kumar
d81be8d855 refactor: date validation
(cherry picked from commit 2de3e6ce6d)
2024-03-22 08:51:28 +00:00
ruthra kumar
0399acdc8e refactor: support for BFS and DFS
(cherry picked from commit 03a38ed025)
2024-03-22 08:51:28 +00:00
ruthra kumar
50963d9ad5 refactor: simplify DFS
(cherry picked from commit 26503a205f)
2024-03-22 08:51:28 +00:00
ruthra kumar
1639974948 refactor: Depth First Search(DFS)
(cherry picked from commit 5a25c80f2e)
2024-03-22 08:51:28 +00:00
ruthra kumar
57ec0d6b41 refactor: some logic
(cherry picked from commit 4c8a8c3bcd)
2024-03-22 08:51:27 +00:00
ruthra kumar
5ad3918232 feat: bisect doctype
(cherry picked from commit decdbd2782)
2024-03-22 08:51:27 +00:00
ruthra kumar
9e15ecfe34 refactor: primitive summary for p&l and balance sheet
(cherry picked from commit eb4c476490)
2024-03-22 08:51:27 +00:00
ruthra kumar
da17496e3d Merge pull request #40607 from frappe/mergify/bp/version-14-hotfix/pr-40520
fix: permissions during bulk transaction logs (backport #40520)
2024-03-22 10:33:49 +05:30
David
99faafb5be fix: permissions during bulk transaction logs
(cherry picked from commit 49dd4c1ef3)
2024-03-22 04:38:17 +00:00
ruthra kumar
6d39a7890e Merge pull request #40596 from frappe/mergify/bp/version-14-hotfix/pr-40386
fix: wrong buying amount if delivered and billed qty varies (backport #40386)
2024-03-22 09:04:26 +05:30
mergify[bot]
390d3a6a9f perf: add in some indexes (backport #40590) (#40604)
* perf: add in some indexes (#40590)

`Sales Invoice Item.purchase_order`
`Delivery Note Item.purchase_order`

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

# Conflicts:
#	erpnext/selling/doctype/sales_order_item/sales_order_item.json
#	erpnext/stock/doctype/delivery_note_item/delivery_note_item.json

* chore: `conflicts`

* chore: `conflicts`

---------

Co-authored-by: Akhil Narang <me@akhilnarang.dev>
Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2024-03-22 08:51:33 +05:30
rohitwaghchaure
5117ba5abf Merge pull request #40599 from frappe/mergify/bp/version-14-hotfix/pr-40595
fix: rate not fetching from the item price (backport #40595)
2024-03-21 22:40:58 +05:30
Rohit Waghchaure
9b3c4ac575 fix: rate not fetching from the item price
(cherry picked from commit d893a465d7)
2024-03-21 16:49:46 +00:00
ruthra kumar
d3a6153077 test: buying amt calculation if DN and SI differ in qty
(cherry picked from commit ccb51ded95)
2024-03-21 15:46:03 +00:00
Dany Robert
2b311131ba fix: wrong buying amount if delivered and billed qty varies
(cherry picked from commit b8da0d9334)
2024-03-21 15:46:02 +00:00
Gursheen Kaur Anand
c072cd941d Merge pull request #40583 from frappe/mergify/bp/version-14-hotfix/pr-40572
fix: PCV validation for previous fiscal year (backport #40572)
2024-03-21 12:44:09 +05:30
ruthra kumar
757cf8a76f Merge pull request #40581 from frappe/mergify/bp/version-14-hotfix/pr-40580
refactor: config changes in Transaction Deletion Record (backport #40580)
2024-03-21 11:07:17 +05:30
Gursheen Anand
82b613353b fix: validate gl for previous fiscal year
(cherry picked from commit a1d108c062)
2024-03-21 05:30:35 +00:00
ruthra kumar
5791c50fdf refactor: config changes in Transaction Deletion Record
(cherry picked from commit 4ba67fb3ec)
2024-03-21 05:17:16 +00:00
ruthra kumar
67481ad062 Merge pull request #40574 from frappe/mergify/bp/version-14-hotfix/pr-39717
refactor: Transaction Deletion record for large volumes (backport #39717)
2024-03-21 10:18:07 +05:30
ruthra kumar
1515bb7f0b refactor: replace get_job with create_job_id utility method 2024-03-21 09:53:55 +05:30
Gursheen Kaur Anand
33e0371c4d Merge pull request #40571 from frappe/mergify/bp/version-14-hotfix/pr-40563
fix: use `Text Editor` for rendering tax breakup table (backport #40563)
2024-03-20 20:39:19 +05:30
Rohit Waghchaure
1df54114a8 chore: fixed test case 2024-03-20 20:20:44 +05:30
Gursheen Anand
cf3b0ee41e chore: resolve conflicts 2024-03-20 20:15:20 +05:30
Gursheen Anand
957f55f6b1 chore: resolve conflicts 2024-03-20 20:12:36 +05:30
Rohit Waghchaure
77349a0af6 chore: fix test case 2024-03-20 20:09:22 +05:30
Rohit Waghchaure
c36a5d1ba3 chore: fix backport issues 2024-03-20 20:09:22 +05:30
rohitwaghchaure
44d4096ba1 chore: fix conflicts 2024-03-20 20:09:22 +05:30
rohitwaghchaure
a694a92df9 chore: fix conflicts 2024-03-20 20:09:22 +05:30
rohitwaghchaure
1c7128e77b chore: fix conflicts 2024-03-20 20:09:22 +05:30
rohitwaghchaure
c147ec168f chore: fix conflicts 2024-03-20 20:09:22 +05:30
rohitwaghchaure
717442c01f chore: fix conflicts 2024-03-20 20:09:22 +05:30
Rohit Waghchaure
ce7a53f810 chore: remove microsecond from posting_datetime
(cherry picked from commit a73ba2c0d2)

# Conflicts:
#	erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
2024-03-20 20:08:37 +05:30
Rohit Waghchaure
1767dada8d test: test cases to test clash timestamp entries
(cherry picked from commit f04676aaed)
2024-03-20 20:08:36 +05:30
Rohit Waghchaure
5e68ebd030 perf: new column posting datetime in SLE to optimize stock ledger related queries
(cherry picked from commit d80ca523a4)
2024-03-20 20:07:36 +05:30
ruthra kumar
87fdb4e720 chore: resolve conflicts 2024-03-20 19:58:18 +05:30
ruthra kumar
e5722a772a chore: fix linting issue in JS
(cherry picked from commit 02c522b7cd)
2024-03-20 14:13:21 +00:00
ruthra kumar
35fcd032ad refactor(test): test cases modified to handle new approach
(cherry picked from commit 81309576b0)

# Conflicts:
#	erpnext/setup/demo.py
#	erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
2024-03-20 14:13:21 +00:00
ruthra kumar
1fe14334f3 refactor: ability to process in single transaction
(cherry picked from commit a158b825d7)
2024-03-20 14:13:20 +00:00
ruthra kumar
b429f75d65 refactor: link running doc validation to company master
(cherry picked from commit 5a3afea8c7)

# Conflicts:
#	erpnext/setup/doctype/company/company.js
#	erpnext/setup/doctype/company/company.py
2024-03-20 14:13:20 +00:00
ruthra kumar
fab5c1170d chore: rename entry point
(cherry picked from commit 5fe0b20be1)
2024-03-20 14:13:19 +00:00
ruthra kumar
d496a1e58e chore: move status and error log to their own section
(cherry picked from commit 3cec62d4f8)
2024-03-20 14:13:19 +00:00
ruthra kumar
6ae9eb250f refactor: minor UI tweaks
(cherry picked from commit 0455d0c46c)
2024-03-20 14:13:19 +00:00
ruthra kumar
5e590389f3 refactor: exception propogation
(cherry picked from commit 4a55240e63)
2024-03-20 14:13:18 +00:00
ruthra kumar
1110dd93ff chore: code cleanup
(cherry picked from commit eea260b9f9)
2024-03-20 14:13:17 +00:00
ruthra kumar
0ea9ce7a5a refactor: better method naming
(cherry picked from commit 30463657bf)
2024-03-20 14:13:17 +00:00
ruthra kumar
cf6cb80d18 refactor: barebones hook on all doctypes with 'company' field
(cherry picked from commit ec194ef076)
2024-03-20 14:13:16 +00:00
ruthra kumar
e908003358 refactor: make sure only one task is running for doc
(cherry picked from commit 78c9cc63b1)
2024-03-20 14:13:16 +00:00
ruthra kumar
e142daca7f chore: hide docfield in list view
(cherry picked from commit 98afb4d468)
2024-03-20 14:13:15 +00:00
ruthra kumar
962105bc87 refactor: validations to prevent duplicate jobs
(cherry picked from commit 31a2da552b)
2024-03-20 14:13:15 +00:00
ruthra kumar
e600109872 refactor: no copy on summary table and more validations
(cherry picked from commit 55e93b3fe1)
2024-03-20 14:13:15 +00:00
ruthra kumar
97ed905627 refactor: reset all flags and remove unwanted code
(cherry picked from commit 2dbe68a09d)
2024-03-20 14:13:14 +00:00
ruthra kumar
c38cfd14f3 chore: show correct status in list view
(cherry picked from commit 1014940953)
2024-03-20 14:13:14 +00:00
ruthra kumar
341e467056 refactor: validate status before running events
(cherry picked from commit 86b5e2e277)
2024-03-20 14:13:14 +00:00
ruthra kumar
833df2c76b refactor: make Excluded doctype table read only
(cherry picked from commit 7c4cff2649)
2024-03-20 14:13:13 +00:00
ruthra kumar
a303788c71 chore: remove unwanted UI code
(cherry picked from commit b98a5e4edc)
2024-03-20 14:13:13 +00:00
ruthra kumar
0d791f594f refactor: use separate child table for summary
(cherry picked from commit 49d3bcbc8d)
2024-03-20 14:13:13 +00:00
ruthra kumar
b1367e839c refactor: chained callback
(cherry picked from commit b12ca65fcc)
2024-03-20 14:13:12 +00:00
ruthra kumar
e56138ddb0 refactor: reorder flags in Tasks section
(cherry picked from commit cccb2d5141)
2024-03-20 14:13:12 +00:00
ruthra kumar
c9d77044b0 refactor: use flags to decide on current stage
(cherry picked from commit 6a77d86a53)

# Conflicts:
#	erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py
2024-03-20 14:13:12 +00:00
ruthra kumar
5542985e25 refactor: UI trigger
(cherry picked from commit 8944ab8b6a)
2024-03-20 14:13:11 +00:00
ruthra kumar
52d22d8b55 refactor: tasks section and UI niceties
(cherry picked from commit d0dc2c6e77)
2024-03-20 14:13:11 +00:00
ruthra kumar
7280a76f73 refactor: set status and trigger job on submit
(cherry picked from commit 6fbb67b1d2)
2024-03-20 14:13:10 +00:00
ruthra kumar
07c98146c5 refactor: more options for 'status' and move it to top
(cherry picked from commit 0d65d878de)

# Conflicts:
#	erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
2024-03-20 14:13:10 +00:00
Ankush Menat
e922ac7c31 fix: style for tax breakup
(cherry picked from commit 967540da18)

# Conflicts:
#	erpnext/public/scss/erpnext.scss
2024-03-20 13:12:16 +00:00
Gursheen Anand
bba1ac5735 fix: use Text Editor for rendering tax breakup table
(cherry picked from commit 1c63983873)

# Conflicts:
#	erpnext/accounts/doctype/pos_invoice/pos_invoice.py
#	erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
#	erpnext/accounts/doctype/sales_invoice/sales_invoice.py
#	erpnext/buying/doctype/purchase_order/purchase_order.json
#	erpnext/buying/doctype/purchase_order/purchase_order.py
#	erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
#	erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
#	erpnext/selling/doctype/quotation/quotation.json
#	erpnext/selling/doctype/quotation/quotation.py
#	erpnext/selling/doctype/sales_order/sales_order.py
#	erpnext/stock/doctype/delivery_note/delivery_note.json
#	erpnext/stock/doctype/delivery_note/delivery_note.py
#	erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
2024-03-20 13:12:15 +00:00
barredterra
d0a0a35d72 chore: remove accidentally added file 2024-03-19 12:53:20 +01:00
barredterra
3b2044dcd7 chore: resolve conflicts 2024-03-19 12:46:14 +01:00
barredterra
7f2a54d95b refactor: usage of in_list
(cherry picked from commit d238751e6b)

# Conflicts:
#	erpnext/accounts/doctype/payment_entry/payment_entry.js
#	erpnext/buying/doctype/purchase_order/purchase_order.js
#	erpnext/public/js/controllers/accounts.js
#	erpnext/public/js/controllers/buying.js
#	erpnext/public/js/controllers/transaction.js
#	erpnext/public/js/utils/sales_common.js
#	erpnext/templates/form_grid/item_grid.html
2024-03-19 11:12:58 +00:00
Danny
ee7bd98878 fix: pass empty string email content of pos invoice 2024-03-18 10:47:42 -04:00
Gursheen Anand
fe3bee44e2 fix: show correct variance for durations with no vouchers
(cherry picked from commit bc78bc33f1)
2024-03-18 05:53:57 +00:00
Gursheen Anand
c3b8c00070 test: sales partner targets with invoices
(cherry picked from commit 1a3ea0c108)
2024-03-18 05:53:57 +00:00
Gursheen Anand
f9ab763cc8 fix: achieved targets for sales partners
(cherry picked from commit 1ac888715c)
2024-03-18 05:53:57 +00:00
Nihantra C. Patel
819ced4cb3 fix: Add to Cart button width for Mobile/Tablet 2024-03-05 17:24:17 +05:30
780 changed files with 11393 additions and 8012 deletions

View File

@@ -28,4 +28,7 @@ b147b85e6ac19a9220cd1e2958a6ebd99373283a
494bd9ef78313436f0424b918f200dab8fc7c20b
# bulk format python code with black
baec607ff5905b1c67531096a9cf50ec7ff00a5d
baec607ff5905b1c67531096a9cf50ec7ff00a5d
# ruff
4d34b1ead73baf4c5430a2ecbe44b9e8468d7626

View File

@@ -23,7 +23,7 @@ jobs:
run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules
- name: Download semgrep
run: pip install semgrep==0.97.0
run: pip install semgrep
- name: Run Semgrep rules
run: semgrep ci --config ./frappe-semgrep-rules/rules --config r/python.lang.correctness

View File

@@ -65,28 +65,18 @@ repos:
.*/loan_write_off.js
)$
- repo: https://github.com/PyCQA/flake8
rev: 5.0.4
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.0
hooks:
- id: flake8
additional_dependencies: [
'flake8-bugbear',
]
args: ['--config', '.github/helper/.flake8_strict']
exclude: ".*setup.py$"
- id: ruff
name: "Run ruff import sorter"
args: ["--select=I", "--fix"]
- repo: https://github.com/adityahase/black
rev: 9cb0a69f4d0030cdf687eddf314468b39ed54119
hooks:
- id: black
additional_dependencies: ['click==8.0.4']
- repo: https://github.com/PyCQA/isort
rev: 5.12.0
hooks:
- id: isort
exclude: ".*setup.py$"
- id: ruff
name: "Run ruff linter"
- id: ruff-format
name: "Run ruff formatter"
ci:
autoupdate_schedule: weekly

View File

@@ -3,7 +3,7 @@ import inspect
import frappe
__version__ = "14.65.7"
__version__ = "14.72.2"
def get_default_company(user=None):
@@ -36,10 +36,8 @@ def get_default_cost_center(company):
if not frappe.flags.company_cost_center:
frappe.flags.company_cost_center = {}
if not company in frappe.flags.company_cost_center:
frappe.flags.company_cost_center[company] = frappe.get_cached_value(
"Company", company, "cost_center"
)
if company not in frappe.flags.company_cost_center:
frappe.flags.company_cost_center[company] = frappe.get_cached_value("Company", company, "cost_center")
return frappe.flags.company_cost_center[company]
@@ -47,7 +45,7 @@ def get_company_currency(company):
"""Returns the default company currency"""
if not frappe.flags.company_currency:
frappe.flags.company_currency = {}
if not company in frappe.flags.company_currency:
if company not in frappe.flags.company_currency:
frappe.flags.company_currency[company] = frappe.db.get_value(
"Company", company, "default_currency", cache=True
)
@@ -81,7 +79,7 @@ def is_perpetual_inventory_enabled(company):
if not hasattr(frappe.local, "enable_perpetual_inventory"):
frappe.local.enable_perpetual_inventory = {}
if not company in frappe.local.enable_perpetual_inventory:
if company not in frappe.local.enable_perpetual_inventory:
frappe.local.enable_perpetual_inventory[company] = (
frappe.get_cached_value("Company", company, "enable_perpetual_inventory") or 0
)
@@ -96,7 +94,7 @@ def get_default_finance_book(company=None):
if not hasattr(frappe.local, "default_finance_book"):
frappe.local.default_finance_book = {}
if not company in frappe.local.default_finance_book:
if company not in frappe.local.default_finance_book:
frappe.local.default_finance_book[company] = frappe.get_cached_value(
"Company", company, "default_finance_book"
)
@@ -108,7 +106,7 @@ def get_party_account_type(party_type):
if not hasattr(frappe.local, "party_account_types"):
frappe.local.party_account_types = {}
if not party_type in frappe.local.party_account_types:
if party_type not in frappe.local.party_account_types:
frappe.local.party_account_types[party_type] = (
frappe.db.get_value("Party Type", party_type, "account_type") or ""
)

View File

@@ -11,14 +11,14 @@ class ERPNextAddress(Address):
def validate(self):
self.validate_reference()
self.update_compnay_address()
super(ERPNextAddress, self).validate()
super().validate()
def link_address(self):
"""Link address based on owner"""
if self.is_your_company_address:
return
return super(ERPNextAddress, self).link_address()
return super().link_address()
def update_compnay_address(self):
for link in self.get("links"):
@@ -26,11 +26,11 @@ class ERPNextAddress(Address):
self.is_your_company_address = 1
def validate_reference(self):
if self.is_your_company_address and not [
row for row in self.links if row.link_doctype == "Company"
]:
if self.is_your_company_address and not [row for row in self.links if row.link_doctype == "Company"]:
frappe.throw(
_("Address needs to be linked to a Company. Please add a row for Company in the Links table."),
_(
"Address needs to be linked to a Company. Please add a row for Company in the Links table."
),
title=_("Company Not Linked"),
)

View File

@@ -37,7 +37,7 @@ def get(
filters = frappe.parse_json(filters) or frappe.parse_json(chart.filters_json)
account = filters.get("account")
company = filters.get("company")
filters.get("company")
if not account and chart_name:
frappe.throw(
@@ -83,7 +83,6 @@ def build_result(account, dates, gl_entries):
# get balances in debit
for entry in gl_entries:
# entry date is after the current pointer, so move the pointer forward
while getdate(entry.posting_date) > result[date_index][0]:
date_index += 1
@@ -133,8 +132,6 @@ def get_dates_from_timegrain(from_date, to_date, timegrain):
dates = [get_period_ending(from_date, timegrain)]
while getdate(dates[-1]) < getdate(to_date):
date = get_period_ending(
add_to_date(dates[-1], years=years, months=months, days=days), timegrain
)
date = get_period_ending(add_to_date(dates[-1], years=years, months=months, days=days), timegrain)
dates.append(date)
return dates

View File

@@ -24,14 +24,10 @@ from erpnext.accounts.utils import get_account_currency
def validate_service_stop_date(doc):
"""Validates service_stop_date for Purchase Invoice and Sales Invoice"""
enable_check = (
"enable_deferred_revenue" if doc.doctype == "Sales Invoice" else "enable_deferred_expense"
)
enable_check = "enable_deferred_revenue" if doc.doctype == "Sales Invoice" else "enable_deferred_expense"
old_stop_dates = {}
old_doc = frappe.db.get_all(
"{0} Item".format(doc.doctype), {"parent": doc.name}, ["name", "service_stop_date"]
)
old_doc = frappe.db.get_all(f"{doc.doctype} Item", {"parent": doc.name}, ["name", "service_stop_date"])
for d in old_doc:
old_stop_dates[d.name] = d.service_stop_date or ""
@@ -62,16 +58,14 @@ def build_conditions(process_type, account, company):
)
if account:
conditions += "AND %s='%s'" % (deferred_account, account)
conditions += f"AND {deferred_account}='{account}'"
elif company:
conditions += f"AND p.company = {frappe.db.escape(company)}"
return conditions
def convert_deferred_expense_to_expense(
deferred_process, start_date=None, end_date=None, conditions=""
):
def convert_deferred_expense_to_expense(deferred_process, start_date=None, end_date=None, conditions=""):
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
if not start_date:
@@ -81,16 +75,14 @@ def convert_deferred_expense_to_expense(
# check for the purchase invoice for which GL entries has to be done
invoices = frappe.db.sql_list(
"""
f"""
select distinct item.parent
from `tabPurchase Invoice Item` item, `tabPurchase Invoice` p
where item.service_start_date<=%s and item.service_end_date>=%s
and item.enable_deferred_expense = 1 and item.parent=p.name
and item.docstatus = 1 and ifnull(item.amount, 0) > 0
{0}
""".format(
conditions
),
{conditions}
""",
(end_date, start_date),
) # nosec
@@ -103,9 +95,7 @@ def convert_deferred_expense_to_expense(
send_mail(deferred_process)
def convert_deferred_revenue_to_income(
deferred_process, start_date=None, end_date=None, conditions=""
):
def convert_deferred_revenue_to_income(deferred_process, start_date=None, end_date=None, conditions=""):
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
if not start_date:
@@ -115,16 +105,14 @@ def convert_deferred_revenue_to_income(
# check for the sales invoice for which GL entries has to be done
invoices = frappe.db.sql_list(
"""
f"""
select distinct item.parent
from `tabSales Invoice Item` item, `tabSales Invoice` p
where item.service_start_date<=%s and item.service_end_date>=%s
and item.enable_deferred_revenue = 1 and item.parent=p.name
and item.docstatus = 1 and ifnull(item.amount, 0) > 0
{0}
""".format(
conditions
),
{conditions}
""",
(end_date, start_date),
) # nosec
@@ -243,9 +231,7 @@ def calculate_monthly_amount(
already_booked_amount, already_booked_amount_in_account_currency = get_already_booked_amount(
doc, item
)
base_amount = flt(
item.base_net_amount - already_booked_amount, item.precision("base_net_amount")
)
base_amount = flt(item.base_net_amount - already_booked_amount, item.precision("base_net_amount"))
if account_currency == doc.company_currency:
amount = base_amount
else:
@@ -265,17 +251,13 @@ def calculate_amount(doc, item, last_gl_entry, total_days, total_booking_days, a
if account_currency == doc.company_currency:
amount = base_amount
else:
amount = flt(
item.net_amount * total_booking_days / flt(total_days), item.precision("net_amount")
)
amount = flt(item.net_amount * total_booking_days / flt(total_days), item.precision("net_amount"))
else:
already_booked_amount, already_booked_amount_in_account_currency = get_already_booked_amount(
doc, item
)
base_amount = flt(
item.base_net_amount - already_booked_amount, item.precision("base_net_amount")
)
base_amount = flt(item.base_net_amount - already_booked_amount, item.precision("base_net_amount"))
if account_currency == doc.company_currency:
amount = base_amount
else:
@@ -296,26 +278,22 @@ def get_already_booked_amount(doc, item):
gl_entries_details = frappe.db.sql(
"""
select sum({0}) as total_credit, sum({1}) as total_credit_in_account_currency, voucher_detail_no
select sum({}) as total_credit, sum({}) as total_credit_in_account_currency, voucher_detail_no
from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s
and is_cancelled = 0
group by voucher_detail_no
""".format(
total_credit_debit, total_credit_debit_currency
),
""".format(total_credit_debit, total_credit_debit_currency),
(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name),
as_dict=True,
)
journal_entry_details = frappe.db.sql(
"""
SELECT sum(c.{0}) as total_credit, sum(c.{1}) as total_credit_in_account_currency, reference_detail_no
SELECT sum(c.{}) as total_credit, sum(c.{}) as total_credit_in_account_currency, reference_detail_no
FROM `tabJournal Entry` p , `tabJournal Entry Account` c WHERE p.name = c.parent and
p.company = %s and c.account=%s and c.reference_type=%s and c.reference_name=%s and c.reference_detail_no=%s
and p.docstatus < 2 group by reference_detail_no
""".format(
total_credit_debit, total_credit_debit_currency
),
""".format(total_credit_debit, total_credit_debit_currency),
(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name),
as_dict=True,
)
@@ -337,9 +315,7 @@ def get_already_booked_amount(doc, item):
def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
enable_check = (
"enable_deferred_revenue" if doc.doctype == "Sales Invoice" else "enable_deferred_expense"
)
enable_check = "enable_deferred_revenue" if doc.doctype == "Sales Invoice" else "enable_deferred_expense"
accounts_frozen_upto = frappe.db.get_single_value("Accounts Settings", "acc_frozen_upto")
@@ -384,45 +360,45 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
)
if not amount:
return
gl_posting_date = end_date
prev_posting_date = None
# check if books nor frozen till endate:
if accounts_frozen_upto and getdate(end_date) <= getdate(accounts_frozen_upto):
gl_posting_date = get_last_day(add_days(accounts_frozen_upto, 1))
prev_posting_date = end_date
if via_journal_entry:
book_revenue_via_journal_entry(
doc,
credit_account,
debit_account,
amount,
base_amount,
gl_posting_date,
project,
account_currency,
item.cost_center,
item,
deferred_process,
submit_journal_entry,
)
else:
make_gl_entries(
doc,
credit_account,
debit_account,
against,
amount,
base_amount,
gl_posting_date,
project,
account_currency,
item.cost_center,
item,
deferred_process,
)
gl_posting_date = end_date
prev_posting_date = None
# check if books nor frozen till endate:
if accounts_frozen_upto and getdate(end_date) <= getdate(accounts_frozen_upto):
gl_posting_date = get_last_day(add_days(accounts_frozen_upto, 1))
prev_posting_date = end_date
if via_journal_entry:
book_revenue_via_journal_entry(
doc,
credit_account,
debit_account,
amount,
base_amount,
gl_posting_date,
project,
account_currency,
item.cost_center,
item,
deferred_process,
submit_journal_entry,
)
else:
make_gl_entries(
doc,
credit_account,
debit_account,
against,
amount,
base_amount,
gl_posting_date,
project,
account_currency,
item.cost_center,
item,
deferred_process,
)
# Returned in case of any errors because it tries to submit the same record again and again in case of errors
if frappe.flags.deferred_accounting_error:
@@ -440,9 +416,7 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
via_journal_entry = cint(
frappe.db.get_singles_value("Accounts Settings", "book_deferred_entries_via_journal_entry")
)
submit_journal_entry = cint(
frappe.db.get_singles_value("Accounts Settings", "submit_journal_entries")
)
submit_journal_entry = cint(frappe.db.get_singles_value("Accounts Settings", "submit_journal_entries"))
book_deferred_entries_based_on = frappe.db.get_singles_value(
"Accounts Settings", "book_deferred_entries_based_on"
)
@@ -462,9 +436,7 @@ def process_deferred_accounting(posting_date=None):
posting_date = today()
if not cint(
frappe.db.get_singles_value(
"Accounts Settings", "automatically_process_deferred_accounting_entry"
)
frappe.db.get_singles_value("Accounts Settings", "automatically_process_deferred_accounting_entry")
):
return
@@ -587,16 +559,13 @@ def book_revenue_via_journal_entry(
deferred_process=None,
submit="No",
):
if amount == 0:
return
journal_entry = frappe.new_doc("Journal Entry")
journal_entry.posting_date = posting_date
journal_entry.company = doc.company
journal_entry.voucher_type = (
"Deferred Revenue" if doc.doctype == "Sales Invoice" else "Deferred Expense"
)
journal_entry.voucher_type = "Deferred Revenue" if doc.doctype == "Sales Invoice" else "Deferred Expense"
journal_entry.process_deferred_accounting = deferred_process
debit_entry = {
@@ -645,7 +614,6 @@ def book_revenue_via_journal_entry(
def get_deferred_booking_accounts(doctype, voucher_detail_no, dr_or_cr):
if doctype == "Sales Invoice":
credit_account, debit_account = frappe.db.get_value(
"Sales Invoice Item",

View File

@@ -29,7 +29,7 @@ class Account(NestedSet):
if frappe.local.flags.ignore_update_nsm:
return
else:
super(Account, self).on_update()
super().on_update()
def onload(self):
frozen_accounts_modifier = frappe.db.get_value(
@@ -87,9 +87,7 @@ class Account(NestedSet):
def set_root_and_report_type(self):
if self.parent_account:
par = frappe.db.get_value(
"Account", self.parent_account, ["report_type", "root_type"], as_dict=1
)
par = frappe.db.get_value("Account", self.parent_account, ["report_type", "root_type"], as_dict=1)
if par.report_type:
self.report_type = par.report_type
@@ -144,9 +142,7 @@ class Account(NestedSet):
def validate_root_company_and_sync_account_to_children(self):
# ignore validation while creating new compnay or while syncing to child companies
if (
frappe.local.flags.ignore_root_company_validation or self.flags.ignore_root_company_validation
):
if frappe.local.flags.ignore_root_company_validation or self.flags.ignore_root_company_validation:
return
ancestors = get_root_company(self.company)
if ancestors:
@@ -341,7 +337,7 @@ class Account(NestedSet):
if self.check_gle_exists():
throw(_("Account with existing transaction can not be deleted"))
super(Account, self).on_trash(True)
super().on_trash(True)
@frappe.whitelist()
@@ -349,9 +345,8 @@ class Account(NestedSet):
def get_parent_account(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql(
"""select name from tabAccount
where is_group = 1 and docstatus != 2 and company = %s
and %s like %s order by name limit %s offset %s"""
% ("%s", searchfield, "%s", "%s", "%s"),
where is_group = 1 and docstatus != 2 and company = {}
and {} like {} order by name limit {} offset {}""".format("%s", searchfield, "%s", "%s", "%s"),
(filters["company"], "%%%s%%" % txt, page_len, start),
as_list=1,
)
@@ -409,9 +404,7 @@ def update_account_number(name, account_name, account_number=None, from_descenda
if not account:
return
old_acc_name, old_acc_number = frappe.db.get_value(
"Account", name, ["account_name", "account_number"]
)
old_acc_name, old_acc_number = frappe.db.get_value("Account", name, ["account_name", "account_number"])
# check if account exists in parent company
ancestors = get_ancestors_of("Company", account.company)
@@ -519,7 +512,5 @@ def sync_update_account_number_in_child(
if old_acc_number:
filters["account_number"] = old_acc_number
for d in frappe.db.get_values(
"Account", filters=filters, fieldname=["company", "name"], as_dict=True
):
for d in frappe.db.get_values("Account", filters=filters, fieldname=["company", "name"], as_dict=True):
update_account_number(d["name"], account_name, account_number, from_descendant=True)

View File

@@ -31,7 +31,6 @@ def create_charts(
"tax_rate",
"account_currency",
]:
account_number = cstr(child.get("account_number")).strip()
account_name, account_name_in_db = add_suffix_if_duplicate(
account_name, account_number, accounts
@@ -39,7 +38,9 @@ def create_charts(
is_group = identify_is_group(child)
report_type = (
"Balance Sheet" if root_type in ["Asset", "Liability", "Equity"] else "Profit and Loss"
"Balance Sheet"
if root_type in ["Asset", "Liability", "Equity"]
else "Profit and Loss"
)
account = frappe.get_doc(
@@ -141,7 +142,7 @@ def get_chart(chart_template, existing_company=None):
for fname in os.listdir(path):
fname = frappe.as_unicode(fname)
if fname.endswith(".json"):
with open(os.path.join(path, fname), "r") as f:
with open(os.path.join(path, fname)) as f:
chart = f.read()
if chart and json.loads(chart).get("name") == chart_template:
return json.loads(chart).get("tree")
@@ -173,7 +174,7 @@ def get_charts_for_country(country, with_standard=False):
for fname in os.listdir(path):
fname = frappe.as_unicode(fname)
if (fname.startswith(country_code) or fname.startswith(country)) and fname.endswith(".json"):
with open(os.path.join(path, fname), "r") as f:
with open(os.path.join(path, fname)) as f:
_get_chart_name(f.read())
# if more than one charts, returned then add the standard
@@ -247,7 +248,13 @@ def validate_bank_account(coa, bank_account):
def _get_account_names(account_master):
for account_name, child in account_master.items():
if account_name not in ["account_number", "account_type", "root_type", "is_group", "tax_rate"]:
if account_name not in [
"account_number",
"account_type",
"root_type",
"is_group",
"tax_rate",
]:
accounts.append(account_name)
_get_account_names(child)

View File

@@ -26,7 +26,7 @@ def go():
default_account_types = get_default_account_types()
country_dirs = []
for basepath, folders, files in os.walk(path):
for basepath, _folders, _files in os.walk(path):
basename = os.path.basename(basepath)
if basename.startswith("l10n_"):
country_dirs.append(basename)
@@ -35,9 +35,7 @@ def go():
accounts, charts = {}, {}
country_path = os.path.join(path, country_dir)
manifest = ast.literal_eval(open(os.path.join(country_path, "__openerp__.py")).read())
data_files = (
manifest.get("data", []) + manifest.get("init_xml", []) + manifest.get("update_xml", [])
)
data_files = manifest.get("data", []) + manifest.get("init_xml", []) + manifest.get("update_xml", [])
files_path = [os.path.join(country_path, d) for d in data_files]
xml_roots = get_xml_roots(files_path)
csv_content = get_csv_contents(files_path)
@@ -90,10 +88,10 @@ def get_csv_contents(files_path):
fname = os.path.basename(filepath)
for file_type in ["account.account.template", "account.account.type", "account.chart.template"]:
if fname.startswith(file_type) and fname.endswith(".csv"):
with open(filepath, "r") as csvfile:
with open(filepath) as csvfile:
try:
csv_content.setdefault(file_type, []).append(read_csv_content(csvfile.read()))
except Exception as e:
except Exception:
continue
return csv_content
@@ -138,7 +136,7 @@ def get_account_types(root_list, csv_content, prefix=None):
if csv_content and csv_content[0][0] == "id":
for row in csv_content[1:]:
row_dict = dict(zip(csv_content[0], row))
row_dict = dict(zip(csv_content[0], row, strict=False))
data = {}
if row_dict.get("code") and account_type_map.get(row_dict["code"]):
data["account_type"] = account_type_map[row_dict["code"]]
@@ -150,7 +148,7 @@ def get_account_types(root_list, csv_content, prefix=None):
def make_maps_for_xml(xml_roots, account_types, country_dir):
"""make maps for `charts` and `accounts`"""
for model, root_list in xml_roots.items():
for _model, root_list in xml_roots.items():
for root in root_list:
for node in root[0].findall("record"):
if node.get("model") == "account.account.template":
@@ -186,7 +184,7 @@ def make_maps_for_xml(xml_roots, account_types, country_dir):
def make_maps_for_csv(csv_content, account_types, country_dir):
for content in csv_content.get("account.account.template", []):
for row in content[1:]:
data = dict(zip(content[0], row))
data = dict(zip(content[0], row, strict=False))
account = {
"name": data.get("name"),
"parent_id": data.get("parent_id:id") or data.get("parent_id/id"),
@@ -206,7 +204,7 @@ def make_maps_for_csv(csv_content, account_types, country_dir):
for content in csv_content.get("account.chart.template", []):
for row in content[1:]:
if row:
data = dict(zip(content[0], row))
data = dict(zip(content[0], row, strict=False))
charts.setdefault(data.get("id"), {}).update(
{
"account_root_id": data.get("account_root_id:id") or data.get("account_root_id/id"),
@@ -241,7 +239,7 @@ def make_charts():
if not src.get("name") or not src.get("account_root_id"):
continue
if not src["account_root_id"] in accounts:
if src["account_root_id"] not in accounts:
continue
filename = src["id"][5:] + "_" + chart_id
@@ -255,14 +253,20 @@ def make_charts():
for key, val in chart["tree"].items():
if key in ["name", "parent_id"]:
chart["tree"].pop(key)
if type(val) == dict:
if isinstance(val, dict):
val["root_type"] = ""
if chart:
fpath = os.path.join(
"erpnext", "erpnext", "accounts", "doctype", "account", "chart_of_accounts", filename + ".json"
"erpnext",
"erpnext",
"accounts",
"doctype",
"account",
"chart_of_accounts",
filename + ".json",
)
with open(fpath, "r") as chartfile:
with open(fpath) as chartfile:
old_content = chartfile.read()
if not old_content or (
json.loads(old_content).get("is_active", "No") == "No"

View File

@@ -260,28 +260,20 @@ class TestAccount(unittest.TestCase):
acc.insert()
self.assertTrue(
frappe.db.exists(
"Account", {"account_name": "Test Group Account", "company": "_Test Company 4"}
)
frappe.db.exists("Account", {"account_name": "Test Group Account", "company": "_Test Company 4"})
)
self.assertTrue(
frappe.db.exists(
"Account", {"account_name": "Test Group Account", "company": "_Test Company 5"}
)
frappe.db.exists("Account", {"account_name": "Test Group Account", "company": "_Test Company 5"})
)
# Try renaming child company account
acc_tc_5 = frappe.db.get_value(
"Account", {"account_name": "Test Group Account", "company": "_Test Company 5"}
)
self.assertRaises(
frappe.ValidationError, update_account_number, acc_tc_5, "Test Modified Account"
)
self.assertRaises(frappe.ValidationError, update_account_number, acc_tc_5, "Test Modified Account")
# Rename child company account with allow_account_creation_against_child_company enabled
frappe.db.set_value(
"Company", "_Test Company 5", "allow_account_creation_against_child_company", 1
)
frappe.db.set_value("Company", "_Test Company 5", "allow_account_creation_against_child_company", 1)
update_account_number(acc_tc_5, "Test Modified Account")
self.assertTrue(
@@ -290,9 +282,7 @@ class TestAccount(unittest.TestCase):
)
)
frappe.db.set_value(
"Company", "_Test Company 5", "allow_account_creation_against_child_company", 0
)
frappe.db.set_value("Company", "_Test Company 5", "allow_account_creation_against_child_company", 0)
to_delete = [
"Test Group Account - _TC3",
@@ -317,9 +307,7 @@ class TestAccount(unittest.TestCase):
self.assertEqual(acc.account_currency, "INR")
# Make a JV against this account
make_journal_entry(
"Test Currency Account - _TC", "Miscellaneous Expenses - _TC", 100, submit=True
)
make_journal_entry("Test Currency Account - _TC", "Miscellaneous Expenses - _TC", 100, submit=True)
acc.account_currency = "USD"
self.assertRaises(frappe.ValidationError, acc.save)

View File

@@ -17,16 +17,12 @@ class AccountClosingBalance(Document):
def make_closing_entries(closing_entries, voucher_name, company, closing_date):
accounting_dimensions = get_accounting_dimensions()
previous_closing_entries = get_previous_closing_entries(
company, closing_date, accounting_dimensions
)
previous_closing_entries = get_previous_closing_entries(company, closing_date, accounting_dimensions)
combined_entries = closing_entries + previous_closing_entries
merged_entries = aggregate_with_last_account_closing_balance(
combined_entries, accounting_dimensions
)
merged_entries = aggregate_with_last_account_closing_balance(combined_entries, accounting_dimensions)
for key, value in merged_entries.items():
for _key, value in merged_entries.items():
cle = frappe.new_doc("Account Closing Balance")
cle.update(value)
cle.update(value["dimensions"])

View File

@@ -17,7 +17,8 @@ class AccountingDimension(Document):
self.set_fieldname_and_label()
def validate(self):
if self.document_type in core_doctypes_list + (
if self.document_type in (
*core_doctypes_list,
"Accounting Dimension",
"Project",
"Cost Center",
@@ -25,13 +26,10 @@ class AccountingDimension(Document):
"Company",
"Account",
):
msg = _("Not allowed to create accounting dimension for {0}").format(self.document_type)
frappe.throw(msg)
exists = frappe.db.get_value(
"Accounting Dimension", {"document_type": self.document_type}, ["name"]
)
exists = frappe.db.get_value("Accounting Dimension", {"document_type": self.document_type}, ["name"])
if exists and self.is_new():
frappe.throw(_("Document Type already used as a dimension"))
@@ -89,7 +87,6 @@ def make_dimension_in_accounting_doctypes(doc, doclist=None):
count = 0
for doctype in doclist:
if (doc_count + 1) % 2 == 0:
insert_after_field = "dimension_col_break"
else:
@@ -123,7 +120,7 @@ def add_dimension_to_budget_doctype(df, doc):
df.update(
{
"insert_after": "cost_center",
"depends_on": "eval:doc.budget_against == '{0}'".format(doc.document_type),
"depends_on": f"eval:doc.budget_against == '{doc.document_type}'",
}
)
@@ -157,19 +154,17 @@ def delete_accounting_dimension(doc):
frappe.db.sql(
"""
DELETE FROM `tabCustom Field`
WHERE fieldname = %s
AND dt IN (%s)"""
% ("%s", ", ".join(["%s"] * len(doclist))), # nosec
tuple([doc.fieldname] + doclist),
WHERE fieldname = {}
AND dt IN ({})""".format("%s", ", ".join(["%s"] * len(doclist))), # nosec
tuple([doc.fieldname, *doclist]),
)
frappe.db.sql(
"""
DELETE FROM `tabProperty Setter`
WHERE field_name = %s
AND doc_type IN (%s)"""
% ("%s", ", ".join(["%s"] * len(doclist))), # nosec
tuple([doc.fieldname] + doclist),
WHERE field_name = {}
AND doc_type IN ({})""".format("%s", ", ".join(["%s"] * len(doclist))), # nosec
tuple([doc.fieldname, *doclist]),
)
budget_against_property = frappe.get_doc("Property Setter", "Budget-budget_against-options")
@@ -218,7 +213,6 @@ def get_doctypes_with_dimensions():
def get_accounting_dimensions(as_list=True, filters=None):
if not filters:
filters = {"disabled": 0}
@@ -249,7 +243,6 @@ def get_checks_for_pl_and_bs_accounts():
def get_dimension_with_children(doctype, dimensions):
if isinstance(dimensions, str):
dimensions = [dimensions]
@@ -257,9 +250,7 @@ def get_dimension_with_children(doctype, dimensions):
for dimension in dimensions:
lft, rgt = frappe.db.get_value(doctype, dimension, ["lft", "rgt"])
children = frappe.get_all(
doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]}, order_by="lft"
)
children = frappe.get_all(doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]}, order_by="lft")
all_dimensions += [c.name for c in children]
return all_dimensions

View File

@@ -57,9 +57,7 @@ class TestAccountingDimensionFilter(unittest.TestCase):
def create_accounting_dimension_filter():
if not frappe.db.get_value(
"Accounting Dimension Filter", {"accounting_dimension": "Cost Center"}
):
if not frappe.db.get_value("Accounting Dimension Filter", {"accounting_dimension": "Cost Center"}):
frappe.get_doc(
{
"doctype": "Accounting Dimension Filter",

View File

@@ -67,7 +67,10 @@ class AccountingPeriod(Document):
for doctype_for_closing in self.get_doctypes_for_closing():
self.append(
"closed_documents",
{"document_type": doctype_for_closing.document_type, "closed": doctype_for_closing.closed},
{
"document_type": doctype_for_closing.document_type,
"closed": doctype_for_closing.closed,
},
)

View File

@@ -34,9 +34,7 @@ class TestAccountingPeriod(unittest.TestCase):
ap1 = create_accounting_period(period_name="Test Accounting Period 2")
ap1.save()
doc = create_sales_invoice(
do_not_save=1, cost_center="_Test Company - _TC", warehouse="Stores - _TC"
)
doc = create_sales_invoice(do_not_save=1, cost_center="_Test Company - _TC", warehouse="Stores - _TC")
self.assertRaises(ClosedAccountingPeriod, doc.save)
def tearDown(self):

View File

@@ -37,11 +37,11 @@ class TestBankAccount(unittest.TestCase):
try:
bank_account.validate_iban()
except ValidationError:
msg = "BankAccount.validate_iban() failed for valid IBAN {}".format(iban)
msg = f"BankAccount.validate_iban() failed for valid IBAN {iban}"
self.fail(msg=msg)
for not_iban in invalid_ibans:
bank_account.iban = not_iban
msg = "BankAccount.validate_iban() accepted invalid IBAN {}".format(not_iban)
msg = f"BankAccount.validate_iban() accepted invalid IBAN {not_iban}"
with self.assertRaises(ValidationError, msg=msg):
bank_account.validate_iban()

View File

@@ -27,7 +27,7 @@ class BankClearance(Document):
condition = "and (clearance_date IS NULL or clearance_date='0000-00-00')"
journal_entries = frappe.db.sql(
"""
f"""
select
"Journal Entry" as payment_document, t1.name as payment_entry,
t1.cheque_no as cheque_number, t1.cheque_date,
@@ -41,9 +41,7 @@ class BankClearance(Document):
and ifnull(t1.is_opening, 'No') = 'No' {condition}
group by t2.account, t1.name
order by t1.posting_date ASC, t1.name DESC
""".format(
condition=condition
),
""",
{"account": self.account, "from": self.from_date, "to": self.to_date},
as_dict=1,
)
@@ -52,7 +50,7 @@ class BankClearance(Document):
condition += "and bank_account = %(bank_account)s"
payment_entries = frappe.db.sql(
"""
f"""
select
"Payment Entry" as payment_document, name as payment_entry,
reference_no as cheque_number, reference_date as cheque_date,
@@ -67,9 +65,7 @@ class BankClearance(Document):
{condition}
order by
posting_date ASC, name DESC
""".format(
condition=condition
),
""",
{
"account": self.account,
"from": self.from_date,
@@ -132,11 +128,9 @@ class BankClearance(Document):
query = query.where(loan_repayment.clearance_date.isnull())
if frappe.db.has_column("Loan Repayment", "repay_from_salary"):
query = query.where((loan_repayment.repay_from_salary == 0))
query = query.where(loan_repayment.repay_from_salary == 0)
query = query.orderby(loan_repayment.posting_date).orderby(
loan_repayment.name, order=frappe.qb.desc
)
query = query.orderby(loan_repayment.posting_date).orderby(loan_repayment.name, order=frappe.qb.desc)
loan_repayments = query.run(as_dict=True)

View File

@@ -61,9 +61,7 @@ def get_bank_transactions(bank_account, from_date=None, to_date=None):
def get_account_balance(bank_account, till_date):
# returns account balance till the specified date
account = frappe.db.get_value("Bank Account", bank_account, "account")
filters = frappe._dict(
{"account": account, "report_date": till_date, "include_pos_transactions": 1}
)
filters = frappe._dict({"account": account, "report_date": till_date, "include_pos_transactions": 1})
data = get_entries(filters)
balance_as_per_system = get_balance_on(filters["account"], filters["report_date"])
@@ -76,10 +74,7 @@ def get_account_balance(bank_account, till_date):
amounts_not_reflected_in_system = get_amounts_not_reflected_in_system(filters)
bank_bal = (
flt(balance_as_per_system)
- flt(total_debit)
+ flt(total_credit)
+ amounts_not_reflected_in_system
flt(balance_as_per_system) - flt(total_debit) + flt(total_credit) + amounts_not_reflected_in_system
)
return bank_bal
@@ -377,12 +372,13 @@ def auto_reconcile_vouchers(
)
transaction = frappe.get_doc("Bank Transaction", transaction.name)
account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
matched_trans = 0
for voucher in vouchers:
gl_entry = frappe.db.get_value(
"GL Entry",
dict(
account=account, voucher_type=voucher["payment_doctype"], voucher_no=voucher["payment_name"]
account=account,
voucher_type=voucher["payment_doctype"],
voucher_no=voucher["payment_name"],
),
["credit", "debit"],
as_dict=1,
@@ -731,7 +727,7 @@ def get_lr_matching_query(bank_account, exact_match, filters):
)
if frappe.db.has_column("Loan Repayment", "repay_from_salary"):
query = query.where((loan_repayment.repay_from_salary == 0))
query = query.where(loan_repayment.repay_from_salary == 0)
if exact_match:
query.where(loan_repayment.amount_paid == filters.get("amount"))
@@ -764,7 +760,7 @@ def get_pe_matching_query(
if cint(filter_by_reference_date):
filter_by_date = f"AND reference_date between '{from_reference_date}' and '{to_reference_date}'"
order_by = " reference_date"
if frappe.flags.auto_reconcile_vouchers == True:
if frappe.flags.auto_reconcile_vouchers is True:
filter_by_reference_no = f"AND reference_no = '{transaction.reference_number}'"
return f"""
SELECT
@@ -815,7 +811,7 @@ def get_je_matching_query(
if cint(filter_by_reference_date):
filter_by_date = f"AND je.cheque_date between '{from_reference_date}' and '{to_reference_date}'"
order_by = " je.cheque_date"
if frappe.flags.auto_reconcile_vouchers == True:
if frappe.flags.auto_reconcile_vouchers is True:
filter_by_reference_no = f"AND je.cheque_no = '{transaction.reference_number}'"
return f"""
SELECT

View File

@@ -21,7 +21,7 @@ INVALID_VALUES = ("", None)
class BankStatementImport(DataImport):
def __init__(self, *args, **kwargs):
super(BankStatementImport, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def validate(self):
doc_before_save = self.get_doc_before_save()
@@ -30,7 +30,6 @@ class BankStatementImport(DataImport):
or (doc_before_save and doc_before_save.import_file != self.import_file)
or (doc_before_save and doc_before_save.google_sheets_url != self.google_sheets_url)
):
template_options_dict = {}
column_to_field_map = {}
bank = frappe.get_doc("Bank", self.bank)
@@ -45,7 +44,6 @@ class BankStatementImport(DataImport):
self.validate_google_sheets_url()
def start_import(self):
preview = frappe.get_doc("Bank Statement Import", self.name).get_preview_from_template(
self.import_file, self.google_sheets_url
)
@@ -102,7 +100,7 @@ def download_errored_template(data_import_name):
def parse_data_from_template(raw_data):
data = []
for i, row in enumerate(raw_data):
for _i, row in enumerate(raw_data):
if all(v in INVALID_VALUES for v in row):
# empty row
continue
@@ -112,9 +110,7 @@ def parse_data_from_template(raw_data):
return data
def start_import(
data_import, bank_account, import_file_path, google_sheets_url, bank, template_options
):
def start_import(data_import, bank_account, import_file_path, google_sheets_url, bank, template_options):
"""This method runs in background job"""
update_mapping_db(bank, template_options)

View File

@@ -1,5 +1,3 @@
from typing import Tuple, Union
import frappe
from frappe.utils import flt
from rapidfuzz import fuzz, process
@@ -19,7 +17,7 @@ class AutoMatchParty:
def get(self, key):
return self.__dict__.get(key, None)
def match(self) -> Union[Tuple, None]:
def match(self) -> tuple | None:
result = None
result = AutoMatchbyAccountIBAN(
bank_party_account_number=self.bank_party_account_number,
@@ -50,7 +48,7 @@ class AutoMatchbyAccountIBAN:
result = self.match_account_in_party()
return result
def match_account_in_party(self) -> Union[Tuple, None]:
def match_account_in_party(self) -> tuple | None:
"""Check if there is a IBAN/Account No. match in Customer/Supplier/Employee"""
result = None
parties = get_parties_in_order(self.deposit)
@@ -97,7 +95,7 @@ class AutoMatchbyPartyNameDescription:
def get(self, key):
return self.__dict__.get(key, None)
def match(self) -> Union[Tuple, None]:
def match(self) -> tuple | None:
# fuzzy search by customer/supplier & employee
if not (self.bank_party_name or self.description):
return None
@@ -105,7 +103,7 @@ class AutoMatchbyPartyNameDescription:
result = self.match_party_name_desc_in_party()
return result
def match_party_name_desc_in_party(self) -> Union[Tuple, None]:
def match_party_name_desc_in_party(self) -> tuple | None:
"""Fuzzy search party name and/or description against parties in the system"""
result = None
parties = get_parties_in_order(self.deposit)
@@ -130,7 +128,7 @@ class AutoMatchbyPartyNameDescription:
return result
def fuzzy_search_and_return_result(self, party, names, field) -> Union[Tuple, None]:
def fuzzy_search_and_return_result(self, party, names, field) -> tuple | None:
skip = False
result = process.extract(
query=self.get(field),
@@ -147,7 +145,7 @@ class AutoMatchbyPartyNameDescription:
party_name,
), skip
def process_fuzzy_result(self, result: Union[list, None]):
def process_fuzzy_result(self, result: list | None):
"""
If there are multiple valid close matches return None as result may be faulty.
Return the result only if one accurate match stands out.

View File

@@ -186,9 +186,7 @@ def get_clearance_details(transaction, payment_entry):
"""
gl_bank_account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
gles = get_related_bank_gl_entries(payment_entry.payment_document, payment_entry.payment_entry)
bt_allocations = get_total_allocated_amount(
payment_entry.payment_document, payment_entry.payment_entry
)
bt_allocations = get_total_allocated_amount(payment_entry.payment_document, payment_entry.payment_entry)
unallocated_amount = min(
transaction.unallocated_amount,
@@ -286,7 +284,6 @@ def get_total_allocated_amount(doctype, docname):
def get_paid_amount(payment_entry, currency, gl_bank_account):
if payment_entry.payment_document in ["Payment Entry", "Sales Invoice", "Purchase Invoice"]:
paid_amount_field = "paid_amount"
if payment_entry.payment_document == "Payment Entry":
doc = frappe.get_doc("Payment Entry", payment_entry.payment_entry)
@@ -325,9 +322,7 @@ def get_paid_amount(payment_entry, currency, gl_bank_account):
)
elif payment_entry.payment_document == "Loan Repayment":
return frappe.db.get_value(
payment_entry.payment_document, payment_entry.payment_entry, "amount_paid"
)
return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "amount_paid")
elif payment_entry.payment_document == "Bank Transaction":
dep, wth = frappe.db.get_value(
@@ -337,9 +332,7 @@ def get_paid_amount(payment_entry, currency, gl_bank_account):
else:
frappe.throw(
"Please reconcile {0}: {1} manually".format(
payment_entry.payment_document, payment_entry.payment_entry
)
f"Please reconcile {payment_entry.payment_document}: {payment_entry.payment_entry} manually"
)

View File

@@ -18,12 +18,12 @@ def upload_bank_statement():
fcontent = frappe.local.uploaded_file
fname = frappe.local.uploaded_filename
if frappe.safe_encode(fname).lower().endswith("csv".encode("utf-8")):
if frappe.safe_encode(fname).lower().endswith(b"csv"):
from frappe.utils.csvutils import read_csv_content
rows = read_csv_content(fcontent, False)
elif frappe.safe_encode(fname).lower().endswith("xlsx".encode("utf-8")):
elif frappe.safe_encode(fname).lower().endswith(b"xlsx"):
from frappe.utils.xlsxutils import read_xlsx_file_from_attached_file
rows = read_xlsx_file_from_attached_file(fcontent=fcontent)

View File

@@ -430,9 +430,7 @@ def add_vouchers(gl_account="_Test Bank - _TC"):
mode_of_payment = frappe.get_doc({"doctype": "Mode of Payment", "name": "Cash"})
if not frappe.db.get_value(
"Mode of Payment Account", {"company": "_Test Company", "parent": "Cash"}
):
if not frappe.db.get_value("Mode of Payment Account", {"company": "_Test Company", "parent": "Cash"}):
mode_of_payment.append("accounts", {"company": "_Test Company", "default_account": gl_account})
mode_of_payment.save()

View File

@@ -0,0 +1,100 @@
// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on("Bisect Accounting Statements", {
onload(frm) {
frm.trigger("render_heatmap");
},
refresh(frm) {
frm.add_custom_button(__("Bisect Left"), () => {
frm.trigger("bisect_left");
});
frm.add_custom_button(__("Bisect Right"), () => {
frm.trigger("bisect_right");
});
frm.add_custom_button(__("Up"), () => {
frm.trigger("move_up");
});
frm.add_custom_button(__("Build Tree"), () => {
frm.trigger("build_tree");
});
},
render_heatmap(frm) {
let bisect_heatmap = frm.get_field("bisect_heatmap").$wrapper;
bisect_heatmap.addClass("bisect_heatmap_location");
// milliseconds in a day
let msiad = 24 * 60 * 60 * 1000;
let datapoints = {};
let fr_dt = new Date(frm.doc.from_date).getTime();
let to_dt = new Date(frm.doc.to_date).getTime();
let bisect_start = new Date(frm.doc.current_from_date).getTime();
let bisect_end = new Date(frm.doc.current_to_date).getTime();
for (let x = fr_dt; x <= to_dt; x += msiad) {
let epoch_in_seconds = x / 1000;
if (bisect_start <= x && x <= bisect_end) {
datapoints[epoch_in_seconds] = 1.0;
} else {
datapoints[epoch_in_seconds] = 0.0;
}
}
new frappe.Chart(".bisect_heatmap_location", {
type: "heatmap",
data: {
dataPoints: datapoints,
start: new Date(frm.doc.from_date),
end: new Date(frm.doc.to_date),
},
countLabel: "Bisecting",
discreteDomains: 1,
});
},
bisect_left(frm) {
frm.call({
doc: frm.doc,
method: "bisect_left",
freeze: true,
freeze_message: __("Bisecting Left ..."),
callback: (r) => {
frm.trigger("render_heatmap");
},
});
},
bisect_right(frm) {
frm.call({
doc: frm.doc,
freeze: true,
freeze_message: __("Bisecting Right ..."),
method: "bisect_right",
callback: (r) => {
frm.trigger("render_heatmap");
},
});
},
move_up(frm) {
frm.call({
doc: frm.doc,
freeze: true,
freeze_message: __("Moving up in tree ..."),
method: "move_up",
callback: (r) => {
frm.trigger("render_heatmap");
},
});
},
build_tree(frm) {
frm.call({
doc: frm.doc,
freeze: true,
freeze_message: __("Rebuilding BTree for period ..."),
method: "build_tree",
callback: (r) => {
frm.trigger("render_heatmap");
},
});
},
});

View File

@@ -0,0 +1,194 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2023-09-15 21:28:28.054773",
"default_view": "List",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"section_break_cvfg",
"company",
"column_break_hcam",
"from_date",
"column_break_qxbi",
"to_date",
"column_break_iwny",
"algorithm",
"section_break_8ph9",
"current_node",
"section_break_ngid",
"bisect_heatmap",
"section_break_hmsy",
"bisecting_from",
"current_from_date",
"column_break_uqyd",
"bisecting_to",
"current_to_date",
"section_break_hbyo",
"heading_cppb",
"p_l_summary",
"column_break_aivo",
"balance_sheet_summary",
"b_s_summary",
"column_break_gvwx",
"difference_heading",
"difference"
],
"fields": [
{
"fieldname": "column_break_qxbi",
"fieldtype": "Column Break"
},
{
"fieldname": "from_date",
"fieldtype": "Datetime",
"label": "From Date"
},
{
"fieldname": "to_date",
"fieldtype": "Datetime",
"label": "To Date"
},
{
"default": "BFS",
"fieldname": "algorithm",
"fieldtype": "Select",
"label": "Algorithm",
"options": "BFS\nDFS"
},
{
"fieldname": "column_break_iwny",
"fieldtype": "Column Break"
},
{
"fieldname": "current_node",
"fieldtype": "Link",
"label": "Current Node",
"options": "Bisect Nodes"
},
{
"fieldname": "section_break_hmsy",
"fieldtype": "Section Break"
},
{
"fieldname": "current_from_date",
"fieldtype": "Datetime",
"read_only": 1
},
{
"fieldname": "current_to_date",
"fieldtype": "Datetime",
"read_only": 1
},
{
"fieldname": "column_break_uqyd",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_hbyo",
"fieldtype": "Section Break"
},
{
"fieldname": "p_l_summary",
"fieldtype": "Float",
"read_only": 1
},
{
"fieldname": "b_s_summary",
"fieldtype": "Float",
"read_only": 1
},
{
"fieldname": "difference",
"fieldtype": "Float",
"read_only": 1
},
{
"fieldname": "column_break_aivo",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_gvwx",
"fieldtype": "Column Break"
},
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company"
},
{
"fieldname": "column_break_hcam",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_ngid",
"fieldtype": "Section Break"
},
{
"fieldname": "section_break_8ph9",
"fieldtype": "Section Break",
"hidden": 1
},
{
"fieldname": "bisect_heatmap",
"fieldtype": "HTML",
"label": "Heatmap"
},
{
"fieldname": "heading_cppb",
"fieldtype": "Heading",
"label": "Profit and Loss Summary"
},
{
"fieldname": "balance_sheet_summary",
"fieldtype": "Heading",
"label": "Balance Sheet Summary"
},
{
"fieldname": "difference_heading",
"fieldtype": "Heading",
"label": "Difference"
},
{
"fieldname": "bisecting_from",
"fieldtype": "Heading",
"label": "Bisecting From"
},
{
"fieldname": "bisecting_to",
"fieldtype": "Heading",
"label": "Bisecting To"
},
{
"fieldname": "section_break_cvfg",
"fieldtype": "Section Break"
}
],
"hide_toolbar": 1,
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2023-12-01 16:49:54.073890",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bisect Accounting Statements",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "Administrator",
"share": 1,
"write": 1
}
],
"read_only": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@@ -0,0 +1,206 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import datetime
from collections import deque
from math import floor
import frappe
from dateutil.relativedelta import relativedelta
from frappe import _
from frappe.model.document import Document
from frappe.utils import getdate
from frappe.utils.data import guess_date_format
class BisectAccountingStatements(Document):
def validate(self):
self.validate_dates()
def validate_dates(self):
if getdate(self.from_date) > getdate(self.to_date):
frappe.throw(
_("From Date: {0} cannot be greater than To date: {1}").format(
frappe.bold(self.from_date), frappe.bold(self.to_date)
)
)
def bfs(self, from_date: datetime, to_date: datetime):
# Make Root node
node = frappe.new_doc("Bisect Nodes")
node.root = None
node.period_from_date = from_date
node.period_to_date = to_date
node.insert()
period_queue = deque([node])
while period_queue:
cur_node = period_queue.popleft()
delta = cur_node.period_to_date - cur_node.period_from_date
if delta.days == 0:
continue
else:
cur_floor = floor(delta.days / 2)
next_to_date = cur_node.period_from_date + relativedelta(days=+cur_floor)
left_node = frappe.new_doc("Bisect Nodes")
left_node.period_from_date = cur_node.period_from_date
left_node.period_to_date = next_to_date
left_node.root = cur_node.name
left_node.generated = False
left_node.insert()
cur_node.left_child = left_node.name
period_queue.append(left_node)
next_from_date = cur_node.period_from_date + relativedelta(days=+(cur_floor + 1))
right_node = frappe.new_doc("Bisect Nodes")
right_node.period_from_date = next_from_date
right_node.period_to_date = cur_node.period_to_date
right_node.root = cur_node.name
right_node.generated = False
right_node.insert()
cur_node.right_child = right_node.name
period_queue.append(right_node)
cur_node.save()
def dfs(self, from_date: datetime, to_date: datetime):
# Make Root node
node = frappe.new_doc("Bisect Nodes")
node.root = None
node.period_from_date = from_date
node.period_to_date = to_date
node.insert()
period_stack = [node]
while period_stack:
cur_node = period_stack.pop()
delta = cur_node.period_to_date - cur_node.period_from_date
if delta.days == 0:
continue
else:
cur_floor = floor(delta.days / 2)
next_to_date = cur_node.period_from_date + relativedelta(days=+cur_floor)
left_node = frappe.new_doc("Bisect Nodes")
left_node.period_from_date = cur_node.period_from_date
left_node.period_to_date = next_to_date
left_node.root = cur_node.name
left_node.generated = False
left_node.insert()
cur_node.left_child = left_node.name
period_stack.append(left_node)
next_from_date = cur_node.period_from_date + relativedelta(days=+(cur_floor + 1))
right_node = frappe.new_doc("Bisect Nodes")
right_node.period_from_date = next_from_date
right_node.period_to_date = cur_node.period_to_date
right_node.root = cur_node.name
right_node.generated = False
right_node.insert()
cur_node.right_child = right_node.name
period_stack.append(right_node)
cur_node.save()
@frappe.whitelist()
def build_tree(self):
frappe.db.delete("Bisect Nodes")
# Convert str to datetime format
dt_format = guess_date_format(self.from_date)
from_date = datetime.datetime.strptime(self.from_date, dt_format)
to_date = datetime.datetime.strptime(self.to_date, dt_format)
if self.algorithm == "BFS":
self.bfs(from_date, to_date)
if self.algorithm == "DFS":
self.dfs(from_date, to_date)
# set root as current node
root = frappe.db.get_all("Bisect Nodes", filters={"root": ["is", "not set"]})[0]
self.get_report_summary()
self.current_node = root.name
self.current_from_date = self.from_date
self.current_to_date = self.to_date
self.save()
def get_report_summary(self):
filters = {
"company": self.company,
"filter_based_on": "Date Range",
"period_start_date": self.current_from_date,
"period_end_date": self.current_to_date,
"periodicity": "Yearly",
}
pl_summary = frappe.get_doc("Report", "Profit and Loss Statement")
self.p_l_summary = pl_summary.execute_script_report(filters=filters)[5]
bs_summary = frappe.get_doc("Report", "Balance Sheet")
self.b_s_summary = bs_summary.execute_script_report(filters=filters)[5]
self.difference = abs(self.p_l_summary - self.b_s_summary)
def update_node(self):
current_node = frappe.get_doc("Bisect Nodes", self.current_node)
current_node.balance_sheet_summary = self.b_s_summary
current_node.profit_loss_summary = self.p_l_summary
current_node.difference = self.difference
current_node.generated = True
current_node.save()
def current_node_has_summary_info(self):
"Assertion method"
return frappe.db.get_value("Bisect Nodes", self.current_node, "generated")
def fetch_summary_info_from_current_node(self):
current_node = frappe.get_doc("Bisect Nodes", self.current_node)
self.p_l_summary = current_node.balance_sheet_summary
self.b_s_summary = current_node.profit_loss_summary
self.difference = abs(self.p_l_summary - self.b_s_summary)
def fetch_or_calculate(self):
if self.current_node_has_summary_info():
self.fetch_summary_info_from_current_node()
else:
self.get_report_summary()
self.update_node()
@frappe.whitelist()
def bisect_left(self):
if self.current_node is not None:
cur_node = frappe.get_doc("Bisect Nodes", self.current_node)
if cur_node.left_child is not None:
lft_node = frappe.get_doc("Bisect Nodes", cur_node.left_child)
self.current_node = cur_node.left_child
self.current_from_date = lft_node.period_from_date
self.current_to_date = lft_node.period_to_date
self.fetch_or_calculate()
self.save()
else:
frappe.msgprint(_("No more children on Left"))
@frappe.whitelist()
def bisect_right(self):
if self.current_node is not None:
cur_node = frappe.get_doc("Bisect Nodes", self.current_node)
if cur_node.right_child is not None:
rgt_node = frappe.get_doc("Bisect Nodes", cur_node.right_child)
self.current_node = cur_node.right_child
self.current_from_date = rgt_node.period_from_date
self.current_to_date = rgt_node.period_to_date
self.fetch_or_calculate()
self.save()
else:
frappe.msgprint(_("No more children on Right"))
@frappe.whitelist()
def move_up(self):
if self.current_node is not None:
cur_node = frappe.get_doc("Bisect Nodes", self.current_node)
if cur_node.root is not None:
root = frappe.get_doc("Bisect Nodes", cur_node.root)
self.current_node = cur_node.root
self.current_from_date = root.period_from_date
self.current_to_date = root.period_to_date
self.fetch_or_calculate()
self.save()
else:
frappe.msgprint(_("Reached Root"))

View File

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

View File

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

View File

@@ -0,0 +1,97 @@
{
"actions": [],
"autoname": "autoincrement",
"creation": "2023-09-27 14:56:38.112462",
"default_view": "List",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"root",
"left_child",
"right_child",
"period_from_date",
"period_to_date",
"difference",
"balance_sheet_summary",
"profit_loss_summary",
"generated"
],
"fields": [
{
"fieldname": "root",
"fieldtype": "Link",
"label": "Root",
"options": "Bisect Nodes"
},
{
"fieldname": "left_child",
"fieldtype": "Link",
"label": "Left Child",
"options": "Bisect Nodes"
},
{
"fieldname": "right_child",
"fieldtype": "Link",
"label": "Right Child",
"options": "Bisect Nodes"
},
{
"fieldname": "period_from_date",
"fieldtype": "Datetime",
"label": "Period_from_date"
},
{
"fieldname": "period_to_date",
"fieldtype": "Datetime",
"label": "Period To Date"
},
{
"fieldname": "difference",
"fieldtype": "Float",
"label": "Difference"
},
{
"fieldname": "balance_sheet_summary",
"fieldtype": "Float",
"label": "Balance Sheet Summary"
},
{
"fieldname": "profit_loss_summary",
"fieldtype": "Float",
"label": "Profit and Loss Summary"
},
{
"default": "0",
"fieldname": "generated",
"fieldtype": "Check",
"label": "Generated"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2023-12-01 17:46:12.437996",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bisect Nodes",
"naming_rule": "Autoincrement",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Administrator",
"share": 1,
"write": 1
}
],
"read_only": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@@ -0,0 +1,29 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class BisectNodes(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
balance_sheet_summary: DF.Float
difference: DF.Float
generated: DF.Check
left_child: DF.Link | None
name: DF.Int | None
period_from_date: DF.Datetime | None
period_to_date: DF.Datetime | None
profit_loss_summary: DF.Float
right_child: DF.Link | None
root: DF.Link | None
# end: auto-generated types
pass

View File

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

View File

@@ -40,10 +40,11 @@ class Budget(Document):
select
b.name, ba.account from `tabBudget` b, `tabBudget Account` ba
where
ba.parent = b.name and b.docstatus < 2 and b.company = %s and %s=%s and
b.fiscal_year=%s and b.name != %s and ba.account in (%s) """
% ("%s", budget_against_field, "%s", "%s", "%s", ",".join(["%s"] * len(accounts))),
(self.company, budget_against, self.fiscal_year, self.name) + tuple(accounts),
ba.parent = b.name and b.docstatus < 2 and b.company = {} and {}={} and
b.fiscal_year={} and b.name != {} and ba.account in ({}) """.format(
"%s", budget_against_field, "%s", "%s", "%s", ",".join(["%s"] * len(accounts))
),
(self.company, budget_against, self.fiscal_year, self.name, *tuple(accounts)),
as_dict=1,
)
@@ -66,12 +67,14 @@ class Budget(Document):
if account_details.is_group:
frappe.throw(_("Budget cannot be assigned against Group Account {0}").format(d.account))
elif account_details.company != self.company:
frappe.throw(_("Account {0} does not belongs to company {1}").format(d.account, self.company))
frappe.throw(
_("Account {0} does not belongs to company {1}").format(d.account, self.company)
)
elif account_details.report_type != "Profit and Loss":
frappe.throw(
_("Budget cannot be assigned against {0}, as it's not an Income or Expense account").format(
d.account
)
_(
"Budget cannot be assigned against {0}, as it's not an Income or Expense account"
).format(d.account)
)
if d.account in account_list:
@@ -118,9 +121,7 @@ def validate_expense_against_budget(args, expense_amount=0):
"Company", args.get("company"), "exception_budget_approver_role"
)
if not frappe.get_cached_value(
"Budget", {"fiscal_year": args.fiscal_year, "company": args.company}
): # nosec
if not frappe.get_cached_value("Budget", {"fiscal_year": args.fiscal_year, "company": args.company}): # nosec
return
if not args.account:
@@ -151,30 +152,24 @@ def validate_expense_against_budget(args, expense_amount=0):
and args.account
and (frappe.get_cached_value("Account", args.account, "root_type") == "Expense")
):
doctype = dimension.get("document_type")
if frappe.get_cached_value("DocType", doctype, "is_tree"):
lft, rgt = frappe.get_cached_value(doctype, args.get(budget_against), ["lft", "rgt"])
condition = """and exists(select name from `tab%s`
where lft<=%s and rgt>=%s and name=b.%s)""" % (
doctype,
lft,
rgt,
budget_against,
) # nosec
condition = f"""and exists(select name from `tab{doctype}`
where lft<={lft} and rgt>={rgt} and name=b.{budget_against})""" # nosec
args.is_tree = True
else:
condition = "and b.%s=%s" % (budget_against, frappe.db.escape(args.get(budget_against)))
condition = f"and b.{budget_against}={frappe.db.escape(args.get(budget_against))}"
args.is_tree = False
args.budget_against_field = budget_against
args.budget_against_doctype = doctype
budget_records = frappe.db.sql(
"""
f"""
select
b.{budget_against_field} as budget_against, ba.budget_amount, b.monthly_distribution,
b.{budget_against} as budget_against, ba.budget_amount, b.monthly_distribution,
ifnull(b.applicable_on_material_request, 0) as for_material_request,
ifnull(applicable_on_purchase_order, 0) as for_purchase_order,
ifnull(applicable_on_booking_actual_expenses,0) as for_actual_expenses,
@@ -187,9 +182,7 @@ def validate_expense_against_budget(args, expense_amount=0):
b.name=ba.parent and b.fiscal_year=%s
and ba.account=%s and b.docstatus=1
{condition}
""".format(
condition=condition, budget_against_field=budget_against
),
""",
(args.fiscal_year, args.account),
as_dict=True,
) # nosec
@@ -201,12 +194,18 @@ def validate_expense_against_budget(args, expense_amount=0):
def validate_budget_records(args, budget_records, expense_amount):
for budget in budget_records:
if flt(budget.budget_amount):
amount = expense_amount or get_amount(args, budget)
yearly_action, monthly_action = get_actions(args, budget)
args["for_material_request"] = budget.for_material_request
args["for_purchase_order"] = budget.for_purchase_order
if yearly_action in ("Stop", "Warn"):
compare_expense_with_budget(
args, flt(budget.budget_amount), _("Annual"), yearly_action, budget.budget_against, amount
args,
flt(budget.budget_amount),
_("Annual"),
yearly_action,
budget.budget_against,
expense_amount,
)
if monthly_action in ["Stop", "Warn"]:
@@ -217,18 +216,32 @@ def validate_budget_records(args, budget_records, expense_amount):
args["month_end_date"] = get_last_day(args.posting_date)
compare_expense_with_budget(
args, budget_amount, _("Accumulated Monthly"), monthly_action, budget.budget_against, amount
args,
budget_amount,
_("Accumulated Monthly"),
monthly_action,
budget.budget_against,
expense_amount,
)
def compare_expense_with_budget(args, budget_amount, action_for, action, budget_against, amount=0):
actual_expense = get_actual_expense(args)
total_expense = actual_expense + amount
args.actual_expense, args.requested_amount, args.ordered_amount = get_actual_expense(args), 0, 0
if not amount:
args.requested_amount, args.ordered_amount = get_requested_amount(args), get_ordered_amount(args)
if args.get("doctype") == "Material Request" and args.for_material_request:
amount = args.requested_amount + args.ordered_amount
elif args.get("doctype") == "Purchase Order" and args.for_purchase_order:
amount = args.ordered_amount
total_expense = args.actual_expense + amount
if total_expense > budget_amount:
if actual_expense > budget_amount:
if args.actual_expense > budget_amount:
error_tense = _("is already")
diff = actual_expense - budget_amount
diff = args.actual_expense - budget_amount
else:
error_tense = _("will be")
diff = total_expense - budget_amount
@@ -245,9 +258,10 @@ def compare_expense_with_budget(args, budget_amount, action_for, action, budget_
frappe.bold(fmt_money(diff, currency=currency)),
)
if (
frappe.flags.exception_approver_role
and frappe.flags.exception_approver_role in frappe.get_roles(frappe.session.user)
msg += get_expense_breakup(args, currency, budget_against)
if frappe.flags.exception_approver_role and frappe.flags.exception_approver_role in frappe.get_roles(
frappe.session.user
):
action = "Warn"
@@ -257,6 +271,83 @@ def compare_expense_with_budget(args, budget_amount, action_for, action, budget_
frappe.msgprint(msg, indicator="orange", title=_("Budget Exceeded"))
def get_expense_breakup(args, currency, budget_against):
msg = "<hr>Total Expenses booked through - <ul>"
common_filters = frappe._dict(
{
args.budget_against_field: budget_against,
"account": args.account,
"company": args.company,
}
)
msg += (
"<li>"
+ frappe.utils.get_link_to_report(
"General Ledger",
label="Actual Expenses",
filters=common_filters.copy().update(
{
"from_date": frappe.get_cached_value("Fiscal Year", args.fiscal_year, "year_start_date"),
"to_date": frappe.get_cached_value("Fiscal Year", args.fiscal_year, "year_end_date"),
"is_cancelled": 0,
}
),
)
+ " - "
+ frappe.bold(fmt_money(args.actual_expense, currency=currency))
+ "</li>"
)
msg += (
"<li>"
+ frappe.utils.get_link_to_report(
"Material Request",
label="Material Requests",
report_type="Report Builder",
doctype="Material Request",
filters=common_filters.copy().update(
{
"status": [["!=", "Stopped"]],
"docstatus": 1,
"material_request_type": "Purchase",
"schedule_date": [["fiscal year", "2023-2024"]],
"item_code": args.item_code,
"per_ordered": [["<", 100]],
}
),
)
+ " - "
+ frappe.bold(fmt_money(args.requested_amount, currency=currency))
+ "</li>"
)
msg += (
"<li>"
+ frappe.utils.get_link_to_report(
"Purchase Order",
label="Unbilled Orders",
report_type="Report Builder",
doctype="Purchase Order",
filters=common_filters.copy().update(
{
"status": [["!=", "Closed"]],
"docstatus": 1,
"transaction_date": [["fiscal year", "2023-2024"]],
"item_code": args.item_code,
"per_billed": [["<", 100]],
}
),
)
+ " - "
+ frappe.bold(fmt_money(args.ordered_amount, currency=currency))
+ "</li></ul>"
)
return msg
def get_actions(args, budget):
yearly_action = budget.action_if_annual_budget_exceeded
monthly_action = budget.action_if_accumulated_monthly_budget_exceeded
@@ -272,31 +363,15 @@ def get_actions(args, budget):
return yearly_action, monthly_action
def get_amount(args, budget):
amount = 0
if args.get("doctype") == "Material Request" and budget.for_material_request:
amount = (
get_requested_amount(args, budget) + get_ordered_amount(args, budget) + get_actual_expense(args)
)
elif args.get("doctype") == "Purchase Order" and budget.for_purchase_order:
amount = get_ordered_amount(args, budget) + get_actual_expense(args)
return amount
def get_requested_amount(args, budget):
def get_requested_amount(args):
item_code = args.get("item_code")
condition = get_other_condition(args, budget, "Material Request")
condition = get_other_condition(args, "Material Request")
data = frappe.db.sql(
""" select ifnull((sum(child.stock_qty - child.ordered_qty) * rate), 0) as amount
from `tabMaterial Request Item` child, `tabMaterial Request` parent where parent.name = child.parent and
child.item_code = %s and parent.docstatus = 1 and child.stock_qty > child.ordered_qty and {0} and
parent.material_request_type = 'Purchase' and parent.status != 'Stopped'""".format(
condition
),
child.item_code = %s and parent.docstatus = 1 and child.stock_qty > child.ordered_qty and {} and
parent.material_request_type = 'Purchase' and parent.status != 'Stopped'""".format(condition),
item_code,
as_list=1,
)
@@ -304,17 +379,15 @@ def get_requested_amount(args, budget):
return data[0][0] if data else 0
def get_ordered_amount(args, budget):
def get_ordered_amount(args):
item_code = args.get("item_code")
condition = get_other_condition(args, budget, "Purchase Order")
condition = get_other_condition(args, "Purchase Order")
data = frappe.db.sql(
""" select ifnull(sum(child.amount - child.billed_amt), 0) as amount
f""" select ifnull(sum(child.amount - child.billed_amt), 0) as amount
from `tabPurchase Order Item` child, `tabPurchase Order` parent where
parent.name = child.parent and child.item_code = %s and parent.docstatus = 1 and child.amount > child.billed_amt
and parent.status != 'Closed' and {0}""".format(
condition
),
and parent.status != 'Closed' and {condition}""",
item_code,
as_list=1,
)
@@ -322,12 +395,12 @@ def get_ordered_amount(args, budget):
return data[0][0] if data else 0
def get_other_condition(args, budget, for_doc):
def get_other_condition(args, for_doc):
condition = "expense_account = '%s'" % (args.expense_account)
budget_against_field = args.get("budget_against_field")
if budget_against_field and args.get(budget_against_field):
condition += " and child.%s = '%s'" % (budget_against_field, args.get(budget_against_field))
condition += f" and child.{budget_against_field} = '{args.get(budget_against_field)}'"
if args.get("fiscal_year"):
date_field = "schedule_date" if for_doc == "Material Request" else "transaction_date"
@@ -335,12 +408,8 @@ def get_other_condition(args, budget, for_doc):
"Fiscal Year", args.get("fiscal_year"), ["year_start_date", "year_end_date"]
)
condition += """ and parent.%s
between '%s' and '%s' """ % (
date_field,
start_date,
end_date,
)
condition += f""" and parent.{date_field}
between '{start_date}' and '{end_date}' """
return condition
@@ -359,21 +428,17 @@ def get_actual_expense(args):
args.update(lft_rgt)
condition2 = """and exists(select name from `tab{doctype}`
condition2 = f"""and exists(select name from `tab{args.budget_against_doctype}`
where lft>=%(lft)s and rgt<=%(rgt)s
and name=gle.{budget_against_field})""".format(
doctype=args.budget_against_doctype, budget_against_field=budget_against_field # nosec
)
and name=gle.{budget_against_field})"""
else:
condition2 = """and exists(select name from `tab{doctype}`
where name=gle.{budget_against} and
gle.{budget_against} = %({budget_against})s)""".format(
doctype=args.budget_against_doctype, budget_against=budget_against_field
)
condition2 = f"""and exists(select name from `tab{args.budget_against_doctype}`
where name=gle.{budget_against_field} and
gle.{budget_against_field} = %({budget_against_field})s)"""
amount = flt(
frappe.db.sql(
"""
f"""
select sum(gle.debit) - sum(gle.credit)
from `tabGL Entry` gle
where
@@ -384,9 +449,7 @@ def get_actual_expense(args):
and gle.company=%(company)s
and gle.docstatus=1
{condition2}
""".format(
condition1=condition1, condition2=condition2
),
""",
(args),
)[0][0]
) # nosec

View File

@@ -41,9 +41,7 @@ class TestBudget(unittest.TestCase):
budget = make_budget(budget_against="Cost Center")
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
@@ -63,9 +61,7 @@ class TestBudget(unittest.TestCase):
budget = make_budget(budget_against="Cost Center")
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
@@ -97,9 +93,7 @@ class TestBudget(unittest.TestCase):
)
fiscal_year = get_fiscal_year(nowdate())[0]
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
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)
mr = frappe.get_doc(
@@ -138,9 +132,7 @@ class TestBudget(unittest.TestCase):
)
fiscal_year = get_fiscal_year(nowdate())[0]
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
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)
po = create_purchase_order(transaction_date=nowdate(), do_not_submit=True)
@@ -158,9 +150,7 @@ class TestBudget(unittest.TestCase):
budget = make_budget(budget_against="Project")
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
project = frappe.get_value("Project", {"project_name": "_Test Project"})
@@ -223,7 +213,7 @@ class TestBudget(unittest.TestCase):
if month > 9:
month = 9
for i in range(month + 1):
for _i in range(month + 1):
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC",
@@ -237,9 +227,7 @@ class TestBudget(unittest.TestCase):
frappe.db.get_value("GL Entry", {"voucher_type": "Journal Entry", "voucher_no": jv.name})
)
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
self.assertRaises(BudgetError, jv.cancel)
@@ -255,7 +243,7 @@ class TestBudget(unittest.TestCase):
month = 9
project = frappe.get_value("Project", {"project_name": "_Test Project"})
for i in range(month + 1):
for _i in range(month + 1):
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC",
@@ -270,9 +258,7 @@ class TestBudget(unittest.TestCase):
frappe.db.get_value("GL Entry", {"voucher_type": "Journal Entry", "voucher_no": jv.name})
)
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
self.assertRaises(BudgetError, jv.cancel)
@@ -284,9 +270,7 @@ class TestBudget(unittest.TestCase):
set_total_expense_zero(nowdate(), "cost_center", "_Test Cost Center 2 - _TC")
budget = make_budget(budget_against="Cost Center", cost_center="_Test Company - _TC")
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
@@ -316,9 +300,7 @@ class TestBudget(unittest.TestCase):
).insert(ignore_permissions=True)
budget = make_budget(budget_against="Cost Center", cost_center=cost_center)
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
@@ -423,13 +405,11 @@ def make_budget(**args):
fiscal_year = get_fiscal_year(nowdate())[0]
if budget_against == "Project":
project_name = "{0}%".format("_Test Project/" + fiscal_year)
project_name = "{}%".format("_Test Project/" + fiscal_year)
budget_list = frappe.get_all("Budget", fields=["name"], filters={"name": ("like", project_name)})
else:
cost_center_name = "{0}%".format(cost_center or "_Test Cost Center - _TC/" + fiscal_year)
budget_list = frappe.get_all(
"Budget", fields=["name"], filters={"name": ("like", cost_center_name)}
)
cost_center_name = "{}%".format(cost_center or "_Test Cost Center - _TC/" + fiscal_year)
budget_list = frappe.get_all("Budget", fields=["name"], filters={"name": ("like", cost_center_name)})
for d in budget_list:
frappe.db.sql("delete from `tabBudget` where name = %(name)s", d)
frappe.db.sql("delete from `tabBudget Account` where parent = %(name)s", d)
@@ -451,24 +431,18 @@ def make_budget(**args):
budget.action_if_annual_budget_exceeded = "Stop"
budget.action_if_accumulated_monthly_budget_exceeded = "Ignore"
budget.budget_against = budget_against
budget.append(
"accounts", {"account": "_Test Account Cost for Goods Sold - _TC", "budget_amount": 200000}
)
budget.append("accounts", {"account": "_Test Account Cost for Goods Sold - _TC", "budget_amount": 200000})
if args.applicable_on_material_request:
budget.applicable_on_material_request = 1
budget.action_if_annual_budget_exceeded_on_mr = (
args.action_if_annual_budget_exceeded_on_mr or "Warn"
)
budget.action_if_annual_budget_exceeded_on_mr = args.action_if_annual_budget_exceeded_on_mr or "Warn"
budget.action_if_accumulated_monthly_budget_exceeded_on_mr = (
args.action_if_accumulated_monthly_budget_exceeded_on_mr or "Warn"
)
if args.applicable_on_purchase_order:
budget.applicable_on_purchase_order = 1
budget.action_if_annual_budget_exceeded_on_po = (
args.action_if_annual_budget_exceeded_on_po or "Warn"
)
budget.action_if_annual_budget_exceeded_on_po = args.action_if_annual_budget_exceeded_on_po or "Warn"
budget.action_if_accumulated_monthly_budget_exceeded_on_po = (
args.action_if_accumulated_monthly_budget_exceeded_on_po or "Warn"
)

View File

@@ -26,9 +26,7 @@ from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import
class ChartofAccountsImporter(Document):
def validate(self):
if self.import_file:
get_coa(
"Chart of Accounts Importer", "All Accounts", file_name=self.import_file, for_validate=1
)
get_coa("Chart of Accounts Importer", "All Accounts", file_name=self.import_file, for_validate=1)
def validate_columns(data):
@@ -104,7 +102,7 @@ def generate_data_from_csv(file_doc, as_dict=False):
file_path = file_doc.get_full_path()
data = []
with open(file_path, "r") as in_file:
with open(file_path) as in_file:
csv_reader = list(csv.reader(in_file))
headers = csv_reader[0]
del csv_reader[0] # delete top row and headers row
@@ -203,10 +201,10 @@ def build_forest(data):
for row in data:
account_name, parent_account, account_number, parent_account_number = row[0:4]
if account_number:
account_name = "{} - {}".format(account_number, account_name)
account_name = f"{account_number} - {account_name}"
if parent_account_number:
parent_account_number = cstr(parent_account_number).strip()
parent_account = "{} - {}".format(parent_account_number, parent_account)
parent_account = f"{parent_account_number} - {parent_account}"
if parent_account == account_name == child:
return [parent_account]
@@ -218,7 +216,7 @@ def build_forest(data):
frappe.bold(parent_account)
)
)
return [child] + parent_account_list
return [child, *parent_account_list]
charts_map, paths = {}, []
@@ -238,12 +236,12 @@ def build_forest(data):
) = i
if not account_name:
error_messages.append("Row {0}: Please enter Account Name".format(line_no))
error_messages.append(f"Row {line_no}: Please enter Account Name")
name = account_name
if account_number:
account_number = cstr(account_number).strip()
account_name = "{} - {}".format(account_number, account_name)
account_name = f"{account_number} - {account_name}"
charts_map[account_name] = {}
charts_map[account_name]["account_name"] = name
@@ -340,9 +338,9 @@ def get_template(template_type, company):
def get_sample_template(writer, company):
currency = frappe.db.get_value("Company", company, "default_currency")
with open(os.path.join(os.path.dirname(__file__), "coa_sample_template.csv"), "r") as f:
with open(os.path.join(os.path.dirname(__file__), "coa_sample_template.csv")) as f:
for row in f:
row = row.strip().split(",") + [currency]
row = [*row.strip().split(","), currency]
writer.writerow(row)
return writer
@@ -451,7 +449,7 @@ def unset_existing_data(company):
"Purchase Taxes and Charges Template",
]:
frappe.db.sql(
'''delete from `tab{0}` where `company`="%s"'''.format(doctype) % (company) # nosec
f'''delete from `tab{doctype}` where `company`="%s"''' % (company) # nosec
)

View File

@@ -31,71 +31,71 @@ def create_or_update_cheque_print_format(template_name):
cheque_print.html = """
<style>
.print-format {
.print-format {{
padding: 0px;
}
@media screen {
.print-format {
}}
@media screen {{
.print-format {{
padding: 0in;
}
}
}}
}}
</style>
<div style="position: relative; top:%(starting_position_from_top_edge)scm">
<div style="width:%(cheque_width)scm;height:%(cheque_height)scm;">
<span style="top:%(acc_pay_dist_from_top_edge)scm; left:%(acc_pay_dist_from_left_edge)scm;
<div style="position: relative; top:{starting_position_from_top_edge}cm">
<div style="width:{cheque_width}cm;height:{cheque_height}cm;">
<span style="top:{acc_pay_dist_from_top_edge}cm; left:{acc_pay_dist_from_left_edge}cm;
border-bottom: solid 1px;border-top:solid 1px; width:2cm;text-align: center; position: absolute;">
%(message_to_show)s
{message_to_show}
</span>
<span style="top:%(date_dist_from_top_edge)scm; left:%(date_dist_from_left_edge)scm;
<span style="top:{date_dist_from_top_edge}cm; left:{date_dist_from_left_edge}cm;
position: absolute;">
{{ frappe.utils.formatdate(doc.reference_date) or '' }}
{{{{ frappe.utils.formatdate(doc.reference_date) or '' }}}}
</span>
<span style="top:%(acc_no_dist_from_top_edge)scm;left:%(acc_no_dist_from_left_edge)scm;
<span style="top:{acc_no_dist_from_top_edge}cm;left:{acc_no_dist_from_left_edge}cm;
position: absolute; min-width: 6cm;">
{{ doc.account_no or '' }}
{{{{ doc.account_no or '' }}}}
</span>
<span style="top:%(payer_name_from_top_edge)scm;left: %(payer_name_from_left_edge)scm;
<span style="top:{payer_name_from_top_edge}cm;left: {payer_name_from_left_edge}cm;
position: absolute; min-width: 6cm;">
{{doc.party_name}}
{{{{doc.party_name}}}}
</span>
<span style="top:%(amt_in_words_from_top_edge)scm; left:%(amt_in_words_from_left_edge)scm;
position: absolute; display: block; width: %(amt_in_word_width)scm;
line-height:%(amt_in_words_line_spacing)scm; word-wrap: break-word;">
{{frappe.utils.money_in_words(doc.base_paid_amount or doc.base_received_amount)}}
<span style="top:{amt_in_words_from_top_edge}cm; left:{amt_in_words_from_left_edge}cm;
position: absolute; display: block; width: {amt_in_word_width}cm;
line-height:{amt_in_words_line_spacing}cm; word-wrap: break-word;">
{{{{frappe.utils.money_in_words(doc.base_paid_amount or doc.base_received_amount)}}}}
</span>
<span style="top:%(amt_in_figures_from_top_edge)scm;left: %(amt_in_figures_from_left_edge)scm;
<span style="top:{amt_in_figures_from_top_edge}cm;left: {amt_in_figures_from_left_edge}cm;
position: absolute; min-width: 4cm;">
{{doc.get_formatted("base_paid_amount") or doc.get_formatted("base_received_amount")}}
{{{{doc.get_formatted("base_paid_amount") or doc.get_formatted("base_received_amount")}}}}
</span>
<span style="top:%(signatory_from_top_edge)scm;left: %(signatory_from_left_edge)scm;
<span style="top:{signatory_from_top_edge}cm;left: {signatory_from_left_edge}cm;
position: absolute; min-width: 6cm;">
{{doc.company}}
{{{{doc.company}}}}
</span>
</div>
</div>""" % {
"starting_position_from_top_edge": doc.starting_position_from_top_edge
</div>""".format(
starting_position_from_top_edge=doc.starting_position_from_top_edge
if doc.cheque_size == "A4"
else 0.0,
"cheque_width": doc.cheque_width,
"cheque_height": doc.cheque_height,
"acc_pay_dist_from_top_edge": doc.acc_pay_dist_from_top_edge,
"acc_pay_dist_from_left_edge": doc.acc_pay_dist_from_left_edge,
"message_to_show": doc.message_to_show if doc.message_to_show else _("Account Pay Only"),
"date_dist_from_top_edge": doc.date_dist_from_top_edge,
"date_dist_from_left_edge": doc.date_dist_from_left_edge,
"acc_no_dist_from_top_edge": doc.acc_no_dist_from_top_edge,
"acc_no_dist_from_left_edge": doc.acc_no_dist_from_left_edge,
"payer_name_from_top_edge": doc.payer_name_from_top_edge,
"payer_name_from_left_edge": doc.payer_name_from_left_edge,
"amt_in_words_from_top_edge": doc.amt_in_words_from_top_edge,
"amt_in_words_from_left_edge": doc.amt_in_words_from_left_edge,
"amt_in_word_width": doc.amt_in_word_width,
"amt_in_words_line_spacing": doc.amt_in_words_line_spacing,
"amt_in_figures_from_top_edge": doc.amt_in_figures_from_top_edge,
"amt_in_figures_from_left_edge": doc.amt_in_figures_from_left_edge,
"signatory_from_top_edge": doc.signatory_from_top_edge,
"signatory_from_left_edge": doc.signatory_from_left_edge,
}
cheque_width=doc.cheque_width,
cheque_height=doc.cheque_height,
acc_pay_dist_from_top_edge=doc.acc_pay_dist_from_top_edge,
acc_pay_dist_from_left_edge=doc.acc_pay_dist_from_left_edge,
message_to_show=doc.message_to_show if doc.message_to_show else _("Account Pay Only"),
date_dist_from_top_edge=doc.date_dist_from_top_edge,
date_dist_from_left_edge=doc.date_dist_from_left_edge,
acc_no_dist_from_top_edge=doc.acc_no_dist_from_top_edge,
acc_no_dist_from_left_edge=doc.acc_no_dist_from_left_edge,
payer_name_from_top_edge=doc.payer_name_from_top_edge,
payer_name_from_left_edge=doc.payer_name_from_left_edge,
amt_in_words_from_top_edge=doc.amt_in_words_from_top_edge,
amt_in_words_from_left_edge=doc.amt_in_words_from_left_edge,
amt_in_word_width=doc.amt_in_word_width,
amt_in_words_line_spacing=doc.amt_in_words_line_spacing,
amt_in_figures_from_top_edge=doc.amt_in_figures_from_top_edge,
amt_in_figures_from_left_edge=doc.amt_in_figures_from_left_edge,
signatory_from_top_edge=doc.signatory_from_top_edge,
signatory_from_left_edge=doc.signatory_from_left_edge,
)
cheque_print.save(ignore_permissions=True)

View File

@@ -125,7 +125,7 @@
"idx": 1,
"is_tree": 1,
"links": [],
"modified": "2022-01-31 13:22:58.916273",
"modified": "2024-04-24 10:55:54.083042",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Cost Center",
@@ -163,6 +163,15 @@
{
"read": 1,
"role": "Purchase User"
},
{
"email": 1,
"export": 1,
"print": 1,
"report": 1,
"role": "Employee",
"select": 1,
"share": 1
}
],
"search_fields": "parent_cost_center, is_group",

View File

@@ -15,9 +15,7 @@ class CostCenter(NestedSet):
def autoname(self):
from erpnext.accounts.utils import get_autoname_with_number
self.name = get_autoname_with_number(
self.cost_center_number, self.cost_center_name, self.company
)
self.name = get_autoname_with_number(self.cost_center_number, self.cost_center_name, self.company)
def validate(self):
self.validate_mandatory()
@@ -90,14 +88,14 @@ class CostCenter(NestedSet):
new_cost_center = get_name_with_abbr(newdn, self.company)
# Validate properties before merging
super(CostCenter, self).before_rename(olddn, new_cost_center, merge, "is_group")
super().before_rename(olddn, new_cost_center, merge, "is_group")
if not merge:
new_cost_center = get_name_with_number(new_cost_center, self.cost_center_number)
return new_cost_center
def after_rename(self, olddn, newdn, merge=False):
super(CostCenter, self).after_rename(olddn, newdn, merge)
super().after_rename(olddn, newdn, merge)
if not merge:
new_cost_center = frappe.db.get_value(

View File

@@ -10,7 +10,6 @@ test_records = frappe.get_test_records("Cost Center")
class TestCostCenter(unittest.TestCase):
def test_cost_center_creation_against_child_node(self):
if not frappe.db.get_value("Cost Center", {"name": "_Test Cost Center 2 - _TC"}):
frappe.get_doc(test_records[1]).insert()

View File

@@ -29,7 +29,7 @@ class InvalidDateError(frappe.ValidationError):
class CostCenterAllocation(Document):
def __init__(self, *args, **kwargs):
super(CostCenterAllocation, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self._skip_from_date_validation = False
def validate(self):
@@ -44,9 +44,7 @@ class CostCenterAllocation(Document):
total_percentage = sum([d.percentage for d in self.get("allocation_percentages", [])])
if total_percentage != 100:
frappe.throw(
_("Total percentage against cost centers should be 100"), WrongPercentageAllocation
)
frappe.throw(_("Total percentage against cost centers should be 100"), WrongPercentageAllocation)
def validate_from_date_based_on_existing_gle(self):
# Check if GLE exists against the main cost center

View File

@@ -18,7 +18,6 @@ class CurrencyExchangeSettings(Document):
def set_parameters_and_result(self):
if self.service_provider == "exchangerate.host":
if not self.access_key:
frappe.throw(
_("Access Key is required for Service Provider: {0}").format(
@@ -53,9 +52,7 @@ class CurrencyExchangeSettings(Document):
transaction_date=nowdate(), to_currency="INR", from_currency="USD"
)
api_url = self.api_endpoint.format(
transaction_date=nowdate(), to_currency="INR", from_currency="USD"
)
api_url = self.api_endpoint.format(transaction_date=nowdate(), to_currency="INR", from_currency="USD")
try:
response = requests.get(api_url, params=params)
@@ -75,14 +72,14 @@ class CurrencyExchangeSettings(Document):
]
except Exception:
frappe.throw(_("Invalid result key. Response:") + " " + response.text)
if not isinstance(value, (int, float)):
if not isinstance(value, int | float):
frappe.throw(_("Returned exchange rate is neither integer not float."))
self.url = response.url
@frappe.whitelist()
def get_api_endpoint(service_provider: str = None, use_http: bool = False):
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 == "exchangerate.host":
api = "api.exchangerate.host/convert"

View File

@@ -246,7 +246,6 @@ class ExchangeRateRevaluation(Document):
# Handle Accounts with '0' balance in Account/Base Currency
for d in [x for x in account_details if x.zero_balance]:
if d.balance != 0:
current_exchange_rate = new_exchange_rate = 0
@@ -259,7 +258,8 @@ class ExchangeRateRevaluation(Document):
new_balance_in_account_currency = 0
current_exchange_rate = (
calculate_exchange_rate_using_last_gle(company, d.account, d.party_type, d.party) or 0.0
calculate_exchange_rate_using_last_gle(company, d.account, d.party_type, d.party)
or 0.0
)
gain_loss = new_balance_in_account_currency - (
@@ -313,9 +313,7 @@ class ExchangeRateRevaluation(Document):
revaluation_jv = self.make_jv_for_revaluation()
if revaluation_jv:
frappe.msgprint(
f"Revaluation Journal: {get_link_to_form('Journal Entry', revaluation_jv.name)}"
)
frappe.msgprint(f"Revaluation Journal: {get_link_to_form('Journal Entry', revaluation_jv.name)}")
return {
"revaluation_jv": revaluation_jv.name if revaluation_jv else None,
@@ -372,7 +370,8 @@ class ExchangeRateRevaluation(Document):
journal_account.update(
{
dr_or_cr: flt(
abs(d.get("balance_in_account_currency")), d.precision("balance_in_account_currency")
abs(d.get("balance_in_account_currency")),
d.precision("balance_in_account_currency"),
),
reverse_dr_or_cr: 0,
"debit": 0,
@@ -498,7 +497,9 @@ class ExchangeRateRevaluation(Document):
abs(d.get("balance_in_account_currency")), d.precision("balance_in_account_currency")
),
"cost_center": erpnext.get_default_cost_center(self.company),
"exchange_rate": flt(d.get("current_exchange_rate"), d.precision("current_exchange_rate")),
"exchange_rate": flt(
d.get("current_exchange_rate"), d.precision("current_exchange_rate")
),
"reference_type": "Exchange Rate Revaluation",
"reference_name": self.name,
}
@@ -576,7 +577,7 @@ def calculate_exchange_rate_using_last_gle(company, account, party_type, party):
@frappe.whitelist()
def get_account_details(
company, posting_date, account, party_type=None, party=None, rounding_loss_allowance: float = None
company, posting_date, account, party_type=None, party=None, rounding_loss_allowance: float | None = None
):
if not (company and posting_date):
frappe.throw(_("Company and Posting Date is mandatory"))
@@ -589,7 +590,7 @@ def get_account_details(
frappe.throw(_("Party Type and Party is mandatory for {0} account").format(account_type))
account_details = {}
company_currency = erpnext.get_company_currency(company)
erpnext.get_company_currency(company)
account_details = {
"account_currency": account_currency,
@@ -603,9 +604,7 @@ def get_account_details(
rounding_loss_allowance=rounding_loss_allowance,
)
if account_balance and (
account_balance[0].balance or account_balance[0].balance_in_account_currency
):
if account_balance and (account_balance[0].balance or account_balance[0].balance_in_account_currency):
if account_with_new_balance := ExchangeRateRevaluation.calculate_new_account_balance(
company, posting_date, account_balance
):

View File

@@ -1,21 +1,14 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe import qb
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, flt, today
from erpnext import get_default_cost_center
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
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
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.party import get_party_account
from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
from erpnext.stock.doctype.item.test_item import create_item
class TestExchangeRateRevaluation(AccountsTestMixin, FrappeTestCase):
@@ -73,9 +66,7 @@ class TestExchangeRateRevaluation(AccountsTestMixin, FrappeTestCase):
err.extend("accounts", accounts)
row = err.accounts[0]
row.new_exchange_rate = 85
row.new_balance_in_base_currency = flt(
row.new_exchange_rate * flt(row.balance_in_account_currency)
)
row.new_balance_in_base_currency = flt(row.new_exchange_rate * flt(row.balance_in_account_currency))
row.gain_loss = row.new_balance_in_base_currency - flt(row.balance_in_base_currency)
err.set_total_gain_loss()
err = err.save().submit()
@@ -127,9 +118,9 @@ class TestExchangeRateRevaluation(AccountsTestMixin, FrappeTestCase):
pe.save().submit()
# Cancel the auto created gain/loss JE to simulate balance only in base currency
je = frappe.db.get_all(
"Journal Entry Account", filters={"reference_name": si.name}, pluck="parent"
)[0]
je = frappe.db.get_all("Journal Entry Account", filters={"reference_name": si.name}, pluck="parent")[
0
]
frappe.get_doc("Journal Entry", je).cancel()
err = frappe.new_doc("Exchange Rate Revaluation")
@@ -235,9 +226,9 @@ class TestExchangeRateRevaluation(AccountsTestMixin, FrappeTestCase):
self.assertEqual(flt(acc.debit, precision), 0.0)
self.assertEqual(flt(acc.credit, precision), 0.0)
row = [x for x in je.accounts if x.account == self.debtors_usd][0]
row = next(x for x in je.accounts if x.account == self.debtors_usd)
self.assertEqual(flt(row.credit_in_account_currency, precision), 5.0) # in USD
row = [x for x in je.accounts if x.account != self.debtors_usd][0]
row = next(x for x in je.accounts if x.account != self.debtors_usd)
self.assertEqual(flt(row.debit_in_account_currency, precision), 421.06) # in INR
# total_debit and total_credit will be 0.0, as JV is posting only to account currency fields
@@ -294,5 +285,5 @@ class TestExchangeRateRevaluation(AccountsTestMixin, FrappeTestCase):
"new_balance_in_account_currency": 100.0,
}
for key, val in expected_data.items():
for key, _val in expected_data.items():
self.assertEqual(expected_data.get(key), account_details.get(key))

View File

@@ -82,7 +82,7 @@
"icon": "fa fa-calendar",
"idx": 1,
"links": [],
"modified": "2020-11-05 12:16:53.081573",
"modified": "2024-05-27 17:29:55.560840",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Fiscal Year",
@@ -118,9 +118,21 @@
{
"read": 1,
"role": "Employee"
},
{
"read": 1,
"role": "Accounts Manager"
},
{
"read": 1,
"role": "Stock Manager"
},
{
"read": 1,
"role": "Auditor"
}
],
"show_name_in_global_search": 1,
"sort_field": "name",
"sort_order": "DESC"
}
}

View File

@@ -98,9 +98,9 @@ class FiscalYear(Document):
if overlap:
frappe.throw(
_("Year start date or end date is overlapping with {0}. To avoid please set company").format(
existing.name
),
_(
"Year start date or end date is overlapping with {0}. To avoid please set company"
).format(existing.name),
frappe.NameError,
)
@@ -116,9 +116,9 @@ def check_duplicate_fiscal_year(doc):
not frappe.flags.in_test
):
frappe.throw(
_("Fiscal Year Start Date and Fiscal Year End Date are already set in Fiscal Year {0}").format(
fiscal_year
)
_(
"Fiscal Year Start Date and Fiscal Year End Date are already set in Fiscal Year {0}"
).format(fiscal_year)
)

View File

@@ -63,13 +63,18 @@ class GLEntry(Document):
]:
# Update outstanding amt on against voucher
if (
self.against_voucher_type in ["Journal Entry", "Sales Invoice", "Purchase Invoice", "Fees"]
self.against_voucher_type
in ["Journal Entry", "Sales Invoice", "Purchase Invoice", "Fees"]
and self.against_voucher
and self.flags.update_outstanding == "Yes"
and not frappe.flags.is_reverse_depr_entry
):
update_outstanding_amt(
self.account, self.party_type, self.party, self.against_voucher_type, self.against_voucher
self.account,
self.party_type,
self.party,
self.against_voucher_type,
self.against_voucher,
)
def check_mandatory(self):
@@ -135,12 +140,13 @@ class GLEntry(Document):
and self.company == dimension.company
and dimension.mandatory_for_pl
and not dimension.disabled
and not self.is_cancelled
):
if not self.get(dimension.fieldname):
frappe.throw(
_("Accounting Dimension <b>{0}</b> is required for 'Profit and Loss' account {1}.").format(
dimension.label, self.account
)
_(
"Accounting Dimension <b>{0}</b> is required for 'Profit and Loss' account {1}."
).format(dimension.label, self.account)
)
if (
@@ -148,12 +154,13 @@ class GLEntry(Document):
and self.company == dimension.company
and dimension.mandatory_for_bs
and not dimension.disabled
and not self.is_cancelled
):
if not self.get(dimension.fieldname):
frappe.throw(
_("Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}.").format(
dimension.label, self.account
)
_(
"Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}."
).format(dimension.label, self.account)
)
def check_pl_account(self):
@@ -201,9 +208,7 @@ class GLEntry(Document):
if not self.cost_center:
return
is_group, company = frappe.get_cached_value(
"Cost Center", self.cost_center, ["is_group", "company"]
)
is_group, company = frappe.get_cached_value("Cost Center", self.cost_center, ["is_group", "company"])
if company != self.company:
frappe.throw(
@@ -272,7 +277,7 @@ def update_outstanding_amt(
account, party_type, party, against_voucher_type, against_voucher, on_cancel=False
):
if party_type and party:
party_condition = " and party_type={0} and party={1}".format(
party_condition = " and party_type={} and party={}".format(
frappe.db.escape(party_type), frappe.db.escape(party)
)
else:
@@ -280,23 +285,19 @@ def update_outstanding_amt(
if against_voucher_type == "Sales Invoice":
party_account = frappe.get_cached_value(against_voucher_type, against_voucher, "debit_to")
account_condition = "and account in ({0}, {1})".format(
frappe.db.escape(account), frappe.db.escape(party_account)
)
account_condition = f"and account in ({frappe.db.escape(account)}, {frappe.db.escape(party_account)})"
else:
account_condition = " and account = {0}".format(frappe.db.escape(account))
account_condition = f" and account = {frappe.db.escape(account)}"
# get final outstanding amt
bal = flt(
frappe.db.sql(
"""
f"""
select sum(debit_in_account_currency) - sum(credit_in_account_currency)
from `tabGL Entry`
where against_voucher_type=%s and against_voucher=%s
and voucher_type != 'Invoice Discounting'
{0} {1}""".format(
party_condition, account_condition
),
{party_condition} {account_condition}""",
(against_voucher_type, against_voucher),
)[0][0]
or 0.0
@@ -307,12 +308,10 @@ def update_outstanding_amt(
elif against_voucher_type == "Journal Entry":
against_voucher_amount = flt(
frappe.db.sql(
"""
f"""
select sum(debit_in_account_currency) - sum(credit_in_account_currency)
from `tabGL Entry` where voucher_type = 'Journal Entry' and voucher_no = %s
and account = %s and (against_voucher is null or against_voucher='') {0}""".format(
party_condition
),
and account = %s and (against_voucher is null or against_voucher='') {party_condition}""",
(against_voucher, account),
)[0][0]
)
@@ -331,7 +330,9 @@ def update_outstanding_amt(
# Validation : Outstanding can not be negative for JV
if bal < 0 and not on_cancel:
frappe.throw(
_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal))
_("Outstanding for {0} cannot be less than zero ({1})").format(
against_voucher, fmt_money(bal)
)
)
if against_voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"]:
@@ -404,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(
"UPDATE `tab{}` SET name = %s, to_rename = 0 where name = %s".format(doctype),
f"UPDATE `tab{doctype}` SET name = %s, to_rename = 0 where name = %s",
(newname, oldname),
auto_commit=True,
)

View File

@@ -14,9 +14,7 @@ from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journ
class TestGLEntry(unittest.TestCase):
def test_round_off_entry(self):
frappe.db.set_value("Company", "_Test Company", "round_off_account", "_Test Write Off - _TC")
frappe.db.set_value(
"Company", "_Test Company", "round_off_cost_center", "_Test Cost Center - _TC"
)
frappe.db.set_value("Company", "_Test Company", "round_off_cost_center", "_Test Cost Center - _TC")
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
@@ -73,7 +71,9 @@ class TestGLEntry(unittest.TestCase):
)
self.assertTrue(all(entry.to_rename == 0 for entry in new_gl_entries))
self.assertTrue(all(new.name != old.name for new, old in zip(gl_entries, new_gl_entries)))
self.assertTrue(
all(new.name != old.name for new, old in zip(gl_entries, new_gl_entries, strict=False))
)
new_naming_series_current_value = frappe.db.sql(
"SELECT current from tabSeries where name = %s", naming_series

View File

@@ -55,9 +55,7 @@ class InvoiceDiscounting(AccountsController):
frappe.throw(
_(
"Row({0}): Outstanding Amount cannot be greater than actual Outstanding Amount {1} in {2}"
).format(
record.idx, frappe.bold(actual_outstanding), frappe.bold(record.sales_invoice)
)
).format(record.idx, frappe.bold(actual_outstanding), frappe.bold(record.sales_invoice))
)
def calculate_total_amount(self):
@@ -77,7 +75,9 @@ class InvoiceDiscounting(AccountsController):
self.status = status
self.db_set("status", status)
for d in self.invoices:
frappe.get_doc("Sales Invoice", d.sales_invoice).set_status(update=True, update_modified=False)
frappe.get_doc("Sales Invoice", d.sales_invoice).set_status(
update=True, update_modified=False
)
else:
self.status = "Draft"
if self.docstatus == 1:

View File

@@ -75,8 +75,8 @@ class TestInvoiceDiscounting(unittest.TestCase):
gle = get_gl_entries("Invoice Discounting", inv_disc.name)
expected_gle = {inv.debit_to: [0.0, 200], self.ar_credit: [200, 0.0]}
for i, gle in enumerate(gle):
self.assertEqual([gle.debit, gle.credit], expected_gle.get(gle.account))
for _i, gle_value in enumerate(gle):
self.assertEqual([gle_value.debit, gle_value.credit], expected_gle.get(gle_value.account))
def test_loan_on_submit(self):
inv = create_sales_invoice(rate=300)
@@ -92,9 +92,7 @@ class TestInvoiceDiscounting(unittest.TestCase):
period=60,
)
self.assertEqual(inv_disc.status, "Sanctioned")
self.assertEqual(
inv_disc.loan_end_date, add_days(inv_disc.loan_start_date, inv_disc.loan_period)
)
self.assertEqual(inv_disc.loan_end_date, add_days(inv_disc.loan_start_date, inv_disc.loan_period))
def test_on_disbursed(self):
inv = create_sales_invoice(rate=500)
@@ -262,13 +260,9 @@ class TestInvoiceDiscounting(unittest.TestCase):
je_on_payment.submit()
self.assertEqual(je_on_payment.accounts[0].account, self.ar_discounted)
self.assertEqual(
je_on_payment.accounts[0].credit_in_account_currency, flt(inv.outstanding_amount)
)
self.assertEqual(je_on_payment.accounts[0].credit_in_account_currency, flt(inv.outstanding_amount))
self.assertEqual(je_on_payment.accounts[1].account, self.bank_account)
self.assertEqual(
je_on_payment.accounts[1].debit_in_account_currency, flt(inv.outstanding_amount)
)
self.assertEqual(je_on_payment.accounts[1].debit_in_account_currency, flt(inv.outstanding_amount))
inv.reload()
self.assertEqual(inv.outstanding_amount, 0)
@@ -304,13 +298,9 @@ class TestInvoiceDiscounting(unittest.TestCase):
je_on_payment.submit()
self.assertEqual(je_on_payment.accounts[0].account, self.ar_unpaid)
self.assertEqual(
je_on_payment.accounts[0].credit_in_account_currency, flt(inv.outstanding_amount)
)
self.assertEqual(je_on_payment.accounts[0].credit_in_account_currency, flt(inv.outstanding_amount))
self.assertEqual(je_on_payment.accounts[1].account, self.bank_account)
self.assertEqual(
je_on_payment.accounts[1].debit_in_account_currency, flt(inv.outstanding_amount)
)
self.assertEqual(je_on_payment.accounts[1].debit_in_account_currency, flt(inv.outstanding_amount))
inv.reload()
self.assertEqual(inv.outstanding_amount, 0)

View File

@@ -14,7 +14,7 @@ class ItemTaxTemplate(Document):
def autoname(self):
if self.company and self.title:
abbr = frappe.get_cached_value("Company", self.company, "abbr")
self.name = "{0} - {1}".format(self.title, abbr)
self.name = f"{self.title} - {abbr}"
def validate_tax_accounts(self):
"""Check whether Tax Rate is not entered twice for same Tax Type"""

View File

@@ -171,7 +171,7 @@ frappe.ui.form.on("Journal Entry", {
!(frm.doc.accounts || []).length ||
((frm.doc.accounts || []).length === 1 && !frm.doc.accounts[0].account)
) {
if (in_list(["Bank Entry", "Cash Entry"], frm.doc.voucher_type)) {
if (["Bank Entry", "Cash Entry"].includes(frm.doc.voucher_type)) {
return frappe.call({
type: "GET",
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account",
@@ -283,7 +283,7 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
filters: [[jvd.reference_type, "docstatus", "=", 1]],
};
if (in_list(["Sales Invoice", "Purchase Invoice"], jvd.reference_type)) {
if (["Sales Invoice", "Purchase Invoice"].includes(jvd.reference_type)) {
out.filters.push([jvd.reference_type, "outstanding_amount", "!=", 0]);
// Filter by cost center
if (jvd.cost_center) {
@@ -295,7 +295,7 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
out.filters.push([jvd.reference_type, party_account_field, "=", jvd.account]);
}
if (in_list(["Sales Order", "Purchase Order"], jvd.reference_type)) {
if (["Sales Order", "Purchase Order"].includes(jvd.reference_type)) {
// party_type and party mandatory
frappe.model.validate_missing(jvd, "party_type");
frappe.model.validate_missing(jvd, "party");
@@ -428,7 +428,10 @@ frappe.ui.form.on("Journal Entry Account", {
}
},
cost_center: function (frm, dt, dn) {
erpnext.journal_entry.set_account_details(frm, dt, dn);
// Don't reset for Gain/Loss type journals, as it will make Debit and Credit values '0'
if (frm.doc.voucher_type != "Exchange Gain Or Loss") {
erpnext.journal_entry.set_account_details(frm, dt, dn);
}
},
account: function (frm, dt, dn) {

View File

@@ -557,7 +557,7 @@
"table_fieldname": "payment_entries"
}
],
"modified": "2023-11-23 12:11:04.128015",
"modified": "2024-07-18 15:32:29.413598",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",

View File

@@ -33,7 +33,7 @@ class StockAccountInvalidTransaction(frappe.ValidationError):
class JournalEntry(AccountsController):
def __init__(self, *args, **kwargs):
super(JournalEntry, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def get_feed(self):
return self.voucher_type
@@ -102,7 +102,7 @@ class JournalEntry(AccountsController):
def on_cancel(self):
# References for this Journal are removed on the `on_cancel` event in accounts_controller
super(JournalEntry, self).on_cancel()
super().on_cancel()
self.ignore_linked_doctypes = (
"GL Entry",
"Stock Ledger Entry",
@@ -137,10 +137,7 @@ class JournalEntry(AccountsController):
frappe.get_doc(voucher_type, voucher_no).set_total_advance_paid()
def validate_inter_company_accounts(self):
if (
self.voucher_type == "Inter Company Journal Entry"
and self.inter_company_journal_entry_reference
):
if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
doc = frappe.get_doc("Journal Entry", self.inter_company_journal_entry_reference)
account_currency = frappe.get_cached_value("Company", self.company, "default_currency")
previous_account_currency = frappe.get_cached_value("Company", doc.company, "default_currency")
@@ -286,10 +283,7 @@ class JournalEntry(AccountsController):
asset.set_status()
def update_inter_company_jv(self):
if (
self.voucher_type == "Inter Company Journal Entry"
and self.inter_company_journal_entry_reference
):
if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
frappe.db.set_value(
"Journal Entry",
self.inter_company_journal_entry_reference,
@@ -317,17 +311,25 @@ class JournalEntry(AccountsController):
if d.account == inv_disc_doc.short_term_loan and d.reference_name == inv_disc:
if self.docstatus == 1:
if d.credit > 0:
_validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Sanctioned", d.idx)
_validate_invoice_discounting_status(
inv_disc, inv_disc_doc.status, "Sanctioned", d.idx
)
status = "Disbursed"
elif d.debit > 0:
_validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Disbursed", d.idx)
_validate_invoice_discounting_status(
inv_disc, inv_disc_doc.status, "Disbursed", d.idx
)
status = "Settled"
else:
if d.credit > 0:
_validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Disbursed", d.idx)
_validate_invoice_discounting_status(
inv_disc, inv_disc_doc.status, "Disbursed", d.idx
)
status = "Sanctioned"
elif d.debit > 0:
_validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Settled", d.idx)
_validate_invoice_discounting_status(
inv_disc, inv_disc_doc.status, "Settled", d.idx
)
status = "Disbursed"
break
if status:
@@ -384,10 +386,7 @@ class JournalEntry(AccountsController):
)
def unlink_inter_company_jv(self):
if (
self.voucher_type == "Inter Company Journal Entry"
and self.inter_company_journal_entry_reference
):
if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
frappe.db.set_value(
"Journal Entry",
self.inter_company_journal_entry_reference,
@@ -409,9 +408,9 @@ class JournalEntry(AccountsController):
if account_type in ["Receivable", "Payable"]:
if not (d.party_type and d.party):
frappe.throw(
_("Row {0}: Party Type and Party is required for Receivable / Payable account {1}").format(
d.idx, d.account
)
_(
"Row {0}: Party Type and Party is required for Receivable / Payable account {1}"
).format(d.idx, d.account)
)
elif (
d.party_type
@@ -476,16 +475,18 @@ class JournalEntry(AccountsController):
def system_generated_gain_loss(self):
return (
self.voucher_type == "Exchange Gain Or Loss"
and self.multi_currency
and self.is_system_generated
self.voucher_type == "Exchange Gain Or Loss" and self.multi_currency and self.is_system_generated
)
def validate_against_jv(self):
for d in self.get("accounts"):
if d.reference_type == "Journal Entry":
account_root_type = frappe.get_cached_value("Account", d.account, "root_type")
if account_root_type == "Asset" and flt(d.debit) > 0 and not self.system_generated_gain_loss():
if (
account_root_type == "Asset"
and flt(d.debit) > 0
and not self.system_generated_gain_loss()
):
frappe.throw(
_(
"Row #{0}: For {1}, you can select reference document only if account gets credited"
@@ -567,11 +568,13 @@ class JournalEntry(AccountsController):
if d.reference_type == "Purchase Order" and flt(d.credit) > 0:
frappe.throw(
_("Row {0}: Credit entry can not be linked with a {1}").format(d.idx, d.reference_type)
_("Row {0}: Credit entry can not be linked with a {1}").format(
d.idx, d.reference_type
)
)
# set totals
if not d.reference_name in self.reference_totals:
if d.reference_name not in self.reference_totals:
self.reference_totals[d.reference_name] = 0.0
if self.voucher_type not in ("Deferred Revenue", "Deferred Expense"):
@@ -589,7 +592,10 @@ class JournalEntry(AccountsController):
# check if party and account match
if d.reference_type in ("Sales Invoice", "Purchase Invoice"):
if self.voucher_type in ("Deferred Revenue", "Deferred Expense") and d.reference_detail_no:
if (
self.voucher_type in ("Deferred Revenue", "Deferred Expense")
and d.reference_detail_no
):
debit_or_credit = "Debit" if d.debit else "Credit"
party_account = get_deferred_booking_accounts(
d.reference_type, d.reference_detail_no, debit_or_credit
@@ -598,7 +604,8 @@ class JournalEntry(AccountsController):
else:
if d.reference_type == "Sales Invoice":
party_account = (
get_party_account_based_on_invoice_discounting(d.reference_name) or against_voucher[1]
get_party_account_based_on_invoice_discounting(d.reference_name)
or against_voucher[1]
)
else:
party_account = against_voucher[1]
@@ -722,7 +729,9 @@ class JournalEntry(AccountsController):
if not (self.voucher_type == "Exchange Gain Or Loss" and self.multi_currency):
if self.difference:
frappe.throw(
_("Total Debit must be equal to Total Credit. The difference is {0}").format(self.difference)
_("Total Debit must be equal to Total Credit. The difference is {0}").format(
self.difference
)
)
def set_total_debit_credit(self):
@@ -786,7 +795,6 @@ class JournalEntry(AccountsController):
and self.posting_date
)
):
ignore_exchange_rate = False
if self.get("flags") and self.flags.get("ignore_exchange_rate"):
ignore_exchange_rate = True
@@ -1032,27 +1040,21 @@ class JournalEntry(AccountsController):
self.validate_total_debit_and_credit()
def get_values(self):
cond = (
" and outstanding_amount <= {0}".format(self.write_off_amount)
if flt(self.write_off_amount) > 0
else ""
)
cond = f" and outstanding_amount <= {self.write_off_amount}" if flt(self.write_off_amount) > 0 else ""
if self.write_off_based_on == "Accounts Receivable":
return frappe.db.sql(
"""select name, debit_to as account, customer as party, outstanding_amount
from `tabSales Invoice` where docstatus = 1 and company = %s
and outstanding_amount > 0 %s"""
% ("%s", cond),
from `tabSales Invoice` where docstatus = 1 and company = {}
and outstanding_amount > 0 {}""".format("%s", cond),
self.company,
as_dict=True,
)
elif self.write_off_based_on == "Accounts Payable":
return frappe.db.sql(
"""select name, credit_to as account, supplier as party, outstanding_amount
from `tabPurchase Invoice` where docstatus = 1 and company = %s
and outstanding_amount > 0 %s"""
% ("%s", cond),
from `tabPurchase Invoice` where docstatus = 1 and company = {}
and outstanding_amount > 0 {}""".format("%s", cond),
self.company,
as_dict=True,
)
@@ -1161,7 +1163,7 @@ def get_payment_entry_against_order(
"amount_field_bank": amount_field_bank,
"amount": amount,
"debit_in_account_currency": debit_in_account_currency,
"remarks": "Advance Payment received against {0} {1}".format(dt, dn),
"remarks": f"Advance Payment received against {dt} {dn}",
"is_advance": "Yes",
"bank_account": bank_account,
"journal_entry": journal_entry,
@@ -1200,7 +1202,7 @@ def get_payment_entry_against_invoice(
"amount_field_bank": amount_field_bank,
"amount": amount if amount else abs(ref_doc.outstanding_amount),
"debit_in_account_currency": debit_in_account_currency,
"remarks": "Payment received against {0} {1}. {2}".format(dt, dn, ref_doc.remarks),
"remarks": f"Payment received against {dt} {dn}. {ref_doc.remarks}",
"is_advance": "No",
"bank_account": bank_account,
"journal_entry": journal_entry,
@@ -1226,9 +1228,7 @@ def get_payment_entry(ref_doc, args):
)
je = frappe.new_doc("Journal Entry")
je.update(
{"voucher_type": "Bank Entry", "company": ref_doc.company, "remark": args.get("remarks")}
)
je.update({"voucher_type": "Bank Entry", "company": ref_doc.company, "remark": args.get("remarks")})
party_row = je.append(
"accounts",
@@ -1251,9 +1251,7 @@ def get_payment_entry(ref_doc, args):
bank_row = je.append("accounts")
# Make it bank_details
bank_account = get_default_bank_cash_account(
ref_doc.company, "Bank", account=args.get("bank_account")
)
bank_account = get_default_bank_cash_account(ref_doc.company, "Bank", account=args.get("bank_account"))
if bank_account:
bank_row.update(bank_account)
# Modified to include the posting date for which the exchange rate is required.
@@ -1293,7 +1291,7 @@ def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
return []
return frappe.db.sql(
"""
f"""
SELECT jv.name, jv.posting_date, jv.user_remark
FROM `tabJournal Entry` jv, `tabJournal Entry Account` jv_detail
WHERE jv_detail.parent = jv.name
@@ -1304,16 +1302,14 @@ def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
OR jv_detail.reference_type = ''
)
AND jv.docstatus = 1
AND jv.`{0}` LIKE %(txt)s
AND jv.`{searchfield}` LIKE %(txt)s
ORDER BY jv.name DESC
LIMIT %(limit)s offset %(offset)s
""".format(
searchfield
),
""",
dict(
account=filters.get("account"),
party=cstr(filters.get("party")),
txt="%{0}%".format(txt),
txt=f"%{txt}%",
offset=start,
limit=page_len,
),
@@ -1335,19 +1331,15 @@ def get_outstanding(args):
condition = " and party=%(party)s" if args.get("party") else ""
against_jv_amount = frappe.db.sql(
"""
f"""
select sum(debit_in_account_currency) - sum(credit_in_account_currency)
from `tabJournal Entry Account` where parent=%(docname)s and account=%(account)s {0}
and (reference_type is null or reference_type = '')""".format(
condition
),
from `tabJournal Entry Account` where parent=%(docname)s and account=%(account)s {condition}
and (reference_type is null or reference_type = '')""",
args,
)
against_jv_amount = flt(against_jv_amount[0][0]) if against_jv_amount else 0
amount_field = (
"credit_in_account_currency" if against_jv_amount > 0 else "debit_in_account_currency"
)
amount_field = "credit_in_account_currency" if against_jv_amount > 0 else "debit_in_account_currency"
return {amount_field: abs(against_jv_amount)}
elif args.get("doctype") in ("Sales Invoice", "Purchase Invoice"):
party_type = "Customer" if args.get("doctype") == "Sales Invoice" else "Supplier"
@@ -1360,9 +1352,7 @@ def get_outstanding(args):
due_date = invoice.get("due_date")
exchange_rate = (
invoice.conversion_rate if (args.get("account_currency") != company_currency) else 1
)
exchange_rate = invoice.conversion_rate if (args.get("account_currency") != company_currency) else 1
if args["doctype"] == "Sales Invoice":
amount_field = (
@@ -1400,17 +1390,13 @@ def get_party_account_and_currency(company, party_type, party):
@frappe.whitelist()
def get_account_details_and_party_type(
account, date, company, debit=None, credit=None, exchange_rate=None
):
def get_account_details_and_party_type(account, date, company, debit=None, credit=None, exchange_rate=None):
"""Returns dict of account details and party type to be set in Journal Entry on selection of account."""
if not frappe.has_permission("Account"):
frappe.msgprint(_("No Permission"), raise_exception=1)
company_currency = erpnext.get_company_currency(company)
account_details = frappe.db.get_value(
"Account", account, ["account_type", "account_currency"], as_dict=1
)
account_details = frappe.db.get_value("Account", account, ["account_type", "account_currency"], as_dict=1)
if not account_details:
return

View File

@@ -69,10 +69,8 @@ class TestJournalEntry(unittest.TestCase):
self.assertTrue(
frappe.db.sql(
"""select name from `tabJournal Entry Account`
where reference_type = %s and reference_name = %s and {0}=400""".format(
dr_or_cr
),
f"""select name from `tabJournal Entry Account`
where reference_type = %s and reference_name = %s and {dr_or_cr}=400""",
(submitted_voucher.doctype, submitted_voucher.name),
)
)
@@ -84,9 +82,8 @@ class TestJournalEntry(unittest.TestCase):
def advance_paid_testcase(self, base_jv, test_voucher, dr_or_cr):
# Test advance paid field
advance_paid = frappe.db.sql(
"""select advance_paid from `tab%s`
where name=%s"""
% (test_voucher.doctype, "%s"),
"""select advance_paid from `tab{}`
where name={}""".format(test_voucher.doctype, "%s"),
(test_voucher.name),
)
payment_against_order = base_jv.get("accounts")[0].get(dr_or_cr)
@@ -159,9 +156,7 @@ class TestJournalEntry(unittest.TestCase):
jv.cancel()
def test_multi_currency(self):
jv = make_journal_entry(
"_Test Bank USD - _TC", "_Test Bank - _TC", 100, exchange_rate=50, save=False
)
jv = make_journal_entry("_Test Bank USD - _TC", "_Test Bank - _TC", 100, exchange_rate=50, save=False)
jv.get("accounts")[1].credit_in_account_currency = 5000
jv.submit()
@@ -201,7 +196,7 @@ class TestJournalEntry(unittest.TestCase):
"credit",
"credit_in_account_currency",
):
for i, gle in enumerate(gl_entries):
for _i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account][field], gle[field])
# cancel
@@ -263,7 +258,7 @@ class TestJournalEntry(unittest.TestCase):
"credit",
"credit_in_account_currency",
):
for i, gle in enumerate(gl_entries):
for _i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account][field], gle[field])
def test_disallow_change_in_account_currency_for_a_party(self):

View File

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

View File

@@ -0,0 +1,70 @@
{
"actions": [],
"autoname": "autoincrement",
"creation": "2024-03-26 17:01:47.443986",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"voucher_type",
"voucher_no",
"checked_on",
"debit_credit_mismatch",
"general_and_payment_ledger_mismatch"
],
"fields": [
{
"fieldname": "voucher_type",
"fieldtype": "Data",
"label": "Voucher Type"
},
{
"fieldname": "voucher_no",
"fieldtype": "Data",
"label": "Voucher No"
},
{
"default": "0",
"fieldname": "debit_credit_mismatch",
"fieldtype": "Check",
"label": "Debit-Credit mismatch"
},
{
"fieldname": "checked_on",
"fieldtype": "Datetime",
"label": "Checked On"
},
{
"default": "0",
"fieldname": "general_and_payment_ledger_mismatch",
"fieldtype": "Check",
"label": "General and Payment Ledger mismatch"
}
],
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-04-09 11:16:07.044484",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Ledger Health",
"naming_rule": "Autoincrement",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"read_only": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@@ -0,0 +1,25 @@
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class LedgerHealth(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
checked_on: DF.Datetime | None
debit_credit_mismatch: DF.Check
general_and_payment_ledger_mismatch: DF.Check
name: DF.Int | None
voucher_no: DF.Data | None
voucher_type: DF.Data | None
# end: auto-generated types
pass

View File

@@ -0,0 +1,109 @@
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import frappe
from frappe import qb
from frappe.tests.utils import FrappeTestCase
from frappe.utils import nowdate
from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
from erpnext.accounts.utils import run_ledger_health_checks
class TestLedgerHealth(AccountsTestMixin, FrappeTestCase):
def setUp(self):
self.create_company()
self.create_customer()
self.configure_monitoring_tool()
self.clear_old_entries()
def tearDown(self):
frappe.db.rollback()
def configure_monitoring_tool(self):
monitor_settings = frappe.get_doc("Ledger Health Monitor")
monitor_settings.enable_health_monitor = True
monitor_settings.enable_for_last_x_days = 60
monitor_settings.debit_credit_mismatch = True
monitor_settings.general_and_payment_ledger_mismatch = True
exists = [x for x in monitor_settings.companies if x.company == self.company]
if not exists:
monitor_settings.append("companies", {"company": self.company})
monitor_settings.save()
def clear_old_entries(self):
super().clear_old_entries()
lh = qb.DocType("Ledger Health")
qb.from_(lh).delete().run()
def create_journal(self):
je = frappe.new_doc("Journal Entry")
je.company = self.company
je.voucher_type = "Journal Entry"
je.posting_date = nowdate()
je.append(
"accounts",
{
"account": self.debit_to,
"party_type": "Customer",
"party": self.customer,
"debit_in_account_currency": 10000,
},
)
je.append("accounts", {"account": self.income_account, "credit_in_account_currency": 10000})
je.save().submit()
self.je = je
def test_debit_credit_mismatch(self):
self.create_journal()
# manually cause debit-credit mismatch
gle = frappe.db.get_all(
"GL Entry", filters={"voucher_no": self.je.name, "account": self.income_account}
)[0]
frappe.db.set_value("GL Entry", gle.name, "credit", 8000)
run_ledger_health_checks()
expected = {
"voucher_type": self.je.doctype,
"voucher_no": self.je.name,
"debit_credit_mismatch": True,
"general_and_payment_ledger_mismatch": False,
}
actual = frappe.db.get_all(
"Ledger Health",
fields=[
"voucher_type",
"voucher_no",
"debit_credit_mismatch",
"general_and_payment_ledger_mismatch",
],
)
self.assertEqual(len(actual), 1)
self.assertEqual(expected, actual[0])
def test_gl_and_pl_mismatch(self):
self.create_journal()
# manually cause GL and PL discrepancy
ple = frappe.db.get_all("Payment Ledger Entry", filters={"voucher_no": self.je.name})[0]
frappe.db.set_value("Payment Ledger Entry", ple.name, "amount", 11000)
run_ledger_health_checks()
expected = {
"voucher_type": self.je.doctype,
"voucher_no": self.je.name,
"debit_credit_mismatch": False,
"general_and_payment_ledger_mismatch": True,
}
actual = frappe.db.get_all(
"Ledger Health",
fields=[
"voucher_type",
"voucher_no",
"debit_credit_mismatch",
"general_and_payment_ledger_mismatch",
],
)
self.assertEqual(len(actual), 1)
self.assertEqual(expected, actual[0])

View File

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

View File

@@ -0,0 +1,104 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2024-03-27 09:38:07.427997",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"enable_health_monitor",
"monitor_section",
"monitor_for_last_x_days",
"debit_credit_mismatch",
"general_and_payment_ledger_mismatch",
"section_break_xdsp",
"companies"
],
"fields": [
{
"default": "0",
"fieldname": "enable_health_monitor",
"fieldtype": "Check",
"label": "Enable Health Monitor"
},
{
"fieldname": "monitor_section",
"fieldtype": "Section Break",
"label": "Configuration"
},
{
"default": "0",
"fieldname": "debit_credit_mismatch",
"fieldtype": "Check",
"label": "Debit-Credit Mismatch"
},
{
"default": "0",
"fieldname": "general_and_payment_ledger_mismatch",
"fieldtype": "Check",
"label": "Discrepancy between General and Payment Ledger"
},
{
"default": "60",
"fieldname": "monitor_for_last_x_days",
"fieldtype": "Int",
"in_list_view": 1,
"label": "Monitor for Last 'X' days",
"reqd": 1
},
{
"fieldname": "section_break_xdsp",
"fieldtype": "Section Break",
"label": "Companies"
},
{
"fieldname": "companies",
"fieldtype": "Table",
"options": "Ledger Health Monitor Company"
}
],
"hide_toolbar": 1,
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2024-03-27 10:14:16.511681",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Ledger Health Monitor",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "Accounts Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "Accounts User",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}

View File

@@ -0,0 +1,28 @@
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class LedgerHealthMonitor(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.ledger_health_monitor_company.ledger_health_monitor_company import (
LedgerHealthMonitorCompany,
)
companies: DF.Table[LedgerHealthMonitorCompany]
debit_credit_mismatch: DF.Check
enable_health_monitor: DF.Check
general_and_payment_ledger_mismatch: DF.Check
monitor_for_last_x_days: DF.Int
# end: auto-generated types
pass

View File

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

View File

@@ -0,0 +1,32 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2024-03-27 10:04:45.727054",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"company"
],
"fields": [
{
"fieldname": "company",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Company",
"options": "Company"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-03-27 10:06:22.806155",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Ledger Health Monitor Company",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

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

View File

@@ -83,7 +83,10 @@ class TestLedgerMerge(unittest.TestCase):
"account": "Indirect Income - _TC",
"merge_accounts": [
{"account": "Indirect Test Income - _TC", "account_name": "Indirect Test Income"},
{"account": "Administrative Test Income - _TC", "account_name": "Administrative Test Income"},
{
"account": "Administrative Test Income - _TC",
"account_name": "Administrative Test Income",
},
],
}
).insert(ignore_permissions=True)

View File

@@ -25,13 +25,11 @@ def get_loyalty_details(
condition += " and expiry_date>='%s' " % expiry_date
loyalty_point_details = frappe.db.sql(
"""select sum(loyalty_points) as loyalty_points,
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""".format(
condition=condition
),
group by customer""",
(customer, loyalty_program, expiry_date),
as_dict=1,
)
@@ -52,9 +50,7 @@ def get_loyalty_program_details_with_points(
include_expired_entry=False,
current_transaction_amount=0,
):
lp_details = get_loyalty_program_details(
customer, loyalty_program, company=company, silent=silent
)
lp_details = get_loyalty_program_details(customer, loyalty_program, company=company, silent=silent)
loyalty_program = frappe.get_doc("Loyalty Program", loyalty_program)
lp_details.update(
get_loyalty_details(customer, loyalty_program.name, expiry_date, company, include_expired_entry)

View File

@@ -19,9 +19,7 @@ class TestLoyaltyProgram(unittest.TestCase):
create_records()
def test_loyalty_points_earned_single_tier(self):
frappe.db.set_value(
"Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty"
)
frappe.db.set_value("Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty")
# create a new sales invoice
si_original = create_sales_invoice_record()
si_original.insert()
@@ -69,9 +67,7 @@ class TestLoyaltyProgram(unittest.TestCase):
d.cancel()
def test_loyalty_points_earned_multiple_tier(self):
frappe.db.set_value(
"Customer", "Test Loyalty Customer", "loyalty_program", "Test Multiple Loyalty"
)
frappe.db.set_value("Customer", "Test Loyalty Customer", "loyalty_program", "Test Multiple Loyalty")
# assign multiple tier program to the customer
customer = frappe.get_doc("Customer", {"customer_name": "Test Loyalty Customer"})
customer.loyalty_program = frappe.get_doc(
@@ -128,9 +124,7 @@ class TestLoyaltyProgram(unittest.TestCase):
def test_cancel_sales_invoice(self):
"""cancelling the sales invoice should cancel the earned points"""
frappe.db.set_value(
"Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty"
)
frappe.db.set_value("Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty")
# create a new sales invoice
si = create_sales_invoice_record()
si.insert()
@@ -140,7 +134,7 @@ class TestLoyaltyProgram(unittest.TestCase):
"Loyalty Point Entry",
{"invoice_type": "Sales Invoice", "invoice": si.name, "customer": si.customer},
)
self.assertEqual(True, not (lpe is None))
self.assertEqual(True, lpe is not None)
# cancelling sales invoice
si.cancel()
@@ -148,9 +142,7 @@ class TestLoyaltyProgram(unittest.TestCase):
self.assertEqual(True, (lpe is None))
def test_sales_invoice_return(self):
frappe.db.set_value(
"Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty"
)
frappe.db.set_value("Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty")
# create a new sales invoice
si_original = create_sales_invoice_record(2)
si_original.conversion_rate = flt(1)
@@ -346,9 +338,7 @@ def create_records():
).insert()
# create item price
if not frappe.db.exists(
"Item Price", {"price_list": "Standard Selling", "item_code": "Loyal Item"}
):
if not frappe.db.exists("Item Price", {"price_list": "Standard Selling", "item_code": "Loyal Item"}):
frappe.get_doc(
{
"doctype": "Item Price",

View File

@@ -37,9 +37,7 @@ class MonthlyDistribution(Document):
total = sum(flt(d.percentage_allocation) for d in self.get("percentages"))
if flt(total, 2) != 100.0:
frappe.throw(
_("Percentage Allocation should be equal to 100%") + " ({0}%)".format(str(flt(total, 2)))
)
frappe.throw(_("Percentage Allocation should be equal to 100%") + f" ({flt(total, 2)!s}%)")
def get_periodwise_distribution_data(distribution_id, period_list, periodicity):

View File

@@ -83,9 +83,7 @@ class TestOpeningInvoiceCreationTool(FrappeTestCase):
company = "_Test Opening Invoice Company"
party_1, party_2 = make_customer("Customer A"), make_customer("Customer B")
old_default_receivable_account = frappe.db.get_value(
"Company", company, "default_receivable_account"
)
old_default_receivable_account = frappe.db.get_value("Company", company, "default_receivable_account")
frappe.db.set_value("Company", company, "default_receivable_account", "")
if not frappe.db.exists("Cost Center", "_Test Opening Invoice Company - _TOIC"):
@@ -121,9 +119,7 @@ class TestOpeningInvoiceCreationTool(FrappeTestCase):
self.assertTrue(error_log)
# teardown
frappe.db.set_value(
"Company", company, "default_receivable_account", old_default_receivable_account
)
frappe.db.set_value("Company", company, "default_receivable_account", old_default_receivable_account)
def test_renaming_of_invoice_using_invoice_number_field(self):
company = "_Test Opening Invoice Company"
@@ -169,7 +165,7 @@ def get_opening_invoice_creation_dict(**args):
{
"qty": 1.0,
"outstanding_amount": 300,
"party": args.get("party_1") or "_Test {0}".format(party),
"party": args.get("party_1") or f"_Test {party}",
"item_name": "Opening Item",
"due_date": "2016-09-10",
"posting_date": "2016-09-05",
@@ -179,7 +175,7 @@ def get_opening_invoice_creation_dict(**args):
{
"qty": 2.0,
"outstanding_amount": 250,
"party": args.get("party_2") or "_Test {0} 1".format(party),
"party": args.get("party_2") or f"_Test {party} 1",
"item_name": "Opening Item",
"due_date": "2016-09-10",
"posting_date": "2016-09-05",

View File

@@ -24,7 +24,10 @@ class PartyLink(Document):
if existing_party_link:
frappe.throw(
_("{} {} is already linked with {} {}").format(
self.primary_role, bold(self.primary_party), self.secondary_role, bold(self.secondary_party)
self.primary_role,
bold(self.primary_party),
self.secondary_role,
bold(self.secondary_party),
)
)

View File

@@ -21,7 +21,7 @@ frappe.ui.form.on('Payment Entry', {
frm.set_query("paid_from", function() {
frm.events.validate_company(frm);
var account_types = in_list(["Pay", "Internal Transfer"], frm.doc.payment_type) ?
var account_types = ["Pay", "Internal Transfer"].includes(frm.doc.payment_type) ?
["Bank", "Cash"] : [frappe.boot.party_account_types[frm.doc.party_type]];
return {
filters: {
@@ -75,7 +75,7 @@ frappe.ui.form.on('Payment Entry', {
frm.set_query("paid_to", function() {
frm.events.validate_company(frm);
var account_types = in_list(["Receive", "Internal Transfer"], frm.doc.payment_type) ?
var account_types = ["Receive", "Internal Transfer"].includes(frm.doc.payment_type) ?
["Bank", "Cash"] : [frappe.boot.party_account_types[frm.doc.party_type]];
return {
filters: {
@@ -121,7 +121,7 @@ frappe.ui.form.on('Payment Entry', {
frm.set_query('payment_term', 'references', function(frm, cdt, cdn) {
const child = locals[cdt][cdn];
if (in_list(['Purchase Invoice', 'Sales Invoice'], child.reference_doctype) && child.reference_name) {
if (['Purchase Invoice', 'Sales Invoice'].includes(child.reference_doctype) && child.reference_name) {
return {
query: "erpnext.controllers.queries.get_payment_terms_for_references",
filters: {
@@ -145,10 +145,27 @@ frappe.ui.form.on('Payment Entry', {
filters: filters
};
});
},
refresh: function(frm) {
erpnext.hide_company();
frm.set_query("sales_taxes_and_charges_template", function () {
return {
filters: {
company: frm.doc.company,
disabled: false,
},
};
});
frm.set_query("purchase_taxes_and_charges_template", function () {
return {
filters: {
company: frm.doc.company,
disabled: false,
},
};
});
},
refresh: function (frm) {
erpnext.hide_company(frm);
frm.events.hide_unhide_fields(frm);
frm.events.set_dynamic_labels(frm);
frm.events.show_general_ledger(frm);
@@ -179,7 +196,7 @@ frappe.ui.form.on('Payment Entry', {
},
hide_unhide_fields: function(frm) {
var company_currency = frm.doc.company? frappe.get_doc(":Company", frm.doc.company).default_currency: "";
var company_currency = frm.doc.company? frappe.get_doc(":Company", frm.doc.company)?.default_currency: "";
frm.toggle_display("source_exchange_rate",
(frm.doc.paid_amount && frm.doc.paid_from_account_currency != company_currency));
@@ -485,7 +502,7 @@ frappe.ui.form.on('Payment Entry', {
if (frm.doc.paid_from_account_currency == company_currency) {
frm.set_value("source_exchange_rate", 1);
} else if (frm.doc.paid_from){
if (in_list(["Internal Transfer", "Pay"], frm.doc.payment_type)) {
if (["Internal Transfer", "Pay"].includes(frm.doc.payment_type)) {
let company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
frappe.call({
method: "erpnext.setup.utils.get_exchange_rate",
@@ -853,7 +870,7 @@ frappe.ui.form.on('Payment Entry', {
}
var allocated_positive_outstanding = paid_amount + allocated_negative_outstanding;
} else if (in_list(["Customer", "Supplier"], frm.doc.party_type)) {
} else if (["Customer", "Supplier"].includes(frm.doc.party_type)) {
total_negative_outstanding = flt(total_negative_outstanding, precision("outstanding_amount"))
if(paid_amount > total_negative_outstanding) {
if(total_negative_outstanding == 0) {
@@ -988,7 +1005,7 @@ frappe.ui.form.on('Payment Entry', {
}
if(frm.doc.party_type=="Customer" &&
!in_list(["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"], row.reference_doctype)
!["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"].includes(row.reference_doctype)
) {
frappe.model.set_value(row.doctype, row.name, "reference_doctype", null);
frappe.msgprint(__("Row #{0}: Reference Document Type must be one of Sales Order, Sales Invoice, Journal Entry or Dunning", [row.idx]));
@@ -996,7 +1013,7 @@ frappe.ui.form.on('Payment Entry', {
}
if(frm.doc.party_type=="Supplier" &&
!in_list(["Purchase Order", "Purchase Invoice", "Journal Entry"], row.reference_doctype)
!["Purchase Order", "Purchase Invoice", "Journal Entry"].includes(row.reference_doctype)
) {
frappe.model.set_value(row.doctype, row.name, "against_voucher_type", null);
frappe.msgprint(__("Row #{0}: Reference Document Type must be one of Purchase Order, Purchase Invoice or Journal Entry", [row.idx]));
@@ -1080,7 +1097,7 @@ frappe.ui.form.on('Payment Entry', {
bank_account: function(frm) {
const field = frm.doc.payment_type == "Pay" ? "paid_from":"paid_to";
if (frm.doc.bank_account && in_list(['Pay', 'Receive'], frm.doc.payment_type)) {
if (frm.doc.bank_account && ['Pay', 'Receive'].includes(frm.doc.payment_type)) {
frappe.call({
method: "erpnext.accounts.doctype.bank_account.bank_account.get_bank_account_details",
args: {
@@ -1088,7 +1105,9 @@ frappe.ui.form.on('Payment Entry', {
},
callback: function(r) {
if (r.message) {
frm.set_value(field, r.message.account);
if (!frm.doc.mode_of_payment) {
frm.set_value(field, r.message.account);
}
frm.set_value('bank', r.message.bank);
frm.set_value('bank_account_no', r.message.bank_account_no);
}
@@ -1393,8 +1412,9 @@ frappe.ui.form.on('Payment Entry Reference', {
args: {
reference_doctype: row.reference_doctype,
reference_name: row.reference_name,
party_account_currency: frm.doc.payment_type=="Receive" ?
frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency
party_account_currency: frm.doc.payment_type == "Receive" ? frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency,
party_type: frm.doc.party_type,
party: frm.doc.party,
},
callback: function(r, rt) {
if(r.message) {

View File

@@ -576,6 +576,7 @@
"fieldtype": "Select",
"hidden": 1,
"label": "Payment Order Status",
"no_copy": 1,
"options": "Initiated\nPayment Ordered",
"read_only": 1
},

View File

@@ -9,8 +9,7 @@ import frappe
from frappe import ValidationError, _, qb, scrub, throw
from frappe.utils import cint, comma_or, flt, getdate, nowdate
from frappe.utils.data import comma_and, fmt_money
from pypika import Case
from pypika.functions import Coalesce, Sum
from pypika.functions import Sum
import erpnext
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_dimensions
@@ -47,7 +46,7 @@ class InvalidPaymentEntry(ValidationError):
class PaymentEntry(AccountsController):
def __init__(self, *args, **kwargs):
super(PaymentEntry, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
if not self.is_new():
self.setup_party_account_field()
@@ -75,7 +74,6 @@ class PaymentEntry(AccountsController):
self.set_exchange_rate()
self.validate_mandatory()
self.validate_reference_documents()
self.set_tax_withholding()
self.set_amounts()
self.validate_amounts()
self.apply_taxes()
@@ -90,6 +88,7 @@ class PaymentEntry(AccountsController):
self.validate_allocated_amount()
self.validate_paid_invoices()
self.ensure_supplier_is_not_blocked()
self.set_tax_withholding()
self.set_status()
def on_submit(self):
@@ -113,7 +112,7 @@ class PaymentEntry(AccountsController):
"Unreconcile Payment",
"Unreconcile Payment Entries",
)
super(PaymentEntry, self).on_cancel()
super().on_cancel()
self.make_gl_entries(cancel=1)
self.update_outstanding_amounts()
self.update_advance_paid()
@@ -221,9 +220,7 @@ class PaymentEntry(AccountsController):
# If term based allocation is enabled, throw
if (
d.payment_term is None or d.payment_term == ""
) and self.term_based_allocation_enabled_for_reference(
d.reference_doctype, d.reference_name
):
) and self.term_based_allocation_enabled_for_reference(d.reference_doctype, d.reference_name):
frappe.throw(
_(
"{0} has Payment Term based allocation enabled. Select a Payment Term for Row #{1} in Payment References section"
@@ -235,7 +232,9 @@ class PaymentEntry(AccountsController):
# The reference has already been fully paid
if not latest:
frappe.throw(
_("{0} {1} has already been fully paid.").format(_(d.reference_doctype), d.reference_name)
_("{0} {1} has already been fully paid.").format(
_(d.reference_doctype), d.reference_name
)
)
# The reference has already been partly paid
elif (
@@ -259,14 +258,14 @@ class PaymentEntry(AccountsController):
and latest.payment_term_outstanding
and (flt(d.allocated_amount) > flt(latest.payment_term_outstanding))
)
and self.term_based_allocation_enabled_for_reference(d.reference_doctype, d.reference_name)
and self.term_based_allocation_enabled_for_reference(
d.reference_doctype, d.reference_name
)
):
frappe.throw(
_(
"Row #{0}: Allocated amount:{1} is greater than outstanding amount:{2} for Payment Term {3}"
).format(
d.idx, d.allocated_amount, latest.payment_term_outstanding, d.payment_term
)
).format(d.idx, d.allocated_amount, latest.payment_term_outstanding, d.payment_term)
)
if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(latest.outstanding_amount):
@@ -338,22 +337,30 @@ class PaymentEntry(AccountsController):
self,
force: bool = False,
update_ref_details_only_for: list | None = None,
ref_exchange_rate: float | None = None,
reference_exchange_details: dict | None = None,
) -> None:
for d in self.get("references"):
if d.allocated_amount:
if update_ref_details_only_for and (
not (d.reference_doctype, d.reference_name) in update_ref_details_only_for
(d.reference_doctype, d.reference_name) not in update_ref_details_only_for
):
continue
ref_details = get_reference_details(
d.reference_doctype, d.reference_name, self.party_account_currency
d.reference_doctype,
d.reference_name,
self.party_account_currency,
self.party_type,
self.party,
)
# Only update exchange rate when the reference is Journal Entry
if ref_exchange_rate and d.reference_doctype == "Journal Entry":
ref_details.update({"exchange_rate": ref_exchange_rate})
if (
reference_exchange_details
and d.reference_doctype == reference_exchange_details.reference_doctype
and d.reference_name == reference_exchange_details.reference_name
):
ref_details.update({"exchange_rate": reference_exchange_details.exchange_rate})
for field, value in ref_details.items():
if d.exchange_gain_loss:
@@ -386,7 +393,9 @@ class PaymentEntry(AccountsController):
else:
if ref_doc:
if self.paid_from_account_currency == ref_doc.currency:
self.source_exchange_rate = ref_doc.get("exchange_rate") or ref_doc.get("conversion_rate")
self.source_exchange_rate = ref_doc.get("exchange_rate") or ref_doc.get(
"conversion_rate"
)
if not self.source_exchange_rate:
self.source_exchange_rate = get_exchange_rate(
@@ -423,7 +432,7 @@ class PaymentEntry(AccountsController):
if d.reference_doctype not in valid_reference_doctypes:
frappe.throw(
_("Reference Doctype must be one of {0}").format(
comma_or((_(d) for d in valid_reference_doctypes))
comma_or(_(d) for d in valid_reference_doctypes)
)
)
@@ -446,7 +455,8 @@ class PaymentEntry(AccountsController):
if d.reference_doctype in frappe.get_hooks("invoice_doctypes"):
if self.party_type == "Customer":
ref_party_account = (
get_party_account_based_on_invoice_discounting(d.reference_name) or ref_doc.debit_to
get_party_account_based_on_invoice_discounting(d.reference_name)
or ref_doc.debit_to
)
elif self.party_type == "Supplier":
ref_party_account = ref_doc.credit_to
@@ -456,7 +466,10 @@ class PaymentEntry(AccountsController):
if ref_party_account != self.party_account:
frappe.throw(
_("{0} {1} is associated with {2}, but Party Account is {3}").format(
_(d.reference_doctype), d.reference_name, ref_party_account, self.party_account
_(d.reference_doctype),
d.reference_name,
ref_party_account,
self.party_account,
)
)
@@ -467,7 +480,9 @@ class PaymentEntry(AccountsController):
)
if ref_doc.docstatus != 1:
frappe.throw(_("{0} {1} must be submitted").format(_(d.reference_doctype), d.reference_name))
frappe.throw(
_("{0} {1} must be submitted").format(_(d.reference_doctype), d.reference_name)
)
def get_valid_reference_doctypes(self):
if self.party_type == "Customer":
@@ -638,9 +653,7 @@ class PaymentEntry(AccountsController):
if not (is_single_currency and reference_is_multi_currency):
return allocated_amount
allocated_amount = flt(
allocated_amount / ref_exchange_rate, self.precision("total_allocated_amount")
)
allocated_amount = flt(allocated_amount / ref_exchange_rate, self.precision("total_allocated_amount"))
return allocated_amount
@@ -661,9 +674,7 @@ class PaymentEntry(AccountsController):
if not self.apply_tax_withholding_amount:
return
order_amount = self.get_order_net_total()
net_total = flt(order_amount) + flt(self.unallocated_amount)
net_total = self.calculate_tax_withholding_net_total()
# Adding args as purchase invoice to get TDS amount
args = frappe._dict(
@@ -688,7 +699,6 @@ class PaymentEntry(AccountsController):
accounts = []
for d in self.taxes:
if d.account_head == tax_withholding_details.get("account_head"):
# Preserve user updated included in paid amount
if d.included_in_paid_amount:
tax_withholding_details.update({"included_in_paid_amount": d.included_in_paid_amount})
@@ -708,7 +718,26 @@ class PaymentEntry(AccountsController):
for d in to_remove:
self.remove(d)
def get_order_net_total(self):
def calculate_tax_withholding_net_total(self):
net_total = 0
order_details = self.get_order_wise_tax_withholding_net_total()
for d in self.references:
tax_withholding_net_total = order_details.get(d.reference_name)
if not tax_withholding_net_total:
continue
net_taxable_outstanding = max(
0, d.outstanding_amount - (d.total_amount - tax_withholding_net_total)
)
net_total += min(net_taxable_outstanding, d.allocated_amount)
net_total += self.unallocated_amount
return net_total
def get_order_wise_tax_withholding_net_total(self):
if self.party_type == "Supplier":
doctype = "Purchase Order"
else:
@@ -716,12 +745,15 @@ class PaymentEntry(AccountsController):
docnames = [d.reference_name for d in self.references if d.reference_doctype == doctype]
tax_withholding_net_total = frappe.db.get_value(
doctype, {"name": ["in", docnames]}, ["sum(base_tax_withholding_net_total)"]
return frappe._dict(
frappe.db.get_all(
doctype,
filters={"name": ["in", docnames]},
fields=["name", "base_tax_withholding_net_total"],
as_list=True,
)
)
return tax_withholding_net_total
def apply_taxes(self):
self.initialize_taxes()
self.determine_exclusive_rate()
@@ -808,7 +840,6 @@ class PaymentEntry(AccountsController):
flt(d.allocated_amount) * flt(exchange_rate), self.precision("base_paid_amount")
)
else:
# Use source/target exchange rate, so no difference amount is calculated.
# then update exchange gain/loss amount in reference table
# if there is an exchange gain/loss amount in reference table, submit a JE for that
@@ -925,7 +956,9 @@ class PaymentEntry(AccountsController):
total_negative_outstanding = flt(
sum(
abs(flt(d.outstanding_amount)) for d in self.get("references") if flt(d.outstanding_amount) < 0
abs(flt(d.outstanding_amount))
for d in self.get("references")
if flt(d.outstanding_amount) < 0
),
self.references[0].precision("outstanding_amount") if self.references else None,
)
@@ -978,7 +1011,6 @@ class PaymentEntry(AccountsController):
)
]
else:
remarks = [
_("Amount {0} {1} {2} {3}").format(
self.party_account_currency,
@@ -998,14 +1030,19 @@ class PaymentEntry(AccountsController):
if d.allocated_amount:
remarks.append(
_("Amount {0} {1} against {2} {3}").format(
self.party_account_currency, d.allocated_amount, d.reference_doctype, d.reference_name
self.party_account_currency,
d.allocated_amount,
d.reference_doctype,
d.reference_name,
)
)
for d in self.get("deductions"):
if d.amount:
remarks.append(
_("Amount {0} {1} deducted against {2}").format(self.company_currency, d.amount, d.account)
_("Amount {0} {1} deducted against {2}").format(
self.company_currency, d.amount, d.account
)
)
self.set("remarks", "\n".join(remarks))
@@ -1440,7 +1477,8 @@ def get_outstanding_reference_documents(args):
return []
elif supplier_status["hold_type"] == "Payments":
if (
not supplier_status["release_date"] or getdate(nowdate()) <= supplier_status["release_date"]
not supplier_status["release_date"]
or getdate(nowdate()) <= supplier_status["release_date"]
):
return []
@@ -1450,7 +1488,7 @@ def get_outstanding_reference_documents(args):
# Get positive outstanding sales /purchase invoices
condition = ""
if args.get("voucher_type") and args.get("voucher_no"):
condition = " and voucher_type={0} and voucher_no={1}".format(
condition = " and voucher_type={} and voucher_no={}".format(
frappe.db.escape(args["voucher_type"]), frappe.db.escape(args["voucher_no"])
)
common_filter.append(ple.voucher_type == args["voucher_type"])
@@ -1465,7 +1503,7 @@ def get_outstanding_reference_documents(args):
active_dimensions = get_dimensions()[0]
for dim in active_dimensions:
if args.get(dim.fieldname):
condition += " and {0}='{1}'".format(dim.fieldname, args.get(dim.fieldname))
condition += f" and {dim.fieldname}='{args.get(dim.fieldname)}'"
accounting_dimensions_filter.append(ple[dim.fieldname] == args.get(dim.fieldname))
date_fields_dict = {
@@ -1475,21 +1513,21 @@ def get_outstanding_reference_documents(args):
for fieldname, date_fields in date_fields_dict.items():
if args.get(date_fields[0]) and args.get(date_fields[1]):
condition += " and {0} between '{1}' and '{2}'".format(
condition += " and {} between '{}' and '{}'".format(
fieldname, args.get(date_fields[0]), args.get(date_fields[1])
)
posting_and_due_date.append(ple[fieldname][args.get(date_fields[0]) : args.get(date_fields[1])])
elif args.get(date_fields[0]):
# if only from date is supplied
condition += " and {0} >= '{1}'".format(fieldname, args.get(date_fields[0]))
condition += f" and {fieldname} >= '{args.get(date_fields[0])}'"
posting_and_due_date.append(ple[fieldname].gte(args.get(date_fields[0])))
elif args.get(date_fields[1]):
# if only to date is supplied
condition += " and {0} <= '{1}'".format(fieldname, args.get(date_fields[1]))
condition += f" and {fieldname} <= '{args.get(date_fields[1])}'"
posting_and_due_date.append(ple[fieldname].lte(args.get(date_fields[1])))
if args.get("company"):
condition += " and company = {0}".format(frappe.db.escape(args.get("company")))
condition += " and company = {}".format(frappe.db.escape(args.get("company")))
common_filter.append(ple.company == args.get("company"))
outstanding_invoices = []
@@ -1561,9 +1599,7 @@ def get_outstanding_reference_documents(args):
frappe.msgprint(
_(
"No outstanding {0} found for the {1} {2} which qualify the filters you have specified."
).format(
_(ref_document_type), _(args.get("party_type")).lower(), frappe.bold(args.get("party"))
)
).format(_(ref_document_type), _(args.get("party_type")).lower(), frappe.bold(args.get("party")))
)
return data
@@ -1599,12 +1635,10 @@ def split_invoices_based_on_payment_terms(outstanding_invoices, company) -> list
return outstanding_invoices_after_split
def get_currency_data(outstanding_invoices: list, company: str = None) -> dict:
def get_currency_data(outstanding_invoices: list, company: str | None = None) -> dict:
"""Get currency and conversion data for a list of invoices."""
exc_rates = frappe._dict()
company_currency = (
frappe.db.get_value("Company", company, "default_currency") if company else None
)
company_currency = frappe.db.get_value("Company", company, "default_currency") if company else None
for doctype in ["Sales Invoice", "Purchase Invoice"]:
invoices = [x.voucher_no for x in outstanding_invoices if x.voucher_type == doctype]
@@ -1699,7 +1733,7 @@ def get_orders_to_be_billed(
active_dimensions = get_dimensions()[0]
for dim in active_dimensions:
if filters.get(dim.fieldname):
condition += " and {0}='{1}'".format(dim.fieldname, filters.get(dim.fieldname))
condition += f" and {dim.fieldname}='{filters.get(dim.fieldname)}'"
if party_account_currency == company_currency:
grand_total_field = "base_grand_total"
@@ -1848,18 +1882,14 @@ def get_account_details(account, date, cost_center=None):
frappe.has_permission("Payment Entry", throw=True)
# to check if the passed account is accessible under reference doctype Payment Entry
account_list = frappe.get_list(
"Account", {"name": account}, reference_doctype="Payment Entry", limit=1
)
account_list = frappe.get_list("Account", {"name": account}, reference_doctype="Payment Entry", limit=1)
# There might be some user permissions which will allow account under certain doctypes
# except for Payment Entry, only in such case we should throw permission error
if not account_list:
frappe.throw(_("Account: {0} is not permitted under Payment Entry").format(account))
account_balance = get_balance_on(
account, date, cost_center=cost_center, ignore_account_permission=True
)
account_balance = get_balance_on(account, date, cost_center=cost_center, ignore_account_permission=True)
return frappe._dict(
{
@@ -1876,53 +1906,59 @@ def get_company_defaults(company):
return frappe.get_cached_value("Company", company, fields, as_dict=1)
def get_outstanding_on_journal_entry(name):
gl = frappe.qb.DocType("GL Entry")
res = (
frappe.qb.from_(gl)
.select(
Case()
.when(
gl.party_type == "Customer",
Coalesce(Sum(gl.debit_in_account_currency - gl.credit_in_account_currency), 0),
)
.else_(Coalesce(Sum(gl.credit_in_account_currency - gl.debit_in_account_currency), 0))
.as_("outstanding_amount")
)
def get_outstanding_on_journal_entry(voucher_no, party_type, party):
ple = frappe.qb.DocType("Payment Ledger Entry")
outstanding = (
frappe.qb.from_(ple)
.select(Sum(ple.amount_in_account_currency))
.where(
(Coalesce(gl.party_type, "") != "")
& (gl.is_cancelled == 0)
& ((gl.voucher_no == name) | (gl.against_voucher == name))
(ple.against_voucher_no == voucher_no)
& (ple.party_type == party_type)
& (ple.party == party)
& (ple.delinked == 0)
)
).run(as_dict=True)
).run()
outstanding_amount = res[0].get("outstanding_amount", 0) if res else 0
outstanding_amount = outstanding[0][0] if outstanding else 0
return outstanding_amount
total = (
frappe.qb.from_(ple)
.select(Sum(ple.amount_in_account_currency))
.where(
(ple.voucher_no == voucher_no)
& (ple.party_type == party_type)
& (ple.party == party)
& (ple.delinked == 0)
)
).run()
total_amount = total[0][0] if total else 0
return outstanding_amount, total_amount
@frappe.whitelist()
def get_reference_details(reference_doctype, reference_name, party_account_currency):
def get_reference_details(
reference_doctype, reference_name, party_account_currency, party_type=None, party=None
):
total_amount = outstanding_amount = exchange_rate = None
ref_doc = frappe.get_doc(reference_doctype, reference_name)
company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(
ref_doc.company
)
company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(ref_doc.company)
if reference_doctype == "Dunning":
total_amount = outstanding_amount = ref_doc.get("dunning_amount")
exchange_rate = 1
elif reference_doctype == "Journal Entry" and ref_doc.docstatus == 1:
total_amount = ref_doc.get("total_amount")
if ref_doc.multi_currency:
exchange_rate = get_exchange_rate(
party_account_currency, company_currency, ref_doc.posting_date
)
exchange_rate = get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
else:
exchange_rate = 1
outstanding_amount = get_outstanding_on_journal_entry(reference_name)
outstanding_amount, total_amount = get_outstanding_on_journal_entry(
reference_name, party_type, party
)
elif reference_doctype != "Journal Entry":
if not total_amount:
@@ -1977,9 +2013,7 @@ def get_payment_entry(
):
doc = frappe.get_doc(dt, dn)
over_billing_allowance = frappe.db.get_single_value("Accounts Settings", "over_billing_allowance")
if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) >= (
100.0 + over_billing_allowance
):
if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) >= (100.0 + over_billing_allowance):
frappe.throw(_("Can only make payment against unbilled {0}").format(_(dt)))
if not party_type:
@@ -2032,9 +2066,7 @@ def get_payment_entry(
pe.paid_from_account_currency = (
party_account_currency if payment_type == "Receive" else bank.account_currency
)
pe.paid_to_account_currency = (
party_account_currency if payment_type == "Pay" else bank.account_currency
)
pe.paid_to_account_currency = party_account_currency if payment_type == "Pay" else bank.account_currency
pe.paid_amount = paid_amount
pe.received_amount = received_amount
pe.letter_head = doc.get("letter_head")
@@ -2063,7 +2095,6 @@ def get_payment_entry(
{"name": doc.payment_terms_template},
"allocate_payment_based_on_payment_terms",
):
for reference in get_reference_as_per_payment_terms(
doc.payment_schedule, dt, dn, doc, grand_total, outstanding_amount, party_account_currency
):
@@ -2184,9 +2215,9 @@ def set_party_account_currency(dt, party_account, doc):
def set_payment_type(dt, doc):
if (
dt == "Sales Order" or (dt in ("Sales Invoice", "Dunning") and doc.outstanding_amount > 0)
) or (dt == "Purchase Invoice" and doc.outstanding_amount < 0):
if (dt == "Sales Order" or (dt in ("Sales Invoice", "Dunning") and doc.outstanding_amount > 0)) or (
dt == "Purchase Invoice" and doc.outstanding_amount < 0
):
payment_type = "Receive"
else:
payment_type = "Pay"
@@ -2246,9 +2277,7 @@ def set_paid_amount_and_received_amount(
return paid_amount, received_amount
def apply_early_payment_discount(
paid_amount, received_amount, doc, party_account_currency, reference_date
):
def apply_early_payment_discount(paid_amount, received_amount, doc, party_account_currency, reference_date):
total_discount = 0
valid_discounts = []
eligible_for_payments = ["Sales Order", "Sales Invoice", "Purchase Order", "Purchase Invoice"]
@@ -2258,7 +2287,6 @@ def apply_early_payment_discount(
if doc.doctype in eligible_for_payments and has_payment_schedule:
for term in doc.payment_schedule:
if not term.discounted_amount and term.discount and reference_date <= term.discount_date:
if term.discount_type == "Percentage":
grand_total = doc.get("grand_total") if is_multi_currency else doc.get("base_grand_total")
discount_amount = flt(grand_total) * (term.discount / 100)
@@ -2287,9 +2315,7 @@ def apply_early_payment_discount(
return paid_amount, received_amount, total_discount, valid_discounts
def set_pending_discount_loss(
pe, doc, discount_amount, base_total_discount_loss, party_account_currency
):
def set_pending_discount_loss(pe, doc, discount_amount, base_total_discount_loss, party_account_currency):
# If multi-currency, get base discount amount to adjust with base currency deductions/losses
if party_account_currency != doc.company_currency:
discount_amount = discount_amount * doc.get("conversion_rate", 1)
@@ -2309,7 +2335,8 @@ def set_pending_discount_loss(
pe.set_gain_or_loss(
account_details={
"account": frappe.get_cached_value("Company", pe.company, account_type),
"cost_center": pe.cost_center or frappe.get_cached_value("Company", pe.company, "cost_center"),
"cost_center": pe.cost_center
or frappe.get_cached_value("Company", pe.company, "cost_center"),
"amount": discount_amount * positive_negative,
}
)
@@ -2332,9 +2359,7 @@ def split_early_payment_discount_loss(pe, doc, valid_discounts) -> float:
def get_total_discount_percent(doc, valid_discounts) -> float:
"""Get total percentage and amount discount applied as a percentage."""
total_discount_percent = (
sum(
discount.get("discount") for discount in valid_discounts if discount.get("type") == "Percentage"
)
sum(discount.get("discount") for discount in valid_discounts if discount.get("type") == "Percentage")
or 0.0
)
@@ -2377,9 +2402,7 @@ def add_tax_discount_loss(pe, doc, total_discount_percentage) -> float:
# The same account head could be used more than once
for tax in doc.get("taxes", []):
base_tax_loss = tax.get("base_tax_amount_after_discount_amount") * (
total_discount_percentage / 100
)
base_tax_loss = tax.get("base_tax_amount_after_discount_amount") * (total_discount_percentage / 100)
account = tax.get("account_head")
if not tax_discount_loss.get(account):
@@ -2396,7 +2419,8 @@ def add_tax_discount_loss(pe, doc, total_discount_percentage) -> float:
"deductions",
{
"account": account,
"cost_center": pe.cost_center or frappe.get_cached_value("Company", pe.company, "cost_center"),
"cost_center": pe.cost_center
or frappe.get_cached_value("Company", pe.company, "cost_center"),
"amount": flt(loss, precision),
},
)
@@ -2419,7 +2443,8 @@ def get_reference_as_per_payment_terms(
if not is_multi_currency_acc:
# If accounting is done in company currency for multi-currency transaction
payment_term_outstanding = flt(
payment_term_outstanding * doc.get("conversion_rate"), payment_term.precision("payment_amount")
payment_term_outstanding * doc.get("conversion_rate"),
payment_term.precision("payment_amount"),
)
if payment_term_outstanding:
@@ -2447,7 +2472,7 @@ def get_paid_amount(dt, dn, party_type, party, account, due_date):
dr_or_cr = "debit_in_account_currency - credit_in_account_currency"
paid_amount = frappe.db.sql(
"""
f"""
select ifnull(sum({dr_or_cr}), 0) as paid_amount
from `tabGL Entry`
where against_voucher_type = %s
@@ -2457,9 +2482,7 @@ def get_paid_amount(dt, dn, party_type, party, account, due_date):
and account = %s
and due_date = %s
and {dr_or_cr} > 0
""".format(
dr_or_cr=dr_or_cr
),
""",
(dt, dn, party_type, party, account, due_date),
)

View File

@@ -2,7 +2,6 @@
# See license.txt
import json
import unittest
import frappe
from frappe import qb
@@ -163,7 +162,7 @@ class TestPaymentEntry(FrappeTestCase):
supplier.on_hold = 0
supplier.save()
except:
except Exception:
pass
else:
raise Exception
@@ -470,9 +469,7 @@ class TestPaymentEntry(FrappeTestCase):
si.save()
si.submit()
pe = get_payment_entry(
"Sales Invoice", si.name, bank_account="_Test Bank - _TC", bank_amount=4700
)
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC", bank_amount=4700)
pe.reference_no = si.name
pe.reference_date = nowdate()
@@ -639,9 +636,7 @@ class TestPaymentEntry(FrappeTestCase):
pe.set_exchange_rate()
pe.set_amounts()
self.assertEqual(
pe.source_exchange_rate, 65.1, "{0} is not equal to {1}".format(pe.source_exchange_rate, 65.1)
)
self.assertEqual(pe.source_exchange_rate, 65.1, f"{pe.source_exchange_rate} is not equal to {65.1}")
def test_internal_transfer_usd_to_inr(self):
pe = frappe.new_doc("Payment Entry")
@@ -910,9 +905,7 @@ class TestPaymentEntry(FrappeTestCase):
cost_center = "_Test Cost Center for BS Account - _TC"
create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
pi = make_purchase_invoice_against_cost_center(
cost_center=cost_center, credit_to="Creditors - _TC"
)
pi = make_purchase_invoice_against_cost_center(cost_center=cost_center, credit_to="Creditors - _TC")
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
self.assertEqual(pe.cost_center, pi.cost_center)
@@ -953,9 +946,7 @@ class TestPaymentEntry(FrappeTestCase):
si = create_sales_invoice_against_cost_center(cost_center=cost_center, debit_to="Debtors - _TC")
account_balance = get_balance_on(account="_Test Bank - _TC", cost_center=si.cost_center)
party_balance = get_balance_on(
party_type="Customer", party=si.customer, cost_center=si.cost_center
)
party_balance = get_balance_on(party_type="Customer", party=si.customer, cost_center=si.cost_center)
party_account_balance = get_balance_on(si.debit_to, cost_center=si.cost_center)
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC")
@@ -1096,7 +1087,9 @@ class TestPaymentEntry(FrappeTestCase):
pe.source_exchange_rate = 50
pe.save()
ref_details = get_reference_details(so.doctype, so.name, pe.paid_from_account_currency)
ref_details = get_reference_details(
so.doctype, so.name, pe.paid_from_account_currency, "Customer", so.customer
)
expected_response = {
"total_amount": 5000.0,
"outstanding_amount": 5000.0,
@@ -1214,7 +1207,7 @@ class TestPaymentEntry(FrappeTestCase):
Overallocation validation shouldn't fire for Template without "Allocate Payment based on Payment Terms" enabled
"""
customer = create_customer()
create_customer()
create_payment_terms_template()
template = frappe.get_doc("Payment Terms Template", "Test Receivable Template")
@@ -1273,9 +1266,7 @@ class TestPaymentEntry(FrappeTestCase):
create_payment_terms_template()
# SI has an earlier due date and SI2 has a later due date
si = create_sales_invoice(
qty=1, rate=100, customer=customer, posting_date=add_days(nowdate(), -4)
)
si = create_sales_invoice(qty=1, rate=100, customer=customer, posting_date=add_days(nowdate(), -4))
si2 = create_sales_invoice(do_not_save=1, qty=1, rate=100, customer=customer)
si2.payment_terms_template = "Test Receivable Template"
si2.submit()
@@ -1401,12 +1392,11 @@ def create_payment_entry(**args):
def create_payment_terms_template():
create_payment_term("Basic Amount Receivable")
create_payment_term("Tax Receivable")
if not frappe.db.exists("Payment Terms Template", "Test Receivable Template"):
payment_term_template = frappe.get_doc(
frappe.get_doc(
{
"doctype": "Payment Terms Template",
"template_name": "Test Receivable Template",

View File

@@ -108,9 +108,9 @@ class PaymentLedgerEntry(Document):
):
if not self.get(dimension.fieldname):
frappe.throw(
_("Accounting Dimension <b>{0}</b> is required for 'Profit and Loss' account {1}.").format(
dimension.label, self.account
)
_(
"Accounting Dimension <b>{0}</b> is required for 'Profit and Loss' account {1}."
).format(dimension.label, self.account)
)
if (
@@ -121,9 +121,9 @@ class PaymentLedgerEntry(Document):
):
if not self.get(dimension.fieldname):
frappe.throw(
_("Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}.").format(
dimension.label, self.account
)
_(
"Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}."
).format(dimension.label, self.account)
)
def validate(self):

View File

@@ -84,11 +84,14 @@ class TestPaymentLedgerEntry(FrappeTestCase):
self.customer = customer.name
def create_sales_invoice(
self, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False
self, qty=1, rate=100, posting_date=None, do_not_save=False, do_not_submit=False
):
"""
Helper function to populate default values in sales invoice
"""
if posting_date is None:
posting_date = nowdate()
sinv = create_sales_invoice(
qty=qty,
rate=rate,
@@ -112,10 +115,12 @@ class TestPaymentLedgerEntry(FrappeTestCase):
)
return sinv
def create_payment_entry(self, amount=100, posting_date=nowdate()):
def create_payment_entry(self, amount=100, posting_date=None):
"""
Helper function to populate default values in payment entry
"""
if posting_date is None:
posting_date = nowdate()
payment = create_payment_entry(
company=self.company,
payment_type="Receive",
@@ -128,9 +133,10 @@ class TestPaymentLedgerEntry(FrappeTestCase):
payment.posting_date = posting_date
return payment
def create_sales_order(
self, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False
):
def create_sales_order(self, qty=1, rate=100, posting_date=None, do_not_save=False, do_not_submit=False):
if posting_date is None:
posting_date = nowdate()
so = make_sales_order(
company=self.company,
transaction_date=posting_date,
@@ -159,9 +165,7 @@ class TestPaymentLedgerEntry(FrappeTestCase):
for doctype in doctype_list:
qb.from_(qb.DocType(doctype)).delete().where(qb.DocType(doctype).company == self.company).run()
def create_journal_entry(
self, acc1=None, acc2=None, amount=0, posting_date=None, cost_center=None
):
def create_journal_entry(self, acc1=None, acc2=None, amount=0, posting_date=None, cost_center=None):
je = frappe.new_doc("Journal Entry")
je.posting_date = posting_date or nowdate()
je.company = self.company
@@ -319,9 +323,7 @@ class TestPaymentLedgerEntry(FrappeTestCase):
ple.amount,
ple.delinked,
)
.where(
(ple.against_voucher_type == cr_note1.doctype) & (ple.against_voucher_no == cr_note1.name)
)
.where((ple.against_voucher_type == cr_note1.doctype) & (ple.against_voucher_no == cr_note1.name))
.orderby(ple.creation)
.run(as_dict=True)
)
@@ -362,9 +364,7 @@ class TestPaymentLedgerEntry(FrappeTestCase):
)
cr_note2.is_return = 1
cr_note2 = cr_note2.save().submit()
je1 = self.create_journal_entry(
self.debit_to, self.debit_to, amount, posting_date=transaction_date
)
je1 = self.create_journal_entry(self.debit_to, self.debit_to, amount, posting_date=transaction_date)
je1.get("accounts")[0].party_type = je1.get("accounts")[1].party_type = "Customer"
je1.get("accounts")[0].party = je1.get("accounts")[1].party = self.customer
je1.get("accounts")[0].reference_type = cr_note2.doctype
@@ -419,9 +419,7 @@ class TestPaymentLedgerEntry(FrappeTestCase):
ple.amount,
ple.delinked,
)
.where(
(ple.against_voucher_type == cr_note2.doctype) & (ple.against_voucher_no == cr_note2.name)
)
.where((ple.against_voucher_type == cr_note2.doctype) & (ple.against_voucher_no == cr_note2.name))
.orderby(ple.creation)
.run(as_dict=True)
)
@@ -518,7 +516,7 @@ class TestPaymentLedgerEntry(FrappeTestCase):
amount = 100
so = self.create_sales_order(qty=1, rate=amount, posting_date=transaction_date).save().submit()
pe = get_payment_entry(so.doctype, so.name).save().submit()
get_payment_entry(so.doctype, so.name).save().submit()
so.reload()
so.cancel()

View File

@@ -36,7 +36,7 @@ frappe.ui.form.on("Payment Order", {
// payment Entry
if (frm.doc.docstatus === 1 && frm.doc.payment_order_type === "Payment Request") {
frm.add_custom_button(__("Create Payment Entries"), function () {
frm.add_custom_button(__("Create Journal Entries"), function () {
frm.trigger("make_payment_records");
});
}
@@ -71,6 +71,7 @@ frappe.ui.form.on("Payment Order", {
target: frm,
date_field: "posting_date",
setters: {
party_type: "Supplier",
party: frm.doc.supplier || "",
},
get_query_filters: {
@@ -91,6 +92,7 @@ frappe.ui.form.on("Payment Order", {
source_doctype: "Payment Request",
target: frm,
setters: {
party_type: "Supplier",
party: frm.doc.supplier || "",
},
get_query_filters: {

View File

@@ -66,9 +66,7 @@ def make_journal_entry(doc, supplier, mode_of_payment=None):
je = frappe.new_doc("Journal Entry")
je.payment_order = doc.name
je.posting_date = nowdate()
mode_of_payment_type = frappe._dict(
frappe.get_all("Mode of Payment", fields=["name", "type"], as_list=1)
)
mode_of_payment_type = frappe._dict(frappe.get_all("Mode of Payment", fields=["name", "type"], as_list=1))
je.voucher_type = "Bank Entry"
if mode_of_payment and mode_of_payment_type.get(mode_of_payment) == "Cash":

View File

@@ -1,7 +1,6 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
@@ -41,9 +40,7 @@ class TestPaymentOrder(FrappeTestCase):
payment_entry.insert()
payment_entry.submit()
doc = create_payment_order_against_payment_entry(
payment_entry, "Payment Entry", self.bank_account
)
doc = create_payment_order_against_payment_entry(payment_entry, "Payment Entry", self.bank_account)
reference_doc = doc.get("references")[0]
self.assertEqual(reference_doc.reference_name, payment_entry.name)
self.assertEqual(reference_doc.reference_doctype, "Payment Entry")

View File

@@ -25,7 +25,7 @@ from erpnext.controllers.accounts_controller import get_advance_payment_entries_
class PaymentReconciliation(Document):
def __init__(self, *args, **kwargs):
super(PaymentReconciliation, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.common_filter_conditions = []
self.accounting_dimension_filter_conditions = []
self.ple_posting_date_filter = []
@@ -200,6 +200,7 @@ class PaymentReconciliation(Document):
conditions.append(doc.docstatus == 1)
conditions.append(doc[frappe.scrub(self.party_type)] == self.party)
conditions.append(doc.is_return == 1)
conditions.append(doc.outstanding_amount != 0)
if self.payment_name:
conditions.append(doc.name.like(f"%{self.payment_name}%"))
@@ -219,7 +220,6 @@ class PaymentReconciliation(Document):
self.return_invoices = self.return_invoices_query.run(as_dict=True)
def get_dr_or_cr_notes(self):
self.build_qb_filter_conditions(get_return_invoices=True)
ple = qb.DocType("Payment Ledger Entry")
@@ -340,9 +340,7 @@ class PaymentReconciliation(Document):
payment_entry[0].get("reference_name")
)
new_difference_amount = self.get_difference_amount(
payment_entry[0], invoice[0], allocated_amount
)
new_difference_amount = self.get_difference_amount(payment_entry[0], invoice[0], allocated_amount)
return new_difference_amount
@frappe.whitelist()
@@ -460,9 +458,9 @@ class PaymentReconciliation(Document):
if running_doc:
frappe.throw(
_("A Reconciliation Job {0} is running for the same filters. Cannot reconcile now").format(
get_link_to_form("Auto Reconcile", running_doc)
)
_(
"A Reconciliation Job {0} is running for the same filters. Cannot reconcile now"
).format(get_link_to_form("Auto Reconcile", running_doc))
)
return
@@ -555,9 +553,7 @@ class PaymentReconciliation(Document):
invoice_exchange_map.update(purchase_invoice_map)
journals = [
d.get("invoice_number") for d in invoices if d.get("invoice_type") == "Journal Entry"
]
journals = [d.get("invoice_number") for d in invoices if d.get("invoice_type") == "Journal Entry"]
journals.extend(
[d.get("reference_name") for d in payments if d.get("reference_type") == "Journal Entry"]
)
@@ -677,7 +673,7 @@ class PaymentReconciliation(Document):
def get_journal_filter_conditions(self):
conditions = []
je = qb.DocType("Journal Entry")
jea = qb.DocType("Journal Entry Account")
qb.DocType("Journal Entry Account")
conditions.append(je.company == self.company)
if self.from_payment_date:
@@ -797,7 +793,7 @@ def adjust_allocations_for_taxes(doc):
@frappe.whitelist()
def get_queries_for_dimension_filters(company: str = None):
def get_queries_for_dimension_filters(company: str | None = None):
dimensions_with_filters = []
for d in get_dimensions()[0]:
filters = {}

View File

@@ -1,7 +1,6 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe import qb
@@ -127,11 +126,14 @@ class TestPaymentReconciliation(FrappeTestCase):
setattr(self, x.attribute, acc.name)
def create_sales_invoice(
self, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False
self, qty=1, rate=100, posting_date=None, do_not_save=False, do_not_submit=False
):
"""
Helper function to populate default values in sales invoice
"""
if posting_date is None:
posting_date = nowdate()
sinv = create_sales_invoice(
qty=qty,
rate=rate,
@@ -155,10 +157,13 @@ class TestPaymentReconciliation(FrappeTestCase):
)
return sinv
def create_payment_entry(self, amount=100, posting_date=nowdate(), customer=None):
def create_payment_entry(self, amount=100, posting_date=None, customer=None):
"""
Helper function to populate default values in payment entry
"""
if posting_date is None:
posting_date = nowdate()
payment = create_payment_entry(
company=self.company,
payment_type="Receive",
@@ -172,11 +177,14 @@ class TestPaymentReconciliation(FrappeTestCase):
return payment
def create_purchase_invoice(
self, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False
self, qty=1, rate=100, posting_date=None, do_not_save=False, do_not_submit=False
):
"""
Helper function to populate default values in sales invoice
"""
if posting_date is None:
posting_date = nowdate()
pinv = make_purchase_invoice(
qty=qty,
rate=rate,
@@ -201,11 +209,14 @@ class TestPaymentReconciliation(FrappeTestCase):
return pinv
def create_purchase_order(
self, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False
self, qty=1, rate=100, posting_date=None, do_not_save=False, do_not_submit=False
):
"""
Helper function to populate default values in sales invoice
"""
if posting_date is None:
posting_date = nowdate()
pord = create_purchase_order(
qty=qty,
rate=rate,
@@ -250,9 +261,7 @@ class TestPaymentReconciliation(FrappeTestCase):
pr.from_invoice_date = pr.to_invoice_date = pr.from_payment_date = pr.to_payment_date = nowdate()
return pr
def create_journal_entry(
self, acc1=None, acc2=None, amount=0, posting_date=None, cost_center=None
):
def create_journal_entry(self, acc1=None, acc2=None, amount=0, posting_date=None, cost_center=None):
je = frappe.new_doc("Journal Entry")
je.posting_date = posting_date or nowdate()
je.company = self.company
@@ -402,7 +411,7 @@ class TestPaymentReconciliation(FrappeTestCase):
rate = 100
invoices = []
payments = []
for i in range(5):
for _i in range(5):
invoices.append(self.create_sales_invoice(qty=1, rate=rate, posting_date=transaction_date))
pe = self.create_payment_entry(amount=rate, posting_date=transaction_date).save().submit()
payments.append(pe)
@@ -821,9 +830,7 @@ class TestPaymentReconciliation(FrappeTestCase):
cr_note.cancel()
pay = self.create_payment_entry(
amount=amount, posting_date=transaction_date, customer=self.customer3
)
pay = self.create_payment_entry(amount=amount, posting_date=transaction_date, customer=self.customer3)
pay.paid_from = self.debtors_eur
pay.paid_from_account_currency = "EUR"
pay.source_exchange_rate = exchange_rate
@@ -1025,9 +1032,7 @@ class TestPaymentReconciliation(FrappeTestCase):
rate = 100
# 'Main - PR' Cost Center
si1 = self.create_sales_invoice(
qty=1, rate=rate, posting_date=transaction_date, do_not_submit=True
)
si1 = self.create_sales_invoice(qty=1, rate=rate, posting_date=transaction_date, do_not_submit=True)
si1.cost_center = self.main_cc.name
si1.submit()
@@ -1043,9 +1048,7 @@ class TestPaymentReconciliation(FrappeTestCase):
je1 = je1.save().submit()
# 'Sub - PR' Cost Center
si2 = self.create_sales_invoice(
qty=1, rate=rate, posting_date=transaction_date, do_not_submit=True
)
si2 = self.create_sales_invoice(qty=1, rate=rate, posting_date=transaction_date, do_not_submit=True)
si2.cost_center = self.sub_cc.name
si2.submit()
@@ -1332,6 +1335,46 @@ class TestPaymentReconciliation(FrappeTestCase):
# Should not raise frappe.exceptions.ValidationError: Payment Entry has been modified after you pulled it. Please pull it again.
pr.reconcile()
def test_cr_note_payment_limit_filter(self):
transaction_date = nowdate()
amount = 100
for _ in range(6):
self.create_sales_invoice(qty=1, rate=amount, posting_date=transaction_date)
cr_note = self.create_sales_invoice(
qty=-1, rate=amount, posting_date=transaction_date, do_not_save=True, do_not_submit=True
)
cr_note.is_return = 1
cr_note = cr_note.save().submit()
pr = self.create_payment_reconciliation()
pr.get_unreconciled_entries()
self.assertEqual(len(pr.invoices), 6)
self.assertEqual(len(pr.payments), 6)
invoices = [x.as_dict() for x in pr.get("invoices")]
payments = [x.as_dict() for x in pr.get("payments")]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
pr.reconcile()
pr.get_unreconciled_entries()
self.assertEqual(pr.get("invoices"), [])
self.assertEqual(pr.get("payments"), [])
self.create_sales_invoice(qty=1, rate=amount, posting_date=transaction_date)
cr_note = self.create_sales_invoice(
qty=-1, rate=amount, posting_date=transaction_date, do_not_save=True, do_not_submit=True
)
cr_note.is_return = 1
cr_note = cr_note.save().submit()
# Limit should not affect in fetching the unallocated cr_note
pr.invoice_limit = 5
pr.payment_limit = 5
pr.get_unreconciled_entries()
self.assertEqual(len(pr.invoices), 1)
self.assertEqual(len(pr.payments), 1)
def make_customer(customer_name, currency=None):
if not frappe.db.exists("Customer", customer_name):

View File

@@ -28,7 +28,7 @@ frappe.ui.form.on("Payment Request", "refresh", function (frm) {
if (
frm.doc.payment_request_type == "Inward" &&
frm.doc.payment_channel !== "Phone" &&
!in_list(["Initiated", "Paid"], frm.doc.status) &&
!["Initiated", "Paid"].includes(frm.doc.status) &&
!frm.doc.__islocal &&
frm.doc.docstatus == 1
) {

View File

@@ -37,7 +37,7 @@ class PaymentRequest(Document):
self.status = "Draft"
self.validate_reference_document()
self.validate_payment_request_amount()
self.validate_currency()
# self.validate_currency()
self.validate_subscription_details()
def validate_reference_document(self):
@@ -50,7 +50,7 @@ class PaymentRequest(Document):
)
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if not hasattr(ref_doc, "order_type") or getattr(ref_doc, "order_type") != "Shopping Cart":
if not hasattr(ref_doc, "order_type") or ref_doc.order_type != "Shopping Cart":
ref_amount = get_amount(ref_doc, self.payment_account)
if existing_payment_request_amount + flt(self.grand_total) > ref_amount:
@@ -103,7 +103,7 @@ class PaymentRequest(Document):
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if (
hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart"
hasattr(ref_doc, "order_type") and ref_doc.order_type == "Shopping Cart"
) or self.flags.mute_email:
send_mail = False
@@ -155,7 +155,7 @@ class PaymentRequest(Document):
def make_invoice(self):
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart":
if hasattr(ref_doc, "order_type") and ref_doc.order_type == "Shopping Cart":
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
si = make_sales_invoice(self.reference_name, ignore_permissions=True)
@@ -241,14 +241,10 @@ class PaymentRequest(Document):
else:
party_account = get_party_account("Customer", ref_doc.get("customer"), ref_doc.company)
party_account_currency = ref_doc.get("party_account_currency") or get_account_currency(
party_account
)
party_account_currency = ref_doc.get("party_account_currency") or get_account_currency(party_account)
bank_amount = self.grand_total
if (
party_account_currency == ref_doc.company_currency and party_account_currency != self.currency
):
if party_account_currency == ref_doc.company_currency and party_account_currency != self.currency:
party_amount = ref_doc.get("base_rounded_total") or ref_doc.get("base_grand_total")
else:
party_amount = self.grand_total
@@ -266,7 +262,7 @@ class PaymentRequest(Document):
"mode_of_payment": self.mode_of_payment,
"reference_no": self.name,
"reference_date": nowdate(),
"remarks": "Payment Entry against {0} {1} via Payment Request {2}".format(
"remarks": "Payment Entry against {} {} via Payment Request {}".format(
self.reference_doctype, self.reference_name, self.name
),
}
@@ -280,21 +276,28 @@ class PaymentRequest(Document):
}
)
if party_account_currency == ref_doc.company_currency and party_account_currency != self.currency:
amount = payment_entry.base_paid_amount
else:
amount = self.grand_total
payment_entry.received_amount = amount
payment_entry.get("references")[0].allocated_amount = amount
# Update 'Paid Amount' on Forex transactions
if self.currency != ref_doc.company_currency:
if (
self.payment_request_type == "Outward"
and payment_entry.paid_from_account_currency == ref_doc.company_currency
and payment_entry.paid_from_account_currency != payment_entry.paid_to_account_currency
):
payment_entry.paid_amount = payment_entry.base_paid_amount = (
payment_entry.target_exchange_rate * payment_entry.received_amount
)
for dimension in get_accounting_dimensions():
payment_entry.update({dimension: self.get(dimension)})
if payment_entry.difference_amount:
company_details = get_company_defaults(ref_doc.company)
payment_entry.append(
"deductions",
{
"account": company_details.exchange_gain_loss_account,
"cost_center": company_details.cost_center,
"amount": payment_entry.difference_amount,
},
)
if submit:
payment_entry.insert(ignore_permissions=True)
payment_entry.submit()
@@ -380,14 +383,13 @@ class PaymentRequest(Document):
and hasattr(frappe.local, "session")
and frappe.local.session.user != "Guest"
) and self.payment_channel != "Phone":
success_url = shopping_cart_settings.payment_success_url
if success_url:
redirect_to = ({"Orders": "/orders", "Invoices": "/invoices", "My Account": "/me"}).get(
success_url, "/me"
)
else:
redirect_to = get_url("/orders/{0}".format(self.reference_name))
redirect_to = get_url(f"/orders/{self.reference_name}")
return redirect_to
@@ -413,15 +415,11 @@ def make_payment_request(**args):
frappe.db.set_value(
"Sales Order", args.dn, "loyalty_points", int(args.loyalty_points), update_modified=False
)
frappe.db.set_value(
"Sales Order", args.dn, "loyalty_amount", loyalty_amount, update_modified=False
)
frappe.db.set_value("Sales Order", args.dn, "loyalty_amount", loyalty_amount, update_modified=False)
grand_total = grand_total - loyalty_amount
bank_account = (
get_party_bank_account(args.get("party_type"), args.get("party"))
if args.get("party_type")
else ""
get_party_bank_account(args.get("party_type"), args.get("party")) if args.get("party_type") else ""
)
draft_payment_request = frappe.db.get_value(
@@ -441,6 +439,12 @@ def make_payment_request(**args):
pr = frappe.get_doc("Payment Request", draft_payment_request)
else:
pr = frappe.new_doc("Payment Request")
if not args.get("payment_request_type"):
args["payment_request_type"] = (
"Outward" if args.get("dt") in ["Purchase Order", "Purchase Invoice"] else "Inward"
)
pr.update(
{
"payment_gateway_account": gateway_account.get("name"),
@@ -499,9 +503,9 @@ def get_amount(ref_doc, payment_account=None):
elif dt in ["Sales Invoice", "Purchase Invoice"]:
if not ref_doc.get("is_pos"):
if ref_doc.party_account_currency == ref_doc.currency:
grand_total = flt(ref_doc.outstanding_amount)
grand_total = flt(ref_doc.grand_total)
else:
grand_total = flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate
grand_total = flt(ref_doc.base_grand_total) / ref_doc.conversion_rate
elif dt == "Sales Invoice":
for pay in ref_doc.payments:
if pay.type == "Phone" and pay.account == payment_account:
@@ -603,7 +607,11 @@ def update_payment_req_status(doc, method):
if payment_request_name:
ref_details = get_reference_details(
ref.reference_doctype, ref.reference_name, doc.party_account_currency
ref.reference_doctype,
ref.reference_name,
doc.party_account_currency,
doc.party_type,
doc.party,
)
pay_req_doc = frappe.get_doc("Payment Request", payment_request_name)
status = pay_req_doc.status

View File

@@ -4,10 +4,12 @@
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.setup.utils import get_exchange_rate
@@ -32,7 +34,7 @@ payment_method = [
]
class TestPaymentRequest(unittest.TestCase):
class TestPaymentRequest(FrappeTestCase):
def setUp(self):
if not frappe.db.get_value("Payment Gateway", payment_gateway["gateway"], "name"):
frappe.get_doc(payment_gateway).insert(ignore_permissions=True)
@@ -86,6 +88,8 @@ class TestPaymentRequest(unittest.TestCase):
pr = make_payment_request(
dt="Purchase Invoice",
dn=si_usd.name,
party_type="Supplier",
party="_Test Supplier USD",
recipient_id="user@example.com",
mute_email=1,
payment_gateway_account="_Test Gateway - USD",
@@ -93,11 +97,56 @@ class TestPaymentRequest(unittest.TestCase):
return_doc=1,
)
pe = pr.create_payment_entry()
pr.create_payment_entry()
pr.load_from_db()
self.assertEqual(pr.status, "Paid")
def test_multiple_payment_entry_against_purchase_invoice(self):
purchase_invoice = make_purchase_invoice(
customer="_Test Supplier USD",
debit_to="_Test Payable USD - _TC",
currency="USD",
conversion_rate=50,
)
pr = make_payment_request(
dt="Purchase Invoice",
party_type="Supplier",
party="_Test Supplier USD",
dn=purchase_invoice.name,
recipient_id="user@example.com",
mute_email=1,
payment_gateway_account="_Test Gateway - USD",
return_doc=1,
)
pr.grand_total = pr.grand_total / 2
pr.submit()
pr.create_payment_entry()
purchase_invoice.load_from_db()
self.assertEqual(purchase_invoice.status, "Partly Paid")
pr = make_payment_request(
dt="Purchase Invoice",
party_type="Supplier",
party="_Test Supplier USD",
dn=purchase_invoice.name,
recipient_id="user@example.com",
mute_email=1,
payment_gateway_account="_Test Gateway - USD",
return_doc=1,
)
pr.save()
pr.submit()
pr.create_payment_entry()
purchase_invoice.load_from_db()
self.assertEqual(purchase_invoice.status, "Paid")
def test_payment_entry(self):
frappe.db.set_value(
"Company", "_Test Company", "exchange_gain_loss_account", "_Test Exchange Gain/Loss - _TC"
@@ -158,7 +207,7 @@ class TestPaymentRequest(unittest.TestCase):
self.assertTrue(gl_entries)
for i, gle in enumerate(gl_entries):
for _i, gle in enumerate(gl_entries):
self.assertEqual(expected_gle[gle.account][0], gle.account)
self.assertEqual(expected_gle[gle.account][1], gle.debit)
self.assertEqual(expected_gle[gle.account][2], gle.credit)
@@ -213,3 +262,19 @@ class TestPaymentRequest(unittest.TestCase):
# Try to make Payment Request more than SO amount, should give validation
pr2.grand_total = 900
self.assertRaises(frappe.ValidationError, pr2.save)
def test_conversion_on_foreign_currency_accounts(self):
po_doc = create_purchase_order(supplier="_Test Supplier USD", currency="USD", do_not_submit=1)
po_doc.conversion_rate = 80
po_doc.items[0].qty = 1
po_doc.items[0].rate = 10
po_doc.save().submit()
pr = make_payment_request(dt=po_doc.doctype, dn=po_doc.name, recipient_id="nabin@erpnext.com")
pr = frappe.get_doc(pr).save().submit()
pe = pr.create_payment_entry()
self.assertEqual(pe.base_paid_amount, 800)
self.assertEqual(pe.paid_amount, 800)
self.assertEqual(pe.base_received_amount, 800)
self.assertEqual(pe.received_amount, 10)

View File

@@ -19,9 +19,7 @@ class PaymentTermsTemplate(Document):
total_portion += flt(term.get("invoice_portion", 0))
if flt(total_portion, 2) != 100.00:
frappe.msgprint(
_("Combined invoice portion must equal 100%"), raise_exception=1, indicator="red"
)
frappe.msgprint(_("Combined invoice portion must equal 100%"), raise_exception=1, indicator="red")
def validate_terms(self):
terms = []

View File

@@ -47,7 +47,8 @@ class PeriodClosingVoucher(AccountsController):
enqueue_after_commit=True,
)
frappe.msgprint(
_("The GL Entries will be cancelled in the background, it can take a few minutes."), alert=True
_("The GL Entries will be cancelled in the background, it can take a few minutes."),
alert=True,
)
else:
make_reverse_gl_entries(voucher_type="Period Closing Voucher", voucher_no=self.name)
@@ -89,9 +90,7 @@ class PeriodClosingVoucher(AccountsController):
self.posting_date, self.fiscal_year, self.company, label=_("Posting Date"), doc=self
)
self.year_start_date = get_fiscal_year(
self.posting_date, self.fiscal_year, company=self.company
)[1]
self.year_start_date = get_fiscal_year(self.posting_date, self.fiscal_year, company=self.company)[1]
self.check_if_previous_year_closed()
@@ -121,7 +120,8 @@ class PeriodClosingVoucher(AccountsController):
previous_fiscal_year = get_fiscal_year(last_year_closing, company=self.company, boolean=True)
if previous_fiscal_year and not frappe.db.exists(
"GL Entry", {"posting_date": ("<=", last_year_closing), "company": self.company}
"GL Entry",
{"posting_date": ("<=", last_year_closing), "company": self.company, "is_cancelled": 0},
):
return
@@ -204,7 +204,9 @@ class PeriodClosingVoucher(AccountsController):
"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,
"credit": abs(flt(acc.bal_in_company_currency))
if flt(acc.bal_in_company_currency) > 0
else 0,
"is_period_closing_voucher_entry": 1,
},
item=acc,
@@ -228,7 +230,9 @@ class PeriodClosingVoucher(AccountsController):
"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,
"credit": abs(flt(acc.bal_in_company_currency))
if flt(acc.bal_in_company_currency) < 0
else 0,
"is_period_closing_voucher_entry": 1,
},
item=acc,

View File

@@ -33,7 +33,7 @@ class POSClosingEntry(StatusUpdater):
for key, value in pos_occurences.items():
if len(value) > 1:
error_list.append(
_("{} is added multiple times on rows: {}".format(frappe.bold(key), frappe.bold(value)))
_("{0} is added multiple times on rows: {1}").format(frappe.bold(key), frappe.bold(value))
)
if error_list:
@@ -128,9 +128,7 @@ def get_pos_invoices(start, end, pos_profile, user):
as_dict=1,
)
data = list(
filter(lambda d: get_datetime(start) <= get_datetime(d.timestamp) <= get_datetime(end), data)
)
data = list(filter(lambda d: get_datetime(start) <= get_datetime(d.timestamp) <= get_datetime(end), data))
# need to get taxes and payments so can't avoid get_doc
data = [frappe.get_doc("POS Invoice", d.name).as_dict() for d in data]
@@ -201,7 +199,11 @@ def make_closing_entry_from_opening(opening_entry):
else:
payments.append(
frappe._dict(
{"mode_of_payment": p.mode_of_payment, "opening_amount": 0, "expected_amount": p.amount}
{
"mode_of_payment": p.mode_of_payment,
"opening_amount": 0,
"expected_amount": p.amount,
}
)
)

View File

@@ -27,7 +27,7 @@ from erpnext.stock.doctype.serial_no.serial_no import (
class POSInvoice(SalesInvoice):
def __init__(self, *args, **kwargs):
super(POSInvoice, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def validate(self):
if not cint(self.is_pos):
@@ -129,7 +129,9 @@ class POSInvoice(SalesInvoice):
)
if paid_amt and pay.amount != paid_amt:
return frappe.throw(_("Payment related to {0} is not completed").format(pay.mode_of_payment))
return frappe.throw(
_("Payment related to {0} is not completed").format(pay.mode_of_payment)
)
def validate_pos_reserved_serial_nos(self, item):
serial_nos = get_serial_nos(item.serial_no)
@@ -164,7 +166,7 @@ class POSInvoice(SalesInvoice):
serial_nos = row.serial_no.split("\n")
if serial_nos:
for key, value in collections.Counter(serial_nos).items():
for _key, value in collections.Counter(serial_nos).items():
if value > 1:
frappe.throw(_("Duplicate Serial No {0} found").format("key"))
@@ -191,9 +193,7 @@ class POSInvoice(SalesInvoice):
frappe.throw(
_(
"Row #{}: Batch No. {} of item {} has less than required stock available, {} more required"
).format(
item.idx, bold_invalid_batch_no, bold_item_name, bold_extra_batch_qty_needed
),
).format(item.idx, bold_invalid_batch_no, bold_item_name, bold_extra_batch_qty_needed),
title=_("Item Unavailable"),
)
@@ -249,7 +249,7 @@ class POSInvoice(SalesInvoice):
available_stock, is_stock_item = get_stock_availability(d.item_code, d.warehouse)
item_code, warehouse, qty = (
item_code, warehouse, _qty = (
frappe.bold(d.item_code),
frappe.bold(d.warehouse),
frappe.bold(d.qty),

View File

@@ -338,9 +338,7 @@ class TestPOSInvoice(unittest.TestCase):
)
pos.set("payments", [])
pos.append(
"payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - _TC", "amount": 50}
)
pos.append("payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - _TC", "amount": 50})
pos.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 60, "default": 1}
)
@@ -594,9 +592,7 @@ class TestPOSInvoice(unittest.TestCase):
from erpnext.accounts.doctype.loyalty_program.test_loyalty_program import create_records
create_records()
frappe.db.set_value(
"Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty"
)
frappe.db.set_value("Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty")
before_lp_details = get_loyalty_program_details_with_points(
"Test Loyalty Customer", company="_Test Company", loyalty_program="Test Single Loyalty"
)
@@ -670,9 +666,7 @@ class TestPOSInvoice(unittest.TestCase):
consolidate_pos_invoices()
pos_inv.load_from_db()
rounded_total = frappe.db.get_value(
"Sales Invoice", pos_inv.consolidated_invoice, "rounded_total"
)
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv.consolidated_invoice, "rounded_total")
self.assertEqual(rounded_total, 3470)
def test_merging_into_sales_invoice_with_discount_and_inclusive_tax(self):
@@ -719,9 +713,7 @@ class TestPOSInvoice(unittest.TestCase):
consolidate_pos_invoices()
pos_inv.load_from_db()
rounded_total = frappe.db.get_value(
"Sales Invoice", pos_inv.consolidated_invoice, "rounded_total"
)
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv.consolidated_invoice, "rounded_total")
self.assertEqual(rounded_total, 840)
def test_merging_with_validate_selling_price(self):
@@ -773,9 +765,7 @@ class TestPOSInvoice(unittest.TestCase):
consolidate_pos_invoices()
pos_inv2.load_from_db()
rounded_total = frappe.db.get_value(
"Sales Invoice", pos_inv2.consolidated_invoice, "rounded_total"
)
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv2.consolidated_invoice, "rounded_total")
self.assertEqual(rounded_total, 400)
def test_pos_batch_item_qty_validation(self):
@@ -839,19 +829,19 @@ class TestPOSInvoice(unittest.TestCase):
pos_inv = create_pos_invoice(qty=1, do_not_submit=1)
pos_inv.items[0].rate = 300
pos_inv.save()
self.assertEquals(pos_inv.items[0].discount_percentage, 10)
self.assertEqual(pos_inv.items[0].discount_percentage, 10)
# rate shouldn't change
self.assertEquals(pos_inv.items[0].rate, 405)
self.assertEqual(pos_inv.items[0].rate, 405)
pos_inv.ignore_pricing_rule = 1
pos_inv.save()
self.assertEquals(pos_inv.ignore_pricing_rule, 1)
self.assertEqual(pos_inv.ignore_pricing_rule, 1)
# rate should reset since pricing rules are ignored
self.assertEquals(pos_inv.items[0].rate, 450)
self.assertEqual(pos_inv.items[0].rate, 450)
pos_inv.items[0].rate = 300
pos_inv.save()
self.assertEquals(pos_inv.items[0].rate, 300)
self.assertEqual(pos_inv.items[0].rate, 300)
finally:
item_price.delete()
@@ -874,7 +864,7 @@ class TestPOSInvoice(unittest.TestCase):
dn = create_delivery_note(item_code="_Test Serialized Item With Series", serial_no=serial_no)
delivery_document_no = frappe.db.get_value("Serial No", serial_no, "delivery_document_no")
self.assertEquals(delivery_document_no, dn.name)
self.assertEqual(delivery_document_no, dn.name)
init_user_and_profile()

View File

@@ -29,7 +29,7 @@ class POSInvoiceMergeLog(Document):
for key, value in pos_occurences.items():
if len(value) > 1:
error_list.append(
_("{} is added multiple times on rows: {}".format(frappe.bold(key), frappe.bold(value)))
_("{0} is added multiple times on rows: {1}").format(frappe.bold(key), frappe.bold(value))
)
if error_list:
@@ -56,7 +56,9 @@ class POSInvoiceMergeLog(Document):
bold_pos_invoice = frappe.bold(d.pos_invoice)
bold_status = frappe.bold(status)
if docstatus != 1:
frappe.throw(_("Row #{}: POS Invoice {} is not submitted yet").format(d.idx, bold_pos_invoice))
frappe.throw(
_("Row #{}: POS Invoice {} is not submitted yet").format(d.idx, bold_pos_invoice)
)
if status == "Consolidated":
frappe.throw(
_("Row #{}: POS Invoice {} has been {}").format(d.idx, bold_pos_invoice, bold_status)
@@ -75,15 +77,17 @@ class POSInvoiceMergeLog(Document):
d.idx, bold_return_against, bold_pos_invoice, bold_unconsolidated
)
msg += " "
msg += _("Original invoice should be consolidated before or along with the return invoice.")
msg += _(
"Original invoice should be consolidated before or along with the return invoice."
)
msg += "<br><br>"
msg += _("You can add original invoice {} manually to proceed.").format(bold_return_against)
msg += _("You can add original invoice {} manually to proceed.").format(
bold_return_against
)
frappe.throw(msg)
def on_submit(self):
pos_invoice_docs = [
frappe.get_cached_doc("POS Invoice", d.pos_invoice) for d in self.pos_invoices
]
pos_invoice_docs = [frappe.get_cached_doc("POS Invoice", d.pos_invoice) for d in self.pos_invoices]
returns = [d for d in pos_invoice_docs if d.get("is_return") == 1]
sales = [d for d in pos_invoice_docs if d.get("is_return") == 0]
@@ -100,9 +104,7 @@ class POSInvoiceMergeLog(Document):
self.update_pos_invoices(pos_invoice_docs, sales_invoice, credit_note)
def on_cancel(self):
pos_invoice_docs = [
frappe.get_cached_doc("POS Invoice", d.pos_invoice) for d in self.pos_invoices
]
pos_invoice_docs = [frappe.get_cached_doc("POS Invoice", d.pos_invoice) for d in self.pos_invoices]
self.update_pos_invoices(pos_invoice_docs)
self.cancel_linked_invoices()
@@ -192,7 +194,9 @@ class POSInvoiceMergeLog(Document):
for t in taxes:
if t.account_head == tax.account_head and t.cost_center == tax.cost_center:
t.tax_amount = flt(t.tax_amount) + flt(tax.tax_amount_after_discount_amount)
t.base_tax_amount = flt(t.base_tax_amount) + flt(tax.base_tax_amount_after_discount_amount)
t.base_tax_amount = flt(t.base_tax_amount) + flt(
tax.base_tax_amount_after_discount_amount
)
update_item_wise_tax_detail(t, tax)
found = True
if not found:
@@ -292,9 +296,7 @@ def update_item_wise_tax_detail(consolidate_tax_row, tax_row):
else:
consolidated_tax_detail.update({item_code: [tax_data[0], tax_data[1]]})
consolidate_tax_row.item_wise_tax_detail = json.dumps(
consolidated_tax_detail, separators=(",", ":")
)
consolidate_tax_row.item_wise_tax_detail = json.dumps(consolidated_tax_detail, separators=(",", ":"))
def get_all_unconsolidated_invoices():
@@ -339,9 +341,7 @@ def consolidate_pos_invoices(pos_invoices=None, closing_entry=None):
if len(invoices) >= 10 and closing_entry:
closing_entry.set_status(update=True, status="Queued")
enqueue_job(
create_merge_logs, invoice_by_customer=invoice_by_customer, closing_entry=closing_entry
)
enqueue_job(create_merge_logs, invoice_by_customer=invoice_by_customer, closing_entry=closing_entry)
else:
create_merge_logs(invoice_by_customer, closing_entry)
@@ -389,9 +389,7 @@ def split_invoices(invoices):
if not item.serial_no:
continue
return_against_is_added = any(
d for d in _invoices if d.pos_invoice == pos_invoice.return_against
)
return_against_is_added = any(d for d in _invoices if d.pos_invoice == pos_invoice.return_against)
if return_against_is_added:
break
@@ -442,8 +440,8 @@ def create_merge_logs(invoice_by_customer, closing_entry=None):
if closing_entry:
closing_entry.set_status(update=True, status="Failed")
if type(error_message) == list:
error_message = frappe.json.dumps(error_message)
if isinstance(error_message, list):
error_message = json.dumps(error_message)
closing_entry.db_set("error_message", error_message)
raise
@@ -493,7 +491,7 @@ def enqueue_job(job, **kwargs):
timeout=10000,
event="processing_merge_logs",
job_name=job_name,
now=frappe.conf.developer_mode or frappe.flags.in_test
now=frappe.conf.developer_mode or frappe.flags.in_test,
)
if job == create_merge_logs:

View File

@@ -28,15 +28,11 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
pos_inv.submit()
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
pos_inv2.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200}
)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200})
pos_inv2.submit()
pos_inv3 = create_pos_invoice(customer="_Test Customer 2", rate=2300, do_not_submit=1)
pos_inv3.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 2300}
)
pos_inv3.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 2300})
pos_inv3.submit()
consolidate_pos_invoices()
@@ -65,15 +61,11 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
pos_inv.submit()
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
pos_inv2.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200}
)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200})
pos_inv2.submit()
pos_inv3 = create_pos_invoice(customer="_Test Customer 2", rate=2300, do_not_submit=1)
pos_inv3.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 2300}
)
pos_inv3.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 2300})
pos_inv3.submit()
pos_inv_cn = make_sales_return(pos_inv.name)
@@ -309,7 +301,7 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
init_user_and_profile()
item_rates = [69, 59, 29]
for i in [1, 2]:
for _i in [1, 2]:
inv = create_pos_invoice(is_return=1, do_not_save=1)
inv.items = []
for rate in item_rates:

View File

@@ -114,10 +114,8 @@ class POSProfile(Document):
condition = " where pfu.default = 1 "
pos_view_users = frappe.db.sql_list(
"""select pfu.user
from `tabPOS Profile User` as pfu {0}""".format(
condition
)
f"""select pfu.user
from `tabPOS Profile User` as pfu {condition}"""
)
for user in pos_view_users:
@@ -144,10 +142,8 @@ def get_item_groups(pos_profile):
def get_child_nodes(group_type, root):
lft, rgt = frappe.db.get_value(group_type, root, ["lft", "rgt"])
return frappe.db.sql(
""" Select name, lft, rgt from `tab{tab}` where
lft >= {lft} and rgt <= {rgt} order by lft""".format(
tab=group_type, lft=lft, rgt=rgt
),
f""" Select name, lft, rgt from `tab{group_type}` where
lft >= {lft} and rgt <= {rgt} order by lft""",
as_dict=1,
)

View File

@@ -52,11 +52,9 @@ def get_customers_list(pos_profile=None):
return (
frappe.db.sql(
""" select name, customer_name, customer_group,
f""" select name, customer_name, customer_group,
territory, customer_pos_id from tabCustomer where disabled = 0
and {cond}""".format(
cond=cond
),
and {cond}""",
tuple(customer_groups),
as_dict=1,
)
@@ -75,7 +73,7 @@ def get_items_list(pos_profile, company):
cond = "and i.item_group in (%s)" % (", ".join(["%s"] * len(args_list)))
return frappe.db.sql(
"""
f"""
select
i.name, i.item_code, i.item_name, i.description, i.item_group, i.has_batch_no,
i.has_serial_no, i.is_stock_item, i.brand, i.stock_uom, i.image,
@@ -88,10 +86,8 @@ def get_items_list(pos_profile, company):
where
i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1 and i.is_fixed_asset = 0
{cond}
""".format(
cond=cond
),
tuple([company] + args_list),
""",
tuple([company, *args_list]),
as_dict=1,
)

View File

@@ -74,15 +74,21 @@
"discount_amount",
"discount_percentage",
"for_price_list",
"section_break_13",
"threshold_percentage",
"priority",
"dynamic_condition_tab",
"condition",
"column_break_66",
"section_break_13",
"apply_multiple_pricing_rules",
"apply_discount_on_rate",
"column_break_66",
"threshold_percentage",
"validate_pricing_rule_section",
"validate_applied_rule",
"column_break_texp",
"rule_description",
"priority_section",
"has_priority",
"column_break_sayg",
"priority",
"help_section",
"pricing_rule_help",
"reference_section",
@@ -477,7 +483,7 @@
{
"collapsible": 1,
"fieldname": "section_break_13",
"fieldtype": "Section Break",
"fieldtype": "Tab Break",
"label": "Advanced Settings"
},
{
@@ -487,6 +493,7 @@
"label": "Threshold for Suggestion (In Percentage)"
},
{
"depends_on": "has_priority",
"description": "Higher the number, higher the priority",
"fieldname": "priority",
"fieldtype": "Select",
@@ -513,6 +520,7 @@
{
"default": "0",
"depends_on": "eval:doc.price_or_product_discount == 'Price'",
"description": "If enabled, then system will only validate the pricing rule and not apply automatically. User has to manually set the discount percentage / margin / free items to validate the pricing rule",
"fieldname": "validate_applied_rule",
"fieldtype": "Check",
"label": "Validate Applied Rule"
@@ -525,7 +533,8 @@
},
{
"fieldname": "help_section",
"fieldtype": "Section Break",
"fieldtype": "Tab Break",
"label": "Help Article",
"options": "Simple"
},
{
@@ -603,12 +612,42 @@
"fieldname": "apply_recursion_over",
"fieldtype": "Float",
"label": "Apply Recursion Over (As Per Transaction UOM)"
},
{
"fieldname": "priority_section",
"fieldtype": "Section Break",
"label": "Priority"
},
{
"fieldname": "dynamic_condition_tab",
"fieldtype": "Tab Break",
"label": "Dynamic Condition"
},
{
"fieldname": "validate_pricing_rule_section",
"fieldtype": "Section Break",
"label": "Validate Pricing Rule"
},
{
"fieldname": "column_break_texp",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_sayg",
"fieldtype": "Column Break"
},
{
"default": "0",
"description": "Enable this checkbox even if you want to set the zero priority",
"fieldname": "has_priority",
"fieldtype": "Check",
"label": "Has Priority"
}
],
"icon": "fa fa-gift",
"idx": 1,
"links": [],
"modified": "2023-02-14 04:53:34.887358",
"modified": "2024-05-17 13:16:34.496704",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",

View File

@@ -31,6 +31,7 @@ class PricingRule(Document):
self.validate_price_list_with_currency()
self.validate_dates()
self.validate_condition()
self.validate_mixed_with_recursion()
if not self.margin_type:
self.margin_rate_or_amount = 0.0
@@ -47,6 +48,12 @@ class PricingRule(Document):
frappe.throw(_("Duplicate {0} found in the table").format(self.apply_on))
def validate_mandatory(self):
if self.has_priority and not self.priority:
throw(_("Priority is mandatory"), frappe.MandatoryError, _("Please Set Priority"))
if self.priority and not self.has_priority:
self.has_priority = 1
for apply_on, field in apply_on_dict.items():
if self.apply_on == apply_on and len(self.get(field) or []) < 1:
throw(_("{0} is not added in the table").format(apply_on), frappe.MandatoryError)
@@ -77,9 +84,9 @@ class PricingRule(Document):
if self.priority and cint(self.priority) == 1:
throw(
_("As the field {0} is enabled, the value of the field {1} should be more than 1.").format(
frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority")
)
_(
"As the field {0} is enabled, the value of the field {1} should be more than 1."
).format(frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority"))
)
def validate_applicable_for_selling_or_buying(self):
@@ -195,6 +202,10 @@ class PricingRule(Document):
):
frappe.throw(_("Invalid condition expression"))
def validate_mixed_with_recursion(self):
if self.mixed_conditions and self.is_recursive:
frappe.throw(_("Recursive Discounts with Mixed condition is not supported by the system"))
# --------------------------------------------------------------------------------
@@ -273,9 +284,7 @@ def apply_pricing_rule(args, doc=None):
def get_serial_no_for_item(args):
from erpnext.stock.get_item_details import get_serial_no
item_details = frappe._dict(
{"doctype": args.doctype, "name": args.name, "serial_no": args.serial_no}
)
item_details = frappe._dict({"doctype": args.doctype, "name": args.name, "serial_no": args.serial_no})
if args.get("parenttype") in ("Sales Invoice", "Delivery Note") and flt(args.stock_qty) > 0:
item_details.serial_no = get_serial_no(args)
return item_details
@@ -373,9 +382,11 @@ def get_pricing_rule_for_item(args, doc=None, for_validate=False):
)
if pricing_rule.apply_rule_on_other_items:
item_details["apply_rule_on_other_items"] = json.dumps(pricing_rule.apply_rule_on_other_items)
item_details["apply_rule_on_other_items"] = json.dumps(
pricing_rule.apply_rule_on_other_items
)
if pricing_rule.coupon_code_based == 1 and args.coupon_code == None:
if pricing_rule.coupon_code_based == 1 and args.coupon_code is None:
return item_details
if not pricing_rule.validate_applied_rule:
@@ -419,7 +430,6 @@ def update_args_for_pricing_rule(args):
if args.transaction_type == "selling":
if args.customer and not (args.customer_group and args.territory):
if args.quotation_to and args.quotation_to != "Customer":
customer = frappe._dict()
else:
@@ -450,9 +460,9 @@ def get_pricing_rule_details(args, pricing_rule):
def apply_price_discount_rule(pricing_rule, item_details, args):
item_details.pricing_rule_for = pricing_rule.rate_or_discount
if (
pricing_rule.margin_type in ["Amount", "Percentage"] and pricing_rule.currency == args.currency
) or (pricing_rule.margin_type == "Percentage"):
if (pricing_rule.margin_type in ["Amount", "Percentage"] and pricing_rule.currency == args.currency) or (
pricing_rule.margin_type == "Percentage"
):
item_details.margin_type = pricing_rule.margin_type
item_details.has_margin = True
@@ -487,6 +497,22 @@ def apply_price_discount_rule(pricing_rule, item_details, args):
if pricing_rule.apply_discount_on_rate and item_details.get("discount_percentage"):
# Apply discount on discounted rate
item_details[field] += (100 - item_details[field]) * (pricing_rule.get(field, 0) / 100)
elif args.price_list_rate:
value = pricing_rule.get(field, 0)
calculate_discount_percentage = False
if field == "discount_percentage":
field = "discount_amount"
value = args.price_list_rate * (value / 100)
calculate_discount_percentage = True
if field not in item_details:
item_details.setdefault(field, 0)
item_details[field] += value if pricing_rule else args.get(field, 0)
if calculate_discount_percentage and args.price_list_rate and item_details.discount_amount:
item_details.discount_percentage = flt(
(flt(item_details.discount_amount) / flt(args.price_list_rate)) * 100
)
else:
if field not in item_details:
item_details.setdefault(field, 0)
@@ -595,7 +621,7 @@ def get_item_uoms(doctype, txt, searchfield, start, page_len, filters):
return frappe.get_all(
"UOM Conversion Detail",
filters={"parent": ("in", items), "uom": ("like", "{0}%".format(txt))},
filters={"parent": ("in", items), "uom": ("like", f"{txt}%")},
fields=["distinct uom"],
as_list=1,
)

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