[added] hospitality domain (#11020)

* [added] hospitality domain

* [tests] wip

* [tests] for restaurant

* [fix] tests for new naming

* [docs] added restaurant docs

* [docs] added restaurant docs
This commit is contained in:
Rushabh Mehta
2017-10-17 12:30:34 +05:30
committed by GitHub
parent bfb108d722
commit bc4e2cd9c1
87 changed files with 2851 additions and 362 deletions

View File

View File

View File

@@ -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');
});
}
});

View File

@@ -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
}

View File

@@ -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

View File

@@ -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']
}
]
}

View File

@@ -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()
]);
});

View File

@@ -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

View File

@@ -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');
},
});

View File

@@ -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
}

View File

@@ -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

View File

@@ -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()
]);
});

View File

@@ -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()

View File

@@ -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
}

View File

@@ -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

View File

@@ -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();
}
});

View File

@@ -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
}

View File

@@ -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

View File

@@ -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()
]);
});

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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

View File

@@ -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) {
}
});

View File

@@ -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
}

View File

@@ -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

View File

@@ -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"
};

View File

@@ -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()
]);
});

View File

@@ -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

View File

@@ -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) {
}
});

View File

@@ -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
}

View File

@@ -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 + '-.##')

View File

@@ -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()
]);
});

View File

@@ -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