diff --git a/__init__.py b/__init__.py
index 6c6ca22..383fb5c 100644
--- a/__init__.py
+++ b/__init__.py
@@ -6,7 +6,6 @@ from . import configuration
from . import room
from . import booking
from . import folio
-from . import housekeeping
from . import company
from . import city
from . import party
@@ -44,8 +43,8 @@ def register():
booking.BookingStatementLine,
booking.StatementPaymentForm,
statement.StatementLine,
- housekeeping.Housekeeping,
- housekeeping.HousekeepingCleaningType,
+ # housekeeping.Housekeeping,
+ # housekeeping.HousekeepingCleaningType,
party.Party,
channel.SaleChannel,
channel.ChannelTax,
@@ -69,14 +68,14 @@ def register():
service.ServiceLine,
service.ServiceKind,
service.CreateDailyServicesStart,
- housekeeping.HotelHousekeepingTask,
- housekeeping.HotelTask,
- housekeeping.HousekeepingServiceStart,
room.CleanningDays,
+ room.CleaningType,
dash.DashApp,
dash.AppHotelPlanner,
invoice.InvoiceLine,
invoice.Invoice,
+ room.HotelTask,
+ room.HousekeepingStart,
# folio.TransferfolioStart,
# folio.TransferChargeStart,
# folio.CheckOutfolioFailed,
@@ -96,7 +95,7 @@ def register():
sale.InvoiceIncomeDailyReport,
sale.InvoiceSimplifiedReport,
service.ServiceReport,
- housekeeping.HousekeepingServiceReport,
+ room.HousekeepingReport,
module='hotel', type_='report')
Pool.register(
booking.SelectRooms,
@@ -111,7 +110,7 @@ def register():
folio.StatisticsByMonth,
folio.ReverseCheckout,
service.CreateDailyServices,
- housekeeping.HousekeepingService,
+ room.Housekeeping,
sale.InvoiceIncomeDaily,
party.CreateGuest,
# folio.ChangeRoom,
diff --git a/booking.fodt b/booking.fodt
index e99b5ec..2dd61b3 100644
Binary files a/booking.fodt and b/booking.fodt differ
diff --git a/booking.py b/booking.py
index cd6008e..5436da6 100644
--- a/booking.py
+++ b/booking.py
@@ -49,7 +49,7 @@ class Booking(Workflow, ModelSQL, ModelView):
party = fields.Many2One('party.party', 'Customer', required=False,
select=True, help="Person or company owner of the booking.",
states={
- 'required': Eval('state') == 'check_in',
+ # 'required': Eval('state') == 'check_in',
'readonly': Not(In(Eval('state'), ['offer', 'confirmed'])),
})
contact = fields.Char('Contact', states=STATES_CHECKIN,
@@ -420,6 +420,9 @@ class Booking(Workflow, ModelSQL, ModelView):
return
payment_mode = bk.channel.payment_mode
+ if not payment_mode:
+ raise UserError(gettext('hotel.msg_missing_payment_mode'))
+
party = bk.channel.agent.party
account_id = Voucher.get_account('receipt', payment_mode)
diff --git a/configuration.py b/configuration.py
index c6dc541..d9e1dad 100644
--- a/configuration.py
+++ b/configuration.py
@@ -38,8 +38,6 @@ class Configuration(ModelSQL, ModelView):
'configuration', 'product', 'Default Charges')
check_in_time = fields.Time('Check In Time', required=True)
check_out_time = fields.Time('Check Out Time', required=True)
- default_accommodation = fields.Many2One('product.product',
- 'Default Accommodation')
taxes_exception_rule = fields.Many2One('account.tax.rule', 'Taxes Exception Rule')
default_channel_seller = fields.Many2One('hotel.channel', 'Default Channel')
company = fields.Many2One('company.company', 'Company', required=True,
@@ -54,11 +52,11 @@ class Configuration(ModelSQL, ModelView):
], 'Full Clean Time')
full_clean_lapse = fields.Integer('Full Clean Lapse', help='In Days')
age_children_policy = fields.Integer('Age Children Policy', help='In Days')
- cleaning_check_out = fields.Many2One('hotel.housekeeping.cleaning_type',
+ cleaning_check_out = fields.Many2One('hotel.room.cleaning_type',
'Cleaning Check Out')
- cleaning_check_in = fields.Many2One('hotel.housekeeping.cleaning_type',
+ cleaning_check_in = fields.Many2One('hotel.room.cleaning_type',
'Cleaning Check In')
- cleaning_occupied = fields.Many2One('hotel.housekeeping.cleaning_type',
+ cleaning_occupied = fields.Many2One('hotel.room.cleaning_type',
'Cleaning Occupied')
quarantine_rooms = fields.Numeric('Quarantine Rooms', digits=(2, 0), help='In days')
booking_email_template = fields.Many2One('email.template',
diff --git a/folio.py b/folio.py
index 9ff53dd..2a2c5cb 100644
--- a/folio.py
+++ b/folio.py
@@ -219,23 +219,21 @@ class Folio(ModelSQL, ModelView):
raise UserError(gettext('hotel.msg_missing_select_room'))
rec.set_registration_number()
rec.check_room()
- cls.update_room(rec.room, 'dirty')
+ cls.update_room(rec, 'check_in')
cls.write(records, {'registration_state': 'check_in'})
def check_room(self):
- Housekeeping = Pool().get('hotel.housekeeping')
- rooms = Housekeeping.search([
- ('room', '=', self.room.id)
- ])
- if not rooms or rooms[0].state != 'clean':
- raise UserError(gettext('hotel.msg_room_no_clean', s=self.room.name))
+ if self.room.state != 'clean':
+ raise UserError(
+ gettext('hotel.msg_room_no_clean', s=self.room.name)
+ )
@classmethod
@ModelView.button
def check_out(cls, records):
for record in records:
cls.write([record], {'registration_state': 'check_out'})
- cls.update_room(record.room, 'dirty')
+ cls.update_room(record, 'check_out')
@classmethod
@ModelView.button
@@ -257,14 +255,21 @@ class Folio(ModelSQL, ModelView):
return 'pending'
@classmethod
- def update_room(cls, room, state):
- Housekeeping = Pool().get('hotel.housekeeping')
- hk_rooms = Housekeeping.search([
- ('room', '=', room.id),
- ])
- for hk_room in hk_rooms:
- hk_room.state = state
- hk_room.save()
+ def update_room(cls, folio, status):
+ pool = Pool()
+ Configuration = pool.get('hotel.configuration')
+ config = Configuration.get_configuration()
+ cleaning_type_id = None
+ if status in 'check_in' and config.cleaning_occupied:
+ cleaning_type_id = config.cleaning_occupied.id
+ elif status in 'check_out' and config.cleaning_check_out:
+ cleaning_type_id = config.cleaning_check_out.id
+
+ room = folio.room
+ room.state = 'dirty'
+ if cleaning_type_id:
+ room.cleaning_type = cleaning_type_id
+ room.save()
def get_invoice_state(self, name=None):
if self.invoice_line:
diff --git a/housekeeping.fods b/housekeeping.fods
index 686dfb8..c9ea765 100644
Binary files a/housekeeping.fods and b/housekeeping.fods differ
diff --git a/housekeeping.py b/housekeeping.py
index 6f71fca..7890637 100644
--- a/housekeeping.py
+++ b/housekeeping.py
@@ -11,11 +11,16 @@ from trytond.pool import Pool
STATES = {'invisible': (Eval('type') != 'service')}
-class HousekeepingCleaningType(ModelSQL, ModelView):
- "Housekeeping Cleaning Type"
+class RoomCleaningType(ModelSQL, ModelView):
+ "Room Cleaning Type"
__name__ = "hotel.housekeeping.cleaning_type"
name = fields.Char('Name', required=True, select=True)
description = fields.Text('Description')
+ kind = fields.Selection([
+ ('tweak', 'Tweak'),
+ ('deep', 'Deep'),
+ ('standard', 'Standard'),
+ ], 'Kind', required=True)
class Housekeeping(Workflow, ModelSQL, ModelView):
@@ -24,17 +29,17 @@ class Housekeeping(Workflow, ModelSQL, ModelView):
employee = fields.Many2One('company.employee', 'Employee')
room = fields.Many2One('hotel.room', 'Room', required=True)
state = fields.Selection([
- ('inspected', 'Inspected'),
- ('dirty', 'Dirty'),
- ('clean', 'Clean'),
- ('maintenance', 'Maintenance'),
- ], 'Status', required=True, readonly=True)
+ ('inspected', 'Inspected'),
+ ('dirty', 'Dirty'),
+ ('clean', 'Clean'),
+ ('maintenance', 'Maintenance'),
+ ], 'Status', required=True, readonly=True)
state_string = state.translated('state')
availability = fields.Selection([
- ('blocked', 'Blocked'),
- ('available', 'Available'),
- ('occupied', 'Occupied'),
- ], 'Availability', required=True)
+ ('blocked', 'Blocked'),
+ ('available', 'Available'),
+ ('occupied', 'Occupied'),
+ ], 'Availability', required=True)
cleaning_type = fields.Many2One('hotel.housekeeping.cleaning_type',
'Cleaning Type', required=False)
availability_string = state.translated('availability')
@@ -44,8 +49,10 @@ class Housekeeping(Workflow, ModelSQL, ModelView):
start_date_assigned = fields.Date('Start Date Assigned')
end_date_assigned = fields.Date('End Date Assigned')
notes = fields.Text('Notes')
- check_in_time = fields.Function(fields.Time('Check In Time'), 'get_check_in_time')
- check_out_time = fields.Function(fields.Time('Check In Time'), 'get_check_out_time')
+ check_in_time = fields.Function(fields.Time('Check In Time'),
+ 'get_check_in_time')
+ check_out_time = fields.Function(fields.Time('Check In Time'),
+ 'get_check_out_time')
amenities = fields.Function(fields.Many2Many('hotel.room-hotel.amenities',
'room', 'amenities', 'Amenities'), 'get_amenities')
@@ -165,87 +172,3 @@ class Housekeeping(Workflow, ModelSQL, ModelView):
# for line in lines:
# occupancies.add(line.id)
# return list(occupancies)
-
-
-class HotelTask(ModelSQL, ModelView):
- "Hotel Task"
- __name__ = "hotel.task"
- name = fields.Char('Name Task', required=True, select=True)
- frecuency = fields.Integer('Frecuency', select=True, help='In days')
- quantity = fields.Integer('Quantity', select=True)
-
-
-class HotelHousekeepingTask(ModelView, ModelSQL):
- 'Hotel Housekeeping Task'
- __name__ = 'hotel.housekeeping.task'
- housekeeping = fields.Many2One('hotel.housekeeping', 'Hotel Housekeeping',
- ondelete='CASCADE', select=True, required=True)
- task = fields.Many2One('hotel.task', 'Task', select=True, required=True)
- frecuency = fields.Integer('Frecuency', select=True, help='In days')
- quantity = fields.Integer('Quantity', select=True)
-
- @fields.depends('task', 'frecuency')
- def on_change_task(self, name=None):
- if self.task:
- self.frecuency = self.task.frecuency
-
-
-class HousekeepingServiceStart(ModelView):
- 'Print Housekeeping Service Start'
- __name__ = 'hotel.print_housekeeping_service.start'
- date = fields.Date('Date', required=True)
- employee = fields.Many2One('company.employee', 'Employee')
- company = fields.Many2One('company.company', 'Company', required=True)
-
- @staticmethod
- def default_date():
- Date_ = Pool().get('ir.date')
- return Date_.today()
-
- @staticmethod
- def default_company():
- return Transaction().context.get('company')
-
-
-class HousekeepingService(Wizard):
- 'Housekeeping Service'
- __name__ = 'hotel.print_housekeeping_service'
- start = StateView('hotel.print_housekeeping_service.start',
- 'hotel.print_housekeeping_service_start_view_form', [
- Button('Cancel', 'end', 'tryton-cancel'),
- Button('Open', 'print_', 'tryton-print', default=True),
- ])
- print_ = StateReport('hotel.print_housekeeping_service.report')
-
- def do_print_(self, action):
- company = self.start.company
- data = {
- 'date': self.start.date,
- 'employee': self.start.employee.id if self.start.employee else None,
- 'company': company.id,
- }
- return action, data
-
- def transition_print_(self):
- return 'end'
-
-
-class HousekeepingServiceReport(Report):
- __name__ = 'hotel.print_housekeeping_service.report'
-
- @classmethod
- def get_context(cls, records, header, data):
- report_context = super().get_context(records, header, data)
- pool = Pool()
- Company = pool.get('company.company')
- Housekeeping = pool.get('hotel.housekeeping')
-
- dom = []
- if data['employee']:
- dom.append(('employee.id', '=', data['employee']))
-
- housekeepings = Housekeeping.search(dom)
- report_context['records'] = housekeepings
- report_context['company'] = Company(data['company']).party.name
- report_context['date'] = datetime.now()
- return report_context
diff --git a/message.xml b/message.xml
index ac92270..36d5cd6 100644
--- a/message.xml
+++ b/message.xml
@@ -81,5 +81,8 @@ this repository contains the full copyright notices and license terms. -->
Missing party or customer to pay!
+
+ Missing payment mode in channel!
+
diff --git a/room.py b/room.py
index 604d03f..7cf8061 100644
--- a/room.py
+++ b/room.py
@@ -1,13 +1,27 @@
#This file is part of Presik. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
-from trytond.model import ModelView, ModelSQL, fields
+from trytond.model import ModelView, ModelSQL, Workflow, fields
from trytond.pyson import Eval
+from trytond.wizard import (
+ Wizard, StateView, Button, StateTransition, StateReport
+)
+from trytond.pool import Pool
+from trytond.report import Report
-STATES = {'readonly': (Eval('state') != 'draft')}
+class CleaningType(ModelSQL, ModelView):
+ "Room Cleaning Type"
+ __name__ = "hotel.room.cleaning_type"
+ name = fields.Char('Name', required=True, select=True)
+ description = fields.Text('Description')
+ kind = fields.Selection([
+ ('tweak', 'Tweak'),
+ ('deep', 'Deep'),
+ ('standard', 'Standard'),
+ ], 'Kind', required=True)
-class Room(ModelSQL, ModelView):
+class Room(Workflow, ModelSQL, ModelView):
'Room'
__name__ = 'hotel.room'
name = fields.Char('Name', required=True)
@@ -33,19 +47,87 @@ class Room(ModelSQL, ModelView):
# TODO: Maybe add require a Current State field
min_unit_price = fields.Numeric('Min. Unit Price', digits=(16, 4))
max_unit_price = fields.Numeric('Max. Unit Price', digits=(16, 4))
+ state = fields.Selection([
+ ('inspected', 'Inspected'),
+ ('dirty', 'Dirty'),
+ ('clean', 'Clean'),
+ ('maintenance', 'Maintenance'),
+ ], 'Status', required=True, readonly=True)
+ state_string = state.translated('state')
+ cleaning_type = fields.Many2One('hotel.room.cleaning_type',
+ 'Cleaning Type', required=False)
+ last_check_in = fields.DateTime('Last Check In')
+ last_check_out = fields.DateTime('Last Check Out')
+ housekeeping = fields.Many2One('company.employee', 'Employee')
+ notes = fields.Text('Notes')
@classmethod
def __setup__(cls):
super(Room, cls).__setup__()
+ cls._transitions |= set((
+ ('clean', 'dirty'),
+ ('clean', 'inspected'),
+ ('clean', 'maintenance'),
+ ('dirty', 'clean'),
+ ('dirty', 'maintenance'),
+ ('dirty', 'inspected'),
+ ('maintenance', 'inspected'),
+ ('maintenance', 'dirty'),
+ ('inspected', 'dirty'),
+ ('inspected', 'maintenance'),
+ ('inspected', 'clean'),
+ ))
+ cls._buttons.update({
+ 'clean': {
+ 'invisible': Eval('state').in_(['maintenance', 'clean']),
+ },
+ 'dirty': {
+ 'invisible': Eval('state').in_(['dirty']),
+ },
+ 'inspected': {
+ 'invisible': Eval('state').in_(['inspected']),
+ },
+ 'maintenance': {
+ 'invisible': Eval('state').in_(['maintenance']),
+ },
+ })
@staticmethod
def default_active():
return True
- @fields.depends('start_mnt', 'end_mnt')
- def on_change_start_mnt(self):
- if not self.start_mnt:
- self.end_mnt = None
+ @staticmethod
+ def default_state():
+ return 'dirty'
+
+ @classmethod
+ @ModelView.button
+ @Workflow.transition('clean')
+ def clean(cls, records):
+ for rec in records:
+ rec.cleaning_type = None
+ rec.save()
+
+ @classmethod
+ @ModelView.button
+ @Workflow.transition('dirty')
+ def dirty(cls, records):
+ Config = Pool().get('hotel.configuration')
+ config = Config.get_configuration()
+ for rec in records:
+ rec.cleaning_type = config.cleaning_occupied.id
+
+ @classmethod
+ @ModelView.button
+ @Workflow.transition('maintenance')
+ def maintenance(cls, records):
+ pass
+
+ @classmethod
+ @ModelView.button
+ @Workflow.transition('inspected')
+ def inspected(cls, records):
+ pass
class RoomAmenities(ModelSQL):
@@ -74,10 +156,6 @@ class Amenities(ModelSQL, ModelView):
'invisible': Eval('type') != 'lingerie',
}, depends=['type'])
- @classmethod
- def __setup__(cls):
- super(Amenities, cls).__setup__()
-
class RoomClassification(ModelSQL, ModelView):
'Room Classification'
@@ -109,3 +187,87 @@ class RoomTemplate(ModelSQL):
ondelete='CASCADE')
template = fields.Many2One('product.template', 'Product Template',
required=True, ondelete='CASCADE')
+
+
+class HousekeepingStart(ModelView):
+ 'Print Housekeeping Service Start'
+ __name__ = 'hotel.print_housekeeping.start'
+ date = fields.Date('Date', required=True)
+ employee = fields.Many2One('company.employee', 'Employee')
+ company = fields.Many2One('company.company', 'Company', required=True)
+
+ @staticmethod
+ def default_date():
+ Date_ = Pool().get('ir.date')
+ return Date_.today()
+
+ @staticmethod
+ def default_company():
+ return Transaction().context.get('company')
+
+
+class Housekeeping(Wizard):
+ 'Housekeeping Service'
+ __name__ = 'hotel.print_housekeeping'
+ start = StateView('hotel.print_housekeeping.start',
+ 'hotel.print_housekeeping_start_view_form', [
+ Button('Cancel', 'end', 'tryton-cancel'),
+ Button('Open', 'print_', 'tryton-print', default=True),
+ ])
+ print_ = StateReport('hotel.print_housekeeping.report')
+
+ def do_print_(self, action):
+ company = self.start.company
+ data = {
+ 'date': self.start.date,
+ 'employee': self.start.employee.id if self.start.employee else None,
+ 'company': company.id,
+ }
+ return action, data
+
+ def transition_print_(self):
+ return 'end'
+
+
+class HousekeepingReport(Report):
+ __name__ = 'hotel.print_housekeeping.report'
+
+ @classmethod
+ def get_context(cls, records, header, data):
+ report_context = super().get_context(records, header, data)
+ pool = Pool()
+ Company = pool.get('company.company')
+ Housekeeping = pool.get('hotel.housekeeping')
+
+ dom = []
+ if data['employee']:
+ dom.append(('employee.id', '=', data['employee']))
+
+ housekeepings = Housekeeping.search(dom)
+ report_context['records'] = housekeepings
+ report_context['company'] = Company(data['company'])
+ report_context['date'] = datetime.now()
+ return report_context
+
+
+class HotelTask(ModelSQL, ModelView):
+ "Hotel Task"
+ __name__ = "hotel.task"
+ name = fields.Char('Name Task', required=True, select=True)
+ frecuency = fields.Integer('Frecuency', select=True, help='In days')
+ quantity = fields.Integer('Quantity', select=True)
+
+
+# class HotelHousekeepingTask(ModelView, ModelSQL):
+# 'Hotel Housekeeping Task'
+# __name__ = 'hotel.housekeeping.task'
+# room = fields.Many2One('hotel.room', 'Hotel Housekeeping',
+# ondelete='CASCADE', select=True, required=True)
+# task = fields.Many2One('hotel.task', 'Task', select=True, required=True)
+# frecuency = fields.Integer('Frecuency', select=True, help='In days')
+# quantity = fields.Integer('Quantity', select=True)
+#
+# @fields.depends('task', 'frecuency')
+# def on_change_task(self, name=None):
+# if self.task:
+# self.frecuency = self.task.frecuency
diff --git a/room.xml b/room.xml
index 8560176..0980d2c 100644
--- a/room.xml
+++ b/room.xml
@@ -193,5 +193,150 @@ this repository contains the full copyright notices and license terms. -->
+
+
+ hotel.room
+ form
+ room_housekeeping_form
+
+
+ hotel.room
+ tree
+ room_housekeeping_tree
+
+
+ Housekeeping
+ hotel.room
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ hotel.room.cleaning_type
+ form
+ room_cleaning_type_form
+
+
+ hotel.room.cleaning_type
+ tree
+ room_cleaning_type_tree
+
+
+ Cleaning Type
+ hotel.room.cleaning_type
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ hotel.task
+ form
+ task_form
+
+
+ hotel.task
+ tree
+ task_tree
+
+
+ Tasks Housekeeping
+ hotel.task
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Housekeeping Report
+
+ hotel.print_housekeeping.report
+ hotel/housekeeping.fods
+
+
+ hotel.print_housekeeping.start
+ form
+ housekeeping_start_form
+
+
+ Housekeeping Report
+ hotel.print_housekeeping
+
+
+
diff --git a/tryton.cfg b/tryton.cfg
index 71a5189..f7cb1c7 100644
--- a/tryton.cfg
+++ b/tryton.cfg
@@ -1,5 +1,5 @@
[tryton]
-version=6.0.24
+version=6.0.25
depends:
party
company
@@ -23,7 +23,6 @@ xml:
location.xml
booking.xml
folio.xml
- housekeeping.xml
company.xml
city.xml
party.xml
diff --git a/view/configuration_form.xml b/view/configuration_form.xml
index e4990ff..400dbf2 100644
--- a/view/configuration_form.xml
+++ b/view/configuration_form.xml
@@ -10,8 +10,6 @@ this repository contains the full copyright notices and license terms. -->
-
-
@@ -26,8 +24,6 @@ this repository contains the full copyright notices and license terms. -->
-
-
diff --git a/view/configuration_tree.xml b/view/configuration_tree.xml
index 50e70df..88336cb 100644
--- a/view/configuration_tree.xml
+++ b/view/configuration_tree.xml
@@ -2,7 +2,6 @@
-
diff --git a/view/housekeeping_cleaning_type_form.xml b/view/room_cleaning_type_form.xml
similarity index 86%
rename from view/housekeeping_cleaning_type_form.xml
rename to view/room_cleaning_type_form.xml
index f7bfd12..81bfee9 100644
--- a/view/housekeeping_cleaning_type_form.xml
+++ b/view/room_cleaning_type_form.xml
@@ -4,6 +4,8 @@ this repository contains the full copyright notices and license terms. -->
diff --git a/view/housekeeping_cleaning_type_tree.xml b/view/room_cleaning_type_tree.xml
similarity index 90%
rename from view/housekeeping_cleaning_type_tree.xml
rename to view/room_cleaning_type_tree.xml
index 882cc49..d4d565f 100644
--- a/view/housekeeping_cleaning_type_tree.xml
+++ b/view/room_cleaning_type_tree.xml
@@ -3,5 +3,6 @@
this repository contains the full copyright notices and license terms. -->
+
diff --git a/view/housekeeping_form.xml b/view/room_housekeeping_form.xml
similarity index 65%
rename from view/housekeeping_form.xml
rename to view/room_housekeeping_form.xml
index ccd0714..0c607cc 100644
--- a/view/housekeeping_form.xml
+++ b/view/room_housekeeping_form.xml
@@ -2,33 +2,23 @@