Skip to content

Commit 9696a23

Browse files
committed
[ADD] hotel: implementation of the hotel industry
task-3765249
1 parent 9375af5 commit 9696a23

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+2747
-0
lines changed

.tx/config

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,15 @@ resource_name = headhunter
388388
replace_edited_strings = false
389389
keep_translations = false
390390

391+
[o:odoo:p:odoo-s18-4:r:hotel]
392+
file_filter = hotel/i18n/<lang>.po
393+
source_file = hotel/i18n/hotel.pot
394+
type = PO
395+
minimum_perc = 0
396+
resource_name = hotel
397+
replace_edited_strings = false
398+
keep_translations = false
399+
391400
[o:odoo:p:odoo-s18-4:r:hvac_services]
392401
file_filter = hvac_services/i18n/<lang>.po
393402
source_file = hvac_services/i18n/hvac_services.pot

hotel/__manifest__.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
'name': 'Hotel',
3+
'version': '1.0',
4+
'category': 'Services',
5+
'author': 'Odoo S.A.',
6+
'depends': [
7+
'account_tax_python',
8+
'appointment_account_payment',
9+
'base_automation',
10+
'base_industry_data',
11+
'contacts',
12+
'knowledge',
13+
'pos_sale',
14+
'sale_project',
15+
'sale_renting_planning',
16+
'web_studio',
17+
'website_appointment',
18+
'website_sale_stock',
19+
'website_sale_stock_renting',
20+
],
21+
'data': [
22+
'data/res_config_settings.xml',
23+
'data/ir_model_fields.xml',
24+
'data/planning_role.xml',
25+
'data/resource_calendar_data.xml',
26+
'data/resource_resource.xml',
27+
'data/uom_uom.xml',
28+
'data/account_tax.xml',
29+
'data/product_category.xml',
30+
'data/product_template.xml',
31+
'data/product_attribute.xml',
32+
'data/product_attribute_value.xml',
33+
'data/product_image.xml',
34+
'data/product_product.xml',
35+
'data/product_template_attribute_line.xml',
36+
'data/product_template_attribute_value.xml',
37+
'data/knowledge_tour.xml',
38+
'data/knowledge_article.xml',
39+
'data/knowledge_article_favorite.xml',
40+
'data/mail_message.xml',
41+
'data/ir_actions_server.xml',
42+
'data/base_automation.xml',
43+
'data/ir_ui_view.xml',
44+
'data/ir_actions_act_window.xml',
45+
'data/ir_filters.xml',
46+
'data/ir_ui_menu.xml',
47+
'data/sale_temporal_recurrence.xml',
48+
'data/product_pricing.xml',
49+
],
50+
'demo': [
51+
'demo/hr_employee.xml',
52+
'demo/payment_provider_demo.xml',
53+
'demo/ir_attachment_post.xml',
54+
'demo/website_view.xml',
55+
'demo/website_page.xml',
56+
'demo/website_menu.xml',
57+
'demo/website_theme_apply.xml',
58+
'demo/website.xml',
59+
'demo/product_template.xml',
60+
],
61+
'license': 'OPL-1',
62+
'cloc_exclude': [
63+
'data/knowledge_article.xml',
64+
'demo/website_view.xml',
65+
],
66+
'images': [
67+
'images/main.png',
68+
],
69+
}

hotel/data/account_tax.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo noupdate="1">
3+
<record id='city_tax_group' model='account.tax.group'>
4+
<field name="name">City Taxes</field>
5+
</record>
6+
<record id="account_tax_1" model="account.tax">
7+
<field name="amount">2.1</field>
8+
<field name="amount_type">fixed</field>
9+
<field name="name">City Tax</field>
10+
<field name="type_tax_use">sale</field>
11+
<field name="tax_group_id" ref="city_tax_group"/>
12+
<field name="price_include_override">tax_excluded</field>
13+
</record>
14+
</odoo>

