diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 4197d547340..b9b5347e3b6 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -5,7 +5,7 @@ import frappe from erpnext.hooks import regional_overrides from frappe.utils import getdate -__version__ = '10.1.76' +__version__ = '10.1.77' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.js b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.js index c18057eb404..779cd6197e9 100644 --- a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.js +++ b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.js @@ -39,6 +39,8 @@ frappe.ui.form.on('Exchange Rate Revaluation', { }); frm.events.get_total_gain_loss(frm); refresh_field("accounts"); + } else { + frappe.msgprint(__("No records found")); } } }); diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py index ae77516eb70..cdfe34beadb 100644 --- a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py +++ b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py @@ -67,17 +67,19 @@ class ExchangeRateRevaluation(Document): and account_currency != %s order by name""",(self.company, company_currency)) - account_details = frappe.db.sql(""" - select - account, party_type, party, account_currency, - sum(debit_in_account_currency) - sum(credit_in_account_currency) as balance_in_account_currency, - sum(debit) - sum(credit) as balance - from `tabGL Entry` - where account in (%s) - group by account, party_type, party - having sum(debit) != sum(credit) - order by account - """ % ', '.join(['%s']*len(accounts)), tuple(accounts), as_dict=1) + account_details = [] + if accounts: + account_details = frappe.db.sql(""" + select + account, party_type, party, account_currency, + sum(debit_in_account_currency) - sum(credit_in_account_currency) as balance_in_account_currency, + sum(debit) - sum(credit) as balance + from `tabGL Entry` + where account in (%s) + group by account, party_type, party + having sum(debit) != sum(credit) + order by account + """ % ', '.join(['%s']*len(accounts)), tuple(accounts), as_dict=1) return account_details diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py index e6fe6caf140..810b6f79b51 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.py +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py @@ -18,15 +18,14 @@ class GLEntry(Document): self.flags.ignore_submit_comment = True self.check_mandatory() self.validate_and_set_fiscal_year() + self.pl_must_have_cost_center() + self.validate_cost_center() if not self.flags.from_repost: - self.pl_must_have_cost_center() self.check_pl_account() - self.validate_cost_center() self.validate_party() self.validate_currency() - def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False): if not from_repost: self.validate_account_details(adv_adj) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 2ed664c9bf7..7ecc6955204 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -200,7 +200,7 @@ class GrossProfitGenerator(object): def skip_row(self, row, product_bundles): if self.filters.get("group_by") != "Invoice": - if not row.get(scrub(self.filters.get("group_by"))): + if not row.get(scrub(self.filters.get("group_by", ""))): return True elif row.get("is_return") == 1: return True @@ -316,7 +316,7 @@ class GrossProfitGenerator(object): on `tabSales Invoice Item`.parent = `tabSales Invoice`.name {sales_team_table} where - `tabSales Invoice`.docstatus=1 {conditions} {match_cond} + `tabSales Invoice`.docstatus=1 and `tabSales Invoice`.is_opening!='Yes' {conditions} {match_cond} order by `tabSales Invoice`.posting_date desc, `tabSales Invoice`.posting_time desc""" .format(conditions=conditions, sales_person_cols=sales_person_cols, diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index 5296e224929..6b3c3cc73d9 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 1, @@ -154,7 +155,7 @@ "columns": 0, "fetch_from": "item_code.asset_category", "fieldname": "asset_category", - "fieldtype": "Read Only", + "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -165,12 +166,12 @@ "label": "Asset Category", "length": 0, "no_copy": 0, - "options": "", + "options": "Asset Category", "permlevel": 0, "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 0, + "read_only": 1, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -1881,7 +1882,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-21 14:44:24.507215", + "modified": "2019-01-15 16:12:48.314196", "modified_by": "Administrator", "module": "Assets", "name": "Asset", diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 24ce7d41f74..9bf38581679 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -499,7 +499,8 @@ def get_bin_details(row): conditions = "" warehouse = row.source_warehouse or row.default_warehouse or row.warehouse if warehouse: - conditions = " and warehouse='{0}'".format(frappe.db.escape(warehouse)) + lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"]) + conditions = " and exists(select name from `tabWarehouse` where lft >= {0} and rgt <= {1} and name=`tabBin`.warehouse)".format(lft, rgt) item_projected_qty = frappe.db.sql(""" select ifnull(sum(projected_qty),0) as projected_qty, ifnull(sum(actual_qty),0) as actual_qty from `tabBin` diff --git a/erpnext/patches.txt b/erpnext/patches.txt index af2463f5957..082f887da98 100755 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -1,9 +1,9 @@ execute:import unidecode # new requirement erpnext.patches.v8_0.move_perpetual_inventory_setting +erpnext.patches.v11_0.rename_production_order_to_work_order erpnext.patches.v11_0.refactor_naming_series erpnext.patches.v11_0.refactor_autoname_naming erpnext.patches.v10_0.rename_schools_to_education -erpnext.patches.v11_0.rename_production_order_to_work_order erpnext.patches.v4_0.validate_v3_patch erpnext.patches.v4_0.fix_employee_user_id erpnext.patches.v4_0.remove_employee_role_if_no_employee diff --git a/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py b/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py index 83130966d4c..52d4621c7b7 100644 --- a/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py +++ b/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals import frappe from frappe.model.rename_doc import rename_doc from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py index 649d73a63f1..371fc5c79b4 100755 --- a/erpnext/projects/doctype/task/task.py +++ b/erpnext/projects/doctype/task/task.py @@ -12,6 +12,7 @@ from frappe.utils.nestedset import NestedSet class CircularReferenceError(frappe.ValidationError): pass +class EndDateCannotBeGreaterThanProjectEndDateError(frappe.ValidationError): pass class Task(NestedSet): nsm_parent_field = 'parent_task' @@ -43,6 +44,12 @@ class Task(NestedSet): if self.act_start_date and self.act_end_date and getdate(self.act_start_date) > getdate(self.act_end_date): frappe.throw(_("'Actual Start Date' can not be greater than 'Actual End Date'")) + if(self.project): + if frappe.db.exists("Project", self.project): + expected_end_date = frappe.db.get_value("Project", self.project, "expected_end_date") + if self.exp_end_date and expected_end_date and getdate(self.exp_end_date) > getdate(expected_end_date) : + frappe.throw(_("Expected end date cannot be after Project: '{0}' Expected end date").format(self.project), EndDateCannotBeGreaterThanProjectEndDateError) + def validate_status(self): if self.status!=self.get_db_value("status") and self.status == "Closed": for d in self.depends_on: diff --git a/erpnext/projects/doctype/task/test_task.py b/erpnext/projects/doctype/task/test_task.py index 0966b768072..6fb54124732 100644 --- a/erpnext/projects/doctype/task/test_task.py +++ b/erpnext/projects/doctype/task/test_task.py @@ -5,11 +5,11 @@ import frappe import unittest from frappe.utils import getdate, nowdate, add_days -from erpnext.projects.doctype.task.task import CircularReferenceError +from erpnext.projects.doctype.task.task import CircularReferenceError, EndDateCannotBeGreaterThanProjectEndDateError class TestTask(unittest.TestCase): def test_circular_reference(self): - task1 = create_task("_Test Task 1", nowdate(), add_days(nowdate(), 10)) + task1 = create_task("_Test Task 1", add_days(nowdate(), -15), add_days(nowdate(), -10)) task2 = create_task("_Test Task 2", add_days(nowdate(), 11), add_days(nowdate(), 15), task1.name) task3 = create_task("_Test Task 3", add_days(nowdate(), 11), add_days(nowdate(), 15), task2.name) @@ -97,7 +97,16 @@ class TestTask(unittest.TestCase): self.assertEqual(frappe.db.get_value("Task", task.name, "status"), "Overdue") -def create_task(subject, start=None, end=None, depends_on=None, project=None): + def test_end_date_validation(self): + task_end = create_task("Testing_Enddate_validation", add_days(nowdate(), 35), add_days(nowdate(), 45), save=False) + pro = frappe.get_doc("Project", task_end.project) + pro.expected_end_date = add_days(nowdate(), 40) + pro.save() + self.assertRaises(EndDateCannotBeGreaterThanProjectEndDateError, task_end.save) + + + +def create_task(subject, start=None, end=None, depends_on=None, project=None, save=True): if not frappe.db.exists("Task", subject): task = frappe.new_doc('Task') task.status = "Open" @@ -105,7 +114,8 @@ def create_task(subject, start=None, end=None, depends_on=None, project=None): task.exp_start_date = start or nowdate() task.exp_end_date = end or nowdate() task.project = project or "_Test Project" - task.save() + if save: + task.save() else: task = frappe.get_doc("Task", subject) @@ -113,6 +123,7 @@ def create_task(subject, start=None, end=None, depends_on=None, project=None): task.append("depends_on", { "task": depends_on }) - task.save() + if save: + task.save() return task \ No newline at end of file diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 035c58d6d2a..9dd9bebb4da 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -416,6 +416,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ item_code: item.item_code, barcode: item.barcode, serial_no: item.serial_no, + set_warehouse: me.frm.doc.set_warehouse, warehouse: item.warehouse, customer: me.frm.doc.customer, supplier: me.frm.doc.supplier, diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py index ea600e46180..78aeee7dd7a 100644 --- a/erpnext/regional/india/utils.py +++ b/erpnext/regional/india/utils.py @@ -11,22 +11,49 @@ def validate_gstin_for_india(doc, method): if not hasattr(doc, 'gstin'): return - if doc.gstin: - doc.gstin = doc.gstin.upper() - if doc.gstin not in ["NA", "na"]: - p = re.compile("[0-9]{2}[a-zA-Z]{5}[0-9]{4}[a-zA-Z]{1}[1-9A-Za-z]{1}[Z]{1}[0-9a-zA-Z]{1}") - if not p.match(doc.gstin): - frappe.throw(_("Invalid GSTIN or Enter NA for Unregistered")) + doc.gstin = doc.gstin.upper().strip() + if not doc.gstin or doc.gstin == 'NA': + return + + if len(doc.gstin) != 15: + frappe.throw(_("Invalid GSTIN! A GSTIN must have 15 characters.")) + + p = re.compile("^[0-9]{2}[A-Z]{4}[0-9A-Z]{1}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[1-9A-Z]{1}[0-9A-Z]{1}$") + if not p.match(doc.gstin): + frappe.throw(_("Invalid GSTIN! The input you've entered doesn't match the format of GSTIN.")) + + validate_gstin_check_digit(doc.gstin) if not doc.gst_state: - if doc.state in states: - doc.gst_state = doc.state + if not doc.state: + return + state = doc.state.lower() + states_lowercase = {s.lower():s for s in states} + if state in states_lowercase: + doc.gst_state = states_lowercase[state] + else: + return - if doc.gst_state: - doc.gst_state_number = state_numbers[doc.gst_state] - if doc.gstin and doc.gstin != "NA" and doc.gst_state_number != doc.gstin[:2]: - frappe.throw(_("First 2 digits of GSTIN should match with State number {0}") - .format(doc.gst_state_number)) + doc.gst_state_number = state_numbers[doc.gst_state] + if doc.gst_state_number != doc.gstin[:2]: + frappe.throw(_("Invalid GSTIN! First 2 digits of GSTIN should match with State number {0}.") + .format(doc.gst_state_number)) + +def validate_gstin_check_digit(gstin): + ''' Function to validate the check digit of the GSTIN.''' + factor = 1 + total = 0 + code_point_chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' + mod = len(code_point_chars) + input_chars = gstin[:-1] + for char in input_chars: + digit = factor * code_point_chars.find(char) + digit = (digit // mod) + (digit % mod) + total += digit + factor = 2 if factor == 1 else 1 + if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]: + frappe.throw(_("Invalid GSTIN! The check digit validation has failed. " + + "Please ensure you've typed the GSTIN correctly.")) def get_itemised_tax_breakup_header(item_doctype, tax_accounts): if frappe.get_meta(item_doctype).has_field('gst_hsn_code'): diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 0da82724ac8..2970d7a5e82 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -177,6 +177,11 @@ class Customer(TransactionBase): frappe.throw(_("""New credit limit is less than current outstanding amount for the customer. Credit limit has to be atleast {0}""").format(outstanding_amt)) def on_trash(self): + if self.customer_primary_contact: + frappe.db.sql("""update `tabCustomer` + set customer_primary_contact=null, mobile_no=null, email_id=null + where name=%s""", self.name) + delete_contact_and_address('Customer', self.name) if self.lead_name: frappe.db.sql("update `tabLead` set status='Interested' where name=%s", self.lead_name) diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py index cc2fc59f41a..fa4f83551df 100644 --- a/erpnext/selling/doctype/customer/test_customer.py +++ b/erpnext/selling/doctype/customer/test_customer.py @@ -98,6 +98,15 @@ class TestCustomer(unittest.TestCase): so.save() + def test_delete_customer_contact(self): + customer = frappe.get_doc( + get_customer_dict('_Test Customer for delete')).insert(ignore_permissions=True) + + customer.mobile_no = "8989889890" + customer.save() + self.assertTrue(customer.customer_primary_contact) + frappe.delete_doc('Customer', customer.name) + def test_disabled_customer(self): make_test_records("Item") diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.py b/erpnext/selling/report/sales_analytics/sales_analytics.py index c078a082491..3239fc626f9 100644 --- a/erpnext/selling/report/sales_analytics/sales_analytics.py +++ b/erpnext/selling/report/sales_analytics/sales_analytics.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import _, scrub -from frappe.utils import getdate, flt +from frappe.utils import getdate, flt, add_to_date, add_days from six import iteritems from erpnext.accounts.utils import get_fiscal_year @@ -40,7 +40,7 @@ class Analytics(object): "fieldtype": "Data", "width": 140 }) - for dummy, end_date in self.periodic_daterange: + for end_date in self.periodic_daterange: period = self.get_period(end_date) self.columns.append({ "label": _(period), @@ -169,7 +169,7 @@ class Analytics(object): "entity_name": self.entity_names.get(entity) } total = 0 - for dummy, end_date in self.periodic_daterange: + for end_date in self.periodic_daterange: period = self.get_period(end_date) amount = flt(period_data.get(period, 0.0)) row[scrub(period)] = amount @@ -188,7 +188,7 @@ class Analytics(object): "indent": self.depth_map.get(d.name) } total = 0 - for dummy, end_date in self.periodic_daterange: + for end_date in self.periodic_daterange: period = self.get_period(end_date) amount = flt(self.entity_periodic_data.get(d.name, {}).get(period, 0.0)) row[scrub(period)] = amount @@ -219,12 +219,11 @@ class Analytics(object): period = "Quarter " + str(((posting_date.month-1)//3)+1) +" " + str(posting_date.year) else: year = get_fiscal_year(posting_date, company=self.filters.company) - period = str(year[2]) - + period = str(year[0]) return period def get_period_date_ranges(self): - from dateutil.relativedelta import relativedelta + from dateutil.relativedelta import relativedelta, MO from_date, to_date = getdate(self.filters.from_date), getdate(self.filters.to_date) increment = { @@ -234,18 +233,26 @@ class Analytics(object): "Yearly": 12 }.get(self.filters.range, 1) + if self.filters.range in ['Monthly', 'Quarterly']: + from_date = from_date.replace(day = 1) + elif self.filters.range == "Yearly": + from_date = get_fiscal_year(from_date)[1] + else: + from_date = from_date + relativedelta(from_date, weekday=MO(-1)) + self.periodic_daterange = [] - for dummy in range(1, 53, increment): + for dummy in range(1, 53): if self.filters.range == "Weekly": - period_end_date = from_date + relativedelta(days=6) + period_end_date = add_days(from_date, 6) else: - period_end_date = from_date + relativedelta(months=increment, days=-1) + period_end_date = add_to_date(from_date, months=increment, days=-1) if period_end_date > to_date: period_end_date = to_date - self.periodic_daterange.append([from_date, period_end_date]) - from_date = period_end_date + relativedelta(days=1) + self.periodic_daterange.append(period_end_date) + + from_date = add_days(period_end_date, 1) if period_end_date == to_date: break diff --git a/erpnext/setup/default_success_action.py b/erpnext/setup/default_success_action.py index e8494a1f965..6c2a97a89c5 100644 --- a/erpnext/setup/default_success_action.py +++ b/erpnext/setup/default_success_action.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals from frappe import _ doctype_list = [ diff --git a/erpnext/setup/doctype/company/company_dashboard.py b/erpnext/setup/doctype/company/company_dashboard.py index 61332267e7a..5efcf3839f6 100644 --- a/erpnext/setup/doctype/company/company_dashboard.py +++ b/erpnext/setup/doctype/company/company_dashboard.py @@ -13,7 +13,7 @@ def get_data(): 'goal_doctype_link': 'company', 'goal_field': 'base_grand_total', 'date_field': 'posting_date', - 'filter_str': 'docstatus = 1', + 'filter_str': "docstatus = 1 and is_opening != 'Yes'", 'aggregation': 'sum' }, diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py index 6bc90361954..f258f7d2954 100644 --- a/erpnext/setup/doctype/item_group/item_group.py +++ b/erpnext/setup/doctype/item_group/item_group.py @@ -136,7 +136,10 @@ def get_child_groups_for_list_in_html(item_group, start, limit, search): rgt = ('<', item_group.rgt), ), or_filters = search_filters, - order_by = 'weightage desc, name asc') + order_by = 'weightage desc, name asc', + start = start, + limit = limit + ) return [get_item_for_list_in_html(r) for r in data] diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index 212bb51185d..bc991b4e153 100644 --- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -10,7 +10,9 @@ from frappe.utils import flt, nowdate, nowtime from erpnext.accounts.utils import get_stock_and_account_difference from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after -from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import EmptyStockReconciliationItemsError +from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import EmptyStockReconciliationItemsError, get_items +from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse +from erpnext.stock.doctype.item.test_item import make_item class TestStockReconciliation(unittest.TestCase): def setUp(self): @@ -79,6 +81,17 @@ class TestStockReconciliation(unittest.TestCase): set_perpetual_inventory(0) + def test_get_items(self): + create_warehouse("_Test Warehouse Group 1", {"is_group": 1}) + create_warehouse("_Test Warehouse Ledger 1", {"is_group": 0, "parent_warehouse": "_Test Warehouse Group 1 - _TC"}) + make_item("_Test Stock Reco Item", {"default_warehouse": "_Test Warehouse Ledger 1 - _TC", + "is_stock_item": 1, "opening_stock": 100, "valuation_rate": 100}) + + items = get_items("_Test Warehouse Group 1 - _TC", nowdate(), nowtime()) + + self.assertEqual(["_Test Stock Reco Item", "_Test Warehouse Ledger 1 - _TC", 100], + [items[0]["item_code"], items[0]["warehouse"], items[0]["qty"]]) + def insert_existing_sle(self): from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry diff --git a/erpnext/stock/doctype/warehouse/test_warehouse.py b/erpnext/stock/doctype/warehouse/test_warehouse.py index 006945e1aa9..b033f86d8e3 100644 --- a/erpnext/stock/doctype/warehouse/test_warehouse.py +++ b/erpnext/stock/doctype/warehouse/test_warehouse.py @@ -90,7 +90,7 @@ class TestWarehouse(unittest.TestCase): self.assertTrue(frappe.db.get_value("Warehouse", filters={"account": "Test Warehouse for Merging 2 - _TC"})) -def create_warehouse(warehouse_name): +def create_warehouse(warehouse_name, properties=None): if not frappe.db.exists("Warehouse", warehouse_name + " - _TC"): w = frappe.new_doc("Warehouse") w.warehouse_name = warehouse_name @@ -98,11 +98,13 @@ def create_warehouse(warehouse_name): w.company = "_Test Company" make_account_for_warehouse(warehouse_name, w) w.account = warehouse_name + " - _TC" + if properties: + w.update(properties) w.save() def make_account_for_warehouse(warehouse_name, warehouse_obj): if not frappe.db.exists("Account", warehouse_name + " - _TC"): - parent_account = frappe.db.get_value('Account', + parent_account = frappe.db.get_value('Account', {'company': warehouse_obj.company, 'is_group':1, 'account_type': 'Stock'},'name') account = create_account(account_name=warehouse_name, \ account_type="Stock", parent_account= parent_account, company=warehouse_obj.company) \ No newline at end of file diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 692fe5d0fbe..bbea9043a35 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -36,6 +36,7 @@ def get_item_details(args): "is_subcontracted": "Yes" / "No", "ignore_pricing_rule": 0/1 "project": "" + "set_warehouse": "" } """ args = process_args(args) @@ -189,7 +190,6 @@ def get_basic_details(args, item): "project": "", barcode: "", serial_no: "", - warehouse: "", currency: "", update_stock: "", price_list: "", @@ -219,7 +219,7 @@ def get_basic_details(args, item): item_defaults = get_item_defaults(item.name, args.company) item_group_defaults = get_item_group_defaults(item.name, args.company) - warehouse = user_default_warehouse or item_defaults.get("default_warehouse") or\ + warehouse = args.get("set_warehouse") or user_default_warehouse or item_defaults.get("default_warehouse") or\ item_group_defaults.get("default_warehouse") or args.warehouse if args.get('doctype') == "Material Request" and not args.get('material_request_type'): @@ -273,7 +273,7 @@ def get_basic_details(args, item): "transaction_date": args.get("transaction_date") }) - if item.enable_deferred_revenue: + if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"): out.update(calculate_service_end_date(args, item)) # calculate conversion factor @@ -310,9 +310,15 @@ def calculate_service_end_date(args, item=None): if not item: item = frappe.get_cached_doc("Item", args.item_code) - enable_deferred = "enable_deferred_revenue" if args.doctype=="Sales Invoice" else "enable_deferred_expense" - no_of_months = "no_of_months" if args.doctype=="Sales Invoice" else "no_of_months_exp" - account = "deferred_revenue_account" if args.doctype=="Sales Invoice" else "deferred_expense_account" + doctype = args.get("parenttype") or args.get("doctype") + if doctype == "Sales Invoice": + enable_deferred = "enable_deferred_revenue" + no_of_months = "no_of_months" + account = "deferred_revenue_account" + else: + enable_deferred = "enable_deferred_expense" + no_of_months = "no_of_months_exp" + account = "deferred_expense_account" service_start_date = args.service_start_date if args.service_start_date else args.transaction_date service_end_date = add_months(service_start_date, item.get(no_of_months)) @@ -336,7 +342,7 @@ def get_default_expense_account(args, item, item_group): or args.expense_account) def get_default_deferred_account(args, item, fieldname=None): - if item.enable_deferred_revenue: + if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"): return (item.get(fieldname) or args.get(fieldname) or frappe.get_cached_value('Company', args.company, "default_"+fieldname)) @@ -370,16 +376,16 @@ def get_price_list_rate(args, item_doc, out): price_list_rate = get_price_list_rate_for(args, item_doc.name) or 0 + # variant + if not price_list_rate and item_doc.variant_of: + price_list_rate = get_price_list_rate_for(args, item_doc.variant_of) + # insert in database if not price_list_rate: if args.price_list and args.rate: insert_item_price(args) return {} - # variant - if not price_list_rate and item_doc.variant_of: - price_list_rate = get_price_list_rate_for(args, item_doc.variant_of) - out.price_list_rate = flt(price_list_rate) * flt(args.plc_conversion_rate) \ / flt(args.conversion_rate)