-
- {% if(!item.image) { %}{{ item.abbr }}{% } %}
+ {% if (i % 4 === 0) { %}
{% } %}
+
-{% } %}
+ {% if ((i % 4 === 3) || (i===data.length - 1)) { %}
{% } %}
+{% endfor %}
\ No newline at end of file
diff --git a/erpnext/public/js/utils/item_selector.js b/erpnext/public/js/utils/item_selector.js
index 98a17f289fd..d04c488a59d 100644
--- a/erpnext/public/js/utils/item_selector.js
+++ b/erpnext/public/js/utils/item_selector.js
@@ -2,6 +2,14 @@ erpnext.ItemSelector = Class.extend({
init: function(opts) {
$.extend(this, opts);
+ if (!this.item_field) {
+ this.item_field = 'item_code';
+ }
+
+ if (!this.item_query) {
+ this.item_query = erpnext.queries.item().query;
+ }
+
this.grid = this.frm.get_field("items").grid;
this.setup();
},
@@ -32,8 +40,8 @@ erpnext.ItemSelector = Class.extend({
this.dialog.results = body.find('.results');
var me = this;
- this.dialog.results.on('click', '.pos-item', function() {
- me.add_item($(this).attr('data-name'))
+ this.dialog.results.on('click', '.image-view-item', function() {
+ me.add_item($(this).attr('data-name'));
});
this.dialog.input.on('keyup', function() {
@@ -52,35 +60,42 @@ erpnext.ItemSelector = Class.extend({
var added = false;
// find row with item if exists
- $.each(this.frm.doc.items || [], function(i, d) {
- if(d.item_code===item_code) {
+ $.each(this.frm.doc.items || [], (i, d) => {
+ if(d[this.item_field]===item_code) {
frappe.model.set_value(d.doctype, d.name, 'qty', d.qty + 1);
- frappe.show_alert(__("Added {0} ({1})", [item_code, d.qty]));
+ frappe.show_alert({message: __("Added {0} ({1})", [item_code, d.qty]), indicator: 'green'});
added = true;
return false;
}
});
if(!added) {
- var d = this.grid.add_new_row();
- frappe.model.set_value(d.doctype, d.name, 'item_code', item_code);
-
- // after item fetch
- frappe.after_ajax(function() {
- setTimeout(function() {
+ var d = null;
+ frappe.run_serially([
+ () => { d = this.grid.add_new_row(); },
+ () => frappe.model.set_value(d.doctype, d.name, this.item_field, item_code),
+ () => frappe.timeout(0.1),
+ () => {
frappe.model.set_value(d.doctype, d.name, 'qty', 1);
- frappe.show_alert(__("Added {0} ({1})", [item_code, 1]));
- }, 100);
- });
+ frappe.show_alert({message: __("Added {0} ({1})", [item_code, 1]), indicator: 'green'});
+ }
+ ]);
}
},
render_items: function() {
- var args = erpnext.queries.item();
+ let args = {
+ query: this.item_query,
+ filters: {}
+ };
args.txt = this.dialog.input.val();
args.as_dict = 1;
+ if (this.get_filters) {
+ $.extend(args.filters, this.get_filters() || {});
+ }
+
var me = this;
frappe.link_search("Item", args, function(r) {
$.each(r.values, function(i, d) {
@@ -92,4 +107,4 @@ erpnext.ItemSelector = Class.extend({
me.dialog.results.html(frappe.render_template('item_selector', {'data':r.values}));
});
}
-})
\ No newline at end of file
+});
\ No newline at end of file
diff --git a/erpnext/docs/user/manual/en/subscription/index.txt b/erpnext/restaurant/__init__.py
similarity index 100%
rename from erpnext/docs/user/manual/en/subscription/index.txt
rename to erpnext/restaurant/__init__.py
diff --git a/erpnext/restaurant/doctype/__init__.py b/erpnext/restaurant/doctype/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/restaurant/doctype/restaurant/__init__.py b/erpnext/restaurant/doctype/restaurant/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/restaurant/doctype/restaurant/restaurant.js b/erpnext/restaurant/doctype/restaurant/restaurant.js
new file mode 100644
index 00000000000..13fda73922a
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant/restaurant.js
@@ -0,0 +1,10 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Restaurant', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Order Entry'), () => {
+ frappe.set_route('Form', 'Restaurant Order Entry');
+ });
+ }
+});
diff --git a/erpnext/restaurant/doctype/restaurant/restaurant.json b/erpnext/restaurant/doctype/restaurant/restaurant.json
new file mode 100644
index 00000000000..f4ecba79452
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant/restaurant.json
@@ -0,0 +1,309 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "prompt",
+ "beta": 0,
+ "creation": "2017-09-15 12:40:41.546933",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "image",
+ "fieldtype": "Attach Image",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Image",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "company",
+ "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": "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "default_customer",
+ "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": "Default Customer",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Customer",
+ "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
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "invoice_series_prefix",
+ "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": "Invoice Series Prefix",
+ "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
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_4",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "active_menu",
+ "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": "Active Menu",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Restaurant Menu",
+ "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_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "default_tax_template",
+ "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": "Default Tax Template",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Sales Taxes and Charges Template",
+ "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_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "address",
+ "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": "Address",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Address",
+ "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
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_field": "image",
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-10-05 17:41:14.422242",
+ "modified_by": "Administrator",
+ "module": "Restaurant",
+ "name": "Restaurant",
+ "name_case": "",
+ "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": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "restrict_to_domain": "Hospitality",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/restaurant/doctype/restaurant/restaurant.py b/erpnext/restaurant/doctype/restaurant/restaurant.py
new file mode 100644
index 00000000000..0bb7b692c75
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant/restaurant.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, 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 Restaurant(Document):
+ pass
diff --git a/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py b/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py
new file mode 100644
index 00000000000..1f84ccf1d8d
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py
@@ -0,0 +1,16 @@
+from frappe import _
+
+def get_data():
+ return {
+ 'fieldname': 'restaurant',
+ 'transactions': [
+ {
+ 'label': _('Setup'),
+ 'items': ['Restaurant Menu', 'Restaurant Table']
+ },
+ {
+ 'label': _('Operations'),
+ 'items': ['Restaurant Reservation', 'Sales Invoice']
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/erpnext/restaurant/doctype/restaurant/test_restaurant.js b/erpnext/restaurant/doctype/restaurant/test_restaurant.js
new file mode 100644
index 00000000000..1cc7c7f069a
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant/test_restaurant.js
@@ -0,0 +1,37 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Restaurant", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(2);
+
+ frappe.run_serially([
+ // insert a new Restaurant
+ () => {
+ return frappe.tests.make('Restaurant', [
+ // values to be set
+ {__newname: 'Test Restaurant 1'},
+ {company: 'Test Company'},
+ {invoice_series_prefix: 'Test-Rest-1-Inv-'}
+ ])
+ },
+ () => {
+ assert.equal(cur_frm.doc.company, 'Test Company');
+ },
+ () => {
+ return frappe.tests.make('Restaurant', [
+ // values to be set
+ {__newname: 'Test Restaurant 2'},
+ {company: 'Test Company'},
+ {invoice_series_prefix: 'Test-Rest-3-Inv-'}
+ ]);
+ },
+ () => {
+ assert.equal(cur_frm.doc.company, 'Test Company');
+ },
+ () => done()
+ ]);
+});
diff --git a/erpnext/restaurant/doctype/restaurant/test_restaurant.py b/erpnext/restaurant/doctype/restaurant/test_restaurant.py
new file mode 100644
index 00000000000..7b9885c4e9c
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant/test_restaurant.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+test_records = [
+ dict(doctype='Restaurant', name='Test Restaurant 1', company='_Test Company 1',
+ invoice_series_prefix='Test-Rest-1-Inv-', defaut_customer='_Test Customer 1'),
+ dict(doctype='Restaurant', name='Test Restaurant 2', company='_Test Company 1',
+ invoice_series_prefix='Test-Rest-2-Inv-', defaut_customer='_Test Customer 1'),
+]
+
+class TestRestaurant(unittest.TestCase):
+ pass
diff --git a/erpnext/restaurant/doctype/restaurant_menu/__init__.py b/erpnext/restaurant/doctype/restaurant_menu/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.js b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.js
new file mode 100644
index 00000000000..da7d43f8a3e
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Restaurant Menu', {
+ setup: function(frm) {
+ frm.add_fetch('item', 'standard_rate', 'rate');
+ },
+});
diff --git a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.json b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.json
new file mode 100644
index 00000000000..264634b0f6f
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.json
@@ -0,0 +1,247 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "prompt",
+ "beta": 0,
+ "creation": "2017-09-15 12:48:29.818715",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "restaurant",
+ "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": "Restaurant",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Restaurant",
+ "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
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "1",
+ "fieldname": "enabled",
+ "fieldtype": "Check",
+ "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": "Enabled",
+ "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_bulk_edit": 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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "price_list",
+ "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": "Price List (Auto created)",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Price List",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "items_section",
+ "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,
+ "label": "Items",
+ "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_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "items",
+ "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": "Items",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Restaurant Menu Item",
+ "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
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-09-21 11:04:20.671542",
+ "modified_by": "Administrator",
+ "module": "Restaurant",
+ "name": "Restaurant Menu",
+ "name_case": "",
+ "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": "Restaurant Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "restrict_to_domain": "Hospitality",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py
new file mode 100644
index 00000000000..83020b6cca8
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, 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 RestaurantMenu(Document):
+ def validate(self):
+ for d in self.items:
+ if not d.rate:
+ d.rate = frappe.db.get_value('Item', d.item, 'standard_rate')
+
+ def on_update(self):
+ '''Sync Price List'''
+ self.make_price_list()
+
+ def on_trash(self):
+ '''clear prices'''
+ self.clear_item_price()
+
+ def clear_item_price(self, price_list=None):
+ '''clear all item prices for this menu'''
+ if not price_list:
+ price_list = self.get_price_list().name
+ frappe.db.sql('delete from `tabItem Price` where price_list = %s', price_list)
+
+ def make_price_list(self):
+ # create price list for menu
+ price_list = self.get_price_list()
+ self.db_set('price_list', price_list.name)
+
+ # delete old items
+ self.clear_item_price(price_list.name)
+
+ for d in self.items:
+ frappe.get_doc(dict(
+ doctype = 'Item Price',
+ price_list = price_list.name,
+ item_code = d.item,
+ price_list_rate = d.rate
+ )).insert()
+
+ def get_price_list(self):
+ '''Create price list for menu if missing'''
+ price_list_name = frappe.db.get_value('Price List', dict(restaurant_menu=self.name))
+ if price_list_name:
+ price_list = frappe.get_doc('Price List', price_list_name)
+ else:
+ price_list = frappe.new_doc('Price List')
+ price_list.restaurant_menu = self.name
+ price_list.price_list_name = self.name
+
+ price_list.enabled = 1
+ price_list.selling = 1
+ price_list.save()
+
+ return price_list
+
+
diff --git a/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.js b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.js
new file mode 100644
index 00000000000..25057d83340
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.js
@@ -0,0 +1,75 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Restaurant Menu", function (assert) {
+ let done = assert.async();
+
+ let items = {
+ "Food Item 1": [
+ {item_code: "Food Item 1"},
+ {item_group: "Products"},
+ {is_stock_item: 1},
+ ],
+ "Food Item 2": [
+ {item_code: "Food Item 2"},
+ {item_group: "Products"},
+ {is_stock_item: 1},
+ ],
+ "Test Product 3": [
+ {item_code: "Food Item 3"},
+ {item_group: "Products"},
+ {is_stock_item: 1},
+ ]
+ };
+
+
+ // number of asserts
+ assert.expect(0);
+
+ frappe.run_serially([
+ // insert a new Restaurant Menu
+ () => frappe.tests.setup_doctype('Item', items),
+ () => {
+ return frappe.tests.make("Restaurant Menu", [
+ {__newname: 'Restaurant Menu 1'},
+ {restaurant: "Test Restaurant 1"},
+ {items: [
+ [
+ {"item": "Food Item 1"},
+ {"rate": 100}
+ ],
+ [
+ {"item": "Food Item 2"},
+ {"rate": 90}
+ ],
+ [
+ {"item": "Food Item 3"},
+ {"rate": 80}
+ ]
+ ]}
+ ]);
+ },
+ () => {
+ return frappe.tests.make("Restaurant Menu", [
+ {__newname: 'Restaurant Menu 2'},
+ {restaurant: "Test Restaurant 2"},
+ {items: [
+ [
+ {"item": "Food Item 1"},
+ {"rate": 105}
+ ],
+ [
+ {"item": "Food Item 3"},
+ {"rate": 85}
+ ]
+ ]}
+ ]);
+ },
+ () => frappe.set_route('Form', 'Restaurant', 'Test Restaurant 1'),
+ () => cur_frm.set_value('active_menu', 'Restaurant Menu 1'),
+ () => cur_frm.save(),
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py
new file mode 100644
index 00000000000..99766f7b017
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+test_records = [
+ dict(doctype='Item', item_code='Food Item 1',
+ item_group='Products', is_stock_item=0),
+ dict(doctype='Item', item_code='Food Item 2',
+ item_group='Products', is_stock_item=0),
+ dict(doctype='Item', item_code='Food Item 3',
+ item_group='Products', is_stock_item=0),
+ dict(doctype='Item', item_code='Food Item 4',
+ item_group='Products', is_stock_item=0),
+ dict(doctype='Restaurant Menu', restaurant='Test Restaurant 1', name='Test Restaurant 1 Menu 1',
+ items = [
+ dict(item='Food Item 1', rate=400),
+ dict(item='Food Item 2', rate=300),
+ dict(item='Food Item 3', rate=200),
+ dict(item='Food Item 4', rate=100),
+ ]),
+ dict(doctype='Restaurant Menu', restaurant='Test Restaurant 1', name='Test Restaurant 1 Menu 2',
+ items = [
+ dict(item='Food Item 1', rate=450),
+ dict(item='Food Item 2', rate=350),
+ ])
+]
+
+class TestRestaurantMenu(unittest.TestCase):
+ def test_price_list_creation_and_editing(self):
+ menu1 = frappe.get_doc('Restaurant Menu', 'Test Restaurant 1 Menu 1')
+ menu1.save()
+
+ menu2 = frappe.get_doc('Restaurant Menu', 'Test Restaurant 1 Menu 2')
+ menu2.save()
+
+ self.assertTrue(frappe.db.get_value('Price List', 'Test Restaurant 1 Menu 1'))
+ self.assertEquals(frappe.db.get_value('Item Price',
+ dict(price_list = 'Test Restaurant 1 Menu 1', item_code='Food Item 1'), 'price_list_rate'), 400)
+ self.assertEquals(frappe.db.get_value('Item Price',
+ dict(price_list = 'Test Restaurant 1 Menu 2', item_code='Food Item 1'), 'price_list_rate'), 450)
+
+ menu1.items[0].rate = 401
+ menu1.save()
+
+ self.assertEquals(frappe.db.get_value('Item Price',
+ dict(price_list = 'Test Restaurant 1 Menu 1', item_code='Food Item 1'), 'price_list_rate'), 401)
+
+ menu1.items[0].rate = 400
+ menu1.save()
diff --git a/erpnext/restaurant/doctype/restaurant_menu_item/__init__.py b/erpnext/restaurant/doctype/restaurant_menu_item/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.json b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.json
new file mode 100644
index 00000000000..87568bf9818
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.json
@@ -0,0 +1,105 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "",
+ "beta": 0,
+ "creation": "2017-09-15 12:49:36.072636",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "item",
+ "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": "Item",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Item",
+ "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
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "rate",
+ "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": "Rate",
+ "length": 0,
+ "no_copy": 0,
+ "options": "",
+ "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
+ }
+ ],
+ "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": "2017-09-15 14:18:55.145088",
+ "modified_by": "Administrator",
+ "module": "Restaurant",
+ "name": "Restaurant Menu Item",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "restrict_to_domain": "Hospitality",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py
new file mode 100644
index 00000000000..cc86bb3165e
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, 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 RestaurantMenuItem(Document):
+ pass
diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/__init__.py b/erpnext/restaurant/doctype/restaurant_order_entry/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.js b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.js
new file mode 100644
index 00000000000..8867e7d707b
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.js
@@ -0,0 +1,162 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Restaurant Order Entry', {
+ setup: function(frm) {
+ let get_item_query = () => {
+ return {
+ query: 'erpnext.restaurant.doctype.restaurant_order_entry.restaurant_order_entry.item_query_restaurant',
+ filters: {
+ 'table': frm.doc.restaurant_table
+ }
+ };
+ };
+ frm.set_query('item', 'items', get_item_query);
+ frm.set_query('add_item', get_item_query);
+ },
+ onload_post_render: function(frm) {
+ if(!this.item_selector) {
+ this.item_selector = new erpnext.ItemSelector({
+ frm: frm,
+ item_field: 'item',
+ item_query: 'erpnext.restaurant.doctype.restaurant_order_entry.restaurant_order_entry.item_query_restaurant',
+ get_filters: () => {
+ return {table: frm.doc.restaurant_table};
+ }
+ });
+ }
+
+ let $input = frm.get_field('add_item').$input;
+
+ $input.on('keyup', function(e) {
+ if (e.which===13) {
+ if (frm.clear_item_timeout) {
+ clearTimeout (frm.clear_item_timeout);
+ }
+
+ // clear the item input so user can enter a new item
+ frm.clear_item_timeout = setTimeout (() => {
+ frm.set_value('add_item', '');
+ }, 1000);
+
+ let item = $input.val();
+
+ if (!item) return;
+
+ var added = false;
+ (frm.doc.items || []).forEach((d) => {
+ if (d.item===item) {
+ d.qty += 1;
+ added = true;
+ }
+ });
+
+ return frappe.run_serially([
+ () => {
+ if (!added) {
+ return frm.add_child('items', {item: item, qty: 1});
+ }
+ },
+ () => frm.get_field("items").refresh()
+ ]);
+ }
+ });
+ },
+ refresh: function(frm) {
+ frm.disable_save();
+ frm.add_custom_button(__('Update'), () => {
+ return frm.trigger('sync');
+ });
+ frm.add_custom_button(__('Clear'), () => {
+ return frm.trigger('clear');
+ });
+ frm.add_custom_button(__('Bill'), () => {
+ return frm.trigger('make_invoice');
+ });
+ },
+ clear: function(frm) {
+ frm.doc.add_item = '';
+ frm.doc.grand_total = 0;
+ frm.doc.items = [];
+ frm.refresh();
+ frm.get_field('add_item').$input.focus();
+ },
+ restaurant_table: function(frm) {
+ // select the open sales order items for this table
+ if (!frm.doc.restaurant_table) {
+ return;
+ }
+ return frappe.call({
+ method: 'erpnext.restaurant.doctype.restaurant_order_entry.restaurant_order_entry.get_invoice',
+ args: {
+ table: frm.doc.restaurant_table
+ },
+ callback: (r) => {
+ frm.events.set_invoice_items(frm, r);
+ }
+ });
+ },
+ sync: function(frm) {
+ return frappe.call({
+ method: 'erpnext.restaurant.doctype.restaurant_order_entry.restaurant_order_entry.sync',
+ args: {
+ table: frm.doc.restaurant_table,
+ items: frm.doc.items
+ },
+ callback: (r) => {
+ frm.events.set_invoice_items(frm, r);
+ frappe.show_alert({message: __('Saved'), indicator: 'green'});
+ }
+ });
+
+ },
+ make_invoice: function(frm) {
+ frm.trigger('sync').then(() => {
+ frappe.prompt([
+ {
+ fieldname: 'customer',
+ label: __('Customer'),
+ fieldtype: 'Link',
+ reqd: 1,
+ options: 'Customer',
+ 'default': frm.invoice.customer
+ },
+ {
+ fieldname: 'mode_of_payment',
+ label: __('Mode of Payment'),
+ fieldtype: 'Link',
+ reqd: 1,
+ options: 'Mode of Payment',
+ 'default': frm.mode_of_payment || ''
+ }
+ ], (data) => {
+ // cache this for next entry
+ frm.mode_of_payment = data.mode_of_payment;
+ return frappe.call({
+ method: 'erpnext.restaurant.doctype.restaurant_order_entry.restaurant_order_entry.make_invoice',
+ args: {
+ table: frm.doc.restaurant_table,
+ customer: data.customer,
+ mode_of_payment: data.mode_of_payment
+ },
+ callback: (r) => {
+ frm.set_value('last_sales_invoice', r.message);
+ frm.trigger('clear');
+ }
+ });
+ },
+ __("Select Customer"));
+ });
+ },
+ set_invoice_items: function(frm, r) {
+ let invoice = r.message;
+ frm.doc.items = [];
+ (invoice.items || []).forEach((d) => {
+ frm.add_child('items', {item: d.item_code, qty: d.qty, rate: d.rate});
+ });
+ frm.set_value('grand_total', invoice.grand_total);
+ frm.set_value('last_sales_invoice', invoice.name);
+ frm.invoice = invoice;
+ frm.refresh();
+ }
+});
diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.json b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.json
new file mode 100644
index 00000000000..3e4d593d5b6
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.json
@@ -0,0 +1,280 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 1,
+ "creation": "2017-09-15 15:10:24.530365",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "restaurant_table",
+ "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": "Restaurant Table",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Restaurant Table",
+ "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_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "restaurant_table",
+ "description": "Click Enter To Add",
+ "fieldname": "add_item",
+ "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": "Add Item",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Item",
+ "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_bulk_edit": 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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "grand_total",
+ "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": "Grand Total",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "last_sales_invoice",
+ "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": "Last Sales Invoice",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Sales Invoice",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "restaurant_table",
+ "fieldname": "current_order",
+ "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,
+ "label": "Current Order",
+ "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_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "restaurant_table",
+ "fieldname": "items",
+ "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": "Items",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Restaurant Order Entry Item",
+ "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
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 1,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-10-04 17:06:20.926999",
+ "modified_by": "Administrator",
+ "module": "Restaurant",
+ "name": "Restaurant Order Entry",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 0,
+ "role": "Restaurant Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "restrict_to_domain": "Hospitality",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py
new file mode 100644
index 00000000000..a748f9a0075
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py
@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe, json
+from frappe.model.document import Document
+from frappe import _
+from erpnext.controllers.queries import item_query
+
+class RestaurantOrderEntry(Document):
+ pass
+
+@frappe.whitelist()
+def get_invoice(table):
+ '''returns the active invoice linked to the given table'''
+ invoice_name = frappe.get_value('Sales Invoice', dict(restaurant_table = table, docstatus=0))
+ restaurant, menu_name = get_restaurant_and_menu_name(table)
+ if invoice_name:
+ invoice = frappe.get_doc('Sales Invoice', invoice_name)
+ else:
+ invoice = frappe.new_doc('Sales Invoice')
+ invoice.naming_series = frappe.db.get_value('Restaurant', restaurant, 'invoice_series_prefix')
+ invoice.is_pos = 1
+ default_customer = frappe.db.get_value('Restaurant', restaurant, 'default_customer')
+ if not default_customer:
+ frappe.throw(_('Please set default customer in Restaurant Settings'))
+ invoice.customer = default_customer
+
+ invoice.taxes_and_charges = frappe.db.get_value('Restaurant', restaurant, 'default_tax_template')
+ invoice.selling_price_list = frappe.db.get_value('Price List', dict(restaurant_menu=menu_name, enabled=1))
+
+ return invoice
+
+@frappe.whitelist()
+def sync(table, items):
+ '''Sync the sales order related to the table'''
+ invoice = get_invoice(table)
+ items = json.loads(items)
+
+ invoice.items = []
+ invoice.restaurant_table = table
+ for d in items:
+ invoice.append('items', dict(
+ item_code = d.get('item'),
+ qty = d.get('qty')
+ ))
+
+ invoice.save()
+ return invoice.as_dict()
+
+@frappe.whitelist()
+def make_invoice(table, customer, mode_of_payment):
+ '''Make table based on Sales Order'''
+ restaurant, menu = get_restaurant_and_menu_name(table)
+ invoice = get_invoice(table)
+ invoice.customer = customer
+ invoice.restaurant = restaurant
+ invoice.calculate_taxes_and_totals()
+ invoice.append('payments', dict(mode_of_payment=mode_of_payment, amount=invoice.grand_total))
+ invoice.save()
+ invoice.submit()
+
+ frappe.msgprint(_('Invoice Created'), indicator='green', alert=True)
+
+ return invoice.name
+
+def item_query_restaurant(doctype='Item', txt='', searchfield='name', start=0, page_len=20, filters=None, as_dict=False):
+ '''Return items that are selected in active menu of the restaurant'''
+ restaurant, menu = get_restaurant_and_menu_name(filters['table'])
+ items = frappe.db.get_all('Restaurant Menu Item', ['item'], dict(parent = menu))
+ del filters['table']
+ filters['name'] = ('in', [d.item for d in items])
+
+ return item_query('Item', txt, searchfield, start, page_len, filters, as_dict)
+
+def get_restaurant_and_menu_name(table):
+ if not table:
+ frappe.throw(_('Please select a table'))
+
+ restaurant = frappe.db.get_value('Restaurant Table', table, 'restaurant')
+ menu = frappe.db.get_value('Restaurant', restaurant, 'active_menu')
+
+ if not menu:
+ frappe.throw(_('Please set an active menu for Restaurant {0}').format(restaurant))
+
+ return restaurant, menu
\ No newline at end of file
diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/test_restaurant_order_entry.js b/erpnext/restaurant/doctype/restaurant_order_entry/test_restaurant_order_entry.js
new file mode 100644
index 00000000000..fec2a2153be
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_order_entry/test_restaurant_order_entry.js
@@ -0,0 +1,53 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Restaurant Order Entry", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(5);
+
+ frappe.run_serially([
+ // insert a new Restaurant Order Entry
+ () => frappe.set_route('Form', 'Restaurant Settings'),
+ () => cur_frm.set_value('default_customer', 'Test Customer 1'),
+ () => cur_frm.save(),
+ () => frappe.set_route('Form', 'Restaurant Order Entry'),
+ () => frappe.click_button('Clear'),
+ () => frappe.timeout(2),
+ () => cur_frm.set_value('restaurant_table', 'Test-Restaurant-1-01'),
+ () => cur_frm.set_value('add_item', 'Food Item 1'),
+ () => frappe.timeout(0.5),
+ () => {
+ var e = $.Event( "keyup", {which: 13} );
+ $('input[data-fieldname="add_item"]').trigger(e);
+ return frappe.timeout(0.5);
+ },
+ () => cur_frm.set_value('add_item', 'Food Item 1'),
+ () => {
+ var e = $.Event( "keyup", {which: 13} );
+ $('input[data-fieldname="add_item"]').trigger(e);
+ return frappe.timeout(0.5);
+ },
+ () => cur_frm.set_value('add_item', 'Food Item 2'),
+ () => {
+ var e = $.Event( "keyup", {which: 13} );
+ $('input[data-fieldname="add_item"]').trigger(e);
+ return frappe.timeout(0.5);
+ },
+ () => {
+ assert.equal(cur_frm.doc.items[0].item, 'Food Item 1');
+ assert.equal(cur_frm.doc.items[0].qty, 2);
+ assert.equal(cur_frm.doc.items[1].item, 'Food Item 2');
+ assert.equal(cur_frm.doc.items[1].qty, 1);
+ },
+ () => frappe.click_button('Update'),
+ () => frappe.timeout(2),
+ () => {
+ assert.equal(cur_frm.doc.grand_total, 290);
+ }
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/test_restaurant_order_entry.py b/erpnext/restaurant/doctype/restaurant_order_entry/test_restaurant_order_entry.py
new file mode 100644
index 00000000000..59605b150b3
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_order_entry/test_restaurant_order_entry.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe, json
+import unittest
+
+from erpnext.restaurant.doctype.restaurant_order_entry.restaurant_order_entry \
+ import (sync, make_invoice, item_query_restaurant)
+
+class TestRestaurantOrderEntry(unittest.TestCase):
+ def setUp(self):
+ # save the menus as Price List is deleted before tests...
+ frappe.get_doc('Restaurant Menu', 'Test Restaurant 1 Menu 1').save()
+ frappe.get_doc('Restaurant Menu', 'Test Restaurant 1 Menu 2').save()
+
+ if not frappe.db.get_value('Restaurant', 'Test Restaurant 1', 'active_menu'):
+ restaurant = frappe.get_doc('Restaurant', 'Test Restaurant 1')
+ restaurant.active_menu = 'Test Restaurant 1 Menu 1'
+ restaurant.save()
+
+ def test_update_order(self):
+ table = frappe.db.get_value('Restaurant Table', dict(restaurant = 'Test Restaurant 1'))
+ invoice = sync(table,
+ json.dumps([dict(item='Food Item 1', qty = 10), dict(item='Food Item 2', qty = 2)]))
+
+ self.assertEquals(invoice.get('restaurant_table'), table)
+ self.assertEquals(invoice.get('items')[0].get('item_code'), 'Food Item 1')
+ self.assertEquals(invoice.get('items')[1].get('item_code'), 'Food Item 2')
+ self.assertEquals(invoice.get('net_total'), 4600)
+
+ return table
+
+ def test_billing(self):
+ table = self.test_update_order()
+ invoice_name = make_invoice(table, '_Test Customer', 'Cash')
+
+ sales_invoice = frappe.get_doc('Sales Invoice', invoice_name)
+
+ self.assertEquals(sales_invoice.grand_total, 4600)
+ self.assertEquals(sales_invoice.items[0].item_code, 'Food Item 1')
+ self.assertEquals(sales_invoice.items[1].item_code, 'Food Item 2')
+ self.assertEquals(sales_invoice.payments[0].mode_of_payment, 'Cash')
+ self.assertEquals(sales_invoice.payments[0].amount, 4600)
+
+ def test_item_query(self):
+ table = frappe.db.get_value('Restaurant Table', dict(restaurant = 'Test Restaurant 1'))
+ result = item_query_restaurant(filters=dict(table=table))
+ items = [d[0] for d in result]
+ self.assertTrue('Food Item 1' in items)
+ self.assertTrue('_Test Item 1' not in items)
diff --git a/erpnext/restaurant/doctype/restaurant_order_entry_item/__init__.py b/erpnext/restaurant/doctype/restaurant_order_entry_item/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.json b/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.json
new file mode 100644
index 00000000000..0240013c784
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.json
@@ -0,0 +1,163 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2017-09-15 15:11:50.313241",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "item",
+ "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": "Item",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Item",
+ "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
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "qty",
+ "fieldtype": "Int",
+ "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": "Qty",
+ "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
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "served",
+ "fieldtype": "Int",
+ "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": "Served",
+ "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_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "rate",
+ "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": "Rate",
+ "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
+ }
+ ],
+ "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": "2017-09-21 08:39:27.232175",
+ "modified_by": "Administrator",
+ "module": "Restaurant",
+ "name": "Restaurant Order Entry Item",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "restrict_to_domain": "Hospitality",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py b/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py
new file mode 100644
index 00000000000..e0c051b1ad7
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, 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 RestaurantOrderEntryItem(Document):
+ pass
diff --git a/erpnext/restaurant/doctype/restaurant_reservation/__init__.py b/erpnext/restaurant/doctype/restaurant_reservation/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.js b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.js
new file mode 100644
index 00000000000..92183384d39
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Restaurant Reservation', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.json b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.json
new file mode 100644
index 00000000000..6a2ffa13277
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.json
@@ -0,0 +1,337 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "REST.######",
+ "beta": 0,
+ "creation": "2017-09-15 13:05:51.063661",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 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": 1,
+ "in_standard_filter": 0,
+ "label": "Status",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Open\nWaitlisted\nCancelled\nNo Show\nSuccess",
+ "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_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "restaurant",
+ "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": "Restaurant",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Restaurant",
+ "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
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "no_of_people",
+ "fieldtype": "Int",
+ "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": "No of People",
+ "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
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "reservation_time",
+ "fieldtype": "Datetime",
+ "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": "Reservation Time",
+ "length": 0,
+ "no_copy": 0,
+ "options": "",
+ "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
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "reservation_end_time",
+ "fieldtype": "Datetime",
+ "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": "Reservation End Time",
+ "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_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_4",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "customer",
+ "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": "Customer",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Customer",
+ "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_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "customer_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Customer 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
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "contact_number",
+ "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": "Contact Number",
+ "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
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-09-15 14:40:56.759315",
+ "modified_by": "Administrator",
+ "module": "Restaurant",
+ "name": "Restaurant Reservation",
+ "name_case": "",
+ "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": "Restaurant Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "restrict_to_domain": "Hospitality",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py
new file mode 100644
index 00000000000..63a36f0a6d2
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, 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
+from datetime import timedelta
+from frappe.utils import get_datetime
+
+class RestaurantReservation(Document):
+ def validate(self):
+ if not self.reservation_end_time:
+ self.reservation_end_time = get_datetime(self.reservation_time) + timedelta(hours=1)
+
+@frappe.whitelist()
+def get_events(start, end, filters=None):
+ """Returns events for Gantt / Calendar view rendering.
+
+ :param start: Start date-time.
+ :param end: End date-time.
+ :param filters: Filters (JSON).
+ """
+ from frappe.desk.calendar import get_event_conditions
+ conditions = get_event_conditions("Restaurant Reservation", filters)
+
+ data = frappe.db.sql("""select name, reservation_time,
+ reservation_end_time, customer_name, status, no_of_people
+ from
+ `tabRestaurant Reservation`
+ where
+ ((ifnull(reservation_time, '0000-00-00')!= '0000-00-00') \
+ and (reservation_time <= %(end)s) \
+ or ((ifnull(reservation_end_time, '0000-00-00')!= '0000-00-00') \
+ and reservation_end_time >= %(start)s))
+ {conditions}""".format(conditions=conditions), {
+ "start": start,
+ "end": end
+ }, as_dict=True, update={"allDay": 0})
+
+ return data
diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation_calendar.js b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation_calendar.js
new file mode 100644
index 00000000000..09e8f8d937b
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation_calendar.js
@@ -0,0 +1,18 @@
+frappe.views.calendar["Restaurant Reservation"] = {
+ field_map: {
+ "start": "reservation_time",
+ "end": "reservation_end_time",
+ "id": "name",
+ "title": "customer_name",
+ "allDay": "allDay",
+ },
+ gantt: true,
+ filters: [
+ {
+ "fieldtype": "Data",
+ "fieldname": "customer_name",
+ "label": __("Customer Name")
+ }
+ ],
+ get_events_method: "erpnext.restaurant.doctype.restaurant_reservation.restaurant_reservation.get_events"
+};
diff --git a/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.js b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.js
new file mode 100644
index 00000000000..eeea5a9f0b2
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.js
@@ -0,0 +1,27 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Restaurant Reservation", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Restaurant Reservation
+ () => frappe.tests.make('Restaurant Reservation', [
+ // values to be set
+ {restaurant: 'Gokul - JP Nagar'},
+ {customer_name: 'test customer'},
+ {reservation_time: frappe.datetime.now_date() + " 19:00:00"},
+ {no_of_people: 4},
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.reservation_end_time,
+ frappe.datetime.now_date() + ' 20:00:00');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py
new file mode 100644
index 00000000000..71681b2f183
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestRestaurantReservation(unittest.TestCase):
+ pass
diff --git a/erpnext/restaurant/doctype/restaurant_table/__init__.py b/erpnext/restaurant/doctype/restaurant_table/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.js b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.js
new file mode 100644
index 00000000000..a55605c90bf
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Restaurant Table', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.json b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.json
new file mode 100644
index 00000000000..da1bcde4046
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.json
@@ -0,0 +1,156 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "",
+ "beta": 0,
+ "creation": "2017-09-15 12:45:24.717355",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "restaurant",
+ "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": "Restaurant",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Restaurant",
+ "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
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "no_of_seats",
+ "fieldtype": "Int",
+ "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": "No of Seats",
+ "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
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "1",
+ "fieldname": "minimum_seating",
+ "fieldtype": "Int",
+ "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": "Minimum Seating",
+ "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
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-09-15 13:18:05.254106",
+ "modified_by": "Administrator",
+ "module": "Restaurant",
+ "name": "Restaurant Table",
+ "name_case": "",
+ "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": "Restaurant Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "restrict_to_domain": "Hospitality",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py
new file mode 100644
index 00000000000..d5ea9d53981
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe, re
+from frappe.model.document import Document
+from frappe.model.naming import make_autoname
+
+class RestaurantTable(Document):
+ def autoname(self):
+ prefix = re.sub('-+', '-', self.restaurant.replace(' ', '-'))
+ self.name = make_autoname(prefix + '-.##')
diff --git a/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.js b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.js
new file mode 100644
index 00000000000..16035f0c892
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.js
@@ -0,0 +1,41 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Restaurant Table", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(0);
+
+ frappe.run_serially([
+ // insert a new Restaurant Table
+ () => frappe.tests.make('Restaurant Table', [
+ // values to be set
+ {restaurant: 'Test Restaurant 1'},
+ {no_of_seats: 4},
+ ]),
+ () => frappe.tests.make('Restaurant Table', [
+ // values to be set
+ {restaurant: 'Test Restaurant 1'},
+ {no_of_seats: 5},
+ ]),
+ () => frappe.tests.make('Restaurant Table', [
+ // values to be set
+ {restaurant: 'Test Restaurant 1'},
+ {no_of_seats: 2},
+ ]),
+ () => frappe.tests.make('Restaurant Table', [
+ // values to be set
+ {restaurant: 'Test Restaurant 1'},
+ {no_of_seats: 2},
+ ]),
+ () => frappe.tests.make('Restaurant Table', [
+ // values to be set
+ {restaurant: 'Test Restaurant 1'},
+ {no_of_seats: 6},
+ ]),
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py
new file mode 100644
index 00000000000..ffdb6f742a3
--- /dev/null
+++ b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+test_records = [
+ dict(restaurant='Test Restaurant 1', no_of_seats=5, minimum_seating=1),
+ dict(restaurant='Test Restaurant 1', no_of_seats=5, minimum_seating=1),
+ dict(restaurant='Test Restaurant 1', no_of_seats=5, minimum_seating=1),
+ dict(restaurant='Test Restaurant 1', no_of_seats=5, minimum_seating=1),
+]
+
+class TestRestaurantTable(unittest.TestCase):
+ pass
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js
index 7110d4c1996..5feae9c28ab 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.js
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.js
@@ -936,7 +936,7 @@ class POSItems {
const all_items = Object.values(_items).map(item => this.get_item_html(item));
let row_items = [];
- const row_container = '
';
+ const row_container = '
';
let curr_row = row_container;
for (let i=0; i < all_items.length; i++) {
diff --git a/erpnext/setup/setup_wizard/domainify.py b/erpnext/setup/setup_wizard/domainify.py
deleted file mode 100644
index ddb2a80afb1..00000000000
--- a/erpnext/setup/setup_wizard/domainify.py
+++ /dev/null
@@ -1,178 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe import _
-
-def get_domain(domain):
- '''Written as a function to prevent data mutation effects'''
- data = {
- 'Manufacturing': {
- 'desktop_icons': ['Item', 'BOM', 'Customer', 'Supplier', 'Sales Order',
- 'Production Order', 'Stock Entry', 'Purchase Order', 'Task', 'Buying', 'Selling',
- 'Accounts', 'HR', 'ToDo'],
- 'remove_roles': ['Academics User', 'Instructor', 'Physician', 'Nursing User',
- 'Laboratory user', 'LabTest Approver', 'Healthcare Administrator'],
- 'properties': [
- {'doctype': 'Item', 'fieldname': 'manufacturing', 'property': 'collapsible_depends_on', 'value': 'is_stock_item'},
- ],
- 'set_value': [
- ['Stock Settings', None, 'show_barcode_field', 1]
- ],
- 'default_portal_role': 'Customer'
- },
-
- 'Retail': {
- 'desktop_icons': ['POS', 'Item', 'Customer', 'Sales Invoice', 'Purchase Order',
- 'Warranty Claim', 'Accounts', 'Task', 'Buying', 'ToDo'],
- 'remove_roles': ['Manufacturing User', 'Manufacturing Manager', 'Academics User', 'Instructor',
- 'Physician', 'Nursing User', 'Laboratory user',
- 'LabTest Approver', 'Healthcare Administrator'],
- 'properties': [
- {'doctype': 'Item', 'fieldname': 'manufacturing', 'property': 'hidden', 'value': 1},
- {'doctype': 'Customer', 'fieldname': 'credit_limit_section', 'property': 'hidden', 'value': 1},
- ],
- 'set_value': [
- ['Stock Settings', None, 'show_barcode_field', 1]
- ],
- 'default_portal_role': 'Customer'
- },
-
- 'Distribution': {
- 'desktop_icons': ['Item', 'Customer', 'Supplier', 'Lead', 'Sales Order', 'Task',
- 'Sales Invoice', 'CRM', 'Selling', 'Buying', 'Stock', 'Accounts', 'HR', 'ToDo'],
- 'remove_roles': ['Manufacturing User', 'Manufacturing Manager', 'Academics User', 'Instructor',
- 'Physician', 'Nursing User', 'Laboratory user',
- 'LabTest Approver', 'Healthcare Administrator'],
- 'set_value': [
- ['Stock Settings', None, 'show_barcode_field', 1]
- ],
- 'default_portal_role': 'Customer'
- },
-
- 'Services': {
- 'desktop_icons': ['Project', 'Timesheet', 'Customer', 'Sales Order', 'Sales Invoice',
- 'Lead', 'Opportunity', 'Task', 'Expense Claim', 'Employee', 'HR', 'ToDo'],
- 'remove_roles': ['Manufacturing User', 'Manufacturing Manager', 'Academics User', 'Instructor',
- 'Physician', 'Nursing User', 'Laboratory user',
- 'LabTest Approver', 'Healthcare Administrator'],
- 'properties': [
- {'doctype': 'Item', 'fieldname': 'is_stock_item', 'property': 'default', 'value': 0},
- ],
- 'set_value': [
- ['Stock Settings', None, 'show_barcode_field', 0]
- ],
- 'default_portal_role': 'Customer'
- },
- 'Education': {
- 'desktop_icons': ['Student', 'Program', 'Course', 'Student Group', 'Instructor',
- 'Fees', 'Task', 'ToDo', 'Schools'],
- 'allow_roles': ['Academics User', 'Accounts User', 'Accounts Manager', 'Item Manager',
- 'Website Manager', 'HR User', 'HR Manager', 'Purchase User', 'Purchase Manager',
- 'Student', 'Projects User', 'Instructor'],
- 'default_portal_role': 'Student'
- },
- 'Healthcare': {
- 'desktop_icons': ['Patient', 'Patient Appointment', 'Consultation', 'Lab Test', 'Healthcare',
- 'Accounts', 'Buying', 'Stock', 'HR', 'ToDo'],
- 'remove_roles': ['Manufacturing User', 'Manufacturing Manager', 'Projects User', 'Projects Manager',
- 'Academics User', 'Instructor'],
- 'default_portal_role': 'Patient'
- },
- }
- if not domain in data:
- raise 'Invalid Domain {0}'.format(domain)
- return frappe._dict(data[domain])
-
-def setup_domain(domain):
- '''Setup roles, desktop icons, properties, values, portal sidebar menu based on domain'''
- data = get_domain(domain)
- setup_roles(data)
- setup_desktop_icons(data)
- setup_properties(data)
- set_values(data)
- setup_sidebar_items(data)
- update_module_def_restrict_to_domain()
-
- if data.get('default_portal_role'):
- frappe.db.set_value('Portal Settings', None, 'default_role', data.get('default_portal_role'))
-
- frappe.clear_cache()
-
-def setup_desktop_icons(data):
- '''set desktop icons form `data.desktop_icons`'''
- from frappe.desk.doctype.desktop_icon.desktop_icon import set_desktop_icons
- if data.desktop_icons:
- set_desktop_icons(data.desktop_icons)
-
-def setup_properties(data):
- if data.properties:
- for args in data.properties:
- frappe.make_property_setter(args)
-
-def setup_roles(data):
- '''Add, remove roles from `data.allow_roles` or `data.remove_roles`'''
- def remove_role(role):
- frappe.db.sql('delete from `tabHas Role` where role=%s', role)
- frappe.set_value('Role', role, 'disabled', 1)
-
- if data.remove_roles:
- for role in data.remove_roles:
- remove_role(role)
-
- if data.allow_roles:
- # remove all roles other than allowed roles
- active_domains = frappe.get_active_domains()
- data.allow_roles += ['Administrator', 'Guest', 'System Manager', 'All']
- for role in frappe.get_all('Role', filters = {"restrict_to_domain": ("not in", active_domains)}):
- if not (role.name in data.allow_roles):
- remove_role(role.name)
-
-def set_values(data):
- '''set values based on `data.set_value`'''
- if data.set_value:
- for args in data.set_value:
- doc = frappe.get_doc(args[0], args[1] or args[0])
- doc.set(args[2], args[3])
- doc.save()
-
-def setup_sidebar_items(data):
- '''Enable / disable sidebar items'''
- if data.allow_sidebar_items:
- # disable all
- frappe.db.sql('update `tabPortal Menu Item` set enabled=0')
-
- # enable
- frappe.db.sql('''update `tabPortal Menu Item` set enabled=1
- where route in ({0})'''.format(', '.join(['"{0}"'.format(d) for d in data.allow_sidebar_items])))
-
- if data.remove_sidebar_items:
- # disable all
- frappe.db.sql('update `tabPortal Menu Item` set enabled=1')
-
- # enable
- frappe.db.sql('''update `tabPortal Menu Item` set enabled=0
- where route in ({0})'''.format(', '.join(['"{0}"'.format(d) for d in data.remove_sidebar_items])))
-
-def reset():
- from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
- add_all_roles_to('Administrator')
-
- frappe.db.sql('delete from `tabProperty Setter`')
-
-def update_module_def_restrict_to_domain():
- """ set the restrict to domain for the module def """
-
- module_def_restrict_to_domain_mapper = {
- "Schools": 'Education'
- }
-
- lang = frappe.db.get_single_value("System Settings", "language") or "en"
- for module, domain in module_def_restrict_to_domain_mapper.iteritems():
- if frappe.db.exists("Domain", _(domain, lang)):
- frappe.db.set_value("Module Def", module, "restrict_to_domain", _(domain, lang))
- elif frappe.db.exists("Domain", domain):
- frappe.db.set_value("Module Def", module, "restrict_to_domain", domain)
- else:
- pass
diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py
index a80399d905c..f7b09d6934e 100644
--- a/erpnext/setup/setup_wizard/setup_wizard.py
+++ b/erpnext/setup/setup_wizard/setup_wizard.py
@@ -10,12 +10,10 @@ from frappe.utils import cstr, flt, getdate
from frappe import _
from frappe.utils.file_manager import save_file
from .default_website import website_maker
-from .healthcare import setup_healthcare
import install_fixtures
from .sample_data import make_sample_data
from erpnext.accounts.doctype.account.account import RootNotEditable
from frappe.core.doctype.communication.comment import add_info_comment
-from erpnext.setup.setup_wizard.domainify import setup_domain
from erpnext.setup.doctype.company.company import install_country_fixtures
def setup_complete(args=None):
@@ -35,20 +33,14 @@ def setup_complete(args=None):
create_letter_head(args)
set_no_copy_fields_in_variant_settings()
- if args.get('domain').lower() == 'education':
- create_academic_year()
- create_academic_term()
-
- if args.domain.lower() == 'healthcare':
- setup_healthcare()
-
if args.get('setup_website'):
website_maker(args)
create_logo(args)
frappe.local.message_log = []
- setup_domain(args.get('domain'))
+ domain_settings = frappe.get_single('Domain Settings')
+ domain_settings.set_active_domains([args.get('domain')])
frappe.db.commit()
login_as_first_user(args)
@@ -400,27 +392,3 @@ def create_employee_for_self(args):
emp.flags.ignore_mandatory = True
emp.insert(ignore_permissions = True)
-# Schools
-def create_academic_term():
- at = ["Semester 1", "Semester 2", "Semester 3"]
- ay = ["2013-14", "2014-15", "2015-16", "2016-17", "2017-18"]
- for y in ay:
- for t in at:
- academic_term = frappe.new_doc("Academic Term")
- academic_term.academic_year = y
- academic_term.term_name = t
- try:
- academic_term.save()
- except frappe.DuplicateEntryError:
- pass
-
-def create_academic_year():
- ac = ["2013-14", "2014-15", "2015-16", "2016-17", "2017-18"]
- for d in ac:
- academic_year = frappe.new_doc("Academic Year")
- academic_year.academic_year_name = d
- try:
- academic_year.save()
- except frappe.DuplicateEntryError:
- pass
-
diff --git a/erpnext/setup/setup_wizard/test_setup_wizard.py b/erpnext/setup/setup_wizard/test_setup_wizard.py
index 57eeeff5b2c..97650f2d24f 100644
--- a/erpnext/setup/setup_wizard/test_setup_wizard.py
+++ b/erpnext/setup/setup_wizard/test_setup_wizard.py
@@ -16,44 +16,50 @@ def run_setup_wizard_test():
# Language slide
driver.wait_for_ajax(True)
- time.sleep(2)
+ time.sleep(1)
+
driver.set_select("language", "English (United States)")
driver.wait_for_ajax(True)
- driver.wait_till_clickable(".next-btn").click()
+ time.sleep(1)
+ driver.click(".next-btn")
# Region slide
driver.wait_for_ajax(True)
driver.set_select("country", "India")
driver.wait_for_ajax(True)
- driver.wait_till_clickable(".next-btn").click()
+ time.sleep(1)
+ driver.click(".next-btn")
# Profile slide
driver.set_field("full_name", "Great Tester")
driver.set_field("email", "great@example.com")
driver.set_field("password", "test")
- driver.wait_till_clickable(".next-btn").click()
+ driver.wait_for_ajax(True)
+ time.sleep(1)
+ driver.click(".next-btn")
+ time.sleep(1)
- # Brand slide
+ # domain slide
driver.set_select("domain", "Manufacturing")
- time.sleep(5)
- driver.wait_till_clickable(".next-btn").click()
+ time.sleep(1)
+ driver.click(".next-btn")
# Org slide
driver.set_field("company_name", "For Testing")
- driver.wait_till_clickable(".next-btn").click()
+ time.sleep(1)
+ driver.print_console()
+ driver.click(".next-btn")
+
driver.set_field("company_tagline", "Just for GST")
driver.set_field("bank_account", "HDFC")
- driver.wait_till_clickable(".complete-btn").click()
+ time.sleep(3)
+ driver.click(".complete-btn")
# Wait for desktop
driver.wait_for('#page-desktop', timeout=600)
- console = driver.get_console()
- if frappe.flags.tests_verbose:
- for line in console:
- print(line)
- print('-' * 40)
- time.sleep(1)
+ driver.print_console()
+ time.sleep(3)
frappe.db.set_default('in_selenium', None)
frappe.db.set_value("Company", "For Testing", "write_off_account", "Write Off - FT")
diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py
index 49c439ba5ca..003a57c852b 100644
--- a/erpnext/setup/utils.py
+++ b/erpnext/setup/utils.py
@@ -111,27 +111,12 @@ def get_exchange_rate(from_currency, to_currency, transaction_date=None):
def enable_all_roles_and_domains():
""" enable all roles and domain for testing """
- roles = frappe.get_list("Role", filters={"disabled": 1})
- for role in roles:
- _role = frappe.get_doc("Role", role.get("name"))
- _role.disabled = 0
- _role.flags.ignore_mandatory = True
- _role.flags.ignore_permissions = True
- _role.save()
-
# add all roles to users
- if roles:
- user = frappe.get_doc("User", "Administrator")
- user.add_roles(*[role.get("name") for role in roles])
-
- domains = frappe.get_list("Domain")
+ domains = frappe.get_all("Domain")
if not domains:
return
- domain_settings = frappe.get_doc("Domain Settings", "Domain Settings")
- domain_settings.set("active_domains", [])
- for domain in domains:
- row = domain_settings.append("active_domains", {})
- row.domain=domain.get("name")
-
- domain_settings.save()
+ from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
+ frappe.get_single('Domain Settings').set_active_domains(\
+ [d.name for d in domains])
+ add_all_roles_to('Administrator')
diff --git a/erpnext/tests/ui/make_fixtures.js b/erpnext/tests/ui/make_fixtures.js
index 0bd74915c29..949e92b1ca4 100644
--- a/erpnext/tests/ui/make_fixtures.js
+++ b/erpnext/tests/ui/make_fixtures.js
@@ -231,7 +231,9 @@ QUnit.test('Make fixtures', assert => {
let done = assert.async();
let tasks = [];
Object.keys(frappe.test_data).forEach(function(doctype) {
- tasks.push(function() { return frappe.tests.setup_doctype(doctype); });
+ tasks.push(function() {
+ return frappe.tests.setup_doctype(doctype, frappe.test_data[doctype]);
+ });
});
frappe.run_serially(tasks).then(() => done());
});
diff --git a/erpnext/tests/ui/tests.txt b/erpnext/tests/ui/tests.txt
index f35f6d7bc1b..4b3c2c503bb 100644
--- a/erpnext/tests/ui/tests.txt
+++ b/erpnext/tests/ui/tests.txt
@@ -129,4 +129,8 @@ erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_issue_with
erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_repack.js
erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_serialize_item.js
erpnext/accounts/doctype/payment_entry/tests/test_payment_against_invoice.js
-erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_last_purchase_rate.js
\ No newline at end of file
+erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_last_purchase_rate.js
+erpnext/restaurant/doctype/restaurant/test_restaurant.js
+erpnext/restaurant/doctype/test_restaurant_table/test_restaurant_table.js
+erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.js
+erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.js