Compare commits

...

63 Commits

Author SHA1 Message Date
ruthra kumar
23dacbe9b2 Merge pull request #35840 from frappe/mergify/bp/version-14/pr-35837
refactor: increase precision for current exc rate in Exchange Rate Revaluation (backport #35837)
2023-06-22 14:34:52 +05:30
ruthra kumar
f45e8b9c16 refactor: increase precision for current exc rate in ERR
(cherry picked from commit b4db25dd18)
2023-06-22 08:37:20 +00:00
Frappe PR Bot
71207a7dae chore(release): Bumped to Version 14.27.10
## [14.27.10](https://github.com/frappe/erpnext/compare/v14.27.9...v14.27.10) (2023-06-22)

### Bug Fixes

* incorrect cost center error in bank reconciliation ([4be554d](4be554d8b4))
* no permission for accounts settings on payment reconciliation ([3194e3a](3194e3a020))
2023-06-22 06:26:14 +00:00
ruthra kumar
71e14b3dbb Merge pull request #35835 from frappe/mergify/bp/version-14/pr-35825
fix: multiple fixes in reconciliation tools (backport #35825)
2023-06-22 11:54:51 +05:30
ruthra kumar
4be554d8b4 fix: incorrect cost center error in bank reconciliation
(cherry picked from commit 41b9e92868)
2023-06-22 05:58:00 +00:00
ruthra kumar
3194e3a020 fix: no permission for accounts settings on payment reconciliation
(cherry picked from commit ad758b8d85)
2023-06-22 05:58:00 +00:00
Frappe PR Bot
2561cf2072 chore(release): Bumped to Version 14.27.9
## [14.27.9](https://github.com/frappe/erpnext/compare/v14.27.8...v14.27.9) (2023-06-20)

### Bug Fixes

* `Process Loss Report` (backport [#35712](https://github.com/frappe/erpnext/issues/35712)) ([#35719](https://github.com/frappe/erpnext/issues/35719)) ([55a8be5](55a8be5cad))
* add validation for QI in PR (backport [#35677](https://github.com/frappe/erpnext/issues/35677)) ([#35757](https://github.com/frappe/erpnext/issues/35757)) ([59ab13c](59ab13c34f))
* Allocated amount validation for other party types ([#35741](https://github.com/frappe/erpnext/issues/35741)) ([5541d68](5541d68477))
* cannot start / stop jobs ([53ec2a9](53ec2a9268))
* conflicts ([697fcef](697fcef98b))
* consider field precision while setting sle actual_qty ([#35717](https://github.com/frappe/erpnext/issues/35717)) ([3f62e85](3f62e854e5))
* date and finance book fixes in fixed asset register (backport [#35751](https://github.com/frappe/erpnext/issues/35751)) ([#35799](https://github.com/frappe/erpnext/issues/35799)) ([8b57ecd](8b57ecd8ef))
* don't add GL Entry for Acc. Depr. while scrapping non-depreciable assets (backport [#35714](https://github.com/frappe/erpnext/issues/35714)) ([#35715](https://github.com/frappe/erpnext/issues/35715)) ([77b0c5f](77b0c5f722))
* Duplicate addresses are creating while using the E-commerce ([703e4f4](703e4f4f5d))
* fix get outstanding invoices btn and add get outstanding orders btn (backport [#35776](https://github.com/frappe/erpnext/issues/35776)) ([#35787](https://github.com/frappe/erpnext/issues/35787)) ([42e25d4](42e25d4cdf))
* for zero bal accounts, dr/cr only on currency that has balance ([7da461b](7da461b862))
* incorrect gl entries for standalone debit note with update stock ([3355dc2](3355dc2a41))
* incorrect stock value for purchase returned with rejected qty (backport [#35747](https://github.com/frappe/erpnext/issues/35747)) ([#35752](https://github.com/frappe/erpnext/issues/35752)) ([c11d950](c11d950fc5))
* keyerror while checking the stock balance report ([baf014f](baf014fc61))
* loan interest accrual date ([#35695](https://github.com/frappe/erpnext/issues/35695)) ([070df97](070df97663))
* **patch:** enable existing serial no in stock settings ([#35762](https://github.com/frappe/erpnext/issues/35762)) ([3c790c1](3c790c12f2))
* stock error for service item ([2bbea63](2bbea63de1))
* test case ([4af0a9b](4af0a9b192))
* unsupported operand type(s) for //: 'float' and 'NoneType' for POS Barcode search ([#35710](https://github.com/frappe/erpnext/issues/35710)) ([58a6bbc](58a6bbcf6d))
* update `Stock Reconciliation` diff qty while reposting ([bdb5cc8](bdb5cc8ad4))
* **ux:** set route options for new `Batch` ([b261242](b261242792))
* validation of job card in stock entry ([ce2bf5f](ce2bf5fb1c))
* work order serial no issue ([50a8907](50a8907e8c))

### Performance Improvements

* Duplicate queries for UOM (backport [#35744](https://github.com/frappe/erpnext/issues/35744)) ([#35745](https://github.com/frappe/erpnext/issues/35745)) ([632b67c](632b67cbc8))
* duplicate queries while checking prevdoc (backport [#35746](https://github.com/frappe/erpnext/issues/35746)) ([#35749](https://github.com/frappe/erpnext/issues/35749)) ([a0fc8e2](a0fc8e252c))
* Ignore cancelled pick lists while fetching picked items (backport [#35737](https://github.com/frappe/erpnext/issues/35737)) ([#35740](https://github.com/frappe/erpnext/issues/35740)) ([01ac54d](01ac54d65d))
* index `purpose` in `Stock Entry` (backport [#35782](https://github.com/frappe/erpnext/issues/35782)) ([#35783](https://github.com/frappe/erpnext/issues/35783)) ([3bac2a8](3bac2a88bd))
* Index pick list field in stock entry and DN (backport [#35738](https://github.com/frappe/erpnext/issues/35738)) ([#35742](https://github.com/frappe/erpnext/issues/35742)) ([b875de6](b875de6fb7))
* Index sales_order_item in Pick list item (backport [#35735](https://github.com/frappe/erpnext/issues/35735)) ([#35736](https://github.com/frappe/erpnext/issues/35736)) ([0e57f4d](0e57f4dd3c))
2023-06-20 16:06:29 +00:00
Deepesh Garg
abbbfe6240 Merge pull request #35807 from frappe/version-14-hotfix
chore: release v14
2023-06-20 21:34:30 +05:30
rohitwaghchaure
4e1b2c6f8d Merge branch 'version-14' into version-14-hotfix 2023-06-20 19:41:56 +05:30
rohitwaghchaure
c669dba691 Merge pull request #35813 from frappe/mergify/bp/version-14-hotfix/pr-35810
fix: stock error for service item (backport #35810)
2023-06-20 17:49:32 +05:30
rohitwaghchaure
8c183741bd Merge pull request #35812 from frappe/mergify/bp/version-14-hotfix/pr-35809
fix: key error while checking the stock balance report (backport #35809)
2023-06-20 17:30:51 +05:30
Rohit Waghchaure
2bbea63de1 fix: stock error for service item
(cherry picked from commit 32965f1af9)
2023-06-20 11:51:27 +00:00
Rohit Waghchaure
baf014fc61 fix: keyerror while checking the stock balance report
(cherry picked from commit a627d2a38c)
2023-06-20 11:32:06 +00:00
rohitwaghchaure
95e3dc9b81 Merge pull request #35805 from rohitwaghchaure/fixed-address-issue-from-e-cart
fix: Duplicate addresses are creating while using the E-commerce
2023-06-20 15:43:58 +05:30
Rohit Waghchaure
703e4f4f5d fix: Duplicate addresses are creating while using the E-commerce 2023-06-20 14:50:40 +05:30
ruthra kumar
bf2ebce6f4 Merge pull request #35803 from frappe/mergify/bp/version-14-hotfix/pr-35794
fix: Exchange Rate Revaluation should only post on the currency that has balance in a 'zero' balance account (backport #35794)
2023-06-20 14:49:06 +05:30
ruthra kumar
65d24ea9ea refactor: higher precision for rounding loss and allow '0'
(cherry picked from commit 6694175a51)
2023-06-20 14:02:45 +05:30
ruthra kumar
6c9c3426f8 refactor: allow '0' rounding allowance
(cherry picked from commit 4567474418)
2023-06-20 14:02:40 +05:30
ruthra kumar
146d41ee81 refactor: allow higher precision for new exchange rate
(cherry picked from commit 9d04af9ecc)
2023-06-20 08:29:53 +00:00
ruthra kumar
7da461b862 fix: for zero bal accounts, dr/cr only on currency that has balance
(cherry picked from commit 1b33afd699)
2023-06-20 08:29:53 +00:00
mergify[bot]
8b57ecd8ef fix: date and finance book fixes in fixed asset register (backport #35751) (#35799)
* fix: date and finance book fixes in fixed asset register (#35751)

* fix: handle finance books properly and show all assets by default in fixed asset register

* chore: rename value to depr amount

* chore: get asset value for correct fb properly

* chore: rename include_default_book_entries to include_default_book_assets

(cherry picked from commit 0d12588583)

# Conflicts:
#	erpnext/assets/report/fixed_asset_register/fixed_asset_register.py

* chore: resolving conflicts and renaming entries to assets

---------

Co-authored-by: Anand Baburajan <anandbaburajan@gmail.com>
2023-06-20 12:52:18 +05:30
rohitwaghchaure
7d010adcd4 Merge pull request #35786 from rohitwaghchaure/fixed-work-order-serial-no-issue
fix: work order serial no issue
2023-06-20 12:13:17 +05:30
Rohit Waghchaure
4af0a9b192 fix: test case 2023-06-20 11:42:02 +05:30
mergify[bot]
3bac2a88bd perf: index purpose in Stock Entry (backport #35782) (#35783)
perf: index `purpose` in `Stock Entry`

(cherry picked from commit 4f941ac5c0)

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-06-19 22:22:50 +05:30
Rohit Waghchaure
50a8907e8c fix: work order serial no issue 2023-06-19 21:29:34 +05:30
mergify[bot]
42e25d4cdf fix: fix get outstanding invoices btn and add get outstanding orders btn (backport #35776) (#35787)
fix: fix get outstanding invoices btn and add get outstanding orders btn (#35776)

* fix: fix get outstanding invoices btn and add get outstanding orders btn

* chore: remove unnecessary arg

(cherry picked from commit c1da3ddbbf)

Co-authored-by: Anand Baburajan <anandbaburajan@gmail.com>
2023-06-19 20:17:56 +05:30
Frappe PR Bot
4c1befab8f chore(release): Bumped to Version 14.27.8
## [14.27.8](https://github.com/frappe/erpnext/compare/v14.27.7...v14.27.8) (2023-06-19)

### Bug Fixes

* Allocated amount validation for other party types ([#35741](https://github.com/frappe/erpnext/issues/35741)) ([3bf7115](3bf7115cdc))
2023-06-19 11:38:53 +00:00
Deepesh Garg
d928a5c3aa Merge pull request #35774 from frappe/mergify/bp/version-14/pr-35770
fix: Allocated amount validation for other party types (#35741)
2023-06-19 17:07:06 +05:30
mergify[bot]
3bf7115cdc fix: Allocated amount validation for other party types (#35741)
fix: Allocated amount validation for other party types (#35741)

* fix: Allocated amount validation for other party types

* chore: Validation for return allocations

* chore: minor typo

---------

Co-authored-by: anandbaburajan <anandbaburajan@gmail.com>
(cherry picked from commit 9d27a25e5f)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
(cherry picked from commit 5541d68477)
2023-06-19 07:22:55 +00:00
mergify[bot]
5541d68477 fix: Allocated amount validation for other party types (#35741)
fix: Allocated amount validation for other party types (#35741)

* fix: Allocated amount validation for other party types

* chore: Validation for return allocations

* chore: minor typo

---------

Co-authored-by: anandbaburajan <anandbaburajan@gmail.com>
(cherry picked from commit 9d27a25e5f)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
2023-06-19 12:52:06 +05:30
mergify[bot]
070df97663 fix: loan interest accrual date (#35695)
fix: loan interest accrual date (#35695)

fix: loan interest accrual date

---------

Co-authored-by: Abhinav Raut <abhinav.raut@zerodha.com>
Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
(cherry picked from commit 2a24423ad2)

Co-authored-by: Abhinav Raut <abhinavrautcs@gmail.com>
2023-06-19 09:14:21 +05:30
Vishal Dhayagude
58a6bbcf6d fix: unsupported operand type(s) for //: 'float' and 'NoneType' for POS Barcode search (#35710) 2023-06-18 23:00:01 +05:30
Sagar Sharma
6650373c9f Merge pull request #35743 from s-aga-r/FIX-35493-V14
fix(ux): set route options for new `Batch`
2023-06-18 15:12:12 +05:30
Sagar Sharma
3c790c12f2 fix(patch): enable existing serial no in stock settings (#35762) 2023-06-17 23:21:30 +05:30
mergify[bot]
b875de6fb7 perf: Index pick list field in stock entry and DN (backport #35738) (#35742)
* perf: Index pick list field in stock entry and DN (#35738)

We check if pick list is created against them but there's no index so we
end up reading entire table.

```
+------+-------------+------------------+-------+---------------+----------+---------+------+--------+-----------+----------+------------+-------------+
| id   | select_type | table            | type  | possible_keys | key      | key_len | ref  | rows   | r_rows    | filtered | r_filtered | Extra       |
+------+-------------+------------------+-------+---------------+----------+---------+------+--------+-----------+----------+------------+-------------+
|    1 | SIMPLE      | tabDelivery Note | index | NULL          | modified | 9       | NULL | 207015 | 348940.00 |   100.00 |       0.00 | Using where |
+------+-------------+------------------+-------+---------------+----------+---------+------+--------+-----------+----------+------------+-------------+
```

After

```
+------+-------------+------------------+------+-----------------+-----------------+---------+-------+------+--------+----------+------------+------------------------------->
| id   | select_type | table            | type | possible_keys   | key             | key_len | ref   | rows | r_rows | filtered | r_filtered | Extra                         >
+------+-------------+------------------+------+-----------------+-----------------+---------+-------+------+--------+----------+------------+------------------------------->
|    1 | SIMPLE      | tabDelivery Note | ref  | pick_list_index | pick_list_index | 563     | const | 1    | 0.00   |   100.00 |     100.00 | Using index condition; Using w>
+------+-------------+------------------+------+-----------------+-----------------+---------+-------+------+--------+----------+------------+------------------------------->
```

(cherry picked from commit 433489a9e6)

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

* chore: conflict

---------

Co-authored-by: Ankush Menat <ankush@frappe.io>
2023-06-17 21:25:30 +05:30
Frappe PR Bot
58e304f64b chore(release): Bumped to Version 14.27.7
## [14.27.7](https://github.com/frappe/erpnext/compare/v14.27.6...v14.27.7) (2023-06-17)

### Bug Fixes

* validation of job card in stock entry ([e7abdc3](e7abdc34d0))
2023-06-17 08:35:04 +00:00
rohitwaghchaure
46171738c0 Merge pull request #35761 from frappe/mergify/bp/version-14/pr-35759
fix: validation of job card in stock entry (backport #35756) (backport #35759)
2023-06-17 14:03:29 +05:30
Rohit Waghchaure
e7abdc34d0 fix: validation of job card in stock entry
(cherry picked from commit df8c3f0888)
(cherry picked from commit ce2bf5fb1c)
2023-06-17 08:32:59 +00:00
rohitwaghchaure
fc103ab4ce Merge pull request #35759 from frappe/mergify/bp/version-14-hotfix/pr-35756
fix: validation of job card in stock entry (backport #35756)
2023-06-17 14:02:11 +05:30
Rohit Waghchaure
ce2bf5fb1c fix: validation of job card in stock entry
(cherry picked from commit df8c3f0888)
2023-06-17 08:03:08 +00:00
mergify[bot]
59ab13c34f fix: add validation for QI in PR (backport #35677) (#35757)
fix: add validation for QI in PR

(cherry picked from commit 2c1ab569a7)

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-06-17 12:52:18 +05:30
Frappe PR Bot
7ffa6b4fbd chore(release): Bumped to Version 14.27.6
## [14.27.6](https://github.com/frappe/erpnext/compare/v14.27.5...v14.27.6) (2023-06-17)

### Bug Fixes

* cannot start / stop Job Card (backport [#35753](https://github.com/frappe/erpnext/issues/35753)) ([#35754](https://github.com/frappe/erpnext/issues/35754)) ([19203bb](19203bb87d))
2023-06-17 06:58:24 +00:00
mergify[bot]
19203bb87d fix: cannot start / stop Job Card (backport #35753) (#35754)
fix: cannot start / stop jobs

(cherry picked from commit 53ec2a9268)

Co-authored-by: Anoop Kurungadam <anoop@earthianslive.com>
2023-06-17 12:18:01 +05:30
rohitwaghchaure
9792099cea Merge pull request #35753 from akurungadam/jobcard-fix
fix: cannot start / stop Job Card
2023-06-17 12:04:49 +05:30
mergify[bot]
c11d950fc5 fix: incorrect stock value for purchase returned with rejected qty (backport #35747) (#35752)
fix: incorrect stock value for purchase returned with rejected qty

(cherry picked from commit 28dd758aa3)

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
2023-06-17 11:33:17 +05:30
Anoop Kurungadam
53ec2a9268 fix: cannot start / stop jobs 2023-06-17 11:21:03 +05:30
mergify[bot]
a0fc8e252c perf: duplicate queries while checking prevdoc (backport #35746) (#35749)
perf: duplicate queries while checking prevdoc (#35746)

These values can't change durning DB transaction AFAIK

(cherry picked from commit 6086d1a99d)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2023-06-16 18:45:23 +05:30
mergify[bot]
632b67cbc8 perf: Duplicate queries for UOM (backport #35744) (#35745)
perf: Duplicate queries for UOM (#35744)

This query repeats for every item, UOMs rarely if ever change

(cherry picked from commit 29da1db516)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2023-06-16 16:40:40 +05:30
s-aga-r
b261242792 fix(ux): set route options for new Batch 2023-06-16 16:28:49 +05:30
mergify[bot]
01ac54d65d perf: Ignore cancelled pick lists while fetching picked items (backport #35737) (#35740)
perf: Ignore cancelled pick lists while fetching picked items (#35737)

(cherry picked from commit 81f916b7d3)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2023-06-16 15:29:20 +05:30
mergify[bot]
0e57f4dd3c perf: Index sales_order_item in Pick list item (backport #35735) (#35736)
* perf: Index sales_order_item in Pick list item (#35735)

- `get_picked_items_qty` does full table scan
- because it also locks, it does full table lock.

(cherry picked from commit 07d748c290)

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

* chore: conflicts

---------

Co-authored-by: Ankush Menat <ankush@frappe.io>
2023-06-16 15:22:44 +05:30
rohitwaghchaure
7339e447bb Merge pull request #35718 from frappe/mergify/bp/version-14-hotfix/pr-35711
fix: incorrect gl entries for standalone debit note (backport #35711)
2023-06-16 13:46:16 +05:30
mergify[bot]
55a8be5cad fix: Process Loss Report (backport #35712) (#35719)
fix: `Process Loss Report`

(cherry picked from commit d176d86e2c)

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-06-15 19:42:53 +05:30
Sagar Sharma
3f62e854e5 fix: consider field precision while setting sle actual_qty (#35717) 2023-06-15 19:26:38 +05:30
rohitwaghchaure
697fcef98b fix: conflicts 2023-06-15 19:14:41 +05:30
Rohit Waghchaure
e2c4e16d72 test: added test case
(cherry picked from commit f9f662679f)
2023-06-15 13:43:20 +00:00
Rohit Waghchaure
3355dc2a41 fix: incorrect gl entries for standalone debit note with update stock
(cherry picked from commit 6e198188ff)

# Conflicts:
#	erpnext/controllers/buying_controller.py
2023-06-15 13:43:20 +00:00
mergify[bot]
77b0c5f722 fix: don't add GL Entry for Acc. Depr. while scrapping non-depreciable assets (backport #35714) (#35715)
fix: don't add GL Entry for Acc. Depr. while scrapping non-depreciable assets (#35714)

fix: on asset scrap, don't add gl entry for acc. depr. if no acc. depr.
(cherry picked from commit bb39a2cac7)

Co-authored-by: Anand Baburajan <anandbaburajan@gmail.com>
2023-06-15 17:37:12 +05:30
Frappe PR Bot
138133e11d chore(release): Bumped to Version 14.27.5
## [14.27.5](https://github.com/frappe/erpnext/compare/v14.27.4...v14.27.5) (2023-06-15)

### Bug Fixes

* typeerror on exchange rate revaluation ([d934dda](d934dda410))
2023-06-15 08:10:29 +00:00
ruthra kumar
582ed2c7f1 Merge pull request #35706 from frappe/mergify/bp/version-14/pr-35701
fix: typeerror on exchange rate revaluation (backport #35701)
2023-06-15 13:38:59 +05:30
ruthra kumar
d934dda410 fix: typeerror on exchange rate revaluation
(cherry picked from commit f8273f7db6)
2023-06-15 06:55:03 +00:00
Sagar Sharma
9d1fac19e5 Merge pull request #35702 from frappe/mergify/bp/version-14-hotfix/pr-35700
fix: update `Stock Reconciliation` diff qty while reposting (backport #35700)
2023-06-15 11:44:14 +05:30
s-aga-r
bdb5cc8ad4 fix: update Stock Reconciliation diff qty while reposting
(cherry picked from commit 6a1b0a2fab)
2023-06-15 06:13:10 +00:00
39 changed files with 618 additions and 274 deletions

View File

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

View File

@@ -10,6 +10,7 @@ from frappe.model.document import Document
from frappe.query_builder.custom import ConstantColumn
from frappe.utils import cint, flt
from erpnext import get_default_cost_center
from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_total_allocated_amount
from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_statement import (
get_amounts_not_reflected_in_system,
@@ -140,6 +141,9 @@ def create_journal_entry_bts(
second_account
)
)
company = frappe.get_value("Account", company_account, "company")
accounts = []
# Multi Currency?
accounts.append(
@@ -149,6 +153,7 @@ def create_journal_entry_bts(
"debit_in_account_currency": bank_transaction.withdrawal,
"party_type": party_type,
"party": party,
"cost_center": get_default_cost_center(company),
}
)
@@ -158,11 +163,10 @@ def create_journal_entry_bts(
"bank_account": bank_transaction.bank_account,
"credit_in_account_currency": bank_transaction.withdrawal,
"debit_in_account_currency": bank_transaction.deposit,
"cost_center": get_default_cost_center(company),
}
)
company = frappe.get_value("Account", company_account, "company")
journal_entry_dict = {
"voucher_type": entry_type,
"company": company,

View File

@@ -37,7 +37,7 @@ frappe.ui.form.on('Exchange Rate Revaluation', {
validate_rounding_loss: function(frm) {
let allowance = frm.doc.rounding_loss_allowance;
if (!(allowance > 0 && allowance < 1)) {
if (!(allowance >= 0 && allowance < 1)) {
frappe.throw(__("Rounding Loss Allowance should be between 0 and 1"));
}
},

View File

@@ -100,15 +100,16 @@
},
{
"default": "0.05",
"description": "Only values between 0 and 1 are allowed. \nEx: If allowance is set at 0.07, accounts that have balance of 0.07 in either of the currencies will be considered as zero balance account",
"description": "Only values between [0,1) are allowed. Like {0.00, 0.04, 0.09, ...}\nEx: If allowance is set at 0.07, accounts that have balance of 0.07 in either of the currencies will be considered as zero balance account",
"fieldname": "rounding_loss_allowance",
"fieldtype": "Float",
"label": "Rounding Loss Allowance"
"label": "Rounding Loss Allowance",
"precision": "9"
}
],
"is_submittable": 1,
"links": [],
"modified": "2023-06-12 21:02:09.818208",
"modified": "2023-06-20 07:29:06.972434",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Exchange Rate Revaluation",

View File

@@ -22,7 +22,7 @@ class ExchangeRateRevaluation(Document):
self.set_total_gain_loss()
def validate_rounding_loss_allowance(self):
if not (self.rounding_loss_allowance > 0 and self.rounding_loss_allowance < 1):
if not (self.rounding_loss_allowance >= 0 and self.rounding_loss_allowance < 1):
frappe.throw(_("Rounding Loss Allowance should be between 0 and 1"))
def set_total_gain_loss(self):
@@ -186,7 +186,7 @@ class ExchangeRateRevaluation(Document):
# round off balance based on currency precision
# and consider debit-credit difference allowance
currency_precision = get_currency_precision()
rounding_loss_allowance = rounding_loss_allowance or 0.05
rounding_loss_allowance = float(rounding_loss_allowance) or 0.05
for acc in account_details:
acc.balance_in_account_currency = flt(acc.balance_in_account_currency, currency_precision)
if abs(acc.balance_in_account_currency) <= rounding_loss_allowance:
@@ -373,6 +373,24 @@ class ExchangeRateRevaluation(Document):
"credit": 0,
}
)
journal_entry_accounts.append(journal_account)
journal_entry_accounts.append(
{
"account": unrealized_exchange_gain_loss_account,
"balance": get_balance_on(unrealized_exchange_gain_loss_account),
"debit": 0,
"credit": 0,
"debit_in_account_currency": abs(d.gain_loss) if d.gain_loss < 0 else 0,
"credit_in_account_currency": abs(d.gain_loss) if d.gain_loss > 0 else 0,
"cost_center": erpnext.get_default_cost_center(self.company),
"exchange_rate": 1,
"reference_type": "Exchange Rate Revaluation",
"reference_name": self.name,
}
)
elif d.get("balance_in_base_currency") and not d.get("new_balance_in_base_currency"):
# Base currency has balance
dr_or_cr = "credit" if d.get("balance_in_base_currency") > 0 else "debit"
@@ -388,22 +406,22 @@ class ExchangeRateRevaluation(Document):
}
)
journal_entry_accounts.append(journal_account)
journal_entry_accounts.append(journal_account)
journal_entry_accounts.append(
{
"account": unrealized_exchange_gain_loss_account,
"balance": get_balance_on(unrealized_exchange_gain_loss_account),
"debit": abs(self.gain_loss_booked) if self.gain_loss_booked < 0 else 0,
"credit": abs(self.gain_loss_booked) if self.gain_loss_booked > 0 else 0,
"debit_in_account_currency": abs(self.gain_loss_booked) if self.gain_loss_booked < 0 else 0,
"credit_in_account_currency": self.gain_loss_booked if self.gain_loss_booked > 0 else 0,
"cost_center": erpnext.get_default_cost_center(self.company),
"exchange_rate": 1,
"reference_type": "Exchange Rate Revaluation",
"reference_name": self.name,
}
)
journal_entry_accounts.append(
{
"account": unrealized_exchange_gain_loss_account,
"balance": get_balance_on(unrealized_exchange_gain_loss_account),
"debit": abs(d.gain_loss) if d.gain_loss < 0 else 0,
"credit": abs(d.gain_loss) if d.gain_loss > 0 else 0,
"debit_in_account_currency": 0,
"credit_in_account_currency": 0,
"cost_center": erpnext.get_default_cost_center(self.company),
"exchange_rate": 1,
"reference_type": "Exchange Rate Revaluation",
"reference_name": self.name,
}
)
journal_entry.set("accounts", journal_entry_accounts)
journal_entry.set_total_debit_credit()
@@ -552,7 +570,7 @@ def calculate_exchange_rate_using_last_gle(company, account, party_type, party):
@frappe.whitelist()
def get_account_details(
company, posting_date, account, party_type=None, party=None, rounding_loss_allowance=None
company, posting_date, account, party_type=None, party=None, rounding_loss_allowance: float = None
):
if not (company and posting_date):
frappe.throw(_("Company and Posting Date is mandatory"))

View File

@@ -73,6 +73,7 @@
"fieldname": "current_exchange_rate",
"fieldtype": "Float",
"label": "Current Exchange Rate",
"precision": "9",
"read_only": 1
},
{
@@ -92,6 +93,7 @@
"fieldtype": "Float",
"in_list_view": 1,
"label": "New Exchange Rate",
"precision": "9",
"reqd": 1
},
{
@@ -147,7 +149,7 @@
],
"istable": 1,
"links": [],
"modified": "2022-12-29 19:38:52.915295",
"modified": "2023-06-22 12:39:56.446722",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Exchange Rate Revaluation Account",

View File

@@ -613,7 +613,7 @@ frappe.ui.form.on('Payment Entry', {
frm.events.set_unallocated_amount(frm);
},
get_outstanding_invoice: function(frm) {
get_outstanding_invoices_or_orders: function(frm, get_outstanding_invoices, get_orders_to_be_billed) {
const today = frappe.datetime.get_today();
const fields = [
{fieldtype:"Section Break", label: __("Posting Date")},
@@ -643,12 +643,29 @@ frappe.ui.form.on('Payment Entry', {
{fieldtype:"Check", label: __("Allocate Payment Amount"), fieldname:"allocate_payment_amount", default:1},
];
let btn_text = "";
if (get_outstanding_invoices) {
btn_text = "Get Outstanding Invoices";
}
else if (get_orders_to_be_billed) {
btn_text = "Get Outstanding Orders";
}
frappe.prompt(fields, function(filters){
frappe.flags.allocate_payment_amount = true;
frm.events.validate_filters_data(frm, filters);
frm.doc.cost_center = filters.cost_center;
frm.events.get_outstanding_documents(frm, filters);
}, __("Filters"), __("Get Outstanding Documents"));
frm.events.get_outstanding_documents(frm, filters, get_outstanding_invoices, get_orders_to_be_billed);
}, __("Filters"), __(btn_text));
},
get_outstanding_invoices: function(frm) {
frm.events.get_outstanding_invoices_or_orders(frm, true, false);
},
get_outstanding_orders: function(frm) {
frm.events.get_outstanding_invoices_or_orders(frm, false, true);
},
validate_filters_data: function(frm, filters) {
@@ -674,7 +691,7 @@ frappe.ui.form.on('Payment Entry', {
}
},
get_outstanding_documents: function(frm, filters) {
get_outstanding_documents: function(frm, filters, get_outstanding_invoices, get_orders_to_be_billed) {
frm.clear_table("references");
if(!frm.doc.party) {
@@ -698,6 +715,13 @@ frappe.ui.form.on('Payment Entry', {
args[key] = filters[key];
}
if (get_outstanding_invoices) {
args["get_outstanding_invoices"] = true;
}
else if (get_orders_to_be_billed) {
args["get_orders_to_be_billed"] = true;
}
frappe.flags.allocate_payment_amount = filters['allocate_payment_amount'];
return frappe.call({

View File

@@ -48,7 +48,8 @@
"base_received_amount",
"base_received_amount_after_tax",
"section_break_14",
"get_outstanding_invoice",
"get_outstanding_invoices",
"get_outstanding_orders",
"references",
"section_break_34",
"total_allocated_amount",
@@ -355,12 +356,6 @@
"fieldtype": "Section Break",
"label": "Reference"
},
{
"depends_on": "eval:doc.docstatus==0",
"fieldname": "get_outstanding_invoice",
"fieldtype": "Button",
"label": "Get Outstanding Invoice"
},
{
"fieldname": "references",
"fieldtype": "Table",
@@ -728,12 +723,24 @@
"fieldname": "section_break_60",
"fieldtype": "Section Break",
"hide_border": 1
},
{
"depends_on": "eval:doc.docstatus==0",
"fieldname": "get_outstanding_invoices",
"fieldtype": "Button",
"label": "Get Outstanding Invoices"
},
{
"depends_on": "eval:doc.docstatus==0",
"fieldname": "get_outstanding_orders",
"fieldtype": "Button",
"label": "Get Outstanding Orders"
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2023-02-14 04:52:30.478523",
"modified": "2023-06-19 11:38:04.387219",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",

View File

@@ -151,6 +151,19 @@ class PaymentEntry(AccountsController):
if self.payment_type == "Internal Transfer":
return
if self.party_type in ("Customer", "Supplier"):
self.validate_allocated_amount_with_latest_data()
else:
fail_message = _("Row #{0}: Allocated Amount cannot be greater than outstanding amount.")
for d in self.get("references"):
if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(d.outstanding_amount):
frappe.throw(fail_message.format(d.idx))
# Check for negative outstanding invoices as well
if flt(d.allocated_amount) < 0 and flt(d.allocated_amount) < flt(d.outstanding_amount):
frappe.throw(fail_message.format(d.idx))
def validate_allocated_amount_with_latest_data(self):
latest_references = get_outstanding_reference_documents(
{
"posting_date": self.posting_date,
@@ -159,6 +172,8 @@ class PaymentEntry(AccountsController):
"payment_type": self.payment_type,
"party": self.party,
"party_account": self.paid_from if self.payment_type == "Receive" else self.paid_to,
"get_outstanding_invoices": True,
"get_orders_to_be_billed": True,
}
)
@@ -168,7 +183,7 @@ class PaymentEntry(AccountsController):
d = frappe._dict(d)
latest_lookup.update({(d.voucher_type, d.voucher_no): d})
for d in self.get("references").copy():
for d in self.get("references"):
latest = latest_lookup.get((d.reference_doctype, d.reference_name))
# The reference has already been fully paid
@@ -183,22 +198,18 @@ class PaymentEntry(AccountsController):
):
frappe.throw(
_(
"{0} {1} has already been partly paid. Please use the 'Get Outstanding Invoice' button to get the latest outstanding amount."
"{0} {1} has already been partly paid. Please use the 'Get Outstanding Invoice' or the 'Get Outstanding Orders' button to get the latest outstanding amounts."
).format(d.reference_doctype, d.reference_name)
)
d.outstanding_amount = latest.outstanding_amount
fail_message = _("Row #{0}: Allocated Amount cannot be greater than outstanding amount.")
if (flt(d.allocated_amount)) > 0:
if flt(d.allocated_amount) > flt(d.outstanding_amount):
frappe.throw(fail_message.format(d.idx))
if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(latest.outstanding_amount):
frappe.throw(fail_message.format(d.idx))
# Check for negative outstanding invoices as well
if flt(d.allocated_amount) < 0:
if flt(d.allocated_amount) < flt(d.outstanding_amount):
frappe.throw(fail_message.format(d.idx))
if flt(d.allocated_amount) < 0 and flt(d.allocated_amount) < flt(latest.outstanding_amount):
frappe.throw(fail_message.format(d.idx))
def delink_advance_entry_references(self):
for reference in self.references:
@@ -1347,62 +1358,75 @@ def get_outstanding_reference_documents(args):
condition += " and company = {0}".format(frappe.db.escape(args.get("company")))
common_filter.append(ple.company == args.get("company"))
outstanding_invoices = get_outstanding_invoices(
args.get("party_type"),
args.get("party"),
args.get("party_account"),
common_filter=common_filter,
posting_date=posting_and_due_date,
min_outstanding=args.get("outstanding_amt_greater_than"),
max_outstanding=args.get("outstanding_amt_less_than"),
accounting_dimensions=accounting_dimensions_filter,
)
outstanding_invoices = split_invoices_based_on_payment_terms(outstanding_invoices)
for d in outstanding_invoices:
d["exchange_rate"] = 1
if party_account_currency != company_currency:
if d.voucher_type in frappe.get_hooks("invoice_doctypes"):
d["exchange_rate"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "conversion_rate")
elif d.voucher_type == "Journal Entry":
d["exchange_rate"] = get_exchange_rate(
party_account_currency, company_currency, d.posting_date
)
if d.voucher_type in ("Purchase Invoice"):
d["bill_no"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "bill_no")
# Get all SO / PO which are not fully billed or against which full advance not paid
orders_to_be_billed = []
orders_to_be_billed = get_orders_to_be_billed(
args.get("posting_date"),
args.get("party_type"),
args.get("party"),
args.get("company"),
party_account_currency,
company_currency,
filters=args,
)
# Get negative outstanding sales /purchase invoices
outstanding_invoices = []
negative_outstanding_invoices = []
if args.get("party_type") != "Employee" and not args.get("voucher_no"):
negative_outstanding_invoices = get_negative_outstanding_invoices(
if args.get("get_outstanding_invoices"):
outstanding_invoices = get_outstanding_invoices(
args.get("party_type"),
args.get("party"),
args.get("party_account"),
common_filter=common_filter,
posting_date=posting_and_due_date,
min_outstanding=args.get("outstanding_amt_greater_than"),
max_outstanding=args.get("outstanding_amt_less_than"),
accounting_dimensions=accounting_dimensions_filter,
)
outstanding_invoices = split_invoices_based_on_payment_terms(outstanding_invoices)
for d in outstanding_invoices:
d["exchange_rate"] = 1
if party_account_currency != company_currency:
if d.voucher_type in frappe.get_hooks("invoice_doctypes"):
d["exchange_rate"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "conversion_rate")
elif d.voucher_type == "Journal Entry":
d["exchange_rate"] = get_exchange_rate(
party_account_currency, company_currency, d.posting_date
)
if d.voucher_type in ("Purchase Invoice"):
d["bill_no"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "bill_no")
# Get negative outstanding sales /purchase invoices
if args.get("party_type") != "Employee" and not args.get("voucher_no"):
negative_outstanding_invoices = get_negative_outstanding_invoices(
args.get("party_type"),
args.get("party"),
args.get("party_account"),
party_account_currency,
company_currency,
condition=condition,
)
# Get all SO / PO which are not fully billed or against which full advance not paid
orders_to_be_billed = []
if args.get("get_orders_to_be_billed"):
orders_to_be_billed = get_orders_to_be_billed(
args.get("posting_date"),
args.get("party_type"),
args.get("party"),
args.get("company"),
party_account_currency,
company_currency,
condition=condition,
filters=args,
)
data = negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
if not data:
if args.get("get_outstanding_invoices") and args.get("get_orders_to_be_billed"):
ref_document_type = "invoices or orders"
elif args.get("get_outstanding_invoices"):
ref_document_type = "invoices"
elif args.get("get_orders_to_be_billed"):
ref_document_type = "orders"
frappe.msgprint(
_(
"No outstanding invoices found for the {0} {1} which qualify the filters you have specified."
).format(_(args.get("party_type")).lower(), frappe.bold(args.get("party")))
"No outstanding {0} found for the {1} {2} which qualify the filters you have specified."
).format(
ref_document_type, _(args.get("party_type")).lower(), frappe.bold(args.get("party"))
)
)
return data

View File

@@ -85,25 +85,29 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
// check for any running reconciliation jobs
if (this.frm.doc.receivable_payable_account) {
frappe.db.get_single_value("Accounts Settings", "auto_reconcile_payments").then((enabled) => {
if(enabled) {
this.frm.call({
'method': "erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.is_any_doc_running",
"args": {
for_filter: {
company: this.frm.doc.company,
party_type: this.frm.doc.party_type,
party: this.frm.doc.party,
receivable_payable_account: this.frm.doc.receivable_payable_account
this.frm.call({
doc: this.frm.doc,
method: 'is_auto_process_enabled',
callback: (r) => {
if (r.message) {
this.frm.call({
'method': "erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.is_any_doc_running",
"args": {
for_filter: {
company: this.frm.doc.company,
party_type: this.frm.doc.party_type,
party: this.frm.doc.party,
receivable_payable_account: this.frm.doc.receivable_payable_account
}
}
}
}).then(r => {
if (r.message) {
let doc_link = frappe.utils.get_form_link("Process Payment Reconciliation", r.message, true);
let msg = __("Payment Reconciliation Job: {0} is running for this party. Can't reconcile now.", [doc_link]);
this.frm.dashboard.add_comment(msg, "yellow");
}
});
}).then(r => {
if (r.message) {
let doc_link = frappe.utils.get_form_link("Process Payment Reconciliation", r.message, true);
let msg = __("Payment Reconciliation Job: {0} is running for this party. Can't reconcile now.", [doc_link]);
this.frm.dashboard.add_comment(msg, "yellow");
}
});
}
}
});
}

View File

@@ -252,6 +252,10 @@ class PaymentReconciliation(Document):
return difference_amount
@frappe.whitelist()
def is_auto_process_enabled(self):
return frappe.db.get_single_value("Accounts Settings", "auto_reconcile_payments")
@frappe.whitelist()
def calculate_difference_on_allocation_change(self, payment_entry, invoice, allocated_amount):
invoice_exchange_map = self.get_invoice_exchange_map(invoice, payment_entry)

View File

@@ -637,13 +637,6 @@ class TestPurchaseInvoice(unittest.TestCase, StockTestMixin):
gle_filters={"account": "Stock In Hand - TCP1"},
)
# assert loss booked in COGS
self.assertGLEs(
return_pi,
[{"credit": 0, "debit": 200}],
gle_filters={"account": "Cost of Goods Sold - TCP1"},
)
def test_return_with_lcv(self):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import (
@@ -1662,6 +1655,21 @@ class TestPurchaseInvoice(unittest.TestCase, 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)
returned_inv = make_purchase_invoice(qty=-5, rate=5, update_stock=True, is_return=True)
# override the rate with valuation rate
sle = frappe.get_all(
"Stock Ledger Entry",
fields=["stock_value_difference", "actual_qty"],
filters={"voucher_no": returned_inv.name},
)[0]
rate = flt(sle.stock_value_difference) / flt(sle.actual_qty)
self.assertAlmostEqual(returned_inv.items[0].rate, rate)
def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
gl_entries = frappe.db.sql(

View File

@@ -1012,10 +1012,16 @@ class SalesInvoice(SellingController):
def check_prev_docstatus(self):
for d in self.get("items"):
if d.sales_order and frappe.db.get_value("Sales Order", d.sales_order, "docstatus") != 1:
if (
d.sales_order
and frappe.db.get_value("Sales Order", d.sales_order, "docstatus", cache=True) != 1
):
frappe.throw(_("Sales Order {0} is not submitted").format(d.sales_order))
if d.delivery_note and frappe.db.get_value("Delivery Note", d.delivery_note, "docstatus") != 1:
if (
d.delivery_note
and frappe.db.get_value("Delivery Note", d.delivery_note, "docstatus", cache=True) != 1
):
throw(_("Delivery Note {0} is not submitted").format(d.delivery_note))
def make_gl_entries(self, gl_entries=None, from_repost=False):

View File

@@ -483,18 +483,22 @@ def get_gl_entries_on_asset_disposal(
},
item=asset,
),
asset.get_gl_dict(
{
"account": accumulated_depr_account,
"debit_in_account_currency": accumulated_depr_amount,
"debit": accumulated_depr_amount,
"cost_center": depreciation_cost_center,
"posting_date": date,
},
item=asset,
),
]
if accumulated_depr_amount:
gl_entries.append(
asset.get_gl_dict(
{
"account": accumulated_depr_account,
"debit_in_account_currency": accumulated_depr_amount,
"debit": accumulated_depr_amount,
"cost_center": depreciation_cost_center,
"posting_date": date,
},
item=asset,
),
)
profit_amount = flt(selling_amount) - flt(value_after_depreciation)
if profit_amount:
get_profit_gl_entries(

View File

@@ -19,56 +19,6 @@ frappe.query_reports["Fixed Asset Register"] = {
options: "\nIn Location\nDisposed",
default: 'In Location'
},
{
"fieldname":"filter_based_on",
"label": __("Period Based On"),
"fieldtype": "Select",
"options": ["Fiscal Year", "Date Range"],
"default": "Fiscal Year",
"reqd": 1
},
{
"fieldname":"from_date",
"label": __("Start Date"),
"fieldtype": "Date",
"default": frappe.datetime.add_months(frappe.datetime.nowdate(), -12),
"depends_on": "eval: doc.filter_based_on == 'Date Range'",
"reqd": 1
},
{
"fieldname":"to_date",
"label": __("End Date"),
"fieldtype": "Date",
"default": frappe.datetime.nowdate(),
"depends_on": "eval: doc.filter_based_on == 'Date Range'",
"reqd": 1
},
{
"fieldname":"from_fiscal_year",
"label": __("Start Year"),
"fieldtype": "Link",
"options": "Fiscal Year",
"default": frappe.defaults.get_user_default("fiscal_year"),
"depends_on": "eval: doc.filter_based_on == 'Fiscal Year'",
"reqd": 1
},
{
"fieldname":"to_fiscal_year",
"label": __("End Year"),
"fieldtype": "Link",
"options": "Fiscal Year",
"default": frappe.defaults.get_user_default("fiscal_year"),
"depends_on": "eval: doc.filter_based_on == 'Fiscal Year'",
"reqd": 1
},
{
"fieldname":"date_based_on",
"label": __("Date Based On"),
"fieldtype": "Select",
"options": ["Purchase Date", "Available For Use Date"],
"default": "Purchase Date",
"reqd": 1
},
{
fieldname:"asset_category",
label: __("Asset Category"),
@@ -89,22 +39,67 @@ frappe.query_reports["Fixed Asset Register"] = {
default: "--Select a group--",
reqd: 1
},
{
fieldname:"finance_book",
label: __("Finance Book"),
fieldtype: "Link",
options: "Finance Book",
depends_on: "eval: doc.filter_by_finance_book == 1",
},
{
fieldname:"filter_by_finance_book",
label: __("Filter by Finance Book"),
fieldtype: "Check"
},
{
fieldname:"only_existing_assets",
label: __("Only existing assets"),
fieldtype: "Check"
},
{
fieldname:"finance_book",
label: __("Finance Book"),
fieldtype: "Link",
options: "Finance Book",
},
{
"fieldname": "include_default_book_assets",
"label": __("Include Default Book Assets"),
"fieldtype": "Check",
"default": 1
},
{
"fieldname":"filter_based_on",
"label": __("Period Based On"),
"fieldtype": "Select",
"options": ["--Select a period--", "Fiscal Year", "Date Range"],
"default": "--Select a period--",
},
{
"fieldname":"from_date",
"label": __("Start Date"),
"fieldtype": "Date",
"default": frappe.datetime.add_months(frappe.datetime.nowdate(), -12),
"depends_on": "eval: doc.filter_based_on == 'Date Range'",
},
{
"fieldname":"to_date",
"label": __("End Date"),
"fieldtype": "Date",
"default": frappe.datetime.nowdate(),
"depends_on": "eval: doc.filter_based_on == 'Date Range'",
},
{
"fieldname":"from_fiscal_year",
"label": __("Start Year"),
"fieldtype": "Link",
"options": "Fiscal Year",
"default": frappe.defaults.get_user_default("fiscal_year"),
"depends_on": "eval: doc.filter_based_on == 'Fiscal Year'",
},
{
"fieldname":"to_fiscal_year",
"label": __("End Year"),
"fieldtype": "Link",
"options": "Fiscal Year",
"default": frappe.defaults.get_user_default("fiscal_year"),
"depends_on": "eval: doc.filter_based_on == 'Fiscal Year'",
},
{
"fieldname":"date_based_on",
"label": __("Date Based On"),
"fieldtype": "Select",
"options": ["Purchase Date", "Available For Use Date"],
"default": "Purchase Date",
"depends_on": "eval: doc.filter_based_on == 'Date Range' || doc.filter_based_on == 'Fiscal Year'",
},
]
};

View File

@@ -2,9 +2,11 @@
# For license information, please see license.txt
from itertools import chain
import frappe
from frappe import _
from frappe.query_builder.functions import Sum
from frappe.query_builder.functions import IfNull, Sum
from frappe.utils import cstr, flt, formatdate, getdate
from erpnext.accounts.report.financial_statements import (
@@ -13,7 +15,6 @@ from erpnext.accounts.report.financial_statements import (
validate_fiscal_year,
)
from erpnext.assets.doctype.asset.asset import get_asset_value_after_depreciation
from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts
def execute(filters=None):
@@ -64,11 +65,9 @@ def get_conditions(filters):
def get_data(filters):
data = []
conditions = get_conditions(filters)
depreciation_amount_map = get_finance_book_value_map(filters)
pr_supplier_map = get_purchase_receipt_supplier_map()
pi_supplier_map = get_purchase_invoice_supplier_map()
@@ -102,20 +101,27 @@ def get_data(filters):
]
assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields)
assets_linked_to_fb = None
assets_linked_to_fb = get_assets_linked_to_fb(filters)
if filters.filter_by_finance_book:
assets_linked_to_fb = frappe.db.get_all(
doctype="Asset Finance Book",
filters={"finance_book": filters.finance_book or ("is", "not set")},
pluck="parent",
)
company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book")
if filters.include_default_book_assets and company_fb:
finance_book = company_fb
elif filters.finance_book:
finance_book = filters.finance_book
else:
finance_book = None
depreciation_amount_map = get_asset_depreciation_amount_map(filters, finance_book)
for asset in assets_record:
if assets_linked_to_fb and asset.asset_id not in assets_linked_to_fb:
continue
asset_value = get_asset_value_after_depreciation(asset.asset_id, filters.finance_book)
asset_value = get_asset_value_after_depreciation(
asset.asset_id, finance_book
) or get_asset_value_after_depreciation(asset.asset_id)
row = {
"asset_id": asset.asset_id,
"asset_name": asset.asset_name,
@@ -126,7 +132,7 @@ def get_data(filters):
or pi_supplier_map.get(asset.purchase_invoice),
"gross_purchase_amount": asset.gross_purchase_amount,
"opening_accumulated_depreciation": asset.opening_accumulated_depreciation,
"depreciated_amount": get_depreciation_amount_of_asset(asset, depreciation_amount_map, filters),
"depreciated_amount": get_depreciation_amount_of_asset(asset, depreciation_amount_map),
"available_for_use_date": asset.available_for_use_date,
"location": asset.location,
"asset_category": asset.asset_category,
@@ -140,14 +146,23 @@ def get_data(filters):
def prepare_chart_data(data, filters):
labels_values_map = {}
date_field = frappe.scrub(filters.date_based_on)
if filters.filter_based_on not in ("Date Range", "Fiscal Year"):
filters_filter_based_on = "Date Range"
date_field = "purchase_date"
filters_from_date = min(data, key=lambda a: a.get(date_field)).get(date_field)
filters_to_date = max(data, key=lambda a: a.get(date_field)).get(date_field)
else:
filters_filter_based_on = filters.filter_based_on
date_field = frappe.scrub(filters.date_based_on)
filters_from_date = filters.from_date
filters_to_date = filters.to_date
period_list = get_period_list(
filters.from_fiscal_year,
filters.to_fiscal_year,
filters.from_date,
filters.to_date,
filters.filter_based_on,
filters_from_date,
filters_to_date,
filters_filter_based_on,
"Monthly",
company=filters.company,
ignore_fiscal_year=True,
@@ -184,57 +199,76 @@ def prepare_chart_data(data, filters):
}
def get_depreciation_amount_of_asset(asset, depreciation_amount_map, filters):
if asset.calculate_depreciation:
depr_amount = depreciation_amount_map.get(asset.asset_id) or 0.0
else:
depr_amount = get_manual_depreciation_amount_of_asset(asset, filters)
def get_assets_linked_to_fb(filters):
afb = frappe.qb.DocType("Asset Finance Book")
return flt(depr_amount, 2)
def get_finance_book_value_map(filters):
date = filters.to_date if filters.filter_based_on == "Date Range" else filters.year_end_date
return frappe._dict(
frappe.db.sql(
""" Select
parent, SUM(depreciation_amount)
FROM `tabDepreciation Schedule`
WHERE
parentfield='schedules'
AND schedule_date<=%s
AND journal_entry IS NOT NULL
AND ifnull(finance_book, '')=%s
GROUP BY parent""",
(date, cstr(filters.finance_book or "")),
)
query = frappe.qb.from_(afb).select(
afb.parent,
)
if filters.include_default_book_assets:
company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book")
def get_manual_depreciation_amount_of_asset(asset, filters):
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'"))
query = query.where(
(afb.finance_book.isin([cstr(filters.finance_book), cstr(company_fb), ""]))
| (afb.finance_book.isnull())
)
else:
query = query.where(
(afb.finance_book.isin([cstr(filters.finance_book), ""])) | (afb.finance_book.isnull())
)
assets_linked_to_fb = list(chain(*query.run(as_list=1)))
return assets_linked_to_fb
def get_depreciation_amount_of_asset(asset, depreciation_amount_map):
return depreciation_amount_map.get(asset.asset_id) or 0.0
def get_asset_depreciation_amount_map(filters, finance_book):
date = filters.to_date if filters.filter_based_on == "Date Range" else filters.year_end_date
(_, _, depreciation_expense_account) = get_depreciation_accounts(asset)
asset = frappe.qb.DocType("Asset")
gle = frappe.qb.DocType("GL Entry")
aca = frappe.qb.DocType("Asset Category Account")
company = frappe.qb.DocType("Company")
result = (
query = (
frappe.qb.from_(gle)
.select(Sum(gle.debit))
.where(gle.against_voucher == asset.asset_id)
.where(gle.account == depreciation_expense_account)
.join(asset)
.on(gle.against_voucher == asset.name)
.join(aca)
.on((aca.parent == asset.asset_category) & (aca.company_name == asset.company))
.join(company)
.on(company.name == asset.company)
.select(asset.name.as_("asset"), Sum(gle.debit).as_("depreciation_amount"))
.where(
gle.account == IfNull(aca.depreciation_expense_account, company.depreciation_expense_account)
)
.where(gle.debit != 0)
.where(gle.is_cancelled == 0)
.where(gle.posting_date <= date)
).run()
.where(asset.docstatus == 1)
.groupby(asset.name)
)
if result and result[0] and result[0][0]:
depr_amount = result[0][0]
if finance_book:
query = query.where(
(gle.finance_book.isin([cstr(finance_book), ""])) | (gle.finance_book.isnull())
)
else:
depr_amount = 0
query = query.where((gle.finance_book.isin([""])) | (gle.finance_book.isnull()))
return depr_amount
if filters.filter_based_on in ("Date Range", "Fiscal Year"):
query = query.where(gle.posting_date <= date)
asset_depr_amount_map = query.run()
return dict(asset_depr_amount_map)
def get_purchase_receipt_supplier_map():

View File

@@ -30,6 +30,8 @@ class BuyingController(SubcontractingController):
return _("From {0} | {1} {2}").format(self.supplier_name, self.currency, self.grand_total)
def validate(self):
self.set_rate_for_standalone_debit_note()
super(BuyingController, self).validate()
if getattr(self, "supplier", None) and not self.supplier_name:
self.supplier_name = frappe.db.get_value("Supplier", self.supplier, "supplier_name")
@@ -72,6 +74,30 @@ 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:
# 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
def set_missing_values(self, for_validate=False):
super(BuyingController, self).set_missing_values(for_validate)
@@ -445,7 +471,7 @@ class BuyingController(SubcontractingController):
continue
if d.warehouse:
pr_qty = flt(d.qty) * flt(d.conversion_factor)
pr_qty = flt(flt(d.qty) * flt(d.conversion_factor), d.precision("stock_qty"))
if pr_qty:
@@ -507,7 +533,7 @@ class BuyingController(SubcontractingController):
d,
{
"warehouse": d.rejected_warehouse,
"actual_qty": flt(d.rejected_qty) * flt(d.conversion_factor),
"actual_qty": flt(flt(d.rejected_qty) * flt(d.conversion_factor), d.precision("stock_qty")),
"serial_no": cstr(d.rejected_serial_no).strip(),
"incoming_rate": 0.0,
},

View File

@@ -617,6 +617,9 @@ def get_filters(
if reference_voucher_detail_no:
filters["voucher_detail_no"] = reference_voucher_detail_no
if item_row and item_row.get("warehouse"):
filters["warehouse"] = item_row.get("warehouse")
return filters

View File

@@ -3,7 +3,7 @@
import frappe
import frappe.defaults
from frappe import _, throw
from frappe import _, bold, throw
from frappe.contacts.doctype.address.address import get_address_display
from frappe.contacts.doctype.contact.contact import get_contact_name
from frappe.utils import cint, cstr, flt, get_fullname
@@ -201,6 +201,11 @@ def get_shopping_cart_menu(context=None):
@frappe.whitelist()
def add_new_address(doc):
doc = frappe.parse_json(doc)
address_title = doc.get("address_title")
if frappe.db.exists("Address", {"address_title": address_title}):
msg = f"The address with the title {bold(address_title)} already exists. Please change the title accordingly."
frappe.throw(_(msg), title=_("Address Already Exists"))
doc.update({"doctype": "Address"})
address = frappe.get_doc(doc)
address.save(ignore_permissions=True)

View File

@@ -162,6 +162,7 @@ def get_next_attribute_and_values(item_code, selected_attributes):
product_info = get_item_variant_price_dict(exact_match[0], cart_settings)
if product_info:
product_info["is_stock_item"] = frappe.get_cached_value("Item", exact_match[0], "is_stock_item")
product_info["allow_items_not_in_stock"] = cint(cart_settings.allow_items_not_in_stock)
else:
product_info = None

View File

@@ -290,8 +290,8 @@ def get_last_accrual_date(loan, posting_date):
# interest for last interest accrual date is already booked, so add 1 day
last_disbursement_date = get_last_disbursement_date(loan, posting_date)
if last_disbursement_date and getdate(last_disbursement_date) > getdate(
last_interest_accrual_date
if last_disbursement_date and getdate(last_disbursement_date) > add_days(
getdate(last_interest_accrual_date), 1
):
last_interest_accrual_date = last_disbursement_date

View File

@@ -161,7 +161,7 @@ class JobCard(Document):
self.total_completed_qty = flt(self.total_completed_qty, self.precision("total_completed_qty"))
for row in self.sub_operations:
self.c += row.completed_qty
self.total_completed_qty += row.completed_qty
def get_overlap_for(self, args, check_next_available_slot=False):
production_capacity = 1

View File

@@ -1657,6 +1657,61 @@ class TestWorkOrder(FrappeTestCase):
job_card2.time_logs = []
job_card2.save()
def test_make_serial_no_batch_from_work_order_for_serial_no(self):
item_code = "Test Serial No Item For Work Order"
warehouse = "_Test Warehouse - _TC"
raw_materials = [
"Test RM Item 1 for Serial No Item In Work Order",
]
make_item(
item_code,
{
"has_stock_item": 1,
"has_serial_no": 1,
"serial_no_series": "TSNIFWO-.#####",
},
)
for rm_item in raw_materials:
make_item(
rm_item,
{
"has_stock_item": 1,
},
)
test_stock_entry.make_stock_entry(item_code=rm_item, target=warehouse, qty=10, basic_rate=100)
bom = make_bom(item=item_code, raw_materials=raw_materials)
frappe.db.set_single_value("Manufacturing Settings", "make_serial_no_batch_from_work_order", 1)
wo_order = make_wo_order_test_record(
item=item_code,
bom_no=bom.name,
qty=5,
skip_transfer=1,
from_wip_warehouse=1,
)
serial_nos = frappe.get_all(
"Serial No",
filters={"item_code": item_code, "work_order": wo_order.name},
)
serial_nos = [d.name for d in serial_nos]
self.assertEqual(len(serial_nos), 5)
stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 5))
stock_entry.submit()
for row in stock_entry.items:
if row.is_finished_item:
self.assertEqual(sorted(get_serial_nos(row.serial_no)), sorted(get_serial_nos(serial_nos)))
frappe.db.set_single_value("Manufacturing Settings", "make_serial_no_batch_from_work_order", 0)
def prepare_data_for_workstation_type_check():
from erpnext.manufacturing.doctype.operation.test_operation import make_operation
@@ -1886,6 +1941,7 @@ def make_wo_order_test_record(**args):
wo_order.sales_order = args.sales_order or None
wo_order.planned_start_date = args.planned_start_date or now()
wo_order.transfer_material_against = args.transfer_material_against or "Work Order"
wo_order.from_wip_warehouse = args.from_wip_warehouse or None
if args.source_warehouse:
for item in wo_order.get("required_items"):

View File

@@ -33,10 +33,9 @@ def get_data(filters: Filters) -> Data:
wo.name,
wo.status,
wo.production_item,
wo.qty,
wo.produced_qty,
wo.process_loss_qty,
(wo.produced_qty - wo.process_loss_qty).as_("actual_produced_qty"),
wo.qty.as_("qty_to_manufacture"),
Sum(se.total_incoming_value).as_("total_fg_value"),
Sum(se.total_outgoing_value).as_("total_rm_value"),
)
@@ -44,6 +43,7 @@ def get_data(filters: Filters) -> Data:
(wo.process_loss_qty > 0)
& (wo.company == filters.company)
& (se.docstatus == 1)
& (se.purpose == "Manufacture")
& (se.posting_date.between(filters.from_date, filters.to_date))
)
.groupby(se.work_order)
@@ -79,20 +79,30 @@ def get_columns() -> Columns:
"width": "100",
},
{"label": _("Status"), "fieldname": "status", "fieldtype": "Data", "width": "100"},
{
"label": _("Qty To Manufacture"),
"fieldname": "qty_to_manufacture",
"fieldtype": "Float",
"width": "150",
},
{
"label": _("Manufactured Qty"),
"fieldname": "produced_qty",
"fieldtype": "Float",
"width": "150",
},
{"label": _("Loss Qty"), "fieldname": "process_loss_qty", "fieldtype": "Float", "width": "150"},
{
"label": _("Actual Manufactured Qty"),
"fieldname": "actual_produced_qty",
"label": _("Process Loss Qty"),
"fieldname": "process_loss_qty",
"fieldtype": "Float",
"width": "150",
},
{
"label": _("Process Loss Value"),
"fieldname": "total_pl_value",
"fieldtype": "Float",
"width": "150",
},
{"label": _("Loss Value"), "fieldname": "total_pl_value", "fieldtype": "Float", "width": "150"},
{"label": _("FG Value"), "fieldname": "total_fg_value", "fieldtype": "Float", "width": "150"},
{
"label": _("Raw Material Value"),
@@ -105,5 +115,5 @@ def get_columns() -> Columns:
def update_data_with_total_pl_value(data: Data) -> None:
for row in data:
value_per_unit_fg = row["total_fg_value"] / row["actual_produced_qty"]
value_per_unit_fg = row["total_fg_value"] / row["qty_to_manufacture"]
row["total_pl_value"] = row["process_loss_qty"] * value_per_unit_fg

View File

@@ -333,3 +333,4 @@ erpnext.patches.v14_0.migrate_gl_to_payment_ledger
erpnext.patches.v14_0.update_company_in_ldc
erpnext.patches.v14_0.set_packed_qty_in_draft_delivery_notes
erpnext.patches.v14_0.cleanup_workspaces
erpnext.patches.v14_0.enable_allow_existing_serial_no

View File

@@ -0,0 +1,9 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
def execute():
frappe.reload_doc("stock", "doctype", frappe.scrub("Stock Settings"))
frappe.db.set_single_value("Stock Settings", "allow_existing_serial_no", 1, update_modified=False)

View File

@@ -123,6 +123,15 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
this.frm.set_query("batch_no", "items", function(doc, cdt, cdn) {
return me.set_query_for_batch(doc, cdt, cdn);
});
let batch_field = this.frm.get_docfield('items', 'batch_no');
if (batch_field) {
batch_field.get_route_options_for_new_doc = (row) => {
return {
'item': row.doc.item_code
}
};
}
}
if(

View File

@@ -49,7 +49,6 @@ def search_by_term(search_term, warehouse, price_list):
)
item_stock_qty, is_stock_item = get_stock_availability(item_code, warehouse)
item_stock_qty = item_stock_qty // item.get("conversion_factor")
item_stock_qty = item_stock_qty // item.get("conversion_factor", 1)
item.update({"actual_qty": item_stock_qty})
@@ -59,7 +58,7 @@ def search_by_term(search_term, warehouse, price_list):
"price_list": price_list,
"item_code": item_code,
},
fields=["uom", "stock_uom", "currency", "price_list_rate"],
fields=["uom", "currency", "price_list_rate"],
)
def __sort(p):

View File

@@ -1222,7 +1222,8 @@
"hidden": 1,
"label": "Pick List",
"options": "Pick List",
"read_only": 1
"read_only": 1,
"search_index": 1
},
{
"default": "0",
@@ -1398,7 +1399,7 @@
"idx": 146,
"is_submittable": 1,
"links": [],
"modified": "2023-04-21 11:15:23.931084",
"modified": "2023-06-16 14:58:55.066602",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",

View File

@@ -36,7 +36,7 @@ class PickList(Document):
for location in self.get("locations"):
if (
location.sales_order
and frappe.db.get_value("Sales Order", location.sales_order, "per_picked") == 100
and frappe.db.get_value("Sales Order", location.sales_order, "per_picked", cache=True) == 100
):
frappe.throw(
_("Row #{}: item {} has been picked already.").format(location.idx, location.item_code)
@@ -360,6 +360,7 @@ class PickList(Document):
(pi_item.item_code.isin([x.item_code for x in items]))
& ((pi_item.picked_qty > 0) | (pi_item.stock_qty > 0))
& (pi.status != "Completed")
& (pi.status != "Cancelled")
& (pi_item.docstatus != 2)
)
.groupby(
@@ -473,7 +474,7 @@ def get_items_with_location_and_quantity(item_doc, item_location_map, docstatus)
)
qty = stock_qty / (item_doc.conversion_factor or 1)
uom_must_be_whole_number = frappe.db.get_value("UOM", item_doc.uom, "must_be_whole_number")
uom_must_be_whole_number = frappe.get_cached_value("UOM", item_doc.uom, "must_be_whole_number")
if uom_must_be_whole_number:
qty = floor(qty)
stock_qty = qty * item_doc.conversion_factor

View File

@@ -149,7 +149,8 @@
"fieldtype": "Data",
"hidden": 1,
"label": "Sales Order Item",
"read_only": 1
"read_only": 1,
"search_index": 1
},
{
"fieldname": "serial_no_and_batch_section",
@@ -191,7 +192,7 @@
],
"istable": 1,
"links": [],
"modified": "2022-04-22 05:27:38.497997",
"modified": "2023-06-16 14:05:51.719959",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",

View File

@@ -124,6 +124,7 @@ class PurchaseReceipt(BuyingController):
self.set_status()
self.po_required()
self.validate_items_quality_inspection()
self.validate_with_previous_doc()
self.validate_uom_is_integer("uom", ["qty", "received_qty"])
self.validate_uom_is_integer("stock_uom", "stock_qty")
@@ -197,6 +198,26 @@ class PurchaseReceipt(BuyingController):
if not d.purchase_order:
frappe.throw(_("Purchase Order number required for Item {0}").format(d.item_code))
def validate_items_quality_inspection(self):
for item in self.get("items"):
if item.quality_inspection:
qi = frappe.db.get_value(
"Quality Inspection",
item.quality_inspection,
["reference_type", "reference_name", "item_code"],
as_dict=True,
)
if qi.reference_type != self.doctype or qi.reference_name != self.name:
msg = f"""Row #{item.idx}: Please select a valid Quality Inspection with Reference Type
{frappe.bold(self.doctype)} and Reference Name {frappe.bold(self.name)}."""
frappe.throw(_(msg))
if qi.item_code != item.item_code:
msg = f"""Row #{item.idx}: Please select a valid Quality Inspection with Item Code
{frappe.bold(item.item_code)}."""
frappe.throw(_(msg))
def get_already_received_qty(self, po, po_detail):
qty = frappe.db.sql(
"""select sum(qty) from `tabPurchase Receipt Item`

View File

@@ -1751,6 +1751,52 @@ class TestPurchaseReceipt(FrappeTestCase):
pr.items[0].delivery_note_item = delivery_note_item
pr.save()
def test_purchase_return_valuation_with_rejected_qty(self):
item_code = "_Test Item Return Valuation"
create_item(item_code)
warehouse = create_warehouse("_Test Warehouse Return Valuation")
rejected_warehouse = create_warehouse("_Test Rejected Warehouse Return Valuation")
# Step 1: Create Purchase Receipt with valuation rate 100
make_purchase_receipt(
item_code=item_code,
warehouse=warehouse,
qty=10,
rate=100,
rejected_qty=2,
rejected_warehouse=rejected_warehouse,
)
# Step 2: Create One more Purchase Receipt with valuation rate 200
pr = make_purchase_receipt(
item_code=item_code,
warehouse=warehouse,
qty=10,
rate=200,
rejected_qty=2,
rejected_warehouse=rejected_warehouse,
)
# Step 3: Create Purchase Return for 2 qty
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_return
pr_return = make_purchase_return(pr.name)
pr_return.items[0].qty = 2 * -1
pr_return.items[0].received_qty = 2 * -1
pr_return.items[0].rejected_qty = 0
pr_return.items[0].rejected_warehouse = ""
pr_return.save()
pr_return.submit()
data = frappe.get_all(
"Stock Ledger Entry",
filters={"voucher_no": pr_return.name, "docstatus": 1},
fields=["SUM(stock_value_difference) as stock_value_difference"],
)[0]
self.assertEqual(abs(data["stock_value_difference"]), 400.00)
def prepare_data_for_internal_transfer():
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier

View File

@@ -307,6 +307,11 @@ def validate_serial_no(sle, item_det):
allow_existing_serial_no = cint(
frappe.get_cached_value("Stock Settings", "None", "allow_existing_serial_no")
)
work_order = None
if sle.voucher_no and sle.voucher_type == "Stock Entry":
work_order = frappe.get_cached_value("Stock Entry", sle.voucher_no, "work_order")
for serial_no in serial_nos:
if frappe.db.exists("Serial No", serial_no):
sr = frappe.db.get_value(
@@ -324,6 +329,7 @@ def validate_serial_no(sle, item_det):
"purchase_document_no",
"company",
"status",
"work_order",
],
as_dict=1,
)
@@ -335,6 +341,9 @@ def validate_serial_no(sle, item_det):
SerialNoItemError,
)
if sr.work_order and work_order and sr.work_order == work_order:
allow_existing_serial_no = True
if not allow_existing_serial_no and sle.voucher_type in [
"Stock Entry",
"Purchase Receipt",

View File

@@ -101,6 +101,14 @@ frappe.ui.form.on('Stock Entry', {
}
});
let batch_field = frm.get_docfield('items', 'batch_no');
if (batch_field) {
batch_field.get_route_options_for_new_doc = (row) => {
return {
'item': row.doc.item_code
}
};
}
frm.add_fetch("bom_no", "inspection_required", "inspection_required");
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);

View File

@@ -125,7 +125,8 @@
"oldfieldname": "purpose",
"oldfieldtype": "Select",
"options": "Material Issue\nMaterial Receipt\nMaterial Transfer\nMaterial Transfer for Manufacture\nMaterial Consumption for Manufacture\nManufacture\nRepack\nSend to Subcontractor",
"read_only": 1
"read_only": 1,
"search_index": 1
},
{
"fieldname": "company",
@@ -577,7 +578,8 @@
"fieldtype": "Link",
"label": "Pick List",
"options": "Pick List",
"read_only": 1
"read_only": 1,
"search_index": 1
},
{
"fieldname": "print_settings_col_break",
@@ -677,7 +679,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2023-06-09 15:46:28.418339",
"modified": "2023-06-19 18:23:40.748114",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry",
@@ -738,7 +740,6 @@
"read": 1,
"report": 1,
"role": "Stock Manager",
"set_user_permissions": 1,
"share": 1,
"submit": 1,
"write": 1

View File

@@ -268,10 +268,10 @@ class StockEntry(StockController):
return
for row in self.items:
if row.job_card_item:
if row.job_card_item or not row.s_warehouse:
continue
msg = f"""Row #{0}: The job card item reference
msg = f"""Row #{row.idx}: The job card item reference
is missing. Kindly create the stock entry
from the job card. If you have added the row manually
then you won't be able to add job card item reference."""

View File

@@ -475,7 +475,7 @@ def add_additional_uom_columns(columns, result, include_uom, conversion_factors)
for row_idx, row in enumerate(result):
for convertible_col, data in convertible_column_map.items():
conversion_factor = conversion_factors[row.get("item_code")] or 1
conversion_factor = conversion_factors.get(row.get("item_code")) or 1.0
for_type = data.for_type
value_before_conversion = row.get(convertible_col)
if for_type == "rate":

View File

@@ -219,7 +219,8 @@ class ItemConfigure {
: ''
}
${available_qty === 0 ? '<span class="text-danger">(' + __('Out of Stock') + ')</span>' : ''}
${available_qty === 0 && product_info && product_info?.is_stock_item
? '<span class="text-danger">(' + __('Out of Stock') + ')</span>' : ''}
</div></div>
<a href data-action="btn_clear_values" data-item-code="${one_item}">
@@ -236,7 +237,8 @@ class ItemConfigure {
</div>`;
/* eslint-disable indent */
if (!product_info?.allow_items_not_in_stock && available_qty === 0) {
if (!product_info?.allow_items_not_in_stock && available_qty === 0
&& product_info && product_info?.is_stock_item) {
item_add_to_cart = '';
}