hotel/data/base_automation.xml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo>
3+
<record id="industry_on_so_line" model="base.automation">
4+
<field name="model_id" ref="sale.model_sale_order"/>
5+
<field name="action_server_ids" eval="[(6, 0, [ref('industry_add_update')])]"/>
6+
<field name="trigger">on_create_or_write</field>
7+
<field name="name">On SO line edit</field>
8+
<field name="trigger_field_ids" eval="[(6, 0, [ref('sale_model_sale_order_x_picked_up')])]"/>
9+
<field name="filter_pre_domain">[('x_picked_up', '=', False)]</field>
10+
<field name="filter_domain">[('x_picked_up', '=', True)]</field>
11+
</record>
12+
<record id="industry_on_slot_fix_times" model="base.automation">
13+
<field name="model_id" ref="planning.model_planning_slot"/>
14+
<field name="action_server_ids" eval="[(6, 0, [ref('industry_fix_slot_times'), ref('industry_trigger_so_update_from_slot')])]"/>
15+
<field name="trigger">on_create_or_write</field>
16+
<field name="name">Fix Slot Times</field>
17+
<field name="trigger_field_ids" eval="[(6, 0, [ref('planning.field_planning_slot__end_datetime'), ref('planning.field_planning_slot__start_datetime'), ref('sale_planning.field_planning_slot__sale_line_id')])]"/>
18+
</record>
19+
</odoo>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo>
3+
<record id="hotel_rooms_schedule_action" model="ir.actions.act_window">
4+
<field name="domain">[("role_id", "ilike", ""), ("role_id.x_is_a_room_offer", "=", True)]</field>
5+
<field name="context">{'search_default_group_by_employee': 1, 'planning_expand_employee': 1, 'planning_expand_role': 1, 'planning_expand_sale_line_id': 1, 'planning_expand_resource': 1}</field>
6+
<field name="name">Schedule</field>
7+
<field name="res_model">planning.slot</field>
8+
<field name="view_mode">gantt,calendar,list,kanban,form</field>
9+
<field name="view_ids" eval="[
10+
(5, 0, 0),
11+
(0, 0, {'view_mode': 'gantt', 'view_id': ref('planning_gantt_view')}),
12+
(0, 0, {'view_mode': 'form', 'view_id': ref('hotel_schedule_form')}),
13+
]"/>
14+
</record>
15+
<record id="hotel_rooms_order_action" model="ir.actions.act_window">
16+
<field name="domain">[("x_order_involves_room", "=", True)]</field>
17+
<field name="context">{'in_rental_app': 1, 'search_default_from_rental': 1}</field>
18+
<field name="name">Orders</field>
19+
<field name="res_model">sale.order</field>
20+
<field name="view_mode">kanban,list,form</field>
21+
<field name="search_view_id" ref="hotel_order_search"/>
22+
<field name="view_ids" eval="[
23+
(5, 0, 0),
24+
(0, 0, {'view_mode': 'kanban', 'view_id': ref('hotel_orders_kanban')}),
25+
(0, 0, {'view_mode': 'list', 'view_id': ref('sale_renting.rental_order_view_tree')}),
26+
(0, 0, {'view_mode': 'form', 'view_id': ref('sale_renting.rental_order_primary_form_view')}),
27+
]"/>
28+
</record>
29+
<record id="hotel_rooms_offers_action" model="ir.actions.act_window">
30+
<field name="name">Room Offers</field>
31+
<field name="res_model">product.template</field>
32+
<field name="domain">[("x_is_a_room_offer", "=", True)]</field>
33+
<field name="context">{'default_x_is_a_room_offer': True, 'default_purchase_ok': False, 'default_sale_ok': True, 'default_rent_ok': True, 'default_type': 'service', 'default_planning_enabled': True}</field>
34+
<field name="view_mode">kanban,list,form</field>
35+
<field name="search_view_id" ref="hotel_offers_search"/>
36+
<field name="view_ids" eval="[
37+
(5, 0, 0),
38+
(0, 0, {'view_mode': 'kanban', 'view_id': ref('hotel_offers_kanban')}),
39+
(0, 0, {'view_mode': 'list', 'view_id': ref('hotel_offers_list')}),
40+
]"/>
41+
</record>
42+
<record id="hotel_rooms_roles_action" model="ir.actions.act_window">
43+
<field name="name">Room Roles</field>
44+
<field name="res_model">planning.role</field>
45+
<field name="domain">[("x_is_a_room_offer", "=", True)]</field>
46+
<field name="context">{'default_x_is_a_room_offer': True}</field>
47+
<field name="view_mode">list,form</field>
48+
<field name="search_view_id" ref="hotel_planning_role_view_search"/>
49+
<field name="view_ids" eval="[
50+
(5, 0, 0),
51+
(0, 0, {'view_mode': 'list', 'view_id': ref('planning.planning_role_view_tree')}),
52+
]"/>
53+
</record>
54+
<record id="hotel_rooms_resources_action" model="ir.actions.act_window">
55+
<field name="name">Room Resources</field>
56+
<field name="res_model">resource.resource</field>
57+
<field name="context">{'default_resource_type': 'material'}</field>
58+
<field name="domain">[("resource_type", "=", "material"), ("role_ids.x_is_a_room_offer", "=", True)]</field>
59+
<field name="view_mode">list,kanban,form</field>
60+
<field name="search_view_id" ref="hotel_planning_resource_view_search"/>
61+
<field name="view_ids" eval="[
62+
(5, 0, 0),
63+
(0, 0, {'view_mode': 'list', 'view_id': ref('planning.resource_resource_tree_view_inherit')}),
64+
(0, 0, {'view_mode': 'form', 'view_id': ref('planning.resource_resource_form_view_inherit')}),
65+
]"/>
66+
</record>
67+
</odoo>

