From 389cd6ad63f71f24069eb5a2c05e4f107768ca21 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 19 Feb 2019 19:18:07 +0530 Subject: [PATCH 01/19] fix: stop button not working in material request --- erpnext/stock/doctype/material_request/material_request.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js index 2b0ed38e93..cb4afef321 100644 --- a/erpnext/stock/doctype/material_request/material_request.js +++ b/erpnext/stock/doctype/material_request/material_request.js @@ -85,7 +85,7 @@ frappe.ui.form.on('Material Request', { // stop frm.add_custom_button(__('Stop'), - () => frm.events.update_status(frm, 'Stop')); + () => frm.events.update_status(frm, 'Stopped')); } } From f4049f9dfd32f591915699791780c2a413723d5e Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 19 Feb 2019 19:46:14 +0530 Subject: [PATCH 02/19] fix: user progress issue --- erpnext/setup/doctype/setup_progress/setup_progress.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/setup/doctype/setup_progress/setup_progress.py b/erpnext/setup/doctype/setup_progress/setup_progress.py index 9187eb7996..e1402f5844 100644 --- a/erpnext/setup/doctype/setup_progress/setup_progress.py +++ b/erpnext/setup/doctype/setup_progress/setup_progress.py @@ -16,8 +16,9 @@ def get_setup_progress(): return frappe.local.setup_progress def get_action_completed_state(action_name): - return [d.is_completed for d in get_setup_progress().actions - if d.action_name == action_name][0] + for d in get_setup_progress().actions: + if d.action_name == action_name: + return d.is_completed def update_action_completed_state(action_name): action_table_doc = [d for d in get_setup_progress().actions From 942c894f93572ea64cee635f76563d0bc4e77b2b Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Tue, 19 Feb 2019 19:51:23 +0530 Subject: [PATCH 03/19] fix: fetch item name in item dashboard --- erpnext/stock/dashboard/item_dashboard.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/dashboard/item_dashboard.py b/erpnext/stock/dashboard/item_dashboard.py index 6242fa767e..487c765659 100644 --- a/erpnext/stock/dashboard/item_dashboard.py +++ b/erpnext/stock/dashboard/item_dashboard.py @@ -28,7 +28,7 @@ def get_data(item_code=None, warehouse=None, item_group=None, # user does not have access on warehouse return [] - return frappe.db.get_all('Bin', fields=['item_code', 'warehouse', 'projected_qty', + items = frappe.db.get_all('Bin', fields=['item_code', 'warehouse', 'projected_qty', 'reserved_qty', 'reserved_qty_for_production', 'reserved_qty_for_sub_contract', 'actual_qty', 'valuation_rate'], or_filters={ 'projected_qty': ['!=', 0], @@ -41,3 +41,10 @@ def get_data(item_code=None, warehouse=None, item_group=None, order_by=sort_by + ' ' + sort_order, limit_start=start, limit_page_length='21') + + for item in items: + item.update({ + 'item_name': frappe.get_cached_value("Item", item.item_code, 'item_name') + }) + + return items From 7e02e1c3cd8657903e449b66207bd22480c2f490 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 19 Feb 2019 22:53:31 +0530 Subject: [PATCH 04/19] fix: not able to cancel maintenance visit --- .../maintenance_visit/maintenance_visit.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py index 6d082bd200..2f2ad00e02 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py +++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py @@ -41,12 +41,19 @@ class MaintenanceVisit(TransactionBase): work_done = nm and nm[0][3] or '' else: status = 'Open' - mntc_date = '' - service_person = '' - work_done = '' + mntc_date = None + service_person = None + work_done = None - frappe.db.sql("update `tabWarranty Claim` set resolution_date=%s, resolved_by=%s, resolution_details=%s, status=%s where name =%s",(mntc_date,service_person,work_done,status,d.prevdoc_docname)) + wc_doc = frappe.get_doc('Warranty Claim', d.prevdoc_docname) + wc_doc.update({ + 'resolution_date': mntc_date, + 'resolved_by': service_person, + 'resolution_details': work_done, + 'status': status + }) + wc_doc.db_update() def check_if_last_visit(self): """check if last maintenance visit against same sales order/ Warranty Claim""" From 3bf0acbac6b59d0b05082fbeea4e542965b45e43 Mon Sep 17 00:00:00 2001 From: Gaurav Naik Date: Wed, 20 Feb 2019 12:08:53 +0530 Subject: [PATCH 05/19] fix(regional,italy): renamed validate hook for address (#16732) --- erpnext/hooks.py | 2 +- erpnext/regional/italy/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 30f51c9957..e98ca4b597 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -210,7 +210,7 @@ doc_events = { "on_trash": "erpnext.regional.check_deletion_permission" }, 'Address': { - 'validate': ['erpnext.regional.india.utils.validate_gstin_for_india', 'erpnext.regional.italy.utils.validate_address'] + 'validate': ['erpnext.regional.india.utils.validate_gstin_for_india', 'erpnext.regional.italy.utils.set_state_code'] }, ('Sales Invoice', 'Purchase Invoice', 'Delivery Note'): { 'validate': 'erpnext.regional.india.utils.set_place_of_supply' diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py index c2dc24dd45..51aa93aebe 100644 --- a/erpnext/regional/italy/utils.py +++ b/erpnext/regional/italy/utils.py @@ -285,7 +285,7 @@ def get_progressive_name_and_number(doc): return progressive_name, progressive_number -def validate_address(doc, method): +def set_state_code(doc, method): if not (hasattr(doc, "state_code") and doc.country in ["Italy", "Italia", "Italian Republic", "Repubblica Italiana"]): return From d48393541d200d02cd7b8f5f07f5370bf7942241 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Wed, 20 Feb 2019 12:31:25 +0550 Subject: [PATCH 06/19] bumped to version 11.1.8 --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 8064ec438a..24cc8ea79c 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.7' +__version__ = '11.1.8' def get_default_company(user=None): '''Get default company for user''' From ef3f864123e86dd6bec4a4ca7b2059472f6af7ee Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Wed, 20 Feb 2019 15:47:06 +0530 Subject: [PATCH 07/19] fix: not able to submit purchase order (#16735) --- erpnext/regional/italy/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py index 51aa93aebe..7e0386a93b 100644 --- a/erpnext/regional/italy/utils.py +++ b/erpnext/regional/italy/utils.py @@ -183,6 +183,9 @@ def get_invoice_summary(items, taxes): #Preflight for successful e-invoice export. def sales_invoice_validate(doc): #Validate company + if doc.doctype != 'Sales Invoice': + return + if not doc.company_address: frappe.throw(_("Please set an Address on the Company '%s'" % doc.company), title=_("E-Invoicing Information Missing")) else: From 9fcfc63f77b4089597075d6bd3463c3219ae98f6 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Wed, 20 Feb 2019 13:03:50 +0530 Subject: [PATCH 08/19] fix: reload report doc and indentation fixes --- .../v11_0/make_italian_localization_fields.py | 30 +-- erpnext/regional/italy/setup.py | 248 +++++++++--------- 2 files changed, 139 insertions(+), 139 deletions(-) diff --git a/erpnext/patches/v11_0/make_italian_localization_fields.py b/erpnext/patches/v11_0/make_italian_localization_fields.py index cb65f23ab1..fa77149752 100644 --- a/erpnext/patches/v11_0/make_italian_localization_fields.py +++ b/erpnext/patches/v11_0/make_italian_localization_fields.py @@ -8,21 +8,21 @@ import frappe def execute(): + company = frappe.get_all('Company', filters = {'country': 'Italy'}) + if not company: + return - company = frappe.get_all('Company', filters = {'country': 'Italy'}) - if not company: - return + frappe.reload_doc('regional', 'report', 'electronic_invoice_register') + make_custom_fields() + setup_report() - make_custom_fields() - setup_report() + # Set state codes + condition = "" + for state, code in state_codes.items(): + condition += " when '{0}' then '{1}'".format(frappe.db.escape(state), frappe.db.escape(code)) - # Set state codes - condition = "" - for state, code in state_codes.items(): - condition += " when '{0}' then '{1}'".format(frappe.db.escape(state), frappe.db.escape(code)) - - if condition: - frappe.db.sql(""" - UPDATE tabAddress set state_code = (case state {condition} end) - WHERE country in ('Italy', 'Italia', 'Italian Republic', 'Repubblica Italiana') - """.format(condition=condition)) + if condition: + frappe.db.sql(""" + UPDATE tabAddress set state_code = (case state {condition} end) + WHERE country in ('Italy', 'Italia', 'Italian Republic', 'Repubblica Italiana') + """.format(condition=condition)) diff --git a/erpnext/regional/italy/setup.py b/erpnext/regional/italy/setup.py index 3e9d7a29e5..a9de2d1f18 100644 --- a/erpnext/regional/italy/setup.py +++ b/erpnext/regional/italy/setup.py @@ -10,12 +10,12 @@ from frappe.custom.doctype.custom_field.custom_field import create_custom_fields from erpnext.regional.italy import fiscal_regimes, tax_exemption_reasons, mode_of_payment_codes, vat_collectability_options def setup(company=None, patch=True): - make_custom_fields() - setup_report() + make_custom_fields() + setup_report() def make_custom_fields(update=True): - invoice_item_fields = [ - dict(fieldname='tax_rate', label='Tax Rate', + invoice_item_fields = [ + dict(fieldname='tax_rate', label='Tax Rate', fieldtype='Float', insert_after='description', print_hide=1, hidden=1, read_only=1), dict(fieldname='tax_amount', label='Tax Amount', @@ -24,135 +24,135 @@ def make_custom_fields(update=True): dict(fieldname='total_amount', label='Total Amount', fieldtype='Currency', insert_after='tax_amount', print_hide=1, hidden=1, read_only=1, options="currency") - ] + ] - custom_fields = { - 'Company': [ - dict(fieldname='sb_e_invoicing', label='E-Invoicing', - fieldtype='Section Break', insert_after='date_of_establishment', print_hide=1), - dict(fieldname='fiscal_regime', label='Fiscal Regime', - fieldtype='Select', insert_after='sb_e_invoicing', print_hide=1, - options="\n".join(map(lambda x: x.decode('utf-8'), fiscal_regimes))), - dict(fieldname='fiscal_code', label='Fiscal Code', fieldtype='Data', insert_after='fiscal_regime', print_hide=1, - description=_("Applicable if the company is an Individual or a Proprietorship")), - dict(fieldname='vat_collectability', label='VAT Collectability', - fieldtype='Select', insert_after='fiscal_code', print_hide=1, - options="\n".join(map(lambda x: x.decode('utf-8'), vat_collectability_options))), - dict(fieldname='cb_e_invoicing1', fieldtype='Column Break', insert_after='vat_collectability', print_hide=1), - dict(fieldname='registrar_office_province', label='Province of the Registrar Office', - fieldtype='Data', insert_after='cb_e_invoicing1', print_hide=1, length=2), - dict(fieldname='registration_number', label='Registration Number', - fieldtype='Data', insert_after='registrar_office_province', print_hide=1, length=20), - dict(fieldname='share_capital_amount', label='Share Capital', - fieldtype='Currency', insert_after='registration_number', print_hide=1, - description=_('Applicable if the company is SpA, SApA or SRL')), - dict(fieldname='no_of_members', label='No of Members', - fieldtype='Select', insert_after='share_capital_amount', print_hide=1, - options="\nSU-Socio Unico\nSM-Piu Soci", description=_("Applicable if the company is a limited liability company")), - dict(fieldname='liquidation_state', label='Liquidation State', - fieldtype='Select', insert_after='no_of_members', print_hide=1, - options="\nLS-In Liquidazione\nLN-Non in Liquidazione") - ], - 'Sales Taxes and Charges': [ - dict(fieldname='tax_exemption_reason', label='Tax Exemption Reason', - fieldtype='Select', insert_after='included_in_print_rate', print_hide=1, - depends_on='eval:doc.charge_type!="Actual" && doc.rate==0.0', - options="\n" + "\n".join(map(lambda x: x.decode('utf-8'), tax_exemption_reasons))), - dict(fieldname='tax_exemption_law', label='Tax Exempt Under', - fieldtype='Text', insert_after='tax_exemption_reason', print_hide=1, - depends_on='eval:doc.charge_type!="Actual" && doc.rate==0.0') - ], - 'Customer': [ - dict(fieldname='fiscal_code', label='Fiscal Code', fieldtype='Data', insert_after='tax_id', print_hide=1), - dict(fieldname='recipient_code', label='Recipient Code', - fieldtype='Data', insert_after='fiscal_code', print_hide=1, default="0000000"), - dict(fieldname='pec', label='Recipient PEC', - fieldtype='Data', insert_after='fiscal_code', print_hide=1), - dict(fieldname='is_public_administration', label='Is Public Administration', - fieldtype='Check', insert_after='is_internal_customer', print_hide=1, - description=_("Set this if the customer is a Public Administration company."), - depends_on='eval:doc.customer_type=="Company"'), - dict(fieldname='first_name', label='First Name', fieldtype='Data', - insert_after='salutation', print_hide=1, depends_on='eval:doc.customer_type!="Company"'), - dict(fieldname='last_name', label='Last Name', fieldtype='Data', - insert_after='first_name', print_hide=1, depends_on='eval:doc.customer_type!="Company"') - ], - 'Mode of Payment': [ - dict(fieldname='mode_of_payment_code', label='Code', - fieldtype='Select', insert_after='included_in_print_rate', print_hide=1, - options="\n".join(map(lambda x: x.decode('utf-8'), mode_of_payment_codes))) - ], - 'Payment Schedule': [ - dict(fieldname='mode_of_payment_code', label='Code', - fieldtype='Select', insert_after='mode_of_payment', print_hide=1, - options="\n".join(map(lambda x: x.decode('utf-8'), mode_of_payment_codes)), - fetch_from="mode_of_payment.mode_of_payment_code", read_only=1), - dict(fieldname='bank_account', label='Bank Account', - fieldtype='Link', insert_after='mode_of_payment_code', print_hide=1, - options="Bank Account"), - dict(fieldname='bank_account_name', label='Bank Account Name', - fieldtype='Data', insert_after='bank_account', print_hide=1, - fetch_from="bank_account.account_name", read_only=1), - dict(fieldname='bank_account_no', label='Bank Account No', - fieldtype='Data', insert_after='bank_account_name', print_hide=1, - fetch_from="bank_account.bank_account_no", read_only=1), - dict(fieldname='bank_account_iban', label='IBAN', - fieldtype='Data', insert_after='bank_account_name', print_hide=1, - fetch_from="bank_account.iban", read_only=1), - ], - "Sales Invoice": [ - dict(fieldname='vat_collectability', label='VAT Collectability', - fieldtype='Select', insert_after='taxes_and_charges', print_hide=1, - options="\n".join(map(lambda x: x.decode('utf-8'), vat_collectability_options)), - fetch_from="company.vat_collectability"), - dict(fieldname='sb_e_invoicing_reference', label='E-Invoicing', - fieldtype='Section Break', insert_after='pos_total_qty', print_hide=1), - dict(fieldname='company_tax_id', label='Company Tax ID', - fieldtype='Data', insert_after='sb_e_invoicing_reference', print_hide=1, read_only=1, - fetch_from="company.tax_id"), - dict(fieldname='company_fiscal_code', label='Company Fiscal Code', - fieldtype='Data', insert_after='company_tax_id', print_hide=1, read_only=1, - fetch_from="company.fiscal_code"), - dict(fieldname='company_fiscal_regime', label='Company Fiscal Regime', - fieldtype='Data', insert_after='company_fiscal_code', print_hide=1, read_only=1, - fetch_from="company.fiscal_regime"), - dict(fieldname='cb_e_invoicing_reference', fieldtype='Column Break', - insert_after='company_fiscal_regime', print_hide=1), - dict(fieldname='customer_fiscal_code', label='Customer Fiscal Code', - fieldtype='Data', insert_after='cb_e_invoicing_reference', read_only=1, - fetch_from="customer.fiscal_code"), - ], - 'Purchase Invoice Item': invoice_item_fields, + custom_fields = { + 'Company': [ + dict(fieldname='sb_e_invoicing', label='E-Invoicing', + fieldtype='Section Break', insert_after='date_of_establishment', print_hide=1), + dict(fieldname='fiscal_regime', label='Fiscal Regime', + fieldtype='Select', insert_after='sb_e_invoicing', print_hide=1, + options="\n".join(map(lambda x: x.decode('utf-8'), fiscal_regimes))), + dict(fieldname='fiscal_code', label='Fiscal Code', fieldtype='Data', insert_after='fiscal_regime', print_hide=1, + description=_("Applicable if the company is an Individual or a Proprietorship")), + dict(fieldname='vat_collectability', label='VAT Collectability', + fieldtype='Select', insert_after='fiscal_code', print_hide=1, + options="\n".join(map(lambda x: x.decode('utf-8'), vat_collectability_options))), + dict(fieldname='cb_e_invoicing1', fieldtype='Column Break', insert_after='vat_collectability', print_hide=1), + dict(fieldname='registrar_office_province', label='Province of the Registrar Office', + fieldtype='Data', insert_after='cb_e_invoicing1', print_hide=1, length=2), + dict(fieldname='registration_number', label='Registration Number', + fieldtype='Data', insert_after='registrar_office_province', print_hide=1, length=20), + dict(fieldname='share_capital_amount', label='Share Capital', + fieldtype='Currency', insert_after='registration_number', print_hide=1, + description=_('Applicable if the company is SpA, SApA or SRL')), + dict(fieldname='no_of_members', label='No of Members', + fieldtype='Select', insert_after='share_capital_amount', print_hide=1, + options="\nSU-Socio Unico\nSM-Piu Soci", description=_("Applicable if the company is a limited liability company")), + dict(fieldname='liquidation_state', label='Liquidation State', + fieldtype='Select', insert_after='no_of_members', print_hide=1, + options="\nLS-In Liquidazione\nLN-Non in Liquidazione") + ], + 'Sales Taxes and Charges': [ + dict(fieldname='tax_exemption_reason', label='Tax Exemption Reason', + fieldtype='Select', insert_after='included_in_print_rate', print_hide=1, + depends_on='eval:doc.charge_type!="Actual" && doc.rate==0.0', + options="\n" + "\n".join(map(lambda x: x.decode('utf-8'), tax_exemption_reasons))), + dict(fieldname='tax_exemption_law', label='Tax Exempt Under', + fieldtype='Text', insert_after='tax_exemption_reason', print_hide=1, + depends_on='eval:doc.charge_type!="Actual" && doc.rate==0.0') + ], + 'Customer': [ + dict(fieldname='fiscal_code', label='Fiscal Code', fieldtype='Data', insert_after='tax_id', print_hide=1), + dict(fieldname='recipient_code', label='Recipient Code', + fieldtype='Data', insert_after='fiscal_code', print_hide=1, default="0000000"), + dict(fieldname='pec', label='Recipient PEC', + fieldtype='Data', insert_after='fiscal_code', print_hide=1), + dict(fieldname='is_public_administration', label='Is Public Administration', + fieldtype='Check', insert_after='is_internal_customer', print_hide=1, + description=_("Set this if the customer is a Public Administration company."), + depends_on='eval:doc.customer_type=="Company"'), + dict(fieldname='first_name', label='First Name', fieldtype='Data', + insert_after='salutation', print_hide=1, depends_on='eval:doc.customer_type!="Company"'), + dict(fieldname='last_name', label='Last Name', fieldtype='Data', + insert_after='first_name', print_hide=1, depends_on='eval:doc.customer_type!="Company"') + ], + 'Mode of Payment': [ + dict(fieldname='mode_of_payment_code', label='Code', + fieldtype='Select', insert_after='included_in_print_rate', print_hide=1, + options="\n".join(map(lambda x: x.decode('utf-8'), mode_of_payment_codes))) + ], + 'Payment Schedule': [ + dict(fieldname='mode_of_payment_code', label='Code', + fieldtype='Select', insert_after='mode_of_payment', print_hide=1, + options="\n".join(map(lambda x: x.decode('utf-8'), mode_of_payment_codes)), + fetch_from="mode_of_payment.mode_of_payment_code", read_only=1), + dict(fieldname='bank_account', label='Bank Account', + fieldtype='Link', insert_after='mode_of_payment_code', print_hide=1, + options="Bank Account"), + dict(fieldname='bank_account_name', label='Bank Account Name', + fieldtype='Data', insert_after='bank_account', print_hide=1, + fetch_from="bank_account.account_name", read_only=1), + dict(fieldname='bank_account_no', label='Bank Account No', + fieldtype='Data', insert_after='bank_account_name', print_hide=1, + fetch_from="bank_account.bank_account_no", read_only=1), + dict(fieldname='bank_account_iban', label='IBAN', + fieldtype='Data', insert_after='bank_account_name', print_hide=1, + fetch_from="bank_account.iban", read_only=1), + ], + "Sales Invoice": [ + dict(fieldname='vat_collectability', label='VAT Collectability', + fieldtype='Select', insert_after='taxes_and_charges', print_hide=1, + options="\n".join(map(lambda x: x.decode('utf-8'), vat_collectability_options)), + fetch_from="company.vat_collectability"), + dict(fieldname='sb_e_invoicing_reference', label='E-Invoicing', + fieldtype='Section Break', insert_after='pos_total_qty', print_hide=1), + dict(fieldname='company_tax_id', label='Company Tax ID', + fieldtype='Data', insert_after='sb_e_invoicing_reference', print_hide=1, read_only=1, + fetch_from="company.tax_id"), + dict(fieldname='company_fiscal_code', label='Company Fiscal Code', + fieldtype='Data', insert_after='company_tax_id', print_hide=1, read_only=1, + fetch_from="company.fiscal_code"), + dict(fieldname='company_fiscal_regime', label='Company Fiscal Regime', + fieldtype='Data', insert_after='company_fiscal_code', print_hide=1, read_only=1, + fetch_from="company.fiscal_regime"), + dict(fieldname='cb_e_invoicing_reference', fieldtype='Column Break', + insert_after='company_fiscal_regime', print_hide=1), + dict(fieldname='customer_fiscal_code', label='Customer Fiscal Code', + fieldtype='Data', insert_after='cb_e_invoicing_reference', read_only=1, + fetch_from="customer.fiscal_code"), + ], + 'Purchase Invoice Item': invoice_item_fields, 'Sales Order Item': invoice_item_fields, 'Delivery Note Item': invoice_item_fields, - 'Sales Invoice Item': invoice_item_fields, + 'Sales Invoice Item': invoice_item_fields, 'Quotation Item': invoice_item_fields, 'Purchase Order Item': invoice_item_fields, 'Purchase Receipt Item': invoice_item_fields, 'Supplier Quotation Item': invoice_item_fields, - 'Address': [ - dict(fieldname='country_code', label='Country Code', - fieldtype='Data', insert_after='country', print_hide=1, read_only=1, - fetch_from="country.code"), - dict(fieldname='state_code', label='State Code', - fieldtype='Data', insert_after='state', print_hide=1) - ] - } + 'Address': [ + dict(fieldname='country_code', label='Country Code', + fieldtype='Data', insert_after='country', print_hide=1, read_only=1, + fetch_from="country.code"), + dict(fieldname='state_code', label='State Code', + fieldtype='Data', insert_after='state', print_hide=1) + ] + } - create_custom_fields(custom_fields, ignore_validate = frappe.flags.in_patch, update=update) + create_custom_fields(custom_fields, ignore_validate = frappe.flags.in_patch, update=update) def setup_report(): - report_name = 'Electronic Invoice Register' + report_name = 'Electronic Invoice Register' - frappe.db.sql(""" update `tabReport` set disabled = 0 where - name = %s """, report_name) + frappe.db.sql(""" update `tabReport` set disabled = 0 where + name = %s """, report_name) - if not frappe.db.get_value('Custom Role', dict(report=report_name)): - frappe.get_doc(dict( - doctype='Custom Role', - report=report_name, - roles= [ - dict(role='Accounts User'), - dict(role='Accounts Manager') - ] - )).insert() + if not frappe.db.get_value('Custom Role', dict(report=report_name)): + frappe.get_doc(dict( + doctype='Custom Role', + report=report_name, + roles= [ + dict(role='Accounts User'), + dict(role='Accounts Manager') + ] + )).insert() From c18e925d6168dbdf74a40651aa596b296997f37e Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Wed, 20 Feb 2019 17:13:15 +0530 Subject: [PATCH 09/19] fix: Moved regional methods from controller to hooks (#16736) --- .../doctype/sales_invoice/sales_invoice.py | 5 ----- erpnext/controllers/accounts_controller.py | 8 -------- erpnext/hooks.py | 5 ++--- erpnext/regional/italy/utils.py | 15 +++++++++++++-- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index abd201f5c7..895ca07da2 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -24,7 +24,6 @@ from erpnext.accounts.general_ledger import get_round_off_account_and_cost_cente from erpnext.accounts.doctype.loyalty_program.loyalty_program import \ get_loyalty_program_details_with_points, get_loyalty_details, validate_loyalty_points from erpnext.accounts.deferred_revenue import validate_service_stop_date -from erpnext.controllers.accounts_controller import on_submit_regional, on_cancel_regional from erpnext.healthcare.utils import manage_invoice_submit_cancel @@ -199,8 +198,6 @@ class SalesInvoice(SellingController): if "Healthcare" in active_domains: manage_invoice_submit_cancel(self, "on_submit") - on_submit_regional(self) - def validate_pos_paid_amount(self): if len(self.payments) == 0 and self.is_pos: frappe.throw(_("At least one mode of payment is required for POS invoice.")) @@ -256,8 +253,6 @@ class SalesInvoice(SellingController): if "Healthcare" in active_domains: manage_invoice_submit_cancel(self, "on_cancel") - on_cancel_regional(self) - def update_status_updater_args(self): if cint(self.update_stock): self.status_updater.extend([{ diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 5a765aa273..34bbe7b999 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -1138,11 +1138,3 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name): @erpnext.allow_regional def validate_regional(doc): pass - -@erpnext.allow_regional -def on_submit_regional(doc): - pass - -@erpnext.allow_regional -def on_cancel_regional(doc): - pass diff --git a/erpnext/hooks.py b/erpnext/hooks.py index e98ca4b597..ccdd412c18 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -202,7 +202,8 @@ doc_events = { "validate": "erpnext.portal.doctype.products_settings.products_settings.home_page_is_products" }, "Sales Invoice": { - "on_submit": "erpnext.regional.france.utils.create_transaction_log", + "on_submit": ["erpnext.regional.france.utils.create_transaction_log", "erpnext.regional.italy.utils.sales_invoice_on_submit"], + "on_cancel": "erpnext.regional.italy.utils.sales_invoice_on_cancel", "on_trash": "erpnext.regional.check_deletion_permission" }, "Payment Entry": { @@ -305,7 +306,5 @@ regional_overrides = { 'Italy': { 'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.italy.utils.update_itemised_tax_data', 'erpnext.controllers.accounts_controller.validate_regional': 'erpnext.regional.italy.utils.sales_invoice_validate', - 'erpnext.controllers.accounts_controller.on_submit_regional': 'erpnext.regional.italy.utils.sales_invoice_on_submit', - 'erpnext.controllers.accounts_controller.on_cancel_regional': 'erpnext.regional.italy.utils.sales_invoice_on_cancel' } } diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py index 7e0386a93b..c86ad78cbc 100644 --- a/erpnext/regional/italy/utils.py +++ b/erpnext/regional/italy/utils.py @@ -222,8 +222,12 @@ def sales_invoice_validate(doc): #Ensure payment details are valid for e-invoice. -def sales_invoice_on_submit(doc): +def sales_invoice_on_submit(doc, method): #Validate payment details + if get_company_country(doc.company) not in ['Italy', + 'Italia', 'Italian Republic', 'Repubblica Italiana']: + return + if not len(doc.payment_schedule): frappe.throw(_("Please set the Payment Schedule"), title=_("E-Invoicing Information Missing")) else: @@ -247,10 +251,17 @@ def prepare_and_attach_invoice(doc): save_file(xml_filename, invoice_xml, dt=doc.doctype, dn=doc.name, is_private=True) #Delete e-invoice attachment on cancel. -def sales_invoice_on_cancel(doc): +def sales_invoice_on_cancel(doc, method): + if get_company_country(doc.company) not in ['Italy', + 'Italia', 'Italian Republic', 'Repubblica Italiana']: + return + for attachment in get_e_invoice_attachments(doc): remove_file(attachment.name, attached_to_doctype=doc.doctype, attached_to_name=doc.name) +def get_company_country(company): + return frappe.get_cached_value('Company', company, 'country') + def get_e_invoice_attachments(invoice): out = [] attachments = get_attachments(invoice.doctype, invoice.name) From 0d64d622e577ddbf4251549dcccfbb8567975b55 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Wed, 20 Feb 2019 17:55:14 +0530 Subject: [PATCH 10/19] fix: filter only unique values for tree options --- erpnext/public/js/utils.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js index 64085a83cd..389e25ece1 100755 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -255,11 +255,16 @@ $.extend(erpnext.utils, { // get valid options for tree based on user permission & locals dict let unscrub_option = frappe.model.unscrub(option); let user_permission = frappe.defaults.get_user_permissions(); + let options; + if(user_permission && user_permission[unscrub_option]) { - return user_permission[unscrub_option].map(perm => perm.doc); + options = user_permission[unscrub_option].map(perm => perm.doc); } else { - return $.map(locals[`:${unscrub_option}`], function(c) { return c.name; }).sort(); + options = $.map(locals[`:${unscrub_option}`], function(c) { return c.name; }).sort(); } + + // filter unique values, as there may be multiple user permissions for any value + return options.filter((value, index, self) => self.indexOf(value) === index); }, get_tree_default: function(option) { // set default for a field based on user permission From ada93e5d775a681f9729ab54bb261ebd1dad311b Mon Sep 17 00:00:00 2001 From: Saurabh Date: Wed, 20 Feb 2019 18:44:17 +0600 Subject: [PATCH 11/19] bumped to version 11.1.9 --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 24cc8ea79c..049a8a0923 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.8' +__version__ = '11.1.9' def get_default_company(user=None): '''Get default company for user''' From 40c15d2e747f722caa5521037d492338d1890474 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 20 Feb 2019 18:55:38 +0530 Subject: [PATCH 12/19] fix: Calendar events for leaves considering user permissions --- .../leave_application/leave_application.py | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index 6b7c0f7e79..b85f38b295 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -487,7 +487,6 @@ def get_events(start, end, filters=None): add_block_dates(events, start, end, employee, company) add_holidays(events, start, end, employee, company) - return events def add_department_leaves(events, start, end, employee, company): @@ -500,10 +499,22 @@ def add_department_leaves(events, start, end, employee, company): department_employees = frappe.db.sql_list("""select name from tabEmployee where department=%s and company=%s""", (department, company)) - match_conditions = "and employee in (\"%s\")" % '", "'.join(department_employees) - add_leaves(events, start, end, match_conditions=match_conditions) + filter_conditions = "employee in (\"%s\")" % '", "'.join(department_employees) + add_leaves(events, start, end, filter_conditions=filter_conditions) + +def add_leaves(events, start, end, filter_conditions=None): + conditions = [] + + if filter_conditions: + conditions.append(filter_conditions) + + if not cint(frappe.db.get_value("HR Settings", None, "show_leaves_of_all_department_members_in_calendar")): + from frappe.desk.reportview import build_match_conditions + match_conditions = build_match_conditions("Leave Application") + + if match_conditions: + conditions.append(match_conditions) -def add_leaves(events, start, end, match_conditions=None): query = """select name, from_date, to_date, employee_name, half_day, status, employee, docstatus from `tabLeave Application` where @@ -511,8 +522,8 @@ def add_leaves(events, start, end, match_conditions=None): and docstatus < 2 and status!="Rejected" """ - if match_conditions: - query += match_conditions + if conditions: + query += ' and ' + ' and '.join(conditions) for d in frappe.db.sql(query, {"start":start, "end": end}, as_dict=True): e = { From 816a4655a023d6b0cb2b19b47ac5bb66c4894f6d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 21 Feb 2019 12:02:36 +0530 Subject: [PATCH 13/19] fix: Consider returned qty while making invoice from DN / PR --- .../doctype/sales_invoice/sales_invoice.js | 3 +- .../doctype/delivery_note/delivery_note.py | 38 ++++++++++--- .../delivery_note/test_delivery_note.py | 29 +++++++++- .../purchase_receipt/purchase_receipt.py | 54 +++++++++++++++++-- .../purchase_receipt/test_purchase_receipt.py | 38 +++++++++++++ 5 files changed, 150 insertions(+), 12 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 8911ddf464..b1a851a4f1 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -201,7 +201,8 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte get_query: function() { var filters = { docstatus: 1, - company: me.frm.doc.company + company: me.frm.doc.company, + is_return: 0 }; if(me.frm.doc.customer) filters["customer"] = me.frm.doc.customer; return { diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 50996eddda..1eb2b0985a 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -391,7 +391,7 @@ def get_invoiced_qty_map(delivery_note): return invoiced_qty_map -def get_returned_qty_map(sales_orders): +def get_returned_qty_map_against_so(sales_orders): """returns a map: {so_detail: returned_qty}""" returned_qty_map = {} @@ -403,12 +403,25 @@ def get_returned_qty_map(sales_orders): return returned_qty_map +def get_returned_qty_map_against_dn(delivery_note): + """returns a map: {so_detail: returned_qty}""" + returned_qty_map = frappe._dict(frappe.db.sql("""select dn_item.item_code, sum(abs(dn_item.qty)) as qty + from `tabDelivery Note Item` dn_item, `tabDelivery Note` dn + where dn.name = dn_item.parent + and dn.docstatus = 1 + and dn.is_return = 1 + and dn.return_against = %s + group by dn_item.item_code + """, delivery_note)) + + return returned_qty_map + @frappe.whitelist() def make_sales_invoice(source_name, target_doc=None): doc = frappe.get_doc('Delivery Note', source_name) sales_orders = [d.against_sales_order for d in doc.items] - returned_qty_map = get_returned_qty_map(sales_orders) - + returned_qty_map_against_so = get_returned_qty_map_against_so(sales_orders) + returned_qty_map_against_dn = get_returned_qty_map_against_dn(source_name) invoiced_qty_map = get_invoiced_qty_map(source_name) def set_missing_values(source, target): @@ -428,13 +441,26 @@ def make_sales_invoice(source_name, target_doc=None): target.update(get_fetch_values("Sales Invoice", 'company_address', target.company_address)) def update_item(source_doc, target_doc, source_parent): - target_doc.qty = (source_doc.qty - - invoiced_qty_map.get(source_doc.name, 0) - returned_qty_map.get(source_doc.so_detail, 0)) + target_doc.qty, returned_qty = get_pending_qty(source_doc) + if not source_doc.so_detail: + returned_qty_map_against_dn[source_doc.item_code] = returned_qty if source_doc.serial_no and source_parent.per_billed > 0: target_doc.serial_no = get_delivery_note_serial_no(source_doc.item_code, target_doc.qty, source_parent.name) + def get_pending_qty(item_row): + pending_qty = item_row.qty - invoiced_qty_map.get(item_row.name, 0) - returned_qty_map_against_so.get(item_row.so_detail, 0) + returned_qty = flt(returned_qty_map_against_dn.get(item_row.item_code, 0)) + if not item_row.so_detail: + if returned_qty >= pending_qty: + pending_qty = 0 + returned_qty -= pending_qty + else: + pending_qty -= returned_qty + returned_qty = 0 + return pending_qty, returned_qty + doc = get_mapped_doc("Delivery Note", source_name, { "Delivery Note": { "doctype": "Sales Invoice", @@ -453,7 +479,7 @@ def make_sales_invoice(source_name, target_doc=None): "cost_center": "cost_center" }, "postprocess": update_item, - "filter": lambda d: abs(d.qty) - abs(invoiced_qty_map.get(d.name, 0))<=0 + "filter": lambda d: get_pending_qty(d)[0]<=0 }, "Sales Taxes and Charges": { "doctype": "Sales Taxes and Charges", diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index 0c5a71c30c..5c031213d8 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -636,7 +636,7 @@ class TestDeliveryNote(unittest.TestCase): self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) set_perpetual_inventory(0, company) - + def test_make_sales_invoice_from_dn_for_returned_qty(self): from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice @@ -655,6 +655,33 @@ class TestDeliveryNote(unittest.TestCase): si = make_sales_invoice(dn.name) self.assertEquals(si.items[0].qty, 1) + def test_make_sales_invoice_from_dn_with_returned_qty_against_dn(self): + from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice + + dn = create_delivery_note(qty=8, do_not_submit=True) + dn.append("items", { + "item_code": "_Test Item", + "warehouse": "_Test Warehouse - _TC", + "qty": 1, + "rate": 100, + "conversion_factor": 1.0, + "expense_account": "Cost of Goods Sold - _TC", + "cost_center": "_Test Cost Center - _TC" + }) + dn.submit() + + si1 = make_sales_invoice(dn.name) + si1.items[0].qty = 4 + si1.items.pop(1) + si1.save() + si1.submit() + + create_delivery_note(is_return=1, return_against=dn.name, qty=-2) + + si2 = make_sales_invoice(dn.name) + self.assertEquals(si2.items[0].qty, 2) + self.assertEquals(si2.items[1].qty, 1) + def create_delivery_note(**args): dn = frappe.new_doc("Delivery Note") args = frappe._dict(args) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index f006d00176..cb51e220b8 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -125,7 +125,7 @@ class PurchaseReceipt(BuyingController): else: self.status = "Completed" - + # Updating stock ledger should always be called after updating prevdoc status, # because updating ordered qty, reserved_qty_for_subcontract in bin # depends upon updated ordered qty in PO @@ -311,7 +311,7 @@ class PurchaseReceipt(BuyingController): "\n".join(warehouse_with_no_account)) return process_gl_map(gl_entries) - + def get_asset_gl_entry(self, gl_entries): for d in self.get("items"): if d.is_fixed_asset: @@ -405,6 +405,11 @@ def update_billed_amount_based_on_po(po_detail, update_modified=True): @frappe.whitelist() def make_purchase_invoice(source_name, target_doc=None): from frappe.model.mapper import get_mapped_doc + doc = frappe.get_doc('Purchase Receipt', source_name) + purchase_orders = [d.purchase_order for d in doc.items] + returned_qty_map_against_po = get_returned_qty_map_against_po(purchase_orders) + returned_qty_map_against_pr = get_returned_qty_map_against_pr(source_name) + invoiced_qty_map = get_invoiced_qty_map(source_name) def set_missing_values(source, target): @@ -417,7 +422,23 @@ def make_purchase_invoice(source_name, target_doc=None): doc.run_method("calculate_taxes_and_totals") def update_item(source_doc, target_doc, source_parent): - target_doc.qty = source_doc.qty - invoiced_qty_map.get(source_doc.name, 0) + target_doc.qty, returned_qty = get_pending_qty(source_doc) + if not source_doc.purchase_order_item: + returned_qty_map_against_pr[source_doc.item_code] = returned_qty + + def get_pending_qty(item_row): + pending_qty = item_row.qty - invoiced_qty_map.get(item_row.name, 0) \ + - returned_qty_map_against_po.get(item_row.purchase_order_item, 0) + returned_qty = flt(returned_qty_map_against_pr.get(item_row.item_code, 0)) + if not item_row.purchase_order_item: + if returned_qty >= pending_qty: + pending_qty = 0 + returned_qty -= pending_qty + else: + pending_qty -= returned_qty + returned_qty = 0 + return pending_qty, returned_qty + doclist = get_mapped_doc("Purchase Receipt", source_name, { "Purchase Receipt": { @@ -440,7 +461,7 @@ def make_purchase_invoice(source_name, target_doc=None): "asset": "asset", }, "postprocess": update_item, - "filter": lambda d: abs(d.qty) - abs(invoiced_qty_map.get(d.name, 0))<=0 + "filter": lambda d: get_pending_qty(d)[0]<=0 }, "Purchase Taxes and Charges": { "doctype": "Purchase Taxes and Charges", @@ -462,6 +483,31 @@ def get_invoiced_qty_map(purchase_receipt): return invoiced_qty_map +def get_returned_qty_map_against_po(purchase_orders): + """returns a map: {so_detail: returned_qty}""" + returned_qty_map = {} + + for name, returned_qty in frappe.get_all('Purchase Order Item', fields = ["name", "returned_qty"], + filters = {'parent': ('in', purchase_orders), 'docstatus': 1}, as_list=1): + if not returned_qty_map.get(name): + returned_qty_map[name] = 0 + returned_qty_map[name] += returned_qty + + return returned_qty_map + +def get_returned_qty_map_against_pr(purchase_receipt): + """returns a map: {so_detail: returned_qty}""" + returned_qty_map = frappe._dict(frappe.db.sql("""select pr_item.item_code, sum(abs(pr_item.qty)) as qty + from `tabPurchase Receipt Item` pr_item, `tabPurchase Receipt` pr + where pr.name = pr_item.parent + and pr.docstatus = 1 + and pr.is_return = 1 + and pr.return_against = %s + group by pr_item.item_code + """, purchase_receipt)) + + return returned_qty_map + @frappe.whitelist() def make_purchase_return(source_name, target_doc=None): from erpnext.controllers.sales_and_purchase_return import make_return_doc diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 472083b5a1..c5ae838c8f 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -404,6 +404,44 @@ class TestPurchaseReceipt(unittest.TestCase): set_perpetual_inventory(0, pr.company) + def test_make_purchase_invoice_from_pr_for_returned_qty(self): + from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order, create_pr_against_po + + po = create_purchase_order() + pr = create_pr_against_po(po.name) + + pr1 = make_purchase_receipt(is_return=1, return_against=pr.name, qty=-1, do_not_submit=True) + pr1.items[0].purchase_order = po.name + pr1.items[0].purchase_order_item = po.items[0].name + pr1.submit() + + pi = make_purchase_invoice(pr.name) + self.assertEquals(pi.items[0].qty, 3) + + def test_make_purchase_invoice_from_dn_with_returned_qty_against_dn(self): + pr1 = make_purchase_receipt(qty=8, do_not_submit=True) + pr1.append("items", { + "item_code": "_Test Item", + "warehouse": "_Test Warehouse - _TC", + "qty": 1, + "received_qty": 1, + "rate": 100, + "conversion_factor": 1.0, + }) + pr1.submit() + + pi1 = make_purchase_invoice(pr1.name) + pi1.items[0].qty = 4 + pi1.items.pop(1) + pi1.save() + pi1.submit() + + make_purchase_receipt(is_return=1, return_against=pr1.name, qty=-2) + + pi2 = make_purchase_invoice(pr1.name) + self.assertEquals(pi2.items[0].qty, 2) + self.assertEquals(pi2.items[1].qty, 1) + def get_gl_entries(voucher_type, voucher_no): return frappe.db.sql("""select account, debit, credit, cost_center from `tabGL Entry` where voucher_type=%s and voucher_no=%s From 14ff6bfc3246d337a88ecb475e4ba15a1a6a3f32 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Thu, 21 Feb 2019 12:08:32 +0530 Subject: [PATCH 14/19] fix: Decimal point issue in gross profit print --- erpnext/accounts/report/gross_profit/gross_profit.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 01211a976f..67105e58de 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -135,9 +135,9 @@ class GrossProfitGenerator(object): row.buying_rate, row.base_rate = 0.0, 0.0 # calculate gross profit - row.gross_profit = row.base_amount - row.buying_amount + row.gross_profit = flt(row.base_amount - row.buying_amount, 3) if row.base_amount: - row.gross_profit_percent = (row.gross_profit / row.base_amount) * 100.0 + row.gross_profit_percent = flt((row.gross_profit / row.base_amount) * 100.0, 3) else: row.gross_profit_percent = 0.0 @@ -174,8 +174,8 @@ class GrossProfitGenerator(object): self.grouped_data.append(row) def set_average_rate(self, new_row): - new_row.gross_profit = new_row.base_amount - new_row.buying_amount - new_row.gross_profit_percent = ((new_row.gross_profit / new_row.base_amount) * 100.0) \ + new_row.gross_profit = flt(new_row.base_amount - new_row.buying_amount,3) + new_row.gross_profit_percent = flt(((new_row.gross_profit / new_row.base_amount) * 100.0),3) \ if new_row.base_amount else 0 new_row.buying_rate = (new_row.buying_amount / new_row.qty) if new_row.qty else 0 new_row.base_rate = (new_row.base_amount / new_row.qty) if new_row.qty else 0 From 26972c954d6ccccfae2d3c1b71e09a3f766da4a6 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 21 Feb 2019 14:32:41 +0530 Subject: [PATCH 15/19] fix: Validate serial no usage in invoice considering multi company transaction --- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 895ca07da2..4cf3a1acf5 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1012,9 +1012,10 @@ class SalesInvoice(SellingController): for serial_no in item.serial_no.split("\n"): sales_invoice = frappe.db.get_value("Serial No", serial_no, "sales_invoice") if sales_invoice and self.name != sales_invoice: - frappe.throw(_("Serial Number: {0} is already referenced in Sales Invoice: {1}".format( - serial_no, sales_invoice - ))) + sales_invoice_company = frappe.db.get_value("Sales Invoice", sales_invoice, "company") + if sales_invoice_company == self.company: + frappe.throw(_("Serial Number: {0} is already referenced in Sales Invoice: {1}" + .format(serial_no, sales_invoice))) def update_project(self): if self.project: From b24caad7891fbf290762974aad0651bd10d47d45 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 21 Feb 2019 17:11:35 +0530 Subject: [PATCH 16/19] fix: Ignore cost center while fetching outstanding invocies if not allowed from accounts settings --- erpnext/accounts/doctype/payment_entry/payment_entry.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index f303301a33..8161cc634b 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals import frappe, erpnext, json from frappe import _, scrub, ValidationError from frappe.utils import flt, comma_or, nowdate, getdate -from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on +from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on, get_allow_cost_center_in_entry_of_bs_account from erpnext.accounts.party import get_party_account from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account from erpnext.setup.utils import get_exchange_rate @@ -564,8 +564,8 @@ def get_outstanding_reference_documents(args): .format(frappe.db.escape(args["voucher_type"]), frappe.db.escape(args["voucher_no"])) # Add cost center condition - if args.get("cost_center"): - condition += " and cost_center='%s'" % args.get("cost_center") + if args.get("cost_center") and get_allow_cost_center_in_entry_of_bs_account(): + condition += " and cost_center='%s'" % args.get("cost_center") outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"), args.get("party_account"), condition=condition) From 90691dc0d88512da2ec2e687a527436d690d4b5c Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 21 Feb 2019 17:18:28 +0530 Subject: [PATCH 17/19] (Profit and Loss Statement, fix): for parent account value was showing as zero --- erpnext/accounts/report/financial_statements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py index 09cf5b1d2f..2c7bd7252f 100644 --- a/erpnext/accounts/report/financial_statements.py +++ b/erpnext/accounts/report/financial_statements.py @@ -270,7 +270,7 @@ def add_total_row(out, root_type, balance_must_be, period_list, company_currency for period in period_list: total_row.setdefault(period.key, 0.0) total_row[period.key] += row.get(period.key, 0.0) - row[period.key] = 0.0 + row[period.key] = row.get(period.key, 0.0) total_row.setdefault("total", 0.0) total_row["total"] += flt(row["total"]) From 1915e15a9ed8f63edccd2fab42f4ca670ddd6677 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Thu, 21 Feb 2019 17:55:57 +0530 Subject: [PATCH 18/19] fix: State code issue fix in regional module(Italy) --- erpnext/regional/italy/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py index c86ad78cbc..421994c398 100644 --- a/erpnext/regional/italy/utils.py +++ b/erpnext/regional/italy/utils.py @@ -300,6 +300,9 @@ def get_progressive_name_and_number(doc): return progressive_name, progressive_number def set_state_code(doc, method): + if not doc.get('state'): + return + if not (hasattr(doc, "state_code") and doc.country in ["Italy", "Italia", "Italian Republic", "Repubblica Italiana"]): return From 76cd402ca5156c8d1a3c749146aed234483470ae Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 21 Feb 2019 18:55:28 +0600 Subject: [PATCH 19/19] bumped to version 11.1.10 --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 049a8a0923..373a3dce8b 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.9' +__version__ = '11.1.10' def get_default_company(user=None): '''Get default company for user'''