From 258faab761d62674a1342e0a459305d9175c69ad Mon Sep 17 00:00:00 2001 From: tundebabzy Date: Wed, 16 Aug 2017 08:46:46 +0100 Subject: [PATCH 01/13] Transaction Forms (Payment Entry, Sales Invoice, Purchase Invoice) can forget company currency (#10409) (#10410) * properly keep track of document currency and company currency * Update taxes_and_totals.js --- erpnext/public/js/controllers/taxes_and_totals.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index c653640de6..d042bb7220 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -62,7 +62,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ this.frm.doc.conversion_rate = flt(this.frm.doc.conversion_rate, (cur_frm) ? precision("conversion_rate") : 9); var conversion_rate_label = frappe.meta.get_label(this.frm.doc.doctype, "conversion_rate", this.frm.doc.name); - var company_currency = this.frm.doc.currency || this.get_company_currency(); + var company_currency = this.get_company_currency(); if(!this.frm.doc.conversion_rate) { if(this.frm.doc.currency == company_currency) { @@ -419,7 +419,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ this.frm.doc.currency, precision("rounded_total")); } if(frappe.meta.get_docfield(this.frm.doc.doctype, "base_rounded_total", this.frm.doc.name)) { - var company_currency = this.frm.doc.currency || this.get_company_currency(); + var company_currency = this.get_company_currency(); this.frm.doc.base_rounded_total = round_based_on_smallest_currency_fraction(this.frm.doc.base_grand_total, From f35710db15d15adc84769abd99f873fa59ce7c0a Mon Sep 17 00:00:00 2001 From: tundebabzy Date: Wed, 16 Aug 2017 08:55:18 +0100 Subject: [PATCH 02/13] remove empty first row if needed (#10378) refactor code: move global functions to callback scope --- erpnext/public/js/controllers/buying.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js index 92ef72540a..010d4d9269 100644 --- a/erpnext/public/js/controllers/buying.js +++ b/erpnext/public/js/controllers/buying.js @@ -346,7 +346,21 @@ erpnext.buying.get_items_from_product_bundle = function(frm) { }, freeze: true, callback: function(r) { + const first_row_is_empty = function(child_table){ + if($.isArray(child_table) && child_table.length > 0) { + return !child_table[0].item_code; + } + return false; + }; + + const remove_empty_first_row = function(frm){ + if (first_row_is_empty(frm.doc.items)){ + frm.doc.items = frm.doc.items.splice(1); + } + }; + if(!r.exc && r.message) { + remove_empty_first_row(frm); for ( var i=0; i< r.message.length; i++ ) { var d = frm.add_child("items"); var item = r.message[i]; @@ -366,3 +380,4 @@ erpnext.buying.get_items_from_product_bundle = function(frm) { }); dialog.show(); } + From 64c32dcd59843d44135f1cdcbec2c5633c611924 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 16 Aug 2017 15:04:18 +0530 Subject: [PATCH 03/13] [fix] Update monthly sales value on Company (#10417) * [fix] Update monthly sales value on cancellation of invoice, also update modified datestamp * Company monthly sales: patches and test cases --- .../doctype/sales_invoice/sales_invoice.py | 12 +++++++- .../sales_invoice/test_sales_invoice.py | 11 ++++++++ erpnext/patches.txt | 2 +- erpnext/setup/doctype/company/company.py | 28 ++++++++----------- .../company/delete_company_transactions.py | 4 +++ 5 files changed, 39 insertions(+), 18 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 9dfacbdb5e..96d617e865 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -19,6 +19,7 @@ from erpnext.accounts.doctype.asset.depreciation \ import get_disposal_account_and_cost_center, get_gl_entries_on_asset_disposal from erpnext.stock.doctype.batch.batch import set_batch_nos from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, get_delivery_note_serial_no +from erpnext.setup.doctype.company.company import update_company_current_month_sales form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -140,7 +141,7 @@ class SalesInvoice(SellingController): self.update_time_sheet(self.name) - frappe.enqueue('erpnext.setup.doctype.company.company.update_company_current_month_sales', company=self.company) + self.update_current_month_sales() def validate_pos_paid_amount(self): if len(self.payments) == 0 and self.is_pos: @@ -178,6 +179,15 @@ class SalesInvoice(SellingController): self.make_gl_entries_on_cancel() frappe.db.set(self, 'status', 'Cancelled') + self.update_current_month_sales() + + def update_current_month_sales(self): + if frappe.flags.in_test: + update_company_current_month_sales(self.company) + else: + frappe.enqueue('erpnext.setup.doctype.company.company.update_company_current_month_sales', + company=self.company) + def update_status_updater_args(self): if cint(self.update_stock): self.status_updater.extend([{ diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 806b489da4..e0a453c5c9 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1272,6 +1272,17 @@ class TestSalesInvoice(unittest.TestCase): si.insert() return si + def test_company_monthly_sales(self): + existing_current_month_sales = frappe.db.get_value("Company", "_Test Company", "total_monthly_sales") + + si = create_sales_invoice() + current_month_sales = frappe.db.get_value("Company", "_Test Company", "total_monthly_sales") + self.assertEqual(current_month_sales, existing_current_month_sales + si.base_grand_total) + + si.cancel() + current_month_sales = frappe.db.get_value("Company", "_Test Company", "total_monthly_sales") + self.assertEqual(current_month_sales, existing_current_month_sales) + def create_sales_invoice(**args): si = frappe.new_doc("Sales Invoice") args = frappe._dict(args) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 60caf0fec1..6b660e1e6d 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -421,7 +421,7 @@ erpnext.patches.v8_1.removed_report_support_hours erpnext.patches.v8_1.add_indexes_in_transaction_doctypes erpnext.patches.v8_3.set_restrict_to_domain_for_module_def erpnext.patches.v8_1.update_expense_claim_status -erpnext.patches.v8_3.update_company_total_sales +erpnext.patches.v8_3.update_company_total_sales #2017-08-16 erpnext.patches.v8_4.make_scorecard_records erpnext.patches.v8_1.set_delivery_date_in_so_item #2017-07-28 erpnext.patches.v8_5.fix_tax_breakup_for_non_invoice_docs diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 29630eeb84..b945ee4104 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe, os from frappe import _ -from frappe.utils import cint +from frappe.utils import cint, today, formatdate import frappe.defaults @@ -312,39 +312,35 @@ def get_name_with_abbr(name, company): return " - ".join(parts) def update_company_current_month_sales(company): - from frappe.utils import today, formatdate current_month_year = formatdate(today(), "MM-yyyy") - results = frappe.db.sql((''' + results = frappe.db.sql(''' select sum(base_grand_total) as total, date_format(posting_date, '%m-%Y') as month_year from `tabSales Invoice` where - date_format(posting_date, '%m-%Y')="{0}" and - company = "{1}" + date_format(posting_date, '%m-%Y')="{0}" + and docstatus = 1 + and company = "{1}" group by - month_year; - ''').format(current_month_year, frappe.db.escape(company)), as_dict = True) + month_year + '''.format(current_month_year, frappe.db.escape(company)), as_dict = True) monthly_total = results[0]['total'] if len(results) > 0 else 0 - frappe.db.sql((''' - update tabCompany set total_monthly_sales = %s where name=%s - '''), (monthly_total, frappe.db.escape(company))) + frappe.db.set_value("Company", company, "total_monthly_sales", monthly_total) frappe.db.commit() - def update_company_monthly_sales(company): '''Cache past year monthly sales of every company based on sales invoices''' from frappe.utils.goal import get_monthly_results import json - filter_str = "company = '{0}' and status != 'Draft'".format(frappe.db.escape(company)) - month_to_value_dict = get_monthly_results("Sales Invoice", "base_grand_total", "posting_date", filter_str, "sum") + filter_str = "company = '{0}' and status != 'Draft' and docstatus=1".format(frappe.db.escape(company)) + month_to_value_dict = get_monthly_results("Sales Invoice", "base_grand_total", + "posting_date", filter_str, "sum") - frappe.db.sql((''' - update tabCompany set sales_monthly_history = %s where name=%s - '''), (json.dumps(month_to_value_dict), frappe.db.escape(company))) + frappe.db.set_value("Company", company, "sales_monthly_history", json.dumps(month_to_value_dict)) frappe.db.commit() def cache_companies_monthly_sales_history(): diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py index f1fb0cf96e..d975a9ee8d 100644 --- a/erpnext/setup/doctype/company/delete_company_transactions.py +++ b/erpnext/setup/doctype/company/delete_company_transactions.py @@ -27,6 +27,10 @@ def delete_company_transactions(company_name): "Purchase Taxes and Charges Template", "POS Profile", 'BOM'): delete_for_doctype(doctype, company_name) + # reset company values + doc.total_monthly_sales = 0 + doc.sales_monthly_history = None + doc.save() # Clear notification counts clear_notifications() From 446c2b0e91dab07a0315a08380474736af3c1be8 Mon Sep 17 00:00:00 2001 From: Makarand Bauskar Date: Thu, 17 Aug 2017 12:39:35 +0530 Subject: [PATCH 04/13] [hotfix] fixes for https://github.com/frappe/erpnext/issues/9782 calculate leave without pay before subtracting holidays (#10355) --- erpnext/hr/doctype/salary_slip/salary_slip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index 1d17613381..356104e69c 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -231,12 +231,12 @@ class SalarySlip(TransactionBase): holidays = self.get_holidays_for_employee(self.start_date, self.end_date) working_days = date_diff(self.end_date, self.start_date) + 1 + actual_lwp = self.calculate_lwp(holidays, working_days) if not cint(frappe.db.get_value("HR Settings", None, "include_holidays_in_total_working_days")): working_days -= len(holidays) if working_days < 0: frappe.throw(_("There are more holidays than working days this month.")) - actual_lwp = self.calculate_lwp(holidays, working_days) if not lwp: lwp = actual_lwp elif lwp != actual_lwp: From fff56530c4e36257fed37da1dd7b165ba2b5cdd2 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 17 Aug 2017 14:47:25 +0530 Subject: [PATCH 05/13] [Fix] Due date not fetching on the payment entry against the invoices (#10419) --- erpnext/accounts/doctype/payment_entry/payment_entry.js | 1 + erpnext/accounts/utils.py | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 05986a0808..92a805f37d 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -499,6 +499,7 @@ frappe.ui.form.on('Payment Entry', { var c = frm.add_child("references"); c.reference_doctype = d.voucher_type; c.reference_name = d.voucher_no; + c.due_date = d.due_date c.total_amount = d.invoice_amount; c.outstanding_amount = d.outstanding_amount; if(!in_list(["Sales Order", "Purchase Order", "Expense Claim"], d.voucher_type)) { diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 6617802235..50530f5dc1 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -580,9 +580,15 @@ def get_outstanding_invoices(party_type, party, account, condition=None): dr_or_cr = "credit_in_account_currency - debit_in_account_currency" payment_dr_or_cr = "payment_gl_entry.debit_in_account_currency - payment_gl_entry.credit_in_account_currency" + invoice = 'Sales Invoice' if party_type == 'Customer' else 'Purchase Invoice' invoice_list = frappe.db.sql(""" select voucher_no, voucher_type, posting_date, ifnull(sum({dr_or_cr}), 0) as invoice_amount, + ( + case when (voucher_type = 'Sales Invoice' or voucher_type = 'Purchase Invoice') + then (select due_date from `tab{invoice}` where name = voucher_no) + else posting_date end + ) as due_date, ( select ifnull(sum({payment_dr_or_cr}), 0) from `tabGL Entry` payment_gl_entry @@ -606,6 +612,7 @@ def get_outstanding_invoices(party_type, party, account, condition=None): having (invoice_amount - payment_amount) > 0.005 order by posting_date, name""".format( dr_or_cr = dr_or_cr, + invoice = invoice, payment_dr_or_cr = payment_dr_or_cr, condition = condition or "" ), { @@ -618,6 +625,7 @@ def get_outstanding_invoices(party_type, party, account, condition=None): outstanding_invoices.append(frappe._dict({ 'voucher_no': d.voucher_no, 'voucher_type': d.voucher_type, + 'due_date': d.due_date, 'posting_date': d.posting_date, 'invoice_amount': flt(d.invoice_amount), 'payment_amount': flt(d.payment_amount), From fe43ecb5ee4db15589297d40fc73b61c95301d20 Mon Sep 17 00:00:00 2001 From: Makarand Bauskar Date: Thu, 17 Aug 2017 17:34:25 +0530 Subject: [PATCH 06/13] [hotfix] fixed type in gst_state_code_data.json file (#10437) --- erpnext/regional/india/gst_state_code_data.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/india/gst_state_code_data.json b/erpnext/regional/india/gst_state_code_data.json index 47af9b190a..6dab81d668 100644 --- a/erpnext/regional/india/gst_state_code_data.json +++ b/erpnext/regional/india/gst_state_code_data.json @@ -147,7 +147,7 @@ { "state_number": "22", "state_code": "CT", - "state_name": "Chattisgarh" + "state_name": "Chhattisgarh" }, { "state_number": "04", From 80d06da978ec553665608e58926f5ae7a6b3ea68 Mon Sep 17 00:00:00 2001 From: Makarand Bauskar Date: Mon, 21 Aug 2017 07:34:45 +0530 Subject: [PATCH 07/13] [hotfix] fixed mysql syntax error in Student and Guardian Contact Details report (#10450) --- .../student_and_guardian_contact_details.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/schools/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py b/erpnext/schools/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py index f191022f20..641b78372c 100644 --- a/erpnext/schools/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py +++ b/erpnext/schools/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py @@ -82,7 +82,7 @@ def get_guardian_map(student_list): select parent, guardian, guardian_name, relation from `tabStudent Guardian` where parent in (%s)''' % ', '.join(['%s']*len(student_list)), tuple(student_list), as_dict=1) - guardian_list = list(set([g.guardian for g in guardian_details])) + guardian_list = list(set([g.guardian for g in guardian_details])) or [''] guardian_mobile_no = dict(frappe.db.sql("""select name, mobile_number from `tabGuardian` where name in (%s)""" % ", ".join(['%s']*len(guardian_list)), tuple(guardian_list))) From 222e86bb13819f9cc472a0957885456dea126133 Mon Sep 17 00:00:00 2001 From: Makarand Bauskar Date: Mon, 21 Aug 2017 07:35:16 +0530 Subject: [PATCH 08/13] [hotfix] fixed the mysql syntax error issue on stock ledger report (#10442) --- erpnext/stock/report/stock_ledger/stock_ledger.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index ec55cec3fb..4a8868ade1 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -73,7 +73,9 @@ def get_sle_conditions(filters): conditions.append("""item_code in (select name from tabItem {item_conditions})""".format(item_conditions=item_conditions)) if filters.get("warehouse"): - conditions.append(get_warehouse_condition(filters.get("warehouse"))) + warehouse_condition = get_warehouse_condition(filters.get("warehouse")) + if warehouse_condition: + conditions.append(warehouse_condition) if filters.get("voucher_no"): conditions.append("voucher_no=%(voucher_no)s") if filters.get("batch_no"): From 6b1624cfee4d73cb50f7f335782e31dcfffaf6cd Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Mon, 21 Aug 2017 07:38:37 +0530 Subject: [PATCH 09/13] [Fix] Tax rule is not working for the parent customer groups (#10458) --- erpnext/accounts/doctype/tax_rule/tax_rule.py | 9 +++++++++ erpnext/accounts/doctype/tax_rule/test_tax_rule.py | 8 ++++++++ erpnext/setup/doctype/customer_group/customer_group.py | 7 +++++++ 3 files changed, 24 insertions(+) diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.py b/erpnext/accounts/doctype/tax_rule/tax_rule.py index 36f4221ce1..9e963328b5 100644 --- a/erpnext/accounts/doctype/tax_rule/tax_rule.py +++ b/erpnext/accounts/doctype/tax_rule/tax_rule.py @@ -8,6 +8,7 @@ from frappe import _ from frappe.model.document import Document from frappe.utils import cstr, cint from frappe.contacts.doctype.address.address import get_default_address +from erpnext.setup.doctype.customer_group.customer_group import get_parent_customer_groups class IncorrectCustomerGroup(frappe.ValidationError): pass class IncorrectSupplierType(frappe.ValidationError): pass @@ -134,6 +135,9 @@ def get_tax_template(posting_date, args): for key, value in args.iteritems(): if key=="use_for_shopping_cart": conditions.append("use_for_shopping_cart = {0}".format(1 if value else 0)) + if key == 'customer_group' and value: + customer_group_condition = get_customer_group_condition(value) + conditions.append("ifnull({0}, '') in ('', {1})".format(key, customer_group_condition)) else: conditions.append("ifnull({0}, '') in ('', '{1}')".format(key, frappe.db.escape(cstr(value)))) @@ -157,3 +161,8 @@ def get_tax_template(posting_date, args): return None return tax_template + +def get_customer_group_condition(customer_group): + customer_groups = ["'%s'"%(d.name) for d in get_parent_customer_groups(frappe.db.escape(customer_group))] + condition = ",".join(['%s'] * len(customer_groups))%(tuple(customer_groups)) + return condition \ No newline at end of file diff --git a/erpnext/accounts/doctype/tax_rule/test_tax_rule.py b/erpnext/accounts/doctype/tax_rule/test_tax_rule.py index a09d81b5c6..383b02b128 100644 --- a/erpnext/accounts/doctype/tax_rule/test_tax_rule.py +++ b/erpnext/accounts/doctype/tax_rule/test_tax_rule.py @@ -34,6 +34,14 @@ class TestTaxRule(unittest.TestCase): tax_rule2.save() self.assertTrue(tax_rule2.name) + def test_for_parent_customer_group(self): + tax_rule1 = make_tax_rule(customer_group= "All Customer Groups", + sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1, from_date = "2015-01-01") + tax_rule1.save() + + self.assertEquals(get_tax_template("2015-01-01", {"customer_group" : "Commercial"}), + "_Test Sales Taxes and Charges Template") + def test_conflict_with_overlapping_dates(self): tax_rule1 = make_tax_rule(customer= "_Test Customer", sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1, from_date = "2015-01-01", to_date = "2015-01-05") diff --git a/erpnext/setup/doctype/customer_group/customer_group.py b/erpnext/setup/doctype/customer_group/customer_group.py index b25095b1b1..0f1ee81863 100644 --- a/erpnext/setup/doctype/customer_group/customer_group.py +++ b/erpnext/setup/doctype/customer_group/customer_group.py @@ -18,3 +18,10 @@ class CustomerGroup(NestedSet): def validate_name_with_customer(self): if frappe.db.exists("Customer", self.name): frappe.msgprint(_("An Customer exists with same name"), raise_exception=1) + +def get_parent_customer_groups(customer_group): + lft, rgt = frappe.db.get_value("Customer Group", customer_group, ['lft', 'rgt']) + + return frappe.db.sql("""select name from `tabCustomer Group` + where lft <= %s and rgt >= %s + order by lft asc""", (lft, rgt), as_dict=True) \ No newline at end of file From 0d9ab86496d4c31149e302250ad13d4df51c661f Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Mon, 21 Aug 2017 07:52:49 +0530 Subject: [PATCH 10/13] [Fix] Making of production order from so, system not fetched the items from the sales order item if packing list has items and vice versa (#10453) --- .../doctype/sales_order/sales_order.js | 2 +- .../doctype/sales_order/sales_order.py | 32 ++++++++++++------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 80dc4f23ec..901e236bd2 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -179,7 +179,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( doc: this.frm.doc, method: 'get_production_order_items', callback: function(r) { - if(!r.message.every(function(d) { return !!d.bom })) { + if(!r.message) { frappe.msgprint({ title: __('Production Order not created'), message: __('No Items with Bill of Materials to Manufacture'), diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index c6dbd7043b..b16169bfd7 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -330,18 +330,19 @@ class SalesOrder(SellingController): def get_production_order_items(self): '''Returns items with BOM that already do not have a linked production order''' items = [] - for i in self.packed_items or self.items: - bom = frappe.get_all('BOM', dict(item=i.item_code, is_active=True), - order_by='is_default desc') - bom = bom[0].name if bom else None - stock_qty = i.qty if self.packed_items else i.stock_qty - items.append(dict( - item_code= i.item_code, - bom = bom, - warehouse = i.warehouse, - pending_qty= stock_qty - flt(frappe.db.sql('''select sum(qty) from `tabProduction Order` - where production_item=%s and sales_order=%s''', (i.item_code, self.name))[0][0]) - )) + + for table in [self.items, self.packed_items]: + for i in table: + bom = get_default_bom_item(i.item_code) + if bom: + stock_qty = i.qty if i.doctype == 'Packed Item' else i.stock_qty + items.append(dict( + item_code= i.item_code, + bom = bom, + warehouse = i.warehouse, + pending_qty= stock_qty - flt(frappe.db.sql('''select sum(qty) from `tabProduction Order` + where production_item=%s and sales_order=%s''', (i.item_code, self.name))[0][0]) + )) return items @@ -774,3 +775,10 @@ def make_production_orders(items, sales_order, company, project=None): def update_status(status, name): so = frappe.get_doc("Sales Order", name) so.update_status(status) + +def get_default_bom_item(item_code): + bom = frappe.get_all('BOM', dict(item=item_code, is_active=True), + order_by='is_default desc') + bom = bom[0].name if bom else None + + return bom From 1f49f511aaa5ebcc62cab2ffd86b2d3739bb92d3 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 21 Aug 2017 08:05:12 +0530 Subject: [PATCH 11/13] Tax rate in Itemised sales/purchase register and cleanups (#10439) --- .../item_wise_purchase_register.py | 76 +++++---------- .../item_wise_sales_register.py | 94 +++++++++++++------ 2 files changed, 88 insertions(+), 82 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 0d1eba1ad3..10862f5e2e 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe from frappe import _ from frappe.utils import flt +from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import get_tax_accounts def execute(filters=None): return _execute(filters) @@ -12,12 +13,12 @@ def execute(filters=None): def _execute(filters=None, additional_table_columns=None, additional_query_columns=None): if not filters: filters = {} columns = get_columns(additional_table_columns) - last_col = len(columns) item_list = get_items(filters, additional_query_columns) aii_account_map = get_aii_accounts() if item_list: - item_row_tax, tax_accounts = get_tax_accounts(item_list, columns) + itemised_tax, tax_columns = get_tax_accounts(item_list, columns, + tax_doctype="Purchase Taxes and Charges") columns.append({ "fieldname": "currency", @@ -26,6 +27,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum "width": 80 }) company_currency = frappe.db.get_value("Company", filters.company, "default_currency") + po_pr_map = get_purchase_receipts_against_purchase_order(item_list) data = [] for d in item_list: @@ -33,8 +35,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum if d.purchase_receipt: purchase_receipt = d.purchase_receipt elif d.po_detail: - purchase_receipt = ", ".join(frappe.db.sql_list("""select distinct parent - from `tabPurchase Receipt Item` where docstatus=1 and purchase_order_item=%s""", d.po_detail)) + purchase_receipt = ", ".join(po_pr_map.get(d.po_detail, [])) expense_account = d.expense_account or aii_account_map.get(d.company) row = [d.item_code, d.item_name, d.item_group, d.parent, d.posting_date, d.supplier, @@ -49,10 +50,12 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum purchase_receipt, expense_account, d.qty, d.base_net_rate, d.base_net_amount ] - for tax in tax_accounts: - row.append(item_row_tax.get(d.name, {}).get(tax, 0)) + total_tax = 0 + for tax in tax_columns: + item_tax = itemised_tax.get(d.name, {}).get(tax, {}) + row += [item_tax.get("tax_rate", 0), item_tax.get("tax_amount", 0)] + total_tax += flt(item_tax.get("tax_amount")) - total_tax = sum(row[last_col:]) row += [total_tax, d.base_net_amount + total_tax, company_currency] data.append(row) @@ -116,53 +119,18 @@ def get_items(filters, additional_query_columns): def get_aii_accounts(): return dict(frappe.db.sql("select name, stock_received_but_not_billed from tabCompany")) -def get_tax_accounts(item_list, columns): - import json - item_row_tax = {} - tax_accounts = [] - invoice_item_row = {} - item_row_map = {} - for d in item_list: - invoice_item_row.setdefault(d.parent, []).append(d) - item_row_map.setdefault(d.parent, {}).setdefault(d.item_code, []).append(d) +def get_purchase_receipts_against_purchase_order(item_list): + po_pr_map = frappe._dict() + po_item_rows = list(set([d.po_detail for d in item_list])) - tax_details = frappe.db.sql(""" - select - parent, account_head, item_wise_tax_detail, charge_type, base_tax_amount_after_discount_amount - from `tabPurchase Taxes and Charges` - where parenttype = 'Purchase Invoice' and docstatus = 1 - and (account_head is not null and account_head != '') - and category in ('Total', 'Valuation and Total') - and parent in (%s) - """ % ', '.join(['%s']*len(invoice_item_row)), tuple(invoice_item_row.keys())) + purchase_receipts = frappe.db.sql(""" + select parent, purchase_order_item + from `tabPurchase Receipt Item` + where docstatus=1 and purchase_order_item in (%s) + group by purchase_order_item, parent + """ % (', '.join(['%s']*len(po_item_rows))), tuple(po_item_rows), as_dict=1) - for parent, account_head, item_wise_tax_detail, charge_type, tax_amount in tax_details: - if account_head not in tax_accounts: - tax_accounts.append(account_head) + for pr in purchase_receipts: + po_pr_map.setdefault(pr.po_detail, []).append(pr.parent) - if item_wise_tax_detail: - try: - item_wise_tax_detail = json.loads(item_wise_tax_detail) - - for item_code, tax_amount in item_wise_tax_detail.items(): - tax_amount = flt(tax_amount[1]) if isinstance(tax_amount, list) else flt(tax_amount) - - item_net_amount = sum([flt(d.base_net_amount) - for d in item_row_map.get(parent, {}).get(item_code, [])]) - - for d in item_row_map.get(parent, {}).get(item_code, []): - item_tax_amount = flt((tax_amount * d.base_net_amount) / item_net_amount) if item_net_amount else 0 - item_row_tax.setdefault(d.name, {})[account_head] = item_tax_amount - - except ValueError: - continue - elif charge_type == "Actual" and tax_amount: - for d in invoice_item_row.get(parent, []): - item_row_tax.setdefault(d.name, {})[account_head] = \ - flt((tax_amount * d.base_net_amount) / d.base_net_total) - - tax_accounts.sort() - columns += [account_head + ":Currency/currency:80" for account_head in tax_accounts] - columns += ["Total Tax:Currency/currency:80", "Total:Currency/currency:80"] - - return item_row_tax, tax_accounts + return po_pr_map \ No newline at end of file diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index 7d10b19dce..37707cd402 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -13,11 +13,10 @@ def execute(filters=None): def _execute(filters=None, additional_table_columns=None, additional_query_columns=None): if not filters: filters = {} columns = get_columns(additional_table_columns) - last_col = len(columns) item_list = get_items(filters, additional_query_columns) if item_list: - item_row_tax, tax_accounts = get_tax_accounts(item_list, columns) + itemised_tax, tax_columns = get_tax_accounts(item_list, columns) columns.append({ "fieldname": "currency", "label": _("Currency"), @@ -26,6 +25,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum }) company_currency = frappe.db.get_value("Company", filters.get("company"), "default_currency") mode_of_payments = get_mode_of_payments(set([d.parent for d in item_list])) + so_dn_map = get_delivery_notes_against_sales_order(item_list) data = [] for d in item_list: @@ -33,8 +33,8 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum if d.delivery_note: delivery_note = d.delivery_note elif d.so_detail: - delivery_note = ", ".join(frappe.db.sql_list("""select distinct parent - from `tabDelivery Note Item` where docstatus=1 and so_detail=%s""", d.so_detail)) + delivery_note = ", ".join(so_dn_map.get(d.so_detail, [])) + if not delivery_note and d.update_stock: delivery_note = d.parent @@ -50,10 +50,12 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum delivery_note, d.income_account, d.cost_center, d.qty, d.base_net_rate, d.base_net_amount ] - for tax in tax_accounts: - row.append(item_row_tax.get(d.name, {}).get(tax, 0)) + total_tax = 0 + for tax in tax_columns: + item_tax = itemised_tax.get(d.name, {}).get(tax, {}) + row += [item_tax.get("tax_rate", 0), item_tax.get("tax_amount", 0)] + total_tax += flt(item_tax.get("tax_amount")) - total_tax = sum(row[last_col:]) row += [total_tax, d.base_net_amount + total_tax, company_currency] data.append(row) @@ -120,54 +122,90 @@ def get_items(filters, additional_query_columns): order by si.posting_date desc, si_item.item_code desc """.format(additional_query_columns or '') % conditions, filters, as_dict=1) -def get_tax_accounts(item_list, columns): +def get_delivery_notes_against_sales_order(item_list): + so_dn_map = frappe._dict() + so_item_rows = list(set([d.so_detail for d in item_list])) + + delivery_notes = frappe.db.sql(""" + select parent, so_detail + from `tabDelivery Note Item` + where docstatus=1 and so_detail in (%s) + group by so_detail, parent + """ % (', '.join(['%s']*len(so_item_rows))), tuple(so_item_rows), as_dict=1) + + for dn in delivery_notes: + so_dn_map.setdefault(dn.so_detail, []).append(dn.parent) + + return so_dn_map + +def get_tax_accounts(item_list, columns, tax_doctype="Sales Taxes and Charges"): import json - item_row_tax = {} - tax_accounts = [] - invoice_item_row = {} item_row_map = {} + tax_columns = [] + invoice_item_row = {} + itemised_tax = {} for d in item_list: invoice_item_row.setdefault(d.parent, []).append(d) item_row_map.setdefault(d.parent, {}).setdefault(d.item_code, []).append(d) tax_details = frappe.db.sql(""" select - parent, account_head, item_wise_tax_detail, + parent, description, item_wise_tax_detail, charge_type, base_tax_amount_after_discount_amount - from `tabSales Taxes and Charges` + from `tab%s` where parenttype = 'Sales Invoice' and docstatus = 1 - and (account_head is not null and account_head != '') + and (description is not null and description != '') and parent in (%s) - """ % ', '.join(['%s']*len(invoice_item_row)), tuple(invoice_item_row.keys())) + order by description + """ % (tax_doctype, ', '.join(['%s']*len(invoice_item_row))), tuple(invoice_item_row.keys())) - for parent, account_head, item_wise_tax_detail, charge_type, tax_amount in tax_details: - if account_head not in tax_accounts: - tax_accounts.append(account_head) + for parent, description, item_wise_tax_detail, charge_type, tax_amount in tax_details: + if description not in tax_columns and tax_amount: + tax_columns.append(description) if item_wise_tax_detail: try: item_wise_tax_detail = json.loads(item_wise_tax_detail) - for item_code, tax_amount in item_wise_tax_detail.items(): - tax_amount = flt(tax_amount[1]) if isinstance(tax_amount, list) else flt(tax_amount) + for item_code, tax_data in item_wise_tax_detail.items(): + itemised_tax.setdefault(item_code, frappe._dict()) + + if isinstance(tax_data, list): + tax_rate, tax_amount = tax_data + else: + tax_rate = tax_data + tax_amount = 0 + + if charge_type == "Actual" and not tax_rate: + tax_rate = "NA" item_net_amount = sum([flt(d.base_net_amount) for d in item_row_map.get(parent, {}).get(item_code, [])]) for d in item_row_map.get(parent, {}).get(item_code, []): - item_tax_amount = flt((tax_amount * d.base_net_amount) / item_net_amount) if item_net_amount else 0 - item_row_tax.setdefault(d.name, {})[account_head] = item_tax_amount + item_tax_amount = flt((tax_amount * d.base_net_amount) / item_net_amount) \ + if item_net_amount else 0 + if item_tax_amount: + itemised_tax.setdefault(d.name, {})[description] = frappe._dict({ + "tax_rate": tax_rate, + "tax_amount": item_tax_amount + }) except ValueError: continue elif charge_type == "Actual" and tax_amount: for d in invoice_item_row.get(parent, []): - item_row_tax.setdefault(d.name, {})[account_head] = \ - flt((tax_amount * d.base_net_amount) / d.base_net_total) + itemised_tax.setdefault(d.name, {})[description] = frappe._dict({ + "tax_rate": "NA", + "tax_amount": flt((tax_amount * d.base_net_amount) / d.base_net_total) + }) - tax_accounts.sort() - columns += [account_head + ":Currency/currency:80" for account_head in tax_accounts] - columns += ["Total Tax:Currency/currency:80", "Total:Currency/currency:80"] + tax_columns.sort() + for desc in tax_columns: + columns.append(desc + " Rate:Data:80") + columns.append(desc + " Amount:Currency/currency:100") - return item_row_tax, tax_accounts + columns += ["Total Tax:Currency/currency:80", "Total:Currency/currency:100"] + + return itemised_tax, tax_columns From 879e162cce039d891035e41e345fb954062b894b Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 21 Aug 2017 08:28:55 +0530 Subject: [PATCH 12/13] Additional GST related fields in Invoice and Sales/Purchase Register reort (#10405) --- .../doctype/sales_invoice/sales_invoice.js | 17 ---- erpnext/accounts/party.py | 2 +- .../item_wise_purchase_register.py | 10 ++- .../item_wise_sales_register.py | 11 +-- erpnext/patches.txt | 3 +- erpnext/patches/v8_7/__init__.py | 0 erpnext/patches/v8_7/add_more_gst_fields.py | 9 ++ erpnext/regional/india/setup.py | 63 ++++++++++---- .../gst_itemised_purchase_register.py | 8 ++ .../gst_itemised_sales_register.py | 10 +++ .../gst_purchase_register.py | 12 ++- .../gst_sales_register/gst_sales_register.py | 14 ++- .../doctype/sales_order/sales_order.py | 5 ++ erpnext/selling/sales_common.js | 17 ++++ .../doctype/delivery_note/delivery_note.json | 87 ++++++++++++++++--- 15 files changed, 204 insertions(+), 64 deletions(-) create mode 100644 erpnext/patches/v8_7/__init__.py create mode 100644 erpnext/patches/v8_7/add_more_gst_fields.py diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index c38645067c..ef233c6799 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -325,23 +325,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte } this.frm.refresh_fields(); - }, - - company_address: function() { - var me = this; - if(this.frm.doc.company_address) { - frappe.call({ - method: "frappe.contacts.doctype.address.address.get_address_display", - args: {"address_dict": this.frm.doc.company_address }, - callback: function(r) { - if(r.message) { - me.frm.set_value("company_address_display", r.message) - } - } - }) - } else { - this.frm.set_value("company_address_display", ""); - } } }); diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 5cb04c5eb6..ba7ae323d4 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -79,7 +79,7 @@ def set_address_details(out, party, party_type, doctype=None, company=None): out.shipping_address = get_address_display(out["shipping_address_name"]) out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name)) - if doctype and doctype in ['Sales Invoice']: + if doctype and doctype in ['Delivery Note', 'Sales Invoice']: out.update(get_company_address(company)) if out.company_address: out.update(get_fetch_values(doctype, 'company_address', out.company_address)) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 10862f5e2e..8f9948e41c 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -47,7 +47,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum row += [ d.credit_to, d.mode_of_payment, d.project, d.company, d.purchase_order, - purchase_receipt, expense_account, d.qty, d.base_net_rate, d.base_net_amount + purchase_receipt, expense_account, d.qty, d.stock_uom, d.base_net_rate, d.base_net_amount ] total_tax = 0 @@ -79,7 +79,8 @@ def get_columns(additional_table_columns): _("Mode of Payment") + ":Link/Mode of Payment:80", _("Project") + ":Link/Project:80", _("Company") + ":Link/Company:100", _("Purchase Order") + ":Link/Purchase Order:100", _("Purchase Receipt") + ":Link/Purchase Receipt:100", _("Expense Account") + ":Link/Account:140", - _("Qty") + ":Float:120", _("Rate") + ":Currency/currency:120", _("Amount") + ":Currency/currency:120" + _("Qty") + ":Float:120", _("Stock UOM") + "::100", + _("Rate") + ":Currency/currency:120", _("Amount") + ":Currency/currency:120" ] return columns @@ -109,8 +110,9 @@ def get_items(filters, additional_query_columns): pi_item.name, pi_item.parent, pi.posting_date, pi.credit_to, pi.company, pi.supplier, pi.remarks, pi.base_net_total, pi_item.item_code, pi_item.item_name, pi_item.item_group, pi_item.project, pi_item.purchase_order, pi_item.purchase_receipt, - pi_item.po_detail, pi_item.expense_account, pi_item.qty, pi_item.base_net_rate, - pi_item.base_net_amount, pi.supplier_name, pi.mode_of_payment {0} + pi_item.po_detail, pi_item.expense_account, pi_item.qty, pi_item.stock_uom, + pi_item.base_net_rate, pi_item.base_net_amount, + pi.supplier_name, pi.mode_of_payment {0} from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pi_item where pi.name = pi_item.parent and pi.docstatus = 1 %s %s order by pi.posting_date desc, pi_item.item_code desc diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index 37707cd402..30c545f58c 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -47,7 +47,8 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum row += [ d.customer_group, d.debit_to, ", ".join(mode_of_payments.get(d.parent, [])), d.territory, d.project, d.company, d.sales_order, - delivery_note, d.income_account, d.cost_center, d.qty, d.base_net_rate, d.base_net_amount + delivery_note, d.income_account, d.cost_center, d.qty, d.stock_uom, + d.base_net_rate, d.base_net_amount ] total_tax = 0 @@ -79,7 +80,7 @@ def get_columns(additional_table_columns): _("Project") + ":Link/Project:80", _("Company") + ":Link/Company:100", _("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100", _("Income Account") + ":Link/Account:140", _("Cost Center") + ":Link/Cost Center:140", - _("Qty") + ":Float:120", + _("Qty") + ":Float:120", _("Stock UOM") + "::100", _("Rate") + ":Currency/currency:120", _("Amount") + ":Currency/currency:120" ] @@ -114,9 +115,9 @@ def get_items(filters, additional_query_columns): si_item.name, si_item.parent, si.posting_date, si.debit_to, si.project, si.customer, si.remarks, si.territory, si.company, si.base_net_total, si_item.item_code, si_item.item_name, si_item.item_group, si_item.sales_order, - si_item.delivery_note, si_item.income_account, si_item.cost_center, si_item.qty, - si_item.base_net_rate, si_item.base_net_amount, si.customer_name, - si.customer_group, si_item.so_detail, si.update_stock {0} + si_item.delivery_note, si_item.income_account, si_item.cost_center, + si_item.qty, si_item.stock_uom, si_item.base_net_rate, si_item.base_net_amount, + si.customer_name, si.customer_group, si_item.so_detail, si.update_stock {0} from `tabSales Invoice` si, `tabSales Invoice Item` si_item where si.name = si_item.parent and si.docstatus = 1 %s order by si.posting_date desc, si_item.item_code desc diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 6b660e1e6d..d781ec788f 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -431,4 +431,5 @@ erpnext.patches.v8_5.set_default_mode_of_payment erpnext.patches.v8_5.update_customer_group_in_POS_profile erpnext.patches.v8_6.update_timesheet_company_from_PO erpnext.patches.v8_6.set_write_permission_for_quotation_for_sales_manager -erpnext.patches.v8_5.remove_project_type_property_setter \ No newline at end of file +erpnext.patches.v8_5.remove_project_type_property_setter +erpnext.patches.v8_7.add_more_gst_fields \ No newline at end of file diff --git a/erpnext/patches/v8_7/__init__.py b/erpnext/patches/v8_7/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/patches/v8_7/add_more_gst_fields.py b/erpnext/patches/v8_7/add_more_gst_fields.py new file mode 100644 index 0000000000..a1512ed9b7 --- /dev/null +++ b/erpnext/patches/v8_7/add_more_gst_fields.py @@ -0,0 +1,9 @@ +import frappe +from erpnext.regional.india.setup import make_custom_fields + +def execute(): + company = frappe.get_all('Company', filters = {'country': 'India'}) + if not company: + return + + make_custom_fields() \ No newline at end of file diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index 7a7e937ea4..0c59ba003a 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -81,6 +81,47 @@ def add_print_formats(): def make_custom_fields(): hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC', fieldtype='Data', options='item_code.gst_hsn_code', insert_after='description', print_hide=1) + invoice_gst_fields = [ + dict(fieldname='gst_section', label='GST Details', fieldtype='Section Break', + insert_after='select_print_heading', print_hide=1, collapsible=1), + dict(fieldname='invoice_copy', label='Invoice Copy', + fieldtype='Select', insert_after='gst_section', print_hide=1, allow_on_submit=1, + options='Original for Recipient\nDuplicate for Transporter\nDuplicate for Supplier\nTriplicate for Supplier'), + dict(fieldname='reverse_charge', label='Reverse Charge', + fieldtype='Select', insert_after='invoice_copy', print_hide=1, + options='Y\nN', default='N'), + dict(fieldname='gst_col_break', fieldtype='Column Break', insert_after='reverse_charge'), + dict(fieldname='invoice_type', label='Invoice Type', + fieldtype='Select', insert_after='reverse_charge', print_hide=1, + options='Regular\nSEZ\nExport\nDeemed Export', default='Regular'), + dict(fieldname='export_type', label='Export Type', + fieldtype='Select', insert_after='invoice_type', print_hide=1, + depends_on='eval:in_list(["SEZ", "Export", "Deemed Export"], doc.invoice_type)', + options='\nWith Payment of Tax\nWithout Payment of Tax'), + dict(fieldname='ecommerce_gstin', label='E-commerce GSTIN', + fieldtype='Data', insert_after='export_type', print_hide=1) + ] + + purchase_invoice_gst_fields = [ + dict(fieldname='supplier_gstin', label='Supplier GSTIN', + fieldtype='Data', insert_after='supplier_address', + options='supplier_address.gstin', print_hide=1), + dict(fieldname='company_gstin', label='Company GSTIN', + fieldtype='Data', insert_after='shipping_address', + options='shipping_address.gstin', print_hide=1) + ] + + sales_invoice_gst_fields = [ + dict(fieldname='customer_gstin', label='Customer GSTIN', + fieldtype='Data', insert_after='shipping_address', + options='shipping_address_name.gstin', print_hide=1), + dict(fieldname='place_of_supply', label='Place of Supply', + fieldtype='Data', insert_after='customer_gstin', print_hide=1, + options='shipping_address_name.gst_state_number', read_only=1), + dict(fieldname='company_gstin', label='Company GSTIN', + fieldtype='Data', insert_after='company_address', + options='company_address.gstin', print_hide=1) + ] custom_fields = { 'Address': [ @@ -91,25 +132,9 @@ def make_custom_fields(): dict(fieldname='gst_state_number', label='GST State Number', fieldtype='Int', insert_after='gst_state', read_only=1), ], - 'Purchase Invoice': [ - dict(fieldname='supplier_gstin', label='Supplier GSTIN', - fieldtype='Data', insert_after='supplier_address', - options='supplier_address.gstin', print_hide=1), - dict(fieldname='company_gstin', label='Company GSTIN', - fieldtype='Data', insert_after='shipping_address', - options='shipping_address.gstin', print_hide=1), - ], - 'Sales Invoice': [ - dict(fieldname='customer_gstin', label='Customer GSTIN', - fieldtype='Data', insert_after='shipping_address', - options='shipping_address_name.gstin', print_hide=1), - dict(fieldname='company_gstin', label='Company GSTIN', - fieldtype='Data', insert_after='company_address', - options='company_address.gstin', print_hide=1), - dict(fieldname='invoice_copy', label='Invoice Copy', - fieldtype='Select', insert_after='select_print_heading', print_hide=1, allow_on_submit=1, - options='Original for Recipient\nDuplicate for Transporter\nDuplicate for Supplier\nTriplicate for Supplier') - ], + 'Purchase Invoice': purchase_invoice_gst_fields + invoice_gst_fields, + 'Sales Invoice': sales_invoice_gst_fields + invoice_gst_fields, + "Delivery Note": sales_invoice_gst_fields, 'Item': [ dict(fieldname='gst_hsn_code', label='HSN/SAC', fieldtype='Link', options='GST HSN Code', insert_after='item_group'), diff --git a/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py b/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py index d88febcf33..1d94c97ed2 100644 --- a/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py +++ b/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py @@ -9,9 +9,17 @@ def execute(filters=None): return _execute(filters, additional_table_columns=[ dict(fieldtype='Data', label='Supplier GSTIN', width=120), dict(fieldtype='Data', label='Company GSTIN', width=120), + dict(fieldtype='Data', label='Reverse Charge', width=120), + dict(fieldtype='Data', label='Invoice Type', width=120), + dict(fieldtype='Data', label='Export Type', width=120), + dict(fieldtype='Data', label='E-Commerce GSTIN', width=130), dict(fieldtype='Data', label='HSN Code', width=120) ], additional_query_columns=[ 'supplier_gstin', 'company_gstin', + 'reverse_charge', + 'invoice_type', + 'export_type', + 'ecommerce_gstin', 'gst_hsn_code' ]) diff --git a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py index 14ddff3753..40bbae8b55 100644 --- a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py +++ b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py @@ -9,9 +9,19 @@ def execute(filters=None): return _execute(filters, additional_table_columns=[ dict(fieldtype='Data', label='Customer GSTIN', width=120), dict(fieldtype='Data', label='Company GSTIN', width=120), + dict(fieldtype='Data', label='Place of Supply', width=120), + dict(fieldtype='Data', label='Reverse Charge', width=120), + dict(fieldtype='Data', label='Invoice Type', width=120), + dict(fieldtype='Data', label='Export Type', width=120), + dict(fieldtype='Data', label='E-Commerce GSTIN', width=130), dict(fieldtype='Data', label='HSN Code', width=120) ], additional_query_columns=[ 'customer_gstin', 'company_gstin', + 'place_of_supply', + 'reverse_charge', + 'invoice_type', + 'export_type', + 'ecommerce_gstin', 'gst_hsn_code' ]) diff --git a/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py b/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py index 59687d0086..8d479a96cd 100644 --- a/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py +++ b/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py @@ -8,9 +8,17 @@ from erpnext.accounts.report.purchase_register.purchase_register import _execute def execute(filters=None): return _execute(filters, additional_table_columns=[ dict(fieldtype='Data', label='Supplier GSTIN', width=120), - dict(fieldtype='Data', label='Company GSTIN', width=120) + dict(fieldtype='Data', label='Company GSTIN', width=120), + dict(fieldtype='Data', label='Reverse Charge', width=120), + dict(fieldtype='Data', label='Invoice Type', width=120), + dict(fieldtype='Data', label='Export Type', width=120), + dict(fieldtype='Data', label='E-Commerce GSTIN', width=130) ], additional_query_columns=[ 'supplier_gstin', - 'company_gstin' + 'company_gstin', + 'reverse_charge', + 'invoice_type', + 'export_type', + 'ecommerce_gstin' ]) diff --git a/erpnext/regional/report/gst_sales_register/gst_sales_register.py b/erpnext/regional/report/gst_sales_register/gst_sales_register.py index 440594abb0..7f6f809276 100644 --- a/erpnext/regional/report/gst_sales_register/gst_sales_register.py +++ b/erpnext/regional/report/gst_sales_register/gst_sales_register.py @@ -8,8 +8,18 @@ from erpnext.accounts.report.sales_register.sales_register import _execute def execute(filters=None): return _execute(filters, additional_table_columns=[ dict(fieldtype='Data', label='Customer GSTIN', width=120), - dict(fieldtype='Data', label='Company GSTIN', width=120) + dict(fieldtype='Data', label='Company GSTIN', width=120), + dict(fieldtype='Data', label='Place of Supply', width=120), + dict(fieldtype='Data', label='Reverse Charge', width=120), + dict(fieldtype='Data', label='Invoice Type', width=120), + dict(fieldtype='Data', label='Export Type', width=120), + dict(fieldtype='Data', label='E-Commerce GSTIN', width=130) ], additional_query_columns=[ 'customer_gstin', - 'company_gstin' + 'company_gstin', + 'place_of_supply', + 'reverse_charge', + 'invoice_type', + 'export_type', + 'ecommerce_gstin' ]) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index b16169bfd7..396b1c2f61 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -466,6 +466,11 @@ def make_delivery_note(source_name, target_doc=None): target.ignore_pricing_rule = 1 target.run_method("set_missing_values") target.run_method("calculate_taxes_and_totals") + + # set company address + target.update(get_company_address(target.company)) + if target.company_address: + target.update(get_fetch_values("Delivery Note", 'company_address', target.company_address)) def update_item(source, target, source_parent): target.base_amount = (flt(source.qty) - flt(source.delivered_qty)) * flt(source.base_rate) diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index 6a84d0e09b..e9671c8711 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -326,6 +326,23 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ this.calculate_taxes_and_totals(); cur_frm.refresh_fields(); } + }, + + company_address: function() { + var me = this; + if(this.frm.doc.company_address) { + frappe.call({ + method: "frappe.contacts.doctype.address.address.get_address_display", + args: {"address_dict": this.frm.doc.company_address }, + callback: function(r) { + if(r.message) { + me.frm.set_value("company_address_display", r.message) + } + } + }) + } else { + this.frm.set_value("company_address_display", ""); + } } }); diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json index 345750f04a..4477c1d0ec 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.json +++ b/erpnext/stock/doctype/delivery_note/delivery_note.json @@ -860,22 +860,22 @@ "bold": 0, "collapsible": 0, "columns": 0, - "description": "", - "fieldname": "customer_group", + "fieldname": "company_address", "fieldtype": "Link", - "hidden": 1, + "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": "Customer Group", + "label": "Company Address Name", "length": 0, "no_copy": 0, - "options": "Customer Group", + "options": "Address", "permlevel": 0, - "print_hide": 1, + "precision": "", + "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, @@ -891,9 +891,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "description": "", - "fieldname": "territory", - "fieldtype": "Link", + "fieldname": "company_address_display", + "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -901,12 +900,12 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Territory", + "label": "Company Address", "length": 0, "no_copy": 0, - "options": "Territory", "permlevel": 0, - "print_hide": 1, + "precision": "", + "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, @@ -2757,6 +2756,68 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "", + "fieldname": "customer_group", + "fieldtype": "Link", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Customer Group", + "length": 0, + "no_copy": 0, + "options": "Customer Group", + "permlevel": 0, + "print_hide": 1, + "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, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "", + "fieldname": "territory", + "fieldtype": "Link", + "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": "Territory", + "length": 0, + "no_copy": 0, + "options": "Territory", + "permlevel": 0, + "print_hide": 1, + "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, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -3426,7 +3487,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2017-07-19 13:48:09.630820", + "modified": "2017-08-09 15:44:14.253457", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note", From ddb26d02e53af04facc5ff1de954b455a71f5ab7 Mon Sep 17 00:00:00 2001 From: mbauskar Date: Mon, 21 Aug 2017 09:27:32 +0600 Subject: [PATCH 13/13] bumped to version 8.8.4 --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index fb7c761e4f..1d47f02b41 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from erpnext.hooks import regional_overrides -__version__ = '8.8.3' +__version__ = '8.8.4' def get_default_company(user=None): '''Get default company for user'''