Compare commits

...

83 Commits

Author SHA1 Message Date
Frappe PR Bot
c910b8ab03 chore(release): Bumped to Version 14.70.2
## [14.70.2](https://github.com/frappe/erpnext/compare/v14.70.1...v14.70.2) (2024-05-23)

### Bug Fixes

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

# Conflicts:
#	erpnext/accounts/doctype/payment_entry/payment_entry.js
#	erpnext/accounts/doctype/payment_entry/payment_entry.py
(cherry picked from commit 50f6afd588)
2024-05-23 10:39:15 +00:00
Frappe PR Bot
b7d6a54bed chore(release): Bumped to Version 14.70.1
## [14.70.1](https://github.com/frappe/erpnext/compare/v14.70.0...v14.70.1) (2024-05-22)

### Bug Fixes

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

(cherry picked from commit 5cf5b18aea)

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

* chore: fix conflicts

* chore: fix conflicts

* chore: fix conflicts

---------

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

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

(cherry picked from commit bd381cc0c6)

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

(cherry picked from commit 0363afcfd0)

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

### Bug Fixes

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

### Features

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

(cherry picked from commit 50dd9fa8a3)

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

* chore: fix conflicts

* chore: fix conflicts

---------

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
2024-05-13 21:37:13 +05:30
mergify[bot]
5366356400 fix: data getting override in delivery trip (backport #41431) (#41432)
fix: data getting override in delivery trip (#41431)

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

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

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

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

### Bug Fixes

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

### Performance Improvements

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

(cherry picked from commit 0887161f2a)

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

* chore: fix conflicts

---------

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

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

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

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

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

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

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

(cherry picked from commit c8e92cb1b2)

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

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

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

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

### Bug Fixes

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

### Features

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

### Performance Improvements

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

(cherry picked from commit 067419b7cd)

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

(cherry picked from commit aefbe21b46)

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

* chore: fix conflicts

* chore: fix conflicts

---------

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

# Conflicts:
#	erpnext/stock/doctype/delivery_note/delivery_note.py
2024-04-26 07:40:31 +00:00
rohitwaghchaure
da69b1e71b Merge pull request #41196 from frappe/mergify/bp/version-14-hotfix/pr-41192
fix: duplicate column in the stock ledger report (backport #41192)
2024-04-26 12:49:35 +05:30
Rohit Waghchaure
3fcdcef178 fix: duplicate column in the stock ledger report
(cherry picked from commit be7fd6bfb4)
2024-04-26 06:53:08 +00:00
rohitwaghchaure
7656fe4bfc Merge pull request #41174 from rohitwaghchaure/fixed-performance-issue-for-serial-no-creation
perf: timeout issue while submitting purchase receipt (v14)
2024-04-26 10:56:28 +05:30
mergify[bot]
59010c9a61 fix: handle stock balance unbuffered_cursor error (backport #41186) (#41187)
fix: handle stock balance unbuffered_cursor error (#41186)

(cherry picked from commit 341fb6d8f3)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2024-04-25 17:26:29 +05:30
Rohit Waghchaure
113351e850 perf: timeout issue while submitting purchase receipt (v14) 2024-04-25 12:10:29 +05:30
ruthra kumar
b9d28fc1ad Merge pull request #41178 from frappe/mergify/bp/version-14-hotfix/pr-41142
fix: mode of payment has precedance in Payment Entry (backport #41142)
2024-04-25 09:02:37 +05:30
ruthra kumar
33d38ba3a7 fix: mode of payment has precedance
Mode of Payment is given precedence over company/party bank account

(cherry picked from commit 4aef969879)
2024-04-25 08:58:01 +05:30
Deepesh Garg
ff8dba1cb7 Merge branch 'version-14-hotfix' of https://github.com/frappe/erpnext into default_dates_in_reports 2024-04-24 17:20:55 +05:30
Deepesh Garg
c3244f009b fix: Default dates in report 2024-04-24 16:59:51 +05:30
71 changed files with 697 additions and 160 deletions

View File

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

View File

@@ -1395,8 +1395,9 @@ frappe.ui.form.on('Payment Entry Reference', {
args: {
reference_doctype: row.reference_doctype,
reference_name: row.reference_name,
party_account_currency: frm.doc.payment_type=="Receive" ?
frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency
party_account_currency: frm.doc.payment_type == "Receive" ? frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency,
party_type: frm.doc.party_type,
party: frm.doc.party,
},
callback: function(r, rt) {
if(r.message) {

View File

@@ -9,8 +9,7 @@ import frappe
from frappe import ValidationError, _, qb, scrub, throw
from frappe.utils import cint, comma_or, flt, getdate, nowdate
from frappe.utils.data import comma_and, fmt_money
from pypika import Case
from pypika.functions import Coalesce, Sum
from pypika.functions import Sum
import erpnext
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_dimensions
@@ -348,7 +347,11 @@ class PaymentEntry(AccountsController):
continue
ref_details = get_reference_details(
d.reference_doctype, d.reference_name, self.party_account_currency
d.reference_doctype,
d.reference_name,
self.party_account_currency,
self.party_type,
self.party,
)
# Only update exchange rate when the reference is Journal Entry
@@ -1883,33 +1886,42 @@ def get_company_defaults(company):
return frappe.get_cached_value("Company", company, fields, as_dict=1)
def get_outstanding_on_journal_entry(name):
gl = frappe.qb.DocType("GL Entry")
res = (
frappe.qb.from_(gl)
.select(
Case()
.when(
gl.party_type == "Customer",
Coalesce(Sum(gl.debit_in_account_currency - gl.credit_in_account_currency), 0),
)
.else_(Coalesce(Sum(gl.credit_in_account_currency - gl.debit_in_account_currency), 0))
.as_("outstanding_amount")
)
def get_outstanding_on_journal_entry(voucher_no, party_type, party):
ple = frappe.qb.DocType("Payment Ledger Entry")
outstanding = (
frappe.qb.from_(ple)
.select(Sum(ple.amount_in_account_currency))
.where(
(Coalesce(gl.party_type, "") != "")
& (gl.is_cancelled == 0)
& ((gl.voucher_no == name) | (gl.against_voucher == name))
(ple.against_voucher_no == voucher_no)
& (ple.party_type == party_type)
& (ple.party == party)
& (ple.delinked == 0)
)
).run(as_dict=True)
).run()
outstanding_amount = res[0].get("outstanding_amount", 0) if res else 0
outstanding_amount = outstanding[0][0] if outstanding else 0
return outstanding_amount
total = (
frappe.qb.from_(ple)
.select(Sum(ple.amount_in_account_currency))
.where(
(ple.voucher_no == voucher_no)
& (ple.party_type == party_type)
& (ple.party == party)
& (ple.delinked == 0)
)
).run()
total_amount = total[0][0] if total else 0
return outstanding_amount, total_amount
@frappe.whitelist()
def get_reference_details(reference_doctype, reference_name, party_account_currency):
def get_reference_details(
reference_doctype, reference_name, party_account_currency, party_type=None, party=None
):
total_amount = outstanding_amount = exchange_rate = None
ref_doc = frappe.get_doc(reference_doctype, reference_name)
@@ -1920,12 +1932,13 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
exchange_rate = 1
elif reference_doctype == "Journal Entry" and ref_doc.docstatus == 1:
total_amount = ref_doc.get("total_amount")
if ref_doc.multi_currency:
exchange_rate = get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
else:
exchange_rate = 1
outstanding_amount = get_outstanding_on_journal_entry(reference_name)
outstanding_amount, total_amount = get_outstanding_on_journal_entry(
reference_name, party_type, party
)
elif reference_doctype != "Journal Entry":
if not total_amount:

View File

@@ -1087,7 +1087,9 @@ class TestPaymentEntry(FrappeTestCase):
pe.source_exchange_rate = 50
pe.save()
ref_details = get_reference_details(so.doctype, so.name, pe.paid_from_account_currency)
ref_details = get_reference_details(
so.doctype, so.name, pe.paid_from_account_currency, "Customer", so.customer
)
expected_response = {
"total_amount": 5000.0,
"outstanding_amount": 5000.0,

View File

@@ -596,7 +596,11 @@ def update_payment_req_status(doc, method):
if payment_request_name:
ref_details = get_reference_details(
ref.reference_doctype, ref.reference_name, doc.party_account_currency
ref.reference_doctype,
ref.reference_name,
doc.party_account_currency,
doc.party_type,
doc.party,
)
pay_req_doc = frappe.get_doc("Payment Request", payment_request_name)
status = pay_req_doc.status

View File

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

View File

@@ -47,6 +47,12 @@ class PricingRule(Document):
frappe.throw(_("Duplicate {0} found in the table").format(self.apply_on))
def validate_mandatory(self):
if self.has_priority and not self.priority:
throw(_("Priority is mandatory"), frappe.MandatoryError, _("Please Set Priority"))
if self.priority and not self.has_priority:
self.has_priority = 1
for apply_on, field in apply_on_dict.items():
if self.apply_on == apply_on and len(self.get(field) or []) < 1:
throw(_("{0} is not added in the table").format(apply_on), frappe.MandatoryError)
@@ -486,6 +492,22 @@ def apply_price_discount_rule(pricing_rule, item_details, args):
if pricing_rule.apply_discount_on_rate and item_details.get("discount_percentage"):
# Apply discount on discounted rate
item_details[field] += (100 - item_details[field]) * (pricing_rule.get(field, 0) / 100)
elif args.price_list_rate:
value = pricing_rule.get(field, 0)
calculate_discount_percentage = False
if field == "discount_percentage":
field = "discount_amount"
value = args.price_list_rate * (value / 100)
calculate_discount_percentage = True
if field not in item_details:
item_details.setdefault(field, 0)
item_details[field] += value if pricing_rule else args.get(field, 0)
if calculate_discount_percentage and args.price_list_rate and item_details.discount_amount:
item_details.discount_percentage = flt(
(flt(item_details.discount_amount) / flt(args.price_list_rate)) * 100
)
else:
if field not in item_details:
item_details.setdefault(field, 0)

View File

@@ -976,7 +976,116 @@ class TestPricingRule(unittest.TestCase):
so.load_from_db()
self.assertEqual(so.items[1].is_free_item, 1)
self.assertEqual(so.items[1].item_code, "_Test Item")
self.assertEqual(so.items[1].qty, 4)
self.assertEqual(so.items[1].qty, 3)
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")
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule 1",
"name": "_Test Pricing Rule 1",
"apply_on": "Item Code",
"currency": "USD",
"items": [
{
"item_code": "_Test Item",
}
],
"selling": 1,
"price_or_product_discount": "Price",
"rate_or_discount": "Discount Percentage",
"discount_percentage": 10,
"apply_multiple_pricing_rules": 1,
"company": "_Test Company",
}
frappe.get_doc(test_record.copy()).insert()
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule 2",
"name": "_Test Pricing Rule 2",
"apply_on": "Item Code",
"currency": "USD",
"items": [
{
"item_code": "_Test Item",
}
],
"selling": 1,
"price_or_product_discount": "Price",
"rate_or_discount": "Discount Amount",
"discount_amount": 100,
"apply_multiple_pricing_rules": 1,
"company": "_Test Company",
}
frappe.get_doc(test_record.copy()).insert()
so = make_sales_order(item_code="_Test Item", qty=1, price_list_rate=1000, do_not_submit=True)
self.assertEqual(so.items[0].discount_amount, 200)
self.assertEqual(so.items[0].rate, 800)
frappe.delete_doc_if_exists("Sales Order", so.name)
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
def test_priority_of_multiple_pricing_rules(self):
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule 1",
"name": "_Test Pricing Rule 1",
"apply_on": "Item Code",
"currency": "USD",
"items": [
{
"item_code": "_Test Item",
}
],
"selling": 1,
"price_or_product_discount": "Price",
"rate_or_discount": "Discount Percentage",
"discount_percentage": 10,
"has_priority": 1,
"priority": 1,
"company": "_Test Company",
}
frappe.get_doc(test_record.copy()).insert()
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule 2",
"name": "_Test Pricing Rule 2",
"apply_on": "Item Code",
"currency": "USD",
"items": [
{
"item_code": "_Test Item",
}
],
"selling": 1,
"price_or_product_discount": "Price",
"rate_or_discount": "Discount Percentage",
"discount_percentage": 20,
"has_priority": 1,
"priority": 3,
"company": "_Test Company",
}
frappe.get_doc(test_record.copy()).insert()
so = make_sales_order(item_code="_Test Item", qty=1, price_list_rate=1000, do_not_submit=True)
self.assertEqual(so.items[0].discount_percentage, 20)
self.assertEqual(so.items[0].rate, 800)
frappe.delete_doc_if_exists("Sales Order", so.name)
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
test_dependencies = ["Campaign"]
@@ -1006,6 +1115,7 @@ def make_pricing_rule(**args):
"priority": args.priority or 1,
"discount_amount": args.discount_amount or 0.0,
"apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0,
"has_priority": args.has_priority or 0,
}
)

View File

@@ -6,6 +6,7 @@
import copy
import json
import math
import frappe
from frappe import _, bold
@@ -32,6 +33,9 @@ def get_pricing_rules(args, doc=None):
for apply_on in ["Item Code", "Item Group", "Brand"]:
pricing_rules.extend(_get_pricing_rules(apply_on, args, values))
if pricing_rules and pricing_rules[0].has_priority:
continue
if pricing_rules and not apply_multiple_pricing_rules(pricing_rules):
break
@@ -638,7 +642,7 @@ def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
if transaction_qty:
qty = flt(transaction_qty) * qty / pricing_rule.recurse_for
if pricing_rule.round_free_qty:
qty = round(qty)
qty = math.floor(qty)
free_item_data_args = {
"item_code": free_item,

View File

@@ -104,7 +104,7 @@ def set_ageing(doc, entry):
ageing_filters = frappe._dict(
{
"company": doc.company,
"report_date": doc.to_date,
"report_date": doc.posting_date,
"ageing_based_on": doc.ageing_based_on,
"range1": 30,
"range2": 60,

View File

@@ -340,10 +340,11 @@
<table class="table table-bordered">
<thead>
<tr>
<th style="width: 25%">30 Days</th>
<th style="width: 25%">60 Days</th>
<th style="width: 25%">90 Days</th>
<th style="width: 25%">120 Days</th>
<th style="width: 25%">0 - 30 Days</th>
<th style="width: 25%">30 - 60 Days</th>
<th style="width: 25%">60 - 90 Days</th>
<th style="width: 25%">90 - 120 Days</th>
<th style="width: 20%">Above 120 Days</th>
</tr>
</thead>
<tbody>
@@ -352,6 +353,7 @@
<td>{{ frappe.utils.fmt_money(ageing.range2, currency=data[0]["currency"]) }}</td>
<td>{{ frappe.utils.fmt_money(ageing.range3, currency=data[0]["currency"]) }}</td>
<td>{{ frappe.utils.fmt_money(ageing.range4, currency=data[0]["currency"]) }}</td>
<td>{{ frappe.utils.fmt_money(ageing.range5, currency=filters.presentation_currency) }}</td>
</tr>
</tbody>
</table>

View File

@@ -11,13 +11,15 @@
{
"fieldname": "cost_center_name",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Cost Center",
"options": "Cost Center"
"options": "Cost Center",
"reqd": 1
}
],
"istable": 1,
"links": [],
"modified": "2020-08-03 16:56:45.744905",
"modified": "2024-05-03 17:16:51.666461",
"modified_by": "Administrator",
"module": "Accounts",
"name": "PSOA Cost Center",
@@ -27,4 +29,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}
}

View File

@@ -440,8 +440,12 @@ function hide_fields(doc) {
var item_fields_stock = ['warehouse_section', 'received_qty', 'rejected_qty'];
cur_frm.fields_dict['items'].grid.set_column_disp(item_fields_stock,
(cint(doc.update_stock)==1 || cint(doc.is_return)==1 ? true : false));
if (cur_frm.fields_dict["items"]) {
cur_frm.fields_dict["items"].grid.set_column_disp(
item_fields_stock,
cint(doc.update_stock) == 1 || cint(doc.is_return) == 1 ? true : false
);
}
cur_frm.refresh_fields();
}

View File

@@ -982,7 +982,7 @@ class PurchaseInvoice(BuyingController):
pr_items = frappe.get_all(
"Purchase Receipt Item",
filters={"parent": ("in", linked_purchase_receipts)},
fields=["name", "provisional_expense_account", "qty", "base_rate"],
fields=["name", "provisional_expense_account", "qty", "base_rate", "rate"],
)
default_provisional_account = self.get_company_default("default_provisional_account")
provisional_accounts = set(
@@ -1010,6 +1010,7 @@ class PurchaseInvoice(BuyingController):
"provisional_account": item.provisional_expense_account or default_provisional_account,
"qty": item.qty,
"base_rate": item.base_rate,
"rate": item.rate,
"has_provisional_entry": item.name in rows_with_provisional_entries,
}
@@ -1026,7 +1027,10 @@ class PurchaseInvoice(BuyingController):
self.posting_date,
pr_item.get("provisional_account"),
reverse=1,
item_amount=(min(item.qty, pr_item.get("qty")) * pr_item.get("base_rate")),
item_amount=(
(min(item.qty, pr_item.get("qty")) * pr_item.get("rate"))
* purchase_receipt_doc.get("conversion_rate")
),
)
def update_gross_purchase_amount_for_linked_assets(self, item):

View File

@@ -2030,7 +2030,7 @@
{
"fieldname": "contact_and_address_tab",
"fieldtype": "Tab Break",
"label": "Contact & Address"
"label": "Address & Contact"
},
{
"fieldname": "payments_tab",
@@ -2184,7 +2184,7 @@
"link_fieldname": "consolidated_invoice"
}
],
"modified": "2024-03-22 17:50:34.395602",
"modified": "2024-05-08 18:02:28.549041",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -21,7 +21,7 @@
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
@@ -53,7 +53,7 @@
"fieldname": "account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
@@ -87,7 +87,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-04-13 18:44:25.055382",
"modified": "2024-04-30 10:26:48.21829",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Withholding Account",

View File

@@ -253,6 +253,14 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N
if taxable_vouchers:
tax_deducted = get_deducted_tax(taxable_vouchers, tax_details)
# If advance is outside the current tax withholding period (usually a fiscal year), `get_deducted_tax` won't fetch it.
# updating `tax_deducted` with correct advance tax value (from current and previous previous withholding periods), will allow the
# rest of the below logic to function properly
# ---FY 2023-------------||---------------------FY 2024-----------------------||--
# ---Advance-------------||---------Inv_1--------Inv_2------------------------||--
if tax_deducted_on_advances:
tax_deducted += get_advance_tax_across_fiscal_year(tax_deducted_on_advances, tax_details)
tax_amount = 0
if party_type == "Supplier":
@@ -389,7 +397,7 @@ def get_taxes_deducted_on_advances_allocated(inv, tax_details):
frappe.qb.from_(at)
.inner_join(pe)
.on(pe.name == at.parent)
.select(at.parent, at.name, at.tax_amount, at.allocated_amount)
.select(pe.posting_date, at.parent, at.name, at.tax_amount, at.allocated_amount)
.where(pe.tax_withholding_category == tax_details.get("tax_withholding_category"))
.where(at.parent.isin(advances))
.where(at.account_head == tax_details.account_head)
@@ -414,6 +422,16 @@ def get_deducted_tax(taxable_vouchers, tax_details):
return sum(entries)
def get_advance_tax_across_fiscal_year(tax_deducted_on_advances, tax_details):
"""
Only applies for Taxes deducted on Advance Payments
"""
advance_tax_from_across_fiscal_year = sum(
[adv.tax_amount for adv in tax_deducted_on_advances if adv.posting_date < tax_details.from_date]
)
return advance_tax_from_across_fiscal_year
def get_tds_amount(ldc, parties, inv, tax_details, vouchers):
tds_amount = 0
invoice_filters = {"name": ("in", vouchers), "docstatus": 1, "apply_tds": 1}

View File

@@ -1,19 +1,22 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import datetime
import unittest
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.tests.utils import change_settings
from frappe.utils import today
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, today
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
from erpnext.accounts.utils import get_fiscal_year
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice
test_dependencies = ["Supplier Group", "Customer Group"]
class TestTaxWithholdingCategory(unittest.TestCase):
class TestTaxWithholdingCategory(FrappeTestCase):
@classmethod
def setUpClass(self):
# create relevant supplier, etc
@@ -22,7 +25,7 @@ class TestTaxWithholdingCategory(unittest.TestCase):
make_pan_no_field()
def tearDown(self):
cancel_invoices()
frappe.db.rollback()
def test_cumulative_threshold_tds(self):
frappe.db.set_value(
@@ -322,8 +325,6 @@ class TestTaxWithholdingCategory(unittest.TestCase):
d.cancel()
def test_tds_deduction_for_po_via_payment_entry(self):
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
frappe.db.set_value(
"Supplier", "Test TDS Supplier8", "tax_withholding_category", "Cumulative Threshold TDS"
)
@@ -490,6 +491,133 @@ class TestTaxWithholdingCategory(unittest.TestCase):
pi2.cancel()
pi3.cancel()
def set_previous_fy_and_tax_category(self):
test_company = "_Test Company"
category = "Cumulative Threshold TDS"
def add_company_to_fy(fy, company):
if not [x.company for x in fy.companies if x.company == company]:
fy.append("companies", {"company": company})
fy.save()
# setup previous fiscal year
fiscal_year = get_fiscal_year(today(), company=test_company)
if prev_fiscal_year := get_fiscal_year(add_days(fiscal_year[1], -10)):
self.prev_fy = frappe.get_doc("Fiscal Year", prev_fiscal_year[0])
add_company_to_fy(self.prev_fy, test_company)
else:
# make previous fiscal year
start = datetime.date(fiscal_year[1].year - 1, fiscal_year[1].month, fiscal_year[1].day)
end = datetime.date(fiscal_year[2].year - 1, fiscal_year[2].month, fiscal_year[2].day)
self.prev_fy = frappe.get_doc(
{
"doctype": "Fiscal Year",
"year_start_date": start,
"year_end_date": end,
"companies": [{"company": test_company}],
}
)
self.prev_fy.save()
# setup tax withholding category for previous fiscal year
cat = frappe.get_doc("Tax Withholding Category", category)
cat.append(
"rates",
{
"from_date": self.prev_fy.year_start_date,
"to_date": self.prev_fy.year_end_date,
"tax_withholding_rate": 10,
"single_threshold": 0,
"cumulative_threshold": 30000,
},
)
cat.save()
def test_tds_across_fiscal_year(self):
"""
Advance TDS on previous fiscal year should be properly allocated on Invoices in upcoming fiscal year
--||-----FY 2023-----||-----FY 2024-----||--
--||-----Advance-----||---Inv1---Inv2---||--
"""
self.set_previous_fy_and_tax_category()
supplier = "Test TDS Supplier"
# Cumulative threshold 30000 and tax rate 10%
category = "Cumulative Threshold TDS"
frappe.db.set_value(
"Supplier",
supplier,
{
"tax_withholding_category": category,
"pan": "ABCTY1234D",
},
)
po_and_advance_posting_date = add_days(self.prev_fy.year_end_date, -10)
po = create_purchase_order(supplier=supplier, qty=10, rate=10000)
po.transaction_date = po_and_advance_posting_date
po.taxes = []
po.apply_tds = False
po.tax_withholding_category = None
po.save().submit()
# Partial advance
payment = get_payment_entry(po.doctype, po.name)
payment.posting_date = po_and_advance_posting_date
payment.paid_amount = 60000
payment.apply_tax_withholding_amount = 1
payment.tax_withholding_category = category
payment.references = []
payment.taxes = []
payment.save().submit()
self.assertEqual(len(payment.taxes), 1)
self.assertEqual(payment.taxes[0].tax_amount, 6000)
# Multiple partial invoices
payment.reload()
pi1 = make_purchase_invoice(source_name=po.name)
pi1.apply_tds = True
pi1.tax_withholding_category = category
pi1.items[0].qty = 3
pi1.items[0].rate = 10000
advances = pi1.get_advance_entries()
pi1.append(
"advances",
{
"reference_type": advances[0].reference_type,
"reference_name": advances[0].reference_name,
"advance_amount": advances[0].amount,
"allocated_amount": 30000,
},
)
pi1.save().submit()
pi1.reload()
payment.reload()
self.assertEqual(pi1.taxes, [])
self.assertEqual(payment.taxes[0].tax_amount, 6000)
self.assertEqual(payment.taxes[0].allocated_amount, 3000)
pi2 = make_purchase_invoice(source_name=po.name)
pi2.apply_tds = True
pi2.tax_withholding_category = category
pi2.items[0].qty = 3
pi2.items[0].rate = 10000
advances = pi2.get_advance_entries()
pi2.append(
"advances",
{
"reference_type": advances[0].reference_type,
"reference_name": advances[0].reference_name,
"advance_amount": advances[0].amount,
"allocated_amount": 30000,
},
)
pi2.save().submit()
pi2.reload()
payment.reload()
self.assertEqual(pi2.taxes, [])
self.assertEqual(payment.taxes[0].tax_amount, 6000)
self.assertEqual(payment.taxes[0].allocated_amount, 6000)
def cancel_invoices():
purchase_invoices = frappe.get_all(

View File

@@ -188,7 +188,9 @@ def set_address_details(
*,
ignore_permissions=False,
):
billing_address_field = "customer_address" if party_type == "Lead" else party_type.lower() + "_address"
billing_address_field = (
"customer_address" if party_type in ["Lead", "Prospect"] else party_type.lower() + "_address"
)
party_details[billing_address_field] = party_address or get_default_address(party_type, party.name)
if doctype:
party_details.update(

View File

@@ -501,8 +501,9 @@ class ReceivablePayableReport:
# Deduct that from paid amount pre allocation
row.paid -= flt(payment_terms_details[0].total_advance)
# If no or single payment terms, no need to split the row
if len(payment_terms_details) <= 1:
# If single payment terms, no need to split the row
if len(payment_terms_details) == 1 and payment_terms_details[0].payment_term:
self.append_payment_term(row, payment_terms_details[0], original_row)
return
for d in payment_terms_details:
@@ -1027,20 +1028,6 @@ class ReceivablePayableReport:
fieldtype="Link",
options="Contact",
)
if self.filters.party_type == "Customer":
self.add_column(
_("Customer Name"),
fieldname="customer_name",
fieldtype="Link",
options="Customer",
)
elif self.filters.party_type == "Supplier":
self.add_column(
_("Supplier Name"),
fieldname="supplier_name",
fieldtype="Link",
options="Supplier",
)
self.add_column(label=_("Cost Center"), fieldname="cost_center", fieldtype="Data")
self.add_column(label=_("Voucher Type"), fieldname="voucher_type", fieldtype="Data")

View File

@@ -15,14 +15,14 @@ frappe.query_reports["Asset Depreciations and Balances"] = {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
reqd: 1,
},
{
fieldname: "to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
reqd: 1,
},
{

View File

@@ -7,7 +7,7 @@ frappe.query_reports["Bank Clearance Summary"] = {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
width: "80",
},
{

View File

@@ -38,14 +38,14 @@ frappe.require("assets/erpnext/js/financial_statements.js", function () {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
reqd: 1,
},
{
fieldname: "to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
reqd: 1,
},
{

View File

@@ -211,7 +211,8 @@ def get_conditions(filters):
if filters.get("account"):
filters.account = get_accounts_with_children(filters.account)
conditions.append("account in %(account)s")
if filters.account:
conditions.append("account in %(account)s")
if filters.get("cost_center"):
filters.cost_center = get_cost_centers_with_children(filters.cost_center)
@@ -316,7 +317,7 @@ def get_accounts_with_children(accounts):
else:
frappe.throw(_("Account: {0} does not exist").format(d))
return list(set(all_accounts))
return list(set(all_accounts)) if all_accounts else None
def get_data_with_opening_closing(filters, account_details, accounting_dimensions, gl_entries):

View File

@@ -15,14 +15,14 @@ frappe.query_reports["Gross Profit"] = {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
reqd: 1,
},
{
fieldname: "to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
reqd: 1,
},
{

View File

@@ -717,20 +717,22 @@ class GrossProfitGenerator:
frappe.qb.from_(purchase_invoice_item)
.inner_join(purchase_invoice)
.on(purchase_invoice.name == purchase_invoice_item.parent)
.select(purchase_invoice_item.base_rate / purchase_invoice_item.conversion_factor)
.select(
purchase_invoice.name,
purchase_invoice_item.base_rate / purchase_invoice_item.conversion_factor,
)
.where(purchase_invoice.docstatus == 1)
.where(purchase_invoice.posting_date <= self.filters.to_date)
.where(purchase_invoice_item.item_code == item_code)
)
if row.project:
query.where(purchase_invoice_item.project == row.project)
query = query.where(purchase_invoice_item.project == row.project)
if row.cost_center:
query.where(purchase_invoice_item.cost_center == row.cost_center)
query = query.where(purchase_invoice_item.cost_center == row.cost_center)
query.orderby(purchase_invoice.posting_date, order=frappe.qb.desc)
query.limit(1)
query = query.orderby(purchase_invoice.posting_date, order=frappe.qb.desc).limit(1)
last_purchase_rate = query.run()
return flt(last_purchase_rate[0][0]) if last_purchase_rate else 0

View File

@@ -15,7 +15,7 @@ frappe.query_reports["Payment Period Based On Invoice Date"] = {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
},
{
fieldname: "to_date",

View File

@@ -59,13 +59,13 @@ frappe.require("assets/erpnext/js/financial_statements.js", function () {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
},
{
fieldname: "to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
},
{
fieldname: "show_zero_values",

View File

@@ -37,13 +37,13 @@ frappe.require("assets/erpnext/js/financial_statements.js", function () {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
},
{
fieldname: "to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
},
{
fieldname: "cost_center",

View File

@@ -36,13 +36,13 @@ frappe.query_reports["Trial Balance for Party"] = {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
},
{
fieldname: "to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
},
{
fieldname: "party_type",

View File

@@ -55,6 +55,9 @@ GL_REPOSTING_CHUNK = 100
def get_fiscal_year(
date=None, fiscal_year=None, label="Date", verbose=1, company=None, as_dict=False, boolean=False
):
if isinstance(boolean, str):
boolean = frappe.json.loads(boolean)
fiscal_years = get_fiscal_years(
date, fiscal_year, label, verbose, company, as_dict=as_dict, boolean=boolean
)
@@ -479,6 +482,11 @@ def reconcile_against_document(
# re-submit advance entry
doc = frappe.get_doc(entry.voucher_type, entry.voucher_no)
gl_map = doc.build_gl_map()
from erpnext.accounts.general_ledger import process_debit_credit_difference
# Make sure there is no overallocation
process_debit_credit_difference(gl_map)
create_payment_ledger_entry(gl_map, update_outstanding="No", cancel=0, adv_adj=1)
# Only update outstanding for newly linked vouchers

View File

@@ -402,7 +402,7 @@
{
"fieldname": "contact_and_address_tab",
"fieldtype": "Tab Break",
"label": "Contact & Address"
"label": "Address & Contact"
},
{
"fieldname": "accounting_tab",
@@ -457,7 +457,7 @@
"link_fieldname": "party"
}
],
"modified": "2023-10-19 16:55:15.148325",
"modified": "2024-05-08 18:02:57.342931",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",

View File

@@ -27,13 +27,13 @@ frappe.query_reports["Procurement Tracker"] = {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
},
{
fieldname: "to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
},
],
};

View File

@@ -35,14 +35,14 @@ frappe.query_reports["Purchase Analytics"] = {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
reqd: 1,
},
{
fieldname: "to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
reqd: 1,
},
{

View File

@@ -1008,7 +1008,12 @@ def is_reposting_pending():
)
def future_sle_exists(args, sl_entries=None):
def future_sle_exists(args, sl_entries=None, allow_force_reposting=True):
if allow_force_reposting and frappe.db.get_single_value(
"Stock Reposting Settings", "do_reposting_for_each_stock_transaction"
):
return True
key = (args.voucher_type, args.voucher_no)
if not hasattr(frappe.local, "future_sle"):
frappe.local.future_sle = {}

View File

@@ -6,13 +6,13 @@ frappe.query_reports["Campaign Efficiency"] = {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
},
{
fieldname: "to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
},
],
};

View File

@@ -6,13 +6,13 @@ frappe.query_reports["Lead Owner Efficiency"] = {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
},
{
fieldname: "to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
},
],
};

View File

@@ -21,7 +21,8 @@ def get_exploded_items(bom, data, indent=0, qty=1):
exploded_items = frappe.get_all(
"BOM Item",
filters={"parent": bom},
fields=["qty", "bom_no", "qty", "item_code", "item_name", "description", "uom"],
fields=["qty", "bom_no", "qty", "item_code", "item_name", "description", "uom", "idx"],
order_by="idx ASC",
)
for item in exploded_items:

View File

@@ -37,14 +37,14 @@ frappe.query_reports["Job Card Summary"] = {
label: __("From Posting Date"),
fieldname: "from_date",
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
reqd: 1,
},
{
label: __("To Posting Date"),
fieldname: "to_date",
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
reqd: 1,
},
{

View File

@@ -16,14 +16,14 @@ frappe.query_reports["Production Analytics"] = {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
reqd: 1,
},
{
fieldname: "to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
reqd: 1,
},
{

View File

@@ -362,4 +362,5 @@ erpnext.stock.doctype.delivery_note.patches.drop_unused_return_against_index # 2
erpnext.patches.v14_0.set_maintain_stock_for_bom_item
execute:frappe.db.set_single_value('E Commerce Settings', 'show_actual_qty', 1)
erpnext.patches.v14_0.delete_orphaned_asset_movement_item_records
erpnext.patches.v14_0.remove_cancelled_asset_capitalization_from_asset
erpnext.patches.v14_0.remove_cancelled_asset_capitalization_from_asset
erpnext.patches.v14_0.enable_set_priority_for_pricing_rules #1

View File

@@ -0,0 +1,10 @@
import frappe
def execute():
pr_table = frappe.qb.DocType("Pricing Rule")
(
frappe.qb.update(pr_table)
.set(pr_table.has_priority, 1)
.where((pr_table.priority.isnotnull()) & (pr_table.priority != ""))
).run()

View File

@@ -410,11 +410,13 @@ $.extend(erpnext.utils, {
method: "erpnext.accounts.utils.get_fiscal_year",
args: {
date: date,
boolean: boolean,
},
async: false,
callback: function (r) {
if (r.message) {
fiscal_year = r.message[0];
if (with_dates) fiscal_year = r.message;
else fiscal_year = r.message[0];
}
},
});

View File

@@ -481,7 +481,7 @@
{
"fieldname": "contact_and_address_tab",
"fieldtype": "Tab Break",
"label": "Contact & Address"
"label": "Address & Contact"
},
{
"fieldname": "defaults_tab",
@@ -567,7 +567,7 @@
"link_fieldname": "party"
}
],
"modified": "2023-12-28 13:15:36.298369",
"modified": "2024-05-08 18:03:20.716169",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer",

View File

@@ -45,6 +45,8 @@ frappe.ui.form.on('Quotation', {
frm.trigger("set_label");
frm.trigger("toggle_reqd_lead_customer");
frm.trigger("set_dynamic_field_label");
frm.set_value("party_name", "");
frm.set_value("customer_name", "");
},
set_label: function(frm) {
@@ -71,7 +73,7 @@ erpnext.selling.QuotationController = class QuotationController extends erpnext.
frappe.dynamic_link = {
doc: this.frm.doc,
fieldname: 'party_name',
doctype: doc.quotation_to == 'Customer' ? 'Customer' : 'Lead',
doctype: doc.quotation_to,
};
var me = this;
@@ -170,6 +172,7 @@ erpnext.selling.QuotationController = class QuotationController extends erpnext.
}
} else if (this.frm.doc.quotation_to == "Prospect") {
this.frm.set_df_property("party_name", "label", "Prospect");
this.frm.fields_dict.party_name.get_query = null;
}
}

View File

@@ -23,14 +23,14 @@ frappe.query_reports["Customer Acquisition and Loyalty"] = {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
reqd: 1,
},
{
fieldname: "to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
reqd: 1,
},
],

View File

@@ -43,14 +43,14 @@ frappe.query_reports["Sales Analytics"] = {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
reqd: 1,
},
{
fieldname: "to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
reqd: 1,
},
{

View File

@@ -21,7 +21,7 @@ frappe.query_reports["Sales Person Commission Summary"] = {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
},
{
fieldname: "to_date",

View File

@@ -20,7 +20,7 @@ frappe.query_reports["Sales Person-wise Transaction Summary"] = {
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
},
{
fieldname: "to_date",

View File

@@ -53,8 +53,6 @@ class AuthorizationRule(Document):
frappe.throw(_("Discount must be less than 100"))
elif self.based_on == "Customerwise Discount" and not self.master_name:
frappe.throw(_("Customer required for 'Customerwise Discount'"))
else:
self.based_on = "Not Applicable"
def validate(self):
self.check_duplicate_entry()

View File

@@ -202,7 +202,7 @@ def update_qty(bin_name, args):
sle = frappe.qb.DocType("Stock Ledger Entry")
# actual qty is not up to date in case of backdated transaction
if future_sle_exists(args):
if future_sle_exists(args, allow_force_reposting=False):
last_sle_qty = (
frappe.qb.from_(sle)
.select(sle.qty_after_transaction)

View File

@@ -739,7 +739,7 @@ def make_sales_invoice(source_name, target_doc=None, args=None):
@frappe.whitelist()
def make_delivery_trip(source_name, target_doc=None):
def make_delivery_trip(source_name, target_doc=None, kwargs=None):
def update_stop_details(source_doc, target_doc, source_parent):
target_doc.customer = source_parent.customer
target_doc.address = source_parent.shipping_address_name

View File

@@ -15,6 +15,9 @@ frappe.ui.form.on("Item", {
frm.add_fetch("tax_type", "tax_rate", "tax_rate");
frm.make_methods = {
Quotation: () => {
open_form(frm, "Quotation", "Quotation Item", "items");
},
"Sales Order": () => {
open_form(frm, "Sales Order", "Sales Order Item", "items");
},

View File

@@ -5,7 +5,7 @@ import copy
import json
import frappe
from frappe import _
from frappe import _, bold
from frappe.model.document import Document
from frappe.utils import (
cint,
@@ -397,6 +397,13 @@ class Item(Document):
def validate_warehouse_for_reorder(self):
"""Validate Reorder level table for duplicate and conditional mandatory"""
warehouse_material_request_type: list[tuple[str, str]] = []
_warehouse_before_save = frappe._dict()
if not self.is_new() and self._doc_before_save:
_warehouse_before_save = {
d.name: d.warehouse for d in self._doc_before_save.get("reorder_levels") or []
}
for d in self.get("reorder_levels"):
if not d.warehouse_group:
d.warehouse_group = d.warehouse
@@ -413,6 +420,19 @@ class Item(Document):
if d.warehouse_reorder_level and not d.warehouse_reorder_qty:
frappe.throw(_("Row #{0}: Please set reorder quantity").format(d.idx))
if d.warehouse_group and d.warehouse:
if _warehouse_before_save.get(d.name) == d.warehouse:
continue
child_warehouses = get_child_warehouses(d.warehouse_group)
if d.warehouse not in child_warehouses:
frappe.throw(
_(
"Row #{0}: The warehouse {1} is not a child warehouse of a group warehouse {2}"
).format(d.idx, bold(d.warehouse), bold(d.warehouse_group)),
title=_("Incorrect Check in (group) Warehouse for Reorder"),
)
def stock_ledger_created(self):
if not hasattr(self, "_stock_ledger_created"):
self._stock_ledger_created = len(
@@ -1318,3 +1338,10 @@ def get_asset_naming_series():
from erpnext.assets.doctype.asset.asset import get_asset_naming_series
return get_asset_naming_series()
@frappe.request_cache
def get_child_warehouses(warehouse):
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
return get_child_warehouses(warehouse)

View File

@@ -848,6 +848,27 @@ class TestItem(FrappeTestCase):
self.assertEqual(data[0].description, item.description)
self.assertTrue("description" in data[0])
def test_group_warehouse_for_reorder_item(self):
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
item_doc = make_item("_Test Group Warehouse For Reorder Item", {"is_stock_item": 1})
warehouse = create_warehouse("_Test Warehouse - _TC")
warehouse_doc = frappe.get_doc("Warehouse", warehouse)
warehouse_doc.db_set("parent_warehouse", "")
item_doc.append(
"reorder_levels",
{
"warehouse": warehouse,
"warehouse_reorder_level": 10,
"warehouse_reorder_qty": 100,
"material_request_type": "Purchase",
"warehouse_group": "_Test Warehouse Group - _TC",
},
)
self.assertRaises(frappe.ValidationError, item_doc.save)
def set_item_variant_settings(fields):
doc = frappe.get_doc("Item Variant Settings")

View File

@@ -18,6 +18,7 @@
"parent_warehouse",
"consider_rejected_warehouses",
"get_item_locations",
"pick_manually",
"section_break_6",
"scan_barcode",
"column_break_13",
@@ -192,11 +193,18 @@
"fieldname": "consider_rejected_warehouses",
"fieldtype": "Check",
"label": "Consider Rejected Warehouses"
},
{
"default": "0",
"description": "If enabled then system won't override the picked qty / batches / serial numbers.",
"fieldname": "pick_manually",
"fieldtype": "Check",
"label": "Pick Manually"
}
],
"is_submittable": 1,
"links": [],
"modified": "2024-01-24 17:05:20.317180",
"modified": "2024-03-27 22:49:16.954637",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
@@ -268,4 +276,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -29,7 +29,8 @@ class PickList(Document):
def before_save(self):
self.update_status()
self.set_item_locations()
if not self.pick_manually:
self.set_item_locations()
if self.get("locations"):
self.validate_sales_order_percentage()

View File

@@ -126,7 +126,8 @@
"in_list_view": 1,
"label": "Item",
"options": "Item",
"reqd": 1
"reqd": 1,
"search_index": 1
},
{
"fieldname": "quantity_section",
@@ -193,7 +194,7 @@
],
"istable": 1,
"links": [],
"modified": "2023-07-25 11:56:23.361867",
"modified": "2024-05-07 15:32:42.905446",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",
@@ -204,4 +205,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -13,6 +13,7 @@
"end_time",
"limits_dont_apply_on",
"item_based_reposting",
"do_reposting_for_each_stock_transaction",
"errors_notification_section",
"notify_reposting_error_to_role"
],
@@ -65,12 +66,18 @@
"fieldname": "errors_notification_section",
"fieldtype": "Section Break",
"label": "Errors Notification"
},
{
"default": "0",
"fieldname": "do_reposting_for_each_stock_transaction",
"fieldtype": "Check",
"label": "Do reposting for each Stock Transaction"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2023-11-01 16:14:29.080697",
"modified": "2024-04-24 12:19:40.204888",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Reposting Settings",
@@ -91,4 +98,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -11,6 +11,10 @@ class StockRepostingSettings(Document):
def validate(self):
self.set_minimum_reposting_time_slot()
def before_save(self):
if self.do_reposting_for_each_stock_transaction:
self.item_based_reposting = 1
def set_minimum_reposting_time_slot(self):
"""Ensure that timeslot for reposting is at least 12 hours."""
if not self.limit_reposting_timeslot:

View File

@@ -38,3 +38,51 @@ class TestStockRepostingSettings(unittest.TestCase):
users = get_recipients()
self.assertTrue(user in users)
def test_do_reposting_for_each_stock_transaction(self):
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
frappe.db.set_single_value("Stock Reposting Settings", "do_reposting_for_each_stock_transaction", 1)
if frappe.db.get_single_value("Stock Reposting Settings", "item_based_reposting"):
frappe.db.set_single_value("Stock Reposting Settings", "item_based_reposting", 0)
item = make_item(
"_Test item for reposting check for each transaction", properties={"is_stock_item": 1}
).name
stock_entry = make_stock_entry(
item_code=item,
qty=1,
rate=100,
stock_entry_type="Material Receipt",
target="_Test Warehouse - _TC",
)
riv = frappe.get_all("Repost Item Valuation", filters={"voucher_no": stock_entry.name}, pluck="name")
self.assertTrue(riv)
frappe.db.set_single_value("Stock Reposting Settings", "do_reposting_for_each_stock_transaction", 0)
def test_do_not_reposting_for_each_stock_transaction(self):
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
frappe.db.set_single_value("Stock Reposting Settings", "do_reposting_for_each_stock_transaction", 0)
if frappe.db.get_single_value("Stock Reposting Settings", "item_based_reposting"):
frappe.db.set_single_value("Stock Reposting Settings", "item_based_reposting", 0)
item = make_item(
"_Test item for do not reposting check for each transaction", properties={"is_stock_item": 1}
).name
stock_entry = make_stock_entry(
item_code=item,
qty=1,
rate=100,
stock_entry_type="Material Receipt",
target="_Test Warehouse - _TC",
)
riv = frappe.get_all("Repost Item Valuation", filters={"voucher_no": stock_entry.name}, pluck="name")
self.assertFalse(riv)

View File

@@ -29,8 +29,15 @@ def execute(filters=None):
sle_count = _estimate_table_row_count("Stock Ledger Entry")
if sle_count > SLE_COUNT_LIMIT and not filters.get("item_code") and not filters.get("warehouse"):
frappe.throw(_("Please select either the Item or Warehouse filter to generate the report."))
if (
sle_count > SLE_COUNT_LIMIT
and not filters.get("item_code")
and not filters.get("warehouse")
and not filters.get("warehouse_type")
):
frappe.throw(
_("Please select either the Item or Warehouse or Warehouse Type filter to generate the report.")
)
if filters.from_date > filters.to_date:
frappe.throw(_("From Date must be before To Date"))
@@ -131,6 +138,7 @@ def get_stock_ledger_entries(filters):
def get_item_warehouse_batch_map(filters, float_precision):
_system_settings = frappe.get_cached_doc("System Settings")
with frappe.db.unbuffered_cursor():
sle = get_stock_ledger_entries(filters)
sle = sle.run(as_dict=True, as_iterator=True)

View File

@@ -22,14 +22,14 @@ frappe.query_reports["Incorrect Serial No Valuation"] = {
fieldtype: "Date",
fieldname: "from_date",
reqd: 1,
default: frappe.defaults.get_user_default("year_start_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
},
{
label: __("To Date"),
fieldtype: "Date",
fieldname: "to_date",
reqd: 1,
default: frappe.defaults.get_user_default("year_end_date"),
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
},
],
};

View File

@@ -229,11 +229,12 @@ class FIFOSlots:
"""
stock_ledger_entries = self.sle
_system_settings = frappe.get_cached_doc("System Settings")
with frappe.db.unbuffered_cursor():
if self.sle is None:
self.sle = self.__get_stock_ledger_entries()
if stock_ledger_entries is None:
stock_ledger_entries = self.__get_stock_ledger_entries()
for d in self.sle:
for d in stock_ledger_entries:
key, fifo_queue, transferred_item_key = self.__init_key_stores(d)
if d.voucher_type == "Stock Reconciliation":

View File

@@ -141,6 +141,8 @@ class StockBalanceReport:
if self.filters.get("show_stock_ageing_data"):
self.sle_entries = self.sle_query.run(as_dict=True)
# HACK: This is required to avoid causing db query in flt
_system_settings = frappe.get_cached_doc("System Settings")
with frappe.db.unbuffered_cursor():
if not self.filters.get("show_stock_ageing_data"):
self.sle_entries = self.sle_query.run(as_dict=True, as_iterator=True)

View File

@@ -156,13 +156,6 @@ def get_columns(filters):
"width": 100,
"convertible": "qty",
},
{
"label": _("Voucher #"),
"fieldname": "voucher_no",
"fieldtype": "Dynamic Link",
"options": "voucher_type",
"width": 150,
},
{
"label": _("Warehouse"),
"fieldname": "warehouse",

View File

@@ -56,13 +56,14 @@ def execute(filters=None):
item_value.setdefault((item, item_map[item]["item_group"]), [])
item_value[(item, item_map[item]["item_group"])].append(total_stock_value)
itemwise_brand = frappe._dict(get_itemwise_brand(items))
# sum bal_qty by item
for (item, item_group), wh_balance in item_balance.items():
if not item_ageing.get(item):
continue
total_stock_value = sum(item_value[(item, item_group)])
row = [item, item_map[item]["item_name"], item_group, total_stock_value]
row = [item, item_map[item]["item_name"], item_group, itemwise_brand.get(item), total_stock_value]
fifo_queue = item_ageing[item]["fifo_queue"]
average_age = 0.00
@@ -85,6 +86,10 @@ def execute(filters=None):
return columns, data
def get_itemwise_brand(items):
return frappe.get_all("Item", filters={"name": ("in", items)}, fields=["name", "brand"], as_list=1)
def get_columns(filters):
"""return columns"""
@@ -92,6 +97,7 @@ def get_columns(filters):
_("Item") + ":Link/Item:150",
_("Item Name") + ":Link/Item:150",
_("Item Group") + "::120",
_("Brand") + ":Link/Brand:120",
_("Value") + ":Currency:120",
_("Age") + ":Float:120",
]

View File

@@ -1490,6 +1490,10 @@ def get_stock_reco_qty_shift(args):
stock_reco_qty_shift = flt(args.qty_after_transaction) - flt(last_balance)
else:
stock_reco_qty_shift = flt(args.actual_qty)
elif args.get("serial_no") or args.get("batch_no"):
stock_reco_qty_shift = flt(args.actual_qty)
else:
# reco is being submitted
last_balance = get_previous_sle_of_current_voucher(args, "<=", exclude_current_voucher=True).get(
@@ -1559,6 +1563,15 @@ def get_datetime_limit_condition(detail):
def validate_negative_qty_in_future_sle(args, allow_negative_stock=False):
if allow_negative_stock or is_negative_stock_allowed(item_code=args.item_code):
return
if (
args.voucher_type == "Stock Reconciliation"
and args.actual_qty < 0
and args.get("batch_no")
and frappe.db.get_value("Stock Reconciliation Item", args.voucher_detail_no, "qty") > 0
):
return
if not (args.actual_qty < 0 or args.voucher_type == "Stock Reconciliation"):
return

View File

@@ -8,6 +8,7 @@ from frappe.utils import cint, flt, getdate, nowdate
import erpnext
from erpnext.accounts.utils import get_account_currency
from erpnext.controllers.subcontracting_controller import SubcontractingController
from erpnext.stock.utils import get_incoming_rate
class SubcontractingReceipt(SubcontractingController):
@@ -67,6 +68,7 @@ class SubcontractingReceipt(SubcontractingController):
self.set_items_bom()
self.set_items_cost_center()
self.set_items_expense_account()
self.reset_rate_for_serial_batch_supplied_items()
def validate(self):
if (
@@ -124,6 +126,26 @@ class SubcontractingReceipt(SubcontractingController):
self.calculate_supplied_items_qty_and_amount()
self.calculate_items_qty_and_amount()
def reset_rate_for_serial_batch_supplied_items(self):
for item in self.supplied_items:
if item.serial_no or item.batch_no:
args = frappe._dict(
{
"item_code": item.rm_item_code,
"warehouse": self.supplier_warehouse,
"posting_date": self.posting_date,
"posting_time": self.posting_time,
"qty": flt(item.consumed_qty),
"serial_no": item.serial_no,
"batch_no": item.batch_no,
"voucher_type": self.doctype,
"voucher_no": self.name,
"company": self.company,
"allow_zero_valuation": 1,
}
)
item.rate = get_incoming_rate(args)
def has_serial_batch_items(self):
if not self.get("supplied_items"):
return False

View File

@@ -1,14 +1,14 @@
<div class="row">
<div class="row {% if df.bold %}important{% endif %} data-field">
{% if doc.flags.show_inclusive_tax_in_print %}
<div class="col-xs-5 {%- if doc.align_labels_right %} text-right{%- endif -%}">
<label>{{ _("Total (Without Tax)") }}</label></div>
<div class="col-xs-7 text-right">
<div class="col-xs-7 text-right value">
{{ doc.get_formatted("net_total", doc) }}
</div>
{% else %}
<div class="col-xs-5 {%- if doc.align_labels_right %} text-right{%- endif -%}">
<label>{{ _(df.label) }}</label></div>
<div class="col-xs-7 text-right">
<div class="col-xs-7 text-right value">
{{ doc.get_formatted("total", doc) }}
</div>
{% endif %}

View File

@@ -1 +0,0 @@
Married,既婚,
1 Married 既婚