From 2dee8fc2551725c155d74fdbf85e221adeccb12d Mon Sep 17 00:00:00 2001 From: Revant Nandgaonkar Date: Mon, 12 Feb 2018 11:57:12 +0530 Subject: [PATCH] Hotels (#11907) * [new-module] hotels, start * Multiple Changes Hotel Settings Added Make invoice on Hotel Reservation * Hotel Room validation for overbooking * Added test fixtures and test for Hotels * Added Tests for Hotels Overbooking Pricing not set * [WIP] Documentation Hotel Room and Screenshot * Added Calendar view for Hotel Room Reservation * Added Report - Hotel Room Occupancy * Added Hotel Reservation User in Hospitality domain --- erpnext/config/desktop.py | 8 + erpnext/docs/assets/img/hotels/hotel-room.png | Bin 0 -> 54510 bytes .../user/manual/en/hospitality/hotel-room.md | 5 + .../docs/user/manual/en/hospitality/index.md | 4 + .../docs/user/manual/en/hospitality/index.txt | 3 +- erpnext/domains/hospitality.py | 5 +- erpnext/hotels/__init__.py | 0 erpnext/hotels/doctype/__init__.py | 0 erpnext/hotels/doctype/hotel_room/__init__.py | 0 .../hotels/doctype/hotel_room/hotel_room.js | 8 + .../hotels/doctype/hotel_room/hotel_room.json | 175 ++++++++ .../hotels/doctype/hotel_room/hotel_room.py | 13 + .../doctype/hotel_room/test_hotel_room.js | 23 + .../doctype/hotel_room/test_hotel_room.py | 25 ++ .../doctype/hotel_room_amenity/__init__.py | 0 .../hotel_room_amenity.json | 103 +++++ .../hotel_room_amenity/hotel_room_amenity.py | 10 + .../doctype/hotel_room_package/__init__.py | 0 .../hotel_room_package/hotel_room_package.js | 23 + .../hotel_room_package.json | 215 +++++++++ .../hotel_room_package/hotel_room_package.py | 20 + .../test_hotel_room_package.js | 23 + .../test_hotel_room_package.py | 49 +++ .../doctype/hotel_room_pricing/__init__.py | 0 .../hotel_room_pricing/hotel_room_pricing.js | 8 + .../hotel_room_pricing.json | 266 +++++++++++ .../hotel_room_pricing/hotel_room_pricing.py | 10 + .../test_hotel_room_pricing.js | 23 + .../test_hotel_room_pricing.py | 21 + .../hotel_room_pricing_item/__init__.py | 0 .../hotel_room_pricing_item.json | 103 +++++ .../hotel_room_pricing_item.py | 10 + .../hotel_room_pricing_package/__init__.py | 0 .../hotel_room_pricing_package.js | 8 + .../hotel_room_pricing_package.json | 162 +++++++ .../hotel_room_pricing_package.py | 10 + .../test_hotel_room_pricing_package.js | 23 + .../test_hotel_room_pricing_package.py | 10 + .../hotel_room_reservation/__init__.py | 0 .../hotel_room_reservation.js | 68 +++ .../hotel_room_reservation.json | 415 ++++++++++++++++++ .../hotel_room_reservation.py | 109 +++++ .../hotel_room_reservation_calendar.js | 9 + .../test_hotel_room_reservation.js | 23 + .../test_hotel_room_reservation.py | 61 +++ .../hotel_room_reservation_item/__init__.py | 0 .../hotel_room_reservation_item.json | 195 ++++++++ .../hotel_room_reservation_item.py | 10 + .../doctype/hotel_room_type/__init__.py | 0 .../hotel_room_type/hotel_room_type.js | 8 + .../hotel_room_type/hotel_room_type.json | 204 +++++++++ .../hotel_room_type/hotel_room_type.py | 10 + .../hotel_room_type/test_hotel_room_type.js | 23 + .../hotel_room_type/test_hotel_room_type.py | 10 + .../hotels/doctype/hotel_settings/__init__.py | 0 .../doctype/hotel_settings/hotel_settings.js | 8 + .../hotel_settings/hotel_settings.json | 175 ++++++++ .../doctype/hotel_settings/hotel_settings.py | 10 + .../hotel_settings/test_hotel_settings.js | 23 + .../hotel_settings/test_hotel_settings.py | 10 + erpnext/hotels/report/__init__.py | 0 .../report/hotel_room_occupancy/__init__.py | 0 .../hotel_room_occupancy.js | 22 + .../hotel_room_occupancy.json | 26 ++ .../hotel_room_occupancy.py | 33 ++ erpnext/modules.txt | 3 +- .../doctype/restaurant/restaurant.json | 4 +- .../restaurant_menu/restaurant_menu.json | 4 +- .../restaurant_reservation.json | 4 +- .../restaurant_table/restaurant_table.json | 4 +- 70 files changed, 2826 insertions(+), 11 deletions(-) create mode 100644 erpnext/docs/assets/img/hotels/hotel-room.png create mode 100644 erpnext/docs/user/manual/en/hospitality/hotel-room.md create mode 100644 erpnext/hotels/__init__.py create mode 100644 erpnext/hotels/doctype/__init__.py create mode 100644 erpnext/hotels/doctype/hotel_room/__init__.py create mode 100644 erpnext/hotels/doctype/hotel_room/hotel_room.js create mode 100644 erpnext/hotels/doctype/hotel_room/hotel_room.json create mode 100644 erpnext/hotels/doctype/hotel_room/hotel_room.py create mode 100644 erpnext/hotels/doctype/hotel_room/test_hotel_room.js create mode 100644 erpnext/hotels/doctype/hotel_room/test_hotel_room.py create mode 100644 erpnext/hotels/doctype/hotel_room_amenity/__init__.py create mode 100644 erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.json create mode 100644 erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py create mode 100644 erpnext/hotels/doctype/hotel_room_package/__init__.py create mode 100644 erpnext/hotels/doctype/hotel_room_package/hotel_room_package.js create mode 100644 erpnext/hotels/doctype/hotel_room_package/hotel_room_package.json create mode 100644 erpnext/hotels/doctype/hotel_room_package/hotel_room_package.py create mode 100644 erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.js create mode 100644 erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py create mode 100644 erpnext/hotels/doctype/hotel_room_pricing/__init__.py create mode 100644 erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.js create mode 100644 erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.json create mode 100644 erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py create mode 100644 erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.js create mode 100644 erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py create mode 100644 erpnext/hotels/doctype/hotel_room_pricing_item/__init__.py create mode 100644 erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.json create mode 100644 erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py create mode 100644 erpnext/hotels/doctype/hotel_room_pricing_package/__init__.py create mode 100644 erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.js create mode 100644 erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.json create mode 100644 erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py create mode 100644 erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.js create mode 100644 erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py create mode 100644 erpnext/hotels/doctype/hotel_room_reservation/__init__.py create mode 100644 erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.js create mode 100644 erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.json create mode 100644 erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py create mode 100644 erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation_calendar.js create mode 100644 erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.js create mode 100644 erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py create mode 100644 erpnext/hotels/doctype/hotel_room_reservation_item/__init__.py create mode 100644 erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.json create mode 100644 erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py create mode 100644 erpnext/hotels/doctype/hotel_room_type/__init__.py create mode 100644 erpnext/hotels/doctype/hotel_room_type/hotel_room_type.js create mode 100644 erpnext/hotels/doctype/hotel_room_type/hotel_room_type.json create mode 100644 erpnext/hotels/doctype/hotel_room_type/hotel_room_type.py create mode 100644 erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.js create mode 100644 erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py create mode 100644 erpnext/hotels/doctype/hotel_settings/__init__.py create mode 100644 erpnext/hotels/doctype/hotel_settings/hotel_settings.js create mode 100644 erpnext/hotels/doctype/hotel_settings/hotel_settings.json create mode 100644 erpnext/hotels/doctype/hotel_settings/hotel_settings.py create mode 100644 erpnext/hotels/doctype/hotel_settings/test_hotel_settings.js create mode 100644 erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py create mode 100644 erpnext/hotels/report/__init__.py create mode 100644 erpnext/hotels/report/hotel_room_occupancy/__init__.py create mode 100644 erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.js create mode 100644 erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.json create mode 100644 erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py diff --git a/erpnext/config/desktop.py b/erpnext/config/desktop.py index 75560837ae0..3c1884494a6 100644 --- a/erpnext/config/desktop.py +++ b/erpnext/config/desktop.py @@ -359,6 +359,14 @@ def get_data(): "label": _("Restaurant"), "hidden": 1 }, + { + "module_name": "Hotels", + "color": "#EA81E8", + "icon": "fa fa-bed", + "type": "module", + "label": _("Hotels"), + "hidden": 1 + }, { "module_name": "Agriculture", "color": "#8BC34A", diff --git a/erpnext/docs/assets/img/hotels/hotel-room.png b/erpnext/docs/assets/img/hotels/hotel-room.png new file mode 100644 index 0000000000000000000000000000000000000000..7aad2273dd2cc694ad9e40eb14ef5fa6aca7104a GIT binary patch literal 54510 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 literal 0 HcmV?d00001 diff --git a/erpnext/docs/user/manual/en/hospitality/hotel-room.md b/erpnext/docs/user/manual/en/hospitality/hotel-room.md new file mode 100644 index 00000000000..b788d1b4155 --- /dev/null +++ b/erpnext/docs/user/manual/en/hospitality/hotel-room.md @@ -0,0 +1,5 @@ +# Hotel Room + +Hotel Room is a master to create hotel rooms for reservation + +Hotel Room diff --git a/erpnext/docs/user/manual/en/hospitality/index.md b/erpnext/docs/user/manual/en/hospitality/index.md index efd7377fc41..dc6c743c8ca 100644 --- a/erpnext/docs/user/manual/en/hospitality/index.md +++ b/erpnext/docs/user/manual/en/hospitality/index.md @@ -6,4 +6,8 @@ ERPNext Hospitality module is designed to handle workflows for Hotels and Restau The Restaurant module in ERPNext will help you manage a chain of restaurants. You can create Restaurants, Menus, Tables, Reservations and a manage Order Entry and Billing. +### Manage Hotels + +The Hotels module in ERPNext will help you manage creating Hotel Rooms, create Hotel Room Reservation. It will also help in creating Invoice from hotel room reservation + {index} \ No newline at end of file diff --git a/erpnext/docs/user/manual/en/hospitality/index.txt b/erpnext/docs/user/manual/en/hospitality/index.txt index cbe6da00773..0c909d846f2 100644 --- a/erpnext/docs/user/manual/en/hospitality/index.txt +++ b/erpnext/docs/user/manual/en/hospitality/index.txt @@ -1,4 +1,5 @@ restaurant restaurant-menu reservations -order-entry \ No newline at end of file +order-entry +hotel-room diff --git a/erpnext/domains/hospitality.py b/erpnext/domains/hospitality.py index bc55d9c47a6..09b98c288bf 100644 --- a/erpnext/domains/hospitality.py +++ b/erpnext/domains/hospitality.py @@ -1,6 +1,7 @@ data = { 'desktop_icons': [ 'Restaurant', + 'Hotels', 'Accounts', 'Buying', 'Stock', @@ -9,7 +10,9 @@ data = { 'ToDo' ], 'restricted_roles': [ - 'Restaurant Manager' + 'Restaurant Manager', + 'Hotel Manager', + 'Hotel Reservation User' ], 'custom_fields': { 'Sales Invoice': [ diff --git a/erpnext/hotels/__init__.py b/erpnext/hotels/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hotels/doctype/__init__.py b/erpnext/hotels/doctype/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hotels/doctype/hotel_room/__init__.py b/erpnext/hotels/doctype/hotel_room/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hotels/doctype/hotel_room/hotel_room.js b/erpnext/hotels/doctype/hotel_room/hotel_room.js new file mode 100644 index 00000000000..76f22d5d4ee --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room/hotel_room.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('Hotel Room', { + refresh: function(frm) { + + } +}); diff --git a/erpnext/hotels/doctype/hotel_room/hotel_room.json b/erpnext/hotels/doctype/hotel_room/hotel_room.json new file mode 100644 index 00000000000..2567c077b63 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room/hotel_room.json @@ -0,0 +1,175 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 1, + "allow_rename": 1, + "autoname": "prompt", + "beta": 1, + "creation": "2017-12-08 12:33:56.320420", + "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": "hotel_room_type", + "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": "Hotel Room Type", + "length": 0, + "no_copy": 0, + "options": "Hotel Room Type", + "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": "capacity", + "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": "Capacity", + "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": "extra_bed_capacity", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Extra Bed Capacity", + "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-12-09 12:10:50.670113", + "modified_by": "Administrator", + "module": "Hotels", + "name": "Hotel Room", + "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 + }, + { + "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": "Hotel 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/hotels/doctype/hotel_room/hotel_room.py b/erpnext/hotels/doctype/hotel_room/hotel_room.py new file mode 100644 index 00000000000..8471aee4a03 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room/hotel_room.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 +from frappe.model.document import Document + +class HotelRoom(Document): + def validate(self): + if not self.capacity: + self.capacity, self.extra_bed_capacity = frappe.db.get_value('Hotel Room Type', + self.hotel_room_type, ['capacity', 'extra_bed_capacity']) \ No newline at end of file diff --git a/erpnext/hotels/doctype/hotel_room/test_hotel_room.js b/erpnext/hotels/doctype/hotel_room/test_hotel_room.js new file mode 100644 index 00000000000..8b2b83330f3 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room/test_hotel_room.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Hotel Room", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Hotel Room + () => frappe.tests.make('Hotel Room', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/hotels/doctype/hotel_room/test_hotel_room.py b/erpnext/hotels/doctype/hotel_room/test_hotel_room.py new file mode 100644 index 00000000000..00d3aea394c --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room/test_hotel_room.py @@ -0,0 +1,25 @@ +# -*- 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="Hotel Room", name="1001", + hotel_room_type="Basic Room"), + dict(doctype="Hotel Room", name="1002", + hotel_room_type="Basic Room"), + dict(doctype="Hotel Room", name="1003", + hotel_room_type="Basic Room"), + dict(doctype="Hotel Room", name="1004", + hotel_room_type="Basic Room"), + dict(doctype="Hotel Room", name="1005", + hotel_room_type="Basic Room"), + dict(doctype="Hotel Room", name="1006", + hotel_room_type="Basic Room") +] + +class TestHotelRoom(unittest.TestCase): + pass diff --git a/erpnext/hotels/doctype/hotel_room_amenity/__init__.py b/erpnext/hotels/doctype/hotel_room_amenity/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.json b/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.json new file mode 100644 index 00000000000..29a0407a8a8 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.json @@ -0,0 +1,103 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2017-12-08 12:35:36.572185", + "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": "billable", + "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": "Billable", + "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-12-09 12:05:07.125687", + "modified_by": "Administrator", + "module": "Hotels", + "name": "Hotel Room Amenity", + "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/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py b/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py new file mode 100644 index 00000000000..69da007fc6b --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.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 HotelRoomAmenity(Document): + pass diff --git a/erpnext/hotels/doctype/hotel_room_package/__init__.py b/erpnext/hotels/doctype/hotel_room_package/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.js b/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.js new file mode 100644 index 00000000000..5b09ae568ef --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.js @@ -0,0 +1,23 @@ +// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Hotel Room Package', { + hotel_room_type: function(frm) { + if (frm.doc.hotel_room_type) { + frappe.model.with_doc('Hotel Room Type', frm.doc.hotel_room_type, () => { + let hotel_room_type = frappe.get_doc('Hotel Room Type', frm.doc.hotel_room_type); + + // reset the amenities + frm.doc.amenities = []; + + for (let amenity of hotel_room_type.amenities) { + let d = frm.add_child('amenities'); + d.item = amenity.item; + d.billable = amenity.billable; + } + + frm.refresh(); + }); + } + } +}); diff --git a/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.json b/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.json new file mode 100644 index 00000000000..57dad44b7d7 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.json @@ -0,0 +1,215 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "prompt", + "beta": 1, + "creation": "2017-12-08 12:43:17.211064", + "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": "hotel_room_type", + "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": "Hotel Room Type", + "length": 0, + "no_copy": 0, + "options": "Hotel Room Type", + "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_2", + "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": "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": "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": "section_break_4", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "amenities", + "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": "Amenities", + "length": 0, + "no_copy": 0, + "options": "Hotel Room Amenity", + "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-12-09 12:10:31.111952", + "modified_by": "Administrator", + "module": "Hotels", + "name": "Hotel Room Package", + "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/hotels/doctype/hotel_room_package/hotel_room_package.py b/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.py new file mode 100644 index 00000000000..8a62eea8fa1 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.py @@ -0,0 +1,20 @@ +# -*- 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 HotelRoomPackage(Document): + def validate(self): + if not self.item: + item = frappe.get_doc(dict( + doctype = 'Item', + item_code = self.name, + item_group = 'Products', + is_stock_item = 0, + stock_uom = 'Unit' + )) + item.insert() + self.item = item.name diff --git a/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.js b/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.js new file mode 100644 index 00000000000..f1ebad41d41 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Hotel Room Package", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Hotel Room Package + () => frappe.tests.make('Hotel Room Package', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py b/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py new file mode 100644 index 00000000000..ebf7f2b7e9f --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py @@ -0,0 +1,49 @@ +# -*- 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='Breakfast', + item_group='Products', is_stock_item=0), + dict(doctype='Item', item_code='Lunch', + item_group='Products', is_stock_item=0), + dict(doctype='Item', item_code='Dinner', + item_group='Products', is_stock_item=0), + dict(doctype='Item', item_code='WiFi', + item_group='Products', is_stock_item=0), + dict(doctype='Hotel Room Type', name="Delux Room", + capacity=4, + extra_bed_capacity=2, + amenities = [ + dict(item='WiFi', billable=0) + ]), + dict(doctype='Hotel Room Type', name="Basic Room", + capacity=4, + extra_bed_capacity=2, + amenities = [ + dict(item='Breakfast', billable=0) + ]), + dict(doctype="Hotel Room Package", name="Basic Room with Breakfast", + hotel_room_type="Basic Room", + amenities = [ + dict(item="Breakfast", billable=0) + ]), + dict(doctype="Hotel Room Package", name="Basic Room with Lunch", + hotel_room_type="Basic Room", + amenities = [ + dict(item="Breakfast", billable=0), + dict(item="Lunch", billable=0) + ]), + dict(doctype="Hotel Room Package", name="Basic Room with Dinner", + hotel_room_type="Basic Room", + amenities = [ + dict(item="Breakfast", billable=0), + dict(item="Dinner", billable=0) + ]) +] + +class TestHotelRoomPackage(unittest.TestCase): + pass diff --git a/erpnext/hotels/doctype/hotel_room_pricing/__init__.py b/erpnext/hotels/doctype/hotel_room_pricing/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.js b/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.js new file mode 100644 index 00000000000..87bb1925707 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.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('Hotel Room Pricing', { + refresh: function(frm) { + + } +}); diff --git a/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.json b/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.json new file mode 100644 index 00000000000..0f5a776211a --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.json @@ -0,0 +1,266 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 1, + "allow_rename": 0, + "autoname": "prompt", + "beta": 1, + "creation": "2017-12-08 12:51:47.088174", + "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, + "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": 0, + "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": "currency", + "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": "Currency", + "length": 0, + "no_copy": 0, + "options": "Currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 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": "from_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "From Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "to_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "To Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_5", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "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": "Hotel Room Pricing 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-12-09 12:10:41.559559", + "modified_by": "Administrator", + "module": "Hotels", + "name": "Hotel Room Pricing", + "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 + }, + { + "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": "Hotel 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/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py b/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py new file mode 100644 index 00000000000..8eee0f24c5c --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.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 HotelRoomPricing(Document): + pass diff --git a/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.js b/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.js new file mode 100644 index 00000000000..ba0d1fd3e96 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Hotel Room Pricing", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Hotel Room Pricing + () => frappe.tests.make('Hotel Room Pricing', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py b/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py new file mode 100644 index 00000000000..2b7848bb452 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py @@ -0,0 +1,21 @@ +# -*- 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="Hotel Room Pricing", enabled=1, + name="Winter 2017", + from_date="2017-01-01", to_date="2017-01-10", + items = [ + dict(item="Basic Room with Breakfast", rate=10000), + dict(item="Basic Room with Lunch", rate=11000), + dict(item="Basic Room with Dinner", rate=12000) + ]) +] + +class TestHotelRoomPricing(unittest.TestCase): + pass diff --git a/erpnext/hotels/doctype/hotel_room_pricing_item/__init__.py b/erpnext/hotels/doctype/hotel_room_pricing_item/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.json b/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.json new file mode 100644 index 00000000000..d6cd826bcc8 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.json @@ -0,0 +1,103 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2017-12-08 12:50:13.486090", + "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": "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": 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": 1, + "max_attachments": 0, + "modified": "2017-12-09 12:04:58.641703", + "modified_by": "Administrator", + "module": "Hotels", + "name": "Hotel Room Pricing 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/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py b/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py new file mode 100644 index 00000000000..6bf01bf941b --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_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 HotelRoomPricingItem(Document): + pass diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/__init__.py b/erpnext/hotels/doctype/hotel_room_pricing_package/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.js b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.js new file mode 100644 index 00000000000..f6decd9e95a --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.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('Hotel Room Pricing Package', { + refresh: function(frm) { + + } +}); diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.json b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.json new file mode 100644 index 00000000000..92bd98050dd --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.json @@ -0,0 +1,162 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2017-12-08 12:50:13.486090", + "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": "from_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "From Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "to_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "To Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "hotel_room_package", + "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": "Hotel Room Package", + "length": 0, + "no_copy": 0, + "options": "Hotel Room Package", + "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, + "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": 1, + "max_attachments": 0, + "modified": "2017-12-08 12:52:01.743866", + "modified_by": "Administrator", + "module": "Hotels", + "name": "Hotel Room Pricing Package", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py new file mode 100644 index 00000000000..9ae9fcfaf83 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.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 HotelRoomPricingPackage(Document): + pass diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.js b/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.js new file mode 100644 index 00000000000..73a561c408c --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Hotel Room Pricing Package", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Hotel Room Pricing Package + () => frappe.tests.make('Hotel Room Pricing Package', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py b/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py new file mode 100644 index 00000000000..fec1c86ad02 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.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 TestHotelRoomPricingPackage(unittest.TestCase): + pass diff --git a/erpnext/hotels/doctype/hotel_room_reservation/__init__.py b/erpnext/hotels/doctype/hotel_room_reservation/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.js b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.js new file mode 100644 index 00000000000..2c9fd7b73b0 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.js @@ -0,0 +1,68 @@ +// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Hotel Room Reservation', { + refresh: function(frm) { + if(frm.doc.docstatus == 1){ + frm.add_custom_button(__("Make Invoice"), ()=> { + frm.trigger("make_invoice"); + }); + } + }, + from_date: function(frm) { + frm.trigger("recalculate_rates"); + }, + to_date: function(frm) { + frm.trigger("recalculate_rates"); + }, + recalculate_rates: function(frm) { + if (!frm.doc.from_date || !frm.doc.to_date + || !frm.doc.items.length){ + return; + } + frappe.call({ + "method": "erpnext.hotels.doctype.hotel_room_reservation.hotel_room_reservation.get_room_rate", + "args": {"hotel_room_reservation": frm.doc} + }).done((r)=> { + for (var i = 0; i < r.message.items.length; i++) { + frm.doc.items[i].rate = r.message.items[i].rate; + frm.doc.items[i].amount = r.message.items[i].amount; + } + frappe.run_serially([ + ()=> frm.set_value("net_total", r.message.net_total), + ()=> frm.refresh_field("items") + ]); + }); + }, + make_invoice: function(frm) { + frappe.model.with_doc("Hotel Settings", "Hotel Settings", ()=>{ + frappe.model.with_doctype("Sales Invoice", ()=>{ + let hotel_settings = frappe.get_doc("Hotel Settings", "Hotel Settings"); + let invoice = frappe.model.get_new_doc("Sales Invoice"); + invoice.customer = frm.doc.customer || hotel_settings.default_customer; + if (hotel_settings.default_invoice_naming_series){ + invoice.naming_series = hotel_settings.default_invoice_naming_series; + } + for (let d of frm.doc.items){ + let invoice_item = frappe.model.add_child(invoice, "items") + invoice_item.item_code = d.item; + invoice_item.qty = d.qty; + invoice_item.rate = d.rate; + } + if (hotel_settings.default_taxes_and_charges){ + invoice.taxes_and_charges = hotel_settings.default_taxes_and_charges; + } + frappe.set_route("Form", invoice.doctype, invoice.name); + }); + }); + } +}); + +frappe.ui.form.on('Hotel Room Reservation Item', { + item: function(frm, doctype, name) { + frm.trigger("recalculate_rates"); + }, + qty: function(frm) { + frm.trigger("recalculate_rates"); + } +}); diff --git a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.json b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.json new file mode 100644 index 00000000000..c65c4e1c544 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.json @@ -0,0 +1,415 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 1, + "allow_rename": 0, + "autoname": "HRES.#######", + "beta": 1, + "creation": "2017-12-08 13:01:34.829175", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Document", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "guest_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Guest 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": "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": "from_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "From Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "to_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "To Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "late_checkin", + "fieldtype": "Check", + "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": "Late Checkin", + "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_6", + "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": "status", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Status", + "length": 0, + "no_copy": 0, + "options": "Booked\nAdvance Paid\nInvoiced\nPaid\nCompleted\nCancelled", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 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": "section_break_8", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "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": "Hotel Room Reservation 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": "net_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": "Net Total", + "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": "amended_from", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Amended From", + "length": 0, + "no_copy": 1, + "options": "Hotel Room Reservation", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 1, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2017-12-09 12:11:26.395419", + "modified_by": "Administrator", + "module": "Hotels", + "name": "Hotel Room 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": "System Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + }, + { + "amend": 1, + "apply_user_permissions": 0, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Hotel Reservation User", + "set_user_permissions": 0, + "share": 1, + "submit": 1, + "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/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py new file mode 100644 index 00000000000..f3f76a92182 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py @@ -0,0 +1,109 @@ +# -*- 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 frappe.utils import date_diff, add_days, flt + +class HotelRoomUnavailableError(frappe.ValidationError): pass +class HotelRoomPricingNotSetError(frappe.ValidationError): pass + +class HotelRoomReservation(Document): + def validate(self): + self.total_rooms = {} + self.set_rates() + self.validate_availability() + + def validate_availability(self): + for i in xrange(date_diff(self.to_date, self.from_date)): + day = add_days(self.from_date, i) + self.rooms_booked = {} + + for d in self.items: + if not d.item in self.rooms_booked: + self.rooms_booked[d.item] = 0 + + room_type = frappe.db.get_value("Hotel Room Package", + d.item, 'hotel_room_type') + rooms_booked = get_rooms_booked(room_type, day, exclude_reservation=self.name) \ + + d.qty + self.rooms_booked.get(d.item) + total_rooms = self.get_total_rooms(d.item) + if total_rooms < rooms_booked: + frappe.throw(_("Hotel Rooms of type {0} are unavailable on {1}".format(d.item, + frappe.format(day, dict(fieldtype="Date")))), exc=HotelRoomUnavailableError) + + self.rooms_booked[d.item] += rooms_booked + + def get_total_rooms(self, item): + if not item in self.total_rooms: + self.total_rooms[item] = frappe.db.sql(""" + select count(*) + from + `tabHotel Room Package` package + inner join + `tabHotel Room` room on package.hotel_room_type = room.hotel_room_type + where + package.item = %s""", item)[0][0] or 0 + + return self.total_rooms[item] + + def set_rates(self): + self.net_total = 0 + for d in self.items: + net_rate = 0.0 + for i in xrange(date_diff(self.to_date, self.from_date)): + day = add_days(self.from_date, i) + if not d.item: + continue + day_rate = frappe.db.sql(""" + select + item.rate + from + `tabHotel Room Pricing Item` item, + `tabHotel Room Pricing` pricing + where + item.parent = pricing.name + and item.item = %s + and %s between pricing.from_date + and pricing.to_date""", (d.item, day)) + + if day_rate: + net_rate += day_rate[0][0] + else: + frappe.throw( + _("Please set Hotel Room Rate on {}".format( + frappe.format(day, dict(fieldtype="Date")))), exc=HotelRoomPricingNotSetError) + d.rate = net_rate + d.amount = net_rate * flt(d.qty) + self.net_total += d.amount + +@frappe.whitelist() +def get_room_rate(hotel_room_reservation): + """Calculate rate for each day as it may belong to different Hotel Room Pricing Item""" + doc = frappe.get_doc(json.loads(hotel_room_reservation)) + doc.set_rates() + return doc.as_dict() + +def get_rooms_booked(room_type, day, exclude_reservation=None): + exclude_condition = '' + if exclude_reservation: + exclude_condition = 'and reservation.name != "{0}"'.format(frappe.db.escape(exclude_reservation)) + + return frappe.db.sql(""" + select sum(item.qty) + from + `tabHotel Room Package` room_package, + `tabHotel Room Reservation Item` item, + `tabHotel Room Reservation` reservation + where + item.parent = reservation.name + and room_package.item = item.item + and room_package.hotel_room_type = %s + and reservation.docstatus = 1 + {exclude_condition} + and %s between reservation.from_date + and reservation.to_date""".format(exclude_condition=exclude_condition), + (room_type, day))[0][0] or 0 diff --git a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation_calendar.js b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation_calendar.js new file mode 100644 index 00000000000..7f7322cf4b6 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation_calendar.js @@ -0,0 +1,9 @@ +frappe.views.calendar["Hotel Room Reservation"] = { + field_map: { + "start": "from_date", + "end": "to_date", + "id": "name", + "title": "guest_name", + "status": "status" + } +} \ No newline at end of file diff --git a/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.js b/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.js new file mode 100644 index 00000000000..2897139359b --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Hotel Room Reservation", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Hotel Room Reservation + () => frappe.tests.make('Hotel Room Reservation', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py b/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py new file mode 100644 index 00000000000..55c63112cd8 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest +from erpnext.hotels.doctype.hotel_room_reservation.hotel_room_reservation import HotelRoomPricingNotSetError, HotelRoomUnavailableError +test_dependencies = ["Hotel Room Pricing", "Hotel Room"] + +class TestHotelRoomReservation(unittest.TestCase): + def setUp(self): + frappe.db.sql("delete from `tabHotel Room Reservation`") + frappe.db.sql("delete from `tabHotel Room Reservation Item`") + + def test_reservation(self): + reservation = make_reservation( + from_date="2017-01-01", + to_date="2017-01-03", + items=[ + dict(item="Basic Room with Dinner", qty=2) + ] + ) + reservation.insert() + self.assertEqual(reservation.net_total, 48000) + + def test_price_not_set(self): + reservation = make_reservation( + from_date="2016-01-01", + to_date="2016-01-03", + items=[ + dict(item="Basic Room with Dinner", qty=2) + ] + ) + self.assertRaises(HotelRoomPricingNotSetError, reservation.insert) + + def test_room_unavailable(self): + reservation = make_reservation( + from_date="2017-01-01", + to_date="2017-01-03", + items=[ + dict(item="Basic Room with Dinner", qty=2), + ] + ) + reservation.insert() + + reservation = make_reservation( + from_date="2017-01-01", + to_date="2017-01-03", + items=[ + dict(item="Basic Room with Dinner", qty=20), + ] + ) + self.assertRaises(HotelRoomUnavailableError, reservation.insert) + +def make_reservation(**kwargs): + kwargs["doctype"] = "Hotel Room Reservation" + if not "guest_name" in kwargs: + kwargs["guest_name"] = "Test Guest" + doc = frappe.get_doc(kwargs) + return doc diff --git a/erpnext/hotels/doctype/hotel_room_reservation_item/__init__.py b/erpnext/hotels/doctype/hotel_room_reservation_item/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.json b/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.json new file mode 100644 index 00000000000..2b7931ebc0f --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.json @@ -0,0 +1,195 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "", + "beta": 0, + "creation": "2017-12-08 12:58:21.733330", + "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": 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": "currency", + "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": "Currency", + "length": 0, + "no_copy": 0, + "options": "Currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "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 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Amount", + "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-12-09 12:04:34.562956", + "modified_by": "Administrator", + "module": "Hotels", + "name": "Hotel Room Reservation 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/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py b/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py new file mode 100644 index 00000000000..3406faea0e6 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_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 HotelRoomReservationItem(Document): + pass diff --git a/erpnext/hotels/doctype/hotel_room_type/__init__.py b/erpnext/hotels/doctype/hotel_room_type/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.js b/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.js new file mode 100644 index 00000000000..d73835db947 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.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('Hotel Room Type', { + refresh: function(frm) { + + } +}); diff --git a/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.json b/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.json new file mode 100644 index 00000000000..3d26413cf8e --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.json @@ -0,0 +1,204 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 1, + "allow_rename": 1, + "autoname": "prompt", + "beta": 1, + "creation": "2017-12-08 12:38:29.485175", + "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": "capacity", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Capacity", + "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": "extra_bed_capacity", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Extra Bed Capacity", + "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": "section_break_3", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "amenities", + "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": "Amenities", + "length": 0, + "no_copy": 0, + "options": "Hotel Room Amenity", + "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-12-09 12:10:23.355486", + "modified_by": "Administrator", + "module": "Hotels", + "name": "Hotel Room Type", + "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 + }, + { + "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": "Hotel 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/hotels/doctype/hotel_room_type/hotel_room_type.py b/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.py new file mode 100644 index 00000000000..1fc1303f393 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.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 HotelRoomType(Document): + pass diff --git a/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.js b/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.js new file mode 100644 index 00000000000..e2dd5780e3c --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Hotel Room Type", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Hotel Room Type + () => frappe.tests.make('Hotel Room Type', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py b/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py new file mode 100644 index 00000000000..3b243e95669 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.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 TestHotelRoomType(unittest.TestCase): + pass diff --git a/erpnext/hotels/doctype/hotel_settings/__init__.py b/erpnext/hotels/doctype/hotel_settings/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hotels/doctype/hotel_settings/hotel_settings.js b/erpnext/hotels/doctype/hotel_settings/hotel_settings.js new file mode 100644 index 00000000000..0b4a2c36ca2 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_settings/hotel_settings.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('Hotel Settings', { + refresh: function(frm) { + + } +}); diff --git a/erpnext/hotels/doctype/hotel_settings/hotel_settings.json b/erpnext/hotels/doctype/hotel_settings/hotel_settings.json new file mode 100644 index 00000000000..d9f5572549e --- /dev/null +++ b/erpnext/hotels/doctype/hotel_settings/hotel_settings.json @@ -0,0 +1,175 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 1, + "creation": "2017-12-08 17:50:24.523107", + "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": "default_customer", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "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": "default_taxes_and_charges", + "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 Taxes and Charges", + "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": "default_invoice_naming_series", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Invoice Naming Series", + "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": 1, + "istable": 0, + "max_attachments": 0, + "modified": "2017-12-09 12:11:12.857308", + "modified_by": "Administrator", + "module": "Hotels", + "name": "Hotel Settings", + "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": "System Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + }, + { + "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": "Hotel 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/hotels/doctype/hotel_settings/hotel_settings.py b/erpnext/hotels/doctype/hotel_settings/hotel_settings.py new file mode 100644 index 00000000000..d78bca149df --- /dev/null +++ b/erpnext/hotels/doctype/hotel_settings/hotel_settings.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 HotelSettings(Document): + pass diff --git a/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.js b/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.js new file mode 100644 index 00000000000..bc0b7f8341d --- /dev/null +++ b/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Hotel Settings", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Hotel Settings + () => frappe.tests.make('Hotel Settings', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py b/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py new file mode 100644 index 00000000000..a081acc0e08 --- /dev/null +++ b/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.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 TestHotelSettings(unittest.TestCase): + pass diff --git a/erpnext/hotels/report/__init__.py b/erpnext/hotels/report/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hotels/report/hotel_room_occupancy/__init__.py b/erpnext/hotels/report/hotel_room_occupancy/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.js b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.js new file mode 100644 index 00000000000..81efb2dd120 --- /dev/null +++ b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.js @@ -0,0 +1,22 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Hotel Room Occupancy"] = { + "filters": [ + { + "fieldname":"from_date", + "label": __("From Date"), + "fieldtype": "Date", + "default": frappe.datetime.now_date(), + "reqd":1 + }, + { + "fieldname":"to_date", + "label": __("To Date"), + "fieldtype": "Date", + "default": frappe.datetime.now_date(), + "reqd":1 + } + ] +} diff --git a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.json b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.json new file mode 100644 index 00000000000..782a48bbb9d --- /dev/null +++ b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.json @@ -0,0 +1,26 @@ +{ + "add_total_row": 1, + "apply_user_permissions": 1, + "creation": "2017-12-09 14:31:26.306705", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "idx": 0, + "is_standard": "Yes", + "modified": "2017-12-09 14:31:26.306705", + "modified_by": "Administrator", + "module": "Hotels", + "name": "Hotel Room Occupancy", + "owner": "Administrator", + "ref_doctype": "Hotel Room Reservation", + "report_name": "Hotel Room Occupancy", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "Hotel Reservation User" + } + ] +} \ No newline at end of file diff --git a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py new file mode 100644 index 00000000000..aebeb4578f8 --- /dev/null +++ b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py @@ -0,0 +1,33 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _ +from frappe.utils import add_days, date_diff + +from erpnext.hotels.doctype.hotel_room_reservation.hotel_room_reservation import get_rooms_booked + +def execute(filters=None): + columns = get_columns(filters) + data = get_data(filters) + return columns, data + +def get_columns(filters): + columns = [ + dict(label=_("Room Type"), fieldname="room_type"), + dict(label=_("Rooms Booked"), fieldtype="Int") + ] + return columns + +def get_data(filters): + out = [] + for room_type in frappe.get_all('Hotel Room Type'): + total_booked = 0 + for i in xrange(date_diff(filters.to_date, filters.from_date)): + day = add_days(filters.from_date, i) + total_booked += get_rooms_booked(room_type.name, day) + + out.append([room_type.name, total_booked]) + + return out \ No newline at end of file diff --git a/erpnext/modules.txt b/erpnext/modules.txt index 42f0f0beaad..d469145304d 100644 --- a/erpnext/modules.txt +++ b/erpnext/modules.txt @@ -20,4 +20,5 @@ Healthcare Restaurant Agriculture ERPNext Integrations -Non Profit \ No newline at end of file +Non Profit +Hotels \ No newline at end of file diff --git a/erpnext/restaurant/doctype/restaurant/restaurant.json b/erpnext/restaurant/doctype/restaurant/restaurant.json index f4ecba79452..85726874119 100644 --- a/erpnext/restaurant/doctype/restaurant/restaurant.json +++ b/erpnext/restaurant/doctype/restaurant/restaurant.json @@ -4,7 +4,7 @@ "allow_import": 0, "allow_rename": 0, "autoname": "prompt", - "beta": 0, + "beta": 1, "creation": "2017-09-15 12:40:41.546933", "custom": 0, "docstatus": 0, @@ -269,7 +269,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-10-05 17:41:14.422242", + "modified": "2017-12-09 12:13:10.185496", "modified_by": "Administrator", "module": "Restaurant", "name": "Restaurant", diff --git a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.json b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.json index 264634b0f6f..1b1610dbacf 100644 --- a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.json +++ b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.json @@ -4,7 +4,7 @@ "allow_import": 0, "allow_rename": 0, "autoname": "prompt", - "beta": 0, + "beta": 1, "creation": "2017-09-15 12:48:29.818715", "custom": 0, "docstatus": 0, @@ -207,7 +207,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-09-21 11:04:20.671542", + "modified": "2017-12-09 12:13:13.684500", "modified_by": "Administrator", "module": "Restaurant", "name": "Restaurant Menu", diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.json b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.json index 6a2ffa13277..06987582975 100644 --- a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.json +++ b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.json @@ -4,7 +4,7 @@ "allow_import": 0, "allow_rename": 0, "autoname": "REST.######", - "beta": 0, + "beta": 1, "creation": "2017-09-15 13:05:51.063661", "custom": 0, "docstatus": 0, @@ -297,7 +297,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-09-15 14:40:56.759315", + "modified": "2017-12-09 12:13:20.027942", "modified_by": "Administrator", "module": "Restaurant", "name": "Restaurant Reservation", diff --git a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.json b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.json index da1bcde4046..5fc6e62ecb9 100644 --- a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.json +++ b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.json @@ -4,7 +4,7 @@ "allow_import": 0, "allow_rename": 0, "autoname": "", - "beta": 0, + "beta": 1, "creation": "2017-09-15 12:45:24.717355", "custom": 0, "docstatus": 0, @@ -116,7 +116,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-09-15 13:18:05.254106", + "modified": "2017-12-09 12:13:24.382345", "modified_by": "Administrator", "module": "Restaurant", "name": "Restaurant Table",