Compare commits

..

130 Commits

Author SHA1 Message Date
Frappe PR Bot
236a064cd3 chore(release): Bumped to Version 14.48.1
## [14.48.1](https://github.com/frappe/erpnext/compare/v14.48.0...v14.48.1) (2023-11-17)

### Bug Fixes

* add revaluation journal filter in Payable report ([4eb37cc](4eb37cce26))
2023-11-17 04:38:02 +00:00
ruthra kumar
dd685e50df Merge pull request #38140 from frappe/mergify/bp/version-14/pr-38119
fix: add revaluation journal filter in Payable report (backport #38119)
2023-11-17 10:06:30 +05:30
ruthra kumar
4eb37cce26 fix: add revaluation journal filter in Payable report
(cherry picked from commit 134201794a)
2023-11-17 10:03:24 +05:30
Anand Baburajan
fb2ca3e172 Merge pull request #38114 from frappe/mergify/bp/version-14/pr-38112
chore: change read only condition of asset quantity field (backport #38111) (backport #38112)
2023-11-15 18:03:01 +05:30
mergify[bot]
7d66cb2195 chore: change read only condition of asset quantity field (backport #38111) (#38112)
chore: change read only condition of asset quantity field (#38111)

chore: change read only condition of asset quantity
(cherry picked from commit 6e0362dee8)

Co-authored-by: Anand Baburajan <anandbaburajan@gmail.com>
(cherry picked from commit 58cb4303ee)
2023-11-15 12:32:19 +00:00
Anand Baburajan
7b14e9d5f6 Merge pull request #38100 from frappe/mergify/bp/version-14/pr-38098
chore: refetch item images on transaction save (backport #38095) (backport #38098)
2023-11-14 20:15:28 +05:30
mergify[bot]
966adfc081 chore: refetch item images on transaction save (backport #38095) (#38098)
* chore: refetch item images on transaction save (#38095)

chore: re fetch item images on transaction save
(cherry picked from commit e93a19ffb5)

# Conflicts:
#	erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json
#	erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
#	erpnext/selling/doctype/quotation_item/quotation_item.json

* chore: fix conflict in pos_invoice_item.json

* chore: fix conflict in sales_invoice_item.json

* chore: fix conflict in quotation_item.json

---------

Co-authored-by: Anand Baburajan <anandbaburajan@gmail.com>
(cherry picked from commit d1a8202624)
2023-11-14 14:43:12 +00:00
Frappe PR Bot
7a2df24129 chore(release): Bumped to Version 14.48.0
# [14.48.0](https://github.com/frappe/erpnext/compare/v14.47.4...v14.48.0) (2023-11-14)

### Bug Fixes

* asset depreciation ledger (backport [#37991](https://github.com/frappe/erpnext/issues/37991)) ([#37992](https://github.com/frappe/erpnext/issues/37992)) ([043dc1b](043dc1b14b))
* close `Credit Limit Crossed` dialog (backport [#38052](https://github.com/frappe/erpnext/issues/38052)) ([#38058](https://github.com/frappe/erpnext/issues/38058)) ([6979c3e](6979c3e490))
* COA Importer app related issues ([#37238](https://github.com/frappe/erpnext/issues/37238)) ([57ce73d](57ce73d540))
* german translations of Accounts Settings ([b75aae9](b75aae99ca))
* indentation issue in the Production Plan Summary report (backport [#38019](https://github.com/frappe/erpnext/issues/38019)) ([#38068](https://github.com/frappe/erpnext/issues/38068)) ([c552884](c5528844fd))
* make adjustment entry using stock reconciliation (backport [#37995](https://github.com/frappe/erpnext/issues/37995)) ([#38008](https://github.com/frappe/erpnext/issues/38008)) ([984703c](984703c3c9))
* make item field read-only in batch (backport [#38010](https://github.com/frappe/erpnext/issues/38010)) ([#38033](https://github.com/frappe/erpnext/issues/38033)) ([424ebd1](424ebd154a))
* minor change added to test_case ([6b34568](6b34568128))
* minor issue ([0eab723](0eab723243))
* new logic for handling revaluation journals ([9c0d80c](9c0d80cef4))
* pick serial nos from selected batch only ([#37988](https://github.com/frappe/erpnext/issues/37988)) ([db29180](db29180eec))
* sales order not assigned to territory orders ([#37905](https://github.com/frappe/erpnext/issues/37905)) ([#38024](https://github.com/frappe/erpnext/issues/38024)) ([620f4f2](620f4f2c10))
* Set right party name in bank transaction ([21b430a](21b430a575))
* **translations:** suggestions from review ([4d2169e](4d2169e48e))
* Use `process.extract` to get the corresponding party doc name of the result ([b0a184e](b0a184e937))

### Features

* **accounts_receivable:** test_case added for multi-select customer group ([cf0d936](cf0d936195))
* multi-select customer group in AR Report ([935286f](935286ff94))
2023-11-14 12:57:28 +00:00
Deepesh Garg
ecb116aa99 Merge pull request #38086 from frappe/version-14-hotfix
chore: release v14
2023-11-14 18:25:20 +05:30
mergify[bot]
8446e87cc2 chore: delete comments and unlink attachments on company transactions deletion (backport #38077) (#38078)
* chore: delete comments and unlink attachments on company transactions deletion

(cherry picked from commit 2f9e96e324)

* fix: unrelated transation date typo

(cherry picked from commit b097bb20d9)

---------

Co-authored-by: anandbaburajan <anandbaburajan@gmail.com>
2023-11-13 19:20:52 +05:30
mergify[bot]
c5528844fd fix: indentation issue in the Production Plan Summary report (backport #38019) (#38068)
fix: indentation issue in the Production Plan Summary report (#38019)

fix: Production Plan Summary report
(cherry picked from commit 4a111f7362)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2023-11-13 14:03:45 +05:30
ruthra kumar
55885e84ab Merge pull request #38066 from frappe/mergify/bp/version-14/pr-38064
refactor: add revaluation journal checkbox in AR/AP summary reports (backport #38064)
2023-11-13 12:15:34 +05:30
ruthra kumar
2faf2ce468 Merge pull request #38065 from frappe/mergify/bp/version-14-hotfix/pr-38064
refactor: add revaluation journal checkbox in AR/AP summary reports (backport #38064)
2023-11-13 12:15:27 +05:30
ruthra kumar
7ab18fc434 refactor: add revaluation journal checkbox in AR/AP summary reports
(cherry picked from commit 95edd82638)
2023-11-13 06:39:03 +00:00
ruthra kumar
a104a4bca6 refactor: add revaluation journal checkbox in AR/AP summary reports
(cherry picked from commit 95edd82638)
2023-11-13 06:38:38 +00:00
mergify[bot]
6979c3e490 fix: close Credit Limit Crossed dialog (backport #38052) (#38058)
fix: close `Credit Limit Crossed` dialog (#38052)

(cherry picked from commit 94faa44697)

Co-authored-by: Arjun <arjun99c@gmail.com>
2023-11-12 18:07:31 +05:30
mergify[bot]
57ce73d540 fix: COA Importer app related issues (#37238)
fix: COA Importer app related issues (#37238)

* fix: COA Importer app related issues

* fix: Clear all account links fields befor import

* fix: Attribute error

(cherry picked from commit 8634abc021)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-11-12 17:40:56 +05:30
mergify[bot]
424ebd154a fix: make item field read-only in batch (backport #38010) (#38033)
* fix: make item field read-only in batch

(cherry picked from commit 779260fb49)

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

* chore: `conflicts`

---------

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-11-11 10:51:36 +05:30
Frappe PR Bot
7c7dc5328e chore(release): Bumped to Version 14.47.4
## [14.47.4](https://github.com/frappe/erpnext/compare/v14.47.3...v14.47.4) (2023-11-10)

### Bug Fixes

* new logic for handling revaluation journals ([010ccf8](010ccf80f5))
2023-11-10 07:46:10 +00:00
ruthra kumar
cb655226de Merge pull request #38037 from frappe/mergify/bp/version-14/pr-38004
fix: handling of exchange rate journals in AR/AP (backport #38004)
2023-11-10 13:14:45 +05:30
ruthra kumar
010ccf80f5 fix: new logic for handling revaluation journals
(cherry picked from commit 1d8fcd66e6)
2023-11-10 12:05:46 +05:30
ruthra kumar
13ea910fa6 Merge pull request #38035 from frappe/mergify/bp/version-14-hotfix/pr-38004
fix: handling of exchange rate journals in AR/AP (backport #38004)
2023-11-10 11:59:03 +05:30
ruthra kumar
9c0d80cef4 fix: new logic for handling revaluation journals
(cherry picked from commit 1d8fcd66e6)
2023-11-10 11:17:46 +05:30
mergify[bot]
620f4f2c10 fix: sales order not assigned to territory orders (#37905) (#38024)
fix: sales order not assigned to territory orders (#37905)

filtered sales order are not assigned to 'territory_orders' which results in 0 order amount and 0 billing amount in the output

(cherry picked from commit 45b4bfc947)

Co-authored-by: jabir-elat <44110258+jabir-elat@users.noreply.github.com>
2023-11-09 21:52:43 +05:30
ruthra kumar
89695022c7 Merge pull request #38021 from frappe/mergify/bp/version-14/pr-37860
refactor: ignore disabled account while selecting Income Accounts (backport #37860)
2023-11-09 17:28:14 +05:30
Frappe PR Bot
50627733b4 chore(release): Bumped to Version 14.47.3
## [14.47.3](https://github.com/frappe/erpnext/compare/v14.47.2...v14.47.3) (2023-11-09)

### Bug Fixes

* make adjustment entry using stock reconciliation (backport [#37995](https://github.com/frappe/erpnext/issues/37995)) (backport [#38008](https://github.com/frappe/erpnext/issues/38008)) ([#38018](https://github.com/frappe/erpnext/issues/38018)) ([7942ad4](7942ad488e))
2023-11-09 11:24:29 +00:00
mergify[bot]
7942ad488e fix: make adjustment entry using stock reconciliation (backport #37995) (backport #38008) (#38018)
fix: make adjustment entry using stock reconciliation (backport #37995) (#38008)

* fix: make adjustment entry using stock reconciliation (#37995)

fix: do adjustment entry using stock reconciliation
(cherry picked from commit a8216b9727)

# Conflicts:
#	erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
#	erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py

* chore: fix conflicts

* fix: conflicts

* chore: fix conflicts

---------

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

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-11-09 16:53:14 +05:30
ruthra kumar
c3d7348c73 refactor: ignore disabled account while selecting Income Accounts
(cherry picked from commit 6e3e094c95)
2023-11-09 11:14:38 +00:00
Deepesh Garg
ad178db28f Merge pull request #38012 from frappe/mergify/bp/version-14-hotfix/pr-37716
feat: multi-select customer group in AR Report (backport #37716)
2023-11-09 14:05:59 +05:30
mergify[bot]
984703c3c9 fix: make adjustment entry using stock reconciliation (backport #37995) (#38008)
* fix: make adjustment entry using stock reconciliation (#37995)

fix: do adjustment entry using stock reconciliation
(cherry picked from commit a8216b9727)

# Conflicts:
#	erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
#	erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py

* chore: fix conflicts

* fix: conflicts

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2023-11-09 13:40:14 +05:30
vishal
6b34568128 fix: minor change added to test_case
(cherry picked from commit 30402033bc)
2023-11-09 07:35:16 +00:00
vishal
cf0d936195 feat(accounts_receivable): test_case added for multi-select customer group
(cherry picked from commit de445b32f5)
2023-11-09 07:35:16 +00:00
vishal
0eab723243 fix: minor issue
(cherry picked from commit b60c57a97d)
2023-11-09 07:35:15 +00:00
vishal
935286ff94 feat: multi-select customer group in AR Report
(cherry picked from commit 8903c1bc6f)
2023-11-09 07:35:15 +00:00
Frappe PR Bot
9a2674ea29 chore(release): Bumped to Version 14.47.2
## [14.47.2](https://github.com/frappe/erpnext/compare/v14.47.1...v14.47.2) (2023-11-09)

### Bug Fixes

* pick serial nos from selected batch only (backport [#37988](https://github.com/frappe/erpnext/issues/37988)) ([#38011](https://github.com/frappe/erpnext/issues/38011)) ([0405aae](0405aae4a0))
2023-11-09 07:28:50 +00:00
mergify[bot]
0405aae4a0 fix: pick serial nos from selected batch only (backport #37988) (#38011)
fix: pick serial nos from selected batch only (#37988)

* fix: pick current serial nos from selected batch only

* test: add test case for current qty and current serial nos

(cherry picked from commit db29180eec)

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-11-09 12:57:03 +05:30
s-aga-r
db29180eec fix: pick serial nos from selected batch only (#37988)
* fix: pick current serial nos from selected batch only

* test: add test case for current qty and current serial nos
2023-11-09 12:30:22 +05:30
ruthra kumar
b5bed65d9e Merge pull request #38001 from frappe/mergify/bp/version-14-hotfix/pr-37860
refactor: ignore disabled account while selecting Income Accounts (backport #37860)
2023-11-09 10:41:13 +05:30
ruthra kumar
3f7f5bd8f0 refactor: ignore disabled account while selecting Income Accounts
(cherry picked from commit 6e3e094c95)
2023-11-09 04:45:53 +00:00
Frappe PR Bot
3f433b1b8b chore(release): Bumped to Version 14.47.1
## [14.47.1](https://github.com/frappe/erpnext/compare/v14.47.0...v14.47.1) (2023-11-08)

### Bug Fixes

* asset depreciation ledger (backport [#37991](https://github.com/frappe/erpnext/issues/37991)) ([#37992](https://github.com/frappe/erpnext/issues/37992)) ([0ac78a9](0ac78a96a9))
2023-11-08 18:40:20 +00:00
Anand Baburajan
0532f72cb1 Merge pull request #37996 from frappe/mergify/bp/version-14/pr-37992
fix: asset depreciation ledger (backport #37991) (backport #37992)
2023-11-09 00:09:05 +05:30
mergify[bot]
0ac78a96a9 fix: asset depreciation ledger (backport #37991) (#37992)
* fix: asset depreciation ledger (#37991)

* fix: include opening acc depr while calculating asset depr ledger report

* chore: include opening acc depr properly in acc depr amt

* chore: add cost_center in asset depr ledger report

* fix: handle finance books properly in asset depr ledger report

* chore: rename 'include default book entries' to 'include default FB entries'

(cherry picked from commit 9a171db97f)

# Conflicts:
#	erpnext/accounts/report/balance_sheet/balance_sheet.js
#	erpnext/accounts/report/cash_flow/cash_flow.js
#	erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js
#	erpnext/accounts/report/trial_balance/trial_balance.js
#	erpnext/translations/pl.csv
#	erpnext/translations/tr.csv

* chore: fix conflict in balance_sheet.js

* chore: fix conflict in cash_flow.js

* chore: fix conflict in consolidated_financial_statement.js

* chore: fix conflict in trial_balance.js

* chore: fix conflict in tr.csv

* chore: fix conflict in pl.csv

---------

Co-authored-by: Anand Baburajan <anandbaburajan@gmail.com>
(cherry picked from commit 043dc1b14b)
2023-11-08 18:07:42 +00:00
mergify[bot]
043dc1b14b fix: asset depreciation ledger (backport #37991) (#37992)
* fix: asset depreciation ledger (#37991)

* fix: include opening acc depr while calculating asset depr ledger report

* chore: include opening acc depr properly in acc depr amt

* chore: add cost_center in asset depr ledger report

* fix: handle finance books properly in asset depr ledger report

* chore: rename 'include default book entries' to 'include default FB entries'

(cherry picked from commit 9a171db97f)

# Conflicts:
#	erpnext/accounts/report/balance_sheet/balance_sheet.js
#	erpnext/accounts/report/cash_flow/cash_flow.js
#	erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js
#	erpnext/accounts/report/trial_balance/trial_balance.js
#	erpnext/translations/pl.csv
#	erpnext/translations/tr.csv

* chore: fix conflict in balance_sheet.js

* chore: fix conflict in cash_flow.js

* chore: fix conflict in consolidated_financial_statement.js

* chore: fix conflict in trial_balance.js

* chore: fix conflict in tr.csv

* chore: fix conflict in pl.csv

---------

Co-authored-by: Anand Baburajan <anandbaburajan@gmail.com>
2023-11-08 23:36:17 +05:30
Deepesh Garg
c5a6b17c15 Merge pull request #37825 from frappe/mergify/bp/version-14-hotfix/pr-37278
fix: german translations of Accounts Settings (backport #37278)
2023-11-08 18:44:11 +05:30
Deepesh Garg
16c3f3bcbd Merge pull request #37913 from frappe/mergify/bp/version-14-hotfix/pr-37299
fix: Set right party name in bank transaction (backport #37299)
2023-11-08 12:28:10 +05:30
Frappe PR Bot
4d804951c6 chore(release): Bumped to Version 14.47.0
# [14.47.0](https://github.com/frappe/erpnext/compare/v14.46.7...v14.47.0) (2023-11-08)

### Bug Fixes

* `TypeError` in PR for non-stock item ([ef4471f](ef4471f8c0))
* add missing disbursement account in update_old_loans patch ([ad64065](ad64065ec6))
* add translation wrapper (backport [#37911](https://github.com/frappe/erpnext/issues/37911)) ([#37946](https://github.com/frappe/erpnext/issues/37946)) ([c53d281](c53d281b9e))
* don't reset rate if greater than zero in standalone debit note (backport [#37935](https://github.com/frappe/erpnext/issues/37935)) ([#37940](https://github.com/frappe/erpnext/issues/37940)) ([64658fc](64658fc790))
* fetch asset received but not billed account only when needed ([7df4009](7df4009dd3))
* gov compliance for tax withholding report ([#37590](https://github.com/frappe/erpnext/issues/37590)) ([273cc35](273cc35b91))
* In-Transit Warehouse company filter (backport [#37796](https://github.com/frappe/erpnext/issues/37796)) ([#37797](https://github.com/frappe/erpnext/issues/37797)) ([0b1da08](0b1da08d78))
* link between parent and child procedure (backport [#37903](https://github.com/frappe/erpnext/issues/37903)) ([#37943](https://github.com/frappe/erpnext/issues/37943)) ([24da29a](24da29a817))
* list index out of range ([#37880](https://github.com/frappe/erpnext/issues/37880)) ([05fed9e](05fed9e352))
* make `Material Request Item` required if `Material Request` is set in PO (backport [#37928](https://github.com/frappe/erpnext/issues/37928)) ([#37936](https://github.com/frappe/erpnext/issues/37936)) ([c870120](c87012046d))
* permission error while creating Supplier Quotation from Portal (backport [#37864](https://github.com/frappe/erpnext/issues/37864)) ([#37870](https://github.com/frappe/erpnext/issues/37870)) ([1a3dae0](1a3dae0f9a))
* **plaid:** Do not sync pending transactions ([ffdc11b](ffdc11bbf6))
* POS change amount gl entry with no amount ([#37799](https://github.com/frappe/erpnext/issues/37799)) ([5e1a89b](5e1a89b3f9))
* Quality Inspection Parameter migration - DuplicateEntryError due to case sensitivity (backport [#37499](https://github.com/frappe/erpnext/issues/37499)) ([#37916](https://github.com/frappe/erpnext/issues/37916)) ([eb3630b](eb3630bcf8))
* remove voucher type and no for Item and Warehouse based reposting (backport [#37849](https://github.com/frappe/erpnext/issues/37849)) ([#37850](https://github.com/frappe/erpnext/issues/37850)) ([e19cade](e19cade12d))
* standard submit perm in repost ledger for editable invoices (backport [#37826](https://github.com/frappe/erpnext/issues/37826)) ([#37854](https://github.com/frappe/erpnext/issues/37854)) ([69b569d](69b569df46))
* status for over delivery or billing ([d8e7430](d8e743013f))
* type error on new payment entry ([38184f7](38184f77c7))
* typo in AR report ([3d72ec7](3d72ec7ca4))
* validate so item with qtn ([4a225b0](4a225b069b))

### Features

* reserved production plan sub assembly items (backport [#37884](https://github.com/frappe/erpnext/issues/37884)) ([#37926](https://github.com/frappe/erpnext/issues/37926)) ([4de97a4](4de97a4fcb))
* settings page for repost ([09cde5d](09cde5da08))
* **Stock Balance:** add filters from route (backport [#37836](https://github.com/frappe/erpnext/issues/37836)) ([#37839](https://github.com/frappe/erpnext/issues/37839)) ([e8a706a](e8a706a5ea))

### Performance Improvements

* Add index to supplier invoice field (backport [#37861](https://github.com/frappe/erpnext/issues/37861)) ([#37862](https://github.com/frappe/erpnext/issues/37862)) ([2c93f81](2c93f81d59))
* index return against for purchase invoice (backport [#37881](https://github.com/frappe/erpnext/issues/37881)) ([#37882](https://github.com/frappe/erpnext/issues/37882)) ([fed25fa](fed25fac76))
2023-11-08 06:19:10 +00:00
Deepesh Garg
c5ddb4153a Merge pull request #37965 from frappe/version-14-hotfix
chore: release v14
2023-11-08 11:47:53 +05:30
ruthra kumar
b0ed3c2f0a Merge pull request #37977 from ruthra-kumar/add_voucher_detail_no_to_payment_ledger
refactor: Add voucher_detail_no to payment ledger
2023-11-08 11:23:15 +05:30
ruthra kumar
3f8d58c9c6 refactor: add voucher_detail_no to PLE doctype 2023-11-08 10:53:16 +05:30
ruthra kumar
8a3139f6f5 Merge pull request #37901 from frappe/mergify/bp/version-14-hotfix/pr-37887
chore: performance optimization on payment ledger entry doctype (backport #37887)
2023-11-08 10:48:30 +05:30
ruthra kumar
0b601d8cae chore: performance optimization on payment ledger entry doctype
(cherry picked from commit f14d1eb871)
2023-11-08 10:23:52 +05:30
ruthra kumar
9be71e45b9 Merge pull request #37975 from frappe/mergify/bp/version-14-hotfix/pr-37971
refactor: optimize bulk transaction for speed (backport #37971)
2023-11-08 07:08:42 +05:30
ruthra kumar
e58604a90f refactor: optimize for speed
(cherry picked from commit 416bd400bb)
2023-11-08 01:03:28 +00:00
mergify[bot]
e895bb3a63 chore: typo in Stock Entry enqueue msg (backport #37970) (#37972)
chore: typo in `Stock Entry` enqueue msg

(cherry picked from commit ee60fa940c)

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-11-07 15:57:20 +00:00
ruthra kumar
38a5e6f10b Merge pull request #37967 from frappe/mergify/bp/version-14-hotfix/pr-37954
refactor: expand repost to `Expense Claim` and make it configurable (backport #37954)
2023-11-07 16:24:44 +05:30
ruthra kumar
8f0cf1b7dc chore: resolve conflict 2023-11-07 15:56:35 +05:30
ruthra kumar
3da2597703 refactor: update permissions for repost settings
(cherry picked from commit 10b9570429)
2023-11-07 10:14:36 +00:00
ruthra kumar
82bf726b83 refactor(test): repost test case for purchase invoice
(cherry picked from commit 11c8d9fcf1)
2023-11-07 10:14:35 +00:00
ruthra kumar
7d4dc67b61 refactor: select distinct types
(cherry picked from commit 61705047b0)
2023-11-07 10:14:33 +00:00
ruthra kumar
35f5498913 refactor(test): update repost settings for test cases
(cherry picked from commit ac79b8483f)
2023-11-07 10:14:32 +00:00
ruthra kumar
ed557274d2 refactor: support for expense claim repost
(cherry picked from commit b651b36fff)
2023-11-07 10:14:30 +00:00
ruthra kumar
18e6931d78 refactor: configurable repost settings
(cherry picked from commit 5a068410c6)
2023-11-07 10:14:29 +00:00
ruthra kumar
560a45b343 chore: patch to update default repost settings value
(cherry picked from commit ebb186c8df)

# Conflicts:
#	erpnext/patches.txt
2023-11-07 10:14:28 +00:00
ruthra kumar
09cde5da08 feat: settings page for repost
(cherry picked from commit d582a73795)
2023-11-07 10:14:21 +00:00
ruthra kumar
503c0f33bb Merge pull request #37957 from frappe/mergify/bp/version-14-hotfix/pr-37956
fix: type error on new payment entry (backport #37956)
2023-11-07 12:47:10 +05:30
ruthra kumar
38184f77c7 fix: type error on new payment entry
(cherry picked from commit adff287160)
2023-11-07 12:40:16 +05:30
Frappe PR Bot
449b641560 chore(release): Bumped to Version 14.46.7
## [14.46.7](https://github.com/frappe/erpnext/compare/v14.46.6...v14.46.7) (2023-11-06)

### Bug Fixes

* typo in AR report ([d54e756](d54e756453))
2023-11-06 15:33:32 +00:00
ruthra kumar
3cc5e5591d Merge pull request #37951 from frappe/mergify/bp/version-14/pr-37948
fix: typo in AR report (backport #37948)
2023-11-06 21:00:23 +05:30
ruthra kumar
bc5e01e846 Merge pull request #37949 from frappe/mergify/bp/version-14-hotfix/pr-37948
fix: typo in AR report (backport #37948)
2023-11-06 20:55:22 +05:30
ruthra kumar
d54e756453 fix: typo in AR report
(cherry picked from commit 67e74d03ed)
2023-11-06 15:00:11 +00:00
ruthra kumar
3d72ec7ca4 fix: typo in AR report
(cherry picked from commit 67e74d03ed)
2023-11-06 14:56:44 +00:00
mergify[bot]
c53d281b9e fix: add translation wrapper (backport #37911) (#37946)
fix: add translation wrapper

(cherry picked from commit 8722318081)

Co-authored-by: hyaray <hyaray@vip.qq.com>
2023-11-06 19:52:11 +05:30
Frappe PR Bot
94b38b900c chore(release): Bumped to Version 14.46.6
## [14.46.6](https://github.com/frappe/erpnext/compare/v14.46.5...v14.46.6) (2023-11-06)

### Bug Fixes

* don't reset rate if greater than zero in standalone debit note (backport [#37935](https://github.com/frappe/erpnext/issues/37935)) (backport [#37940](https://github.com/frappe/erpnext/issues/37940)) ([#37945](https://github.com/frappe/erpnext/issues/37945)) ([235f166](235f1664e0))
2023-11-06 14:15:53 +00:00
mergify[bot]
235f1664e0 fix: don't reset rate if greater than zero in standalone debit note (backport #37935) (backport #37940) (#37945)
fix: don't reset rate if greater than zero in standalone debit note (backport #37935) (#37940)

* fix: don't reset rate if greater than zero in standalone debit note

(cherry picked from commit 5cce522ecd)

* fix(test): `test_gl_entries_for_standalone_debit_note`

(cherry picked from commit f9fc6c9c9d)

---------

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

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-11-06 19:37:15 +05:30
mergify[bot]
24da29a817 fix: link between parent and child procedure (backport #37903) (#37943)
* fix: link between parent and child procedure

(cherry picked from commit 05f24ede96)

* chore: add missing filters for `Parent Procedure`

(cherry picked from commit 8fbd4cea5b)

* test: add test case for Quality Procedure`

(cherry picked from commit 30c6b83a10)

---------

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-11-06 19:28:19 +05:30
mergify[bot]
64658fc790 fix: don't reset rate if greater than zero in standalone debit note (backport #37935) (#37940)
* fix: don't reset rate if greater than zero in standalone debit note

(cherry picked from commit 5cce522ecd)

* fix(test): `test_gl_entries_for_standalone_debit_note`

(cherry picked from commit f9fc6c9c9d)

---------

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-11-06 19:27:28 +05:30
mergify[bot]
c87012046d fix: make Material Request Item required if Material Request is set in PO (backport #37928) (#37936)
fix: make `Material Request Item` required if `Material Request` is set in PO

(cherry picked from commit a9d91189b0)

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-11-06 17:26:37 +05:30
mergify[bot]
4de97a4fcb feat: reserved production plan sub assembly items (backport #37884) (#37926)
feat: reserved production plan sub assembly items (#37884)

(cherry picked from commit 34d3eb88b3)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2023-11-06 11:40:21 +05:30
ruthra kumar
932d1e7c62 Merge pull request #37924 from frappe/mergify/bp/version-14-hotfix/pr-37879
refactor: flag to toggle billed amy update in DN for Credit Note (backport #37879)
2023-11-06 11:24:08 +05:30
ruthra kumar
71ad448281 refactor(test): enable billed amt update on Sales Return(Cr Note)
(cherry picked from commit 0c5bdbdcf3)
2023-11-06 09:40:32 +05:30
ruthra kumar
6eb867a1e4 refactor: flag to toggle billed amy update in DN for Credit Note
(cherry picked from commit a3191f1c8c)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/sales_invoice.json
2023-11-06 03:11:20 +00:00
mergify[bot]
5e1a89b3f9 fix: POS change amount gl entry with no amount (#37799)
fix: POS change amount gl entry with no amount (#37799)

(cherry picked from commit 2b02ef0066)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-11-05 17:56:19 +05:30
viralkansodiya15
05fed9e352 fix: list index out of range (#37880)
* fix: list index out of range

* fix: changes in error message

* fix: change error message and date comparision

* fix: change a return a value when disposal date is equal to available for use date

* fix: changes to fix linter test failing
2023-11-05 11:54:39 +05:30
mergify[bot]
eb3630bcf8 fix: Quality Inspection Parameter migration - DuplicateEntryError due to case sensitivity (backport #37499) (#37916)
fix: Quality Inspection Parameter migration - DuplicateEntryError due to case sensitivity (#37499)

* fix: account for case-insensitive database primary key for parameter names

* chore: linting

(cherry picked from commit b099590b2c)

Co-authored-by: Richard Case <110036763+casesolved-co-uk@users.noreply.github.com>
2023-11-05 06:16:23 +00:00
ruthra kumar
c2001bec15 Merge pull request #37915 from ruthra-kumar/prevent_precision_based_validation_error_reconciliation
refactor: avoid precision based validation error on reconciliation
2023-11-05 05:58:32 +05:30
ruthra kumar
be925d2d33 refactor: avoid precision based validation error on reconciliation 2023-11-05 05:22:09 +05:30
marination
b0a184e937 fix: Use process.extract to get the corresponding party doc name of the result
- rapidfuzz accepts an iterable or a dict. dict input gives the dict key and value in the result

(cherry picked from commit e0a03789ae)
2023-11-04 15:48:18 +00:00
marination
21b430a575 fix: Set right party name in bank transaction
- If party name and docname are different, set the docname in Bank Transaction

(cherry picked from commit ff1dc72d74)
2023-11-04 15:48:18 +00:00
Anand Baburajan
65dfef021a chore: rename depreciation_amount_based_on_num_days_in_month to daily_prorata_based [v14] (#37898)
chore: rename depreciation_amount_based_on_num_days_in_month to daily_prorata_based
2023-11-03 20:18:20 +00:00
Anand Baburajan
86c6ae6275 chore: rename daily_depreciation in asset to depreciation_amount_based_on_num_days_in_month [v14] (#37895)
chore: rename daily_depreciation to depreciation_amount_based_on_num_days_in_month
2023-11-03 23:26:34 +05:30
mergify[bot]
fed25fac76 perf: index return against for purchase invoice (backport #37881) (#37882)
perf: index return against for purchase invoice (#37881)

(cherry picked from commit 469ae2c7f1)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2023-11-03 21:59:46 +05:30
Anand Baburajan
6b5cffc77a Merge pull request #37889 from anandbaburajan/update_old_loans_disb_account
fix: add missing disbursement account in update_old_loans patch
2023-11-03 21:45:33 +05:30
anandbaburajan
ad64065ec6 fix: add missing disbursement account in update_old_loans patch 2023-11-03 20:57:52 +05:30
mergify[bot]
1a3dae0f9a fix: permission error while creating Supplier Quotation from Portal (backport #37864) (#37870)
* fix: permission error while creating Supplier Quotation from Portal

(cherry picked from commit e019d43d0b)

# Conflicts:
#	erpnext/controllers/buying_controller.py

* chore: `conflicts`

---------

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-11-03 16:24:36 +05:30
ruthra kumar
15308c9aac Merge pull request #37875 from frappe/mergify/bp/version-14-hotfix/pr-37852
refactor: better ledger comparision report (backport #37852)
2023-11-03 13:25:22 +05:30
ruthra kumar
09ba6c1266 Merge pull request #37873 from frappe/mergify/bp/version-14-hotfix/pr-37869
refactor: 'group only by voucher' flag in AR/AP report (backport #37869)
2023-11-03 13:25:04 +05:30
ruthra kumar
afa6ed9e22 refactor(test): for ledger comparision report
(cherry picked from commit 639f427d6d)
2023-11-03 07:22:59 +00:00
ruthra kumar
3d2ff7eea3 refactor: better output on gl and pl comparison report
(cherry picked from commit 539f0251d9)
2023-11-03 07:22:58 +00:00
ruthra kumar
ee5898a773 refactor: group only by voucher flag in AR/AP report
(cherry picked from commit 23beb46d15)
2023-11-03 07:00:25 +00:00
mergify[bot]
2c93f81d59 perf: Add index to supplier invoice field (backport #37861) (#37862)
fix: Add index to supplier invoice field (#37861)

* fix: Add index to supplier invoice field

* chore: remove unintetional changes

(cherry picked from commit c37e374fdd)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-11-03 11:52:07 +05:30
mergify[bot]
e19cade12d fix: remove voucher type and no for Item and Warehouse based reposting (backport #37849) (#37850)
* fix: remove voucher type and no for Item and Warehouse based reposting

(cherry picked from commit 0104897d69)

* chore: fix test cases

---------

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
2023-11-02 15:15:53 +05:30
mergify[bot]
273cc35b91 fix: gov compliance for tax withholding report (#37590)
* refactor: avoid relying only on against in tds docs query

(cherry picked from commit 705dadae8e)

* chore: change column order

(cherry picked from commit 7ecc0d5a04)

* fix: sort by section code

(cherry picked from commit 4471ad581e)

* feat: proprietorship & partnership options in entity type

(cherry picked from commit ed2457bddf)

# Conflicts:
#	erpnext/buying/doctype/supplier/supplier.json
#	erpnext/selling/doctype/customer/customer.json

* chore: linting issues

(cherry picked from commit 75441017c6)

* feat: add cols for supplier inv details

(cherry picked from commit 6d5ccde864)

* chore: resolve conflicts

* chore: resolve conflicts

* chore: linting issues

---------

Co-authored-by: Gursheen Anand <gursheen@frappe.io>
Co-authored-by: Gursheen Kaur Anand <40693548+GursheenK@users.noreply.github.com>
2023-11-02 14:34:23 +05:30
mergify[bot]
69b569df46 fix: standard submit perm in repost ledger for editable invoices (backport #37826) (#37854)
fix: standard submit perm in repost ledger for editable invoices (#37826)

* fix: ignore perm while reposting ledger

* fix: use flag in save

* fix: remove unnecessary save

(cherry picked from commit 1b808e1d7c)

Co-authored-by: Gursheen Kaur Anand <40693548+GursheenK@users.noreply.github.com>
2023-11-02 14:33:33 +05:30
rohitwaghchaure
a07d58bd0e Merge pull request #37841 from frappe/mergify/bp/version-14-hotfix/pr-37819
fix: `TypeError` in PR for non-stock item (backport #37819)
2023-11-02 13:34:23 +05:30
ruthra kumar
50fdc9dda0 Merge pull request #37846 from frappe/mergify/copy/version-14-hotfix/pr-37845
chore: add std permissions for Process Payment Reconciilation log (copy #37845)
2023-11-02 12:10:27 +05:30
ruthra kumar
9b0a46853f chore: std permissions for Process Payment Reconciilation log
(cherry picked from commit a9fceeb00f)
2023-11-02 06:10:54 +00:00
ruthra kumar
64d7590bd0 Merge pull request #37843 from frappe/mergify/bp/version-14-hotfix/pr-37838
refactor: pass limits to JE and PE queries in reconciliation tool (backport #37838)
2023-11-02 11:08:51 +05:30
mergify[bot]
e8a706a5ea feat(Stock Balance): add filters from route (backport #37836) (#37839)
feat(Stock Balance): add filters from route

(cherry picked from commit 38e5e4a893)

Co-authored-by: barredterra <14891507+barredterra@users.noreply.github.com>
2023-11-02 10:46:42 +05:30
ruthra kumar
289236d065 refactor: pass limits to JE and PE queries in reconciliation tool
(cherry picked from commit 54e8ce1ac5)
2023-11-02 05:13:08 +00:00
s-aga-r
ef4471f8c0 fix: TypeError in PR for non-stock item
(cherry picked from commit 028b3e2fbf)
2023-11-02 05:10:19 +00:00
ruthra kumar
e616a0bb63 Merge pull request #37833 from frappe/mergify/bp/version-14-hotfix/pr-37832
refactor: checkbox to toggle remarks in General Ledger (backport #37832)
2023-11-02 08:06:40 +05:30
ruthra kumar
174b76f6ff refactor: checkbox to toggle remarks in General Ledger
(cherry picked from commit 8fa677b8e8)
2023-11-02 07:28:42 +05:30
mergify[bot]
875d7f8b72 refactor: update fields label and remove unused fields from BIN (backport #37827) (#37829)
* refactor: rearrange fields and update label

(cherry picked from commit ec1a7869f8)

* refactor: remove unused fields `fcfs_rate` and `ma_rate` from Bin

(cherry picked from commit f0a1f4ac7c)

---------

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-11-01 16:41:33 +05:30
Raffael Meyer
2c1fdecc91 chore: resolve merge conflicts 2023-11-01 11:54:29 +01:00
barredterra
4d2169e48e fix(translations): suggestions from review
(cherry picked from commit 115f024260)
2023-11-01 09:43:41 +00:00
barredterra
b75aae99ca fix: german translations of Accounts Settings
(cherry picked from commit b3486b43c4)

# Conflicts:
#	erpnext/translations/de.csv
2023-11-01 09:43:40 +00:00
Deepesh Garg
f502ec2268 Merge pull request #37821 from frappe/mergify/bp/version-14-hotfix/pr-37635
fix: validate sales order item with quotation (backport #37635)
2023-11-01 15:13:26 +05:30
Deepesh Garg
0196d7ac23 Merge pull request #37717 from frappe/mergify/bp/version-14-hotfix/pr-37690
fix(plaid): Do not sync pending transactions (#37690)
2023-11-01 14:12:33 +05:30
Deepesh Garg
357697702b chore: resolve conflicts 2023-11-01 14:11:36 +05:30
Gursheen Anand
4a225b069b fix: validate so item with qtn
(cherry picked from commit 17ebc1ea80)
2023-11-01 08:34:50 +00:00
Deepesh Garg
28c9458482 Merge pull request #37815 from frappe/mergify/bp/version-14-hotfix/pr-37680
fix: status when over delivery or billing in SO (#37680)
2023-11-01 14:03:59 +05:30
Gursheen Anand
d8e743013f fix: status for over delivery or billing
(cherry picked from commit d69b0d76dd)
2023-11-01 07:00:14 +00:00
Deepesh Garg
555cc62e50 Merge pull request #37812 from frappe/mergify/bp/version-14-hotfix/pr-37737
fix: fetch asset received but not billed account only when needed (backport #37737)
2023-11-01 12:10:04 +05:30
Deepesh Garg
7df4009dd3 fix: fetch asset received but not billed account only when needed
(cherry picked from commit 3a8736374c)
2023-11-01 04:49:59 +00:00
ruthra kumar
08a9a9d188 Merge pull request #37806 from frappe/mergify/bp/version-14-hotfix/pr-37795
chore: update default limit values in reconciliation tool (backport #37795)
2023-10-31 20:37:40 +05:30
ruthra kumar
e98be384f9 Merge pull request #37804 from frappe/mergify/bp/version-14-hotfix/pr-37793
refactor: pull remarks only if needed on AR/AP report (backport #37793)
2023-10-31 20:37:06 +05:30
ruthra kumar
fdf2977ce2 chore: update default limit values in reconciliation tool
(cherry picked from commit 1fd888175f)
2023-10-31 14:22:29 +00:00
ruthra kumar
3276f39740 refactor: pull remarks only if needed on AR/AP report
(cherry picked from commit eb73017798)
2023-10-31 14:21:52 +00:00
mergify[bot]
0b1da08d78 fix: In-Transit Warehouse company filter (backport #37796) (#37797)
fix: In-Transit Warehouse company filter (#37796)

(cherry picked from commit daf2ec063c)

Co-authored-by: hyaray <hyaray@vip.qq.com>
2023-10-31 18:53:37 +05:30
Deepesh Garg
ffdc11bbf6 fix(plaid): Do not sync pending transactions
(cherry picked from commit 46ea868559)

# Conflicts:
#	erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
2023-10-27 06:08:46 +00:00
177 changed files with 1495 additions and 573 deletions

View File

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

View File

@@ -112,7 +112,8 @@ class AutoMatchbyPartyNameDescription:
for party in parties:
filters = {"status": "Active"} if party == "Employee" else {"disabled": 0}
names = frappe.get_all(party, filters=filters, pluck=party.lower() + "_name")
field = party.lower() + "_name"
names = frappe.get_all(party, filters=filters, fields=[f"{field} as party_name", "name"])
for field in ["bank_party_name", "description"]:
if not self.get(field):
@@ -131,7 +132,11 @@ class AutoMatchbyPartyNameDescription:
def fuzzy_search_and_return_result(self, party, names, field) -> Union[Tuple, None]:
skip = False
result = process.extract(query=self.get(field), choices=names, scorer=fuzz.token_set_ratio)
result = process.extract(
query=self.get(field),
choices={row.get("name"): row.get("party_name") for row in names},
scorer=fuzz.token_set_ratio,
)
party_name, skip = self.process_fuzzy_result(result)
if not party_name:
@@ -149,14 +154,14 @@ class AutoMatchbyPartyNameDescription:
Returns: Result, Skip (whether or not to discontinue matching)
"""
PARTY, SCORE, CUTOFF = 0, 1, 80
SCORE, PARTY_ID, CUTOFF = 1, 2, 80
if not result or not len(result):
return None, False
first_result = result[0]
if len(result) == 1:
return (first_result[PARTY] if first_result[SCORE] > CUTOFF else None), True
return (first_result[PARTY_ID] if first_result[SCORE] > CUTOFF else None), True
second_result = result[1]
if first_result[SCORE] > CUTOFF:
@@ -165,7 +170,7 @@ class AutoMatchbyPartyNameDescription:
if first_result[SCORE] == second_result[SCORE]:
return None, True
return first_result[PARTY], True
return first_result[PARTY_ID], True
else:
return None, False

View File

@@ -89,7 +89,6 @@ class BankTransaction(StatusUpdater):
- 0 > a: Error: already over-allocated
- clear means: set the latest transaction date as clearance date
"""
gl_bank_account = frappe.db.get_value("Bank Account", self.bank_account, "account")
remaining_amount = self.unallocated_amount
for payment_entry in self.payment_entries:
if payment_entry.allocated_amount == 0.0:

View File

@@ -53,10 +53,18 @@ frappe.ui.form.on('Chart of Accounts Importer', {
of Accounts. Please enter the account names and add more rows as per your requirement.`);
}
}
}
},
{
label : "Company",
fieldname: "company",
fieldtype: "Link",
reqd: 1,
hidden: 1,
default: frm.doc.company,
},
],
primary_action: function() {
var data = d.get_values();
let data = d.get_values();
if (!data.template_type) {
frappe.throw(__('Please select <b>Template Type</b> to download template'));
@@ -66,7 +74,8 @@ frappe.ui.form.on('Chart of Accounts Importer', {
'/api/method/erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.download_template',
{
file_type: data.file_type,
template_type: data.template_type
template_type: data.template_type,
company: data.company
}
);

View File

@@ -8,6 +8,7 @@ from functools import reduce
import frappe
from frappe import _
from frappe.desk.form.linked_with import get_linked_fields
from frappe.model.document import Document
from frappe.utils import cint, cstr
from frappe.utils.csvutils import UnicodeWriter
@@ -294,10 +295,8 @@ def build_response_as_excel(writer):
@frappe.whitelist()
def download_template(file_type, template_type):
data = frappe._dict(frappe.local.form_dict)
writer = get_template(template_type)
def download_template(file_type, template_type, company):
writer = get_template(template_type, company)
if file_type == "CSV":
# download csv file
@@ -308,8 +307,7 @@ def download_template(file_type, template_type):
build_response_as_excel(writer)
def get_template(template_type):
def get_template(template_type, company):
fields = [
"Account Name",
"Parent Account",
@@ -335,34 +333,17 @@ def get_template(template_type):
["", "", "", "", 0, account_type.get("account_type"), account_type.get("root_type")]
)
else:
writer = get_sample_template(writer)
writer = get_sample_template(writer, company)
return writer
def get_sample_template(writer):
template = [
["Application Of Funds(Assets)", "", "", "", 1, "", "Asset"],
["Sources Of Funds(Liabilities)", "", "", "", 1, "", "Liability"],
["Equity", "", "", "", 1, "", "Equity"],
["Expenses", "", "", "", 1, "", "Expense"],
["Income", "", "", "", 1, "", "Income"],
["Bank Accounts", "Application Of Funds(Assets)", "", "", 1, "Bank", "Asset"],
["Cash In Hand", "Application Of Funds(Assets)", "", "", 1, "Cash", "Asset"],
["Stock Assets", "Application Of Funds(Assets)", "", "", 1, "Stock", "Asset"],
["Cost Of Goods Sold", "Expenses", "", "", 0, "Cost of Goods Sold", "Expense"],
["Asset Depreciation", "Expenses", "", "", 0, "Depreciation", "Expense"],
["Fixed Assets", "Application Of Funds(Assets)", "", "", 0, "Fixed Asset", "Asset"],
["Accounts Payable", "Sources Of Funds(Liabilities)", "", "", 0, "Payable", "Liability"],
["Accounts Receivable", "Application Of Funds(Assets)", "", "", 1, "Receivable", "Asset"],
["Stock Expenses", "Expenses", "", "", 0, "Stock Adjustment", "Expense"],
["Sample Bank", "Bank Accounts", "", "", 0, "Bank", "Asset"],
["Cash", "Cash In Hand", "", "", 0, "Cash", "Asset"],
["Stores", "Stock Assets", "", "", 0, "Stock", "Asset"],
]
for row in template:
writer.writerow(row)
def get_sample_template(writer, company):
currency = frappe.db.get_value("Company", company, "default_currency")
with open(os.path.join(os.path.dirname(__file__), "coa_sample_template.csv"), "r") as f:
for row in f:
row = row.strip().split(",") + [currency]
writer.writerow(row)
return writer
@@ -453,14 +434,11 @@ def get_mandatory_account_types():
def unset_existing_data(company):
linked = frappe.db.sql(
'''select fieldname from tabDocField
where fieldtype="Link" and options="Account" and parent="Company"''',
as_dict=True,
)
# remove accounts data from company
update_values = {d.fieldname: "" for d in linked}
fieldnames = get_linked_fields("Account").get("Company", {}).get("fieldname", [])
linked = [{"fieldname": name} for name in fieldnames]
update_values = {d.get("fieldname"): "" for d in linked}
frappe.db.set_value("Company", company, update_values, update_values)
# remove accounts data from various doctypes

View File

@@ -0,0 +1,17 @@
Application Of Funds(Assets),,,,1,,Asset
Sources Of Funds(Liabilities),,,,1,,Liability
Equity,,,,1,,Equity
Expenses,,,,1,Expense Account,Expense
Income,,,,1,Income Account,Income
Bank Accounts,Application Of Funds(Assets),,,1,Bank,Asset
Cash In Hand,Application Of Funds(Assets),,,1,Cash,Asset
Stock Assets,Application Of Funds(Assets),,,1,Stock,Asset
Cost Of Goods Sold,Expenses,,,0,Cost of Goods Sold,Expense
Asset Depreciation,Expenses,,,0,Depreciation,Expense
Fixed Assets,Application Of Funds(Assets),,,0,Fixed Asset,Asset
Accounts Payable,Sources Of Funds(Liabilities),,,0,Payable,Liability
Accounts Receivable,Application Of Funds(Assets),,,1,Receivable,Asset
Stock Expenses,Expenses,,,0,Stock Adjustment,Expense
Sample Bank,Bank Accounts,,,0,Bank,Asset
Cash,Cash In Hand,,,0,Cash,Asset
Stores,Stock Assets,,,0,Stock,Asset
1 Application Of Funds(Assets) 1 Asset
2 Sources Of Funds(Liabilities) 1 Liability
3 Equity 1 Equity
4 Expenses 1 Expense Account Expense
5 Income 1 Income Account Income
6 Bank Accounts Application Of Funds(Assets) 1 Bank Asset
7 Cash In Hand Application Of Funds(Assets) 1 Cash Asset
8 Stock Assets Application Of Funds(Assets) 1 Stock Asset
9 Cost Of Goods Sold Expenses 0 Cost of Goods Sold Expense
10 Asset Depreciation Expenses 0 Depreciation Expense
11 Fixed Assets Application Of Funds(Assets) 0 Fixed Asset Asset
12 Accounts Payable Sources Of Funds(Liabilities) 0 Payable Liability
13 Accounts Receivable Application Of Funds(Assets) 1 Receivable Asset
14 Stock Expenses Expenses 0 Stock Adjustment Expense
15 Sample Bank Bank Accounts 0 Bank Asset
16 Cash Cash In Hand 0 Cash Asset
17 Stores Stock Assets 0 Stock Asset

View File

@@ -152,7 +152,7 @@ frappe.ui.form.on('Payment Entry', {
frm.events.hide_unhide_fields(frm);
frm.events.set_dynamic_labels(frm);
frm.events.show_general_ledger(frm);
if(frm.doc.references.find((elem) => {return elem.exchange_gain_loss != 0})) {
if((frm.doc.references) && (frm.doc.references.find((elem) => {return elem.exchange_gain_loss != 0}))) {
frm.add_custom_button(__("View Exchange Gain/Loss Journals"), function() {
frappe.set_route("List", "Journal Entry", {"voucher_type": "Exchange Gain Or Loss", "reference_name": frm.doc.name});
}, __('Actions'));

View File

@@ -13,6 +13,7 @@
"party_type",
"party",
"due_date",
"voucher_detail_no",
"cost_center",
"finance_book",
"voucher_type",
@@ -64,7 +65,8 @@
"fieldtype": "Link",
"in_standard_filter": 1,
"label": "Voucher Type",
"options": "DocType"
"options": "DocType",
"search_index": 1
},
{
"fieldname": "voucher_no",
@@ -72,14 +74,16 @@
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Voucher No",
"options": "voucher_type"
"options": "voucher_type",
"search_index": 1
},
{
"fieldname": "against_voucher_type",
"fieldtype": "Link",
"in_standard_filter": 1,
"label": "Against Voucher Type",
"options": "DocType"
"options": "DocType",
"search_index": 1
},
{
"fieldname": "against_voucher_no",
@@ -87,7 +91,8 @@
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Against Voucher No",
"options": "against_voucher_type"
"options": "against_voucher_type",
"search_index": 1
},
{
"fieldname": "amount",
@@ -143,12 +148,18 @@
"fieldname": "remarks",
"fieldtype": "Text",
"label": "Remarks"
},
{
"fieldname": "voucher_detail_no",
"fieldtype": "Data",
"label": "Voucher Detail No",
"search_index": 1
}
],
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2023-10-30 16:15:00.470283",
"modified": "2023-11-08 10:53:10.664896",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Ledger Entry",

View File

@@ -93,6 +93,8 @@ class PaymentReconciliation(Document):
"t2.against_account like %(bank_cash_account)s" if self.bank_cash_account else "1=1"
)
limit = f"limit {self.payment_limit}" if self.payment_limit else " "
# nosemgrep
journal_entries = frappe.db.sql(
"""
@@ -116,11 +118,13 @@ class PaymentReconciliation(Document):
ELSE {bank_account_condition}
END)
order by t1.posting_date
{limit}
""".format(
**{
"dr_or_cr": dr_or_cr,
"bank_account_condition": bank_account_condition,
"condition": condition,
"limit": limit,
}
),
{
@@ -146,7 +150,7 @@ class PaymentReconciliation(Document):
if self.payment_name:
conditions.append(doc.name.like(f"%{self.payment_name}%"))
self.return_invoices = (
self.return_invoices_query = (
qb.from_(doc)
.select(
ConstantColumn(voucher_type).as_("voucher_type"),
@@ -154,8 +158,11 @@ class PaymentReconciliation(Document):
doc.return_against,
)
.where(Criterion.all(conditions))
.run(as_dict=True)
)
if self.payment_limit:
self.return_invoices_query = self.return_invoices_query.limit(self.payment_limit)
self.return_invoices = self.return_invoices_query.run(as_dict=True)
def get_dr_or_cr_notes(self):

View File

@@ -185,6 +185,7 @@
"label": "Image"
},
{
"fetch_from": "item_code.image",
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
@@ -821,7 +822,7 @@
],
"istable": 1,
"links": [],
"modified": "2022-11-02 12:52:39.125295",
"modified": "2023-11-14 18:33:22.585715",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice Item",
@@ -831,4 +832,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -110,7 +110,7 @@
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2023-04-21 17:36:26.642617",
"modified": "2023-11-02 11:32:12.254018",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Payment Reconciliation Log",
@@ -125,7 +125,19 @@
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"role": "Accounts Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"share": 1,
"write": 1
}

View File

@@ -383,7 +383,8 @@
"label": "Supplier Invoice No",
"oldfieldname": "bill_no",
"oldfieldtype": "Data",
"print_hide": 1
"print_hide": 1,
"search_index": 1
},
{
"fieldname": "column_break_15",
@@ -406,7 +407,8 @@
"no_copy": 1,
"options": "Purchase Invoice",
"print_hide": 1,
"read_only": 1
"read_only": 1,
"search_index": 1
},
{
"fieldname": "section_addresses",
@@ -1592,7 +1594,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
"modified": "2023-10-16 16:24:51.886231",
"modified": "2023-11-03 15:47:30.319200",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@@ -1718,9 +1718,14 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
self.assertTrue(return_pi.docstatus == 1)
def test_gl_entries_for_standalone_debit_note(self):
make_purchase_invoice(qty=5, rate=500, update_stock=True)
from erpnext.stock.doctype.item.test_item import make_item
returned_inv = make_purchase_invoice(qty=-5, rate=5, update_stock=True, is_return=True)
item_code = make_item(properties={"is_stock_item": 1})
make_purchase_invoice(item_code=item_code, qty=5, rate=500, update_stock=True)
returned_inv = make_purchase_invoice(
item_code=item_code, qty=-5, rate=5, update_stock=True, is_return=True
)
# override the rate with valuation rate
sle = frappe.get_all(
@@ -1730,7 +1735,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
)[0]
rate = flt(sle.stock_value_difference) / flt(sle.actual_qty)
self.assertAlmostEqual(returned_inv.items[0].rate, rate)
self.assertAlmostEqual(rate, 500)
def test_payment_allocation_for_payment_terms(self):
from erpnext.buying.doctype.purchase_order.test_purchase_order import (
@@ -1833,6 +1838,12 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
disable_dimension()
def test_repost_accounting_entries(self):
# update repost settings
settings = frappe.get_doc("Repost Accounting Ledger Settings")
if not [x for x in settings.allowed_types if x.document_type == "Purchase Invoice"]:
settings.append("allowed_types", {"document_type": "Purchase Invoice", "allowed": True})
settings.save()
pi = make_purchase_invoice(
rate=1000,
price_list_rate=1000,

View File

@@ -156,6 +156,7 @@
"width": "300px"
},
{
"fetch_from": "item_code.image",
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
@@ -890,7 +891,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2023-10-03 21:01:01.824892",
"modified": "2023-11-14 18:33:48.547297",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",

View File

@@ -5,9 +5,7 @@ frappe.ui.form.on("Repost Accounting Ledger", {
setup: function(frm) {
frm.fields_dict['vouchers'].grid.get_field('voucher_type').get_query = function(doc) {
return {
filters: {
name: ['in', ['Purchase Invoice', 'Sales Invoice', 'Payment Entry', 'Journal Entry']],
}
query: "erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger.get_repost_allowed_types"
}
}

View File

@@ -10,9 +10,12 @@ from frappe.utils.data import comma_and
class RepostAccountingLedger(Document):
def __init__(self, *args, **kwargs):
super(RepostAccountingLedger, self).__init__(*args, **kwargs)
self._allowed_types = set(
["Purchase Invoice", "Sales Invoice", "Payment Entry", "Journal Entry"]
)
self._allowed_types = [
x.document_type
for x in frappe.db.get_all(
"Repost Allowed Types", filters={"allowed": True}, fields=["distinct(document_type)"]
)
]
def validate(self):
self.validate_vouchers()
@@ -157,7 +160,7 @@ def start_repost(account_repost_doc=str) -> None:
doc.docstatus = 1
doc.make_gl_entries()
elif doc.doctype in ["Payment Entry", "Journal Entry"]:
elif doc.doctype in ["Payment Entry", "Journal Entry", "Expense Claim"]:
if not repost_doc.delete_cancelled_entries:
doc.make_gl_entries(1)
doc.make_gl_entries()
@@ -186,3 +189,18 @@ def validate_docs_for_deferred_accounting(sales_docs, purchase_docs):
frappe.bold(comma_and([x[0] for x in docs_with_deferred_expense + docs_with_deferred_revenue]))
)
)
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_repost_allowed_types(doctype, txt, searchfield, start, page_len, filters):
filters = {"allowed": True}
if txt:
filters.update({"document_type": ("like", f"%{txt}%")})
if allowed_types := frappe.db.get_all(
"Repost Allowed Types", filters=filters, fields=["distinct(document_type)"], as_list=1
):
return allowed_types
return []

View File

@@ -20,10 +20,18 @@ class TestRepostAccountingLedger(AccountsTestMixin, FrappeTestCase):
self.create_company()
self.create_customer()
self.create_item()
self.update_repost_settings()
def teadDown(self):
frappe.db.rollback()
def update_repost_settings(self):
allowed_types = ["Sales Invoice", "Purchase Invoice", "Payment Entry", "Journal Entry"]
repost_settings = frappe.get_doc("Repost Accounting Ledger Settings")
for x in allowed_types:
repost_settings.append("allowed_types", {"document_type": x, "allowed": True})
repost_settings.save()
def test_01_basic_functions(self):
si = create_sales_invoice(
item=self.item,

View File

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

View File

@@ -0,0 +1,46 @@
{
"actions": [],
"creation": "2023-11-07 09:57:20.619939",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"allowed_types"
],
"fields": [
{
"fieldname": "allowed_types",
"fieldtype": "Table",
"label": "Allowed Doctypes",
"options": "Repost Allowed Types"
}
],
"in_create": 1,
"issingle": 1,
"links": [],
"modified": "2023-11-07 14:24:13.321522",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Repost Accounting Ledger Settings",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "Administrator",
"share": 1,
"write": 1
},
{
"read": 1,
"role": "System Manager",
"select": 1
}
],
"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 RepostAccountingLedgerSettings(Document):
pass

View File

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

View File

@@ -0,0 +1,45 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2023-11-07 09:58:03.595382",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"document_type",
"column_break_sfzb",
"allowed"
],
"fields": [
{
"fieldname": "document_type",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Doctype",
"options": "DocType"
},
{
"default": "0",
"fieldname": "allowed",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Allowed"
},
{
"fieldname": "column_break_sfzb",
"fieldtype": "Column Break"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2023-11-07 10:01:39.217861",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Repost Allowed Types",
"owner": "Administrator",
"permissions": [],
"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 RepostAllowedTypes(Document):
pass

View File

@@ -181,7 +181,6 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e
erpnext.accounts.unreconcile_payments.add_unreconcile_btn(me.frm);
}
make_maintenance_schedule() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_maintenance_schedule",
@@ -557,15 +556,6 @@ cur_frm.fields_dict.write_off_cost_center.get_query = function(doc) {
}
}
// Income Account in Details Table
// --------------------------------
cur_frm.set_query("income_account", "items", function(doc) {
return{
query: "erpnext.controllers.queries.get_income_account",
filters: {'company': doc.company}
}
});
// Cost Center in Details Table
// -----------------------------
cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(doc) {
@@ -660,6 +650,16 @@ frappe.ui.form.on('Sales Invoice', {
};
});
frm.set_query("income_account", "items", function() {
return{
query: "erpnext.controllers.queries.get_income_account",
filters: {
'company': frm.doc.company,
"disabled": 0
}
}
});
frm.custom_make_buttons = {
'Delivery Note': 'Delivery',
'Sales Invoice': 'Return / Credit Note',

View File

@@ -26,6 +26,7 @@
"is_return",
"return_against",
"update_billed_amount_in_sales_order",
"update_billed_amount_in_delivery_note",
"is_debit_note",
"amended_from",
"accounting_dimensions_section",
@@ -2144,6 +2145,13 @@
"fieldname": "use_company_roundoff_cost_center",
"fieldtype": "Check",
"label": "Use Company default Cost Center for Round off"
},
{
"default": "0",
"depends_on": "eval: doc.is_return",
"fieldname": "update_billed_amount_in_delivery_note",
"fieldtype": "Check",
"label": "Update Billed Amount in Delivery Note"
}
],
"icon": "fa fa-file-text",
@@ -2156,7 +2164,7 @@
"link_fieldname": "consolidated_invoice"
}
],
"modified": "2023-06-19 16:02:05.309332",
"modified": "2023-11-03 14:39:38.012346",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -261,6 +261,7 @@ class SalesInvoice(SellingController):
self.update_status_updater_args()
self.update_prevdoc_status()
self.update_billing_status_in_dn()
self.clear_unallocated_mode_of_payments()
@@ -1036,7 +1037,7 @@ class SalesInvoice(SellingController):
def make_customer_gl_entry(self, gl_entries):
# Checked both rounding_adjustment and rounded_total
# because rounded_total had value even before introcution of posting GLE based on rounded total
# because rounded_total had value even before introduction of posting GLE based on rounded total
grand_total = (
self.rounded_total if (self.rounding_adjustment and self.rounded_total) else self.grand_total
)
@@ -1271,7 +1272,7 @@ class SalesInvoice(SellingController):
if skip_change_gl_entries and payment_mode.account == self.account_for_change_amount:
payment_mode.base_amount -= flt(self.change_amount)
if payment_mode.amount:
if payment_mode.base_amount:
# POS, make payment entries
gl_entries.append(
self.get_gl_dict(
@@ -1433,6 +1434,8 @@ class SalesInvoice(SellingController):
)
def update_billing_status_in_dn(self, update_modified=True):
if self.is_return and not self.update_billed_amount_in_delivery_note:
return
updated_delivery_notes = []
for d in self.get("items"):
if d.dn_detail:

View File

@@ -167,6 +167,7 @@
"print_hide": 1
},
{
"fetch_from": "item_code.image",
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
@@ -891,7 +892,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2023-07-25 11:58:10.723833",
"modified": "2023-11-14 18:34:10.479329",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",
@@ -901,4 +902,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -144,6 +144,11 @@ frappe.query_reports["Accounts Payable"] = {
"label": __("Show Future Payments"),
"fieldtype": "Check",
},
{
"fieldname": "for_revaluation_journals",
"label": __("Revaluation Journals"),
"fieldtype": "Check",
},
{
"fieldname": "ignore_accounts",
"label": __("Group by Voucher"),

View File

@@ -110,6 +110,11 @@ frappe.query_reports["Accounts Payable Summary"] = {
"fieldname":"based_on_payment_terms",
"label": __("Based On Payment Terms"),
"fieldtype": "Check",
},
{
"fieldname": "for_revaluation_journals",
"label": __("Revaluation Journals"),
"fieldtype": "Check",
}
],

View File

@@ -114,10 +114,13 @@ frappe.query_reports["Accounts Receivable"] = {
"reqd": 1
},
{
"fieldname": "customer_group",
"fieldname":"customer_group",
"label": __("Customer Group"),
"fieldtype": "Link",
"options": "Customer Group"
"fieldtype": "MultiSelectList",
"options": "Customer Group",
get_data: function(txt) {
return frappe.db.get_link_options('Customer Group', txt);
}
},
{
"fieldname": "payment_terms_template",
@@ -173,12 +176,18 @@ frappe.query_reports["Accounts Receivable"] = {
"label": __("Show Remarks"),
"fieldtype": "Check",
},
{
"fieldname": "for_revaluation_journals",
"label": __("Revaluation Journals"),
"fieldtype": "Check",
},
{
"fieldname": "ignore_accounts",
"label": __("Group by Voucher"),
"fieldtype": "Check",
}
],
"formatter": function(value, row, column, data, default_formatter) {

View File

@@ -117,7 +117,7 @@ class ReceivablePayableReport(object):
for ple in self.ple_entries:
# get the balance object for voucher_type
if self.filters.get("ingore_accounts"):
if self.filters.get("ignore_accounts"):
key = (ple.voucher_type, ple.voucher_no, ple.party)
else:
key = (ple.account, ple.voucher_type, ple.voucher_no, ple.party)
@@ -188,7 +188,7 @@ class ReceivablePayableReport(object):
):
return
if self.filters.get("ingore_accounts"):
if self.filters.get("ignore_accounts"):
key = (ple.against_voucher_type, ple.against_voucher_no, ple.party)
else:
key = (ple.account, ple.against_voucher_type, ple.against_voucher_no, ple.party)
@@ -200,7 +200,7 @@ class ReceivablePayableReport(object):
if ple.against_voucher_no in self.return_entries:
return_against = self.return_entries.get(ple.against_voucher_no)
if return_against:
if self.filters.get("ingore_accounts"):
if self.filters.get("ignore_accounts"):
key = (ple.against_voucher_type, return_against, ple.party)
else:
key = (ple.account, ple.against_voucher_type, return_against, ple.party)
@@ -209,7 +209,7 @@ class ReceivablePayableReport(object):
if not row:
# no invoice, this is an invoice / stand-alone payment / credit note
if self.filters.get("ingore_accounts"):
if self.filters.get("ignore_accounts"):
row = self.voucher_balance.get((ple.voucher_type, ple.voucher_no, ple.party))
else:
row = self.voucher_balance.get((ple.account, ple.voucher_type, ple.voucher_no, ple.party))
@@ -281,11 +281,20 @@ class ReceivablePayableReport(object):
row.invoice_grand_total = row.invoiced
if (abs(row.outstanding) > 1.0 / 10**self.currency_precision) and (
(abs(row.outstanding_in_account_currency) > 1.0 / 10**self.currency_precision)
or (row.voucher_no in self.err_journals)
):
must_consider = False
if self.filters.get("for_revaluation_journals"):
if (abs(row.outstanding) > 1.0 / 10**self.currency_precision) or (
(abs(row.outstanding_in_account_currency) > 1.0 / 10**self.currency_precision)
):
must_consider = True
else:
if (abs(row.outstanding) > 1.0 / 10**self.currency_precision) and (
(abs(row.outstanding_in_account_currency) > 1.0 / 10**self.currency_precision)
or (row.voucher_no in self.err_journals)
):
must_consider = True
if must_consider:
# non-zero oustanding, we must consider this row
if self.is_invoice(row) and self.filters.based_on_payment_terms:
@@ -732,6 +741,7 @@ class ReceivablePayableReport(object):
query = (
qb.from_(ple)
.select(
ple.name,
ple.account,
ple.voucher_type,
ple.voucher_no,
@@ -745,13 +755,15 @@ class ReceivablePayableReport(object):
ple.account_currency,
ple.amount,
ple.amount_in_account_currency,
ple.remarks,
)
.where(ple.delinked == 0)
.where(Criterion.all(self.qb_selection_filter))
.where(Criterion.any(self.or_filters))
)
if self.filters.get("show_remarks"):
query = query.select(ple.remarks)
if self.filters.get("group_by_party"):
query = query.orderby(self.ple.party, self.ple.posting_date)
else:
@@ -837,7 +849,13 @@ class ReceivablePayableReport(object):
self.customer = qb.DocType("Customer")
if self.filters.get("customer_group"):
self.get_hierarchical_filters("Customer Group", "customer_group")
groups = get_customer_group_with_children(self.filters.customer_group)
customers = (
qb.from_(self.customer)
.select(self.customer.name)
.where(self.customer["customer_group"].isin(groups))
)
self.qb_selection_filter.append(self.ple.party.isin(customers))
if self.filters.get("territory"):
self.get_hierarchical_filters("Territory", "territory")
@@ -1129,3 +1147,19 @@ class ReceivablePayableReport(object):
.run()
)
self.err_journals = [x[0] for x in results] if results else []
def get_customer_group_with_children(customer_groups):
if not isinstance(customer_groups, list):
customer_groups = [d.strip() for d in customer_groups.strip().split(",") if d]
all_customer_groups = []
for d in customer_groups:
if frappe.db.exists("Customer Group", d):
lft, rgt = frappe.db.get_value("Customer Group", d, ["lft", "rgt"])
children = frappe.get_all("Customer Group", filters={"lft": [">=", lft], "rgt": ["<=", rgt]})
all_customer_groups += [c.name for c in children]
else:
frappe.throw(_("Customer Group: {0} does not exist").format(d))
return list(set(all_customer_groups))

View File

@@ -475,6 +475,30 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
report = execute(filters)[1]
self.assertEqual(len(report), 0)
def test_multi_customer_group_filter(self):
si = self.create_sales_invoice()
cus_group = frappe.db.get_value("Customer", self.customer, "customer_group")
# Create a list of customer groups, e.g., ["Group1", "Group2"]
cus_groups_list = [cus_group, "_Test Customer Group 1"]
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"customer_group": cus_groups_list, # Use the list of customer groups
}
report = execute(filters)[1]
# Assert that the report contains data for the specified customer groups
self.assertTrue(len(report) > 0)
for row in report:
# Assert that the customer group of each row is in the list of customer groups
self.assertIn(row.customer_group, cus_groups_list)
def test_party_account_filter(self):
si1 = self.create_sales_invoice()
self.customer2 = (

View File

@@ -139,6 +139,11 @@ frappe.query_reports["Accounts Receivable Summary"] = {
"label": __("Show GL Balance"),
"fieldtype": "Check",
},
{
"fieldname": "for_revaluation_journals",
"label": __("Revaluation Journals"),
"fieldtype": "Check",
}
],
onload: function(report) {

View File

@@ -31,6 +31,18 @@ frappe.query_reports["Asset Depreciation Ledger"] = {
"fieldtype": "Link",
"options": "Asset"
},
{
"fieldname":"asset_category",
"label": __("Asset Category"),
"fieldtype": "Link",
"options": "Asset Category"
},
{
"fieldname":"cost_center",
"label": __("Cost Center"),
"fieldtype": "Link",
"options": "Cost Center"
},
{
"fieldname":"finance_book",
"label": __("Finance Book"),
@@ -38,10 +50,10 @@ frappe.query_reports["Asset Depreciation Ledger"] = {
"options": "Finance Book"
},
{
"fieldname":"asset_category",
"label": __("Asset Category"),
"fieldtype": "Link",
"options": "Asset Category"
}
"fieldname": "include_default_book_assets",
"label": __("Include Default FB Assets"),
"fieldtype": "Check",
"default": 1
},
]
}

View File

@@ -1,15 +1,15 @@
{
"add_total_row": 1,
"add_total_row": 0,
"columns": [],
"creation": "2016-04-08 14:49:58.133098",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 2,
"idx": 6,
"is_standard": "Yes",
"letterhead": null,
"modified": "2023-07-26 21:05:33.554778",
"modified": "2023-11-08 20:17:05.774211",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Asset Depreciation Ledger",

View File

@@ -4,7 +4,7 @@
import frappe
from frappe import _
from frappe.utils import flt
from frappe.utils import cstr, flt
def execute(filters=None):
@@ -32,7 +32,6 @@ def get_data(filters):
filters_data.append(["against_voucher", "=", filters.get("asset")])
if filters.get("asset_category"):
assets = frappe.db.sql_list(
"""select name from tabAsset
where asset_category = %s and docstatus=1""",
@@ -41,12 +40,27 @@ def get_data(filters):
filters_data.append(["against_voucher", "in", assets])
if filters.get("finance_book"):
filters_data.append(["finance_book", "in", ["", filters.get("finance_book")]])
company_fb = frappe.get_cached_value("Company", filters.get("company"), "default_finance_book")
if filters.get("include_default_book_assets") and company_fb:
if filters.get("finance_book") and cstr(filters.get("finance_book")) != cstr(company_fb):
frappe.throw(_("To use a different finance book, please uncheck 'Include Default FB Assets'"))
else:
finance_book = company_fb
elif filters.get("finance_book"):
finance_book = filters.get("finance_book")
else:
finance_book = None
if finance_book:
or_filters_data = [["finance_book", "in", ["", finance_book]], ["finance_book", "is", "not set"]]
else:
or_filters_data = [["finance_book", "in", [""]], ["finance_book", "is", "not set"]]
gl_entries = frappe.get_all(
"GL Entry",
filters=filters_data,
or_filters=or_filters_data,
fields=["against_voucher", "debit_in_account_currency as debit", "voucher_no", "posting_date"],
order_by="against_voucher, posting_date",
)
@@ -61,7 +75,9 @@ def get_data(filters):
asset_data = assets_details.get(d.against_voucher)
if asset_data:
if not asset_data.get("accumulated_depreciation_amount"):
asset_data.accumulated_depreciation_amount = d.debit
asset_data.accumulated_depreciation_amount = d.debit + asset_data.get(
"opening_accumulated_depreciation"
)
else:
asset_data.accumulated_depreciation_amount += d.debit
@@ -70,7 +86,7 @@ def get_data(filters):
{
"depreciation_amount": d.debit,
"depreciation_date": d.posting_date,
"amount_after_depreciation": (
"value_after_depreciation": (
flt(row.gross_purchase_amount) - flt(row.accumulated_depreciation_amount)
),
"depreciation_entry": d.voucher_no,
@@ -88,10 +104,12 @@ def get_assets_details(assets):
fields = [
"name as asset",
"gross_purchase_amount",
"opening_accumulated_depreciation",
"asset_category",
"status",
"depreciation_method",
"purchase_date",
"cost_center",
]
for d in frappe.get_all("Asset", fields=fields, filters={"name": ("in", assets)}):
@@ -121,6 +139,12 @@ def get_columns():
"fieldtype": "Currency",
"width": 120,
},
{
"label": _("Opening Accumulated Depreciation"),
"fieldname": "opening_accumulated_depreciation",
"fieldtype": "Currency",
"width": 140,
},
{
"label": _("Depreciation Amount"),
"fieldname": "depreciation_amount",
@@ -134,8 +158,8 @@ def get_columns():
"width": 210,
},
{
"label": _("Amount After Depreciation"),
"fieldname": "amount_after_depreciation",
"label": _("Value After Depreciation"),
"fieldname": "value_after_depreciation",
"fieldtype": "Currency",
"width": 180,
},
@@ -153,12 +177,13 @@ def get_columns():
"options": "Asset Category",
"width": 120,
},
{"label": _("Current Status"), "fieldname": "status", "fieldtype": "Data", "width": 120},
{
"label": _("Depreciation Method"),
"fieldname": "depreciation_method",
"fieldtype": "Data",
"width": 130,
"label": _("Cost Center"),
"fieldtype": "Link",
"fieldname": "cost_center",
"options": "Cost Center",
"width": 100,
},
{"label": _("Current Status"), "fieldname": "status", "fieldtype": "Data", "width": 120},
{"label": _("Purchase Date"), "fieldname": "purchase_date", "fieldtype": "Date", "width": 120},
]

View File

@@ -15,7 +15,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
frappe.query_reports["Balance Sheet"]["filters"].push({
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"label": __("Include Default FB Entries"),
"fieldtype": "Check",
"default": 1
});

View File

@@ -16,7 +16,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
frappe.query_reports["Cash Flow"]["filters"].push(
{
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"label": __("Include Default FB Entries"),
"fieldtype": "Check",
"default": 1
}

View File

@@ -105,7 +105,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
},
{
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"label": __("Include Default FB Entries"),
"fieldtype": "Check",
"default": 1
},

View File

@@ -561,9 +561,7 @@ def apply_additional_conditions(doctype, query, from_date, ignore_closing_entrie
company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book")
if filters.finance_book and company_fb and cstr(filters.finance_book) != cstr(company_fb):
frappe.throw(
_("To use a different finance book, please uncheck 'Include Default Book Entries'")
)
frappe.throw(_("To use a different finance book, please uncheck 'Include Default FB Entries'"))
query = query.where(
(gl_entry.finance_book.isin([cstr(filters.finance_book), cstr(company_fb), ""]))

View File

@@ -79,7 +79,9 @@ class General_Payment_Ledger_Comparison(object):
.select(
gle.company,
gle.account,
gle.voucher_type,
gle.voucher_no,
gle.party_type,
gle.party,
outstanding,
)
@@ -89,7 +91,9 @@ class General_Payment_Ledger_Comparison(object):
& (gle.account.isin(val.accounts))
)
.where(Criterion.all(filter_criterion))
.groupby(gle.company, gle.account, gle.voucher_no, gle.party)
.groupby(
gle.company, gle.account, gle.voucher_type, gle.voucher_no, gle.party_type, gle.party
)
.run()
)
@@ -112,7 +116,13 @@ class General_Payment_Ledger_Comparison(object):
self.account_types[acc_type].ple = (
qb.from_(ple)
.select(
ple.company, ple.account, ple.voucher_no, ple.party, Sum(ple.amount).as_("outstanding")
ple.company,
ple.account,
ple.voucher_type,
ple.voucher_no,
ple.party_type,
ple.party,
Sum(ple.amount).as_("outstanding"),
)
.where(
(ple.company == self.filters.company)
@@ -120,7 +130,9 @@ class General_Payment_Ledger_Comparison(object):
& (ple.account.isin(val.accounts))
)
.where(Criterion.all(filter_criterion))
.groupby(ple.company, ple.account, ple.voucher_no, ple.party)
.groupby(
ple.company, ple.account, ple.voucher_type, ple.voucher_no, ple.party_type, ple.party
)
.run()
)
@@ -138,12 +150,12 @@ class General_Payment_Ledger_Comparison(object):
self.diff = frappe._dict({})
for x in self.variation_in_payment_ledger:
self.diff[(x[0], x[1], x[2], x[3])] = frappe._dict({"gl_balance": x[4]})
self.diff[(x[0], x[1], x[2], x[3], x[4], x[5])] = frappe._dict({"gl_balance": x[6]})
for x in self.variation_in_general_ledger:
self.diff.setdefault((x[0], x[1], x[2], x[3]), frappe._dict({"gl_balance": 0.0})).update(
frappe._dict({"pl_balance": x[4]})
)
self.diff.setdefault(
(x[0], x[1], x[2], x[3], x[4], x[5]), frappe._dict({"gl_balance": 0.0})
).update(frappe._dict({"pl_balance": x[6]}))
def generate_data(self):
self.data = []
@@ -151,8 +163,12 @@ class General_Payment_Ledger_Comparison(object):
self.data.append(
frappe._dict(
{
"voucher_no": key[2],
"party": key[3],
"company": key[0],
"account": key[1],
"voucher_type": key[2],
"voucher_no": key[3],
"party_type": key[4],
"party": key[5],
"gl_balance": val.gl_balance,
"pl_balance": val.pl_balance,
}
@@ -162,12 +178,52 @@ class General_Payment_Ledger_Comparison(object):
def get_columns(self):
self.columns = []
options = None
self.columns.append(
dict(
label=_("Company"),
fieldname="company",
fieldtype="Link",
options="Company",
width="100",
)
)
self.columns.append(
dict(
label=_("Account"),
fieldname="account",
fieldtype="Link",
options="Account",
width="100",
)
)
self.columns.append(
dict(
label=_("Voucher Type"),
fieldname="voucher_type",
fieldtype="Link",
options="DocType",
width="100",
)
)
self.columns.append(
dict(
label=_("Voucher No"),
fieldname="voucher_no",
fieldtype="Data",
options=options,
fieldtype="Dynamic Link",
options="voucher_type",
width="100",
)
)
self.columns.append(
dict(
label=_("Party Type"),
fieldname="party_type",
fieldtype="Link",
options="DocType",
width="100",
)
)
@@ -176,8 +232,8 @@ class General_Payment_Ledger_Comparison(object):
dict(
label=_("Party"),
fieldname="party",
fieldtype="Data",
options=options,
fieldtype="Dynamic Link",
options="party_type",
width="100",
)
)

View File

@@ -50,7 +50,11 @@ class TestGeneralAndPaymentLedger(FrappeTestCase, AccountsTestMixin):
self.assertEqual(len(data), 1)
expected = {
"company": sinv.company,
"account": sinv.debit_to,
"voucher_type": sinv.doctype,
"voucher_no": sinv.name,
"party_type": "Customer",
"party": sinv.customer,
"gl_balance": sinv.grand_total,
"pl_balance": sinv.grand_total - 1,

View File

@@ -175,7 +175,7 @@ frappe.query_reports["General Ledger"] = {
},
{
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"label": __("Include Default FB Entries"),
"fieldtype": "Check",
"default": 1
},
@@ -188,7 +188,13 @@ frappe.query_reports["General Ledger"] = {
"fieldname": "show_net_values_in_party_account",
"label": __("Show Net Values in Party Account"),
"fieldtype": "Check"
},
{
"fieldname": "show_remarks",
"label": __("Show Remarks"),
"fieldtype": "Check"
}
]
}

View File

@@ -163,6 +163,9 @@ def get_gl_entries(filters, accounting_dimensions):
select_fields = """, debit, credit, debit_in_account_currency,
credit_in_account_currency """
if filters.get("show_remarks"):
select_fields += """,remarks"""
order_by_statement = "order by posting_date, account, creation"
if filters.get("include_dimensions"):
@@ -189,7 +192,7 @@ def get_gl_entries(filters, accounting_dimensions):
voucher_type, voucher_no, {dimension_fields}
cost_center, project,
against_voucher_type, against_voucher, account_currency,
remarks, against, is_opening, creation {select_fields}
against, is_opening, creation {select_fields}
from `tabGL Entry`
where company=%(company)s {conditions}
{order_by_statement}
@@ -249,9 +252,7 @@ def get_conditions(filters):
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'")
)
frappe.throw(_("To use a different finance book, please uncheck 'Include Default FB Entries'"))
else:
conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)")
else:
@@ -593,8 +594,10 @@ def get_columns(filters):
"width": 100,
},
{"label": _("Supplier Invoice No"), "fieldname": "bill_no", "fieldtype": "Data", "width": 100},
{"label": _("Remarks"), "fieldname": "remarks", "width": 400},
]
)
if filters.get("show_remarks"):
columns.extend([{"label": _("Remarks"), "fieldname": "remarks", "width": 400}])
return columns

View File

@@ -47,6 +47,7 @@ def get_result(
out = []
for name, details in gle_map.items():
tax_amount, total_amount, grand_total, base_total = 0, 0, 0, 0
bill_no, bill_date = "", ""
tax_withholding_category = tax_category_map.get(name)
rate = tax_rate_map.get(tax_withholding_category)
@@ -70,7 +71,10 @@ def get_result(
if net_total_map.get(name):
if voucher_type == "Journal Entry" and tax_amount and rate:
# back calcalute total amount from rate and tax_amount
total_amount = grand_total = base_total = tax_amount / (rate / 100)
if rate:
total_amount = grand_total = base_total = tax_amount / (rate / 100)
elif voucher_type == "Purchase Invoice":
total_amount, grand_total, base_total, bill_no, bill_date = net_total_map.get(name)
else:
total_amount, grand_total, base_total = net_total_map.get(name)
else:
@@ -96,7 +100,7 @@ def get_result(
row.update(
{
"section_code": tax_withholding_category,
"section_code": tax_withholding_category or "",
"entity_type": party_map.get(party, {}).get(party_type),
"rate": rate,
"total_amount": total_amount,
@@ -106,10 +110,14 @@ def get_result(
"transaction_date": posting_date,
"transaction_type": voucher_type,
"ref_no": name,
"supplier_invoice_no": bill_no,
"supplier_invoice_date": bill_date,
}
)
out.append(row)
out.sort(key=lambda x: x["section_code"])
return out
@@ -157,14 +165,14 @@ def get_gle_map(documents):
def get_columns(filters):
pan = "pan" if frappe.db.has_column(filters.party_type, "pan") else "tax_id"
columns = [
{"label": _(frappe.unscrub(pan)), "fieldname": pan, "fieldtype": "Data", "width": 60},
{
"label": _(filters.get("party_type")),
"fieldname": "party",
"fieldtype": "Dynamic Link",
"options": "party_type",
"width": 180,
"label": _("Section Code"),
"options": "Tax Withholding Category",
"fieldname": "section_code",
"fieldtype": "Link",
"width": 90,
},
{"label": _(frappe.unscrub(pan)), "fieldname": pan, "fieldtype": "Data", "width": 60},
]
if filters.naming_series == "Naming Series":
@@ -179,51 +187,60 @@ def get_columns(filters):
columns.extend(
[
{
"label": _("Date of Transaction"),
"fieldname": "transaction_date",
"fieldtype": "Date",
"width": 100,
},
{
"label": _("Section Code"),
"options": "Tax Withholding Category",
"fieldname": "section_code",
"fieldtype": "Link",
"width": 90,
},
{"label": _("Entity Type"), "fieldname": "entity_type", "fieldtype": "Data", "width": 100},
{
"label": _("Total Amount"),
"fieldname": "total_amount",
"fieldtype": "Float",
"width": 90,
},
]
)
if filters.party_type == "Supplier":
columns.extend(
[
{
"label": _("Supplier Invoice No"),
"fieldname": "supplier_invoice_no",
"fieldtype": "Data",
"width": 120,
},
{
"label": _("Supplier Invoice Date"),
"fieldname": "supplier_invoice_date",
"fieldtype": "Date",
"width": 120,
},
]
)
columns.extend(
[
{
"label": _("TDS Rate %") if filters.get("party_type") == "Supplier" else _("TCS Rate %"),
"fieldname": "rate",
"fieldtype": "Percent",
"width": 90,
"width": 60,
},
{
"label": _("Tax Amount"),
"fieldname": "tax_amount",
"label": _("Total Amount"),
"fieldname": "total_amount",
"fieldtype": "Float",
"width": 90,
},
{
"label": _("Grand Total"),
"fieldname": "grand_total",
"fieldtype": "Float",
"width": 90,
"width": 120,
},
{
"label": _("Base Total"),
"fieldname": "base_total",
"fieldtype": "Float",
"width": 90,
"width": 120,
},
{"label": _("Transaction Type"), "fieldname": "transaction_type", "width": 100},
{
"label": _("Tax Amount"),
"fieldname": "tax_amount",
"fieldtype": "Float",
"width": 120,
},
{
"label": _("Grand Total"),
"fieldname": "grand_total",
"fieldtype": "Float",
"width": 120,
},
{"label": _("Transaction Type"), "fieldname": "transaction_type", "width": 130},
{
"label": _("Reference No."),
"fieldname": "ref_no",
@@ -231,6 +248,12 @@ def get_columns(filters):
"options": "transaction_type",
"width": 180,
},
{
"label": _("Date of Transaction"),
"fieldname": "transaction_date",
"fieldtype": "Date",
"width": 100,
},
]
)
@@ -253,27 +276,7 @@ def get_tds_docs(filters):
"Tax Withholding Account", {"company": filters.get("company")}, pluck="account"
)
query_filters = {
"account": ("in", tds_accounts),
"posting_date": ("between", [filters.get("from_date"), filters.get("to_date")]),
"is_cancelled": 0,
"against": ("not in", bank_accounts),
}
party = frappe.get_all(filters.get("party_type"), pluck="name")
or_filters.update({"against": ("in", party), "voucher_type": "Journal Entry"})
if filters.get("party"):
del query_filters["account"]
del query_filters["against"]
or_filters = {"against": filters.get("party"), "party": filters.get("party")}
tds_docs = frappe.get_all(
"GL Entry",
filters=query_filters,
or_filters=or_filters,
fields=["voucher_no", "voucher_type", "against", "party"],
)
tds_docs = get_tds_docs_query(filters, bank_accounts, tds_accounts).run(as_dict=True)
for d in tds_docs:
if d.voucher_type == "Purchase Invoice":
@@ -309,6 +312,47 @@ def get_tds_docs(filters):
)
def get_tds_docs_query(filters, bank_accounts, tds_accounts):
if not tds_accounts:
frappe.throw(
_("No {0} Accounts found for this company.").format(frappe.bold("Tax Withholding")),
title=_("Accounts Missing Error"),
)
gle = frappe.qb.DocType("GL Entry")
query = (
frappe.qb.from_(gle)
.select("voucher_no", "voucher_type", "against", "party")
.where((gle.is_cancelled == 0))
)
if filters.get("from_date"):
query = query.where(gle.posting_date >= filters.get("from_date"))
if filters.get("to_date"):
query = query.where(gle.posting_date <= filters.get("to_date"))
if bank_accounts:
query = query.where(gle.against.notin(bank_accounts))
if filters.get("party"):
party = [filters.get("party")]
query = query.where(
((gle.account.isin(tds_accounts) & gle.against.isin(party)))
| ((gle.voucher_type == "Journal Entry") & (gle.party == filters.get("party")))
| gle.party.isin(party)
)
else:
party = frappe.get_all(filters.get("party_type"), pluck="name")
query = query.where(
((gle.account.isin(tds_accounts) & gle.against.isin(party)))
| (
(gle.voucher_type == "Journal Entry")
& ((gle.party_type == filters.get("party_type")) | (gle.party_type == ""))
)
| gle.party.isin(party)
)
return query
def get_journal_entry_party_map(journal_entries):
journal_entry_party_map = {}
for d in frappe.db.get_all(
@@ -335,6 +379,8 @@ def get_doc_info(vouchers, doctype, tax_category_map, net_total_map=None):
"base_tax_withholding_net_total",
"grand_total",
"base_total",
"bill_no",
"bill_date",
],
"Sales Invoice": ["base_net_total", "grand_total", "base_total"],
"Payment Entry": [
@@ -353,7 +399,13 @@ def get_doc_info(vouchers, doctype, tax_category_map, net_total_map=None):
for entry in entries:
tax_category_map.update({entry.name: entry.tax_withholding_category})
if doctype == "Purchase Invoice":
value = [entry.base_tax_withholding_net_total, entry.grand_total, entry.base_total]
value = [
entry.base_tax_withholding_net_total,
entry.grand_total,
entry.base_total,
entry.bill_no,
entry.bill_date,
]
elif doctype == "Sales Invoice":
value = [entry.base_net_total, entry.grand_total, entry.base_total]
elif doctype == "Payment Entry":

View File

@@ -96,7 +96,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
},
{
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"label": __("Include Default FB Entries"),
"fieldtype": "Check",
"default": 1
},

View File

@@ -275,9 +275,7 @@ def get_opening_balance(
company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book")
if filters.finance_book and company_fb and cstr(filters.finance_book) != cstr(company_fb):
frappe.throw(
_("To use a different finance book, please uncheck 'Include Default Book Entries'")
)
frappe.throw(_("To use a different finance book, please uncheck 'Include Default FB Entries'"))
opening_balance = opening_balance.where(
(closing_balance.finance_book.isin([cstr(filters.finance_book), cstr(company_fb), ""]))

View File

@@ -511,7 +511,7 @@ def check_if_advance_entry_modified(args):
party_account_field = (
"paid_from" if erpnext.get_party_account_type(args.party_type) == "Receivable" else "paid_to"
)
precision = frappe.get_precision("Payment Entry", "unallocated_amount")
if args.voucher_detail_no:
ret = frappe.db.sql(
"""select t1.name
@@ -533,9 +533,9 @@ def check_if_advance_entry_modified(args):
where
name = %(voucher_no)s and docstatus = 1
and party_type = %(party_type)s and party = %(party)s and {0} = %(account)s
and unallocated_amount = %(unreconciled_amount)s
and round(unallocated_amount, {1}) = %(unreconciled_amount)s
""".format(
party_account_field
party_account_field, precision
),
args,
)

View File

@@ -495,11 +495,10 @@
"read_only": 1
},
{
"depends_on": "eval.doc.asset_quantity",
"fieldname": "asset_quantity",
"fieldtype": "Int",
"label": "Asset Quantity",
"read_only": 1
"read_only_depends_on": "eval:!doc.is_existing_asset && !doc.is_composite_asset"
},
{
"fieldname": "depr_entry_posting_status",
@@ -565,7 +564,7 @@
"link_fieldname": "target_asset"
}
],
"modified": "2023-10-27 17:03:46.629617",
"modified": "2023-11-15 17:40:17.315203",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",

View File

@@ -1216,7 +1216,7 @@ def get_item_details(item_code, asset_category, gross_purchase_amount):
"depreciation_method": d.depreciation_method,
"total_number_of_depreciations": d.total_number_of_depreciations,
"frequency_of_depreciation": d.frequency_of_depreciation,
"daily_depreciation": d.daily_depreciation,
"daily_prorata_based": d.daily_prorata_based,
"salvage_value_percentage": d.salvage_value_percentage,
"expected_value_after_useful_life": flt(gross_purchase_amount)
* flt(d.salvage_value_percentage / 100),
@@ -1396,7 +1396,7 @@ def get_straight_line_or_manual_depr_amount(
)
# if the Depreciation Schedule is being modified after Asset Value Adjustment due to decrease in asset value
elif asset.flags.decrease_in_asset_value_due_to_value_adjustment:
if row.daily_depreciation:
if row.daily_prorata_based:
daily_depr_amount = (
flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
) / date_diff(
@@ -1441,7 +1441,7 @@ def get_straight_line_or_manual_depr_amount(
) / number_of_pending_depreciations
# if the Depreciation Schedule is being prepared for the first time
else:
if row.daily_depreciation:
if row.daily_prorata_based:
daily_depr_amount = (
flt(asset.gross_purchase_amount)
- flt(asset.opening_accumulated_depreciation)

View File

@@ -740,6 +740,15 @@ def get_disposal_account_and_cost_center(company):
def get_value_after_depreciation_on_disposal_date(asset, disposal_date, finance_book=None):
asset_doc = frappe.get_doc("Asset", asset)
if asset_doc.available_for_use_date > getdate(disposal_date):
frappe.throw(
"Disposal date {0} cannot be before available for use date {1} of the asset.".format(
disposal_date, asset_doc.available_for_use_date
)
)
elif asset_doc.available_for_use_date == getdate(disposal_date):
return flt(asset_doc.gross_purchase_amount - asset_doc.opening_accumulated_depreciation)
if asset_doc.calculate_depreciation:
asset_doc.prepare_depreciation_data(getdate(disposal_date))

View File

@@ -731,7 +731,9 @@ class TestDepreciationMethods(AssetSetup):
self.assertEqual(schedules, expected_schedules)
def test_schedule_for_straight_line_method_with_daily_depreciation(self):
def test_schedule_for_straight_line_method_with_daily_prorata_based(
self,
):
asset = create_asset(
calculate_depreciation=1,
available_for_use_date="2023-01-01",
@@ -740,7 +742,7 @@ class TestDepreciationMethods(AssetSetup):
depreciation_start_date="2023-01-31",
total_number_of_depreciations=12,
frequency_of_depreciation=1,
daily_depreciation=1,
daily_prorata_based=1,
)
expected_schedules = [
@@ -1703,7 +1705,7 @@ def create_asset(**args):
"total_number_of_depreciations": args.total_number_of_depreciations or 5,
"expected_value_after_useful_life": args.expected_value_after_useful_life or 0,
"depreciation_start_date": args.depreciation_start_date,
"daily_depreciation": args.daily_depreciation or 0,
"daily_prorata_based": args.daily_prorata_based or 0,
},
)

View File

@@ -8,7 +8,7 @@
"finance_book",
"depreciation_method",
"total_number_of_depreciations",
"daily_depreciation",
"daily_prorata_based",
"column_break_5",
"frequency_of_depreciation",
"depreciation_start_date",
@@ -82,23 +82,23 @@
"fieldtype": "Percent",
"label": "Rate of Depreciation"
},
{
"default": "0",
"depends_on": "eval:doc.depreciation_method == \"Straight Line\" || doc.depreciation_method == \"Manual\"",
"fieldname": "daily_depreciation",
"fieldtype": "Check",
"label": "Daily Depreciation"
},
{
"fieldname": "salvage_value_percentage",
"fieldtype": "Percent",
"label": "Salvage Value Percentage"
},
{
"default": "0",
"depends_on": "eval:doc.depreciation_method == \"Straight Line\" || doc.depreciation_method == \"Manual\"",
"fieldname": "daily_prorata_based",
"fieldtype": "Check",
"label": "Depreciate based on daily pro-rata"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2023-09-29 15:39:52.740594",
"modified": "2023-11-03 22:21:52.090191",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Finance Book",

View File

@@ -52,7 +52,7 @@ frappe.query_reports["Fixed Asset Register"] = {
},
{
"fieldname": "include_default_book_assets",
"label": __("Include Default Book Assets"),
"label": __("Include Default FB Assets"),
"fieldtype": "Check",
"default": 1
},

View File

@@ -223,7 +223,7 @@ def get_assets_linked_to_fb(filters):
company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book")
if filters.finance_book and company_fb and cstr(filters.finance_book) != cstr(company_fb):
frappe.throw(_("To use a different finance book, please uncheck 'Include Default Book Assets'"))
frappe.throw(_("To use a different finance book, please uncheck 'Include Default FB Assets'"))
query = query.where(
(afb.finance_book.isin([cstr(filters.finance_book), cstr(company_fb), ""]))

View File

@@ -190,6 +190,7 @@
"fieldtype": "Column Break"
},
{
"fetch_from": "item_code.image",
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
@@ -471,6 +472,7 @@
"fieldname": "material_request",
"fieldtype": "Link",
"label": "Material Request",
"mandatory_depends_on": "eval: doc.material_request_item",
"no_copy": 1,
"oldfieldname": "prevdoc_docname",
"oldfieldtype": "Link",
@@ -486,6 +488,7 @@
"fieldtype": "Data",
"hidden": 1,
"label": "Material Request Item",
"mandatory_depends_on": "eval: doc.material_request",
"no_copy": 1,
"oldfieldname": "prevdoc_detail_docname",
"oldfieldtype": "Data",
@@ -915,7 +918,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2023-10-27 15:50:42.655573",
"modified": "2023-11-14 18:34:27.267382",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item",

View File

@@ -88,6 +88,7 @@
"width": "300px"
},
{
"fetch_from": "item_code.image",
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
@@ -261,13 +262,15 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2020-09-24 17:26:46.276934",
"modified": "2023-11-14 18:34:48.327224",
"modified_by": "Administrator",
"module": "Buying",
"name": "Request for Quotation Item",
"naming_rule": "Random",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}

View File

@@ -170,7 +170,7 @@
"fieldname": "supplier_type",
"fieldtype": "Select",
"label": "Supplier Type",
"options": "Company\nIndividual",
"options": "Company\nIndividual\nProprietorship\nPartnership",
"reqd": 1
},
{
@@ -457,7 +457,7 @@
"link_fieldname": "party"
}
],
"modified": "2023-05-09 15:34:13.408932",
"modified": "2023-10-19 16:55:15.148325",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",
@@ -525,4 +525,4 @@
"states": [],
"title_field": "supplier_name",
"track_changes": 1
}
}

View File

@@ -134,6 +134,7 @@
"fieldtype": "Column Break"
},
{
"fetch_from": "item_code.image",
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
@@ -560,13 +561,15 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2020-10-19 12:36:26.913211",
"modified": "2023-11-14 18:35:03.435817",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation Item",
"naming_rule": "Random",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}

View File

@@ -2249,6 +2249,7 @@ class AccountsController(TransactionBase):
repost_ledger = frappe.new_doc("Repost Accounting Ledger")
repost_ledger.company = self.company
repost_ledger.append("vouchers", {"voucher_type": self.doctype, "voucher_no": self.name})
repost_ledger.flags.ignore_permissions = True
repost_ledger.insert()
repost_ledger.submit()
self.db_set("repost_required", 0)

View File

@@ -4,7 +4,7 @@
import frappe
from frappe import ValidationError, _, msgprint
from frappe.contacts.doctype.address.address import get_address_display
from frappe.contacts.doctype.address.address import render_address
from frappe.utils import cint, cstr, flt, getdate
from frappe.utils.data import nowtime
@@ -78,26 +78,26 @@ class BuyingController(SubcontractingController):
def set_rate_for_standalone_debit_note(self):
if self.get("is_return") and self.get("update_stock") and not self.return_against:
for row in self.items:
if row.rate <= 0:
# override the rate with valuation rate
row.rate = get_incoming_rate(
{
"item_code": row.item_code,
"warehouse": row.warehouse,
"posting_date": self.get("posting_date"),
"posting_time": self.get("posting_time"),
"qty": row.qty,
"serial_and_batch_bundle": row.get("serial_and_batch_bundle"),
"company": self.company,
"voucher_type": self.doctype,
"voucher_no": self.name,
},
raise_error_if_no_rate=False,
)
# override the rate with valuation rate
row.rate = get_incoming_rate(
{
"item_code": row.item_code,
"warehouse": row.warehouse,
"posting_date": self.get("posting_date"),
"posting_time": self.get("posting_time"),
"qty": row.qty,
"serial_and_batch_bundle": row.get("serial_and_batch_bundle"),
"company": self.company,
"voucher_type": self.doctype,
"voucher_no": self.name,
},
raise_error_if_no_rate=False,
)
row.discount_percentage = 0.0
row.discount_amount = 0.0
row.margin_rate_or_amount = 0.0
row.discount_percentage = 0.0
row.discount_amount = 0.0
row.margin_rate_or_amount = 0.0
def set_missing_values(self, for_validate=False):
super(BuyingController, self).set_missing_values(for_validate)
@@ -219,7 +219,9 @@ class BuyingController(SubcontractingController):
for address_field, address_display_field in address_dict.items():
if self.get(address_field):
self.set(address_display_field, get_address_display(self.get(address_field)))
self.set(
address_display_field, render_address(self.get(address_field), check_permissions=False)
)
def set_total_in_words(self):
from frappe.utils import money_in_words
@@ -336,7 +338,7 @@ class BuyingController(SubcontractingController):
{
"item_code": d.item_code,
"warehouse": d.get("from_warehouse"),
"posting_date": self.get("posting_date") or self.get("transation_date"),
"posting_date": self.get("posting_date") or self.get("transaction_date"),
"posting_time": posting_time,
"qty": -1 * flt(d.get("stock_qty")),
"serial_no": d.get("serial_no"),

View File

@@ -560,6 +560,8 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters):
if filters.get("company"):
condition += "and tabAccount.company = %(company)s"
condition += f"and tabAccount.disabled = {filters.get('disabled', 0)}"
return frappe.db.sql(
"""select tabAccount.name from `tabAccount`
where (tabAccount.report_type = "Profit and Loss"

View File

@@ -47,15 +47,15 @@ status_map = {
],
[
"To Bill",
"eval:(self.per_delivered == 100 or self.skip_delivery_note) and self.per_billed < 100 and self.docstatus == 1",
"eval:(self.per_delivered >= 100 or self.skip_delivery_note) and self.per_billed < 100 and self.docstatus == 1",
],
[
"To Deliver",
"eval:self.per_delivered < 100 and self.per_billed == 100 and self.docstatus == 1 and not self.skip_delivery_note",
"eval:self.per_delivered < 100 and self.per_billed >= 100 and self.docstatus == 1 and not self.skip_delivery_note",
],
[
"Completed",
"eval:(self.per_delivered == 100 or self.skip_delivery_note) and self.per_billed == 100 and self.docstatus == 1",
"eval:(self.per_delivered >= 100 or self.skip_delivery_note) and self.per_billed >= 100 and self.docstatus == 1",
],
["Cancelled", "eval:self.docstatus==2"],
["Closed", "eval:self.status=='Closed' and self.docstatus != 2"],

View File

@@ -1043,8 +1043,6 @@ def create_item_wise_repost_entries(voucher_type, voucher_no, allow_zero_rate=Fa
repost_entry = frappe.new_doc("Repost Item Valuation")
repost_entry.based_on = "Item and Warehouse"
repost_entry.voucher_type = voucher_type
repost_entry.voucher_no = voucher_no
repost_entry.item_code = sle.item_code
repost_entry.warehouse = sle.warehouse

View File

@@ -103,6 +103,7 @@
"fieldtype": "Column Break"
},
{
"fetch_from": "item_code.image",
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
@@ -165,7 +166,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2021-07-30 16:39:09.775720",
"modified": "2023-11-14 18:35:30.887278",
"modified_by": "Administrator",
"module": "CRM",
"name": "Opportunity Item",
@@ -173,5 +174,6 @@
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}

View File

@@ -7,7 +7,7 @@ import frappe
from frappe import _
from frappe.desk.doctype.tag.tag import add_tag
from frappe.model.document import Document
from frappe.utils import add_months, formatdate, getdate, today
from frappe.utils import add_months, formatdate, getdate, sbool, today
from plaid.errors import ItemError
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
@@ -238,8 +238,6 @@ def new_bank_transaction(transaction):
deposit = abs(amount)
withdrawal = 0.0
status = "Pending" if transaction["pending"] == "True" else "Settled"
tags = []
try:
tags += transaction["category"]
@@ -247,13 +245,14 @@ def new_bank_transaction(transaction):
except KeyError:
pass
if not frappe.db.exists("Bank Transaction", dict(transaction_id=transaction["transaction_id"])):
if not frappe.db.exists(
"Bank Transaction", dict(transaction_id=transaction["transaction_id"])
) and not sbool(transaction["pending"]):
try:
new_transaction = frappe.get_doc(
{
"doctype": "Bank Transaction",
"date": getdate(transaction["date"]),
"status": status,
"bank_account": bank_account,
"deposit": deposit,
"withdrawal": withdrawal,

View File

@@ -85,6 +85,7 @@
"fieldtype": "Column Break"
},
{
"fetch_from": "item_code.image",
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
@@ -169,7 +170,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2022-05-27 13:42:23.305455",
"modified": "2023-11-14 18:35:40.856895",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Explosion Item",

View File

@@ -111,6 +111,7 @@
"fieldtype": "Column Break"
},
{
"fetch_from": "item_code.image",
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
@@ -289,7 +290,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2022-07-28 10:20:51.559010",
"modified": "2023-11-14 18:35:51.378513",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Item",

View File

@@ -89,10 +89,6 @@ frappe.ui.form.on('Production Plan', {
frm.trigger("show_progress");
if (frm.doc.status !== "Completed") {
frm.add_custom_button(__("Work Order Tree"), ()=> {
frappe.set_route('Tree', 'Work Order', {production_plan: frm.doc.name});
}, __('View'));
frm.add_custom_button(__("Production Plan Summary"), ()=> {
frappe.set_route('query-report', 'Production Plan Summary', {production_plan: frm.doc.name});
}, __('View'));

View File

@@ -36,6 +36,7 @@
"prod_plan_references",
"section_break_24",
"combine_sub_items",
"sub_assembly_warehouse",
"section_break_ucc4",
"skip_available_sub_assembly_item",
"column_break_igxl",
@@ -416,13 +417,19 @@
{
"fieldname": "column_break_igxl",
"fieldtype": "Column Break"
},
{
"fieldname": "sub_assembly_warehouse",
"fieldtype": "Link",
"label": "Sub Assembly Warehouse",
"options": "Warehouse"
}
],
"icon": "fa fa-calendar",
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2023-09-29 11:41:03.246059",
"modified": "2023-11-03 14:08:11.928027",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Plan",

View File

@@ -490,6 +490,12 @@ class ProductionPlan(Document):
bin = frappe.get_doc("Bin", bin_name, for_update=True)
bin.update_reserved_qty_for_production_plan()
for d in self.sub_assembly_items:
if d.fg_warehouse and d.type_of_manufacturing == "In House":
bin_name = get_or_make_bin(d.production_item, d.fg_warehouse)
bin = frappe.get_doc("Bin", bin_name, for_update=True)
bin.update_reserved_qty_for_for_sub_assembly()
def delete_draft_work_order(self):
for d in frappe.get_all(
"Work Order", fields=["name"], filters={"docstatus": 0, "production_plan": ("=", self.name)}
@@ -808,7 +814,11 @@ class ProductionPlan(Document):
bom_data = []
warehouse = row.warehouse if self.skip_available_sub_assembly_item else None
warehouse = (
(self.sub_assembly_warehouse or row.warehouse)
if self.skip_available_sub_assembly_item
else None
)
get_sub_assembly_items(row.bom_no, bom_data, row.planned_qty, self.company, warehouse=warehouse)
self.set_sub_assembly_items_based_on_level(row, bom_data, manufacturing_type)
sub_assembly_items_store.extend(bom_data)
@@ -817,8 +827,6 @@ class ProductionPlan(Document):
# Combine subassembly items
sub_assembly_items_store = self.combine_subassembly_items(sub_assembly_items_store)
sub_assembly_items_store.sort(key=lambda d: d.bom_level, reverse=True) # sort by bom level
for idx, row in enumerate(sub_assembly_items_store):
row.idx = idx + 1
self.append("sub_assembly_items", row)
@@ -830,7 +838,7 @@ class ProductionPlan(Document):
for data in bom_data:
data.qty = data.stock_qty
data.production_plan_item = row.name
data.fg_warehouse = row.warehouse
data.fg_warehouse = self.sub_assembly_warehouse or row.warehouse
data.schedule_date = row.planned_start_date
data.type_of_manufacturing = manufacturing_type or (
"Subcontract" if data.is_sub_contracted_item else "In House"
@@ -1636,8 +1644,8 @@ def get_reserved_qty_for_production_plan(item_code, warehouse):
query = query.run()
if not query:
return 0.0
if not query or query[0][0] is None:
return None
reserved_qty_for_production_plan = flt(query[0][0])
@@ -1779,3 +1787,29 @@ def sales_order_query(
query = query.offset(start)
return query.run()
def get_reserved_qty_for_sub_assembly(item_code, warehouse):
table = frappe.qb.DocType("Production Plan")
child = frappe.qb.DocType("Production Plan Sub Assembly Item")
query = (
frappe.qb.from_(table)
.inner_join(child)
.on(table.name == child.parent)
.select(Sum(child.qty - IfNull(child.wo_produced_qty, 0)))
.where(
(table.docstatus == 1)
& (child.production_item == item_code)
& (child.fg_warehouse == warehouse)
& (table.status.notin(["Completed", "Closed"]))
)
)
query = query.run()
if not query or query[0][0] is None:
return None
qty = flt(query[0][0])
return qty if qty > 0 else 0.0

View File

@@ -653,49 +653,6 @@ class TestProductionPlan(FrappeTestCase):
frappe.db.rollback()
def test_subassmebly_sorting(self):
"Test subassembly sorting in case of multiple items with nested BOMs."
from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
prefix = "_TestLevel_"
boms = {
"Assembly": {
"SubAssembly1": {
"ChildPart1": {},
"ChildPart2": {},
},
"ChildPart6": {},
"SubAssembly4": {"SubSubAssy2": {"ChildPart7": {}}},
},
"MegaDeepAssy": {
"SecretSubassy": {
"SecretPart": {"VerySecret": {"SuperSecret": {"Classified": {}}}},
},
# ^ assert that this is
# first item in subassy table
},
}
create_nested_bom(boms, prefix=prefix)
items = [prefix + item_code for item_code in boms.keys()]
plan = create_production_plan(item_code=items[0], do_not_save=True)
plan.append(
"po_items",
{
"use_multi_level_bom": 1,
"item_code": items[1],
"bom_no": frappe.db.get_value("Item", items[1], "default_bom"),
"planned_qty": 1,
"planned_start_date": now_datetime(),
},
)
plan.get_sub_assembly_items()
bom_level_order = [d.bom_level for d in plan.sub_assembly_items]
self.assertEqual(bom_level_order, sorted(bom_level_order, reverse=True))
# lowest most level of subassembly should be first
self.assertIn("SuperSecret", plan.sub_assembly_items[0].production_item)
def test_multiple_work_order_for_production_plan_item(self):
"Test producing Prod Plan (making WO) in parts."
@@ -1031,13 +988,14 @@ class TestProductionPlan(FrappeTestCase):
after_qty = flt(frappe.db.get_value("Bin", bin_name, "reserved_qty_for_production_plan"))
self.assertEqual(after_qty - before_qty, 1)
pln = frappe.get_doc("Production Plan", pln.name)
pln.cancel()
bin_name = get_or_make_bin("Raw Material Item 1", "_Test Warehouse - _TC")
after_qty = flt(frappe.db.get_value("Bin", bin_name, "reserved_qty_for_production_plan"))
pln.reload()
self.assertEqual(pln.docstatus, 2)
self.assertEqual(after_qty, before_qty)
def test_resered_qty_for_production_plan_for_work_order(self):
@@ -1348,6 +1306,93 @@ class TestProductionPlan(FrappeTestCase):
if row.item_code == "ChildPart2 For SUB Test":
self.assertEqual(row.quantity, 2)
def test_reserve_sub_assembly_items(self):
from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
bom_tree = {
"Fininshed Goods Bicycle": {
"Frame Assembly": {"Frame": {}},
"Chain Assembly": {"Chain": {}},
}
}
parent_bom = create_nested_bom(bom_tree, prefix="")
warehouse = "_Test Warehouse - _TC"
company = "_Test Company"
sub_assembly_warehouse = create_warehouse("SUB ASSEMBLY WH", company=company)
for item_code in ["Frame", "Chain"]:
make_stock_entry(item_code=item_code, target=warehouse, qty=2, basic_rate=100)
before_qty = flt(
frappe.db.get_value(
"Bin",
{"item_code": "Frame Assembly", "warehouse": sub_assembly_warehouse},
"reserved_qty_for_production_plan",
)
)
plan = create_production_plan(
item_code=parent_bom.item,
planned_qty=2,
ignore_existing_ordered_qty=1,
do_not_submit=1,
skip_available_sub_assembly_item=1,
warehouse=warehouse,
sub_assembly_warehouse=sub_assembly_warehouse,
)
plan.get_sub_assembly_items()
plan.submit()
after_qty = flt(
frappe.db.get_value(
"Bin",
{"item_code": "Frame Assembly", "warehouse": sub_assembly_warehouse},
"reserved_qty_for_production_plan",
)
)
self.assertEqual(after_qty, before_qty + 2)
plan.make_work_order()
work_orders = frappe.get_all(
"Work Order",
fields=["name", "production_item"],
filters={"production_plan": plan.name},
order_by="creation desc",
)
for d in work_orders:
wo_doc = frappe.get_doc("Work Order", d.name)
wo_doc.skip_transfer = 1
wo_doc.from_wip_warehouse = 1
wo_doc.wip_warehouse = (
warehouse
if d.production_item in ["Frame Assembly", "Chain Assembly"]
else sub_assembly_warehouse
)
wo_doc.submit()
if d.production_item == "Frame Assembly":
self.assertEqual(wo_doc.fg_warehouse, sub_assembly_warehouse)
se_doc = frappe.get_doc(make_se_from_wo(wo_doc.name, "Manufacture", 2))
se_doc.submit()
after_qty = flt(
frappe.db.get_value(
"Bin",
{"item_code": "Frame Assembly", "warehouse": sub_assembly_warehouse},
"reserved_qty_for_production_plan",
)
)
self.assertEqual(after_qty, before_qty)
def create_production_plan(**args):
"""
@@ -1368,6 +1413,7 @@ def create_production_plan(**args):
"ignore_existing_ordered_qty": args.ignore_existing_ordered_qty or 0,
"get_items_from": "Sales Order",
"skip_available_sub_assembly_item": args.skip_available_sub_assembly_item or 0,
"sub_assembly_warehouse": args.sub_assembly_warehouse,
}
)

View File

@@ -17,11 +17,10 @@
"type_of_manufacturing",
"supplier",
"work_order_details_section",
"work_order",
"wo_produced_qty",
"purchase_order",
"production_plan_item",
"column_break_7",
"produced_qty",
"received_qty",
"indent",
"section_break_19",
@@ -52,13 +51,6 @@
"fieldtype": "Section Break",
"label": "Reference"
},
{
"fieldname": "work_order",
"fieldtype": "Link",
"label": "Work Order",
"options": "Work Order",
"read_only": 1
},
{
"fieldname": "column_break_7",
"fieldtype": "Column Break"
@@ -81,7 +73,8 @@
{
"fieldname": "received_qty",
"fieldtype": "Float",
"label": "Received Qty"
"label": "Received Qty",
"read_only": 1
},
{
"fieldname": "bom_no",
@@ -161,12 +154,6 @@
"label": "Target Warehouse",
"options": "Warehouse"
},
{
"fieldname": "produced_qty",
"fieldtype": "Data",
"label": "Produced Quantity",
"read_only": 1
},
{
"default": "In House",
"fieldname": "type_of_manufacturing",
@@ -209,12 +196,18 @@
"label": "Projected Qty",
"no_copy": 1,
"read_only": 1
},
{
"fieldname": "wo_produced_qty",
"fieldtype": "Float",
"label": "Produced Qty",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2023-05-22 17:52:34.708879",
"modified": "2023-11-03 13:33:42.959387",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Plan Sub Assembly Item",

View File

@@ -710,7 +710,7 @@ erpnext.work_order = {
return new Promise((resolve, reject) => {
frappe.prompt({
fieldtype: 'Float',
label: __('Qty for {0}', [purpose]),
label: __('Qty for {0}', [__(purpose)]),
fieldname: 'qty',
description: __('Max: {0}', [max]),
default: max

View File

@@ -297,6 +297,7 @@ class WorkOrder(Document):
update_produced_qty_in_so_item(self.sales_order, self.sales_order_item)
if self.production_plan:
self.set_produced_qty_for_sub_assembly_item()
self.update_production_plan_status()
def get_transferred_or_manufactured_qty(self, purpose):
@@ -544,16 +545,49 @@ class WorkOrder(Document):
)
def update_planned_qty(self):
from erpnext.manufacturing.doctype.production_plan.production_plan import (
get_reserved_qty_for_sub_assembly,
)
qty_dict = {"planned_qty": get_planned_qty(self.production_item, self.fg_warehouse)}
if self.production_plan_sub_assembly_item and self.production_plan:
qty_dict["reserved_qty_for_production_plan"] = get_reserved_qty_for_sub_assembly(
self.production_item, self.fg_warehouse
)
update_bin_qty(
self.production_item,
self.fg_warehouse,
{"planned_qty": get_planned_qty(self.production_item, self.fg_warehouse)},
qty_dict,
)
if self.material_request:
mr_obj = frappe.get_doc("Material Request", self.material_request)
mr_obj.update_requested_qty([self.material_request_item])
def set_produced_qty_for_sub_assembly_item(self):
table = frappe.qb.DocType("Work Order")
query = (
frappe.qb.from_(table)
.select(Sum(table.produced_qty))
.where(
(table.production_plan == self.production_plan)
& (table.production_plan_sub_assembly_item == self.production_plan_sub_assembly_item)
& (table.docstatus == 1)
)
).run()
produced_qty = flt(query[0][0]) if query else 0
frappe.db.set_value(
"Production Plan Sub Assembly Item",
self.production_plan_sub_assembly_item,
"wo_produced_qty",
produced_qty,
)
def update_ordered_qty(self):
if (
self.production_plan

View File

@@ -22,9 +22,9 @@ frappe.query_reports["Production Plan Summary"] = {
"formatter": function(value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
if (column.fieldname == "document_name") {
if (column.fieldname == "item_code") {
var color = data.pending_qty > 0 ? 'red': 'green';
value = `<a style='color:${color}' href="#Form/${data['document_type']}/${data['document_name']}" data-doctype="${data['document_type']}">${data['document_name']}</a>`;
value = `<a style='color:${color}' href="/app/item/${data['item_code']}" data-doctype="Item">${data['item_code']}</a>`;
}
return value;

View File

@@ -44,6 +44,7 @@ def get_production_plan_item_details(filters, data, order_details):
{
"indent": 0,
"item_code": row.item_code,
"sales_order": row.get("sales_order"),
"item_name": frappe.get_cached_value("Item", row.item_code, "item_name"),
"qty": row.planned_qty,
"document_type": "Work Order",
@@ -80,7 +81,7 @@ def get_production_plan_sub_assembly_item_details(
data.append(
{
"indent": 1,
"indent": 1 + item.indent,
"item_code": item.production_item,
"item_name": item.item_name,
"qty": item.qty,
@@ -98,7 +99,7 @@ def get_work_order_details(filters, order_details):
for row in frappe.get_all(
"Work Order",
filters={"production_plan": filters.get("production_plan")},
fields=["name", "produced_qty", "production_plan", "production_item"],
fields=["name", "produced_qty", "production_plan", "production_item", "sales_order"],
):
order_details.setdefault((row.name, row.production_item), row)
@@ -118,10 +119,17 @@ def get_column(filters):
"label": _("Finished Good"),
"fieldtype": "Link",
"fieldname": "item_code",
"width": 300,
"width": 240,
"options": "Item",
},
{"label": _("Item Name"), "fieldtype": "data", "fieldname": "item_name", "width": 100},
{"label": _("Item Name"), "fieldtype": "data", "fieldname": "item_name", "width": 150},
{
"label": _("Sales Order"),
"options": "Sales Order",
"fieldtype": "Link",
"fieldname": "sales_order",
"width": 100,
},
{
"label": _("Document Type"),
"fieldtype": "Link",
@@ -133,10 +141,16 @@ def get_column(filters):
"label": _("Document Name"),
"fieldtype": "Dynamic Link",
"fieldname": "document_name",
"width": 150,
"options": "document_type",
"width": 180,
},
{"label": _("BOM Level"), "fieldtype": "Int", "fieldname": "bom_level", "width": 100},
{"label": _("Order Qty"), "fieldtype": "Float", "fieldname": "qty", "width": 120},
{"label": _("Received Qty"), "fieldtype": "Float", "fieldname": "produced_qty", "width": 160},
{
"label": _("Produced / Received Qty"),
"fieldtype": "Float",
"fieldname": "produced_qty",
"width": 200,
},
{"label": _("Pending Qty"), "fieldtype": "Float", "fieldname": "pending_qty", "width": 110},
]

View File

@@ -344,5 +344,10 @@ erpnext.patches.v14_0.migrate_deferred_accounts_to_item_defaults
erpnext.patches.v14_0.create_accounting_dimensions_in_sales_order_item
erpnext.patches.v14_0.rename_over_order_allowance_field
erpnext.patches.v14_0.migrate_delivery_stop_lock_field
execute:frappe.db.set_single_value("Payment Reconciliation", "invoice_limit", 50)
execute:frappe.db.set_single_value("Payment Reconciliation", "payment_limit", 50)
erpnext.patches.v14_0.rename_daily_depreciation_to_depreciation_amount_based_on_num_days_in_month
erpnext.patches.v14_0.rename_depreciation_amount_based_on_num_days_in_month_to_daily_prorata_based
erpnext.patches.v14_0.add_default_for_repost_settings
# below migration patch should always run last
erpnext.patches.v14_0.migrate_gl_to_payment_ledger

View File

@@ -0,0 +1,12 @@
import frappe
def execute():
"""
Update Repost Accounting Ledger Settings with default values
"""
allowed_types = ["Sales Invoice", "Purchase Invoice", "Payment Entry", "Journal Entry"]
repost_settings = frappe.get_doc("Repost Accounting Ledger Settings")
for x in allowed_types:
repost_settings.append("allowed_types", {"document_type": x, "allowed": True})
repost_settings.save()

View File

@@ -0,0 +1,16 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from frappe.model.utils.rename_field import rename_field
def execute():
try:
rename_field(
"Asset Finance Book", "daily_depreciation", "depreciation_amount_based_on_num_days_in_month"
)
except Exception as e:
if e.args[0] != 1054:
raise

View File

@@ -0,0 +1,16 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from frappe.model.utils.rename_field import rename_field
def execute():
try:
rename_field(
"Asset Finance Book", "depreciation_amount_based_on_num_days_in_month", "daily_prorata_based"
)
except Exception as e:
if e.args[0] != 1054:
raise

View File

@@ -3,10 +3,10 @@
frappe.ui.form.on('Quality Procedure', {
refresh: function(frm) {
frm.set_query("procedure","processes", (frm) =>{
frm.set_query('procedure', 'processes', (frm) =>{
return {
filters: {
name: ["not in", [frm.parent_quality_procedure, frm.name]]
name: ['not in', [frm.parent_quality_procedure, frm.name]]
}
};
});
@@ -14,7 +14,8 @@ frappe.ui.form.on('Quality Procedure', {
frm.set_query('parent_quality_procedure', function(){
return {
filters: {
is_group: 1
is_group: 1,
name: ['!=', frm.doc.name]
}
};
});

View File

@@ -16,16 +16,13 @@ class QualityProcedure(NestedSet):
def on_update(self):
NestedSet.on_update(self)
self.set_parent()
self.remove_parent_from_old_child()
self.add_child_to_parent()
self.remove_child_from_old_parent()
def after_insert(self):
self.set_parent()
# add child to parent if missing
if self.parent_quality_procedure:
parent = frappe.get_doc("Quality Procedure", self.parent_quality_procedure)
if not [d for d in parent.processes if d.procedure == self.name]:
parent.append("processes", {"procedure": self.name, "process_description": self.name})
parent.save()
self.add_child_to_parent()
def on_trash(self):
# clear from child table (sub procedures)
@@ -36,15 +33,6 @@ class QualityProcedure(NestedSet):
)
NestedSet.on_trash(self, allow_root_deletion=True)
def set_parent(self):
for process in self.processes:
# Set parent for only those children who don't have a parent
has_parent = frappe.db.get_value(
"Quality Procedure", process.procedure, "parent_quality_procedure"
)
if not has_parent and process.procedure:
frappe.db.set_value(self.doctype, process.procedure, "parent_quality_procedure", self.name)
def check_for_incorrect_child(self):
for process in self.processes:
if process.procedure:
@@ -61,6 +49,48 @@ class QualityProcedure(NestedSet):
title=_("Invalid Child Procedure"),
)
def set_parent(self):
"""Set `Parent Procedure` in `Child Procedures`"""
for process in self.processes:
if process.procedure:
if not frappe.db.get_value("Quality Procedure", process.procedure, "parent_quality_procedure"):
frappe.db.set_value(
"Quality Procedure", process.procedure, "parent_quality_procedure", self.name
)
def remove_parent_from_old_child(self):
"""Remove `Parent Procedure` from `Old Child Procedures`"""
if old_doc := self.get_doc_before_save():
if old_child_procedures := set([d.procedure for d in old_doc.processes if d.procedure]):
current_child_procedures = set([d.procedure for d in self.processes if d.procedure])
if removed_child_procedures := list(old_child_procedures.difference(current_child_procedures)):
for child_procedure in removed_child_procedures:
frappe.db.set_value("Quality Procedure", child_procedure, "parent_quality_procedure", None)
def add_child_to_parent(self):
"""Add `Child Procedure` to `Parent Procedure`"""
if self.parent_quality_procedure:
parent = frappe.get_doc("Quality Procedure", self.parent_quality_procedure)
if not [d for d in parent.processes if d.procedure == self.name]:
parent.append("processes", {"procedure": self.name, "process_description": self.name})
parent.save()
def remove_child_from_old_parent(self):
"""Remove `Child Procedure` from `Old Parent Procedure`"""
if old_doc := self.get_doc_before_save():
if old_parent := old_doc.parent_quality_procedure:
if self.parent_quality_procedure != old_parent:
parent = frappe.get_doc("Quality Procedure", old_parent)
for process in parent.processes:
if process.procedure == self.name:
parent.remove(process)
parent.save()
@frappe.whitelist()
def get_children(doctype, parent=None, parent_quality_procedure=None, is_root=False):

View File

@@ -1,56 +1,107 @@
# Copyright (c) 2018, Frappe and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
from .quality_procedure import add_node
class TestQualityProcedure(unittest.TestCase):
class TestQualityProcedure(FrappeTestCase):
def test_add_node(self):
try:
procedure = frappe.get_doc(
dict(
doctype="Quality Procedure",
quality_procedure_name="Test Procedure 1",
processes=[dict(process_description="Test Step 1")],
)
).insert()
frappe.local.form_dict = frappe._dict(
doctype="Quality Procedure",
quality_procedure_name="Test Child 1",
parent_quality_procedure=procedure.name,
cmd="test",
is_root="false",
)
node = add_node()
procedure.reload()
self.assertEqual(procedure.is_group, 1)
# child row created
self.assertTrue([d for d in procedure.processes if d.procedure == node.name])
node.delete()
procedure.reload()
# child unset
self.assertFalse([d for d in procedure.processes if d.name == node.name])
finally:
procedure.delete()
def create_procedure():
return frappe.get_doc(
dict(
doctype="Quality Procedure",
quality_procedure_name="Test Procedure 1",
is_group=1,
processes=[dict(process_description="Test Step 1")],
procedure = create_procedure(
{
"quality_procedure_name": "Test Procedure 1",
"is_group": 1,
"processes": [dict(process_description="Test Step 1")],
}
)
).insert()
frappe.local.form_dict = frappe._dict(
doctype="Quality Procedure",
quality_procedure_name="Test Child 1",
parent_quality_procedure=procedure.name,
cmd="test",
is_root="false",
)
node = add_node()
procedure.reload()
self.assertEqual(procedure.is_group, 1)
# child row created
self.assertTrue([d for d in procedure.processes if d.procedure == node.name])
node.delete()
procedure.reload()
# child unset
self.assertFalse([d for d in procedure.processes if d.name == node.name])
def test_remove_parent_from_old_child(self):
child_qp = create_procedure(
{
"quality_procedure_name": "Test Child 1",
"is_group": 0,
}
)
group_qp = create_procedure(
{
"quality_procedure_name": "Test Group",
"is_group": 1,
"processes": [dict(procedure=child_qp.name)],
}
)
child_qp.reload()
self.assertEqual(child_qp.parent_quality_procedure, group_qp.name)
group_qp.reload()
del group_qp.processes[0]
group_qp.save()
child_qp.reload()
self.assertEqual(child_qp.parent_quality_procedure, None)
def remove_child_from_old_parent(self):
child_qp = create_procedure(
{
"quality_procedure_name": "Test Child 1",
"is_group": 0,
}
)
group_qp = create_procedure(
{
"quality_procedure_name": "Test Group",
"is_group": 1,
"processes": [dict(procedure=child_qp.name)],
}
)
group_qp.reload()
self.assertTrue([d for d in group_qp.processes if d.procedure == child_qp.name])
child_qp.reload()
self.assertEqual(child_qp.parent_quality_procedure, group_qp.name)
child_qp.parent_quality_procedure = None
child_qp.save()
group_qp.reload()
self.assertFalse([d for d in group_qp.processes if d.procedure == child_qp.name])
def create_procedure(kwargs=None):
kwargs = frappe._dict(kwargs or {})
doc = frappe.new_doc("Quality Procedure")
doc.quality_procedure_name = kwargs.quality_procedure_name or "_Test Procedure"
doc.is_group = kwargs.is_group or 0
for process in kwargs.processes or []:
doc.append("processes", process)
doc.insert()
return doc

View File

@@ -131,7 +131,7 @@
"label": "Customer Type",
"oldfieldname": "customer_type",
"oldfieldtype": "Select",
"options": "Company\nIndividual",
"options": "Company\nIndividual\nProprietorship\nPartnership",
"reqd": 1
},
{
@@ -568,7 +568,7 @@
"link_fieldname": "party"
}
],
"modified": "2023-05-09 15:38:40.255193",
"modified": "2023-10-19 16:56:27.327035",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer",
@@ -655,4 +655,4 @@
"states": [],
"title_field": "customer_name",
"track_changes": 1
}
}

View File

@@ -541,6 +541,7 @@ def check_credit_limit(customer, company, ignore_outstanding_sales_order=False,
primary_action={
"label": "Send Email",
"server_action": "erpnext.selling.doctype.customer.customer.send_emails",
"hide_on_success": True,
"args": {
"customer": customer,
"customer_outstanding": customer_outstanding,

View File

@@ -137,6 +137,7 @@
"width": "300px"
},
{
"fetch_from": "item_code.image",
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
@@ -668,7 +669,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2023-09-27 14:02:12.332407",
"modified": "2023-11-14 18:24:24.619832",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation Item",
@@ -678,4 +679,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -204,7 +204,15 @@ class SalesOrder(SellingController):
def validate_with_previous_doc(self):
super(SalesOrder, self).validate_with_previous_doc(
{"Quotation": {"ref_dn_field": "prevdoc_docname", "compare_fields": [["company", "="]]}}
{
"Quotation": {"ref_dn_field": "prevdoc_docname", "compare_fields": [["company", "="]]},
"Quotation Item": {
"ref_dn_field": "quotation_item",
"compare_fields": [["item_code", "="], ["uom", "="], ["conversion_factor", "="]],
"is_child_table": True,
"allow_duplicate_prev_row_id": True,
},
}
)
if cint(frappe.db.get_single_value("Selling Settings", "maintain_same_sales_rate")):

View File

@@ -66,7 +66,6 @@
"total_weight",
"column_break_21",
"weight_uom",
"accounting_dimensions_section",
"warehouse_and_reference",
"warehouse",
"target_warehouse",
@@ -177,6 +176,7 @@
"print_hide": 1
},
{
"fetch_from": "item_code.image",
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
@@ -869,18 +869,12 @@
"label": "Production Plan Qty",
"no_copy": 1,
"read_only": 1
},
{
"collapsible": 1,
"fieldname": "accounting_dimensions_section",
"fieldtype": "Section Break",
"label": "Accounting Dimensions"
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2023-10-17 18:18:26.475259",
"modified": "2023-11-14 18:37:12.787893",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order Item",

View File

@@ -80,7 +80,7 @@ def get_data(filters=None):
territory_orders = []
if t_quotation_names and sales_orders:
list(filter(lambda x: x.quotation in t_quotation_names, sales_orders))
territory_orders = list(filter(lambda x: x.quotation in t_quotation_names, sales_orders))
t_order_names = []
if territory_orders:
t_order_names = [t.name for t in territory_orders]

View File

@@ -40,7 +40,7 @@ frappe.ui.form.on("Company", {
filters:{
'warehouse_type' : 'Transit',
'is_group': 0,
'company': frm.doc.company
'company': frm.doc.company_name
}
};
});

View File

@@ -108,7 +108,16 @@ class TransactionDeletionRecord(Document):
if no_of_docs > 0:
self.delete_version_log(docfield["parent"], docfield["fieldname"])
self.delete_communications(docfield["parent"], docfield["fieldname"])
reference_docs = frappe.get_all(
docfield["parent"], filters={docfield["fieldname"]: self.company}
)
reference_doc_names = [r.name for r in reference_docs]
self.delete_communications(docfield["parent"], reference_doc_names)
self.delete_comments(docfield["parent"], reference_doc_names)
self.unlink_attachments(docfield["parent"], reference_doc_names)
self.populate_doctypes_table(tables, docfield["parent"], no_of_docs)
self.delete_child_tables(docfield["parent"], docfield["fieldname"])
@@ -197,19 +206,49 @@ class TransactionDeletionRecord(Document):
(versions.ref_doctype == doctype) & (versions.docname.isin(batch))
).run()
def delete_communications(self, doctype, company_fieldname):
reference_docs = frappe.get_all(doctype, filters={company_fieldname: self.company})
reference_doc_names = [r.name for r in reference_docs]
def delete_communications(self, doctype, reference_doc_names):
communications = frappe.get_all(
"Communication",
filters={"reference_doctype": doctype, "reference_name": ["in", reference_doc_names]},
)
communication_names = [c.name for c in communications]
if not communication_names:
return
for batch in create_batch(communication_names, self.batch_size):
frappe.delete_doc("Communication", batch, ignore_permissions=True)
def delete_comments(self, doctype, reference_doc_names):
comments = frappe.get_all(
"Comment",
filters={"reference_doctype": doctype, "reference_name": ["in", reference_doc_names]},
)
comment_names = [c.name for c in comments]
if not comment_names:
return
for batch in create_batch(comment_names, self.batch_size):
frappe.delete_doc("Comment", batch, ignore_permissions=True)
def unlink_attachments(self, doctype, reference_doc_names):
files = frappe.get_all(
"File",
filters={"attached_to_doctype": doctype, "attached_to_name": ["in", reference_doc_names]},
)
file_names = [c.name for c in files]
if not file_names:
return
file = qb.DocType("File")
for batch in create_batch(file_names, self.batch_size):
qb.update(file).set(file.attached_to_doctype, None).set(file.attached_to_name, None).where(
file.name.isin(batch)
).run()
@frappe.whitelist()
def get_doctypes_to_be_ignored():

View File

@@ -61,6 +61,7 @@
"oldfieldname": "item",
"oldfieldtype": "Link",
"options": "Item",
"read_only_depends_on": "eval:!doc.__islocal",
"reqd": 1
},
{
@@ -207,7 +208,7 @@
"image_field": "image",
"links": [],
"max_attachments": 5,
"modified": "2022-02-21 08:08:23.999236",
"modified": "2023-11-09 12:17:28.339975",
"modified_by": "Administrator",
"module": "Stock",
"name": "Batch",

View File

@@ -5,20 +5,23 @@
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"warehouse",
"item_code",
"reserved_qty",
"column_break_yreo",
"warehouse",
"section_break_stag",
"actual_qty",
"ordered_qty",
"indented_qty",
"planned_qty",
"projected_qty",
"indented_qty",
"ordered_qty",
"column_break_xn5j",
"reserved_qty",
"reserved_qty_for_production",
"reserved_qty_for_sub_contract",
"reserved_qty_for_production_plan",
"ma_rate",
"projected_qty",
"section_break_pmrs",
"stock_uom",
"fcfs_rate",
"column_break_0slj",
"valuation_rate",
"stock_value"
],
@@ -56,7 +59,7 @@
"fieldname": "reserved_qty",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Reserved Quantity",
"label": "Reserved Qty",
"oldfieldname": "reserved_qty",
"oldfieldtype": "Currency",
"read_only": 1
@@ -67,7 +70,7 @@
"fieldtype": "Float",
"in_filter": 1,
"in_list_view": 1,
"label": "Actual Quantity",
"label": "Actual Qty",
"oldfieldname": "actual_qty",
"oldfieldtype": "Currency",
"read_only": 1
@@ -77,7 +80,7 @@
"fieldname": "ordered_qty",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Ordered Quantity",
"label": "Ordered Qty",
"oldfieldname": "ordered_qty",
"oldfieldtype": "Currency",
"read_only": 1
@@ -86,7 +89,7 @@
"default": "0.00",
"fieldname": "indented_qty",
"fieldtype": "Float",
"label": "Requested Quantity",
"label": "Requested Qty",
"oldfieldname": "indented_qty",
"oldfieldtype": "Currency",
"read_only": 1
@@ -116,20 +119,9 @@
{
"fieldname": "reserved_qty_for_sub_contract",
"fieldtype": "Float",
"label": "Reserved Qty for sub contract",
"label": "Reserved Qty for Subcontract",
"read_only": 1
},
{
"fieldname": "ma_rate",
"fieldtype": "Float",
"hidden": 1,
"label": "Moving Average Rate",
"oldfieldname": "ma_rate",
"oldfieldtype": "Currency",
"print_hide": 1,
"read_only": 1,
"report_hide": 1
},
{
"fieldname": "stock_uom",
"fieldtype": "Link",
@@ -140,17 +132,6 @@
"options": "UOM",
"read_only": 1
},
{
"fieldname": "fcfs_rate",
"fieldtype": "Float",
"hidden": 1,
"label": "FCFS Rate",
"oldfieldname": "fcfs_rate",
"oldfieldtype": "Currency",
"print_hide": 1,
"read_only": 1,
"report_hide": 1
},
{
"fieldname": "valuation_rate",
"fieldtype": "Float",
@@ -172,13 +153,33 @@
"fieldtype": "Float",
"label": "Reserved Qty for Production Plan",
"read_only": 1
},
{
"fieldname": "section_break_stag",
"fieldtype": "Section Break"
},
{
"fieldname": "column_break_yreo",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_xn5j",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_pmrs",
"fieldtype": "Section Break"
},
{
"fieldname": "column_break_0slj",
"fieldtype": "Column Break"
}
],
"hide_toolbar": 1,
"idx": 1,
"in_create": 1,
"links": [],
"modified": "2023-05-02 23:26:21.806965",
"modified": "2023-11-01 15:35:51.722534",
"modified_by": "Administrator",
"module": "Stock",
"name": "Bin",

View File

@@ -34,10 +34,15 @@ class Bin(Document):
get_reserved_qty_for_production_plan,
)
self.reserved_qty_for_production_plan = get_reserved_qty_for_production_plan(
reserved_qty_for_production_plan = get_reserved_qty_for_production_plan(
self.item_code, self.warehouse
)
if reserved_qty_for_production_plan is None and not self.reserved_qty_for_production_plan:
return
self.reserved_qty_for_production_plan = flt(reserved_qty_for_production_plan)
self.db_set(
"reserved_qty_for_production_plan",
flt(self.reserved_qty_for_production_plan),
@@ -48,6 +53,29 @@ class Bin(Document):
self.set_projected_qty()
self.db_set("projected_qty", self.projected_qty, update_modified=True)
def update_reserved_qty_for_for_sub_assembly(self):
from erpnext.manufacturing.doctype.production_plan.production_plan import (
get_reserved_qty_for_sub_assembly,
)
reserved_qty_for_production_plan = get_reserved_qty_for_sub_assembly(
self.item_code, self.warehouse
)
if reserved_qty_for_production_plan is None and not self.reserved_qty_for_production_plan:
return
self.reserved_qty_for_production_plan = flt(reserved_qty_for_production_plan)
self.set_projected_qty()
self.db_set(
{
"projected_qty": self.projected_qty,
"reserved_qty_for_production_plan": flt(self.reserved_qty_for_production_plan),
},
update_modified=True,
)
def update_reserved_qty_for_production(self):
"""Update qty reserved for production from Production Item tables
in open work orders"""

View File

@@ -1056,6 +1056,7 @@ class TestDeliveryNote(FrappeTestCase):
dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-3)
si1 = make_sales_invoice(dn1.name)
si1.update_billed_amount_in_delivery_note = True
si1.insert()
si1.submit()
dn1.reload()
@@ -1064,6 +1065,7 @@ class TestDeliveryNote(FrappeTestCase):
dn2 = create_delivery_note(is_return=1, return_against=dn.name, qty=-4)
si2 = make_sales_invoice(dn2.name)
si2.update_billed_amount_in_delivery_note = True
si2.insert()
si2.submit()
dn2.reload()

View File

@@ -165,6 +165,7 @@
"width": "300px"
},
{
"fetch_from": "item_code.image",
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
@@ -869,7 +870,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2023-10-16 16:18:18.013379",
"modified": "2023-11-14 18:37:38.638144",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note Item",

View File

@@ -111,6 +111,7 @@
"width": "250px"
},
{
"fetch_from": "item_code.image",
"fieldname": "image",
"fieldtype": "Attach Image",
"label": "Image",
@@ -479,7 +480,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2023-10-27 15:53:41.444236",
"modified": "2023-11-14 18:37:59.599115",
"modified_by": "Administrator",
"module": "Stock",
"name": "Material Request Item",

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