From 4448e2d66bb224deee3a6dda181a358223d3c480 Mon Sep 17 00:00:00 2001 From: NahuelOperto Date: Fri, 21 Jun 2019 08:50:37 -0300 Subject: [PATCH 01/95] fix order in general ledger --- erpnext/accounts/report/general_ledger/general_ledger.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index 1c5e089534..2924907e8f 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -11,6 +11,7 @@ from erpnext.accounts.utils import get_account_currency from erpnext.accounts.report.financial_statements import get_cost_centers_with_children from six import iteritems from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions +from collections import OrderedDict def execute(filters=None): if not filters: @@ -267,7 +268,7 @@ def group_by_field(group_by): return 'voucher_no' def initialize_gle_map(gl_entries, filters): - gle_map = frappe._dict() + gle_map = OrderedDict() group_by = group_by_field(filters.get('group_by')) for gle in gl_entries: From 42fe68d06513a71d3f237510b32f69e29c634fdc Mon Sep 17 00:00:00 2001 From: NahuelOperto Date: Mon, 24 Jun 2019 08:29:14 -0300 Subject: [PATCH 02/95] feat: order type in trr type filter --- .../report/sales_analytics/sales_analytics.js | 2 +- .../report/sales_analytics/sales_analytics.py | 73 ++++++++++++++----- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.js b/erpnext/selling/report/sales_analytics/sales_analytics.js index fbe045bf35..149c923d5c 100644 --- a/erpnext/selling/report/sales_analytics/sales_analytics.js +++ b/erpnext/selling/report/sales_analytics/sales_analytics.js @@ -8,7 +8,7 @@ frappe.query_reports["Sales Analytics"] = { fieldname: "tree_type", label: __("Tree Type"), fieldtype: "Select", - options: ["Customer Group","Customer","Item Group","Item","Territory"], + options: ["Customer Group","Customer","Item Group","Item","Territory","Order Type"], default: "Customer", reqd: 1 }, diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.py b/erpnext/selling/report/sales_analytics/sales_analytics.py index 3239fc626f..8a5e50a61e 100644 --- a/erpnext/selling/report/sales_analytics/sales_analytics.py +++ b/erpnext/selling/report/sales_analytics/sales_analytics.py @@ -23,15 +23,15 @@ class Analytics(object): self.get_columns() self.get_data() self.get_chart_data() - return self.columns, self.data , None, self.chart + return self.columns, self.data, None, self.chart def get_columns(self): - self.columns =[{ + self.columns = [{ "label": _(self.filters.tree_type + " ID"), - "options": self.filters.tree_type, + "options": self.filters.tree_type if self.filters.tree_type != "Order Type" else "", "fieldname": "entity", - "fieldtype": "Link", - "width": 140 + "fieldtype": "Link" if self.filters.tree_type != "Order Type" else "Data", + "width": 140 if self.filters.tree_type != "Order Type" else 200 }] if self.filters.tree_type in ["Customer", "Supplier", "Item"]: self.columns.append({ @@ -73,6 +73,28 @@ class Analytics(object): self.get_sales_transactions_based_on_item_group() self.get_rows_by_group() + elif self.filters.tree_type == "Order Type": + if self.filters.doc_type != "Sales Order": + self.data = [] + return + self.get_sales_transactions_based_on_order_type() + self.get_rows_by_group() + + def get_sales_transactions_based_on_order_type(self): + if self.filters["value_quantity"] == 'Value': + value_field = "base_net_total" + else: + value_field = "total_qty" + + self.entries = frappe.db.sql(""" select s.order_type as entity, s.{value_field} as value_field, s.{date_field} + from `tab{doctype}` s where s.docstatus = 1 and s.company = %s and s.{date_field} between %s and %s + and ifnull(s.order_type, '') != '' order by s.order_type + """ + .format(date_field=self.date_field, value_field=value_field, doctype=self.filters.doc_type), + (self.filters.company, self.filters.from_date, self.filters.to_date), as_dict=1) + + self.get_teams() + def get_sales_transactions_based_on_customers_or_suppliers(self): if self.filters["value_quantity"] == 'Value': value_field = "base_net_total as value_field" @@ -88,7 +110,7 @@ class Analytics(object): self.entries = frappe.get_all(self.filters.doc_type, fields=[entity, entity_name, value_field, self.date_field], - filters = { + filters={ "docstatus": 1, "company": self.filters.company, self.date_field: ('between', [self.filters.from_date, self.filters.to_date]) @@ -112,7 +134,7 @@ class Analytics(object): where s.name = i.parent and i.docstatus = 1 and s.company = %s and s.{date_field} between %s and %s """ - .format(date_field=self.date_field, value_field = value_field, doctype=self.filters.doc_type), + .format(date_field=self.date_field, value_field=value_field, doctype=self.filters.doc_type), (self.filters.company, self.filters.from_date, self.filters.to_date), as_dict=1) self.entity_names = {} @@ -135,7 +157,7 @@ class Analytics(object): self.entries = frappe.get_all(self.filters.doc_type, fields=[entity_field, value_field, self.date_field], - filters = { + filters={ "docstatus": 1, "company": self.filters.company, self.date_field: ('between', [self.filters.from_date, self.filters.to_date]) @@ -154,13 +176,13 @@ class Analytics(object): from `tab{doctype} Item` i , `tab{doctype}` s where s.name = i.parent and i.docstatus = 1 and s.company = %s and s.{date_field} between %s and %s - """.format(date_field=self.date_field, value_field = value_field, doctype=self.filters.doc_type), + """.format(date_field=self.date_field, value_field=value_field, doctype=self.filters.doc_type), (self.filters.company, self.filters.from_date, self.filters.to_date), as_dict=1) self.get_groups() def get_rows(self): - self.data=[] + self.data = [] self.get_periodic_data() for entity, period_data in iteritems(self.entity_periodic_data): @@ -192,7 +214,7 @@ class Analytics(object): period = self.get_period(end_date) amount = flt(self.entity_periodic_data.get(d.name, {}).get(period, 0.0)) row[scrub(period)] = amount - if d.parent: + if d.parent and (self.filters.tree_type != "Order Type" or d.parent == "Order Types"): self.entity_periodic_data.setdefault(d.parent, frappe._dict()).setdefault(period, 0.0) self.entity_periodic_data[d.parent][period] += amount total += amount @@ -216,7 +238,7 @@ class Analytics(object): elif self.filters.range == 'Monthly': period = str(self.months[posting_date.month - 1]) + " " + str(posting_date.year) elif self.filters.range == 'Quarterly': - period = "Quarter " + str(((posting_date.month-1)//3)+1) +" " + str(posting_date.year) + period = "Quarter " + str(((posting_date.month - 1) // 3) + 1) + " " + str(posting_date.year) else: year = get_fiscal_year(posting_date, company=self.filters.company) period = str(year[0]) @@ -234,7 +256,7 @@ class Analytics(object): }.get(self.filters.range, 1) if self.filters.range in ['Monthly', 'Quarterly']: - from_date = from_date.replace(day = 1) + from_date = from_date.replace(day=1) elif self.filters.range == "Yearly": from_date = get_fiscal_year(from_date)[1] else: @@ -270,7 +292,22 @@ class Analytics(object): self.group_entries = frappe.db.sql("""select name, lft, rgt , {parent} as parent from `tab{tree}` order by lft""" - .format(tree=self.filters.tree_type, parent=parent), as_dict=1) + .format(tree=self.filters.tree_type, parent=parent), as_dict=1) + + for d in self.group_entries: + if d.parent: + self.depth_map.setdefault(d.name, self.depth_map.get(d.parent) + 1) + else: + self.depth_map.setdefault(d.name, 0) + + def get_teams(self): + self.depth_map = frappe._dict() + + self.group_entries = frappe.db.sql(""" select * from (select "Order Types" as name, 0 as lft, + 2 as rgt, '' as parent union select distinct order_type as name, 1 as lft, 1 as rgt, "Order Types" as parent + from `tab{doctype}` where ifnull(order_type, '') != '') as b order by lft, name + """ + .format(doctype=self.filters.doc_type), as_dict=1) for d in self.group_entries: if d.parent: @@ -285,13 +322,13 @@ class Analytics(object): length = len(self.columns) if self.filters.tree_type in ["Customer", "Supplier", "Item"]: - labels = [d.get("label") for d in self.columns[2:length-1]] + labels = [d.get("label") for d in self.columns[2:length - 1]] else: - labels = [d.get("label") for d in self.columns[1:length-1]] + labels = [d.get("label") for d in self.columns[1:length - 1]] self.chart = { "data": { 'labels': labels, - 'datasets':[] + 'datasets': [] }, "type": "line" - } \ No newline at end of file + } From c41403c8a987b632c776da9b8b5f07cf5d9e7db3 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 27 Jun 2019 16:33:19 +0530 Subject: [PATCH 03/95] fix: remove move and add buttons from stock summary --- erpnext/stock/dashboard/item_dashboard.js | 99 +------------------ .../stock/dashboard/item_dashboard_list.html | 15 --- 2 files changed, 1 insertion(+), 113 deletions(-) diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js index 157dbfe174..f820b7aa86 100644 --- a/erpnext/stock/dashboard/item_dashboard.js +++ b/erpnext/stock/dashboard/item_dashboard.js @@ -16,18 +16,6 @@ erpnext.stock.ItemDashboard = Class.extend({ this.content = $(frappe.render_template('item_dashboard')).appendTo(this.parent); this.result = this.content.find('.result'); - // move - this.content.on('click', '.btn-move', function() { - erpnext.stock.move_item(unescape($(this).attr('data-item')), $(this).attr('data-warehouse'), - null, $(this).attr('data-actual_qty'), null, function() { me.refresh(); }); - }); - - this.content.on('click', '.btn-add', function() { - erpnext.stock.move_item(unescape($(this).attr('data-item')), null, $(this).attr('data-warehouse'), - $(this).attr('data-actual_qty'), $(this).attr('data-rate'), - function() { me.refresh(); }); - }); - // more this.content.find('.btn-more').on('click', function() { me.start += 20; @@ -111,89 +99,4 @@ erpnext.stock.ItemDashboard = Class.extend({ show_item: show_item || false } } -}) - -erpnext.stock.move_item = function(item, source, target, actual_qty, rate, callback) { - var dialog = new frappe.ui.Dialog({ - title: target ? __('Add Item') : __('Move Item'), - fields: [ - {fieldname: 'item_code', label: __('Item'), - fieldtype: 'Link', options: 'Item', read_only: 1}, - {fieldname: 'source', label: __('Source Warehouse'), - fieldtype: 'Link', options: 'Warehouse', read_only: 1}, - {fieldname: 'target', label: __('Target Warehouse'), - fieldtype: 'Link', options: 'Warehouse', reqd: 1}, - {fieldname: 'qty', label: __('Quantity'), reqd: 1, - fieldtype: 'Float', description: __('Available {0}', [actual_qty]) }, - {fieldname: 'rate', label: __('Rate'), fieldtype: 'Currency', hidden: 1 }, - ], - }) - dialog.show(); - dialog.get_field('item_code').set_input(item); - - if(source) { - dialog.get_field('source').set_input(source); - } else { - dialog.get_field('source').df.hidden = 1; - dialog.get_field('source').refresh(); - } - - if(rate) { - dialog.get_field('rate').set_value(rate); - dialog.get_field('rate').df.hidden = 0; - dialog.get_field('rate').refresh(); - } - - if(target) { - dialog.get_field('target').df.read_only = 1; - dialog.get_field('target').value = target; - dialog.get_field('target').refresh(); - } - - dialog.set_primary_action(__('Submit'), function() { - var values = dialog.get_values(); - if(!values) { - return; - } - if(source && values.qty > actual_qty) { - frappe.msgprint(__('Quantity must be less than or equal to {0}', [actual_qty])); - return; - } - if(values.source === values.target) { - frappe.msgprint(__('Source and target warehouse must be different')); - } - - frappe.call({ - method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry', - args: values, - freeze: true, - callback: function(r) { - frappe.show_alert(__('Stock Entry {0} created', - ['' + r.message.name+ ''])); - dialog.hide(); - callback(r); - }, - }); - }); - - $('

' - + __("Add more items or open full form") + '

') - .appendTo(dialog.body) - .find('.link-open') - .on('click', function() { - frappe.model.with_doctype('Stock Entry', function() { - var doc = frappe.model.get_new_doc('Stock Entry'); - doc.from_warehouse = dialog.get_value('source'); - doc.to_warehouse = dialog.get_value('target'); - var row = frappe.model.add_child(doc, 'items'); - row.item_code = dialog.get_value('item_code'); - row.f_warehouse = dialog.get_value('target'); - row.t_warehouse = dialog.get_value('target'); - row.qty = dialog.get_value('qty'); - row.conversion_factor = 1; - row.transfer_qty = dialog.get_value('qty'); - row.basic_rate = dialog.get_value('rate'); - frappe.set_route('Form', doc.doctype, doc.name); - }) - }); -} \ No newline at end of file +}) \ No newline at end of file diff --git a/erpnext/stock/dashboard/item_dashboard_list.html b/erpnext/stock/dashboard/item_dashboard_list.html index 5a3fa2ed48..f0e87b1c53 100644 --- a/erpnext/stock/dashboard/item_dashboard_list.html +++ b/erpnext/stock/dashboard/item_dashboard_list.html @@ -39,21 +39,6 @@ - {% if can_write %} -
- {% if d.actual_qty %} -
- {% endif %} {% endfor %} From 126a02e2084cd7c5e9d3035d38692a068e2ff8f8 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 2 Jul 2019 15:28:57 +0530 Subject: [PATCH 04/95] fix: set invoice status considering invoice discounting --- .../discounted_invoice.json | 147 +--- .../invoice_discounting.json | 674 ++---------------- .../invoice_discounting.py | 33 +- .../doctype/journal_entry/journal_entry.py | 18 +- .../doctype/sales_invoice/sales_invoice.js | 13 +- .../doctype/sales_invoice/sales_invoice.json | 13 +- .../doctype/sales_invoice/sales_invoice.py | 66 +- .../sales_invoice/sales_invoice_list.js | 23 +- .../doctype/purchase_order/purchase_order.py | 1 - erpnext/controllers/status_updater.py | 2 + 10 files changed, 206 insertions(+), 784 deletions(-) diff --git a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json index 0d04b19fd1..8d7ed74eb9 100644 --- a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json +++ b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json @@ -1,177 +1,64 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, "creation": "2019-03-07 12:07:09.416101", - "custom": 0, - "docstatus": 0, "doctype": "DocType", - "document_type": "", "editable_grid": 1, "engine": "InnoDB", + "field_order": [ + "sales_invoice", + "customer", + "column_break_3", + "posting_date", + "outstanding_amount" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "sales_invoice", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Invoice", - "length": 0, - "no_copy": 0, "options": "Sales Invoice", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "sales_invoice.customer", "fieldname": "customer", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Customer", - "length": 0, - "no_copy": 0, "options": "Customer", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "sales_invoice.posting_date", "fieldname": "posting_date", "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "sales_invoice.grand_total", "fieldname": "outstanding_amount", "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Outstanding Amount", - "length": 0, - "no_copy": 0, "options": "Company:company:default_currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 + }, + { + "fieldname": "column_break_3", + "fieldtype": "Column Break" } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, "istable": 1, - "max_attachments": 0, - "modified": "2019-03-07 16:38:03.622666", + "modified": "2019-05-30 19:27:29.436153", "modified_by": "Administrator", "module": "Accounts", "name": "Discounted Invoice", - "name_case": "", "owner": "Administrator", "permissions": [], "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.json b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.json index 8927ca708d..3bfe259432 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.json +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.json @@ -1,744 +1,177 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, "allow_import": 1, - "allow_rename": 0, "autoname": "ACC-INV-DISC-.YYYY.-.#####", - "beta": 0, "creation": "2019-03-07 12:01:56.296952", - "custom": 0, - "docstatus": 0, "doctype": "DocType", - "document_type": "", "editable_grid": 1, "engine": "InnoDB", + "field_order": [ + "posting_date", + "loan_start_date", + "loan_period", + "loan_end_date", + "column_break_3", + "status", + "company", + "section_break_5", + "invoices", + "section_break_7", + "total_amount", + "column_break_9", + "bank_charges", + "section_break_6", + "short_term_loan", + "bank_account", + "bank_charges_account", + "column_break_15", + "accounts_receivable_credit", + "accounts_receivable_discounted", + "accounts_receivable_unpaid", + "amended_from" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "Today", "fieldname": "posting_date", "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Posting Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "loan_start_date", "fieldtype": "Date", - "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": "Loan Start Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Loan Start Date" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "loan_period", "fieldtype": "Int", - "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": "Loan Period", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Loan Period (Days)" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "loan_end_date", "fieldtype": "Date", - "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": "Loan End Date", - "length": 0, "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_3", - "fieldtype": "Column Break", - "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, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "status", "fieldtype": "Select", - "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": "Status", - "length": 0, "no_copy": 1, "options": "Draft\nSanctioned\nDisbursed\nSettled\nCancelled", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "company", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Company", - "length": 0, - "no_copy": 0, "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "section_break_5", - "fieldtype": "Section Break", - "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, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Section Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "invoices", "fieldtype": "Table", - "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": "Invoices", - "length": 0, - "no_copy": 0, "options": "Discounted Invoice", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "section_break_7", - "fieldtype": "Section Break", - "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, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Section Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "total_amount", "fieldtype": "Currency", - "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": "Total Amount", - "length": 0, - "no_copy": 0, "options": "Company:company:default_currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_9", - "fieldtype": "Column Break", - "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, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "bank_charges", "fieldtype": "Currency", - "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": "Bank Charges", - "length": 0, - "no_copy": 0, - "options": "Company:company:default_currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Company:company:default_currency" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "section_break_6", - "fieldtype": "Section Break", - "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, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Section Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "short_term_loan", "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": "Short Term Loan Account", - "length": 0, - "no_copy": 0, "options": "Account", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "bank_account", "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": "Bank Account", - "length": 0, - "no_copy": 0, "options": "Account", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "bank_charges_account", "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": "Bank Charges Account", - "length": 0, - "no_copy": 0, "options": "Account", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_15", - "fieldtype": "Column Break", - "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, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "accounts_receivable_credit", "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": "Accounts Receivable Credit Account", - "length": 0, - "no_copy": 0, "options": "Account", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "accounts_receivable_discounted", "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": "Accounts Receivable Discounted Account", - "length": 0, - "no_copy": 0, "options": "Account", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "accounts_receivable_unpaid", "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": "Accounts Receivable Unpaid Account", - "length": 0, - "no_copy": 0, "options": "Account", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "amended_from", "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": "Amended From", - "length": 0, "no_copy": 1, "options": "Invoice Discounting", - "permlevel": 0, "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2019-03-08 14:24:31.222027", + "modified": "2019-05-30 19:08:21.199759", "modified_by": "Administrator", "module": "Accounts", "name": "Invoice Discounting", - "name_case": "", "owner": "Administrator", "permissions": [ { @@ -748,26 +181,17 @@ "delete": 1, "email": 1, "export": 1, - "if_owner": 0, "import": 1, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "System Manager", - "set_user_permissions": 0, "share": 1, "submit": 1, "write": 1 } ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py index c8756af7d7..29475d5644 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py @@ -28,18 +28,39 @@ class InvoiceDiscounting(AccountsController): self.total_amount = sum([flt(d.outstanding_amount) for d in self.invoices]) def on_submit(self): + self.update_sales_invoice() self.make_gl_entries() def on_cancel(self): self.set_status() + self.update_sales_invoice() self.make_gl_entries() - def set_status(self): - self.status = "Draft" - if self.docstatus == 1: - self.status = "Sanctioned" - elif self.docstatus == 2: - self.status = "Cancelled" + def set_status(self, status=None): + if status: + self.status = status + self.db_set("status", status) + for d in self.invoices: + frappe.get_doc("Sales Invoice", d.sales_invoice).set_status(update=True, update_modified=False) + else: + self.status = "Draft" + if self.docstatus == 1: + self.status = "Sanctioned" + elif self.docstatus == 2: + self.status = "Cancelled" + + def update_sales_invoice(self): + for d in self.invoices: + if self.docstatus == 1: + is_discounted = 1 + else: + discounted_invoice = frappe.db.exists({ + "doctype": "Discounted Invoice", + "sales_invoice": d.sales_invoice, + "docstatus": 1 + }) + is_discounted = 1 if discounted_invoice else 0 + frappe.db.set_value("Sales Invoice", d.sales_invoice, "is_discounted", is_discounted) def make_gl_entries(self): company_currency = frappe.get_cached_value('Company', self.company, "default_currency") diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index d082b60211..a9929c379d 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -105,24 +105,28 @@ class JournalEntry(AccountsController): invoice_discounting_list = list(set([d.reference_name for d in self.accounts if d.reference_type=="Invoice Discounting"])) for inv_disc in invoice_discounting_list: - short_term_loan_account, id_status = frappe.db.get_value("Invoice Discounting", inv_disc, ["short_term_loan", "status"]) + inv_disc_doc = frappe.get_doc("Invoice Discounting", inv_disc) + status = None for d in self.accounts: - if d.account == short_term_loan_account and d.reference_name == inv_disc: + if d.account == inv_disc_doc.short_term_loan and d.reference_name == inv_disc: if self.docstatus == 1: if d.credit > 0: - _validate_invoice_discounting_status(inv_disc, id_status, "Sanctioned", d.idx) + _validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Sanctioned", d.idx) status = "Disbursed" elif d.debit > 0: - _validate_invoice_discounting_status(inv_disc, id_status, "Disbursed", d.idx) + _validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Disbursed", d.idx) status = "Settled" else: if d.credit > 0: - _validate_invoice_discounting_status(inv_disc, id_status, "Disbursed", d.idx) + _validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Disbursed", d.idx) status = "Sanctioned" elif d.debit > 0: - _validate_invoice_discounting_status(inv_disc, id_status, "Settled", d.idx) + _validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Settled", d.idx) status = "Disbursed" - frappe.db.set_value("Invoice Discounting", inv_disc, "status", status) + break + if status: + inv_disc_doc.set_status(status=status) + def unlink_advance_entry_reference(self): for d in self.get("accounts"): diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 07494a27d6..eaf59d3bf5 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -83,10 +83,14 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte } } - if (doc.outstanding_amount>0 && !cint(doc.is_return)) { + if (doc.outstanding_amount>0) { cur_frm.add_custom_button(__('Payment Request'), function() { me.make_payment_request(); }, __('Create')); + + cur_frm.add_custom_button(__('Invoice Discounting'), function() { + cur_frm.events.create_invoice_discounting(cur_frm); + }, __('Create')); } if (doc.docstatus === 1) { @@ -804,6 +808,13 @@ frappe.ui.form.on('Sales Invoice', { frm.set_df_property("patient_name", "hidden", 1); frm.set_df_property("ref_practitioner", "hidden", 1); } + }, + + create_invoice_discounting: function(frm) { + frappe.model.open_mapped_doc({ + method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.create_invoice_discounting", + frm: frm + }); } }) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 292d95d7b6..c0a1abd785 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -155,6 +155,7 @@ "inter_company_invoice_reference", "customer_group", "campaign", + "is_discounted", "col_break23", "status", "source", @@ -1336,7 +1337,7 @@ "in_standard_filter": 1, "label": "Status", "no_copy": 1, - "options": "\nDraft\nReturn\nCredit Note Issued\nSubmitted\nPaid\nUnpaid\nOverdue\nCancelled", + "options": "\nDraft\nReturn\nCredit Note Issued\nSubmitted\nPaid\nUnpaid\nUnpaid and Discounted\nOverdue and Discounted\nOverdue\nOverdue\nCancelled", "print_hide": 1, "read_only": 1 }, @@ -1553,12 +1554,20 @@ { "fieldname": "dimension_col_break", "fieldtype": "Column Break" + }, + { + "default": "0", + "fieldname": "is_discounted", + "fieldtype": "Check", + "label": "Is Discounted", + "no_copy": 1, + "read_only": 1 } ], "icon": "fa fa-file-text", "idx": 181, "is_submittable": 1, - "modified": "2019-05-25 22:05:03.474745", + "modified": "2019-07-02 15:21:40.257028", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index d6cf5d8b90..54e127d2f4 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1174,6 +1174,56 @@ class SalesInvoice(SellingController): self.set_missing_values(for_validate = True) + def get_discounting_status(self): + status = None + if self.is_discounted: + invoice_discounting_list = frappe.db.sql(""" + select status + from `tabInvoice Discounting` id, `tabDiscounted Invoice` d + where + id.name = d.parent + and d.sales_invoice=%s + and id.docstatus=1 + and status in ('Disbursed', 'Settled') + """, self.name) + for d in invoice_discounting_list: + status = d[0] + if status == "Disbursed": + break + return status + + def set_status(self, update=False, status=None, update_modified=True): + if self.is_new(): + if self.get('amended_from'): + self.status = 'Draft' + return + + if not status: + if self.docstatus == 2: + status = "Cancelled" + elif self.docstatus == 1: + if flt(self.outstanding_amount) > 0 and getdate(self.due_date) < getdate(nowdate()) and self.is_discounted and self.get_discounting_status()=='Disbursed': + self.status = "Overdue and Discounted" + elif self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()): + self.status = "Overdue" + elif self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.is_discounted and self.get_discounting_status()=='Disbursed': + self.status = "Unpaid and Discounted" + elif self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()): + self.status = "Unpaid" + elif self.outstanding_amount < 0 and self.is_return==0 and get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}): + self.status = "Credit Note Issued" + elif self.outstanding_amount<=0 and self.is_return==0: + self.status = "Paid" + elif self.is_return == 1: + self.status = "Return" + else: + self.status = "Submitted" + else: + self.status = "Draft" + + if update: + self.db_set('status', self.status, update_modified = update_modified) + def validate_inter_company_party(doctype, party, company, inter_company_reference): if not party: return @@ -1428,4 +1478,18 @@ def get_loyalty_programs(customer): frappe.db.set(customer, 'loyalty_program', lp_details[0]) return [] else: - return lp_details \ No newline at end of file + return lp_details + +@frappe.whitelist() +def create_invoice_discounting(source_name, target_doc=None): + invoice = frappe.get_doc("Sales Invoice", source_name) + invoice_discounting = frappe.new_doc("Invoice Discounting") + invoice_discounting.company = invoice.company + invoice_discounting.append("invoices", { + "sales_invoice": source_name, + "customer": invoice.customer, + "posting_date": invoice.posting_date, + "outstanding_amount": invoice.outstanding_amount + }) + + return invoice_discounting \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js index 3c9c4b428d..05d49df711 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js @@ -6,17 +6,18 @@ frappe.listview_settings['Sales Invoice'] = { add_fields: ["customer", "customer_name", "base_grand_total", "outstanding_amount", "due_date", "company", "currency", "is_return"], get_indicator: function(doc) { - if(cint(doc.is_return)==1) { - return [__("Return"), "darkgrey", "is_return,=,Yes"]; - } else if(flt(doc.outstanding_amount)==0) { - return [__("Paid"), "green", "outstanding_amount,=,0"] - } else if(flt(doc.outstanding_amount) < 0) { - return [__("Credit Note Issued"), "darkgrey", "outstanding_amount,<,0"] - }else if (flt(doc.outstanding_amount) > 0 && doc.due_date >= frappe.datetime.get_today()) { - return [__("Unpaid"), "orange", "outstanding_amount,>,0|due_date,>,Today"] - } else if (flt(doc.outstanding_amount) > 0 && doc.due_date < frappe.datetime.get_today()) { - return [__("Overdue"), "red", "outstanding_amount,>,0|due_date,<=,Today"] - } + var status_color = { + "Draft": "grey", + "Unpaid": "orange", + "Paid": "green", + "Return": "darkgrey", + "Credit Note Issued": "darkgrey", + "Unpaid and Discounted": "orange", + "Overdue and Discounted": "red", + "Overdue": "red" + + }; + return [__(doc.status), status_color[doc.status], "status,=,"+doc.status]; }, right_column: "grand_total" }; diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index a9a2094f08..8117d9d514 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -510,4 +510,3 @@ def update_status(status, name): def make_inter_company_sales_order(source_name, target_doc=None): from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction return make_inter_company_transaction("Purchase Order", source_name, target_doc) - diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 42e0a43e6e..c7542a8951 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -50,7 +50,9 @@ status_map = { ["Paid", "eval:self.outstanding_amount<=0 and self.docstatus==1 and self.is_return==0"], ["Credit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1 and self.is_return==0 and get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"], ["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"], + ["Unpaid and Discounted", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1 and self.is_discounted and self.discounting_status=='Disbursed'"], ["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"], + ["Overdue and Discounted", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1 and self.is_discounted and self.discounting_status=='Disbursed'"], ["Cancelled", "eval:self.docstatus==2"], ], "Purchase Invoice": [ From 3bbcd491e4e1ccabddef3051796beae93834c16c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 2 Jul 2019 15:31:24 +0530 Subject: [PATCH 05/95] fix: set invoice status considering invoice discounting --- erpnext/controllers/status_updater.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index c7542a8951..db6460f00c 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -43,18 +43,6 @@ status_map = { ["Closed", "eval:self.status=='Closed'"], ["On Hold", "eval:self.status=='On Hold'"], ], - "Sales Invoice": [ - ["Draft", None], - ["Submitted", "eval:self.docstatus==1"], - ["Return", "eval:self.is_return==1 and self.docstatus==1"], - ["Paid", "eval:self.outstanding_amount<=0 and self.docstatus==1 and self.is_return==0"], - ["Credit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1 and self.is_return==0 and get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"], - ["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"], - ["Unpaid and Discounted", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1 and self.is_discounted and self.discounting_status=='Disbursed'"], - ["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"], - ["Overdue and Discounted", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1 and self.is_discounted and self.discounting_status=='Disbursed'"], - ["Cancelled", "eval:self.docstatus==2"], - ], "Purchase Invoice": [ ["Draft", None], ["Submitted", "eval:self.docstatus==1"], From 05fee62314957890b0772c2d2fa3f4f8266303a5 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 2 Jul 2019 17:55:26 +0530 Subject: [PATCH 06/95] fix: inv status --- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 54e127d2f4..43bbfab130 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1210,7 +1210,7 @@ class SalesInvoice(SellingController): self.status = "Unpaid and Discounted" elif self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()): self.status = "Unpaid" - elif self.outstanding_amount < 0 and self.is_return==0 and get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}): + elif self.outstanding_amount < 0 and self.is_return==0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}): self.status = "Credit Note Issued" elif self.outstanding_amount<=0 and self.is_return==0: self.status = "Paid" From 38b930b638f10888b629c02284813212dc36e5d7 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Fri, 5 Jul 2019 10:38:48 +0530 Subject: [PATCH 07/95] refactor: Move and Add buttons open new stock entry --- erpnext/stock/dashboard/item_dashboard.js | 25 +++++++++++++++++++ .../stock/dashboard/item_dashboard_list.html | 15 +++++++++++ 2 files changed, 40 insertions(+) diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js index f820b7aa86..ed325a16b8 100644 --- a/erpnext/stock/dashboard/item_dashboard.js +++ b/erpnext/stock/dashboard/item_dashboard.js @@ -16,6 +16,31 @@ erpnext.stock.ItemDashboard = Class.extend({ this.content = $(frappe.render_template('item_dashboard')).appendTo(this.parent); this.result = this.content.find('.result'); + this.content.on('click', '.btn-move', function() { + let item = unescape($(this).attr('data-item')); + let warehouse = unescape($(this).attr('data-warehouse')); + open_stock_entry(item, warehouse, "Material Transfer"); + }); + + this.content.on('click', '.btn-add', function() { + let item = unescape($(this).attr('data-item')); + let warehouse = unescape($(this).attr('data-warehouse')); + open_stock_entry(item, warehouse); + }); + + function open_stock_entry(item, warehouse, entry_type) { + frappe.model.with_doctype('Stock Entry', function() { + var doc = frappe.model.get_new_doc('Stock Entry'); + if (entry_type) doc.stock_entry_type = entry_type; + + var row = frappe.model.add_child(doc, 'items'); + row.item_code = item; + row.s_warehouse = warehouse; + + frappe.set_route('Form', doc.doctype, doc.name); + }) + } + // more this.content.find('.btn-more').on('click', function() { me.start += 20; diff --git a/erpnext/stock/dashboard/item_dashboard_list.html b/erpnext/stock/dashboard/item_dashboard_list.html index f0e87b1c53..5a3fa2ed48 100644 --- a/erpnext/stock/dashboard/item_dashboard_list.html +++ b/erpnext/stock/dashboard/item_dashboard_list.html @@ -39,6 +39,21 @@ + {% if can_write %} +
+ {% if d.actual_qty %} +
+ {% endif %} {% endfor %} From db3c5625aedc97b6b4b43438960fe0944371d14f Mon Sep 17 00:00:00 2001 From: Bhavishya Sharma Date: Sat, 6 Jul 2019 13:54:30 +0530 Subject: [PATCH 08/95] feat: Manufacturer is Missing Contacts --- .../doctype/manufacturer/manufacturer.js | 10 +- .../doctype/manufacturer/manufacturer.json | 358 +++++------------- .../doctype/manufacturer/manufacturer.py | 5 +- 3 files changed, 118 insertions(+), 255 deletions(-) diff --git a/erpnext/stock/doctype/manufacturer/manufacturer.js b/erpnext/stock/doctype/manufacturer/manufacturer.js index 67df1bf4c0..dcbe2a05f0 100644 --- a/erpnext/stock/doctype/manufacturer/manufacturer.js +++ b/erpnext/stock/doctype/manufacturer/manufacturer.js @@ -3,6 +3,14 @@ frappe.ui.form.on('Manufacturer', { refresh: function(frm) { - + frappe.dynamic_link = { doc: frm.doc, fieldname: 'name', doctype: 'Manufacturer' } + if (frm.doc.__islocal) { + hide_field(['address_html','contact_html']); + frappe.contacts.clear_address_and_contact(frm); + } + else { + unhide_field(['address_html','contact_html']); + frappe.contacts.render_address_and_contact(frm); + } } }); diff --git a/erpnext/stock/doctype/manufacturer/manufacturer.json b/erpnext/stock/doctype/manufacturer/manufacturer.json index 5025917836..3a64fbeceb 100644 --- a/erpnext/stock/doctype/manufacturer/manufacturer.json +++ b/erpnext/stock/doctype/manufacturer/manufacturer.json @@ -1,268 +1,120 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:short_name", - "beta": 0, - "creation": "2016-01-17 11:04:52.761731", - "custom": 0, - "description": "Manufacturers used in Items", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 0, + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:short_name", + "creation": "2016-01-17 11:04:52.761731", + "description": "Manufacturers used in Items", + "doctype": "DocType", + "document_type": "Setup", + "engine": "InnoDB", + "field_order": [ + "short_name", + "full_name", + "website", + "country", + "logo", + "address_contacts", + "address_html", + "column_break_8", + "contact_html", + "section_break_10", + "notes" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Limited to 12 characters", - "fieldname": "short_name", - "fieldtype": "Data", - "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": "Short Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "description": "Limited to 12 characters", + "fieldname": "short_name", + "fieldtype": "Data", + "label": "Short Name", + "reqd": 1, + "unique": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "full_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Full Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "full_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Full Name" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "website", - "fieldtype": "Data", - "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": "Website", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "website", + "fieldtype": "Data", + "label": "Website" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "country", - "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": "Country", - "length": 0, - "no_copy": 0, - "options": "Country", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "country", + "fieldtype": "Link", + "label": "Country", + "options": "Country" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "logo", - "fieldtype": "Attach Image", - "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": "Logo", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "logo", + "fieldtype": "Attach Image", + "label": "Logo" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "notes", - "fieldtype": "Small Text", - "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": "Notes", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 + "fieldname": "notes", + "fieldtype": "Small Text", + "label": "Notes" + }, + { + "depends_on": "eval:!doc.__islocal", + "fieldname": "address_contacts", + "fieldtype": "Section Break", + "label": "Address and Contacts", + "options": "fa fa-map-marker" + }, + { + "fieldname": "address_html", + "fieldtype": "HTML", + "label": "Address HTML", + "read_only": 1 + }, + { + "fieldname": "column_break_8", + "fieldtype": "Column Break" + }, + { + "fieldname": "contact_html", + "fieldtype": "HTML", + "label": "Contact HTML", + "read_only": 1 + }, + { + "fieldname": "section_break_10", + "fieldtype": "Section Break" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-certificate", - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-08-03 06:27:57.182666", - "modified_by": "Administrator", - "module": "Stock", - "name": "Manufacturer", - "name_case": "", - "owner": "Administrator", + ], + "icon": "fa fa-certificate", + "modified": "2019-07-06 13:06:47.237014", + "modified_by": "Administrator", + "module": "Stock", + "name": "Manufacturer", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Stock Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Stock Manager", + "share": 1, "write": 1 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Stock User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 0 + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Stock User", + "share": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "search_fields": "short_name, full_name", - "show_name_in_global_search": 1, - "sort_field": "", - "sort_order": "DESC", - "title_field": "short_name", - "track_changes": 0, - "track_seen": 0 + ], + "search_fields": "short_name, full_name", + "show_name_in_global_search": 1, + "sort_order": "DESC", + "title_field": "short_name" } \ No newline at end of file diff --git a/erpnext/stock/doctype/manufacturer/manufacturer.py b/erpnext/stock/doctype/manufacturer/manufacturer.py index 7b85b05aa1..b624f73b77 100644 --- a/erpnext/stock/doctype/manufacturer/manufacturer.py +++ b/erpnext/stock/doctype/manufacturer/manufacturer.py @@ -4,7 +4,10 @@ from __future__ import unicode_literals import frappe +from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address from frappe.model.document import Document class Manufacturer(Document): - pass + def onload(self): + """Load address and contacts in `__onload`""" + load_address_and_contact(self) From 607611ebdc68186d051f2d8c4b72006e061b3bf7 Mon Sep 17 00:00:00 2001 From: Bhavishya Sharma Date: Sat, 6 Jul 2019 15:02:57 +0530 Subject: [PATCH 09/95] codacy fix --- erpnext/stock/doctype/manufacturer/manufacturer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/manufacturer/manufacturer.js b/erpnext/stock/doctype/manufacturer/manufacturer.js index dcbe2a05f0..bb7e314e14 100644 --- a/erpnext/stock/doctype/manufacturer/manufacturer.js +++ b/erpnext/stock/doctype/manufacturer/manufacturer.js @@ -3,7 +3,7 @@ frappe.ui.form.on('Manufacturer', { refresh: function(frm) { - frappe.dynamic_link = { doc: frm.doc, fieldname: 'name', doctype: 'Manufacturer' } + frappe.dynamic_link = { doc: frm.doc, fieldname: 'name', doctype: 'Manufacturer' }; if (frm.doc.__islocal) { hide_field(['address_html','contact_html']); frappe.contacts.clear_address_and_contact(frm); From 444091b35013f9747a2fa4048f4388cf4d0154a5 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 10 Jul 2019 10:22:08 +0530 Subject: [PATCH 10/95] refactor: disable quick entry for batched and serialized items --- erpnext/stock/dashboard/item_dashboard.js | 102 +++++++++++++++++- erpnext/stock/dashboard/item_dashboard.py | 4 +- .../stock/dashboard/item_dashboard_list.html | 2 + 3 files changed, 104 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js index ed325a16b8..c84acc54b3 100644 --- a/erpnext/stock/dashboard/item_dashboard.js +++ b/erpnext/stock/dashboard/item_dashboard.js @@ -19,13 +19,24 @@ erpnext.stock.ItemDashboard = Class.extend({ this.content.on('click', '.btn-move', function() { let item = unescape($(this).attr('data-item')); let warehouse = unescape($(this).attr('data-warehouse')); - open_stock_entry(item, warehouse, "Material Transfer"); + let actual_qty = unescape($(this).attr('data-actual_qty')); + let disable_quick_entry = Number(unescape($(this).attr('data-disable_quick_entry'))); + + if (disable_quick_entry) open_stock_entry(item, warehouse, "Material Transfer"); + + else erpnext.stock.move_item(item, warehouse, null, actual_qty, null, function() { me.refresh(); }) }); this.content.on('click', '.btn-add', function() { let item = unescape($(this).attr('data-item')); let warehouse = unescape($(this).attr('data-warehouse')); - open_stock_entry(item, warehouse); + let actual_qty = unescape($(this).attr('data-actual_qty')); + let disable_quick_entry = Number(unescape($(this).attr('data-disable_quick_entry'))); + let rate = unescape($(this).attr('data-rate')); + + if (disable_quick_entry) open_stock_entry(item, warehouse); + + else erpnext.stock.move_item(item, null, warehouse, actual_qty, rate, function() { me.refresh(); }) }); function open_stock_entry(item, warehouse, entry_type) { @@ -124,4 +135,89 @@ erpnext.stock.ItemDashboard = Class.extend({ show_item: show_item || false } } -}) \ No newline at end of file +}) + +erpnext.stock.move_item = function(item, source, target, actual_qty, rate, callback) { + var dialog = new frappe.ui.Dialog({ + title: target ? __('Add Item') : __('Move Item'), + fields: [ + {fieldname: 'item_code', label: __('Item'), + fieldtype: 'Link', options: 'Item', read_only: 1}, + {fieldname: 'source', label: __('Source Warehouse'), + fieldtype: 'Link', options: 'Warehouse', read_only: 1}, + {fieldname: 'target', label: __('Target Warehouse'), + fieldtype: 'Link', options: 'Warehouse', reqd: 1}, + {fieldname: 'qty', label: __('Quantity'), reqd: 1, + fieldtype: 'Float', description: __('Available {0}', [actual_qty]) }, + {fieldname: 'rate', label: __('Rate'), fieldtype: 'Currency', hidden: 1 }, + ], + }) + dialog.show(); + dialog.get_field('item_code').set_input(item); + + if(source) { + dialog.get_field('source').set_input(source); + } else { + dialog.get_field('source').df.hidden = 1; + dialog.get_field('source').refresh(); + } + + if(rate) { + dialog.get_field('rate').set_value(rate); + dialog.get_field('rate').df.hidden = 0; + dialog.get_field('rate').refresh(); + } + + if(target) { + dialog.get_field('target').df.read_only = 1; + dialog.get_field('target').value = target; + dialog.get_field('target').refresh(); + } + + dialog.set_primary_action(__('Submit'), function() { + var values = dialog.get_values(); + if(!values) { + return; + } + if(source && values.qty > actual_qty) { + frappe.msgprint(__('Quantity must be less than or equal to {0}', [actual_qty])); + return; + } + if(values.source === values.target) { + frappe.msgprint(__('Source and target warehouse must be different')); + } + + frappe.call({ + method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry', + args: values, + freeze: true, + callback: function(r) { + frappe.show_alert(__('Stock Entry {0} created', + ['' + r.message.name+ ''])); + dialog.hide(); + callback(r); + }, + }); + }); + + $('

' + + __("Add more items or open full form") + '

') + .appendTo(dialog.body) + .find('.link-open') + .on('click', function() { + frappe.model.with_doctype('Stock Entry', function() { + var doc = frappe.model.get_new_doc('Stock Entry'); + doc.from_warehouse = dialog.get_value('source'); + doc.to_warehouse = dialog.get_value('target'); + var row = frappe.model.add_child(doc, 'items'); + row.item_code = dialog.get_value('item_code'); + row.f_warehouse = dialog.get_value('target'); + row.t_warehouse = dialog.get_value('target'); + row.qty = dialog.get_value('qty'); + row.conversion_factor = 1; + row.transfer_qty = dialog.get_value('qty'); + row.basic_rate = dialog.get_value('rate'); + frappe.set_route('Form', doc.doctype, doc.name); + }) + }); +} \ No newline at end of file diff --git a/erpnext/stock/dashboard/item_dashboard.py b/erpnext/stock/dashboard/item_dashboard.py index 487c765659..7634ff0a28 100644 --- a/erpnext/stock/dashboard/item_dashboard.py +++ b/erpnext/stock/dashboard/item_dashboard.py @@ -44,7 +44,9 @@ def get_data(item_code=None, warehouse=None, item_group=None, for item in items: item.update({ - 'item_name': frappe.get_cached_value("Item", item.item_code, 'item_name') + 'item_name': frappe.get_cached_value("Item", item.item_code, 'item_name'), + 'disable_quick_entry': frappe.get_cached_value("Item", item.item_code, 'has_batch_no') + or frappe.get_cached_value("Item", item.item_code, 'has_serial_no'), }) return items diff --git a/erpnext/stock/dashboard/item_dashboard_list.html b/erpnext/stock/dashboard/item_dashboard_list.html index 5a3fa2ed48..e1914ed76a 100644 --- a/erpnext/stock/dashboard/item_dashboard_list.html +++ b/erpnext/stock/dashboard/item_dashboard_list.html @@ -43,11 +43,13 @@
{% if d.actual_qty %}