hotel/data/ir_actions_server.xml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo>
3+
<record id="industry_add_update" model="ir.actions.server">
4+
<field name="name">Add/Update City Tax</field>
5+
<field name="model_id" ref="sale.model_sale_order"/>
6+
<field name="usage">base_automation</field>
7+
<field name="state">code</field>
8+
<field name="code"><![CDATA[
9+
stay_taxes = 0
10+
stay_tax_line = False
11+
for so_line in record.order_line:
12+
if so_line.product_id.x_is_a_room_offer:
13+
if so_line.x_nights > 0: stay_taxes += so_line.x_nights
14+
if so_line.product_id.x_is_stay_tax: stay_tax_line = so_line
15+
if stay_taxes > 0:
16+
if stay_tax_line: stay_tax_line['product_uom_qty'] = stay_taxes
17+
else: # Add stay tax product
18+
product = env['product.product'].search([('x_is_stay_tax', '=', True)], limit=1)
19+
order_line_vals = {'order_id': record.id,'product_id': product.id,'product_uom_qty': stay_taxes,'product_uom_id': product.uom_id.id,'name': product.name,'tax_ids': product.taxes_id}
20+
env['sale.order.line'].create(order_line_vals)]]></field>
21+
</record>
22+
<record id="industry_trigger_so_update_from_slot" model="ir.actions.server">
23+
<field name="name">Trigger SO Update from Slot</field>
24+
<field name="model_id" ref="planning.model_planning_slot"/>
25+
<field name="usage">base_automation</field>
26+
<field name="state">code</field>
27+
<field name="code"><![CDATA[
28+
sale_order = record.sale_order_id
29+
if sale_order:
30+
stay_taxes = 0
31+
stay_tax_line = False
32+
for so_line in sale_order.order_line:
33+
if so_line.product_id.x_is_a_room_offer:
34+
if so_line.x_nights > 0:
35+
stay_taxes += so_line.x_nights
36+
if so_line.product_id.x_is_stay_tax:
37+
stay_tax_line = so_line
38+
if stay_taxes > 0:
39+
if stay_tax_line:
40+
stay_tax_line['product_uom_qty'] = stay_taxes
41+
]]></field>
42+
</record>
43+
<record id="industry_fix_slot_times" model="ir.actions.server">
44+
<field name="binding_model_id" ref="planning.model_planning_slot"/>
45+
<field name="model_id" ref="planning.model_planning_slot"/>
46+
<field name="usage">base_automation</field>
47+
<field name="state">code</field>
48+
<field name="name">Fix Slot Times</field>
49+
<field name="code"><![CDATA[def ceil(x):
50+
return int(x) if x == int(x) else int(x) + 1
51+
start_datetime = record.start_datetime
52+
end_datetime = record.end_datetime
53+
if record.role_id and record.role_id.x_is_a_room_offer:
54+
if record.start_datetime and str(record.start_datetime.time()) != "18:00:00":
55+
start_datetime = datetime.datetime.combine(record.start_datetime.date(), datetime.time(16,0,0))
56+
if start_datetime >= end_datetime:
57+
start_datetime = start_datetime - datetime.timedelta(days=1)
58+
if record.end_datetime and str(record.end_datetime.time()) != "09:00:00":
59+
end_datetime = datetime.datetime.combine(record.end_datetime.date(), datetime.time(7,0,0))
60+
if start_datetime >= end_datetime:
61+
end_datetime = end_datetime + datetime.timedelta(days=1)
62+
record['start_datetime'] = start_datetime
63+
record['end_datetime'] = end_datetime
64+
if record.sale_line_id:
65+
nights = 0
66+
if record.sale_line_id.planning_slot_ids:
67+
for slot in record.sale_line_id.planning_slot_ids:
68+
nights += ceil( (slot.end_datetime - slot.start_datetime).total_seconds() / (24*3600) )
69+
record['sale_line_id']['x_nights'] = nights
70+
]]></field>
71+
</record>
72+
</odoo>

