Compare commits

...

81 Commits

Author SHA1 Message Date
Deepesh Garg
d6da1a93ae chore: version bump 2022-06-14 16:24:13 +05:30
Deepesh Garg
5af2b74039 Merge pull request #31352 from frappe/version-12-hotfix
chore: version-12 release
2022-06-14 16:19:50 +05:30
Marica
1ee62a8342 Merge pull request #31280 from RJPvT/patch-2
fix: locale Currency and Float setting in update_employee
2022-06-09 18:29:56 +05:30
RJPvT
74748c03e2 fix: locale Currency and Float setting in update_employee
In fieldtypes locale settings (example NL) . and , changes whereby the field is inproperly filled
2022-06-08 10:55:15 +02:00
mergify[bot]
73484ef1bc fix(india): e-invoice eligibility if company gstin is not configured (#31276) 2022-06-08 12:55:16 +05:30
mergify[bot]
1c25d7c6f2 fix(india): error while parsing e-invoice (backport #31053) (#31224) 2022-06-06 14:28:40 +05:30
mergify[bot]
432210d13d fix(india): minor e-invoicing fixes (backport #30553) (#31067) 2022-05-19 14:26:38 +05:30
mergify[bot]
836bfc603a fix(stock_ledger): round off values near to zero (#30803)
(cherry picked from commit 6a014d12c1)

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2022-04-26 10:16:06 +05:30
mergify[bot]
2d7c678a9d fix: warehouse naming when suffix is present (#30621) (#30768)
(cherry picked from commit be04eaf723)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2022-04-21 12:04:25 +05:30
Ankush Menat
a92c53dd2b chore: disable coverage
coverage adds overhead which isn't necessary on v12 branch now

[skip ci]
2022-04-21 11:41:08 +05:30
mergify[bot]
68fd8a1dcf fix(india): transporter name is null while generating e-way bill (backport #30736) 2022-04-20 19:48:22 +05:30
Ankush Menat
619c178049 chore: bump version 2022-04-10 11:54:57 +05:30
Ankush Menat
579a2366f6 Merge branch 'v12-pre-release' into version-12 2022-04-10 11:54:30 +05:30
mergify[bot]
6ad2684121 fix: dont fetch entire barcode table in get_item_details (#30131) (#30667)
(cherry picked from commit 64905188c4)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2022-04-10 11:53:28 +05:30
mergify[bot]
5b2b76c4a7 fix: dont fetch entire barcode table in get_item_details (#30131) (#30666)
(cherry picked from commit 64905188c4)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2022-04-10 11:52:35 +05:30
Deepesh Garg
5bedb88e62 chore: version bump and release notes 2022-03-28 23:27:54 +05:30
Deepesh Garg
0c4a61d4e6 Merge pull request #30456 from frappe/version-12-hotfix
chore: Release for v12.27.0
2022-03-28 19:20:52 +05:30
Saqib Ansari
c8780b0062 Merge pull request #30401 from nextchamp-saqib/add-client-cred-fields-einvoicing
feat: add client id & client secret fields in e invoice settings
2022-03-25 10:28:57 +05:30
Saqib Ansari
f531d1a69b feat: add client id & client secret fields in e invoice settings 2022-03-24 17:50:05 +05:30
Rucha Mahabal
51aa55f3b0 fix: salary slip amount rounding errors (#30250) 2022-03-15 12:23:48 +05:30
Saqib Ansari
db0e3d3fbe Merge pull request #30088 from frappe/mergify/bp/version-12-hotfix/pr-30084
fix(e-invoicing): remove batch no from e-invoices (backport #30084)
2022-03-07 11:57:29 +05:30
Saqib Ansari
ccffcf2596 fix(e-invoicing): remove batch no from e-invoices
(cherry picked from commit 031a0dd703)
2022-03-07 06:25:43 +00:00
Rohit Waghchaure
1413af8f3a Merge branch 'v12-pre-release' into version-12 2022-02-15 22:29:43 +05:30
Rohit Waghchaure
9a1afeb13b bumped to version 12.29.0 2022-02-15 22:49:43 +05:50
rohitwaghchaure
13a9b304b7 Merge pull request #29817 from rohitwaghchaure/change-log-for-v12-29
chore: change log for v12.29.0
2022-02-15 22:27:38 +05:30
Rohit Waghchaure
ee7ac93ff3 chore: change log for v12.29.0 2022-02-15 19:49:04 +05:30
rohitwaghchaure
3aa4411a0d Merge pull request #29602 from rohitwaghchaure/merge-branch-hotfix-to-pre-release-for-12-29
chore: merge branch 'version-12-hotfix' into 'v12-pre-release'
2022-02-03 13:06:56 +05:30
Rohit Waghchaure
7db947550b chore: merge branch 'version-12-hotfix' into 'v12-pre-release' 2022-02-02 23:20:27 +05:30
Saqib Ansari
c74a6f1827 Merge pull request #29291 from GangaManoj/prevent-depr-of-sold-assets
fix: Display 'Make Depreciation Entry' only for submitted or partially depreciated Assets
2022-01-14 18:49:13 +05:30
GangaManoj
73243c8ac3 fix: Hide Make Depreciation Entry if the Asset is not in the Submitted or Partially Depreciated state 2022-01-14 17:40:59 +05:30
GangaManoj
1800ce2780 fix: Only allow posting of Depreciation Entries if the Asset is in the Submitted or Partially Depreciated state 2022-01-14 15:33:16 +05:30
Ankush Menat
e5ea16a6dd fix: loosen dependencies for pandas 2022-01-10 18:12:50 +05:30
Rohit Waghchaure
54cb62c7bf Merge branch 'v12-pre-release' into version-12 2022-01-02 23:41:11 +05:30
Rohit Waghchaure
11ad77f491 bumped to version 12.28.0 2022-01-03 00:01:11 +05:50
rohitwaghchaure
95b0c743d4 Merge pull request #29097 from rohitwaghchaure/change-log-for-v12-28
chore: change log for v12.28.0
2022-01-02 23:38:20 +05:30
Rohit Waghchaure
fee83e8ba4 chore: change log for v12.28.0 2022-01-02 23:28:09 +05:30
rohitwaghchaure
4c5b5607ba Merge pull request #29074 from rohitwaghchaure/merge-hotfix-to-pre-release-for-12-28
chore: Merge branch 'version-12-hotfix' into 'v12-pre-release'
2021-12-30 11:27:41 +05:30
Rohit Waghchaure
00b40c0f3c fix: failing test case 2021-12-30 10:14:14 +05:30
Rohit Waghchaure
ac08379f2b chore: Merge branch 'version-12-hotfix' into 'v12-pre-release' 2021-12-29 23:40:23 +05:30
rohitwaghchaure
753adf3ce4 Merge pull request #29063 from rohitwaghchaure/fixed-backport-issue
fix: travis failing
2021-12-29 23:27:46 +05:30
Rohit Waghchaure
fbbf29e829 fix: travis failing 2021-12-29 15:46:14 +05:30
Ganga Manoj
ce2aa767b2 fix: Use depreciation cost center for creating credit entries in JEs (#28908) 2021-12-23 12:04:15 +05:30
Ankush Menat
c9927efcae test: dynamic fiscal year creation in tests (#28667)
(cherry picked from commit fdffa037b5)

fix: resolve conflict

fix
2021-12-14 22:50:26 +05:30
Rucha Mahabal
e9dbb46a06 fix: incorrect amount based on payment days in timesheet salary slip (#28884) 2021-12-14 20:04:37 +05:30
mergify[bot]
39125a78e0 fix!: dont allow renaming warehouse primary key (backport #28712)
* fix!: dont allow renaming warehouse primary key

(cherry picked from commit 72dbc3d6b8)

* fix: remove autocommit from item rename

(cherry picked from commit 5caf411be3)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2021-12-14 17:45:08 +05:30
Saqib
2a00164059 Merge pull request #28848 from frappe/mergify/bp/version-12-hotfix/pr-28797
fix: validate if asset account is set against company (backport #28797)
2021-12-13 22:41:15 +05:30
Saqib
7d1953bb3b fix: validate if asset account is set against company
(cherry picked from commit c3e0de28b1)
2021-12-13 14:44:48 +00:00
Deepesh Garg
33eeb64fec Merge pull request #28463 from frappe/mergify/bp/version-12-hotfix/pr-28459
fix(India): GST category not getting auto updated (backport #28459)
2021-12-03 09:39:09 +05:30
Rohit Waghchaure
bbffb5d91e Merge branch 'v12-pre-release' into version-12 2021-12-02 20:30:31 +05:30
Rohit Waghchaure
260b9c1885 bumped to version 12.27.0 2021-12-02 20:50:31 +05:50
rohitwaghchaure
034e8bd028 Merge pull request #28695 from rohitwaghchaure/change-log-for-v12-27
chore: change log for v12.27
2021-12-02 20:28:59 +05:30
Rohit Waghchaure
eb8b03f590 chore: change log for v12.27 2021-12-02 20:26:13 +05:30
mergify[bot]
abb4d99ca8 fix: actual tax conversion in case of multicurrency invoices (#28687) 2021-12-02 15:01:06 +05:30
rohitwaghchaure
a6fd5a69e8 Merge pull request #28674 from rohitwaghchaure/merge-hotfix-to-pre-release-for-12-27
chore: Merge branch 'version-12-hotfix' into 'v12-pre-release'
2021-12-02 11:03:53 +05:30
Rohit Waghchaure
849c795113 fix: test case for fiscal year 2021-12-02 00:03:25 +05:30
Rohit Waghchaure
3647a24f60 chore: Merge branch 'version-12-hotfix' into 'v12-pre-release' 2021-12-01 23:03:34 +05:30
Deepesh Garg
67f17c7a0c fix: Remove tests 2021-11-29 18:05:36 +05:30
Ankush Menat
24c004b537 fix: use get_all instead of get_list for child tables
(cherry picked from commit f862339024)
2021-11-29 16:28:04 +05:30
Ankush Menat
1fce25180c chore: correct docstrings
(cherry picked from commit c7701ace80)
2021-11-29 16:28:04 +05:30
Saqib
23946cea2e fix: debit & credit currency in bank transaction (#28574) 2021-11-29 15:13:22 +05:30
mergify[bot]
1b78c501a1 fix: incorrect balance for warehouses (#28583) (#28585)
(cherry picked from commit 7ff30a4b2b)

Co-authored-by: Noah Jacob <noahjacobkurian@gmail.com>
2021-11-26 17:36:16 +05:30
Deepesh Garg
d09ed0a578 fix: Conflicts 2021-11-19 13:11:07 +05:30
Deepesh Garg
9b83e3856a fix: Add test for gst category check
(cherry picked from commit cdbc991e3f)

# Conflicts:
#	erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
2021-11-19 06:52:43 +00:00
Deepesh Garg
656686f2b1 fix(India): GST category not getting auto updated
(cherry picked from commit f8a26a9fac)
2021-11-19 06:52:42 +00:00
mergify[bot]
8e7ee953c1 chore: remove woocommerce package (#25736) (#28424)
This is not used anywhere. It was added in this commit
df83148d7c
even there it isn't being used.

(cherry picked from commit e1ab290911)

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-11-17 09:50:18 +05:30
mergify[bot]
d2af2b31e5 fix: validate hmac unconditionally (#28375)
(cherry picked from commit c0f06bc8e3)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2021-11-12 14:53:51 +05:30
mergify[bot]
f79651c54d fix(WooCommerce): always expect signature in webhook requests (#28371)
(cherry picked from commit 24b048925b)

Co-authored-by: Sagar Vora <sagar@resilient.tech>
2021-11-12 14:10:49 +05:30
mergify[bot]
80ba0cf978 fix: specify fields to be set in Lead (backport #28288)
* fix: specify fields to be set in Lead (#28288)

(cherry picked from commit da22744e0f)

# Conflicts:
#	erpnext/shopping_cart/cart.py

* fix: merge conflict

Co-authored-by: Sagar Vora <sagar@resilient.tech>
2021-11-09 16:05:37 +05:30
Deepesh Garg
30c1a7bb20 Merge pull request #28279 from frappe/mergify/bp/version-12-hotfix/pr-28065
fix(minor): check if gst_category exists while validating GSTIN (backport #28065)
2021-11-09 13:48:29 +05:30
Anuja Pawar
d119b4321d fix: sider
(cherry picked from commit f2fbcc8124)
2021-11-08 18:37:03 +00:00
Anuja Pawar
4b1befb691 fix: update set_value query
(cherry picked from commit dd3cadd46b)
2021-11-08 18:37:01 +00:00
Anuja Pawar
fa5e018330 fix: re-writing sql query with ORM methods
(cherry picked from commit bc1e7bc15f)
2021-11-08 18:36:58 +00:00
Anuja Pawar
8c84d6a1d9 fix: sider
(cherry picked from commit 6a3bd882b4)
2021-11-08 18:36:56 +00:00
Anuja Pawar
f76139dceb fix: sider
(cherry picked from commit 4f53837624)
2021-11-08 18:36:54 +00:00
Anuja Pawar
97544e2bbc fix: check if gst_category exist
(cherry picked from commit 59c31bb124)
2021-11-08 18:36:53 +00:00
mergify[bot]
117718d410 fix: ignore unsupported methods while resyncing (#28210) (#28211)
(cherry picked from commit 72a050fb0b)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2021-11-02 23:09:44 +05:30
Marica
bcb0683be1 Merge pull request #28198 from frappe/mergify/bp/version-12-hotfix/pr-28195
fix: (ux) Remove warehouse filter on Batch field for Material Receipt (backport #28195)
2021-11-02 17:04:23 +05:30
marination
bf5f0a226e chore: Add comment above fix for future reference
(cherry picked from commit 48886ee705)
2021-11-02 10:41:16 +00:00
marination
55aaefb53c fix: Remove warehouse filter on Batch field for Material Receipt
(cherry picked from commit 048210a8f6)
2021-11-02 10:41:15 +00:00
Ankush Menat
ba537b0b93 fix: py2 string formatting 2021-10-29 15:41:55 +05:30
mergify[bot]
89b0e5023a fix: Skip empty rows while updating unsaved BOM cost (#28136) (#28141)
- Dont try to get valuation rate if row has no item code
- Dont try to add exploded items if row has no item code

(cherry picked from commit 292419bc9e)

Co-authored-by: Marica <maricadsouza221197@gmail.com>
2021-10-29 15:40:14 +05:30
40 changed files with 281 additions and 262 deletions

View File

@@ -16,11 +16,11 @@ jobs:
include:
- name: "Python 2.7 Server Side Test"
python: 2.7
script: bench --site test_site run-tests --app erpnext --coverage
script: bench --site test_site run-tests --app erpnext
- name: "Python 3.6 Server Side Test"
python: 3.6
script: bench --site test_site run-tests --app erpnext --coverage
script: bench --site test_site run-tests --app erpnext
- name: "Python 2.7 Patch Test"
python: 2.7
@@ -74,8 +74,3 @@ install:
- bench get-app erpnext $TRAVIS_BUILD_DIR
- bench start &
- bench --site test_site reinstall --yes
after_script:
- pip install coverage==4.5.4
- pip install python-coveralls
- coveralls -b apps/erpnext -d ../../sites/.coverage

View File

@@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
__version__ = '12.26.0'
__version__ = '12.31.0'
def get_default_company(user=None):
'''Get default company for user'''

View File

@@ -271,6 +271,7 @@
"label": "Debit",
"length": 0,
"no_copy": 0,
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -304,6 +305,7 @@
"label": "Credit",
"length": 0,
"no_copy": 0,
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -632,6 +634,7 @@
"label": "Allocated Amount",
"length": 0,
"no_copy": 0,
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -731,6 +734,7 @@
"label": "Unallocated Amount",
"length": 0,
"no_copy": 0,
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -755,7 +759,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-05-11 05:27:55.244721",
"modified": "2021-11-26 12:44:55.244721",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Transaction",

View File

@@ -3,11 +3,13 @@
from __future__ import unicode_literals
import frappe, unittest
import unittest
import frappe
from frappe.utils import now_datetime
from erpnext.accounts.doctype.fiscal_year.fiscal_year import FiscalYearIncorrectDate
test_records = frappe.get_test_records('Fiscal Year')
test_ignore = ["Company"]
class TestFiscalYear(unittest.TestCase):
@@ -23,3 +25,29 @@ class TestFiscalYear(unittest.TestCase):
})
self.assertRaises(FiscalYearIncorrectDate, fy.insert)
def test_record_generator():
test_records = [
{
"doctype": "Fiscal Year",
"year": "_Test Short Fiscal Year 2011",
"is_short_year": 1,
"year_end_date": "2011-04-01",
"year_start_date": "2011-12-31"
}
]
start = 2012
end = now_datetime().year + 5
for year in range(start, end):
test_records.append({
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year {}".format(year),
"year_start_date": "{}-01-01".format(year),
"year_end_date": "{}-12-31".format(year)
})
return test_records
test_records = test_record_generator()

View File

@@ -1,69 +0,0 @@
[
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2012",
"year_end_date": "2012-12-31",
"year_start_date": "2012-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2013",
"year_end_date": "2013-12-31",
"year_start_date": "2013-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2014",
"year_end_date": "2014-12-31",
"year_start_date": "2014-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2015",
"year_end_date": "2015-12-31",
"year_start_date": "2015-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2016",
"year_end_date": "2016-12-31",
"year_start_date": "2016-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2017",
"year_end_date": "2017-12-31",
"year_start_date": "2017-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2018",
"year_end_date": "2018-12-31",
"year_start_date": "2018-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2019",
"year_end_date": "2019-12-31",
"year_start_date": "2019-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2020",
"year_end_date": "2020-12-31",
"year_start_date": "2020-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2021",
"year_end_date": "2021-12-31",
"year_start_date": "2021-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Short Fiscal Year 2021",
"is_short_year": 1,
"year_end_date": "2021-12-31",
"year_start_date": "2021-04-01"
}
]

View File

@@ -247,8 +247,15 @@ class PurchaseInvoice(BuyingController):
else:
item.expense_account = stock_not_billed_account
elif item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category):
item.expense_account = get_asset_category_account('fixed_asset_account', item=item.item_code,
asset_category_account = get_asset_category_account('fixed_asset_account', item=item.item_code,
company = self.company)
if not asset_category_account:
form_link = get_link_to_form('Asset Category', asset_category)
throw(
_("Please set Fixed Asset Account in {} against {}.").format(form_link, self.company),
title=_("Missing Account")
)
item.expense_account = asset_category_account
elif item.is_fixed_asset and item.pr_detail:
item.expense_account = asset_received_but_not_billed
elif not item.expense_account and for_validate:

View File

@@ -1,7 +1,8 @@
{%- from "templates/print_formats/standard_macros.html" import add_header, render_field, print_value -%}
{%- set einvoice = json.loads(doc.signed_einvoice) -%}
<div class="page-break">
{% if doc.signed_einvoice %}
{%- set einvoice = json.loads(doc.signed_einvoice) -%}
<div {% if print_settings.repeat_header_footer %} id="header-html" class="hidden-pdf" {% endif %}>
{% if letter_head and not no_letterhead %}
<div class="letter-head">{{ letter_head }}</div>
@@ -163,4 +164,10 @@
</tbody>
</table>
</div>
</div>
{% else %}
<div class="text-center" style="color: #98A1A9; font-size: 14px;">
You must generate IRN before you can preview GST E-Invoice.
</div>
{% endif %}
</div>

View File

@@ -49,7 +49,10 @@ class TestAccountBalance(unittest.TestCase):
},
]
self.assertEqual(expected_data, report[1])
expected_data = sorted(expected_data, key=lambda k:k['account'])
output = sorted(report[1], key=lambda k:k['account'])
self.assertEqual(expected_data, output)
def make_sales_invoice():
frappe.set_user("Administrator")

View File

@@ -78,6 +78,7 @@ frappe.ui.form.on('Asset', {
frappe.ui.form.trigger("Asset", "is_existing_asset");
frm.toggle_display("next_depreciation_date", frm.doc.docstatus < 1);
frm.events.make_schedules_editable(frm);
frm.trigger("toggle_make_depreciation_entry");
if (frm.doc.docstatus==1) {
if (in_list(["Submitted", "Partially Depreciated", "Fully Depreciated"], frm.doc.status)) {
@@ -141,6 +142,18 @@ frappe.ui.form.on('Asset', {
}
},
toggle_make_depreciation_entry: function(frm) {
if (frm.doc.calculate_depreciation){
if (in_list(["Submitted", "Partially Depreciated"], frm.doc.status)){
frm.fields_dict['schedules'].grid.set_column_disp('make_depreciation_entry', true);
} else {
frm.fields_dict['schedules'].grid.set_column_disp('make_depreciation_entry', false);
}
frm.refresh_field('schedules');
}
},
toggle_reference_doc: function(frm) {
if (frm.doc.purchase_receipt && frm.doc.purchase_invoice && frm.doc.docstatus === 1) {
frm.set_df_property('purchase_invoice', 'read_only', 1);

View File

@@ -34,6 +34,8 @@ def make_depreciation_entry(asset_name, date=None):
date = today()
asset = frappe.get_doc("Asset", asset_name)
validate_asset(asset)
fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account = \
get_depreciation_accounts(asset)
@@ -59,7 +61,7 @@ def make_depreciation_entry(asset_name, date=None):
"credit_in_account_currency": d.depreciation_amount,
"reference_type": "Asset",
"reference_name": asset.name,
"cost_center": ""
"cost_center": depreciation_cost_center
}
debit_entry = {
@@ -101,6 +103,10 @@ def make_depreciation_entry(asset_name, date=None):
return asset
def validate_asset(asset):
if asset.status not in ['Submitted', 'Partially Depreciated']:
frappe.throw(_("Cannot depreciate {0} Asset").format(asset.status))
def get_depreciation_accounts(asset):
fixed_asset_account = accumulated_depreciation_account = depreciation_expense_account = None

View File

@@ -0,0 +1,9 @@
## ERPNext Version 12.27.0 Release Notes
### Fixes & Enhancements
- Always expect signature in webhook requests for WooCommerce ([#28367](https://github.com/frappe/erpnext/pull/28367))
- Debit & Credit currency in bank transaction ([#28574](https://github.com/frappe/erpnext/pull/28574))
- Incorrect balance in "Warehouse Wise Item Balance and Age" report ([#28583](https://github.com/frappe/erpnext/pull/28583))
- Check if gst_category exists while validating GSTIN ([#28065](https://github.com/frappe/erpnext/pull/28065))
- Skip empty rows while updating unsaved BOM cost ([#28136](https://github.com/frappe/erpnext/pull/28136))
- Remove warehouse filter on Batch field for Material Receipt ([#28195](https://github.com/frappe/erpnext/pull/28195))

View File

@@ -0,0 +1,7 @@
## ERPNext Version 12.28.0 Release Notes
### Fixes & Enhancements
- Set cost center for credit entries while posting Depreciation Entries ([#28908](https://github.com/frappe/erpnext/pull/28908))
- Incorrect amount based on Payment Days in timesheet based salary slip ([#28884](https://github.com/frappe/erpnext/pull/28884))
- Removed rename feature for the Warehouse document ([#28712](https://github.com/frappe/erpnext/pull/28712))
- Actual tax conversion in case of multicurrency invoices ([#28539](https://github.com/frappe/erpnext/pull/28539))

View File

@@ -0,0 +1,5 @@
## ERPNext Version 12.29.0 Release Notes
### Fixes & Enhancements
- Display 'Make Depreciation Entry' only for submitted or partially depreciated Assets ([#29291](https://github.com/frappe/erpnext/pull/29291))

View File

@@ -0,0 +1,7 @@
## ERPNext Version 12.29.0 Release Notes
### Fixes & Enhancements
* fix(e-invoicing): remove batch no from e-invoices ([#30088](https://github.com/frappe/erpnext/pull/30088))
* fix: salary slip amount rounding errors ([#30250](https://github.com/frappe/erpnext/pull/30250))
* feat: add client id & client secret fields in e invoice settings ([#30401](https://github.com/frappe/erpnext/pull/30401))

View File

@@ -14,8 +14,7 @@ def verify_request():
)
if frappe.request.data and \
frappe.get_request_header("X-Wc-Webhook-Signature") and \
not sig == bytes(frappe.get_request_header("X-Wc-Webhook-Signature").encode()):
not sig == frappe.get_request_header("X-Wc-Webhook-Signature", "").encode():
frappe.throw(_("Unverified Webhook Data"))
frappe.set_user(woocommerce_settings.creation_user)

View File

@@ -64,5 +64,8 @@ def dump_request_data(data, event="create/order"):
@frappe.whitelist()
def resync(method, name, request_data):
frappe.db.set_value("Shopify Log", name, "status", "Queued", update_modified=False)
if not method.startswith("erpnext.erpnext_integrations.connectors.shopify_connection"):
return
frappe.enqueue(method=method, queue='short', timeout=300, is_async=True,
**{"order": json.loads(request_data), "request_id": name})

View File

@@ -18,7 +18,6 @@ def validate_webhooks_request(doctype, hmac_key, secret_key='secret'):
)
if frappe.request.data and \
frappe.get_request_header(hmac_key) and \
not sig == bytes(frappe.get_request_header(hmac_key).encode()):
frappe.throw(_("Unverified Webhook Data"))
frappe.set_user(settings.modified_by)

View File

@@ -303,11 +303,11 @@ class SalarySlip(TransactionBase):
if self.salary_structure:
self.calculate_component_amounts("deductions")
self.set_loan_repayment()
self.set_component_amounts_based_on_payment_days()
self.set_net_pay()
def set_net_pay(self):
self.total_deduction = self.get_component_totals("deductions")
self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment))
@@ -519,7 +519,7 @@ class SalarySlip(TransactionBase):
# Total taxable earnings including additional and other incomes
total_taxable_earnings = previous_taxable_earnings + current_structured_taxable_earnings + future_structured_taxable_earnings \
+ current_additional_earnings + other_incomes + unclaimed_taxable_benefits - total_exemption_amount
# Total taxable earnings without additional earnings with full tax
total_taxable_earnings_without_full_tax_addl_components = total_taxable_earnings - current_additional_earnings_with_full_tax
@@ -527,7 +527,7 @@ class SalarySlip(TransactionBase):
total_structured_tax_amount = self.calculate_tax_by_tax_slab(
total_taxable_earnings_without_full_tax_addl_components, tax_slab)
current_structured_tax_amount = (total_structured_tax_amount - previous_total_paid_taxes) / remaining_sub_periods
# Total taxable earnings with additional earnings with full tax
full_tax_on_additional_earnings = 0.0
if current_additional_earnings_with_full_tax:
@@ -563,7 +563,7 @@ class SalarySlip(TransactionBase):
select sum(sd.amount)
from
`tabSalary Detail` sd join `tabSalary Slip` ss on sd.parent=ss.name
where
where
sd.parentfield='earnings'
and sd.is_tax_applicable=1
and is_flexible_benefit=0
@@ -676,9 +676,11 @@ class SalarySlip(TransactionBase):
def get_amount_based_on_payment_days(self, row, joining_date, relieving_date):
amount, additional_amount = row.amount, row.additional_amount
timesheet_component = frappe.db.get_value("Salary Structure", self.salary_structure, "salary_component")
if (self.salary_structure and
cint(row.depends_on_payment_days) and cint(self.total_working_days) and
(not self.salary_slip_based_on_timesheet or
cint(row.depends_on_payment_days) and cint(self.total_working_days)
and (row.salary_component != timesheet_component or
getdate(self.start_date) < joining_date or
(relieving_date and getdate(self.end_date) > relieving_date)
)):
@@ -687,14 +689,14 @@ class SalarySlip(TransactionBase):
amount = flt((flt(row.default_amount) * flt(self.payment_days)
/ cint(self.total_working_days)), row.precision("amount")) + additional_amount
elif not self.payment_days and not self.salary_slip_based_on_timesheet and cint(row.depends_on_payment_days):
elif not self.payment_days and row.salary_component != timesheet_component and cint(row.depends_on_payment_days):
amount, additional_amount = 0, 0
elif not row.amount:
amount = flt(row.default_amount) + flt(row.additional_amount)
# apply rounding
if frappe.get_cached_value("Salary Component", row.salary_component, "round_to_the_nearest_integer"):
amount, additional_amount = rounded(amount), rounded(additional_amount)
amount, additional_amount = rounded(amount or 0), rounded(additional_amount or 0)
return amount, additional_amount
@@ -782,7 +784,7 @@ class SalarySlip(TransactionBase):
if flt(d.max_taxable_income) and flt(d.max_taxable_income) < annual_taxable_earning:
continue
tax_amount += tax_amount * flt(d.percent) / 100
return tax_amount

View File

@@ -115,6 +115,41 @@ class TestSalarySlip(unittest.TestCase):
frappe.db.set_value("Employee", frappe.get_value("Employee",
{"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
def test_payment_days_in_salary_slip_based_on_timesheet(self):
from erpnext.projects.doctype.timesheet.test_timesheet import (
make_salary_structure_for_timesheet,
make_timesheet,
)
from erpnext.projects.doctype.timesheet.timesheet import (
make_salary_slip as make_salary_slip_for_timesheet,
)
# Holidays included in working days
frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 0)
emp = make_employee("test_employee_timesheet1@salary.com", company=erpnext.get_default_company())
frappe.db.set_value("Employee", emp, {"relieving_date": None, "status": "Active"})
# salary structure based on timesheet
make_salary_structure_for_timesheet(emp)
timesheet = make_timesheet(emp, simulate=True)
salary_slip = make_salary_slip_for_timesheet(timesheet.name)
salary_slip.start_date = get_first_day(nowdate())
salary_slip.end_date = get_last_day(nowdate())
salary_slip.save()
salary_slip.submit()
no_of_days = self.get_no_of_days()
days_in_month = no_of_days[0]
no_of_holidays = no_of_days[1]
self.assertEqual(salary_slip.payment_days, days_in_month - no_of_holidays)
# gross pay calculation based on attendance (payment days)
gross_pay = 78100 - ((78000 / (days_in_month - no_of_holidays)) * flt(salary_slip.leave_without_pay))
self.assertEqual(salary_slip.gross_pay, flt(gross_pay, 2))
def test_employee_salary_slip_read_permission(self):
make_employee("test_employee@salary.com")
@@ -175,7 +210,7 @@ class TestSalarySlip(unittest.TestCase):
# as per assigned salary structure 40500 in monthly salary so 236000*5/100/12
frappe.db.sql("""delete from `tabPayroll Period`""")
frappe.db.sql("""delete from `tabSalary Component`""")
payroll_period = create_payroll_period()
create_tax_slab(payroll_period, allow_tax_exemption=True)

View File

@@ -138,6 +138,8 @@ def update_employee(employee, details, date=None, cancel=False):
new_data = getdate(new_data)
elif fieldtype =="Datetime" and new_data:
new_data = get_datetime(new_data)
elif fieldtype in ["Currency", "Float"] and new_data:
new_data = flt(new_data)
setattr(employee, item.fieldname, new_data)
if item.fieldname in ["department", "designation", "branch"]:
internal_work_history[item.fieldname] = item.new

View File

@@ -240,6 +240,9 @@ class BOM(WebsiteGenerator):
existing_bom_cost = self.total_cost
for d in self.get("items"):
if not d.item_code:
continue
rate = self.get_rm_rate({
"company": self.company,
"item_code": d.item_code,
@@ -549,7 +552,7 @@ class BOM(WebsiteGenerator):
for d in self.get('items'):
if d.bom_no:
self.get_child_exploded_items(d.bom_no, d.stock_qty)
else:
elif d.item_code:
self.add_to_cur_exploded_items(frappe._dict({
'item_code' : d.item_code,
'item_name' : d.item_name,

View File

@@ -88,7 +88,7 @@ def get_bom_stock(filters):
GROUP BY bom_item.item_code""".format(qty_field=qty_field, table=table, conditions=conditions, bom=bom), as_dict=1)
def get_manufacturer_records():
details = frappe.get_list('Item Manufacturer', fields = ["manufacturer", "manufacturer_part_no", "parent"])
details = frappe.get_all('Item Manufacturer', fields = ["manufacturer", "manufacturer_part_no", "parent"])
manufacture_details = frappe._dict()
for detail in details:
dic = manufacture_details.setdefault(detail.get('parent'), {})

View File

@@ -20,10 +20,6 @@ class TestTimesheet(unittest.TestCase):
for dt in ["Salary Slip", "Salary Structure", "Salary Structure Assignment", "Timesheet"]:
frappe.db.sql("delete from `tab%s`" % dt)
if not frappe.db.exists("Salary Component", "Timesheet Component"):
frappe.get_doc({"doctype": "Salary Component", "salary_component": "Timesheet Component"}).insert()
def test_timesheet_billing_amount(self):
make_salary_structure_for_timesheet("_T-Employee-00001")
timesheet = make_timesheet("_T-Employee-00001", simulate=True, billable=1)
@@ -177,6 +173,9 @@ def make_salary_structure_for_timesheet(employee):
salary_structure_name = "Timesheet Salary Structure Test"
frequency = "Monthly"
if not frappe.db.exists("Salary Component", "Timesheet Component"):
frappe.get_doc({"doctype": "Salary Component", "salary_component": "Timesheet Component"}).insert()
salary_structure = make_salary_structure(salary_structure_name, frequency, dont_submit=True)
salary_structure.salary_component = "Timesheet Component"
salary_structure.salary_slip_based_on_timesheet = 1

View File

@@ -940,7 +940,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
$.each(this.frm.doc.taxes || [], function(i, d) {
if(d.charge_type == "Actual") {
frappe.model.set_value(d.doctype, d.name, "tax_amount",
flt(d.tax_amount) / flt(exchange_rate));
flt(d.base_tax_amount) / flt(exchange_rate));
}
});
},

View File

@@ -9,6 +9,10 @@
"section_break_2",
"sandbox_mode",
"credentials",
"advanced_settings_section",
"client_id",
"column_break_8",
"client_secret",
"auth_token",
"token_expiry"
],
@@ -48,12 +52,32 @@
"fieldname": "sandbox_mode",
"fieldtype": "Check",
"label": "Sandbox Mode"
},
{
"collapsible": 1,
"fieldname": "advanced_settings_section",
"fieldtype": "Section Break",
"label": "Advanced Settings"
},
{
"fieldname": "client_id",
"fieldtype": "Data",
"label": "Client ID"
},
{
"fieldname": "client_secret",
"fieldtype": "Password",
"label": "Client Secret"
},
{
"fieldname": "column_break_8",
"fieldtype": "Column Break"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2021-01-13 12:04:49.449199",
"modified": "2021-11-16 19:50:28.029517",
"modified_by": "Administrator",
"module": "Regional",
"name": "E Invoice Settings",

View File

@@ -23,9 +23,5 @@
"StateCesAmt": "{item.state_cess_amount}",
"StateCesNonAdvlAmt": "{item.state_cess_nadv_amount}",
"OthChrg": "{item.other_charges}",
"TotItemVal": "{item.total_value}",
"BchDtls": {{
"Nm": "{item.batch_no}",
"ExpDt": "{item.batch_expiry_date}"
}}
"TotItemVal": "{item.total_value}"
}}

View File

@@ -36,6 +36,7 @@ def validate_eligibility(doc):
return False
invalid_company = not frappe.db.get_value('E Invoice User', { 'company': doc.get('company') })
invalid_company_gstin = not frappe.db.get_value('E Invoice User', {'gstin': doc.get('company_gstin')})
invalid_supply_type = doc.get('gst_category') not in ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export']
company_transaction = doc.get('billing_address_gstin') == doc.get('company_gstin')
@@ -44,7 +45,7 @@ def validate_eligibility(doc):
no_taxes_applied = not doc.get('taxes') and not doc.get('gst_category') == 'Overseas'
has_non_gst_item = any(d for d in doc.get('items', []) if d.get('is_non_gst'))
if invalid_company or invalid_supply_type or company_transaction or no_taxes_applied or has_non_gst_item:
if invalid_company or invalid_company_gstin or invalid_supply_type or company_transaction or no_taxes_applied or has_non_gst_item:
return False
return True
@@ -200,8 +201,6 @@ def get_item_list(invoice):
item.taxable_value = abs(item.taxable_value)
item.discount_amount = 0
item.batch_expiry_date = frappe.db.get_value('Batch', d.batch_no, 'expiry_date') if d.batch_no else None
item.batch_expiry_date = format_date(item.batch_expiry_date, 'dd/mm/yyyy') if item.batch_expiry_date else None
item.is_service_item = 'Y' if item.gst_hsn_code and item.gst_hsn_code[:2] == "99" else 'N'
item.serial_no = ""
@@ -308,7 +307,7 @@ def update_other_charges(tax_row, invoice_value_details, gst_accounts_list, invo
def get_payment_details(invoice):
payee_name = invoice.company
mode_of_payment = ', '.join([d.mode_of_payment for d in invoice.payments])
mode_of_payment = ""
paid_amount = invoice.base_paid_amount
outstanding_amount = invoice.outstanding_amount
@@ -459,10 +458,16 @@ def make_einvoice(invoice):
try:
einvoice = safe_json_load(einvoice)
einvoice = santize_einvoice_fields(einvoice)
except json.JSONDecodeError:
raise
except Exception:
show_link_to_error_log(invoice, einvoice)
validate_totals(einvoice)
try:
validate_totals(einvoice)
except Exception:
log_error(einvoice)
raise
return einvoice
@@ -534,7 +539,14 @@ def safe_json_load(json_string):
pos = e.pos
start, end = max(0, pos-20), min(len(json_string)-1, pos+20)
snippet = json_string[start:end]
frappe.throw(_("Error in input data. Please check for any special characters near following input: <br> {}").format(snippet))
frappe.throw(
_(
"Error in input data. Please check for any special characters near following input: <br> {}"
).format(snippet),
title=_("Invalid JSON"),
exc=e,
)
def throw_error_list(errors, title):
if len(errors) > 1:
@@ -611,10 +623,17 @@ class GSPConnector():
request_log.save(ignore_permissions=True)
frappe.db.commit()
def get_client_credentials(self):
if self.e_invoice_settings.client_id and self.e_invoice_settings.client_secret:
return self.e_invoice_settings.client_id, self.e_invoice_settings.get_password('client_secret')
return frappe.conf.einvoice_client_id, frappe.conf.einvoice_client_secret
def fetch_auth_token(self):
client_id, client_secret = self.get_client_credentials()
headers = {
'gspappid': frappe.conf.einvoice_client_id,
'gspappsecret': frappe.conf.einvoice_client_secret
'gspappid': client_id,
'gspappsecret': client_secret
}
res = {}
try:
@@ -757,12 +776,13 @@ class GSPConnector():
headers = self.get_headers()
eway_bill_details = get_eway_bill_details(args)
data = json.dumps({
'Irn': args.irn,
'Distance': cint(eway_bill_details.distance),
'TransMode': eway_bill_details.mode_of_transport,
'TransId': eway_bill_details.gstin,
'TransName': eway_bill_details.transporter,
'TransName': eway_bill_details.name,
'TrnDocDt': eway_bill_details.document_date,
'TrnDocNo': eway_bill_details.document_name,
'VehNo': eway_bill_details.vehicle_no,
@@ -854,7 +874,7 @@ class GSPConnector():
if errors:
throw_error_list(errors, title)
else:
link_to_error_list = '<a href="desk#List/Error Log/List?method=E Invoice Request Failed">Error Log</a>'
link_to_error_list = '<a href="desk#List/Error Log/List?method=E Invoice Request Failed" target="_blank">Error Log</a>'
frappe.msgprint(
_('An error occurred while making e-invoicing request. Please check {} for more information.').format(link_to_error_list),
title=title,

View File

@@ -30,12 +30,13 @@ def validate_gstin_for_india(doc, method):
gst_category = []
if len(doc.links):
link_doctype = doc.links[0].get("link_doctype")
link_name = doc.links[0].get("link_name")
if hasattr(doc, 'gst_category'):
if len(doc.links):
link_doctype = doc.links[0].get("link_doctype")
link_name = doc.links[0].get("link_name")
if link_doctype in ["Customer", "Supplier"]:
gst_category = frappe.db.get_value(link_doctype, {'name': link_name}, ['gst_category'])
if link_doctype in ["Customer", "Supplier"]:
gst_category = frappe.db.get_value(link_doctype, {'name': link_name}, ['gst_category'])
doc.gstin = doc.gstin.upper().strip()
if not doc.gstin or doc.gstin == 'NA':
@@ -68,10 +69,9 @@ def validate_tax_category(doc, method):
def update_gst_category(doc, method):
for link in doc.links:
if link.link_doctype in ['Customer', 'Supplier']:
if doc.get('gstin'):
frappe.db.sql("""
UPDATE `tab{0}` SET gst_category = %s WHERE name = %s AND gst_category = 'Unregistered'
""".format(link.link_doctype), ("Registered Regular", link.link_name)) #nosec
meta = frappe.get_meta(link.link_doctype)
if doc.get('gstin') and meta.has_field('gst_category'):
frappe.db.set_value(link.link_doctype, {'name': link.link_name, 'gst_category': 'Unregistered'}, 'gst_category', 'Registered Regular')
def set_gst_state_and_state_number(doc):
if not doc.gst_state:

View File

@@ -104,14 +104,14 @@ def set_address_details(row, special_characters):
row.update({'ship_to_state': row.to_state})
def set_taxes(row, filters):
taxes = frappe.get_list("Sales Taxes and Charges",
taxes = frappe.get_all("Sales Taxes and Charges",
filters={
'parent': row.dn_id
},
fields=('item_wise_tax_detail', 'account_head'))
account_list = ["cgst_account", "sgst_account", "igst_account", "cess_account"]
taxes_list = frappe.get_list("GST Account",
taxes_list = frappe.get_all("GST Account",
filters={
"parent": "GST Settings",
"company": filters.company

View File

@@ -175,7 +175,9 @@ def add_new_address(doc):
def create_lead_for_item_inquiry(lead, subject, message):
lead = frappe.parse_json(lead)
lead_doc = frappe.new_doc('Lead')
lead_doc.update(lead)
for fieldname in ("lead_name", "company_name", "email_id", "phone"):
lead_doc.set(fieldname, lead.get(fieldname))
lead_doc.set('lead_owner', '')
try:

View File

@@ -206,10 +206,11 @@ class Item(WebsiteGenerator):
'route')) + '/' + self.scrub((self.item_name if self.item_name else self.item_code) + '-' + random_string(5))
def validate_website_image(self):
"""Validate if the website image is a public file"""
if frappe.flags.in_import:
return
"""Validate if the website image is a public file"""
auto_set_website_image = False
if not self.website_image and self.image:
auto_set_website_image = True
@@ -239,10 +240,11 @@ class Item(WebsiteGenerator):
self.website_image = None
def make_thumbnail(self):
"""Make a thumbnail of `website_image`"""
if frappe.flags.in_import:
return
"""Make a thumbnail of `website_image`"""
import requests.exceptions
if not self.is_new() and self.website_image != frappe.db.get_value(self.doctype, self.name, "website_image"):
@@ -688,7 +690,6 @@ class Item(WebsiteGenerator):
def recalculate_bin_qty(self, new_name):
from erpnext.stock.stock_balance import repost_stock
frappe.db.auto_commit_on_many_writes = 1
existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
@@ -702,7 +703,6 @@ class Item(WebsiteGenerator):
repost_stock(new_name, warehouse)
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock)
frappe.db.auto_commit_on_many_writes = 0
def copy_specification_from_item_group(self):
self.set("website_specifications", [])

View File

@@ -468,7 +468,7 @@ class TestItem(unittest.TestCase):
item_doc.save()
# Check values saved correctly
barcodes = frappe.get_list(
barcodes = frappe.get_all(
'Item Barcode',
fields=['barcode', 'barcode_type'],
filters={'parent': item_code})

View File

@@ -78,7 +78,11 @@ frappe.ui.form.on('Stock Entry', {
}
}
filters["warehouse"] = item.s_warehouse || item.t_warehouse;
// User could want to select a manually created empty batch (no warehouse)
// or a pre-existing batch
if (frm.doc.purpose != "Material Receipt") {
filters["warehouse"] = item.s_warehouse || item.t_warehouse;
}
return {
query : "erpnext.controllers.queries.get_batch_no",

View File

@@ -32,64 +32,15 @@ class TestWarehouse(unittest.TestCase):
self.assertEqual(p_warehouse.name, child_warehouse.parent_warehouse)
self.assertEqual(child_warehouse.is_group, 0)
def test_warehouse_renaming(self):
set_perpetual_inventory(1)
create_warehouse("Test Warehouse for Renaming 1")
account = get_inventory_account("_Test Company", "Test Warehouse for Renaming 1 - _TC")
self.assertTrue(frappe.db.get_value("Warehouse", filters={"account": account}))
def test_naming(self):
company = "Wind Power LLC"
warehouse_name = "Named Warehouse - WP"
wh = frappe.get_doc(doctype="Warehouse", warehouse_name=warehouse_name, company=company).insert()
self.assertEqual(wh.name, warehouse_name)
# Rename with abbr
if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 2 - _TC"):
frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC")
rename_doc("Warehouse", "Test Warehouse for Renaming 1 - _TC", "Test Warehouse for Renaming 2 - _TC")
self.assertTrue(frappe.db.get_value("Warehouse",
filters={"account": "Test Warehouse for Renaming 1 - _TC"}))
# Rename without abbr
if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 3 - _TC"):
frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 3 - _TC")
rename_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC", "Test Warehouse for Renaming 3")
self.assertTrue(frappe.db.get_value("Warehouse",
filters={"account": "Test Warehouse for Renaming 1 - _TC"}))
# Another rename with multiple dashes
if frappe.db.exists("Warehouse", "Test - Warehouse - Company - _TC"):
frappe.delete_doc("Warehouse", "Test - Warehouse - Company - _TC")
rename_doc("Warehouse", "Test Warehouse for Renaming 3 - _TC", "Test - Warehouse - Company")
def test_warehouse_merging(self):
set_perpetual_inventory(1)
create_warehouse("Test Warehouse for Merging 1")
create_warehouse("Test Warehouse for Merging 2")
make_stock_entry(item_code="_Test Item", target="Test Warehouse for Merging 1 - _TC",
qty=1, rate=100)
make_stock_entry(item_code="_Test Item", target="Test Warehouse for Merging 2 - _TC",
qty=1, rate=100)
existing_bin_qty = (
cint(frappe.db.get_value("Bin",
{"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 1 - _TC"}, "actual_qty"))
+ cint(frappe.db.get_value("Bin",
{"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 2 - _TC"}, "actual_qty"))
)
rename_doc("Warehouse", "Test Warehouse for Merging 1 - _TC",
"Test Warehouse for Merging 2 - _TC", merge=True)
self.assertFalse(frappe.db.exists("Warehouse", "Test Warehouse for Merging 1 - _TC"))
bin_qty = frappe.db.get_value("Bin",
{"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 2 - _TC"}, "actual_qty")
self.assertEqual(bin_qty, existing_bin_qty)
self.assertTrue(frappe.db.get_value("Warehouse",
filters={"account": "Test Warehouse for Merging 2 - _TC"}))
warehouse_name = "Unnamed Warehouse"
wh = frappe.get_doc(doctype="Warehouse", warehouse_name=warehouse_name, company=company).insert()
self.assertIn(warehouse_name, wh.name)
def create_warehouse(warehouse_name, properties=None, company=None):
if not company:
@@ -145,4 +96,4 @@ def get_group_stock_account(company, company_abbr=None):
if not company_abbr:
company_abbr = frappe.get_cached_value("Company", company, 'abbr')
group_stock_account = "Current Assets - " + company_abbr
return group_stock_account
return group_stock_account

View File

@@ -1,6 +1,5 @@
{
"allow_import": 1,
"allow_rename": 1,
"creation": "2013-03-07 18:50:32",
"description": "A logical Warehouse against which stock entries are made.",
"doctype": "DocType",
@@ -235,7 +234,7 @@
"idx": 1,
"is_tree": 1,
"links": [],
"modified": "2020-08-03 18:41:52.442502",
"modified": "2021-12-03 04:40:06.414630",
"modified_by": "Administrator",
"module": "Stock",
"name": "Warehouse",

View File

@@ -7,6 +7,7 @@ from frappe.utils import cint, flt
from frappe import throw, _
from collections import defaultdict
from frappe.utils.nestedset import NestedSet
from erpnext.stock import get_warehouse_account
from frappe.contacts.address_and_contact import load_address_and_contact
@@ -18,8 +19,9 @@ class Warehouse(NestedSet):
suffix = " - " + frappe.get_cached_value('Company', self.company, "abbr")
if not self.warehouse_name.endswith(suffix):
self.name = self.warehouse_name + suffix
else:
self.name = self.warehouse_name
return
self.name = self.warehouse_name
def onload(self):
'''load account name for General Ledger Report'''
@@ -63,57 +65,6 @@ class Warehouse(NestedSet):
return frappe.db.sql("""select name from `tabWarehouse`
where parent_warehouse = %s limit 1""", self.name)
def before_rename(self, old_name, new_name, merge=False):
super(Warehouse, self).before_rename(old_name, new_name, merge)
# Add company abbr if not provided
new_warehouse = erpnext.encode_company_abbr(new_name, self.company)
if merge:
if not frappe.db.exists("Warehouse", new_warehouse):
frappe.throw(_("Warehouse {0} does not exist").format(new_warehouse))
if self.company != frappe.db.get_value("Warehouse", new_warehouse, "company"):
frappe.throw(_("Both Warehouse must belong to same Company"))
return new_warehouse
def after_rename(self, old_name, new_name, merge=False):
super(Warehouse, self).after_rename(old_name, new_name, merge)
new_warehouse_name = self.get_new_warehouse_name_without_abbr(new_name)
self.db_set("warehouse_name", new_warehouse_name)
if merge:
self.recalculate_bin_qty(new_name)
def get_new_warehouse_name_without_abbr(self, name):
company_abbr = frappe.get_cached_value('Company', self.company, "abbr")
parts = name.rsplit(" - ", 1)
if parts[-1].lower() == company_abbr.lower():
name = parts[0]
return name
def recalculate_bin_qty(self, new_name):
from erpnext.stock.stock_balance import repost_stock
frappe.db.auto_commit_on_many_writes = 1
existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
repost_stock_for_items = frappe.db.sql_list("""select distinct item_code
from tabBin where warehouse=%s""", new_name)
# Delete all existing bins to avoid duplicate bins for the same item and warehouse
frappe.db.sql("delete from `tabBin` where warehouse=%s", new_name)
for item_code in repost_stock_for_items:
repost_stock(item_code, new_name)
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock)
frappe.db.auto_commit_on_many_writes = 0
def convert_to_group_or_ledger(self):
if self.is_group:
self.convert_to_ledger()
@@ -232,4 +183,4 @@ def get_warehouses_based_on_account(account, company=None):
frappe.throw(_("Warehouse not found against the account {0}")
.format(account))
return warehouses
return warehouses

View File

@@ -329,7 +329,7 @@ def get_basic_details(args, item, overwrite_warehouse=True):
if not out[d[1]]:
out[d[1]] = frappe.get_cached_value('Company', args.company, d[2]) if d[2] else None
for fieldname in ("item_name", "item_group", "barcodes", "brand", "stock_uom"):
for fieldname in ("item_name", "item_group", "brand", "stock_uom"):
out[fieldname] = item.get(fieldname)
if args.get("manufacturer"):

View File

@@ -39,8 +39,8 @@ def execute(filters=None):
item_balance.setdefault((item, item_map[item]["item_group"]), [])
total_stock_value = 0.00
for wh in warehouse_list:
row += [qty_dict.bal_qty] if wh.name in warehouse else [0.00]
total_stock_value += qty_dict.bal_val if wh.name in warehouse else 0.00
row += [qty_dict.bal_qty] if wh.name == warehouse else [0.00]
total_stock_value += qty_dict.bal_val if wh.name == warehouse else 0.00
item_balance[(item, item_map[item]["item_group"])].append(row)
item_value.setdefault((item, item_map[item]["item_group"]),[])

View File

@@ -368,7 +368,7 @@ class update_entries_after(object):
batch = self.stock_queue[index]
if qty_to_pop >= batch[0]:
# consume current batch
qty_to_pop = qty_to_pop - batch[0]
qty_to_pop = _round_off_if_near_zero(qty_to_pop - batch[0])
self.stock_queue.pop(index)
if not self.stock_queue and qty_to_pop:
# stock finished, qty still remains to be withdrawn
@@ -382,8 +382,8 @@ class update_entries_after(object):
batch[0] = batch[0] - qty_to_pop
qty_to_pop = 0
stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in self.stock_queue))
stock_qty = sum((flt(batch[0]) for batch in self.stock_queue))
stock_value = _round_off_if_near_zero(sum((flt(batch[0]) * flt(batch[1]) for batch in self.stock_queue)))
stock_qty = _round_off_if_near_zero(sum((flt(batch[0]) for batch in self.stock_queue)))
if stock_qty:
self.valuation_rate = stock_value / flt(stock_qty)
@@ -549,3 +549,12 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
frappe.throw(msg=msg, title=_("Valuation Rate Missing"))
return valuation_rate
def _round_off_if_near_zero(number, precision = 7):
"""Rounds off the number to zero only if number is close to zero for decimal
specified in precision. Precision defaults to 7.
"""
if abs(0.0 - flt(number)) < (1.0 / (10**precision)):
return 0.0
return flt(number)

View File

@@ -2,10 +2,9 @@ braintree==3.57.1
# frappe # https://github.com/frappe/frappe is installed during bench-init
gocardless-pro==1.11.0
googlemaps==3.1.1
pandas==0.24.2
pandas>=0.24.0,<1.2.0
plaid-python~=7.2.1
PyGithub==1.44.1
python-stdnum==1.12
Unidecode==1.1.1
WooCommerce==2.1.1
pycryptodome==3.9.8