Compare commits

...

606 Commits

Author SHA1 Message Date
Frappe PR Bot
08cabd1717 chore(release): Bumped to Version 15.38.4
## [15.38.4](https://github.com/frappe/erpnext/compare/v15.38.3...v15.38.4) (2024-10-17)

### Bug Fixes

* list view and form status not same for purchase order (backport [#43690](https://github.com/frappe/erpnext/issues/43690)) ([#43692](https://github.com/frappe/erpnext/issues/43692)) ([752d175](752d175d22))
2024-10-17 16:05:56 +00:00
rohitwaghchaure
6f98fe15e4 Merge pull request #43706 from frappe/mergify/bp/version-15/pr-43692
fix: list view and form status not same for purchase order (backport #43690) (backport #43692)
2024-10-17 21:34:34 +05:30
mergify[bot]
752d175d22 fix: list view and form status not same for purchase order (backport #43690) (#43692)
* fix: list view and form status not same for purchase order (#43690)

(cherry picked from commit a671fe13d4)

# Conflicts:
#	erpnext/buying/doctype/purchase_order/purchase_order.js
#	erpnext/buying/doctype/purchase_order/purchase_order_list.js

* chore: fix conflicts

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
(cherry picked from commit a33d5535a7)
2024-10-17 04:44:18 +00:00
Frappe PR Bot
99ead94ffe chore(release): Bumped to Version 15.38.3
## [15.38.3](https://github.com/frappe/erpnext/compare/v15.38.2...v15.38.3) (2024-10-16)

### Bug Fixes

* added parentheses for correct query formation for logical OR condition ([21a7dd4](21a7dd43a9))
* added string for translation in bank reconciliation statement ([e10a580](e10a58074f))
* conversion factor issue (backport [#43645](https://github.com/frappe/erpnext/issues/43645)) ([#43674](https://github.com/frappe/erpnext/issues/43674)) ([b2deb89](b2deb89826))
* delete invalid pricing rule on change of applicable_for ([5d6fc71](5d6fc71556))
* don't update reference to SI / PI on advances ([b72906a](b72906a7a1))
* ignore free item when qty is zero ([e5aaa5b](e5aaa5b6e5))
* incorrect warehouse in the serial no selector for rejection (backport [#43671](https://github.com/frappe/erpnext/issues/43671)) ([#43673](https://github.com/frappe/erpnext/issues/43673)) ([c490a66](c490a66540))
* Link opportunity from RFQ to supplier quotation ([eb1f125](eb1f1255eb))
* missing child company accounts in consolidated balance sheet ([4db12fe](4db12fe2da))
* quotation to so frappe crm (backport [#43644](https://github.com/frappe/erpnext/issues/43644)) ([#43646](https://github.com/frappe/erpnext/issues/43646)) ([f3ceb4a](f3ceb4ac7d))
* refetch items from BOM if 'Use Multi-Level BOM' has changed usin… (backport [#43672](https://github.com/frappe/erpnext/issues/43672)) ([#43676](https://github.com/frappe/erpnext/issues/43676)) ([492ba53](492ba539e8))
* removed unused query ([8668ae9](8668ae92d8))
* run gl_entries and closing voucher processes in same function ([ea12897](ea12897ce9))
* show incorrect entries filter in Stock Ledger Invariant Check report (backport [#43619](https://github.com/frappe/erpnext/issues/43619)) ([#43622](https://github.com/frappe/erpnext/issues/43622)) ([d604b12](d604b12d51))
* **stock:** Grab posting date/time from SABB (backport [#43493](https://github.com/frappe/erpnext/issues/43493)) ([#43502](https://github.com/frappe/erpnext/issues/43502)) ([cd9f949](cd9f949b12))
* update formatings ([c2c6d27](c2c6d27625))
* update formatings ([a70181e](a70181e025))
* update item details with actual quantity. ([930e79c](930e79c351))
* Use `ref_doc.get()` for `party_account_currency` ([928b6b1](928b6b1510))
* zero incoming rate for delivery note return ([#43642](https://github.com/frappe/erpnext/issues/43642)) ([85088e4](85088e4aff))
2024-10-16 05:01:44 +00:00
ruthra kumar
e05ae14d49 Merge pull request #43667 from frappe/version-15-hotfix
chore: release v15
2024-10-16 10:30:25 +05:30
mergify[bot]
cd9f949b12 fix(stock): Grab posting date/time from SABB (backport #43493) (#43502)
fix(stock): Grab posting date/time from SABB (#43493)

(cherry picked from commit ade121dac6)

Co-authored-by: Corentin Forler <10946971+cogk@users.noreply.github.com>
2024-10-15 17:45:35 +05:30
ruthra kumar
aef544cd53 Merge pull request #43684 from frappe/mergify/bp/version-15-hotfix/pr-43661
fix: missing child company accounts in consolidated balance sheet (backport #43661)
2024-10-15 17:37:52 +05:30
ruthra kumar
d34025dc11 Merge pull request #43682 from frappe/mergify/bp/version-15-hotfix/pr-43663
fix: run gl_entries and closing voucher processes in same function (backport #43663)
2024-10-15 17:22:39 +05:30
ljain112
4db12fe2da fix: missing child company accounts in consolidated balance sheet
(cherry picked from commit 7fae9d57d2)
2024-10-15 11:38:10 +00:00
ljain112
ea12897ce9 fix: run gl_entries and closing voucher processes in same function
(cherry picked from commit af4daa5b0f)
2024-10-15 11:35:55 +00:00
ruthra kumar
802d9b2d4a Merge pull request #43680 from frappe/mergify/bp/version-15-hotfix/pr-43602
fix: added parentheses for correct query formation for logical OR condition (backport #43602)
2024-10-15 17:03:22 +05:30
mergify[bot]
492ba539e8 fix: refetch items from BOM if 'Use Multi-Level BOM' has changed usin… (backport #43672) (#43676)
fix: refetch items from BOM if 'Use Multi-Level BOM' has changed usin… (#43672)

fix: refetch items from BOM if 'Use Multi-Level BOM' has changed using api
(cherry picked from commit 05915415de)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-15 16:47:40 +05:30
ljain112
21a7dd43a9 fix: added parentheses for correct query formation for logical OR condition
(cherry picked from commit c0da8f11f7)
2024-10-15 11:15:59 +00:00
ruthra kumar
50d1fa4665 Merge pull request #43678 from frappe/mergify/bp/version-15-hotfix/pr-43600
fix: added string for translation in bank reconciliation statement (backport #43600)
2024-10-15 16:41:06 +05:30
ljain112
e10a58074f fix: added string for translation in bank reconciliation statement
(cherry picked from commit c99d9f7037)
2024-10-15 11:02:42 +00:00
mergify[bot]
b2deb89826 fix: conversion factor issue (backport #43645) (#43674)
fix: conversion factor issue (#43645)

(cherry picked from commit a52756f1d4)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-15 16:04:48 +05:30
mergify[bot]
c490a66540 fix: incorrect warehouse in the serial no selector for rejection (backport #43671) (#43673)
fix: incorrect warehouse in the serial no selector for rejection (#43671)

(cherry picked from commit 29ff682eca)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-15 16:04:36 +05:30
ruthra kumar
afa0c13587 Merge pull request #43670 from frappe/mergify/bp/version-15-hotfix/pr-43557
fix: delete invalid pricing rule on change of applicable_for values (backport #43557)
2024-10-15 15:56:43 +05:30
ljain112
4dbee00b82 test: added test for change in applicable_for_value in promotional scheme
(cherry picked from commit 2613bdd868)
2024-10-15 10:00:47 +00:00
ljain112
5d6fc71556 fix: delete invalid pricing rule on change of applicable_for
(cherry picked from commit 42746fc630)
2024-10-15 10:00:47 +00:00
ruthra kumar
06dd5e0071 Merge pull request #43666 from frappe/mergify/bp/version-15-hotfix/pr-43662
fix: removed unused query (backport #43662)
2024-10-15 13:52:32 +05:30
ruthra kumar
105f9ec2e1 chore: resolve conflict 2024-10-15 13:32:29 +05:30
ruthra kumar
dc6fdbb836 Merge pull request #43660 from frappe/mergify/bp/version-15-hotfix/pr-43642
fix: zero incoming rate for delivery note return (backport #43642)
2024-10-15 13:26:32 +05:30
ljain112
8668ae92d8 fix: removed unused query
(cherry picked from commit 5f590ddfa2)

# Conflicts:
#	erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
2024-10-15 07:53:44 +00:00
ruthra kumar
ec7e5c48de Merge pull request #43658 from frappe/mergify/bp/version-15-hotfix/pr-43570
fix: update item details with actual quantity (backport #43570)
2024-10-15 13:15:39 +05:30
rohitwaghchaure
85088e4aff fix: zero incoming rate for delivery note return (#43642)
(cherry picked from commit 6087a57b0c)
2024-10-15 06:28:59 +00:00
Bhavan23
c2c6d27625 fix: update formatings
(cherry picked from commit 5044297321)
2024-10-15 06:27:52 +00:00
Bhavan23
a70181e025 fix: update formatings
(cherry picked from commit 5f4a523340)
2024-10-15 06:27:52 +00:00
Bhavan23
86017b223a test: Validate the actual quantity when creating a material request from the sales order
(cherry picked from commit 17fdd42645)
2024-10-15 06:27:51 +00:00
Bhavan23
930e79c351 fix: update item details with actual quantity.
(cherry picked from commit 9dbdfec9b7)
2024-10-15 06:27:51 +00:00
ruthra kumar
2c7f5ec324 Merge pull request #43521 from mujeerhashmi/version-15-hotfix
fix: Link opportunity from RFQ to supplier quotation
2024-10-15 10:08:25 +05:30
ruthra kumar
a9f5e86600 Merge pull request #43654 from frappe/mergify/bp/version-15-hotfix/pr-43601
refactor: remove 'format:' based naming (backport #43601)
2024-10-15 07:34:35 +05:30
ruthra kumar
d6decf9172 Merge pull request #43650 from frappe/mergify/bp/version-15-hotfix/pr-43614
fix: ignore free item when qty is zero (backport #43614)
2024-10-15 06:01:30 +05:30
ruthra kumar
1fac17b36f chore: resolve conflict 2024-10-15 06:00:12 +05:30
venkat102
9d05a6ebc0 refactor: remove 'format:' based naming
(cherry picked from commit e8e1ec0e85)

# Conflicts:
#	erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.json
2024-10-14 15:46:06 +00:00
Ninad1306
389ee909a5 test: test case to validate free item is ignored when qty is zero
(cherry picked from commit a2b41a0c16)
2024-10-14 10:50:58 +00:00
Ninad1306
e5aaa5b6e5 fix: ignore free item when qty is zero
(cherry picked from commit 7ae98f77ee)
2024-10-14 10:50:58 +00:00
mergify[bot]
f3ceb4ac7d fix: quotation to so frappe crm (backport #43644) (#43646)
fix: quotation to so frappe crm (#43644)

(cherry picked from commit d57624b182)

Co-authored-by: Nihantra C. Patel <141945075+Nihantra-Patel@users.noreply.github.com>
2024-10-14 15:03:35 +05:30
Smit Vora
050ca4b726 Merge pull request #43641 from frappe/mergify/bp/version-15-hotfix/pr-43638
fix: Use `ref_doc.get()` for `party_account_currency` (backport #43638)
2024-10-14 13:59:13 +05:30
Abdeali Chharchhoda
928b6b1510 fix: Use ref_doc.get() for party_account_currency
(cherry picked from commit b79549422a)
2024-10-14 06:09:09 +00:00
Frappe PR Bot
ef1e121bd4 chore(release): Bumped to Version 15.38.2
## [15.38.2](https://github.com/frappe/erpnext/compare/v15.38.1...v15.38.2) (2024-10-13)

### Bug Fixes

* don't update reference to SI / PI on advances ([8bf8bcf](8bf8bcf739))
2024-10-13 05:23:41 +00:00
ruthra kumar
68f1b41969 Merge pull request #43633 from frappe/mergify/bp/version-15/pr-43627
fix: reconciled advance from reported in reconciliation tool (backport #43627)
2024-10-13 10:52:21 +05:30
ruthra kumar
a329003f7f chore: use correct hook for advance payment doctypes 2024-10-13 10:35:48 +05:30
ruthra kumar
cf1eabe049 chore: resolve conflict 2024-10-13 10:35:14 +05:30
ruthra kumar
4c78a682ad chore: better comments for context
(cherry picked from commit e7505e92c9)
2024-10-13 04:59:58 +00:00
ruthra kumar
4752ed2483 test: reconciled Invoice should not showup in tool
Scenario should be tested on 'Advance in separate party account'

(cherry picked from commit f1ec61c19e)
2024-10-13 04:59:58 +00:00
ruthra kumar
e56dd8268b test: unreconciliation of individual SO from Advance Payment
(cherry picked from commit 8a6978e550)
2024-10-13 04:59:58 +00:00
ruthra kumar
e0477cf59f refactor(test): utility methods for enabling advance in separate acc
(cherry picked from commit a21a406d04)

# Conflicts:
#	erpnext/accounts/test/accounts_mixin.py
2024-10-13 04:59:58 +00:00
ruthra kumar
8c115e146b refactor: use hooks to identify advance doctypes
(cherry picked from commit e7bb960bb5)
2024-10-13 04:59:58 +00:00
ruthra kumar
6267ab994c refactor: reference update logic in advance
(cherry picked from commit a112581acd)
2024-10-13 04:59:58 +00:00
ruthra kumar
8bf8bcf739 fix: don't update reference to SI / PI on advances
(cherry picked from commit b409f74620)
2024-10-13 04:59:57 +00:00
ruthra kumar
eed02d3f44 Merge pull request #43632 from frappe/mergify/bp/version-15-hotfix/pr-43627
fix: reconciled advance from reported in reconciliation tool (backport #43627)
2024-10-13 10:24:41 +05:30
ruthra kumar
6265582e53 refactor: use correct hook for identifying advance doctypes 2024-10-13 09:50:41 +05:30
ruthra kumar
361836e735 chore: resolve conflict 2024-10-13 08:45:15 +05:30
ruthra kumar
ae73d9c621 chore: better comments for context
(cherry picked from commit e7505e92c9)
2024-10-13 03:08:25 +00:00
ruthra kumar
2c2ca22d12 test: reconciled Invoice should not showup in tool
Scenario should be tested on 'Advance in separate party account'

(cherry picked from commit f1ec61c19e)
2024-10-13 03:08:25 +00:00
ruthra kumar
e37a88fdb6 test: unreconciliation of individual SO from Advance Payment
(cherry picked from commit 8a6978e550)
2024-10-13 03:08:25 +00:00
ruthra kumar
9c26093a51 refactor(test): utility methods for enabling advance in separate acc
(cherry picked from commit a21a406d04)

# Conflicts:
#	erpnext/accounts/test/accounts_mixin.py
2024-10-13 03:08:24 +00:00
ruthra kumar
5ce2d73692 refactor: use hooks to identify advance doctypes
(cherry picked from commit e7bb960bb5)
2024-10-13 03:08:24 +00:00
ruthra kumar
ca0a962870 refactor: reference update logic in advance
(cherry picked from commit a112581acd)
2024-10-13 03:08:24 +00:00
ruthra kumar
b72906a7a1 fix: don't update reference to SI / PI on advances
(cherry picked from commit b409f74620)
2024-10-13 03:08:23 +00:00
mergify[bot]
d604b12d51 fix: show incorrect entries filter in Stock Ledger Invariant Check report (backport #43619) (#43622)
fix: show incorrect entries filter in Stock Ledger Invariant Check report (#43619)

fix: show incorrect entry filter in Stock Ledger Invariant Check report
(cherry picked from commit 8beee1982f)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-11 16:22:22 +05:30
Frappe PR Bot
d46cf46375 chore(release): Bumped to Version 15.38.1
## [15.38.1](https://github.com/frappe/erpnext/compare/v15.38.0...v15.38.1) (2024-10-09)

### Bug Fixes

* 'NoneType' object has no attribute 'has_serial_no' (backport [#43514](https://github.com/frappe/erpnext/issues/43514)) ([#43574](https://github.com/frappe/erpnext/issues/43574)) ([60508a9](60508a9706))
* [#42014](https://github.com/frappe/erpnext/issues/42014) --resolve conflicts ([85d7405](85d74050e1))
* Accepted and Rejected warehouse cannot be same (backport [#43568](https://github.com/frappe/erpnext/issues/43568)) ([#43573](https://github.com/frappe/erpnext/issues/43573)) ([83ce3dd](83ce3dd915))
* add include closed orders option in so/po trends report v15 ([5660e8b](5660e8b26d))
* add parenttype condition for item table in Purchase Register Report ([8ce81a0](8ce81a058a))
* Add removed test code `b41f10c1b9` ([30fd11f](30fd11f138))
* allow to change the batch in the subcontracting receipt (backport [#43584](https://github.com/frappe/erpnext/issues/43584)) ([#43588](https://github.com/frappe/erpnext/issues/43588)) ([9e109ac](9e109acec7))
* create Account Closing Balance even though there are no transaction in period ([d6f70f5](d6f70f533a))
* creation of contact, customer, opportunity, quotation and prospect from lead ([ef10c4e](ef10c4ea4f))
* creation of contact, customer, opportunity, quotation and prospect from lead --prettier ([5a2a404](5a2a404a50))
* deduct advances adjusted for threshold check for tcs ([6decb7c](6decb7cc34))
* do not include advances for tds vouchers ([ee8485a](ee8485a54a))
* frappe dependency update ([0a70b3f](0a70b3ffcc))
* include parent item group in query ([55464c7](55464c79c4))
* make LCV button not working for PI and PR (backport [#43592](https://github.com/frappe/erpnext/issues/43592)) ([#43593](https://github.com/frappe/erpnext/issues/43593)) ([120b481](120b481c4a))
* multiple issues in Payment Request ([#42427](https://github.com/frappe/erpnext/issues/42427)) ([ea69ba7](ea69ba7cd8))
* production plan bom error (backport [#43591](https://github.com/frappe/erpnext/issues/43591)) ([#43594](https://github.com/frappe/erpnext/issues/43594)) ([029021f](029021f035))
* read only filters in multidialog fields (backport [#43503](https://github.com/frappe/erpnext/issues/43503)) ([#43513](https://github.com/frappe/erpnext/issues/43513)) ([d69a974](d69a974a4d))
* Remove `advance_payment_status` uses ([907e3af](907e3af1b0))
* Remove unreference method ([770bc1c](770bc1c293))
* Remove unused  field ([e785928](e785928c0f))
* Remove unused function `get_paid_amount_against_order` ([7591662](75916629c8))
* Separate `on_submit` and `before_submit` of PR ([dbd7b83](dbd7b83204))
* the purchase receipt trends and delivery note trends report (backport [#43585](https://github.com/frappe/erpnext/issues/43585)) ([#43587](https://github.com/frappe/erpnext/issues/43587)) ([355ba2f](355ba2f632))
* Unknown column 'serial_no' in 'field list' (backport [#43515](https://github.com/frappe/erpnext/issues/43515)) ([#43569](https://github.com/frappe/erpnext/issues/43569)) ([fc9a3c0](fc9a3c0c92))
* Update Values before `after_mapping` hook is called ([#42682](https://github.com/frappe/erpnext/issues/42682)) ([6770610](6770610c6d))
* validation for corrective job card (backport [#43555](https://github.com/frappe/erpnext/issues/43555)) ([#43558](https://github.com/frappe/erpnext/issues/43558)) ([cf0fa0d](cf0fa0db7b))
2024-10-09 12:02:42 +00:00
rohitwaghchaure
c3f6edcd01 Merge pull request #43563 from frappe/version-15-hotfix
chore: release v15
2024-10-09 17:31:15 +05:30
mergify[bot]
120b481c4a fix: make LCV button not working for PI and PR (backport #43592) (#43593)
fix: make LCV button not working for PI and PR (#43592)

(cherry picked from commit 48a12e7213)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-09 15:41:38 +05:30
mergify[bot]
029021f035 fix: production plan bom error (backport #43591) (#43594)
fix: production plan bom error (#43591)

(cherry picked from commit ab171326f3)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-09 15:41:21 +05:30
mergify[bot]
9e109acec7 fix: allow to change the batch in the subcontracting receipt (backport #43584) (#43588)
fix: allow to change the batch in the subcontracting receipt (#43584)

(cherry picked from commit fc67867a60)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-09 13:43:02 +05:30
mergify[bot]
355ba2f632 fix: the purchase receipt trends and delivery note trends report (backport #43585) (#43587)
* fix: fix the purchase receipt trends and delivery note trends report

(cherry picked from commit 2e9dda1588)

* fix: trends date filter issue --formatter

(cherry picked from commit b3e4463a4f)

---------

Co-authored-by: Vishv-silveroak <108357657+Vishv-024@users.noreply.github.com>
Co-authored-by: Nihantra C. Patel <141945075+Nihantra-Patel@users.noreply.github.com>
2024-10-09 13:38:43 +05:30
mergify[bot]
83ce3dd915 fix: Accepted and Rejected warehouse cannot be same (backport #43568) (#43573)
fix: Accepted and Rejected warehouse cannot be same (#43568)

(cherry picked from commit 5130f7d411)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-09 09:06:34 +05:30
mergify[bot]
60508a9706 fix: 'NoneType' object has no attribute 'has_serial_no' (backport #43514) (#43574)
fix: 'NoneType' object has no attribute 'has_serial_no' (#43514)

(cherry picked from commit 6ddda6c949)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-09 09:06:20 +05:30
Smit Vora
660d20f7fa Merge pull request #43572 from frappe/mergify/bp/version-15-hotfix/pr-43271
fix: deduct advances adjusted for threshold check for tcs (backport #43271)
2024-10-08 22:31:21 +05:30
Nihantra C. Patel
0b2603bbf1 Merge pull request #43577 from Nihantra-Patel/feat_trends_report_v15
fix: add include closed orders option in so/po trends report v15
2024-10-08 19:07:39 +05:30
Nihantra Patel
5660e8b26d fix: add include closed orders option in so/po trends report v15 2024-10-08 18:48:11 +05:30
mergify[bot]
cf0fa0db7b fix: validation for corrective job card (backport #43555) (#43558)
* fix: validation for corrective job card (#43555)

(cherry picked from commit 7a0a893d08)

# Conflicts:
#	erpnext/manufacturing/doctype/job_card/job_card.py

* chore: fix conflicts

* chore: fix linters issue

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-08 17:40:52 +05:30
mergify[bot]
fc9a3c0c92 fix: Unknown column 'serial_no' in 'field list' (backport #43515) (#43569)
fix: Unknown column 'serial_no' in 'field list' (#43515)

(cherry picked from commit 69127e8609)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-08 17:40:22 +05:30
ljain112
2b4cd0a9bb test: added test cases for the tcs deduction for advances adjusted.
(cherry picked from commit efe238cefd)
2024-10-08 12:05:52 +00:00
ljain112
6decb7cc34 fix: deduct advances adjusted for threshold check for tcs
(cherry picked from commit 767c8f92be)
2024-10-08 12:05:52 +00:00
Smit Vora
9039b86e8a Merge pull request #43553 from frappe/mergify/bp/version-15-hotfix/pr-43397
fix: do not include advances for tds vouchers (backport #43397)
2024-10-08 11:30:02 +05:30
ljain112
ee8485a54a fix: do not include advances for tds vouchers
(cherry picked from commit 7ef918421e)
2024-10-08 05:09:10 +00:00
mergify[bot]
05db28c64f chore: Allow apps to extend voucher subtypes (backport #43528) (backport #43550) (#43551)
chore: Allow apps to extend voucher subtypes (#43528)

* chore: Allow apps to extend voucher subtypes

(cherry picked from commit a1525d9b8e)

* chore: Allow apps to extend voucher subtypes

(cherry picked from commit 8a1e38a43b)

* chore: Allow apps to extend voucher subtypes

(cherry picked from commit ca8820b566)

---------

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
(cherry picked from commit bcd0105915)

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-10-08 09:20:34 +05:30
mergify[bot]
bcd0105915 chore: Allow apps to extend voucher subtypes (#43528)
* chore: Allow apps to extend voucher subtypes

(cherry picked from commit a1525d9b8e)

* chore: Allow apps to extend voucher subtypes

(cherry picked from commit 8a1e38a43b)

* chore: Allow apps to extend voucher subtypes

(cherry picked from commit ca8820b566)

---------

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2024-10-08 09:01:25 +05:30
Smit Vora
225adf5cbc Merge pull request #43527 from frappe/mergify/bp/version-15-hotfix/pr-43391
fix: create Account Closing Balance even though there are no transaction in period (backport #43391)
2024-10-07 22:34:46 +05:30
Smit Vora
af5947edd0 Merge pull request #43407 from Abdeali099/pr-backport
fix: multiple issues in Payment Request (#42427)
2024-10-07 21:45:01 +05:30
ljain112
d6f70f533a fix: create Account Closing Balance even though there are no transaction in period
(cherry picked from commit 43deaea96b)
2024-10-07 16:12:28 +00:00
Smit Vora
1dd4168c0e Merge pull request #43525 from frappe/mergify/bp/version-15-hotfix/pr-43384
fix: add parenttype condition for item table in Purchase Register Report (backport #43384)
2024-10-07 21:42:06 +05:30
Smit Vora
db4360d76c Merge pull request #43523 from frappe/mergify/bp/version-15-hotfix/pr-43385
fix: include parent item group in query (backport #43385)
2024-10-07 21:41:05 +05:30
ljain112
8ce81a058a fix: add parenttype condition for item table in Purchase Register Report
(cherry picked from commit 28abf191fc)
2024-10-07 15:55:50 +00:00
ljain112
55464c79c4 fix: include parent item group in query
(cherry picked from commit ad0090068d)
2024-10-07 15:47:46 +00:00
Smit Vora
0c599c2b6d chore: remove unused filed 2024-10-07 20:36:53 +05:30
Syed Mujeer Hashmi
eb1f1255eb fix: Link opportunity from RFQ to supplier quotation 2024-10-07 14:12:43 +00:00
Abdeali Chharchhoda
62cc86114b test: Change Accounts Settings for multi currency (https://github.com/frappe/erpnext/pull/42427#discussion_r1789859737) 2024-10-07 16:00:06 +05:30
Smit Vora
5268da2e55 Merge pull request #43355 from Ninad1306/mapping_docs_fix
fix: update child table from the last source doc (backport #42925)
2024-10-07 15:18:41 +05:30
Smit Vora
d695fea251 Merge pull request #43512 from Ninad1306/sales_purchase_mapping_fix
fix: Update Values before `after_mapping` hook is called (backport #42682)
2024-10-07 15:15:44 +05:30
Nihantra C. Patel
6b2983d8c1 Merge pull request #43296 from frappe/mergify/bp/version-15-hotfix/pr-42014
fix: creation of contact, customer, opportunity, quotation and prospect from lead (backport #42014)
2024-10-07 14:59:57 +05:30
Nihantra C. Patel
85d74050e1 fix: #42014 --resolve conflicts 2024-10-07 14:51:04 +05:30
mergify[bot]
d69a974a4d fix: read only filters in multidialog fields (backport #43503) (#43513)
fix: read only filters in multidialog fields (#43503)

(cherry picked from commit 13eb3c5c14)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-07 13:57:56 +05:30
Abdeali Chharchhoda
3d9d56ab50 test: Remove Payment Gateway settings from test 2024-10-07 12:42:59 +05:30
Abdeali Chharchhoda
dbd7b83204 fix: Separate on_submit and before_submit of PR 2024-10-07 12:33:42 +05:30
Ninad Parikh
6770610c6d fix: Update Values before after_mapping hook is called (#42682)
* fix: update values before after_mapping hook is called

* fix: appropriate function name
2024-10-07 12:19:49 +05:30
Abdeali Chharchhoda
75916629c8 fix: Remove unused function get_paid_amount_against_order 2024-10-07 12:10:51 +05:30
Abdeali Chharchhoda
e785928c0f fix: Remove unused field 2024-10-07 12:08:02 +05:30
Frappe PR Bot
edfa6e41e1 chore(release): Bumped to Version 15.38.0
# [15.38.0](https://github.com/frappe/erpnext/compare/v15.37.0...v15.38.0) (2024-10-04)

### Bug Fixes

* 'NoneType' object has no attribute 'has_serial_no' ([21a0157](21a01575b6))
* add company filter in Warehouse wise Item Balance Age and Value ([4fc6d3e](4fc6d3ef64))
* adjustmen entry for stock reco ([c551c27](c551c2714c))
* Cannot read properties of undefined (reading 'price_list_rate') (backport [#43376](https://github.com/frappe/erpnext/issues/43376)) ([#43377](https://github.com/frappe/erpnext/issues/43377)) ([47f06dc](47f06dc180))
* Data missing in table: None, MandatoryError (backport [#43422](https://github.com/frappe/erpnext/issues/43422)) ([#43429](https://github.com/frappe/erpnext/issues/43429)) ([4b3f143](4b3f143f83))
* **Dunning:** logic for fetching text (backport [#43160](https://github.com/frappe/erpnext/issues/43160)) ([#43490](https://github.com/frappe/erpnext/issues/43490)) ([1b28a4e](1b28a4e928))
* Fix API endpoint for Frankfurter ([d96cee8](d96cee8779))
* Ignore transaction deletion check on ledger entry insertion ([1d6f97a](1d6f97ad94))
* **Item:** error message on tax rate (backport [#42955](https://github.com/frappe/erpnext/issues/42955)) ([#42956](https://github.com/frappe/erpnext/issues/42956)) ([5fc5934](5fc5934942))
* last purchase rate for purchase invoice (backport [#43448](https://github.com/frappe/erpnext/issues/43448)) ([#43452](https://github.com/frappe/erpnext/issues/43452)) ([ee2c8c8](ee2c8c869a))
* negative stock error for batch (backport [#43450](https://github.com/frappe/erpnext/issues/43450)) ([#43454](https://github.com/frappe/erpnext/issues/43454)) ([7bf6251](7bf6251c21))
* patch to update Currency Exchange Settings for `frankfurter.app` (backport [#43481](https://github.com/frappe/erpnext/issues/43481)) ([#43483](https://github.com/frappe/erpnext/issues/43483)) ([35a08f8](35a08f8830))
* quality inspection creation (backport [#43416](https://github.com/frappe/erpnext/issues/43416)) ([#43417](https://github.com/frappe/erpnext/issues/43417)) ([a1b6628](a1b6628c41))
* **Quotation:** calculate row values for alternative items (backport [#43054](https://github.com/frappe/erpnext/issues/43054)) ([#43495](https://github.com/frappe/erpnext/issues/43495)) ([4fa5131](4fa5131590))
* removed validation for materials return (backport [#43461](https://github.com/frappe/erpnext/issues/43461)) ([#43463](https://github.com/frappe/erpnext/issues/43463)) ([9c0a17e](9c0a17e4d5))
* serial and batch no selector (backport [#43387](https://github.com/frappe/erpnext/issues/43387)) ([#43390](https://github.com/frappe/erpnext/issues/43390)) ([74c880c](74c880c232))
* set margin fields for purchase documents when updating items ([6516e68](6516e68fa0))
* Stock Ledger Invariant Check report ([2984bad](2984bad2c0))
* Stock UOM not fetched when Stock Entry create from Item Dashboard (backport [#43457](https://github.com/frappe/erpnext/issues/43457)) ([#43465](https://github.com/frappe/erpnext/issues/43465)) ([f2a72e5](f2a72e5f82))
* tests for work order consumption (backport [#41814](https://github.com/frappe/erpnext/issues/41814)) ([#43430](https://github.com/frappe/erpnext/issues/43430)) ([86b10ce](86b10ce9bb))
* use serial and batch fields (backport [#43421](https://github.com/frappe/erpnext/issues/43421)) ([#43423](https://github.com/frappe/erpnext/issues/43423)) ([d495d93](d495d93840))

### Features

* added 'cost of new capitalized asset' column ([27cd51e](27cd51e267))
* provide hook point for bulk transaction tasks ([50e47e7](50e47e796d))
2024-10-04 03:07:05 +00:00
ruthra kumar
5a9522e70f Merge pull request #43467 from frappe/version-15-hotfix
chore: release v15
2024-10-04 08:35:53 +05:30
mergify[bot]
4fa5131590 fix(Quotation): calculate row values for alternative items (backport #43054) (#43495)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix(Quotation): calculate row values for alternative items (#43054)
2024-10-04 01:23:59 +01:00
mergify[bot]
1b28a4e928 fix(Dunning): logic for fetching text (backport #43160) (#43490)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix(Dunning): logic for fetching text (#43160)
2024-10-03 20:28:53 +01:00
mergify[bot]
f2a72e5f82 fix: Stock UOM not fetched when Stock Entry create from Item Dashboard (backport #43457) (#43465)
fix: Stock UOM not fetched when Stock Entry create from Item Dashboard (#43457)

(cherry picked from commit 895b072bad)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-02 18:46:01 +05:30
Sagar Vora
661eb058b9 Merge pull request #43485 from frappe/mergify/bp/version-15-hotfix/pr-43475
fix: set margin fields for purchase documents when updating items (backport #43475)
2024-10-02 15:24:08 +05:30
Sagar Vora
6516e68fa0 fix: set margin fields for purchase documents when updating items
(cherry picked from commit 7be4d56be2)
2024-10-02 09:52:29 +00:00
mergify[bot]
35a08f8830 fix: patch to update Currency Exchange Settings for frankfurter.app (backport #43481) (#43483)
Co-authored-by: Sagar Vora <sagar@resilient.tech>
2024-10-02 15:15:48 +05:30
Sagar Vora
562327f041 Merge pull request #43478 from frappe/mergify/bp/version-15-hotfix/pr-43476
fix: Fix API endpoint for Frankfurter (backport #43476)
2024-10-02 14:43:14 +05:30
Sagar Vora
8e7d893669 test: update test for API change
(cherry picked from commit c444de017a)
2024-10-02 09:11:47 +00:00
Corentin Forler
d96cee8779 fix: Fix API endpoint for Frankfurter
(cherry picked from commit 33e72111c7)
2024-10-02 09:11:47 +00:00
mergify[bot]
96c4d1af63 Serial no report (backport #43444) (#43464)
Serial no report (#43444)

* chore: remove the field that which is not exiting in serial no

* chore: remove the field that which is not exiting in serial no

* chore: remove the field that which is not exiting in serial no

(cherry picked from commit 661efadf41)

Co-authored-by: Vishv-silveroak <108357657+Vishv-024@users.noreply.github.com>
2024-10-01 14:27:27 +05:30
mergify[bot]
9c0a17e4d5 fix: removed validation for materials return (backport #43461) (#43463)
fix: removed validation for materials return (#43461)

(cherry picked from commit 1c7154c7ca)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-01 14:26:38 +05:30
mergify[bot]
ee2c8c869a fix: last purchase rate for purchase invoice (backport #43448) (#43452)
* fix: last purchase rate for purchase invoice

(cherry picked from commit fb9d106633)

# Conflicts:
#	erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py

* chore: fix conflicts

---------

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
2024-10-01 12:54:26 +05:30
Nihantra C. Patel
15b34a607f Merge pull request #43459 from frappe/mergify/bp/version-15-hotfix/pr-43455
fix: add company filter in Warehouse wise Item Balance Age and Value (backport #43455)
2024-10-01 11:46:46 +05:30
Nihantra Patel
4fc6d3ef64 fix: add company filter in Warehouse wise Item Balance Age and Value
(cherry picked from commit 75950f86cf)
2024-10-01 05:47:36 +00:00
mergify[bot]
7bf6251c21 fix: negative stock error for batch (backport #43450) (#43454)
fix: negative stock error for batch (#43450)

(cherry picked from commit 912ba7789c)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-10-01 10:34:48 +05:30
mergify[bot]
5fc5934942 fix(Item): error message on tax rate (backport #42955) (#42956)
Co-authored-by: barredterra <14891507+barredterra@users.noreply.github.com>
2024-09-30 22:18:49 +02:00
Frappe PR Bot
01f9139ebd chore(release): Bumped to Version 15.37.0
# [15.37.0](https://github.com/frappe/erpnext/compare/v15.36.4...v15.37.0) (2024-09-30)

### Features

* added 'cost of new capitalized asset' column ([96d8b52](96d8b5242d))
2024-09-30 17:21:09 +00:00
rohitwaghchaure
4be557bdce Merge pull request #43453 from frappe/mergify/bp/version-15/pr-43412
feat: added 'cost of new capitalized asset' column (backport #43399) (backport #43412)
2024-09-30 22:49:53 +05:30
Khushi Rawat
96d8b5242d feat: added 'cost of new capitalized asset' column
(cherry picked from commit 1eb9cc33fc)
(cherry picked from commit 27cd51e267)
2024-09-30 15:45:59 +00:00
Abdeali Chharchhoda
67bd540135 test: Removed initial PR status assertion 2024-09-30 18:21:59 +05:30
Abdeali Chharchhoda
30fd11f138 fix: Add removed test code b41f10c1b9 2024-09-30 17:20:42 +05:30
rohitwaghchaure
0986d3ebe4 Merge pull request #43440 from frappe/mergify/bp/version-15-hotfix/pr-43437
fix: adjustment entry for stock reco (backport #43437)
2024-09-30 15:38:00 +05:30
Rohit Waghchaure
c551c2714c fix: adjustmen entry for stock reco
(cherry picked from commit 4e463b7d6d)
2024-09-30 08:57:54 +00:00
rohitwaghchaure
efc97cc59f Merge pull request #43438 from frappe/mergify/bp/version-15-hotfix/pr-43436
fix: 'NoneType' object has no attribute 'has_serial_no' (backport #43436)
2024-09-30 14:26:17 +05:30
Rohit Waghchaure
21a01575b6 fix: 'NoneType' object has no attribute 'has_serial_no'
(cherry picked from commit 28f9fd2507)
2024-09-30 08:11:20 +00:00
ruthra kumar
6f3b5604b9 Merge pull request #43434 from frappe/mergify/bp/version-15-hotfix/pr-43058
refactor: use hooks to extend bulk_transaction (backport #43058)
2024-09-30 09:58:44 +05:30
Kitti U
50e47e796d feat: provide hook point for bulk transaction tasks
(cherry picked from commit d4dd01d8d1)
2024-09-30 04:07:53 +00:00
Khushi Rawat
4d3e43bdbe Merge pull request #43412 from frappe/mergify/bp/version-15-hotfix/pr-43399
feat: added 'cost of new capitalized asset' column (backport #43399)
2024-09-29 23:28:43 +05:30
rohitwaghchaure
928c887de5 Merge pull request #43433 from frappe/mergify/bp/version-15-hotfix/pr-43420
fix: Stock Ledger Invariant Check report (backport #43420)
2024-09-29 22:55:58 +05:30
Rohit Waghchaure
2984bad2c0 fix: Stock Ledger Invariant Check report
(cherry picked from commit d7daedc5b2)
2024-09-29 17:07:33 +00:00
Frappe PR Bot
2d09ef2509 chore(release): Bumped to Version 15.36.4
## [15.36.4](https://github.com/frappe/erpnext/compare/v15.36.3...v15.36.4) (2024-09-29)

### Bug Fixes

* Data missing in table: None, MandatoryError (backport [#43422](https://github.com/frappe/erpnext/issues/43422)) ([#43429](https://github.com/frappe/erpnext/issues/43429)) ([2c4610c](2c4610c021))
2024-09-29 16:38:13 +00:00
rohitwaghchaure
8b5997e38f Merge pull request #43431 from frappe/mergify/bp/version-15/pr-43429
fix: Data missing in table: None, MandatoryError (backport #43422) (backport #43429)
2024-09-29 22:07:02 +05:30
mergify[bot]
86b10ce9bb fix: tests for work order consumption (backport #41814) (#43430)
fix: tests for work order consumption (#41814)

* fix: tests for work order automatic SABB creation

* fix: qty

* chore: show created sabb

* chore: fix syntax

* fix: check SABB qty

* fix: add batched consumable to manufacture

* fix: missing fg qty field

* fix: improve test debug

* chore: linting

* chore: removed extra hash icons

---------

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
(cherry picked from commit ca3c680909)

Co-authored-by: Richard Case <110036763+casesolved-co-uk@users.noreply.github.com>
2024-09-29 22:06:50 +05:30
mergify[bot]
2c4610c021 fix: Data missing in table: None, MandatoryError (backport #43422) (#43429)
fix: Data missing in table: None, MandatoryError (#43422)

(cherry picked from commit 8e33e0e1d2)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
(cherry picked from commit 4b3f143f83)
2024-09-29 15:57:24 +00:00
mergify[bot]
4b3f143f83 fix: Data missing in table: None, MandatoryError (backport #43422) (#43429)
fix: Data missing in table: None, MandatoryError (#43422)

(cherry picked from commit 8e33e0e1d2)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-29 21:18:25 +05:30
mergify[bot]
d495d93840 fix: use serial and batch fields (backport #43421) (#43423)
fix: use serial and batch fields (#43421)

(cherry picked from commit ca16089d9d)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-29 11:09:32 +05:30
mergify[bot]
a1b6628c41 fix: quality inspection creation (backport #43416) (#43417)
fix: quality inspection creation (#43416)

(cherry picked from commit a594c05296)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-29 09:46:14 +05:30
Abdeali Chharchhoda
770bc1c293 fix: Remove unreference method 2024-09-28 12:29:34 +05:30
Abdeali Chharchhoda
907e3af1b0 fix: Remove advance_payment_status uses 2024-09-28 12:09:33 +05:30
Frappe PR Bot
e706aa692a chore(release): Bumped to Version 15.36.3
## [15.36.3](https://github.com/frappe/erpnext/compare/v15.36.2...v15.36.3) (2024-09-27)

### Bug Fixes

* Ignore transaction deletion check on ledger entry insertion ([c1f14f2](c1f14f2991))
2024-09-27 18:30:37 +00:00
Deepesh Garg
a5fa287dad Merge pull request #43413 from frappe/mergify/bp/version-15/pr-43411
fix: Ignore transaction deletion check on ledger entry insertion (#43410)
2024-09-27 23:58:16 +05:30
Deepesh Garg
c1f14f2991 fix: Ignore transaction deletion check on ledger entry insertion
(cherry picked from commit 998f6a92a4)
(cherry picked from commit 1d6f97ad94)
2024-09-27 18:25:49 +00:00
Deepesh Garg
6d66002374 Merge pull request #43411 from frappe/mergify/bp/version-15-hotfix/pr-43410
fix: Ignore transaction deletion check on ledger entry insertion (#43410)
2024-09-27 23:54:54 +05:30
Khushi Rawat
27cd51e267 feat: added 'cost of new capitalized asset' column
(cherry picked from commit 1eb9cc33fc)
2024-09-27 18:23:34 +00:00
Deepesh Garg
1d6f97ad94 fix: Ignore transaction deletion check on ledger entry insertion
(cherry picked from commit 998f6a92a4)
2024-09-27 18:22:41 +00:00
Abdeali Chharchhodawala
ea69ba7cd8 fix: multiple issues in Payment Request (#42427)
* fix: multiple issues in Payment Request

* chore: minor changes

* fix: remove  bug

* fix: replace `round` with `flt`

* fix: update `set_advance_payment_status()` logic

* fix: removed bug of `set_advance_payment_status`

* fix: changes as per review

* refactor: replace sql query of `matched_payment_requests` to query builder

* fix: replace `locals` with `get_doc` in set_query

* fix: changes during review

* fix: minor review changes

* fix: remove unnecessary code for setting payment entry received amount

* fix: logic for ser payment_request if PE made from transaction

* fix: Use rounded total to make Payment Request from `Sales Invoice` or `Purchase Invoice`

* refactor: enhance logic of `set_open_payment_requests_to_references`

* fix: added one optional arg `created_from_payment_request`

* fix: handle multiple allocation of PR at PE's reference

* fix: logic for PR if outstanding docs fetch

* fix: formatted Link field for `Payment Request` for PE's references

* fix: replace `get_all()` with `get_list()` for getting Payment Request for Link field

* fix: replace `get_all()` with `get_list()` for getting Payment Request for Link field

* chore: format `payment_entry.js` file

* style: Show preview popup of `Payment Request`

* fix: remove minor bug

* fix: add virtual field for Payment Term and Request `outstanding_amount` in PE's reference

* fix: get outstanding amount in PE's reference on realtime

* fix: move allocation of allocated_amount to server side (no change)

* fix: some minor changes to allocation

* fix: Split `Payment Request` if PE is created from PR and there are `Payment Terms`

* fix: minor logic changes

* fix: Allocation of allocated_amount if `paid_amount` is changes

* fix: improve logic of allocation

* fix: set matched payment request if unset

* fix: minor changes

* fix: Allocate single Payment Request if PE created from PR

* fix: improve code logic

* fix: Removed duplication code

* fix: proper message title

* refactor: Rename method of Allocation Amount to References

* refactor: Changing `grand_total` description based on `party_type`

* refactor: update Payment Request

* fix: Remove virtual property of payment_term_oustanding from references

* fix: fetch party account currency for creating payment request

* fix: use transaction currency as base in payment request

* fix: party amount for creating payment entry

* fix: allow for proportional amount paid by bank

* fix: Changed field order in Payment Request

* fix: Minor refactor in Payment Entry Reference table data

* test: Added test cases for allow Payment at `Partially Paid` status for PR

* test: Update partial paid status test case

* test: Update test case for same currency PR

* refactor: Wider the `msgprint` dialog for after save PE

* test: Update PR test cases

* chore: Remove dirty lines

* test: Checking `Advance Payment Status`

* fix: formatting update

* fix: Use `flt` where doing subtraction

* test: PR test case with Payment Term for same currency

* fix: remove redundant `flt`

* test: Add test cases for PR

---------

Co-authored-by: Sagar Vora <sagar@resilient.tech>
2024-09-27 20:29:22 +05:30
mergify[bot]
74c880c232 fix: serial and batch no selector (backport #43387) (#43390)
fix: serial and batch no selector (#43387)

(cherry picked from commit e4e96d2a44)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-26 12:06:27 +05:30
Frappe PR Bot
8d188dccd7 chore(release): Bumped to Version 15.36.2
## [15.36.2](https://github.com/frappe/erpnext/compare/v15.36.1...v15.36.2) (2024-09-25)

### Bug Fixes

* add currency in financial statement ([927f800](927f80035d))
* added date condition ([0e18845](0e1884539e))
* AR / AP report to ignore 0.0 outstanding ([979d801](979d801de5))
* **Bank Account:** dashboard connections (backport [#43365](https://github.com/frappe/erpnext/issues/43365)) ([#43367](https://github.com/frappe/erpnext/issues/43367)) ([cfea2de](cfea2de131))
* change dynamic link doctype fieldtype to data ([05c92cc](05c92cce71))
* closing amount reset to expected amount on save (backport [#43358](https://github.com/frappe/erpnext/issues/43358)) ([#43368](https://github.com/frappe/erpnext/issues/43368)) ([0722aa5](0722aa5a3f))
* create_address is failing ([557ef5d](557ef5d214))
* handle missing liability account scenario in `set_liability_account` ([4045928](40459288f6))
* incorrect outstanding on non-pos invoice with write_off_account ([f89a3db](f89a3dbb65))
* incorrect stock balance for inventory dimension (backport [#43284](https://github.com/frappe/erpnext/issues/43284)) ([#43290](https://github.com/frappe/erpnext/issues/43290)) ([f6725e2](f6725e2eed))
* item_query in pos_invoice ([99e004b](99e004b619))
* make to tax category on tax rule to filter with percent ([63d4fdd](63d4fddb49))
* **minor:** include condition to check docstatus ([1f42302](1f42302997))
* not able to cancel Quality Inspection (backport [#43374](https://github.com/frappe/erpnext/issues/43374)) ([#43375](https://github.com/frappe/erpnext/issues/43375)) ([40fbb1d](40fbb1d6ff))
* partial return on POS invoice ([998fef7](998fef779b))
* partial return on POS invoice ([b99ca7d](b99ca7d9e9))
* Payment Ledger Report currency fieldtype fix ([ad2d6a1](ad2d6a1625))
* **Payment Reconciliation:** German translations ([e06a01f](e06a01fae5))
* set group_by condition if empty and voucher_no is set ([ec27077](ec27077d9c))
* shipping rule must match the company ([085a4c6](085a4c61ac))
* show chart tool tip in report currency ([e5ae828](e5ae828580))
* stock dashboard (backport [#43347](https://github.com/frappe/erpnext/issues/43347)) ([#43349](https://github.com/frappe/erpnext/issues/43349)) ([176feb2](176feb20ad))
* transaction exchange rate on GL's for Multi currency Journals ([a7ccc94](a7ccc9420b))
* translate in js ([84e26e2](84e26e21ab))
* Translation for button SO to PO ([73d98ad](73d98addbc))
* ui clean-up (backport [#43305](https://github.com/frappe/erpnext/issues/43305)) ([#43312](https://github.com/frappe/erpnext/issues/43312)) ([7e6d6f0](7e6d6f08a2))
* update clearance date in invoice payment table ([10ecdb9](10ecdb99fe))
2024-09-25 04:40:17 +00:00
mergify[bot]
47f06dc180 fix: Cannot read properties of undefined (reading 'price_list_rate') (backport #43376) (#43377)
fix: Cannot read properties of undefined (reading 'price_list_rate') (#43376)

(cherry picked from commit a63dca0984)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-25 10:09:17 +05:30
ruthra kumar
9de0d4329c Merge pull request #43361 from frappe/version-15-hotfix
chore: release v15
2024-09-25 10:09:04 +05:30
mergify[bot]
40fbb1d6ff fix: not able to cancel Quality Inspection (backport #43374) (#43375)
fix: not able to cancel Quality Inspection (#43374)

(cherry picked from commit 8c32ebee68)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-25 00:02:24 +05:30
mergify[bot]
0722aa5a3f fix: closing amount reset to expected amount on save (backport #43358) (#43368)
fix: closing amount reset to expected amount on save (#43358)

(cherry picked from commit 9974b7c4ae)

Co-authored-by: jabir-elat <44110258+jabir-elat@users.noreply.github.com>
2024-09-24 20:49:42 +05:30
mergify[bot]
cfea2de131 fix(Bank Account): dashboard connections (backport #43365) (#43367)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
fix(Bank Account): dashboard connections (#43365)
2024-09-24 16:20:50 +02:00
Khushi Rawat
fe206b0d77 Merge pull request #43370 from khushi8112/manual-backport-for-asset-depreciation-and-balances-report-fix
fix: Manual backport for asset depreciation and balances report fix
2024-09-24 18:49:01 +05:30
Khushi Rawat
4e621b09ba style: added comment 2024-09-24 18:18:04 +05:30
Khushi Rawat
1f42302997 fix(minor): include condition to check docstatus 2024-09-24 18:17:25 +05:30
Khushi Rawat
0e1884539e fix: added date condition 2024-09-24 18:16:37 +05:30
ruthra kumar
b17a811abf Merge pull request #43364 from frappe/mergify/bp/version-15-hotfix/pr-43356
fix: AR / AP report to ignore 0.0 outstanding (backport #43356)
2024-09-24 16:58:35 +05:30
ruthra kumar
979d801de5 fix: AR / AP report to ignore 0.0 outstanding
(cherry picked from commit 6e2cf79e2c)
2024-09-24 10:14:53 +00:00
ruthra kumar
49d5b7c4d3 Merge pull request #43360 from frappe/mergify/bp/version-15-hotfix/pr-43235
fix: set group_by condition to "Group by Voucher (Consolidated)" if `None` and voucher_no is set (backport #43235)
2024-09-24 15:41:15 +05:30
mergify[bot]
176feb20ad fix: stock dashboard (backport #43347) (#43349)
fix: stock dashboard (#43347)

(cherry picked from commit 9e8be8db51)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-24 15:25:42 +05:30
Vishakh Desai
ec27077d9c fix: set group_by condition if empty and voucher_no is set
(cherry picked from commit a6b0cb6cac)
2024-09-24 09:24:28 +00:00
Ninad1306
0a70b3ffcc fix: frappe dependency update 2024-09-24 11:24:31 +05:30
ruthra kumar
7db135dab5 Merge pull request #43353 from frappe/mergify/bp/version-15-hotfix/pr-43310
fix: update clearance date in invoice payment table (backport #43310)
2024-09-24 11:20:43 +05:30
ruthra kumar
4278b08147 Merge pull request #43065 from Ninad1306/merge_taxes_fix
fix: Reset Value Conditionally Based on Merge Taxes
2024-09-24 11:10:09 +05:30
Smit Vora
f36a68b42b Merge pull request #42925 from Ninad1306/mapping_docs_fix
fix: Replace `add_if_empty` with `reset_value` flag
2024-09-24 11:10:09 +05:30
Kavin
8bc76bae9c refactor: update clearance date in payment entry
(cherry picked from commit c218f7527f)
2024-09-24 05:29:49 +00:00
Kavin
9d2cbccff2 test: add test case for updating clearance date on pos invoice
(cherry picked from commit ce8600520f)
2024-09-24 05:29:49 +00:00
Kavin
10ecdb99fe fix: update clearance date in invoice payment table
(cherry picked from commit 487c2a29a6)
2024-09-24 05:29:49 +00:00
ruthra kumar
2aa1380c81 Merge pull request #43351 from frappe/mergify/bp/version-15-hotfix/pr-43257
fix: item_query in pos_invoice (backport #43257)
2024-09-24 10:27:33 +05:30
ljain112
99e004b619 fix: item_query in pos_invoice
(cherry picked from commit 7f82a06e65)
2024-09-24 02:56:24 +00:00
ruthra kumar
b415e858e7 Merge pull request #43346 from frappe/mergify/bp/version-15-hotfix/pr-43283
fix: shipping rule must match the company (backport #43283)
2024-09-24 08:25:18 +05:30
Nihantra C. Patel
4cec68c7ad Merge pull request #43343 from frappe/mergify/bp/version-15-hotfix/pr-43253
fix: partial return on POS invoice (backport #43253)
2024-09-23 23:36:04 +05:30
barredterra
085a4c61ac fix: shipping rule must match the company
(cherry picked from commit df8f4086f6)
2024-09-23 14:41:18 +00:00
ruthra kumar
5f08ef5cd1 Merge pull request #43344 from frappe/mergify/bp/version-15-hotfix/pr-43299
fix(Payment Reconciliation): German translations (backport #43299)
2024-09-23 20:07:53 +05:30
barredterra
e06a01fae5 fix(Payment Reconciliation): German translations
(cherry picked from commit 32d4f96e02)
2024-09-23 14:35:49 +00:00
Nihantra C. Patel
998fef779b fix: partial return on POS invoice
(cherry picked from commit 18bdd06652)
2024-09-23 14:26:21 +00:00
Nihantra C. Patel
b99ca7d9e9 fix: partial return on POS invoice
(cherry picked from commit 76289fa8dc)
2024-09-23 14:26:21 +00:00
ruthra kumar
0fd2964032 Merge pull request #43336 from frappe/mergify/bp/version-15-hotfix/pr-43316
fix: incorrect outstanding on non-pos invoice with write_off_account (backport #43316)
2024-09-23 18:22:30 +05:30
ruthra kumar
15baa3f305 Merge pull request #43338 from frappe/mergify/bp/version-15-hotfix/pr-43308
fix: show chart tool tip in report currency (backport #43308)
2024-09-23 18:22:06 +05:30
ruthra kumar
5920525369 Merge pull request #43340 from frappe/mergify/bp/version-15-hotfix/pr-43307
fix: change dynamic link doctype fieldtype to data (backport #43307)
2024-09-23 18:21:48 +05:30
venkat102
05c92cce71 fix: change dynamic link doctype fieldtype to data
(cherry picked from commit 1e46f7344a)
2024-09-23 12:23:52 +00:00
ruthra kumar
a0f01dac1a Merge pull request #43334 from frappe/mergify/bp/version-15-hotfix/pr-43331
fix: transaction exchange rate on GL's for Multi currency Journals (backport #43331)
2024-09-23 17:52:51 +05:30
ruthra kumar
e8c174c12b Merge pull request #43333 from frappe/mergify/bp/version-15-hotfix/pr-43321
fix: handle missing liability account scenario in `set_liability_account` (backport #43321)
2024-09-23 17:50:06 +05:30
venkat102
927f80035d fix: add currency in financial statement
(cherry picked from commit 91a27bda84)
2024-09-23 12:11:54 +00:00
venkat102
e5ae828580 fix: show chart tool tip in report currency
(cherry picked from commit 827b3f4542)
2024-09-23 12:11:53 +00:00
ruthra kumar
f89a3dbb65 fix: incorrect outstanding on non-pos invoice with write_off_account
(cherry picked from commit d5e2906e59)
2024-09-23 12:09:50 +00:00
ruthra kumar
2d9142832d test: transaction exchange rate on multi-currency journals
(cherry picked from commit c524825d2d)
2024-09-23 12:03:59 +00:00
ruthra kumar
a7ccc9420b fix: transaction exchange rate on GL's for Multi currency Journals
(cherry picked from commit 8cd9ad5361)
2024-09-23 12:03:59 +00:00
ljain112
40459288f6 fix: handle missing liability account scenario in set_liability_account
(cherry picked from commit ee7ab4b065)
2024-09-23 12:00:39 +00:00
ruthra kumar
250a1c9341 Merge pull request #43332 from frappe/mergify/bp/version-15-hotfix/pr-43328
fix: allow tax rule filter on tax category name with % (backport #43328)
2024-09-23 17:26:06 +05:30
venkat102
63d4fddb49 fix: make to tax category on tax rule to filter with percent
(cherry picked from commit 3aaa13cb29)
2024-09-23 11:47:22 +00:00
mergify[bot]
7e6d6f08a2 fix: ui clean-up (backport #43305) (#43312)
* fix: ui clean-up (#43305)

fix: ui cleanup
(cherry picked from commit b127a0c8b7)

# Conflicts:
#	erpnext/manufacturing/doctype/bom_creator/bom_creator.json
#	erpnext/manufacturing/doctype/plant_floor/plant_floor.json
#	erpnext/public/js/templates/visual_plant_floor_template.html

* chore: fix conflicts

* chore: fix conflicts

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-22 11:18:42 +05:30
Smit Vora
d1c72dc27b Merge pull request #43314 from frappe/mergify/bp/version-15-hotfix/pr-42842
refactor: use common functionality to validate account number (backport #42842)
2024-09-21 07:06:49 +05:30
HENRY Florian
86ae644574 refactor: use common functionality to validate account number (#42842)
feat: Allow unique Account number by root type (not unique for accros all Accounts)
(cherry picked from commit 40d97f4fe9)
2024-09-21 01:20:03 +00:00
Nihantra Patel
5a2a404a50 fix: creation of contact, customer, opportunity, quotation and prospect from lead --prettier
(cherry picked from commit 5844897c34)

# Conflicts:
#	erpnext/crm/doctype/lead/lead.js
2024-09-19 05:58:01 +00:00
Nihantra Patel
ef10c4ea4f fix: creation of contact, customer, opportunity, quotation and prospect from lead
(cherry picked from commit 8304d19e8b)

# Conflicts:
#	erpnext/crm/doctype/lead/lead.js
2024-09-19 05:58:01 +00:00
mergify[bot]
f6725e2eed fix: incorrect stock balance for inventory dimension (backport #43284) (#43290)
fix: incorrect stock balance for inventory dimension (#43284)

(cherry picked from commit 3e7a7a54bf)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-19 09:35:54 +05:30
ruthra kumar
e90532e406 Merge pull request #43293 from frappe/mergify/bp/version-15-hotfix/pr-43274
fix: translate in js (backport #43274)
2024-09-19 09:17:39 +05:30
Doğancan
84e26e21ab fix: translate in js
(cherry picked from commit 25faec5662)
2024-09-19 03:27:13 +00:00
Frappe PR Bot
34ca0c3bb6 chore(release): Bumped to Version 15.36.1
## [15.36.1](https://github.com/frappe/erpnext/compare/v15.36.0...v15.36.1) (2024-09-19)

### Bug Fixes

* create_address is failing ([17ad402](17ad402695))
2024-09-19 01:43:11 +00:00
ruthra kumar
42e4b8a68c Merge pull request #43287 from frappe/mergify/bp/version-15/pr-43279
fix: create_address is failing while creating customer (backport #43279)
2024-09-19 07:11:56 +05:30
ruthra kumar
34d159b3a2 Merge pull request #43213 from sameer55chauhan/patch-4
fix: Payment Ledger Report currency fieldtype fix
2024-09-19 07:05:43 +05:30
Shariq Ansari
17ad402695 fix: create_address is failing
(cherry picked from commit acc1d52ac8)
2024-09-19 01:21:13 +00:00
Shariq Ansari
953b5790ed Merge pull request #43281 from frappe/mergify/bp/version-15-hotfix/pr-43279
fix: create_address is failing while creating customer (backport #43279)
2024-09-18 22:47:56 +05:30
Shariq Ansari
557ef5d214 fix: create_address is failing
(cherry picked from commit acc1d52ac8)
2024-09-18 17:01:49 +00:00
Nihantra C. Patel
680354ac0d Merge pull request #43278 from frappe/mergify/bp/version-15-hotfix/pr-43276
fix: Translation for button SO to PO (backport #43276)
2024-09-18 21:51:03 +05:30
Nihantra C. Patel
73d98addbc fix: Translation for button SO to PO
(cherry picked from commit a5275e9f28)
2024-09-18 16:14:54 +00:00
Frappe PR Bot
479e8573c2 chore(release): Bumped to Version 15.36.0
# [15.36.0](https://github.com/frappe/erpnext/compare/v15.35.2...v15.36.0) (2024-09-18)

### Bug Fixes

* A project without tasks should be able to complete ([dea735d](dea735de4d))
* add currency in options for rate field in pricing rule ([782c9dd](782c9dda1a))
* batch based item price not working (backport [#43172](https://github.com/frappe/erpnext/issues/43172)) ([#43206](https://github.com/frappe/erpnext/issues/43206)) ([61a42ea](61a42ea5d7))
* cancel cost center allocation and journal entry after test ([3d29007](3d29007aeb))
* consistent behaviour on refresh ([01f3068](01f30682ee))
* create and link address while creating prospect & customer ([d6a3d0d](d6a3d0d468))
* create fiscal year without overlapping existing Fiscal Years ([78768f8](78768f883c))
* currency changing while making PO from Supplier Quotation (backport [#43187](https://github.com/frappe/erpnext/issues/43187)) ([#43205](https://github.com/frappe/erpnext/issues/43205)) ([ef6b172](ef6b172616))
* delete exchange gain loss journal entry while deleting payment entry ([5789de2](5789de25b9))
* do not auto apply tds in purchase order ([741c18b](741c18b144))
* do not check appy_tds in Purchase Order Automatically ([5edebb2](5edebb28a5))
* do not validate purchase document for composite asset ([c505156](c5051561e4))
* fetch cost center allocation percentage only from the applicable allocation ([0fe901a](0fe901a137))
* hide and reset discount control on new POS order ([42494db](42494db3c7))
* **holiday-list:** use same date format for same holiday error message (backport [#42606](https://github.com/frappe/erpnext/issues/42606)) ([#43222](https://github.com/frappe/erpnext/issues/43222)) ([f101a1c](f101a1ce3b))
* ignore repost logic on Payment Reconciliation ([d91013a](d91013a467))
* invalid gp calculation ([291f0a5](291f0a580b))
* item list view in website (backport [#43165](https://github.com/frappe/erpnext/issues/43165)) ([#43207](https://github.com/frappe/erpnext/issues/43207)) ([c1a6c56](c1a6c56217))
* map rows on journal entry by validating account, party, debit and credit value ([86e1818](86e1818420))
* prevent KeyError by checking `report_filter` existence ([984acb6](984acb661d))
* revert 091c5496b2 ([2ad6d63](2ad6d637ee))
* set party_type null when payment_type is changed to Internal Transfer ([45ff8fa](45ff8fa296))
* set tax_withholding_category from Purchase Order while creating pi form po ([7027be8](7027be8fbc))
* tds workflow in purchase order ([11359bd](11359bd235))
* typo with po_date when creating remarks ([1657a83](1657a83151))
* updated filtering in depreciation and balances report ([78c6839](78c68397d9))
* **ux:** set amount based on account currency while adding new row ([f7cedac](f7cedac526))
* **ux:** set amount on foreign currency when foreign currency account is selected on last row of journal ([d8d4cd2](d8d4cd23a5))

### Features

* API for crm integration ([f060534](f060534625))
2024-09-18 07:32:30 +00:00
ruthra kumar
6a0b15211a Merge pull request #43254 from frappe/version-15-hotfix
chore: release v15
2024-09-18 13:01:08 +05:30
ruthra kumar
7aeadcbf98 Merge pull request #43268 from frappe/mergify/bp/version-15-hotfix/pr-43239
fix: add currency in options for rate field in pricing rule (backport #43239)
2024-09-18 12:28:59 +05:30
ruthra kumar
82982e25c6 chore: resolve conflict 2024-09-18 12:10:42 +05:30
krishna
782c9dda1a fix: add currency in options for rate field in pricing rule
(cherry picked from commit 636c0131fa)

# Conflicts:
#	erpnext/accounts/doctype/pricing_rule/pricing_rule.json
2024-09-18 06:29:42 +00:00
ruthra kumar
dfe47261ae Merge pull request #43266 from frappe/mergify/bp/version-15-hotfix/pr-43216
fix: get cost center allocation percentage only from the applicable allocation (backport #43216)
2024-09-18 11:40:02 +05:30
venkat102
3d29007aeb fix: cancel cost center allocation and journal entry after test
(cherry picked from commit 3c65b98b49)
2024-09-18 05:49:34 +00:00
venkat102
52a161f076 test: add unit test for validating multiple cost center allocation with different child cost center
(cherry picked from commit 4d5d6150e1)
2024-09-18 05:49:34 +00:00
venkat102
0fe901a137 fix: fetch cost center allocation percentage only from the applicable allocation
(cherry picked from commit 36e5945c66)
2024-09-18 05:49:34 +00:00
Khushi Rawat
8c28cb6b25 Merge pull request #43264 from frappe/mergify/bp/version-15-hotfix/pr-43210
fix: updated filtering in depreciation and balances report (backport #43210)
2024-09-18 02:13:54 +05:30
Khushi Rawat
4ba37e49d8 chore: resolved failing check
(cherry picked from commit af52f0e71f)
2024-09-17 20:27:32 +00:00
Khushi Rawat
1e89c007ed chore: resolved linter check with #nosemgrep
(cherry picked from commit 8c8e25214c)
2024-09-17 20:27:32 +00:00
Khushi Rawat
78c68397d9 fix: updated filtering in depreciation and balances report
(cherry picked from commit 3a34eecdcf)
2024-09-17 20:27:32 +00:00
ruthra kumar
f61cec27ae Merge pull request #43259 from frappe/mergify/bp/version-15-hotfix/pr-43226
fix: map rows on journal entry by validating account, party, debit and credit value (backport #43226)
2024-09-17 20:22:59 +05:30
Navin-S-R
78768f883c fix: create fiscal year without overlapping existing Fiscal Years
(cherry picked from commit 720a330617)
2024-09-17 14:35:39 +00:00
Navin-S-R
edcdfdd194 refactor: update formatting changes
(cherry picked from commit 768bb0312a)
2024-09-17 14:35:39 +00:00
ruthra kumar
861edb438b refactor(test): make use existing test data and dynamic fy creation
(cherry picked from commit f45638015f)
2024-09-17 14:35:39 +00:00
ruthra kumar
d91013a467 fix: ignore repost logic on Payment Reconciliation
(cherry picked from commit 75babd4c18)
2024-09-17 14:35:39 +00:00
Navin-S-R
310b131469 test: reconcile payment jv from closed fiscal year
(cherry picked from commit f47ea46806)
2024-09-17 14:35:39 +00:00
Navin-S-R
86e1818420 fix: map rows on journal entry by validating account, party, debit and credit value
(cherry picked from commit b634aa9cfb)
2024-09-17 14:35:38 +00:00
ruthra kumar
5fe347c909 Merge pull request #43249 from frappe/mergify/bp/version-15-hotfix/pr-43188
fix: invalid gp calculation (backport #43188)
2024-09-17 14:34:58 +05:30
Khushi Rawat
44dde1c58d Merge pull request #43243 from frappe/mergify/bp/version-15-hotfix/pr-43233
fix: do not validate purchase document for composite asset (backport #43233)
2024-09-17 12:31:24 +05:30
Dany Robert
291f0a580b fix: invalid gp calculation
(cherry picked from commit c79851239c)
2024-09-17 06:33:19 +00:00
ruthra kumar
9c4eaa230c Merge pull request #43246 from frappe/mergify/bp/version-15-hotfix/pr-42969
fix: A project without tasks should be able to complete (backport #42969)
2024-09-17 10:43:18 +05:30
Frappe PR Bot
28f1f9355d chore(release): Bumped to Version 15.35.2
## [15.35.2](https://github.com/frappe/erpnext/compare/v15.35.1...v15.35.2) (2024-09-17)

### Bug Fixes

* currency changing while making PO from Supplier Quotation (backport [#43187](https://github.com/frappe/erpnext/issues/43187)) ([#43205](https://github.com/frappe/erpnext/issues/43205)) ([2f56ba7](2f56ba7f42))
2024-09-17 05:00:07 +00:00
ruthra kumar
41db9d3886 Merge pull request #43209 from frappe/mergify/bp/version-15/pr-43205
fix: currency changing while making PO from Supplier Quotation (backport #43187) (backport #43205)
2024-09-17 10:28:43 +05:30
ruthra kumar
53c4c153ca Merge pull request #43245 from frappe/mergify/bp/version-15-hotfix/pr-43225
fix(ux): set amount based on account currency while adding new row (backport #43225)
2024-09-17 10:26:43 +05:30
ruthra kumar
bee27f314f Merge pull request #43230 from frappe/mergify/bp/version-15-hotfix/pr-43212
fix: prevent KeyError by checking `report_filter` existence (backport #43212)
2024-09-17 10:23:58 +05:30
ruthra kumar
c9b6b0d868 refactor(test): fix linter
(cherry picked from commit 4eeae8011e)
2024-09-17 04:49:45 +00:00
lukas.brandhoff
dea735de4d fix: A project without tasks should be able to complete
(cherry picked from commit 268962c25f)
2024-09-17 04:49:44 +00:00
Navin-S-R
f7cedac526 fix(ux): set amount based on account currency while adding new row
(cherry picked from commit 0ff04f774d)
2024-09-17 04:48:42 +00:00
Khushi Rawat
c5051561e4 fix: do not validate purchase document for composite asset
(cherry picked from commit 5fd058dde9)
2024-09-16 18:48:26 +00:00
Shariq Ansari
48158fbde0 Merge pull request #43242 from frappe/mergify/bp/version-15-hotfix/pr-43238
fix: create and link address while creating prospect & customer (backport #43238)
2024-09-16 22:47:00 +05:30
Shariq Ansari
d6a3d0d468 fix: create and link address while creating prospect & customer
(cherry picked from commit 035c15794c)
2024-09-16 16:46:01 +00:00
Smit Vora
30e9f08f37 Merge pull request #43241 from frappe/mergify/bp/version-15-hotfix/pr-43176
fix: hide and reset discount control on new POS order (backport #43176)
2024-09-16 20:01:26 +05:30
ljain112
42494db3c7 fix: hide and reset discount control on new POS order
(cherry picked from commit 5b0053f8dd)
2024-09-16 14:25:20 +00:00
Smit Vora
a6a2b2daae Merge pull request #43237 from frappe/mergify/bp/version-15-hotfix/pr-42849
fix: TDS workflow consistency in Purchase Order (backport #42849)
2024-09-16 19:41:33 +05:30
ljain112
741c18b144 fix: do not auto apply tds in purchase order
(cherry picked from commit 0b942a0614)
2024-09-16 13:16:15 +00:00
ljain112
7027be8fbc fix: set tax_withholding_category from Purchase Order while creating pi form po
(cherry picked from commit b9048ca6fa)
2024-09-16 13:16:15 +00:00
ljain112
01f30682ee fix: consistent behaviour on refresh
(cherry picked from commit b216d71278)
2024-09-16 13:16:15 +00:00
ljain112
5edebb28a5 fix: do not check appy_tds in Purchase Order Automatically
(cherry picked from commit be6c174b43)
2024-09-16 13:16:14 +00:00
ljain112
11359bd235 fix: tds workflow in purchase order
(cherry picked from commit a7888b26a7)
2024-09-16 13:16:13 +00:00
ljain112
2ad6d637ee fix: revert 091c5496b2
(cherry picked from commit eeb6e75dcf)
2024-09-16 13:16:12 +00:00
ruthra kumar
564ff034b7 Merge pull request #43232 from frappe/mergify/bp/version-15-hotfix/pr-43224
fix(ux): set amount on foreign currency when foreign currency account… (backport #43224)
2024-09-16 13:49:32 +05:30
venkat102
d8d4cd23a5 fix(ux): set amount on foreign currency when foreign currency account is selected on last row of journal
(cherry picked from commit 2b66842d34)
2024-09-16 06:16:09 +00:00
ljain112
984acb661d fix: prevent KeyError by checking report_filter existence
(cherry picked from commit c1d2cc2c14)
2024-09-16 03:48:37 +00:00
Shariq Ansari
00f144ed68 Merge pull request #43223 from frappe/mergify/bp/version-15-hotfix/pr-43198
feat: API for crm integration (backport #43198)
2024-09-14 14:46:14 +05:30
Nabin Hait
f060534625 feat: API for crm integration
(cherry picked from commit b7bf9f80f2)
2024-09-14 08:59:51 +00:00
mergify[bot]
f101a1ce3b fix(holiday-list): use same date format for same holiday error message (backport #42606) (#43222)
fix(holiday-list): use same date format for same holiday error message (#42606)

* fix(holiday-list): use same date format for same holiday error message

* chore: fix formatting

---------

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
(cherry picked from commit a435441536)

Co-authored-by: Ananyobrata Pal <74728797+ananyo141@users.noreply.github.com>
2024-09-14 13:36:26 +05:30
sameer Chauhan
ad2d6a1625 fix: Payment Ledger Report currency fieldtype fix 2024-09-13 17:32:44 +05:30
mergify[bot]
2f56ba7f42 fix: currency changing while making PO from Supplier Quotation (backport #43187) (#43205)
fix: currency changing while making PO from Supplier Quotation (#43187)

(cherry picked from commit 2b96e37c34)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
(cherry picked from commit ef6b172616)
2024-09-13 08:01:44 +00:00
mergify[bot]
ef6b172616 fix: currency changing while making PO from Supplier Quotation (backport #43187) (#43205)
fix: currency changing while making PO from Supplier Quotation (#43187)

(cherry picked from commit 2b96e37c34)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-13 13:30:36 +05:30
mergify[bot]
61a42ea5d7 fix: batch based item price not working (backport #43172) (#43206)
* fix: batch based item price not working (#43172)

(cherry picked from commit d9e4ed13cb)

# Conflicts:
#	erpnext/stock/get_item_details.py

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-13 13:30:12 +05:30
mergify[bot]
c1a6c56217 fix: item list view in website (backport #43165) (#43207)
fix: item list view in website (#43165)

(cherry picked from commit ce34bb9793)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-13 13:29:58 +05:30
ruthra kumar
b7e95bfd22 Merge pull request #43202 from frappe/mergify/bp/version-15-hotfix/pr-43191
fix: delete exchange gain loss journal entry while deleting payment entry (backport #43191)
2024-09-13 11:22:46 +05:30
ruthra kumar
7989bc23e1 Merge pull request #43204 from frappe/mergify/bp/version-15-hotfix/pr-43192
refactor(test): use test fixture on pricing rule test suite (backport #43192)
2024-09-13 11:22:13 +05:30
ruthra kumar
055e7820c8 refactor(test): use test fixture on pricing rule test suite
(cherry picked from commit 0ea1d6d960)
2024-09-13 05:20:22 +00:00
Navin-S-R
d618c9a481 test: add unit test for deletion of gain loss jv while deleting payment entry
(cherry picked from commit 7855d3034b)
2024-09-13 05:19:05 +00:00
Navin-S-R
5789de25b9 fix: delete exchange gain loss journal entry while deleting payment entry
(cherry picked from commit 9886cf0d46)
2024-09-13 05:19:04 +00:00
Sagar Vora
4df38d357f Merge pull request #43186 from frappe/mergify/bp/version-15-hotfix/pr-43171
fix: set `party_type` null when `payment_type` is changed to `Internal Transfer` (backport #43171)
2024-09-12 12:03:28 +05:30
Vishakh Desai
45ff8fa296 fix: set party_type null when payment_type is changed to Internal Transfer
(cherry picked from commit 502cf0eb8d)
2024-09-12 06:32:46 +00:00
Frappe PR Bot
7f95e42bec chore(release): Bumped to Version 15.35.1
## [15.35.1](https://github.com/frappe/erpnext/compare/v15.35.0...v15.35.1) (2024-09-12)

### Bug Fixes

* typo with po_date when creating remarks ([31e0bb4](31e0bb477e))
2024-09-12 06:11:04 +00:00
ruthra kumar
578ddb9be4 Merge pull request #43184 from frappe/mergify/bp/version-15/pr-43182
fix: typo with po_date when creating remarks (backport #43182)
2024-09-12 11:39:39 +05:30
ruthra kumar
28607f0026 Merge pull request #43183 from frappe/mergify/bp/version-15-hotfix/pr-43182
fix: typo with po_date when creating remarks (backport #43182)
2024-09-12 11:30:53 +05:30
Smit Vora
31e0bb477e fix: typo with po_date when creating remarks
(cherry picked from commit a55502e0f1)
2024-09-12 05:47:40 +00:00
Smit Vora
1657a83151 fix: typo with po_date when creating remarks
(cherry picked from commit a55502e0f1)
2024-09-12 05:45:00 +00:00
ruthra kumar
aab91a2307 Merge pull request #43169 from ruthra-kumar/no_copy_on_purchase_invoice_status
refactor: enable no-copy on Purchase Invoice status
2024-09-11 13:25:33 +05:30
ruthra kumar
0d9741fdd7 refactor: enable no-copy on Purchase Invoice status 2024-09-11 13:03:20 +05:30
Frappe PR Bot
d9d86dae35 chore(release): Bumped to Version 15.35.0
# [15.35.0](https://github.com/frappe/erpnext/compare/v15.34.2...v15.35.0) (2024-09-11)

### Bug Fixes

* `default_advance_account` field in Process Payment Reconciliation ([75cb298](75cb29890d))
* bom cost update is not working (backport [#43155](https://github.com/frappe/erpnext/issues/43155)) ([#43157](https://github.com/frappe/erpnext/issues/43157)) ([8c8dc24](8c8dc241e5))
* cancel common party advance jv while canceling the invoice ([9bd3d7a](9bd3d7a020))
* Cannot read properties of null (reading 'doc') (backport [#43071](https://github.com/frappe/erpnext/issues/43071)) ([#43118](https://github.com/frappe/erpnext/issues/43118)) ([80b5c16](80b5c16a2e))
* check multi-currency on jv for common party accounting with foreign currency ([d17badd](d17baddb0d))
* concurrency issue while picking materials (backport [#43087](https://github.com/frappe/erpnext/issues/43087)) ([#43152](https://github.com/frappe/erpnext/issues/43152)) ([cd57e00](cd57e009dd))
* **Delivery Note:** translatability of validation errors ([ea4f736](ea4f7365ea))
* ensure `SellingController.onload` gets called for SO & DN ([2c1f72e](2c1f72e44c))
* incorrect actual cost in Procurement Tracker report (backport [#43109](https://github.com/frappe/erpnext/issues/43109)) ([#43138](https://github.com/frappe/erpnext/issues/43138)) ([5110975](5110975c6d))
* incorrect qty after transaction in SLE (backport [#43103](https://github.com/frappe/erpnext/issues/43103)) ([#43105](https://github.com/frappe/erpnext/issues/43105)) ([8447bf3](8447bf34f0))
* **minor:** reorder expected value validation ([6fde07d](6fde07da0e))
* multiple fixes related to remarks for GL Report ([#42753](https://github.com/frappe/erpnext/issues/42753)) ([f45b1db](f45b1db1a4))
* **Opening Invoice Creation Tool:** translatability of messages ([3fd9df0](3fd9df0d2e))
* pass company from asset to asset capitalization ([9e72a84](9e72a844f7))
* permission on guest PR creation ([a23e8b1](a23e8b13be))
* return type of `get_party_details` (backport [#43131](https://github.com/frappe/erpnext/issues/43131)) ([#43134](https://github.com/frappe/erpnext/issues/43134)) ([d2923ba](d2923bae85))
* set today in 'On This Date' in Available Batch Report ([03e3374](03e3374a8b))
* uncomment internal parties ([33174b1](33174b1ba2))
* unhide action button after form redirect ([208bd2b](208bd2b8ff))
* unreconcile allocation child table redirect url voucher no issue ([2dddd79](2dddd7906b))
* validate the item code when updating the other item's price rule ([8f4dc80](8f4dc8048d))

### Features

* added revaluation surplus and impairment acc in standard charts… ([#43022](https://github.com/frappe/erpnext/issues/43022)) ([ea86bc2](ea86bc2235))
* utility report to identify invalid ledger entries ([5929d50](5929d50c72))

### Performance Improvements

* timeout error (backport [#43154](https://github.com/frappe/erpnext/issues/43154)) ([#43158](https://github.com/frappe/erpnext/issues/43158)) ([c9f49ca](c9f49caecc))
2024-09-11 05:11:52 +00:00
ruthra kumar
d61f38b8ed Merge pull request #43151 from frappe/version-15-hotfix
chore: release v15
2024-09-11 10:40:35 +05:30
mergify[bot]
8c8dc241e5 fix: bom cost update is not working (backport #43155) (#43157)
fix: bom cost update is not working (#43155)

(cherry picked from commit 05f9015c0b)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-10 23:07:07 +05:30
mergify[bot]
c9f49caecc perf: timeout error (backport #43154) (#43158)
perf: timeout error (#43154)

(cherry picked from commit 1bf60248d9)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-10 23:06:38 +05:30
mergify[bot]
cd57e009dd fix: concurrency issue while picking materials (backport #43087) (#43152)
fix: concurrency issue while picking materials (#43087)

(cherry picked from commit 5c7dff0e84)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-10 17:01:53 +05:30
ruthra kumar
f11e298984 Merge pull request #43149 from frappe/mergify/bp/version-15-hotfix/pr-43146
fix: permission error on Payment Request creation by Guest (backport #43146)
2024-09-10 16:00:00 +05:30
Khushi Rawat
2eec0c057a Merge pull request #43140 from frappe/mergify/bp/version-15-hotfix/pr-43114
fix: primary action button not showing (backport #43114)
2024-09-10 15:45:09 +05:30
ruthra kumar
50b4257a6f Merge pull request #43148 from frappe/mergify/bp/version-15-hotfix/pr-43144
feat: utility report for identifying invalid ledger entries (backport #43144)
2024-09-10 14:55:03 +05:30
ruthra kumar
a23e8b13be fix: permission on guest PR creation
(cherry picked from commit ea02e5f15a)
2024-09-10 09:18:23 +00:00
ruthra kumar
9f09bf14cb refactor: allow all accounts
(cherry picked from commit 43198c946b)
2024-09-10 09:07:06 +00:00
ruthra kumar
5413372aeb refactor: fetch as dictionary
(cherry picked from commit 2126b10a92)
2024-09-10 09:07:06 +00:00
ruthra kumar
710d30074d refactor: barebones methods with basic logic
(cherry picked from commit b05b378ef0)
2024-09-10 09:07:06 +00:00
ruthra kumar
14e30d12b4 refactor: standard filters
(cherry picked from commit dccbc1f432)
2024-09-10 09:07:06 +00:00
ruthra kumar
5929d50c72 feat: utility report to identify invalid ledger entries
(cherry picked from commit 832c4aaf82)
2024-09-10 09:07:06 +00:00
mergify[bot]
d2923bae85 fix: return type of get_party_details (backport #43131) (#43134)
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix: return type of `get_party_details` (#43131)
2024-09-09 19:26:38 +02:00
Khushi Rawat
9e72a844f7 fix: pass company from asset to asset capitalization
(cherry picked from commit f3445d645d)
2024-09-09 17:00:01 +00:00
Khushi Rawat
208bd2b8ff fix: unhide action button after form redirect
(cherry picked from commit 5ce5b1b6a2)
2024-09-09 17:00:01 +00:00
mergify[bot]
5110975c6d fix: incorrect actual cost in Procurement Tracker report (backport #43109) (#43138)
fix: incorrect actual cost in Procurement Tracker report (#43109)

(cherry picked from commit 80f101f92e)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-09 20:34:56 +05:30
ruthra kumar
82764af09e Merge pull request #43132 from frappe/mergify/bp/version-15-hotfix/pr-43056
fix(Opening Invoice Creation Tool): translatability of messages (backport #43056)
2024-09-09 16:54:08 +05:30
barredterra
3fd9df0d2e fix(Opening Invoice Creation Tool): translatability of messages
(cherry picked from commit f3c5803198)
2024-09-09 09:48:34 +00:00
ruthra kumar
cf81202d94 Merge pull request #43129 from frappe/mergify/bp/version-15-hotfix/pr-42801
fix(Delivery Note): translatability of validation errors (backport #42801)
2024-09-09 15:15:45 +05:30
barredterra
0c0f103b83 refactor: extract common validation method
(cherry picked from commit 08646b7ab7)
2024-09-09 09:14:23 +00:00
barredterra
ea4f7365ea fix(Delivery Note): translatability of validation errors
(cherry picked from commit 34df6e39dc)
2024-09-09 09:14:23 +00:00
ruthra kumar
346c06977c Merge pull request #43127 from frappe/mergify/bp/version-15-hotfix/pr-43051
fix: unreconcile allocation child table redirect url voucher no issue (backport #43051)
2024-09-09 14:38:17 +05:30
Prashant Kamble
2dddd7906b fix: unreconcile allocation child table redirect url voucher no issue
(cherry picked from commit 5d6f6a2fb9)
2024-09-09 09:00:37 +00:00
ruthra kumar
026c2d7590 Merge pull request #43122 from frappe/mergify/bp/version-15-hotfix/pr-43022
feat: added revaluation surplus and impairment acc in standard charts… (backport #43022)
2024-09-09 14:19:34 +05:30
ruthra kumar
8e5252d6f8 Merge pull request #43125 from frappe/mergify/bp/version-15-hotfix/pr-43064
fix: validate the item code when updating the other item's price rule (backport #43064)
2024-09-09 14:16:49 +05:30
ruthra kumar
ffc119a8a4 Merge pull request #43123 from frappe/mergify/bp/version-15-hotfix/pr-43121
fix: set today in 'On This Date' in Available Batch Report (backport #43121)
2024-09-09 14:14:19 +05:30
Bhavan23
8f4dc8048d fix: validate the item code when updating the other item's price rule
(cherry picked from commit 45de18069c)
2024-09-09 08:43:58 +00:00
Nihantra C. Patel
03e3374a8b fix: set today in 'On This Date' in Available Batch Report
(cherry picked from commit 9fd55e4c83)
2024-09-09 08:26:38 +00:00
rahulgupta8848
ea86bc2235 feat: added revaluation surplus and impairment acc in standard charts… (#43022)
feat: added revaluation surplus and impairment acc in standard charts of accounts

Co-authored-by: “rahulgupta8848” <“rahul.gupta@8848digital.com”>
(cherry picked from commit 8202f505cc)
2024-09-09 06:43:00 +00:00
ruthra kumar
60b81a2a59 Merge pull request #43120 from frappe/mergify/bp/version-15-hotfix/pr-43095
fix: check multi-currency on jv for common party accounting with foreign currency (backport #43095)
2024-09-09 11:17:43 +05:30
ruthra kumar
354c34e4d8 chore: resolve conflict 2024-09-09 10:51:45 +05:30
ruthra kumar
a9bd11f59a refactor(test): use change_settings decorator
(cherry picked from commit ee94fb37c8)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
2024-09-09 05:06:38 +00:00
venkat102
33174b1ba2 fix: uncomment internal parties
(cherry picked from commit 454e18ad5f)
2024-09-09 05:06:38 +00:00
venkat102
47b216373d test: add unit test for common party with foreign currency
(cherry picked from commit 740a04a704)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
2024-09-09 05:06:38 +00:00
venkat102
d17baddb0d fix: check multi-currency on jv for common party accounting with foreign currency
(cherry picked from commit 00938bfd4d)
2024-09-09 05:06:38 +00:00
mergify[bot]
80b5c16a2e fix: Cannot read properties of null (reading 'doc') (backport #43071) (#43118)
fix: Cannot read properties of null (reading 'doc')

(cherry picked from commit 62c3389bd6)

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
2024-09-09 09:56:29 +05:30
Smit Vora
a9b142eccd Merge pull request #43117 from frappe/mergify/bp/version-15-hotfix/pr-42753
fix: multiple fixes related to remarks for GL Report (backport #42753)
2024-09-09 08:00:45 +05:30
Smit Vora
a66d1c30ae Merge pull request #43116 from frappe/mergify/bp/version-15-hotfix/pr-42816
fix: ensure `SellingController.onload` gets called for SO & DN (backport #42816)
2024-09-09 08:00:33 +05:30
Smit Vora
c379b783b1 Merge pull request #43092 from frappe/mergify/bp/version-15-hotfix/pr-43013
fix: `default_advance_account` field in Process Payment Reconciliation (backport #43013)
2024-09-09 08:00:07 +05:30
Smit Vora
f45b1db1a4 fix: multiple fixes related to remarks for GL Report (#42753)
* fix: show remarks in report only if it exists

* fix: additional fixes to reduce redundancy in report print format

* fix: revert changes for supplier invoice reference

* fix: update remarks before submit to ensure all available details before submit are used

* fix: patch to update invoice remarks where it's not set

* fix: update remarks in payment ledger entry

(cherry picked from commit e5a49f738b)
2024-09-09 01:54:40 +00:00
Smit Vora
a69623c131 Merge pull request #43115 from frappe/mergify/bp/version-15-hotfix/pr-42736
refactor: age range in one field (backport #42736)
2024-09-09 07:14:18 +05:30
Sagar Vora
2c1f72e44c fix: ensure SellingController.onload gets called for SO & DN
(cherry picked from commit 8431e3c275)
2024-09-09 01:44:17 +00:00
Smit Vora
3915018400 chore: resolve conflicts with backport 2024-09-09 07:00:32 +05:30
Sanket322
b832b60b28 refactor: age range in one field (#42736)
* fix: age range in one field

* fix: patch for custom reports

* refactor: stock ageing and account payable report

* fix: fixing the test cases

* fix: common patch for reports with ageing

* refactor: rename variable and minor refactor

* fix: fixing the test case

(cherry picked from commit 05de8994b0)
2024-09-09 01:20:13 +00:00
Khushi Rawat
b70eb46222 Merge pull request #43099 from frappe/mergify/bp/version-15-hotfix/pr-43098
fix(minor): reorder expected value validation (backport #43098)
2024-09-08 23:38:07 +05:30
Frappe PR Bot
829660e7f3 chore(release): Bumped to Version 15.34.2
## [15.34.2](https://github.com/frappe/erpnext/compare/v15.34.1...v15.34.2) (2024-09-07)

### Bug Fixes

* incorrect qty after transaction in SLE (backport [#43103](https://github.com/frappe/erpnext/issues/43103)) ([#43105](https://github.com/frappe/erpnext/issues/43105)) ([0bc947f](0bc947f30d))
2024-09-07 12:40:39 +00:00
rohitwaghchaure
4649cf0a25 Merge pull request #43107 from frappe/mergify/bp/version-15/pr-43105
fix: incorrect qty after transaction in SLE (backport #43103) (backport #43105)
2024-09-07 18:09:17 +05:30
mergify[bot]
0bc947f30d fix: incorrect qty after transaction in SLE (backport #43103) (#43105)
fix: incorrect qty after transaction in SLE (#43103)

(cherry picked from commit 5ff87edc85)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
(cherry picked from commit 8447bf34f0)
2024-09-07 12:04:01 +00:00
mergify[bot]
8447bf34f0 fix: incorrect qty after transaction in SLE (backport #43103) (#43105)
fix: incorrect qty after transaction in SLE (#43103)

(cherry picked from commit 5ff87edc85)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-07 17:32:42 +05:30
Khushi Rawat
6fde07da0e fix(minor): reorder expected value validation
(cherry picked from commit 0a6bf1559b)
2024-09-06 18:44:41 +00:00
ruthra kumar
6bd95a6d17 Merge pull request #43097 from frappe/mergify/bp/version-15-hotfix/pr-43077
fix: cancel common party advance jv while canceling the invoice (backport #43077)
2024-09-06 20:41:20 +05:30
venkat102
6c74180e1c test: add unit test for canceling the common party advance jv created from sales invoice
(cherry picked from commit 8c6e3f3c12)
2024-09-06 14:50:08 +00:00
venkat102
9bd3d7a020 fix: cancel common party advance jv while canceling the invoice
(cherry picked from commit 6a928b92df)
2024-09-06 14:50:07 +00:00
ruthra kumar
84b0fa38d5 refactor: fetch advance account on party seleection
(cherry picked from commit c4ed04cb31)
2024-09-06 09:48:47 +00:00
ljain112
75cb29890d fix: default_advance_account field in Process Payment Reconciliation
(cherry picked from commit 143209f91a)

# Conflicts:
#	erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.json
2024-09-06 09:48:47 +00:00
ruthra kumar
c31b4e6b4b Merge pull request #43074 from frappe/mergify/bp/version-15-hotfix/pr-43070
fix: AP filter to simulate employee advance as a ledger impacting voucher (backport #43070)
2024-09-06 10:09:30 +05:30
ruthra kumar
cb64f90d7d chore: resolve conflict 2024-09-05 17:22:47 +05:30
Frappe PR Bot
7f261f3448 chore(release): Bumped to Version 15.34.1
## [15.34.1](https://github.com/frappe/erpnext/compare/v15.34.0...v15.34.1) (2024-09-05)

### Bug Fixes

* add the company in payment request bcz delete company transactions (backport [#42664](https://github.com/frappe/erpnext/issues/42664)) ([#42982](https://github.com/frappe/erpnext/issues/42982)) ([42e7725](42e7725442))
* added app permission check for apps page ([a35ce12](a35ce12d60))
* adjust price insertion logic for internal suppliers/customers ([#42988](https://github.com/frappe/erpnext/issues/42988)) ([daa75ee](daa75eea00))
* auto reorder material request mail issue (backport [#43066](https://github.com/frappe/erpnext/issues/43066)) ([#43068](https://github.com/frappe/erpnext/issues/43068)) ([d2b2002](d2b2002664))
* **capitalization:** debit cwip account instead of fixed asset account ([#42857](https://github.com/frappe/erpnext/issues/42857)) ([f3c60ea](f3c60ea0a7))
* company accounts setup_queries ([b99cdb5](b99cdb5be7))
* disabled batches showing in the list (backport [#43024](https://github.com/frappe/erpnext/issues/43024)) ([#43069](https://github.com/frappe/erpnext/issues/43069)) ([56dad7d](56dad7d365))
* don't allow capitalizing only service item for new composite asset ([a833010](a833010d2b))
* improve asset item matching logic ([3bb1867](3bb186736d))
* indentation ([4d7c0c0](4d7c0c004a))
* link Purchase Invoice and Receipt Items to Asset ([1121c66](1121c6663f))
* retain date filter when redirecting in Profit and Loss report ([f0e3fb4](f0e3fb466a))
* typeerror on Payment Entry ([6d51d14](6d51d14dfd))
* typerror on default_currency ([7d6984c](7d6984c873))
* update develop_version in hooks ([6c8e0fd](6c8e0fd1fb))
* validate component quantity according to BOM (backport [#43011](https://github.com/frappe/erpnext/issues/43011)) ([#43014](https://github.com/frappe/erpnext/issues/43014)) ([fee2255](fee2255661))
2024-09-05 11:44:28 +00:00
ruthra kumar
efdc2173b2 refactor: filter to toggle employee advance scenario in AP
(cherry picked from commit 257e13c299)

# Conflicts:
#	erpnext/accounts/report/accounts_payable/accounts_payable.js
2024-09-05 11:44:04 +00:00
ruthra kumar
99828d945f refactor: Handle Emp Advance as separate row in AP report
(cherry picked from commit eedf22b07a)
2024-09-05 11:44:03 +00:00
ruthra kumar
11a6ebaeef Merge pull request #43026 from frappe/version-15-hotfix
chore: release v15
2024-09-05 17:13:12 +05:30
mergify[bot]
d2b2002664 fix: auto reorder material request mail issue (backport #43066) (#43068)
fix: auto reorder material request mail issue (#43066)

fix: auto reorder matreial request mail issue
(cherry picked from commit a8055a6da9)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-05 16:00:47 +05:30
mergify[bot]
56dad7d365 fix: disabled batches showing in the list (backport #43024) (#43069)
fix: disabled batches showing in the list (#43024)

(cherry picked from commit c13a147df1)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-05 16:00:33 +05:30
Khushi Rawat
6869e5dde9 Merge pull request #43039 from khushi8112/backport-asset-value-through-landed-cost-voucher
fix: backport asset value through landed cost voucher
2024-09-05 14:53:51 +05:30
Khushi Rawat
5d5ec2ab7c chore: resolve test failing 2024-09-05 14:31:05 +05:30
Khushi Rawat
f5a4ec129b chore: patch correction 2024-09-05 14:31:05 +05:30
Khushi Rawat
e185a06a15 refactor: rename to in SLE query functions 2024-09-05 14:31:05 +05:30
Khushi Rawat
193d7981ea chore: linters/semgrep check 2024-09-05 14:31:05 +05:30
Khushi Rawat
957eabf53e chore: resolved linter warnings with #nosemgrep 2024-09-05 14:31:05 +05:30
Khushi Rawat
3bb186736d fix: improve asset item matching logic 2024-09-05 14:31:05 +05:30
Khushi Rawat
1121c6663f fix: link Purchase Invoice and Receipt Items to Asset 2024-09-05 14:31:05 +05:30
Smit Vora
944479313c Merge pull request #43046 from frappe/mergify/bp/version-15-hotfix/pr-42988
fix: adjust price insertion logic for internal suppliers/customers (backport #42988)
2024-09-04 13:19:52 +05:30
Lakshit Jain
daa75eea00 fix: adjust price insertion logic for internal suppliers/customers (#42988)
* fix: adjust price insertion logic for internal suppliers/customers

* refactor: correct indentation, specify conditions within function

* fix: typo

---------

Co-authored-by: Smit Vora <smitvora203@gmail.com>
(cherry picked from commit 38f925b376)
2024-09-04 07:27:47 +00:00
ruthra kumar
a2b7fc18ab Merge pull request #43033 from frappe/mergify/bp/version-15-hotfix/pr-43030
fix: typerror on default_currency (backport #43030)
2024-09-03 16:51:22 +05:30
ruthra kumar
7d6984c873 fix: typerror on default_currency
(cherry picked from commit 4a7cc4da87)
2024-09-03 11:11:29 +00:00
Nihantra C. Patel
64cbf446bd Merge pull request #43031 from frappe/mergify/bp/version-15-hotfix/pr-43029
fix: move setup_queries to refresh event for company (backport #43029)
2024-09-03 16:12:27 +05:30
Nihantra C. Patel
b99cdb5be7 fix: company accounts setup_queries
(cherry picked from commit 80ace72541)
2024-09-03 10:36:29 +00:00
ruthra kumar
d6de50634f Merge pull request #43028 from frappe/mergify/bp/version-15-hotfix/pr-42974
fix: retain date filter when redirecting in Profit and Loss report (backport #42974)
2024-09-03 15:51:46 +05:30
vishnu
4d7c0c004a fix: indentation
(cherry picked from commit 598e9c1390)
2024-09-03 10:14:32 +00:00
vishnu
f0e3fb466a fix: retain date filter when redirecting in Profit and Loss report
(cherry picked from commit bb29fc4c3d)
2024-09-03 10:14:31 +00:00
Khushi Rawat
8337439589 Merge pull request #43018 from frappe/mergify/bp/version-15-hotfix/pr-43015
chore: test case failing issue (backport #43015)
2024-09-03 03:55:32 +05:30
Khushi Rawat
88e5ed7998 chore: test case failing issue
(cherry picked from commit 0bdffdfa98)
2024-09-02 22:09:22 +00:00
mergify[bot]
fee2255661 fix: validate component quantity according to BOM (backport #43011) (#43014)
* fix: validate component quantity according to BOM (#43011)

(cherry picked from commit f3b91d4d62)

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

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-09-02 16:29:30 +05:30
Nihantra C. Patel
23d91145d0 Merge pull request #43009 from frappe/mergify/bp/version-15-hotfix/pr-43008
fix: update develop_version in hooks (backport #43008)
2024-09-02 12:21:03 +05:30
Nihantra C. Patel
6c8e0fd1fb fix: update develop_version in hooks
(cherry picked from commit 01b345e046)
2024-09-02 06:13:37 +00:00
Shariq Ansari
512a171ad5 Merge pull request #42994 from frappe/mergify/bp/version-15-hotfix/pr-42993
fix: added app permission check for apps page (backport #42993)
2024-08-30 18:05:55 +05:30
Shariq Ansari
30f034555b chore: linter fix
(cherry picked from commit 1d9ed27a89)
2024-08-30 12:06:10 +00:00
Shariq Ansari
a35ce12d60 fix: added app permission check for apps page
(cherry picked from commit e8f8fb8a8f)
2024-08-30 12:06:10 +00:00
Khushi Rawat
8cf057849e Merge pull request #42986 from frappe/mergify/bp/version-15-hotfix/pr-42857
fix(capitalization): debit cwip account instead of fixed asset account (backport #42857)
2024-08-30 00:46:06 +05:30
Khushi Rawat
f3c60ea0a7 fix(capitalization): debit cwip account instead of fixed asset account (#42857)
* fix(capitalization): debit cwip account instead of fixed asset account

* fix: post entries for capitalized asset through background jobs

* chore: run pre-commit

* fix: correct GL entries posting for composite assets

* fix(minor): resolve failing check

* chore: update gl entry check logic

* chore: handle none values

(cherry picked from commit 5d99f17583)
2024-08-29 11:01:03 +00:00
ruthra kumar
c724573a18 Merge pull request #42985 from frappe/mergify/bp/version-15-hotfix/pr-42983
refactor: link utility report with bank reconciliation statement (backport #42983)
2024-08-29 16:19:47 +05:30
ruthra kumar
53e1b57354 refactor: link utility report with bank reconciliation statement
(cherry picked from commit 00eac65712)
2024-08-29 10:42:57 +00:00
mergify[bot]
42e7725442 fix: add the company in payment request bcz delete company transactions (backport #42664) (#42982)
* fix: add the company in payment request bcz delete company transactions

(cherry picked from commit 12834ccf9a)

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

* fix: link company when make payment request

(cherry picked from commit e3008843d1)

* fix: add the company in payment request bcz delete company transactions --conflicts

---------

Co-authored-by: Nihantra Patel <nihantra@frappe.io>
Co-authored-by: Nihantra C. Patel <141945075+Nihantra-Patel@users.noreply.github.com>
2024-08-29 15:41:08 +05:30
ruthra kumar
18b7af977c Merge pull request #42981 from frappe/mergify/bp/version-15-hotfix/pr-42979
refactor: better UX on Bank Clearance tool (backport #42979)
2024-08-29 14:07:49 +05:30
ruthra kumar
db746a4def refactor: better UX on Bank Clearance tool
(cherry picked from commit 6a06e26d04)
2024-08-29 08:25:12 +00:00
Khushi Rawat
3d5fb5fc90 Merge pull request #42977 from frappe/mergify/bp/version-15-hotfix/pr-42976
fix: don't allow capitalizing only service item for new composite asset (backport #42976)
2024-08-29 11:47:28 +05:30
Khushi Rawat
a833010d2b fix: don't allow capitalizing only service item for new composite asset
(cherry picked from commit f1d2138258)
2024-08-28 20:43:15 +00:00
ruthra kumar
0d6148f218 Merge pull request #42968 from frappe/mergify/bp/version-15-hotfix/pr-42966
fix: typeerror on Payment Entry (backport #42966)
2024-08-28 13:21:32 +05:30
ruthra kumar
6d51d14dfd fix: typeerror on Payment Entry
(cherry picked from commit e9cf8937cd)
2024-08-28 06:58:04 +00:00
Frappe PR Bot
cb2cb4447a chore(release): Bumped to Version 15.34.0
# [15.34.0](https://github.com/frappe/erpnext/compare/v15.33.5...v15.34.0) (2024-08-28)

### Bug Fixes

* calculation correction for annual depreciation ([fa85482](fa85482662))
* call 'process' directly instead of creating 'process_subscripti ([7582827](758282739e))
* Cannot read properties of null (reading 'doctype') (backport [#42941](https://github.com/frappe/erpnext/issues/42941)) ([#42943](https://github.com/frappe/erpnext/issues/42943)) ([2c99075](2c99075899))
* Column 'valuation_rate' cannot be null (backport [#42909](https://github.com/frappe/erpnext/issues/42909)) ([#42913](https://github.com/frappe/erpnext/issues/42913)) ([8c350d4](8c350d43b2))
* custom stock entry type issue (backport [#42835](https://github.com/frappe/erpnext/issues/42835)) ([#42846](https://github.com/frappe/erpnext/issues/42846)) ([831e2aa](831e2aaf18))
* do not copy date fields in opportunity doctype ([7401dc4](7401dc4015))
* get amount with taxes and charges from payment entry ([c54e97b](c54e97b89a))
* include erpnext in apps page ([7428df8](7428df8778))
* incorrect in and out qty in the Batch-Wise Balance History (backport [#42866](https://github.com/frappe/erpnext/issues/42866)) ([#42876](https://github.com/frappe/erpnext/issues/42876)) ([d9ca680](d9ca680a29))
* incorrect Received Qty Amount in Purchase Order Analysis (backport [#42852](https://github.com/frappe/erpnext/issues/42852)) ([#42854](https://github.com/frappe/erpnext/issues/42854)) ([72c1609](72c16097d6))
* last purchase rate not updated from purchase invoice (backport [#42847](https://github.com/frappe/erpnext/issues/42847)) ([#42853](https://github.com/frappe/erpnext/issues/42853)) ([2203ea9](2203ea9301))
* LCV based on purchase invoice amount with multi-currency (backport [#42890](https://github.com/frappe/erpnext/issues/42890)) ([#42894](https://github.com/frappe/erpnext/issues/42894)) ([ff868a9](ff868a9290))
* make party naming sequential when naming_by set as auto name ([0650c22](0650c22b53))
* not able to make stock entry against MR (backport [#42874](https://github.com/frappe/erpnext/issues/42874)) ([#42875](https://github.com/frappe/erpnext/issues/42875)) ([08bed61](08bed618f6))
* same posting date and time, creation causing incorrect balance qty (backport [#42904](https://github.com/frappe/erpnext/issues/42904)) ([#42920](https://github.com/frappe/erpnext/issues/42920)) ([2624892](26248924b6))
* spec mobile and email fields for notifications ([f56ee58](f56ee58e81))
* timeout while submitting stock entry (backport [#42929](https://github.com/frappe/erpnext/issues/42929)) ([#42931](https://github.com/frappe/erpnext/issues/42931)) ([ec26c92](ec26c92263))
* unsupported operand type(s) for *: 'float' and 'NoneType' (backport [#42916](https://github.com/frappe/erpnext/issues/42916)) ([#42918](https://github.com/frappe/erpnext/issues/42918)) ([8d29dc6](8d29dc6a81))
* update dimesions in exchange_gain_loss jv based on base document ([caa6ca1](caa6ca1d0b))
* Update get_amount to return currency precision grand total ([976abf7](976abf7b3c))
* use of incorrect attribute ([80244ba](80244bafa4))

### Features

* added finance book filter in depreciation and balances report ([5bdd298](5bdd2989c6))
* Disassembly Order (backport [#42655](https://github.com/frappe/erpnext/issues/42655)) ([#42957](https://github.com/frappe/erpnext/issues/42957)) ([8d8dd0c](8d8dd0cd2b))
* report to identify incorrectly cleared cheques ([25193c5](25193c5e92))
2024-08-28 05:04:27 +00:00
ruthra kumar
b3a8fe9391 Merge pull request #42937 from frappe/version-15-hotfix
chore: release v15
2024-08-28 10:33:09 +05:30
ruthra kumar
2a820a85ed Merge pull request #42952 from frappe/mergify/bp/version-15-hotfix/pr-41925
fix: spec mobile and email fields for notifications (backport #41925)
2024-08-28 10:13:26 +05:30
mergify[bot]
8d8dd0cd2b feat: Disassembly Order (backport #42655) (#42957)
* feat: Disassembly Order (#42655)

(cherry picked from commit 663a08e4cd)

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

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-27 23:07:37 +05:30
ruthra kumar
3a5f19853a Merge pull request #42947 from frappe/mergify/bp/version-15-hotfix/pr-42923
fix: get amount with taxes and charges from payment entry (backport #42923)
2024-08-27 17:39:30 +05:30
Khushi Rawat
c0dd794e15 Merge pull request #42944 from frappe/mergify/bp/version-15-hotfix/pr-42939
feat: added finance book filter in depreciation and balances report (backport #42939)
2024-08-27 17:18:10 +05:30
David
f56ee58e81 fix: spec mobile and email fields for notifications
(cherry picked from commit 18993a97ce)
2024-08-27 11:45:40 +00:00
mergify[bot]
2c99075899 fix: Cannot read properties of null (reading 'doctype') (backport #42941) (#42943)
fix: Cannot read properties of null (reading 'doctype') (#42941)

(cherry picked from commit 86d3a9ab03)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-27 17:15:23 +05:30
ruthra kumar
01cd509113 Merge pull request #42950 from frappe/mergify/bp/version-15-hotfix/pr-41949
refactor: item-wise purchase history (query to script report) (backport #41949)
2024-08-27 17:11:46 +05:30
ruthra kumar
5563bea789 Merge pull request #42949 from frappe/mergify/bp/version-15-hotfix/pr-42936
fix: remove unnecessary condition on 'voucher_no' (backport #42936)
2024-08-27 17:08:56 +05:30
Nihantra Patel
a0a932a235 refactor: item-wise purchase history (query to script report) --upd
(cherry picked from commit 2851764ed6)
2024-08-27 11:19:03 +00:00
Nihantra Patel
6f75a3c617 refactor: item-wise purchase history (query to script report) --prettier
(cherry picked from commit 7bae18aba8)
2024-08-27 11:19:03 +00:00
Nihantra Patel
a4d3934f75 refactor: item-wise purchase history (query to script report) --prettier
(cherry picked from commit f740c94363)
2024-08-27 11:19:03 +00:00
Nihantra Patel
b4171e4bd9 refactor: item-wise purchase history (query to script report) -- formatter
(cherry picked from commit 003a9608dc)
2024-08-27 11:19:03 +00:00
Nihantra Patel
76d32ab07a refactor: item-wise purchase history (query to script report)
(cherry picked from commit 49331e6109)
2024-08-27 11:19:03 +00:00
Nihantra Patel
3d469db47b refactor: item-wise purchase history (query to script report)
(cherry picked from commit 5de91cf55e)
2024-08-27 11:19:02 +00:00
ruthra kumar
80244bafa4 fix: use of incorrect attribute
(cherry picked from commit fb32d2cafb)
2024-08-27 11:06:38 +00:00
venkat102
c54e97b89a fix: get amount with taxes and charges from payment entry
(cherry picked from commit b3a901b631)
2024-08-27 11:01:36 +00:00
ruthra kumar
14202fae06 Merge pull request #42453 from mujeerhashmi/patch-2
fix: Update get_amount to return currency precision grand total
2024-08-27 16:29:08 +05:30
Khushi Rawat
9fc0ac1a92 chore: resolved linter warnings with #nosemgrep
(cherry picked from commit adf1e487e1)
2024-08-27 10:54:11 +00:00
Khushi Rawat
5bdd2989c6 feat: added finance book filter in depreciation and balances report
(cherry picked from commit 45804c68f0)
2024-08-27 10:54:10 +00:00
ruthra kumar
42dccadff1 Merge pull request #42940 from frappe/mergify/bp/version-15-hotfix/pr-42921
fix: make party naming sequential when naming_by set as auto name (backport #42921)
2024-08-27 16:13:00 +05:30
venkat102
0650c22b53 fix: make party naming sequential when naming_by set as auto name
(cherry picked from commit c9015f7c04)
2024-08-27 10:07:50 +00:00
mergify[bot]
ec26c92263 fix: timeout while submitting stock entry (backport #42929) (#42931)
fix: timeout while submitting stock entry (#42929)

(cherry picked from commit ca2fde891e)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-27 11:03:45 +05:30
mergify[bot]
26248924b6 fix: same posting date and time, creation causing incorrect balance qty (backport #42904) (#42920)
fix: same posting date and time, creation causing incorrect balance qty (#42904)

fix: same posting date and time, creation causing incorrect balance quantity
(cherry picked from commit 27364b7e6b)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-27 09:30:47 +05:30
mergify[bot]
8d29dc6a81 fix: unsupported operand type(s) for *: 'float' and 'NoneType' (backport #42916) (#42918)
fix: unsupported operand type(s) for *: 'float' and 'NoneType' (#42916)

(cherry picked from commit 10434742e9)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-26 18:18:31 +05:30
ruthra kumar
6eb50fa300 Merge pull request #42915 from frappe/mergify/bp/version-15-hotfix/pr-42887
fix: update dimesions in exchange_gain_loss jv based on base document (backport #42887)
2024-08-26 17:56:21 +05:30
mergify[bot]
8c350d43b2 fix: Column 'valuation_rate' cannot be null (backport #42909) (#42913)
fix: Column 'valuation_rate' cannot be null (#42909)

(cherry picked from commit 92bde71ab1)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-26 17:35:20 +05:30
ljain112
caa6ca1d0b fix: update dimesions in exchange_gain_loss jv based on base document
(cherry picked from commit 96df19149d)
2024-08-26 12:01:28 +00:00
ruthra kumar
47f1714be4 Merge pull request #42912 from frappe/mergify/bp/version-15-hotfix/pr-42910
feat: utility report to better diagnose incorrectly cleared Cheques and Deposits (backport #42910)
2024-08-26 16:32:29 +05:30
ruthra kumar
ecb0506dba refactor: build dictionary for Journal
remove redundant filter

(cherry picked from commit 2144e0337d)
2024-08-26 10:11:24 +00:00
ruthra kumar
42382b3945 chore: remove redundant column
(cherry picked from commit 74b36db24e)
2024-08-26 10:11:23 +00:00
ruthra kumar
993114942e refactor: build dict for payment entry
(cherry picked from commit 784dec24c8)
2024-08-26 10:11:23 +00:00
ruthra kumar
5a28a1728e refactor: working state with minimum functions
(cherry picked from commit 4cd023444a)
2024-08-26 10:11:23 +00:00
ruthra kumar
80a5df0e96 refactor: barebones functions
(cherry picked from commit ceaa1be729)
2024-08-26 10:11:23 +00:00
ruthra kumar
25193c5e92 feat: report to identify incorrectly cleared cheques
(cherry picked from commit 28890fa833)
2024-08-26 10:11:23 +00:00
ruthra kumar
1ee14ac135 Merge pull request #42907 from frappe/mergify/bp/version-15-hotfix/pr-42905
refactor: better err msg on clearance tool (backport #42905)
2024-08-26 15:29:48 +05:30
ruthra kumar
a3e5ffe915 refactor: better err msg on clearance tool
(cherry picked from commit 092411b54f)
2024-08-26 08:55:01 +00:00
mergify[bot]
ff868a9290 fix: LCV based on purchase invoice amount with multi-currency (backport #42890) (#42894)
fix: LCV based on purchase invoice amount with multi-currency (#42890)

(cherry picked from commit 6721ae76de)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-26 13:25:18 +05:30
Smit Vora
247ae7a965 Merge pull request #42892 from frappe/mergify/bp/version-15-hotfix/pr-42848
fix: do not copy date fields in opportunity doctype (backport #42848)
2024-08-24 13:12:13 +05:30
Smit Vora
3a149b3c9b chore: resolve conflicts 2024-08-24 12:38:49 +05:30
mergify[bot]
08bed618f6 fix: not able to make stock entry against MR (backport #42874) (#42875)
fix: not able to make stock entry against MR (#42874)

(cherry picked from commit 63ca1025bc)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-23 15:22:39 +05:30
mergify[bot]
d9ca680a29 fix: incorrect in and out qty in the Batch-Wise Balance History (backport #42866) (#42876)
fix: incorrect in and out qty in the Batch-Wise Balance History (#42866)

(cherry picked from commit ce7f6ee71c)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-23 15:22:23 +05:30
ljain112
7401dc4015 fix: do not copy date fields in opportunity doctype
(cherry picked from commit 74afa57a9f)

# Conflicts:
#	erpnext/crm/doctype/opportunity/opportunity.json
2024-08-23 08:48:33 +00:00
Frappe PR Bot
eb7e063d5c chore(release): Bumped to Version 15.33.5
## [15.33.5](https://github.com/frappe/erpnext/compare/v15.33.4...v15.33.5) (2024-08-23)

### Bug Fixes

* include erpnext in apps page ([be736cf](be736cf641))
2024-08-23 00:37:45 +00:00
ruthra kumar
0dbe79645c Merge pull request #42882 from frappe/mergify/bp/version-15/pr-42727
fix: include erpnext in apps page (backport #42727)
2024-08-23 06:05:20 +05:30
Shariq Ansari
995773088a chore: renamed include_as_app to include_in_apps_screen
(cherry picked from commit 5280132423)
2024-08-23 00:19:55 +00:00
Shariq Ansari
be736cf641 fix: include erpnext in apps page
(cherry picked from commit 1d52ef7afe)
2024-08-23 00:19:54 +00:00
ruthra kumar
85089d3d64 Merge pull request #42871 from frappe/mergify/bp/version-15-hotfix/pr-42867
fix: call 'process' directly instead of creating 'process_subscription' (backport #42867)
2024-08-22 17:51:37 +05:30
ruthra kumar
eed6d2b81c Merge pull request #42869 from frappe/mergify/bp/version-15-hotfix/pr-42851
refactor: Allow equity type Account in Payment Entry for shareholders (backport #42851)
2024-08-22 17:30:50 +05:30
Shariq Ansari
edf53f1ab7 Merge pull request #42863 from frappe/mergify/bp/version-15-hotfix/pr-42727
fix: include erpnext in apps page (backport #42727)
2024-08-22 17:24:33 +05:30
ruthra kumar
758282739e fix: call 'process' directly instead of creating 'process_subscripti
reason: 'process' follows simple DB transaction model.
(cherry picked from commit b4d22c2936)
2024-08-22 11:53:32 +00:00
ruthra kumar
49d995c3ac refactor: filter shareholder on company
(cherry picked from commit 63ad9f4f86)
2024-08-22 11:40:39 +00:00
ruthra kumar
72ca2ec9a5 refactor: allow equity types on Payment Entry
(cherry picked from commit 6cbf98294a)
2024-08-22 11:40:39 +00:00
Shariq Ansari
4297895bd9 chore: renamed include_as_app to include_in_apps_screen
(cherry picked from commit 5280132423)
2024-08-22 06:57:25 +00:00
Shariq Ansari
7428df8778 fix: include erpnext in apps page
(cherry picked from commit 1d52ef7afe)
2024-08-22 06:57:25 +00:00
Khushi Rawat
767c79663c Merge pull request #42862 from frappe/mergify/bp/version-15-hotfix/pr-42861
fix(minor): calculation correction for annual depreciation (backport #42861)
2024-08-22 11:56:08 +05:30
Khushi Rawat
fa85482662 fix: calculation correction for annual depreciation
(cherry picked from commit f440243b75)
2024-08-22 05:48:09 +00:00
mergify[bot]
831e2aaf18 fix: custom stock entry type issue (backport #42835) (#42846)
* fix: custom stock entry type issue (#42835)

(cherry picked from commit 9c82c2b5d3)

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

* chore: fix conflicts

* chore: fix linters issue

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-21 16:46:05 +05:30
Frappe PR Bot
9ac665b4bd chore(release): Bumped to Version 15.33.4
## [15.33.4](https://github.com/frappe/erpnext/compare/v15.33.3...v15.33.4) (2024-08-21)

### Bug Fixes

* incorrect Received Qty Amount in Purchase Order Analysis (backport [#42852](https://github.com/frappe/erpnext/issues/42852)) (backport [#42854](https://github.com/frappe/erpnext/issues/42854)) ([#42856](https://github.com/frappe/erpnext/issues/42856)) ([8d8d84b](8d8d84bae4))
* last purchase rate not updated from purchase invoice (backport [#42847](https://github.com/frappe/erpnext/issues/42847)) (backport [#42853](https://github.com/frappe/erpnext/issues/42853)) ([#42855](https://github.com/frappe/erpnext/issues/42855)) ([9f4cb98](9f4cb98de6))
2024-08-21 11:08:23 +00:00
mergify[bot]
8d8d84bae4 fix: incorrect Received Qty Amount in Purchase Order Analysis (backport #42852) (backport #42854) (#42856)
fix: incorrect Received Qty Amount in Purchase Order Analysis (backport #42852) (#42854)

fix: incorrect Received Qty Amount in Purchase Order Analysis (#42852)

(cherry picked from commit fb846ffa12)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
(cherry picked from commit 72c16097d6)

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-08-21 16:37:08 +05:30
mergify[bot]
9f4cb98de6 fix: last purchase rate not updated from purchase invoice (backport #42847) (backport #42853) (#42855)
fix: last purchase rate not updated from purchase invoice (backport #42847) (#42853)

fix: last purchase rate not updated from purchase invoice (#42847)

(cherry picked from commit 5b9309cf34)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
(cherry picked from commit 2203ea9301)

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-08-21 16:37:00 +05:30
mergify[bot]
72c16097d6 fix: incorrect Received Qty Amount in Purchase Order Analysis (backport #42852) (#42854)
fix: incorrect Received Qty Amount in Purchase Order Analysis (#42852)

(cherry picked from commit fb846ffa12)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-21 16:12:33 +05:30
mergify[bot]
2203ea9301 fix: last purchase rate not updated from purchase invoice (backport #42847) (#42853)
fix: last purchase rate not updated from purchase invoice (#42847)

(cherry picked from commit 5b9309cf34)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-21 15:20:50 +05:30
Frappe PR Bot
28c9f2adab chore(release): Bumped to Version 15.33.3
## [15.33.3](https://github.com/frappe/erpnext/compare/v15.33.2...v15.33.3) (2024-08-21)

### Bug Fixes

* Auto Create Serial and Batch Bundle For Outward (backport [#42778](https://github.com/frappe/erpnext/issues/42778)) ([#42792](https://github.com/frappe/erpnext/issues/42792)) ([7cc7179](7cc7179b05))
* backport german translations from develop ([9e9de4c](9e9de4c99e))
* bank reconcilation tool cost center company filter adding ([cd59940](cd5994017c))
* Create Sales Order from Quotation for Prospect ([f547bef](f547befeb9))
* create SO from Quot for Prospect --conflicts ([ec0201c](ec0201cb85))
* create SO from Quot for Prospect --conflicts ([5d7fb1d](5d7fb1d945))
* disable rename from warehouse ([3a1ad6e](3a1ad6e844))
* disable rename from warehouse ([40abd82](40abd82e2d))
* dropping index to improve performance (backport [#42820](https://github.com/frappe/erpnext/issues/42820)) ([#42821](https://github.com/frappe/erpnext/issues/42821)) ([b24de3e](b24de3e35b))
* german translations ([751c209](751c20984f))
* german translations of "HR" ([6f7fdbe](6f7fdbefac))
* ignore pricing rule while making DN from Pick List (backport [#42763](https://github.com/frappe/erpnext/issues/42763)) ([#42768](https://github.com/frappe/erpnext/issues/42768)) ([aba54ba](aba54ba18f))
* not able to create the batch (backport [#42784](https://github.com/frappe/erpnext/issues/42784)) ([#42785](https://github.com/frappe/erpnext/issues/42785)) ([0f9849e](0f9849e672))
* **patch:** replace repost with direct sql to update 'against_voucher ([e420fa9](e420fa9779))
* removed extra filter condition ([b84ca04](b84ca04975))
* set up filters for dimensions ([abb8866](abb88662c1))
* translatability of boldened text ([4914481](4914481105))
* update the testcase format ([33542cb](33542cb909))
* update the testcase format ([549dc28](549dc286d0))

### Performance Improvements

* asset creation from purchase receipt ([1040198](1040198ce1))
* data import for stock entries (backport [#42711](https://github.com/frappe/erpnext/issues/42711)) ([#42819](https://github.com/frappe/erpnext/issues/42819)) ([0344442](0344442d42))
2024-08-21 05:22:44 +00:00
ruthra kumar
d04f7ffe87 Merge pull request #42832 from frappe/version-15-hotfix
chore: release v15
2024-08-21 10:51:29 +05:30
Khushi Rawat
21e5c01f11 Merge pull request #42828 from frappe/mergify/bp/version-15-hotfix/pr-42824
perf: asset creation from purchase receipt (backport #42824)
2024-08-20 15:17:51 +05:30
mergify[bot]
ae6c1a30ac refactor: brand js and allow quick entry (backport #42829) (#42830)
* refactor: brand js and allow quick entry (#42829)

* refactor: brand js and allow quick entry

* refactor: brand js and allow quick entry --prettier

* refactor: brand js and allow quick entry --prettier

(cherry picked from commit a1183f0165)

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

* refactor: brand js and allow quick entry --refactor

---------

Co-authored-by: Nihantra C. Patel <141945075+Nihantra-Patel@users.noreply.github.com>
2024-08-20 15:03:23 +05:30
Khushi Rawat
1040198ce1 perf: asset creation from purchase receipt
(cherry picked from commit 6e84fc5143)
2024-08-20 08:12:48 +00:00
Nihantra C. Patel
69878b7847 Merge pull request #42826 from frappe/mergify/bp/version-15-hotfix/pr-42379
fix: Create Sales Order from Quotation for Prospect (backport #42379)
2024-08-20 11:57:29 +05:30
Nihantra C. Patel
ec0201cb85 fix: create SO from Quot for Prospect --conflicts 2024-08-20 11:34:27 +05:30
Nihantra C. Patel
5d7fb1d945 fix: create SO from Quot for Prospect --conflicts 2024-08-20 11:31:49 +05:30
Nihantra Patel
33542cb909 fix: update the testcase format
(cherry picked from commit ee44022249)
2024-08-20 05:11:02 +00:00
Nihantra Patel
549dc286d0 fix: update the testcase format
(cherry picked from commit 29d50b770e)
2024-08-20 05:11:02 +00:00
Nihantra Patel
f547befeb9 fix: Create Sales Order from Quotation for Prospect
(cherry picked from commit 2f63fae31d)

# Conflicts:
#	erpnext/selling/doctype/quotation/quotation.py
2024-08-20 05:11:02 +00:00
ruthra kumar
a144059c7c Merge pull request #42825 from frappe/mergify/bp/version-15-hotfix/pr-42731
fix: bank reconcilation tool cost center company filter adding (backport #42731)
2024-08-20 10:35:21 +05:30
Parameshwari Palanisamy
b96361e837 refactor: update dialog_manager.js
(cherry picked from commit 6d19aae423)
2024-08-20 04:44:47 +00:00
creative-paramu
cd5994017c fix: bank reconcilation tool cost center company filter adding
(cherry picked from commit 6e2ac09821)
2024-08-20 04:44:47 +00:00
Raffael Meyer
431fb62803 Merge pull request #42823 from barredterra/backport-german-translations 2024-08-19 19:25:16 +02:00
barredterra
9e9de4c99e fix: backport german translations from develop 2024-08-19 16:43:22 +02:00
Raffael Meyer
d3369368db Merge pull request #42804 from frappe/mergify/bp/version-15-hotfix/pr-42800
fix: translatability of boldened text (backport #42800)
2024-08-19 16:03:11 +02:00
mergify[bot]
b24de3e35b fix: dropping index to improve performance (backport #42820) (#42821)
fix: dropping index to improve performance (#42820)

fix: droping index to improve peformance
(cherry picked from commit 5404b21c7d)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-19 17:34:24 +05:30
mergify[bot]
0344442d42 perf: data import for stock entries (backport #42711) (#42819)
perf: data import for stock entries (#42711)

(cherry picked from commit 1511280464)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-19 14:55:41 +05:30
Raffael Meyer
0decd0955b Merge pull request #42805 from barredterra/de-hr-transl 2024-08-17 02:49:22 +02:00
barredterra
6f7fdbefac fix: german translations of "HR" 2024-08-17 02:48:39 +02:00
barredterra
dbd466b6b2 chore: resolve conflicts 2024-08-17 02:24:58 +02:00
barredterra
4914481105 fix: translatability of boldened text
(cherry picked from commit af0ae930ca)

# Conflicts:
#	erpnext/controllers/accounts_controller.py
2024-08-17 00:21:05 +00:00
Raffael Meyer
8514c01a91 Merge pull request #42798 from barredterra/20240816-de-translations 2024-08-16 19:11:37 +02:00
barredterra
751c20984f fix: german translations 2024-08-16 18:54:06 +02:00
Frappe PR Bot
81b1cbd367 chore(release): Bumped to Version 15.33.2
## [15.33.2](https://github.com/frappe/erpnext/compare/v15.33.1...v15.33.2) (2024-08-16)

### Bug Fixes

* **patch:** replace repost with direct sql to update 'against_voucher ([4d9f522](4d9f522f22))
2024-08-16 11:09:43 +00:00
ruthra kumar
a72383da0e Merge pull request #42796 from frappe/mergify/bp/version-15/pr-42791
fix(patch): Use sql to update 'against_voucher' rather than reposting (backport #42791)
2024-08-16 16:38:27 +05:30
ruthra kumar
eb8213c4e7 chore: update patches.txt
(cherry picked from commit 1721175a20)
2024-08-16 10:26:26 +00:00
ruthra kumar
4d9f522f22 fix(patch): replace repost with direct sql to update 'against_voucher
(cherry picked from commit 13bb48434f)
2024-08-16 10:26:26 +00:00
ruthra kumar
528f42c713 Merge pull request #42794 from frappe/mergify/bp/version-15-hotfix/pr-42791
fix(patch): Use sql to update 'against_voucher' rather than reposting (backport #42791)
2024-08-16 15:55:14 +05:30
mergify[bot]
7cc7179b05 fix: Auto Create Serial and Batch Bundle For Outward (backport #42778) (#42792)
fix: Auto Create Serial and Batch Bundle For Outward (#42778)

(cherry picked from commit 48c3b0d094)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-16 15:54:14 +05:30
ruthra kumar
cfaad685a4 chore: update patches.txt
(cherry picked from commit 1721175a20)
2024-08-16 10:02:44 +00:00
ruthra kumar
e420fa9779 fix(patch): replace repost with direct sql to update 'against_voucher
(cherry picked from commit 13bb48434f)
2024-08-16 10:02:44 +00:00
Frappe PR Bot
fbf1160357 chore(release): Bumped to Version 15.33.1
## [15.33.1](https://github.com/frappe/erpnext/compare/v15.33.0...v15.33.1) (2024-08-16)

### Bug Fixes

* not able to create the batch (backport [#42784](https://github.com/frappe/erpnext/issues/42784)) (backport [#42785](https://github.com/frappe/erpnext/issues/42785)) ([#42786](https://github.com/frappe/erpnext/issues/42786)) ([a3e3585](a3e3585e50))
2024-08-16 06:19:07 +00:00
mergify[bot]
a3e3585e50 fix: not able to create the batch (backport #42784) (backport #42785) (#42786)
fix: not able to create the batch (backport #42784) (#42785)

fix: not able to create the batch (#42784)

(cherry picked from commit 32c4fab14f)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
(cherry picked from commit 0f9849e672)

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-08-16 11:47:53 +05:30
mergify[bot]
0f9849e672 fix: not able to create the batch (backport #42784) (#42785)
fix: not able to create the batch (#42784)

(cherry picked from commit 32c4fab14f)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-16 11:39:15 +05:30
ruthra kumar
3be037221a Merge pull request #42783 from frappe/mergify/bp/version-15-hotfix/pr-42774
refactor: Loosen account currency validation on groups (backport #42774)
2024-08-16 10:41:56 +05:30
ruthra kumar
b2e108afcc refactor: allow foreign currency accounts in Supplier Group
(cherry picked from commit 164498bafb)
2024-08-16 04:30:12 +00:00
ruthra kumar
114a5f8cca refactor: allow foreign currency accounts in customer group
(cherry picked from commit 066e935892)
2024-08-16 04:30:12 +00:00
mergify[bot]
aba54ba18f fix: ignore pricing rule while making DN from Pick List (backport #42763) (#42768)
fix: ignore pricing rule while making DN from Pick List (#42763)

(cherry picked from commit 0db82ec93a)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-14 23:03:01 +05:30
Nihantra C. Patel
6a7768367e Merge pull request #42771 from frappe/mergify/bp/version-15-hotfix/pr-42769
fix: disable rename from warehouse (backport #42769)
2024-08-14 17:15:26 +05:30
Nihantra C. Patel
3a1ad6e844 fix: disable rename from warehouse 2024-08-14 16:37:36 +05:30
Nihantra C. Patel
40abd82e2d fix: disable rename from warehouse
(cherry picked from commit c1812f74e8)

# Conflicts:
#	erpnext/stock/doctype/warehouse/warehouse.json
2024-08-14 11:03:49 +00:00
Khushi Rawat
2933a86458 Merge pull request #42767 from frappe/mergify/bp/version-15-hotfix/pr-42765
fix: set up filters for dimensions (backport #42765)
2024-08-14 14:45:14 +05:30
Khushi Rawat
ecf0d0b388 chore: linters check
(cherry picked from commit 0d42793397)
2024-08-14 09:07:38 +00:00
Khushi Rawat
b84ca04975 fix: removed extra filter condition
(cherry picked from commit 6fa29376a0)
2024-08-14 09:07:38 +00:00
Khushi Rawat
abb88662c1 fix: set up filters for dimensions
(cherry picked from commit 2fd8de2f76)
2024-08-14 09:07:37 +00:00
Frappe PR Bot
73af5be1c3 chore(release): Bumped to Version 15.33.0
# [15.33.0](https://github.com/frappe/erpnext/compare/v15.32.1...v15.33.0) (2024-08-14)

### Bug Fixes

* allow sale of asset for internal transfer ([97cadfe](97cadfe5d3))
* cancel Journal Entry on cancellation of asset value adjustment ([a429f2f](a429f2f626))
* currency changing while making PR from the PO (backport [#42718](https://github.com/frappe/erpnext/issues/42718)) ([#42721](https://github.com/frappe/erpnext/issues/42721)) ([50b1fa5](50b1fa5deb))
* delivery note creation issue (backport [#42696](https://github.com/frappe/erpnext/issues/42696)) ([#42697](https://github.com/frappe/erpnext/issues/42697)) ([6f16ae3](6f16ae3e00))
* dimensions in common party journal entry ([fd4143e](fd4143e686))
* duplicate labels in stock entry (backport [#42756](https://github.com/frappe/erpnext/issues/42756)) ([#42758](https://github.com/frappe/erpnext/issues/42758)) ([8624a0a](8624a0abce))
* error message in coa importer ([20c1bcd](20c1bcd654))
* **Exchange Rate Revaluation:** translatable strings ([da6eea7](da6eea7743))
* fetch months last date to avoid miscalculation ([765c110](765c1104c4))
* force fetch updates for subcription ([582fffc](582fffca93))
* german translation of exit ([a2df276](a2df276880))
* german translations for incoterms ([9789648](9789648175))
* ledger entries for pos return with update outstanding for self ([8cd1952](8cd1952da3))
* Maintain same rate on qty change on Quotation to Sales Order ([7ed7c22](7ed7c22469))
* patch to fix incorrect against_voucher references in ledger ([389227b](389227bce8))
* pre-commit for better code formatting ([94f4c92](94f4c92a03))
* price list when invoice created from timesheet ([2926915](2926915a06))
* price list when invoice created from timesheet ([536dc47](536dc47eb0))
* promotional scheme doctype fields in consitency with pricing rule ([#42432](https://github.com/frappe/erpnext/issues/42432)) ([87d8603](87d8603d1d))
* resolved conflict ([defd554](defd5541b0))
* Sort lists before calling itertools.groupby ([d8939e0](d8939e0bb0))
* text color in sales funnel report based on theme ([a8de8ae](a8de8aecf5))
* typeerror on payment entry ([64e75a8](64e75a8e08))
* update 'Paid Amount' on forex payment request ([c71f06b](c71f06be9e))
* Update Rate as per Valuation Rate for Internal Transfers only if Setting is Enabled ([#42050](https://github.com/frappe/erpnext/issues/42050)) ([6e833cc](6e833cce6a))
* warning message for negative stock (backport [#42683](https://github.com/frappe/erpnext/issues/42683)) ([#42710](https://github.com/frappe/erpnext/issues/42710)) ([a990577](a99057754d))

### Features

* changes in opportunity.py to show contacts and addresses from referenced and opportunities ([3cac4a5](3cac4a598f))
2024-08-14 08:02:34 +00:00
ruthra kumar
81e3d269dc Merge pull request #42745 from frappe/version-15-hotfix
chore: release v15
2024-08-14 13:31:20 +05:30
ruthra kumar
3dafa98eef Merge pull request #42761 from frappe/mergify/bp/version-15-hotfix/pr-42720
fix: incorrect 'against_voucher' for Pos return with 'Update Outstanding for Self' disabled. (backport #42720)
2024-08-14 12:27:24 +05:30
ruthra kumar
3699b96adf refactor: move patch to v14 and update patches.txt
(cherry picked from commit da2286802a)
2024-08-14 06:26:48 +00:00
ruthra kumar
f782af8ab3 test: against_voucher for pos_returns without updating for self
(cherry picked from commit 3fb0858321)
2024-08-14 06:26:48 +00:00
ruthra kumar
2af48e40a1 refactor: update patches.txt
(cherry picked from commit 4dc0d3a003)
2024-08-14 06:26:48 +00:00
ruthra kumar
389227bce8 fix: patch to fix incorrect against_voucher references in ledger
(cherry picked from commit 487d0a55f5)
2024-08-14 06:26:48 +00:00
ruthra kumar
8cd1952da3 fix: ledger entries for pos return with update outstanding for self
(cherry picked from commit 2cd9b28e5b)
2024-08-14 06:26:48 +00:00
Khushi Rawat
f128fcd86c Merge pull request #42759 from frappe/mergify/bp/version-15-hotfix/pr-42719
fix: linkage between asset repair and asset value adjustment (backport #42719)
2024-08-14 11:23:33 +05:30
Khushi Rawat
d890d02b5c test: new depreciation after cancelling asset repair
(cherry picked from commit 88a5824e31)
2024-08-13 19:01:02 +00:00
Khushi Rawat
defd5541b0 fix: resolved conflict
(cherry picked from commit c085b6159b)
2024-08-13 19:01:01 +00:00
mergify[bot]
8624a0abce fix: duplicate labels in stock entry (backport #42756) (#42758)
fix: duplicate labels in stock entry (#42756)

(cherry picked from commit 8aadc18ee8)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-13 20:31:05 +05:30
ruthra kumar
13b79c6781 Merge pull request #42750 from frappe/mergify/bp/version-15-hotfix/pr-40964
fix: price list when invoice created from timesheet (backport #40964)
2024-08-13 17:35:50 +05:30
Nihantra C. Patel
2926915a06 fix: price list when invoice created from timesheet
(cherry picked from commit 882227a460)
2024-08-13 11:41:40 +00:00
Nihantra C. Patel
536dc47eb0 fix: price list when invoice created from timesheet
(cherry picked from commit 39d6df7c7d)
2024-08-13 11:41:39 +00:00
ruthra kumar
225843265e Merge pull request #42749 from frappe/mergify/bp/version-15-hotfix/pr-42221
fix: Force Fetching updates on Subscriptions (backport #42221)
2024-08-13 16:47:35 +05:30
ruthra kumar
a1f98603a6 refactor: test for force-fetch on future subscription
(cherry picked from commit fd680380bb)
2024-08-13 10:53:24 +00:00
ruthra kumar
ab59b33606 chore: minor naming change
(cherry picked from commit d8b6767697)
2024-08-13 10:53:24 +00:00
ruthra kumar
1f1e934675 refactor: don't process future subscriptions
(cherry picked from commit 3a11577411)
2024-08-13 10:53:24 +00:00
ruthra kumar
582fffca93 fix: force fetch updates for subcription
(cherry picked from commit 1ef890db73)
2024-08-13 10:53:23 +00:00
Khushi Rawat
e9b3a24221 Merge pull request #42742 from frappe/mergify/bp/version-15-hotfix/pr-42689
fix: fetch month's last date to avoid miscalculation (backport #42689)
2024-08-13 15:32:04 +05:30
ruthra kumar
0d5ac078f6 Merge pull request #42741 from frappe/mergify/bp/version-15-hotfix/pr-42726
fix: text color in sales funnel report based on theme (backport #42726)
2024-08-13 14:36:13 +05:30
ruthra kumar
f109164f88 Merge pull request #42739 from frappe/mergify/bp/version-15-hotfix/pr-42590
fix: error message in coa importer (backport #42590)
2024-08-13 14:35:53 +05:30
Khushi Rawat
765c1104c4 fix: fetch months last date to avoid miscalculation
(cherry picked from commit 70ff4e7644)
2024-08-13 08:42:33 +00:00
ljain112
a8de8aecf5 fix: text color in sales funnel report based on theme
(cherry picked from commit 61bc0925d5)
2024-08-13 08:36:31 +00:00
ljain112
20c1bcd654 fix: error message in coa importer
(cherry picked from commit 5d0a38dfc7)
2024-08-13 08:33:21 +00:00
ruthra kumar
6eaad90535 Merge pull request #42735 from frappe/mergify/bp/version-15-hotfix/pr-42733
refactor: add a new filter flag in Process Statement of Accounts (backport #42733)
2024-08-13 11:49:29 +05:30
Smit Vora
91a5c562d8 Merge pull request #42489 from frappe/mergify/bp/version-15-hotfix/pr-42050
fix: Update Rate as per Valuation Rate for Internal Transfers only if Setting is Enabled (backport #42050)
2024-08-13 11:25:09 +05:30
ruthra kumar
70d5593ace chore: resolve conflict 2024-08-13 11:21:09 +05:30
ruthra kumar
f3401243be refactor: pass filter to General Ledger
(cherry picked from commit 90880c8c01)
2024-08-13 05:41:35 +00:00
ruthra kumar
19dfeca96d 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
2024-08-13 05:41:35 +00:00
ruthra kumar
774db56762 refactor: combine vouchers from both ignore
(cherry picked from commit 4cc5cd5a71)
2024-08-13 05:41:35 +00:00
Khushi Rawat
d15c535f86 Merge pull request #42730 from frappe/mergify/bp/version-15-hotfix/pr-42729
fix: cancel Journal Entry on cancellation of asset value adjustment (backport #42729)
2024-08-13 02:31:24 +05:30
Khushi Rawat
a429f2f626 fix: cancel Journal Entry on cancellation of asset value adjustment
(cherry picked from commit 4b7f1f2d67)
2024-08-12 20:43:30 +00:00
ruthra kumar
dfbc7e8b33 Merge pull request #42725 from frappe/mergify/bp/version-15-hotfix/pr-42672
fix: update 'Paid Amount' on forex payment request (backport #42672)
2024-08-12 16:31:35 +05:30
ruthra kumar
b41f10c1b9 chore: resolve conflict 2024-08-12 16:13:59 +05:30
ruthra kumar
44745a757d test: currency conversion on foreign currency account
(cherry picked from commit f913c0fde1)
2024-08-12 10:38:35 +00:00
ruthra kumar
47bf2d408b 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:35 +00:00
ruthra kumar
c71f06be9e fix: update 'Paid Amount' on forex payment request
(cherry picked from commit 7b0dfb2a05)
2024-08-12 10:38:34 +00:00
mergify[bot]
50b1fa5deb fix: currency changing while making PR from the PO (backport #42718) (#42721)
fix: currency changing while making PR from the PO (#42718)

(cherry picked from commit 17ba0cff44)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-12 15:20:04 +05:30
mergify[bot]
a99057754d fix: warning message for negative stock (backport #42683) (#42710)
fix: warning message for negative stock (#42683)

(cherry picked from commit deccb007c1)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-11 12:35:13 +05:30
mergify[bot]
6f16ae3e00 fix: delivery note creation issue (backport #42696) (#42697)
fix: delivery note creation issue (#42696)

(cherry picked from commit b65072cd98)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-09 15:24:34 +05:30
ruthra kumar
38d80aab99 Merge pull request #42695 from frappe/mergify/bp/version-15-hotfix/pr-42428
fix: Sort lists before calling itertools.groupby (backport #42428)
2024-08-09 12:44:38 +05:30
Corentin Forler
d8939e0bb0 fix: Sort lists before calling itertools.groupby
(cherry picked from commit 45a6ecbd38)
2024-08-09 06:23:57 +00:00
ruthra kumar
f376abf0fe Merge pull request #42693 from frappe/mergify/bp/version-15-hotfix/pr-42691
fix: typeerror on payment entry (backport #42691)
2024-08-09 11:52:18 +05:30
ruthra kumar
64e75a8e08 fix: typeerror on payment entry
(cherry picked from commit 9cdca0d662)
2024-08-09 06:11:16 +00:00
Raffael Meyer
67a210f722 Merge pull request #42684 from barredterra/exit-translation
fix: german translation of exit
2024-08-08 22:23:34 +02:00
barredterra
a2df276880 fix: german translation of exit 2024-08-08 20:20:22 +02:00
Raffael Meyer
151d293aaf Merge pull request #42680 from frappe/mergify/bp/version-15-hotfix/pr-42679
fix(Exchange Rate Revaluation): translatable strings (backport #42679)
2024-08-08 13:17:27 +02:00
barredterra
13f6f3259d refactor(Exchange Rate Revaluation): remove unused variables
(cherry picked from commit 8bd84e9d51)
2024-08-08 10:09:53 +00:00
barredterra
da6eea7743 fix(Exchange Rate Revaluation): translatable strings
(cherry picked from commit dc29fb8759)
2024-08-08 10:09:52 +00:00
ruthra kumar
b28fa8b994 Merge pull request #42678 from frappe/mergify/bp/version-15-hotfix/pr-42673
fix: Maintain same rate on qty change on Quotation to Sales Order (backport #42673)
2024-08-08 13:43:46 +05:30
ruthra kumar
7ed7c22469 fix: Maintain same rate on qty change on Quotation to Sales Order
(cherry picked from commit 91ce9fce9b)
2024-08-08 08:04:30 +00:00
Frappe PR Bot
6a4f06cf4a chore(release): Bumped to Version 15.32.1
## [15.32.1](https://github.com/frappe/erpnext/compare/v15.32.0...v15.32.1) (2024-08-08)

### Bug Fixes

* promotional scheme doctype fields in consitency with pricing rule ([#42432](https://github.com/frappe/erpnext/issues/42432)) ([2aa90fd](2aa90fdc14))
2024-08-08 07:06:38 +00:00
ruthra kumar
dfe0079573 Merge pull request #42674 from frappe/mergify/bp/version-15/pr-42550
fix: promotional scheme doctype fields in consitency with pricing rule (backport #42432) (backport #42550)
2024-08-08 12:35:25 +05:30
Lakshit Jain
a983d65404 chore: resolve conflicts (#42553)
(cherry picked from commit 78eb443614)
2024-08-08 06:43:38 +00:00
Lakshit Jain
2aa90fdc14 fix: promotional scheme doctype fields in consitency with pricing rule (#42432)
* fix: add "round_free_qty" check box in promotional scheme

* fix: add `add_for_price_list` field

* fix: set_query in setup for promotional scheme

---------

(cherry picked from commit 8624aeca54)

# Conflicts:
#	erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.json
#	erpnext/accounts/doctype/promotional_scheme_product_discount/promotional_scheme_product_discount.json
(cherry picked from commit 87d8603d1d)
2024-08-08 06:43:38 +00:00
Shariq Ansari
a81bc28afb Merge pull request #42668 from frappe/mergify/bp/version-15-hotfix/pr-42596
fix: changes in opportunity.py to show contacts and addresses created from opportunity (backport #42596)
2024-08-08 11:39:44 +05:30
Smit Vora
70e40183bb Merge pull request #42551 from frappe/mergify/bp/version-15-hotfix/pr-42392
fix: allow sale of asset for internal transfer (backport #42392)
2024-08-08 11:22:00 +05:30
Smit Vora
bdfc1ddfc3 Merge pull request #42550 from frappe/mergify/bp/version-15-hotfix/pr-42432
fix: promotional scheme doctype fields in consitency with pricing rule (backport #42432)
2024-08-08 11:21:09 +05:30
Raffael Meyer
fb770f5633 Merge pull request #42669 from barredterra/incoterms-translation 2024-08-07 20:52:32 +02:00
barredterra
9789648175 fix: german translations for incoterms 2024-08-07 20:08:54 +02:00
Dietmar Fischer
94f4c92a03 fix: pre-commit for better code formatting
(cherry picked from commit 511a0b9f37)
2024-08-07 14:29:48 +00:00
Dietmar Fischer
3cac4a598f feat: changes in opportunity.py to show contacts and addresses from referenced and opportunities
(cherry picked from commit 61576ca030)
2024-08-07 14:29:47 +00:00
ruthra kumar
654fea8a3b Merge pull request #42661 from frappe/mergify/bp/version-15-hotfix/pr-42578
fix: dimensions in common party journal entry (backport #42578)
2024-08-07 16:23:54 +05:30
ruthra kumar
838d341d91 test: dimension inheritance on Exc Gain/Loss JV on Common party
(cherry picked from commit 8040544216)
2024-08-07 10:34:09 +00:00
ljain112
fd4143e686 fix: dimensions in common party journal entry
(cherry picked from commit ac629ede79)
2024-08-07 10:34:09 +00:00
Frappe PR Bot
2e3b2db03b chore(release): Bumped to Version 15.32.0
# [15.32.0](https://github.com/frappe/erpnext/compare/v15.31.5...v15.32.0) (2024-08-07)

### Bug Fixes

* 'undefined' in PL and BS report summary on Consolidated report ([3da7071](3da7071327))
* all warehouse filter for the stock report (backport [#42584](https://github.com/frappe/erpnext/issues/42584)) ([#42604](https://github.com/frappe/erpnext/issues/42604)) ([830b95b](830b95bdcb))
* company filter for filtring tax withheld vouchers ([3ad1f2d](3ad1f2d0d0))
* disable primary action button only when there are no active capitalization ([2d644ac](2d644ac066))
* Discount and taxes in return document should follow the reference document (backport [#41911](https://github.com/frappe/erpnext/issues/41911)) ([#42574](https://github.com/frappe/erpnext/issues/42574)) ([9321408](9321408154))
* do not update item price and last purchase rate for inter transf… (backport [#42616](https://github.com/frappe/erpnext/issues/42616)) ([#42633](https://github.com/frappe/erpnext/issues/42633)) ([59b9b7d](59b9b7dc91))
* german translations ([f27e9f3](f27e9f3089))
* inter transfer delivery note issue with batch (backport [#42552](https://github.com/frappe/erpnext/issues/42552)) ([#42556](https://github.com/frappe/erpnext/issues/42556)) ([97cc308](97cc3082e1))
* min height for rows in sales funnel ([2f81c99](2f81c99143))
* resolved conflict ([#42557](https://github.com/frappe/erpnext/issues/42557)) ([c3293d1](c3293d110c))
* reverse debit credit for party gl entry in payment entry based on negative amount ([#42367](https://github.com/frappe/erpnext/issues/42367)) ([14f9aef](14f9aef55c))
* set currency on change of company considering customer default currency (backport [#42405](https://github.com/frappe/erpnext/issues/42405)) ([#42547](https://github.com/frappe/erpnext/issues/42547)) ([7c8d13c](7c8d13c51a))
* set query filters for sales / purchase tax template on PE ([dc9cf74](dc9cf74be8))
* use get_last_day to get the correct date (backport [#42564](https://github.com/frappe/erpnext/issues/42564)) ([#42598](https://github.com/frappe/erpnext/issues/42598)) ([2de86eb](2de86eb0f4))

### Features

* expiry date column in Available Batch Report (backport [#42628](https://github.com/frappe/erpnext/issues/42628)) ([#42642](https://github.com/frappe/erpnext/issues/42642)) ([d8768c5](d8768c5377))
2024-08-07 09:30:48 +00:00
ruthra kumar
51fa336350 Merge pull request #42649 from frappe/version-15-hotfix
chore: release v15
2024-08-07 14:59:36 +05:30
Khushi Rawat
0a3c0ecea2 Merge pull request #42654 from frappe/mergify/bp/version-15-hotfix/pr-42593
fix: disable primary action button only when there are no active capitalization (backport #42593)
2024-08-06 20:19:11 +05:30
Khushi Rawat
2d644ac066 fix: disable primary action button only when there are no active capitalization
(cherry picked from commit bb877f4a6b)
2024-08-06 13:43:27 +00:00
mergify[bot]
d8768c5377 feat: expiry date column in Available Batch Report (backport #42628) (#42642)
feat: expiry date column in Available Batch Report (#42628)

(cherry picked from commit faff84c6e5)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-06 14:45:12 +05:30
ruthra kumar
65c1387a04 Merge pull request #42646 from frappe/mergify/bp/version-15-hotfix/pr-42592
fix: company filter for filtring tax withheld vouchers (backport #42592)
2024-08-06 13:38:47 +05:30
ljain112
3ad1f2d0d0 fix: company filter for filtring tax withheld vouchers
(cherry picked from commit cfe2ae604b)
2024-08-06 07:47:21 +00:00
ruthra kumar
af31f3b291 Merge pull request #42644 from frappe/mergify/bp/version-15-hotfix/pr-42545
fix: min height for rows in sales funnel (backport #42545)
2024-08-06 13:09:29 +05:30
ljain112
2f81c99143 fix: min height for rows in sales funnel
(cherry picked from commit fd71d8af52)
2024-08-06 07:33:19 +00:00
ruthra kumar
e679b336ef Merge pull request #42638 from frappe/mergify/bp/version-15-hotfix/pr-42636
refactor: posting date should not be considered for ignore filters in GL (backport #42636)
2024-08-06 11:43:46 +05:30
ruthra kumar
82c17632f7 refactor: posting date is not considered for ignore filters in GL
(cherry picked from commit c930f8ba9d)
2024-08-06 05:26:25 +00:00
mergify[bot]
59b9b7dc91 fix: do not update item price and last purchase rate for inter transf… (backport #42616) (#42633)
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:59 +05:30
ruthra kumar
d242d5330c Merge pull request #42626 from frappe/mergify/bp/version-15-hotfix/pr-42555
refactor: date filters should be mandatory in Sales Pipeline Analytics report (backport #42555)
2024-08-05 15:32:17 +05:30
ruthra kumar
05c606b65d refactor(test): use test fixture and supply from and to dates
(cherry picked from commit 4253caf910)
2024-08-05 09:39:30 +00:00
ruthra kumar
52578b03b4 refactor: consider empty-string as Not Assigned
(cherry picked from commit 213b2ba942)
2024-08-05 09:39:30 +00:00
ruthra kumar
8978a54479 refactor: report columns should be based on from and to dates
(cherry picked from commit 751a25c4b7)
2024-08-05 09:39:30 +00:00
ruthra kumar
b44598cb7a refactor: make 'from_date' and 'to_date' mandatory
(cherry picked from commit 3617b41b95)
2024-08-05 09:39:30 +00:00
ruthra kumar
48e05b6110 refactor: date filters should be explicit
(cherry picked from commit 40c166a0a0)
2024-08-05 09:39:30 +00:00
ruthra kumar
3640bc7f88 Merge pull request #42623 from frappe/mergify/bp/version-15-hotfix/pr-42621
refactor(test): clear data before GL report tests (backport #42621)
2024-08-05 14:02:19 +05:30
ruthra kumar
531410820f refactor(test): clear old records on GL report tests
(cherry picked from commit 56620785a0)
2024-08-05 08:15:31 +00:00
ruthra kumar
d08eba7308 Merge pull request #42614 from frappe/mergify/bp/version-15-hotfix/pr-42597
refactor: filter to ignore system generated cr / dr reconciliation journals on general ledger (backport #42597)
2024-08-05 11:34:00 +05:30
ruthra kumar
c1bfa0a31a refactor(test): filter and reconcile concerned vouchers
(cherry picked from commit 9ade269b7a)
2024-08-05 05:44:25 +00:00
ruthra kumar
155ca14b19 test: clear old data
(cherry picked from commit 991069bfbc)
2024-08-05 05:44:25 +00:00
ruthra kumar
3ee5991896 refactor: make use of date filters on ignore filterss
(cherry picked from commit 03f3ab522f)
2024-08-05 05:44:25 +00:00
ruthra kumar
7ec7e11634 test: ignore filter for system generated cr / dr note journals
(cherry picked from commit 3ffac73598)
2024-08-05 05:44:25 +00:00
ruthra kumar
17a6224a3f refactor: ignore system generated cr / dr notes on general ledger
(cherry picked from commit bb8c9b5a58)
2024-08-05 05:44:25 +00:00
ruthra kumar
e9bcb1bbb2 refactor: ignore filter in general ledger for cr / dr notes
(cherry picked from commit 59d5beee20)
2024-08-05 05:44:25 +00:00
mergify[bot]
830b95bdcb fix: all warehouse filter for the stock report (backport #42584) (#42604)
fix: all warehouse filter for the stock report

(cherry picked from commit a4311e345d)

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
2024-08-03 09:02:25 +05:30
mergify[bot]
2de86eb0f4 fix: use get_last_day to get the correct date (backport #42564) (#42598)
fix: use get_last_day to get the correct date (#42564)

(cherry picked from commit 5d58eb67a6)

Co-authored-by: Khushi Rawat <142375893+khushi8112@users.noreply.github.com>
2024-08-02 17:10:37 +05:30
Raffael Meyer
9616c59ed8 Merge pull request #42581 from barredterra/german-translations-01082024 2024-08-01 16:56:24 +02:00
barredterra
f27e9f3089 fix: german translations 2024-08-01 16:33:19 +02:00
mergify[bot]
9321408154 fix: Discount and taxes in return document should follow the reference document (backport #41911) (#42574)
fix: Discount and taxes in return document should follow the reference document (#41911)

* fix: Discount and taxes in return document should follow the reference document

* fix: Ignore Pricing rule on debit/credit note if created against PI/SI with test cases

* fix: linter issue

(cherry picked from commit 281198456d)

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
2024-08-01 15:45:18 +05:30
mergify[bot]
97cc3082e1 fix: inter transfer delivery note issue with batch (backport #42552) (#42556)
fix: inter transfer delivery note issue with batch (#42552)

(cherry picked from commit f620ef20ae)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2024-08-01 13:22:33 +05:30
ruthra kumar
b7b4de7c8d Merge pull request #42566 from frappe/mergify/bp/version-15-hotfix/pr-42563
fix: set query filters for sales / purchase tax template on PE (backport #42563)
2024-07-31 17:28:56 +05:30
ruthra kumar
dc9cf74be8 fix: set query filters for sales / purchase tax template on PE
(cherry picked from commit 9fe47ac101)
2024-07-31 11:39:12 +00:00
ruthra kumar
4e826fb3e9 Merge pull request #42560 from frappe/mergify/bp/version-15-hotfix/pr-42558
fix: 'undefined' in PL and BS report summary on Consolidated report (backport #42558)
2024-07-31 16:19:29 +05:30
Raffael Meyer
553513c4c6 Merge pull request #42561 from barredterra/backport-translations 2024-07-31 12:48:52 +02:00
barredterra
5cfa2d0692 chore: backport german translations from develop 2024-07-31 12:19:13 +02:00
ruthra kumar
3da7071327 fix: 'undefined' in PL and BS report summary on Consolidated report
(cherry picked from commit dd5a5e4919)
2024-07-31 10:04:00 +00:00
Nabin Hait
c3293d110c fix: resolved conflict (#42557) 2024-07-31 14:54:52 +05:30
Lakshit Jain
78eb443614 chore: resolve conflicts (#42553) 2024-07-31 13:38:38 +05:30
ljain112
97cadfe5d3 fix: allow sale of asset for internal transfer
(cherry picked from commit 972329cc16)
2024-07-31 07:54:58 +00:00
Lakshit Jain
87d8603d1d fix: promotional scheme doctype fields in consitency with pricing rule (#42432)
* fix: add "round_free_qty" check box in promotional scheme

* fix: add `add_for_price_list` field

* fix: set_query in setup for promotional scheme

---------

(cherry picked from commit 8624aeca54)

# Conflicts:
#	erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.json
#	erpnext/accounts/doctype/promotional_scheme_product_discount/promotional_scheme_product_discount.json
2024-07-31 07:51:57 +00:00
Smit Vora
7dc68cabcc Merge pull request #42548 from frappe/mergify/bp/version-15-hotfix/pr-42367
fix: reverse debit credit for party gl entry in payment entry based on negative amount (backport #42367)
2024-07-31 13:17:08 +05:30
mergify[bot]
7c8d13c51a fix: set currency on change of company considering customer default currency (backport #42405) (#42547)
fix: set currency on change of company considering customer default currency (#42405)

(cherry picked from commit 4986f28a89)

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

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
2024-07-31 13:02:12 +05:30
Lakshit Jain
14f9aef55c fix: reverse debit credit for party gl entry in payment entry based on negative amount (#42367)
* fix: do not absolute the amount for party gl entries

* fix: reverse debit credit for party gl entry based on negative amount

* refactor: reduce nesting of if condition

---------

(cherry picked from commit a694390a12)
2024-07-31 07:16:57 +00:00
Ninad Parikh
6e833cce6a fix: Update Rate as per Valuation Rate for Internal Transfers only if Setting is Enabled (#42050)
* fix: update rate for internal transfers only if settings enabled

* fix: better naming

* fix: create field for storing incoming rate in purchase doctypes

* fix: use qty instead of qty_in_stock_uom

* fix: add description, refactor for readablility

* test: test case to validate internal transfers at arm's length price

* fix: minor fix

* fix: deletion of code not required

---------

Co-authored-by: Smit Vora <smitvora203@gmail.com>
(cherry picked from commit 723ac0ffc4)
2024-07-26 12:58:12 +00:00
Syed Mujeer Hashmi
976abf7b3c fix: Update get_amount to return currency precision grand total
In case of multi-currency purchase invoice, we are getting the error "Total Payment Request amount cannot be greater than Purchase Invoice amount" because of rounding difference.
2024-07-24 11:59:45 +05:30
274 changed files with 11265 additions and 2098 deletions

View File

@@ -2,8 +2,9 @@ import functools
import inspect
import frappe
from frappe.utils.user import is_website_user
__version__ = "15.31.5"
__version__ = "15.38.4"
def get_default_company(user=None):
@@ -149,3 +150,13 @@ def allow_regional(fn):
return frappe.get_attr(overrides[function_path][-1])(*args, **kwargs)
return caller
def check_app_permission():
if frappe.session.user == "Administrator":
return True
if is_website_user():
return False
return True

View File

@@ -103,14 +103,12 @@ class Account(NestedSet):
self.name = get_autoname_with_number(self.account_number, self.account_name, self.company)
def validate(self):
from erpnext.accounts.utils import validate_field_number
if frappe.local.flags.allow_unverified_charts:
return
self.validate_parent()
self.validate_parent_child_account_type()
self.validate_root_details()
validate_field_number("Account", self.name, self.account_number, self.company, "account_number")
self.validate_account_number()
self.validate_group_or_ledger()
self.set_root_and_report_type()
self.validate_mandatory()
@@ -202,7 +200,7 @@ class Account(NestedSet):
msg = _(
"There are ledger entries against this account. Changing {0} to non-{1} in live system will cause incorrect output in 'Accounts {2}' report"
).format(
frappe.bold("Account Type"), doc_before_save.account_type, doc_before_save.account_type
frappe.bold(_("Account Type")), doc_before_save.account_type, doc_before_save.account_type
)
frappe.msgprint(msg)
self.add_comment("Comment", msg)
@@ -311,6 +309,22 @@ class Account(NestedSet):
if frappe.db.get_value("GL Entry", {"account": self.name}):
frappe.throw(_("Currency can not be changed after making entries using some other currency"))
def validate_account_number(self, account_number=None):
if not account_number:
account_number = self.account_number
if account_number:
account_with_same_number = frappe.db.get_value(
"Account",
{"account_number": account_number, "company": self.company, "name": ["!=", self.name]},
)
if account_with_same_number:
frappe.throw(
_("Account Number {0} already used in account {1}").format(
account_number, account_with_same_number
)
)
def create_account_for_child_company(self, parent_acc_name_map, descendants, parent_acc_name):
for company in descendants:
company_bold = frappe.bold(company)
@@ -464,19 +478,6 @@ def get_account_autoname(account_number, account_name, company):
return " - ".join(parts)
def validate_account_number(name, account_number, company):
if account_number:
account_with_same_number = frappe.db.get_value(
"Account", {"account_number": account_number, "company": company, "name": ["!=", name]}
)
if account_with_same_number:
frappe.throw(
_("Account Number {0} already used in account {1}").format(
account_number, account_with_same_number
)
)
@frappe.whitelist()
def update_account_number(name, account_name, account_number=None, from_descendant=False):
account = frappe.get_cached_doc("Account", name)
@@ -517,7 +518,7 @@ def update_account_number(name, account_name, account_number=None, from_descenda
frappe.throw(message, title=_("Rename Not Allowed"))
validate_account_number(name, account_number, account.company)
account.validate_account_number(account_number)
if account_number:
frappe.db.set_value("Account", name, "account_number", account_number.strip())
else:

View File

@@ -109,7 +109,8 @@
"Utility Expenses": {},
"Write Off": {},
"Exchange Gain/Loss": {},
"Gain/Loss on Asset Disposal": {}
"Gain/Loss on Asset Disposal": {},
"Impairment": {}
},
"root_type": "Expense"
},
@@ -132,7 +133,8 @@
"Source of Funds (Liabilities)": {
"Capital Account": {
"Reserves and Surplus": {},
"Shareholders Funds": {}
"Shareholders Funds": {},
"Revaluation Surplus": {}
},
"Current Liabilities": {
"Accounts Payable": {

View File

@@ -72,6 +72,7 @@ def get():
_("Write Off"): {},
_("Exchange Gain/Loss"): {},
_("Gain/Loss on Asset Disposal"): {},
_("Impairment"): {},
},
"root_type": "Expense",
},
@@ -104,6 +105,7 @@ def get():
_("Dividends Paid"): {"account_type": "Equity"},
_("Opening Balance Equity"): {"account_type": "Equity"},
_("Retained Earnings"): {"account_type": "Equity"},
_("Revaluation Surplus"): {"account_type": "Equity"},
"root_type": "Equity",
},
}

View File

@@ -208,8 +208,54 @@
"label": "Disabled"
}
],
"links": [],
"modified": "2023-09-22 21:31:34.763977",
"links": [
{
"group": "Transactions",
"link_doctype": "Payment Request",
"link_fieldname": "bank_account"
},
{
"group": "Transactions",
"link_doctype": "Payment Order",
"link_fieldname": "bank_account"
},
{
"group": "Transactions",
"link_doctype": "Bank Guarantee",
"link_fieldname": "bank_account"
},
{
"group": "Transactions",
"link_doctype": "Payroll Entry",
"link_fieldname": "bank_account"
},
{
"group": "Transactions",
"link_doctype": "Bank Transaction",
"link_fieldname": "bank_account"
},
{
"group": "Accounting",
"link_doctype": "Payment Entry",
"link_fieldname": "bank_account"
},
{
"group": "Accounting",
"link_doctype": "Journal Entry",
"link_fieldname": "bank_account"
},
{
"group": "Party",
"link_doctype": "Customer",
"link_fieldname": "default_bank_account"
},
{
"group": "Party",
"link_doctype": "Supplier",
"link_fieldname": "default_bank_account"
}
],
"modified": "2024-09-24 06:57:41.292970",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Account",
@@ -246,4 +292,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -1,20 +0,0 @@
from frappe import _
def get_data():
return {
"fieldname": "bank_account",
"non_standard_fieldnames": {
"Customer": "default_bank_account",
"Supplier": "default_bank_account",
},
"transactions": [
{
"label": _("Payments"),
"items": ["Payment Entry", "Payment Request", "Payment Order", "Payroll Entry"],
},
{"label": _("Party"), "items": ["Customer", "Supplier"]},
{"items": ["Bank Guarantee"]},
{"items": ["Journal Entry"]},
],
}

View File

@@ -38,6 +38,11 @@ frappe.ui.form.on("Bank Clearance", {
frm.add_custom_button(__("Get Payment Entries"), () => frm.trigger("get_payment_entries"));
frm.change_custom_button_type(__("Get Payment Entries"), null, "primary");
if (frm.doc.payment_entries.length) {
frm.add_custom_button(__("Update Clearance Date"), () => frm.trigger("update_clearance_date"));
frm.change_custom_button_type(__("Get Payment Entries"), null, "default");
frm.change_custom_button_type(__("Update Clearance Date"), null, "primary");
}
},
update_clearance_date: function (frm) {
@@ -45,13 +50,7 @@ frappe.ui.form.on("Bank Clearance", {
method: "update_clearance_date",
doc: frm.doc,
callback: function (r, rt) {
frm.refresh_field("payment_entries");
frm.refresh_fields();
if (!frm.doc.payment_entries.length) {
frm.change_custom_button_type(__("Get Payment Entries"), null, "primary");
frm.change_custom_button_type(__("Update Clearance Date"), null, "default");
}
frm.refresh();
},
});
},
@@ -60,17 +59,8 @@ frappe.ui.form.on("Bank Clearance", {
return frappe.call({
method: "get_payment_entries",
doc: frm.doc,
callback: function (r, rt) {
frm.refresh_field("payment_entries");
if (frm.doc.payment_entries.length) {
frm.add_custom_button(__("Update Clearance Date"), () =>
frm.trigger("update_clearance_date")
);
frm.change_custom_button_type(__("Get Payment Entries"), null, "default");
frm.change_custom_button_type(__("Update Clearance Date"), null, "primary");
}
callback: function () {
frm.refresh();
},
});
},

View File

@@ -6,7 +6,7 @@ import frappe
from frappe import _, msgprint
from frappe.model.document import Document
from frappe.query_builder.custom import ConstantColumn
from frappe.utils import flt, fmt_money, getdate
from frappe.utils import flt, fmt_money, get_link_to_form, getdate
from pypika import Order
import erpnext
@@ -96,8 +96,11 @@ class BankClearance(Document):
if d.cheque_date and getdate(d.clearance_date) < getdate(d.cheque_date):
frappe.throw(
_("Row #{0}: Clearance date {1} cannot be before Cheque Date {2}").format(
d.idx, d.clearance_date, d.cheque_date
_("Row #{0}: For {1} Clearance date {2} cannot be before Cheque Date {3}").format(
d.idx,
get_link_to_form(d.payment_document, d.payment_entry),
d.clearance_date,
d.cheque_date,
)
)
@@ -105,8 +108,18 @@ class BankClearance(Document):
if not d.clearance_date:
d.clearance_date = None
payment_entry = frappe.get_doc(d.payment_document, d.payment_entry)
payment_entry.db_set("clearance_date", d.clearance_date)
if d.payment_document == "Sales Invoice":
frappe.db.set_value(
"Sales Invoice Payment",
{"parent": d.payment_entry, "account": self.get("account"), "amount": [">", 0]},
"clearance_date",
d.clearance_date,
)
else:
frappe.db.set_value(
d.payment_document, d.payment_entry, "clearance_date", d.clearance_date
)
clearance_date_updated = True

View File

@@ -6,16 +6,29 @@ import unittest
import frappe
from frappe.utils import add_months, getdate
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.tests.utils import if_lending_app_installed, if_lending_app_not_installed
class TestBankClearance(unittest.TestCase):
@classmethod
def setUpClass(cls):
create_warehouse(
warehouse_name="_Test Warehouse",
properties={"parent_warehouse": "All Warehouses - _TC"},
company="_Test Company",
)
create_item("_Test Item")
create_cost_center(cost_center_name="_Test Cost Center", company="_Test Company")
clear_payment_entries()
clear_loan_transactions()
clear_pos_sales_invoices()
make_bank_account()
add_transactions()
@@ -83,11 +96,41 @@ class TestBankClearance(unittest.TestCase):
bank_clearance.get_payment_entries()
self.assertEqual(len(bank_clearance.payment_entries), 3)
def test_update_clearance_date_on_si(self):
sales_invoice = make_pos_sales_invoice()
date = getdate()
bank_clearance = frappe.get_doc("Bank Clearance")
bank_clearance.account = "_Test Bank Clearance - _TC"
bank_clearance.from_date = add_months(date, -1)
bank_clearance.to_date = date
bank_clearance.include_pos_transactions = 1
bank_clearance.get_payment_entries()
self.assertNotEqual(len(bank_clearance.payment_entries), 0)
for payment in bank_clearance.payment_entries:
if payment.payment_entry == sales_invoice.name:
payment.clearance_date = date
bank_clearance.update_clearance_date()
si_clearance_date = frappe.db.get_value(
"Sales Invoice Payment",
{"parent": sales_invoice.name, "account": bank_clearance.account},
"clearance_date",
)
self.assertEqual(si_clearance_date, date)
def clear_payment_entries():
frappe.db.delete("Payment Entry")
def clear_pos_sales_invoices():
frappe.db.delete("Sales Invoice", {"is_pos": 1})
@if_lending_app_installed
def clear_loan_transactions():
for dt in [
@@ -115,9 +158,45 @@ def add_transactions():
def make_payment_entry():
pi = make_purchase_invoice(supplier="_Test Supplier", qty=1, rate=690)
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
supplier = create_supplier(supplier_name="_Test Supplier")
pi = make_purchase_invoice(
supplier=supplier,
supplier_warehouse="_Test Warehouse - _TC",
expense_account="Cost of Goods Sold - _TC",
uom="Nos",
qty=1,
rate=690,
)
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank Clearance - _TC")
pe.reference_no = "Conrad Oct 18"
pe.reference_date = "2018-10-24"
pe.insert()
pe.submit()
def make_pos_sales_invoice():
from erpnext.accounts.doctype.opening_invoice_creation_tool.test_opening_invoice_creation_tool import (
make_customer,
)
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"}):
mode_of_payment.append(
"accounts", {"company": "_Test Company", "default_account": "_Test Bank Clearance - _TC"}
)
mode_of_payment.save()
customer = make_customer(customer="_Test Customer")
si = create_sales_invoice(customer=customer, item="_Test Item", is_pos=1, qty=1, rate=1000, do_not_save=1)
si.set("payments", [])
si.append(
"payments", {"mode_of_payment": "Cash", "account": "_Test Bank Clearance - _TC", "amount": 1000}
)
si.insert()
si.submit()
return si

View File

@@ -47,9 +47,11 @@ def validate_columns(data):
no_of_columns = max([len(d) for d in data])
if no_of_columns > 8:
if no_of_columns != 8:
frappe.throw(
_("More columns found than expected. Please compare the uploaded file with standard template"),
_(
"Columns are not according to template. Please compare the uploaded file with standard template"
),
title=(_("Wrong Template")),
)

View File

@@ -22,8 +22,10 @@ class TestCostCenterAllocation(unittest.TestCase):
cost_centers = [
"Main Cost Center 1",
"Main Cost Center 2",
"Main Cost Center 3",
"Sub Cost Center 1",
"Sub Cost Center 2",
"Sub Cost Center 3",
]
for cc in cost_centers:
create_cost_center(cost_center_name=cc, company="_Test Company")
@@ -36,7 +38,7 @@ class TestCostCenterAllocation(unittest.TestCase):
)
jv = make_journal_entry(
"_Test Cash - _TC", "Sales - _TC", 100, cost_center="Main Cost Center 1 - _TC", submit=True
"Cash - _TC", "Sales - _TC", 100, cost_center="Main Cost Center 1 - _TC", submit=True
)
expected_values = [["Sub Cost Center 1 - _TC", 0.0, 60], ["Sub Cost Center 2 - _TC", 0.0, 40]]
@@ -120,7 +122,7 @@ class TestCostCenterAllocation(unittest.TestCase):
def test_valid_from_based_on_existing_gle(self):
# GLE posted against Sub Cost Center 1 on today
jv = make_journal_entry(
"_Test Cash - _TC",
"Cash - _TC",
"Sales - _TC",
100,
cost_center="Main Cost Center 1 - _TC",
@@ -141,6 +143,53 @@ class TestCostCenterAllocation(unittest.TestCase):
jv.cancel()
def test_multiple_cost_center_allocation_on_same_main_cost_center(self):
coa1 = create_cost_center_allocation(
"_Test Company",
"Main Cost Center 3 - _TC",
{"Sub Cost Center 1 - _TC": 30, "Sub Cost Center 2 - _TC": 30, "Sub Cost Center 3 - _TC": 40},
valid_from=add_days(today(), -5),
)
coa2 = create_cost_center_allocation(
"_Test Company",
"Main Cost Center 3 - _TC",
{"Sub Cost Center 1 - _TC": 50, "Sub Cost Center 2 - _TC": 50},
valid_from=add_days(today(), -1),
)
jv = make_journal_entry(
"Cash - _TC",
"Sales - _TC",
100,
cost_center="Main Cost Center 3 - _TC",
posting_date=today(),
submit=True,
)
expected_values = {"Sub Cost Center 1 - _TC": 50, "Sub Cost Center 2 - _TC": 50}
gle = frappe.qb.DocType("GL Entry")
gl_entries = (
frappe.qb.from_(gle)
.select(gle.cost_center, gle.debit, gle.credit)
.where(gle.voucher_type == "Journal Entry")
.where(gle.voucher_no == jv.name)
.where(gle.account == "Sales - _TC")
.orderby(gle.cost_center)
).run(as_dict=1)
self.assertTrue(gl_entries)
for gle in gl_entries:
self.assertTrue(gle.cost_center in expected_values)
self.assertEqual(gle.debit, 0)
self.assertEqual(gle.credit, expected_values[gle.cost_center])
coa1.cancel()
coa2.cancel()
jv.cancel()
def create_cost_center_allocation(
company,

View File

@@ -109,7 +109,7 @@ def get_api_endpoint(service_provider: str | None = None, use_http: bool = False
if service_provider == "exchangerate.host":
api = "api.exchangerate.host/convert"
elif service_provider == "frankfurter.app":
api = "frankfurter.app/{transaction_date}"
api = "api.frankfurter.app/{transaction_date}"
protocol = "https://"
if use_http:

View File

@@ -210,19 +210,31 @@ def get_linked_dunnings_as_per_state(sales_invoice, state):
@frappe.whitelist()
def get_dunning_letter_text(dunning_type, doc, language=None):
def get_dunning_letter_text(dunning_type: str, doc: str | dict, language: str | None = None) -> dict:
DOCTYPE = "Dunning Letter Text"
FIELDS = ["body_text", "closing_text", "language"]
if isinstance(doc, str):
doc = json.loads(doc)
if not language:
language = doc.get("language")
if language:
filters = {"parent": dunning_type, "language": language}
else:
filters = {"parent": dunning_type, "is_default_language": 1}
letter_text = frappe.db.get_value(
"Dunning Letter Text", filters, ["body_text", "closing_text", "language"], as_dict=1
)
if letter_text:
return {
"body_text": frappe.render_template(letter_text.body_text, doc),
"closing_text": frappe.render_template(letter_text.closing_text, doc),
"language": letter_text.language,
}
letter_text = frappe.db.get_value(
DOCTYPE, {"parent": dunning_type, "language": language}, FIELDS, as_dict=1
)
if not letter_text:
letter_text = frappe.db.get_value(
DOCTYPE, {"parent": dunning_type, "is_default_language": 1}, FIELDS, as_dict=1
)
if not letter_text:
return {}
return {
"body_text": frappe.render_template(letter_text.body_text, doc),
"closing_text": frappe.render_template(letter_text.closing_text, doc),
"language": letter_text.language,
}

View File

@@ -85,18 +85,16 @@ frappe.ui.form.on("Exchange Rate Revaluation", {
},
make_jv: function (frm) {
let revaluation_journal = null;
let zero_balance_journal = null;
frappe.call({
method: "make_jv_entries",
doc: frm.doc,
freeze: true,
freeze_message: "Making Journal Entries...",
freeze_message: __("Creating Journal Entries..."),
callback: function (r) {
if (r.message) {
let response = r.message;
if (response["revaluation_jv"] || response["zero_balance_jv"]) {
frappe.msgprint(__("Journals have been created"));
frappe.msgprint(__("Journal entries have been created"));
}
}
},

View File

@@ -360,21 +360,23 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
accounts_add(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
row.exchange_rate = 1;
$.each(doc.accounts, function (i, d) {
if (d.account && d.party && d.party_type) {
row.account = d.account;
row.party = d.party;
row.party_type = d.party_type;
row.exchange_rate = d.exchange_rate;
}
});
// set difference
if (doc.difference) {
if (doc.difference > 0) {
row.credit_in_account_currency = doc.difference;
row.credit_in_account_currency = doc.difference / row.exchange_rate;
row.credit = doc.difference;
} else {
row.debit_in_account_currency = -doc.difference;
row.debit_in_account_currency = -doc.difference / row.exchange_rate;
row.debit = -doc.difference;
}
}
@@ -680,6 +682,7 @@ $.extend(erpnext.journal_entry, {
callback: function (r) {
if (r.message) {
$.extend(d, r.message);
erpnext.journal_entry.set_amount_on_last_row(frm, dt, dn);
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, dt, dn);
refresh_field("accounts");
}
@@ -687,4 +690,26 @@ $.extend(erpnext.journal_entry, {
});
}
},
set_amount_on_last_row: function (frm, dt, dn) {
let row = locals[dt][dn];
let length = frm.doc.accounts.length;
if (row.idx != length) return;
let difference = frm.doc.accounts.reduce((total, row) => {
if (row.idx == length) return total;
return total + row.debit - row.credit;
}, 0);
if (difference) {
if (difference > 0) {
row.credit_in_account_currency = difference / row.exchange_rate;
row.credit = difference;
} else {
row.debit_in_account_currency = -difference / row.exchange_rate;
row.debit = -difference;
}
}
refresh_field("accounts");
},
});

View File

@@ -195,6 +195,11 @@ class JournalEntry(AccountsController):
self.update_booked_depreciation()
def on_update_after_submit(self):
# Flag will be set on Reconciliation
# Reconciliation tool will anyways repost ledger entries. So, no need to check and do implicit repost.
if self.flags.get("ignore_reposting_on_reconciliation"):
return
self.needs_repost = self.check_if_fields_updated(fields_to_check=[], child_tables={"accounts": []})
if self.needs_repost:
self.validate_for_repost()

View File

@@ -515,6 +515,23 @@ class TestJournalEntry(unittest.TestCase):
self.assertEqual(row.debit_in_account_currency, 100)
self.assertEqual(row.credit_in_account_currency, 100)
def test_transaction_exchange_rate_on_journals(self):
jv = make_journal_entry("_Test Bank - _TC", "_Test Receivable USD - _TC", 100, save=False)
jv.accounts[0].update({"debit_in_account_currency": 8500, "exchange_rate": 1})
jv.accounts[1].update({"party_type": "Customer", "party": "_Test Customer USD", "exchange_rate": 85})
jv.submit()
actual = frappe.db.get_all(
"GL Entry",
filters={"voucher_no": jv.name, "is_cancelled": 0},
fields=["account", "transaction_exchange_rate"],
order_by="account",
)
expected = [
{"account": "_Test Bank - _TC", "transaction_exchange_rate": 1.0},
{"account": "_Test Receivable USD - _TC", "transaction_exchange_rate": 85.0},
]
self.assertEqual(expected, actual)
def make_journal_entry(
account1,

View File

@@ -28,7 +28,12 @@ frappe.ui.form.on("Opening Invoice Creation Tool", {
frm.refresh_fields();
frm.page.clear_indicator();
frm.dashboard.hide_progress();
frappe.msgprint(__("Opening {0} Invoices created", [frm.doc.invoice_type]));
if (frm.doc.invoice_type == "Sales") {
frappe.msgprint(__("Opening Sales Invoices have been created."));
} else {
frappe.msgprint(__("Opening Purchase Invoices have been created."));
}
},
1500,
data.title
@@ -48,12 +53,19 @@ frappe.ui.form.on("Opening Invoice Creation Tool", {
!frm.doc.import_in_progress && frm.trigger("make_dashboard");
frm.page.set_primary_action(__("Create Invoices"), () => {
let btn_primary = frm.page.btn_primary.get(0);
let freeze_message;
if (frm.doc.invoice_type == "Sales") {
freeze_message = __("Creating Sales Invoices ...");
} else {
freeze_message = __("Creating Purchase Invoices ...");
}
return frm.call({
doc: frm.doc,
btn: $(btn_primary),
method: "make_invoices",
freeze: 1,
freeze_message: __("Creating {0} Invoice", [frm.doc.invoice_type]),
freeze_message: freeze_message,
});
});

View File

@@ -35,6 +35,11 @@ frappe.ui.form.on("Payment Entry", {
var account_types = ["Pay", "Internal Transfer"].includes(frm.doc.payment_type)
? ["Bank", "Cash"]
: [frappe.boot.party_account_types[frm.doc.party_type]];
if (frm.doc.party_type == "Shareholder") {
account_types.push("Equity");
}
return {
filters: {
account_type: ["in", account_types],
@@ -90,6 +95,9 @@ frappe.ui.form.on("Payment Entry", {
var account_types = ["Receive", "Internal Transfer"].includes(frm.doc.payment_type)
? ["Bank", "Cash"]
: [frappe.boot.party_account_types[frm.doc.party_type]];
if (frm.doc.party_type == "Shareholder") {
account_types.push("Equity");
}
return {
filters: {
account_type: ["in", account_types],
@@ -165,6 +173,42 @@ frappe.ui.form.on("Payment Entry", {
filters: filters,
};
});
frm.set_query("payment_request", "references", function (doc, cdt, cdn) {
const row = frappe.get_doc(cdt, cdn);
return {
query: "erpnext.accounts.doctype.payment_request.payment_request.get_open_payment_requests_query",
filters: {
reference_doctype: row.reference_doctype,
reference_name: row.reference_name,
},
};
});
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,
},
};
});
frm.add_fetch(
"payment_request",
"outstanding_amount",
"payment_request_outstanding",
"Payment Entry Reference"
);
},
refresh: function (frm) {
@@ -191,6 +235,7 @@ frappe.ui.form.on("Payment Entry", {
);
}
erpnext.accounts.unreconcile_payment.add_unreconcile_btn(frm);
frappe.flags.allocate_payment_amount = true;
},
validate_company: (frm) => {
@@ -213,7 +258,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
? frappe.get_doc(":Company", frm.doc.company)?.default_currency
: "";
frm.toggle_display(
@@ -280,7 +325,7 @@ frappe.ui.form.on("Payment Entry", {
set_dynamic_labels: function (frm) {
var company_currency = frm.doc.company
? frappe.get_doc(":Company", frm.doc.company).default_currency
? frappe.get_doc(":Company", frm.doc.company)?.default_currency
: "";
frm.set_currency_labels(
@@ -360,7 +405,15 @@ frappe.ui.form.on("Payment Entry", {
payment_type: function (frm) {
if (frm.doc.payment_type == "Internal Transfer") {
$.each(
["party", "party_balance", "paid_from", "paid_to", "references", "total_allocated_amount"],
[
"party",
"party_type",
"party_balance",
"paid_from",
"paid_to",
"references",
"total_allocated_amount",
],
function (i, field) {
frm.set_value(field, null);
}
@@ -395,6 +448,12 @@ frappe.ui.form.on("Payment Entry", {
return {
query: "erpnext.controllers.queries.employee_query",
};
} else if (frm.doc.party_type == "Shareholder") {
return {
filters: {
company: frm.doc.company,
},
};
}
});
@@ -627,7 +686,7 @@ frappe.ui.form.on("Payment Entry", {
frm.set_value("source_exchange_rate", 1);
} else if (frm.doc.paid_from) {
if (["Internal Transfer", "Pay"].includes(frm.doc.payment_type)) {
let company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
let company_currency = frappe.get_doc(":Company", frm.doc.company)?.default_currency;
frappe.call({
method: "erpnext.setup.utils.get_exchange_rate",
args: {
@@ -758,7 +817,7 @@ frappe.ui.form.on("Payment Entry", {
);
if (frm.doc.payment_type == "Pay")
frm.events.allocate_party_amount_against_ref_docs(frm, frm.doc.received_amount, 1);
frm.events.allocate_party_amount_against_ref_docs(frm, frm.doc.received_amount, true);
else frm.events.set_unallocated_amount(frm);
frm.set_paid_amount_based_on_received_amount = false;
@@ -779,7 +838,7 @@ frappe.ui.form.on("Payment Entry", {
}
if (frm.doc.payment_type == "Receive")
frm.events.allocate_party_amount_against_ref_docs(frm, frm.doc.paid_amount, 1);
frm.events.allocate_party_amount_against_ref_docs(frm, frm.doc.paid_amount, true);
else frm.events.set_unallocated_amount(frm);
},
@@ -950,6 +1009,7 @@ frappe.ui.form.on("Payment Entry", {
c.outstanding_amount = d.outstanding_amount;
c.bill_no = d.bill_no;
c.payment_term = d.payment_term;
c.payment_term_outstanding = d.payment_term_outstanding;
c.allocated_amount = d.allocated_amount;
c.account = d.account;
@@ -999,7 +1059,8 @@ frappe.ui.form.on("Payment Entry", {
frm.events.allocate_party_amount_against_ref_docs(
frm,
frm.doc.payment_type == "Receive" ? frm.doc.paid_amount : frm.doc.received_amount
frm.doc.payment_type == "Receive" ? frm.doc.paid_amount : frm.doc.received_amount,
false
);
},
});
@@ -1013,93 +1074,13 @@ frappe.ui.form.on("Payment Entry", {
return ["Sales Invoice", "Purchase Invoice"];
},
allocate_party_amount_against_ref_docs: function (frm, paid_amount, paid_amount_change) {
var total_positive_outstanding_including_order = 0;
var total_negative_outstanding = 0;
var total_deductions = frappe.utils.sum(
$.map(frm.doc.deductions || [], function (d) {
return flt(d.amount);
})
);
paid_amount -= total_deductions;
$.each(frm.doc.references || [], function (i, row) {
if (flt(row.outstanding_amount) > 0)
total_positive_outstanding_including_order += flt(row.outstanding_amount);
else total_negative_outstanding += Math.abs(flt(row.outstanding_amount));
allocate_party_amount_against_ref_docs: async function (frm, paid_amount, paid_amount_change) {
await frm.call("allocate_amount_to_references", {
paid_amount: paid_amount,
paid_amount_change: paid_amount_change,
allocate_payment_amount: frappe.flags.allocate_payment_amount ?? false,
});
var allocated_negative_outstanding = 0;
if (
(frm.doc.payment_type == "Receive" && frm.doc.party_type == "Customer") ||
(frm.doc.payment_type == "Pay" && frm.doc.party_type == "Supplier") ||
(frm.doc.payment_type == "Pay" && frm.doc.party_type == "Employee")
) {
if (total_positive_outstanding_including_order > paid_amount) {
var remaining_outstanding = total_positive_outstanding_including_order - paid_amount;
allocated_negative_outstanding =
total_negative_outstanding < remaining_outstanding
? total_negative_outstanding
: remaining_outstanding;
}
var allocated_positive_outstanding = paid_amount + allocated_negative_outstanding;
} 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) {
frappe.msgprint(
__("Cannot {0} {1} {2} without any negative outstanding invoice", [
frm.doc.payment_type,
frm.doc.party_type == "Customer" ? "to" : "from",
frm.doc.party_type,
])
);
return false;
} else {
frappe.msgprint(
__("Paid Amount cannot be greater than total negative outstanding amount {0}", [
total_negative_outstanding,
])
);
return false;
}
} else {
allocated_positive_outstanding = total_negative_outstanding - paid_amount;
allocated_negative_outstanding =
paid_amount +
(total_positive_outstanding_including_order < allocated_positive_outstanding
? total_positive_outstanding_including_order
: allocated_positive_outstanding);
}
}
$.each(frm.doc.references || [], function (i, row) {
if (frappe.flags.allocate_payment_amount == 0) {
//If allocate payment amount checkbox is unchecked, set zero to allocate amount
row.allocated_amount = 0;
} else if (
frappe.flags.allocate_payment_amount != 0 &&
(!row.allocated_amount || paid_amount_change)
) {
if (row.outstanding_amount > 0 && allocated_positive_outstanding >= 0) {
row.allocated_amount =
row.outstanding_amount >= allocated_positive_outstanding
? allocated_positive_outstanding
: row.outstanding_amount;
allocated_positive_outstanding -= flt(row.allocated_amount);
} else if (row.outstanding_amount < 0 && allocated_negative_outstanding) {
row.allocated_amount =
Math.abs(row.outstanding_amount) >= allocated_negative_outstanding
? -1 * allocated_negative_outstanding
: row.outstanding_amount;
allocated_negative_outstanding -= Math.abs(flt(row.allocated_amount));
}
}
});
frm.refresh_fields();
frm.events.set_total_allocated_amount(frm);
},
@@ -1647,6 +1628,62 @@ frappe.ui.form.on("Payment Entry", {
return current_tax_amount;
},
cost_center: function (frm) {
if (frm.doc.posting_date && (frm.doc.paid_from || frm.doc.paid_to)) {
return frappe.call({
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_party_and_account_balance",
args: {
company: frm.doc.company,
date: frm.doc.posting_date,
paid_from: frm.doc.paid_from,
paid_to: frm.doc.paid_to,
ptype: frm.doc.party_type,
pty: frm.doc.party,
cost_center: frm.doc.cost_center,
},
callback: function (r, rt) {
if (r.message) {
frappe.run_serially([
() => {
frm.set_value(
"paid_from_account_balance",
r.message.paid_from_account_balance
);
frm.set_value("paid_to_account_balance", r.message.paid_to_account_balance);
frm.set_value("party_balance", r.message.party_balance);
},
]);
}
},
});
}
},
after_save: function (frm) {
const { matched_payment_requests } = frappe.last_response;
if (!matched_payment_requests) return;
const COLUMN_LABEL = [
[__("Reference DocType"), __("Reference Name"), __("Allocated Amount"), __("Payment Request")],
];
frappe.msgprint({
title: __("Unset Matched Payment Request"),
message: COLUMN_LABEL.concat(matched_payment_requests),
as_table: true,
wide: true,
primary_action: {
label: __("Allocate Payment Request"),
action() {
frappe.hide_msgprint();
frm.call("set_matched_payment_requests", { matched_payment_requests }, () => {
frm.dirty();
});
},
},
});
},
});
frappe.ui.form.on("Payment Entry Reference", {
@@ -1739,35 +1776,3 @@ frappe.ui.form.on("Payment Entry Deduction", {
frm.events.set_unallocated_amount(frm);
},
});
frappe.ui.form.on("Payment Entry", {
cost_center: function (frm) {
if (frm.doc.posting_date && (frm.doc.paid_from || frm.doc.paid_to)) {
return frappe.call({
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_party_and_account_balance",
args: {
company: frm.doc.company,
date: frm.doc.posting_date,
paid_from: frm.doc.paid_from,
paid_to: frm.doc.paid_to,
ptype: frm.doc.party_type,
pty: frm.doc.party,
cost_center: frm.doc.cost_center,
},
callback: function (r, rt) {
if (r.message) {
frappe.run_serially([
() => {
frm.set_value(
"paid_from_account_balance",
r.message.paid_from_account_balance
);
frm.set_value("paid_to_account_balance", r.message.paid_to_account_balance);
frm.set_value("party_balance", r.message.party_balance);
},
]);
}
},
});
}
},
});

View File

@@ -7,8 +7,10 @@ from functools import reduce
import frappe
from frappe import ValidationError, _, qb, scrub, throw
from frappe.query_builder import Tuple
from frappe.query_builder.functions import Count
from frappe.utils import cint, comma_or, flt, getdate, nowdate
from frappe.utils.data import comma_and, fmt_money
from frappe.utils.data import comma_and, fmt_money, get_link_to_form
from pypika import Case
from pypika.functions import Coalesce, Sum
@@ -37,7 +39,6 @@ from erpnext.accounts.utils import (
get_account_currency,
get_balance_on,
get_outstanding_invoices,
get_party_types_from_account_type,
)
from erpnext.controllers.accounts_controller import (
AccountsController,
@@ -99,13 +100,17 @@ class PaymentEntry(AccountsController):
self.set_status()
self.set_total_in_words()
def before_save(self):
self.set_matched_unset_payment_requests_to_response()
def on_submit(self):
if self.difference_amount:
frappe.throw(_("Difference Amount must be zero"))
self.make_gl_entries()
self.update_outstanding_amounts()
self.update_advance_paid()
self.update_payment_schedule()
self.update_payment_requests()
self.update_advance_paid() # advance_paid_status depends on the payment request amount
self.set_status()
def set_liability_account(self):
@@ -146,9 +151,21 @@ class PaymentEntry(AccountsController):
self.is_opening = "No"
return
liability_account = get_party_account(
self.party_type, self.party, self.company, include_advance=True
)[1]
accounts = get_party_account(self.party_type, self.party, self.company, include_advance=True)
liability_account = accounts[1] if len(accounts) > 1 else None
fieldname = (
"default_advance_received_account"
if self.party_type == "Customer"
else "default_advance_paid_account"
)
if not liability_account:
throw(
_("Please set default {0} in Company {1}").format(
frappe.bold(frappe.get_meta("Company").get_label(fieldname)), frappe.bold(self.company)
)
)
self.set(self.party_account_field, liability_account)
@@ -177,30 +194,34 @@ class PaymentEntry(AccountsController):
super().on_cancel()
self.make_gl_entries(cancel=1)
self.update_outstanding_amounts()
self.update_advance_paid()
self.delink_advance_entry_references()
self.update_payment_schedule(cancel=1)
self.set_payment_req_status()
self.update_payment_requests(cancel=True)
self.update_advance_paid() # advance_paid_status depends on the payment request amount
self.set_status()
def set_payment_req_status(self):
from erpnext.accounts.doctype.payment_request.payment_request import update_payment_req_status
def update_payment_requests(self, cancel=False):
from erpnext.accounts.doctype.payment_request.payment_request import (
update_payment_requests_as_per_pe_references,
)
update_payment_req_status(self, None)
update_payment_requests_as_per_pe_references(self.references, cancel=cancel)
def update_outstanding_amounts(self):
self.set_missing_ref_details(force=True)
def validate_duplicate_entry(self):
reference_names = []
reference_names = set()
for d in self.get("references"):
if (d.reference_doctype, d.reference_name, d.payment_term) in reference_names:
key = (d.reference_doctype, d.reference_name, d.payment_term, d.payment_request)
if key in reference_names:
frappe.throw(
_("Row #{0}: Duplicate entry in References {1} {2}").format(
d.idx, d.reference_doctype, d.reference_name
)
)
reference_names.append((d.reference_doctype, d.reference_name, d.payment_term))
reference_names.add(key)
def set_bank_account_data(self):
if self.bank_account:
@@ -226,6 +247,8 @@ class PaymentEntry(AccountsController):
if self.payment_type == "Internal Transfer":
return
self.validate_allocated_amount_as_per_payment_request()
if self.party_type in ("Customer", "Supplier"):
self.validate_allocated_amount_with_latest_data()
else:
@@ -238,6 +261,27 @@ class PaymentEntry(AccountsController):
if flt(d.allocated_amount) < 0 and flt(d.allocated_amount) < flt(d.outstanding_amount):
frappe.throw(fail_message.format(d.idx))
def validate_allocated_amount_as_per_payment_request(self):
"""
Allocated amount should not be greater than the outstanding amount of the Payment Request.
"""
if not self.references:
return
pr_outstanding_amounts = get_payment_request_outstanding_set_in_references(self.references)
if not pr_outstanding_amounts:
return
for ref in self.references:
if ref.payment_request and ref.allocated_amount > pr_outstanding_amounts[ref.payment_request]:
frappe.throw(
msg=_(
"Row #{0}: Allocated Amount cannot be greater than Outstanding Amount of Payment Request {1}"
).format(ref.idx, get_link_to_form("Payment Request", ref.payment_request)),
title=_("Invalid Allocated Amount"),
)
def term_based_allocation_enabled_for_reference(
self, reference_doctype: str, reference_name: str
) -> bool:
@@ -1119,90 +1163,103 @@ class PaymentEntry(AccountsController):
self.make_advance_gl_entries(cancel=cancel)
def add_party_gl_entries(self, gl_entries):
if self.party_account:
if self.payment_type == "Receive":
against_account = self.paid_to
else:
against_account = self.paid_from
if not self.party_account:
return
party_gl_dict = self.get_gl_dict(
advance_payment_doctypes = frappe.get_hooks("advance_payment_doctypes")
if self.payment_type == "Receive":
against_account = self.paid_to
else:
against_account = self.paid_from
party_account_type = frappe.db.get_value("Party Type", self.party_type, "account_type")
party_gl_dict = self.get_gl_dict(
{
"account": self.party_account,
"party_type": self.party_type,
"party": self.party,
"against": against_account,
"account_currency": self.party_account_currency,
"cost_center": self.cost_center,
},
item=self,
)
for d in self.get("references"):
# re-defining dr_or_cr for every reference in order to avoid the last value affecting calculation of reverse
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
cost_center = self.cost_center
if d.reference_doctype == "Sales Invoice" and not cost_center:
cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center")
gle = party_gl_dict.copy()
allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d)
if (
d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]
and d.allocated_amount < 0
and (
(party_account_type == "Receivable" and self.payment_type == "Pay")
or (party_account_type == "Payable" and self.payment_type == "Receive")
)
):
# reversing dr_cr because because it will get reversed in gl processing due to negative amount
dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
gle.update(
{
"account": self.party_account,
"party_type": self.party_type,
"party": self.party,
"against": against_account,
"account_currency": self.party_account_currency,
"cost_center": self.cost_center,
},
item=self,
dr_or_cr: allocated_amount_in_company_currency,
dr_or_cr + "_in_account_currency": d.allocated_amount,
"cost_center": cost_center,
}
)
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
for d in self.get("references"):
# re-defining dr_or_cr for every reference in order to avoid the last value affecting calculation of reverse
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
cost_center = self.cost_center
if d.reference_doctype == "Sales Invoice" and not cost_center:
cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center")
gle = party_gl_dict.copy()
allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d)
reverse_dr_or_cr = 0
if d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]:
is_return = frappe.db.get_value(d.reference_doctype, d.reference_name, "is_return")
payable_party_types = get_party_types_from_account_type("Payable")
receivable_party_types = get_party_types_from_account_type("Receivable")
if (
is_return
and self.party_type in receivable_party_types
and (self.payment_type == "Pay")
):
reverse_dr_or_cr = 1
elif (
is_return
and self.party_type in payable_party_types
and (self.payment_type == "Receive")
):
reverse_dr_or_cr = 1
if is_return and not reverse_dr_or_cr:
dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
gle.update(
{
dr_or_cr: abs(allocated_amount_in_company_currency),
dr_or_cr + "_in_account_currency": abs(d.allocated_amount),
"against_voucher_type": d.reference_doctype,
"against_voucher": d.reference_name,
"cost_center": cost_center,
}
)
gl_entries.append(gle)
if self.unallocated_amount:
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
exchange_rate = self.get_exchange_rate()
base_unallocated_amount = self.unallocated_amount * exchange_rate
gle = party_gl_dict.copy()
gle.update(
{
dr_or_cr + "_in_account_currency": self.unallocated_amount,
dr_or_cr: base_unallocated_amount,
}
)
if self.book_advance_payments_in_separate_party_account:
if self.book_advance_payments_in_separate_party_account:
if d.reference_doctype in advance_payment_doctypes:
# Upon reconciliation, whole ledger will be reposted. So, reference to SO/PO is fine
gle.update(
{
"against_voucher_type": "Payment Entry",
"against_voucher": self.name,
"against_voucher_type": d.reference_doctype,
"against_voucher": d.reference_name,
}
)
gl_entries.append(gle)
else:
# Do not reference Invoices while Advance is in separate party account
gle.update({"against_voucher_type": self.doctype, "against_voucher": self.name})
else:
gle.update(
{
"against_voucher_type": d.reference_doctype,
"against_voucher": d.reference_name,
}
)
gl_entries.append(gle)
if self.unallocated_amount:
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
exchange_rate = self.get_exchange_rate()
base_unallocated_amount = self.unallocated_amount * exchange_rate
gle = party_gl_dict.copy()
gle.update(
{
dr_or_cr + "_in_account_currency": self.unallocated_amount,
dr_or_cr: base_unallocated_amount,
}
)
if self.book_advance_payments_in_separate_party_account:
gle.update(
{
"against_voucher_type": "Payment Entry",
"against_voucher": self.name,
}
)
gl_entries.append(gle)
def make_advance_gl_entries(
self, entry: object | dict = None, cancel: bool = 0, update_outstanding: str = "Yes"
@@ -1603,6 +1660,380 @@ class PaymentEntry(AccountsController):
return current_tax_fraction
def set_matched_unset_payment_requests_to_response(self):
"""
Find matched Payment Requests for those references which have no Payment Request set.\n
And set to `frappe.response` to show in the frontend for allocation.
"""
if not self.references:
return
matched_payment_requests = get_matched_payment_request_of_references(
[row for row in self.references if not row.payment_request]
)
if not matched_payment_requests:
return
frappe.response["matched_payment_requests"] = matched_payment_requests
@frappe.whitelist()
def allocate_amount_to_references(self, paid_amount, paid_amount_change, allocate_payment_amount):
"""
Allocate `Allocated Amount` and `Payment Request` against `Reference` based on `Paid Amount` and `Outstanding Amount`.\n
:param paid_amount: Paid Amount / Received Amount.
:param paid_amount_change: Flag to check if `Paid Amount` is changed or not.
:param allocate_payment_amount: Flag to allocate amount or not. (Payment Request is also dependent on this flag)
"""
if not self.references:
return
if not allocate_payment_amount:
for ref in self.references:
ref.allocated_amount = 0
return
# calculating outstanding amounts
precision = self.precision("paid_amount")
total_positive_outstanding_including_order = 0
total_negative_outstanding = 0
paid_amount -= sum(flt(d.amount, precision) for d in self.deductions)
for ref in self.references:
reference_outstanding_amount = ref.outstanding_amount
abs_outstanding_amount = abs(reference_outstanding_amount)
if reference_outstanding_amount > 0:
total_positive_outstanding_including_order += abs_outstanding_amount
else:
total_negative_outstanding += abs_outstanding_amount
# calculating allocated outstanding amounts
allocated_negative_outstanding = 0
allocated_positive_outstanding = 0
# checking party type and payment type
if (self.payment_type == "Receive" and self.party_type == "Customer") or (
self.payment_type == "Pay" and self.party_type in ("Supplier", "Employee")
):
if total_positive_outstanding_including_order > paid_amount:
remaining_outstanding = flt(
total_positive_outstanding_including_order - paid_amount, precision
)
allocated_negative_outstanding = min(remaining_outstanding, total_negative_outstanding)
allocated_positive_outstanding = paid_amount + allocated_negative_outstanding
elif self.party_type in ("Supplier", "Employee"):
if paid_amount > total_negative_outstanding:
if total_negative_outstanding == 0:
frappe.msgprint(
_("Cannot {0} from {2} without any negative outstanding invoice").format(
self.payment_type,
self.party_type,
)
)
else:
frappe.msgprint(
_("Paid Amount cannot be greater than total negative outstanding amount {0}").format(
total_negative_outstanding
)
)
return
else:
allocated_positive_outstanding = flt(total_negative_outstanding - paid_amount, precision)
allocated_negative_outstanding = paid_amount + min(
total_positive_outstanding_including_order, allocated_positive_outstanding
)
# inner function to set `allocated_amount` to those row which have no PR
def _allocation_to_unset_pr_row(
row, outstanding_amount, allocated_positive_outstanding, allocated_negative_outstanding
):
if outstanding_amount > 0 and allocated_positive_outstanding >= 0:
row.allocated_amount = min(allocated_positive_outstanding, outstanding_amount)
allocated_positive_outstanding = flt(
allocated_positive_outstanding - row.allocated_amount, precision
)
elif outstanding_amount < 0 and allocated_negative_outstanding:
row.allocated_amount = min(allocated_negative_outstanding, abs(outstanding_amount)) * -1
allocated_negative_outstanding = flt(
allocated_negative_outstanding - abs(row.allocated_amount), precision
)
return allocated_positive_outstanding, allocated_negative_outstanding
# allocate amount based on `paid_amount` is changed or not
if not paid_amount_change:
for ref in self.references:
allocated_positive_outstanding, allocated_negative_outstanding = _allocation_to_unset_pr_row(
ref,
ref.outstanding_amount,
allocated_positive_outstanding,
allocated_negative_outstanding,
)
allocate_open_payment_requests_to_references(self.references, self.precision("paid_amount"))
else:
payment_request_outstanding_amounts = (
get_payment_request_outstanding_set_in_references(self.references) or {}
)
references_outstanding_amounts = get_references_outstanding_amount(self.references) or {}
remaining_references_allocated_amounts = references_outstanding_amounts.copy()
# Re allocate amount to those references which have PR set (Higher priority)
for ref in self.references:
if not ref.payment_request:
continue
# fetch outstanding_amount of `Reference` (Payment Term) and `Payment Request` to allocate new amount
key = (ref.reference_doctype, ref.reference_name, ref.get("payment_term"))
reference_outstanding_amount = references_outstanding_amounts[key]
pr_outstanding_amount = payment_request_outstanding_amounts[ref.payment_request]
if reference_outstanding_amount > 0 and allocated_positive_outstanding >= 0:
# allocate amount according to outstanding amounts
outstanding_amounts = (
allocated_positive_outstanding,
reference_outstanding_amount,
pr_outstanding_amount,
)
ref.allocated_amount = min(outstanding_amounts)
# update amounts to track allocation
allocated_amount = ref.allocated_amount
allocated_positive_outstanding = flt(
allocated_positive_outstanding - allocated_amount, precision
)
remaining_references_allocated_amounts[key] = flt(
remaining_references_allocated_amounts[key] - allocated_amount, precision
)
payment_request_outstanding_amounts[ref.payment_request] = flt(
payment_request_outstanding_amounts[ref.payment_request] - allocated_amount, precision
)
elif reference_outstanding_amount < 0 and allocated_negative_outstanding:
# allocate amount according to outstanding amounts
outstanding_amounts = (
allocated_negative_outstanding,
abs(reference_outstanding_amount),
pr_outstanding_amount,
)
ref.allocated_amount = min(outstanding_amounts) * -1
# update amounts to track allocation
allocated_amount = abs(ref.allocated_amount)
allocated_negative_outstanding = flt(
allocated_negative_outstanding - allocated_amount, precision
)
remaining_references_allocated_amounts[key] += allocated_amount # negative amount
payment_request_outstanding_amounts[ref.payment_request] = flt(
payment_request_outstanding_amounts[ref.payment_request] - allocated_amount, precision
)
# Re allocate amount to those references which have no PR (Lower priority)
for ref in self.references:
if ref.payment_request:
continue
key = (ref.reference_doctype, ref.reference_name, ref.get("payment_term"))
reference_outstanding_amount = remaining_references_allocated_amounts[key]
allocated_positive_outstanding, allocated_negative_outstanding = _allocation_to_unset_pr_row(
ref,
reference_outstanding_amount,
allocated_positive_outstanding,
allocated_negative_outstanding,
)
@frappe.whitelist()
def set_matched_payment_requests(self, matched_payment_requests):
"""
Set `Payment Request` against `Reference` based on `matched_payment_requests`.\n
:param matched_payment_requests: List of tuple of matched Payment Requests.
---
Example: [(reference_doctype, reference_name, allocated_amount, payment_request), ...]
"""
if not self.references or not matched_payment_requests:
return
if isinstance(matched_payment_requests, str):
matched_payment_requests = json.loads(matched_payment_requests)
# modify matched_payment_requests
# like (reference_doctype, reference_name, allocated_amount): payment_request
payment_requests = {}
for row in matched_payment_requests:
key = tuple(row[:3])
payment_requests[key] = row[3]
for ref in self.references:
if ref.payment_request:
continue
key = (ref.reference_doctype, ref.reference_name, ref.allocated_amount)
if key in payment_requests:
ref.payment_request = payment_requests[key]
del payment_requests[key] # to avoid duplicate allocation
def get_matched_payment_request_of_references(references=None):
"""
Get those `Payment Requests` which are matched with `References`.\n
- Amount must be same.
- Only single `Payment Request` available for this amount.
Example: [(reference_doctype, reference_name, allocated_amount, payment_request), ...]
"""
if not references:
return
# to fetch matched rows
refs = {
(row.reference_doctype, row.reference_name, row.allocated_amount)
for row in references
if row.reference_doctype and row.reference_name and row.allocated_amount
}
if not refs:
return
PR = frappe.qb.DocType("Payment Request")
# query to group by reference_doctype, reference_name, outstanding_amount
subquery = (
frappe.qb.from_(PR)
.select(
PR.reference_doctype,
PR.reference_name,
PR.outstanding_amount.as_("allocated_amount"),
PR.name.as_("payment_request"),
Count("*").as_("count"),
)
.where(Tuple(PR.reference_doctype, PR.reference_name, PR.outstanding_amount).isin(refs))
.where(PR.status != "Paid")
.where(PR.docstatus == 1)
.groupby(PR.reference_doctype, PR.reference_name, PR.outstanding_amount)
)
# query to fetch matched rows which are single
matched_prs = (
frappe.qb.from_(subquery)
.select(
subquery.reference_doctype,
subquery.reference_name,
subquery.allocated_amount,
subquery.payment_request,
)
.where(subquery.count == 1)
.run()
)
return matched_prs if matched_prs else None
def get_references_outstanding_amount(references=None):
"""
Fetch accurate outstanding amount of `References`.\n
- If `Payment Term` is set, then fetch outstanding amount from `Payment Schedule`.
- If `Payment Term` is not set, then fetch outstanding amount from `References` it self.
Example: {(reference_doctype, reference_name, payment_term): outstanding_amount, ...}
"""
if not references:
return
refs_with_payment_term = get_outstanding_of_references_with_payment_term(references) or {}
refs_without_payment_term = get_outstanding_of_references_with_no_payment_term(references) or {}
return {**refs_with_payment_term, **refs_without_payment_term}
def get_outstanding_of_references_with_payment_term(references=None):
"""
Fetch outstanding amount of `References` which have `Payment Term` set.\n
Example: {(reference_doctype, reference_name, payment_term): outstanding_amount, ...}
"""
if not references:
return
refs = {
(row.reference_doctype, row.reference_name, row.payment_term)
for row in references
if row.reference_doctype and row.reference_name and row.payment_term
}
if not refs:
return
PS = frappe.qb.DocType("Payment Schedule")
response = (
frappe.qb.from_(PS)
.select(PS.parenttype, PS.parent, PS.payment_term, PS.outstanding)
.where(Tuple(PS.parenttype, PS.parent, PS.payment_term).isin(refs))
).run(as_dict=True)
if not response:
return
return {(row.parenttype, row.parent, row.payment_term): row.outstanding for row in response}
def get_outstanding_of_references_with_no_payment_term(references):
"""
Fetch outstanding amount of `References` which have no `Payment Term` set.\n
- Fetch outstanding amount from `References` it self.
Note: `None` is used for allocation of `Payment Request`
Example: {(reference_doctype, reference_name, None): outstanding_amount, ...}
"""
if not references:
return
outstanding_amounts = {}
for ref in references:
if ref.payment_term:
continue
key = (ref.reference_doctype, ref.reference_name, None)
if key not in outstanding_amounts:
outstanding_amounts[key] = ref.outstanding_amount
return outstanding_amounts
def get_payment_request_outstanding_set_in_references(references=None):
"""
Fetch outstanding amount of `Payment Request` which are set in `References`.\n
Example: {payment_request: outstanding_amount, ...}
"""
if not references:
return
referenced_payment_requests = {row.payment_request for row in references if row.payment_request}
if not referenced_payment_requests:
return
PR = frappe.qb.DocType("Payment Request")
response = (
frappe.qb.from_(PR)
.select(PR.name, PR.outstanding_amount)
.where(PR.name.isin(referenced_payment_requests))
).run()
return dict(response) if response else None
def validate_inclusive_tax(tax, doc):
def _on_previous_row_error(row_range):
@@ -1749,7 +2180,7 @@ def get_outstanding_reference_documents(args, validate=False):
d["bill_no"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "bill_no")
# Get negative outstanding sales /purchase invoices
if args.get("party_type") != "Employee" and not args.get("voucher_no"):
if args.get("party_type") != "Employee":
negative_outstanding_invoices = get_negative_outstanding_invoices(
args.get("party_type"),
args.get("party"),
@@ -2233,6 +2664,8 @@ def get_payment_entry(
party_type=None,
payment_type=None,
reference_date=None,
ignore_permissions=False,
created_from_payment_request=False,
):
doc = frappe.get_doc(dt, dn)
over_billing_allowance = frappe.db.get_single_value("Accounts Settings", "over_billing_allowance")
@@ -2382,9 +2815,179 @@ def get_payment_entry(
pe.set_difference_amount()
# If PE is created from PR directly, then no need to find open PRs for the references
if not created_from_payment_request:
allocate_open_payment_requests_to_references(pe.references, pe.precision("paid_amount"))
return pe
def get_open_payment_requests_for_references(references=None):
"""
Fetch all unpaid Payment Requests for the references. \n
- Each reference can have multiple Payment Requests. \n
Example: {("Sales Invoice", "SINV-00001"): {"PREQ-00001": 1000, "PREQ-00002": 2000}}
"""
if not references:
return
refs = {
(row.reference_doctype, row.reference_name)
for row in references
if row.reference_doctype and row.reference_name and row.allocated_amount
}
if not refs:
return
PR = frappe.qb.DocType("Payment Request")
response = (
frappe.qb.from_(PR)
.select(PR.name, PR.reference_doctype, PR.reference_name, PR.outstanding_amount)
.where(Tuple(PR.reference_doctype, PR.reference_name).isin(list(refs)))
.where(PR.status != "Paid")
.where(PR.docstatus == 1)
.orderby(Coalesce(PR.transaction_date, PR.creation), order=frappe.qb.asc)
).run(as_dict=True)
if not response:
return
reference_payment_requests = {}
for row in response:
key = (row.reference_doctype, row.reference_name)
if key not in reference_payment_requests:
reference_payment_requests[key] = {row.name: row.outstanding_amount}
else:
reference_payment_requests[key][row.name] = row.outstanding_amount
return reference_payment_requests
def allocate_open_payment_requests_to_references(references=None, precision=None):
"""
Allocate unpaid Payment Requests to the references. \n
---
- Allocation based on below factors
- Reference Allocated Amount
- Reference Outstanding Amount (With Payment Terms or without Payment Terms)
- Reference Payment Request's outstanding amount
---
- Allocation based on below scenarios
- Reference's Allocated Amount == Payment Request's Outstanding Amount
- Allocate the Payment Request to the reference
- This PR will not be allocated further
- Reference's Allocated Amount < Payment Request's Outstanding Amount
- Allocate the Payment Request to the reference
- Reduce the PR's outstanding amount by the allocated amount
- This PR can be allocated further
- Reference's Allocated Amount > Payment Request's Outstanding Amount
- Allocate the Payment Request to the reference
- Reduce Allocated Amount of the reference by the PR's outstanding amount
- Create a new row for the remaining amount until the Allocated Amount is 0
- Allocate PR if available
---
- Note:
- Priority is given to the first Payment Request of respective references.
- Single Reference can have multiple rows.
- With Payment Terms or without Payment Terms
- With Payment Request or without Payment Request
"""
if not references:
return
# get all unpaid payment requests for the references
references_open_payment_requests = get_open_payment_requests_for_references(references)
if not references_open_payment_requests:
return
if not precision:
precision = references[0].precision("allocated_amount")
# to manage new rows
row_number = 1
MOVE_TO_NEXT_ROW = 1
TO_SKIP_NEW_ROW = 2
while row_number <= len(references):
row = references[row_number - 1]
reference_key = (row.reference_doctype, row.reference_name)
# update the idx to maintain the order
row.idx = row_number
# unpaid payment requests for the reference
reference_payment_requests = references_open_payment_requests.get(reference_key)
if not reference_payment_requests:
row_number += MOVE_TO_NEXT_ROW # to move to next reference row
continue
# get the first payment request and its outstanding amount
payment_request, pr_outstanding_amount = next(iter(reference_payment_requests.items()))
allocated_amount = row.allocated_amount
# allocate the payment request to the reference and PR's outstanding amount
row.payment_request = payment_request
if pr_outstanding_amount == allocated_amount:
del reference_payment_requests[payment_request]
row_number += MOVE_TO_NEXT_ROW
elif pr_outstanding_amount > allocated_amount:
# reduce the outstanding amount of the payment request
reference_payment_requests[payment_request] -= allocated_amount
row_number += MOVE_TO_NEXT_ROW
else:
# split the reference row to allocate the remaining amount
del reference_payment_requests[payment_request]
row.allocated_amount = pr_outstanding_amount
allocated_amount = flt(allocated_amount - pr_outstanding_amount, precision)
# set the remaining amount to the next row
while allocated_amount:
# create a new row for the remaining amount
new_row = frappe.copy_doc(row)
references.insert(row_number, new_row)
# get the first payment request and its outstanding amount
payment_request, pr_outstanding_amount = next(
iter(reference_payment_requests.items()), (None, None)
)
# update new row
new_row.idx = row_number + 1
new_row.payment_request = payment_request
new_row.allocated_amount = min(
pr_outstanding_amount if pr_outstanding_amount else allocated_amount, allocated_amount
)
if not payment_request or not pr_outstanding_amount:
row_number += TO_SKIP_NEW_ROW
break
elif pr_outstanding_amount == allocated_amount:
del reference_payment_requests[payment_request]
row_number += TO_SKIP_NEW_ROW
break
elif pr_outstanding_amount > allocated_amount:
reference_payment_requests[payment_request] -= allocated_amount
row_number += TO_SKIP_NEW_ROW
break
else:
allocated_amount = flt(allocated_amount - pr_outstanding_amount, precision)
del reference_payment_requests[payment_request]
row_number += MOVE_TO_NEXT_ROW
def update_accounting_dimensions(pe, doc):
"""
Updates accounting dimensions in Payment Entry based on the accounting dimensions in the reference document

View File

@@ -1791,6 +1791,79 @@ class TestPaymentEntry(FrappeTestCase):
# 'Is Opening' should always be 'No' for normal advance payments
self.assertEqual(gl_with_opening_set, [])
@change_settings("Accounts Settings", {"delete_linked_ledger_entries": 1})
def test_delete_linked_exchange_gain_loss_journal(self):
from erpnext.accounts.doctype.account.test_account import create_account
from erpnext.accounts.doctype.opening_invoice_creation_tool.test_opening_invoice_creation_tool import (
make_customer,
)
debtors = create_account(
account_name="Debtors USD",
parent_account="Accounts Receivable - _TC",
company="_Test Company",
account_currency="USD",
account_type="Receivable",
)
# create a customer
customer = make_customer(customer="_Test Party USD")
cust_doc = frappe.get_doc("Customer", customer)
cust_doc.default_currency = "USD"
test_account_details = {
"company": "_Test Company",
"account": debtors,
}
cust_doc.append("accounts", test_account_details)
cust_doc.save()
# create a sales invoice
si = create_sales_invoice(
customer=customer,
currency="USD",
conversion_rate=83.970000000,
debit_to=debtors,
do_not_save=1,
)
si.party_account_currency = "USD"
si.save()
si.submit()
# create a payment entry for the invoice
pe = get_payment_entry("Sales Invoice", si.name)
pe.reference_no = "1"
pe.reference_date = frappe.utils.nowdate()
pe.paid_amount = 100
pe.source_exchange_rate = 90
pe.append(
"deductions",
{
"account": "_Test Exchange Gain/Loss - _TC",
"cost_center": "_Test Cost Center - _TC",
"amount": 2710,
},
)
pe.save()
pe.submit()
# check creation of journal entry
jv = frappe.get_all(
"Journal Entry Account",
{"reference_type": pe.doctype, "reference_name": pe.name, "docstatus": 1},
pluck="parent",
)
self.assertTrue(jv)
# check cancellation of payment entry and journal entry
pe.cancel()
self.assertTrue(pe.docstatus == 2)
self.assertTrue(frappe.db.get_value("Journal Entry", {"name": jv[0]}, "docstatus") == 2)
# check deletion of payment entry and journal entry
pe.delete()
self.assertRaises(frappe.DoesNotExistError, frappe.get_doc, pe.doctype, pe.name)
self.assertRaises(frappe.DoesNotExistError, frappe.get_doc, "Journal Entry", jv[0])
def create_payment_entry(**args):
payment_entry = frappe.new_doc("Payment Entry")

View File

@@ -10,6 +10,7 @@
"due_date",
"bill_no",
"payment_term",
"payment_term_outstanding",
"account_type",
"payment_type",
"column_break_4",
@@ -18,7 +19,9 @@
"allocated_amount",
"exchange_rate",
"exchange_gain_loss",
"account"
"account",
"payment_request",
"payment_request_outstanding"
],
"fields": [
{
@@ -120,12 +123,33 @@
"fieldname": "payment_type",
"fieldtype": "Data",
"label": "Payment Type"
},
{
"fieldname": "payment_request",
"fieldtype": "Link",
"label": "Payment Request",
"options": "Payment Request"
},
{
"depends_on": "eval: doc.payment_term",
"fieldname": "payment_term_outstanding",
"fieldtype": "Float",
"label": "Payment Term Outstanding",
"read_only": 1
},
{
"depends_on": "eval: doc.payment_request && doc.payment_request_outstanding",
"fieldname": "payment_request_outstanding",
"fieldtype": "Float",
"is_virtual": 1,
"label": "Payment Request Outstanding",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-04-05 09:44:08.310593",
"modified": "2024-09-16 18:11:50.019343",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry Reference",

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe.model.document import Document
@@ -25,11 +25,19 @@ class PaymentEntryReference(Document):
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
payment_request: DF.Link | None
payment_request_outstanding: DF.Float
payment_term: DF.Link | None
payment_term_outstanding: DF.Float
payment_type: DF.Data | None
reference_doctype: DF.Link
reference_name: DF.DynamicLink
total_amount: DF.Float
# end: auto-generated types
pass
@property
def payment_request_outstanding(self):
if not self.payment_request:
return
return frappe.db.get_value("Payment Request", self.payment_request, "outstanding_amount")

View File

@@ -5,7 +5,7 @@
import frappe
from frappe import qb
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, flt, nowdate
from frappe.utils import add_days, add_years, flt, getdate, nowdate, today
from erpnext import get_default_cost_center
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
@@ -13,6 +13,7 @@ from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_pay
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.utils import get_fiscal_year
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
from erpnext.stock.doctype.item.test_item import create_item
@@ -1845,6 +1846,78 @@ class TestPaymentReconciliation(FrappeTestCase):
self.assertEqual(len(pr.invoices), 1)
self.assertEqual(len(pr.payments), 1)
def test_reconciliation_on_closed_period_payment(self):
# create backdated fiscal year
first_fy_start_date = frappe.db.get_value("Fiscal Year", {"disabled": 0}, "min(year_start_date)")
prev_fy_start_date = add_years(first_fy_start_date, -1)
prev_fy_end_date = add_days(first_fy_start_date, -1)
create_fiscal_year(
company=self.company, year_start_date=prev_fy_start_date, year_end_date=prev_fy_end_date
)
# make journal entry for previous year
je_1 = frappe.new_doc("Journal Entry")
je_1.posting_date = add_days(prev_fy_start_date, 20)
je_1.company = self.company
je_1.user_remark = "test"
je_1.set(
"accounts",
[
{
"account": self.debit_to,
"cost_center": self.cost_center,
"party_type": "Customer",
"party": self.customer,
"debit_in_account_currency": 0,
"credit_in_account_currency": 1000,
},
{
"account": self.bank,
"cost_center": self.sub_cc.name,
"credit_in_account_currency": 0,
"debit_in_account_currency": 500,
},
{
"account": self.cash,
"cost_center": self.sub_cc.name,
"credit_in_account_currency": 0,
"debit_in_account_currency": 500,
},
],
)
je_1.submit()
# make period closing voucher
pcv = make_period_closing_voucher(
company=self.company, cost_center=self.cost_center, posting_date=prev_fy_end_date
)
pcv.reload()
# check if period closing voucher is completed
self.assertEqual(pcv.gle_processing_status, "Completed")
# make journal entry for active year
je_2 = self.create_journal_entry(
acc1=self.debit_to, acc2=self.income_account, amount=1000, posting_date=today()
)
je_2.accounts[0].party_type = "Customer"
je_2.accounts[0].party = self.customer
je_2.submit()
# process reconciliation on closed period payment
pr = self.create_payment_reconciliation(party_is_customer=True)
pr.from_invoice_date = pr.to_invoice_date = pr.from_payment_date = pr.to_payment_date = None
pr.get_unreconciled_entries()
invoices = [invoice.as_dict() for invoice in pr.invoices]
payments = [payment.as_dict() for payment in pr.payments]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
pr.reconcile()
je_1.reload()
je_2.reload()
# check whether the payment reconciliation is done on the closed period
self.assertEqual(pr.get("invoices"), [])
self.assertEqual(pr.get("payments"), [])
def make_customer(customer_name, currency=None):
if not frappe.db.exists("Customer", customer_name):
@@ -1872,3 +1945,61 @@ def make_supplier(supplier_name, currency=None):
return supplier.name
else:
return supplier_name
def create_fiscal_year(company, year_start_date, year_end_date):
fy_docname = frappe.db.exists(
"Fiscal Year", {"year_start_date": year_start_date, "year_end_date": year_end_date}
)
if not fy_docname:
fy_doc = frappe.get_doc(
{
"doctype": "Fiscal Year",
"year": f"{getdate(year_start_date).year}-{getdate(year_end_date).year}",
"year_start_date": year_start_date,
"year_end_date": year_end_date,
"companies": [{"company": company}],
}
).save()
return fy_doc
else:
fy_doc = frappe.get_doc("Fiscal Year", fy_docname)
if not frappe.db.exists("Fiscal Year Company", {"parent": fy_docname, "company": company}):
fy_doc.append("companies", {"company": company})
fy_doc.save()
return fy_doc
def make_period_closing_voucher(company, cost_center, posting_date=None, submit=True):
from erpnext.accounts.doctype.account.test_account import create_account
parent_account = frappe.db.get_value(
"Account", {"company": company, "account_name": "Current Liabilities", "is_group": 1}, "name"
)
surplus_account = create_account(
account_name="Reserve and Surplus",
is_group=0,
company=company,
root_type="Liability",
report_type="Balance Sheet",
account_currency="INR",
parent_account=parent_account,
doctype="Account",
)
pcv = frappe.get_doc(
{
"doctype": "Period Closing Voucher",
"transaction_date": posting_date or today(),
"posting_date": posting_date or today(),
"company": company,
"fiscal_year": get_fiscal_year(posting_date or today(), company=company)[0],
"cost_center": cost_center,
"closing_account_head": surplus_account,
"remarks": "test",
}
)
pcv.insert()
if submit:
pcv.submit()
return pcv

View File

@@ -48,8 +48,8 @@ frappe.ui.form.on("Payment Request", "refresh", function (frm) {
}
if (
(!frm.doc.payment_gateway_account || frm.doc.payment_request_type == "Outward") &&
frm.doc.status == "Initiated"
frm.doc.payment_request_type == "Outward" &&
["Initiated", "Partially Paid"].includes(frm.doc.status)
) {
frm.add_custom_button(__("Create Payment Entry"), function () {
frappe.call({

View File

@@ -9,6 +9,7 @@
"transaction_date",
"column_break_2",
"naming_series",
"company",
"mode_of_payment",
"party_details",
"party_type",
@@ -18,9 +19,11 @@
"reference_name",
"transaction_details",
"grand_total",
"currency",
"is_a_subscription",
"column_break_18",
"currency",
"outstanding_amount",
"party_account_currency",
"subscription_section",
"subscription_plans",
"bank_account_details",
@@ -68,6 +71,7 @@
{
"fieldname": "transaction_date",
"fieldtype": "Date",
"in_preview": 1,
"label": "Transaction Date"
},
{
@@ -132,7 +136,8 @@
"no_copy": 1,
"options": "reference_doctype",
"print_hide": 1,
"read_only": 1
"read_only": 1,
"search_index": 1
},
{
"fieldname": "transaction_details",
@@ -140,12 +145,14 @@
"label": "Transaction Details"
},
{
"description": "Amount in customer's currency",
"description": "Amount in transaction currency",
"fieldname": "grand_total",
"fieldtype": "Currency",
"in_preview": 1,
"label": "Amount",
"non_negative": 1,
"options": "currency"
"options": "currency",
"reqd": 1
},
{
"default": "0",
@@ -390,13 +397,38 @@
"options": "Payment Request",
"print_hide": 1,
"read_only": 1
},
{
"depends_on": "eval: doc.docstatus === 1",
"description": "Amount in party's bank account currency",
"fieldname": "outstanding_amount",
"fieldtype": "Currency",
"in_preview": 1,
"label": "Outstanding Amount",
"non_negative": 1,
"options": "party_account_currency",
"read_only": 1
},
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company",
"read_only": 1
},
{
"fieldname": "party_account_currency",
"fieldtype": "Link",
"label": "Party Account Currency",
"options": "Currency",
"read_only": 1
}
],
"in_create": 1,
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2024-06-20 13:54:55.245774",
"modified": "2024-09-16 17:50:54.440090",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Request",
@@ -431,6 +463,7 @@
"write": 1
}
],
"show_preview_popup": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": []

View File

@@ -3,9 +3,11 @@ import json
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.query_builder.functions import Sum
from frappe.utils import flt, nowdate
from frappe.utils.background_jobs import enqueue
from erpnext import get_company_currency
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_accounting_dimensions,
)
@@ -15,7 +17,7 @@ from erpnext.accounts.doctype.payment_entry.payment_entry import (
)
from erpnext.accounts.doctype.subscription_plan.subscription_plan import get_plan_rate
from erpnext.accounts.party import get_party_account, get_party_bank_account
from erpnext.accounts.utils import get_account_currency
from erpnext.accounts.utils import get_account_currency, get_currency_precision
from erpnext.utilities import payment_app_import_guard
@@ -45,6 +47,7 @@ class PaymentRequest(Document):
bank_account: DF.Link | None
bank_account_no: DF.ReadOnly | None
branch_code: DF.ReadOnly | None
company: DF.Link | None
cost_center: DF.Link | None
currency: DF.Link | None
email_to: DF.Data | None
@@ -56,16 +59,18 @@ class PaymentRequest(Document):
mode_of_payment: DF.Link | None
mute_email: DF.Check
naming_series: DF.Literal["ACC-PRQ-.YYYY.-"]
outstanding_amount: DF.Currency
party: DF.DynamicLink | None
party_account_currency: DF.Link | None
party_type: DF.Link | None
payment_account: DF.ReadOnly | None
payment_channel: DF.Literal["", "Email", "Phone"]
payment_channel: DF.Literal["", "Email", "Phone", "Other"]
payment_gateway: DF.ReadOnly | None
payment_gateway_account: DF.Link | None
payment_order: DF.Link | None
payment_request_type: DF.Literal["Outward", "Inward"]
payment_url: DF.Data | None
print_format: DF.Literal
print_format: DF.Literal[None]
project: DF.Link | None
reference_doctype: DF.Link | None
reference_name: DF.DynamicLink | None
@@ -99,6 +104,12 @@ class PaymentRequest(Document):
frappe.throw(_("To create a Payment Request reference document is required"))
def validate_payment_request_amount(self):
if self.grand_total == 0:
frappe.throw(
_("{0} cannot be zero").format(self.get_label_from_fieldname("grand_total")),
title=_("Invalid Amount"),
)
existing_payment_request_amount = flt(
get_existing_payment_request_amount(self.reference_doctype, self.reference_name)
)
@@ -146,6 +157,28 @@ class PaymentRequest(Document):
).format(self.grand_total, amount)
)
def before_submit(self):
if (
self.currency != self.party_account_currency
and self.party_account_currency == get_company_currency(self.company)
):
# set outstanding amount in party account currency
invoice = frappe.get_value(
self.reference_doctype,
self.reference_name,
["rounded_total", "grand_total", "base_rounded_total", "base_grand_total"],
as_dict=1,
)
grand_total = invoice.get("rounded_total") or invoice.get("grand_total")
base_grand_total = invoice.get("base_rounded_total") or invoice.get("base_grand_total")
self.outstanding_amount = flt(
self.grand_total / grand_total * base_grand_total,
self.precision("outstanding_amount"),
)
else:
self.outstanding_amount = self.grand_total
def on_submit(self):
if self.payment_request_type == "Outward":
self.db_set("status", "Initiated")
@@ -274,7 +307,7 @@ class PaymentRequest(Document):
def set_as_paid(self):
if self.payment_channel == "Phone":
self.db_set("status", "Paid")
self.db_set({"status": "Paid", "outstanding_amount": 0})
else:
payment_entry = self.create_payment_entry()
@@ -295,26 +328,32 @@ 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 = (
self.get("party_account_currency")
or ref_doc.get("party_account_currency")
or get_account_currency(party_account)
)
party_amount = bank_amount = self.outstanding_amount
bank_amount = self.grand_total
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
exchange_rate = ref_doc.get("conversion_rate")
bank_amount = flt(self.outstanding_amount / exchange_rate, self.precision("grand_total"))
# outstanding amount is already in Part's account currency
payment_entry = get_payment_entry(
self.reference_doctype,
self.reference_name,
party_amount=party_amount,
bank_account=self.payment_account,
bank_amount=bank_amount,
created_from_payment_request=True,
)
payment_entry.update(
{
"mode_of_payment": self.mode_of_payment,
"reference_no": self.name,
"reference_no": self.name, # to prevent validation error
"reference_date": nowdate(),
"remarks": "Payment Entry against {} {} via Payment Request {}".format(
self.reference_doctype, self.reference_name, self.name
@@ -322,6 +361,9 @@ class PaymentRequest(Document):
}
)
# Allocate payment_request for each reference in payment_entry (Payment Term can splits the row)
self._allocate_payment_request_to_pe_references(references=payment_entry.references)
# Update dimensions
payment_entry.update(
{
@@ -330,13 +372,16 @@ 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)})
@@ -417,6 +462,62 @@ class PaymentRequest(Document):
return create_stripe_subscription(gateway_controller, data)
def _allocate_payment_request_to_pe_references(self, references):
"""
Allocate the Payment Request to the Payment Entry references based on\n
- Allocated Amount.
- Outstanding Amount of Payment Request.\n
Payment Request is doc itself and references are the rows of Payment Entry.
"""
if len(references) == 1:
references[0].payment_request = self.name
return
precision = references[0].precision("allocated_amount")
outstanding_amount = self.outstanding_amount
# to manage rows
row_number = 1
MOVE_TO_NEXT_ROW = 1
TO_SKIP_NEW_ROW = 2
NEW_ROW_ADDED = False
while row_number <= len(references):
row = references[row_number - 1]
# update the idx to maintain the order
row.idx = row_number
if outstanding_amount == 0:
if not NEW_ROW_ADDED:
break
row_number += MOVE_TO_NEXT_ROW
continue
# allocate the payment request to the row
row.payment_request = self.name
if row.allocated_amount <= outstanding_amount:
outstanding_amount = flt(outstanding_amount - row.allocated_amount, precision)
row_number += MOVE_TO_NEXT_ROW
else:
remaining_allocated_amount = flt(row.allocated_amount - outstanding_amount, precision)
row.allocated_amount = outstanding_amount
outstanding_amount = 0
# create a new row without PR for remaining unallocated amount
new_row = frappe.copy_doc(row)
references.insert(row_number, new_row)
# update new row
new_row.idx = row_number + 1
new_row.payment_request = None
new_row.allocated_amount = remaining_allocated_amount
NEW_ROW_ADDED = True
row_number += TO_SKIP_NEW_ROW
@frappe.whitelist(allow_guest=True)
def make_payment_request(**args):
@@ -447,11 +548,15 @@ def make_payment_request(**args):
{"reference_doctype": args.dt, "reference_name": args.dn, "docstatus": 0},
)
existing_payment_request_amount = get_existing_payment_request_amount(args.dt, args.dn)
# fetches existing payment request `grand_total` amount
existing_payment_request_amount = get_existing_payment_request_amount(ref_doc.doctype, ref_doc.name)
if existing_payment_request_amount:
grand_total -= existing_payment_request_amount
if not grand_total:
frappe.throw(_("Payment Request is already created"))
if draft_payment_request:
frappe.db.set_value(
"Payment Request", draft_payment_request, "grand_total", grand_total, update_modified=False
@@ -465,6 +570,13 @@ def make_payment_request(**args):
"Outward" if args.get("dt") in ["Purchase Order", "Purchase Invoice"] else "Inward"
)
party_type = args.get("party_type") or "Customer"
party_account_currency = ref_doc.get("party_account_currency")
if not party_account_currency:
party_account = get_party_account(party_type, ref_doc.get(party_type.lower()), ref_doc.company)
party_account_currency = get_account_currency(party_account)
pr.update(
{
"payment_gateway_account": gateway_account.get("name"),
@@ -473,6 +585,7 @@ def make_payment_request(**args):
"payment_channel": gateway_account.get("payment_channel"),
"payment_request_type": args.get("payment_request_type"),
"currency": ref_doc.currency,
"party_account_currency": party_account_currency,
"grand_total": grand_total,
"mode_of_payment": args.mode_of_payment,
"email_to": args.recipient_id or ref_doc.owner,
@@ -480,7 +593,8 @@ def make_payment_request(**args):
"message": gateway_account.get("message") or get_dummy_message(ref_doc),
"reference_doctype": args.dt,
"reference_name": args.dn,
"party_type": args.get("party_type") or "Customer",
"company": ref_doc.get("company"),
"party_type": party_type,
"party": args.get("party") or ref_doc.get("customer"),
"bank_account": bank_account,
}
@@ -503,6 +617,8 @@ def make_payment_request(**args):
if frappe.db.get_single_value("Accounts Settings", "create_pr_in_draft_status", cache=True):
pr.insert(ignore_permissions=True)
if args.submit_doc:
if pr.get("__unsaved"):
pr.insert(ignore_permissions=True)
pr.submit()
if args.order_type == "Shopping Cart":
@@ -524,9 +640,11 @@ 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.grand_total)
grand_total = flt(ref_doc.rounded_total or ref_doc.grand_total)
else:
grand_total = flt(ref_doc.base_grand_total) / ref_doc.conversion_rate
grand_total = flt(
flt(ref_doc.base_rounded_total or 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:
@@ -541,31 +659,27 @@ def get_amount(ref_doc, payment_account=None):
grand_total = ref_doc.outstanding_amount
if grand_total > 0:
return grand_total
return flt(grand_total, get_currency_precision())
else:
frappe.throw(_("Payment Entry is already created"))
def get_existing_payment_request_amount(ref_dt, ref_dn):
"""
Get the existing payment request which are unpaid or partially paid for payment channel other than Phone
and get the summation of existing paid payment request for Phone payment channel.
Return the total amount of Payment Requests against a reference document.
"""
existing_payment_request_amount = frappe.db.sql(
"""
select sum(grand_total)
from `tabPayment Request`
where
reference_doctype = %s
and reference_name = %s
and docstatus = 1
and (status != 'Paid'
or (payment_channel = 'Phone'
and status = 'Paid'))
""",
(ref_dt, ref_dn),
PR = frappe.qb.DocType("Payment Request")
response = (
frappe.qb.from_(PR)
.select(Sum(PR.grand_total))
.where(PR.reference_doctype == ref_dt)
.where(PR.reference_name == ref_dn)
.where(PR.docstatus == 1)
.run()
)
return flt(existing_payment_request_amount[0][0]) if existing_payment_request_amount else 0
return response[0][0] if response[0] else 0
def get_gateway_details(args): # nosemgrep
@@ -612,41 +726,66 @@ def make_payment_entry(docname):
return doc.create_payment_entry(submit=False).as_dict()
def update_payment_req_status(doc, method):
from erpnext.accounts.doctype.payment_entry.payment_entry import get_reference_details
def update_payment_requests_as_per_pe_references(references=None, cancel=False):
"""
Update Payment Request's `Status` and `Outstanding Amount` based on Payment Entry Reference's `Allocated Amount`.
"""
if not references:
return
for ref in doc.references:
payment_request_name = frappe.db.get_value(
"Payment Request",
{
"reference_doctype": ref.reference_doctype,
"reference_name": ref.reference_name,
"docstatus": 1,
},
precision = references[0].precision("allocated_amount")
referenced_payment_requests = frappe.get_all(
"Payment Request",
filters={"name": ["in", {row.payment_request for row in references if row.payment_request}]},
fields=[
"name",
"grand_total",
"outstanding_amount",
"payment_request_type",
],
)
referenced_payment_requests = {pr.name: pr for pr in referenced_payment_requests}
for ref in references:
if not ref.payment_request:
continue
payment_request = referenced_payment_requests[ref.payment_request]
pr_outstanding = payment_request["outstanding_amount"]
# update outstanding amount
new_outstanding_amount = flt(
pr_outstanding + ref.allocated_amount if cancel else pr_outstanding - ref.allocated_amount,
precision,
)
if payment_request_name:
ref_details = get_reference_details(
ref.reference_doctype,
ref.reference_name,
doc.party_account_currency,
doc.party_type,
doc.party,
# to handle same payment request for the multiple allocations
payment_request["outstanding_amount"] = new_outstanding_amount
if not cancel and new_outstanding_amount < 0:
frappe.throw(
msg=_(
"The allocated amount is greater than the outstanding amount of Payment Request {0}"
).format(ref.payment_request),
title=_("Invalid Allocated Amount"),
)
pay_req_doc = frappe.get_doc("Payment Request", payment_request_name)
status = pay_req_doc.status
if status != "Paid" and not ref_details.outstanding_amount:
status = "Paid"
elif status != "Partially Paid" and ref_details.outstanding_amount != ref_details.total_amount:
status = "Partially Paid"
elif ref_details.outstanding_amount == ref_details.total_amount:
if pay_req_doc.payment_request_type == "Outward":
status = "Initiated"
elif pay_req_doc.payment_request_type == "Inward":
status = "Requested"
# update status
if new_outstanding_amount == payment_request["grand_total"]:
status = "Initiated" if payment_request["payment_request_type"] == "Outward" else "Requested"
elif new_outstanding_amount == 0:
status = "Paid"
elif new_outstanding_amount > 0:
status = "Partially Paid"
pay_req_doc.db_set("status", status)
# update database
frappe.db.set_value(
"Payment Request",
ref.payment_request,
{"outstanding_amount": new_outstanding_amount, "status": status},
)
def get_dummy_message(doc):
@@ -730,3 +869,35 @@ def validate_payment(doc, method=None):
doc.reference_docname
)
)
@frappe.whitelist()
def get_open_payment_requests_query(doctype, txt, searchfield, start, page_len, filters):
# permission checks in `get_list()`
reference_doctype = filters.get("reference_doctype")
reference_name = filters.get("reference_doctype")
if not reference_doctype or not reference_name:
return []
open_payment_requests = frappe.get_list(
"Payment Request",
filters={
"reference_doctype": filters["reference_doctype"],
"reference_name": filters["reference_name"],
"status": ["!=", "Paid"],
"outstanding_amount": ["!=", 0], # for compatibility with old data
"docstatus": 1,
},
fields=["name", "grand_total", "outstanding_amount"],
order_by="transaction_date ASC,creation ASC",
)
return [
(
pr.name,
_("<strong>Grand Total:</strong> {0}").format(pr.grand_total),
_("<strong>Outstanding Amount:</strong> {0}").format(pr.outstanding_amount),
)
for pr in open_payment_requests
]

View File

@@ -1,18 +1,23 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import re
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase, change_settings
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
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
test_dependencies = ["Currency Exchange", "Journal Entry", "Contact", "Address"]
payment_gateway = {"doctype": "Payment Gateway", "gateway": "_Test Gateway"}
payment_method = [
@@ -32,7 +37,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)
@@ -260,3 +265,262 @@ 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)
def test_multiple_payment_if_partially_paid_for_same_currency(self):
so = make_sales_order(currency="INR", qty=1, rate=1000)
pr = make_payment_request(
dt="Sales Order",
dn=so.name,
mute_email=1,
submit_doc=1,
return_doc=1,
)
self.assertEqual(pr.grand_total, 1000)
self.assertEqual(pr.outstanding_amount, pr.grand_total)
self.assertEqual(pr.party_account_currency, pr.currency) # INR
so.load_from_db()
# to make partial payment
pe = pr.create_payment_entry(submit=False)
pe.paid_amount = 200
pe.references[0].allocated_amount = 200
pe.submit()
self.assertEqual(pe.references[0].payment_request, pr.name)
so.load_from_db()
pr.load_from_db()
self.assertEqual(pr.status, "Partially Paid")
self.assertEqual(pr.outstanding_amount, 800)
self.assertEqual(pr.grand_total, 1000)
# complete payment
pe = pr.create_payment_entry()
self.assertEqual(pe.paid_amount, 800) # paid amount set from pr's outstanding amount
self.assertEqual(pe.references[0].allocated_amount, 800)
self.assertEqual(pe.references[0].outstanding_amount, 800) # for Orders it is not zero
self.assertEqual(pe.references[0].payment_request, pr.name)
so.load_from_db()
pr.load_from_db()
self.assertEqual(pr.status, "Paid")
self.assertEqual(pr.outstanding_amount, 0)
self.assertEqual(pr.grand_total, 1000)
# creating a more payment Request must not allowed
self.assertRaisesRegex(
frappe.exceptions.ValidationError,
re.compile(r"Payment Request is already created"),
make_payment_request,
dt="Sales Order",
dn=so.name,
mute_email=1,
submit_doc=1,
return_doc=1,
)
@change_settings("Accounts Settings", {"allow_multi_currency_invoices_against_single_party_account": 1})
def test_multiple_payment_if_partially_paid_for_multi_currency(self):
pi = make_purchase_invoice(currency="USD", conversion_rate=50, qty=1, rate=100, do_not_save=1)
pi.credit_to = "Creditors - _TC"
pi.submit()
pr = make_payment_request(
dt="Purchase Invoice",
dn=pi.name,
mute_email=1,
submit_doc=1,
return_doc=1,
)
# 100 USD -> 5000 INR
self.assertEqual(pr.grand_total, 100)
self.assertEqual(pr.outstanding_amount, 5000)
self.assertEqual(pr.currency, "USD")
self.assertEqual(pr.party_account_currency, "INR")
self.assertEqual(pr.status, "Initiated")
# to make partial payment
pe = pr.create_payment_entry(submit=False)
pe.paid_amount = 2000
pe.references[0].allocated_amount = 2000
pe.submit()
self.assertEqual(pe.references[0].payment_request, pr.name)
pr.load_from_db()
self.assertEqual(pr.status, "Partially Paid")
self.assertEqual(pr.outstanding_amount, 3000)
self.assertEqual(pr.grand_total, 100)
# complete payment
pe = pr.create_payment_entry()
self.assertEqual(pe.paid_amount, 3000) # paid amount set from pr's outstanding amount
self.assertEqual(pe.references[0].allocated_amount, 3000)
self.assertEqual(pe.references[0].outstanding_amount, 0) # for Invoices it will zero
self.assertEqual(pe.references[0].payment_request, pr.name)
pr.load_from_db()
self.assertEqual(pr.status, "Paid")
self.assertEqual(pr.outstanding_amount, 0)
self.assertEqual(pr.grand_total, 100)
# creating a more payment Request must not allowed
self.assertRaisesRegex(
frappe.exceptions.ValidationError,
re.compile(r"Payment Request is already created"),
make_payment_request,
dt="Purchase Invoice",
dn=pi.name,
mute_email=1,
submit_doc=1,
return_doc=1,
)
def test_single_payment_with_payment_term_for_same_currency(self):
create_payment_terms_template()
po = create_purchase_order(do_not_save=1, currency="INR", qty=1, rate=20000)
po.payment_terms_template = "Test Receivable Template" # 84.746 and 15.254
po.save()
po.submit()
pr = make_payment_request(
dt="Purchase Order",
dn=po.name,
mute_email=1,
submit_doc=1,
return_doc=1,
)
self.assertEqual(pr.grand_total, 20000)
self.assertEqual(pr.outstanding_amount, pr.grand_total)
self.assertEqual(pr.party_account_currency, pr.currency) # INR
self.assertEqual(pr.status, "Initiated")
po.load_from_db()
pe = pr.create_payment_entry()
self.assertEqual(len(pe.references), 2)
self.assertEqual(pe.paid_amount, 20000)
# check 1st payment term
self.assertEqual(pe.references[0].allocated_amount, 16949.2)
self.assertEqual(pe.references[0].payment_request, pr.name)
# check 2nd payment term
self.assertEqual(pe.references[1].allocated_amount, 3050.8)
self.assertEqual(pe.references[1].payment_request, pr.name)
po.load_from_db()
pr.load_from_db()
self.assertEqual(pr.status, "Paid")
self.assertEqual(pr.outstanding_amount, 0)
self.assertEqual(pr.grand_total, 20000)
@change_settings("Accounts Settings", {"allow_multi_currency_invoices_against_single_party_account": 1})
def test_single_payment_with_payment_term_for_multi_currency(self):
create_payment_terms_template()
si = create_sales_invoice(
do_not_save=1, currency="USD", debit_to="Debtors - _TC", qty=1, rate=200, conversion_rate=50
)
si.payment_terms_template = "Test Receivable Template" # 84.746 and 15.254
si.save()
si.submit()
pr = make_payment_request(
dt="Sales Invoice",
dn=si.name,
mute_email=1,
submit_doc=1,
return_doc=1,
)
# 200 USD -> 10000 INR
self.assertEqual(pr.grand_total, 200)
self.assertEqual(pr.outstanding_amount, 10000)
self.assertEqual(pr.currency, "USD")
self.assertEqual(pr.party_account_currency, "INR")
pe = pr.create_payment_entry()
self.assertEqual(len(pe.references), 2)
self.assertEqual(pe.paid_amount, 10000)
# check 1st payment term
# convert it via dollar and conversion_rate
self.assertEqual(pe.references[0].allocated_amount, 8474.5) # multi currency conversion
self.assertEqual(pe.references[0].payment_request, pr.name)
# check 2nd payment term
self.assertEqual(pe.references[1].allocated_amount, 1525.5) # multi currency conversion
self.assertEqual(pe.references[1].payment_request, pr.name)
pr.load_from_db()
self.assertEqual(pr.status, "Paid")
self.assertEqual(pr.outstanding_amount, 0)
self.assertEqual(pr.grand_total, 200)
def test_payment_cancel_process(self):
so = make_sales_order(currency="INR", qty=1, rate=1000)
pr = make_payment_request(
dt="Sales Order",
dn=so.name,
mute_email=1,
submit_doc=1,
return_doc=1,
)
self.assertEqual(pr.grand_total, 1000)
self.assertEqual(pr.outstanding_amount, pr.grand_total)
so.load_from_db()
pe = pr.create_payment_entry(submit=False)
pe.paid_amount = 800
pe.references[0].allocated_amount = 800
pe.submit()
self.assertEqual(pe.references[0].payment_request, pr.name)
so.load_from_db()
pr.load_from_db()
self.assertEqual(pr.status, "Partially Paid")
self.assertEqual(pr.outstanding_amount, 200)
self.assertEqual(pr.grand_total, 1000)
# cancelling PE
pe.cancel()
pr.load_from_db()
self.assertEqual(pr.status, "Requested")
self.assertEqual(pr.outstanding_amount, 1000)
self.assertEqual(pr.grand_total, 1000)
so.load_from_db()

View File

@@ -60,7 +60,7 @@ class PeriodClosingVoucher(AccountsController):
)
if gle_count > 5000:
frappe.enqueue(
make_reverse_gl_entries,
process_cancellation,
voucher_type="Period Closing Voucher",
voucher_no=self.name,
queue="long",
@@ -71,9 +71,7 @@ class PeriodClosingVoucher(AccountsController):
alert=True,
)
else:
make_reverse_gl_entries(voucher_type="Period Closing Voucher", voucher_no=self.name)
self.delete_closing_entries()
process_cancellation(voucher_type="Period Closing Voucher", voucher_no=self.name)
def validate_future_closing_vouchers(self):
if frappe.db.exists(
@@ -86,12 +84,6 @@ class PeriodClosingVoucher(AccountsController):
)
)
def delete_closing_entries(self):
closing_balance = frappe.qb.DocType("Account Closing Balance")
frappe.qb.from_(closing_balance).delete().where(
closing_balance.period_closing_voucher == self.name
).run()
def validate_account_head(self):
closing_account_type = frappe.get_cached_value("Account", self.closing_account_head, "root_type")
@@ -166,14 +158,7 @@ class PeriodClosingVoucher(AccountsController):
closing_entries = self.get_grouped_gl_entries(get_opening_entries=get_opening_entries)
if len(gl_entries + closing_entries) > 3000:
frappe.enqueue(
process_gl_entries,
gl_entries=gl_entries,
voucher_name=self.name,
timeout=3000,
)
frappe.enqueue(
process_closing_entries,
process_gl_and_closing_entries,
gl_entries=gl_entries,
closing_entries=closing_entries,
voucher_name=self.name,
@@ -187,8 +172,9 @@ class PeriodClosingVoucher(AccountsController):
alert=True,
)
else:
process_gl_entries(gl_entries, self.name)
process_closing_entries(gl_entries, closing_entries, self.name, self.company, self.posting_date)
process_gl_and_closing_entries(
gl_entries, closing_entries, self.name, self.company, self.posting_date
)
def get_grouped_gl_entries(self, get_opening_entries=False):
closing_entries = []
@@ -353,9 +339,10 @@ class PeriodClosingVoucher(AccountsController):
if get_opening_entries:
query = query.where(
gl_entry.posting_date.between(self.get("year_start_date"), self.posting_date)
| gl_entry.is_opening
== "Yes"
( # noqa: UP034
(gl_entry.posting_date.between(self.get("year_start_date"), self.posting_date))
| (gl_entry.is_opening == "Yes")
)
)
else:
query = query.where(
@@ -373,12 +360,16 @@ class PeriodClosingVoucher(AccountsController):
return query.run(as_dict=1)
def process_gl_entries(gl_entries, voucher_name):
def process_gl_and_closing_entries(gl_entries, closing_entries, voucher_name, company, closing_date):
from erpnext.accounts.doctype.account_closing_balance.account_closing_balance import (
make_closing_entries,
)
from erpnext.accounts.general_ledger import make_gl_entries
try:
if gl_entries:
make_gl_entries(gl_entries, merge_entries=False)
make_closing_entries(gl_entries + closing_entries, voucher_name, company, closing_date)
frappe.db.set_value("Period Closing Voucher", voucher_name, "gle_processing_status", "Completed")
except Exception as e:
frappe.db.rollback()
@@ -386,26 +377,21 @@ def process_gl_entries(gl_entries, voucher_name):
frappe.db.set_value("Period Closing Voucher", voucher_name, "gle_processing_status", "Failed")
def process_closing_entries(gl_entries, closing_entries, voucher_name, company, closing_date):
from erpnext.accounts.doctype.account_closing_balance.account_closing_balance import (
make_closing_entries,
)
try:
if gl_entries + closing_entries:
make_closing_entries(gl_entries + closing_entries, voucher_name, company, closing_date)
except Exception as e:
frappe.db.rollback()
frappe.log_error(e)
def make_reverse_gl_entries(voucher_type, voucher_no):
def process_cancellation(voucher_type, voucher_no):
from erpnext.accounts.general_ledger import make_reverse_gl_entries
try:
make_reverse_gl_entries(voucher_type=voucher_type, voucher_no=voucher_no)
delete_closing_entries(voucher_no)
frappe.db.set_value("Period Closing Voucher", voucher_no, "gle_processing_status", "Completed")
except Exception as e:
frappe.db.rollback()
frappe.log_error(e)
frappe.db.set_value("Period Closing Voucher", voucher_no, "gle_processing_status", "Failed")
def delete_closing_entries(voucher_no):
closing_balance = frappe.qb.DocType("Account Closing Balance")
frappe.qb.from_(closing_balance).delete().where(
closing_balance.period_closing_voucher == voucher_no
).run()

View File

@@ -194,7 +194,9 @@ function refresh_payments(d, frm) {
}
if (payment) {
payment.expected_amount += flt(p.amount);
payment.closing_amount = payment.expected_amount;
if (payment.closing_amount === 0) {
payment.closing_amount = payment.expected_amount;
}
payment.difference = payment.closing_amount - payment.expected_amount;
} else {
frm.add_child("payment_reconciliation", {

View File

@@ -87,19 +87,15 @@ class POSClosingEntry(StatusUpdater):
as_dict=1,
)[0]
if pos_invoice.consolidated_invoice:
invalid_row.setdefault("msg", []).append(
_("POS Invoice is {}").format(frappe.bold("already consolidated"))
)
invalid_row.setdefault("msg", []).append(_("POS Invoice is already consolidated"))
invalid_rows.append(invalid_row)
continue
if pos_invoice.pos_profile != self.pos_profile:
invalid_row.setdefault("msg", []).append(
_("POS Profile doesn't matches {}").format(frappe.bold(self.pos_profile))
_("POS Profile doesn't match {}").format(frappe.bold(self.pos_profile))
)
if pos_invoice.docstatus != 1:
invalid_row.setdefault("msg", []).append(
_("POS Invoice is not {}").format(frappe.bold("submitted"))
)
invalid_row.setdefault("msg", []).append(_("POS Invoice is not submitted"))
if pos_invoice.owner != self.user:
invalid_row.setdefault("msg", []).append(
_("POS Invoice isn't created by user {}").format(frappe.bold(self.owner))

View File

@@ -40,6 +40,19 @@ erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnex
};
});
this.frm.set_query("item_code", "items", function (doc) {
return {
query: "erpnext.accounts.doctype.pos_invoice.pos_invoice.item_query",
filters: {
has_variants: ["=", 0],
is_sales_item: ["=", 1],
disabled: ["=", 0],
is_fixed_asset: ["=", 0],
pos_profile: ["=", doc.pos_profile],
},
};
});
erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
}

View File

@@ -6,6 +6,7 @@ import frappe
from frappe import _, bold
from frappe.query_builder.functions import IfNull, Sum
from frappe.utils import cint, flt, get_link_to_form, getdate, nowdate
from frappe.utils.nestedset import get_descendants_of
from erpnext.accounts.doctype.loyalty_program.loyalty_program import validate_loyalty_points
from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
@@ -15,6 +16,7 @@ from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
update_multi_mode_option,
)
from erpnext.accounts.party import get_due_date, get_party_account
from erpnext.controllers.queries import item_query as _item_query
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
@@ -188,7 +190,7 @@ class POSInvoice(SalesInvoice):
def validate(self):
if not cint(self.is_pos):
frappe.throw(
_("POS Invoice should have {} field checked.").format(frappe.bold("Include Payment"))
_("POS Invoice should have the field {0} checked.").format(frappe.bold(_("Include Payment")))
)
# run on validate method of selling controller
@@ -449,7 +451,7 @@ class POSInvoice(SalesInvoice):
if self.is_return and entry.amount > 0:
frappe.throw(_("Row #{0} (Payment Table): Amount must be negative").format(entry.idx))
if self.is_return:
if self.is_return and self.docstatus != 0:
invoice_total = self.rounded_total or self.grand_total
total_amount_in_payments = flt(total_amount_in_payments, self.precision("grand_total"))
if total_amount_in_payments and total_amount_in_payments < invoice_total:
@@ -837,3 +839,30 @@ def add_return_modes(doc, pos_profile):
]:
payment_mode = get_mode_of_payment_info(mode_of_payment, doc.company)
append_payment(payment_mode[0])
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False):
if pos_profile := filters.get("pos_profile")[1]:
pos_profile = frappe.get_cached_doc("POS Profile", pos_profile)
if item_groups := get_item_group(pos_profile):
filters["item_group"] = ["in", tuple(item_groups)]
del filters["pos_profile"]
else:
filters.pop("pos_profile", None)
return _item_query(doctype, txt, searchfield, start, page_len, filters, as_dict)
def get_item_group(pos_profile):
item_groups = []
if pos_profile.get("item_groups"):
# Get items based on the item groups defined in the POS profile
for row in pos_profile.get("item_groups"):
item_groups.append(row.item_group)
item_groups.extend(get_descendants_of("Item Group", row.item_group))
return list(set(item_groups))

View File

@@ -97,16 +97,15 @@ class POSInvoiceMergeLog(Document):
return_against_status = frappe.db.get_value("POS Invoice", return_against, "status")
if return_against_status != "Consolidated":
# if return entry is not getting merged in the current pos closing and if it is not consolidated
bold_unconsolidated = frappe.bold("not Consolidated")
msg = _("Row #{}: Original Invoice {} of return invoice {} is {}.").format(
d.idx, bold_return_against, bold_pos_invoice, bold_unconsolidated
)
msg = _(
"Row #{}: The original Invoice {} of return invoice {} is not consolidated."
).format(d.idx, bold_return_against, bold_pos_invoice)
msg += " "
msg += _(
"Original invoice should be consolidated before or along with the return invoice."
"The 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(
msg += _("You can add the original invoice {} manually to proceed.").format(
bold_return_against
)
frappe.throw(msg)

View File

@@ -419,7 +419,8 @@
"depends_on": "eval:doc.rate_or_discount==\"Rate\"",
"fieldname": "rate",
"fieldtype": "Currency",
"label": "Rate"
"label": "Rate",
"options": "currency"
},
{
"default": "0",
@@ -647,7 +648,7 @@
"icon": "fa fa-gift",
"idx": 1,
"links": [],
"modified": "2024-05-17 13:16:34.496704",
"modified": "2024-09-16 18:14:51.314765",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",
@@ -709,4 +710,4 @@
"sort_order": "DESC",
"states": [],
"title_field": "title"
}
}

View File

@@ -186,7 +186,8 @@ class PricingRule(Document):
if not self.priority:
throw(
_("As the field {0} is enabled, the field {1} is mandatory.").format(
frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority")
frappe.bold(_("Apply Discount on Discounted Rate")),
frappe.bold(_("Priority")),
)
)
@@ -194,7 +195,7 @@ class PricingRule(Document):
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"))
).format(frappe.bold(_("Apply Discount on Discounted Rate")), frappe.bold(_("Priority")))
)
def validate_applicable_for_selling_or_buying(self):

View File

@@ -5,14 +5,17 @@
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase, change_settings
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.controllers.sales_and_purchase_return import make_return_doc
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.get_item_details import get_item_details
class TestPricingRule(unittest.TestCase):
class TestPricingRule(FrappeTestCase):
def setUp(self):
delete_existing_pricing_rules()
setup_pricing_rule_data()
@@ -1128,6 +1131,12 @@ class TestPricingRule(unittest.TestCase):
self.assertEqual(so.items[1].item_code, "_Test Item")
self.assertEqual(so.items[1].qty, 3)
so = make_sales_order(item_code="_Test Item", qty=5, do_not_submit=1)
so.items[0].qty = 1
del so.items[-1]
so.save()
self.assertEqual(len(so.items), 1)
def test_apply_multiple_pricing_rules_for_discount_percentage_and_amount(self):
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
@@ -1311,6 +1320,69 @@ class TestPricingRule(unittest.TestCase):
pricing_rule.is_recursive = True
self.assertRaises(frappe.ValidationError, pricing_rule.save)
def test_ignore_pricing_rule_for_credit_note(self):
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule")
pricing_rule = make_pricing_rule(
discount_percentage=20,
selling=1,
buying=1,
priority=1,
title="_Test Pricing Rule",
)
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", qty=1)
item = si.items[0]
si.submit()
self.assertEqual(item.discount_percentage, 20)
self.assertEqual(item.rate, 80)
# change discount on pricing rule
pricing_rule.discount_percentage = 30
pricing_rule.save()
credit_note = make_return_doc(si.doctype, si.name)
credit_note.save()
self.assertEqual(credit_note.ignore_pricing_rule, 1)
self.assertEqual(credit_note.pricing_rules, [])
self.assertEqual(credit_note.items[0].discount_percentage, 20)
self.assertEqual(credit_note.items[0].rate, 80)
self.assertEqual(credit_note.items[0].pricing_rules, None)
credit_note.delete()
si.cancel()
def test_ignore_pricing_rule_for_debit_note(self):
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule")
pricing_rule = make_pricing_rule(
discount_percentage=20,
buying=1,
priority=1,
title="_Test Pricing Rule",
)
pi = make_purchase_invoice(do_not_submit=True, supplier="_Test Supplier 1", qty=1)
item = pi.items[0]
pi.submit()
self.assertEqual(item.discount_percentage, 20)
self.assertEqual(item.rate, 40)
# change discount on pricing rule
pricing_rule.discount_percentage = 30
pricing_rule.save()
# create debit note from purchase invoice
debit_note = make_return_doc(pi.doctype, pi.name)
debit_note.save()
self.assertEqual(debit_note.ignore_pricing_rule, 1)
self.assertEqual(debit_note.pricing_rules, [])
self.assertEqual(debit_note.items[0].discount_percentage, 20)
self.assertEqual(debit_note.items[0].rate, 40)
self.assertEqual(debit_note.items[0].pricing_rules, None)
debit_note.delete()
pi.cancel()
test_dependencies = ["Campaign"]

View File

@@ -486,7 +486,7 @@ def get_qty_and_rate_for_other_item(doc, pr_doc, pricing_rules, row_item):
continue
stock_qty = row.get("qty") * (row.get("conversion_factor") or 1.0)
amount = stock_qty * (row.get("price_list_rate") or row.get("rate"))
amount = stock_qty * (flt(row.get("price_list_rate")) or flt(row.get("rate")))
pricing_rules = filter_pricing_rules_for_qty_amount(stock_qty, amount, pricing_rules, row)
if pricing_rules and pricing_rules[0]:
@@ -657,6 +657,9 @@ def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
if pricing_rule.round_free_qty:
qty = math.floor(qty)
if not qty:
return
free_item_data_args = {
"item_code": free_item,
"qty": qty,

View File

@@ -20,6 +20,17 @@ frappe.ui.form.on("Process Payment Reconciliation", {
},
};
});
frm.set_query("default_advance_account", function (doc) {
return {
filters: {
company: doc.company,
is_group: 0,
account_type: doc.party_type == "Customer" ? "Receivable" : "Payable",
root_type: doc.party_type == "Customer" ? "Liability" : "Asset",
},
};
});
frm.set_query("cost_center", function (doc) {
return {
filters: {
@@ -102,6 +113,7 @@ frappe.ui.form.on("Process Payment Reconciliation", {
company(frm) {
frm.set_value("party", "");
frm.set_value("receivable_payable_account", "");
frm.set_value("default_advance_account", "");
},
party_type(frm) {
frm.set_value("party", "");
@@ -109,6 +121,7 @@ frappe.ui.form.on("Process Payment Reconciliation", {
party(frm) {
frm.set_value("receivable_payable_account", "");
frm.set_value("default_advance_account", "");
if (!frm.doc.receivable_payable_account && frm.doc.party_type && frm.doc.party) {
return frappe.call({
method: "erpnext.accounts.party.get_party_account",
@@ -116,10 +129,16 @@ frappe.ui.form.on("Process Payment Reconciliation", {
company: frm.doc.company,
party_type: frm.doc.party_type,
party: frm.doc.party,
include_advance: 1,
},
callback: (r) => {
if (!r.exc && r.message) {
frm.set_value("receivable_payable_account", r.message);
if (typeof r.message === "string") {
frm.set_value("receivable_payable_account", r.message);
} else if (Array.isArray(r.message)) {
frm.set_value("receivable_payable_account", r.message[0]);
frm.set_value("default_advance_account", r.message[1]);
}
}
frm.refresh();
},

View File

@@ -13,6 +13,7 @@
"column_break_io6c",
"party",
"receivable_payable_account",
"default_advance_account",
"filter_section",
"from_invoice_date",
"to_invoice_date",
@@ -141,12 +142,23 @@
{
"fieldname": "section_break_a8yx",
"fieldtype": "Section Break"
},
{
"depends_on": "eval:doc.party",
"description": "Only 'Payment Entries' made against this advance account are supported.",
"documentation_url": "https://docs.erpnext.com/docs/user/manual/en/advance-in-separate-party-account",
"fieldname": "default_advance_account",
"fieldtype": "Link",
"label": "Default Advance Account",
"mandatory_depends_on": "doc.party_type",
"options": "Account",
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2023-08-11 10:56:51.699137",
"modified": "2024-08-27 14:48:56.715320",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Payment Reconciliation",
@@ -180,4 +192,4 @@
"sort_order": "DESC",
"states": [],
"title_field": "company"
}
}

View File

@@ -23,6 +23,7 @@ class ProcessPaymentReconciliation(Document):
bank_cash_account: DF.Link | None
company: DF.Link
cost_center: DF.Link | None
default_advance_account: DF.Link
error_log: DF.LongText | None
from_invoice_date: DF.Date | None
from_payment_date: DF.Date | None
@@ -101,6 +102,7 @@ def get_pr_instance(doc: str):
"party_type",
"party",
"receivable_payable_account",
"default_advance_account",
"from_invoice_date",
"to_invoice_date",
"from_payment_date",

View File

@@ -16,6 +16,7 @@
"cost_center",
"territory",
"ignore_exchange_rate_revaluation_journals",
"ignore_cr_dr_notes",
"column_break_14",
"to_date",
"finance_book",
@@ -383,10 +384,16 @@
"fieldname": "ignore_exchange_rate_revaluation_journals",
"fieldtype": "Check",
"label": "Ignore Exchange Rate Revaluation Journals"
},
{
"default": "0",
"fieldname": "ignore_cr_dr_notes",
"fieldtype": "Check",
"label": "Ignore System Generated Credit / Debit Notes"
}
],
"links": [],
"modified": "2023-12-18 12:20:08.965120",
"modified": "2024-08-13 10:41:18.381165",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",

View File

@@ -54,6 +54,7 @@ class ProcessStatementOfAccounts(Document):
frequency: DF.Literal["Weekly", "Monthly", "Quarterly"]
from_date: DF.Date | None
group_by: DF.Literal["", "Group by Voucher", "Group by Voucher (Consolidated)"]
ignore_cr_dr_notes: DF.Check
ignore_exchange_rate_revaluation_journals: DF.Check
include_ageing: DF.Check
include_break: DF.Check
@@ -133,6 +134,9 @@ def get_statement_dict(doc, get_statement_dict=False):
if doc.ignore_exchange_rate_revaluation_journals:
filters.update({"ignore_err": True})
if doc.ignore_cr_dr_notes:
filters.update({"ignore_cr_dr_notes": True})
if doc.report == "General Ledger":
filters.update(get_gl_filters(doc, entry, tax_id, presentation_currency))
col, res = get_soa(filters)

View File

@@ -2,6 +2,18 @@
// For license information, please see license.txt
frappe.ui.form.on("Promotional Scheme", {
setup: function (frm) {
frm.set_query("for_price_list", "price_discount_slabs", (doc) => {
return {
filters: {
selling: doc.selling,
buying: doc.buying,
currency: doc.currency,
},
};
});
},
refresh: function (frm) {
frm.trigger("set_options_for_applicable_for");
frm.trigger("toggle_reqd_apply_on");

View File

@@ -5,6 +5,8 @@
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.query_builder import Criterion
from frappe.query_builder.functions import IfNull
pricing_rule_fields = [
"apply_on",
@@ -51,6 +53,7 @@ price_discount_fields = [
"discount_percentage",
"validate_applied_rule",
"apply_multiple_pricing_rules",
"for_price_list",
]
product_discount_fields = [
@@ -63,6 +66,7 @@ product_discount_fields = [
"recurse_for",
"apply_recursion_over",
"apply_multiple_pricing_rules",
"round_free_qty",
]
@@ -160,22 +164,50 @@ class PromotionalScheme(Document):
if self.is_new():
return
transaction_exists = False
docnames = []
invalid_pricing_rule = self.get_invalid_pricing_rules()
# If user has changed applicable for
if self.get_doc_before_save() and self.get_doc_before_save().applicable_for == self.applicable_for:
if not invalid_pricing_rule:
return
docnames = frappe.get_all("Pricing Rule", filters={"promotional_scheme": self.name})
if frappe.db.exists(
"Pricing Rule Detail",
{
"pricing_rule": ["in", invalid_pricing_rule],
"docstatus": ["<", 2],
},
):
raise_for_transaction_exists(self.name)
for docname in docnames:
if frappe.db.exists("Pricing Rule Detail", {"pricing_rule": docname.name, "docstatus": ("<", 2)}):
raise_for_transaction_exists(self.name)
for doc in invalid_pricing_rule:
frappe.delete_doc("Pricing Rule", doc)
if docnames and not transaction_exists:
for docname in docnames:
frappe.delete_doc("Pricing Rule", docname.name)
frappe.msgprint(
_("The following invalid Pricing Rules are deleted:")
+ "<br><br><ul><li>"
+ "</li><li>".join(invalid_pricing_rule)
+ "</li></ul>"
)
def get_invalid_pricing_rules(self):
pr = frappe.qb.DocType("Pricing Rule")
conditions = []
conditions.append(pr.promotional_scheme == self.name)
if self.applicable_for:
applicable_for = frappe.scrub(self.applicable_for)
applicable_for_list = [d.get(applicable_for) for d in self.get(applicable_for)]
conditions.append(
(IfNull(pr.applicable_for, "") != self.applicable_for)
| (
(IfNull(pr.applicable_for, "") == self.applicable_for)
& IfNull(pr[applicable_for], "").notin(applicable_for_list)
)
)
else:
conditions.append(IfNull(pr.applicable_for, "") != "")
return frappe.qb.from_(pr).select(pr.name).where(Criterion.all(conditions)).run(pluck=True)
def on_update(self):
self.validate()

View File

@@ -90,6 +90,31 @@ class TestPromotionalScheme(unittest.TestCase):
price_rules = frappe.get_all("Pricing Rule", filters={"promotional_scheme": ps.name})
self.assertEqual(price_rules, [])
def test_change_applicable_for_values_in_promotional_scheme(self):
ps = make_promotional_scheme(applicable_for="Customer", customer="_Test Customer")
ps.append("customer", {"customer": "_Test Customer 2"})
ps.save()
price_rules = frappe.get_all(
"Pricing Rule", filters={"promotional_scheme": ps.name, "applicable_for": "Customer"}
)
self.assertTrue(len(price_rules), 2)
ps.set("customer", [])
ps.append("customer", {"customer": "_Test Customer 2"})
ps.save()
price_rules = frappe.get_all(
"Pricing Rule",
filters={
"promotional_scheme": ps.name,
"applicable_for": "Customer",
"customer": "_Test Customer",
},
)
self.assertEqual(price_rules, [])
frappe.delete_doc("Promotional Scheme", ps.name)
def test_min_max_amount_configuration(self):
ps = make_promotional_scheme()
ps.price_discount_slabs[0].min_amount = 10

View File

@@ -21,6 +21,7 @@
"rate",
"discount_amount",
"discount_percentage",
"for_price_list",
"section_break_11",
"warehouse",
"threshold_percentage",
@@ -120,6 +121,13 @@
"fieldtype": "Float",
"label": "Discount Percentage"
},
{
"depends_on": "eval:doc.rate_or_discount!=\"Rate\"",
"fieldname": "for_price_list",
"fieldtype": "Link",
"label": "For Price List",
"options": "Price List"
},
{
"fieldname": "section_break_11",
"fieldtype": "Section Break"
@@ -169,7 +177,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-11-16 00:25:33.843996",
"modified": "2024-07-23 12:33:46.574950",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Promotional Scheme Price Discount",
@@ -177,4 +185,4 @@
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC"
}
}

View File

@@ -19,6 +19,7 @@ class PromotionalSchemePriceDiscount(Document):
disable: DF.Check
discount_amount: DF.Currency
discount_percentage: DF.Float
for_price_list: DF.Link | None
max_amount: DF.Currency
max_qty: DF.Float
min_amount: DF.Currency

View File

@@ -22,6 +22,7 @@
"column_break_9",
"free_item_uom",
"free_item_rate",
"round_free_qty",
"section_break_12",
"warehouse",
"threshold_percentage",
@@ -181,12 +182,18 @@
"fieldtype": "Float",
"label": "Apply Recursion Over (As Per Transaction UOM)",
"mandatory_depends_on": "is_recursive"
},
{
"default": "0",
"fieldname": "round_free_qty",
"fieldtype": "Check",
"label": "Round Free Qty"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-03-12 12:53:58.199108",
"modified": "2024-07-22 17:25:07.880984",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Promotional Scheme Product Discount",
@@ -195,4 +202,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -53,6 +53,7 @@ class PromotionalSchemeProductDiscount(Document):
"20",
]
recurse_for: DF.Float
round_free_qty: DF.Check
rule_description: DF.SmallText
same_item: DF.Check
threshold_percentage: DF.Percent

View File

@@ -561,11 +561,12 @@ frappe.ui.form.on("Purchase Invoice", {
frm.custom_make_buttons = {
"Purchase Invoice": "Return / Debit Note",
"Payment Entry": "Payment",
"Landed Cost Voucher": function () {
frm.trigger("create_landed_cost_voucher");
},
};
if (frm.doc.update_stock) {
frm.custom_make_buttons["Landed Cost Voucher"] = "Landed Cost Voucher";
}
frm.set_query("additional_discount_account", function () {
return {
filters: {
@@ -607,20 +608,6 @@ frappe.ui.form.on("Purchase Invoice", {
});
},
create_landed_cost_voucher: function (frm) {
let lcv = frappe.model.get_new_doc("Landed Cost Voucher");
lcv.company = frm.doc.company;
let lcv_receipt = frappe.model.get_new_doc("Landed Cost Purchase Invoice");
lcv_receipt.receipt_document_type = "Purchase Invoice";
lcv_receipt.receipt_document = frm.doc.name;
lcv_receipt.supplier = frm.doc.supplier;
lcv_receipt.grand_total = frm.doc.grand_total;
lcv.purchase_receipts = [lcv_receipt];
frappe.set_route("Form", lcv.doctype, lcv.name);
},
add_custom_buttons: function (frm) {
if (frm.doc.docstatus == 1 && frm.doc.per_received < 100) {
frm.add_custom_button(
@@ -645,14 +632,40 @@ frappe.ui.form.on("Purchase Invoice", {
__("View")
);
}
if (frm.doc.docstatus === 1 && frm.doc.update_stock) {
frm.add_custom_button(
__("Landed Cost Voucher"),
() => {
frm.events.make_lcv(frm);
},
__("Create")
);
}
},
make_lcv(frm) {
frappe.call({
method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_lcv",
args: {
doctype: frm.doc.doctype,
docname: frm.doc.name,
},
callback: (r) => {
if (r.message) {
var doc = frappe.model.sync(r.message);
frappe.set_route("Form", doc[0].doctype, doc[0].name);
}
},
});
},
onload: function (frm) {
if (frm.doc.__onload && frm.is_new()) {
if (frm.doc.supplier) {
if (frm.doc.__onload && frm.doc.supplier) {
if (frm.is_new()) {
frm.doc.apply_tds = frm.doc.__onload.supplier_tds ? 1 : 0;
}
if (!frm.doc.__onload.enable_apply_tds) {
if (!frm.doc.__onload.supplier_tds) {
frm.set_df_property("apply_tds", "read_only", 1);
}
}

View File

@@ -1271,6 +1271,7 @@
"fieldtype": "Select",
"in_standard_filter": 1,
"label": "Status",
"no_copy": 1,
"options": "\nDraft\nReturn\nDebit Note Issued\nSubmitted\nPaid\nPartly Paid\nUnpaid\nOverdue\nCancelled\nInternal Transfer",
"print_hide": 1
},
@@ -1630,7 +1631,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
"modified": "2024-07-25 19:42:36.931278",
"modified": "2024-09-11 12:59:19.130593",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@@ -285,7 +285,6 @@ class PurchaseInvoice(BuyingController):
self.set_against_expense_account()
self.validate_write_off_account()
self.validate_multiple_billing("Purchase Receipt", "pr_detail", "amount")
self.create_remarks()
self.set_status()
self.validate_purchase_receipt_if_update_stock()
validate_inter_company_party(
@@ -322,10 +321,11 @@ class PurchaseInvoice(BuyingController):
def create_remarks(self):
if not self.remarks:
if self.bill_no and self.bill_date:
self.remarks = _("Against Supplier Invoice {0} dated {1}").format(
self.bill_no, formatdate(self.bill_date)
)
if self.bill_no:
self.remarks = _("Against Supplier Invoice {0}").format(self.bill_no)
if self.bill_date:
self.remarks += " " + _("dated {0}").format(formatdate(self.bill_date))
else:
self.remarks = _("No Remarks")
@@ -346,22 +346,6 @@ class PurchaseInvoice(BuyingController):
self.tax_withholding_category = tds_category
self.set_onload("supplier_tds", tds_category)
# If Linked Purchase Order has TDS applied, enable 'apply_tds' checkbox
if purchase_orders := [x.purchase_order for x in self.items if x.purchase_order]:
po = qb.DocType("Purchase Order")
po_with_tds = (
qb.from_(po)
.select(po.name)
.where(
po.docstatus.eq(1)
& (po.name.isin(purchase_orders))
& (po.apply_tds.eq(1))
& (po.tax_withholding_category.notnull())
)
.run()
)
self.set_onload("enable_apply_tds", True if po_with_tds else False)
super().set_missing_values(for_validate)
def validate_credit_to_acc(self):
@@ -377,16 +361,16 @@ class PurchaseInvoice(BuyingController):
if account.report_type != "Balance Sheet":
frappe.throw(
_(
"Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account."
).format(frappe.bold("Credit To")),
"Please ensure that the {0} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account."
).format(frappe.bold(_("Credit To"))),
title=_("Invalid Account"),
)
if self.supplier and account.account_type != "Payable":
frappe.throw(
_(
"Please ensure {} account {} is a Payable account. Change the account type to Payable or select a different account."
).format(frappe.bold("Credit To"), frappe.bold(self.credit_to)),
"Please ensure that the {0} account {1} is a Payable account. You can change the account type to Payable or select a different account."
).format(frappe.bold(_("Credit To")), frappe.bold(self.credit_to)),
title=_("Invalid Account"),
)
@@ -634,7 +618,7 @@ class PurchaseInvoice(BuyingController):
"To submit the invoice without purchase order please set {0} as {1} in {2}"
).format(
frappe.bold(_("Purchase Order Required")),
frappe.bold("No"),
frappe.bold(_("No")),
get_link_to_form("Buying Settings", "Buying Settings", "Buying Settings"),
)
throw(msg, title=_("Mandatory Purchase Order"))
@@ -655,7 +639,7 @@ class PurchaseInvoice(BuyingController):
"To submit the invoice without purchase receipt please set {0} as {1} in {2}"
).format(
frappe.bold(_("Purchase Receipt Required")),
frappe.bold("No"),
frappe.bold(_("No")),
get_link_to_form("Buying Settings", "Buying Settings", "Buying Settings"),
)
throw(msg, title=_("Mandatory Purchase Receipt"))
@@ -747,6 +731,9 @@ class PurchaseInvoice(BuyingController):
validate_docs_for_voucher_types(["Purchase Invoice"])
validate_docs_for_deferred_accounting([], [self.name])
def before_submit(self):
self.create_remarks()
def on_submit(self):
super().on_submit()
@@ -1262,7 +1249,11 @@ class PurchaseInvoice(BuyingController):
def update_gross_purchase_amount_for_linked_assets(self, item):
assets = frappe.db.get_all(
"Asset",
filters={"purchase_invoice": self.name, "item_code": item.item_code},
filters={
"purchase_invoice": self.name,
"item_code": item.item_code,
"purchase_invoice_item": ("in", [item.name, ""]),
},
fields=["name", "asset_quantity"],
)
for asset in assets:

View File

@@ -2236,6 +2236,80 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
self.assertEqual(pi_expected_values[i][1], gle.debit)
self.assertEqual(pi_expected_values[i][2], gle.credit)
def test_adjust_incoming_rate_from_pi_with_multi_currency(self):
from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import (
make_landed_cost_voucher,
)
frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 0)
frappe.db.set_single_value("Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 1)
# Increase the cost of the item
pr = make_purchase_receipt(
qty=10, rate=1, currency="USD", do_not_save=1, supplier="_Test Supplier USD"
)
pr.conversion_rate = 6300
pr.plc_conversion_rate = 1
pr.save()
pr.submit()
self.assertEqual(pr.conversion_rate, 6300)
self.assertEqual(pr.plc_conversion_rate, 1)
self.assertEqual(pr.base_grand_total, 6300 * 10)
stock_value_difference = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": "Purchase Receipt", "voucher_no": pr.name},
"stock_value_difference",
)
self.assertEqual(stock_value_difference, 6300 * 10)
make_landed_cost_voucher(
company=pr.company,
receipt_document_type="Purchase Receipt",
receipt_document=pr.name,
charges=3000,
distribute_charges_based_on="Qty",
)
pi = create_purchase_invoice_from_receipt(pr.name)
for row in pi.items:
row.rate = 1.1
pi.save()
pi.submit()
stock_value_difference = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": "Purchase Receipt", "voucher_no": pr.name},
"stock_value_difference",
)
self.assertEqual(stock_value_difference, 7230 * 10)
frappe.db.set_single_value("Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 0)
frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 1)
def test_last_purchase_rate(self):
item = create_item("_Test Item For Last Purchase Rate from PI", is_stock_item=1)
pi1 = make_purchase_invoice(item_code=item.item_code, qty=10, rate=100)
item.reload()
self.assertEqual(item.last_purchase_rate, 100)
pi2 = make_purchase_invoice(item_code=item.item_code, qty=10, rate=200)
item.reload()
self.assertEqual(item.last_purchase_rate, 200)
pi2.cancel()
item.reload()
self.assertEqual(item.last_purchase_rate, 100)
pi1.cancel()
item.reload()
self.assertEqual(item.last_purchase_rate, 0)
def set_advance_flag(company, flag, default_account):
frappe.db.set_value(

View File

@@ -57,6 +57,7 @@
"base_net_rate",
"base_net_amount",
"valuation_rate",
"sales_incoming_rate",
"item_tax_amount",
"landed_cost_voucher_amount",
"rm_supp_cost",
@@ -958,12 +959,22 @@
"print_hide": 1,
"read_only": 1,
"search_index": 1
},
{
"description": "Valuation rate for the item as per Sales Invoice (Only for Internal Transfers)",
"fieldname": "sales_incoming_rate",
"fieldtype": "Currency",
"hidden": 1,
"label": "Sales Incoming Rate",
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2024-06-14 11:57:07.171700",
"modified": "2024-07-19 12:12:42.449298",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",

View File

@@ -79,6 +79,7 @@ class PurchaseInvoiceItem(Document):
rejected_serial_no: DF.Text | None
rejected_warehouse: DF.Link | None
rm_supp_cost: DF.Currency
sales_incoming_rate: DF.Currency
sales_invoice_item: DF.Data | None
serial_and_batch_bundle: DF.Link | None
serial_no: DF.Text | None

View File

@@ -278,7 +278,6 @@ class SalesInvoice(SellingController):
self.check_sales_order_on_hold_or_close("sales_order")
self.validate_debit_to_acc()
self.clear_unallocated_advances("Sales Invoice Advance", "advances")
self.add_remarks()
self.validate_fixed_asset()
self.set_income_account_for_fixed_assets()
self.validate_item_cost_centers()
@@ -341,6 +340,7 @@ class SalesInvoice(SellingController):
):
validate_loyalty_points(self, self.loyalty_points)
self.allow_write_off_only_on_pos()
self.reset_default_field_value("set_warehouse", "items", "warehouse")
def validate_accounts(self):
@@ -422,6 +422,9 @@ class SalesInvoice(SellingController):
self.set_account_for_mode_of_payment()
self.set_paid_amount()
def before_submit(self):
self.add_remarks()
def on_submit(self):
self.validate_pos_paid_amount()
@@ -514,7 +517,7 @@ class SalesInvoice(SellingController):
)
if pos_closing_entry and pos_closing_entry[0]:
msg = _("To cancel a {} you need to cancel the POS Closing Entry {}.").format(
frappe.bold("Consolidated Sales Invoice"),
frappe.bold(_("Consolidated Sales Invoice")),
get_link_to_form("POS Closing Entry", pos_closing_entry[0]),
)
frappe.throw(msg, title=_("Not Allowed"))
@@ -858,7 +861,7 @@ class SalesInvoice(SellingController):
if account.report_type != "Balance Sheet":
msg = (
_("Please ensure {} account is a Balance Sheet account.").format(frappe.bold("Debit To"))
_("Please ensure {} account is a Balance Sheet account.").format(frappe.bold(_("Debit To")))
+ " "
)
msg += _(
@@ -869,7 +872,7 @@ class SalesInvoice(SellingController):
if self.customer and account.account_type != "Receivable":
msg = (
_("Please ensure {} account {} is a Receivable account.").format(
frappe.bold("Debit To"), frappe.bold(self.debit_to)
frappe.bold(_("Debit To")), frappe.bold(self.debit_to)
)
+ " "
)
@@ -946,10 +949,11 @@ class SalesInvoice(SellingController):
def add_remarks(self):
if not self.remarks:
if self.po_no and self.po_date:
self.remarks = _("Against Customer Order {0} dated {1}").format(
self.po_no, formatdate(self.po_date)
)
if self.po_no:
self.remarks = _("Against Customer Order {0}").format(self.po_no)
if self.po_date:
self.remarks += " " + _("dated {0}").format(formatdate(self.po_date))
else:
self.remarks = _("No Remarks")
@@ -1018,6 +1022,10 @@ class SalesInvoice(SellingController):
raise_exception=1,
)
def allow_write_off_only_on_pos(self):
if not self.is_pos and self.write_off_account:
self.write_off_account = None
def validate_write_off_account(self):
if flt(self.write_off_amount) and not self.write_off_account:
self.write_off_account = frappe.get_cached_value("Company", self.company, "write_off_account")
@@ -1316,6 +1324,10 @@ class SalesInvoice(SellingController):
for item in self.get("items"):
if flt(item.base_net_amount, item.precision("base_net_amount")):
# Do not book income for transfer within same company
if self.is_internal_transfer():
continue
if item.is_fixed_asset:
asset = self.get_asset(item)
@@ -1374,37 +1386,33 @@ class SalesInvoice(SellingController):
self.set_asset_status(asset)
else:
# Do not book income for transfer within same company
if not self.is_internal_transfer():
income_account = (
item.income_account
if (not item.enable_deferred_revenue or self.is_return)
else item.deferred_revenue_account
)
income_account = (
item.income_account
if (not item.enable_deferred_revenue or self.is_return)
else item.deferred_revenue_account
)
amount, base_amount = self.get_amount_and_base_amount(
item, enable_discount_accounting
)
amount, base_amount = self.get_amount_and_base_amount(item, enable_discount_accounting)
account_currency = get_account_currency(income_account)
gl_entries.append(
self.get_gl_dict(
{
"account": income_account,
"against": self.customer,
"credit": flt(base_amount, item.precision("base_net_amount")),
"credit_in_account_currency": (
flt(base_amount, item.precision("base_net_amount"))
if account_currency == self.company_currency
else flt(amount, item.precision("net_amount"))
),
"cost_center": item.cost_center,
"project": item.project or self.project,
},
account_currency,
item=item,
)
account_currency = get_account_currency(income_account)
gl_entries.append(
self.get_gl_dict(
{
"account": income_account,
"against": self.customer,
"credit": flt(base_amount, item.precision("base_net_amount")),
"credit_in_account_currency": (
flt(base_amount, item.precision("base_net_amount"))
if account_currency == self.company_currency
else flt(amount, item.precision("net_amount"))
),
"cost_center": item.cost_center,
"project": item.project or self.project,
},
account_currency,
item=item,
)
)
# expense account gl entries
if cint(self.update_stock) and erpnext.is_perpetual_inventory_enabled(self.company):
@@ -1479,6 +1487,10 @@ class SalesInvoice(SellingController):
if skip_change_gl_entries and payment_mode.account == self.account_for_change_amount:
payment_mode.base_amount -= flt(self.change_amount)
against_voucher = self.name
if self.is_return and self.return_against and not self.update_outstanding_for_self:
against_voucher = self.return_against
if payment_mode.base_amount:
# POS, make payment entries
gl_entries.append(
@@ -1492,7 +1504,7 @@ class SalesInvoice(SellingController):
"credit_in_account_currency": payment_mode.base_amount
if self.party_account_currency == self.company_currency
else payment_mode.amount,
"against_voucher": self.name,
"against_voucher": against_voucher,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center,
},
@@ -2111,7 +2123,7 @@ def make_delivery_note(source_name, target_doc=None):
"postprocess": update_item,
"condition": lambda doc: doc.delivered_by_supplier != 1,
},
"Sales Taxes and Charges": {"doctype": "Sales Taxes and Charges", "add_if_empty": True},
"Sales Taxes and Charges": {"doctype": "Sales Taxes and Charges", "reset_value": True},
"Sales Team": {
"doctype": "Sales Team",
"field_map": {"incentives": "incentives"},

View File

@@ -5,9 +5,10 @@ import copy
import json
import frappe
from frappe import qb
from frappe.model.dynamic_links import get_dynamic_link_map
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, flt, getdate, nowdate, today
from frappe.utils import add_days, flt, format_date, getdate, nowdate, today
import erpnext
from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account
@@ -3083,6 +3084,128 @@ class TestSalesInvoice(FrappeTestCase):
party_link.delete()
frappe.db.set_single_value("Accounts Settings", "enable_common_party_accounting", 0)
def test_sales_invoice_against_supplier_usd_with_dimensions(self):
from erpnext.accounts.doctype.opening_invoice_creation_tool.test_opening_invoice_creation_tool import (
make_customer,
)
from erpnext.accounts.doctype.party_link.party_link import create_party_link
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
# create a customer
customer = make_customer(customer="_Test Common Supplier USD")
cust_doc = frappe.get_doc("Customer", customer)
cust_doc.default_currency = "USD"
cust_doc.save()
# create a supplier
supplier = create_supplier(supplier_name="_Test Common Supplier USD").name
supp_doc = frappe.get_doc("Supplier", supplier)
supp_doc.default_currency = "USD"
supp_doc.save()
# create a party link between customer & supplier
party_link = create_party_link("Supplier", supplier, customer)
# enable common party accounting
frappe.db.set_single_value("Accounts Settings", "enable_common_party_accounting", 1)
# create a dimension and make it mandatory
if not frappe.get_all("Accounting Dimension", filters={"document_type": "Department"}):
dim = frappe.get_doc(
{
"doctype": "Accounting Dimension",
"document_type": "Department",
"dimension_defaults": [{"company": "_Test Company", "mandatory_for_bs": True}],
}
)
dim.save()
else:
dim = frappe.get_doc(
"Accounting Dimension",
frappe.get_all("Accounting Dimension", filters={"document_type": "Department"})[0],
)
dim.disabled = False
dim.dimension_defaults = []
dim.append("dimension_defaults", {"company": "_Test Company", "mandatory_for_bs": True})
dim.save()
# create a sales invoice
si = create_sales_invoice(
customer=customer, parent_cost_center="_Test Cost Center - _TC", do_not_submit=True
)
si.department = "All Departments"
si.save().submit()
# check outstanding of sales invoice
si.reload()
self.assertEqual(si.status, "Paid")
self.assertEqual(flt(si.outstanding_amount), 0.0)
# check creation of journal entry
jv = frappe.get_all(
"Journal Entry Account",
{
"account": si.debit_to,
"party_type": "Customer",
"party": si.customer,
"reference_type": si.doctype,
"reference_name": si.name,
"department": "All Departments",
},
pluck="credit_in_account_currency",
)
self.assertTrue(jv)
self.assertEqual(jv[0], si.grand_total)
dim.disabled = True
dim.save()
party_link.delete()
frappe.db.set_single_value("Accounts Settings", "enable_common_party_accounting", 0)
def test_sales_invoice_cancel_with_common_party_advance_jv(self):
from erpnext.accounts.doctype.opening_invoice_creation_tool.test_opening_invoice_creation_tool import (
make_customer,
)
from erpnext.accounts.doctype.party_link.party_link import create_party_link
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
# create a customer
customer = make_customer(customer="_Test Common Supplier")
# create a supplier
supplier = create_supplier(supplier_name="_Test Common Supplier").name
# create a party link between customer & supplier
party_link = create_party_link("Supplier", supplier, customer)
# enable common party accounting
frappe.db.set_single_value("Accounts Settings", "enable_common_party_accounting", 1)
# create a sales invoice
si = create_sales_invoice(customer=customer)
# check creation of journal entry
jv = frappe.db.get_value(
"Journal Entry Account",
filters={
"reference_type": si.doctype,
"reference_name": si.name,
"docstatus": 1,
},
fieldname="parent",
)
self.assertTrue(jv)
# cancel sales invoice
si.cancel()
# check cancellation of journal entry
jv_status = frappe.db.get_value("Journal Entry", jv, "docstatus")
self.assertEqual(jv_status, 2)
party_link.delete()
frappe.db.set_single_value("Accounts Settings", "enable_common_party_accounting", 0)
def test_payment_statuses(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
@@ -3758,6 +3881,130 @@ class TestSalesInvoice(FrappeTestCase):
]
self.assertEqual(expected, actual)
def test_pos_returns_without_update_outstanding_for_self(self):
from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_sales_return
pos_profile = make_pos_profile()
pos_profile.payments = []
pos_profile.append("payments", {"default": 1, "mode_of_payment": "Cash"})
pos_profile.save()
pos = create_sales_invoice(qty=10, do_not_save=True)
pos.is_pos = 1
pos.pos_profile = pos_profile.name
pos.append(
"payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - _TC", "amount": 500}
)
pos.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 500})
pos.save().submit()
pos_return = make_sales_return(pos.name)
pos_return.update_outstanding_for_self = False
pos_return.save().submit()
gle = qb.DocType("GL Entry")
res = (
qb.from_(gle)
.select(gle.against_voucher)
.distinct()
.where(
gle.is_cancelled.eq(0) & gle.voucher_no.eq(pos_return.name) & gle.against_voucher.notnull()
)
.run(as_list=1)
)
self.assertEqual(len(res), 1)
self.assertEqual(res[0][0], pos_return.return_against)
@change_settings("Accounts Settings", {"enable_common_party_accounting": True})
def test_common_party_with_foreign_currency_jv(self):
from erpnext.accounts.doctype.account.test_account import create_account
from erpnext.accounts.doctype.opening_invoice_creation_tool.test_opening_invoice_creation_tool import (
make_customer,
)
from erpnext.accounts.doctype.party_link.party_link import create_party_link
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
from erpnext.setup.utils import get_exchange_rate
creditors = create_account(
account_name="Creditors USD",
parent_account="Accounts Payable - _TC",
company="_Test Company",
account_currency="USD",
account_type="Payable",
)
debtors = create_account(
account_name="Debtors USD",
parent_account="Accounts Receivable - _TC",
company="_Test Company",
account_currency="USD",
account_type="Receivable",
)
# create a customer
customer = make_customer(customer="_Test Common Party USD")
cust_doc = frappe.get_doc("Customer", customer)
cust_doc.default_currency = "USD"
test_account_details = {
"company": "_Test Company",
"account": debtors,
}
cust_doc.append("accounts", test_account_details)
cust_doc.save()
# create a supplier
supplier = create_supplier(supplier_name="_Test Common Party USD").name
supp_doc = frappe.get_doc("Supplier", supplier)
supp_doc.default_currency = "USD"
test_account_details = {
"company": "_Test Company",
"account": creditors,
}
supp_doc.append("accounts", test_account_details)
supp_doc.save()
# create a party link between customer & supplier
create_party_link("Supplier", supplier, customer)
# create a sales invoice
si = create_sales_invoice(
customer=customer,
currency="USD",
conversion_rate=get_exchange_rate("USD", "INR"),
debit_to=debtors,
do_not_save=1,
)
si.party_account_currency = "USD"
si.save()
si.submit()
# check outstanding of sales invoice
si.reload()
self.assertEqual(si.status, "Paid")
self.assertEqual(flt(si.outstanding_amount), 0.0)
# check creation of journal entry
jv = frappe.get_all(
"Journal Entry Account",
{
"account": si.debit_to,
"party_type": "Customer",
"party": si.customer,
"reference_type": si.doctype,
"reference_name": si.name,
},
pluck="credit_in_account_currency",
)
self.assertTrue(jv)
self.assertEqual(jv[0], si.grand_total)
def test_invoice_remarks(self):
si = frappe.copy_doc(test_records[0])
si.po_no = "Test PO"
si.po_date = nowdate()
si.save()
si.submit()
self.assertEqual(si.remarks, f"Against Customer Order Test PO dated {format_date(nowdate())}")
def set_advance_flag(company, flag, default_account):
frappe.db.set_value(

View File

@@ -38,6 +38,12 @@ frappe.ui.form.on("Subscription", {
__("Actions")
);
frm.add_custom_button(
__("Force-Fetch Subscription Updates"),
() => frm.trigger("force_fetch_subscription_updates"),
__("Actions")
);
frm.add_custom_button(
__("Cancel Subscription"),
() => frm.trigger("cancel_this_subscription"),
@@ -82,4 +88,11 @@ frappe.ui.form.on("Subscription", {
}
});
},
force_fetch_subscription_updates: function (frm) {
frm.call("force_fetch_subscription_updates").then((r) => {
if (!r.exec) {
frm.reload_doc();
}
});
},
});

View File

@@ -717,6 +717,28 @@ class Subscription(Document):
self.update_subscription_period(posting_date or nowdate())
self.save()
@frappe.whitelist()
def force_fetch_subscription_updates(self):
"""
Process Subscription and create Invoices even if current date doesn't lie between current_invoice_start and currenct_invoice_end
It makes use of 'Proces Subscription' to force processing in a specific 'posting_date'
"""
# Don't process future subscriptions
if nowdate() < self.current_invoice_start:
frappe.msgprint(_("Subscription for Future dates cannot be processed."))
return
processing_date = None
if self.generate_invoice_at == "Beginning of the current subscription period":
processing_date = self.current_invoice_start
elif self.generate_invoice_at == "End of the current subscription period":
processing_date = self.current_invoice_end
elif self.generate_invoice_at == "Days before the current subscription period":
processing_date = add_days(self.current_invoice_start, -self.number_of_days)
self.process(posting_date=processing_date)
def is_prorate() -> int:
return cint(frappe.db.get_single_value("Subscription Settings", "prorate"))

View File

@@ -521,6 +521,18 @@ class TestSubscription(FrappeTestCase):
subscription.process(posting_date="2023-01-22")
self.assertEqual(len(subscription.invoices), 2)
def test_future_subscription(self):
"""Force-Fetch should not process future subscriptions"""
subscription = create_subscription(
start_date=add_months(nowdate(), 1),
submit_invoice=0,
generate_new_invoices_past_due_date=1,
party="_Test Subscription Customer John Doe",
)
subscription.force_fetch_subscription_updates()
subscription.reload()
self.assertEqual(len(subscription.invoices), 0)
def make_plans():
create_plan(plan_name="_Test Plan Name", cost=900, currency="INR")

View File

@@ -185,7 +185,7 @@ def get_tax_template(posting_date, args):
conditions.append("(from_date is null) and (to_date is null)")
conditions.append(
"ifnull(tax_category, '') = {}".format(frappe.db.escape(cstr(args.get("tax_category"))))
"ifnull(tax_category, '') = {}".format(frappe.db.escape(cstr(args.get("tax_category")), False))
)
if "tax_category" in args.keys():
del args["tax_category"]

View File

@@ -327,7 +327,7 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N
tax_amount = 0
else:
# if no TCS has been charged in FY,
# then chargeable value is "prev invoices + advances" value which cross the threshold
# then chargeable value is "prev invoices + advances - advance_adjusted" value which cross the threshold
tax_amount = get_tcs_amount(parties, inv, tax_details, vouchers, advance_vouchers)
if cint(tax_details.round_off_tax_amount):
@@ -375,12 +375,14 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"):
AND ja.party in %s
AND j.apply_tds = 1
AND j.tax_withholding_category = %s
AND j.company = %s
""",
(
tax_details.from_date,
tax_details.to_date,
tuple(parties),
tax_details.get("tax_withholding_category"),
company,
),
as_dict=1,
)
@@ -412,6 +414,9 @@ def get_advance_vouchers(parties, company=None, from_date=None, to_date=None, pa
Use Payment Ledger to fetch unallocated Advance Payments
"""
if party_type == "Supplier":
return []
ple = qb.DocType("Payment Ledger Entry")
conditions = []
@@ -497,6 +502,7 @@ def get_tds_amount(ldc, parties, inv, tax_details, vouchers):
"unallocated_amount": (">", 0),
"posting_date": ["between", (tax_details.from_date, tax_details.to_date)],
"tax_withholding_category": tax_details.get("tax_withholding_category"),
"company": inv.company,
}
field = "sum(tax_withholding_net_total)"
@@ -604,8 +610,6 @@ def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers):
conditions.append(ple.voucher_no == ple.against_voucher_no)
conditions.append(ple.company == inv.company)
(qb.from_(ple).select(Abs(Sum(ple.amount))).where(Criterion.all(conditions)).run(as_list=1))
advance_amt = (
qb.from_(ple).select(Abs(Sum(ple.amount))).where(Criterion.all(conditions)).run()[0][0] or 0.0
)
@@ -628,9 +632,12 @@ def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers):
)
cumulative_threshold = tax_details.get("cumulative_threshold", 0)
advance_adjusted = get_advance_adjusted_in_invoice(inv)
current_invoice_total = get_invoice_total_without_tcs(inv, tax_details)
total_invoiced_amt = current_invoice_total + invoiced_amt + advance_amt - credit_note_amt
total_invoiced_amt = (
current_invoice_total + invoiced_amt + advance_amt - credit_note_amt - advance_adjusted
)
if cumulative_threshold and total_invoiced_amt >= cumulative_threshold:
chargeable_amt = total_invoiced_amt - cumulative_threshold
@@ -639,6 +646,14 @@ def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers):
return tcs_amount
def get_advance_adjusted_in_invoice(inv):
advances_adjusted = 0
for row in inv.get("advances", []):
advances_adjusted += row.allocated_amount
return advances_adjusted
def get_invoice_total_without_tcs(inv, tax_details):
tcs_tax_row = [d for d in inv.taxes if d.account_head == tax_details.account_head]
tcs_tax_row_amount = tcs_tax_row[0].base_tax_amount if tcs_tax_row else 0

View File

@@ -210,6 +210,46 @@ class TestTaxWithholdingCategory(FrappeTestCase):
d.reload()
d.cancel()
def test_tcs_on_allocated_advance_payments(self):
frappe.db.set_value(
"Customer", "Test TCS Customer", "tax_withholding_category", "Cumulative Threshold TCS"
)
vouchers = []
# create advance payment
pe = create_payment_entry(
payment_type="Receive", party_type="Customer", party="Test TCS Customer", paid_amount=30000
)
pe.paid_from = "Debtors - _TC"
pe.paid_to = "Cash - _TC"
pe.submit()
vouchers.append(pe)
si = create_sales_invoice(customer="Test TCS Customer", rate=50000)
advances = si.get_advance_entries()
si.append(
"advances",
{
"reference_type": advances[0].reference_type,
"reference_name": advances[0].reference_name,
"advance_amount": advances[0].amount,
"allocated_amount": 30000,
},
)
si.submit()
vouchers.append(si)
# assert tax collection on total invoice ,advance payment adjusted should be excluded.
tcs_charged = sum([d.base_tax_amount for d in si.taxes if d.account_head == "TCS - _TC"])
# tcs = (inv amt)50000+(adv amt)30000-(adv adj) 30000 - threshold(30000) * rate 10%
self.assertEqual(tcs_charged, 2000)
# cancel invoice and payments to avoid clashing
for d in reversed(vouchers):
d.reload()
d.cancel()
def test_tds_calculation_on_net_total(self):
frappe.db.set_value(
"Supplier", "Test TDS Supplier4", "tax_withholding_category", "Cumulative Threshold TDS"

View File

@@ -7,7 +7,9 @@ from frappe.utils import today
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry
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.selling.doctype.sales_order.sales_order import make_sales_invoice
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
@@ -363,3 +365,100 @@ class TestUnreconcilePayment(AccountsTestMixin, FrappeTestCase):
self.assertEqual(so.advance_paid, 0)
self.assertEqual(len(pe.references), 0)
self.assertEqual(pe.unallocated_amount, 100)
def test_06_unreconcile_advance_from_payment_entry(self):
self.enable_advance_as_liability()
so1 = self.create_sales_order()
so2 = self.create_sales_order()
pe = self.create_payment_entry()
# Allocation payment against Sales Order
pe.paid_amount = 260
pe.append(
"references",
{"reference_doctype": so1.doctype, "reference_name": so1.name, "allocated_amount": 150},
)
pe.append(
"references",
{"reference_doctype": so2.doctype, "reference_name": so2.name, "allocated_amount": 110},
)
pe.save().submit()
# Assert 'Advance Paid'
so1.reload()
self.assertEqual(so1.advance_paid, 150)
so2.reload()
self.assertEqual(so2.advance_paid, 110)
unreconcile = frappe.get_doc(
{
"doctype": "Unreconcile Payment",
"company": self.company,
"voucher_type": pe.doctype,
"voucher_no": pe.name,
}
)
unreconcile.add_references()
self.assertEqual(len(unreconcile.allocations), 2)
allocations = [(x.reference_name, x.allocated_amount) for x in unreconcile.allocations]
self.assertListEqual(allocations, [(so1.name, 150), (so2.name, 110)])
# unreconcile so2
unreconcile.remove(unreconcile.allocations[0])
unreconcile.save().submit()
# Assert 'Advance Paid'
so1.reload()
so2.reload()
pe.reload()
self.assertEqual(so1.advance_paid, 150)
self.assertEqual(so2.advance_paid, 0)
self.assertEqual(len(pe.references), 1)
self.assertEqual(pe.unallocated_amount, 110)
self.disable_advance_as_liability()
def test_07_adv_from_so_to_invoice(self):
self.enable_advance_as_liability()
so = self.create_sales_order()
pe = self.create_payment_entry()
pe.paid_amount = 1000
pe.append(
"references",
{"reference_doctype": so.doctype, "reference_name": so.name, "allocated_amount": 1000},
)
pe.save().submit()
# Assert 'Advance Paid'
so.reload()
self.assertEqual(so.advance_paid, 1000)
si = make_sales_invoice(so.name)
si.insert().submit()
pr = frappe.get_doc(
{
"doctype": "Payment Reconciliation",
"company": self.company,
"party_type": "Customer",
"party": so.customer,
}
)
accounts = get_party_account("Customer", so.customer, so.company, True)
pr.receivable_payable_account = accounts[0]
pr.default_advance_account = accounts[1]
pr.get_unreconciled_entries()
self.assertEqual(len(pr.get("invoices")), 1)
self.assertEqual(len(pr.get("payments")), 1)
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()
self.assertEqual(len(pr.get("invoices")), 0)
self.assertEqual(len(pr.get("payments")), 0)
# Assert 'Advance Paid'
so.reload()
self.assertEqual(so.advance_paid, 0)
self.disable_advance_as_liability()

View File

@@ -1,7 +1,5 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "format:UNREC-{#####}",
"creation": "2023-08-22 10:26:34.421423",
"default_view": "List",
"doctype": "DocType",
@@ -58,11 +56,10 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2023-08-28 17:42:50.261377",
"modified": "2024-10-10 12:03:50.022444",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Unreconcile Payment",
"naming_rule": "Expression",
"owner": "Administrator",
"permissions": [
{

View File

@@ -179,50 +179,53 @@ def process_gl_map(gl_map, merge_entries=True, precision=None):
def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None):
cost_center_allocation = get_cost_center_allocation_data(gl_map[0]["company"], gl_map[0]["posting_date"])
if not cost_center_allocation:
return gl_map
new_gl_map = []
for d in gl_map:
cost_center = d.get("cost_center")
# Validate budget against main cost center
validate_expense_against_budget(d, expense_amount=flt(d.debit, precision) - flt(d.credit, precision))
if cost_center and cost_center_allocation.get(cost_center):
for sub_cost_center, percentage in cost_center_allocation.get(cost_center, {}).items():
gle = copy.deepcopy(d)
gle.cost_center = sub_cost_center
for field in ("debit", "credit", "debit_in_account_currency", "credit_in_account_currency"):
gle[field] = flt(flt(d.get(field)) * percentage / 100, precision)
new_gl_map.append(gle)
else:
cost_center_allocation = get_cost_center_allocation_data(
gl_map[0]["company"], gl_map[0]["posting_date"], cost_center
)
if not cost_center_allocation:
new_gl_map.append(d)
continue
for sub_cost_center, percentage in cost_center_allocation:
gle = copy.deepcopy(d)
gle.cost_center = sub_cost_center
for field in ("debit", "credit", "debit_in_account_currency", "credit_in_account_currency"):
gle[field] = flt(flt(d.get(field)) * percentage / 100, precision)
new_gl_map.append(gle)
return new_gl_map
def get_cost_center_allocation_data(company, posting_date):
par = frappe.qb.DocType("Cost Center Allocation")
child = frappe.qb.DocType("Cost Center Allocation Percentage")
def get_cost_center_allocation_data(company, posting_date, cost_center):
cost_center_allocation = frappe.db.get_value(
"Cost Center Allocation",
{
"docstatus": 1,
"company": company,
"valid_from": ("<=", posting_date),
"main_cost_center": cost_center,
},
pluck="name",
order_by="valid_from desc",
)
records = (
frappe.qb.from_(par)
.inner_join(child)
.on(par.name == child.parent)
.select(par.main_cost_center, child.cost_center, child.percentage)
.where(par.docstatus == 1)
.where(par.company == company)
.where(par.valid_from <= posting_date)
.orderby(par.valid_from, order=frappe.qb.desc)
).run(as_dict=True)
if not cost_center_allocation:
return []
cc_allocation = frappe._dict()
for d in records:
cc_allocation.setdefault(d.main_cost_center, frappe._dict()).setdefault(d.cost_center, d.percentage)
records = frappe.db.get_all(
"Cost Center Allocation Percentage",
{"parent": cost_center_allocation},
["cost_center", "percentage"],
as_list=True,
)
return cc_allocation
return records
def merge_similar_entries(gl_map, precision=None):

View File

@@ -68,7 +68,7 @@ def get_party_details(
pos_profile=None,
):
if not party:
return {}
return frappe._dict()
if not frappe.db.exists(party_type, party):
frappe.throw(_("{0}: {1} does not exists").format(party_type, party))
return _get_party_details(

View File

@@ -61,32 +61,10 @@ frappe.query_reports["Accounts Payable"] = {
default: "Due Date",
},
{
fieldname: "range1",
label: __("Ageing Range 1"),
fieldtype: "Int",
default: "30",
reqd: 1,
},
{
fieldname: "range2",
label: __("Ageing Range 2"),
fieldtype: "Int",
default: "60",
reqd: 1,
},
{
fieldname: "range3",
label: __("Ageing Range 3"),
fieldtype: "Int",
default: "90",
reqd: 1,
},
{
fieldname: "range4",
label: __("Ageing Range 4"),
fieldtype: "Int",
default: "120",
reqd: 1,
fieldname: "range",
label: __("Ageing Range"),
fieldtype: "Data",
default: "30, 60, 90, 120",
},
{
fieldname: "payment_terms_template",
@@ -162,6 +140,11 @@ frappe.query_reports["Accounts Payable"] = {
label: __("In Party Currency"),
fieldtype: "Check",
},
{
fieldname: "handle_employee_advances",
label: __("Handle Employee Advances"),
fieldtype: "Check",
},
],
formatter: function (value, row, column, data, default_formatter) {

View File

@@ -30,10 +30,7 @@ class TestAccountsPayable(AccountsTestMixin, FrappeTestCase):
"party_type": "Supplier",
"party": [self.supplier],
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
"in_party_currency": 1,
}

View File

@@ -24,32 +24,10 @@ frappe.query_reports["Accounts Payable Summary"] = {
default: "Due Date",
},
{
fieldname: "range1",
label: __("Ageing Range 1"),
fieldtype: "Int",
default: "30",
reqd: 1,
},
{
fieldname: "range2",
label: __("Ageing Range 2"),
fieldtype: "Int",
default: "60",
reqd: 1,
},
{
fieldname: "range3",
label: __("Ageing Range 3"),
fieldtype: "Int",
default: "90",
reqd: 1,
},
{
fieldname: "range4",
label: __("Ageing Range 4"),
fieldtype: "Int",
default: "120",
reqd: 1,
fieldname: "range",
label: __("Ageing Range"),
fieldtype: "Data",
default: "30, 60, 90, 120",
},
{
fieldname: "finance_book",

View File

@@ -89,32 +89,10 @@ frappe.query_reports["Accounts Receivable"] = {
default: "Due Date",
},
{
fieldname: "range1",
label: __("Ageing Range 1"),
fieldtype: "Int",
default: "30",
reqd: 1,
},
{
fieldname: "range2",
label: __("Ageing Range 2"),
fieldtype: "Int",
default: "60",
reqd: 1,
},
{
fieldname: "range3",
label: __("Ageing Range 3"),
fieldtype: "Int",
default: "90",
reqd: 1,
},
{
fieldname: "range4",
label: __("Ageing Range 4"),
fieldtype: "Int",
default: "120",
reqd: 1,
fieldname: "range",
label: __("Ageing Range"),
fieldtype: "Data",
default: "30, 60, 90, 120",
},
{
fieldname: "customer_group",

View File

@@ -50,6 +50,11 @@ class ReceivablePayableReport:
getdate(nowdate()) if self.filters.report_date > getdate(nowdate()) else self.filters.report_date
)
if not self.filters.range:
self.filters.range = "30, 60, 90, 120"
self.ranges = [num.strip() for num in self.filters.range.split(",") if num.strip().isdigit()]
self.range_numbers = [num for num in range(1, len(self.ranges) + 2)]
def run(self, args):
self.filters.update(args)
self.set_defaults()
@@ -112,6 +117,26 @@ class ReceivablePayableReport:
self.build_data()
def build_voucher_dict(self, ple):
return frappe._dict(
voucher_type=ple.voucher_type,
voucher_no=ple.voucher_no,
party=ple.party,
party_account=ple.account,
posting_date=ple.posting_date,
account_currency=ple.account_currency,
remarks=ple.remarks,
invoiced=0.0,
paid=0.0,
credit_note=0.0,
outstanding=0.0,
invoiced_in_account_currency=0.0,
paid_in_account_currency=0.0,
credit_note_in_account_currency=0.0,
outstanding_in_account_currency=0.0,
cost_center=ple.cost_center,
)
def init_voucher_balance(self):
# build all keys, since we want to exclude vouchers beyond the report date
for ple in self.ple_entries:
@@ -123,24 +148,8 @@ class ReceivablePayableReport:
key = (ple.account, ple.voucher_type, ple.voucher_no, ple.party)
if key not in self.voucher_balance:
self.voucher_balance[key] = frappe._dict(
voucher_type=ple.voucher_type,
voucher_no=ple.voucher_no,
party=ple.party,
party_account=ple.account,
posting_date=ple.posting_date,
account_currency=ple.account_currency,
remarks=ple.remarks,
invoiced=0.0,
paid=0.0,
credit_note=0.0,
outstanding=0.0,
invoiced_in_account_currency=0.0,
paid_in_account_currency=0.0,
credit_note_in_account_currency=0.0,
outstanding_in_account_currency=0.0,
cost_center=ple.cost_center,
)
self.voucher_balance[key] = self.build_voucher_dict(ple)
self.get_invoices(ple)
if self.filters.get("group_by_party"):
@@ -208,6 +217,18 @@ class ReceivablePayableReport:
row = self.voucher_balance.get(key)
# Build and use a separate row for Employee Advances.
# This allows Payments or Journals made against Emp Advance to be processed.
if (
not row
and ple.against_voucher_type == "Employee Advance"
and self.filters.handle_employee_advances
):
_d = self.build_voucher_dict(ple)
_d.voucher_type = ple.against_voucher_type
_d.voucher_no = ple.against_voucher_no
row = self.voucher_balance[key] = _d
if not row:
# no invoice, this is an invoice / stand-alone payment / credit note
if self.filters.get("ignore_accounts"):
@@ -289,8 +310,8 @@ class ReceivablePayableReport:
must_consider = False
if self.filters.get("for_revaluation_journals"):
if (abs(row.outstanding) >= 0.0 / 10**self.currency_precision) or (
abs(row.outstanding_in_account_currency) >= 0.0 / 10**self.currency_precision
if (abs(row.outstanding) >= 1.0 / 10**self.currency_precision) or (
abs(row.outstanding_in_account_currency) >= 1.0 / 10**self.currency_precision
):
must_consider = True
else:
@@ -717,37 +738,22 @@ class ReceivablePayableReport:
# ageing buckets should not have amounts if due date is not reached
if getdate(entry_date) > getdate(self.filters.report_date):
row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0
[setattr(row, f"range{i}", 0.0) for i in self.range_numbers]
row.total_due = row.range1 + row.range2 + row.range3 + row.range4 + row.range5
row.total_due = sum(row[f"range{i}"] for i in self.range_numbers)
def get_ageing_data(self, entry_date, row):
# [0-30, 30-60, 60-90, 90-120, 120-above]
row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0
[setattr(row, f"range{i}", 0.0) for i in self.range_numbers]
if not (self.age_as_on and entry_date):
return
row.age = (getdate(self.age_as_on) - getdate(entry_date)).days or 0
index = None
if not (self.filters.range1 and self.filters.range2 and self.filters.range3 and self.filters.range4):
self.filters.range1, self.filters.range2, self.filters.range3, self.filters.range4 = (
30,
60,
90,
120,
)
for i, days in enumerate(
[self.filters.range1, self.filters.range2, self.filters.range3, self.filters.range4]
):
if cint(row.age) <= cint(days):
index = i
break
if index is None:
index = 4
index = next(
(i for i, days in enumerate(self.ranges) if cint(row.age) <= cint(days)), len(self.ranges)
)
row["range" + str(index + 1)] = row.outstanding
def get_ple_entries(self):
@@ -1059,6 +1065,7 @@ class ReceivablePayableReport:
self.add_column(_("Debit Note"), fieldname="credit_note")
self.add_column(_("Outstanding Amount"), fieldname="outstanding")
self.add_column(label=_("Age (Days)"), fieldname="age", fieldtype="Int", width=80)
self.setup_ageing_columns()
self.add_column(
@@ -1117,34 +1124,26 @@ class ReceivablePayableReport:
def setup_ageing_columns(self):
# for charts
self.ageing_column_labels = []
self.add_column(label=_("Age (Days)"), fieldname="age", fieldtype="Int", width=80)
ranges = [*self.ranges, "Above"]
prev_range_value = 0
for idx, curr_range_value in enumerate(ranges):
label = f"{prev_range_value}-{curr_range_value}"
self.add_column(label=label, fieldname="range" + str(idx + 1))
for i, label in enumerate(
[
"0-{range1}".format(range1=self.filters["range1"]),
"{range1}-{range2}".format(
range1=cint(self.filters["range1"]) + 1, range2=self.filters["range2"]
),
"{range2}-{range3}".format(
range2=cint(self.filters["range2"]) + 1, range3=self.filters["range3"]
),
"{range3}-{range4}".format(
range3=cint(self.filters["range3"]) + 1, range4=self.filters["range4"]
),
_("{range4}-Above").format(range4=cint(self.filters["range4"]) + 1),
]
):
self.add_column(label=label, fieldname="range" + str(i + 1))
self.ageing_column_labels.append(label)
if curr_range_value.isdigit():
prev_range_value = cint(curr_range_value) + 1
def get_chart_data(self):
precision = cint(frappe.db.get_default("float_precision")) or 2
rows = []
for row in self.data:
row = frappe._dict(row)
if not cint(row.bold):
values = [row.range1, row.range2, row.range3, row.range4, row.range5]
precision = cint(frappe.db.get_default("float_precision")) or 2
rows.append({"values": [flt(val, precision) for val in values]})
values = [flt(row.get(f"range{i}", None), precision) for i in self.range_numbers]
rows.append({"values": values})
self.chart = {
"data": {"labels": self.ageing_column_labels, "datasets": rows},

View File

@@ -83,10 +83,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
"party": [self.customer],
"report_date": add_days(today(), 2),
"based_on_payment_terms": 0,
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
"show_remarks": False,
}
@@ -116,10 +113,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
"company": self.company,
"based_on_payment_terms": 1,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
"show_remarks": True,
}
@@ -172,10 +166,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
"show_remarks": True,
}
@@ -266,10 +257,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
"company": self.company,
"based_on_payment_terms": 0,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
}
report = execute(filters)
@@ -328,10 +316,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
}
report = execute(filters)
@@ -397,10 +382,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
}
report = execute(filters)
self.assertEqual(report[1], [])
@@ -416,10 +398,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
"group_by_party": True,
}
report = execute(filters)[1]
@@ -493,10 +472,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
"show_future_payments": True,
}
report = execute(filters)[1]
@@ -555,10 +531,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
"sales_person": sales_person.name,
"show_sales_person": True,
}
@@ -575,10 +548,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
"cost_center": self.cost_center,
}
report = execute(filters)[1]
@@ -593,10 +563,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
"customer_group": cus_group,
}
report = execute(filters)[1]
@@ -618,10 +585,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
"customer_group": cus_groups_list, # Use the list of customer groups
}
report = execute(filters)[1]
@@ -660,10 +624,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
"party_account": self.debit_to,
}
report = execute(filters)[1]
@@ -711,10 +672,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
"party_type": "Customer",
"party": [self.customer],
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
"in_party_currency": 1,
}
@@ -754,10 +712,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
"party_type": "Customer",
"party": [self.customer1, self.customer3],
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
}
si1 = self.create_sales_invoice(no_payment_schedule=True, do_not_submit=True)
@@ -837,10 +792,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
}
report_ouput = execute(filters)[1]
@@ -903,10 +855,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
{
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
"show_future_payments": True,
"in_party_currency": False,
}
@@ -965,10 +914,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
}
# check invoice grand total and invoiced column's value for 3 payment terms
@@ -991,10 +937,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
}
# check invoice grand total and invoiced column's value for 3 payment terms

View File

@@ -24,32 +24,10 @@ frappe.query_reports["Accounts Receivable Summary"] = {
default: "Due Date",
},
{
fieldname: "range1",
label: __("Ageing Range 1"),
fieldtype: "Int",
default: "30",
reqd: 1,
},
{
fieldname: "range2",
label: __("Ageing Range 2"),
fieldtype: "Int",
default: "60",
reqd: 1,
},
{
fieldname: "range3",
label: __("Ageing Range 3"),
fieldtype: "Int",
default: "90",
reqd: 1,
},
{
fieldname: "range4",
label: __("Ageing Range 4"),
fieldtype: "Int",
default: "120",
reqd: 1,
fieldname: "range",
label: __("Ageing Range"),
fieldtype: "Data",
default: "30, 60, 90, 120",
},
{
fieldname: "finance_book",

View File

@@ -104,25 +104,23 @@ class AccountsReceivableSummary(ReceivablePayableReport):
self.set_party_details(d)
def init_party_total(self, row):
default_dict = {
"invoiced": 0.0,
"paid": 0.0,
"credit_note": 0.0,
"outstanding": 0.0,
"total_due": 0.0,
"future_amount": 0.0,
"sales_person": [],
"party_type": row.party_type,
}
for i in self.range_numbers:
range_key = f"range{i}"
default_dict[range_key] = 0.0
self.party_total.setdefault(
row.party,
frappe._dict(
{
"invoiced": 0.0,
"paid": 0.0,
"credit_note": 0.0,
"outstanding": 0.0,
"range1": 0.0,
"range2": 0.0,
"range3": 0.0,
"range4": 0.0,
"range5": 0.0,
"total_due": 0.0,
"future_amount": 0.0,
"sales_person": [],
"party_type": row.party_type,
}
),
frappe._dict(default_dict),
)
def set_party_details(self, row):
@@ -173,6 +171,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
self.add_column(_("Difference"), fieldname="diff")
self.setup_ageing_columns()
self.add_column(label="Total Amount Due", fieldname="total_due")
if self.filters.show_future_payments:
self.add_column(label=_("Future Payment Amount"), fieldname="future_amount")
@@ -206,27 +205,6 @@ class AccountsReceivableSummary(ReceivablePayableReport):
label=_("Currency"), fieldname="currency", fieldtype="Link", options="Currency", width=80
)
def setup_ageing_columns(self):
for i, label in enumerate(
[
"0-{range1}".format(range1=self.filters["range1"]),
"{range1}-{range2}".format(
range1=cint(self.filters["range1"]) + 1, range2=self.filters["range2"]
),
"{range2}-{range3}".format(
range2=cint(self.filters["range2"]) + 1, range3=self.filters["range3"]
),
"{range3}-{range4}".format(
range3=cint(self.filters["range3"]) + 1, range4=self.filters["range4"]
),
"{range4}-{above}".format(range4=cint(self.filters["range4"]) + 1, above=_("Above")),
]
):
self.add_column(label=label, fieldname="range" + str(i + 1))
# Add column for total due amount
self.add_column(label="Total Amount Due", fieldname="total_due")
def get_gl_balance(report_date, company):
return frappe._dict(

View File

@@ -27,10 +27,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
"company": self.company,
"customer": self.customer,
"posting_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
}
si = create_sales_invoice(
@@ -121,10 +118,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
"company": self.company,
"customer": self.customer,
"posting_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"range": "30, 60, 90, 120",
}
si = create_sales_invoice(

View File

@@ -46,5 +46,11 @@ frappe.query_reports["Asset Depreciations and Balances"] = {
options: "Asset",
depends_on: "eval: doc.group_by == 'Asset'",
},
{
fieldname: "finance_book",
label: __("Finance Book"),
fieldtype: "Link",
options: "Finance Book",
},
],
};

View File

@@ -36,6 +36,7 @@ def get_group_by_asset_category_data(filters):
+ flt(row.cost_of_new_purchase)
- flt(row.cost_of_sold_asset)
- flt(row.cost_of_scrapped_asset)
- flt(row.cost_of_capitalized_asset)
)
row.update(
@@ -68,7 +69,10 @@ def get_group_by_asset_category_data(filters):
def get_asset_categories_for_grouped_by_category(filters):
condition = ""
if filters.get("asset_category"):
condition += " and asset_category = %(asset_category)s"
condition += " and a.asset_category = %(asset_category)s"
if filters.get("finance_book"):
condition += " and exists (select 1 from `tabAsset Depreciation Schedule` ads where ads.asset = a.name and ads.finance_book = %(finance_book)s)"
# nosemgrep
return frappe.db.sql(
f"""
@@ -108,10 +112,26 @@ def get_asset_categories_for_grouped_by_category(filters):
end
else
0
end), 0) as cost_of_scrapped_asset
end), 0) as cost_of_scrapped_asset,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s then
case when a.status = "Capitalized" then
a.gross_purchase_amount
else
0
end
else
0
end), 0) as cost_of_capitalized_asset
from `tabAsset` a
where docstatus=1 and company=%(company)s and purchase_date <= %(to_date)s {condition}
and not exists(select name from `tabAsset Capitalization Asset Item` where asset = a.name)
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s {condition}
and not exists(
select 1 from `tabAsset Capitalization Asset Item` acai join `tabAsset Capitalization` ac on acai.parent=ac.name
where acai.asset = a.name
and ac.posting_date < %(from_date)s
and ac.docstatus=1
)
group by a.asset_category
""",
{
@@ -119,6 +139,7 @@ def get_asset_categories_for_grouped_by_category(filters):
"from_date": filters.from_date,
"company": filters.company,
"asset_category": filters.get("asset_category"),
"finance_book": filters.get("finance_book"),
},
as_dict=1,
)
@@ -127,55 +148,77 @@ def get_asset_categories_for_grouped_by_category(filters):
def get_asset_details_for_grouped_by_category(filters):
condition = ""
if filters.get("asset"):
condition += " and name = %(asset)s"
condition += " and a.name = %(asset)s"
if filters.get("finance_book"):
condition += " and exists (select 1 from `tabAsset Depreciation Schedule` ads where ads.asset = a.name and ads.finance_book = %(finance_book)s)"
# nosemgrep
return frappe.db.sql(
f"""
SELECT name,
ifnull(sum(case when purchase_date < %(from_date)s then
case when ifnull(disposal_date, 0) = 0 or disposal_date >= %(from_date)s then
gross_purchase_amount
SELECT a.name,
ifnull(sum(case when a.purchase_date < %(from_date)s then
case when ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s then
a.gross_purchase_amount
else
0
end
else
0
end), 0) as cost_as_on_from_date,
ifnull(sum(case when purchase_date >= %(from_date)s then
gross_purchase_amount
ifnull(sum(case when a.purchase_date >= %(from_date)s then
a.gross_purchase_amount
else
0
end), 0) as cost_of_new_purchase,
ifnull(sum(case when ifnull(disposal_date, 0) != 0
and disposal_date >= %(from_date)s
and disposal_date <= %(to_date)s then
case when status = "Sold" then
gross_purchase_amount
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s then
case when a.status = "Sold" then
a.gross_purchase_amount
else
0
end
else
0
end), 0) as cost_of_sold_asset,
ifnull(sum(case when ifnull(disposal_date, 0) != 0
and disposal_date >= %(from_date)s
and disposal_date <= %(to_date)s then
case when status = "Scrapped" then
gross_purchase_amount
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s then
case when a.status = "Scrapped" then
a.gross_purchase_amount
else
0
end
else
0
end), 0) as cost_of_scrapped_asset
from `tabAsset`
where docstatus=1 and company=%(company)s and purchase_date <= %(to_date)s {condition}
group by name
end), 0) as cost_of_scrapped_asset,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s then
case when a.status = "Capitalized" then
a.gross_purchase_amount
else
0
end
else
0
end), 0) as cost_of_capitalized_asset
from `tabAsset` a
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s {condition}
and not exists(
select 1 from `tabAsset Capitalization Asset Item` acai join `tabAsset Capitalization` ac on acai.parent=ac.name
where acai.asset = a.name
and ac.posting_date < %(from_date)s
and ac.docstatus=1
)
group by a.name
""",
{
"to_date": filters.to_date,
"from_date": filters.from_date,
"company": filters.company,
"asset": filters.get("asset"),
"finance_book": filters.get("finance_book"),
},
as_dict=1,
)
@@ -197,6 +240,7 @@ def get_group_by_asset_data(filters):
+ flt(row.cost_of_new_purchase)
- flt(row.cost_of_sold_asset)
- flt(row.cost_of_scrapped_asset)
- flt(row.cost_of_capitalized_asset)
)
row.update(next(asset for asset in assets if asset["asset"] == asset_detail.get("name", "")))
@@ -223,9 +267,15 @@ def get_group_by_asset_data(filters):
def get_assets_for_grouped_by_category(filters):
condition = ""
if filters.get("asset_category"):
condition = " and a.asset_category = '{}'".format(filters.get("asset_category"))
condition = f" and a.asset_category = '{filters.get('asset_category')}'"
finance_book_filter = ""
if filters.get("finance_book"):
finance_book_filter += " and ifnull(gle.finance_book, '')=%(finance_book)s"
condition += " and exists (select 1 from `tabAsset Depreciation Schedule` ads where ads.asset = a.name and ads.finance_book = %(finance_book)s)"
# nosemgrep
return frappe.db.sql(
"""
f"""
SELECT results.asset_category,
sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date,
sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
@@ -255,7 +305,14 @@ def get_assets_for_grouped_by_category(filters):
aca.parent = a.asset_category and aca.company_name = %(company)s
join `tabCompany` company on
company.name = %(company)s
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and gle.debit != 0 and gle.is_cancelled = 0 and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account) {0}
where
a.docstatus=1
and a.company=%(company)s
and a.purchase_date <= %(to_date)s
and gle.debit != 0
and gle.is_cancelled = 0
and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account)
{condition} {finance_book_filter}
group by a.asset_category
union
SELECT a.asset_category,
@@ -271,11 +328,16 @@ def get_assets_for_grouped_by_category(filters):
end), 0) as depreciation_eliminated_during_the_period,
0 as depreciation_amount_during_the_period
from `tabAsset` a
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s {0}
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s {condition}
group by a.asset_category) as results
group by results.asset_category
""".format(condition),
{"to_date": filters.to_date, "from_date": filters.from_date, "company": filters.company},
""",
{
"to_date": filters.to_date,
"from_date": filters.from_date,
"company": filters.company,
"finance_book": filters.get("finance_book", ""),
},
as_dict=1,
)
@@ -283,9 +345,15 @@ def get_assets_for_grouped_by_category(filters):
def get_assets_for_grouped_by_asset(filters):
condition = ""
if filters.get("asset"):
condition = " and a.name = '{}'".format(filters.get("asset"))
condition = f" and a.name = '{filters.get('asset')}'"
finance_book_filter = ""
if filters.get("finance_book"):
finance_book_filter += " and ifnull(gle.finance_book, '')=%(finance_book)s"
condition += " and exists (select 1 from `tabAsset Depreciation Schedule` ads where ads.asset = a.name and ads.finance_book = %(finance_book)s)"
# nosemgrep
return frappe.db.sql(
"""
f"""
SELECT results.name as asset,
sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date,
sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
@@ -315,7 +383,14 @@ def get_assets_for_grouped_by_asset(filters):
aca.parent = a.asset_category and aca.company_name = %(company)s
join `tabCompany` company on
company.name = %(company)s
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and gle.debit != 0 and gle.is_cancelled = 0 and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account) {0}
where
a.docstatus=1
and a.company=%(company)s
and a.purchase_date <= %(to_date)s
and gle.debit != 0
and gle.is_cancelled = 0
and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account)
{finance_book_filter} {condition}
group by a.name
union
SELECT a.name as name,
@@ -331,11 +406,16 @@ def get_assets_for_grouped_by_asset(filters):
end), 0) as depreciation_eliminated_during_the_period,
0 as depreciation_amount_during_the_period
from `tabAsset` a
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s {0}
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s {condition}
group by a.name) as results
group by results.name
""".format(condition),
{"to_date": filters.to_date, "from_date": filters.from_date, "company": filters.company},
""",
{
"to_date": filters.to_date,
"from_date": filters.from_date,
"company": filters.company,
"finance_book": filters.get("finance_book", ""),
},
as_dict=1,
)
@@ -389,6 +469,12 @@ def get_columns(filters):
"fieldtype": "Currency",
"width": 140,
},
{
"label": _("Cost of New Capitalized Asset"),
"fieldname": "cost_of_capitalized_asset",
"fieldtype": "Currency",
"width": 140,
},
{
"label": _("Cost as on") + " " + formatdate(filters.to_date),
"fieldname": "cost_as_on_to_date",

View File

@@ -95,7 +95,7 @@ def execute(filters=None):
filters.periodicity, period_list, filters.accumulated_values, company=filters.company
)
chart = get_chart_data(filters, columns, asset, liability, equity)
chart = get_chart_data(filters, columns, asset, liability, equity, currency)
report_summary, primitive_summary = get_report_summary(
period_list, asset, liability, equity, provisional_profit_loss, currency, filters
@@ -221,7 +221,7 @@ def get_report_summary(
], (net_asset - net_liability + net_equity)
def get_chart_data(filters, columns, asset, liability, equity):
def get_chart_data(filters, columns, asset, liability, equity, currency):
labels = [d.get("label") for d in columns[2:]]
asset_data, liability_data, equity_data = [], [], []
@@ -249,4 +249,8 @@ def get_chart_data(filters, columns, asset, liability, equity):
else:
chart["type"] = "line"
chart["fieldtype"] = "Currency"
chart["options"] = "currency"
chart["currency"] = currency
return chart

View File

@@ -46,4 +46,20 @@ frappe.query_reports["Bank Reconciliation Statement"] = {
fieldtype: "Check",
},
],
formatter: function (value, row, column, data, default_formatter, filter) {
if (column.fieldname == "payment_entry" && value == __("Cheques and Deposits incorrectly cleared")) {
column.link_onclick =
"frappe.query_reports['Bank Reconciliation Statement'].open_utility_report()";
}
return default_formatter(value, row, column, data);
},
open_utility_report: function () {
frappe.route_options = {
company: frappe.query_report.get_filter_value("company"),
account: frappe.query_report.get_filter_value("account"),
report_date: frappe.query_report.get_filter_value("report_date"),
};
frappe.open_in_new_tab = true;
frappe.set_route("query-report", "Cheques and Deposits Incorrectly cleared");
},
};

View File

@@ -154,8 +154,8 @@ def get_payment_entries(filters):
select
"Payment Entry" as payment_document, name as payment_entry,
reference_no, reference_date as ref_date,
if(paid_to=%(account)s, received_amount, 0) as debit,
if(paid_from=%(account)s, paid_amount, 0) as credit,
if(paid_to=%(account)s, received_amount_after_tax, 0) as debit,
if(paid_from=%(account)s, paid_amount_after_tax, 0) as credit,
posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date,
if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
from `tabPayment Entry`

View File

@@ -111,7 +111,7 @@ def execute(filters=None):
)
columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, filters.company)
chart = get_chart_data(columns, data)
chart = get_chart_data(columns, data, company_currency)
report_summary = get_report_summary(summary_data, company_currency)
@@ -252,7 +252,7 @@ def get_report_summary(summary_data, currency):
return report_summary
def get_chart_data(columns, data):
def get_chart_data(columns, data, currency):
labels = [d.get("label") for d in columns[2:]]
datasets = [
{
@@ -267,5 +267,7 @@ def get_chart_data(columns, data):
chart = {"data": {"labels": labels, "datasets": datasets}, "type": "bar"}
chart["fieldtype"] = "Currency"
chart["options"] = "currency"
chart["currency"] = currency
return chart

View File

@@ -0,0 +1,44 @@
// Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.query_reports["Cheques and Deposits Incorrectly cleared"] = {
filters: [
{
fieldname: "company",
label: __("Company"),
fieldtype: "Link",
options: "Company",
reqd: 1,
default: frappe.defaults.get_user_default("Company"),
},
{
fieldname: "account",
label: __("Bank Account"),
fieldtype: "Link",
options: "Account",
default: frappe.defaults.get_user_default("Company")
? locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"]
: "",
reqd: 1,
get_query: function () {
var company = frappe.query_report.get_filter_value("company");
return {
query: "erpnext.controllers.queries.get_account_list",
filters: [
["Account", "account_type", "in", "Bank, Cash"],
["Account", "is_group", "=", 0],
["Account", "disabled", "=", 0],
["Account", "company", "=", company],
],
};
},
},
{
fieldname: "report_date",
label: __("Date"),
fieldtype: "Date",
default: frappe.datetime.get_today(),
reqd: 1,
},
],
};

View File

@@ -0,0 +1,29 @@
{
"add_total_row": 0,
"columns": [],
"creation": "2024-07-30 17:20:07.570971",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 0,
"is_standard": "Yes",
"letterhead": null,
"modified": "2024-07-30 17:20:07.570971",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Cheques and Deposits Incorrectly cleared",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Payment Entry",
"report_name": "Cheques and Deposits Incorrectly cleared",
"report_type": "Script Report",
"roles": [
{
"role": "Accounts User"
},
{
"role": "Accounts Manager"
}
]
}

View File

@@ -0,0 +1,153 @@
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe import _, qb
from frappe.query_builder import CustomFunction
from frappe.query_builder.custom import ConstantColumn
def execute(filters=None):
columns = get_columns()
data = build_data(filters)
return columns, data
def build_payment_entry_dict(row: dict) -> dict:
row_dict = frappe._dict()
row_dict.update(
{
"payment_document": row.get("doctype"),
"payment_entry": row.get("name"),
"posting_date": row.get("posting_date"),
"clearance_date": row.get("clearance_date"),
}
)
if row.get("payment_type") == "Receive" and row.get("party_type") in ["Customer", "Supplier"]:
row_dict.update(
{
"debit": row.get("amount"),
"credit": 0,
}
)
else:
row_dict.update(
{
"debit": 0,
"credit": row.get("amount"),
}
)
return row_dict
def build_journal_entry_dict(row: dict) -> dict:
row_dict = frappe._dict()
row_dict.update(
{
"payment_document": row.get("doctype"),
"payment_entry": row.get("name"),
"posting_date": row.get("posting_date"),
"clearance_date": row.get("clearance_date"),
"debit": row.get("debit_in_account_currency"),
"credit": row.get("credit_in_account_currency"),
}
)
return row_dict
def build_data(filters):
vouchers = get_amounts_not_reflected_in_system_for_bank_reconciliation_statement(filters)
data = []
for x in vouchers:
if x.doctype == "Payment Entry":
data.append(build_payment_entry_dict(x))
elif x.doctype == "Journal Entry":
data.append(build_journal_entry_dict(x))
return data
def get_amounts_not_reflected_in_system_for_bank_reconciliation_statement(filters):
je = qb.DocType("Journal Entry")
jea = qb.DocType("Journal Entry Account")
doctype_name = ConstantColumn("Journal Entry")
journals = (
qb.from_(je)
.inner_join(jea)
.on(je.name == jea.parent)
.select(
doctype_name.as_("doctype"),
je.name,
jea.debit_in_account_currency,
jea.credit_in_account_currency,
je.posting_date,
je.clearance_date,
)
.where(
je.docstatus.eq(1)
& jea.account.eq(filters.account)
& je.posting_date.gt(filters.report_date)
& je.clearance_date.lte(filters.report_date)
& (je.is_opening.isnull() | je.is_opening.eq("No"))
)
.run(as_dict=1)
)
ifelse = CustomFunction("IF", ["condition", "then", "else"])
pe = qb.DocType("Payment Entry")
doctype_name = ConstantColumn("Payment Entry")
payments = (
qb.from_(pe)
.select(
doctype_name.as_("doctype"),
pe.name,
ifelse(pe.paid_from.eq(filters.account), pe.paid_amount, pe.received_amount).as_("amount"),
pe.payment_type,
pe.party_type,
pe.posting_date,
pe.clearance_date,
)
.where(
pe.docstatus.eq(1)
& (pe.paid_from.eq(filters.account) | pe.paid_to.eq(filters.account))
& pe.posting_date.gt(filters.report_date)
& pe.clearance_date.lte(filters.report_date)
)
.run(as_dict=1)
)
return journals + payments
def get_columns():
return [
{
"fieldname": "payment_document",
"label": _("Payment Document Type"),
"fieldtype": "Data",
"width": 220,
},
{
"fieldname": "payment_entry",
"label": _("Payment Document"),
"fieldtype": "Dynamic Link",
"options": "payment_document",
"width": 220,
},
{
"fieldname": "debit",
"label": _("Debit"),
"fieldtype": "Currency",
"options": "account_currency",
"width": 120,
},
{
"fieldname": "credit",
"label": _("Credit"),
"fieldtype": "Currency",
"options": "account_currency",
"width": 120,
},
{"fieldname": "posting_date", "label": _("Posting Date"), "fieldtype": "Date", "width": 110},
{"fieldname": "clearance_date", "label": _("Clearance Date"), "fieldtype": "Date", "width": 110},
]

View File

@@ -104,7 +104,7 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters):
if total_credit:
data.append(total_credit)
report_summary = get_bs_summary(
report_summary, primitive_summary = get_bs_summary(
companies,
asset,
liability,
@@ -115,7 +115,7 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters):
True,
)
chart = get_chart_data(filters, columns, asset, liability, equity)
chart = get_chart_data(filters, columns, asset, liability, equity, company_currency)
return data, message, chart, report_summary
@@ -173,9 +173,9 @@ def get_profit_loss_data(fiscal_year, companies, columns, filters):
if net_profit_loss:
data.append(net_profit_loss)
chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss)
chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss, company_currency)
report_summary = get_pl_summary(
report_summary, primitive_summary = get_pl_summary(
companies, "", income, expense, net_profit_loss, company_currency, filters, True
)
@@ -469,10 +469,13 @@ def update_parent_account_names(accounts):
for d in accounts:
if d.account_number:
account_name = d.account_number + " - " + d.account_name
account_key = d.account_number + " - " + d.account_name
else:
account_name = d.account_name
name_to_account_map[d.name] = account_name
account_key = d.account_name
d.account_key = account_key
name_to_account_map[d.name] = account_key
for account in accounts:
if account.parent_account:
@@ -505,33 +508,26 @@ def get_subsidiary_companies(company):
def get_accounts(root_type, companies):
accounts = []
added_accounts = []
for company in companies:
for account in frappe.get_all(
"Account",
fields=[
"name",
"is_group",
"company",
"parent_account",
"lft",
"rgt",
"root_type",
"report_type",
"account_name",
"account_number",
],
filters={"company": company, "root_type": root_type},
):
if account.account_number:
account_key = account.account_number + "-" + account.account_name
else:
account_key = account.account_name
if account_key not in added_accounts:
accounts.append(account)
added_accounts.append(account_key)
accounts.extend(
frappe.get_all(
"Account",
fields=[
"name",
"is_group",
"company",
"parent_account",
"lft",
"rgt",
"root_type",
"report_type",
"account_name",
"account_number",
],
filters={"company": company, "root_type": root_type},
)
)
return accounts
@@ -770,15 +766,17 @@ def add_total_row(out, root_type, balance_must_be, companies, company_currency):
def filter_accounts(accounts, depth=10):
parent_children_map = {}
accounts_by_name = {}
for d in accounts:
if d.account_number:
account_name = d.account_number + " - " + d.account_name
else:
account_name = d.account_name
d["company_wise_opening_bal"] = defaultdict(float)
accounts_by_name[account_name] = d
added_accounts = []
parent_children_map.setdefault(d.parent_account or None, []).append(d)
for d in accounts:
if d.account_key in added_accounts:
continue
added_accounts.append(d.account_key)
d["company_wise_opening_bal"] = defaultdict(float)
accounts_by_name[d.account_key] = d
parent_children_map.setdefault(d.parent_account_name or None, []).append(d)
filtered_accounts = []
@@ -790,7 +788,7 @@ def filter_accounts(accounts, depth=10):
for child in children:
child.indent = level
filtered_accounts.append(child)
add_to_list(child.name, level + 1)
add_to_list(child.account_key, level + 1)
add_to_list(None, 0)

View File

@@ -199,8 +199,7 @@ class General_Payment_Ledger_Comparison:
dict(
label=_("Voucher Type"),
fieldname="voucher_type",
fieldtype="Link",
options="DocType",
fieldtype="Data",
width="100",
)
)
@@ -219,8 +218,7 @@ class General_Payment_Ledger_Comparison:
dict(
label=_("Party Type"),
fieldname="party_type",
fieldtype="Link",
options="DocType",
fieldtype="Data",
width="100",
)
)

View File

@@ -48,8 +48,9 @@
<br>
{% } %}
<br>{%= __("Remarks") %}: {%= data[i].remarks %}
{% if(data[i].bill_no) { %}
{% if(data[i].remarks) { %}
<br>{%= __("Remarks") %}: {%= data[i].remarks %}
{% } else if(data[i].bill_no) { %}
<br>{%= __("Supplier Invoice No") %}: {%= data[i].bill_no %}
{% } %}
</span>

View File

@@ -209,6 +209,11 @@ frappe.query_reports["General Ledger"] = {
label: __("Ignore Exchange Rate Revaluation Journals"),
fieldtype: "Check",
},
{
fieldname: "ignore_cr_dr_notes",
label: __("Ignore System Generated Credit / Debit Notes"),
fieldtype: "Check",
},
],
};

View File

@@ -35,6 +35,9 @@ def execute(filters=None):
if filters.get("party"):
filters.party = frappe.parse_json(filters.get("party"))
if filters.get("voucher_no") and not filters.get("group_by"):
filters.group_by = "Group by Voucher (Consolidated)"
validate_filters(filters, account_details)
validate_party(filters)
@@ -236,6 +239,23 @@ def get_conditions(filters):
if err_journals:
filters.update({"voucher_no_not_in": [x[0] for x in err_journals]})
if filters.get("ignore_cr_dr_notes"):
system_generated_cr_dr_journals = frappe.db.get_all(
"Journal Entry",
filters={
"company": filters.get("company"),
"docstatus": 1,
"voucher_type": ("in", ["Credit Note", "Debit Note"]),
"is_system_generated": 1,
},
as_list=True,
)
if system_generated_cr_dr_journals:
vouchers_to_ignore = (filters.get("voucher_no_not_in") or []) + [
x[0] for x in system_generated_cr_dr_journals
]
filters.update({"voucher_no_not_in": vouchers_to_ignore})
if filters.get("voucher_no_not_in"):
conditions.append("voucher_no not in %(voucher_no_not_in)s")

View File

@@ -2,13 +2,32 @@
# MIT License. See license.txt
import frappe
from frappe import qb
from frappe.tests.utils import FrappeTestCase
from frappe.utils import flt, today
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.report.general_ledger.general_ledger import execute
from erpnext.controllers.sales_and_purchase_return import make_return_doc
class TestGeneralLedger(FrappeTestCase):
def setUp(self):
self.company = "_Test Company"
self.clear_old_entries()
def clear_old_entries(self):
doctype_list = [
"GL Entry",
"Payment Ledger Entry",
"Sales Invoice",
"Purchase Invoice",
"Payment Entry",
"Journal Entry",
]
for doctype in doctype_list:
qb.from_(qb.DocType(doctype)).delete().where(qb.DocType(doctype).company == self.company).run()
def test_foreign_account_balance_after_exchange_rate_revaluation(self):
"""
Checks the correctness of balance after exchange rate revaluation
@@ -248,3 +267,68 @@ class TestGeneralLedger(FrappeTestCase):
)
)
self.assertIn(revaluation_jv.name, set([x.voucher_no for x in data]))
def test_ignore_cr_dr_notes_filter(self):
si = create_sales_invoice()
cr_note = make_return_doc(si.doctype, si.name)
cr_note.submit()
pr = frappe.get_doc("Payment Reconciliation")
pr.company = si.company
pr.party_type = "Customer"
pr.party = si.customer
pr.receivable_payable_account = si.debit_to
pr.get_unreconciled_entries()
invoices = [invoice.as_dict() for invoice in pr.invoices if invoice.invoice_number == si.name]
payments = [payment.as_dict() for payment in pr.payments if payment.reference_name == cr_note.name]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
pr.reconcile()
system_generated_journal = frappe.db.get_all(
"Journal Entry",
filters={
"docstatus": 1,
"reference_type": si.doctype,
"reference_name": si.name,
"voucher_type": "Credit Note",
"is_system_generated": True,
},
fields=["name"],
)
self.assertEqual(len(system_generated_journal), 1)
expected = set([si.name, cr_note.name, system_generated_journal[0].name])
# Without ignore_cr_dr_notes
columns, data = execute(
frappe._dict(
{
"company": si.company,
"from_date": si.posting_date,
"to_date": si.posting_date,
"account": [si.debit_to],
"group_by": "Group by Voucher (Consolidated)",
"ignore_cr_dr_notes": False,
}
)
)
actual = set([x.voucher_no for x in data if x.voucher_no])
self.assertEqual(expected, actual)
# Without ignore_cr_dr_notes
expected = set([si.name, cr_note.name])
columns, data = execute(
frappe._dict(
{
"company": si.company,
"from_date": si.posting_date,
"to_date": si.posting_date,
"account": [si.debit_to],
"group_by": "Group by Voucher (Consolidated)",
"ignore_cr_dr_notes": True,
}
)
)
actual = set([x.voucher_no for x in data if x.voucher_no])
self.assertEqual(expected, actual)

View File

@@ -0,0 +1,51 @@
// Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
function get_filters() {
let filters = [
{
fieldname: "company",
label: __("Company"),
fieldtype: "Link",
options: "Company",
default: frappe.defaults.get_user_default("Company"),
reqd: 1,
},
{
fieldname: "from_date",
label: __("Start Date"),
fieldtype: "Date",
reqd: 1,
default: frappe.datetime.add_months(frappe.datetime.get_today(), -1),
},
{
fieldname: "to_date",
label: __("End Date"),
fieldtype: "Date",
reqd: 1,
default: frappe.datetime.get_today(),
},
{
fieldname: "account",
label: __("Account"),
fieldtype: "MultiSelectList",
options: "Account",
get_data: function (txt) {
return frappe.db.get_link_options("Account", txt, {
company: frappe.query_report.get_filter_value("company"),
});
},
},
{
fieldname: "voucher_no",
label: __("Voucher No"),
fieldtype: "Data",
width: 100,
},
];
return filters;
}
frappe.query_reports["Invalid Ledger Entries"] = {
filters: get_filters(),
};

View File

@@ -0,0 +1,23 @@
{
"add_total_row": 0,
"columns": [],
"creation": "2024-09-09 12:31:25.295976",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 0,
"is_standard": "Yes",
"letterhead": null,
"modified": "2024-09-09 12:31:25.295976",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Invalid Ledger Entries",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "GL Entry",
"report_name": "Invalid Ledger Entries",
"report_type": "Script Report",
"roles": [],
"timeout": 0
}

View File

@@ -0,0 +1,137 @@
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe import _, qb
from frappe.query_builder import Criterion
from frappe.query_builder.custom import ConstantColumn
def execute(filters: dict | None = None):
"""Return columns and data for the report.
This is the main entry point for the report. It accepts the filters as a
dictionary and should return columns and data. It is called by the framework
every time the report is refreshed or a filter is updated.
"""
validate_filters(filters)
columns = get_columns()
data = get_data(filters)
return columns, data
def get_columns() -> list[dict]:
"""Return columns for the report.
One field definition per column, just like a DocType field definition.
"""
return [
{"label": _("Voucher Type"), "fieldname": "voucher_type", "fieldtype": "Link", "options": "DocType"},
{
"label": _("Voucher No"),
"fieldname": "voucher_no",
"fieldtype": "Dynamic Link",
"options": "voucher_type",
},
]
def get_data(filters) -> list[list]:
"""Return data for the report.
The report data is a list of rows, with each row being a list of cell values.
"""
active_vouchers = get_active_vouchers_for_period(filters)
invalid_vouchers = identify_cancelled_vouchers(active_vouchers)
return invalid_vouchers
def identify_cancelled_vouchers(active_vouchers: list[dict] | list | None = None) -> list[dict]:
cancelled_vouchers = []
if active_vouchers:
# Group by voucher types and use single query to identify cancelled vouchers
vtypes = set([x.voucher_type for x in active_vouchers])
for _t in vtypes:
_names = [x.voucher_no for x in active_vouchers if x.voucher_type == _t]
dt = qb.DocType(_t)
non_active_vouchers = (
qb.from_(dt)
.select(ConstantColumn(_t).as_("voucher_type"), dt.name.as_("voucher_no"))
.where(dt.docstatus.ne(1) & dt.name.isin(_names))
.run(as_dict=True)
)
if non_active_vouchers:
cancelled_vouchers.extend(non_active_vouchers)
return cancelled_vouchers
def validate_filters(filters: dict | None = None):
if not filters:
frappe.throw(_("Filters missing"))
if not filters.company:
frappe.throw(_("Company is mandatory"))
if filters.from_date > filters.to_date:
frappe.throw(_("Start Date should be lower than End Date"))
def build_query_filters(filters: dict | None = None) -> list:
qb_filters = []
if filters:
if filters.account:
qb_filters.append(qb.Field("account").isin(filters.account))
if filters.voucher_no:
qb_filters.append(qb.Field("voucher_no").eq(filters.voucher_no))
return qb_filters
def get_active_vouchers_for_period(filters: dict | None = None) -> list[dict]:
uniq_vouchers = []
if filters:
gle = qb.DocType("GL Entry")
ple = qb.DocType("Payment Ledger Entry")
qb_filters = build_query_filters(filters)
gl_vouchers = (
qb.from_(gle)
.select(gle.voucher_type)
.distinct()
.select(gle.voucher_no)
.distinct()
.where(
gle.is_cancelled.eq(0)
& gle.company.eq(filters.company)
& gle.posting_date[filters.from_date : filters.to_date]
)
.where(Criterion.all(qb_filters))
.run(as_dict=True)
)
pl_vouchers = (
qb.from_(ple)
.select(ple.voucher_type)
.distinct()
.select(ple.voucher_no)
.distinct()
.where(
ple.delinked.eq(0)
& ple.company.eq(filters.company)
& ple.posting_date[filters.from_date : filters.to_date]
)
.where(Criterion.all(qb_filters))
.run(as_dict=True)
)
uniq_vouchers.extend(gl_vouchers)
uniq_vouchers.extend(pl_vouchers)
return uniq_vouchers

View File

@@ -210,7 +210,7 @@ class PaymentLedger:
)
)
self.columns.append(
dict(label=_("Currency"), fieldname="currency", fieldtype="Currency", hidden=True)
dict(label=_("Currency"), fieldname="currency", fieldtype="Link", options="Currency", hidden=True)
)
def run(self):

View File

@@ -59,11 +59,11 @@ def execute(filters=None):
columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, filters.company)
chart = get_chart_data(filters, columns, income, expense, net_profit_loss)
currency = filters.presentation_currency or frappe.get_cached_value(
"Company", filters.company, "default_currency"
)
chart = get_chart_data(filters, columns, income, expense, net_profit_loss, currency)
report_summary, primitive_summary = get_report_summary(
period_list, filters.periodicity, income, expense, net_profit_loss, currency, filters
)
@@ -152,7 +152,7 @@ def get_net_profit_loss(income, expense, period_list, company, currency=None, co
return net_profit_loss
def get_chart_data(filters, columns, income, expense, net_profit_loss):
def get_chart_data(filters, columns, income, expense, net_profit_loss, currency):
labels = [d.get("label") for d in columns[2:]]
income_data, expense_data, net_profit = [], [], []
@@ -181,5 +181,7 @@ def get_chart_data(filters, columns, income, expense, net_profit_loss):
chart["type"] = "line"
chart["fieldtype"] = "Currency"
chart["options"] = "currency"
chart["currency"] = currency
return chart

View File

@@ -311,6 +311,7 @@ def get_account_columns(invoice_list, include_payments):
"""select distinct expense_account
from `tabPurchase Invoice Item` where docstatus = 1
and (expense_account is not null and expense_account != '')
and parenttype='Purchase Invoice'
and parent in (%s) order by expense_account"""
% ", ".join(["%s"] * len(invoice_list)),
tuple([inv.name for inv in invoice_list]),
@@ -451,7 +452,7 @@ def get_invoice_expense_map(invoice_list):
"""
select parent, expense_account, sum(base_net_amount) as amount
from `tabPurchase Invoice Item`
where parent in (%s)
where parent in (%s) and parenttype='Purchase Invoice'
group by parent, expense_account
"""
% ", ".join(["%s"] * len(invoice_list)),
@@ -522,7 +523,7 @@ def get_invoice_po_pr_map(invoice_list):
"""
select parent, purchase_order, purchase_receipt, po_detail, project
from `tabPurchase Invoice Item`
where parent in (%s)
where parent in (%s) and parenttype='Purchase Invoice'
"""
% ", ".join(["%s"] * len(invoice_list)),
tuple(inv.name for inv in invoice_list),

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