diff --git a/erpnext/__init__.py b/erpnext/__init__.py index d8357f82170..6bd3a6ad416 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__ = '11.1.25' +__version__ = '11.1.26' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/sales_invoice/regional/india.js b/erpnext/accounts/doctype/sales_invoice/regional/india.js new file mode 100644 index 00000000000..5fec3ba6d32 --- /dev/null +++ b/erpnext/accounts/doctype/sales_invoice/regional/india.js @@ -0,0 +1,38 @@ +frappe.ui.form.on("Sales Invoice", { + setup: function(frm) { + frm.set_query('transporter', function() { + return { + filters: { + 'is_transporter': 1 + } + }; + }); + + frm.set_query('driver', function(doc) { + return { + filters: { + 'transporter': doc.transporter + } + }; + }); + }, + + refresh: function(frm) { + if(frm.doc.docstatus == 1 && !frm.is_dirty() + && !frm.doc.is_return && !frm.doc.ewaybill) { + + frm.add_custom_button('Generate e-Way Bill JSON', () => { + var w = window.open( + frappe.urllib.get_full_url( + "/api/method/erpnext.regional.india.utils.generate_ewb_json?" + + "dt=" + encodeURIComponent(frm.doc.doctype) + + "&dn=" + encodeURIComponent(frm.doc.name) + ) + ); + if (!w) { + frappe.msgprint(__("Please enable pop-ups")); return; + } + }, __("Make")); + } + } +}); diff --git a/erpnext/accounts/doctype/sales_invoice/regional/india_list.js b/erpnext/accounts/doctype/sales_invoice/regional/india_list.js new file mode 100644 index 00000000000..66d74b4b06a --- /dev/null +++ b/erpnext/accounts/doctype/sales_invoice/regional/india_list.js @@ -0,0 +1,33 @@ +var globalOnload = frappe.listview_settings['Sales Invoice'].onload; +frappe.listview_settings['Sales Invoice'].onload = function (doclist) { + + // Provision in case onload event is added to sales_invoice.js in future + if (globalOnload) { + globalOnload(doclist); + } + + const action = () => { + const selected_docs = doclist.get_checked_items(); + const docnames = doclist.get_checked_items(true); + + for (let doc of selected_docs) { + if (doc.docstatus !== 1) { + frappe.throw(__("e-Way Bill JSON can only be generated from a submitted document")); + } + } + + var w = window.open( + frappe.urllib.get_full_url( + "/api/method/erpnext.regional.india.utils.generate_ewb_json?" + + "dt=" + encodeURIComponent(doclist.doctype) + + "&dn=" + encodeURIComponent(docnames) + ) + ); + if (!w) { + frappe.msgprint(__("Please enable pop-ups")); return; + } + + }; + + doclist.page.add_actions_menu_item(__('Generate e-Way Bill JSON'), action, false); +}; \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index dc02a6b3e6f..bfcbe5a98eb 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -18,6 +18,8 @@ from erpnext.accounts.doctype.account.test_account import get_inventory_account, from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data from erpnext.stock.doctype.item.test_item import create_item from six import iteritems +from erpnext.regional.india.utils import get_ewb_data + class TestSalesInvoice(unittest.TestCase): def make(self): w = frappe.copy_doc(test_records[0]) @@ -1611,6 +1613,110 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(expected_gle[i][2], gle.credit) self.assertEqual(getdate(expected_gle[i][3]), gle.posting_date) + def test_eway_bill_json(self): + if not frappe.db.exists('Address', '_Test Address for Eway bill-Billing'): + address = frappe.get_doc({ + "address_line1": "_Test Address Line 1", + "address_title": "_Test Address for Eway bill", + "address_type": "Billing", + "city": "_Test City", + "state": "Test State", + "country": "India", + "doctype": "Address", + "is_primary_address": 1, + "phone": "+91 0000000000", + "gstin": "27AAECE4835E1ZR", + "gst_state": "Maharashtra", + "gst_state_number": "27", + "pincode": "401108" + }).insert() + + address.append("links", { + "link_doctype": "Company", + "link_name": "_Test Company" + }) + + address.save() + + if not frappe.db.exists('Address', '_Test Customer-Address for Eway bill-Shipping'): + address = frappe.get_doc({ + "address_line1": "_Test Address Line 1", + "address_title": "_Test Customer-Address for Eway bill", + "address_type": "Shipping", + "city": "_Test City", + "state": "Test State", + "country": "India", + "doctype": "Address", + "is_primary_address": 1, + "phone": "+91 0000000000", + "gst_state": "Maharashtra", + "gst_state_number": "27", + "pincode": "410038" + }).insert() + + address.append("links", { + "link_doctype": "Customer", + "link_name": "_Test Customer" + }) + + address.save() + + gst_settings = frappe.get_doc("GST Settings") + + gst_account = frappe.get_all( + "GST Account", + fields=["cgst_account", "sgst_account", "igst_account"], + filters = {"company": "_Test Company"}) + + if not gst_account: + gst_settings.append("gst_accounts", { + "company": "_Test Company", + "cgst_account": "CGST - _TC", + "sgst_account": "SGST - _TC", + "igst_account": "IGST - _TC", + }) + + gst_settings.save() + + si = create_sales_invoice(do_not_save =1, rate = '60000') + + si.distance = 2000 + si.company_address = "_Test Address for Eway bill-Billing" + si.customer_address = "_Test Customer-Address for Eway bill-Shipping" + si.vehicle_no = "KA12KA1234" + + si.append("taxes", { + "charge_type": "On Net Total", + "account_head": "CGST - _TC", + "cost_center": "Main - _TC", + "description": "CGST @ 9.0", + "rate": 9 + }) + + si.append("taxes", { + "charge_type": "On Net Total", + "account_head": "SGST - _TC", + "cost_center": "Main - _TC", + "description": "SGST @ 9.0", + "rate": 9 + }) + + si.submit() + + data = get_ewb_data("Sales Invoice", si.name) + + self.assertEqual(data['version'], '1.0.1118') + self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR') + self.assertEqual(data['billLists'][0]['fromTrdName'], '_Test Company') + self.assertEqual(data['billLists'][0]['toTrdName'], '_Test Customer') + self.assertEqual(data['billLists'][0]['vehicleType'], 'R') + self.assertEqual(data['billLists'][0]['totalValue'], 60000) + self.assertEqual(data['billLists'][0]['cgstValue'], 5400) + self.assertEqual(data['billLists'][0]['sgstValue'], 5400) + self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234') + self.assertEqual(data['billLists'][0]['itemList'][0]['taxableAmount'], 60000) + + def create_sales_invoice(**args): si = frappe.new_doc("Sales Invoice") args = frappe._dict(args) diff --git a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py index 844942ff0f6..fd169f8f70f 100644 --- a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py +++ b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py @@ -80,27 +80,24 @@ def get_data(filters): sales_invoice_data = get_sales_details(filters) for item in items: + row = { + "item_group": item.item_group, + "item": item.name, + "item_name": item.item_name + } + if sales_invoice_data.get(item.name): item_obj = sales_invoice_data[item.name] if item_obj.days_since_last_order > cint(filters['days']): - row = { + row.update({ "territory": item_obj.territory, - "item_group": item_obj.item_group, - "item": item_obj.name, - "item_name": item_obj.item_name, "customer": item_obj.customer, "last_order_date": item_obj.last_order_date, "qty": item_obj.qty, "days_since_last_order": item_obj.days_since_last_order - } - data.append(row) - else: - row = { - "item_group": item.item_group, - "item": item.name, - "item_name": item.item_name - } - data.append(row) + }) + + data.append(row) return data diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index f2b15ad20ce..8cf11f785be 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -205,11 +205,14 @@ def get_already_returned_items(doc): def make_return_doc(doctype, source_name, target_doc=None): from frappe.model.mapper import get_mapped_doc + company = frappe.db.get_value("Delivery Note", source_name, "company") + default_warehouse_for_sales_return = frappe.db.get_value("Company", company, "default_warehouse_for_sales_return") def set_missing_values(source, target): doc = frappe.get_doc(target) doc.is_return = 1 doc.return_against = source.name doc.ignore_pricing_rule = 1 + doc.set_warehouse = "" if doctype == "Sales Invoice": doc.is_pos = source.is_pos @@ -277,12 +280,16 @@ def make_return_doc(doctype, source_name, target_doc=None): target_doc.so_detail = source_doc.so_detail target_doc.si_detail = source_doc.si_detail target_doc.expense_account = source_doc.expense_account + if default_warehouse_for_sales_return: + target_doc.warehouse = default_warehouse_for_sales_return elif doctype == "Sales Invoice": target_doc.sales_order = source_doc.sales_order target_doc.delivery_note = source_doc.delivery_note target_doc.so_detail = source_doc.so_detail target_doc.dn_detail = source_doc.dn_detail target_doc.expense_account = source_doc.expense_account + if default_warehouse_for_sales_return: + target_doc.warehouse = default_warehouse_for_sales_return def update_terms(source_doc, target_doc, source_parent): target_doc.payment_amount = -source_doc.payment_amount diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 5bbef1831ad..2db18298d38 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -608,7 +608,7 @@ def get_itemised_tax_breakup_data(doc): return itemised_tax, itemised_taxable_amount -def get_itemised_tax(taxes): +def get_itemised_tax(taxes, with_tax_account=False): itemised_tax = {} for tax in taxes: if getattr(tax, "category", None) and tax.category=="Valuation": @@ -633,6 +633,9 @@ def get_itemised_tax(taxes): tax_amount = tax_amount )) + if with_tax_account: + itemised_tax[item_code][tax.description].tax_account = tax.account_head + return itemised_tax def get_itemised_taxable_amount(items): diff --git a/erpnext/crm/doctype/lead/lead_dashboard.py b/erpnext/crm/doctype/lead/lead_dashboard.py index e8472aafc2e..d58527e00cd 100644 --- a/erpnext/crm/doctype/lead/lead_dashboard.py +++ b/erpnext/crm/doctype/lead/lead_dashboard.py @@ -4,6 +4,10 @@ from frappe import _ def get_data(): return { 'fieldname': 'lead', + 'non_standard_fieldnames': { + 'Quotation': 'party_name', + 'Opportunity': 'party_name' + }, 'transactions': [ { 'items': ['Opportunity', 'Quotation'] diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 3ddc069331b..10a998e4e99 100755 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -571,7 +571,7 @@ execute:frappe.delete_doc_if_exists("Page", "sales-analytics") execute:frappe.delete_doc_if_exists("Page", "purchase-analytics") execute:frappe.delete_doc_if_exists("Page", "stock-analytics") execute:frappe.delete_doc_if_exists("Page", "production-analytics") -erpnext.patches.v11_0.ewaybill_fields_gst_india #2018-11-13 #2019-01-09 #2019-04-01 #2019-04-26 +erpnext.patches.v11_0.ewaybill_fields_gst_india #2018-11-13 #2019-01-09 #2019-04-01 #2019-04-26 #2019-05-03 erpnext.patches.v11_0.drop_column_max_days_allowed erpnext.patches.v11_0.change_healthcare_desktop_icons erpnext.patches.v10_0.update_user_image_in_employee @@ -595,4 +595,6 @@ erpnext.patches.v11_1.woocommerce_set_creation_user erpnext.patches.v11_1.delete_bom_browser erpnext.patches.v11_1.set_salary_details_submittable erpnext.patches.v11_1.rename_depends_on_lwp -erpnext.patches.v11_1.set_missing_title_for_quotation \ No newline at end of file +erpnext.patches.v11_1.set_missing_title_for_quotation +execute:frappe.delete_doc("Report", "Inactive Items") +erpnext.patches.v11_1.delete_scheduling_tool \ No newline at end of file diff --git a/erpnext/patches/v11_1/delete_scheduling_tool.py b/erpnext/patches/v11_1/delete_scheduling_tool.py new file mode 100644 index 00000000000..b7ad28a3fd6 --- /dev/null +++ b/erpnext/patches/v11_1/delete_scheduling_tool.py @@ -0,0 +1,9 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + if frappe.db.exists("DocType", "Scheduling Tool"): + frappe.delete_doc("DocType", "Scheduling Tool", ignore_permissions=True) diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index fc58df0ffc5..b328f56ccd8 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -318,7 +318,8 @@ class Project(Document): if not self.get('deleted_task_list'): return for d in self.get('deleted_task_list'): - frappe.delete_doc("Task", d) + # unlink project + frappe.db.set_value('Task', d, 'project', '') self.deleted_task_list = [] diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py index 12302789a9b..8a469cd269b 100755 --- a/erpnext/projects/doctype/task/task.py +++ b/erpnext/projects/doctype/task/task.py @@ -157,6 +157,12 @@ class Task(NestedSet): if check_if_child_exists(self.name): throw(_("Child Task exists for this Task. You can not delete this Task.")) + if self.project: + tasks = frappe.get_doc('Project', self.project).tasks + for task in tasks: + if (task.get('task_id') == self.name): + frappe.delete_doc('Project Task', task.name) + self.update_nsm_model() def update_status(self): diff --git a/erpnext/projects/report/billing_summary.py b/erpnext/projects/report/billing_summary.py index d2a229315fd..929a13f6683 100644 --- a/erpnext/projects/report/billing_summary.py +++ b/erpnext/projects/report/billing_summary.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe from frappe import _ -from frappe.utils import time_diff_in_hours +from frappe.utils import time_diff_in_hours, flt def get_columns(): return [ @@ -43,7 +43,7 @@ def get_columns(): "width": 50 }, { - "label": _("Amount"), + "label": _("Billing Amount"), "fieldtype": "Currency", "fieldname": "amount", "width": 100 @@ -52,46 +52,53 @@ def get_columns(): def get_data(filters): data = [] - record = get_records(filters) + if(filters.from_date > filters.to_date): + frappe.msgprint(_(" From Date can not be greater than To Date")) + return data - for entries in record: + timesheets = get_timesheets(filters) + + filters.from_date = frappe.utils.get_datetime(filters.from_date) + filters.to_date = frappe.utils.add_to_date(frappe.utils.get_datetime(filters.to_date), days=1, seconds=-1) + + timesheet_details = get_timesheet_details(filters, timesheets.keys()) + + for ts, ts_details in timesheet_details.items(): total_hours = 0 - total_billable_hours = 0 + total_billing_hours = 0 total_amount = 0 - entries_exists = False - timesheet_details = get_timesheet_details(filters, entries.name) - for activity in timesheet_details: - entries_exists = True - time_start = activity.from_time - time_end = frappe.utils.add_to_date(activity.from_time, hours=activity.hours) - from_date = frappe.utils.get_datetime(filters.from_date) - to_date = frappe.utils.get_datetime(filters.to_date) + for row in ts_details: + from_time, to_time = filters.from_date, filters.to_date - if time_start <= from_date and time_end >= from_date: - total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity, - time_end, from_date, total_hours, total_billable_hours, total_amount) - elif time_start <= to_date and time_end >= to_date: - total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity, - to_date, time_start, total_hours, total_billable_hours, total_amount) - elif time_start >= from_date and time_end <= to_date: - total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity, - time_end, time_start, total_hours, total_billable_hours, total_amount) + if row.to_time < from_time or row.from_time > to_time: + continue + + if row.from_time > from_time: + from_time = row.from_time + + if row.to_time < to_time: + to_time = row.to_time + + activity_duration, billing_duration = get_billable_and_total_duration(row, from_time, to_time) + + total_hours += activity_duration + total_billing_hours += billing_duration + total_amount += billing_duration * flt(row.billing_rate) + + if total_hours: + data.append({ + "employee": timesheets.get(ts).employee, + "employee_name": timesheets.get(ts).employee_name, + "timesheet": ts, + "total_billable_hours": total_billing_hours, + "total_hours": total_hours, + "amount": total_amount + }) - row = { - "employee": entries.employee, - "employee_name": entries.employee_name, - "timesheet": entries.name, - "total_billable_hours": total_billable_hours, - "total_hours": total_hours, - "amount": total_amount - } - if entries_exists: - data.append(row) - entries_exists = False return data -def get_records(filters): +def get_timesheets(filters): record_filters = [ ["start_date", "<=", filters.to_date], ["end_date", ">=", filters.from_date], @@ -101,23 +108,39 @@ def get_records(filters): if "employee" in filters: record_filters.append(["employee", "=", filters.employee]) - return frappe.get_all("Timesheet", filters=record_filters, fields=[" * "] ) + timesheets = frappe.get_all("Timesheet", filters=record_filters, fields=["employee", "employee_name", "name"]) + timesheet_map = frappe._dict() + for d in timesheets: + timesheet_map.setdefault(d.name, d) -def get_billable_and_total_hours(activity, end, start, total_hours, total_billable_hours, total_amount): - total_hours += abs(time_diff_in_hours(end, start)) - if activity.billable: - total_billable_hours += abs(time_diff_in_hours(end, start)) - total_amount += total_billable_hours * activity.billing_rate - return total_hours, total_billable_hours, total_amount + return timesheet_map -def get_timesheet_details(filters, parent): - timesheet_details_filter = {"parent": parent} +def get_timesheet_details(filters, timesheet_list): + timesheet_details_filter = { + "parent": ["in", timesheet_list] + } if "project" in filters: timesheet_details_filter["project"] = filters.project - return frappe.get_all( + timesheet_details = frappe.get_all( "Timesheet Detail", filters = timesheet_details_filter, - fields=["*"] - ) + fields=["from_time", "to_time", "hours", "billable", "billing_hours", "billing_rate", "parent"] + ) + + timesheet_details_map = frappe._dict() + for d in timesheet_details: + timesheet_details_map.setdefault(d.parent, []).append(d) + + return timesheet_details_map + +def get_billable_and_total_duration(activity, start_time, end_time): + activity_duration = time_diff_in_hours(end_time, start_time) + billing_duration = 0.0 + if activity.billable: + billing_duration = activity.billing_hours + if activity_duration != activity.billing_hours: + billing_duration = activity_duration * activity.billing_hours / activity.hours + + return flt(activity_duration, 2), flt(billing_duration, 2) \ No newline at end of file diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js index 5869c4da4c2..6aad29183fc 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -8,9 +8,10 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) { method = "erpnext.accounts.party.get_party_details"; } if(!args) { - if(frm.doctype != "Purchase Order" && frm.doc.customer) { + if((frm.doctype != "Purchase Order" && frm.doc.customer) + || (frm.doc.party_name && in_list(['Quotation', 'Opportunity'], frm.doc.doctype))) { args = { - party: frm.doc.customer, + party: frm.doc.customer || frm.doc.party_name, party_type: "Customer", price_list: frm.doc.selling_price_list }; diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index f1a64dc8310..2f255b65471 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -189,9 +189,10 @@ def make_custom_fields(update=True): 'fieldname': 'gst_transporter_id', 'label': 'GST Transporter ID', 'fieldtype': 'Data', - 'insert_after': 'transporter_name', + 'insert_after': 'transporter', 'fetch_from': 'transporter.gst_transporter_id', - 'print_hide': 1 + 'print_hide': 1, + 'translatable': 0 }, { 'fieldname': 'mode_of_transport', @@ -199,18 +200,142 @@ def make_custom_fields(update=True): 'fieldtype': 'Select', 'options': '\nRoad\nAir\nRail\nShip', 'default': 'Road', + 'insert_after': 'transporter_name', + 'print_hide': 1, + 'translatable': 0 + }, + { + 'fieldname': 'gst_vehicle_type', + 'label': 'GST Vehicle Type', + 'fieldtype': 'Select', + 'options': 'Regular\nOver Dimensional Cargo (ODC)', + 'depends_on': 'eval:(doc.mode_of_transport === "Road")', + 'default': 'Regular', 'insert_after': 'lr_date', + 'print_hide': 1, + 'translatable': 0 + } + ] + + si_ewaybill_fields = [ + { + 'fieldname': 'transporter_info', + 'label': 'Transporter Info', + 'fieldtype': 'Section Break', + 'insert_after': 'terms', + 'collapsible': 1, + 'collapsible_depends_on': 'transporter', + 'print_hide': 1 + }, + { + 'fieldname': 'transporter', + 'label': 'Transporter', + 'fieldtype': 'Link', + 'insert_after': 'transporter_info', + 'options': 'Supplier', + 'print_hide': 1 + }, + { + 'fieldname': 'gst_transporter_id', + 'label': 'GST Transporter ID', + 'fieldtype': 'Data', + 'insert_after': 'transporter', + 'fetch_from': 'transporter.gst_transporter_id', + 'print_hide': 1, + 'translatable': 0 + }, + { + 'fieldname': 'driver', + 'label': 'Driver', + 'fieldtype': 'Link', + 'insert_after': 'gst_transporter_id', + 'options': 'Driver', + 'print_hide': 1 + }, + { + 'fieldname': 'lr_no', + 'label': 'Transport Receipt No', + 'fieldtype': 'Data', + 'insert_after': 'driver', + 'print_hide': 1, + 'translatable': 0 + }, + { + 'fieldname': 'vehicle_no', + 'label': 'Vehicle No', + 'fieldtype': 'Data', + 'insert_after': 'lr_no', + 'print_hide': 1, + 'translatable': 0 + }, + { + 'fieldname': 'distance', + 'label': 'Distance (in km)', + 'fieldtype': 'Float', + 'insert_after': 'vehicle_no', + 'print_hide': 1 + }, + { + 'fieldname': 'transporter_col_break', + 'fieldtype': 'Column Break', + 'insert_after': 'distance' + }, + { + 'fieldname': 'transporter_name', + 'label': 'Transporter Name', + 'fieldtype': 'Data', + 'insert_after': 'transporter_col_break', + 'fetch_from': 'transporter.name', + 'read_only': 1, + 'print_hide': 1, + 'translatable': 0 + }, + { + 'fieldname': 'mode_of_transport', + 'label': 'Mode of Transport', + 'fieldtype': 'Select', + 'options': '\nRoad\nAir\nRail\nShip', + 'default': 'Road', + 'insert_after': 'transporter_name', + 'print_hide': 1, + 'translatable': 0 + }, + { + 'fieldname': 'driver_name', + 'label': 'Driver Name', + 'fieldtype': 'Data', + 'insert_after': 'mode_of_transport', + 'fetch_from': 'driver.full_name', + 'print_hide': 1, + 'translatable': 0 + }, + { + 'fieldname': 'lr_date', + 'label': 'Transport Receipt Date', + 'fieldtype': 'Date', + 'insert_after': 'driver_name', + 'default': 'Today', 'print_hide': 1 }, { 'fieldname': 'gst_vehicle_type', 'label': 'GST Vehicle Type', 'fieldtype': 'Select', - 'options': '\nRegular\nOver Dimensional Cargo (ODC)', - 'default': 'Regular', + 'options': 'Regular\nOver Dimensional Cargo (ODC)', 'depends_on': 'eval:(doc.mode_of_transport === "Road")', - 'insert_after': 'mode_of_transport', - 'print_hide': 1 + 'default': 'Regular', + 'insert_after': 'lr_date', + 'print_hide': 1, + 'translatable': 0 + }, + { + 'fieldname': 'ewaybill', + 'label': 'e-Way Bill No.', + 'fieldtype': 'Data', + 'depends_on': 'eval:(doc.docstatus === 1)', + 'allow_on_submit': 1, + 'insert_after': 'project', + 'translatable': 0 } ] @@ -226,7 +351,8 @@ def make_custom_fields(update=True): 'Purchase Invoice': invoice_gst_fields + purchase_invoice_gst_fields + purchase_invoice_itc_fields, 'Purchase Order': purchase_invoice_gst_fields, 'Purchase Receipt': purchase_invoice_gst_fields, - 'Sales Invoice': invoice_gst_fields + sales_invoice_gst_fields + sales_invoice_shipping_fields, + 'Sales Invoice': (invoice_gst_fields + sales_invoice_gst_fields + + sales_invoice_shipping_fields + si_ewaybill_fields), 'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields, 'Sales Order': sales_invoice_gst_fields, 'Sales Taxes and Charges Template': inter_state_gst_field, @@ -306,7 +432,7 @@ def make_custom_fields(update=True): ] } - create_custom_fields(custom_fields, ignore_validate = frappe.flags.in_patch, update=update) + create_custom_fields(custom_fields, update=update) def make_fixtures(company=None): docs = [] diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py index 4267a94043b..c6100cf5fcf 100644 --- a/erpnext/regional/india/utils.py +++ b/erpnext/regional/india/utils.py @@ -1,5 +1,5 @@ from __future__ import unicode_literals -import frappe, re +import frappe, re, json from frappe import _ from frappe.utils import cstr, flt, date_diff, nowdate from erpnext.regional.india import states, state_numbers @@ -14,6 +14,8 @@ def validate_gstin_for_india(doc, method): if not hasattr(doc, 'gstin') or not doc.gstin: return + set_gst_state_and_state_number(doc) + doc.gstin = doc.gstin.upper().strip() if doc.gstin else "" if not doc.gstin or doc.gstin == 'NA': return @@ -27,6 +29,11 @@ def validate_gstin_for_india(doc, method): validate_gstin_check_digit(doc.gstin) + 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 set_gst_state_and_state_number(doc): if not doc.gst_state: if not doc.state: return @@ -38,11 +45,9 @@ def validate_gstin_for_india(doc, method): return 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): + +def validate_gstin_check_digit(gstin, label='GSTIN'): ''' Function to validate the check digit of the GSTIN.''' factor = 1 total = 0 @@ -55,8 +60,8 @@ def validate_gstin_check_digit(gstin): 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.")) + frappe.throw(_("Invalid {0}! The check digit validation has failed. " + + "Please ensure you've typed the {0} correctly.".format(label))) def get_itemised_tax_breakup_header(item_doctype, tax_accounts): if frappe.get_meta(item_doctype).has_field('gst_hsn_code'): @@ -64,8 +69,8 @@ def get_itemised_tax_breakup_header(item_doctype, tax_accounts): else: return [_("Item"), _("Taxable Amount")] + tax_accounts -def get_itemised_tax_breakup_data(doc): - itemised_tax = get_itemised_tax(doc.taxes) +def get_itemised_tax_breakup_data(doc, account_wise=False): + itemised_tax = get_itemised_tax(doc.taxes, with_tax_account=account_wise) itemised_taxable_amount = get_itemised_taxable_amount(doc.items) @@ -80,14 +85,17 @@ def get_itemised_tax_breakup_data(doc): for item, taxes in itemised_tax.items(): hsn_code = item_hsn_map.get(item) hsn_tax.setdefault(hsn_code, frappe._dict()) - for tax_account, tax_detail in taxes.items(): - hsn_tax[hsn_code].setdefault(tax_account, {"tax_rate": 0, "tax_amount": 0}) - hsn_tax[hsn_code][tax_account]["tax_rate"] = tax_detail.get("tax_rate") - hsn_tax[hsn_code][tax_account]["tax_amount"] += tax_detail.get("tax_amount") + for tax_desc, tax_detail in taxes.items(): + key = tax_desc + if account_wise: + key = tax_detail.get('tax_account') + hsn_tax[hsn_code].setdefault(key, {"tax_rate": 0, "tax_amount": 0}) + hsn_tax[hsn_code][key]["tax_rate"] = tax_detail.get("tax_rate") + hsn_tax[hsn_code][key]["tax_amount"] += tax_detail.get("tax_amount") # set taxable amount hsn_taxable_amount = frappe._dict() - for item, taxable_amount in itemised_taxable_amount.items(): + for item in itemised_taxable_amount: hsn_code = item_hsn_map.get(item) hsn_taxable_amount.setdefault(hsn_code, 0) hsn_taxable_amount[hsn_code] += itemised_taxable_amount.get(item) @@ -262,3 +270,276 @@ def calculate_hra_exemption_for_period(doc): exemptions["monthly_house_rent"] = monthly_rent exemptions["total_eligible_hra_exemption"] = eligible_hra return exemptions + + +def get_ewb_data(dt, dn): + if dt != 'Sales Invoice': + frappe.throw(_('e-Way Bill JSON can only be generated from Sales Invoice')) + + dn = dn.split(',') + + ewaybills = [] + for doc_name in dn: + doc = frappe.get_doc(dt, doc_name) + + validate_sales_invoice(doc) + + data = frappe._dict({ + "transporterId": "", + "TotNonAdvolVal": 0, + }) + + data.userGstin = data.fromGstin = doc.company_gstin + data.supplyType = 'O' + + if doc.invoice_type in ['Regular', 'SEZ']: + data.subSupplyType = 1 + elif doc.invoice_type in ['Export', 'Deemed Export']: + data.subSupplyType = 3 + else: + frappe.throw(_('Unsupported Invoice Type for e-Way Bill JSON generation')) + + data.docType = 'INV' + data.docDate = frappe.utils.formatdate(doc.posting_date, 'dd/mm/yyyy') + + company_address = frappe.get_doc('Address', doc.company_address) + billing_address = frappe.get_doc('Address', doc.customer_address) + + shipping_address = frappe.get_doc('Address', doc.shipping_address_name) + + data = get_address_details(data, doc, company_address, billing_address) + + data.itemList = [] + data.totalValue = doc.total + + data = get_item_list(data, doc) + + disable_rounded = frappe.db.get_single_value('Global Defaults', 'disable_rounded_total') + data.totInvValue = doc.grand_total if disable_rounded else doc.rounded_total + + data = get_transport_details(data, doc) + + fields = { + "/. -": { + 'docNo': doc.name, + 'fromTrdName': doc.company, + 'toTrdName': doc.customer_name, + 'transDocNo': doc.lr_no, + }, + "@#/,&. -": { + 'fromAddr1': company_address.address_line1, + 'fromAddr2': company_address.address_line2, + 'fromPlace': company_address.city, + 'toAddr1': shipping_address.address_line1, + 'toAddr2': shipping_address.address_line2, + 'toPlace': shipping_address.city, + 'transporterName': doc.transporter_name + } + } + + for allowed_chars, field_map in fields.items(): + for key, value in field_map.items(): + if not value: + data[key] = '' + else: + data[key] = re.sub(r'[^\w' + allowed_chars + ']', '', value) + + ewaybills.append(data) + + data = { + 'version': '1.0.1118', + 'billLists': ewaybills + } + + return data + +@frappe.whitelist() +def generate_ewb_json(dt, dn): + + data = get_ewb_data(dt, dn) + + frappe.local.response.filecontent = json.dumps(data, indent=4, sort_keys=True) + frappe.local.response.type = 'download' + + if len(data['billLists']) > 1: + doc_name = 'Bulk' + else: + doc_name = dn + + frappe.local.response.filename = '{0}_e-WayBill_Data_{1}.json'.format(doc_name, frappe.utils.random_string(5)) + + +def get_address_details(data, doc, company_address, billing_address): + data.fromPincode = validate_pincode(company_address.pincode, 'Company Address') + data.fromStateCode = data.actualFromStateCode = validate_state_code( + company_address.gst_state_number, 'Company Address') + + if not doc.billing_address_gstin or len(doc.billing_address_gstin) < 15: + data.toGstin = 'URP' + set_gst_state_and_state_number(billing_address) + else: + data.toGstin = doc.billing_address_gstin + + data.toPincode = validate_pincode(billing_address.pincode, 'Customer Address') + data.toStateCode = validate_state_code(billing_address.gst_state_number, 'Customer Address') + + if doc.customer_address != doc.shipping_address_name: + data.transType = 2 + shipping_address = frappe.get_doc('Address', doc.shipping_address_name) + set_gst_state_and_state_number(shipping_address) + data.toPincode = validate_pincode(shipping_address.pincode, 'Shipping Address') + data.actualToStateCode = validate_state_code(shipping_address.gst_state_number, 'Shipping Address') + else: + data.transType = 1 + data.actualToStateCode = data.toStateCode + shipping_address = billing_address + + return data + +def get_item_list(data, doc): + for attr in ['cgstValue', 'sgstValue', 'igstValue', 'cessValue', 'OthValue']: + data[attr] = 0 + + gst_accounts = get_gst_accounts(doc.company, account_wise=True) + tax_map = { + 'sgst_account': ['sgstRate', 'sgstValue'], + 'cgst_account': ['cgstRate', 'cgstValue'], + 'igst_account': ['igstRate', 'igstValue'], + 'cess_account': ['cessRate', 'cessValue'] + } + item_data_attrs = ['sgstRate', 'cgstRate', 'igstRate', 'cessRate', 'cessNonAdvol'] + hsn_wise_charges, hsn_taxable_amount = get_itemised_tax_breakup_data(doc, account_wise=True) + for hsn_code, taxable_amount in hsn_taxable_amount.items(): + item_data = frappe._dict() + if not hsn_code: + frappe.throw(_('GST HSN Code does not exist for one or more items')) + item_data.hsnCode = int(hsn_code) + item_data.taxableAmount = taxable_amount + item_data.qtyUnit = "" + for attr in item_data_attrs: + item_data[attr] = 0 + + for account, tax_detail in hsn_wise_charges.get(hsn_code, {}).items(): + account_type = gst_accounts.get(account, '') + for tax_acc, attrs in tax_map.items(): + if account_type == tax_acc: + item_data[attrs[0]] = tax_detail.get('tax_rate') + data[attrs[1]] += tax_detail.get('tax_amount') + break + else: + data.OthValue += tax_detail.get('tax_amount') + + data.itemList.append(item_data) + + # Tax amounts rounded to 2 decimals to avoid exceeding max character limit + for attr in ['sgstValue', 'cgstValue', 'igstValue', 'cessValue']: + data[attr] = flt(data[attr], 2) + + return data + +def validate_sales_invoice(doc): + if doc.docstatus != 1: + frappe.throw(_('e-Way Bill JSON can only be generated from submitted document')) + + if doc.is_return: + frappe.throw(_('e-Way Bill JSON cannot be generated for Sales Return as of now')) + + if doc.ewaybill: + frappe.throw(_('e-Way Bill already exists for this document')) + + reqd_fields = ['company_gstin', 'company_address', 'customer_address', + 'shipping_address_name', 'mode_of_transport', 'distance'] + + for fieldname in reqd_fields: + if not doc.get(fieldname): + frappe.throw(_('{} is required to generate e-Way Bill JSON'.format( + doc.meta.get_label(fieldname) + ))) + + if len(doc.company_gstin) < 15: + frappe.throw(_('You must be a registered supplier to generate e-Way Bill')) + +def get_transport_details(data, doc): + if doc.distance > 4000: + frappe.throw(_('Distance cannot be greater than 4000 kms')) + + data.transDistance = int(round(doc.distance)) + + transport_modes = { + 'Road': 1, + 'Rail': 2, + 'Air': 3, + 'Ship': 4 + } + + vehicle_types = { + 'Regular': 'R', + 'Over Dimensional Cargo (ODC)': 'O' + } + + data.transMode = transport_modes.get(doc.mode_of_transport) + + if doc.mode_of_transport == 'Road': + if not doc.gst_transporter_id and not doc.vehicle_no: + frappe.throw(_('Either GST Transporter ID or Vehicle No is required if Mode of Transport is Road')) + if doc.vehicle_no: + data.vehicleNo = doc.vehicle_no.replace(' ', '') + if not doc.gst_vehicle_type: + frappe.throw(_('Vehicle Type is required if Mode of Transport is Road')) + else: + data.vehicleType = vehicle_types.get(doc.gst_vehicle_type) + else: + if not doc.lr_no or not doc.lr_date: + frappe.throw(_('Transport Receipt No and Date are mandatory for your chosen Mode of Transport')) + + if doc.lr_no: + data.transDocNo = doc.lr_no + + if doc.lr_date: + data.transDocDate = frappe.utils.formatdate(doc.lr_date, 'dd/mm/yyyy') + + if doc.gst_transporter_id: + validate_gstin_check_digit(doc.gst_transporter_id, label='GST Transporter ID') + data.transporterId = doc.gst_transporter_id + + return data + + +def validate_pincode(pincode, address): + pin_not_found = "Pin Code doesn't exist for {}" + incorrect_pin = "Pin Code for {} is incorrecty formatted. It must be 6 digits (without spaces)" + + if not pincode: + frappe.throw(_(pin_not_found.format(address))) + + pincode = pincode.replace(' ', '') + if not pincode.isdigit() or len(pincode) != 6: + frappe.throw(_(incorrect_pin.format(address))) + else: + return int(pincode) + +def validate_state_code(state_code, address): + no_state_code = "GST State Code not found for {0}. Please set GST State in {0}" + if not state_code: + frappe.throw(_(no_state_code.format(address))) + else: + return int(state_code) + +def get_gst_accounts(company, account_wise=False): + gst_accounts = frappe._dict() + gst_settings_accounts = frappe.get_all("GST Account", + filters={"parent": "GST Settings", "company": company}, + fields=["cgst_account", "sgst_account", "igst_account", "cess_account"]) + + if not gst_settings_accounts: + frappe.throw(_("Please set GST Accounts in GST Settings")) + + for d in gst_settings_accounts: + for acc, val in d.items(): + if not account_wise: + gst_accounts.setdefault(acc, []).append(val) + elif val: + gst_accounts[val] = acc + + + return gst_accounts \ No newline at end of file diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py index aba12dc09ee..514ebd8c77e 100644 --- a/erpnext/regional/report/gstr_1/gstr_1.py +++ b/erpnext/regional/report/gstr_1/gstr_1.py @@ -7,6 +7,7 @@ from frappe import _ from frappe.utils import flt, formatdate from datetime import date from six import iteritems +from erpnext.regional.india.utils import get_gst_accounts def execute(filters=None): return Gstr1Report(filters).run() @@ -41,7 +42,7 @@ class Gstr1Report(object): def run(self): self.get_columns() - self.get_gst_accounts() + self.gst_accounts = get_gst_accounts(self.filters.company) self.get_invoice_data() if self.invoices: @@ -60,7 +61,7 @@ class Gstr1Report(object): for inv, items_based_on_rate in self.items_based_on_tax_rate.items(): invoice_details = self.invoices.get(inv) for rate, items in items_based_on_rate.items(): - row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items) + row = self.get_row_data_for_invoice(inv, invoice_details, rate, items) if self.filters.get("type_of_business") == "CDNR": row.append("Y" if invoice_details.posting_date <= date(2017, 7, 1) else "N") @@ -117,7 +118,7 @@ class Gstr1Report(object): for item_code, net_amount in self.invoice_items.get(invoice).items() if item_code in items]) row += [tax_rate or 0, taxable_value] - return row, taxable_value + return row def get_invoice_data(self): self.invoices = frappe._dict() @@ -239,19 +240,6 @@ class Gstr1Report(object): and frappe.db.get_value(self.doctype, invoice, "export_type") == "Without Payment of Tax": self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, items.keys()) - def get_gst_accounts(self): - self.gst_accounts = frappe._dict() - gst_settings_accounts = frappe.get_all("GST Account", - filters={"parent": "GST Settings", "company": self.filters.company}, - fields=["cgst_account", "sgst_account", "igst_account", "cess_account"]) - - if not gst_settings_accounts: - frappe.throw(_("Please set GST Accounts in GST Settings")) - - for d in gst_settings_accounts: - for acc, val in d.items(): - self.gst_accounts.setdefault(acc, []).append(val) - def get_columns(self): self.tax_columns = [ { diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js index 89811656eed..8d590a0c9d0 100644 --- a/erpnext/selling/doctype/customer/customer.js +++ b/erpnext/selling/doctype/customer/customer.js @@ -124,10 +124,5 @@ frappe.ui.form.on("Customer", { validate: function(frm) { if(frm.doc.lead_name) frappe.model.clear_doc("Lead", frm.doc.lead_name); - var total = 0; - for (var idx in frm.doc.sales_team) { - total += frm.doc.sales_team[idx].allocated_percentage; - if (total > 100) frappe.throw(__("Total contribution percentage can't exceed 100")); - } }, }); \ No newline at end of file diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index f815e5f97cb..892639403f2 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -60,6 +60,10 @@ class Customer(TransactionBase): if self.loyalty_program == customer.loyalty_program and not self.loyalty_program_tier: self.loyalty_program_tier = customer.loyalty_program_tier + if self.sales_team: + if sum([member.allocated_percentage for member in self.sales_team]) != 100: + frappe.throw(_("Total contribution percentage should be equal to 100")) + def check_customer_group_change(self): frappe.flags.customer_group_changed = False diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js index 397c853097b..5d4b8a0116f 100644 --- a/erpnext/selling/doctype/quotation/quotation.js +++ b/erpnext/selling/doctype/quotation/quotation.js @@ -42,10 +42,16 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({ this._super(doc, dt, dn); }, + party_name: function() { + var me = this; + erpnext.utils.get_party_details(this.frm, null, null, function() { + me.apply_price_list(); + }); + }, refresh: function(doc, dt, dn) { this._super(doc, dt, dn); doctype = doc.quotation_to == 'Customer' ? 'Customer':'Lead'; - frappe.dynamic_link = {doc: this.frm.doc, fieldname: doctype.toLowerCase(), doctype: doctype} + frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'party_name', doctype: doctype} var me = this; diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json index abafbbf6a16..4083b8e6d0b 100644 --- a/erpnext/selling/doctype/quotation/quotation.json +++ b/erpnext/selling/doctype/quotation/quotation.json @@ -169,8 +169,8 @@ "in_filter": 0, "in_global_search": 1, "in_list_view": 0, - "in_standard_filter": 1, - "label": "Customer/Lead", + "in_standard_filter": 0, + "label": "Party", "length": 0, "no_copy": 0, "oldfieldname": "customer", @@ -542,7 +542,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "eval:doc.quotaion_to=='Customer' && doc.party_name", + "depends_on": "", "fetch_if_empty": 0, "fieldname": "contact_person", "fieldtype": "Link", @@ -3224,7 +3224,7 @@ "istable": 0, "max_attachments": 1, "menu_index": 0, - "modified": "2019-05-02 15:16:37.394455", + "modified": "2019-05-07 14:29:22.565474", "modified_by": "Administrator", "module": "Selling", "name": "Quotation", diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py index 821a7d39ec8..c344d266949 100644 --- a/erpnext/selling/doctype/quotation/quotation.py +++ b/erpnext/selling/doctype/quotation/quotation.py @@ -212,35 +212,38 @@ def _make_sales_invoice(source_name, target_doc=None, ignore_permissions=False): return doclist def _make_customer(source_name, ignore_permissions=False): - quotation = frappe.db.get_value("Quotation", source_name, ["order_type", "party_name", "customer_name"]) - if quotation and quotation[1] and not quotation[2]: - lead_name = quotation[1] - customer_name = frappe.db.get_value("Customer", {"lead_name": lead_name}, - ["name", "customer_name"], as_dict=True) - if not customer_name: - from erpnext.crm.doctype.lead.lead import _make_customer - customer_doclist = _make_customer(lead_name, ignore_permissions=ignore_permissions) - customer = frappe.get_doc(customer_doclist) - customer.flags.ignore_permissions = ignore_permissions - if quotation[1] == "Shopping Cart": - customer.customer_group = frappe.db.get_value("Shopping Cart Settings", None, - "default_customer_group") + quotation = frappe.db.get_value("Quotation", + source_name, ["order_type", "party_name", "customer_name"], as_dict=1) - try: - customer.insert() - return customer - except frappe.NameError: - if frappe.defaults.get_global_default('cust_master_name') == "Customer Name": - customer.run_method("autoname") - customer.name += "-" + lead_name + if quotation and quotation.get('party_name'): + if not frappe.db.exists("Customer", quotation.get("party_name")): + lead_name = quotation.get("party_name") + customer_name = frappe.db.get_value("Customer", {"lead_name": lead_name}, + ["name", "customer_name"], as_dict=True) + if not customer_name: + from erpnext.crm.doctype.lead.lead import _make_customer + customer_doclist = _make_customer(lead_name, ignore_permissions=ignore_permissions) + customer = frappe.get_doc(customer_doclist) + customer.flags.ignore_permissions = ignore_permissions + if quotation.get("party_name") == "Shopping Cart": + customer.customer_group = frappe.db.get_value("Shopping Cart Settings", None, + "default_customer_group") + + try: customer.insert() return customer - else: - raise - except frappe.MandatoryError: - frappe.local.message_log = [] - frappe.throw(_("Please create Customer from Lead {0}").format(lead_name)) + except frappe.NameError: + if frappe.defaults.get_global_default('cust_master_name') == "Customer Name": + customer.run_method("autoname") + customer.name += "-" + lead_name + customer.insert() + return customer + else: + raise + except frappe.MandatoryError: + frappe.local.message_log = [] + frappe.throw(_("Please create Customer from Lead {0}").format(lead_name)) + else: + return customer_name else: - return customer_name - elif quotation and quotation[1]: - return frappe.get_doc("Customer",quotation[1]) + return frappe.get_doc("Customer", quotation.get("party_name")) diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index dbd7c4149f3..d03cca050d2 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -22,7 +22,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "details", "fieldtype": "Section Break", "hidden": 0, @@ -47,7 +46,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -55,7 +54,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "company_name", "fieldtype": "Data", "hidden": 0, @@ -81,7 +79,7 @@ "set_only_once": 0, "translatable": 0, "unique": 1 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -90,7 +88,6 @@ "collapsible": 0, "columns": 0, "description": "", - "fetch_if_empty": 0, "fieldname": "abbr", "fieldtype": "Data", "hidden": 0, @@ -116,7 +113,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -124,8 +121,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "eval:!doc.__islocal && in_list(frappe.user_roles, \"System Manager\")", - "fetch_if_empty": 0, + "depends_on": "eval:!doc.__islocal && in_list(frappe.user_roles, \"System Manager\")", "fieldname": "change_abbr", "fieldtype": "Button", "hidden": 0, @@ -149,7 +145,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -157,7 +153,6 @@ "bold": 1, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "is_group", "fieldtype": "Check", "hidden": 0, @@ -182,7 +177,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -190,7 +185,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "default_finance_book", "fieldtype": "Link", "hidden": 0, @@ -216,7 +210,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -224,7 +218,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "cb0", "fieldtype": "Column Break", "hidden": 0, @@ -247,7 +240,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -255,7 +248,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "domain", "fieldtype": "Link", "hidden": 0, @@ -280,7 +272,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -288,7 +280,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "parent_company", "fieldtype": "Link", "hidden": 0, @@ -314,7 +305,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -322,7 +313,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "sb_about", "fieldtype": "Section Break", "hidden": 0, @@ -347,7 +337,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -355,7 +345,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "company_logo", "fieldtype": "Attach Image", "hidden": 0, @@ -380,7 +369,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -388,7 +377,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "company_description", "fieldtype": "Text Editor", "hidden": 0, @@ -413,7 +401,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -421,7 +409,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "sales_settings", "fieldtype": "Section Break", "hidden": 0, @@ -446,7 +433,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -454,7 +441,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "sales_monthly_history", "fieldtype": "Small Text", "hidden": 1, @@ -479,7 +465,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -487,7 +473,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "transactions_annual_history", "fieldtype": "Code", "hidden": 1, @@ -512,7 +497,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -520,7 +505,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "monthly_sales_target", "fieldtype": "Currency", "hidden": 0, @@ -546,7 +530,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -554,7 +538,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_goals", "fieldtype": "Column Break", "hidden": 0, @@ -578,7 +561,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -586,7 +569,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "total_monthly_sales", "fieldtype": "Currency", "hidden": 0, @@ -612,7 +594,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -620,7 +602,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "charts_section", "fieldtype": "Section Break", "hidden": 0, @@ -644,7 +625,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -652,7 +633,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "default_currency", "fieldtype": "Link", "hidden": 0, @@ -677,7 +657,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -685,7 +665,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "default_letter_head", "fieldtype": "Link", "hidden": 0, @@ -711,7 +690,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -719,7 +698,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "default_holiday_list", "fieldtype": "Link", "hidden": 0, @@ -745,7 +723,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -753,7 +731,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "standard_working_hours", "fieldtype": "Float", "hidden": 0, @@ -778,7 +755,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -786,7 +763,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "default_terms", "fieldtype": "Link", "hidden": 0, @@ -811,7 +787,40 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "default_warehouse_for_sales_return", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Default warehouse for Sales Return", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -819,7 +828,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_10", "fieldtype": "Column Break", "hidden": 0, @@ -843,7 +851,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -851,7 +859,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "country", "fieldtype": "Link", "hidden": 0, @@ -876,7 +883,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -884,7 +891,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "create_chart_of_accounts_based_on", "fieldtype": "Select", "hidden": 0, @@ -910,7 +916,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -919,7 +925,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Standard Template\"", - "fetch_if_empty": 0, "fieldname": "chart_of_accounts", "fieldtype": "Select", "hidden": 0, @@ -945,7 +950,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -954,7 +959,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Existing Company\"", - "fetch_if_empty": 0, "fieldname": "existing_company", "fieldtype": "Link", "hidden": 0, @@ -980,7 +984,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -988,7 +992,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "tax_id", "fieldtype": "Data", "hidden": 0, @@ -1013,7 +1016,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1021,7 +1024,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "date_of_establishment", "fieldtype": "Date", "hidden": 0, @@ -1046,7 +1048,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1054,7 +1056,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "default_settings", "fieldtype": "Section Break", "hidden": 0, @@ -1079,7 +1080,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1088,7 +1089,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fetch_if_empty": 0, "fieldname": "default_bank_account", "fieldtype": "Link", "hidden": 0, @@ -1115,7 +1115,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1124,7 +1124,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fetch_if_empty": 0, "fieldname": "default_cash_account", "fieldtype": "Link", "hidden": 0, @@ -1149,7 +1148,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1158,7 +1157,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fetch_if_empty": 0, "fieldname": "default_receivable_account", "fieldtype": "Link", "hidden": 0, @@ -1185,7 +1183,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1193,7 +1191,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "round_off_account", "fieldtype": "Link", "hidden": 0, @@ -1219,7 +1216,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1227,7 +1224,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "round_off_cost_center", "fieldtype": "Link", "hidden": 0, @@ -1253,7 +1249,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1261,7 +1257,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "write_off_account", "fieldtype": "Link", "hidden": 0, @@ -1287,7 +1282,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1295,7 +1290,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "discount_allowed_account", "fieldtype": "Link", "hidden": 0, @@ -1321,7 +1315,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1329,7 +1323,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "discount_received_account", "fieldtype": "Link", "hidden": 0, @@ -1355,7 +1348,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1363,7 +1356,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "exchange_gain_loss_account", "fieldtype": "Link", "hidden": 0, @@ -1389,7 +1381,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1397,7 +1389,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "unrealized_exchange_gain_loss_account", "fieldtype": "Link", "hidden": 0, @@ -1423,7 +1414,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1431,7 +1422,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break0", "fieldtype": "Column Break", "hidden": 0, @@ -1456,41 +1446,7 @@ "translatable": 0, "unique": 0, "width": "50%" - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.parent_company", - "fetch_if_empty": 0, - "fieldname": "allow_account_creation_against_child_company", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Allow Account Creation Against Child Company", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1499,7 +1455,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fetch_if_empty": 0, "fieldname": "default_payable_account", "fieldtype": "Link", "hidden": 0, @@ -1526,7 +1481,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1534,7 +1489,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "default_employee_advance_account", "fieldtype": "Link", "hidden": 0, @@ -1560,7 +1514,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1569,7 +1523,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fetch_if_empty": 0, "fieldname": "default_expense_account", "fieldtype": "Link", "hidden": 0, @@ -1594,7 +1547,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1603,7 +1556,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fetch_if_empty": 0, "fieldname": "default_income_account", "fieldtype": "Link", "hidden": 0, @@ -1628,7 +1580,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1637,7 +1589,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fetch_if_empty": 0, "fieldname": "default_deferred_revenue_account", "fieldtype": "Link", "hidden": 0, @@ -1663,7 +1614,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1672,7 +1623,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fetch_if_empty": 0, "fieldname": "default_deferred_expense_account", "fieldtype": "Link", "hidden": 0, @@ -1698,7 +1648,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1707,7 +1657,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fetch_if_empty": 0, "fieldname": "default_payroll_payable_account", "fieldtype": "Link", "hidden": 0, @@ -1733,7 +1682,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1742,7 +1691,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fetch_if_empty": 0, "fieldname": "default_expense_claim_payable_account", "fieldtype": "Link", "hidden": 0, @@ -1768,7 +1716,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1776,7 +1724,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "section_break_22", "fieldtype": "Section Break", "hidden": 0, @@ -1800,7 +1747,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1809,7 +1756,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fetch_if_empty": 0, "fieldname": "cost_center", "fieldtype": "Link", "hidden": 0, @@ -1834,7 +1780,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1842,7 +1788,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_26", "fieldtype": "Column Break", "hidden": 0, @@ -1866,7 +1811,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1875,7 +1820,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fetch_if_empty": 0, "fieldname": "credit_limit", "fieldtype": "Currency", "hidden": 0, @@ -1902,7 +1846,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1911,7 +1855,6 @@ "collapsible": 0, "columns": 0, "depends_on": "", - "fetch_if_empty": 0, "fieldname": "payment_terms", "fieldtype": "Link", "hidden": 0, @@ -1937,7 +1880,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1946,7 +1889,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fetch_if_empty": 0, "fieldname": "auto_accounting_for_stock_settings", "fieldtype": "Section Break", "hidden": 0, @@ -1970,7 +1912,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1979,7 +1921,6 @@ "collapsible": 0, "columns": 0, "default": "1", - "fetch_if_empty": 0, "fieldname": "enable_perpetual_inventory", "fieldtype": "Check", "hidden": 0, @@ -2004,7 +1945,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2012,7 +1953,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "default_inventory_account", "fieldtype": "Link", "hidden": 0, @@ -2038,7 +1978,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2046,7 +1986,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "stock_adjustment_account", "fieldtype": "Link", "hidden": 0, @@ -2071,7 +2010,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2079,7 +2018,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_32", "fieldtype": "Column Break", "hidden": 0, @@ -2103,7 +2041,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2111,7 +2049,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "stock_received_but_not_billed", "fieldtype": "Link", "hidden": 0, @@ -2136,7 +2073,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2144,7 +2081,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "expenses_included_in_valuation", "fieldtype": "Link", "hidden": 0, @@ -2169,7 +2105,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2177,7 +2113,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "fixed_asset_depreciation_settings", "fieldtype": "Section Break", "hidden": 0, @@ -2202,7 +2137,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2210,7 +2145,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "accumulated_depreciation_account", "fieldtype": "Link", "hidden": 0, @@ -2236,7 +2170,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2244,7 +2178,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "depreciation_expense_account", "fieldtype": "Link", "hidden": 0, @@ -2270,7 +2203,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2278,7 +2211,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "series_for_depreciation_entry", "fieldtype": "Data", "hidden": 0, @@ -2303,7 +2235,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2311,7 +2243,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "expenses_included_in_asset_valuation", "fieldtype": "Link", "hidden": 0, @@ -2337,7 +2268,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2345,7 +2276,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_40", "fieldtype": "Column Break", "hidden": 0, @@ -2369,7 +2299,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2377,7 +2307,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "disposal_account", "fieldtype": "Link", "hidden": 0, @@ -2403,7 +2332,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2411,7 +2340,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "depreciation_cost_center", "fieldtype": "Link", "hidden": 0, @@ -2437,7 +2365,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2445,7 +2373,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "capital_work_in_progress_account", "fieldtype": "Link", "hidden": 0, @@ -2471,7 +2398,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2479,7 +2406,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "asset_received_but_not_billed", "fieldtype": "Link", "hidden": 0, @@ -2505,7 +2431,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2513,7 +2439,6 @@ "bold": 0, "collapsible": 1, "columns": 0, - "fetch_if_empty": 0, "fieldname": "budget_detail", "fieldtype": "Section Break", "hidden": 0, @@ -2538,7 +2463,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2546,7 +2471,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "exception_budget_approver_role", "fieldtype": "Link", "hidden": 0, @@ -2572,7 +2496,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2581,7 +2505,6 @@ "collapsible": 0, "columns": 0, "description": "For reference only.", - "fetch_if_empty": 0, "fieldname": "company_info", "fieldtype": "Section Break", "hidden": 0, @@ -2605,7 +2528,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2613,7 +2536,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "date_of_incorporation", "fieldtype": "Date", "hidden": 0, @@ -2638,7 +2560,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2646,7 +2568,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "address_html", "fieldtype": "HTML", "hidden": 0, @@ -2670,7 +2591,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2678,7 +2599,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break1", "fieldtype": "Column Break", "hidden": 0, @@ -2703,7 +2623,7 @@ "translatable": 0, "unique": 0, "width": "50%" - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2712,7 +2632,6 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:doc.date_of_incorporation", - "fetch_if_empty": 0, "fieldname": "date_of_commencement", "fieldtype": "Date", "hidden": 0, @@ -2737,7 +2656,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2745,7 +2664,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "phone_no", "fieldtype": "Data", "hidden": 0, @@ -2772,7 +2690,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2780,7 +2698,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "fax", "fieldtype": "Data", "hidden": 0, @@ -2807,7 +2724,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2815,7 +2732,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "email", "fieldtype": "Data", "hidden": 0, @@ -2842,7 +2758,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2850,7 +2766,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "website", "fieldtype": "Data", "hidden": 0, @@ -2876,7 +2791,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2885,7 +2800,6 @@ "collapsible": 0, "columns": 0, "description": "", - "fetch_if_empty": 0, "fieldname": "registration_info", "fieldtype": "Section Break", "hidden": 0, @@ -2911,7 +2825,7 @@ "translatable": 0, "unique": 0, "width": "50%" - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2920,7 +2834,6 @@ "collapsible": 0, "columns": 0, "description": "Company registration numbers for your reference. Tax numbers etc.", - "fetch_if_empty": 0, "fieldname": "registration_details", "fieldtype": "Code", "hidden": 0, @@ -2946,7 +2859,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2954,7 +2867,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "delete_company_transactions", "fieldtype": "Button", "hidden": 0, @@ -2979,7 +2891,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2987,7 +2899,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "lft", "fieldtype": "Int", "hidden": 1, @@ -3012,7 +2923,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -3020,7 +2931,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "rgt", "fieldtype": "Int", "hidden": 1, @@ -3045,7 +2955,7 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -3053,7 +2963,6 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_if_empty": 0, "fieldname": "old_parent", "fieldtype": "Data", "hidden": 1, @@ -3093,7 +3002,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2019-03-26 17:15:50.390548", + "modified": "2019-02-26 13:24:55.386120", "modified_by": "Administrator", "module": "Setup", "name": "Company", @@ -3117,7 +3026,7 @@ "share": 1, "submit": 0, "write": 1 - }, + }, { "amend": 0, "cancel": 0, @@ -3136,7 +3045,7 @@ "share": 0, "submit": 0, "write": 0 - }, + }, { "amend": 0, "cancel": 0, @@ -3155,7 +3064,7 @@ "share": 0, "submit": 0, "write": 0 - }, + }, { "amend": 0, "cancel": 0, @@ -3174,7 +3083,7 @@ "share": 0, "submit": 0, "write": 0 - }, + }, { "amend": 0, "cancel": 0, @@ -3193,7 +3102,7 @@ "share": 0, "submit": 0, "write": 0 - }, + }, { "amend": 0, "cancel": 0, @@ -3212,7 +3121,7 @@ "share": 0, "submit": 0, "write": 0 - }, + }, { "amend": 0, "cancel": 0, diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py index ef0a317d657..8ea7c44c07f 100644 --- a/erpnext/stock/doctype/batch/batch.py +++ b/erpnext/stock/doctype/batch/batch.py @@ -9,6 +9,7 @@ from frappe.model.naming import make_autoname, revert_series_if_last from frappe.utils import flt, cint from frappe.utils.jinja import render_template from frappe.utils.data import add_days +from six import string_types class UnableToSelectBatchError(frappe.ValidationError): pass @@ -60,7 +61,7 @@ def _make_naming_series_key(prefix): :param prefix: Naming series prefix gotten from Stock Settings :return: The derived key. If no prefix is given, an empty string is returned """ - if not unicode(prefix): + if not isinstance(prefix, string_types): return '' else: return prefix.upper() + '.#####' @@ -86,7 +87,7 @@ class Batch(Document): def autoname(self): """Generate random ID for batch if not specified""" if not self.batch_id: - create_new_batch, batch_number_series = frappe.db.get_value('Item', self.item, + create_new_batch, batch_number_series = frappe.db.get_value('Item', self.item, ['create_new_batch', 'batch_number_series']) if create_new_batch: diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index dc9c4fc3fe8..d1815c996c5 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -1068,7 +1068,7 @@ class StockEntry(StockController): frappe.MappingMismatchError) def validate_batch(self): - if self.purpose in ["Material Transfer for Manufacture", "Manufacture", "Repack", "Subcontract", "Material Issue"]: + if self.purpose in ["Material Transfer for Manufacture", "Manufacture", "Repack", "Subcontract"]: for item in self.get("items"): if item.batch_no: disabled = frappe.db.get_value("Batch", item.batch_no, "disabled")