hotel/data/ir_filters.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo noupdate="1">
3+
<record id="filter_orders_today" model="ir.filters">
4+
<field name="name">Today</field>
5+
<field name="model_id">sale.order</field>
6+
<field name="action_id" ref="hotel_rooms_order_action"/>
7+
<field name="domain">["|", "&amp;", "&amp;", "&amp;", ("rental_status", "=", "return"), ("rental_return_date", "&gt;=", datetime.datetime.combine(context_today(), datetime.time(0, 0, 0)).to_utc().strftime("%Y-%m-%d %H:%M:%S")), ("rental_return_date", "&lt;", datetime.datetime.combine(context_today() + relativedelta(days = 1), datetime.time(0, 0, 0)).to_utc().strftime("%Y-%m-%d %H:%M:%S")), ("state", "=", "sale"), "&amp;", "&amp;", "&amp;", ("rental_status", "=", "pickup"), ("rental_start_date", "&gt;=", datetime.datetime.combine(context_today(), datetime.time(0, 0, 0)).to_utc().strftime("%Y-%m-%d %H:%M:%S")), ("rental_start_date", "&lt;", datetime.datetime.combine(context_today() + relativedelta(days = 1), datetime.time(0, 0, 0)).to_utc().strftime("%Y-%m-%d %H:%M:%S")), ("state", "=", "sale")]</field>
8+
</record>
9+
</odoo>

