Compare commits

..

519 Commits

Author SHA1 Message Date
Frappe PR Bot
975010c987 chore(release): Bumped to Version 14.27.3
## [14.27.3](https://github.com/frappe/erpnext/compare/v14.27.2...v14.27.3) (2023-06-14)

### Bug Fixes

* reference error while using exchange rate revaluation ([aa7c81a](aa7c81a0bc))
2023-06-14 15:21:49 +00:00
ruthra kumar
1f6352532e Merge pull request #35696 from frappe/mergify/bp/version-14/pr-35694
fix: reference error while using exchange rate revaluation (backport #35694)
2023-06-14 20:50:16 +05:30
ruthra kumar
aa7c81a0bc fix: reference error while using exchange rate revaluation
(cherry picked from commit cd538e138a)
2023-06-14 15:16:16 +00:00
Frappe PR Bot
08729b49e9 chore(release): Bumped to Version 14.27.2
## [14.27.2](https://github.com/frappe/erpnext/compare/v14.27.1...v14.27.2) (2023-06-14)

### Bug Fixes

* `enqueue_after_commit` wherever it makes sense (backport [#35588](https://github.com/frappe/erpnext/issues/35588)) ([#35590](https://github.com/frappe/erpnext/issues/35590)) ([e505516](e5055160fb))
* `TypeError` in Closing Stock Balance ([32e5bbb](32e5bbbb46))
* **accounts:** validate payment entry references with latest data. ([#31166](https://github.com/frappe/erpnext/issues/31166)) ([4add1b4](4add1b4374))
* added process loss in job card ([6a21d61](6a21d617ce))
* allow user to set rounding loss allowance for accounts balance ([cf14858](cf14858909))
* attribute error on payment reconciliation tool ([25b3c77](25b3c7736b))
* based on status_update.py update opportunity status to converted… ([#35145](https://github.com/frappe/erpnext/issues/35145)) ([dee8275](dee82754ab))
* calculate wdv depr schedule properly for existing assets [v14] ([#35613](https://github.com/frappe/erpnext/issues/35613)) ([feb5d00](feb5d0089b))
* conflicts ([2060a00](2060a003c8))
* CSS not applied to product title ([#35630](https://github.com/frappe/erpnext/issues/35630)) ([2cf871c](2cf871c21e))
* don't set default payment amount in case of invoice return ([#35645](https://github.com/frappe/erpnext/issues/35645)) ([79483cc](79483cc90e))
* Lower deduction certificate not getting applied ([#35667](https://github.com/frappe/erpnext/issues/35667)) ([6f59fa9](6f59fa9e5b))
* Make difference entry button not working ([#35622](https://github.com/frappe/erpnext/issues/35622)) ([043815e](043815e745))
* make showing taxes as table in print configurable (backport [#35672](https://github.com/frappe/erpnext/issues/35672)) ([#35678](https://github.com/frappe/erpnext/issues/35678)) ([f39ae9d](f39ae9dbb1))
* Payment against credit notes will be considered as payment against parent invoice in Accounts Receivable/Payable report ([#35642](https://github.com/frappe/erpnext/issues/35642)) ([81ef2ba](81ef2babe9))
* Project in item-wise sales register ([#35596](https://github.com/frappe/erpnext/issues/35596)) ([7737b90](7737b9061f))
* Stock Reconciliation document update while reposting ([8b617fb](8b617fb75e))
* test case ([7af0380](7af03800c9))
* Update de.csv ([#35278](https://github.com/frappe/erpnext/issues/35278)) ([2077f6e](2077f6e89c))
* Validation for delivery date in Sales Order ([#35597](https://github.com/frappe/erpnext/issues/35597)) ([4a8ce22](4a8ce226f6))
2023-06-14 05:06:16 +00:00
Deepesh Garg
a02469f09c Merge pull request #35664 from frappe/version-14-hotfix
chore: release v14
2023-06-14 10:34:24 +05:30
mergify[bot]
4a8ce226f6 fix: Validation for delivery date in Sales Order (#35597)
fix: Validation for delivery date in Sales Order (#35597)

* fix: Validation for delivery date in Sales Order

* chore: update utils

* chore: revert

* chore: Add default delivery date

(cherry picked from commit 984f89d274)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-06-14 09:01:38 +05:30
mergify[bot]
6f59fa9e5b fix: Lower deduction certificate not getting applied (#35667)
* fix: Lower deduction certificate not getting applied (#35667)

(cherry picked from commit 937c0feefe)

# Conflicts:
#	erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py

* chore: resolve conflicts

---------

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-06-14 09:01:04 +05:30
mergify[bot]
f39ae9dbb1 fix: make showing taxes as table in print configurable (backport #35672) (#35678)
* fix: make showing taxes as table in print configurable (#35672)

(cherry picked from commit 491a50a027)

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

* chore: fix conflict

---------

Co-authored-by: Anand Baburajan <anandbaburajan@gmail.com>
2023-06-13 20:44:05 +05:30
mergify[bot]
4add1b4374 fix(accounts): validate payment entry references with latest data. (#31166)
fix(accounts): validate payment entry references with latest data. (#31166)

* test: payment entry over allocation.

* fix: validate allocated_amount against latest outstanding amount.

* fix: payment entry get outstanding documents for advance payments

* fix: only fetch latest outstanding_amount.

* fix: throw if reference is allocated

* test: throw error if a reference has been partially allocated after inital creation.

* chore: test name

* fix: remove unused part of test

* chore: linter

* chore: more user friendly error messages

* fix: only validate outstanding amount if partly paid and don't filter by cost center

* chore: minor refactor for doc.cost_center

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>

---------

Co-authored-by: Anand Baburajan <anandbaburajan@gmail.com>
Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
(cherry picked from commit 20de27d480)

Co-authored-by: Devin Slauenwhite <devin.slauenwhite@gmail.com>
2023-06-13 19:47:20 +05:30
mergify[bot]
dffa682b80 Stock aging report fix when called in dashboard chart (backport #35671) (#35675)
fix: get_range_age conditions fixed (#35671)

see https://github.com/frappe/erpnext/issues/35669

(cherry picked from commit 9f669d4c2f)

Co-authored-by: Hossein Yousefian <86075967+ihosseinu@users.noreply.github.com>
2023-06-13 19:22:25 +05:30
rohitwaghchaure
74ffb1d59c Merge pull request #35658 from frappe/mergify/bp/version-14-hotfix/pr-35629
fix: added process loss in job card (backport #35629)
2023-06-13 11:52:52 +05:30
rohitwaghchaure
2060a003c8 fix: conflicts 2023-06-13 11:22:59 +05:30
ruthra kumar
9d18b40fb0 Merge pull request #35661 from frappe/mergify/bp/version-14-hotfix/pr-35659
fix: attribute error on payment reconciliation tool (backport #35659)
2023-06-13 10:44:51 +05:30
ruthra kumar
25b3c7736b fix: attribute error on payment reconciliation tool
(cherry picked from commit bada5796fa)
2023-06-13 04:47:20 +00:00
ruthra kumar
6a08d04706 Merge pull request #35660 from frappe/mergify/bp/version-14-hotfix/pr-35620
fix: allow higher debit-credit diff tolerance in Exchange Rate Revaluation (backport #35620)
2023-06-13 10:16:47 +05:30
ruthra kumar
cf14858909 fix: allow user to set rounding loss allowance for accounts balance
(cherry picked from commit 96a0132501)
2023-06-13 04:16:55 +00:00
Rohit Waghchaure
7af03800c9 fix: test case
(cherry picked from commit 0382eecff4)
2023-06-12 17:59:56 +00:00
Rohit Waghchaure
6a21d617ce fix: added process loss in job card
(cherry picked from commit e9a6191af9)

# Conflicts:
#	erpnext/manufacturing/doctype/job_card/job_card.json
2023-06-12 17:59:56 +00:00
Sagar Sharma
48c2c82dc4 Merge pull request #35649 from frappe/mergify/bp/version-14-hotfix/pr-35646
fix: Stock Reconciliation document update while reposting (backport #35646)
2023-06-12 18:45:12 +05:30
s-aga-r
8b617fb75e fix: Stock Reconciliation document update while reposting
(cherry picked from commit db159dd11f)
2023-06-12 13:13:17 +00:00
Anand Baburajan
79483cc90e fix: don't set default payment amount in case of invoice return (#35645) 2023-06-12 18:34:13 +05:30
mergify[bot]
81ef2babe9 fix: Payment against credit notes will be considered as payment against parent invoice in Accounts Receivable/Payable report (#35642)
fix: Payment against credit notes will be considered as payment against parent invoice in Accounts Receivable/Payable report (#35642)

* fix: payment against credit note should be linked to parent invoice

* test: AR/AP report for payment against cr note scenario

* fix: cr_note shows up as outstanding invoice

Payment made against cr_note causes it be reported as outstanding invoice

(cherry picked from commit 42f4f80e0c)

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
2023-06-12 18:06:26 +05:30
mergify[bot]
043815e745 fix: Make difference entry button not working (#35622)
fix: Make difference entry button not working (#35622)

(cherry picked from commit 2f24546b21)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-06-12 15:35:48 +05:30
Trusted Computer
2cf871c21e fix: CSS not applied to product title (#35630) 2023-06-11 19:35:24 +05:30
Frappe PR Bot
0ccb5a34bd chore(release): Bumped to Version 14.27.1
## [14.27.1](https://github.com/frappe/erpnext/compare/v14.27.0...v14.27.1) (2023-06-09)

### Bug Fixes

* calculate wdv depr schedule properly for existing assets [v14] ([#35613](https://github.com/frappe/erpnext/issues/35613)) ([a630db1](a630db1b21))
2023-06-09 16:55:54 +00:00
Anand Baburajan
8372f038c0 Merge pull request #35628 from frappe/mergify/bp/version-14/pr-35613
fix: calculate wdv depr schedule properly for existing assets [v14] (backport #35613)
2023-06-09 22:24:24 +05:30
Anand Baburajan
a630db1b21 fix: calculate wdv depr schedule properly for existing assets [v14] (#35613)
* fix: calculate wdv depr schedule properly for existing assets

* fix: calculate wdv depr schedule properly for existing assets properly

(cherry picked from commit feb5d0089b)
2023-06-09 16:28:14 +00:00
Sagar Sharma
a59dffe42a Merge pull request #35619 from frappe/mergify/bp/version-14-hotfix/pr-35617
fix: `TypeError` in Closing Stock Balance (backport #35617)
2023-06-09 12:24:27 +05:30
s-aga-r
32e5bbbb46 fix: TypeError in Closing Stock Balance
(cherry picked from commit 446253ff39)
2023-06-09 06:07:07 +00:00
Anand Baburajan
feb5d0089b fix: calculate wdv depr schedule properly for existing assets [v14] (#35613)
* fix: calculate wdv depr schedule properly for existing assets

* fix: calculate wdv depr schedule properly for existing assets properly
2023-06-08 23:16:28 +05:30
mergify[bot]
059141df52 refactor: get default contact or address (#35248)
refactor: get default contact or address (#35248)

* refactor: get_party_shipping_address

* refactor: get_default_contact

* chore: adding docstrings

* fix: keep original order

* fix: use get_all instead of get_list

---------

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
(cherry picked from commit b91bb17779)

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2023-06-08 22:04:13 +05:30
mergify[bot]
29e079d5d6 refactor: use delete_contact_and_address (#34497)
refactor: use delete_contact_and_address (#34497)

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

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2023-06-08 19:59:22 +05:30
mergify[bot]
7737b9061f fix: Project in item-wise sales register (#35596)
fix: Project in item-wise sales register (#35596)

(cherry picked from commit f732cac678)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-06-07 22:36:31 +05:30
mergify[bot]
2077f6e89c fix: Update de.csv (#35278)
fix: Update de.csv (#35278)

added many fixes on the base of 'No' which is often wrongly translated to 'Kein'.

Also removed translation of Naming Seris like ACC-INV-.YYYY.- to ACC-INV-.YYYY.-

(cherry picked from commit c236979508)

Co-authored-by: Wolfram Schmidt <wolfram.schmidt@phamos.eu>
2023-06-07 22:04:14 +05:30
mergify[bot]
dee82754ab fix: based on status_update.py update opportunity status to converted… (#35145)
fix: based on status_update.py update opportunity status to converted… (#35145)

fix: based on status_update.py update opportunity status to converted on sales submit
(cherry picked from commit a9a47a51e4)

Co-authored-by: HarryPaulo <paulo_fabris@hotmail.com>
2023-06-07 22:02:03 +05:30
mergify[bot]
e5055160fb fix: enqueue_after_commit wherever it makes sense (backport #35588) (#35590)
fix: `enqueue_after_commit` wherever it makes sense (#35588)

(cherry picked from commit 4507cb3cd7)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2023-06-07 15:27:45 +05:30
Ankush Menat
a8ac2a088d chore: extend default role profiles
(cherry picked from commit 0166f69b31)
2023-06-07 15:10:20 +05:30
Frappe PR Bot
0dd16fc97d chore(release): Bumped to Version 14.27.0
# [14.27.0](https://github.com/frappe/erpnext/compare/v14.26.0...v14.27.0) (2023-06-07)

### Bug Fixes

* add validation for existing Serial No Manufactured/Received again ([#35534](https://github.com/frappe/erpnext/issues/35534)) ([4ed701b](4ed701b477))
* get party details ([c7391c8](c7391c8a0f))
* higher precision makes ERR to misjudge zero bal acc as non-zero ([456c336](456c336899))
* ignore `Non-Stock Item` mapping in Pick List ([200166b](200166bc24))
* ignore `Non-Stock Item` while calculating `% Picked` in Sales Order ([c0d8271](c0d82710b7))
* Interest Accrual on Loan Topup ([#35555](https://github.com/frappe/erpnext/issues/35555)) ([6140f13](6140f13f3a))
* missing bom details in the stock entry ([2ee0229](2ee0229751))
* **regional:** allow regional override for updating gl_dict ([#35550](https://github.com/frappe/erpnext/issues/35550)) ([57b502b](57b502b9de))
* Task gantt popup style ([20e2242](20e224224b))
* update `Stock Reconciliation` document while reposting ([cc95ced](cc95cedfee))
* **ux:** throw if no row selected to create repost entries (backport [#35503](https://github.com/frappe/erpnext/issues/35503)) ([#35504](https://github.com/frappe/erpnext/issues/35504)) ([5ba5fb1](5ba5fb1b1c))

### Features

* ability to create quotation against a prospect ([d82d159](d82d1597ac))
2023-06-07 06:18:29 +00:00
Deepesh Garg
35d488d909 Merge pull request #35571 from frappe/version-14-hotfix
chore: release v14
2023-06-07 11:46:26 +05:30
Deepesh Garg
0e82932de1 Merge branch 'version-14' into version-14-hotfix 2023-06-07 10:45:44 +05:30
mergify[bot]
7798bab0d8 chore: Default role profiles (#35584)
chore: Default role profiles (#35584)

(cherry picked from commit 76197cc437)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-06-07 10:30:28 +05:30
mergify[bot]
6140f13f3a fix: Interest Accrual on Loan Topup (#35555)
fix: Interest Accrual on Loan Topup (#35555)

* fix: Interest Accrual on Loan Topup

* chore: CI

* chore: Ignore test

(cherry picked from commit 2ffcca6f10)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-06-07 10:12:12 +05:30
Nabin Hait
c7c1a6e501 Merge pull request #35579 from frappe/mergify/bp/version-14-hotfix/pr-35572
feat: ability to create quotation against a prospect (backport #35572)
2023-06-06 21:55:48 +05:30
Nabin Hait
c7391c8a0f fix: get party details
(cherry picked from commit 5a0aacc0b6)
2023-06-06 16:25:11 +00:00
Nabin Hait
d82d1597ac feat: ability to create quotation against a prospect
(cherry picked from commit 47ce6de57d)
2023-06-06 16:25:11 +00:00
Sagar Vora
307fadc8e2 Merge pull request #35560 from frappe/mergify/bp/version-14-hotfix/pr-35550
fix(regional): allow regional override for updating gl_dict (backport #35550)
2023-06-05 13:58:03 +05:30
Smit Vora
57b502b9de fix(regional): allow regional override for updating gl_dict (#35550)
(cherry picked from commit b1ef19a0cd)
2023-06-05 08:27:44 +00:00
Sagar Sharma
5b92334e95 Merge pull request #35544 from frappe/mergify/bp/version-14-hotfix/pr-35510
fix: ignore `Non-Stock Item` while calculating `% Picked` in Sales Order (backport #35510)
2023-06-03 11:52:19 +05:30
s-aga-r
c0d82710b7 fix: ignore Non-Stock Item while calculating % Picked in Sales Order
(cherry picked from commit 0305a925fe)
2023-06-03 05:48:53 +00:00
s-aga-r
200166bc24 fix: ignore Non-Stock Item mapping in Pick List
(cherry picked from commit 03d7742737)
2023-06-03 05:48:52 +00:00
Sagar Sharma
4ed701b477 fix: add validation for existing Serial No Manufactured/Received again (#35534)
* feat: add new field `Allow existing Serial No` in `Stock Settings`

* fix: add validation for existing Serial No to be Manufactured/Received again
2023-06-03 11:15:55 +05:30
Suraj Shetty
9e71f3263d Merge pull request #35531 from frappe/mergify/bp/version-14-hotfix/pr-35530
fix: Task gantt popup style and info (backport #35530)
2023-06-02 11:10:46 +05:30
Suraj Shetty
20e224224b fix: Task gantt popup style
(cherry picked from commit f7b2d103e7)
2023-06-02 05:39:53 +00:00
rohitwaghchaure
90c79cb24f Merge pull request #35481 from s-aga-r/FIX-ISS-23-24-01138
fix: update `Stock Reconciliation` document while reposting
2023-06-01 21:23:14 +05:30
ruthra kumar
114cb98b8e Merge pull request #35362 from frappe/mergify/bp/version-14-hotfix/pr-35299
refactor: replace join with subquery in PCV (backport #35299)
2023-06-01 15:43:37 +05:30
ruthra kumar
4a62252e7e Merge pull request #35521 from frappe/mergify/bp/version-14-hotfix/pr-35518
fix:higher precision causes ERR to misjudge zero bal acc as non-zero (backport #35518)
2023-06-01 15:39:50 +05:30
ruthra kumar
a6a7cc24a4 Merge pull request #35519 from frappe/mergify/bp/version-14-hotfix/pr-35112
refactor(Gross Profit): simplify group by invoice logic (backport #35112)
2023-06-01 15:12:48 +05:30
ruthra kumar
456c336899 fix: higher precision makes ERR to misjudge zero bal acc as non-zero
(cherry picked from commit 0cd47f07a6)
2023-06-01 09:29:46 +00:00
mergify[bot]
caf886d4a6 chore: typo in pricing rule schema (#35457)
chore: typo in pricing rule schema (#35457)
2023-06-01 14:41:43 +05:30
ruthra kumar
e29ce12a58 refactor: simplify group by invoice logic
(cherry picked from commit 092c4b4c58)
2023-06-01 09:05:35 +00:00
mergify[bot]
1e09a020a9 refactor: Workspace cleanup (backport #35409) (#35512)
refactor: Workspace cleanup (backport #35409) (#35505)

* refactor: Workspace cleanup

(cherry picked from commit 243c49c550)

# Conflicts:
#	erpnext/accounts/workspace/accounting/accounting.json
#	erpnext/assets/workspace/assets/assets.json

* fix: Delete Retail and Utilities worspaces amd hide default Settings and Integration workspaces

(cherry picked from commit 0b28f641ad)

* fix: Added pos links in Selling workspace

(cherry picked from commit 86f88817a9)

* fix: removed duplicate links of manufacturing workspace

(cherry picked from commit 5cf4c8c8b7)

* fix: Rearranged accounting module links

(cherry picked from commit e78a7de1e5)

# Conflicts:
#	erpnext/accounts/workspace/accounting/accounting.json

* chore: typo

(cherry picked from commit bb67cc03df)

* chore: conflicts

---------

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
Co-authored-by: Ankush Menat <ankushmenat@gmail.com>
Co-authored-by: Ankush Menat <ankush@frappe.io>
(cherry picked from commit 841d2e4b2c)

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-06-01 11:57:07 +05:30
rohitwaghchaure
6835efa132 Merge pull request #35506 from frappe/mergify/bp/version-14-hotfix/pr-35482
fix: missing bom details in the stock entry (backport #35482)
2023-05-31 18:02:46 +05:30
Rohit Waghchaure
2ee0229751 fix: missing bom details in the stock entry
(cherry picked from commit 2fc7d82324)
2023-05-31 12:00:05 +00:00
s-aga-r
5c9506c8ca test: add test case for update stock reconciliation doc 2023-05-31 16:59:53 +05:30
s-aga-r
cc95cedfee fix: update Stock Reconciliation document while reposting 2023-05-31 16:59:53 +05:30
mergify[bot]
841d2e4b2c refactor: Workspace cleanup (backport #35409) (#35505)
* refactor: Workspace cleanup

(cherry picked from commit 243c49c550)

# Conflicts:
#	erpnext/accounts/workspace/accounting/accounting.json
#	erpnext/assets/workspace/assets/assets.json

* fix: Delete Retail and Utilities worspaces amd hide default Settings and Integration workspaces

(cherry picked from commit 0b28f641ad)

* fix: Added pos links in Selling workspace

(cherry picked from commit 86f88817a9)

* fix: removed duplicate links of manufacturing workspace

(cherry picked from commit 5cf4c8c8b7)

* fix: Rearranged accounting module links

(cherry picked from commit e78a7de1e5)

# Conflicts:
#	erpnext/accounts/workspace/accounting/accounting.json

* chore: typo

(cherry picked from commit bb67cc03df)

* chore: conflicts

---------

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
Co-authored-by: Ankush Menat <ankushmenat@gmail.com>
Co-authored-by: Ankush Menat <ankush@frappe.io>
2023-05-31 16:51:54 +05:30
mergify[bot]
5ba5fb1b1c fix(ux): throw if no row selected to create repost entries (backport #35503) (#35504)
fix(ux): throw if no row selected to create repost entries

(cherry picked from commit 1905239ec2)

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-05-31 16:37:52 +05:30
Sagar Vora
9fc798efc0 Merge pull request #35501 from frappe/mergify/bp/version-14-hotfix/pr-35500 2023-05-31 14:46:06 +05:30
Sagar Vora
b10dfba931 chore: remove whitelisting for method not accessed from UI
(cherry picked from commit 517d8a03ec)
2023-05-31 09:15:46 +00:00
Frappe PR Bot
69b214b85b chore(release): Bumped to Version 14.26.0
# [14.26.0](https://github.com/frappe/erpnext/compare/v14.25.1...v14.26.0) (2023-05-31)

### Bug Fixes

* account group totals calculation to consider include_in_gross ([8dcb930](8dcb9302b4))
* add total col for gross and net profit ([cb9b4fb](cb9b4fbb91))
* available qty not fetching for raw material in PP ([746a734](746a734257))
* balance quantity ([56ba7d6](56ba7d6a8a))
* Billing Address display in buying transactions ([#35451](https://github.com/frappe/erpnext/issues/35451)) ([33e8d05](33e8d05718))
* don't map items twice ([6f0c7cf](6f0c7cf9a4))
* Error while validating budget ([#35487](https://github.com/frappe/erpnext/issues/35487)) ([5fd00e7](5fd00e7113))
* **Gross Profit:** 'company' column is ambiguous in filter ([a59c205](a59c205d2e))
* incorrect `POS Reserved Qty` in `Stock Projected Qty` Report ([71e4f34](71e4f34b86))
* incorrect available quantity in BIN ([5a9452f](5a9452f4a3))
* incorrect transferred qty in the job card ([#35478](https://github.com/frappe/erpnext/issues/35478)) ([86801c2](86801c29cb))
* make DN item reference mandatory for Packing Slip Item ([b4e481a](b4e481a390))
* map `Packed Items` while creating `Packing Slip` ([984e32c](984e32c34a))
* monthly WDV depr schedule for existing assets [v14] ([#35458](https://github.com/frappe/erpnext/issues/35458)) ([37d437a](37d437a33c))
* Negative value in Reserved Qty for Production Plan ([6fe42c9](6fe42c937c))
* Packing Slip Item Qty ([5345ebe](5345ebe242))
* **patch:** add patch to set `packed_qty` in draft DN ([b3da2f7](b3da2f7c26))
* rate not fetching properly for inter transfer purchase order ([7b75f45](7b75f454d3))
* remove duplicate items validation ([c7628c9](c7628c98c5))
* retention stock entry: grab conversion factor from source ([bd75584](bd75584c27))
* Show future payments in accounts receivable summary ([#35416](https://github.com/frappe/erpnext/issues/35416)) ([11440cc](11440cca4c))
* Stock Analytics and Warehouse wise Item Balance Age and Value issue ([2058993](205899348a))
* stock onboarding (backport [#35453](https://github.com/frappe/erpnext/issues/35453)) ([#35480](https://github.com/frappe/erpnext/issues/35480)) ([d231b19](d231b19b9f))
* tab-uniformity (backport [#35400](https://github.com/frappe/erpnext/issues/35400)) ([#35402](https://github.com/frappe/erpnext/issues/35402)) ([989052c](989052c075))
* travis ([fe1e2fe](fe1e2fec7a))
* update `Packed Qty` in DN on submit and cancel of `Packing Slip` ([0bed062](0bed06284e))
* **ux:** don't show `Create > Packing Slip` button if items are already packed ([9854c84](9854c84ad8))
* **ux:** get items on selecting DN in Packing Slip ([b96aa75](b96aa75ded))
* **ux:** remove `Get Items` button from `Packing Slip` ([4017342](4017342c15))
* validate Packing Slip Item Qty with DN Items ([cc7e267](cc7e267c35))

### Features

* add field `Packed Qty` in `Delivery Note Item` and `Packed Item` ([509b684](509b68404c))
* add field `pi_detail` in `Packing Slip` ([2b75474](2b75474649))
2023-05-31 06:16:00 +00:00
Deepesh Garg
10afde75da Merge pull request #35473 from frappe/version-14-hotfix
chore: release v14
2023-05-31 11:44:01 +05:30
mergify[bot]
33e8d05718 fix: Billing Address display in buying transactions (#35451)
fix: Billing Address display in buying transactions (#35451)

(cherry picked from commit bb21c044f6)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-05-31 11:03:49 +05:30
mergify[bot]
5fd00e7113 fix: Error while validating budget (#35487)
fix: Error while validating budget (#35487)

* fix: Error while validating budget

* chore: remove print statement

(cherry picked from commit 27d5e6a99b)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-05-31 11:02:14 +05:30
mergify[bot]
86801c29cb fix: incorrect transferred qty in the job card (#35478)
fix: incorrect transfer quantity in the job card

(cherry picked from commit d3a5e49db9)

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
2023-05-31 08:45:02 +05:30
Ankush Menat
c17e537bb6 chore: trigger ci 2023-05-30 19:00:40 +05:30
mergify[bot]
d231b19b9f fix: stock onboarding (backport #35453) (#35480)
* fix: stock settings tour

- remove dead fields
- Keep only essential fields in tour

(cherry picked from commit 2e13fbab5e)

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

* fix: hide ledger button on new warehouse

(cherry picked from commit 7a18db561f)

* fix: warehouse form cleanup

- organize fields
- group transit fields and move them lower
- enable/disable should be button
- hide pointless fields from listview

(cherry picked from commit 40ce33dff1)

* fix: disable/enable with button

(cherry picked from commit 81e901ba62)

* fix: warehouse tour

- remove warehouse type, it doesn't do what it says. Misleading.

(cherry picked from commit aa9f926298)

* fix: filter parent warehouses by company

(cherry picked from commit 3341cd6b80)

* fix: reorder stock reco tour

(cherry picked from commit dd245ccc7f)

* fix: replace stock projected with ledger

Ledger is much more widely used report, better to show that first?

(cherry picked from commit 8fe8f80033)

* chore: docs for stock settings

[skip ci]

(cherry picked from commit 964bb1d948)

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

* chore: conflicts

---------

Co-authored-by: Ankush Menat <ankush@frappe.io>
2023-05-30 18:42:07 +05:30
rohitwaghchaure
09d3a98873 Merge pull request #35466 from frappe/mergify/bp/version-14-hotfix/pr-35465
fix: rate not fetching properly for inter transfer purchase order (backport #35465)
2023-05-30 11:49:30 +05:30
Sagar Sharma
a6f334a15e Merge pull request #35467 from frappe/mergify/bp/version-14-hotfix/pr-35459
fix: retention stock entry: grab conversion factor from source (backport #35459)
2023-05-30 11:35:55 +05:30
Marc de Lima Lucio
bd75584c27 fix: retention stock entry: grab conversion factor from source
(cherry picked from commit 6954f538c9)
2023-05-30 05:36:33 +00:00
Rohit Waghchaure
7b75f454d3 fix: rate not fetching properly for inter transfer purchase order
(cherry picked from commit 2931c657f4)
2023-05-30 03:45:03 +00:00
Anand Baburajan
37d437a33c fix: monthly WDV depr schedule for existing assets [v14] (#35458)
* fix: monthly wdv depr schedule for existing assets

* fix: monthly wdv depr schedule for existing assets properly
2023-05-29 23:17:59 +05:30
mergify[bot]
11440cca4c fix: Show future payments in accounts receivable summary (#35416)
fix: Show future payments in accounts receivable summary (#35416)

(cherry picked from commit 3504bf7f62)

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
2023-05-29 09:52:48 +05:30
Sagar Sharma
3673104949 Merge pull request #35443 from frappe/mergify/bp/version-14-hotfix/pr-35437
fix: incorrect `POS Reserved Qty` in `Stock Projected Qty` Report (backport #35437)
2023-05-28 16:18:29 +05:30
Sagar Sharma
71e4f34b86 fix: incorrect POS Reserved Qty in Stock Projected Qty Report
(cherry picked from commit 027de41600)
2023-05-28 09:35:34 +00:00
rohitwaghchaure
0a9c764f31 Merge pull request #35436 from frappe/mergify/bp/version-14-hotfix/pr-35426
fix: incorrect available quantity in BIN (backport #35426)
2023-05-27 12:46:02 +05:30
Rohit Waghchaure
fe1e2fec7a fix: travis
(cherry picked from commit 718ad3f240)
2023-05-26 17:18:40 +00:00
Rohit Waghchaure
5a9452f4a3 fix: incorrect available quantity in BIN
(cherry picked from commit 9e5e2de5d5)
2023-05-26 17:18:39 +00:00
Sagar Sharma
e251180c1a Merge pull request #35427 from frappe/mergify/bp/version-14-hotfix/pr-35108
refactor: Packing Slip (backport #35108)
2023-05-26 00:55:06 +05:30
Sagar Sharma
f5b2b80707 chore: conflict 2023-05-26 00:26:14 +05:30
Sagar Sharma
b3da2f7c26 fix(patch): add patch to set packed_qty in draft DN
(cherry picked from commit 196e18187f)
2023-05-25 18:24:56 +00:00
s-aga-r
ca6607e800 refactor: use get_product_bundle_list() to get all product bundle at once
(cherry picked from commit bbcb65894b)
2023-05-25 18:24:56 +00:00
s-aga-r
70857bf157 test: add test case for packed qty validation on DN submit
(cherry picked from commit ba61292dfc)
2023-05-25 18:24:56 +00:00
s-aga-r
dd7e5e019f refactor: validate_packed_qty()
(cherry picked from commit 699532647d)
2023-05-25 18:24:55 +00:00
s-aga-r
7105648468 refactor(minor): use set_onload to get unpacked items details
(cherry picked from commit b0eb9ea7bd)
2023-05-25 18:24:55 +00:00
s-aga-r
1ead0a3fef test: add test cases for Packing Slip
(cherry picked from commit 7742c592c5)
2023-05-25 18:24:55 +00:00
s-aga-r
9854c84ad8 fix(ux): don't show Create > Packing Slip button if items are already packed
(cherry picked from commit da00fc0f16)
2023-05-25 18:24:55 +00:00
s-aga-r
4017342c15 fix(ux): remove Get Items button from Packing Slip
(cherry picked from commit 8d1bccada4)
2023-05-25 18:24:54 +00:00
s-aga-r
b96aa75ded fix(ux): get items on selecting DN in Packing Slip
(cherry picked from commit e75aa4e291)
2023-05-25 18:24:54 +00:00
s-aga-r
1412c63158 refactor: move js validations to py
(cherry picked from commit 269cc96c41)
2023-05-25 18:24:54 +00:00
s-aga-r
cc7e267c35 fix: validate Packing Slip Item Qty with DN Items
(cherry picked from commit 90701c7ae9)
2023-05-25 18:24:54 +00:00
s-aga-r
b4e481a390 fix: make DN item reference mandatory for Packing Slip Item
(cherry picked from commit 9e5b102768)
2023-05-25 18:24:54 +00:00
s-aga-r
5345ebe242 fix: Packing Slip Item Qty
(cherry picked from commit 372bce4567)
2023-05-25 18:24:54 +00:00
s-aga-r
19713f9f6f chore: enable no_copy for dn_detail and pi_detail in Packing Slip Item
(cherry picked from commit 0add90e7ec)
2023-05-25 18:24:53 +00:00
s-aga-r
0bed06284e fix: update Packed Qty in DN on submit and cancel of Packing Slip
(cherry picked from commit 77f1e8ce78)
2023-05-25 18:24:53 +00:00
s-aga-r
509b68404c feat: add field Packed Qty in Delivery Note Item and Packed Item
(cherry picked from commit e6fc281acf)

# Conflicts:
#	erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
2023-05-25 18:24:53 +00:00
s-aga-r
6f0c7cf9a4 fix: don't map items twice
* don't explicitly map Delivery Note Item custom fields to Packing Slip Item, get auto-mapped while mapping the doc.
* call Packing List `set_missing_values` after mapping the doc.
* refactor `get_recommended_case_no`, use `frappe.db.get_value` instead of `frappe.db.sql`.

(cherry picked from commit 75fe9dd3ea)
2023-05-25 18:24:53 +00:00
s-aga-r
c7628c98c5 fix: remove duplicate items validation
(cherry picked from commit ee9f97ca7c)
2023-05-25 18:24:52 +00:00
s-aga-r
0c7efae858 refactor: packing_slip.js
(cherry picked from commit b62bf78814)
2023-05-25 18:24:52 +00:00
s-aga-r
984e32c34a fix: map Packed Items while creating Packing Slip
(cherry picked from commit 380dd73065)
2023-05-25 18:24:52 +00:00
s-aga-r
2b75474649 feat: add field pi_detail in Packing Slip
(cherry picked from commit eca77134ae)
2023-05-25 18:24:52 +00:00
Sagar Sharma
eb5cc2cf66 Merge pull request #35424 from frappe/mergify/bp/version-14-hotfix/pr-35422
chore: typo in stock balance (backport #35422)
2023-05-25 17:23:18 +05:30
Sagar Sharma
10a1681e87 chore: typo in stock balance
(cherry picked from commit c4e1f927ee)
2023-05-25 11:52:50 +00:00
ruthra kumar
54fac5786a Merge pull request #35419 from frappe/mergify/bp/version-14-hotfix/pr-35417
fix(Gross Profit): 'company' column is ambiguous in filter (backport #35417)
2023-05-25 16:44:45 +05:30
ruthra kumar
a59c205d2e fix(Gross Profit): 'company' column is ambiguous in filter
(cherry picked from commit 448712f719)
2023-05-25 09:37:24 +00:00
Deepesh Garg
151b599808 Merge pull request #35320 from akurungadam/gross-and-net-profit-fix
fix: Gross and Net Profit Report - incorrect calculation of totals
2023-05-25 14:43:10 +05:30
Frappe PR Bot
eb723637d3 chore(release): Bumped to Version 14.25.1
## [14.25.1](https://github.com/frappe/erpnext/compare/v14.25.0...v14.25.1) (2023-05-25)

### Bug Fixes

* Negative value in Reserved Qty for Production Plan ([20ceb6c](20ceb6c617))
2023-05-25 06:54:14 +00:00
rohitwaghchaure
aba322e086 Merge pull request #35414 from frappe/mergify/bp/version-14/pr-35411
fix: Negative value in Reserved Qty for Production Plan (backport #35410) (backport #35411)
2023-05-25 12:21:59 +05:30
Rohit Waghchaure
20ceb6c617 fix: Negative value in Reserved Qty for Production Plan
(cherry picked from commit a37608a36c)
(cherry picked from commit 6fe42c937c)
2023-05-25 04:37:18 +00:00
rohitwaghchaure
591b7705ac Merge pull request #35411 from frappe/mergify/bp/version-14-hotfix/pr-35410
fix: Negative value in Reserved Qty for Production Plan (backport #35410)
2023-05-24 22:57:21 +05:30
rohitwaghchaure
7163d7d27f Merge pull request #35413 from frappe/mergify/bp/version-14-hotfix/pr-35348
refactor: stock balance report (backport #35348)
2023-05-24 22:56:59 +05:30
Rohit Waghchaure
205899348a fix: Stock Analytics and Warehouse wise Item Balance Age and Value issue
(cherry picked from commit 3f548ac910)
2023-05-24 14:16:56 +00:00
Rohit Waghchaure
56ba7d6a8a fix: balance quantity
(cherry picked from commit 545b2d32cd)
2023-05-24 14:16:56 +00:00
Rohit Waghchaure
9fcfab219c refactor: stock balance report
(cherry picked from commit d9979b2ffb)
2023-05-24 14:16:56 +00:00
Rohit Waghchaure
6fe42c937c fix: Negative value in Reserved Qty for Production Plan
(cherry picked from commit a37608a36c)
2023-05-24 13:39:03 +00:00
rohitwaghchaure
1fe22f0fcf Merge pull request #35406 from frappe/mergify/bp/version-14-hotfix/pr-35405
fix: available qty not fetching for raw material in PP (backport #35405)
2023-05-24 17:29:39 +05:30
Rohit Waghchaure
746a734257 fix: available qty not fetching for raw material in PP
(cherry picked from commit 8e3463c4ef)
2023-05-24 08:55:40 +00:00
mergify[bot]
989052c075 fix: tab-uniformity (backport #35400) (#35402)
fix: tab-uniformity (#35400)

Made Doctype tabs uniform

Co-authored-by: Sagar Sharma <sagarsharma.s312@gmail.com>
(cherry picked from commit c1f1a033c9)

Co-authored-by: Gursheen Kaur Anand <40693548+GursheenK@users.noreply.github.com>
2023-05-24 12:47:38 +05:30
Frappe PR Bot
cd3991dd14 chore(release): Bumped to Version 14.25.0
# [14.25.0](https://github.com/frappe/erpnext/compare/v14.24.3...v14.25.0) (2023-05-24)

### Bug Fixes

* consider 0 if rate/qty are null (backport [#35338](https://github.com/frappe/erpnext/issues/35338)) ([#35340](https://github.com/frappe/erpnext/issues/35340)) ([15c1af3](15c1af3d8a))
* Creating landed cost voucher from connections ([2631224](2631224e49))
* depreciation schedule for existing assets [v14] ([#35255](https://github.com/frappe/erpnext/issues/35255)) ([0a080ef](0a080efce2))
* don't recalculate rate for SCR rejected warehouse SLE ([633a170](633a1703dc))
* error while saving job card ([fb7d3b7](fb7d3b7878))
* incorrect depr schedule and posting dates on selling of existing assets [v14] ([#35396](https://github.com/frappe/erpnext/issues/35396)) ([8af6a11](8af6a113d1))
* Pick List Status ([4888436](48884366ea))
* Pick List TypeError ([6df9b53](6df9b53682))
* possible type error on quotation -> sales order creation ([d23b93a](d23b93a462))
* replace quotation with invoice in first onboarding (backport [#35389](https://github.com/frappe/erpnext/issues/35389)) ([#35394](https://github.com/frappe/erpnext/issues/35394)) ([9b9772e](9b9772eb14))
* tds incorrectly calculated for invoice that are below threshold ([bdf81a4](bdf81a43c6))
* **test:** cumulative threshold checks ([879946e](879946e2c8))
* use flt instead of mandatory field ([668b092](668b092f6b))
* **ux:** SCR consumed-qty read-only property ([aa7fede](aa7fede0dc))

### Features

* provision to make reposting entries from Stock and Account Value Comparison Report ([3a0cdf3](3a0cdf30ce))
* provision to skip available sub assembly items in the production plan ([ce601af](ce601afc4e))
2023-05-24 03:05:06 +00:00
Deepesh Garg
e586c07bdd Merge pull request #35392 from frappe/version-14-hotfix
chore: release v14
2023-05-24 08:31:31 +05:30
Anand Baburajan
8af6a113d1 fix: incorrect depr schedule and posting dates on selling of existing assets [v14] (#35396)
* fix: use date in asset get gl entries functions

* fix: calc depr amount properly on selling of existing assets

* fix: calc depr amount properly on selling of existing assets again

* chore: remove unnecessary line breaks
2023-05-23 23:04:04 +05:30
mergify[bot]
9b9772eb14 fix: replace quotation with invoice in first onboarding (backport #35389) (#35394)
fix: replace quotation with invoice in first onboarding (#35389)

(cherry picked from commit b0eb72ffac)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2023-05-23 15:36:56 +05:30
Sagar Sharma
88ecc933f7 Merge pull request #35390 from frappe/mergify/bp/version-14-hotfix/pr-35303
fix: Pick List TypeError (backport #35303)
2023-05-23 15:06:05 +05:30
Sagar Sharma
6df9b53682 fix: Pick List TypeError
(cherry picked from commit a111917114)
2023-05-23 08:51:32 +00:00
rohitwaghchaure
47e97e0b3d Merge pull request #35382 from frappe/mergify/bp/version-14-hotfix/pr-35381
feat: provision to skip available sub assembly items in the production plan (backport #35381)
2023-05-23 12:29:18 +05:30
Sagar Sharma
fec6e3724e Merge pull request #35383 from frappe/mergify/bp/version-14-hotfix/pr-35380
fix: TypeError while saving Job card (backport #35380)
2023-05-23 10:52:00 +05:30
vishnu
668b092f6b fix: use flt instead of mandatory field
(cherry picked from commit 8c34cc0e00)
2023-05-23 05:20:22 +00:00
vishnu
fb7d3b7878 fix: error while saving job card
(cherry picked from commit a209fb4b64)
2023-05-23 05:20:22 +00:00
Rohit Waghchaure
f6857b4698 test: test case to skip available qty for sub-assembly items
(cherry picked from commit 9dd566c1e8)
2023-05-23 04:09:40 +00:00
Rohit Waghchaure
ce601afc4e feat: provision to skip available sub assembly items in the production plan
(cherry picked from commit 64751ec4d9)
2023-05-23 04:09:40 +00:00
Anoop
5b4b71d941 Merge branch 'version-14-hotfix' into gross-and-net-profit-fix 2023-05-22 17:23:03 +05:30
Sagar Sharma
1b827f61f7 Merge pull request #35377 from frappe/mergify/bp/version-14-hotfix/pr-35376
fix: don't recalculate rate for SCR rejected warehouse SLE (backport #35376)
2023-05-22 16:08:25 +05:30
Sagar Sharma
633a1703dc fix: don't recalculate rate for SCR rejected warehouse SLE
(cherry picked from commit 57ee473fa4)
2023-05-22 10:16:09 +00:00
Ankush Menat
abfd975eb6 chore: drop outdated navigation video
new stuff is in work, this one is actually counter-productive rn.

(cherry picked from commit ba61865ee6)
2023-05-20 19:47:17 +05:30
rohitwaghchaure
9106b01c04 Merge pull request #35368 from frappe/mergify/bp/version-14-hotfix/pr-35365
feat: provision to make reposting entries from Stock and Account Value Comparison Report (backport #35365)
2023-05-20 18:31:00 +05:30
Rohit Waghchaure
3a0cdf30ce feat: provision to make reposting entries from Stock and Account Value Comparison Report
(cherry picked from commit 7b818e9d34)
2023-05-20 11:37:02 +00:00
ruthra kumar
4620ed6e42 refactor: replace join with sub-query for fetching accounts
(cherry picked from commit e6a9252f79)
2023-05-19 05:32:43 +00:00
Frappe PR Bot
756ac6c587 chore(release): Bumped to Version 14.24.3
## [14.24.3](https://github.com/frappe/erpnext/compare/v14.24.2...v14.24.3) (2023-05-18)

### Bug Fixes

* tds incorrectly calculated for invoice that are below threshold ([14565ed](14565ed8b1))
* **test:** cumulative threshold checks ([cdd378c](cdd378c518))
2023-05-18 14:07:04 +00:00
ruthra kumar
b5b1b2da32 Merge pull request #35359 from frappe/mergify/bp/version-14/pr-35335
fix: tds incorrectly calculated for invoice that are below threshold (backport #35335)
2023-05-18 19:35:11 +05:30
ruthra kumar
cdd378c518 fix(test): cumulative threshold checks
(cherry picked from commit 132846bbd1)
2023-05-18 13:30:03 +00:00
ruthra kumar
14565ed8b1 fix: tds incorrectly calculated for invoice that are below threshold
Two purchase invoices for the same supplier, using different tax
withholding categories have this issue.

| Category | single | cumulative |
|----------+--------+------------|
| cat1     |    100 |        500 |
| cat2     |   1000 |       5000 |

1. PINV1 of net total: 105/- uses cat1. TDS is calculated as it
breached single threshold
2. PINV2 of net total: 200/- uses cat2. TDS incorrectly calculated as
PINV1 already has TDS calculated and 'consider_party_ledger_amount' is enabled.

(cherry picked from commit 84b7c1bba0)
2023-05-18 13:30:02 +00:00
ruthra kumar
44b290f58e Merge pull request #35357 from frappe/mergify/bp/version-14-hotfix/pr-35355
fix: possible type error on quotation -> sales order creation (backport #35355)
2023-05-18 14:35:53 +05:30
ruthra kumar
d23b93a462 fix: possible type error on quotation -> sales order creation
(cherry picked from commit b2290c6f57)
2023-05-18 13:39:58 +05:30
ruthra kumar
80f4a11d60 Merge pull request #35353 from frappe/mergify/bp/version-14-hotfix/pr-35335
fix: tds incorrectly calculated for invoice that are below threshold (backport #35335)
2023-05-18 13:03:40 +05:30
Sagar Sharma
9caa39195c Merge pull request #35344 from frappe/mergify/bp/version-14-hotfix/pr-35306
fix: Pick List Status (backport #35306)
2023-05-18 12:52:25 +05:30
ruthra kumar
879946e2c8 fix(test): cumulative threshold checks
(cherry picked from commit 132846bbd1)
2023-05-18 07:09:20 +00:00
ruthra kumar
bdf81a43c6 fix: tds incorrectly calculated for invoice that are below threshold
Two purchase invoices for the same supplier, using different tax
withholding categories have this issue.

| Category | single | cumulative |
|----------+--------+------------|
| cat1     |    100 |        500 |
| cat2     |   1000 |       5000 |

1. PINV1 of net total: 105/- uses cat1. TDS is calculated as it
breached single threshold
2. PINV2 of net total: 200/- uses cat2. TDS incorrectly calculated as
PINV1 already has TDS calculated and 'consider_party_ledger_amount' is enabled.

(cherry picked from commit 84b7c1bba0)
2023-05-18 07:09:19 +00:00
Sagar Sharma
cb681e0b96 Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-35306 2023-05-18 12:30:40 +05:30
ruthra kumar
65554bdabf Merge pull request #35336 from frappe/mergify/bp/version-14-hotfix/pr-35239
fix: in payment_entry  difference amount cal is broken (backport #35239)
2023-05-18 12:15:44 +05:30
rohitwaghchaure
0d2d45f32f Merge pull request #35351 from frappe/mergify/bp/version-14-hotfix/pr-35298
fix: Creating landed cost voucher from connections (backport #35298)
2023-05-18 06:16:11 +05:30
vishnu
2631224e49 fix: Creating landed cost voucher from connections
(cherry picked from commit f2ceb00379)
2023-05-18 00:43:36 +00:00
Anand Baburajan
0a080efce2 fix: depreciation schedule for existing assets [v14] (#35255)
* fix: depreciation schedule for existing assets

* chore: correct logic for existing assets and fix test
2023-05-17 22:21:00 +05:30
Sagar Sharma
48884366ea fix: Pick List Status
(cherry picked from commit 9fb8b1827d)
2023-05-17 12:43:08 +00:00
mergify[bot]
15c1af3d8a fix: consider 0 if rate/qty are null (backport #35338) (#35340)
fix: consider 0 if rate/qty are null (#35338)

[skip ci]

(cherry picked from commit e5c86bc2e8)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2023-05-17 16:17:21 +05:30
Sagar Sharma
350f75877a Merge pull request #35339 from frappe/mergify/bp/version-14-hotfix/pr-35337
fix(ux): SCR consumed-qty read-only property (backport #35337)
2023-05-17 15:58:29 +05:30
Sagar Sharma
aa7fede0dc fix(ux): SCR consumed-qty read-only property
(cherry picked from commit adf2474d9d)
2023-05-17 10:28:03 +00:00
Ashish Shah
e9f2ab5caf refactor: use 'flt' for base_total_taxes_and_charges
difference_amount calculation is broken, as calculation gives NaN. Fix is make frm.doc.base_total_taxes_and_charges as flt(frm.doc.base_total_taxes_and_charges)

(cherry picked from commit ae4e56747c)
2023-05-17 09:40:55 +00:00
Frappe PR Bot
7076c23a4f chore(release): Bumped to Version 14.24.2
## [14.24.2](https://github.com/frappe/erpnext/compare/v14.24.1...v14.24.2) (2023-05-16)

### Bug Fixes

* add missing options for `Content Align` ([3697e8f](3697e8f1f9))
* allow over-payment against SO ([#35079](https://github.com/frappe/erpnext/issues/35079)) ([fe9e0c2](fe9e0c2121))
* bad strings format for command get-untraslated  ([#34361](https://github.com/frappe/erpnext/issues/34361)) ([5a54296](5a54296686))
* bad strings format for update-translations ([#34592](https://github.com/frappe/erpnext/issues/34592)) ([e3c1d73](e3c1d736ce))
* bom item filter issue ([098603d](098603dd35))
* cancelled vouchers in tax withheld vouchers list ([#35309](https://github.com/frappe/erpnext/issues/35309)) ([c41e1d7](c41e1d7d71))
* enqueue submit/cancel action for stock entry to avoid time out error ([457846e](457846e34c))
* force to do reposting for cancelled document ([6f96e5d](6f96e5dcd4))
* function `batch_no` should only be declared once ([#35115](https://github.com/frappe/erpnext/issues/35115)) ([26928b3](26928b395b))
* incorrect packing items ([ab56470](ab56470171))
* inventory dimension for inter company transfer return use case ([6d121b8](6d121b8107))
* inventory dimension for material transfer not working ([1d8050d](1d8050d24d))
* item list view not working ([d9efa66](d9efa662d4))
* port option for additional_conditions in item wise sales register ([#35187](https://github.com/frappe/erpnext/issues/35187)) ([42037f9](42037f9f73))
* recalculate costs in SCR while reposting ([9a8ee62](9a8ee62d5a))
* sales person allocated amount calculation error nonetype and float ([#35293](https://github.com/frappe/erpnext/issues/35293)) ([3a7c69f](3a7c69fc71))
* test case ([3f8928b](3f8928be5c))
* test case ([9b2b467](9b2b46737e))
* typo ([2772a91](2772a911ed))
* unable to create partial invoice with auto fetch terms enabled ([#35285](https://github.com/frappe/erpnext/issues/35285)) ([fa9fa97](fa9fa97e05))
* update workstation hour rate when workstation change in job card ([bc88415](bc88415e73))
* **UX:** misc "home" onboarding improvements (backport [#35319](https://github.com/frappe/erpnext/issues/35319)) ([#35321](https://github.com/frappe/erpnext/issues/35321)) ([f8c58b6](f8c58b6893))
* validate for active sla ([#32132](https://github.com/frappe/erpnext/issues/32132)) ([38e27a6](38e27a68d5))

### Performance Improvements

* cache and simplify queries for holiday list (backport [#35315](https://github.com/frappe/erpnext/issues/35315)) ([#35318](https://github.com/frappe/erpnext/issues/35318)) ([0e78403](0e7840301f))
2023-05-16 17:00:00 +00:00
Deepesh Garg
bdfd682664 Merge pull request #35324 from frappe/version-14-hotfix
chore: release v14
2023-05-16 22:28:33 +05:30
Anoop
fb0f82eed3 Merge branch 'version-14-hotfix' into gross-and-net-profit-fix 2023-05-16 20:10:23 +05:30
mergify[bot]
fa9fa97e05 fix: unable to create partial invoice with auto fetch terms enabled (#35285)
fix: unable to create partial invoice with auto fetch terms enabled (#35285)

fix: fetch so/po terms if auto fetch is enabled
(cherry picked from commit 0da6c1688b)

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
2023-05-16 18:59:12 +05:30
mergify[bot]
c41e1d7d71 fix: cancelled vouchers in tax withheld vouchers list (#35309)
fix: cancelled vouchers in tax withheld vouchers list (#35309)

(cherry picked from commit 776a83066d)

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
2023-05-16 18:58:04 +05:30
rohitwaghchaure
8f8c0a597b Merge pull request #35329 from frappe/mergify/bp/version-14-hotfix/pr-35328
fix: force to do reposting for cancelled document (backport #35328)
2023-05-16 18:53:33 +05:30
Rohit Waghchaure
6f96e5dcd4 fix: force to do reposting for cancelled document
(cherry picked from commit 6e661e7c0e)
2023-05-16 12:03:43 +00:00
mergify[bot]
f8c58b6893 fix(UX): misc "home" onboarding improvements (backport #35319) (#35321)
fix(UX): misc "home" onboarding improvements (#35319)

* fix(UX): cleanup "Home" onboarding

- Remove company, letterhead, data import etc from home onboarding step

* fix(UX): Show quick entry for item

* chore: fix copy here and there

(cherry picked from commit 5574d9a72d)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2023-05-16 16:00:25 +05:30
mergify[bot]
0e7840301f perf: cache and simplify queries for holiday list (backport #35315) (#35318)
Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2023-05-16 13:44:35 +05:30
Anoop Kurungadam
cb9b4fbb91 fix: add total col for gross and net profit 2023-05-16 12:08:42 +05:30
Anoop Kurungadam
1a3b9c5bdf refactor: merge separate loops for calculating group / leaf node totals
rename function
remove return statement as the list is  mutated
2023-05-16 12:08:32 +05:30
Anoop Kurungadam
50822f207e refactor: remove unused parameters 2023-05-16 12:08:24 +05:30
Anoop Kurungadam
8dcb9302b4 fix: account group totals calculation to consider include_in_gross 2023-05-16 12:08:17 +05:30
rohitwaghchaure
19f08afcef Merge pull request #35314 from frappe/mergify/bp/version-14-hotfix/pr-35312
fix: item list view not working (backport #35312)
2023-05-16 11:10:18 +05:30
mergify[bot]
42037f9f73 fix: port option for additional_conditions in item wise sales register (#35187)
fix: port option for additional_conditions in item wise sales register (#35187)

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

Co-authored-by: Smit Vora <smitvora203@gmail.com>
2023-05-16 07:29:48 +05:30
Rohit Waghchaure
d9efa662d4 fix: item list view not working
(cherry picked from commit 0489e30244)
2023-05-15 19:40:23 +00:00
rohitwaghchaure
ee147e62d5 Merge pull request #35311 from CodeVenturers/version-14-hotfix
fix: update workstation hour rate when workstation change in job card
2023-05-16 00:44:26 +05:30
vishnu
bc88415e73 fix: update workstation hour rate when workstation change in job card 2023-05-15 14:50:40 +00:00
Sagar Sharma
5463f0b137 Merge pull request #35308 from frappe/mergify/bp/version-14-hotfix/pr-35138
fix: recalculate costs in SCR while reposting (backport #35138)
2023-05-15 17:14:57 +05:30
Sagar Sharma
a8fc17e0ae refactor: use calculate_items_qty_and_amount() to update scr items rate
(cherry picked from commit 9c72c2a6cb)
2023-05-15 10:56:51 +00:00
Sagar Sharma
0575b105d0 refactor(minor): rename function to be more descriptive
(cherry picked from commit d6433f803b)
2023-05-15 10:56:51 +00:00
Sagar Sharma
4c8dbeddec test: add test case
(cherry picked from commit e0b22edb2e)
2023-05-15 10:56:51 +00:00
s-aga-r
9a8ee62d5a fix: recalculate costs in SCR while reposting
(cherry picked from commit a6cb6c6f47)
2023-05-15 10:56:50 +00:00
mergify[bot]
3a7c69fc71 fix: sales person allocated amount calculation error nonetype and float (#35293)
fix: sales person allocated amount calculation error nonetype and float (#35293)

fix: sales person allocated amount calculation error nontype and float
(cherry picked from commit 0c8276ec82)

Co-authored-by: Indrajith.vs <91895505+Gubbu77@users.noreply.github.com>
2023-05-15 13:16:47 +05:30
rohitwaghchaure
dd116a3071 Merge pull request #35291 from frappe/mergify/bp/version-14-hotfix/pr-35289
fix: inventory dimension for returned inter company transfer (backport #35289)
2023-05-14 16:29:34 +05:30
rohitwaghchaure
3f8928be5c fix: test case 2023-05-14 15:49:58 +05:30
mergify[bot]
26928b395b fix: function batch_no should only be declared once (#35115)
fix: function `batch_no` should only be declared once (#35115)

fix: remove twice event call of `batch_no` to update batch qty
(cherry picked from commit 19cd687784)

Co-authored-by: Daizy Modi <modidaizy5217@gmail.com>
2023-05-14 11:54:15 +05:30
mergify[bot]
fe9e0c2121 fix: allow over-payment against SO (#35079)
fix: allow over-payment against SO (#35079)

(cherry picked from commit 870b02b03c)

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2023-05-14 11:44:50 +05:30
Deepesh Garg
77cf2e5475 Merge pull request #35262 from akiratfli/fix-bad-string
fix: bad strings format for translations
2023-05-14 08:06:24 +05:30
rohitwaghchaure
2772a911ed fix: typo 2023-05-13 15:14:41 +05:30
Rohit Waghchaure
6d121b8107 fix: inventory dimension for inter company transfer return use case
(cherry picked from commit 38aaba5720)
2023-05-13 08:57:03 +00:00
Sagar Sharma
c30dda3328 Merge pull request #35283 from frappe/mergify/bp/version-14-hotfix/pr-35275
fix: add missing options for `Content Align` (backport #35275)
2023-05-13 09:42:20 +05:30
Sagar Sharma
b2e6fdc0cb Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-35275 2023-05-13 09:41:30 +05:30
rohitwaghchaure
75af689f77 Merge pull request #35282 from frappe/mergify/bp/version-14-hotfix/pr-35224
fix: inventory dimension for material transfer not working (backport #35224)
2023-05-13 09:36:42 +05:30
Sagar Sharma
3697e8f1f9 fix: add missing options for Content Align
(cherry picked from commit d16caa2d2c)
2023-05-13 04:05:15 +00:00
Rohit Waghchaure
1d8050d24d fix: inventory dimension for material transfer not working
(cherry picked from commit 6798b900ef)
2023-05-12 20:46:04 +00:00
Frappe PR Bot
897a467846 chore(release): Bumped to Version 14.24.1
## [14.24.1](https://github.com/frappe/erpnext/compare/v14.24.0...v14.24.1) (2023-05-12)

### Bug Fixes

* bom item filter issue ([54e822d](54e822d83a))
* enqueue submit/cancel action for stock entry to avoid time out error ([762a46a](762a46a5e3))
* incorrect packing items ([b02ed0d](b02ed0d9a8))
* test case ([1783594](1783594178))
2023-05-12 10:05:31 +00:00
rohitwaghchaure
f06a8fd01c Merge pull request #35270 from frappe/mergify/bp/version-14/pr-35266
fix: enqueue submit/cancel action for stock entry to avoid time out error (backport #35261) (backport #35266)
2023-05-12 15:30:55 +05:30
rohitwaghchaure
b139ec6ec0 Merge pull request #35271 from frappe/mergify/bp/version-14/pr-35269
fix: BOM item filter issue (backport #35268) (backport #35269)
2023-05-12 15:30:43 +05:30
rohitwaghchaure
e97eaccdfb Merge pull request #35276 from frappe/mergify/bp/version-14/pr-35274
fix: incorrect packing items (backport #35273) (backport #35274)
2023-05-12 15:30:28 +05:30
Rohit Waghchaure
b02ed0d9a8 fix: incorrect packing items
(cherry picked from commit a686b8c337)
(cherry picked from commit ab56470171)
2023-05-12 09:37:12 +00:00
rohitwaghchaure
4206f01c05 Merge pull request #35274 from frappe/mergify/bp/version-14-hotfix/pr-35273
fix: incorrect packing items (backport #35273)
2023-05-12 15:06:25 +05:30
Rohit Waghchaure
ab56470171 fix: incorrect packing items
(cherry picked from commit a686b8c337)
2023-05-12 09:13:52 +00:00
Rohit Waghchaure
54e822d83a fix: bom item filter issue
(cherry picked from commit 2879cb7c28)
(cherry picked from commit 098603dd35)
2023-05-12 07:42:57 +00:00
rohitwaghchaure
8af1e49e96 Merge pull request #35269 from frappe/mergify/bp/version-14-hotfix/pr-35268
fix: BOM item filter issue (backport #35268)
2023-05-12 13:12:11 +05:30
Rohit Waghchaure
1783594178 fix: test case
(cherry picked from commit 2d6f112727)
(cherry picked from commit 9b2b46737e)
2023-05-12 07:41:34 +00:00
Rohit Waghchaure
762a46a5e3 fix: enqueue submit/cancel action for stock entry to avoid time out error
(cherry picked from commit 7a3801578c)
(cherry picked from commit 457846e34c)
2023-05-12 07:41:34 +00:00
rohitwaghchaure
19f0676592 Merge pull request #35266 from frappe/mergify/bp/version-14-hotfix/pr-35261
fix: enqueue submit/cancel action for stock entry to avoid time out error (backport #35261)
2023-05-12 13:10:48 +05:30
Rohit Waghchaure
098603dd35 fix: bom item filter issue
(cherry picked from commit 2879cb7c28)
2023-05-12 07:40:38 +00:00
Rohit Waghchaure
9b2b46737e fix: test case
(cherry picked from commit 2d6f112727)
2023-05-12 07:03:22 +00:00
Rohit Waghchaure
457846e34c fix: enqueue submit/cancel action for stock entry to avoid time out error
(cherry picked from commit 7a3801578c)
2023-05-12 07:03:21 +00:00
Danny
5a54296686 fix: bad strings format for command get-untraslated (#34361)
(cherry picked from commit ca10e2bb9f)
2023-05-12 03:19:01 +00:00
justin.li
e3c1d736ce fix: bad strings format for update-translations (#34592)
(cherry picked from commit 07c9b99072)
2023-05-12 02:21:19 +00:00
Saqib Ansari
c8e3ce48e1 Merge pull request #35257 from frappe/mergify/bp/version-14-hotfix/pr-32132
fix: validate for active sla (backport #32132)
2023-05-11 17:50:00 +05:30
Shadrak Gurupnor
38e27a68d5 fix: validate for active sla (#32132)
(cherry picked from commit f2b7c9ee66)
2023-05-11 12:18:49 +00:00
Frappe PR Bot
e509664d4f chore(release): Bumped to Version 14.24.0
# [14.24.0](https://github.com/frappe/erpnext/compare/v14.23.4...v14.24.0) (2023-05-10)

### Bug Fixes

* added search index to improve performance ([362003e](362003ec5f))
* broken save on empty row existance ([c0f9ff4](c0f9ff4995))
* bypass flag in Customer Group wasn't effective ([c73b76f](c73b76fdb6))
* Changed type of column 'serial_no' in Stock Reconciliation to fix Data too long error ([709f94c](709f94c8d3))
* child acc will inherit acc currency if explicitly specified ([72255fa](72255fae80))
* enabling lead even after "Opportunity" created against it ([#34627](https://github.com/frappe/erpnext/issues/34627)) ([5e98679](5e98679f91))
* error regarding accepted and supplier warehouse ([42f5888](42f5888426))
* fetch default sales team on Quotation -> Sales Order creation ([f42225b](f42225bc82))
* handle empty FBs properly in TB and GL [v14] ([#35189](https://github.com/frappe/erpnext/issues/35189)) ([ed5f39c](ed5f39c2c2))
* incorrect fg item quantity in subcontracted PO ([5c38645](5c38645560))
* internal transfer condition ([f5f4902](f5f4902494))
* non manufacturing items/fixed asset items in BOM ([8133be4](8133be4868))
* not allow to transfer excess materials against the job card ([b0c042d](b0c042de1b))
* over production percentage not considered in validation ([bf6e1b6](bf6e1b67a5))
* pick the in progress reposting entries first ([545f956](545f956160))

### Features

* configuration to notify reposting errors to specific role ([33cd14f](33cd14f859))
* reserve qty against production plan raw materials in BIN ([d1a9117](d1a91177e5))
2023-05-10 05:40:21 +00:00
Deepesh Garg
2fb3659694 Merge pull request #35222 from frappe/version-14-hotfix
chore: release v14
2023-05-10 11:08:42 +05:30
ruthra kumar
1145149f0e Merge pull request #35228 from frappe/mergify/bp/version-14-hotfix/pr-35216
fix: broken save on empty row existance (backport #35216)
2023-05-10 10:11:32 +05:30
rohitwaghchaure
dd20bf931b Merge pull request #35234 from frappe/mergify/bp/version-14-hotfix/pr-35230
fix: Changed type of column 'serial_no' in Stock Reconciliation to fix Data too Long error (backport #35230)
2023-05-09 21:06:14 +05:30
Rohit Waghchaure
709f94c8d3 fix: Changed type of column 'serial_no' in Stock Reconciliation to fix Data too long error
(cherry picked from commit 1a673fd424)
2023-05-09 14:26:13 +00:00
rohitwaghchaure
2933c4f1c5 Merge pull request #35231 from frappe/mergify/bp/version-14-hotfix/pr-35227
fix: non manufacturing items/fixed asset items in BOM (backport #35227)
2023-05-09 19:53:53 +05:30
Rohit Waghchaure
8133be4868 fix: non manufacturing items/fixed asset items in BOM
(cherry picked from commit aba8431d70)
2023-05-09 13:18:47 +00:00
Dany Robert
c0f9ff4995 fix: broken save on empty row existance
(cherry picked from commit d9b231aa16)
2023-05-09 13:02:54 +00:00
rohitwaghchaure
7b6a1e5184 Merge pull request #35221 from frappe/mergify/bp/version-14-hotfix/pr-35220
fix: added search index to improve performance (backport #35220)
2023-05-09 16:04:36 +05:30
Rohit Waghchaure
362003ec5f fix: added search index to improve performance
(cherry picked from commit 80ea22b56c)
2023-05-09 09:05:43 +00:00
ruthra kumar
30e137e9f2 Merge pull request #35214 from frappe/mergify/bp/version-14-hotfix/pr-35212
chore: convert throw to msgprint in payment reconciliation job hook (backport #35212)
2023-05-08 19:07:41 +05:30
ruthra kumar
08a4781de7 chore: convert throw to msgprint
(cherry picked from commit 73134d57bf)
2023-05-08 12:28:01 +00:00
ruthra kumar
14706d4326 Merge pull request #35209 from frappe/mergify/bp/version-14-hotfix/pr-35153
fix: fetch default sales team on Quotation -> Sales Order creation (backport #35153)
2023-05-08 14:51:45 +05:30
ruthra kumar
fd09d1c4c3 Merge pull request #35208 from frappe/mergify/bp/version-14-hotfix/pr-35142
fix: ineffective bypass flag for Credit Limit in Customer Group (backport #35142)
2023-05-08 14:51:29 +05:30
rohitwaghchaure
afbbf26f15 Merge pull request #35202 from frappe/mergify/bp/version-14-hotfix/pr-35196
fix: pick the in progress reposting entries first (backport #35196)
2023-05-08 14:40:10 +05:30
rohitwaghchaure
f83fcf5261 Merge pull request #35203 from frappe/mergify/bp/version-14-hotfix/pr-35200
fix: error regarding accepted and supplier warehouse (backport #35200)
2023-05-08 14:39:52 +05:30
ruthra kumar
5879475a00 Merge pull request #35207 from frappe/mergify/bp/version-14-hotfix/pr-35186
fix: child acc will inherit acc currency if explicitly specified (backport #35186)
2023-05-08 14:35:26 +05:30
ruthra kumar
f42225bc82 fix: fetch default sales team on Quotation -> Sales Order creation
(cherry picked from commit 4d31436917)
2023-05-08 08:50:09 +00:00
ruthra kumar
c73b76fdb6 fix: bypass flag in Customer Group wasn't effective
(cherry picked from commit f9a4972cb6)
2023-05-08 08:41:51 +00:00
ruthra kumar
e451916803 test: currency inheritance on child accounts
(cherry picked from commit f6ea8fd8d7)
2023-05-08 08:40:28 +00:00
ruthra kumar
72255fae80 fix: child acc will inherit acc currency if explicitly specified
(cherry picked from commit abe691c03d)
2023-05-08 08:40:28 +00:00
Rohit Waghchaure
42f5888426 fix: error regarding accepted and supplier warehouse
(cherry picked from commit 15f5f98858)
2023-05-08 03:54:40 +00:00
Rohit Waghchaure
545f956160 fix: pick the in progress reposting entries first
(cherry picked from commit c8a4791d9b)
2023-05-08 03:54:22 +00:00
rohitwaghchaure
1226f3294f Merge pull request #35198 from frappe/mergify/bp/version-14-hotfix/pr-35197
fix: incorrect fg item quantity in subcontracted PO (backport #35197)
2023-05-07 17:05:13 +05:30
Rohit Waghchaure
5c38645560 fix: incorrect fg item quantity in subcontracted PO
(cherry picked from commit af16fbb0a3)
2023-05-06 20:09:31 +00:00
Frappe PR Bot
9a755ca23d chore(release): Bumped to Version 14.23.4
## [14.23.4](https://github.com/frappe/erpnext/compare/v14.23.3...v14.23.4) (2023-05-06)

### Bug Fixes

* handle empty FBs properly in TB and GL [v14] (backport [#35189](https://github.com/frappe/erpnext/issues/35189)) ([#35191](https://github.com/frappe/erpnext/issues/35191)) ([a5a08c9](a5a08c9889))
2023-05-06 11:12:52 +00:00
mergify[bot]
a5a08c9889 fix: handle empty FBs properly in TB and GL [v14] (backport #35189) (#35191)
fix: handle empty FBs properly in TB and GL [v14] (#35189)

fix: handle empty FBs properly in TB and GL
(cherry picked from commit ed5f39c2c2)

Co-authored-by: Anand Baburajan <anandbaburajan@gmail.com>
2023-05-06 16:41:10 +05:30
Anand Baburajan
ed5f39c2c2 fix: handle empty FBs properly in TB and GL [v14] (#35189)
fix: handle empty FBs properly in TB and GL
2023-05-06 16:38:59 +05:30
Frappe PR Bot
a1842103b6 chore(release): Bumped to Version 14.23.3
## [14.23.3](https://github.com/frappe/erpnext/compare/v14.23.2...v14.23.3) (2023-05-04)

### Bug Fixes

* internal transfer condition ([736c34e](736c34e61a))
* not allow to transfer excess materials against the job card ([580641f](580641f55c))
2023-05-04 18:02:30 +00:00
rohitwaghchaure
4d54430010 Merge pull request #35174 from frappe/mergify/bp/version-14/pr-35163
fix: internal transfer condition (backport #35158) (backport #35163)
2023-05-04 23:30:29 +05:30
rohitwaghchaure
e855866820 Merge pull request #35175 from frappe/mergify/bp/version-14/pr-35169
fix: not allow to transfer excess materials against the job card (backport #35167) (backport #35169)
2023-05-04 23:30:07 +05:30
Rohit Waghchaure
580641f55c fix: not allow to transfer excess materials against the job card
(cherry picked from commit 8167b24219)
(cherry picked from commit b0c042de1b)
2023-05-04 17:11:54 +00:00
rohitwaghchaure
816ce879f9 Merge pull request #35169 from frappe/mergify/bp/version-14-hotfix/pr-35167
fix: not allow to transfer excess materials against the job card (backport #35167)
2023-05-04 22:41:07 +05:30
Rohit Waghchaure
736c34e61a fix: internal transfer condition
(cherry picked from commit b5a2ccf21d)
(cherry picked from commit f5f4902494)
2023-05-04 17:10:41 +00:00
rohitwaghchaure
f4858fbf8a Merge pull request #35163 from frappe/mergify/bp/version-14-hotfix/pr-35158
fix: internal transfer condition (backport #35158)
2023-05-04 22:39:55 +05:30
Rohit Waghchaure
b0c042de1b fix: not allow to transfer excess materials against the job card
(cherry picked from commit 8167b24219)
2023-05-04 13:41:34 +00:00
rohitwaghchaure
c463df4fd1 Merge pull request #35166 from frappe/mergify/bp/version-14-hotfix/pr-35161
feat: configuration to notify reposting errors to specific role (backport #35161)
2023-05-04 18:46:05 +05:30
Rohit Waghchaure
33cd14f859 feat: configuration to notify reposting errors to specific role
(cherry picked from commit c7b62011db)
2023-05-04 12:06:35 +00:00
Rohit Waghchaure
f5f4902494 fix: internal transfer condition
(cherry picked from commit b5a2ccf21d)
2023-05-04 11:32:45 +00:00
Frappe PR Bot
144594b3e1 chore(release): Bumped to Version 14.23.2
## [14.23.2](https://github.com/frappe/erpnext/compare/v14.23.1...v14.23.2) (2023-05-04)

### Bug Fixes

* over production percentage not considered in validation ([4e83d0b](4e83d0baa6))
2023-05-04 04:54:00 +00:00
rohitwaghchaure
64b416b4dd Merge pull request #35152 from frappe/mergify/bp/version-14/pr-35149
fix: over production percentage not considered in validation (backport #35148) (backport #35149)
2023-05-04 10:22:33 +05:30
Rohit Waghchaure
4e83d0baa6 fix: over production percentage not considered in validation
(cherry picked from commit a84d0af81e)
(cherry picked from commit bf6e1b67a5)
2023-05-04 04:29:28 +00:00
rohitwaghchaure
a01e2ca9ac Merge pull request #35149 from frappe/mergify/bp/version-14-hotfix/pr-35148
fix: over production percentage not considered in validation (backport #35148)
2023-05-04 09:58:43 +05:30
Rohit Waghchaure
bf6e1b67a5 fix: over production percentage not considered in validation
(cherry picked from commit a84d0af81e)
2023-05-03 18:44:32 +00:00
rohitwaghchaure
148342a132 Merge pull request #35147 from frappe/mergify/bp/version-14-hotfix/pr-35144
feat: reserve qty against production plan raw materials in BIN (backport #35144)
2023-05-04 00:00:04 +05:30
Rohit Waghchaure
d1a91177e5 feat: reserve qty against production plan raw materials in BIN
(cherry picked from commit 06e91e758f)
2023-05-03 16:54:53 +00:00
Nabin Hait
8d6034de16 Merge pull request #34647 from frappe/mergify/bp/version-14-hotfix/pr-34627
fix: enabling lead even after "Opportunity" created against it (backport #34627)
2023-05-03 13:27:07 +05:30
Nabin Hait
d306bb080a Update patches.txt 2023-05-03 12:42:36 +05:30
Nabin Hait
eb3e6ff145 Update patches.txt 2023-05-03 12:21:23 +05:30
Nabin Hait
82c3d862ce Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-34627 2023-05-03 11:21:48 +05:30
Frappe PR Bot
5eb5bf7102 chore(release): Bumped to Version 14.23.1
## [14.23.1](https://github.com/frappe/erpnext/compare/v14.23.0...v14.23.1) (2023-05-03)

### Bug Fixes

* conflicts ([3ba2b9e](3ba2b9ed2e))
* don't allow to make reposting for the closed period ([cca2fce](cca2fcec54))
* don't create material request from sales order against the delivered items ([a5489ee](a5489ee2ac))
* handle expected_value_after_useful_life properly in asset value adjustment ([#35117](https://github.com/frappe/erpnext/issues/35117)) ([80230fe](80230fec3e))
* handle finance book properly in trial balance and general ledger [v14] ([#35136](https://github.com/frappe/erpnext/issues/35136)) ([344c339](344c339484))
* Hyperlink in Quality Inspection Summary ([e4ce6fa](e4ce6fa195))
* incorrect paid_amount and exchange rate in PE ([f50b4d8](f50b4d80f1))
* linter issue ([78c34d7](78c34d71e2))
* linter issue ([453249d](453249d868))
* Naming series error in Journal Entry template ([#35084](https://github.com/frappe/erpnext/issues/35084)) ([7021e3a](7021e3adb1))
* not able to create delivery note from sales order ([28dfc13](28dfc13dc6))
* Report link, option, and added a link for Sales Person in GP ([fc611cf](fc611cf86b))
* test case ([35ec125](35ec125b34))
* test case ([6597c74](6597c74d6c))
* test case ([d844a2b](d844a2b990))
* timeout error while submitting delivery note ([e33fb3b](e33fb3b242))
* Updates in process statement of Accounts ([#35064](https://github.com/frappe/erpnext/issues/35064)) ([bef9dd7](bef9dd79e7))
2023-05-03 04:22:30 +00:00
Deepesh Garg
51d9d0a454 Merge pull request #35131 from frappe/version-14-hotfix
chore: release v14
2023-05-03 09:50:51 +05:30
Anand Baburajan
344c339484 fix: handle finance book properly in trial balance and general ledger [v14] (#35136)
fix: handle FBs properly in general ledger and trial balance
2023-05-03 07:11:01 +05:30
mergify[bot]
bef9dd79e7 fix: Updates in process statement of Accounts (#35064)
* fix: Updates in process statement of Accounts (#35064)

(cherry picked from commit ea0b03ae9e)

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

* chore: resolve conflicts

---------

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-05-02 23:06:52 +05:30
rohitwaghchaure
815696964a Merge pull request #35121 from frappe/mergify/bp/version-14-hotfix/pr-35118
fix: don't allow to make reposting for the closed period (backport #35118)
2023-05-02 18:02:23 +05:30
ruthra kumar
f0ae02e921 Merge pull request #35132 from frappe/mergify/bp/version-14-hotfix/pr-35107
fix: incorrect paid_amount and exchange rate in Payment Entry (backport #35107)
2023-05-02 15:43:08 +05:30
ruthra kumar
f50b4d80f1 fix: incorrect paid_amount and exchange rate in PE
If Company master has no default cash or bank account set but Party has
default company bank account set. In this case, paid_amount and
conversion rate are not calculated correctly

(cherry picked from commit 123355392b)
2023-05-02 09:39:03 +00:00
ruthra kumar
7ad795bec5 Merge pull request #35129 from frappe/mergify/bp/version-14-hotfix/pr-35091
refactor: button to toggle parent doc cost center preference for rounding adjustment amount (backport #35091)
2023-05-02 15:07:54 +05:30
ruthra kumar
662d9cb5aa Merge pull request #35128 from frappe/mergify/bp/version-14-hotfix/pr-35061
refactor: don't book exchange gain/loss for sales/purchase orders (backport #35061)
2023-05-02 15:07:09 +05:30
ruthra kumar
8ac718d98c refactor: checkbox to toggle parent doc cost center preference
(cherry picked from commit 4ccce93394)
2023-05-02 08:38:13 +00:00
ruthra kumar
3810b02023 refactor: checkbox in Sales Invoice
(cherry picked from commit 0f3b06cc8a)
2023-05-02 08:38:13 +00:00
ruthra kumar
25b37737a2 refactor: checkbox to toggle parent doc cost center preference
(cherry picked from commit ebe6787510)
2023-05-02 08:38:13 +00:00
ruthra kumar
0e39e5e868 refactor: checkbox in purchase invoice
(cherry picked from commit b44331c981)
2023-05-02 08:38:13 +00:00
ruthra kumar
fedde7fe3b test: Sales/Purchase Orders will not book Exchange gain/loss
(cherry picked from commit ce4e18c8d2)
2023-05-02 08:34:53 +00:00
ruthra kumar
551c96e1e5 refactor: don't book exch gain/loss for sales/purchase orders
(cherry picked from commit effb34bbfa)
2023-05-02 08:34:53 +00:00
rohitwaghchaure
78c34d71e2 fix: linter issue 2023-05-02 14:01:26 +05:30
rohitwaghchaure
453249d868 fix: linter issue 2023-05-02 11:08:06 +05:30
rohitwaghchaure
35ec125b34 fix: test case 2023-05-02 11:00:12 +05:30
rohitwaghchaure
2f3ed23a9d Merge pull request #35125 from frappe/mergify/bp/version-14-hotfix/pr-35123
fix: timeout error while submitting delivery note (backport #35123)
2023-05-02 00:00:46 +05:30
rohitwaghchaure
6597c74d6c fix: test case 2023-05-01 23:32:54 +05:30
Rohit Waghchaure
e33fb3b242 fix: timeout error while submitting delivery note
(cherry picked from commit 2d5ccc07b1)
2023-05-01 18:01:02 +00:00
rohitwaghchaure
d844a2b990 fix: test case 2023-05-01 20:49:17 +05:30
rohitwaghchaure
3ba2b9ed2e fix: conflicts 2023-05-01 20:47:12 +05:30
Rohit Waghchaure
cca2fcec54 fix: don't allow to make reposting for the closed period
(cherry picked from commit f751727149)

# Conflicts:
#	erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py
2023-05-01 15:12:01 +00:00
Anand Baburajan
80230fec3e fix: handle expected_value_after_useful_life properly in asset value adjustment (#35117) 2023-05-01 19:53:39 +05:30
mergify[bot]
7021e3adb1 fix: Naming series error in Journal Entry template (#35084)
fix: Naming series error in Journal Entry template (#35084)

(cherry picked from commit f3b3dabb9a)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-05-01 13:02:11 +05:30
rohitwaghchaure
69c0d81c55 Merge pull request #35093 from frappe/mergify/bp/version-14-hotfix/pr-35092
fix: not able to create delivery note from sales order (backport #35092)
2023-04-30 14:54:43 +05:30
Rohit Waghchaure
28dfc13dc6 fix: not able to create delivery note from sales order
(cherry picked from commit bdf2f7416a)
2023-04-28 10:33:23 +00:00
rohitwaghchaure
5f381cd520 Merge pull request #35070 from frappe/mergify/bp/version-14-hotfix/pr-35066
fix: don't create material request from sales order against delivered items (backport #35066)
2023-04-28 16:02:15 +05:30
Sagar Sharma
8571e6c5d2 Merge pull request #35088 from frappe/mergify/bp/version-14-hotfix/pr-35081
fix: Hyperlink in Quality Inspection Summary (backport #35081)
2023-04-28 12:53:45 +05:30
Nihantra Patel
e4ce6fa195 fix: Hyperlink in Quality Inspection Summary
(cherry picked from commit 72dd7884a8)
2023-04-28 07:19:15 +00:00
ruthra kumar
ef3d352a17 Merge pull request #35080 from frappe/mergify/bp/version-14-hotfix/pr-35077
fix: Report link, option, and added a link for Sales Person in GP (backport #35077)
2023-04-27 17:42:30 +05:30
Nihantra Patel
fc611cf86b fix: Report link, option, and added a link for Sales Person in GP
(cherry picked from commit 6dfca79af3)
2023-04-27 11:12:01 +00:00
Rohit Waghchaure
a5489ee2ac fix: don't create material request from sales order against the delivered items
(cherry picked from commit 1e2deee579)
2023-04-27 03:36:23 +00:00
Frappe PR Bot
85f3a5d318 chore(release): Bumped to Version 14.23.0
# [14.23.0](https://github.com/frappe/erpnext/compare/v14.22.3...v14.23.0) (2023-04-25)

### Bug Fixes

* `PermissionError` in Work Order ([a3568c1](a3568c1b27))
* Add company field to lower deduction certificate ([#34914](https://github.com/frappe/erpnext/issues/34914)) ([d732083](d732083166))
* add item-code filter for SCR supplied-items batch-no ([7c4f83e](7c4f83ed60))
* add limit for get_next_stock_reco ([#34937](https://github.com/frappe/erpnext/issues/34937)) ([7131ff2](7131ff28fd))
* added validation for extra job card ([a5fde5d](a5fde5d933))
* batch qty conversion factor issue fixed in pos transaction ([#34917](https://github.com/frappe/erpnext/issues/34917)) ([56ef0ba](56ef0baa9d))
* broken 'set exchange gain/loss' btn in payment entry ([#34940](https://github.com/frappe/erpnext/issues/34940)) ([00968ba](00968badf5))
* Bulk Payment Entry from PO/SO ([#34942](https://github.com/frappe/erpnext/issues/34942)) ([878d747](878d7477bc))
* click handler should not attempt indexed access of empty array ([#35013](https://github.com/frappe/erpnext/issues/35013)) ([06f204a](06f204a8d6))
* Common party JV cost center ([#35008](https://github.com/frappe/erpnext/issues/35008)) ([693007a](693007adfe))
* duplicate reposting entries of same voucher ([aeac43c](aeac43ccf9))
* FEC report for France accountancy  ([#34781](https://github.com/frappe/erpnext/issues/34781)) ([6aabab2](6aabab26d8))
* filtering via batch no ([#34951](https://github.com/frappe/erpnext/issues/34951)) ([3b23fc1](3b23fc1eba)), closes [#34950](https://github.com/frappe/erpnext/issues/34950)
* Incorrect difference value in Stock and Account Value Comparison report ([e7ca833](e7ca833929))
* incorrect OR condition causing timeout error ([c020789](c020789bfc))
* internal Purchase Receipt GL Entries ([f7e436f](f7e436fe71))
* item not showing in the BOM ([28cd79a](28cd79a040))
* pass reference_doctype in link queries (backport [#35038](https://github.com/frappe/erpnext/issues/35038)) ([#35039](https://github.com/frappe/erpnext/issues/35039)) ([5cc3978](5cc3978c16))
* Payment entry with TDS in bank reco statement ([#34961](https://github.com/frappe/erpnext/issues/34961)) ([f43ea0d](f43ea0d6ff))
* per_billed condition for Payment Entry ([#34969](https://github.com/frappe/erpnext/issues/34969)) ([f9f42c7](f9f42c7e98))
* process_loss_percentage in BOM ([4418862](4418862965))
* removed depends on for the Employee Detail section ([9d17d3f](9d17d3ff06))
* respect title_field from doctype to bulk transactions ([#34928](https://github.com/frappe/erpnext/issues/34928)) ([29aa4a0](29aa4a0222))
* set `frappe.flags.company` to call regional code accurately ([789dfd6](789dfd6774))
* simplify `erpnext.get_region` ([87595bd](87595bdb7e))
* SLA permissions (backport [#34981](https://github.com/frappe/erpnext/issues/34981)) ([#34986](https://github.com/frappe/erpnext/issues/34986)) ([83a1b83](83a1b836f9))
* stock entry type issue ([33a1608](33a16086ef))
* **test:** `test_backdated_stock_reco_cancellation_future_negative_stock` ([2ad157b](2ad157bd77))
* **test:** `test_internal_pr_gl_entries` ([7740ceb](7740ceb27e))
* Unable to allocate advance against invoice ([#35007](https://github.com/frappe/erpnext/issues/35007)) ([5045ad6](5045ad6be6))
* use `functools.wraps` to preserve doc signature ([2ec18eb](2ec18eb4cf))
* use CombineDatetime instead of Timestamp in QB queries ([55da91c](55da91cb34))
* use filter_by_finance_book instead of only_depreciable_assets in fixed asset register (backport [#35031](https://github.com/frappe/erpnext/issues/35031)) ([#35035](https://github.com/frappe/erpnext/issues/35035)) ([5630e81](5630e8189b))
* Use set instead of db_set as it is called from validate ([#34967](https://github.com/frappe/erpnext/issues/34967)) ([6650212](665021270f))
* v14, Bank Reconcile Tools not cover case JV debit bank ([#35000](https://github.com/frappe/erpnext/issues/35000)) ([82d8379](82d8379188))
* validation for internal transfer entry ([a582354](a5823547d3))
* value of depreciable assets not updating after manual depr entry [v14] ([#35010](https://github.com/frappe/erpnext/issues/35010)) ([3c75e55](3c75e55cb9))
* wrong qty of remaining work orders to be created when using "Create" > "Work Order" ([#34726](https://github.com/frappe/erpnext/issues/34726)) ([47df41f](47df41fdbd))

### Features

* Reconcile Payments in background ([#34596](https://github.com/frappe/erpnext/issues/34596)) ([5923a80](5923a80a0f))

### Performance Improvements

* Journal Entries (backport [#34918](https://github.com/frappe/erpnext/issues/34918)) ([#35054](https://github.com/frappe/erpnext/issues/35054)) ([39b5147](39b5147768))

### Reverts

* Revert "fix: Rate from LDC in TDS reports (#33699)" ([f44a79f](f44a79fa73)), closes [#33699](https://github.com/frappe/erpnext/issues/33699)
2023-04-25 17:00:40 +00:00
Deepesh Garg
b1473c9932 Merge pull request #35034 from frappe/version-14-hotfix
chore: release v14
2023-04-25 22:28:48 +05:30
mergify[bot]
82d8379188 fix: v14, Bank Reconcile Tools not cover case JV debit bank (#35000)
fix: v14, Bank Reconcile Tools not cover case JV debit bank (#35000)

(cherry picked from commit c36dc3dc57)

Co-authored-by: Kitti U. @ Ecosoft <kittiu@gmail.com>
2023-04-25 21:58:27 +05:30
mergify[bot]
39b5147768 perf: Journal Entries (backport #34918) (#35054)
* refactor: rewrite `get_stock_value_on()` queries in `QB`

(cherry picked from commit e43bc38e05)

* refactor: sum up SLE value in query

(cherry picked from commit 9a37ac6c25)

* refactor: `get_stock_value_on()` to get stock value of multiple warehouses at once

(cherry picked from commit e782a054c8)

---------

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-04-25 21:53:07 +05:30
mergify[bot]
d732083166 fix: Add company field to lower deduction certificate (#34914)
* fix: Add company field to lower deduction certificate (#34914)

(cherry picked from commit b545e3def0)

# Conflicts:
#	erpnext/patches.txt

* chore: resolve conflicts

---------

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-25 21:33:43 +05:30
mergify[bot]
693007adfe fix: Common party JV cost center (#35008)
fix: Common party JV cost center (#35008)

(cherry picked from commit f88431a79a)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-25 21:16:59 +05:30
mergify[bot]
f43ea0d6ff fix: Payment entry with TDS in bank reco statement (#34961)
fix: Payment entry with TDS in bank reco statement (#34961)

(cherry picked from commit ecea9b44a3)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-25 21:13:20 +05:30
mergify[bot]
f9f42c7e98 fix: per_billed condition for Payment Entry (#34969)
fix: per_billed condition for Payment Entry (#34969)

(cherry picked from commit d6bc8bba8b)

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2023-04-25 21:12:58 +05:30
mergify[bot]
06f204a8d6 fix: click handler should not attempt indexed access of empty array (#35013)
fix: click handler should not attempt indexed access of empty array (#35013)

fix: click handler should not attempt indexed access
of empty array

(cherry picked from commit 3d90b970d1)

Co-authored-by: tundebabzy <tundebabzy@gmail.com>
2023-04-25 21:11:08 +05:30
mergify[bot]
47df41fdbd fix: wrong qty of remaining work orders to be created when using "Create" > "Work Order" (#34726)
fix: wrong qty of remaining work orders to be created when using "Create" > "Work Order" (#34726)

* fix: convert asynchronous field update to synchronous

* fix: wrong qty of remaining work orders to be created when using "Create" > "Work Order"

(cherry picked from commit 189b020d22)

Co-authored-by: danjeremynavarro <46537526+danjeremynavarro@users.noreply.github.com>
2023-04-25 20:08:01 +05:30
mergify[bot]
878d7477bc fix: Bulk Payment Entry from PO/SO (#34942)
fix: Bulk Payment Entry from PO/SO (#34942)

Co-authored-by: Nihantra Patel <n.patel.serpentcs@gmail.com>
(cherry picked from commit f1acc5fabb)

Co-authored-by: Solufy Solution <34390782+Solufyin@users.noreply.github.com>
2023-04-25 20:05:34 +05:30
mergify[bot]
29aa4a0222 fix: respect title_field from doctype to bulk transactions (#34928)
fix: respect title_field from doctype to bulk transactions (#34928)

(cherry picked from commit 22290c2694)

Co-authored-by: HarryPaulo <paulo_fabris@hotmail.com>
2023-04-25 20:05:13 +05:30
mergify[bot]
5045ad6be6 fix: Unable to allocate advance against invoice (#35007)
fix: Unable to allocate advance against invoice (#35007)

(cherry picked from commit f7b50f2ade)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-25 20:04:47 +05:30
mergify[bot]
665021270f fix: Use set instead of db_set as it is called from validate (#34967)
fix: Use set instead of db_set as it is called from validate (#34967)

(cherry picked from commit 72b5c1f70a)

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
2023-04-25 20:04:28 +05:30
mergify[bot]
5923a80a0f feat: Reconcile Payments in background (#34596)
feat: Reconcile Payments in background (#34596)

* feat: auto reconcile in background

* chore: Option to enable auto reconciliation in settings

* refactor: validate if feature is enabled in settings

* refactor: check for running job while using reconciliation tool

* chore: using doc to get filter values

* chore: use frappe.db.get_value in validations

* chore: cleanup commented out code

* chore: replace get_list with get_all

* chore: use block scope variable

* chore: type information for functions

* refactor: flag to ignore job validation check

* refactor: update parent doc status if all reconciled

* chore: create test_records file

* test: create a bunch of vouchers for testing auto reconcile

* chore: renamed auto_reconcile to process_payment_reconciliation

* chore: another child doctype to hold payments

* chore: remove duplicate field

* chore: add fetched payments to log

* chore: Popup comment message update

* chore: replace get_all with get_value

* chore: replace label in settings page

* chore: remove unit test and records

* refactor: status in reconciliation log

* refactor: set status in log as well

* chore: fix field name

* chore: change triggered job name

* chore: use status field in list view of log

* chore: status while there are no allocations

* refactor: split trigger function into two

* chore: adding cancelled status

* refactor: function trigger queued docs

* chore: cron job scheduled

* chore: fixing accouts settings json file

* chore: typos and variable scope

* chore: use 'pluck' in db call

* chore: remove redundant whitelist decorator

* chore: use single DB call to fetch values

* chore: replace get_all with get_value

* refactor: use raw db calls to fetch reconciliation log records

Using get_doc on `Process Payment Reconciliation Log` is costly when
handling large volumes of invoices.

Use raw frappe.db.get_all to selectively pull status and reconciled count

* chore: update status on successful batch operation

* chore: make payment table readonly

* chore: ability to pause the background job

* chore: remove isolate_each_allocation

* chore: more description in progress bar

* refactor: partially working state

* refactor: update reconcile flag and setting hard limits for fetching

* chore: make allocation editable -- NEED TO REVERT

* chore: pause button

* refactor: skip setter function in Payment Entry for better performan

* refactor: split reconcile function and skip a setter function

1. Split reconcile function into 2
2. While reconciling against payment entry, skip a
set_missing_ref_details setter method

* chore: increase payment limit

* refactor: replace frappe.db.get_all with frappe.db.get_value

* chore: remove unwanted doctypes

* refactor: make allocation table readonly

* perf: update ref_details only for newly linked invoices

* chore: rename skip flag

* refactor(UI): receivable_payable field should auto populate

* refactor: no control statements in finally block

* chore: cleanup section and rename checkbox

* chore: update new fieldname in code

* chore: update error msg

* refactor: start and pause integrated into status

pause checkbox has been removed

* refactor: added cancelled status to the log doctype

1. Moved the status section to the bottom in parent doc
2. Using alerts to indicate Job trigger status

(cherry picked from commit ed14d1ce44)

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
2023-04-25 19:20:06 +05:30
mergify[bot]
5cc3978c16 fix: pass reference_doctype in link queries (backport #35038) (#35039)
fix: pass reference_doctype in link queries (#35038)

(cherry picked from commit 6de71eb158)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2023-04-25 18:42:32 +05:30
mergify[bot]
5630e8189b fix: use filter_by_finance_book instead of only_depreciable_assets in fixed asset register (backport #35031) (#35035)
fix: use filter_by_finance_book instead of only_depreciable_assets in fixed asset register (#35031)

fix: use filter_by_finance_book instead of only_depreciable_assets
(cherry picked from commit e08d636bf7)

Co-authored-by: Anand Baburajan <anandbaburajan@gmail.com>
2023-04-25 15:53:10 +05:30
rohitwaghchaure
d121282439 Merge pull request #35016 from frappe/mergify/bp/version-14-hotfix/pr-35012
fix: item not showing in the BOM (backport #35012)
2023-04-25 14:49:35 +05:30
Anand Baburajan
3c75e55cb9 fix: value of depreciable assets not updating after manual depr entry [v14] (#35010)
* fix: update value of asset with calc_depr on after manual depr entry

* fix: value of asset with calc_depr on after manual depr entry not reflecting in asset_depr_and_bal report

* chore: add validation for depr journal entry

* test: manual_depr_for_depreciable_asset and manual_depr_w_incorrect_jv_voucher_type

* chore: unlink depreciable asset from manual depr entry
2023-04-25 12:44:58 +05:30
rohitwaghchaure
aa22cccf99 Merge pull request #35028 from frappe/mergify/bp/version-14-hotfix/pr-35026
Revert "fix: Incorrect difference value in Stock and Account Value Comparison…" (backport #35026)
2023-04-25 12:10:03 +05:30
rohitwaghchaure
7d9c9884dc Revert "fix: Incorrect difference value in Stock and Account Value Comparison…"
(cherry picked from commit 7a63fbef4f)
2023-04-25 06:39:36 +00:00
ruthra kumar
e03eaa31fe Merge pull request #35023 from frappe/mergify/bp/version-14-hotfix/pr-34974
Revert "fix: Rate from LDC in TDS reports" (backport #34974)
2023-04-25 12:04:50 +05:30
ruthra kumar
f44a79fa73 Revert "fix: Rate from LDC in TDS reports (#33699)"
This reverts commit db9beb3cdd.

(cherry picked from commit cb7a99cbaa)
2023-04-25 05:47:51 +00:00
Frappe PR Bot
943acbfea8 chore(release): Bumped to Version 14.22.3
## [14.22.3](https://github.com/frappe/erpnext/compare/v14.22.2...v14.22.3) (2023-04-24)

### Bug Fixes

* incorrect OR condition causing timeout error ([d5910fb](d5910fba44))
2023-04-24 12:41:30 +00:00
rohitwaghchaure
e955eeeabc Merge pull request #35018 from frappe/mergify/bp/version-14/pr-35017
fix: incorrect OR condition causing timeout error (For more than 50 line items) (backport #35015) (backport #35017)
2023-04-24 18:09:45 +05:30
Rohit Waghchaure
d5910fba44 fix: incorrect OR condition causing timeout error
(cherry picked from commit 379b215aea)
(cherry picked from commit c020789bfc)
2023-04-24 12:39:21 +00:00
rohitwaghchaure
c8622fb46f Merge pull request #35017 from frappe/mergify/bp/version-14-hotfix/pr-35015
fix: incorrect OR condition causing timeout error (For more than 50 line items) (backport #35015)
2023-04-24 18:08:34 +05:30
Rohit Waghchaure
c020789bfc fix: incorrect OR condition causing timeout error
(cherry picked from commit 379b215aea)
2023-04-24 12:37:50 +00:00
Rohit Waghchaure
28cd79a040 fix: item not showing in the BOM
(cherry picked from commit 02c3b41dc2)
2023-04-24 12:37:26 +00:00
mergify[bot]
70014028e9 chore: ERPNext setup wizard cleanup (#33675)
chore: ERPNext setup wizard cleanup (#33675)

* chore: ERPNext setup wizard cleanup

* chore: Remove default website

* chore: Remove flaky tests

* chore: remove unwanted tests

(cherry picked from commit 3598bcc9a8)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-24 15:28:41 +05:30
rohitwaghchaure
79cbe1cce8 Merge pull request #34995 from frappe/mergify/bp/version-14-hotfix/pr-34994
fix: duplicate reposting entries of same voucher (backport #34994)
2023-04-22 14:55:50 +05:30
Rohit Waghchaure
aeac43ccf9 fix: duplicate reposting entries of same voucher
(cherry picked from commit f2253dd645)
2023-04-22 08:38:53 +00:00
rohitwaghchaure
a5e6b371ac Merge pull request #34987 from frappe/mergify/bp/version-14-hotfix/pr-34982
fix: added validation for extra job cards (backport #34982)
2023-04-22 08:40:42 +05:30
mergify[bot]
83a1b836f9 fix: SLA permissions (backport #34981) (#34986)
fix: SLA permissions (#34981)

(cherry picked from commit ac871797b2)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2023-04-21 21:13:38 +05:30
rohitwaghchaure
6e03c09017 Merge pull request #34983 from frappe/mergify/bp/version-14-hotfix/pr-34980
fix: validation for internal transfer entry (backport #34980)
2023-04-21 18:53:41 +05:30
Rohit Waghchaure
a5fde5d933 fix: added validation for extra job card
(cherry picked from commit 6a0b7c9e8c)
2023-04-21 13:21:27 +00:00
Rohit Waghchaure
a5823547d3 fix: validation for internal transfer entry
(cherry picked from commit 19911b48fd)
2023-04-21 12:16:43 +00:00
mergify[bot]
00968badf5 fix: broken 'set exchange gain/loss' btn in payment entry (#34940)
fix: broken set exchagne gain/loss btn broken in payment entry

(cherry picked from commit df0682fa8c)

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
2023-04-21 14:26:10 +05:30
mergify[bot]
6aabab26d8 fix: FEC report for France accountancy (#34781)
fix: FEC report for France accountancy  (#34781)

* fix: FEC report for France Accountancy legal requirement

* fix: FEC report for France Accountancy legal requirement

* fix: change to query standard

* fix: change to query standard

* fix: columns to standard dict

* fix: columns to standard dict

* fix: columns to data

* refactor: french report FEC

* refactor: french report FEC (2)

---------

Co-authored-by: barredterra <14891507+barredterra@users.noreply.github.com>
(cherry picked from commit af8da53cf4)

Co-authored-by: HENRY Florian <florian.henry@open-concept.pro>
2023-04-21 14:23:18 +05:30
mergify[bot]
de86e8fb95 chore: Move source and campaign to more info section (#34946)
chore: Move source and campaign to more info section (#34946)

(cherry picked from commit a02705ded7)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-21 14:22:42 +05:30
ruthra kumar
e5048812fd Merge pull request #34943 from frappe/mergify/bp/version-14-hotfix/pr-34922
refactor: refactor set_missing_values and set_missing_ref_details in Payment Entry (backport #34922)
2023-04-21 09:41:28 +05:30
rohitwaghchaure
237bd6e831 Merge pull request #34964 from frappe/mergify/bp/version-14-hotfix/pr-34960
fix: stock entry type issue (backport #34960)
2023-04-20 23:41:46 +05:30
rohitwaghchaure
c2953bc3e0 Merge pull request #34965 from frappe/mergify/bp/version-14-hotfix/pr-34958
fix: removed depends on for the Employee Detail section (backport #34958)
2023-04-20 23:41:06 +05:30
Rohit Waghchaure
9d17d3ff06 fix: removed depends on for the Employee Detail section
(cherry picked from commit a90a5b4aa4)
2023-04-20 12:34:34 +00:00
Rohit Waghchaure
33a16086ef fix: stock entry type issue
(cherry picked from commit c3b5dcb767)
2023-04-20 12:34:11 +00:00
Sagar Vora
6e0d22c23b Merge pull request #34962 from frappe/mergify/bp/version-14-hotfix/pr-34738
fix: misc regional improvements (backport #34738)
2023-04-20 05:20:19 -07:00
Sagar Vora
2ec18eb4cf fix: use functools.wraps to preserve doc signature
(cherry picked from commit 776b56ccd1)
2023-04-20 12:18:21 +00:00
Sagar Vora
87595bdb7e fix: simplify erpnext.get_region
(cherry picked from commit 2fa641f86d)
2023-04-20 12:18:21 +00:00
Sagar Vora
789dfd6774 fix: set frappe.flags.company to call regional code accurately
(cherry picked from commit 17ef3c964f)
2023-04-20 12:18:20 +00:00
mergify[bot]
56ef0baa9d fix: batch qty conversion factor issue fixed in pos transaction (#34917)
fix: batch qty conversion factor issue fixed in pos transaction (#34917)

(cherry picked from commit 59f3fedbf7)

Co-authored-by: Vishal Dhayagude <vishdha@users.noreply.github.com>
Co-authored-by: Sagar Sharma <sagarsharma.s312@gmail.com>
2023-04-20 17:23:23 +05:30
Sagar Sharma
11e4fcb058 Merge pull request #34956 from frappe/mergify/bp/version-14-hotfix/pr-34953
fix: `PermissionError` in Work Order (backport #34953)
2023-04-20 16:01:47 +05:30
s-aga-r
a3568c1b27 fix: PermissionError in Work Order
(cherry picked from commit 8108b2de0a)
2023-04-20 10:28:04 +00:00
rohitwaghchaure
2a48a7b427 Merge pull request #34955 from frappe/mergify/bp/version-14-hotfix/pr-34954
fix: process_loss_percentage in BOM (backport #34954)
2023-04-20 15:02:05 +05:30
Nihantra Patel
4418862965 fix: process_loss_percentage in BOM
(cherry picked from commit b572bef71d)
2023-04-20 09:31:46 +00:00
rohitwaghchaure
e5aae90078 Merge pull request #34944 from frappe/mergify/bp/version-14-hotfix/pr-34912
fix: internal Purchase Receipt GL Entries (backport #34912)
2023-04-20 14:36:56 +05:30
Sagar Sharma
e2818afb62 Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-34912 2023-04-20 14:05:48 +05:30
s-aga-r
7740ceb27e fix(test): test_internal_pr_gl_entries 2023-04-20 14:05:08 +05:30
ruthra kumar
3d3da75726 refactor: update ref details for selected references
set_missing_ref_details can update only for selected references

(cherry picked from commit b7d6e30f63)
2023-04-20 13:29:51 +05:30
ruthra kumar
8c5d644671 refactor: move set_missing_ref_detials out of set_missing_values
(cherry picked from commit 11cb2db3fe)
2023-04-20 13:29:47 +05:30
Frappe PR Bot
ca9b02fb53 chore(release): Bumped to Version 14.22.2
## [14.22.2](https://github.com/frappe/erpnext/compare/v14.22.1...v14.22.2) (2023-04-20)

### Bug Fixes

* filtering via batch no ([#34951](https://github.com/frappe/erpnext/issues/34951)) ([1b827e6](1b827e6b67)), closes [#34950](https://github.com/frappe/erpnext/issues/34950)
2023-04-20 07:24:45 +00:00
Deepesh Garg
74abe94711 Merge pull request #34952 from frappe/mergify/bp/version-14/pr-34951
fix: filtering via batch no (backport #34951)
2023-04-20 12:53:14 +05:30
mergify[bot]
1b827e6b67 fix: filtering via batch no (#34951)
fix: filtering via batch no(#34950)

* fix: filtering via batch no

(cherry picked from commit ea6eeace80)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
(cherry picked from commit 3b23fc1eba)
2023-04-20 07:21:04 +00:00
mergify[bot]
3b23fc1eba fix: filtering via batch no (#34951)
fix: filtering via batch no(#34950)

* fix: filtering via batch no

(cherry picked from commit ea6eeace80)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-20 12:50:40 +05:30
Sagar Sharma
1743413e00 Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-34912 2023-04-20 12:19:43 +05:30
Sagar Sharma
c11b98fa9f Merge pull request #34926 from frappe/mergify/bp/version-14-hotfix/pr-34895
fix: use `CombineDatetime` instead of `Timestamp` in QB queries (backport #34895)
2023-04-20 12:17:32 +05:30
Sagar Sharma
a2c25ed49e Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-34895 2023-04-20 12:17:12 +05:30
s-aga-r
2ad157bd77 fix(test): test_backdated_stock_reco_cancellation_future_negative_stock
(cherry picked from commit 11c8503180)
2023-04-20 06:06:05 +00:00
s-aga-r
7cc0129302 test: add test case for internal PR GL Entries
(cherry picked from commit c86c543fbf)
2023-04-20 06:06:05 +00:00
s-aga-r
f7e436fe71 fix: internal Purchase Receipt GL Entries
(cherry picked from commit 6fca9adcd4)
2023-04-20 06:06:05 +00:00
ruthra kumar
1ab83c5c02 Merge pull request #34916 from frappe/mergify/bp/version-14-hotfix/pr-34838
refactor: toggle merging similar ledger entries in JE (backport #34838)
2023-04-20 11:15:36 +05:30
Frappe PR Bot
6faf459f97 chore(release): Bumped to Version 14.22.1
## [14.22.1](https://github.com/frappe/erpnext/compare/v14.22.0...v14.22.1) (2023-04-20)

### Bug Fixes

* add limit for get_next_stock_reco ([#34937](https://github.com/frappe/erpnext/issues/34937)) ([78ad0ea](78ad0eaa74))
2023-04-20 05:12:57 +00:00
Deepesh Garg
40058c2617 Merge pull request #34939 from frappe/mergify/bp/version-14/pr-34938
fix: add limit for get_next_stock_reco (#34937)
2023-04-20 10:41:31 +05:30
mergify[bot]
78ad0eaa74 fix: add limit for get_next_stock_reco (#34937)
fix: limit stock reco issue

(cherry picked from commit fcfa8842a7)

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
(cherry picked from commit 7131ff28fd)
2023-04-20 05:08:45 +00:00
mergify[bot]
7131ff28fd fix: add limit for get_next_stock_reco (#34937)
fix: limit stock reco issue

(cherry picked from commit fcfa8842a7)

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
2023-04-20 10:37:58 +05:30
Sagar Sharma
33d89b4a8b Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-34895 2023-04-20 10:05:58 +05:30
rohitwaghchaure
fef381e8eb Merge pull request #34930 from frappe/mergify/bp/version-14-hotfix/pr-34929
fix: Incorrect difference value in Stock and Account Value Comparison… (backport #34929)
2023-04-19 23:58:34 +05:30
Sagar Sharma
9e148b4277 Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-34895 2023-04-19 21:21:52 +05:30
Rohit Waghchaure
e7ca833929 fix: Incorrect difference value in Stock and Account Value Comparison report
(cherry picked from commit a77182645f)
2023-04-19 15:38:16 +00:00
Sagar Sharma
322102e56b Merge pull request #34927 from frappe/mergify/bp/version-14-hotfix/pr-34901
fix: add item-code filter for SCR supplied-items batch-no (backport #34901)
2023-04-19 19:26:39 +05:30
s-aga-r
7c4f83ed60 fix: add item-code filter for SCR supplied-items batch-no
(cherry picked from commit e91abbfbe3)
2023-04-19 13:54:00 +00:00
s-aga-r
55da91cb34 fix: use CombineDatetime instead of Timestamp in QB queries
(cherry picked from commit 91a398a191)
2023-04-19 13:50:30 +00:00
ruthra kumar
9f090d2861 chore(patch): by default ledger entries of JE's will not be merged
(cherry picked from commit 3f537d30bd)
2023-04-19 09:59:36 +05:30
ruthra kumar
93bc1c5382 refactor: checkbox to toggle merging of JE account heads
(cherry picked from commit a3e3fe149d)
2023-04-19 04:19:31 +00:00
Frappe PR Bot
b12bd5f558 chore(release): Bumped to Version 14.22.0
# [14.22.0](https://github.com/frappe/erpnext/compare/v14.21.0...v14.22.0) (2023-04-19)

### Bug Fixes

* Add offers info to website item ([#34873](https://github.com/frappe/erpnext/issues/34873)) ([f1a1fc6](f1a1fc6c5b))
* Advance payment against payment terms ([#34872](https://github.com/frappe/erpnext/issues/34872)) ([7461239](7461239218))
* change discuss forum url ([#34891](https://github.com/frappe/erpnext/issues/34891)) ([8f26d62](8f26d62b35))
* don't show disabled warehouses in the Warehouse Wise Stock Balance report ([461780d](461780da22))
* Don't use stale item details ([#34847](https://github.com/frappe/erpnext/issues/34847)) ([c11aeba](c11aebaaae))
* for Tree Type item and item group show net amount ([#31776](https://github.com/frappe/erpnext/issues/31776)) ([7c8194a](7c8194a1a8))
* linters issues ([c53dc06](c53dc06f80))
* Remove unnecessary checkbox from Accounts doctype ([#34821](https://github.com/frappe/erpnext/issues/34821)) ([0cf6144](0cf6144b3f))
* selling workspace is not migrating properly ([79fd38c](79fd38cf3f))
* stock reco test case ([2f356dc](2f356dcc6c))
* too many writes error while making backdated stock reconciliation ([a981b79](a981b79865))
* unable to change `company` for manual `Serial No` entry ([2e7043c](2e7043ca90))
* **ux:** don't throw error when company defaults aren't set ([#34825](https://github.com/frappe/erpnext/issues/34825)) ([15f5e8d](15f5e8d4ff))
* whitelist doc method ([09b92fd](09b92fd78c))

### Features

* add german sales tax template ([#34823](https://github.com/frappe/erpnext/issues/34823)) ([3738ea5](3738ea5794))
2023-04-19 01:36:11 +00:00
Deepesh Garg
be8a22d33b Merge pull request #34905 from frappe/version-14-hotfix
chore: release v14
2023-04-19 07:04:25 +05:30
Sagar Sharma
757c168a8d Merge pull request #34903 from frappe/mergify/bp/version-14-hotfix/pr-34860
fix: add items field label (backport #34860)
2023-04-18 14:22:47 +05:30
s-aga-r
b0b00dc869 chore: add items field label
(cherry picked from commit c9418aab45)
2023-04-18 07:35:01 +00:00
Ankush Menat
09b92fd78c fix: whitelist doc method
This should've been whitelisted, looks like it was missed out

closes https://github.com/frappe/erpnext/issues/34898

(cherry picked from commit e4f152a416)
2023-04-18 08:25:26 +05:30
mergify[bot]
f1a1fc6c5b fix: Add offers info to website item (#34873)
fix: Add offers info to website item (#34873)

* fix: Add offers info to website item

* Revert "fix: Add offers info to website item"

This reverts commit 88b598edb6.

* fix: Add offer properties to website item

(cherry picked from commit 534ea5ad21)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-18 07:43:17 +05:30
mergify[bot]
8f26d62b35 fix: change discuss forum url (#34891)
fix: change discuss forum url (#34891)

[skip ci]

(cherry picked from commit dd93ea067e)

Co-authored-by: MohsinAli <mmatiyailol@gmail.com>
2023-04-18 07:42:45 +05:30
rohitwaghchaure
8e9d72bd2e Merge pull request #34887 from frappe/mergify/bp/version-14-hotfix/pr-34886
fix: stock reconciliation test case (backport #34886)
2023-04-17 16:02:15 +05:30
mergify[bot]
7461239218 fix: Advance payment against payment terms (#34872)
* fix: Advance payment against payment terms (#34872)

(cherry picked from commit 5c75894065)

# Conflicts:
#	erpnext/accounts/doctype/payment_entry/payment_entry.py

* chore: resolve conflicts

---------

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-17 15:54:54 +05:30
Rohit Waghchaure
2f356dcc6c fix: stock reco test case
(cherry picked from commit 6bccd8644e)
2023-04-17 09:52:59 +00:00
rohitwaghchaure
4640febc83 Merge pull request #34884 from frappe/mergify/bp/version-14-hotfix/pr-34851
fix: too many writes error while making backdated stock reconciliation (backport #34851)
2023-04-17 13:48:25 +05:30
Rohit Waghchaure
c53dc06f80 fix: linters issues
(cherry picked from commit d9dd64b4d2)
2023-04-17 07:13:00 +00:00
Rohit Waghchaure
a981b79865 fix: too many writes error while making backdated stock reconciliation
(cherry picked from commit 7bfc8f1236)
2023-04-17 07:13:00 +00:00
rohitwaghchaure
050339c88e Merge pull request #34883 from frappe/mergify/bp/version-14-hotfix/pr-34882
fix: don't show disabled warehouses in the Warehouse Wise Stock Balance report (backport #34882)
2023-04-17 12:41:25 +05:30
Rohit Waghchaure
461780da22 fix: don't show disabled warehouses in the Warehouse Wise Stock Balance report
(cherry picked from commit 9ceb1f6bda)
2023-04-17 06:31:44 +00:00
Shariq Ansari
e8db543028 Merge pull request #34877 from frappe/mergify/bp/version-14-hotfix/pr-34876
fix: selling workspace is not migrating properly (backport #34876)
2023-04-16 14:30:23 +05:30
Shariq Ansari
79fd38cf3f fix: selling workspace is not migrating properly
(cherry picked from commit 5a4dd354c1)
2023-04-16 08:57:11 +00:00
Sagar Sharma
dfb1e105bd Merge pull request #34868 from frappe/mergify/bp/version-14-hotfix/pr-34858
fix: unable to change `company` for manual `Serial No` entry (backport #34858)
2023-04-15 12:45:29 +05:30
s-aga-r
2e7043ca90 fix: unable to change company for manual Serial No entry
(cherry picked from commit fb3271c624)
2023-04-15 06:41:00 +00:00
mergify[bot]
7c8194a1a8 fix: for Tree Type item and item group show net amount (#31776)
fix: for Tree Type item and item group show net amout

(cherry picked from commit 91762097a5)

Co-authored-by: hrzzz <paulo_fabris@hotmail.com>
2023-04-14 16:42:37 +05:30
mergify[bot]
15f5e8d4ff fix(ux): don't throw error when company defaults aren't set (#34825)
fix(ux): don't throw error when company defaults aren't set (#34825)

* fix(ux): don't throw error when company defaults aren't set; instead prompt account input.

* fix: translate label and title

(cherry picked from commit 51c4338661)

Co-authored-by: Devin Slauenwhite <devin.slauenwhite@gmail.com>
2023-04-14 16:42:12 +05:30
mergify[bot]
3738ea5794 feat: add german sales tax template (#34823)
feat: add german sales tax template (#34823)

Nullsteuersatz nach § 12 Abs. 3 UStG

(cherry picked from commit 59f6b773cd)

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2023-04-14 14:52:02 +05:30
mergify[bot]
c11aebaaae fix: Don't use stale item details (#34847)
fix: Don't use stale item details (#34847)

(cherry picked from commit a7051cb9b5)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-14 11:26:33 +05:30
mergify[bot]
0cf6144b3f fix: Remove unnecessary checkbox from Accounts doctype (#34821)
fix: Remove unnecessary checkbox from Accounts doctype (#34821)

(cherry picked from commit 66130493eb)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-14 11:26:14 +05:30
mergify[bot]
41a7d3fd60 chore: update CODEOWNERS (#34817)
* chore: update CODEOWNERS

[skip ci]

(cherry picked from commit aa8b241d5a)

# Conflicts:
#	CODEOWNERS

* fix: conflicts

---------

Co-authored-by: Saqib Ansari <nextchamp.saqib@gmail.com>
2023-04-12 07:39:07 +05:30
Frappe PR Bot
2b0b24f7c3 chore(release): Bumped to Version 14.21.0
# [14.21.0](https://github.com/frappe/erpnext/compare/v14.20.3...v14.21.0) (2023-04-11)

### Bug Fixes

* `payment entry is already created` on posawesome. (backport [#34712](https://github.com/frappe/erpnext/issues/34712)) ([#34752](https://github.com/frappe/erpnext/issues/34752)) ([8ba1e0f](8ba1e0f31e))
* add german translation of "Partly Paid" ([#34776](https://github.com/frappe/erpnext/issues/34776)) ([3023dbb](3023dbbe95))
* Allocate tax loss to tax account head on early payment discount ([#34287](https://github.com/frappe/erpnext/issues/34287)) ([be2990e](be2990ec88))
* asset monthly WDV and DD schedule [v14] ([#34644](https://github.com/frappe/erpnext/issues/34644)) ([88c8c36](88c8c36805))
* Bank clearance for case loan (disburstment/repayment) ([#34586](https://github.com/frappe/erpnext/issues/34586)) ([f1687cf](f1687cfb14))
* BOM Update Cost, when no actual qty ([8757435](8757435898))
* bom update log not working for large batch size ([551190a](551190af30))
* Column value mismatch in COA blank template ([#34658](https://github.com/frappe/erpnext/issues/34658)) ([5e03a4e](5e03a4e9e2))
* consider qty field precision ([2c54e76](2c54e763e4))
* customer selection not mandatory in purchase invoice to fetch item details ([#34810](https://github.com/frappe/erpnext/issues/34810)) ([994272b](994272b966))
* don't include cancelled JVs in assdeprledger report ([3896d41](3896d41e95))
* enclose ternary operator in parentheses ([b835760](b835760b0b))
* incorrect arg name in asset value adjustment ([8d9305e](8d9305ee5f))
* incorrect balance qty in the stock ledger report ([3494c9c](3494c9ccb6))
* incorrect stock balance quantity for batch item ([d817c50](d817c50581))
* Item tax validity comparison fixes ([#34784](https://github.com/frappe/erpnext/issues/34784)) ([cc21241](cc21241887))
* lost opportunity report issue ([#34626](https://github.com/frappe/erpnext/issues/34626)) ([3e67994](3e67994cc7))
* Multiple issues in purchase invoice submission ([#34600](https://github.com/frappe/erpnext/issues/34600)) ([5677f25](5677f25215))
* plaid log_error syntax issue (backport [#34642](https://github.com/frappe/erpnext/issues/34642)) ([#34667](https://github.com/frappe/erpnext/issues/34667)) ([61858a6](61858a60c2))
* posting time issue ([bb5eeb6](bb5eeb6bd6))
* provide filter by depreciable assets in fixed asset register ([#34803](https://github.com/frappe/erpnext/issues/34803)) ([fee4cd5](fee4cd5f40))
* reposting record not created for backdated stock reco ([9b90323](9b90323d53))
* serial no with zero quantity issue in stock reco ([f47be46](f47be46717))
* Shop by category fixes (backport [#34688](https://github.com/frappe/erpnext/issues/34688)) ([#34750](https://github.com/frappe/erpnext/issues/34750)) ([3ad5d67](3ad5d676ab))
* Subcontracting Receipt incorrect `status` ([99226d3](99226d3811))
* Supplier RFQ email link ([#34338](https://github.com/frappe/erpnext/issues/34338)) ([a00459a](a00459aec3))
* Total debit and credit while importing via Data Import ([#34659](https://github.com/frappe/erpnext/issues/34659)) ([5e28d02](5e28d0234e))
* **ui:** recalculate difference amount on allocation change ([#34694](https://github.com/frappe/erpnext/issues/34694)) ([6b866e2](6b866e24f6))
* Unable to create payment request against purchase invoice ([#34762](https://github.com/frappe/erpnext/issues/34762)) ([a1f7e35](a1f7e35914))
* use stock qty to calculate POS reserved stock ([c0f7f7d](c0f7f7da42))
* UX for stock entry, bom and work order ([d4a6035](d4a6035c83))

### Features

* add `Received Qty` field in `Delivery Note Item` ([1c5e36c](1c5e36c7b6))
* Auto allocate advance payments only against orders ([#34727](https://github.com/frappe/erpnext/issues/34727)) ([05d24e3](05d24e3665))

### Reverts

* remove frappe.send_message (v14) ([#34816](https://github.com/frappe/erpnext/issues/34816)) ([8a331e0](8a331e0f26))
2023-04-11 11:40:59 +00:00
Deepesh Garg
f72fc73913 Merge pull request #34813 from frappe/version-14-hotfix
chore: release v14
2023-04-11 17:09:31 +05:30
Ritwik Puri
8a331e0f26 revert: remove frappe.send_message (v14) (#34816)
revert: remove frappe.send_message
2023-04-11 16:10:32 +05:30
Deepesh Garg
da913d49a7 Merge branch 'version-14' into version-14-hotfix 2023-04-11 15:56:58 +05:30
rohitwaghchaure
21aea52c32 Merge pull request #34814 from frappe/mergify/bp/version-14-hotfix/pr-34808
fix: reposting record not created for backdated stock reconciliation  (backport #34808)
2023-04-11 15:36:32 +05:30
Rohit Waghchaure
9b90323d53 fix: reposting record not created for backdated stock reco
(cherry picked from commit 6851b5ba97)
2023-04-11 09:33:26 +00:00
Deepesh Garg
994272b966 fix: customer selection not mandatory in purchase invoice to fetch item details (#34810) 2023-04-11 14:17:27 +05:30
mergify[bot]
fee4cd5f40 fix: provide filter by depreciable assets in fixed asset register (#34803)
fix: provide filter by depreciable assets in fixed asset register (#34803)

(cherry picked from commit c957a5cd2e)

Co-authored-by: Anand Baburajan <anandbaburajan@gmail.com>
2023-04-11 13:50:04 +05:30
mergify[bot]
3023dbbe95 fix: add german translation of "Partly Paid" (#34776)
fix: add german translation of "Partly Paid" (#34776)

(cherry picked from commit 934e1b4e6a)

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2023-04-09 20:13:36 +05:30
mergify[bot]
cc21241887 fix: Item tax validity comparison fixes (#34784)
fix: Item tax validity comparison fixes (#34784)

fix: Item tax validity comparsion fixes
(cherry picked from commit 6f6928fa7b)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-09 18:55:11 +05:30
Sagar Sharma
66fdd1c13f Merge pull request #34786 from frappe/mergify/bp/version-14-hotfix/pr-34632
refactor: rewrite `batch.py` queries in `QB` (backport #34632)
2023-04-08 22:10:22 +05:30
s-aga-r
5723a200c5 chore: conflicts 2023-04-08 19:10:39 +05:30
s-aga-r
35c9493336 refactor: rewrite batch.py queries in QB
(cherry picked from commit 517b5f8567)

# Conflicts:
#	erpnext/stock/doctype/batch/batch.py
2023-04-08 07:41:49 +00:00
Anand Baburajan
b235b95bed Merge pull request #34779 from frappe/mergify/bp/version-14-hotfix/pr-34735
'Make Asset Movement' button translation fix in asset_list.js (backport #34735)
2023-04-07 15:34:20 +05:30
Hossein Yousefian
50abbded34 'Make Asset Movement' button translation fix
(cherry picked from commit b70615ef18)
2023-04-07 10:01:19 +00:00
Sagar Sharma
31b479d71f Merge pull request #34772 from frappe/mergify/bp/version-14-hotfix/pr-34760
fix: validate `Received Qty` for Internal Purchase Receipt (backport #34760)
2023-04-06 17:20:46 +05:30
s-aga-r
769736ffea test: add test cases for internal PR received qty
(cherry picked from commit a575bd50ef)
2023-04-06 10:56:11 +00:00
s-aga-r
b79ddbbf60 chore: add Delivery Note Item in Purchase Receipt Status Updater
(cherry picked from commit 0d1df26b88)
2023-04-06 10:56:11 +00:00
s-aga-r
1c5e36c7b6 feat: add Received Qty field in Delivery Note Item
(cherry picked from commit bc39dfab5d)
2023-04-06 10:56:11 +00:00
Sagar Sharma
eaf577f078 Merge pull request #34770 from frappe/mergify/bp/version-14-hotfix/pr-34769
fix: Subcontracting Receipt incorrect `status` (backport #34769)
2023-04-06 14:53:34 +05:30
rohitwaghchaure
e02ad91c39 Merge pull request #34771 from frappe/mergify/bp/version-14-hotfix/pr-34768
fix: UX for stock entry, bom and work order (backport #34768)
2023-04-06 14:44:45 +05:30
Rohit Waghchaure
d4a6035c83 fix: UX for stock entry, bom and work order
(cherry picked from commit 82a136f991)
2023-04-06 08:47:08 +00:00
s-aga-r
99226d3811 fix: Subcontracting Receipt incorrect status
(cherry picked from commit a55b818119)
2023-04-06 08:27:32 +00:00
Frappe PR Bot
2a8c9f8e69 chore(release): Bumped to Version 14.20.3
## [14.20.3](https://github.com/frappe/erpnext/compare/v14.20.2...v14.20.3) (2023-04-06)

### Bug Fixes

* Unable to create payment request against purchase invoice ([#34762](https://github.com/frappe/erpnext/issues/34762)) ([f4473b3](f4473b36a5))
2023-04-06 07:54:09 +00:00
mergify[bot]
f4473b36a5 fix: Unable to create payment request against purchase invoice (#34762)
fix: Unable to create payment request against purchase invoice (#34762)

fix: Unable to create payment request against purchase invoice (#34762)

(cherry picked from commit 91a26608ee)

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

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-04-06 13:22:09 +05:30
mergify[bot]
a1f7e35914 fix: Unable to create payment request against purchase invoice (#34762)
fix: Unable to create payment request against purchase invoice (#34762)

(cherry picked from commit 91a26608ee)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-06 12:49:15 +05:30
Frappe PR Bot
b6ae9a4a72 chore(release): Bumped to Version 14.20.2
## [14.20.2](https://github.com/frappe/erpnext/compare/v14.20.1...v14.20.2) (2023-04-05)

### Bug Fixes

* incorrect stock balance quantity for batch item ([c7cee86](c7cee86685))
2023-04-05 18:57:55 +00:00
rohitwaghchaure
313e1a5e04 Merge pull request #34759 from frappe/mergify/bp/version-14/pr-34758
fix: incorrect stock balance quantity for batch item (backport #34743) (backport #34758)
2023-04-06 00:26:07 +05:30
Rohit Waghchaure
c7cee86685 fix: incorrect stock balance quantity for batch item
(cherry picked from commit ef4bd77196)
(cherry picked from commit d817c50581)
2023-04-05 18:18:47 +00:00
rohitwaghchaure
915c4819b6 Merge pull request #34758 from frappe/mergify/bp/version-14-hotfix/pr-34743
fix: incorrect stock balance quantity for batch item (backport #34743)
2023-04-05 23:47:17 +05:30
Rohit Waghchaure
d817c50581 fix: incorrect stock balance quantity for batch item
(cherry picked from commit ef4bd77196)
2023-04-05 17:52:45 +00:00
Frappe PR Bot
33ee958cfb chore: release v14 (#34733) 2023-04-05 17:41:20 +05:30
mergify[bot]
8ba1e0f31e fix: payment entry is already created on posawesome. (backport #34712) (#34752) 2023-04-05 13:55:13 +05:30
mergify[bot]
3ad5d676ab fix: Shop by category fixes (backport #34688) (#34750)
fix: Shop by category fixes (#34688)

* fix: Shop by category fixes

* chore: Update tests

(cherry picked from commit 56f5078357)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-05 13:09:34 +05:30
mergify[bot]
05d24e3665 feat: Auto allocate advance payments only against orders (#34727)
* feat: Auto allocate advance payments only against orders (#34727)

feat: Auto allocate advance payments only againt orders
(cherry picked from commit fd3fb64aa3)

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

* chore: Resolve conflicts

---------

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-05 13:00:40 +05:30
mergify[bot]
3c0cc024aa fix!: require sender and message for contact us page (#34707)
fix!: require sender and message for contact us page (#34707)

* fix: require sender and message for contact us page

* refactor: dont override frappe.send_message from client side

used override_whitelisted_method hook for the same

(cherry picked from commit f193393f57)

Co-authored-by: Ritwik Puri <ritwikpuri5678@gmail.com>
2023-04-05 12:33:55 +05:30
Anand Baburajan
88c8c36805 fix: asset monthly WDV and DD schedule [v14] (#34644)
* fix: monthly wdv and dd schedule

* chore: handle case without pro rata

* chore: fix DD rate and prev depr amount in case of disposal

* chore: minor fix for schedules with just 2 rows

* chore: minor bug

* refactor: get_depreciation_amount

* refactor: another one for get_depreciation_amount
2023-04-05 11:45:45 +05:30
Anand Baburajan
7c4a9b56ff Merge pull request #34737 from AnandBaburajan/asdeprledger_cancelled_deprs
fix: don't include cancelled JVs in assdeprledger report
2023-04-05 11:33:53 +05:30
Anand Baburajan
16e554dd7b Merge branch 'version-14-hotfix' into asdeprledger_cancelled_deprs 2023-04-04 17:51:21 +05:30
anandbaburajan
3896d41e95 fix: don't include cancelled JVs in assdeprledger report 2023-04-04 17:49:16 +05:30
Sagar Sharma
12625d87b0 Merge pull request #34717 from frappe/mergify/bp/version-14-hotfix/pr-34713
fix: consider qty field precision (backport #34713)
2023-04-04 08:45:12 +05:30
Frappe PR Bot
dfadfdc32c chore(release): Bumped to Version 14.20.1
## [14.20.1](https://github.com/frappe/erpnext/compare/v14.20.0...v14.20.1) (2023-04-03)

### Bug Fixes

* bom update log not working for large batch size ([da35436](da354362be))
2023-04-03 17:50:43 +00:00
rohitwaghchaure
e4def081f5 Merge pull request #34724 from frappe/mergify/bp/version-14/pr-34719
fix: bom update log not working for large batch size (backport #34715) (backport #34719)
2023-04-03 23:19:00 +05:30
Sagar Sharma
cbb8dd6aa6 Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-34713 2023-04-03 22:23:20 +05:30
Rohit Waghchaure
da354362be fix: bom update log not working for large batch size
(cherry picked from commit d56070301c)
(cherry picked from commit 551190af30)
2023-04-03 16:06:57 +00:00
rohitwaghchaure
9372d46c08 Merge pull request #34711 from vishdha/reserved_pos_qty
fix: use stock qty to calculate POS reserved stock
2023-04-03 21:14:36 +05:30
rohitwaghchaure
dff61ab759 Merge pull request #34719 from frappe/mergify/bp/version-14-hotfix/pr-34715
fix: bom update log not working for large batch size (backport #34715)
2023-04-03 16:55:27 +05:30
Rohit Waghchaure
551190af30 fix: bom update log not working for large batch size
(cherry picked from commit d56070301c)
2023-04-03 10:20:09 +00:00
s-aga-r
2c54e763e4 fix: consider qty field precision
(cherry picked from commit 6ec7590c21)
2023-04-03 10:07:42 +00:00
mergify[bot]
6b866e24f6 fix(ui): recalculate difference amount on allocation change (#34694)
fix: recalculate difference amount on allocation change

(cherry picked from commit 32a4ca6b6c)

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
2023-04-03 14:55:32 +05:30
mergify[bot]
be2990ec88 fix: Allocate tax loss to tax account head on early payment discount (#34287)
* fix: Taxes aren't discounted on early payment discount

- Deductions in payment entry must be split into income loss and tax loss
- Compute total discount in percentage, makes discounting different amounts proportionately easier

(cherry picked from commit 768c3a4927)

* fix: Recalculate difference amount after setting deductions

(cherry picked from commit 75ec0a0a85)

* fix: Set deductions in base currency

- Use field precision to get more accurate values

(cherry picked from commit dc2998f544)

* fix: Back update discounted amount in Invoice based on discount type

- Discount value was always trated as a percentage on back updation

(cherry picked from commit 2ae5834290)

* test: PE from SI with early payment discount amount & PE assertions in discount % test

(cherry picked from commit c217bb2018)

* fix: Set deduction amount in company currency on Doctype

- Even via JS, deductions amount is always in company currency
- Since there is nothing dynamic about this field, set it in the doctype spec itself
- fixed: Inconsistency between label currency and field currency formatted value

(cherry picked from commit 7f2e7badff)

* fix: Don't add to deductions if amount is 0

- misc: better docstring

(cherry picked from commit f02fc8acf0)

* fix: Paid amount must be discounted considering accounting currency

- Accounting is in the same currency if party currency and company currency is the same
- If accounting is in the same currency, paid and recvd amount is in the base currency
- Then, discount amount must also be in the base currency as it is deducted from paid amount
- Received amount must be in base currency if not multi currency
- cleanup: Deductions setting broken into smaller functions

(cherry picked from commit 761f68d7bf)

* fix: Multi-currency SI with base currency PE

- Return total discount loss in base currency
- Allocate payment based on terms: Set allocated amount in references table in base currency if accounting is in that currency
- Allocate payment based on terms: While back updating set paid amount (payment schedule) in transaction currency always
- minor: discount msgprint in correct currency

(cherry picked from commit b09c2381ca)

* test: Multi currency SI with multi-currency accounting and single currency accounting + Early payment discount

(cherry picked from commit 9abf0ef615)

* fix: Handle rounding more gracefully

- Round off pending discount loss to avoid miniscule losses rounded to 0.0 that are added in deductions
- Use base amounts to calculate base losses instead of using conversion factor which increases rounding error
- Round of total base loss instead of individual income and tax losses to reduce rounding error
- Use default round off account for pending rounding loss in deductions

(cherry picked from commit caa1a3dccf)

* fix: Provision to apply early payment discount if payment is recorded late

- Party could have paid on time but payment is recorded late
- Prompt for reference date so that discount is applied while mapping
- Prompt only if discount in payment schedule of valid doctypes
- test: Reference date and impact on PE
- `make_payment_entry` (JS) must be able to access `this`

(cherry picked from commit d6d0163514)

* feat: Make Tax loss booking optional

- Checkbox in Accounts Settings
- Apply checkbox in PE deductions setting logic
- Adjust tests

(cherry picked from commit 216a46bd66)

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

* fix: Merge conflicts

---------

Co-authored-by: marination <maricadsouza221197@gmail.com>
2023-04-03 13:00:22 +05:30
Vishal
c0f7f7da42 fix: use stock qty to calculate POS reserved stock 2023-04-03 12:46:57 +05:30
Sagar Sharma
b34c78c4e7 Merge pull request #34697 from frappe/mergify/bp/version-14-hotfix/pr-34656
fix: BOM Update Cost, when no actual qty (backport #34656)
2023-04-02 19:16:41 +05:30
Sagar Sharma
4ada090cb2 Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-34656 2023-04-02 14:59:38 +05:30
mergify[bot]
5677f25215 fix: Multiple issues in purchase invoice submission (#34600)
fix: Multiple issues in purchase invoice submission (#34600)

* fix: Multiple issues in purchase invoice submission

* fix: Base grand total calculation

* chore: Calculate base grand total separately only in multi currency docs

* fix: Add gl entry for round off

(cherry picked from commit 4c61ee30bb)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-02 12:56:58 +05:30
mergify[bot]
f1687cfb14 fix: Bank clearance for case loan (disburstment/repayment) (#34586)
fix: Bank clearance for case loan (disburstment/repayment) (#34586)

(cherry picked from commit 74b29eb5e2)

Co-authored-by: Kitti U. @ Ecosoft <kittiu@ecosoft.co.th>
2023-04-01 22:07:50 +05:30
mergify[bot]
a00459aec3 fix: Supplier RFQ email link (#34338)
fix: Supplier RFQ email link (#34338)

(cherry picked from commit fc86a8568f)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-04-01 22:07:28 +05:30
s-aga-r
8757435898 fix: BOM Update Cost, when no actual qty
(cherry picked from commit a4112c75c5)
2023-04-01 10:54:51 +00:00
ruthra kumar
dcf62dc548 Merge pull request #34686 from frappe/mergify/bp/version-14-hotfix/pr-34679
fix: enclose ternary operator in parenthesis (backport #34679)
2023-03-31 14:05:30 +05:30
ruthra kumar
b835760b0b fix: enclose ternary operator in parentheses
(cherry picked from commit 986daa6578)
2023-03-31 08:02:13 +00:00
Sagar Sharma
bd0c20f789 Merge pull request #34681 from frappe/mergify/bp/version-14-hotfix/pr-34677
chore: make `Production Plan Item Reference` table hidden in Production Plan (backport #34677)
2023-03-31 12:37:19 +05:30
s-aga-r
5ef98fcea1 chore: make Production Plan Item Reference table hidden in Production Plan
(cherry picked from commit 706be2a415)
2023-03-31 07:05:20 +00:00
Deepesh Garg
985b232251 Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-34627 2023-03-31 11:59:48 +05:30
mergify[bot]
5e28d0234e fix: Total debit and credit while importing via Data Import (#34659)
fix: Total debit and credit while importing via Data Import (#34659)

(cherry picked from commit 7c42b72ee7)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-03-31 11:58:45 +05:30
mergify[bot]
5e03a4e9e2 fix: Column value mismatch in COA blank template (#34658)
fix: Column value mismatch in COA blank template (#34658)

(cherry picked from commit 576575c227)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-03-31 11:58:16 +05:30
rohitwaghchaure
e98e64f925 Merge pull request #34669 from frappe/mergify/bp/version-14-hotfix/pr-34664
fix: incorrect balance qty in the stock ledger report (backport #34664)
2023-03-30 18:18:07 +05:30
rohitwaghchaure
9ce281d008 Merge pull request #34671 from frappe/mergify/bp/version-14-hotfix/pr-34636
fix: posting time issue (backport #34636)
2023-03-30 18:17:31 +05:30
Anand Baburajan
27a3f2ce55 Merge pull request #34665 from frappe/mergify/bp/version-14-hotfix/pr-34661
chore: improve asset depr posting failure msg (backport #34661)
2023-03-30 17:50:24 +05:30
mergify[bot]
61858a60c2 fix: plaid log_error syntax issue (backport #34642) (#34667)
fix: plaid log_error syntax issue (#34642)

(cherry picked from commit ddb17a8880)

Co-authored-by: Richard Case <110036763+casesolved-co-uk@users.noreply.github.com>
2023-03-30 17:28:37 +05:30
Rohit Waghchaure
bb5eeb6bd6 fix: posting time issue
(cherry picked from commit 345e6facbe)
2023-03-30 11:56:35 +00:00
Rohit Waghchaure
3494c9ccb6 fix: incorrect balance qty in the stock ledger report
(cherry picked from commit cbdaab940d)
2023-03-30 11:56:27 +00:00
Anand Baburajan
a0df23415b chore: improve asset depr posting failure msg (#34661)
* chore: improve asset depr posting error msg

* chore: add period

* chore: improve msg

(cherry picked from commit d999dea3e4)
2023-03-30 11:09:32 +00:00
mergify[bot]
8510c398a4 chore: auto fill asset name and available for use date (backport #34660) (#34662)
* chore: auto fill asset name and available for use date

(cherry picked from commit af3e807607)

# Conflicts:
#	erpnext/assets/doctype/asset/asset.json

* Update asset.json

---------

Co-authored-by: anandbaburajan <anandbaburajan@gmail.com>
2023-03-30 16:37:35 +05:30
rohitwaghchaure
bae476cc99 Merge pull request #34652 from frappe/mergify/bp/version-14-hotfix/pr-34648
fix: serial no with zero quantity issue in stock reco (backport #34648)
2023-03-30 13:39:58 +05:30
Anand Baburajan
4dfc660cc0 Merge pull request #34650 from frappe/mergify/bp/version-14-hotfix/pr-34649
fix: incorrect arg name in asset value adjustment (backport #34649)
2023-03-30 13:10:26 +05:30
Rohit Waghchaure
f47be46717 fix: serial no with zero quantity issue in stock reco
(cherry picked from commit 17131e5a02)
2023-03-30 07:35:38 +00:00
anandbaburajan
8d9305ee5f fix: incorrect arg name in asset value adjustment
(cherry picked from commit 2b0470d1f5)
2023-03-30 07:34:09 +00:00
Deepesh Garg
bc94358e98 chore: resolve conflicts 2023-03-30 12:15:56 +05:30
Komal-Saraf0609
5e98679f91 fix: enabling lead even after "Opportunity" created against it (#34627)
* fix: enabling lead even after "Opportunity" created against it

* chore: Linting Issues

---------

Co-authored-by: Komal Saraf <komal@frappe.io>
Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
(cherry picked from commit ad11934d39)

# Conflicts:
#	erpnext/patches.txt
#	erpnext/patches/v14_0/enable_all_leads.py
2023-03-30 02:34:48 +00:00
Anand Baburajan
6819f0106d Merge pull request #34640 from frappe/mergify/bp/version-14-hotfix/pr-34607
Asset maintenance task add dropdown "3 Yearly" (backport #34607)
2023-03-29 18:13:54 +05:30
Bevan Tony Medrano
e3de229b82 Asset maintenance task add dropdown "3 Yearly" (#34607)
* feat(asset_maintenance.json):Add 3 yearly in periodicity dropdown

* add server side implications for 3 yearly

(cherry picked from commit 625b8e8005)
2023-03-29 12:15:40 +00:00
mergify[bot]
3e67994cc7 fix: lost opportunity report issue (#34626)
fix: lost opportunity report issue (#34626)

* fix: lost opportunity report issue

* chore: Linting Issues

---------

Co-authored-by: Komal Saraf <komal@frappe.io>
Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
(cherry picked from commit d0660ad222)

Co-authored-by: Komal-Saraf0609 <81952590+Komal-Saraf0609@users.noreply.github.com>
2023-03-29 17:04:00 +05:30
Frappe PR Bot
a60c8f0e18 chore(release): Bumped to Version 14.20.0
# [14.20.0](https://github.com/frappe/erpnext/compare/v14.19.0...v14.20.0) (2023-03-28)

### Bug Fixes

* default pos conversion factor set to 1 ([#34437](https://github.com/frappe/erpnext/issues/34437)) ([18d813a](18d813a656))
* don't get zero value entries for exchange rate calculation ([#34475](https://github.com/frappe/erpnext/issues/34475)) ([ff24b3e](ff24b3e40c))
* incorrect `Opening Value` in `Stock Balance` report ([76b782a](76b782a03f))
* Note username overlapping with note content(CRM) ([096e5ef](096e5ef197))
* Party Name in SOA print when viewed from Customer/Supplier master ([#34597](https://github.com/frappe/erpnext/issues/34597)) ([835edbe](835edbe80e))
* Percentage billing in Sales Order ([#34606](https://github.com/frappe/erpnext/issues/34606)) ([477cb12](477cb12240))
* recalculate WDV rate after asset repair [v14] ([#34571](https://github.com/frappe/erpnext/issues/34571)) ([d2ca6f8](d2ca6f8d1f))
* remove unused translation ([#34519](https://github.com/frappe/erpnext/issues/34519)) ([881e92e](881e92e7b3))
* removing redundant validation ([fd6db41](fd6db41b6e))
* Sales person variance report without item group ([#34552](https://github.com/frappe/erpnext/issues/34552)) ([90ddc4a](90ddc4a1e2))
* Tax Category not able to set hence it calculating zero tax for item whoes tax template set ([#34525](https://github.com/frappe/erpnext/issues/34525)) ([a8567b0](a8567b09e6))
* Time button not working in the job card ([8fed33b](8fed33b03b))
* translations and UX in alternative item mapping ([#34433](https://github.com/frappe/erpnext/issues/34433)) ([702d07e](702d07ea7d))
* unset address and contact on trash (backport [#34495](https://github.com/frappe/erpnext/issues/34495)) ([#34560](https://github.com/frappe/erpnext/issues/34560)) ([db01bf5](db01bf5dec))
* zero rm-cost for batch rm item in SCR (backport [#34616](https://github.com/frappe/erpnext/issues/34616)) ([#34623](https://github.com/frappe/erpnext/issues/34623)) ([cff35d7](cff35d7286))

### Features

* deprecate get_customer_list ([#34563](https://github.com/frappe/erpnext/issues/34563)) ([67576ad](67576ad5bd))
2023-03-28 18:23:52 +00:00
Deepesh Garg
efdbb91a21 Merge pull request #34611 from frappe/version-14-hotfix
chore: release v14
2023-03-28 23:49:38 +05:30
mergify[bot]
cff35d7286 fix: zero rm-cost for batch rm item in SCR (backport #34616) (#34623)
fix: zero rm-cost for batch rm item in SCR (#34616)

fix: `0` rm-cost for batch rm item in SCR
(cherry picked from commit 867d898304)

Co-authored-by: Sagar Sharma <sagarsharma.s312@gmail.com>
2023-03-28 21:09:01 +05:30
rohitwaghchaure
c671f3ddc9 Merge pull request #34621 from frappe/mergify/bp/version-14-hotfix/pr-34461
fix: incorrect `Opening Value` in `Stock Balance` report (backport #34461)
2023-03-28 18:41:42 +05:30
s-aga-r
76b782a03f fix: incorrect Opening Value in Stock Balance report
(cherry picked from commit b04a101c11)
2023-03-28 12:11:54 +00:00
ruthra kumar
6f502bdc54 Merge pull request #34619 from frappe/mergify/bp/version-14-hotfix/pr-34608
chore: removing redundant validation (backport #34608)
2023-03-28 17:21:11 +05:30
mergify[bot]
a8567b09e6 fix: Tax Category not able to set hence it calculating zero tax for item whoes tax template set (#34525)
fix: Tax Category not able to set hence it calculating zero tax for item whoes tax template set (#34525)

* fix: Tax Category not able to set hence it calculating zero tax for item whoes tax template set

* fix: minor change added

(cherry picked from commit 7aafc90d58)

Co-authored-by: Vishal Dhayagude <vishdha@users.noreply.github.com>
2023-03-28 17:20:26 +05:30
ruthra kumar
fd6db41b6e fix: removing redundant validation
(cherry picked from commit d52f7e2820)
2023-03-28 16:59:42 +05:30
mergify[bot]
ff24b3e40c fix: don't get zero value entries for exchange rate calculation (#34475)
fix: don't get zero value entries for exchange rate calculation (#34475)

* fix: multiply None by float

* chore: remove debug

(cherry picked from commit 393bc25e2d)

Co-authored-by: Devin Slauenwhite <devin.slauenwhite@gmail.com>
2023-03-28 16:58:22 +05:30
mergify[bot]
477cb12240 fix: Percentage billing in Sales Order (#34606)
fix: Percentage billing in Sales Order (#34606)

(cherry picked from commit 12ad2aa2e5)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-03-28 16:52:53 +05:30
mergify[bot]
835edbe80e fix: Party Name in SOA print when viewed from Customer/Supplier master (#34597)
fix: Party Name in SOA print when viewed from Customer/Supplier master (#34597)

fix: Party Name in SOA print when viewd from Customer/Supplier master
(cherry picked from commit 50c1172f29)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-03-28 16:48:53 +05:30
mergify[bot]
18d813a656 fix: default pos conversion factor set to 1 (#34437)
* fix: default pos conversion factor set to 1 (#34437)

(cherry picked from commit 08fc686513)

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

* chore: Resolve conflicts

---------

Co-authored-by: Shram Kadia <65490105+Shram007@users.noreply.github.com>
Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-03-24 15:14:52 +05:30
mergify[bot]
67576ad5bd feat: deprecate get_customer_list (#34563)
feat: deprecate get_customer_list (#34563)

(cherry picked from commit 8c7fa5712b)

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2023-03-24 15:14:25 +05:30
ruthra kumar
37f2ba882e Merge pull request #34583 from frappe/mergify/bp/version-14-hotfix/pr-34577
refactor: additional filters and columns in Payment Ledger report (backport #34577)
2023-03-24 14:22:55 +05:30
ruthra kumar
57ecac4aa7 refactor: additional filters and columns in Payment Ledger report (#34577)
1. 'Party type' and 'Party' filters have been added
2. checkbox to include Amount in Acccount Currency
3. Grouping vouchers on Party
4. Replaced Company with Posting Date

(cherry picked from commit f7780cdb58)
2023-03-24 08:11:34 +00:00
rohitwaghchaure
070dea1bc5 Merge pull request #34574 from frappe/mergify/bp/version-14-hotfix/pr-34573
fix: Timer buttons not working in the job card (backport #34573)
2023-03-24 08:40:56 +05:30
Rohit Waghchaure
8fed33b03b fix: Time button not working in the job card
(cherry picked from commit 34c190b7d6)
2023-03-23 17:06:58 +00:00
mergify[bot]
90ddc4a1e2 fix: Sales person variance report without item group (#34552)
fix: Sales person variance report without item group (#34552)

fix: Sales person variance report witout item group
(cherry picked from commit 87108be11a)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-03-23 21:49:13 +05:30
Anand Baburajan
d2ca6f8d1f fix: recalculate WDV rate after asset repair [v14] (#34571)
fix: recalculate wdv rate after asset repair
2023-03-23 21:08:59 +05:30
mergify[bot]
db01bf5dec fix: unset address and contact on trash (backport #34495) (#34560)
fix: unset address and contact on trash (#34495)

* fix(Customer): unset address and contact on trash

* fix(Supplier): unset address and contact on trash

---------

Co-authored-by: Sagar Sharma <sagarsharma.s312@gmail.com>
(cherry picked from commit f7bf1b8a0c)

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2023-03-23 12:58:32 +05:30
mergify[bot]
881e92e7b3 fix: remove unused translation (#34519)
* fix: remove unused translation (#34519)

(cherry picked from commit 0df3a1a3af)

# Conflicts:
#	erpnext/translations/tr.csv

* chore: resolve conflicts

---------

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2023-03-23 00:06:14 +05:30
Shariq Ansari
d2e9527563 Merge pull request #34549 from frappe/mergify/bp/version-14-hotfix/pr-34547
fix: Note username overlapping with note content(CRM) (backport #34547)
2023-03-22 12:05:56 +05:30
Shariq Ansari
096e5ef197 fix: Note username overlapping with note content(CRM)
(cherry picked from commit 76cea7dd6a)
2023-03-22 06:32:46 +00:00
mergify[bot]
702d07ea7d fix: translations and UX in alternative item mapping (#34433)
fix: translations and UX in alternative item mapping (#34433)

* fix: disable deletion in alternative item mapping

* feat: german translations

* fix: make string translatable

---------

Co-authored-by: Anand Baburajan <anandbaburajan@gmail.com>
Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
(cherry picked from commit 79911734e9)

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2023-03-21 22:48:38 +05:30
370 changed files with 10093 additions and 4402 deletions

2
.github/stale.yml vendored
View File

@@ -13,7 +13,7 @@ exemptProjects: true
exemptMilestones: true
pulls:
daysUntilStale: 15
daysUntilStale: 14
daysUntilClose: 3
exemptLabels:
- hotfix

View File

@@ -3,13 +3,13 @@
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
erpnext/accounts/ @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
erpnext/accounts/ @deepeshgarg007 @ruthra-kumar
erpnext/assets/ @anandbaburajan @deepeshgarg007
erpnext/loan_management/ @nextchamp-saqib @deepeshgarg007
erpnext/regional @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
erpnext/selling @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
erpnext/support/ @nextchamp-saqib @deepeshgarg007
pos* @nextchamp-saqib
erpnext/loan_management/ @deepeshgarg007
erpnext/regional @deepeshgarg007 @ruthra-kumar
erpnext/selling @deepeshgarg007 @ruthra-kumar
erpnext/support/ @deepeshgarg007
pos*
erpnext/buying/ @rohitwaghchaure @s-aga-r
erpnext/maintenance/ @rohitwaghchaure @s-aga-r
@@ -18,12 +18,8 @@ erpnext/quality_management/ @rohitwaghchaure @s-aga-r
erpnext/stock/ @rohitwaghchaure @s-aga-r
erpnext/subcontracting @rohitwaghchaure @s-aga-r
erpnext/crm/ @NagariaHussain
erpnext/education/ @rutwikhdev
erpnext/projects/ @ruchamahabal
erpnext/controllers/ @deepeshgarg007 @rohitwaghchaure
erpnext/patches/ @deepeshgarg007
erpnext/controllers/ @deepeshgarg007 @nextchamp-saqib @rohitwaghchaure
erpnext/patches/ @deepeshgarg007 @nextchamp-saqib
.github/ @ankush
.github/ @deepeshgarg007
pyproject.toml @ankush

View File

@@ -1,8 +1,9 @@
import functools
import inspect
import frappe
__version__ = "14.19.0"
__version__ = "14.27.3"
def get_default_company(user=None):
@@ -120,12 +121,14 @@ def get_region(company=None):
You can also set global company flag in `frappe.flags.company`
"""
if company or frappe.flags.company:
return frappe.get_cached_value("Company", company or frappe.flags.company, "country")
elif frappe.flags.country:
return frappe.flags.country
else:
return frappe.get_system_settings("country")
if not company:
company = frappe.local.flags.company
if company:
return frappe.get_cached_value("Company", company, "country")
return frappe.flags.country or frappe.get_system_settings("country")
def allow_regional(fn):
@@ -136,6 +139,7 @@ def allow_regional(fn):
def myfunction():
pass"""
@functools.wraps(fn)
def caller(*args, **kwargs):
overrides = frappe.get_hooks("regional_overrides", {}).get(get_region())
function_path = f"{inspect.getmodule(fn).__name__}.{fn.__name__}"

View File

@@ -18,7 +18,6 @@
"root_type",
"report_type",
"account_currency",
"inter_company_account",
"column_break1",
"parent_account",
"account_type",
@@ -34,15 +33,11 @@
{
"fieldname": "properties",
"fieldtype": "Section Break",
"oldfieldtype": "Section Break",
"show_days": 1,
"show_seconds": 1
"oldfieldtype": "Section Break"
},
{
"fieldname": "column_break0",
"fieldtype": "Column Break",
"show_days": 1,
"show_seconds": 1,
"width": "50%"
},
{
@@ -53,9 +48,7 @@
"no_copy": 1,
"oldfieldname": "account_name",
"oldfieldtype": "Data",
"reqd": 1,
"show_days": 1,
"show_seconds": 1
"reqd": 1
},
{
"fieldname": "account_number",
@@ -63,17 +56,13 @@
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Account Number",
"read_only": 1,
"show_days": 1,
"show_seconds": 1
"read_only": 1
},
{
"default": "0",
"fieldname": "is_group",
"fieldtype": "Check",
"label": "Is Group",
"show_days": 1,
"show_seconds": 1
"label": "Is Group"
},
{
"fieldname": "company",
@@ -85,9 +74,7 @@
"options": "Company",
"read_only": 1,
"remember_last_selected_value": 1,
"reqd": 1,
"show_days": 1,
"show_seconds": 1
"reqd": 1
},
{
"fieldname": "root_type",
@@ -95,9 +82,7 @@
"in_standard_filter": 1,
"label": "Root Type",
"options": "\nAsset\nLiability\nIncome\nExpense\nEquity",
"read_only": 1,
"show_days": 1,
"show_seconds": 1
"read_only": 1
},
{
"fieldname": "report_type",
@@ -105,32 +90,18 @@
"in_standard_filter": 1,
"label": "Report Type",
"options": "\nBalance Sheet\nProfit and Loss",
"read_only": 1,
"show_days": 1,
"show_seconds": 1
"read_only": 1
},
{
"depends_on": "eval:doc.is_group==0",
"fieldname": "account_currency",
"fieldtype": "Link",
"label": "Currency",
"options": "Currency",
"show_days": 1,
"show_seconds": 1
},
{
"default": "0",
"fieldname": "inter_company_account",
"fieldtype": "Check",
"label": "Inter Company Account",
"show_days": 1,
"show_seconds": 1
"options": "Currency"
},
{
"fieldname": "column_break1",
"fieldtype": "Column Break",
"show_days": 1,
"show_seconds": 1,
"width": "50%"
},
{
@@ -142,9 +113,7 @@
"oldfieldtype": "Link",
"options": "Account",
"reqd": 1,
"search_index": 1,
"show_days": 1,
"show_seconds": 1
"search_index": 1
},
{
"description": "Setting Account Type helps in selecting this Account in transactions.",
@@ -154,9 +123,7 @@
"label": "Account Type",
"oldfieldname": "account_type",
"oldfieldtype": "Select",
"options": "\nAccumulated Depreciation\nAsset Received But Not Billed\nBank\nCash\nChargeable\nCapital Work in Progress\nCost of Goods Sold\nDepreciation\nEquity\nExpense Account\nExpenses Included In Asset Valuation\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nPayable\nReceivable\nRound Off\nStock\nStock Adjustment\nStock Received But Not Billed\nService Received But Not Billed\nTax\nTemporary",
"show_days": 1,
"show_seconds": 1
"options": "\nAccumulated Depreciation\nAsset Received But Not Billed\nBank\nCash\nChargeable\nCapital Work in Progress\nCost of Goods Sold\nDepreciation\nEquity\nExpense Account\nExpenses Included In Asset Valuation\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nPayable\nReceivable\nRound Off\nStock\nStock Adjustment\nStock Received But Not Billed\nService Received But Not Billed\nTax\nTemporary"
},
{
"description": "Rate at which this tax is applied",
@@ -164,9 +131,7 @@
"fieldtype": "Float",
"label": "Rate",
"oldfieldname": "tax_rate",
"oldfieldtype": "Currency",
"show_days": 1,
"show_seconds": 1
"oldfieldtype": "Currency"
},
{
"description": "If the account is frozen, entries are allowed to restricted users.",
@@ -175,17 +140,13 @@
"label": "Frozen",
"oldfieldname": "freeze_account",
"oldfieldtype": "Select",
"options": "No\nYes",
"show_days": 1,
"show_seconds": 1
"options": "No\nYes"
},
{
"fieldname": "balance_must_be",
"fieldtype": "Select",
"label": "Balance must be",
"options": "\nDebit\nCredit",
"show_days": 1,
"show_seconds": 1
"options": "\nDebit\nCredit"
},
{
"fieldname": "lft",
@@ -194,9 +155,7 @@
"label": "Lft",
"print_hide": 1,
"read_only": 1,
"search_index": 1,
"show_days": 1,
"show_seconds": 1
"search_index": 1
},
{
"fieldname": "rgt",
@@ -205,9 +164,7 @@
"label": "Rgt",
"print_hide": 1,
"read_only": 1,
"search_index": 1,
"show_days": 1,
"show_seconds": 1
"search_index": 1
},
{
"fieldname": "old_parent",
@@ -215,33 +172,27 @@
"hidden": 1,
"label": "Old Parent",
"print_hide": 1,
"read_only": 1,
"show_days": 1,
"show_seconds": 1
"read_only": 1
},
{
"default": "0",
"depends_on": "eval:(doc.report_type == 'Profit and Loss' && !doc.is_group)",
"fieldname": "include_in_gross",
"fieldtype": "Check",
"label": "Include in gross",
"show_days": 1,
"show_seconds": 1
"label": "Include in gross"
},
{
"default": "0",
"fieldname": "disabled",
"fieldtype": "Check",
"label": "Disable",
"show_days": 1,
"show_seconds": 1
"label": "Disable"
}
],
"icon": "fa fa-money",
"idx": 1,
"is_tree": 1,
"links": [],
"modified": "2020-06-11 15:15:54.338622",
"modified": "2023-04-11 16:08:46.983677",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account",
@@ -301,5 +252,6 @@
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "ASC",
"states": [],
"track_changes": 1
}

View File

@@ -201,8 +201,11 @@ class Account(NestedSet):
)
def validate_account_currency(self):
self.currency_explicitly_specified = True
if not self.account_currency:
self.account_currency = frappe.get_cached_value("Company", self.company, "default_currency")
self.currency_explicitly_specified = False
gl_currency = frappe.db.get_value("GL Entry", {"account": self.name}, "account_currency")
@@ -248,8 +251,10 @@ class Account(NestedSet):
{
"company": company,
# parent account's currency should be passed down to child account's curreny
# if it is None, it picks it up from default company currency, which might be unintended
"account_currency": erpnext.get_company_currency(company),
# if currency explicitly specified by user, child will inherit. else, default currency will be used.
"account_currency": self.account_currency
if self.currency_explicitly_specified
else erpnext.get_company_currency(company),
"parent_account": parent_acc_name_map[company],
}
)

View File

@@ -5,10 +5,13 @@
import unittest
import frappe
from frappe.test_runner import make_test_records
from erpnext.accounts.doctype.account.account import merge_account, update_account_number
from erpnext.stock import get_company_default_inventory_account, get_warehouse_account
test_dependencies = ["Company"]
class TestAccount(unittest.TestCase):
def test_rename_account(self):
@@ -188,6 +191,58 @@ class TestAccount(unittest.TestCase):
frappe.delete_doc("Account", "1234 - Test Rename Sync Account - _TC4")
frappe.delete_doc("Account", "1234 - Test Rename Sync Account - _TC5")
def test_account_currency_sync(self):
"""
In a parent->child company setup, child should inherit parent account currency if explicitly specified.
"""
make_test_records("Company")
frappe.local.flags.pop("ignore_root_company_validation", None)
def create_bank_account():
acc = frappe.new_doc("Account")
acc.account_name = "_Test Bank JPY"
acc.parent_account = "Temporary Accounts - _TC6"
acc.company = "_Test Company 6"
return acc
acc = create_bank_account()
# Explicitly set currency
acc.account_currency = "JPY"
acc.insert()
self.assertTrue(
frappe.db.exists(
{
"doctype": "Account",
"account_name": "_Test Bank JPY",
"account_currency": "JPY",
"company": "_Test Company 7",
}
)
)
frappe.delete_doc("Account", "_Test Bank JPY - _TC6")
frappe.delete_doc("Account", "_Test Bank JPY - _TC7")
acc = create_bank_account()
# default currency is used
acc.insert()
self.assertTrue(
frappe.db.exists(
{
"doctype": "Account",
"account_name": "_Test Bank JPY",
"account_currency": "USD",
"company": "_Test Company 7",
}
)
)
frappe.delete_doc("Account", "_Test Bank JPY - _TC6")
frappe.delete_doc("Account", "_Test Bank JPY - _TC7")
def test_child_company_account_rename_sync(self):
frappe.local.flags.pop("ignore_root_company_validation", None)
@@ -297,7 +352,7 @@ def _make_test_records(verbose=None):
# fixed asset depreciation
["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None],
["_Test Accumulated Depreciations", "Current Assets", 0, "Accumulated Depreciation", None],
["_Test Depreciations", "Expenses", 0, None, None],
["_Test Depreciations", "Expenses", 0, "Depreciation", None],
["_Test Gain/Loss on Asset Disposal", "Expenses", 0, None, None],
# Receivable / Payable Account
["_Test Receivable", "Current Assets", 0, "Receivable", None],

View File

@@ -50,13 +50,15 @@ class AccountingDimension(Document):
if frappe.flags.in_test:
make_dimension_in_accounting_doctypes(doc=self)
else:
frappe.enqueue(make_dimension_in_accounting_doctypes, doc=self, queue="long")
frappe.enqueue(
make_dimension_in_accounting_doctypes, doc=self, queue="long", enqueue_after_commit=True
)
def on_trash(self):
if frappe.flags.in_test:
delete_accounting_dimension(doc=self)
else:
frappe.enqueue(delete_accounting_dimension, doc=self, queue="long")
frappe.enqueue(delete_accounting_dimension, doc=self, queue="long", enqueue_after_commit=True)
def set_fieldname_and_label(self):
if not self.label:

View File

@@ -19,6 +19,8 @@
"column_break_17",
"enable_common_party_accounting",
"allow_multi_currency_invoices_against_single_party_account",
"journals_section",
"merge_similar_account_heads",
"report_setting_section",
"use_custom_cash_flow",
"deferred_accounting_settings_section",
@@ -31,12 +33,16 @@
"determine_address_tax_category_from",
"column_break_19",
"add_taxes_from_item_tax_template",
"book_tax_discount_loss",
"print_settings",
"show_inclusive_tax_in_print",
"show_taxes_as_table_in_print",
"column_break_12",
"show_payment_schedule_in_print",
"currency_exchange_section",
"allow_stale",
"section_break_jpd0",
"auto_reconcile_payments",
"stale_days",
"invoicing_settings_tab",
"accounts_transactions_settings_section",
@@ -167,11 +173,6 @@
"fieldtype": "Int",
"label": "Stale Days"
},
{
"fieldname": "report_settings_sb",
"fieldtype": "Section Break",
"label": "Report Settings"
},
{
"default": "0",
"description": "Only select this if you have set up the Cash Flow Mapper documents",
@@ -181,6 +182,7 @@
},
{
"default": "0",
"description": "Payment Terms from orders will be fetched into the invoices as is",
"fieldname": "automatically_fetch_payment_terms",
"fieldtype": "Check",
"label": "Automatically Fetch Payment Terms from Order"
@@ -347,6 +349,42 @@
"fieldname": "allow_multi_currency_invoices_against_single_party_account",
"fieldtype": "Check",
"label": "Allow multi-currency invoices against single party account "
},
{
"default": "0",
"description": "Split Early Payment Discount Loss into Income and Tax Loss",
"fieldname": "book_tax_discount_loss",
"fieldtype": "Check",
"label": "Book Tax Loss on Early Payment Discount"
},
{
"fieldname": "journals_section",
"fieldtype": "Section Break",
"label": "Journals"
},
{
"default": "0",
"description": "Rows with Same Account heads will be merged on Ledger",
"fieldname": "merge_similar_account_heads",
"fieldtype": "Check",
"label": "Merge Similar Account Heads"
},
{
"fieldname": "section_break_jpd0",
"fieldtype": "Section Break",
"label": "Payment Reconciliations"
},
{
"default": "0",
"fieldname": "auto_reconcile_payments",
"fieldtype": "Check",
"label": "Auto Reconcile Payments"
},
{
"default": "0",
"fieldname": "show_taxes_as_table_in_print",
"fieldtype": "Check",
"label": "Show Taxes as Table in Print"
}
],
"icon": "icon-cog",
@@ -354,7 +392,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2022-11-27 21:49:52.538655",
"modified": "2023-06-13 18:47:46.430291",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
@@ -383,4 +421,4 @@
"sort_order": "ASC",
"states": [],
"track_changes": 1
}
}

View File

@@ -56,7 +56,7 @@ class BankClearance(Document):
select
"Payment Entry" as payment_document, name as payment_entry,
reference_no as cheque_number, reference_date as cheque_date,
if(paid_from=%(account)s, paid_amount, 0) as credit,
if(paid_from=%(account)s, paid_amount + total_taxes_and_charges, 0) as credit,
if(paid_from=%(account)s, 0, received_amount) as debit,
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
@@ -81,7 +81,7 @@ class BankClearance(Document):
loan_disbursement = frappe.qb.DocType("Loan Disbursement")
loan_disbursements = (
query = (
frappe.qb.from_(loan_disbursement)
.select(
ConstantColumn("Loan Disbursement").as_("payment_document"),
@@ -90,17 +90,22 @@ class BankClearance(Document):
ConstantColumn(0).as_("debit"),
loan_disbursement.reference_number.as_("cheque_number"),
loan_disbursement.reference_date.as_("cheque_date"),
loan_disbursement.clearance_date.as_("clearance_date"),
loan_disbursement.disbursement_date.as_("posting_date"),
loan_disbursement.applicant.as_("against_account"),
)
.where(loan_disbursement.docstatus == 1)
.where(loan_disbursement.disbursement_date >= self.from_date)
.where(loan_disbursement.disbursement_date <= self.to_date)
.where(loan_disbursement.clearance_date.isnull())
.where(loan_disbursement.disbursement_account.isin([self.bank_account, self.account]))
.orderby(loan_disbursement.disbursement_date)
.orderby(loan_disbursement.name, order=frappe.qb.desc)
).run(as_dict=1)
)
if not self.include_reconciled_entries:
query = query.where(loan_disbursement.clearance_date.isnull())
loan_disbursements = query.run(as_dict=1)
loan_repayment = frappe.qb.DocType("Loan Repayment")
@@ -113,16 +118,19 @@ class BankClearance(Document):
ConstantColumn(0).as_("credit"),
loan_repayment.reference_number.as_("cheque_number"),
loan_repayment.reference_date.as_("cheque_date"),
loan_repayment.clearance_date.as_("clearance_date"),
loan_repayment.applicant.as_("against_account"),
loan_repayment.posting_date,
)
.where(loan_repayment.docstatus == 1)
.where(loan_repayment.clearance_date.isnull())
.where(loan_repayment.posting_date >= self.from_date)
.where(loan_repayment.posting_date <= self.to_date)
.where(loan_repayment.payment_account.isin([self.bank_account, self.account]))
)
if not self.include_reconciled_entries:
query = query.where(loan_repayment.clearance_date.isnull())
if frappe.db.has_column("Loan Repayment", "repay_from_salary"):
query = query.where((loan_repayment.repay_from_salary == 0))

View File

@@ -46,7 +46,7 @@ class BankTransaction(StatusUpdater):
def add_payment_entries(self, vouchers):
"Add the vouchers with zero allocation. Save() will perform the allocations and clearance"
if 0.0 >= self.unallocated_amount:
frappe.throw(frappe._(f"Bank Transaction {self.name} is already fully reconciled"))
frappe.throw(frappe._("Bank Transaction {0} is already fully reconciled").format(self.name))
added = False
for voucher in vouchers:
@@ -114,9 +114,7 @@ class BankTransaction(StatusUpdater):
elif 0.0 > unallocated_amount:
self.db_delete_payment_entry(payment_entry)
frappe.throw(
frappe._(f"Voucher {payment_entry.payment_entry} is over-allocated by {unallocated_amount}")
)
frappe.throw(frappe._("Voucher {0} is over-allocated by {1}").format(unallocated_amount))
self.reload()
@@ -178,7 +176,9 @@ def get_clearance_details(transaction, payment_entry):
if gle["gl_account"] == gl_bank_account:
if gle["amount"] <= 0.0:
frappe.throw(
frappe._(f"Voucher {payment_entry.payment_entry} value is broken: {gle['amount']}")
frappe._("Voucher {0} value is broken: {1}").format(
payment_entry.payment_entry, gle["amount"]
)
)
unmatched_gles -= 1
@@ -281,10 +281,13 @@ def get_paid_amount(payment_entry, currency, gl_bank_account):
)
elif payment_entry.payment_document == "Journal Entry":
return frappe.db.get_value(
"Journal Entry Account",
{"parent": payment_entry.payment_entry, "account": gl_bank_account},
"sum(credit_in_account_currency)",
return abs(
frappe.db.get_value(
"Journal Entry Account",
{"parent": payment_entry.payment_entry, "account": gl_bank_account},
"sum(debit_in_account_currency-credit_in_account_currency)",
)
or 0
)
elif payment_entry.payment_document == "Expense Claim":

View File

@@ -125,14 +125,27 @@ def validate_expense_against_budget(args, expense_amount=0):
if not args.account:
return
for budget_against in ["project", "cost_center"] + get_accounting_dimensions():
default_dimensions = [
{
"fieldname": "project",
"document_type": "Project",
},
{
"fieldname": "cost_center",
"document_type": "Cost Center",
},
]
for dimension in default_dimensions + get_accounting_dimensions(as_list=False):
budget_against = dimension.get("fieldname")
if (
args.get(budget_against)
and args.account
and frappe.db.get_value("Account", {"name": args.account, "root_type": "Expense"})
):
doctype = frappe.unscrub(budget_against)
doctype = dimension.get("document_type")
if frappe.get_cached_value("DocType", doctype, "is_tree"):
lft, rgt = frappe.db.get_value(doctype, args.get(budget_against), ["lft", "rgt"])

View File

@@ -325,14 +325,14 @@ def get_template(template_type):
if template_type == "Blank Template":
for root_type in get_root_types():
writer.writerow(["", "", "", 1, "", root_type])
writer.writerow(["", "", "", "", 1, "", root_type])
for account in get_mandatory_group_accounts():
writer.writerow(["", "", "", 1, account, "Asset"])
writer.writerow(["", "", "", "", 1, account, "Asset"])
for account_type in get_mandatory_account_types():
writer.writerow(
["", "", "", 0, account_type.get("account_type"), account_type.get("root_type")]
["", "", "", "", 0, account_type.get("account_type"), account_type.get("root_type")]
)
else:
writer = get_sample_template(writer)

View File

@@ -35,6 +35,21 @@ frappe.ui.form.on('Exchange Rate Revaluation', {
}
},
validate_rounding_loss: function(frm) {
let allowance = frm.doc.rounding_loss_allowance;
if (!(allowance > 0 && allowance < 1)) {
frappe.throw(__("Rounding Loss Allowance should be between 0 and 1"));
}
},
rounding_loss_allowance: function(frm) {
frm.events.validate_rounding_loss(frm);
},
validate: function(frm) {
frm.events.validate_rounding_loss(frm);
},
get_entries: function(frm, account) {
frappe.call({
method: "get_accounts_data",
@@ -126,7 +141,8 @@ var get_account_details = function(frm, cdt, cdn) {
company: frm.doc.company,
posting_date: frm.doc.posting_date,
party_type: row.party_type,
party: row.party
party: row.party,
rounding_loss_allowance: frm.doc.rounding_loss_allowance
},
callback: function(r){
$.extend(row, r.message);

View File

@@ -8,6 +8,7 @@
"engine": "InnoDB",
"field_order": [
"posting_date",
"rounding_loss_allowance",
"column_break_2",
"company",
"section_break_4",
@@ -96,11 +97,18 @@
{
"fieldname": "column_break_10",
"fieldtype": "Column Break"
},
{
"default": "0.05",
"description": "Only values between 0 and 1 are allowed. \nEx: If allowance is set at 0.07, accounts that have balance of 0.07 in either of the currencies will be considered as zero balance account",
"fieldname": "rounding_loss_allowance",
"fieldtype": "Float",
"label": "Rounding Loss Allowance"
}
],
"is_submittable": 1,
"links": [],
"modified": "2022-12-29 19:38:24.416529",
"modified": "2023-06-12 21:02:09.818208",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Exchange Rate Revaluation",

View File

@@ -12,13 +12,19 @@ from frappe.utils import flt, get_link_to_form
import erpnext
from erpnext.accounts.doctype.journal_entry.journal_entry import get_balance_on
from erpnext.accounts.utils import get_currency_precision
from erpnext.setup.utils import get_exchange_rate
class ExchangeRateRevaluation(Document):
def validate(self):
self.validate_rounding_loss_allowance()
self.set_total_gain_loss()
def validate_rounding_loss_allowance(self):
if not (self.rounding_loss_allowance > 0 and self.rounding_loss_allowance < 1):
frappe.throw(_("Rounding Loss Allowance should be between 0 and 1"))
def set_total_gain_loss(self):
total_gain_loss = 0
@@ -91,7 +97,12 @@ class ExchangeRateRevaluation(Document):
def get_accounts_data(self):
self.validate_mandatory()
account_details = self.get_account_balance_from_gle(
company=self.company, posting_date=self.posting_date, account=None, party_type=None, party=None
company=self.company,
posting_date=self.posting_date,
account=None,
party_type=None,
party=None,
rounding_loss_allowance=self.rounding_loss_allowance,
)
accounts_with_new_balance = self.calculate_new_account_balance(
self.company, self.posting_date, account_details
@@ -103,7 +114,9 @@ class ExchangeRateRevaluation(Document):
return accounts_with_new_balance
@staticmethod
def get_account_balance_from_gle(company, posting_date, account, party_type, party):
def get_account_balance_from_gle(
company, posting_date, account, party_type, party, rounding_loss_allowance
):
account_details = []
if company and posting_date:
@@ -170,6 +183,23 @@ class ExchangeRateRevaluation(Document):
.run(as_dict=True)
)
# round off balance based on currency precision
# and consider debit-credit difference allowance
currency_precision = get_currency_precision()
rounding_loss_allowance = rounding_loss_allowance or 0.05
for acc in account_details:
acc.balance_in_account_currency = flt(acc.balance_in_account_currency, currency_precision)
if abs(acc.balance_in_account_currency) <= rounding_loss_allowance:
acc.balance_in_account_currency = 0
acc.balance = flt(acc.balance, currency_precision)
if abs(acc.balance) <= rounding_loss_allowance:
acc.balance = 0
acc.zero_balance = (
True if (acc.balance == 0 or acc.balance_in_account_currency == 0) else False
)
return account_details
@staticmethod
@@ -490,6 +520,8 @@ def calculate_exchange_rate_using_last_gle(company, account, party_type, party):
conditions.append(gl.company == company)
conditions.append(gl.account == account)
conditions.append(gl.is_cancelled == 0)
conditions.append((gl.debit > 0) | (gl.credit > 0))
conditions.append((gl.debit_in_account_currency > 0) | (gl.credit_in_account_currency > 0))
if party_type:
conditions.append(gl.party_type == party_type)
if party:
@@ -519,7 +551,9 @@ def calculate_exchange_rate_using_last_gle(company, account, party_type, party):
@frappe.whitelist()
def get_account_details(company, posting_date, account, party_type=None, party=None):
def get_account_details(
company, posting_date, account, party_type=None, party=None, rounding_loss_allowance=None
):
if not (company and posting_date):
frappe.throw(_("Company and Posting Date is mandatory"))
@@ -537,7 +571,12 @@ def get_account_details(company, posting_date, account, party_type=None, party=N
"account_currency": account_currency,
}
account_balance = ExchangeRateRevaluation.get_account_balance_from_gle(
company=company, posting_date=posting_date, account=account, party_type=party_type, party=party
company=company,
posting_date=posting_date,
account=account,
party_type=party_type,
party=party,
rounding_loss_allowance=rounding_loss_allowance,
)
if account_balance and (

View File

@@ -8,7 +8,7 @@ frappe.provide("erpnext.journal_entry");
frappe.ui.form.on("Journal Entry", {
setup: function(frm) {
frm.add_fetch("bank_account", "account", "account");
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger"];
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger", 'Asset', 'Asset Movement'];
},
refresh: function(frm) {

View File

@@ -51,7 +51,7 @@ class JournalEntry(AccountsController):
self.validate_multi_currency()
self.set_amounts_in_company_currency()
self.validate_debit_credit_amount()
self.set_total_debit_credit()
# Do not validate while importing via data import
if not frappe.flags.in_import:
self.validate_total_debit_and_credit()
@@ -69,6 +69,7 @@ class JournalEntry(AccountsController):
self.validate_empty_accounts_table()
self.set_account_and_party_balance()
self.validate_inter_company_accounts()
self.validate_depr_entry_voucher_type()
if self.docstatus == 0:
self.apply_tax_withholding()
@@ -130,6 +131,13 @@ class JournalEntry(AccountsController):
if self.total_credit != doc.total_debit or self.total_debit != doc.total_credit:
frappe.throw(_("Total Credit/ Debit Amount should be same as linked Journal Entry"))
def validate_depr_entry_voucher_type(self):
if (
any(d.account_type == "Depreciation" for d in self.get("accounts"))
and self.voucher_type != "Depreciation Entry"
):
frappe.throw(_("Journal Entry type should be set as Depreciation Entry for asset depreciation"))
def validate_stock_accounts(self):
stock_accounts = get_stock_accounts(self.company, self.doctype, self.name)
for account in stock_accounts:
@@ -233,25 +241,30 @@ class JournalEntry(AccountsController):
self.remove(d)
def update_asset_value(self):
if self.voucher_type != "Depreciation Entry":
if self.flags.planned_depr_entry or self.voucher_type != "Depreciation Entry":
return
processed_assets = []
for d in self.get("accounts"):
if (
d.reference_type == "Asset" and d.reference_name and d.reference_name not in processed_assets
d.reference_type == "Asset"
and d.reference_name
and d.account_type == "Depreciation"
and d.debit
):
processed_assets.append(d.reference_name)
asset = frappe.get_doc("Asset", d.reference_name)
if asset.calculate_depreciation:
continue
depr_value = d.debit or d.credit
asset.db_set("value_after_depreciation", asset.value_after_depreciation - depr_value)
fb_idx = 1
if self.finance_book:
for fb_row in asset.get("finance_books"):
if fb_row.finance_book == self.finance_book:
fb_idx = fb_row.idx
break
fb_row = asset.get("finance_books")[fb_idx - 1]
fb_row.value_after_depreciation -= d.debit
fb_row.db_update()
else:
asset.db_set("value_after_depreciation", asset.value_after_depreciation - d.debit)
asset.set_status()
@@ -316,35 +329,35 @@ class JournalEntry(AccountsController):
if self.voucher_type != "Depreciation Entry":
return
processed_assets = []
for d in self.get("accounts"):
if (
d.reference_type == "Asset" and d.reference_name and d.reference_name not in processed_assets
d.reference_type == "Asset"
and d.reference_name
and d.account_type == "Depreciation"
and d.debit
):
processed_assets.append(d.reference_name)
asset = frappe.get_doc("Asset", d.reference_name)
if asset.calculate_depreciation:
fb_idx = None
for s in asset.get("schedules"):
if s.journal_entry == self.name:
s.db_set("journal_entry", None)
idx = cint(s.finance_book_id) or 1
finance_books = asset.get("finance_books")[idx - 1]
finance_books.value_after_depreciation += s.depreciation_amount
finance_books.db_update()
asset.set_status()
fb_idx = cint(s.finance_book_id) or 1
break
if not fb_idx:
fb_idx = 1
if self.finance_book:
for fb_row in asset.get("finance_books"):
if fb_row.finance_book == self.finance_book:
fb_idx = fb_row.idx
break
fb_row = asset.get("finance_books")[fb_idx - 1]
fb_row.value_after_depreciation += d.debit
fb_row.db_update()
else:
depr_value = d.debit or d.credit
asset.db_set("value_after_depreciation", asset.value_after_depreciation + depr_value)
asset.set_status()
asset.db_set("value_after_depreciation", asset.value_after_depreciation + d.debit)
asset.set_status()
def unlink_inter_company_jv(self):
if (
@@ -659,7 +672,6 @@ class JournalEntry(AccountsController):
frappe.throw(_("Row {0}: Both Debit and Credit values cannot be zero").format(d.idx))
def validate_total_debit_and_credit(self):
self.set_total_debit_credit()
if not (self.voucher_type == "Exchange Gain Or Loss" and self.multi_currency):
if self.difference:
frappe.throw(
@@ -879,6 +891,8 @@ class JournalEntry(AccountsController):
def make_gl_entries(self, cancel=0, adv_adj=0):
from erpnext.accounts.general_ledger import make_gl_entries
merge_entries = frappe.db.get_single_value("Accounts Settings", "merge_similar_account_heads")
gl_map = self.build_gl_map()
if self.voucher_type in ("Deferred Revenue", "Deferred Expense"):
update_outstanding = "No"
@@ -886,7 +900,13 @@ class JournalEntry(AccountsController):
update_outstanding = "Yes"
if gl_map:
make_gl_entries(gl_map, cancel=cancel, adv_adj=adv_adj, update_outstanding=update_outstanding)
make_gl_entries(
gl_map,
cancel=cancel,
adv_adj=adv_adj,
merge_entries=merge_entries,
update_outstanding=update_outstanding,
)
@frappe.whitelist()
def get_balance(self, difference_account=None):
@@ -920,6 +940,7 @@ class JournalEntry(AccountsController):
blank_row.debit_in_account_currency = abs(diff)
blank_row.debit = abs(diff)
self.set_total_debit_credit()
self.validate_total_debit_and_credit()
@frappe.whitelist()

View File

@@ -287,10 +287,6 @@ class TestJournalEntry(unittest.TestCase):
jv.submit()
def test_inter_company_jv(self):
frappe.db.set_value("Account", "Sales Expenses - _TC", "inter_company_account", 1)
frappe.db.set_value("Account", "Buildings - _TC", "inter_company_account", 1)
frappe.db.set_value("Account", "Sales Expenses - _TC1", "inter_company_account", 1)
frappe.db.set_value("Account", "Buildings - _TC1", "inter_company_account", 1)
jv = make_journal_entry(
"Sales Expenses - _TC",
"Buildings - _TC",

View File

@@ -2,6 +2,21 @@
// For license information, please see license.txt
frappe.ui.form.on("Journal Entry Template", {
onload: function(frm) {
if(frm.is_new()) {
frappe.call({
type: "GET",
method: "erpnext.accounts.doctype.journal_entry_template.journal_entry_template.get_naming_series",
callback: function(r){
if(r.message) {
frm.set_df_property("naming_series", "options", r.message.split("\n"));
frm.set_value("naming_series", r.message.split("\n")[0]);
frm.refresh_field("naming_series");
}
}
});
}
},
refresh: function(frm) {
frappe.model.set_default_values(frm.doc);
@@ -19,18 +34,6 @@ frappe.ui.form.on("Journal Entry Template", {
return { filters: filters };
});
frappe.call({
type: "GET",
method: "erpnext.accounts.doctype.journal_entry_template.journal_entry_template.get_naming_series",
callback: function(r){
if(r.message){
frm.set_df_property("naming_series", "options", r.message.split("\n"));
frm.set_value("naming_series", r.message.split("\n")[0]);
frm.refresh_field("naming_series");
}
}
});
},
voucher_type: function(frm) {
var add_accounts = function(doc, r) {

View File

@@ -245,8 +245,6 @@ frappe.ui.form.on('Payment Entry', {
frm.set_currency_labels(["total_amount", "outstanding_amount", "allocated_amount"],
party_account_currency, "references");
frm.set_currency_labels(["amount"], company_currency, "deductions");
cur_frm.set_df_property("source_exchange_rate", "description",
("1 " + frm.doc.paid_from_account_currency + " = [?] " + company_currency));
@@ -907,7 +905,7 @@ frappe.ui.form.on('Payment Entry', {
function(d) { return flt(d.amount) }));
frm.set_value("difference_amount", difference_amount - total_deductions +
frm.doc.base_total_taxes_and_charges);
flt(frm.doc.base_total_taxes_and_charges));
frm.events.hide_unhide_fields(frm);
},
@@ -973,29 +971,48 @@ frappe.ui.form.on('Payment Entry', {
},
callback: function(r, rt) {
if(r.message) {
var write_off_row = $.map(frm.doc["deductions"] || [], function(t) {
const write_off_row = $.map(frm.doc["deductions"] || [], function(t) {
return t.account==r.message[account] ? t : null; });
var row = [];
var difference_amount = flt(frm.doc.difference_amount,
const difference_amount = flt(frm.doc.difference_amount,
precision("difference_amount"));
if (!write_off_row.length && difference_amount) {
row = frm.add_child("deductions");
row.account = r.message[account];
row.cost_center = r.message["cost_center"];
} else {
row = write_off_row[0];
}
const add_deductions = (details) => {
let row = null;
if (!write_off_row.length && difference_amount) {
row = frm.add_child("deductions");
row.account = details[account];
row.cost_center = details["cost_center"];
} else {
row = write_off_row[0];
}
if (row) {
row.amount = flt(row.amount) + difference_amount;
} else {
frappe.msgprint(__("No gain or loss in the exchange rate"))
}
if (row) {
row.amount = flt(row.amount) + difference_amount;
} else {
frappe.msgprint(__("No gain or loss in the exchange rate"))
}
refresh_field("deductions");
};
refresh_field("deductions");
if (!r.message[account]) {
frappe.prompt({
label: __("Please Specify Account"),
fieldname: account,
fieldtype: "Link",
options: "Account",
get_query: () => ({
filters: {
company: frm.doc.company,
}
})
}, (values) => {
const details = Object.assign({}, r.message, values);
add_deductions(details);
}, __(frappe.unscrub(account)));
} else {
add_deductions(r.message);
}
frm.events.set_unallocated_amount(frm);
}

View File

@@ -60,6 +60,7 @@ class PaymentEntry(AccountsController):
def validate(self):
self.setup_party_account_field()
self.set_missing_values()
self.set_missing_ref_details()
self.validate_payment_type()
self.validate_party_details()
self.set_exchange_rate()
@@ -147,19 +148,57 @@ class PaymentEntry(AccountsController):
)
def validate_allocated_amount(self):
for d in self.get("references"):
if self.payment_type == "Internal Transfer":
return
latest_references = get_outstanding_reference_documents(
{
"posting_date": self.posting_date,
"company": self.company,
"party_type": self.party_type,
"payment_type": self.payment_type,
"party": self.party,
"party_account": self.paid_from if self.payment_type == "Receive" else self.paid_to,
}
)
# Group latest_references by (voucher_type, voucher_no)
latest_lookup = {}
for d in latest_references:
d = frappe._dict(d)
latest_lookup.update({(d.voucher_type, d.voucher_no): d})
for d in self.get("references").copy():
latest = latest_lookup.get((d.reference_doctype, d.reference_name))
# The reference has already been fully paid
if not latest:
frappe.throw(
_("{0} {1} has already been fully paid.").format(d.reference_doctype, d.reference_name)
)
# The reference has already been partly paid
elif (
latest.outstanding_amount < latest.invoice_amount
and d.outstanding_amount != latest.outstanding_amount
):
frappe.throw(
_(
"{0} {1} has already been partly paid. Please use the 'Get Outstanding Invoice' button to get the latest outstanding amount."
).format(d.reference_doctype, d.reference_name)
)
d.outstanding_amount = latest.outstanding_amount
fail_message = _("Row #{0}: Allocated Amount cannot be greater than outstanding amount.")
if (flt(d.allocated_amount)) > 0:
if flt(d.allocated_amount) > flt(d.outstanding_amount):
frappe.throw(
_("Row #{0}: Allocated Amount cannot be greater than outstanding amount.").format(d.idx)
)
frappe.throw(fail_message.format(d.idx))
# Check for negative outstanding invoices as well
if flt(d.allocated_amount) < 0:
if flt(d.allocated_amount) < flt(d.outstanding_amount):
frappe.throw(
_("Row #{0}: Allocated Amount cannot be greater than outstanding amount.").format(d.idx)
)
frappe.throw(fail_message.format(d.idx))
def delink_advance_entry_references(self):
for reference in self.references:
@@ -219,11 +258,16 @@ class PaymentEntry(AccountsController):
else self.paid_to_account_currency
)
self.set_missing_ref_details()
def set_missing_ref_details(self, force=False):
def set_missing_ref_details(
self, force: bool = False, update_ref_details_only_for: list | None = None
) -> None:
for d in self.get("references"):
if d.allocated_amount:
if update_ref_details_only_for and (
not (d.reference_doctype, d.reference_name) in update_ref_details_only_for
):
continue
ref_details = get_reference_details(
d.reference_doctype, d.reference_name, self.party_account_currency
)
@@ -367,7 +411,7 @@ class PaymentEntry(AccountsController):
for k, v in no_oustanding_refs.items():
frappe.msgprint(
_(
"{} - {} now have {} as they had no outstanding amount left before submitting the Payment Entry."
"{} - {} now has {} as it had no outstanding amount left before submitting the Payment Entry."
).format(
_(k),
frappe.bold(", ".join(d.reference_name for d in v)),
@@ -416,7 +460,7 @@ class PaymentEntry(AccountsController):
for ref in self.get("references"):
if ref.payment_term and ref.reference_name:
key = (ref.payment_term, ref.reference_name)
key = (ref.payment_term, ref.reference_name, ref.reference_doctype)
invoice_payment_amount_map.setdefault(key, 0.0)
invoice_payment_amount_map[key] += ref.allocated_amount
@@ -424,20 +468,37 @@ class PaymentEntry(AccountsController):
payment_schedule = frappe.get_all(
"Payment Schedule",
filters={"parent": ref.reference_name},
fields=["paid_amount", "payment_amount", "payment_term", "discount", "outstanding"],
fields=[
"paid_amount",
"payment_amount",
"payment_term",
"discount",
"outstanding",
"discount_type",
],
)
for term in payment_schedule:
invoice_key = (term.payment_term, ref.reference_name)
invoice_key = (term.payment_term, ref.reference_name, ref.reference_doctype)
invoice_paid_amount_map.setdefault(invoice_key, {})
invoice_paid_amount_map[invoice_key]["outstanding"] = term.outstanding
invoice_paid_amount_map[invoice_key]["discounted_amt"] = ref.total_amount * (
term.discount / 100
)
if not (term.discount_type and term.discount):
continue
if term.discount_type == "Percentage":
invoice_paid_amount_map[invoice_key]["discounted_amt"] = ref.total_amount * (
term.discount / 100
)
else:
invoice_paid_amount_map[invoice_key]["discounted_amt"] = term.discount
for idx, (key, allocated_amount) in enumerate(invoice_payment_amount_map.items(), 1):
if not invoice_paid_amount_map.get(key):
frappe.throw(_("Payment term {0} not used in {1}").format(key[0], key[1]))
allocated_amount = self.get_allocated_amount_in_transaction_currency(
allocated_amount, key[2], key[1]
)
outstanding = flt(invoice_paid_amount_map.get(key, {}).get("outstanding"))
discounted_amt = flt(invoice_paid_amount_map.get(key, {}).get("discounted_amt"))
@@ -472,6 +533,33 @@ class PaymentEntry(AccountsController):
(allocated_amount - discounted_amt, discounted_amt, allocated_amount, key[1], key[0]),
)
def get_allocated_amount_in_transaction_currency(
self, allocated_amount, reference_doctype, reference_docname
):
"""
Payment Entry could be in base currency while reference's payment schedule
is always in transaction currency.
E.g.
* SI with base=INR and currency=USD
* SI with payment schedule in USD
* PE in INR (accounting done in base currency)
"""
ref_currency, ref_exchange_rate = frappe.db.get_value(
reference_doctype, reference_docname, ["currency", "conversion_rate"]
)
is_single_currency = self.paid_from_account_currency == self.paid_to_account_currency
# PE in different currency
reference_is_multi_currency = self.paid_from_account_currency != ref_currency
if not (is_single_currency and reference_is_multi_currency):
return allocated_amount
allocated_amount = flt(
allocated_amount / ref_exchange_rate, self.precision("total_allocated_amount")
)
return allocated_amount
def set_status(self):
if self.docstatus == 2:
self.status = "Cancelled"
@@ -604,6 +692,28 @@ class PaymentEntry(AccountsController):
self.precision("base_received_amount"),
)
def calculate_base_allocated_amount_for_reference(self, d) -> float:
base_allocated_amount = 0
if d.reference_doctype in frappe.get_hooks("advance_payment_doctypes"):
# When referencing Sales/Purchase Order, use the source/target exchange rate depending on payment type.
# This is so there are no Exchange Gain/Loss generated for such doctypes
exchange_rate = 1
if self.payment_type == "Receive":
exchange_rate = self.source_exchange_rate
elif self.payment_type == "Pay":
exchange_rate = self.target_exchange_rate
base_allocated_amount += flt(
flt(d.allocated_amount) * flt(exchange_rate), self.precision("base_paid_amount")
)
else:
base_allocated_amount += flt(
flt(d.allocated_amount) * flt(d.exchange_rate), self.precision("base_paid_amount")
)
return base_allocated_amount
def set_total_allocated_amount(self):
if self.payment_type == "Internal Transfer":
return
@@ -612,9 +722,7 @@ class PaymentEntry(AccountsController):
for d in self.get("references"):
if d.allocated_amount:
total_allocated_amount += flt(d.allocated_amount)
base_total_allocated_amount += flt(
flt(d.allocated_amount) * flt(d.exchange_rate), self.precision("base_paid_amount")
)
base_total_allocated_amount += self.calculate_base_allocated_amount_for_reference(d)
self.total_allocated_amount = abs(total_allocated_amount)
self.base_total_allocated_amount = abs(base_total_allocated_amount)
@@ -831,9 +939,7 @@ class PaymentEntry(AccountsController):
}
)
allocated_amount_in_company_currency = flt(
flt(d.allocated_amount) * flt(d.exchange_rate), self.precision("paid_amount")
)
allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d)
gle.update(
{
@@ -1381,7 +1487,7 @@ def get_orders_to_be_billed(
if voucher_type:
doc = frappe.get_doc({"doctype": voucher_type})
condition = ""
if doc and hasattr(doc, "cost_center"):
if doc and hasattr(doc, "cost_center") and doc.cost_center:
condition = " and cost_center='%s'" % cost_center
orders = []
@@ -1427,9 +1533,15 @@ def get_orders_to_be_billed(
order_list = []
for d in orders:
if not (
flt(d.outstanding_amount) >= flt(filters.get("outstanding_amt_greater_than"))
and flt(d.outstanding_amount) <= flt(filters.get("outstanding_amt_less_than"))
if (
filters
and filters.get("outstanding_amt_greater_than")
and filters.get("outstanding_amt_less_than")
and not (
flt(filters.get("outstanding_amt_greater_than"))
<= flt(d.outstanding_amount)
<= flt(filters.get("outstanding_amt_less_than"))
)
):
continue
@@ -1550,17 +1662,7 @@ def get_account_details(account, date, cost_center=None):
@frappe.whitelist()
def get_company_defaults(company):
fields = ["write_off_account", "exchange_gain_loss_account", "cost_center"]
ret = frappe.get_cached_value("Company", company, fields, as_dict=1)
for fieldname in fields:
if not ret[fieldname]:
frappe.throw(
_("Please set default {0} in Company {1}").format(
frappe.get_meta("Company").get_label(fieldname), company
)
)
return ret
return frappe.get_cached_value("Company", company, fields, as_dict=1)
def get_outstanding_on_journal_entry(name):
@@ -1642,11 +1744,21 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
@frappe.whitelist()
def get_payment_entry(
dt, dn, party_amount=None, bank_account=None, bank_amount=None, party_type=None, payment_type=None
dt,
dn,
party_amount=None,
bank_account=None,
bank_amount=None,
party_type=None,
payment_type=None,
reference_date=None,
):
reference_doc = None
doc = frappe.get_doc(dt, dn)
if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) >= 99.99:
over_billing_allowance = frappe.db.get_single_value("Accounts Settings", "over_billing_allowance")
if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) >= (
100.0 + over_billing_allowance
):
frappe.throw(_("Can only make payment against unbilled {0}").format(dt))
if not party_type:
@@ -1665,12 +1777,20 @@ def get_payment_entry(
# bank or cash
bank = get_bank_cash_account(doc, bank_account)
# if default bank or cash account is not set in company master and party has default company bank account, fetch it
if party_type in ["Customer", "Supplier"] and not bank:
party_bank_account = get_party_bank_account(party_type, doc.get(scrub(party_type)))
if party_bank_account:
account = frappe.db.get_value("Bank Account", party_bank_account, "account")
bank = get_bank_cash_account(doc, account)
paid_amount, received_amount = set_paid_amount_and_received_amount(
dt, party_account_currency, bank, outstanding_amount, payment_type, bank_amount, doc
)
paid_amount, received_amount, discount_amount = apply_early_payment_discount(
paid_amount, received_amount, doc
reference_date = getdate(reference_date)
paid_amount, received_amount, discount_amount, valid_discounts = apply_early_payment_discount(
paid_amount, received_amount, doc, party_account_currency, reference_date
)
pe = frappe.new_doc("Payment Entry")
@@ -1678,6 +1798,7 @@ def get_payment_entry(
pe.company = doc.company
pe.cost_center = doc.get("cost_center")
pe.posting_date = nowdate()
pe.reference_date = reference_date
pe.mode_of_payment = doc.get("mode_of_payment")
pe.party_type = party_type
pe.party = doc.get(scrub(party_type))
@@ -1711,14 +1832,19 @@ def get_payment_entry(
if doc.doctype == "Purchase Invoice" and doc.invoice_is_blocked():
frappe.msgprint(_("{0} is on hold till {1}").format(doc.name, doc.release_date))
else:
if doc.doctype in ("Sales Invoice", "Purchase Invoice") and frappe.get_value(
if doc.doctype in (
"Sales Invoice",
"Purchase Invoice",
"Purchase Order",
"Sales Order",
) and frappe.get_cached_value(
"Payment Terms Template",
{"name": doc.payment_terms_template},
"allocate_payment_based_on_payment_terms",
):
for reference in get_reference_as_per_payment_terms(
doc.payment_schedule, dt, dn, doc, grand_total, outstanding_amount
doc.payment_schedule, dt, dn, doc, grand_total, outstanding_amount, party_account_currency
):
pe.append("references", reference)
else:
@@ -1763,22 +1889,24 @@ def get_payment_entry(
pe.setup_party_account_field()
pe.set_missing_values()
pe.set_missing_ref_details()
update_accounting_dimensions(pe, doc)
if party_account and bank:
pe.set_exchange_rate(ref_doc=reference_doc)
pe.set_amounts()
if discount_amount:
pe.set_gain_or_loss(
account_details={
"account": frappe.get_cached_value("Company", pe.company, "default_discount_account"),
"cost_center": pe.cost_center
or frappe.get_cached_value("Company", pe.company, "cost_center"),
"amount": discount_amount * (-1 if payment_type == "Pay" else 1),
}
base_total_discount_loss = 0
if frappe.db.get_single_value("Accounts Settings", "book_tax_discount_loss"):
base_total_discount_loss = split_early_payment_discount_loss(pe, doc, valid_discounts)
set_pending_discount_loss(
pe, doc, discount_amount, base_total_discount_loss, party_account_currency
)
pe.set_difference_amount()
pe.set_difference_amount()
return pe
@@ -1872,37 +2000,53 @@ def set_paid_amount_and_received_amount(
paid_amount = received_amount = 0
if party_account_currency == bank.account_currency:
paid_amount = received_amount = abs(outstanding_amount)
elif payment_type == "Receive":
paid_amount = abs(outstanding_amount)
if bank_amount:
received_amount = bank_amount
else:
received_amount = paid_amount * doc.get("conversion_rate", 1)
else:
received_amount = abs(outstanding_amount)
if bank_amount:
paid_amount = bank_amount
company_currency = frappe.get_cached_value("Company", doc.get("company"), "default_currency")
if payment_type == "Receive":
paid_amount = abs(outstanding_amount)
if bank_amount:
received_amount = bank_amount
else:
if company_currency != bank.account_currency:
received_amount = paid_amount / doc.get("conversion_rate", 1)
else:
received_amount = paid_amount * doc.get("conversion_rate", 1)
else:
# if party account currency and bank currency is different then populate paid amount as well
paid_amount = received_amount * doc.get("conversion_rate", 1)
received_amount = abs(outstanding_amount)
if bank_amount:
paid_amount = bank_amount
else:
if company_currency != bank.account_currency:
paid_amount = received_amount / doc.get("conversion_rate", 1)
else:
# if party account currency and bank currency is different then populate paid amount as well
paid_amount = received_amount * doc.get("conversion_rate", 1)
return paid_amount, received_amount
def apply_early_payment_discount(paid_amount, received_amount, doc):
def apply_early_payment_discount(
paid_amount, received_amount, doc, party_account_currency, reference_date
):
total_discount = 0
valid_discounts = []
eligible_for_payments = ["Sales Order", "Sales Invoice", "Purchase Order", "Purchase Invoice"]
has_payment_schedule = hasattr(doc, "payment_schedule") and doc.payment_schedule
is_multi_currency = party_account_currency != doc.company_currency
if doc.doctype in eligible_for_payments and has_payment_schedule:
for term in doc.payment_schedule:
if not term.discounted_amount and term.discount and getdate(nowdate()) <= term.discount_date:
if not term.discounted_amount and term.discount and reference_date <= term.discount_date:
if term.discount_type == "Percentage":
discount_amount = flt(doc.get("grand_total")) * (term.discount / 100)
grand_total = doc.get("grand_total") if is_multi_currency else doc.get("base_grand_total")
discount_amount = flt(grand_total) * (term.discount / 100)
else:
discount_amount = term.discount
discount_amount_in_foreign_currency = discount_amount * doc.get("conversion_rate", 1)
# if accounting is done in the same currency, paid_amount = received_amount
conversion_rate = doc.get("conversion_rate", 1) if is_multi_currency else 1
discount_amount_in_foreign_currency = discount_amount * conversion_rate
if doc.doctype == "Sales Invoice":
paid_amount -= discount_amount
@@ -1911,23 +2055,151 @@ def apply_early_payment_discount(paid_amount, received_amount, doc):
received_amount -= discount_amount
paid_amount -= discount_amount_in_foreign_currency
valid_discounts.append({"type": term.discount_type, "discount": term.discount})
total_discount += discount_amount
if total_discount:
money = frappe.utils.fmt_money(total_discount, currency=doc.get("currency"))
currency = doc.get("currency") if is_multi_currency else doc.company_currency
money = frappe.utils.fmt_money(total_discount, currency=currency)
frappe.msgprint(_("Discount of {} applied as per Payment Term").format(money), alert=1)
return paid_amount, received_amount, total_discount
return paid_amount, received_amount, total_discount, valid_discounts
def set_pending_discount_loss(
pe, doc, discount_amount, base_total_discount_loss, party_account_currency
):
# If multi-currency, get base discount amount to adjust with base currency deductions/losses
if party_account_currency != doc.company_currency:
discount_amount = discount_amount * doc.get("conversion_rate", 1)
# Avoid considering miniscule losses
discount_amount = flt(discount_amount - base_total_discount_loss, doc.precision("grand_total"))
# Set base discount amount (discount loss/pending rounding loss) in deductions
if discount_amount > 0.0:
positive_negative = -1 if pe.payment_type == "Pay" else 1
# If tax loss booking is enabled, pending loss will be rounding loss.
# Otherwise it will be the total discount loss.
book_tax_loss = frappe.db.get_single_value("Accounts Settings", "book_tax_discount_loss")
account_type = "round_off_account" if book_tax_loss else "default_discount_account"
pe.set_gain_or_loss(
account_details={
"account": frappe.get_cached_value("Company", pe.company, account_type),
"cost_center": pe.cost_center or frappe.get_cached_value("Company", pe.company, "cost_center"),
"amount": discount_amount * positive_negative,
}
)
def split_early_payment_discount_loss(pe, doc, valid_discounts) -> float:
"""Split early payment discount into Income Loss & Tax Loss."""
total_discount_percent = get_total_discount_percent(doc, valid_discounts)
if not total_discount_percent:
return 0.0
base_loss_on_income = add_income_discount_loss(pe, doc, total_discount_percent)
base_loss_on_taxes = add_tax_discount_loss(pe, doc, total_discount_percent)
# Round off total loss rather than individual losses to reduce rounding error
return flt(base_loss_on_income + base_loss_on_taxes, doc.precision("grand_total"))
def get_total_discount_percent(doc, valid_discounts) -> float:
"""Get total percentage and amount discount applied as a percentage."""
total_discount_percent = (
sum(
discount.get("discount") for discount in valid_discounts if discount.get("type") == "Percentage"
)
or 0.0
)
# Operate in percentages only as it makes the income & tax split easier
total_discount_amount = (
sum(discount.get("discount") for discount in valid_discounts if discount.get("type") == "Amount")
or 0.0
)
if total_discount_amount:
discount_percentage = (total_discount_amount / doc.get("grand_total")) * 100
total_discount_percent += discount_percentage
return total_discount_percent
return total_discount_percent
def add_income_discount_loss(pe, doc, total_discount_percent) -> float:
"""Add loss on income discount in base currency."""
precision = doc.precision("total")
base_loss_on_income = doc.get("base_total") * (total_discount_percent / 100)
pe.append(
"deductions",
{
"account": frappe.get_cached_value("Company", pe.company, "default_discount_account"),
"cost_center": pe.cost_center or frappe.get_cached_value("Company", pe.company, "cost_center"),
"amount": flt(base_loss_on_income, precision),
},
)
return base_loss_on_income # Return loss without rounding
def add_tax_discount_loss(pe, doc, total_discount_percentage) -> float:
"""Add loss on tax discount in base currency."""
tax_discount_loss = {}
base_total_tax_loss = 0
precision = doc.precision("tax_amount_after_discount_amount", "taxes")
# The same account head could be used more than once
for tax in doc.get("taxes", []):
base_tax_loss = tax.get("base_tax_amount_after_discount_amount") * (
total_discount_percentage / 100
)
account = tax.get("account_head")
if not tax_discount_loss.get(account):
tax_discount_loss[account] = base_tax_loss
else:
tax_discount_loss[account] += base_tax_loss
for account, loss in tax_discount_loss.items():
base_total_tax_loss += loss
if loss == 0.0:
continue
pe.append(
"deductions",
{
"account": account,
"cost_center": pe.cost_center or frappe.get_cached_value("Company", pe.company, "cost_center"),
"amount": flt(loss, precision),
},
)
return base_total_tax_loss # Return loss without rounding
def get_reference_as_per_payment_terms(
payment_schedule, dt, dn, doc, grand_total, outstanding_amount
payment_schedule, dt, dn, doc, grand_total, outstanding_amount, party_account_currency
):
references = []
is_multi_currency_acc = (doc.currency != doc.company_currency) and (
party_account_currency != doc.company_currency
)
for payment_term in payment_schedule:
payment_term_outstanding = flt(
payment_term.payment_amount - payment_term.paid_amount, payment_term.precision("payment_amount")
)
if not is_multi_currency_acc:
# If accounting is done in company currency for multi-currency transaction
payment_term_outstanding = flt(
payment_term_outstanding * doc.get("conversion_rate"), payment_term.precision("payment_amount")
)
if payment_term_outstanding:
references.append(

View File

@@ -5,7 +5,7 @@ import unittest
import frappe
from frappe import qb
from frappe.tests.utils import FrappeTestCase
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import flt, nowdate
from erpnext.accounts.doctype.payment_entry.payment_entry import (
@@ -51,6 +51,38 @@ class TestPaymentEntry(FrappeTestCase):
so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
self.assertEqual(so_advance_paid, 0)
def test_payment_against_sales_order_usd_to_inr(self):
so = make_sales_order(
customer="_Test Customer USD", currency="USD", qty=1, rate=100, do_not_submit=True
)
so.conversion_rate = 50
so.submit()
pe = get_payment_entry("Sales Order", so.name)
pe.source_exchange_rate = 55
pe.received_amount = 5500
pe.insert()
pe.submit()
# there should be no difference amount
pe.reload()
self.assertEqual(pe.difference_amount, 0)
self.assertEqual(pe.deductions, [])
expected_gle = dict(
(d[0], d)
for d in [["_Test Receivable USD - _TC", 0, 5500, so.name], ["Cash - _TC", 5500.0, 0, None]]
)
self.validate_gl_entries(pe.name, expected_gle)
so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
self.assertEqual(so_advance_paid, 100)
pe.cancel()
so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
self.assertEqual(so_advance_paid, 0)
def test_payment_entry_for_blocked_supplier_invoice(self):
supplier = frappe.get_doc("Supplier", "_Test Supplier")
supplier.on_hold = 1
@@ -256,10 +288,25 @@ class TestPaymentEntry(FrappeTestCase):
},
)
si.save()
si.submit()
frappe.db.set_single_value("Accounts Settings", "book_tax_discount_loss", 1)
pe_with_tax_loss = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Cash - _TC")
self.assertEqual(pe_with_tax_loss.references[0].payment_term, "30 Credit Days with 10% Discount")
self.assertEqual(pe_with_tax_loss.references[0].allocated_amount, 236.0)
self.assertEqual(pe_with_tax_loss.paid_amount, 212.4)
self.assertEqual(pe_with_tax_loss.deductions[0].amount, 20.0) # Loss on Income
self.assertEqual(pe_with_tax_loss.deductions[1].amount, 3.6) # Loss on Tax
self.assertEqual(pe_with_tax_loss.deductions[1].account, "_Test Account Service Tax - _TC")
frappe.db.set_single_value("Accounts Settings", "book_tax_discount_loss", 0)
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Cash - _TC")
self.assertEqual(pe.references[0].allocated_amount, 236.0)
self.assertEqual(pe.paid_amount, 212.4)
self.assertEqual(pe.deductions[0].amount, 23.6)
pe.submit()
si.load_from_db()
@@ -269,6 +316,190 @@ class TestPaymentEntry(FrappeTestCase):
self.assertEqual(si.payment_schedule[0].outstanding, 0)
self.assertEqual(si.payment_schedule[0].discounted_amount, 23.6)
def test_payment_entry_against_payment_terms_with_discount_amount(self):
si = create_sales_invoice(do_not_save=1, qty=1, rate=200)
si.payment_terms_template = "Test Discount Amount Template"
create_payment_terms_template_with_discount(
name="30 Credit Days with Rs.50 Discount",
discount_type="Amount",
discount=50,
template_name="Test Discount Amount Template",
)
frappe.db.set_value("Company", si.company, "default_discount_account", "Write Off - _TC")
si.append(
"taxes",
{
"charge_type": "On Net Total",
"account_head": "_Test Account Service Tax - _TC",
"cost_center": "_Test Cost Center - _TC",
"description": "Service Tax",
"rate": 18,
},
)
si.save()
si.submit()
# Set reference date past discount cut off date
pe_1 = get_payment_entry(
"Sales Invoice",
si.name,
bank_account="_Test Cash - _TC",
reference_date=frappe.utils.add_days(si.posting_date, 2),
)
self.assertEqual(pe_1.paid_amount, 236.0) # discount not applied
# Test if tax loss is booked on enabling configuration
frappe.db.set_single_value("Accounts Settings", "book_tax_discount_loss", 1)
pe_with_tax_loss = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Cash - _TC")
self.assertEqual(pe_with_tax_loss.deductions[0].amount, 42.37) # Loss on Income
self.assertEqual(pe_with_tax_loss.deductions[1].amount, 7.63) # Loss on Tax
self.assertEqual(pe_with_tax_loss.deductions[1].account, "_Test Account Service Tax - _TC")
frappe.db.set_single_value("Accounts Settings", "book_tax_discount_loss", 0)
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Cash - _TC")
self.assertEqual(pe.references[0].allocated_amount, 236.0)
self.assertEqual(pe.paid_amount, 186)
self.assertEqual(pe.deductions[0].amount, 50.0)
pe.submit()
si.load_from_db()
self.assertEqual(si.payment_schedule[0].payment_amount, 236.0)
self.assertEqual(si.payment_schedule[0].paid_amount, 186)
self.assertEqual(si.payment_schedule[0].outstanding, 0)
self.assertEqual(si.payment_schedule[0].discounted_amount, 50)
@change_settings(
"Accounts Settings",
{
"allow_multi_currency_invoices_against_single_party_account": 1,
"book_tax_discount_loss": 1,
},
)
def test_payment_entry_multicurrency_si_with_base_currency_accounting_early_payment_discount(
self,
):
"""
1. Multi-currency SI with single currency accounting (company currency)
2. PE with early payment discount
3. Test if Paid Amount is calculated in company currency
4. Test if deductions are calculated in company currency
SI is in USD to document agreed amounts that are in USD, but the accounting is in base currency.
"""
si = create_sales_invoice(
customer="_Test Customer",
currency="USD",
conversion_rate=50,
do_not_save=1,
)
create_payment_terms_template_with_discount()
si.payment_terms_template = "Test Discount Template"
frappe.db.set_value("Company", si.company, "default_discount_account", "Write Off - _TC")
si.save()
si.submit()
pe = get_payment_entry(
"Sales Invoice",
si.name,
bank_account="_Test Bank - _TC",
)
pe.reference_no = si.name
pe.reference_date = nowdate()
# Early payment discount loss on income
self.assertEqual(pe.paid_amount, 4500.0) # Amount in company currency
self.assertEqual(pe.received_amount, 4500.0)
self.assertEqual(pe.deductions[0].amount, 500.0)
self.assertEqual(pe.deductions[0].account, "Write Off - _TC")
self.assertEqual(pe.difference_amount, 0.0)
pe.insert()
pe.submit()
expected_gle = dict(
(d[0], d)
for d in [
["Debtors - _TC", 0, 5000, si.name],
["_Test Bank - _TC", 4500, 0, None],
["Write Off - _TC", 500.0, 0, None],
]
)
self.validate_gl_entries(pe.name, expected_gle)
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, 0)
def test_payment_entry_multicurrency_accounting_si_with_early_payment_discount(self):
"""
1. Multi-currency SI with multi-currency accounting
2. PE with early payment discount and also exchange loss
3. Test if Paid Amount is calculated in transaction currency
4. Test if deductions are calculated in base/company currency
5. Test if exchange loss is reflected in difference
"""
si = create_sales_invoice(
customer="_Test Customer USD",
debit_to="_Test Receivable USD - _TC",
currency="USD",
conversion_rate=50,
do_not_save=1,
)
create_payment_terms_template_with_discount()
si.payment_terms_template = "Test Discount Template"
frappe.db.set_value("Company", si.company, "default_discount_account", "Write Off - _TC")
si.save()
si.submit()
pe = get_payment_entry(
"Sales Invoice", si.name, bank_account="_Test Bank - _TC", bank_amount=4700
)
pe.reference_no = si.name
pe.reference_date = nowdate()
# Early payment discount loss on income
self.assertEqual(pe.paid_amount, 90.0)
self.assertEqual(pe.received_amount, 4200.0) # 5000 - 500 (discount) - 300 (exchange loss)
self.assertEqual(pe.deductions[0].amount, 500.0)
self.assertEqual(pe.deductions[0].account, "Write Off - _TC")
# Exchange loss
self.assertEqual(pe.difference_amount, 300.0)
pe.append(
"deductions",
{
"account": "_Test Exchange Gain/Loss - _TC",
"cost_center": "_Test Cost Center - _TC",
"amount": 300.0,
},
)
pe.insert()
pe.submit()
self.assertEqual(pe.difference_amount, 0.0)
expected_gle = dict(
(d[0], d)
for d in [
["_Test Receivable USD - _TC", 0, 5000, si.name],
["_Test Bank - _TC", 4200, 0, None],
["Write Off - _TC", 500.0, 0, None],
["_Test Exchange Gain/Loss - _TC", 300.0, 0, None],
]
)
self.validate_gl_entries(pe.name, expected_gle)
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, 0)
def test_payment_against_purchase_invoice_to_check_status(self):
pi = make_purchase_invoice(
supplier="_Test Supplier USD",
@@ -782,6 +1013,30 @@ class TestPaymentEntry(FrappeTestCase):
employee = make_employee("test_payment_entry@salary.com", company="_Test Company")
create_payment_entry(party_type="Employee", party=employee, save=True)
def test_duplicate_payment_entry_allocate_amount(self):
si = create_sales_invoice()
pe_draft = get_payment_entry("Sales Invoice", si.name)
pe_draft.insert()
pe = get_payment_entry("Sales Invoice", si.name)
pe.submit()
self.assertRaises(frappe.ValidationError, pe_draft.submit)
def test_duplicate_payment_entry_partial_allocate_amount(self):
si = create_sales_invoice()
pe_draft = get_payment_entry("Sales Invoice", si.name)
pe_draft.insert()
pe = get_payment_entry("Sales Invoice", si.name)
pe.received_amount = si.total / 2
pe.references[0].allocated_amount = si.total / 2
pe.submit()
self.assertRaises(frappe.ValidationError, pe_draft.submit)
def create_payment_entry(**args):
payment_entry = frappe.new_doc("Payment Entry")
@@ -839,24 +1094,27 @@ def create_payment_terms_template():
).insert()
def create_payment_terms_template_with_discount():
def create_payment_terms_template_with_discount(
name=None, discount_type=None, discount=None, template_name=None
):
create_payment_term(name or "30 Credit Days with 10% Discount")
template_name = template_name or "Test Discount Template"
create_payment_term("30 Credit Days with 10% Discount")
if not frappe.db.exists("Payment Terms Template", "Test Discount Template"):
payment_term_template = frappe.get_doc(
if not frappe.db.exists("Payment Terms Template", template_name):
frappe.get_doc(
{
"doctype": "Payment Terms Template",
"template_name": "Test Discount Template",
"template_name": template_name,
"allocate_payment_based_on_payment_terms": 1,
"terms": [
{
"doctype": "Payment Terms Template Detail",
"payment_term": "30 Credit Days with 10% Discount",
"payment_term": name or "30 Credit Days with 10% Discount",
"invoice_portion": 100,
"credit_days_based_on": "Day(s) after invoice date",
"credit_days": 2,
"discount": 10,
"discount_type": discount_type or "Percentage",
"discount": discount or 10,
"discount_validity_based_on": "Day(s) after invoice date",
"discount_validity": 1,
}

View File

@@ -3,6 +3,7 @@
"creation": "2016-06-15 15:56:30.815503",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"account",
"cost_center",
@@ -17,9 +18,7 @@
"in_list_view": 1,
"label": "Account",
"options": "Account",
"reqd": 1,
"show_days": 1,
"show_seconds": 1
"reqd": 1
},
{
"fieldname": "cost_center",
@@ -28,37 +27,30 @@
"label": "Cost Center",
"options": "Cost Center",
"print_hide": 1,
"reqd": 1,
"show_days": 1,
"show_seconds": 1
"reqd": 1
},
{
"fieldname": "amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Amount",
"reqd": 1,
"show_days": 1,
"show_seconds": 1
"label": "Amount (Company Currency)",
"options": "Company:company:default_currency",
"reqd": 1
},
{
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"show_days": 1,
"show_seconds": 1
"fieldtype": "Column Break"
},
{
"fieldname": "description",
"fieldtype": "Small Text",
"label": "Description",
"show_days": 1,
"show_seconds": 1
"label": "Description"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2020-09-12 20:38:08.110674",
"modified": "2023-03-06 07:11:57.739619",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry Deduction",
@@ -66,5 +58,6 @@
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC"
"sort_order": "DESC",
"states": []
}

View File

@@ -82,6 +82,32 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
this.frm.change_custom_button_type('Get Unreconciled Entries', null, 'default');
this.frm.change_custom_button_type('Allocate', null, 'default');
}
// check for any running reconciliation jobs
if (this.frm.doc.receivable_payable_account) {
frappe.db.get_single_value("Accounts Settings", "auto_reconcile_payments").then((enabled) => {
if(enabled) {
this.frm.call({
'method': "erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.is_any_doc_running",
"args": {
for_filter: {
company: this.frm.doc.company,
party_type: this.frm.doc.party_type,
party: this.frm.doc.party,
receivable_payable_account: this.frm.doc.receivable_payable_account
}
}
}).then(r => {
if (r.message) {
let doc_link = frappe.utils.get_form_link("Process Payment Reconciliation", r.message, true);
let msg = __("Payment Reconciliation Job: {0} is running for this party. Can't reconcile now.", [doc_link]);
this.frm.dashboard.add_comment(msg, "yellow");
}
});
}
});
}
}
company() {
@@ -272,4 +298,32 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
}
};
frappe.ui.form.on('Payment Reconciliation Allocation', {
allocated_amount: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
// filter invoice
let invoice = frm.doc.invoices.filter((x) => (x.invoice_number == row.invoice_number));
// filter payment
let payment = frm.doc.payments.filter((x) => (x.reference_name == row.reference_name));
frm.call({
doc: frm.doc,
method: 'calculate_difference_on_allocation_change',
args: {
payment_entry: payment,
invoice: invoice,
allocated_amount: row.allocated_amount
},
callback: (r) => {
if (r.message) {
row.difference_amount = r.message;
frm.refresh();
}
}
});
}
});
extend_cscript(cur_frm.cscript, new erpnext.accounts.PaymentReconciliationController({frm: cur_frm}));

View File

@@ -6,10 +6,12 @@ import frappe
from frappe import _, msgprint, qb
from frappe.model.document import Document
from frappe.query_builder.custom import ConstantColumn
from frappe.query_builder.functions import IfNull
from frappe.utils import flt, getdate, nowdate, today
from frappe.utils import flt, get_link_to_form, getdate, nowdate, today
import erpnext
from erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation import (
is_any_doc_running,
)
from erpnext.accounts.utils import (
QueryPaymentLedger,
get_outstanding_invoices,
@@ -124,12 +126,29 @@ class PaymentReconciliation(Document):
return list(journal_entries)
def get_return_invoices(self):
voucher_type = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice"
doc = qb.DocType(voucher_type)
self.return_invoices = (
qb.from_(doc)
.select(
ConstantColumn(voucher_type).as_("voucher_type"),
doc.name.as_("voucher_no"),
doc.return_against,
)
.where(
(doc.docstatus == 1)
& (doc[frappe.scrub(self.party_type)] == self.party)
& (doc.is_return == 1)
)
.run(as_dict=True)
)
def get_dr_or_cr_notes(self):
self.build_qb_filter_conditions(get_return_invoices=True)
ple = qb.DocType("Payment Ledger Entry")
voucher_type = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice"
if erpnext.get_party_account_type(self.party_type) == "Receivable":
self.common_filter_conditions.append(ple.account_type == "Receivable")
@@ -137,19 +156,10 @@ class PaymentReconciliation(Document):
self.common_filter_conditions.append(ple.account_type == "Payable")
self.common_filter_conditions.append(ple.account == self.receivable_payable_account)
# get return invoices
doc = qb.DocType(voucher_type)
return_invoices = (
qb.from_(doc)
.select(ConstantColumn(voucher_type).as_("voucher_type"), doc.name.as_("voucher_no"))
.where(
(doc.docstatus == 1)
& (doc[frappe.scrub(self.party_type)] == self.party)
& (doc.is_return == 1)
& (IfNull(doc.return_against, "") == "")
)
.run(as_dict=True)
)
self.get_return_invoices()
return_invoices = [
x for x in self.return_invoices if x.return_against == None or x.return_against == ""
]
outstanding_dr_or_cr = []
if return_invoices:
@@ -201,6 +211,15 @@ class PaymentReconciliation(Document):
accounting_dimensions=self.accounting_dimension_filter_conditions,
)
cr_dr_notes = (
[x.voucher_no for x in self.return_invoices]
if self.party_type in ["Customer", "Supplier"]
else []
)
# Filter out cr/dr notes from outstanding invoices list
# Happens when non-standalone cr/dr notes are linked with another invoice through journal entry
non_reconciled_invoices = [x for x in non_reconciled_invoices if x.voucher_no not in cr_dr_notes]
if self.invoice_limit:
non_reconciled_invoices = non_reconciled_invoices[: self.invoice_limit]
@@ -233,6 +252,15 @@ class PaymentReconciliation(Document):
return difference_amount
@frappe.whitelist()
def calculate_difference_on_allocation_change(self, payment_entry, invoice, allocated_amount):
invoice_exchange_map = self.get_invoice_exchange_map(invoice, payment_entry)
invoice[0]["exchange_rate"] = invoice_exchange_map.get(invoice[0].get("invoice_number"))
new_difference_amount = self.get_difference_amount(
payment_entry[0], invoice[0], allocated_amount
)
return new_difference_amount
@frappe.whitelist()
def allocate_entries(self, args):
self.validate_entries()
@@ -295,9 +323,7 @@ class PaymentReconciliation(Document):
}
)
@frappe.whitelist()
def reconcile(self):
self.validate_allocation()
def reconcile_allocations(self, skip_ref_details_update_for_pe=False):
dr_or_cr = (
"credit_in_account_currency"
if erpnext.get_party_account_type(self.party_type) == "Receivable"
@@ -321,12 +347,35 @@ class PaymentReconciliation(Document):
self.make_difference_entry(payment_details)
if entry_list:
reconcile_against_document(entry_list)
reconcile_against_document(entry_list, skip_ref_details_update_for_pe)
if dr_or_cr_notes:
reconcile_dr_cr_note(dr_or_cr_notes, self.company)
@frappe.whitelist()
def reconcile(self):
if frappe.db.get_single_value("Accounts Settings", "auto_reconcile_payments"):
running_doc = is_any_doc_running(
dict(
company=self.company,
party_type=self.party_type,
party=self.party,
receivable_payable_account=self.receivable_payable_account,
)
)
if running_doc:
frappe.throw(
_("A Reconciliation Job {0} is running for the same filters. Cannot reconcile now").format(
get_link_to_form("Auto Reconcile", running_doc)
)
)
return
self.validate_allocation()
self.reconcile_allocations()
msgprint(_("Successfully Reconciled"))
self.get_unreconciled_entries()
def make_difference_entry(self, row):

View File

@@ -497,10 +497,16 @@ def get_amount(ref_doc, payment_account=None):
if dt in ["Sales Order", "Purchase Order"]:
grand_total = flt(ref_doc.rounded_total) or flt(ref_doc.grand_total)
elif dt in ["Sales Invoice", "Purchase Invoice"]:
if ref_doc.party_account_currency == ref_doc.currency:
grand_total = flt(ref_doc.outstanding_amount)
else:
grand_total = flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate
if not ref_doc.get("is_pos"):
if ref_doc.party_account_currency == ref_doc.currency:
grand_total = flt(ref_doc.outstanding_amount)
else:
grand_total = flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate
elif dt == "Sales Invoice":
for pay in ref_doc.payments:
if pay.type == "Phone" and pay.account == payment_account:
grand_total = pay.amount
break
elif dt == "POS Invoice":
for pay in ref_doc.payments:
if pay.type == "Phone" and pay.account == payment_account:

View File

@@ -6,6 +6,7 @@ import unittest
import frappe
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.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.setup.utils import get_exchange_rate
@@ -74,6 +75,29 @@ class TestPaymentRequest(unittest.TestCase):
self.assertEqual(pr.reference_name, si_usd.name)
self.assertEqual(pr.currency, "USD")
def test_payment_entry_against_purchase_invoice(self):
si_usd = make_purchase_invoice(
customer="_Test Supplier USD",
debit_to="_Test Payable USD - _TC",
currency="USD",
conversion_rate=50,
)
pr = make_payment_request(
dt="Purchase Invoice",
dn=si_usd.name,
recipient_id="user@example.com",
mute_email=1,
payment_gateway_account="_Test Gateway - USD",
submit_doc=1,
return_doc=1,
)
pe = pr.create_payment_entry()
pr.load_from_db()
self.assertEqual(pr.status, "Paid")
def test_payment_entry(self):
frappe.db.set_value(
"Company", "_Test Company", "exchange_gain_loss_account", "_Test Exchange Gain/Loss - _TC"

View File

@@ -35,6 +35,7 @@ class PeriodClosingVoucher(AccountsController):
voucher_type="Period Closing Voucher",
voucher_no=self.name,
queue="long",
enqueue_after_commit=True,
)
frappe.msgprint(
_("The GL Entries will be cancelled in the background, it can take a few minutes."), alert=True
@@ -169,21 +170,18 @@ class PeriodClosingVoucher(AccountsController):
return frappe.db.sql(
"""
select
t2.account_currency,
t1.account_currency,
{dimension_fields},
sum(t1.debit_in_account_currency) - sum(t1.credit_in_account_currency) as bal_in_account_currency,
sum(t1.debit) - sum(t1.credit) as bal_in_company_currency
from `tabGL Entry` t1, `tabAccount` t2
from `tabGL Entry` t1
where
t1.is_cancelled = 0
and t1.account = t2.name
and t2.report_type = 'Profit and Loss'
and t2.docstatus < 2
and t2.company = %s
and t1.account in (select name from `tabAccount` where report_type = 'Profit and Loss' and docstatus < 2 and company = %s)
and t1.posting_date between %s and %s
group by {dimension_fields}
""".format(
dimension_fields=", ".join(dimension_fields)
dimension_fields=", ".join(dimension_fields),
),
(self.company, self.get("year_start_date"), self.posting_date),
as_dict=1,

View File

@@ -5,7 +5,7 @@
import unittest
import frappe
from frappe.utils import today
from frappe.utils import add_months, today
from erpnext.accounts.doctype.finance_book.test_finance_book import create_finance_book
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
@@ -176,6 +176,23 @@ class TestPeriodClosingVoucher(unittest.TestCase):
)
self.assertSequenceEqual(pcv_gle, expected_gle)
warehouse = frappe.db.get_value("Warehouse", {"company": company}, "name")
repost_doc = frappe.get_doc(
{
"doctype": "Repost Item Valuation",
"company": company,
"posting_date": "2020-03-15",
"based_on": "Item and Warehouse",
"item_code": "Test Item 1",
"warehouse": warehouse,
}
)
self.assertRaises(frappe.ValidationError, repost_doc.save)
repost_doc.posting_date = add_months(today(), 13)
repost_doc.save()
def make_period_closing_voucher(self, submit=True):
surplus_account = create_account()

View File

@@ -4,6 +4,7 @@
import frappe
from frappe import _
from frappe.query_builder.functions import IfNull, Sum
from frappe.utils import cint, flt, get_link_to_form, getdate, nowdate
from erpnext.accounts.doctype.loyalty_program.loyalty_program import validate_loyalty_points
@@ -673,18 +674,22 @@ def get_bin_qty(item_code, warehouse):
def get_pos_reserved_qty(item_code, warehouse):
reserved_qty = frappe.db.sql(
"""select sum(p_item.qty) as qty
from `tabPOS Invoice` p, `tabPOS Invoice Item` p_item
where p.name = p_item.parent
and ifnull(p.consolidated_invoice, '') = ''
and p_item.docstatus = 1
and p_item.item_code = %s
and p_item.warehouse = %s
""",
(item_code, warehouse),
as_dict=1,
)
p_inv = frappe.qb.DocType("POS Invoice")
p_item = frappe.qb.DocType("POS Invoice Item")
reserved_qty = (
frappe.qb.from_(p_inv)
.from_(p_item)
.select(Sum(p_item.qty).as_("qty"))
.where(
(p_inv.name == p_item.parent)
& (IfNull(p_inv.consolidated_invoice, "") == "")
& (p_inv.is_return == 0)
& (p_item.docstatus == 1)
& (p_item.item_code == item_code)
& (p_item.warehouse == warehouse)
)
).run(as_dict=True)
return reserved_qty[0].qty or 0 if reserved_qty else 0

View File

@@ -469,7 +469,7 @@
"options": "UOM"
},
{
"description": "If rate is zero them item will be treated as \"Free Item\"",
"description": "If rate is zero then item will be treated as \"Free Item\"",
"fieldname": "free_item_rate",
"fieldtype": "Currency",
"label": "Free Item Rate"
@@ -670,4 +670,4 @@
"sort_order": "DESC",
"states": [],
"title_field": "title"
}
}

View File

@@ -0,0 +1,130 @@
// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on("Process Payment Reconciliation", {
onload: function(frm) {
// set queries
frm.set_query("party_type", function() {
return {
"filters": {
"name": ["in", Object.keys(frappe.boot.party_account_types)],
}
}
});
frm.set_query('receivable_payable_account', function(doc) {
return {
filters: {
"company": doc.company,
"is_group": 0,
"account_type": frappe.boot.party_account_types[doc.party_type]
}
};
});
frm.set_query('cost_center', function(doc) {
return {
filters: {
"company": doc.company,
"is_group": 0,
}
};
});
frm.set_query('bank_cash_account', function(doc) {
return {
filters:[
['Account', 'company', '=', doc.company],
['Account', 'is_group', '=', 0],
['Account', 'account_type', 'in', ['Bank', 'Cash']]
]
};
});
},
refresh: function(frm) {
if (frm.doc.docstatus==1 && ['Queued', 'Paused'].find(x => x == frm.doc.status)) {
let execute_btn = __("Start / Resume")
frm.add_custom_button(execute_btn, () => {
frm.call({
method: 'erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.trigger_job_for_doc',
args: {
docname: frm.doc.name
}
}).then(r => {
if(!r.exc) {
frappe.show_alert(__("Job Started"));
frm.reload_doc();
}
});
});
}
if (frm.doc.docstatus==1 && ['Completed', 'Running', 'Paused', 'Partially Reconciled'].find(x => x == frm.doc.status)) {
frm.call({
'method': "erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.get_reconciled_count",
args: {
"docname": frm.docname,
}
}).then(r => {
if (r.message) {
let progress = 0;
let description = "";
if (r.message.processed) {
progress = (r.message.processed/r.message.total) * 100;
description = r.message.processed + "/" + r.message.total + " processed";
} else if (r.message.total == 0 && frm.doc.status == "Completed") {
progress = 100;
}
frm.dashboard.add_progress('Reconciliation Progress', progress, description);
}
})
}
if (frm.doc.docstatus==1 && frm.doc.status == 'Running') {
let execute_btn = __("Pause")
frm.add_custom_button(execute_btn, () => {
frm.call({
'method': "erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.pause_job_for_doc",
args: {
"docname": frm.docname,
}
}).then(r => {
if (!r.exc) {
frappe.show_alert(__("Job Paused"));
frm.reload_doc()
}
});
});
}
},
company(frm) {
frm.set_value('party', '');
frm.set_value('receivable_payable_account', '');
},
party_type(frm) {
frm.set_value('party', '');
},
party(frm) {
frm.set_value('receivable_payable_account', '');
if (!frm.doc.receivable_payable_account && frm.doc.party_type && frm.doc.party) {
return frappe.call({
method: "erpnext.accounts.party.get_party_account",
args: {
company: frm.doc.company,
party_type: frm.doc.party_type,
party: frm.doc.party
},
callback: (r) => {
if (!r.exc && r.message) {
frm.set_value("receivable_payable_account", r.message);
}
frm.refresh();
}
});
}
}
});

View File

@@ -0,0 +1,173 @@
{
"actions": [],
"autoname": "format:ACC-PPR-{#####}",
"beta": 1,
"creation": "2023-03-30 21:28:39.793927",
"default_view": "List",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"company",
"party_type",
"column_break_io6c",
"party",
"receivable_payable_account",
"filter_section",
"from_invoice_date",
"to_invoice_date",
"column_break_kegk",
"from_payment_date",
"to_payment_date",
"column_break_uj04",
"cost_center",
"bank_cash_account",
"section_break_2n02",
"status",
"error_log",
"section_break_a8yx",
"amended_from"
],
"fields": [
{
"allow_on_submit": 1,
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
"options": "\nQueued\nRunning\nPaused\nCompleted\nPartially Reconciled\nFailed\nCancelled",
"read_only": 1
},
{
"fieldname": "company",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Company",
"options": "Company",
"reqd": 1
},
{
"fieldname": "party_type",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Party Type",
"options": "DocType",
"reqd": 1
},
{
"fieldname": "column_break_io6c",
"fieldtype": "Column Break"
},
{
"fieldname": "party",
"fieldtype": "Dynamic Link",
"in_list_view": 1,
"label": "Party",
"options": "party_type",
"reqd": 1
},
{
"fieldname": "receivable_payable_account",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Receivable/Payable Account",
"options": "Account",
"reqd": 1
},
{
"fieldname": "filter_section",
"fieldtype": "Section Break",
"label": "Filters"
},
{
"fieldname": "from_invoice_date",
"fieldtype": "Date",
"label": "From Invoice Date"
},
{
"fieldname": "to_invoice_date",
"fieldtype": "Date",
"label": "To Invoice Date"
},
{
"fieldname": "column_break_kegk",
"fieldtype": "Column Break"
},
{
"fieldname": "from_payment_date",
"fieldtype": "Date",
"label": "From Payment Date"
},
{
"fieldname": "to_payment_date",
"fieldtype": "Date",
"label": "To Payment Date"
},
{
"fieldname": "column_break_uj04",
"fieldtype": "Column Break"
},
{
"fieldname": "cost_center",
"fieldtype": "Link",
"label": "Cost Center",
"options": "Cost Center"
},
{
"fieldname": "bank_cash_account",
"fieldtype": "Link",
"label": "Bank/Cash Account",
"options": "Account"
},
{
"fieldname": "section_break_2n02",
"fieldtype": "Section Break",
"label": "Status"
},
{
"depends_on": "eval:doc.error_log",
"fieldname": "error_log",
"fieldtype": "Long Text",
"label": "Error Log"
},
{
"fieldname": "amended_from",
"fieldtype": "Link",
"label": "Amended From",
"no_copy": 1,
"options": "Process Payment Reconciliation",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "section_break_a8yx",
"fieldtype": "Section Break"
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2023-04-21 17:19:30.912953",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Payment Reconciliation",
"naming_rule": "Expression",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"title_field": "company"
}

View File

@@ -0,0 +1,503 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe import _, qb
from frappe.model.document import Document
from frappe.utils import get_link_to_form
from frappe.utils.scheduler import is_scheduler_inactive
class ProcessPaymentReconciliation(Document):
def validate(self):
self.validate_receivable_payable_account()
self.validate_bank_cash_account()
def validate_receivable_payable_account(self):
if self.receivable_payable_account:
if self.company != frappe.db.get_value("Account", self.receivable_payable_account, "company"):
frappe.throw(
_("Receivable/Payable Account: {0} doesn't belong to company {1}").format(
frappe.bold(self.receivable_payable_account), frappe.bold(self.company)
)
)
def validate_bank_cash_account(self):
if self.bank_cash_account:
if self.company != frappe.db.get_value("Account", self.bank_cash_account, "company"):
frappe.throw(
_("Bank/Cash Account {0} doesn't belong to company {1}").format(
frappe.bold(self.bank_cash_account), frappe.bold(self.company)
)
)
def before_save(self):
self.status = ""
self.error_log = ""
def on_submit(self):
self.db_set("status", "Queued")
self.db_set("error_log", None)
def on_cancel(self):
self.db_set("status", "Cancelled")
log = frappe.db.get_value(
"Process Payment Reconciliation Log", filters={"process_pr": self.name}
)
if log:
frappe.db.set_value("Process Payment Reconciliation Log", log, "status", "Cancelled")
@frappe.whitelist()
def get_reconciled_count(docname: str | None = None) -> float:
current_status = {}
if docname:
reconcile_log = frappe.db.get_value(
"Process Payment Reconciliation Log", filters={"process_pr": docname}, fieldname="name"
)
if reconcile_log:
res = frappe.get_all(
"Process Payment Reconciliation Log",
filters={"name": reconcile_log},
fields=["reconciled_entries", "total_allocations"],
as_list=1,
)
current_status["processed"], current_status["total"] = res[0]
return current_status
def get_pr_instance(doc: str):
process_payment_reconciliation = frappe.get_doc("Process Payment Reconciliation", doc)
pr = frappe.get_doc("Payment Reconciliation")
fields = [
"company",
"party_type",
"party",
"receivable_payable_account",
"from_invoice_date",
"to_invoice_date",
"from_payment_date",
"to_payment_date",
]
d = {}
for field in fields:
d[field] = process_payment_reconciliation.get(field)
pr.update(d)
pr.invoice_limit = 1000
pr.payment_limit = 1000
return pr
def is_job_running(job_name: str) -> bool:
jobs = frappe.db.get_all("RQ Job", filters={"status": ["in", ["started", "queued"]]})
for x in jobs:
if x.job_name == job_name:
return True
return False
@frappe.whitelist()
def pause_job_for_doc(docname: str | None = None):
if docname:
frappe.db.set_value("Process Payment Reconciliation", docname, "status", "Paused")
log = frappe.db.get_value("Process Payment Reconciliation Log", filters={"process_pr": docname})
if log:
frappe.db.set_value("Process Payment Reconciliation Log", log, "status", "Paused")
@frappe.whitelist()
def trigger_job_for_doc(docname: str | None = None):
"""
Trigger background job
"""
if not docname:
return
if not frappe.db.get_single_value("Accounts Settings", "auto_reconcile_payments"):
frappe.throw(
_("Auto Reconciliation of Payments has been disabled. Enable it through {0}").format(
get_link_to_form("Accounts Settings", "Accounts Settings")
)
)
return
if not is_scheduler_inactive():
if frappe.db.get_value("Process Payment Reconciliation", docname, "status") == "Queued":
frappe.db.set_value("Process Payment Reconciliation", docname, "status", "Running")
job_name = f"start_processing_{docname}"
if not is_job_running(job_name):
job = frappe.enqueue(
method="erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.reconcile_based_on_filters",
queue="long",
is_async=True,
job_name=job_name,
enqueue_after_commit=True,
doc=docname,
)
elif frappe.db.get_value("Process Payment Reconciliation", docname, "status") == "Paused":
frappe.db.set_value("Process Payment Reconciliation", docname, "status", "Running")
log = frappe.db.get_value("Process Payment Reconciliation Log", filters={"process_pr": docname})
if log:
frappe.db.set_value("Process Payment Reconciliation Log", log, "status", "Running")
# Resume tasks for running doc
job_name = f"start_processing_{docname}"
if not is_job_running(job_name):
job = frappe.enqueue(
method="erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.reconcile_based_on_filters",
queue="long",
is_async=True,
job_name=job_name,
doc=docname,
)
else:
frappe.msgprint(_("Scheduler is Inactive. Can't trigger job now."))
def trigger_reconciliation_for_queued_docs():
"""
Will be called from Cron Job
Fetch queued docs and start reconciliation process for each one
"""
if not frappe.db.get_single_value("Accounts Settings", "auto_reconcile_payments"):
frappe.msgprint(
_("Auto Reconciliation of Payments has been disabled. Enable it through {0}").format(
get_link_to_form("Accounts Settings", "Accounts Settings")
)
)
return
if not is_scheduler_inactive():
# Get all queued documents
all_queued = frappe.db.get_all(
"Process Payment Reconciliation",
filters={"docstatus": 1, "status": "Queued"},
order_by="creation desc",
as_list=1,
)
docs_to_trigger = []
unique_filters = set()
queue_size = 5
fields = ["company", "party_type", "party", "receivable_payable_account"]
def get_filters_as_tuple(fields, doc):
filters = ()
for x in fields:
filters += tuple(doc.get(x))
return filters
for x in all_queued:
doc = frappe.get_doc("Process Payment Reconciliation", x)
filters = get_filters_as_tuple(fields, doc)
if filters not in unique_filters:
unique_filters.add(filters)
docs_to_trigger.append(doc.name)
if len(docs_to_trigger) == queue_size:
break
# trigger reconcilation process for queue_size unique filters
for doc in docs_to_trigger:
trigger_job_for_doc(doc)
else:
frappe.msgprint(_("Scheduler is Inactive. Can't trigger jobs now."))
def reconcile_based_on_filters(doc: None | str = None) -> None:
"""
Identify current state of document and execute next tasks in background
"""
if doc:
log = frappe.db.get_value("Process Payment Reconciliation Log", filters={"process_pr": doc})
if not log:
log = frappe.new_doc("Process Payment Reconciliation Log")
log.process_pr = doc
log.status = "Running"
log = log.save()
job_name = f"process_{doc}_fetch_and_allocate"
if not is_job_running(job_name):
job = frappe.enqueue(
method="erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.fetch_and_allocate",
queue="long",
timeout="3600",
is_async=True,
job_name=job_name,
enqueue_after_commit=True,
doc=doc,
)
else:
res = frappe.get_all(
"Process Payment Reconciliation Log",
filters={"name": log},
fields=["allocated", "reconciled"],
as_list=1,
)
allocated, reconciled = res[0]
if not allocated:
job_name = f"process__{doc}_fetch_and_allocate"
if not is_job_running(job_name):
job = frappe.enqueue(
method="erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.fetch_and_allocate",
queue="long",
timeout="3600",
is_async=True,
job_name=job_name,
enqueue_after_commit=True,
doc=doc,
)
elif not reconciled:
allocation = get_next_allocation(log)
if allocation:
reconcile_job_name = (
f"process_{doc}_reconcile_allocation_{allocation[0].idx}_{allocation[-1].idx}"
)
else:
reconcile_job_name = f"process_{doc}_reconcile"
if not is_job_running(reconcile_job_name):
job = frappe.enqueue(
method="erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.reconcile",
queue="long",
timeout="3600",
is_async=True,
job_name=reconcile_job_name,
enqueue_after_commit=True,
doc=doc,
)
elif reconciled:
frappe.db.set_value("Process Payment Reconciliation", doc, "status", "Completed")
def get_next_allocation(log: str) -> list:
if log:
allocations = []
next = frappe.db.get_all(
"Process Payment Reconciliation Log Allocations",
filters={"parent": log, "reconciled": 0},
fields=["reference_type", "reference_name"],
order_by="idx",
limit=1,
)
if next:
allocations = frappe.db.get_all(
"Process Payment Reconciliation Log Allocations",
filters={
"parent": log,
"reconciled": 0,
"reference_type": next[0].reference_type,
"reference_name": next[0].reference_name,
},
fields=["*"],
order_by="idx",
)
return allocations
return []
def fetch_and_allocate(doc: str) -> None:
"""
Fetch Invoices and Payments based on filters applied. FIFO ordering is used for allocation.
"""
if doc:
log = frappe.db.get_value("Process Payment Reconciliation Log", filters={"process_pr": doc})
if log:
if not frappe.db.get_value("Process Payment Reconciliation Log", log, "allocated"):
reconcile_log = frappe.get_doc("Process Payment Reconciliation Log", log)
pr = get_pr_instance(doc)
pr.get_unreconciled_entries()
if len(pr.invoices) > 0 and len(pr.payments) > 0:
invoices = [x.as_dict() for x in pr.invoices]
payments = [x.as_dict() for x in pr.payments]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
for x in pr.get("allocation"):
reconcile_log.append(
"allocations",
x.as_dict().update(
{
"parenttype": "Process Payment Reconciliation Log",
"parent": reconcile_log.name,
"name": None,
"reconciled": False,
}
),
)
reconcile_log.allocated = True
reconcile_log.total_allocations = len(reconcile_log.get("allocations"))
reconcile_log.reconciled_entries = 0
reconcile_log.save()
# generate reconcile job name
allocation = get_next_allocation(log)
if allocation:
reconcile_job_name = (
f"process_{doc}_reconcile_allocation_{allocation[0].idx}_{allocation[-1].idx}"
)
else:
reconcile_job_name = f"process_{doc}_reconcile"
if not is_job_running(reconcile_job_name):
job = frappe.enqueue(
method="erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.reconcile",
queue="long",
timeout="3600",
is_async=True,
job_name=reconcile_job_name,
enqueue_after_commit=True,
doc=doc,
)
def reconcile(doc: None | str = None) -> None:
if doc:
log = frappe.db.get_value("Process Payment Reconciliation Log", filters={"process_pr": doc})
if log:
res = frappe.get_all(
"Process Payment Reconciliation Log",
filters={"name": log},
fields=["reconciled_entries", "total_allocations"],
as_list=1,
limit=1,
)
reconciled_entries, total_allocations = res[0]
if reconciled_entries != total_allocations:
try:
# Fetch next allocation
allocations = get_next_allocation(log)
pr = get_pr_instance(doc)
# pass allocation to PR instance
for x in allocations:
pr.append("allocation", x)
# reconcile
pr.reconcile_allocations(skip_ref_details_update_for_pe=True)
# If Payment Entry, update details only for newly linked references
# This is for performance
if allocations[0].reference_type == "Payment Entry":
references = [(x.invoice_type, x.invoice_number) for x in allocations]
pe = frappe.get_doc(allocations[0].reference_type, allocations[0].reference_name)
pe.flags.ignore_validate_update_after_submit = True
pe.set_missing_ref_details(update_ref_details_only_for=references)
pe.save()
# Update reconciled flag
allocation_names = [x.name for x in allocations]
ppa = qb.DocType("Process Payment Reconciliation Log Allocations")
qb.update(ppa).set(ppa.reconciled, True).where(ppa.name.isin(allocation_names)).run()
# Update reconciled count
reconciled_count = frappe.db.count(
"Process Payment Reconciliation Log Allocations", filters={"parent": log, "reconciled": True}
)
frappe.db.set_value(
"Process Payment Reconciliation Log", log, "reconciled_entries", reconciled_count
)
except Exception as err:
# Update the parent doc about the exception
frappe.db.rollback()
traceback = frappe.get_traceback()
if traceback:
message = "Traceback: <br>" + traceback
frappe.db.set_value("Process Payment Reconciliation Log", log, "error_log", message)
frappe.db.set_value(
"Process Payment Reconciliation",
doc,
"error_log",
message,
)
if reconciled_entries and total_allocations and reconciled_entries < total_allocations:
frappe.db.set_value(
"Process Payment Reconciliation Log", log, "status", "Partially Reconciled"
)
frappe.db.set_value(
"Process Payment Reconciliation",
doc,
"status",
"Partially Reconciled",
)
else:
frappe.db.set_value("Process Payment Reconciliation Log", log, "status", "Failed")
frappe.db.set_value(
"Process Payment Reconciliation",
doc,
"status",
"Failed",
)
finally:
if reconciled_entries == total_allocations:
frappe.db.set_value("Process Payment Reconciliation Log", log, "status", "Reconciled")
frappe.db.set_value("Process Payment Reconciliation Log", log, "reconciled", True)
frappe.db.set_value("Process Payment Reconciliation", doc, "status", "Completed")
else:
if not (frappe.db.get_value("Process Payment Reconciliation", doc, "status") == "Paused"):
# trigger next batch in job
# generate reconcile job name
allocation = get_next_allocation(log)
if allocation:
reconcile_job_name = (
f"process_{doc}_reconcile_allocation_{allocation[0].idx}_{allocation[-1].idx}"
)
else:
reconcile_job_name = f"process_{doc}_reconcile"
if not is_job_running(reconcile_job_name):
job = frappe.enqueue(
method="erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.reconcile",
queue="long",
timeout="3600",
is_async=True,
job_name=reconcile_job_name,
enqueue_after_commit=True,
doc=doc,
)
else:
frappe.db.set_value("Process Payment Reconciliation Log", log, "status", "Reconciled")
frappe.db.set_value("Process Payment Reconciliation Log", log, "reconciled", True)
frappe.db.set_value("Process Payment Reconciliation", doc, "status", "Completed")
@frappe.whitelist()
def is_any_doc_running(for_filter: str | dict | None = None) -> str | None:
running_doc = None
if for_filter:
if type(for_filter) == str:
for_filter = frappe.json.loads(for_filter)
running_doc = frappe.db.get_value(
"Process Payment Reconciliation",
filters={
"docstatus": 1,
"status": ["in", ["Running", "Paused"]],
"company": for_filter.get("company"),
"party_type": for_filter.get("party_type"),
"party": for_filter.get("party"),
"receivable_payable_account": for_filter.get("receivable_payable_account"),
},
fieldname="name",
)
else:
running_doc = frappe.db.get_value(
"Process Payment Reconciliation", filters={"docstatus": 1, "status": "Running"}
)
return running_doc

View File

@@ -0,0 +1,15 @@
from frappe import _
def get_data():
return {
"fieldname": "process_pr",
"transactions": [
{
"label": _("Reconciliation Logs"),
"items": [
"Process Payment Reconciliation Log",
],
},
],
}

View File

@@ -0,0 +1,15 @@
frappe.listview_settings['Process Payment Reconciliation'] = {
add_fields: ["status"],
get_indicator: function(doc) {
let colors = {
'Queued': 'orange',
'Paused': 'orange',
'Completed': 'green',
'Partially Reconciled': 'orange',
'Running': 'blue',
'Failed': 'red',
};
let status = doc.status;
return [__(status), colors[status], 'status,=,'+status];
},
};

View File

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

View File

@@ -0,0 +1,17 @@
// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on("Process Payment Reconciliation Log", {
refresh(frm) {
if (['Completed', 'Running', 'Paused', 'Partially Reconciled'].find(x => x == frm.doc.status)) {
let progress = 0;
if (frm.doc.reconciled_entries != 0) {
progress = frm.doc.reconciled_entries / frm.doc.total_allocations * 100;
} else if(frm.doc.total_allocations == 0 && frm.doc.status == "Completed"){
progress = 100;
}
frm.dashboard.add_progress(__('Reconciliation Progress'), progress);
}
},
});

View File

@@ -0,0 +1,137 @@
{
"actions": [],
"autoname": "format:PPR-LOG-{##}",
"beta": 1,
"creation": "2023-03-13 15:00:09.149681",
"default_view": "List",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"process_pr",
"section_break_fvdw",
"status",
"tasks_section",
"allocated",
"reconciled",
"column_break_yhin",
"total_allocations",
"reconciled_entries",
"section_break_4ywv",
"error_log",
"allocations_section",
"allocations"
],
"fields": [
{
"fieldname": "allocations",
"fieldtype": "Table",
"label": "Allocations",
"options": "Process Payment Reconciliation Log Allocations",
"read_only": 1
},
{
"default": "0",
"description": "All allocations have been successfully reconciled",
"fieldname": "reconciled",
"fieldtype": "Check",
"label": "Reconciled",
"read_only": 1
},
{
"fieldname": "total_allocations",
"fieldtype": "Int",
"in_list_view": 1,
"label": "Total Allocations",
"read_only": 1
},
{
"default": "0",
"description": "Invoices and Payments have been Fetched and Allocated",
"fieldname": "allocated",
"fieldtype": "Check",
"label": "Allocated",
"read_only": 1
},
{
"fieldname": "reconciled_entries",
"fieldtype": "Int",
"in_list_view": 1,
"label": "Reconciled Entries",
"read_only": 1
},
{
"fieldname": "tasks_section",
"fieldtype": "Section Break",
"label": "Tasks"
},
{
"fieldname": "allocations_section",
"fieldtype": "Section Break",
"label": "Allocations"
},
{
"fieldname": "column_break_yhin",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_4ywv",
"fieldtype": "Section Break"
},
{
"depends_on": "eval:doc.error_log",
"fieldname": "error_log",
"fieldtype": "Long Text",
"label": "Reconciliation Error Log",
"read_only": 1
},
{
"fieldname": "process_pr",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Parent Document",
"options": "Process Payment Reconciliation",
"read_only": 1,
"reqd": 1
},
{
"fieldname": "section_break_fvdw",
"fieldtype": "Section Break",
"label": "Status"
},
{
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
"options": "Running\nPaused\nReconciled\nPartially Reconciled\nFailed\nCancelled",
"read_only": 1
}
],
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2023-04-21 17:36:26.642617",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Payment Reconciliation Log",
"naming_rule": "Expression",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"search_fields": "allocated, reconciled, total_allocations, reconciled_entries",
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@@ -0,0 +1,9 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class ProcessPaymentReconciliationLog(Document):
pass

View File

@@ -0,0 +1,15 @@
frappe.listview_settings['Process Payment Reconciliation Log'] = {
add_fields: ["status"],
get_indicator: function(doc) {
var colors = {
'Partially Reconciled': 'orange',
'Paused': 'orange',
'Reconciled': 'green',
'Failed': 'red',
'Cancelled': 'red',
'Running': 'blue',
};
let status = doc.status;
return [__(status), colors[status], "status,=,"+status];
},
};

View File

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

View File

@@ -0,0 +1,170 @@
{
"actions": [],
"creation": "2023-03-13 13:51:27.351463",
"default_view": "List",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"reference_type",
"reference_name",
"reference_row",
"column_break_3",
"invoice_type",
"invoice_number",
"section_break_6",
"allocated_amount",
"unreconciled_amount",
"column_break_8",
"amount",
"is_advance",
"section_break_5",
"difference_amount",
"column_break_7",
"difference_account",
"exchange_rate",
"currency",
"reconciled"
],
"fields": [
{
"fieldname": "reference_type",
"fieldtype": "Link",
"label": "Reference Type",
"options": "DocType",
"read_only": 1,
"reqd": 1
},
{
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"in_list_view": 1,
"label": "Reference Name",
"options": "reference_type",
"read_only": 1,
"reqd": 1
},
{
"fieldname": "reference_row",
"fieldtype": "Data",
"hidden": 1,
"label": "Reference Row",
"read_only": 1
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"fieldname": "invoice_type",
"fieldtype": "Link",
"label": "Invoice Type",
"options": "DocType",
"read_only": 1,
"reqd": 1
},
{
"fieldname": "invoice_number",
"fieldtype": "Dynamic Link",
"in_list_view": 1,
"label": "Invoice Number",
"options": "invoice_type",
"read_only": 1,
"reqd": 1
},
{
"fieldname": "section_break_6",
"fieldtype": "Section Break"
},
{
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Allocated Amount",
"options": "currency",
"reqd": 1
},
{
"fieldname": "unreconciled_amount",
"fieldtype": "Currency",
"hidden": 1,
"label": "Unreconciled Amount",
"options": "currency",
"read_only": 1
},
{
"fieldname": "column_break_8",
"fieldtype": "Column Break"
},
{
"fieldname": "amount",
"fieldtype": "Currency",
"hidden": 1,
"label": "Amount",
"options": "currency",
"read_only": 1
},
{
"fieldname": "is_advance",
"fieldtype": "Data",
"hidden": 1,
"label": "Is Advance",
"read_only": 1
},
{
"fieldname": "section_break_5",
"fieldtype": "Section Break"
},
{
"fieldname": "difference_amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Difference Amount",
"options": "Currency",
"read_only": 1
},
{
"fieldname": "column_break_7",
"fieldtype": "Column Break"
},
{
"fieldname": "difference_account",
"fieldtype": "Link",
"label": "Difference Account",
"options": "Account",
"read_only": 1
},
{
"fieldname": "exchange_rate",
"fieldtype": "Float",
"label": "Exchange Rate",
"read_only": 1
},
{
"fieldname": "currency",
"fieldtype": "Link",
"hidden": 1,
"label": "Currency",
"options": "Currency"
},
{
"default": "0",
"fieldname": "reconciled",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Reconciled"
}
],
"istable": 1,
"links": [],
"modified": "2023-03-20 21:05:43.121945",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Payment Reconciliation Log Allocations",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}

View File

@@ -0,0 +1,9 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class ProcessPaymentReconciliationLogAllocations(Document):
pass

View File

@@ -15,7 +15,12 @@
</div>
<h2 class="text-center">{{ _("STATEMENTS OF ACCOUNTS") }}</h2>
<div>
<h5 style="float: left;">{{ _("Customer: ") }} <b>{{filters.party_name[0] }}</b></h5>
{% if filters.party[0] == filters.party_name[0] %}
<h5 style="float: left;">{{ _("Customer: ") }} <b>{{ filters.party_name[0] }}</b></h5>
{% else %}
<h5 style="float: left;">{{ _("Customer: ") }} <b>{{ filters.party[0] }}</b></h5>
<h5 style="float: left; margin-left:15px">{{ _("Customer Name: ") }} <b>{{filters.party_name[0] }}</b></h5>
{% endif %}
<h5 style="float: right;">
{{ _("Date: ") }}
<b>{{ frappe.format(filters.from_date, 'Date')}}

View File

@@ -34,6 +34,8 @@
"terms_and_conditions",
"section_break_1",
"enable_auto_email",
"column_break_ocfq",
"sender",
"section_break_18",
"frequency",
"filter_duration",
@@ -284,10 +286,32 @@
"fieldtype": "Link",
"label": "Terms and Conditions",
"options": "Terms and Conditions"
},
{
"default": "1",
"fieldname": "include_break",
"fieldtype": "Check",
"label": "Page Break After Each SoA"
},
{
"default": "0",
"fieldname": "show_net_values_in_party_account",
"fieldtype": "Check",
"label": "Show Net Values in Party Account"
},
{
"fieldname": "sender",
"fieldtype": "Link",
"label": "Sender",
"options": "Email Account"
},
{
"fieldname": "column_break_ocfq",
"fieldtype": "Column Break"
}
],
"links": [],
"modified": "2021-09-06 21:00:45.732505",
"modified": "2023-04-26 12:46:43.645455",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",

View File

@@ -327,7 +327,7 @@ def send_emails(document_name, from_scheduler=False):
queue="short",
method=frappe.sendmail,
recipients=recipients,
sender=frappe.session.user,
sender=doc.sender or frappe.session.user,
cc=cc,
subject=subject,
message=message,

View File

@@ -27,7 +27,7 @@
},
{
"fieldname": "billing_email",
"fieldtype": "Read Only",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Billing Email"
},
@@ -41,7 +41,7 @@
],
"istable": 1,
"links": [],
"modified": "2023-03-13 00:12:34.508086",
"modified": "2023-04-26 13:02:41.964499",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts Customer",

View File

@@ -82,7 +82,11 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
if(doc.docstatus == 1 && doc.outstanding_amount != 0
&& !(doc.is_return && doc.return_against) && !doc.on_hold) {
this.frm.add_custom_button(__('Payment'), this.make_payment_entry, __('Create'));
this.frm.add_custom_button(
__('Payment'),
() => this.make_payment_entry(),
__('Create')
);
cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
}
@@ -299,7 +303,7 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
apply_tds(frm) {
var me = this;
me.frm.set_value("tax_withheld_vouchers", []);
if (!me.frm.doc.apply_tds) {
me.frm.set_value("tax_withholding_category", '');
me.frm.set_df_property("tax_withholding_category", "hidden", 1);

View File

@@ -89,6 +89,7 @@
"column_break8",
"grand_total",
"rounding_adjustment",
"use_company_roundoff_cost_center",
"rounded_total",
"in_words",
"total_advance",
@@ -118,6 +119,7 @@
"paid_amount",
"advances_section",
"allocate_advances_automatically",
"only_include_allocated_payments",
"get_advances",
"advances",
"advance_tax",
@@ -1367,6 +1369,7 @@
"options": "Warehouse",
"print_hide": 1,
"print_width": "50px",
"ignore_user_permissions": 1,
"width": "50px"
},
{
@@ -1550,17 +1553,30 @@
"fieldname": "named_place",
"fieldtype": "Data",
"label": "Named Place"
},
{
"default": "0",
"depends_on": "allocate_advances_automatically",
"description": "Advance payments allocated against orders will only be fetched",
"fieldname": "only_include_allocated_payments",
"fieldtype": "Check",
"label": "Only Include Allocated Payments"
},
{
"default": "0",
"fieldname": "use_company_roundoff_cost_center",
"fieldtype": "Check",
"label": "Use Company Default Round Off Cost Center"
}
],
"icon": "fa fa-file-text",
"idx": 204,
"is_submittable": 1,
"links": [],
"modified": "2023-01-28 19:18:56.586321",
"modified": "2023-04-29 12:57:50.832598",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
"name_case": "Title Case",
"naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [

View File

@@ -117,7 +117,7 @@ class PurchaseInvoice(BuyingController):
self.validate_expense_account()
self.set_against_expense_account()
self.validate_write_off_account()
self.validate_multiple_billing("Purchase Receipt", "pr_detail", "amount", "items")
self.validate_multiple_billing("Purchase Receipt", "pr_detail", "amount")
self.create_remarks()
self.set_status()
self.validate_purchase_receipt_if_update_stock()
@@ -232,7 +232,7 @@ class PurchaseInvoice(BuyingController):
)
if (
cint(frappe.db.get_single_value("Buying Settings", "maintain_same_rate"))
cint(frappe.get_cached_value("Buying Settings", "None", "maintain_same_rate"))
and not self.is_return
and not self.is_internal_supplier
):
@@ -581,6 +581,7 @@ class PurchaseInvoice(BuyingController):
self.make_supplier_gl_entry(gl_entries)
self.make_item_gl_entries(gl_entries)
self.make_precision_loss_gl_entry(gl_entries)
if self.check_asset_cwip_enabled():
self.get_asset_gl_entry(gl_entries)
@@ -975,6 +976,30 @@ class PurchaseInvoice(BuyingController):
item.item_tax_amount, item.precision("item_tax_amount")
)
def make_precision_loss_gl_entry(self, gl_entries):
round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
self.company, "Purchase Invoice", self.name, self.use_company_roundoff_cost_center
)
precision_loss = self.get("base_net_total") - flt(
self.get("net_total") * self.conversion_rate, self.precision("net_total")
)
if precision_loss:
gl_entries.append(
self.get_gl_dict(
{
"account": round_off_account,
"against": self.supplier,
"credit": precision_loss,
"cost_center": round_off_cost_center
if self.use_company_roundoff_cost_center
else self.cost_center or round_off_cost_center,
"remarks": _("Net total calculation precision loss"),
}
)
)
def get_asset_gl_entry(self, gl_entries):
arbnb_account = self.get_company_default("asset_received_but_not_billed")
eiiav_account = self.get_company_default("expenses_included_in_asset_valuation")
@@ -1363,7 +1388,7 @@ class PurchaseInvoice(BuyingController):
not self.is_internal_transfer() and self.rounding_adjustment and self.base_rounding_adjustment
):
round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
self.company, "Purchase Invoice", self.name
self.company, "Purchase Invoice", self.name, self.use_company_roundoff_cost_center
)
gl_entries.append(
@@ -1373,7 +1398,9 @@ class PurchaseInvoice(BuyingController):
"against": self.supplier,
"debit_in_account_currency": self.rounding_adjustment,
"debit": self.base_rounding_adjustment,
"cost_center": self.cost_center or round_off_cost_center,
"cost_center": round_off_cost_center
if self.use_company_roundoff_cost_center
else (self.cost_center or round_off_cost_center),
},
item=self,
)

View File

@@ -93,9 +93,12 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e
if (doc.docstatus == 1 && doc.outstanding_amount!=0
&& !(cint(doc.is_return) && doc.return_against)) {
cur_frm.add_custom_button(__('Payment'),
this.make_payment_entry, __('Create'));
cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
this.frm.add_custom_button(
__('Payment'),
() => this.make_payment_entry(),
__('Create')
);
this.frm.page.set_inner_btn_group_as_primary(__('Create'));
}
if(doc.docstatus==1 && !doc.is_return) {
@@ -331,6 +334,7 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e
}
make_inter_company_invoice() {
let me = this;
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_inter_company_purchase_invoice",
frm: me.frm

View File

@@ -79,6 +79,7 @@
"column_break5",
"grand_total",
"rounding_adjustment",
"use_company_roundoff_cost_center",
"rounded_total",
"in_words",
"total_advance",
@@ -120,6 +121,7 @@
"account_for_change_amount",
"advances_section",
"allocate_advances_automatically",
"only_include_allocated_payments",
"get_advances",
"advances",
"write_off_section",
@@ -2126,6 +2128,19 @@
"label": "Repost Required",
"no_copy": 1,
"read_only": 1
},
{
"depends_on": "allocate_advances_automatically",
"description": "Advance payments allocated against orders will only be fetched",
"fieldname": "only_include_allocated_payments",
"fieldtype": "Check",
"label": "Only Include Allocated Payments"
},
{
"default": "0",
"fieldname": "use_company_roundoff_cost_center",
"fieldtype": "Check",
"label": "Use Company default Cost Center for Round off"
}
],
"icon": "fa fa-file-text",
@@ -2138,7 +2153,7 @@
"link_fieldname": "consolidated_invoice"
}
],
"modified": "2023-03-13 11:43:15.883055",
"modified": "2023-04-28 14:15:59.901154",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -145,7 +145,7 @@ class SalesInvoice(SellingController):
self.set_against_income_account()
self.validate_time_sheets_are_submitted()
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount", "items")
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount")
if not self.is_return:
self.validate_serial_numbers()
else:
@@ -1179,7 +1179,12 @@ class SalesInvoice(SellingController):
if self.is_return:
fixed_asset_gl_entries = get_gl_entries_on_asset_regain(
asset, item.base_net_amount, item.finance_book, self.get("doctype"), self.get("name")
asset,
item.base_net_amount,
item.finance_book,
self.get("doctype"),
self.get("name"),
self.get("posting_date"),
)
asset.db_set("disposal_date", None)
@@ -1194,7 +1199,12 @@ class SalesInvoice(SellingController):
asset.reload()
fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(
asset, item.base_net_amount, item.finance_book, self.get("doctype"), self.get("name")
asset,
item.base_net_amount,
item.finance_book,
self.get("doctype"),
self.get("name"),
self.get("posting_date"),
)
asset.db_set("disposal_date", self.posting_date)
@@ -1450,7 +1460,7 @@ class SalesInvoice(SellingController):
and not self.is_internal_transfer()
):
round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
self.company, "Sales Invoice", self.name
self.company, "Sales Invoice", self.name, self.use_company_roundoff_cost_center
)
gl_entries.append(
@@ -1462,7 +1472,9 @@ class SalesInvoice(SellingController):
self.rounding_adjustment, self.precision("rounding_adjustment")
),
"credit": flt(self.base_rounding_adjustment, self.precision("base_rounding_adjustment")),
"cost_center": self.cost_center or round_off_cost_center,
"cost_center": round_off_cost_center
if self.use_company_roundoff_cost_center
else (self.cost_center or round_off_cost_center),
},
item=self,
)

View File

@@ -5,7 +5,7 @@
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import cint, getdate
from frappe.utils import cint, flt, getdate
class TaxWithholdingCategory(Document):
@@ -215,7 +215,7 @@ def get_tax_row_for_tds(tax_details, tax_amount):
}
def get_lower_deduction_certificate(tax_details, pan_no):
def get_lower_deduction_certificate(company, tax_details, pan_no):
ldc_name = frappe.db.get_value(
"Lower Deduction Certificate",
{
@@ -223,6 +223,7 @@ def get_lower_deduction_certificate(tax_details, pan_no):
"tax_withholding_category": tax_details.tax_withholding_category,
"valid_from": (">=", tax_details.from_date),
"valid_upto": ("<=", tax_details.to_date),
"company": company,
},
"name",
)
@@ -255,7 +256,7 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N
tax_amount = 0
if party_type == "Supplier":
ldc = get_lower_deduction_certificate(tax_details, pan_no)
ldc = get_lower_deduction_certificate(inv.company, tax_details, pan_no)
if tax_deducted:
net_total = inv.tax_withholding_net_total
if ldc:
@@ -301,7 +302,7 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"):
"docstatus": 1,
}
if not tax_details.get("consider_party_ledger_amount") and doctype != "Sales Invoice":
if doctype != "Sales Invoice":
filters.update(
{"apply_tds": 1, "tax_withholding_category": tax_details.get("tax_withholding_category")}
)
@@ -568,7 +569,12 @@ def get_tds_amount_from_ldc(ldc, parties, tax_details, posting_date, net_total):
tds_amount = 0
limit_consumed = frappe.db.get_value(
"Purchase Invoice",
{"supplier": ("in", parties), "apply_tds": 1, "docstatus": 1},
{
"supplier": ("in", parties),
"apply_tds": 1,
"docstatus": 1,
"posting_date": ("between", (ldc.valid_from, ldc.valid_upto)),
},
"sum(tax_withholding_net_total)",
)
@@ -583,10 +589,10 @@ def get_tds_amount_from_ldc(ldc, parties, tax_details, posting_date, net_total):
def get_ltds_amount(current_amount, deducted_amount, certificate_limit, rate, tax_details):
if current_amount < (certificate_limit - deducted_amount):
if certificate_limit - flt(deducted_amount) - flt(current_amount) >= 0:
return current_amount * rate / 100
else:
ltds_amount = certificate_limit - deducted_amount
ltds_amount = certificate_limit - flt(deducted_amount)
tds_amount = current_amount - ltds_amount
return ltds_amount * rate / 100 + tds_amount * tax_details.rate / 100
@@ -597,9 +603,9 @@ def is_valid_certificate(
):
valid = False
if (
getdate(valid_from) <= getdate(posting_date) <= getdate(valid_upto)
) and certificate_limit > deducted_amount:
available_amount = flt(certificate_limit) - flt(deducted_amount) - flt(current_amount)
if (getdate(valid_from) <= getdate(posting_date) <= getdate(valid_upto)) and available_amount > 0:
valid = True
return valid

View File

@@ -110,9 +110,9 @@ class TestTaxWithholdingCategory(unittest.TestCase):
invoices.append(pi1)
# Cumulative threshold is 30000
# Threshold calculation should be on both the invoices
# TDS should be applied only on 1000
self.assertEqual(pi1.taxes[0].tax_amount, 1000)
# Threshold calculation should be only on the Second invoice
# Second didn't breach, no TDS should be applied
self.assertEqual(pi1.taxes, [])
for d in reversed(invoices):
d.cancel()

View File

@@ -0,0 +1,41 @@
{
"creation": "2023-05-23 09:58:17.235916",
"docstatus": 0,
"doctype": "Form Tour",
"first_document": 0,
"idx": 0,
"include_name_field": 0,
"is_standard": 1,
"modified": "2023-05-23 13:10:56.227127",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
"owner": "Administrator",
"reference_doctype": "Sales Invoice",
"save_on_complete": 1,
"steps": [
{
"description": "Select a customer for whom this invoice is being prepared.",
"fieldname": "customer",
"fieldtype": "Link",
"has_next_condition": 1,
"is_table_field": 0,
"label": "Customer",
"next_step_condition": "eval: doc.customer",
"position": "Right",
"title": "Select Customer"
},
{
"child_doctype": "Sales Invoice Item",
"description": "Select item that you have sold along with quantity and rate.",
"fieldname": "items",
"fieldtype": "Table",
"has_next_condition": 0,
"is_table_field": 0,
"parent_fieldname": "items",
"position": "Top",
"title": "Select Item"
}
],
"title": "Sales Invoice"
}

View File

@@ -472,7 +472,9 @@ def update_accounting_dimensions(round_off_gle):
round_off_gle[dimension] = dimension_values.get(dimension)
def get_round_off_account_and_cost_center(company, voucher_type, voucher_no):
def get_round_off_account_and_cost_center(
company, voucher_type, voucher_no, use_company_default=False
):
round_off_account, round_off_cost_center = frappe.get_cached_value(
"Company", company, ["round_off_account", "round_off_cost_center"]
) or [None, None]
@@ -480,7 +482,7 @@ def get_round_off_account_and_cost_center(company, voucher_type, voucher_no):
meta = frappe.get_meta(voucher_type)
# Give first preference to parent cost center for round off GLE
if meta.has_field("cost_center"):
if not use_company_default and meta.has_field("cost_center"):
parent_cost_center = frappe.db.get_value(voucher_type, voucher_no, "cost_center")
if parent_cost_center:
round_off_cost_center = parent_cost_center

View File

@@ -2,6 +2,8 @@
# License: GNU General Public License v3. See license.txt
from typing import Optional
import frappe
from frappe import _, msgprint, scrub
from frappe.contacts.doctype.address.address import (
@@ -174,6 +176,9 @@ def _get_party_details(
party_type, party.name, "tax_withholding_category"
)
if not party_details.get("tax_category") and pos_profile:
party_details["tax_category"] = frappe.get_value("POS Profile", pos_profile, "tax_category")
return party_details
@@ -256,6 +261,8 @@ def set_address_details(
)
if doctype in TRANSACTION_TYPES:
# required to set correct region
frappe.flags.company = company
get_regional_address_details(party_details, doctype, company)
return party_address, shipping_address
@@ -642,12 +649,12 @@ def set_taxes(
else:
args.update(get_party_details(party, party_type))
if party_type in ("Customer", "Lead"):
if party_type in ("Customer", "Lead", "Prospect"):
args.update({"tax_type": "Sales"})
if party_type == "Lead":
if party_type in ["Lead", "Prospect"]:
args["customer"] = None
del args["lead"]
del args[frappe.scrub(party_type)]
else:
args.update({"tax_type": "Purchase"})
@@ -845,7 +852,7 @@ def get_dashboard_info(party_type, party, loyalty_program=None):
return company_wise_info
def get_party_shipping_address(doctype, name):
def get_party_shipping_address(doctype: str, name: str) -> Optional[str]:
"""
Returns an Address name (best guess) for the given doctype and name for which `address_type == 'Shipping'` is true.
and/or `is_shipping_address = 1`.
@@ -856,37 +863,41 @@ def get_party_shipping_address(doctype, name):
:param name: Party name
:return: String
"""
out = frappe.db.sql(
"SELECT dl.parent "
"from `tabDynamic Link` dl join `tabAddress` ta on dl.parent=ta.name "
"where "
"dl.link_doctype=%s "
"and dl.link_name=%s "
"and dl.parenttype='Address' "
"and ifnull(ta.disabled, 0) = 0 and"
"(ta.address_type='Shipping' or ta.is_shipping_address=1) "
"order by ta.is_shipping_address desc, ta.address_type desc limit 1",
(doctype, name),
shipping_addresses = frappe.get_all(
"Address",
filters=[
["Dynamic Link", "link_doctype", "=", doctype],
["Dynamic Link", "link_name", "=", name],
["disabled", "=", 0],
],
or_filters=[
["is_shipping_address", "=", 1],
["address_type", "=", "Shipping"],
],
pluck="name",
limit=1,
order_by="is_shipping_address DESC",
)
if out:
return out[0][0]
else:
return ""
return shipping_addresses[0] if shipping_addresses else None
def get_partywise_advanced_payment_amount(
party_type, posting_date=None, future_payment=0, company=None
party_type, posting_date=None, future_payment=0, company=None, party=None
):
cond = "1=1"
if posting_date:
if future_payment:
cond = "posting_date <= '{0}' OR DATE(creation) <= '{0}' " "".format(posting_date)
cond = "(posting_date <= '{0}' OR DATE(creation) <= '{0}')" "".format(posting_date)
else:
cond = "posting_date <= '{0}'".format(posting_date)
if company:
cond += "and company = {0}".format(frappe.db.escape(company))
if party:
cond += "and party = {0}".format(frappe.db.escape(party))
data = frappe.db.sql(
""" SELECT party, sum({0}) as amount
FROM `tabGL Entry`
@@ -898,36 +909,36 @@ def get_partywise_advanced_payment_amount(
),
party_type,
)
if data:
return frappe._dict(data)
def get_default_contact(doctype, name):
def get_default_contact(doctype: str, name: str) -> Optional[str]:
"""
Returns default contact for the given doctype and name.
Can be ordered by `contact_type` to either is_primary_contact or is_billing_contact.
Returns contact name only if there is a primary contact for given doctype and name.
Else returns None
:param doctype: Party Doctype
:param name: Party name
:return: String
"""
out = frappe.db.sql(
"""
SELECT dl.parent, c.is_primary_contact, c.is_billing_contact
FROM `tabDynamic Link` dl
INNER JOIN `tabContact` c ON c.name = dl.parent
WHERE
dl.link_doctype=%s AND
dl.link_name=%s AND
dl.parenttype = 'Contact'
ORDER BY is_primary_contact DESC, is_billing_contact DESC
""",
(doctype, name),
contacts = frappe.get_all(
"Contact",
filters=[
["Dynamic Link", "link_doctype", "=", doctype],
["Dynamic Link", "link_name", "=", name],
],
or_filters=[
["is_primary_contact", "=", 1],
["is_billing_contact", "=", 1],
],
pluck="name",
limit=1,
order_by="is_primary_contact DESC, is_billing_contact DESC",
)
if out:
try:
return out[0][0]
except Exception:
return None
else:
return None
return contacts[0] if contacts else None
def add_party_account(party_type, party, company, account):

View File

@@ -181,6 +181,16 @@ class ReceivablePayableReport(object):
return
key = (ple.against_voucher_type, ple.against_voucher_no, ple.party)
# If payment is made against credit note
# and credit note is made against a Sales Invoice
# then consider the payment against original sales invoice.
if ple.against_voucher_type in ("Sales Invoice", "Purchase Invoice"):
if ple.against_voucher_no in self.return_entries:
return_against = self.return_entries.get(ple.against_voucher_no)
if return_against:
key = (ple.against_voucher_type, return_against, ple.party)
row = self.voucher_balance.get(key)
if not row:
@@ -610,7 +620,7 @@ class ReceivablePayableReport(object):
def get_return_entries(self):
doctype = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice"
filters = {"is_return": 1, "docstatus": 1}
filters = {"is_return": 1, "docstatus": 1, "company": self.filters.company}
party_field = scrub(self.filters.party_type)
if self.filters.get(party_field):
filters.update({party_field: self.filters.get(party_field)})

View File

@@ -210,6 +210,67 @@ class TestAccountsReceivable(FrappeTestCase):
],
)
def test_payment_against_credit_note(self):
"""
Payment against credit/debit note should be considered against the parent invoice
"""
company = "_Test Company 2"
customer = "_Test Customer 2"
si1 = make_sales_invoice()
pe = get_payment_entry("Sales Invoice", si1.name, bank_account="Cash - _TC2")
pe.paid_from = "Debtors - _TC2"
pe.insert()
pe.submit()
cr_note = make_credit_note(si1.name)
si2 = make_sales_invoice()
# manually link cr_note with si2 using journal entry
je = frappe.new_doc("Journal Entry")
je.company = company
je.voucher_type = "Credit Note"
je.posting_date = today()
debit_account = "Debtors - _TC2"
debit_entry = {
"account": debit_account,
"party_type": "Customer",
"party": customer,
"debit": 100,
"debit_in_account_currency": 100,
"reference_type": cr_note.doctype,
"reference_name": cr_note.name,
"cost_center": "Main - _TC2",
}
credit_entry = {
"account": debit_account,
"party_type": "Customer",
"party": customer,
"credit": 100,
"credit_in_account_currency": 100,
"reference_type": si2.doctype,
"reference_name": si2.name,
"cost_center": "Main - _TC2",
}
je.append("accounts", debit_entry)
je.append("accounts", credit_entry)
je = je.save().submit()
filters = {
"company": company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
}
report = execute(filters)
self.assertEqual(report[1], [])
def make_sales_invoice(no_payment_schedule=False, do_not_submit=False):
frappe.set_user("Administrator")
@@ -256,7 +317,7 @@ def make_payment(docname):
def make_credit_note(docname):
create_sales_invoice(
credit_note = create_sales_invoice(
company="_Test Company 2",
customer="_Test Customer 2",
currency="EUR",
@@ -269,3 +330,5 @@ def make_credit_note(docname):
is_return=1,
return_against=docname,
)
return credit_note

View File

@@ -31,7 +31,6 @@ class AccountsReceivableSummary(ReceivablePayableReport):
def get_data(self, args):
self.data = []
self.receivables = ReceivablePayableReport(self.filters).run(args)[1]
self.get_party_total(args)
@@ -42,6 +41,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
self.filters.report_date,
self.filters.show_future_payments,
self.filters.company,
party=self.filters.get(scrub(self.party_type)),
)
or {}
)
@@ -74,6 +74,9 @@ class AccountsReceivableSummary(ReceivablePayableReport):
row.gl_balance = gl_balance_map.get(party)
row.diff = flt(row.outstanding) - flt(row.gl_balance)
if self.filters.show_future_payments:
row.remaining_balance = flt(row.outstanding) - flt(row.future_amount)
self.data.append(row)
def get_party_total(self, args):
@@ -106,6 +109,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
"range4": 0.0,
"range5": 0.0,
"total_due": 0.0,
"future_amount": 0.0,
"sales_person": [],
}
),
@@ -151,6 +155,10 @@ class AccountsReceivableSummary(ReceivablePayableReport):
self.setup_ageing_columns()
if self.filters.show_future_payments:
self.add_column(label=_("Future Payment Amount"), fieldname="future_amount")
self.add_column(label=_("Remaining Balance"), fieldname="remaining_balance")
if self.party_type == "Customer":
self.add_column(
label=_("Territory"), fieldname="territory", fieldtype="Link", options="Territory"

View File

@@ -25,6 +25,7 @@ def get_data(filters):
["posting_date", "<=", filters.get("to_date")],
["against_voucher_type", "=", "Asset"],
["account", "in", depreciation_accounts],
["is_cancelled", "=", 0],
]
if filters.get("asset"):

View File

@@ -114,28 +114,6 @@ def get_assets(filters):
sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
from (SELECT a.asset_category,
ifnull(sum(case when ds.schedule_date < %(from_date)s and (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then
ds.depreciation_amount
else
0
end), 0) as accumulated_depreciation_as_on_from_date,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s and ds.schedule_date <= a.disposal_date then
ds.depreciation_amount
else
0
end), 0) as depreciation_eliminated_during_the_period,
ifnull(sum(case when ds.schedule_date >= %(from_date)s and ds.schedule_date <= %(to_date)s
and (ifnull(a.disposal_date, 0) = 0 or ds.schedule_date <= a.disposal_date) then
ds.depreciation_amount
else
0
end), 0) as depreciation_amount_during_the_period
from `tabAsset` a, `tabDepreciation Schedule` ds
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and a.name = ds.parent and ifnull(ds.journal_entry, '') != ''
group by a.asset_category
union
SELECT a.asset_category,
ifnull(sum(case when gle.posting_date < %(from_date)s and (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then
gle.debit
else
@@ -160,7 +138,7 @@ def get_assets(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.calculate_depreciation=0 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)
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)
group by a.asset_category
union
SELECT a.asset_category,

View File

@@ -4,6 +4,7 @@
import frappe
from frappe import _
from frappe.query_builder.custom import ConstantColumn
from frappe.utils import getdate, nowdate
@@ -79,7 +80,7 @@ def get_entries(filters):
payment_entries = frappe.db.sql(
"""SELECT
"Payment Entry", name, posting_date, reference_no, clearance_date, party,
if(paid_from=%(account)s, paid_amount * -1, received_amount)
if(paid_from=%(account)s, ((paid_amount * -1) - total_taxes_and_charges) , received_amount)
FROM
`tabPayment Entry`
WHERE
@@ -91,4 +92,65 @@ def get_entries(filters):
as_list=1,
)
return sorted(journal_entries + payment_entries, key=lambda k: k[2] or getdate(nowdate()))
# Loan Disbursement
loan_disbursement = frappe.qb.DocType("Loan Disbursement")
query = (
frappe.qb.from_(loan_disbursement)
.select(
ConstantColumn("Loan Disbursement").as_("payment_document_type"),
loan_disbursement.name.as_("payment_entry"),
loan_disbursement.disbursement_date.as_("posting_date"),
loan_disbursement.reference_number.as_("cheque_no"),
loan_disbursement.clearance_date.as_("clearance_date"),
loan_disbursement.applicant.as_("against"),
-loan_disbursement.disbursed_amount.as_("amount"),
)
.where(loan_disbursement.docstatus == 1)
.where(loan_disbursement.disbursement_date >= filters["from_date"])
.where(loan_disbursement.disbursement_date <= filters["to_date"])
.where(loan_disbursement.disbursement_account == filters["account"])
.orderby(loan_disbursement.disbursement_date, order=frappe.qb.desc)
.orderby(loan_disbursement.name, order=frappe.qb.desc)
)
if filters.get("from_date"):
query = query.where(loan_disbursement.disbursement_date >= filters["from_date"])
if filters.get("to_date"):
query = query.where(loan_disbursement.disbursement_date <= filters["to_date"])
loan_disbursements = query.run(as_list=1)
# Loan Repayment
loan_repayment = frappe.qb.DocType("Loan Repayment")
query = (
frappe.qb.from_(loan_repayment)
.select(
ConstantColumn("Loan Repayment").as_("payment_document_type"),
loan_repayment.name.as_("payment_entry"),
loan_repayment.posting_date.as_("posting_date"),
loan_repayment.reference_number.as_("cheque_no"),
loan_repayment.clearance_date.as_("clearance_date"),
loan_repayment.applicant.as_("against"),
loan_repayment.amount_paid.as_("amount"),
)
.where(loan_repayment.docstatus == 1)
.where(loan_repayment.posting_date >= filters["from_date"])
.where(loan_repayment.posting_date <= filters["to_date"])
.where(loan_repayment.payment_account == filters["account"])
.orderby(loan_repayment.posting_date, order=frappe.qb.desc)
.orderby(loan_repayment.name, order=frappe.qb.desc)
)
if filters.get("from_date"):
query = query.where(loan_repayment.posting_date >= filters["from_date"])
if filters.get("to_date"):
query = query.where(loan_repayment.posting_date <= filters["to_date"])
loan_repayments = query.run(as_list=1)
return sorted(
journal_entries + payment_entries + loan_disbursements + loan_repayments,
key=lambda k: k[2] or getdate(nowdate()),
)

View File

@@ -492,11 +492,26 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
additional_conditions.append("cost_center in %(cost_center)s")
if filters.get("include_default_book_entries"):
additional_conditions.append(
"(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)"
)
if filters.get("finance_book"):
if filters.get("company_fb") and cstr(filters.get("finance_book")) != cstr(
filters.get("company_fb")
):
frappe.throw(
_("To use a different finance book, please uncheck 'Include Default Book Entries'")
)
else:
additional_conditions.append(
"(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)"
)
else:
additional_conditions.append("(finance_book in (%(company_fb)s, '') OR finance_book IS NULL)")
else:
additional_conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)")
if filters.get("finance_book"):
additional_conditions.append(
"(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)"
)
else:
additional_conditions.append("(finance_book in ('') OR finance_book IS NULL)")
if accounting_dimensions:
for dimension in accounting_dimensions:

View File

@@ -58,9 +58,8 @@ frappe.query_reports["General Ledger"] = {
{
"fieldname":"party_type",
"label": __("Party Type"),
"fieldtype": "Link",
"options": "Party Type",
"default": "",
"fieldtype": "Autocomplete",
options: Object.keys(frappe.boot.party_account_types),
on_change: function() {
frappe.query_report.set_filter_value('party', "");
}
@@ -177,7 +176,8 @@ frappe.query_reports["General Ledger"] = {
{
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"fieldtype": "Check"
"fieldtype": "Check",
"default": 1
},
{
"fieldname": "show_cancelled_entries",

View File

@@ -244,13 +244,23 @@ def get_conditions(filters):
if filters.get("project"):
conditions.append("project in %(project)s")
if filters.get("finance_book"):
if filters.get("include_default_book_entries"):
conditions.append(
"(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)"
)
if filters.get("include_default_book_entries"):
if filters.get("finance_book"):
if filters.get("company_fb") and cstr(filters.get("finance_book")) != cstr(
filters.get("company_fb")
):
frappe.throw(
_("To use a different finance book, please uncheck 'Include Default Book Entries'")
)
else:
conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)")
else:
conditions.append("finance_book in (%(finance_book)s)")
conditions.append("(finance_book in (%(company_fb)s, '') OR finance_book IS NULL)")
else:
if filters.get("finance_book"):
conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)")
else:
conditions.append("(finance_book in ('') OR finance_book IS NULL)")
if not filters.get("show_cancelled_entries"):
conditions.append("is_cancelled = 0")

View File

@@ -24,7 +24,6 @@ class TestGeneralLedger(FrappeTestCase):
"root_type": "Asset",
"report_type": "Balance Sheet",
"account_currency": "USD",
"inter_company_account": 0,
"parent_account": "Bank Accounts - _TC",
"account_type": "Bank",
"doctype": "Account",

View File

@@ -125,12 +125,14 @@ def get_revenue(data, period_list, include_in_gross=1):
data_to_be_removed = True
while data_to_be_removed:
revenue, data_to_be_removed = remove_parent_with_no_child(revenue, period_list)
revenue = adjust_account(revenue, period_list)
revenue, data_to_be_removed = remove_parent_with_no_child(revenue)
adjust_account_totals(revenue, period_list)
return copy.deepcopy(revenue)
def remove_parent_with_no_child(data, period_list):
def remove_parent_with_no_child(data):
data_to_be_removed = False
for parent in data:
if "is_group" in parent and parent.get("is_group") == 1:
@@ -147,16 +149,19 @@ def remove_parent_with_no_child(data, period_list):
return data, data_to_be_removed
def adjust_account(data, period_list, consolidated=False):
leaf_nodes = [item for item in data if item["is_group"] == 0]
def adjust_account_totals(data, period_list):
totals = {}
for node in leaf_nodes:
set_total(node, node["total"], data, totals)
for d in data:
for period in period_list:
key = period if consolidated else period.key
d["total"] = totals[d["account"]]
return data
for d in reversed(data):
if d.get("is_group"):
for period in period_list:
# reset totals for group accounts as totals set by get_data doesn't consider include_in_gross check
d[period.key] = sum(
item[period.key] for item in data if item.get("parent_account") == d.get("account")
)
else:
set_total(d, d["total"], data, totals)
d["total"] = totals[d["account"]]
def set_total(node, value, complete_list, totals):
@@ -191,6 +196,9 @@ def get_profit(
if profit_loss[key]:
has_value = True
if not profit_loss.get("total"):
profit_loss["total"] = 0
profit_loss["total"] += profit_loss[key]
if has_value:
return profit_loss
@@ -229,6 +237,9 @@ def get_net_profit(
if profit_loss[key]:
has_value = True
if not profit_loss.get("total"):
profit_loss["total"] = 0
profit_loss["total"] += profit_loss[key]
if has_value:
return profit_loss

View File

@@ -59,7 +59,7 @@ frappe.query_reports["Gross Profit"] = {
if (column.fieldname == "sales_invoice" && column.options == "Item" && data && data.indent == 0) {
column._options = "Sales Invoice";
} else {
column._options = "Item";
column._options = "";
}
value = default_formatter(value, row, column, data);

View File

@@ -1,6 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from collections import OrderedDict
import frappe
from frappe import _, qb, scrub
@@ -250,7 +251,7 @@ def get_columns(group_wise_columns, filters):
"label": _("Warehouse"),
"fieldname": "warehouse",
"fieldtype": "Link",
"options": "warehouse",
"options": "Warehouse",
"width": 100,
},
"qty": {"label": _("Qty"), "fieldname": "qty", "fieldtype": "Float", "width": 80},
@@ -305,7 +306,8 @@ def get_columns(group_wise_columns, filters):
"sales_person": {
"label": _("Sales Person"),
"fieldname": "sales_person",
"fieldtype": "Data",
"fieldtype": "Link",
"options": "Sales Person",
"width": 100,
},
"allocated_amount": {
@@ -326,14 +328,14 @@ def get_columns(group_wise_columns, filters):
"label": _("Customer Group"),
"fieldname": "customer_group",
"fieldtype": "Link",
"options": "customer",
"options": "Customer Group",
"width": 100,
},
"territory": {
"label": _("Territory"),
"fieldname": "territory",
"fieldtype": "Link",
"options": "territory",
"options": "Territory",
"width": 100,
},
"monthly": {
@@ -735,7 +737,7 @@ class GrossProfitGenerator(object):
def load_invoice_items(self):
conditions = ""
if self.filters.company:
conditions += " and company = %(company)s"
conditions += " and `tabSales Invoice`.company = %(company)s"
if self.filters.from_date:
conditions += " and posting_date >= %(from_date)s"
if self.filters.to_date:
@@ -848,30 +850,30 @@ class GrossProfitGenerator(object):
Turns list of Sales Invoice Items to a tree of Sales Invoices with their Items as children.
"""
parents = []
grouped = OrderedDict()
for row in self.si_list:
if row.parent not in parents:
parents.append(row.parent)
# initialize list with a header row for each new parent
grouped.setdefault(row.parent, [self.get_invoice_row(row)]).append(
row.update(
{"indent": 1.0, "parent_invoice": row.parent, "invoice_or_item": row.item_code}
) # descendant rows will have indent: 1.0 or greater
)
parents_index = 0
for index, row in enumerate(self.si_list):
if parents_index < len(parents) and row.parent == parents[parents_index]:
invoice = self.get_invoice_row(row)
self.si_list.insert(index, invoice)
parents_index += 1
# if item is a bundle, add it's components as seperate rows
if frappe.db.exists("Product Bundle", row.item_code):
bundled_items = self.get_bundle_items(row)
for x in bundled_items:
bundle_item = self.get_bundle_item_row(row, x)
grouped.get(row.parent).append(bundle_item)
else:
# skipping the bundle items rows
if not row.indent:
row.indent = 1.0
row.parent_invoice = row.parent
row.invoice_or_item = row.item_code
self.si_list.clear()
if frappe.db.exists("Product Bundle", row.item_code):
self.add_bundle_items(row, index)
for items in grouped.values():
self.si_list.extend(items)
def get_invoice_row(self, row):
# header row format
return frappe._dict(
{
"parent_invoice": "",
@@ -900,13 +902,6 @@ class GrossProfitGenerator(object):
}
)
def add_bundle_items(self, product_bundle, index):
bundle_items = self.get_bundle_items(product_bundle)
for i, item in enumerate(bundle_items):
bundle_item = self.get_bundle_item_row(product_bundle, item)
self.si_list.insert((index + i + 1), bundle_item)
def get_bundle_items(self, product_bundle):
return frappe.get_all(
"Product Bundle Item", filters={"parent": product_bundle.item_code}, fields=["item_code", "qty"]

View File

@@ -19,14 +19,19 @@ def execute(filters=None):
return _execute(filters)
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None):
def _execute(
filters=None,
additional_table_columns=None,
additional_query_columns=None,
additional_conditions=None,
):
if not filters:
filters = {}
columns = get_columns(additional_table_columns, filters)
company_currency = frappe.get_cached_value("Company", filters.get("company"), "default_currency")
item_list = get_items(filters, additional_query_columns)
item_list = get_items(filters, additional_query_columns, additional_conditions)
if item_list:
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency)
@@ -328,7 +333,7 @@ def get_columns(additional_table_columns, filters):
return columns
def get_conditions(filters):
def get_conditions(filters, additional_conditions=None):
conditions = ""
for opts in (
@@ -341,6 +346,9 @@ def get_conditions(filters):
if filters.get(opts[0]):
conditions += opts[1]
if additional_conditions:
conditions += additional_conditions
if filters.get("mode_of_payment"):
conditions += """ and exists(select name from `tabSales Invoice Payment`
where parent=`tabSales Invoice`.name
@@ -376,8 +384,8 @@ def get_group_by_conditions(filters, doctype):
return "ORDER BY `tab{0}`.{1}".format(doctype, frappe.scrub(filters.get("group_by")))
def get_items(filters, additional_query_columns):
conditions = get_conditions(filters)
def get_items(filters, additional_query_columns, additional_conditions=None):
conditions = get_conditions(filters, additional_conditions)
if additional_query_columns:
additional_query_columns = ", " + ", ".join(additional_query_columns)
@@ -391,8 +399,9 @@ def get_items(filters, additional_query_columns):
`tabSales Invoice`.posting_date, `tabSales Invoice`.debit_to,
`tabSales Invoice`.unrealized_profit_loss_account,
`tabSales Invoice`.is_internal_customer,
`tabSales Invoice`.project, `tabSales Invoice`.customer, `tabSales Invoice`.remarks,
`tabSales Invoice`.customer, `tabSales Invoice`.remarks,
`tabSales Invoice`.territory, `tabSales Invoice`.company, `tabSales Invoice`.base_net_total,
`tabSales Invoice Item`.project,
`tabSales Invoice Item`.item_code, `tabSales Invoice Item`.description,
`tabSales Invoice Item`.`item_name`, `tabSales Invoice Item`.`item_group`,
`tabSales Invoice Item`.sales_order, `tabSales Invoice Item`.delivery_note,

View File

@@ -37,6 +37,29 @@ function get_filters() {
});
}
},
{
"fieldname":"party_type",
"label": __("Party Type"),
"fieldtype": "Link",
"options": "Party Type",
"default": "",
on_change: function() {
frappe.query_report.set_filter_value('party', "");
}
},
{
"fieldname":"party",
"label": __("Party"),
"fieldtype": "MultiSelectList",
get_data: function(txt) {
if (!frappe.query_report.filters) return;
let party_type = frappe.query_report.get_filter_value('party_type');
if (!party_type) return;
return frappe.db.get_link_options(party_type, txt);
},
},
{
"fieldname":"voucher_no",
"label": __("Voucher No"),
@@ -49,6 +72,20 @@ function get_filters() {
"fieldtype": "Data",
"width": 100,
},
{
"fieldname":"include_account_currency",
"label": __("Include Account Currency"),
"fieldtype": "Check",
"width": 100,
},
{
"fieldname":"group_party",
"label": __("Group by Party"),
"fieldtype": "Check",
"width": 100,
},
]
return filters;

View File

@@ -17,34 +17,26 @@ class PaymentLedger(object):
self.ple = qb.DocType("Payment Ledger Entry")
def init_voucher_dict(self):
if self.voucher_amount:
s = set()
# build a set of unique vouchers
# for each ple, using group_by_key to create a key and assign it to +/- list
for ple in self.voucher_amount:
key = (ple.voucher_type, ple.voucher_no, ple.party)
s.add(key)
group_by_key = None
if not self.filters.group_party:
group_by_key = (ple.against_voucher_type, ple.against_voucher_no, ple.party)
else:
group_by_key = (ple.party_type, ple.party)
# for each unique vouchers, initialize +/- list
for key in s:
self.voucher_dict[key] = frappe._dict(increase=list(), decrease=list())
# for each ple, using against voucher and amount, assign it to +/- list
# group by against voucher
for ple in self.voucher_amount:
against_key = (ple.against_voucher_type, ple.against_voucher_no, ple.party)
target = None
if self.voucher_dict.get(against_key):
if ple.amount > 0:
target = self.voucher_dict.get(against_key).increase
else:
target = self.voucher_dict.get(against_key).decrease
if ple.amount > 0:
target = self.voucher_dict.setdefault(group_by_key, {}).setdefault("increase", [])
else:
target = self.voucher_dict.setdefault(group_by_key, {}).setdefault("decrease", [])
# this if condition will lose unassigned ple entries(against_voucher doc doesn't have ple)
# need to somehow include the stray entries as well.
if target is not None:
entry = frappe._dict(
company=ple.company,
posting_date=ple.posting_date,
account=ple.account,
party_type=ple.party_type,
party=ple.party,
@@ -66,10 +58,10 @@ class PaymentLedger(object):
for value in self.voucher_dict.values():
voucher_data = []
if value.increase != []:
voucher_data.extend(value.increase)
if value.decrease != []:
voucher_data.extend(value.decrease)
if value.get("increase"):
voucher_data.extend(value.get("increase"))
if value.get("decrease"):
voucher_data.extend(value.get("decrease"))
if voucher_data:
# balance row
@@ -117,6 +109,12 @@ class PaymentLedger(object):
if self.filters.against_voucher_no:
self.conditions.append(self.ple.against_voucher_no == self.filters.against_voucher_no)
if self.filters.party_type:
self.conditions.append(self.ple.party_type == self.filters.party_type)
if self.filters.party:
self.conditions.append(self.ple.party.isin(self.filters.party))
def get_data(self):
ple = self.ple
@@ -134,7 +132,13 @@ class PaymentLedger(object):
def get_columns(self):
options = None
self.columns.append(
dict(label=_("Company"), fieldname="company", fieldtype="data", options=options, width="100")
dict(
label=_("Posting Date"),
fieldname="posting_date",
fieldtype="Date",
options=options,
width="100",
)
)
self.columns.append(
@@ -160,7 +164,11 @@ class PaymentLedger(object):
)
self.columns.append(
dict(
label=_("Voucher No"), fieldname="voucher_no", fieldtype="data", options=options, width="100"
label=_("Voucher No"),
fieldname="voucher_no",
fieldtype="Dynamic Link",
options="voucher_type",
width="100",
)
)
self.columns.append(
@@ -176,8 +184,8 @@ class PaymentLedger(object):
dict(
label=_("Against Voucher No"),
fieldname="against_voucher_no",
fieldtype="data",
options=options,
fieldtype="Dynamic Link",
options="against_voucher_type",
width="100",
)
)
@@ -209,7 +217,7 @@ class PaymentLedger(object):
self.get_columns()
self.get_data()
# initialize dictionary and group using against voucher
# initialize dictionary and group using key
self.init_voucher_dict()
# convert dictionary to list and add balance rows

View File

@@ -4,7 +4,6 @@
import frappe
from frappe import _
from frappe.utils import flt
def execute(filters=None):
@@ -66,12 +65,6 @@ def get_result(
else:
total_amount_credited += entry.credit
## Check if ldc is applied and show rate as per ldc
actual_rate = (tds_deducted / total_amount_credited) * 100
if flt(actual_rate) < flt(rate):
rate = actual_rate
if tds_deducted:
row = {
"pan"

View File

@@ -157,12 +157,25 @@ def get_rootwise_opening_balances(filters, report_type):
if filters.project:
additional_conditions += " and project = %(project)s"
company_fb = frappe.db.get_value("Company", filters.company, "default_finance_book")
if filters.get("include_default_book_entries"):
additional_conditions += (
" AND (finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)"
)
if filters.get("finance_book"):
if company_fb and cstr(filters.get("finance_book")) != cstr(company_fb):
frappe.throw(
_("To use a different finance book, please uncheck 'Include Default Book Entries'")
)
else:
additional_conditions += (
" AND (finance_book in (%(finance_book)s, '') OR finance_book IS NULL)"
)
else:
additional_conditions += " AND (finance_book in (%(company_fb)s, '') OR finance_book IS NULL)"
else:
additional_conditions += " AND (finance_book in (%(finance_book)s, '') OR finance_book IS NULL)"
if filters.get("finance_book"):
additional_conditions += " AND (finance_book in (%(finance_book)s, '') OR finance_book IS NULL)"
else:
additional_conditions += " AND (finance_book in ('') OR finance_book IS NULL)"
accounting_dimensions = get_accounting_dimensions(as_list=False)
@@ -174,7 +187,7 @@ def get_rootwise_opening_balances(filters, report_type):
"year_start_date": filters.year_start_date,
"project": filters.project,
"finance_book": filters.finance_book,
"company_fb": frappe.db.get_value("Company", filters.company, "default_finance_book"),
"company_fb": company_fb,
}
if accounting_dimensions:

View File

@@ -420,7 +420,7 @@ def add_cc(args=None):
return cc.name
def reconcile_against_document(args): # nosemgrep
def reconcile_against_document(args, skip_ref_details_update_for_pe=False): # nosemgrep
"""
Cancel PE or JV, Update against document, split if required and resubmit
"""
@@ -449,13 +449,9 @@ def reconcile_against_document(args): # nosemgrep
if voucher_type == "Journal Entry":
update_reference_in_journal_entry(entry, doc, do_not_save=True)
else:
update_reference_in_payment_entry(entry, doc, do_not_save=True)
if doc.doctype == "Journal Entry":
try:
doc.validate_total_debit_and_credit()
except Exception as validation_exception:
raise frappe.ValidationError(_(f"Validation Error for {doc.name}")) from validation_exception
update_reference_in_payment_entry(
entry, doc, do_not_save=True, skip_ref_details_update_for_pe=skip_ref_details_update_for_pe
)
doc.save(ignore_permissions=True)
# re-submit advance entry
@@ -592,7 +588,9 @@ def update_reference_in_journal_entry(d, journal_entry, do_not_save=False):
journal_entry.save(ignore_permissions=True)
def update_reference_in_payment_entry(d, payment_entry, do_not_save=False):
def update_reference_in_payment_entry(
d, payment_entry, do_not_save=False, skip_ref_details_update_for_pe=False
):
reference_details = {
"reference_doctype": d.against_voucher_type,
"reference_name": d.against_voucher,
@@ -638,6 +636,13 @@ def update_reference_in_payment_entry(d, payment_entry, do_not_save=False):
payment_entry.set_gain_or_loss(account_details=account_details)
payment_entry.flags.ignore_validate_update_after_submit = True
payment_entry.setup_party_account_field()
payment_entry.set_missing_values()
if not skip_ref_details_update_for_pe:
payment_entry.set_missing_ref_details()
payment_entry.set_amounts()
if not do_not_save:
payment_entry.save(ignore_permissions=True)
@@ -1358,10 +1363,7 @@ def get_stock_and_account_balance(account=None, posting_date=None, company=None)
if wh_details.account == account and not wh_details.is_group
]
total_stock_value = 0.0
for warehouse in related_warehouses:
value = get_stock_value_on(warehouse, posting_date)
total_stock_value += value
total_stock_value = get_stock_value_on(related_warehouses, posting_date)
precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency")
return flt(account_balance, precision), flt(total_stock_value, precision), related_warehouses

View File

@@ -5,8 +5,9 @@
"label": "Profit and Loss"
}
],
"content": "[{\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Accounts\",\"col\":12}},{\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Chart of Accounts\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Purchase Invoice\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Receivable\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"General Ledger\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Trial Balance\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Accounting Masters\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"General Ledger\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Receivable\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Payable\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Financial Statements\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Multi Currency\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Bank Statement\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Subscription Management\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Share Management\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Cost Center and Budgeting\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Opening and Closing\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Taxes\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Profitability\",\"col\":4}}]",
"content": "[{\"id\":\"MmUf9abwxg\",\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Accounts\",\"col\":12}},{\"id\":\"i0EtSjDAXq\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"id\":\"X78jcbq1u3\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"vikWSkNm6_\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"id\":\"pMywM0nhlj\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Chart of Accounts\",\"col\":3}},{\"id\":\"_pRdD6kqUG\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":3}},{\"id\":\"G984SgVRJN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Purchase Invoice\",\"col\":3}},{\"id\":\"1ArNvt9qhz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"id\":\"F9f4I1viNr\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"id\":\"4IBBOIxfqW\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Receivable\",\"col\":3}},{\"id\":\"El2anpPaFY\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"General Ledger\",\"col\":3}},{\"id\":\"1nwcM9upJo\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Trial Balance\",\"col\":3}},{\"id\":\"OF9WOi1Ppc\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"id\":\"B7-uxs8tkU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"tHb3yxthkR\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"DnNtsmxpty\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounting Masters\",\"col\":4}},{\"id\":\"nKKr6fjgjb\",\"type\":\"card\",\"data\":{\"card_name\":\"General Ledger\",\"col\":4}},{\"id\":\"xOHTyD8b5l\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Receivable\",\"col\":4}},{\"id\":\"_Cb7C8XdJJ\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Payable\",\"col\":4}},{\"id\":\"p7NY6MHe2Y\",\"type\":\"card\",\"data\":{\"card_name\":\"Financial Statements\",\"col\":4}},{\"id\":\"KlqilF5R_V\",\"type\":\"card\",\"data\":{\"card_name\":\"Taxes\",\"col\":4}},{\"id\":\"jTUy8LB0uw\",\"type\":\"card\",\"data\":{\"card_name\":\"Cost Center and Budgeting\",\"col\":4}},{\"id\":\"Wn2lhs7WLn\",\"type\":\"card\",\"data\":{\"card_name\":\"Multi Currency\",\"col\":4}},{\"id\":\"PAQMqqNkBM\",\"type\":\"card\",\"data\":{\"card_name\":\"Bank Statement\",\"col\":4}},{\"id\":\"Q_hBCnSeJY\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"id\":\"3AK1Zf0oew\",\"type\":\"card\",\"data\":{\"card_name\":\"Profitability\",\"col\":4}},{\"id\":\"kxhoaiqdLq\",\"type\":\"card\",\"data\":{\"card_name\":\"Opening and Closing\",\"col\":4}},{\"id\":\"q0MAlU2j_Z\",\"type\":\"card\",\"data\":{\"card_name\":\"Subscription Management\",\"col\":4}},{\"id\":\"ptm7T6Hwu-\",\"type\":\"card\",\"data\":{\"card_name\":\"Share Management\",\"col\":4}},{\"id\":\"OX7lZHbiTr\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
"creation": "2020-03-02 15:41:59.515192",
"custom_blocks": [],
"docstatus": 0,
"doctype": "Workspace",
"for_user": "",
@@ -1093,10 +1094,11 @@
"type": "Link"
}
],
"modified": "2022-06-24 05:41:09.236458",
"modified": "2023-05-30 13:23:29.316711",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting",
"number_cards": [],
"owner": "Administrator",
"parent_page": "",
"public": 1,

View File

@@ -469,6 +469,9 @@ frappe.ui.form.on('Asset', {
} else {
frm.set_value('purchase_date', purchase_doc.posting_date);
}
if (!frm.doc.is_existing_asset && !frm.doc.available_for_use_date) {
frm.set_value('available_for_use_date', frm.doc.purchase_date);
}
const item = purchase_doc.items.find(item => item.item_code === frm.doc.item_code);
if (!item) {
doctype_field = frappe.scrub(doctype)

View File

@@ -81,6 +81,9 @@
"options": "ACC-ASS-.YYYY.-"
},
{
"depends_on": "item_code",
"fetch_from": "item_code.item_name",
"fetch_if_empty": 1,
"fieldname": "asset_name",
"fieldtype": "Data",
"in_list_view": 1,
@@ -527,7 +530,7 @@
"table_fieldname": "accounts"
}
],
"modified": "2023-01-25 17:45:48.649543",
"modified": "2023-03-30 15:07:41.542374",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",
@@ -571,4 +574,4 @@
"states": [],
"title_field": "asset_name",
"track_changes": 1
}
}

View File

@@ -26,6 +26,7 @@ from erpnext.accounts.general_ledger import make_reverse_gl_entries
from erpnext.assets.doctype.asset.depreciation import (
get_depreciation_accounts,
get_disposal_account_and_cost_center,
is_first_day_of_the_month,
is_last_day_of_the_month,
)
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
@@ -294,17 +295,42 @@ class Asset(AccountsController):
if has_pro_rata:
number_of_pending_depreciations += 1
has_wdv_or_dd_non_yearly_pro_rata = False
if (
finance_book.depreciation_method in ("Written Down Value", "Double Declining Balance")
and cint(finance_book.frequency_of_depreciation) != 12
):
has_wdv_or_dd_non_yearly_pro_rata = self.check_is_pro_rata(
finance_book, wdv_or_dd_non_yearly=True
)
skip_row = False
should_get_last_day = is_last_day_of_the_month(finance_book.depreciation_start_date)
depreciation_amount = 0
for n in range(start[finance_book.idx - 1], number_of_pending_depreciations):
# If depreciation is already completed (for double declining balance)
if skip_row:
continue
depreciation_amount = get_depreciation_amount(self, value_after_depreciation, finance_book)
if n > 0 and len(self.get("schedules")) > n - 1:
prev_depreciation_amount = self.get("schedules")[n - 1].depreciation_amount
else:
prev_depreciation_amount = 0
if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1:
depreciation_amount = get_depreciation_amount(
self,
value_after_depreciation,
finance_book,
n,
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
)
if not has_pro_rata or (
n < (cint(number_of_pending_depreciations) - 1) or number_of_pending_depreciations == 2
):
schedule_date = add_months(
finance_book.depreciation_start_date, n * cint(finance_book.frequency_of_depreciation)
)
@@ -312,15 +338,14 @@ class Asset(AccountsController):
if should_get_last_day:
schedule_date = get_last_day(schedule_date)
# schedule date will be a year later from start date
# so monthly schedule date is calculated by removing 11 months from it
monthly_schedule_date = add_months(schedule_date, -finance_book.frequency_of_depreciation + 1)
# if asset is being sold
if date_of_disposal:
from_date = self.get_from_date(finance_book.finance_book)
from_date = self.get_from_date_for_disposal(finance_book)
depreciation_amount, days, months = self.get_pro_rata_amt(
finance_book, depreciation_amount, from_date, date_of_disposal
finance_book,
depreciation_amount,
from_date,
date_of_disposal,
)
if depreciation_amount > 0:
@@ -335,17 +360,41 @@ class Asset(AccountsController):
break
# For first row
if has_pro_rata and not self.opening_accumulated_depreciation and n == 0:
if (
n == 0
and (has_pro_rata or has_wdv_or_dd_non_yearly_pro_rata)
and not self.opening_accumulated_depreciation
):
from_date = add_days(
self.available_for_use_date, -1
) # needed to calc depr amount for available_for_use_date too
depreciation_amount, days, months = self.get_pro_rata_amt(
finance_book, depreciation_amount, from_date, finance_book.depreciation_start_date
finance_book,
depreciation_amount,
from_date,
finance_book.depreciation_start_date,
has_wdv_or_dd_non_yearly_pro_rata,
)
elif n == 0 and has_wdv_or_dd_non_yearly_pro_rata and self.opening_accumulated_depreciation:
if not is_first_day_of_the_month(getdate(self.available_for_use_date)):
from_date = get_last_day(
add_months(
getdate(self.available_for_use_date),
((self.number_of_depreciations_booked - 1) * finance_book.frequency_of_depreciation),
)
)
else:
from_date = add_months(
getdate(add_days(self.available_for_use_date, -1)),
(self.number_of_depreciations_booked * finance_book.frequency_of_depreciation),
)
depreciation_amount, days, months = self.get_pro_rata_amt(
finance_book,
depreciation_amount,
from_date,
finance_book.depreciation_start_date,
has_wdv_or_dd_non_yearly_pro_rata,
)
# For first depr schedule date will be the start date
# so monthly schedule date is calculated by removing month difference between use date and start date
monthly_schedule_date = add_months(finance_book.depreciation_start_date, -months + 1)
# For last row
elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1:
@@ -359,40 +408,35 @@ class Asset(AccountsController):
depreciation_amount_without_pro_rata = depreciation_amount
depreciation_amount, days, months = self.get_pro_rata_amt(
finance_book, depreciation_amount, schedule_date, self.to_date
finance_book,
depreciation_amount,
schedule_date,
self.to_date,
has_wdv_or_dd_non_yearly_pro_rata,
)
depreciation_amount = self.get_adjusted_depreciation_amount(
depreciation_amount_without_pro_rata, depreciation_amount, finance_book.finance_book
)
monthly_schedule_date = add_months(schedule_date, 1)
schedule_date = add_days(schedule_date, days)
last_schedule_date = schedule_date
if not depreciation_amount:
continue
value_after_depreciation -= flt(depreciation_amount, self.precision("gross_purchase_amount"))
# Adjust depreciation amount in the last period based on the expected value after useful life
if (
finance_book.expected_value_after_useful_life
and (
(
n == cint(number_of_pending_depreciations) - 1
and value_after_depreciation != finance_book.expected_value_after_useful_life
)
or value_after_depreciation < finance_book.expected_value_after_useful_life
)
and (
not self.flags.increase_in_asset_value_due_to_repair
or not finance_book.depreciation_method in ("Written Down Value", "Double Declining Balance")
if finance_book.expected_value_after_useful_life and (
(
n == cint(number_of_pending_depreciations) - 1
and value_after_depreciation != finance_book.expected_value_after_useful_life
)
or value_after_depreciation < finance_book.expected_value_after_useful_life
):
depreciation_amount += value_after_depreciation - finance_book.expected_value_after_useful_life
skip_row = True
if depreciation_amount > 0:
if flt(depreciation_amount, self.precision("gross_purchase_amount")) > 0:
self._add_depreciation_row(
schedule_date,
depreciation_amount,
@@ -467,16 +511,19 @@ class Asset(AccountsController):
return start
def get_from_date(self, finance_book):
def get_from_date_for_disposal(self, finance_book):
if not self.get("schedules"):
return self.available_for_use_date
return add_months(
getdate(self.available_for_use_date),
(self.number_of_depreciations_booked * finance_book.frequency_of_depreciation),
)
if len(self.finance_books) == 1:
return self.schedules[-1].schedule_date
from_date = ""
for schedule in self.get("schedules"):
if schedule.finance_book == finance_book:
if schedule.finance_book == finance_book.finance_book:
from_date = schedule.schedule_date
if from_date:
@@ -486,28 +533,37 @@ class Asset(AccountsController):
return add_days(self.available_for_use_date, -1)
# if it returns True, depreciation_amount will not be equal for the first and last rows
def check_is_pro_rata(self, row):
def check_is_pro_rata(self, row, wdv_or_dd_non_yearly=False):
has_pro_rata = False
# if not existing asset, from_date = available_for_use_date
# otherwise, if number_of_depreciations_booked = 2, available_for_use_date = 01/01/2020 and frequency_of_depreciation = 12
# from_date = 01/01/2022
from_date = self.get_modified_available_for_use_date(row)
from_date = self.get_modified_available_for_use_date(row, wdv_or_dd_non_yearly)
days = date_diff(row.depreciation_start_date, from_date) + 1
# if frequency_of_depreciation is 12 months, total_days = 365
total_days = get_total_days(row.depreciation_start_date, row.frequency_of_depreciation)
if wdv_or_dd_non_yearly:
total_days = get_total_days(row.depreciation_start_date, 12)
else:
# if frequency_of_depreciation is 12 months, total_days = 365
total_days = get_total_days(row.depreciation_start_date, row.frequency_of_depreciation)
if days < total_days:
has_pro_rata = True
return has_pro_rata
def get_modified_available_for_use_date(self, row):
return add_months(
self.available_for_use_date,
(self.number_of_depreciations_booked * row.frequency_of_depreciation),
)
def get_modified_available_for_use_date(self, row, wdv_or_dd_non_yearly=False):
if wdv_or_dd_non_yearly:
return add_months(
self.available_for_use_date,
(self.number_of_depreciations_booked * 12),
)
else:
return add_months(
self.available_for_use_date,
(self.number_of_depreciations_booked * row.frequency_of_depreciation),
)
def validate_asset_finance_books(self, row):
if flt(row.expected_value_after_useful_life) >= flt(self.gross_purchase_amount):
@@ -910,20 +966,51 @@ class Asset(AccountsController):
float_precision = cint(frappe.db.get_default("float_precision")) or 2
if args.get("depreciation_method") == "Double Declining Balance":
return 200.0 / args.get("total_number_of_depreciations")
return 200.0 / (
(
flt(args.get("total_number_of_depreciations"), 2) * flt(args.get("frequency_of_depreciation"))
)
/ 12
)
if args.get("depreciation_method") == "Written Down Value":
if args.get("rate_of_depreciation") and on_validate:
if (
args.get("rate_of_depreciation")
and on_validate
and not self.flags.increase_in_asset_value_due_to_repair
):
return args.get("rate_of_depreciation")
value = flt(args.get("expected_value_after_useful_life")) / flt(self.gross_purchase_amount)
depreciation_rate = math.pow(value, 1.0 / flt(args.get("total_number_of_depreciations"), 2))
if self.flags.increase_in_asset_value_due_to_repair:
value = flt(args.get("expected_value_after_useful_life")) / flt(
args.get("value_after_depreciation")
)
else:
value = flt(args.get("expected_value_after_useful_life")) / flt(self.gross_purchase_amount)
depreciation_rate = math.pow(
value,
1.0
/ (
(
flt(args.get("total_number_of_depreciations"), 2)
* flt(args.get("frequency_of_depreciation"))
)
/ 12
),
)
return flt((100 * (1 - depreciation_rate)), float_precision)
def get_pro_rata_amt(self, row, depreciation_amount, from_date, to_date):
def get_pro_rata_amt(
self, row, depreciation_amount, from_date, to_date, has_wdv_or_dd_non_yearly_pro_rata=False
):
days = date_diff(to_date, from_date)
months = month_diff(to_date, from_date)
total_days = get_total_days(to_date, row.frequency_of_depreciation)
if has_wdv_or_dd_non_yearly_pro_rata:
total_days = get_total_days(to_date, 12)
else:
total_days = get_total_days(to_date, row.frequency_of_depreciation)
return (depreciation_amount * flt(days)) / flt(total_days), days, months
@@ -1180,27 +1267,74 @@ def get_total_days(date, frequency):
@erpnext.allow_regional
def get_depreciation_amount(asset, depreciable_value, row):
def get_depreciation_amount(
asset,
depreciable_value,
row,
schedule_idx=0,
prev_depreciation_amount=0,
has_wdv_or_dd_non_yearly_pro_rata=False,
):
if row.depreciation_method in ("Straight Line", "Manual"):
# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset life and value
if asset.flags.increase_in_asset_life:
depreciation_amount = (
flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
) / (date_diff(asset.to_date, asset.available_for_use_date) / 365)
# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset value
elif asset.flags.increase_in_asset_value_due_to_repair:
depreciation_amount = (
flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
) / flt(row.total_number_of_depreciations)
# if the Depreciation Schedule is being prepared for the first time
else:
depreciation_amount = (
flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
) / flt(row.total_number_of_depreciations)
return get_straight_line_or_manual_depr_amount(asset, row)
else:
depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100))
return get_wdv_or_dd_depr_amount(
depreciable_value,
row.rate_of_depreciation,
row.frequency_of_depreciation,
schedule_idx,
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
)
return depreciation_amount
def get_straight_line_or_manual_depr_amount(asset, row):
# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset life and value
if asset.flags.increase_in_asset_life:
return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / (
date_diff(asset.to_date, asset.available_for_use_date) / 365
)
# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset value
elif asset.flags.increase_in_asset_value_due_to_repair:
return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / flt(
row.total_number_of_depreciations
)
# if the Depreciation Schedule is being prepared for the first time
else:
return (
flt(asset.gross_purchase_amount)
- flt(asset.opening_accumulated_depreciation)
- flt(row.expected_value_after_useful_life)
) / flt(row.total_number_of_depreciations - asset.number_of_depreciations_booked)
def get_wdv_or_dd_depr_amount(
depreciable_value,
rate_of_depreciation,
frequency_of_depreciation,
schedule_idx,
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
):
if cint(frequency_of_depreciation) == 12:
return flt(depreciable_value) * (flt(rate_of_depreciation) / 100)
else:
if has_wdv_or_dd_non_yearly_pro_rata:
if schedule_idx == 0:
return flt(depreciable_value) * (flt(rate_of_depreciation) / 100)
elif schedule_idx % (12 / cint(frequency_of_depreciation)) == 1:
return (
flt(depreciable_value) * flt(frequency_of_depreciation) * (flt(rate_of_depreciation) / 1200)
)
else:
return prev_depreciation_amount
else:
if schedule_idx % (12 / cint(frequency_of_depreciation)) == 0:
return (
flt(depreciable_value) * flt(frequency_of_depreciation) * (flt(rate_of_depreciation) / 1200)
)
else:
return prev_depreciation_amount
@frappe.whitelist()

View File

@@ -36,7 +36,7 @@ frappe.listview_settings['Asset'] = {
}
},
onload: function(me) {
me.page.add_action_item('Make Asset Movement', function() {
me.page.add_action_item(__("Make Asset Movement"), function() {
const assets = me.get_checked_items();
frappe.call({
method: "erpnext.assets.doctype.asset.asset.make_asset_movement",

View File

@@ -4,7 +4,16 @@
import frappe
from frappe import _
from frappe.utils import add_months, cint, flt, get_last_day, getdate, nowdate, today
from frappe.utils import (
add_months,
cint,
flt,
get_first_day,
get_last_day,
getdate,
nowdate,
today,
)
from frappe.utils.data import get_link_to_form
from frappe.utils.user import get_users_with_role
@@ -126,6 +135,7 @@ def make_depreciation_entry(asset_name, date=None):
je.append("accounts", debit_entry)
je.flags.ignore_permissions = True
je.flags.planned_depr_entry = True
je.save()
if not je.meta.get_workflow():
je.submit()
@@ -218,10 +228,16 @@ def notify_depr_entry_posting_error(failed_asset_names):
asset_links = get_comma_separated_asset_links(failed_asset_names)
message = (
_("Hi,")
+ "<br>"
+ _("The following assets have failed to post depreciation entries: {0}").format(asset_links)
_("Hello,")
+ "<br><br>"
+ _("The following assets have failed to automatically post depreciation entries: {0}").format(
asset_links
)
+ "."
+ "<br><br>"
+ _(
"Please raise a support ticket and share this email, or forward this email to your development team so that they can find the issue in the developer console by manually creating the depreciation entry via the asset's depreciation schedule table."
)
)
frappe.sendmail(recipients=recipients, subject=subject, message=message)
@@ -265,7 +281,7 @@ def scrap_asset(asset_name):
je.company = asset.company
je.remark = "Scrap Entry for asset {0}".format(asset_name)
for entry in get_gl_entries_on_asset_disposal(asset):
for entry in get_gl_entries_on_asset_disposal(asset, date):
entry.update({"reference_type": "Asset", "reference_name": asset_name})
je.append("accounts", entry)
@@ -388,8 +404,11 @@ def disposal_happens_in_the_future(posting_date_of_disposal):
def get_gl_entries_on_asset_regain(
asset, selling_amount=0, finance_book=None, voucher_type=None, voucher_no=None
asset, selling_amount=0, finance_book=None, voucher_type=None, voucher_no=None, date=None
):
if not date:
date = getdate()
(
fixed_asset_account,
asset,
@@ -407,7 +426,7 @@ def get_gl_entries_on_asset_regain(
"debit_in_account_currency": asset.gross_purchase_amount,
"debit": asset.gross_purchase_amount,
"cost_center": depreciation_cost_center,
"posting_date": getdate(),
"posting_date": date,
},
item=asset,
),
@@ -417,7 +436,7 @@ def get_gl_entries_on_asset_regain(
"credit_in_account_currency": accumulated_depr_amount,
"credit": accumulated_depr_amount,
"cost_center": depreciation_cost_center,
"posting_date": getdate(),
"posting_date": date,
},
item=asset,
),
@@ -426,7 +445,7 @@ def get_gl_entries_on_asset_regain(
profit_amount = abs(flt(value_after_depreciation)) - abs(flt(selling_amount))
if profit_amount:
get_profit_gl_entries(
asset, profit_amount, gl_entries, disposal_account, depreciation_cost_center
asset, profit_amount, gl_entries, disposal_account, depreciation_cost_center, date
)
if voucher_type and voucher_no:
@@ -438,8 +457,11 @@ def get_gl_entries_on_asset_regain(
def get_gl_entries_on_asset_disposal(
asset, selling_amount=0, finance_book=None, voucher_type=None, voucher_no=None
asset, selling_amount=0, finance_book=None, voucher_type=None, voucher_no=None, date=None
):
if not date:
date = getdate()
(
fixed_asset_account,
asset,
@@ -457,7 +479,7 @@ def get_gl_entries_on_asset_disposal(
"credit_in_account_currency": asset.gross_purchase_amount,
"credit": asset.gross_purchase_amount,
"cost_center": depreciation_cost_center,
"posting_date": getdate(),
"posting_date": date,
},
item=asset,
),
@@ -467,7 +489,7 @@ def get_gl_entries_on_asset_disposal(
"debit_in_account_currency": accumulated_depr_amount,
"debit": accumulated_depr_amount,
"cost_center": depreciation_cost_center,
"posting_date": getdate(),
"posting_date": date,
},
item=asset,
),
@@ -476,7 +498,7 @@ def get_gl_entries_on_asset_disposal(
profit_amount = flt(selling_amount) - flt(value_after_depreciation)
if profit_amount:
get_profit_gl_entries(
asset, profit_amount, gl_entries, disposal_account, depreciation_cost_center
asset, profit_amount, gl_entries, disposal_account, depreciation_cost_center, date
)
if voucher_type and voucher_no:
@@ -510,8 +532,12 @@ def get_asset_details(asset, finance_book=None):
def get_profit_gl_entries(
asset, profit_amount, gl_entries, disposal_account, depreciation_cost_center
asset, profit_amount, gl_entries, disposal_account, depreciation_cost_center, date=None
):
if not date:
date = getdate()
debit_or_credit = "debit" if profit_amount < 0 else "credit"
gl_entries.append(
asset.get_gl_dict(
@@ -520,7 +546,7 @@ def get_profit_gl_entries(
"cost_center": depreciation_cost_center,
debit_or_credit: abs(profit_amount),
debit_or_credit + "_in_account_currency": abs(profit_amount),
"posting_date": getdate(),
"posting_date": date,
},
item=asset,
)
@@ -574,3 +600,9 @@ def is_last_day_of_the_month(date):
last_day_of_the_month = get_last_day(date)
return getdate(last_day_of_the_month) == getdate(date)
def is_first_day_of_the_month(date):
first_day_of_the_month = get_first_day(date)
return getdate(first_day_of_the_month) == getdate(date)

View File

@@ -327,6 +327,79 @@ class TestAsset(AssetSetup):
si.cancel()
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
def test_gle_made_by_asset_sale_for_existing_asset(self):
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
asset = create_asset(
calculate_depreciation=1,
available_for_use_date="2020-04-01",
purchase_date="2020-04-01",
expected_value_after_useful_life=0,
total_number_of_depreciations=5,
number_of_depreciations_booked=2,
frequency_of_depreciation=12,
depreciation_start_date="2023-03-31",
opening_accumulated_depreciation=24000,
gross_purchase_amount=60000,
submit=1,
)
expected_depr_values = [
["2023-03-31", 12000, 36000],
["2024-03-31", 12000, 48000],
["2025-03-31", 12000, 60000],
]
for i, schedule in enumerate(asset.schedules):
self.assertEqual(getdate(expected_depr_values[i][0]), schedule.schedule_date)
self.assertEqual(expected_depr_values[i][1], schedule.depreciation_amount)
self.assertEqual(expected_depr_values[i][2], schedule.accumulated_depreciation_amount)
post_depreciation_entries(date="2023-03-31")
si = create_sales_invoice(
item_code="Macbook Pro", asset=asset.name, qty=1, rate=40000, posting_date=getdate("2023-05-23")
)
asset.load_from_db()
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold")
expected_values = [["2023-03-31", 12000, 36000], ["2023-05-23", 1742.47, 37742.47]]
for i, schedule in enumerate(asset.schedules):
self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
self.assertTrue(schedule.journal_entry)
expected_gle = (
(
"_Test Accumulated Depreciations - _TC",
37742.47,
0.0,
),
(
"_Test Fixed Asset - _TC",
0.0,
60000.0,
),
(
"_Test Gain/Loss on Asset Disposal - _TC",
0.0,
17742.47,
),
("Debtors - _TC", 40000.0, 0.0),
)
gle = frappe.db.sql(
"""select account, debit, credit from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no = %s
order by account""",
si.name,
)
self.assertSequenceEqual(gle, expected_gle)
def test_asset_with_maintenance_required_status_after_sale(self):
asset = create_asset(
calculate_depreciation=1,
@@ -649,7 +722,7 @@ class TestDepreciationMethods(AssetSetup):
)
self.assertEqual(asset.status, "Draft")
expected_schedules = [["2032-12-31", 30000.0, 77095.89], ["2033-06-06", 12904.11, 90000.0]]
expected_schedules = [["2032-12-31", 42904.11, 90000.0]]
schedules = [
[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount]
for d in asset.get("schedules")
@@ -693,14 +766,14 @@ class TestDepreciationMethods(AssetSetup):
number_of_depreciations_booked=1,
opening_accumulated_depreciation=50000,
expected_value_after_useful_life=10000,
depreciation_start_date="2030-12-31",
depreciation_start_date="2031-12-31",
total_number_of_depreciations=3,
frequency_of_depreciation=12,
)
self.assertEqual(asset.status, "Draft")
expected_schedules = [["2030-12-31", 33333.50, 83333.50], ["2031-12-31", 6666.50, 90000.0]]
expected_schedules = [["2031-12-31", 33333.50, 83333.50], ["2032-12-31", 6666.50, 90000.0]]
schedules = [
[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
@@ -818,12 +891,12 @@ class TestDepreciationMethods(AssetSetup):
)
expected_schedules = [
["2022-02-28", 647.25, 647.25],
["2022-03-31", 1210.71, 1857.96],
["2022-04-30", 1053.99, 2911.95],
["2022-05-31", 917.55, 3829.5],
["2022-06-30", 798.77, 4628.27],
["2022-07-15", 371.73, 5000.0],
["2022-02-28", 310.89, 310.89],
["2022-03-31", 654.45, 965.34],
["2022-04-30", 654.45, 1619.79],
["2022-05-31", 654.45, 2274.24],
["2022-06-30", 654.45, 2928.69],
["2022-07-15", 2071.31, 5000.0],
]
schedules = [
@@ -1453,7 +1526,7 @@ class TestDepreciationBasics(AssetSetup):
)
self.assertEqual(asset.status, "Submitted")
self.assertEqual(asset.get("value_after_depreciation"), 100000)
self.assertEqual(asset.get_value_after_depreciation(), 100000)
jv = make_journal_entry(
"_Test Depreciations - _TC", "_Test Accumulated Depreciations - _TC", 100, save=False
@@ -1466,12 +1539,68 @@ class TestDepreciationBasics(AssetSetup):
jv.submit()
asset.reload()
self.assertEqual(asset.get("value_after_depreciation"), 99900)
self.assertEqual(asset.get_value_after_depreciation(), 99900)
jv.cancel()
asset.reload()
self.assertEqual(asset.get("value_after_depreciation"), 100000)
self.assertEqual(asset.get_value_after_depreciation(), 100000)
def test_manual_depreciation_for_depreciable_asset(self):
asset = create_asset(
item_code="Macbook Pro",
calculate_depreciation=1,
purchase_date="2020-01-30",
available_for_use_date="2020-01-30",
expected_value_after_useful_life=10000,
total_number_of_depreciations=10,
frequency_of_depreciation=1,
submit=1,
)
self.assertEqual(asset.status, "Submitted")
self.assertEqual(asset.get_value_after_depreciation(), 100000)
jv = make_journal_entry(
"_Test Depreciations - _TC", "_Test Accumulated Depreciations - _TC", 100, save=False
)
for d in jv.accounts:
d.reference_type = "Asset"
d.reference_name = asset.name
jv.voucher_type = "Depreciation Entry"
jv.insert()
jv.submit()
asset.reload()
self.assertEqual(asset.get_value_after_depreciation(), 99900)
jv.cancel()
asset.reload()
self.assertEqual(asset.get_value_after_depreciation(), 100000)
def test_manual_depreciation_with_incorrect_jv_voucher_type(self):
asset = create_asset(
item_code="Macbook Pro",
calculate_depreciation=1,
purchase_date="2020-01-30",
available_for_use_date="2020-01-30",
expected_value_after_useful_life=10000,
total_number_of_depreciations=10,
frequency_of_depreciation=1,
submit=1,
)
jv = make_journal_entry(
"_Test Depreciations - _TC", "_Test Accumulated Depreciations - _TC", 100, save=False
)
for d in jv.accounts:
d.reference_type = "Asset"
d.reference_name = asset.name
d.account_type = "Depreciation"
jv.voucher_type = "Journal Entry"
self.assertRaises(frappe.ValidationError, jv.insert)
def create_asset_data():

View File

@@ -436,6 +436,7 @@ class AssetCapitalization(StockController):
item.get("finance_book") or self.get("finance_book"),
self.get("doctype"),
self.get("name"),
self.get("posting_date"),
)
asset.db_set("disposal_date", self.posting_date)

View File

@@ -96,7 +96,6 @@ class AssetCategory(Document):
frappe.throw(msg, title=_("Missing Account"))
@frappe.whitelist()
def get_asset_category_account(
fieldname, item=None, asset=None, account=None, asset_category=None, company=None
):

View File

@@ -84,6 +84,8 @@ def calculate_next_due_date(
next_due_date = add_years(start_date, 1)
if periodicity == "2 Yearly":
next_due_date = add_years(start_date, 2)
if periodicity == "3 Yearly":
next_due_date = add_years(start_date, 3)
if periodicity == "Quarterly":
next_due_date = add_months(start_date, 3)
if end_date and (

View File

@@ -1,664 +1,156 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "",
"beta": 0,
"creation": "2017-10-20 07:10:55.903571",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"engine": "InnoDB",
"actions": [],
"creation": "2017-10-20 07:10:55.903571",
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"maintenance_task",
"maintenance_type",
"column_break_2",
"maintenance_status",
"section_break_2",
"start_date",
"periodicity",
"column_break_4",
"end_date",
"certificate_required",
"section_break_9",
"assign_to",
"column_break_10",
"assign_to_name",
"section_break_10",
"next_due_date",
"column_break_14",
"last_completion_date",
"section_break_7",
"description"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "maintenance_task",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Maintenance Task",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "maintenance_task",
"fieldtype": "Data",
"in_filter": 1,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Maintenance Task",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "maintenance_type",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Maintenance Type",
"length": 0,
"no_copy": 0,
"options": "Preventive Maintenance\nCalibration",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "maintenance_type",
"fieldtype": "Select",
"label": "Maintenance Type",
"options": "Preventive Maintenance\nCalibration"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "column_break_2",
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "maintenance_status",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Maintenance Status",
"length": 0,
"no_copy": 0,
"options": "Planned\nOverdue\nCancelled",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "maintenance_status",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Maintenance Status",
"options": "Planned\nOverdue\nCancelled",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_2",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "section_break_2",
"fieldtype": "Section Break"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Today",
"fieldname": "start_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Start Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"default": "Today",
"fieldname": "start_date",
"fieldtype": "Date",
"label": "Start Date",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "periodicity",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Periodicity",
"length": 0,
"no_copy": 0,
"options": "\nDaily\nWeekly\nMonthly\nQuarterly\nYearly\n2 Yearly",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "periodicity",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Periodicity",
"options": "\nDaily\nWeekly\nMonthly\nQuarterly\nYearly\n2 Yearly\n3 Yearly",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_4",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "end_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "End Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "end_date",
"fieldtype": "Date",
"label": "End Date"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "certificate_required",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Certificate Required",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 1,
"translatable": 0,
"unique": 0
},
"default": "0",
"fieldname": "certificate_required",
"fieldtype": "Check",
"label": "Certificate Required",
"search_index": 1,
"set_only_once": 1
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_9",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "section_break_9",
"fieldtype": "Section Break"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "assign_to",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Assign To",
"length": 0,
"no_copy": 0,
"options": "User",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "assign_to",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Assign To",
"options": "User"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_10",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "column_break_10",
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "assign_to.full_name",
"fieldname": "assign_to_name",
"fieldtype": "Read Only",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Assign to Name",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "assign_to_name",
"fieldtype": "Read Only",
"label": "Assign to Name"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_10",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "section_break_10",
"fieldtype": "Section Break"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "next_due_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Next Due Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "next_due_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Next Due Date"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_14",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "column_break_14",
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "last_completion_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Last Completion Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "last_completion_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Last Completion Date"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_7",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "section_break_7",
"fieldtype": "Section Break"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "description",
"fieldtype": "Text Editor",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldname": "description",
"fieldtype": "Text Editor",
"label": "Description"
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-06-18 16:12:04.330021",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Maintenance Task",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
],
"istable": 1,
"links": [],
"modified": "2023-03-23 07:03:07.113452",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Maintenance Task",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@@ -56,8 +56,6 @@ class AssetRepair(AccountsController):
self.asset_doc.flags.ignore_validate_update_after_submit = True
self.asset_doc.prepare_depreciation_data()
if self.asset_doc.calculate_depreciation:
self.update_asset_expected_value_after_useful_life()
self.asset_doc.save()
def before_cancel(self):
@@ -81,8 +79,6 @@ class AssetRepair(AccountsController):
self.asset_doc.flags.ignore_validate_update_after_submit = True
self.asset_doc.prepare_depreciation_data()
if self.asset_doc.calculate_depreciation:
self.update_asset_expected_value_after_useful_life()
self.asset_doc.save()
def after_delete(self):
@@ -103,26 +99,6 @@ class AssetRepair(AccountsController):
title=_("Missing Warehouse"),
)
def update_asset_expected_value_after_useful_life(self):
for row in self.asset_doc.get("finance_books"):
if row.depreciation_method in ("Written Down Value", "Double Declining Balance"):
accumulated_depreciation_after_full_schedule = [
d.accumulated_depreciation_amount
for d in self.asset_doc.get("schedules")
if cint(d.finance_book_id) == row.idx
]
accumulated_depreciation_after_full_schedule = max(
accumulated_depreciation_after_full_schedule
)
asset_value_after_full_schedule = flt(
flt(row.value_after_depreciation) - flt(accumulated_depreciation_after_full_schedule),
row.precision("expected_value_after_useful_life"),
)
row.expected_value_after_useful_life = asset_value_after_full_schedule
def increase_asset_value(self):
total_value_of_stock_consumed = self.get_total_value_of_stock_consumed()

View File

@@ -49,7 +49,7 @@ frappe.ui.form.on('Asset Value Adjustment', {
frm.call({
method: "erpnext.assets.doctype.asset.asset.get_asset_value_after_depreciation",
args: {
asset: frm.doc.asset,
asset_name: frm.doc.asset,
finance_book: frm.doc.finance_book
},
callback: function(r) {

View File

@@ -116,7 +116,9 @@ class AssetValueAdjustment(Document):
if d.depreciation_method in ("Straight Line", "Manual"):
end_date = max(s.schedule_date for s in asset.schedules if cint(s.finance_book_id) == d.idx)
total_days = date_diff(end_date, self.date)
rate_per_day = flt(d.value_after_depreciation) / flt(total_days)
rate_per_day = flt(d.value_after_depreciation - d.expected_value_after_useful_life) / flt(
total_days
)
from_date = self.date
else:
no_of_depreciations = len(

View File

@@ -24,7 +24,7 @@ frappe.query_reports["Fixed Asset Register"] = {
"label": __("Period Based On"),
"fieldtype": "Select",
"options": ["Fiscal Year", "Date Range"],
"default": ["Fiscal Year"],
"default": "Fiscal Year",
"reqd": 1
},
{
@@ -75,12 +75,6 @@ frappe.query_reports["Fixed Asset Register"] = {
fieldtype: "Link",
options: "Asset Category"
},
{
fieldname:"finance_book",
label: __("Finance Book"),
fieldtype: "Link",
options: "Finance Book"
},
{
fieldname:"cost_center",
label: __("Cost Center"),
@@ -96,8 +90,20 @@ frappe.query_reports["Fixed Asset Register"] = {
reqd: 1
},
{
fieldname:"is_existing_asset",
label: __("Is Existing Asset"),
fieldname:"finance_book",
label: __("Finance Book"),
fieldtype: "Link",
options: "Finance Book",
depends_on: "eval: doc.filter_by_finance_book == 1",
},
{
fieldname:"filter_by_finance_book",
label: __("Filter by Finance Book"),
fieldtype: "Check"
},
{
fieldname:"only_existing_assets",
label: __("Only existing assets"),
fieldtype: "Check"
},
]

View File

@@ -45,8 +45,8 @@ def get_conditions(filters):
filters.year_end_date = getdate(fiscal_year.year_end_date)
conditions[date_field] = ["between", [filters.year_start_date, filters.year_end_date]]
if filters.get("is_existing_asset"):
conditions["is_existing_asset"] = filters.get("is_existing_asset")
if filters.get("only_existing_assets"):
conditions["is_existing_asset"] = filters.get("only_existing_assets")
if filters.get("asset_category"):
conditions["asset_category"] = filters.get("asset_category")
if filters.get("cost_center"):
@@ -102,19 +102,18 @@ def get_data(filters):
]
assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields)
assets_linked_to_fb = frappe.db.get_all(
doctype="Asset Finance Book",
filters={"finance_book": filters.finance_book or ("is", "not set")},
pluck="parent",
)
assets_linked_to_fb = None
if filters.filter_by_finance_book:
assets_linked_to_fb = frappe.db.get_all(
doctype="Asset Finance Book",
filters={"finance_book": filters.finance_book or ("is", "not set")},
pluck="parent",
)
for asset in assets_record:
if filters.finance_book:
if asset.asset_id not in assets_linked_to_fb:
continue
else:
if asset.calculate_depreciation and asset.asset_id not in assets_linked_to_fb:
continue
if assets_linked_to_fb and asset.asset_id not in assets_linked_to_fb:
continue
asset_value = get_asset_value_after_depreciation(asset.asset_id, filters.finance_book)
row = {
@@ -172,11 +171,11 @@ def prepare_chart_data(data, filters):
"datasets": [
{
"name": _("Asset Value"),
"values": [d.get("asset_value") for d in labels_values_map.values()],
"values": [flt(d.get("asset_value"), 2) for d in labels_values_map.values()],
},
{
"name": _("Depreciatied Amount"),
"values": [d.get("depreciated_amount") for d in labels_values_map.values()],
"values": [flt(d.get("depreciated_amount"), 2) for d in labels_values_map.values()],
},
],
},
@@ -310,7 +309,7 @@ def get_columns(filters):
return [
{
"label": _("Asset Id"),
"label": _("Asset ID"),
"fieldtype": "Link",
"fieldname": "asset_id",
"options": "Asset",

View File

@@ -7,12 +7,14 @@
],
"content": "[{\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Assets\",\"col\":12}},{\"type\":\"chart\",\"data\":{\"chart_name\":\"Asset Value Analytics\",\"col\":12}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Asset\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Asset Category\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Fixed Asset Register\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Assets\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Maintenance\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}}]",
"creation": "2020-03-02 15:43:27.634865",
"custom_blocks": [],
"docstatus": 0,
"doctype": "Workspace",
"for_user": "",
"hide_custom": 0,
"icon": "assets",
"idx": 0,
"is_hidden": 0,
"label": "Assets",
"links": [
{
@@ -183,13 +185,15 @@
"type": "Link"
}
],
"modified": "2021-10-04 12:15:54.839454",
"modified": "2023-05-24 14:47:20.243146",
"modified_by": "Administrator",
"module": "Assets",
"name": "Assets",
"number_cards": [],
"owner": "Administrator",
"parent_page": "",
"parent_page": "Accounting",
"public": 1,
"quick_lists": [],
"restrict_to_domain": "",
"roles": [],
"sequence_id": 4.0,
@@ -216,4 +220,4 @@
}
],
"title": "Assets"
}
}

View File

@@ -236,7 +236,11 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
this.make_purchase_invoice, __('Create'));
if(flt(doc.per_billed) < 100 && doc.status != "Delivered") {
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __('Create'));
this.frm.add_custom_button(
__('Payment'),
() => this.make_payment_entry(),
__('Create')
);
}
if(flt(doc.per_billed) < 100) {

View File

@@ -157,7 +157,7 @@
"party_account_currency",
"inter_company_order_reference",
"is_old_subcontracting_flow",
"dashboard"
"connections_tab"
],
"fields": [
{
@@ -495,6 +495,7 @@
"allow_bulk_edit": 1,
"fieldname": "items",
"fieldtype": "Table",
"label": "Items",
"oldfieldname": "po_details",
"oldfieldtype": "Table",
"options": "Purchase Order Item",
@@ -1100,8 +1101,7 @@
{
"fieldname": "before_items_section",
"fieldtype": "Section Break",
"hide_border": 1,
"label": "Items"
"hide_border": 1
},
{
"fieldname": "items_col_break",
@@ -1184,12 +1184,6 @@
"fieldtype": "Tab Break",
"label": "More Info"
},
{
"fieldname": "dashboard",
"fieldtype": "Tab Break",
"label": "Dashboard",
"show_dashboard": 1
},
{
"fieldname": "column_break_7",
"fieldtype": "Column Break"
@@ -1265,13 +1259,19 @@
"fieldname": "shipping_address_section",
"fieldtype": "Section Break",
"label": "Shipping Address"
},
{
"fieldname": "connections_tab",
"fieldtype": "Tab Break",
"label": "Connections",
"show_dashboard": 1
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
"links": [],
"modified": "2023-01-28 18:59:16.322824",
"modified": "2023-05-24 11:16:41.195340",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",

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