diff --git a/erpnext/__init__.py b/erpnext/__init__.py index b9846c8f57..9660cb9688 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals import frappe -__version__ = '7.1.15' +__version__ = '7.1.16' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/asset/asset.js b/erpnext/accounts/doctype/asset/asset.js index 8ff4b83d68..664ed4da25 100644 --- a/erpnext/accounts/doctype/asset/asset.js +++ b/erpnext/accounts/doctype/asset/asset.js @@ -28,6 +28,7 @@ frappe.ui.form.on('Asset', { refresh: function(frm) { frappe.ui.form.trigger("Asset", "is_existing_asset"); frm.toggle_display("next_depreciation_date", frm.doc.docstatus < 1); + frm.events.make_schedules_editable(frm); if (frm.doc.docstatus==1) { if (frm.doc.status=='Submitted' && !frm.doc.is_existing_asset && !frm.doc.purchase_invoice) { @@ -141,6 +142,22 @@ frappe.ui.form.on('Asset', { frm.toggle_enable("supplier", frm.doc.is_existing_asset); frm.toggle_reqd("next_depreciation_date", !frm.doc.is_existing_asset); }, + + opening_accumulated_depreciation: function(frm) { + erpnext.asset.set_accululated_depreciation(frm); + }, + + depreciation_method: function(frm) { + frm.events.make_schedules_editable(frm); + }, + + make_schedules_editable: function(frm) { + var is_editable = frm.doc.depreciation_method==="Manual" ? true : false; + frm.toggle_enable("schedules", is_editable); + frm.fields_dict["schedules"].grid.toggle_enable("schedule_date", is_editable); + frm.fields_dict["schedules"].grid.toggle_enable("depreciation_amount", is_editable); + } + }); frappe.ui.form.on('Depreciation Schedule', { @@ -159,9 +176,25 @@ frappe.ui.form.on('Depreciation Schedule', { } }) } + }, + + depreciation_amount: function(frm, cdt, cdn) { + erpnext.asset.set_accululated_depreciation(frm); } + }) +erpnext.asset.set_accululated_depreciation = function(frm) { + if(frm.doc.depreciation_method != "Manual") return; + + accumulated_depreciation = flt(frm.doc.opening_accumulated_depreciation); + $.each(frm.doc.schedules || [], function(i, row) { + accumulated_depreciation += flt(row.depreciation_amount); + frappe.model.set_value(row.doctype, row.name, + "accumulated_depreciation_amount", accumulated_depreciation); + }) +} + erpnext.asset.make_purchase_invoice = function(frm) { frappe.call({ args: { diff --git a/erpnext/accounts/doctype/asset/asset.json b/erpnext/accounts/doctype/asset/asset.json index d3a88fbaa4..95d9b48603 100644 --- a/erpnext/accounts/doctype/asset/asset.json +++ b/erpnext/accounts/doctype/asset/asset.json @@ -516,7 +516,7 @@ "columns": 0, "fieldname": "value_after_depreciation", "fieldtype": "Currency", - "hidden": 0, + "hidden": 1, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, @@ -580,7 +580,7 @@ "label": "Depreciation Method", "length": 0, "no_copy": 0, - "options": "\nStraight Line\nDouble Declining Balance", + "options": "\nStraight Line\nDouble Declining Balance\nManual", "permlevel": 0, "precision": "", "print_hide": 0, @@ -750,7 +750,7 @@ "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -797,7 +797,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-11-03 14:58:53.710357", + "modified": "2016-11-18 15:59:19.774500", "modified_by": "Administrator", "module": "Accounts", "name": "Asset", diff --git a/erpnext/accounts/doctype/asset/asset.py b/erpnext/accounts/doctype/asset/asset.py index da73218b25..9caac071f9 100644 --- a/erpnext/accounts/doctype/asset/asset.py +++ b/erpnext/accounts/doctype/asset/asset.py @@ -18,6 +18,7 @@ class Asset(Document): self.set_missing_values() self.validate_asset_values() self.make_depreciation_schedule() + self.set_accumulated_depreciation() self.validate_expected_value_after_useful_life() # Validate depreciation related accounts get_depreciation_accounts(self) @@ -48,7 +49,7 @@ class Asset(Document): for field, value in item_details.items(): if not self.get(field): self.set(field, value) - + self.value_after_depreciation = (flt(self.gross_purchase_amount) - flt(self.opening_accumulated_depreciation)) @@ -87,9 +88,10 @@ class Asset(Document): frappe.throw(_("Please set Next Depreciation Date")) def make_depreciation_schedule(self): - self.schedules = [] + if self.depreciation_method != 'Manual': + self.schedules = [] + if not self.get("schedules") and self.next_depreciation_date: - accumulated_depreciation = flt(self.opening_accumulated_depreciation) value_after_depreciation = flt(self.value_after_depreciation) number_of_pending_depreciations = cint(self.total_number_of_depreciations) - \ @@ -100,18 +102,21 @@ class Asset(Document): n * cint(self.frequency_of_depreciation)) depreciation_amount = self.get_depreciation_amount(value_after_depreciation) - - accumulated_depreciation += flt(depreciation_amount) value_after_depreciation -= flt(depreciation_amount) self.append("schedules", { "schedule_date": schedule_date, - "depreciation_amount": depreciation_amount, - "accumulated_depreciation_amount": accumulated_depreciation + "depreciation_amount": depreciation_amount }) + + def set_accumulated_depreciation(self): + accumulated_depreciation = flt(self.opening_accumulated_depreciation) + for d in self.get("schedules"): + accumulated_depreciation += flt(d.depreciation_amount) + d.accumulated_depreciation_amount = accumulated_depreciation def get_depreciation_amount(self, depreciable_value): - if self.depreciation_method == "Straight Line": + if self.depreciation_method in ("Straight Line", "Manual"): depreciation_amount = (flt(self.value_after_depreciation) - flt(self.expected_value_after_useful_life)) / (cint(self.total_number_of_depreciations) - cint(self.number_of_depreciations_booked)) @@ -126,16 +131,15 @@ class Asset(Document): return depreciation_amount def validate_expected_value_after_useful_life(self): - if self.depreciation_method == "Double Declining Balance": - accumulated_depreciation_after_full_schedule = \ - max([d.accumulated_depreciation_amount for d in self.get("schedules")]) - - asset_value_after_full_schedule = (flt(self.gross_purchase_amount) - - flt(accumulated_depreciation_after_full_schedule)) - - if self.expected_value_after_useful_life < asset_value_after_full_schedule: - frappe.throw(_("Expected value after useful life must be greater than or equal to {0}") - .format(asset_value_after_full_schedule)) + accumulated_depreciation_after_full_schedule = \ + max([d.accumulated_depreciation_amount for d in self.get("schedules")]) + + asset_value_after_full_schedule = (flt(self.gross_purchase_amount) - + flt(accumulated_depreciation_after_full_schedule)) + + if self.expected_value_after_useful_life < asset_value_after_full_schedule: + frappe.throw(_("Expected value after useful life must be greater than or equal to {0}") + .format(asset_value_after_full_schedule)) def validate_cancellation(self): if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"): diff --git a/erpnext/accounts/doctype/asset/test_asset.py b/erpnext/accounts/doctype/asset/test_asset.py index b409ec3a25..51496b918c 100644 --- a/erpnext/accounts/doctype/asset/test_asset.py +++ b/erpnext/accounts/doctype/asset/test_asset.py @@ -119,6 +119,30 @@ class TestAsset(unittest.TestCase): for d in asset.get("schedules")] self.assertEqual(schedules, expected_schedules) + + def test_schedule_for_manual_method(self): + asset = frappe.get_doc("Asset", "Macbook Pro 1") + asset.depreciation_method = "Manual" + asset.schedules = [] + for schedule_date, amount in [["2020-12-31", 40000], ["2021-06-30", 30000], ["2021-10-31", 20000]]: + asset.append("schedules", { + "schedule_date": schedule_date, + "depreciation_amount": amount + }) + asset.save() + + self.assertEqual(asset.status, "Draft") + + expected_schedules = [ + ["2020-12-31", 40000, 40000], + ["2021-06-30", 30000, 70000], + ["2021-10-31", 20000, 90000] + ] + + schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] + for d in asset.get("schedules")] + + self.assertEqual(schedules, expected_schedules) def test_depreciation(self): asset = frappe.get_doc("Asset", "Macbook Pro 1") diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.js b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.js index 85d3187131..f1ccd9f8c3 100644 --- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.js +++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.js @@ -46,6 +46,12 @@ frappe.ui.form.on("Bank Reconciliation", { callback: function(r, rt) { frm.refresh_field("payment_entries"); frm.refresh_fields(); + + $(frm.fields_dict.payment_entries.wrapper).find("[data-fieldname=amount]").each(function(i,v){ + if (i !=0){ + $(v).addClass("text-right") + } + }) } }); } diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py index a56170d992..abc6ebaf9c 100644 --- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py +++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import frappe -from frappe.utils import flt, getdate, nowdate +from frappe.utils import flt, getdate, nowdate, fmt_money from frappe import msgprint, _ from frappe.model.document import Document @@ -26,8 +26,8 @@ class BankReconciliation(Document): select "Journal Entry" as payment_document, t1.name as payment_entry, t1.cheque_no as cheque_number, t1.cheque_date, - abs(t2.debit_in_account_currency - t2.credit_in_account_currency) as amount, - t1.posting_date, t2.against_account, t1.clearance_date + t2.debit_in_account_currency as debit, t2.credit_in_account_currency as credit, + t1.posting_date, t2.against_account, t1.clearance_date, t2.account_currency from `tabJournal Entry` t1, `tabJournal Entry Account` t2 where @@ -36,21 +36,23 @@ class BankReconciliation(Document): and ifnull(t1.is_opening, 'No') = 'No' {0} order by t1.posting_date ASC, t1.name DESC """.format(condition), (self.bank_account, self.from_date, self.to_date), as_dict=1) - + payment_entries = frappe.db.sql(""" select "Payment Entry" as payment_document, name as payment_entry, reference_no as cheque_number, reference_date as cheque_date, - if(paid_from=%s, paid_amount, received_amount) as amount, - posting_date, party as against_account, clearance_date + if(paid_from=%(account)s, paid_amount, "") as credit, + if(paid_from=%(account)s, "", received_amount) as debit, + posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date, + if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency from `tabPayment Entry` where - (paid_from=%s or paid_to=%s) and docstatus=1 - and posting_date >= %s and posting_date <= %s {0} + (paid_from=%(account)s or paid_to=%(account)s) and docstatus=1 + and posting_date >= %(from)s and posting_date <= %(to)s {0} order by posting_date ASC, name DESC """.format(condition), - (self.bank_account, self.bank_account, self.bank_account, self.from_date, self.to_date), as_dict=1) + {"account":self.bank_account, "from":self.from_date, "to":self.to_date}, as_dict=1) entries = sorted(list(payment_entries)+list(journal_entries), key=lambda k: k['posting_date'] or getdate(nowdate())) @@ -60,6 +62,11 @@ class BankReconciliation(Document): for d in entries: row = self.append('payment_entries', {}) + + d.amount = fmt_money(d.debit if d.debit else d.credit, 2, d.account_currency) + " " + (_("Dr") if d.debit else _("Cr")) + d.pop("credit") + d.pop("debit") + d.pop("account_currency") row.update(d) self.total_amount += flt(d.amount) diff --git a/erpnext/accounts/doctype/bank_reconciliation_detail/bank_reconciliation_detail.json b/erpnext/accounts/doctype/bank_reconciliation_detail/bank_reconciliation_detail.json index 0f30feefa8..2e4af267ee 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_detail/bank_reconciliation_detail.json +++ b/erpnext/accounts/doctype/bank_reconciliation_detail/bank_reconciliation_detail.json @@ -40,14 +40,14 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "columns": 0, + "columns": 1, "fieldname": "payment_entry", "fieldtype": "Dynamic Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, - "in_list_view": 0, + "in_list_view": 1, "label": "Payment Entry", "length": 0, "no_copy": 0, @@ -69,7 +69,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "columns": 3, + "columns": 2, "fieldname": "against_account", "fieldtype": "Data", "hidden": 0, @@ -99,7 +99,7 @@ "collapsible": 0, "columns": 2, "fieldname": "amount", - "fieldtype": "Currency", + "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -110,7 +110,7 @@ "no_copy": 0, "oldfieldname": "debit", "oldfieldtype": "Currency", - "options": "account_currency", + "options": "", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -151,7 +151,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "columns": 0, + "columns": 2, "fieldname": "posting_date", "fieldtype": "Date", "hidden": 0, @@ -178,7 +178,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "columns": 3, + "columns": 1, "fieldname": "cheque_number", "fieldtype": "Data", "hidden": 0, @@ -267,7 +267,7 @@ "istable": 1, "max_attachments": 0, "menu_index": 0, - "modified": "2016-08-26 01:51:36.123941", + "modified": "2016-11-17 11:39:00.308624", "modified_by": "Administrator", "module": "Accounts", "name": "Bank Reconciliation Detail", diff --git a/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.json b/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.json index 57c14b7974..1fadf5eb4f 100644 --- a/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.json +++ b/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.json @@ -10,11 +10,13 @@ "doctype": "DocType", "document_type": "Document", "editable_grid": 1, + "engine": "InnoDB", "fields": [ { "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "schedule_date", "fieldtype": "Date", "hidden": 0, @@ -29,7 +31,8 @@ "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, "search_index": 0, @@ -40,6 +43,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "depreciation_amount", "fieldtype": "Currency", "hidden": 0, @@ -55,7 +59,8 @@ "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, "search_index": 0, @@ -66,6 +71,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "column_break_3", "fieldtype": "Column Break", "hidden": 0, @@ -80,6 +86,7 @@ "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, @@ -90,6 +97,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "accumulated_depreciation_amount", "fieldtype": "Currency", "hidden": 0, @@ -106,8 +114,9 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -116,6 +125,8 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.docstatus==1", "fieldname": "journal_entry", "fieldtype": "Link", "hidden": 0, @@ -132,6 +143,7 @@ "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, @@ -142,7 +154,8 @@ "allow_on_submit": 1, "bold": 0, "collapsible": 0, - "depends_on": "eval:(!doc.journal_entry && doc.schedule_date <= get_today())", + "columns": 0, + "depends_on": "eval:(doc.docstatus==1 && !doc.journal_entry && doc.schedule_date <= get_today())", "fieldname": "make_depreciation_entry", "fieldtype": "Button", "hidden": 0, @@ -158,6 +171,7 @@ "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, @@ -175,7 +189,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-07-11 03:27:59.603924", + "modified": "2016-11-18 16:42:19.543657", "modified_by": "Administrator", "module": "Accounts", "name": "Depreciation Schedule", diff --git a/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.json b/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.json index 377a95c7d5..7af7f48ce7 100644 --- a/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.json +++ b/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.json @@ -9,11 +9,14 @@ "description": "**Monthly Distribution** helps you distribute the Budget/Target across months if you have seasonality in your business.", "docstatus": 0, "doctype": "DocType", + "editable_grid": 0, + "engine": "InnoDB", "fields": [ { "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "description": "Name of the Monthly Distribution", "fieldname": "distribution_id", "fieldtype": "Data", @@ -31,6 +34,7 @@ "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, @@ -41,6 +45,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "fiscal_year", "fieldtype": "Link", "hidden": 0, @@ -58,6 +63,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 1, @@ -68,6 +74,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "percentages", "fieldtype": "Table", "hidden": 0, @@ -85,6 +92,7 @@ "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, @@ -96,13 +104,14 @@ "hide_toolbar": 0, "icon": "icon-bar-chart", "idx": 1, + "image_view": 0, "in_create": 0, "in_dialog": 0, "is_submittable": 0, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-05-16 16:35:20.349194", + "modified": "2016-11-21 14:54:35.998761", "modified_by": "Administrator", "module": "Accounts", "name": "Monthly Distribution", @@ -119,6 +128,7 @@ "export": 0, "if_owner": 0, "import": 0, + "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -139,6 +149,7 @@ "export": 0, "if_owner": 0, "import": 0, + "is_custom": 0, "permlevel": 2, "print": 0, "read": 1, @@ -150,7 +161,7 @@ "write": 0 } ], - "quick_entry": 1, + "quick_entry": 0, "read_only": 0, "read_only_onload": 0, "sort_field": "modified", diff --git a/erpnext/accounts/doctype/pos_customer_group/__init__.py b/erpnext/accounts/doctype/pos_customer_group/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/accounts/doctype/pos_customer_group/pos_customer_group.json b/erpnext/accounts/doctype/pos_customer_group/pos_customer_group.json new file mode 100644 index 0000000000..4f6a675fb6 --- /dev/null +++ b/erpnext/accounts/doctype/pos_customer_group/pos_customer_group.json @@ -0,0 +1,66 @@ +{ + "allow_copy": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2016-11-16 15:27:16.413449", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "customer_group", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Customer Group", + "length": 0, + "no_copy": 0, + "options": "Customer Group", + "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 + } + ], + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2016-11-16 15:27:25.730507", + "modified_by": "Administrator", + "module": "Accounts", + "name": "POS Customer Group", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/pos_customer_group/pos_customer_group.py b/erpnext/accounts/doctype/pos_customer_group/pos_customer_group.py new file mode 100644 index 0000000000..85c1c9f8dd --- /dev/null +++ b/erpnext/accounts/doctype/pos_customer_group/pos_customer_group.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class POSCustomerGroup(Document): + pass diff --git a/erpnext/accounts/doctype/pos_item_group/__init__.py b/erpnext/accounts/doctype/pos_item_group/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/accounts/doctype/pos_item_group/pos_item_group.json b/erpnext/accounts/doctype/pos_item_group/pos_item_group.json new file mode 100644 index 0000000000..b278765234 --- /dev/null +++ b/erpnext/accounts/doctype/pos_item_group/pos_item_group.json @@ -0,0 +1,66 @@ +{ + "allow_copy": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2016-11-16 15:26:47.706713", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "item_group", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Item Group", + "length": 0, + "no_copy": 0, + "options": "Item Group", + "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 + } + ], + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2016-11-16 15:27:32.263630", + "modified_by": "Administrator", + "module": "Accounts", + "name": "POS Item Group", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/pos_item_group/pos_item_group.py b/erpnext/accounts/doctype/pos_item_group/pos_item_group.py new file mode 100644 index 0000000000..ceaa57ba60 --- /dev/null +++ b/erpnext/accounts/doctype/pos_item_group/pos_item_group.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class POSItemGroup(Document): + pass diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.js b/erpnext/accounts/doctype/pos_profile/pos_profile.js index c1aa0c3cb5..bbbab73e1c 100755 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.js +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.js @@ -26,6 +26,30 @@ frappe.ui.form.on("POS Profile", "onload", function(frm) { }); }); +frappe.ui.form.on("POS Profile", { + setup: function(frm) { + frm.trigger("get_query_for_groups") + }, + + get_query_for_groups: function(frm) { + frm.fields_dict['item_groups'].grid.get_field('item_group').get_query = function(frm, cdt, cdn) { + return{ + filters: { + 'is_group': 0 + } + } + } + + frm.fields_dict['customer_groups'].grid.get_field('customer_group').get_query = function(frm, cdt, cdn) { + return{ + filters: { + 'is_group': 0 + } + } + } + } +}) + // Income Account // -------------------------------- cur_frm.fields_dict['income_account'].get_query = function(doc,cdt,cdn) { diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.json b/erpnext/accounts/doctype/pos_profile/pos_profile.json index f450121817..e6cfd7409b 100644 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.json +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.json @@ -375,6 +375,114 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_14", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 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, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "item_groups", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Item Groups", + "length": 0, + "no_copy": 0, + "options": "POS Item Group", + "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 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_16", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 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, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "customer_groups", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Groups", + "length": 0, + "no_copy": 0, + "options": "POS Customer Group", + "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 + }, { "allow_on_submit": 0, "bold": 0, @@ -543,34 +651,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "customer_group", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Customer Group", - "length": 0, - "no_copy": 0, - "options": "Customer Group", - "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 - }, { "allow_on_submit": 0, "bold": 0, @@ -951,8 +1031,8 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-11-03 15:53:33.820428", - "modified_by": "Administrator", + "modified": "2016-11-17 00:20:51.377850", + "modified_by": "rohit@erpnext.com", "module": "Accounts", "name": "POS Profile", "owner": "Administrator", diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.py b/erpnext/accounts/doctype/pos_profile/pos_profile.py index 5f4d5bc75d..ef497bfe29 100644 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.py +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.py @@ -13,6 +13,7 @@ class POSProfile(Document): def validate(self): self.check_for_duplicate() self.validate_all_link_fields() + self.validate_duplicate_groups() def check_for_duplicate(self): res = frappe.db.sql("""select name, user from `tabPOS Profile` @@ -37,6 +38,16 @@ class POSProfile(Document): "company": self.company, "name": link_dn}): frappe.throw(_("{0} does not belong to Company {1}").format(link_dn, self.company)) + def validate_duplicate_groups(self): + item_groups = [d.item_group for d in self.item_groups] + customer_groups = [d.customer_group for d in self.customer_groups] + + if len(item_groups) != len(set(item_groups)): + frappe.throw(_("Duplicate item group found in the item group table"), title = "Duplicate Item Group") + + if len(customer_groups) != len(set(customer_groups)): + frappe.throw(_("Duplicate customer group found in the cutomer group table"), title = "Duplicate Customer Group") + def before_save(self): set_account_for_mode_of_payment(self) diff --git a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py index 62274a332f..9c6a11487c 100644 --- a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py +++ b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py @@ -5,8 +5,47 @@ from __future__ import unicode_literals import frappe import unittest - -# test_records = frappe.get_test_records('POS Profile') +from erpnext.stock.get_item_details import get_pos_profile +from erpnext.accounts.doctype.sales_invoice.pos import get_items_list, get_customers_list class TestPOSProfile(unittest.TestCase): - pass + def test_pos_profile(self): + make_pos_profile() + + pos_profile = get_pos_profile("_Test Company") or {} + if pos_profile: + doc = frappe.get_doc("POS Profile", pos_profile.get("name")) + doc.append('item_groups', {'item_group': '_Test Item Group'}) + doc.append('customer_groups', {'customer_group': '_Test Customer Group'}) + doc.save() + + items = get_items_list(doc) + customers = get_customers_list(doc) + + products_count = frappe.db.sql(""" select count(name) from tabItem where item_group = '_Test Item Group'""", as_list=1) + customers_count = frappe.db.sql(""" select count(name) from tabCustomer where customer_group = '_Test Customer Group'""") + + self.assertEquals(len(items), products_count[0][0]) + self.assertEquals(len(customers), customers_count[0][0]) + + frappe.db.sql("delete from `tabPOS Profile`") + +def make_pos_profile(): + pos_profile = frappe.get_doc({ + "company": "_Test Company", + "cost_center": "_Test Cost Center - _TC", + "currency": "INR", + "doctype": "POS Profile", + "expense_account": "_Test Account Cost for Goods Sold - _TC", + "income_account": "Sales - _TC", + "name": "_Test POS Profile", + "naming_series": "_T-POS Profile-", + "selling_price_list": "_Test Price List", + "territory": "_Test Territory", + "warehouse": "_Test Warehouse - _TC", + "write_off_account": "_Test Write Off - _TC", + "write_off_cost_center": "_Test Write Off Cost Center - _TC" + }) + + if not frappe.db.exists("POS Profile", "_Test POS Profile"): + pos_profile.insert() \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py index 1d1a122011..e0a81216c8 100644 --- a/erpnext/accounts/doctype/sales_invoice/pos.py +++ b/erpnext/accounts/doctype/sales_invoice/pos.py @@ -30,10 +30,16 @@ def get_pos_data(): return { 'doc': doc, 'default_customer': pos_profile.get('customer'), - 'items': get_items(doc, pos_profile), - 'customers': get_customers(pos_profile, doc, company_data.default_currency), - 'pricing_rules': get_pricing_rules(doc), + 'items': get_items_list(pos_profile), + 'customers': get_customers_list(pos_profile), + 'serial_no_data': get_serial_no_data(pos_profile, doc.company), + 'batch_no_data': get_batch_no_data(), + 'tax_data': get_item_tax_data(), + 'price_list_data': get_price_list_data(doc.selling_price_list), + 'bin_data': get_bin_data(pos_profile), + 'pricing_rules': get_pricing_rule_data(doc), 'print_template': print_template, + 'pos_profile': pos_profile, 'meta': { 'invoice': frappe.get_meta('Sales Invoice'), 'items': frappe.get_meta('Sales Invoice Item'), @@ -104,63 +110,117 @@ def update_tax_table(doc): for tax in taxes: doc.append('taxes', tax) -def get_items(doc, pos_profile): - item_list = [] - for item in frappe.get_all("Item", fields=["*"], filters={'disabled': 0, 'has_variants': 0, 'is_sales_item': 1}): - item_doc = frappe.get_doc('Item', item.name) - if item_doc.taxes: - item.taxes = json.dumps(dict(([d.tax_type, d.tax_rate] for d in - item_doc.get("taxes")))) +def get_items_list(pos_profile): + cond = "1=1" + item_groups = [] + if pos_profile.get('item_groups'): + # Get items based on the item groups defined in the POS profile - item.price_list_rate = frappe.db.get_value('Item Price', {'item_code': item.name, - 'price_list': doc.selling_price_list}, 'price_list_rate') or 0 - item.default_warehouse = pos_profile.get('warehouse') or \ - get_item_warehouse_for_company(doc.company, item.default_warehouse) or None - item.expense_account = pos_profile.get('expense_account') or item.expense_account - item.income_account = pos_profile.get('income_account') or item_doc.income_account - item.cost_center = pos_profile.get('cost_center') or item_doc.selling_cost_center - item.actual_qty = frappe.db.get_value('Bin', {'item_code': item.name, - 'warehouse': item.default_warehouse}, 'actual_qty') or 0 - item.serial_nos = get_serial_nos(item, pos_profile, doc.company) - item.batch_nos = frappe.db.sql_list("""select name from `tabBatch` where ifnull(expiry_date, '4000-10-10') > curdate() - and item = %(item_code)s""", {'item_code': item.item_code}) + cond = "item_group in (%s)"%(', '.join(['%s']*len(pos_profile.get('item_groups')))) + item_groups = [d.item_group for d in pos_profile.get('item_groups')] - item_list.append(item) + return frappe.db.sql(""" + select + name, item_code, item_name, description, item_group, expense_account, has_batch_no, + has_serial_no, expense_account, selling_cost_center, stock_uom, image, + default_warehouse, is_stock_item + from + tabItem + where + disabled = 0 and has_variants = 0 and is_sales_item = 1 and {cond} + """.format(cond=cond), tuple(item_groups), as_dict=1) - return item_list +def get_customers_list(pos_profile): + cond = "1=1" + customer_groups = [] + if pos_profile.get('customer_groups'): + # Get customers based on the customer groups defined in the POS profile -def get_item_warehouse_for_company(company, warehouse): - if frappe.db.get_value('Warehouse', warehouse, 'company') != company: - warehouse = None - return warehouse + cond = "customer_group in (%s)"%(', '.join(['%s']*len(pos_profile.get('customer_groups')))) + customer_groups = [d.customer_group for d in pos_profile.get('customer_groups')] + + return frappe.db.sql(""" select name, customer_name, customer_group, + territory from tabCustomer where disabled = 0 + and {cond}""".format(cond=cond), tuple(customer_groups), as_dict=1) or {} + +def get_serial_no_data(pos_profile, company): + # get itemwise serial no data + # example {'Nokia Lumia 1020': {'SN0001': 'Pune'}} + # where Nokia Lumia 1020 is item code, SN0001 is serial no and Pune is warehouse -def get_serial_nos(item, pos_profile, company): cond = "1=1" if pos_profile.get('update_stock') and pos_profile.get('warehouse'): cond = "warehouse = '{0}'".format(pos_profile.get('warehouse')) - serial_nos = frappe.db.sql("""select name, warehouse from `tabSerial No` where {0} - and item_code = %(item_code)s and company = %(company)s - """.format(cond), {'item_code': item.item_code, 'company': company}, as_dict=1) + serial_nos = frappe.db.sql("""select name, warehouse, item_code from `tabSerial No` where {0} + and company = %(company)s """.format(cond), {'company': company}, as_dict=1) - serial_no_list = {} - for serial_no in serial_nos: - serial_no_list[serial_no.name] = serial_no.warehouse + itemwise_serial_no = {} + for sn in serial_nos: + if sn.item_code not in itemwise_serial_no: + itemwise_serial_no.setdefault(sn.item_code, {}) + itemwise_serial_no[sn.item_code][sn.name] = sn.warehouse - return serial_no_list + return itemwise_serial_no -def get_customers(pos_profile, doc, company_currency): - filters = {'disabled': 0} - customer_list = [] - customers = frappe.get_all("Customer", fields=["*"], filters = filters) +def get_batch_no_data(): + # get itemwise batch no data + # exmaple: {'LED-GRE': [Batch001, Batch002]} + # where LED-GRE is item code, SN0001 is serial no and Pune is warehouse - for customer in customers: - customer_currency = get_party_account_currency('Customer', customer.name, doc.company) or doc.currency - if customer_currency == doc.currency or customer_currency == company_currency: - customer_list.append(customer) - return customer_list + itemwise_batch = {} + batches = frappe.db.sql("""select name, item from `tabBatch` + where ifnull(expiry_date, '4000-10-10') >= curdate()""", as_dict=1) -def get_pricing_rules(doc): + for batch in batches: + if batch.item not in itemwise_batch: + itemwise_batch.setdefault(batch.item, []) + itemwise_batch[batch.item].append(batch.name) + + return itemwise_batch + +def get_item_tax_data(): + # get default tax of an item + # example: {'Consulting Services': {'Excise 12 - TS': '12.000'}} + + itemwise_tax = {} + taxes = frappe.db.sql(""" select parent, tax_type, tax_rate from `tabItem Tax`""", as_dict=1) + + for tax in taxes: + if tax.parent not in itemwise_tax: + itemwise_tax.setdefault(tax.parent, {}) + itemwise_tax[tax.parent][tax.tax_type] = tax.tax_rate + + return itemwise_tax + +def get_price_list_data(selling_price_list): + itemwise_price_list = {} + price_lists = frappe.db.sql("""Select ifnull(price_list_rate, 0) as price_list_rate, + item_code from `tabItem Price` ip where price_list = %(price_list)s""", + {'price_list': selling_price_list}, as_dict=1) + + for item in price_lists: + itemwise_price_list[item.item_code] = item.price_list_rate + + return itemwise_price_list + +def get_bin_data(pos_profile): + itemwise_bin_data = {} + cond = "1=1" + if pos_profile.get('warehouse'): + cond = "warehouse = '{0}'".format(pos_profile.get('warehouse')) + + bin_data = frappe.db.sql(""" select item_code, warehouse, actual_qty from `tabBin` + where actual_qty > 0 and {cond}""".format(cond=cond), as_dict=1) + + for bins in bin_data: + if bins.item_code not in itemwise_bin_data: + itemwise_bin_data.setdefault(bins.item_code, {}) + itemwise_bin_data[bins.item_code][bins.warehouse] = bins.actual_qty + + return itemwise_bin_data + +def get_pricing_rule_data(doc): pricing_rules = "" if doc.ignore_pricing_rule == 0: pricing_rules = frappe.db.sql(""" Select * from `tabPricing Rule` where docstatus < 2 diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 9b4306e68d..4cd66f532f 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -20,6 +20,13 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte erpnext.queries.setup_queries(this.frm, "Warehouse", function() { return erpnext.queries.warehouse(me.frm.doc); }); + + if(this.frm.doc.__islocal && this.frm.doc.is_pos) { + //Load pos profile data on the invoice if the default value of Is POS is 1 + + me.frm.script_manager.trigger("is_pos"); + me.frm.refresh_fields(); + } }, refresh: function(doc, dt, dn) { diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 511eeaab9f..c4f275aba9 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -7,6 +7,7 @@ import unittest, copy from frappe.utils import nowdate, add_days, flt, nowdate from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice +from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError @@ -467,7 +468,7 @@ class TestSalesInvoice(unittest.TestCase): def test_pos_gl_entry_with_perpetual_inventory(self): set_perpetual_inventory() - self.make_pos_profile() + make_pos_profile() self._insert_purchase_receipt() pos = copy.deepcopy(test_records[1]) @@ -486,7 +487,7 @@ class TestSalesInvoice(unittest.TestCase): def test_pos_change_amount(self): set_perpetual_inventory() - self.make_pos_profile() + make_pos_profile() self._insert_purchase_receipt() pos = copy.deepcopy(test_records[1]) @@ -508,7 +509,7 @@ class TestSalesInvoice(unittest.TestCase): set_perpetual_inventory() - self.make_pos_profile() + make_pos_profile() self._insert_purchase_receipt() pos = copy.deepcopy(test_records[1]) @@ -572,26 +573,6 @@ class TestSalesInvoice(unittest.TestCase): frappe.db.sql("delete from `tabPOS Profile`") - def make_pos_profile(self): - pos_profile = frappe.get_doc({ - "company": "_Test Company", - "cost_center": "_Test Cost Center - _TC", - "currency": "INR", - "doctype": "POS Profile", - "expense_account": "_Test Account Cost for Goods Sold - _TC", - "income_account": "Sales - _TC", - "name": "_Test POS Profile", - "naming_series": "_T-POS Profile-", - "selling_price_list": "_Test Price List", - "territory": "_Test Territory", - "warehouse": "_Test Warehouse - _TC", - "write_off_account": "_Test Write Off - _TC", - "write_off_cost_center": "_Test Write Off Cost Center - _TC" - }) - - if not frappe.db.exists("POS Profile", "_Test POS Profile"): - pos_profile.insert() - def test_sales_invoice_gl_entry_with_perpetual_inventory_no_item_code(self): set_perpetual_inventory() diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js index 32e9b3ab60..57ffcb1346 100644 --- a/erpnext/accounts/page/pos/pos.js +++ b/erpnext/accounts/page/pos/pos.js @@ -25,7 +25,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.set_indicator(); this.onload(); this.make_menu_list(); - this.set_interval_for_si_sync(); this.si_docs = this.get_doc_from_localstorage(); }, @@ -73,8 +72,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.get_data_from_server(function(){ me.create_new(); }); - - this.check_internet_connection(); }, make_menu_list: function(){ @@ -204,13 +201,10 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ freeze: true, freeze_message: __("Master data syncing, it might take some time"), callback: function(r){ - window.items = r.message.items; - window.customers = r.message.customers; - window.pricing_rules = r.message.pricing_rules; - window.meta = r.message.meta; - window.print_template = r.message.print_template; - me.default_customer = r.message.default_customer || null; + me.init_master_data(r) localStorage.setItem('doc', JSON.stringify(r.message.doc)); + me.set_interval_for_si_sync(); + me.check_internet_connection(); if(callback){ callback(); } @@ -218,6 +212,22 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }) }, + init_master_data: function(r){ + var me = this; + this.meta = r.message.meta; + this.item_data = r.message.items; + this.customers = r.message.customers; + this.serial_no_data = r.message.serial_no_data; + this.batch_no_data = r.message.batch_no_data; + this.tax_data = r.message.tax_data; + this.price_list_data = r.message.price_list_data; + this.bin_data = r.message.bin_data; + this.pricing_rules = r.message.pricing_rules; + this.print_template = r.message.print_template; + this.pos_profile_data = r.message.pos_profile; + this.default_customer = r.message.default_customer || null; + }, + save_previous_entry : function(){ if(this.frm.doc.items.length > 0){ this.create_invoice() @@ -233,20 +243,19 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }, load_data: function(load_doc){ - this.items = window.items; - this.customers = window.customers; - this.pricing_rules = window.pricing_rules; + var me = this; + this.items = this.item_data; if(load_doc) { this.frm.doc = JSON.parse(localStorage.getItem('doc')); } - $.each(window.meta, function(i, data){ + $.each(this.meta, function(i, data){ frappe.meta.sync(data) }) this.print_template = frappe.render_template("print_template", - {content: window.print_template, title:"POS", + {content: this.print_template, title:"POS", base_url: frappe.urllib.get_base_url(), print_css: frappe.boot.print_css}) }, @@ -387,12 +396,12 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ var $wrap = me.wrapper.find(".item-list"); me.wrapper.find(".item-list").empty(); - if (this.items) { + if (this.items.length > 0) { $.each(this.items, function(index, obj) { if(index < 30){ $(frappe.render_template("pos_item", { item_code: obj.name, - item_price: format_currency(obj.price_list_rate, me.frm.doc.currency), + item_price: format_currency(me.price_list_data[obj.name], me.frm.doc.currency), item_name: obj.name===obj.item_name ? "" : obj.item_name, item_image: obj.image ? "url('" + obj.image + "')" : null, color: frappe.get_palette(obj.item_name), @@ -400,6 +409,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ })).tooltip().appendTo($wrap); } }); + } else { + $("