hotel/data/ir_model_fields.xml

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo>
3+
<record id="planning_model_planning_role_x_is_a_room_offer_field" model="ir.model.fields">
4+
<field name="ttype">boolean</field>
5+
<field name="copied" eval="True"/>
6+
<field name="field_description">Is a room offer</field>
7+
<field name="model_id" ref="planning.model_planning_role"/>
8+
<field name="name">x_is_a_room_offer</field>
9+
</record>
10+
<record id="base_model_res_partner_x_nationality_field" model="ir.model.fields">
11+
<field name="ttype">many2one</field>
12+
<field name="copied" eval="True"/>
13+
<field name="field_description">Nationality</field>
14+
<field name="model_id" ref="base.model_res_partner"/>
15+
<field name="name">x_nationality</field>
16+
<field name="relation">res.country</field>
17+
</record>
18+
<record id="base_model_res_partner_x_document_type_field" model="ir.model.fields">
19+
<field name="ttype">selection</field>
20+
<field name="copied" eval="True"/>
21+
<field name="field_description">Document Type</field>
22+
<field name="model_id" ref="base.model_res_partner"/>
23+
<field name="name">x_document_type</field>
24+
<field name="selection">[('Passport', 'Passport'), ('ID card', 'ID card'), ('Driving license', 'Driving license')]</field>
25+
</record>
26+
<record id="base_model_res_partner_x_document_number_field" model="ir.model.fields">
27+
<field name="ttype">char</field>
28+
<field name="copied" eval="True"/>
29+
<field name="field_description">Document Number</field>
30+
<field name="model_id" ref="base.model_res_partner"/>
31+
<field name="name">x_document_number</field>
32+
</record>
33+
<record id="sale_model_sale_order_x_guests_field" model="ir.model.fields">
34+
<field name="ttype">many2many</field>
35+
<field name="copied" eval="True"/>
36+
<field name="field_description">New Many2Many</field>
37+
<field name="model_id" ref="sale.model_sale_order"/>
38+
<field name="name">x_guests</field>
39+
<field name="relation">res.partner</field>
40+
<field name="relation_table">x_res_partner_sale_order_rel</field>
41+
</record>
42+
<record id="base_model_res_partner_x_char_field_4ho_1ivl4p6r4_field" model="ir.model.fields">
43+
<field name="ttype">char</field>
44+
<field name="copied" eval="True"/>
45+
<field name="field_description">New Text</field>
46+
<field name="model_id" ref="base.model_res_partner"/>
47+
<field name="name">x_char_field_4ho_1ivl4p6r4</field>
48+
</record>
49+
<record id="base_model_res_partner_x_identity_check_field" model="ir.model.fields">
50+
<field name="compute"><![CDATA[for record in self:
51+
if not record.x_nationality and not record.x_document_type and not record.x_document_number: record['x_identity_check'] = "NA"
52+
else:
53+
if record.x_nationality and record.x_document_type and record.x_document_number: record['x_identity_check'] = "OK"
54+
else: record['x_identity_check'] = "Invalid"]]></field>
55+
<field name="ttype">char</field>
56+
<field name="depends">x_nationality, x_document_type, x_document_number</field>
57+
<field name="field_description">Identity Check</field>
58+
<field name="model_id" ref="base.model_res_partner"/>
59+
<field name="name">x_identity_check</field>
60+
<field name="readonly" eval="True"/>
61+
<field name="selectable" eval="False"/>
62+
<field name="store" eval="False"/>
63+
</record>
64+
<record id="product_model_product_template_x_is_a_room_offer_field" model="ir.model.fields">
65+
<field name="ttype">boolean</field>
66+
<field name="copied" eval="True"/>
67+
<field name="field_description">Is Room Offer</field>
68+
<field name="model_id" ref="product.model_product_template"/>
69+
<field name="name">x_is_a_room_offer</field>
70+
</record>
71+
<record id="product_model_product_template_x_is_stay_tax_field" model="ir.model.fields">
72+
<field name="ttype">boolean</field>
73+
<field name="copied" eval="True"/>
74+
<field name="field_description">Is City Tax</field>
75+
<field name="model_id" ref="product.model_product_template"/>
76+
<field name="name">x_is_stay_tax</field>
77+
</record>
78+
<record id="sale_model_sale_order_x_nights_field" model="ir.model.fields">
79+
<field name="ttype">integer</field>
80+
<field name="field_description">Nights</field>
81+
<field name="readonly" eval="True"/>
82+
<field name="model_id" ref="sale.model_sale_order_line"/>
83+
<field name="copied" eval="False"/>
84+
<field name="name">x_nights</field>
85+
</record>
86+
<record id="sale_order_x_order_involves_room" model="ir.model.fields">
87+
<field name="ttype">boolean</field>
88+
<field name="field_description">Order Involves Room</field>
89+
<field name="model_id" ref="sale.model_sale_order"/>
90+
<field name="name">x_order_involves_room</field>
91+
<field name="compute"><![CDATA[for record in self:
92+
record['x_order_involves_room'] = any(line.product_id.x_is_a_room_offer for line in record.order_line)
93+
]]></field>
94+
<field name="depends">order_line</field>
95+
</record>
96+
<record id="sale_model_sale_order_x_picked_up" model="ir.model.fields">
97+
<field name="ttype">boolean</field>
98+
<field name="field_description">Picked up</field>
99+
<field name="readonly" eval="True"/>
100+
<field name="model_id" ref="sale.model_sale_order"/>
101+
<field name="name">x_picked_up</field>
102+
<field name="compute"><![CDATA[for record in self:
103+
record['x_picked_up'] = False
104+
if record.state == 'sale' and record.is_rental_order:
105+
rental_order_lines = record.order_line.filtered(lambda line: line.is_rental and line.product_type != 'combo')
106+
record['x_picked_up'] = not any(sol.qty_delivered < sol.product_uom_qty for sol in rental_order_lines)
107+
]]></field>
108+
<field name="depends">order_line.qty_delivered</field>
109+
</record>
110+
</odoo>

hotel/data/ir_ui_menu.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<odoo auto_sequence="1">
3+
<menuitem id="hotel_menu_root" name="Hotel" sequence="2">
4+
<menuitem id="hotel_schedule_menu" name="Schedule" action="hotel_rooms_schedule_action" sequence="1"/>
5+
<menuitem id="hotel_orders_menu" name="Orders" action="hotel_rooms_order_action" sequence="2"/>
6+
<menuitem id="hotel_rooms_menu" name="Rooms" sequence="3">
7+
<menuitem id="hotel_rooms_offers_menu" name="Offers" action="hotel_rooms_offers_action" sequence="1"/>
8+
<menuitem id="hotel_rooms_roles_menu" name="Roles" action="hotel_rooms_roles_action" sequence="2"/>
9+
<menuitem id="hotel_rooms_resources_menu" name="Resources" action="hotel_rooms_resources_action" sequence="3"/>
10+
</menuitem>
11+
</menuitem>
12+
<record id="hotel_menu_root" model="ir.ui.menu">
13+
<field name="web_icon_data" type="base64" file="hotel/static/description/icon_no_border.png"/>
14+
</record>
15+
</odoo>

0 commit comments

Comments
 (0)