from datetime import datetime, timedelta from odoo import _ from odoo.exceptions import MissingError from odoo.addons.base_rest import restapi from odoo.addons.base_rest_datamodel.restapi import Datamodel from odoo.addons.component.core import Component class PmsReservationService(Component): _inherit = "base.rest.service" _name = "pms.reservation.service" _usage = "reservations" _collection = "pms.services" @restapi.method( [ ( [ "/", ], "GET", ) ], input_param=Datamodel("pms.search.param", is_list=False), output_param=Datamodel("pms.reservation.info", is_list=False), auth="jwt_api_pms", ) def get_reservation(self, reservation_id, pms_search_param): domain = list() domain.append(("id", "=", reservation_id)) if pms_search_param.pmsPropertyId: domain.append(("pms_property_id", "=", pms_search_param.pmsPropertyId)) reservation = self.env["pms.reservation"].search(domain) res = [] PmsReservationInfo = self.env.datamodels["pms.reservation.info"] if not reservation: pass else: # messages = [] # import re # text = re.compile("<.*?>") # for message in reservation.message_ids.sorted(key=lambda x: x.date): # messages.append( # { # "author": message.author_id.name, # "date": str(message.date), # # print(self.env["ir.fields.converter"].text_from_html(message.body)) # "body": re.sub(text, "", message.body), # } # ) res = PmsReservationInfo( id=reservation.id, name=reservation.name, folioId=reservation.folio_id.id, folioSequence=reservation.folio_sequence, partnerName=reservation.partner_name, boardServiceId=reservation.board_service_room_id.id if reservation.board_service_room_id else None, saleChannelId=reservation.channel_type_id.id if reservation.channel_type_id else None, agencyId=reservation.agency_id.id if reservation.agency_id else None, userId=reservation.user_id.id, checkin=datetime.combine( reservation.checkin, datetime.min.time() ).isoformat(), checkout=datetime.combine( reservation.checkout, datetime.min.time() ).isoformat(), arrivalHour=reservation.arrival_hour, departureHour=reservation.departure_hour, roomTypeId=reservation.room_type_id.id if reservation.room_type_id else None, preferredRoomId=reservation.preferred_room_id.id if reservation.preferred_room_id else None, pricelistId=reservation.pricelist_id.id if reservation.pricelist_id else None, adults=reservation.adults if reservation.adults else None, overbooking=reservation.overbooking, externalReference=reservation.external_reference if reservation.external_reference else None, stateCode=reservation.state, stateDescription=dict( reservation.fields_get(["state"])["state"]["selection"] )[reservation.state], children=reservation.children if reservation.children else None, readyForCheckin=reservation.ready_for_checkin, allowedCheckout=reservation.allowed_checkout, isSplitted=reservation.splitted, pendingCheckinData=reservation.pending_checkin_data, createDate=reservation.create_date.isoformat(), segmentationId=reservation.segmentation_ids[0].id if reservation.segmentation_ids else None, toAssign=reservation.to_assign, reservationType=reservation.reservation_type, priceTotal=round(reservation.price_room_services_set, 2), discount=round(reservation.discount, 2), commissionAmount=round(reservation.commission_amount, 2) if reservation.commission_amount else None, priceOnlyServices=round(reservation.price_services, 2), priceOnlyRoom=round(reservation.price_total, 2), ) return res @restapi.method( [ ( [ "/", ], "PATCH", ) ], input_param=Datamodel("pms.reservation.updates", is_list=False), auth="jwt_api_pms", ) def update_reservation(self, reservation_id, reservation_lines_changes): if reservation_lines_changes.reservationLinesChanges: # get date of first reservation id to change first_reservation_line_id_to_change = ( reservation_lines_changes.reservationLinesChanges[0][ "reservationLineId" ] ) first_reservation_line_to_change = self.env["pms.reservation.line"].browse( first_reservation_line_id_to_change ) date_first_reservation_line_to_change = datetime.strptime( reservation_lines_changes.reservationLinesChanges[0]["date"], "%Y-%m-%d" ) # iterate changes for change_iterator in sorted( reservation_lines_changes.reservationLinesChanges, # adjust order to start changing from last/first reservation line # to avoid reservation line date constraint reverse=first_reservation_line_to_change.date < date_first_reservation_line_to_change.date(), key=lambda x: datetime.strptime(x["date"], "%Y-%m-%d"), ): # recordset of each line line_to_change = self.env["pms.reservation.line"].search( [ ("reservation_id", "=", reservation_id), ("id", "=", change_iterator["reservationLineId"]), ] ) # modifying date, room_id, ... if "date" in change_iterator: line_to_change.date = change_iterator["date"] if ( "roomId" in change_iterator and line_to_change.room_id.id != change_iterator["roomId"] ): line_to_change.room_id = change_iterator["roomId"] max_value = max( first_reservation_line_to_change.reservation_id.reservation_line_ids.mapped( "date" ) ) + timedelta(days=1) min_value = min( first_reservation_line_to_change.reservation_id.reservation_line_ids.mapped( "date" ) ) reservation = self.env["pms.reservation"].browse(reservation_id) reservation.checkin = min_value reservation.checkout = max_value else: reservation_to_update = ( self.env["pms.reservation"].sudo().search([("id", "=", reservation_id)]) ) reservation_vals = {} if reservation_lines_changes.preferredRoomId: reservation_vals.update( {"preferred_room_id": reservation_lines_changes.preferredRoomId} ) if reservation_lines_changes.boardServiceId: reservation_vals.update( {"board_service_room_id": reservation_lines_changes.boardServiceId} ) if reservation_lines_changes.pricelistId: reservation_vals.update( {"pricelist_id": reservation_lines_changes.pricelistId} ) if reservation_lines_changes.adults: reservation_vals.update({"adults": reservation_lines_changes.adults}) if reservation_lines_changes.children: reservation_vals.update( {"children": reservation_lines_changes.children} ) if reservation_lines_changes.segmentationId: reservation_vals.update( { "segmentation_ids": [ (6, 0, [reservation_lines_changes.segmentationId]) ] } ) reservation_to_update.write(reservation_vals) @restapi.method( [ ( [ "//reservation-lines", ], "GET", ) ], output_param=Datamodel("pms.reservation.line.info", is_list=True), auth="jwt_api_pms", ) def get_reservation_line(self, reservation_id): reservation = self.env["pms.reservation"].search([("id", "=", reservation_id)]) if not reservation: raise MissingError(_("Reservation not found")) result_lines = [] PmsReservationLineInfo = self.env.datamodels["pms.reservation.line.info"] for reservation_line in reservation.reservation_line_ids: result_lines.append( PmsReservationLineInfo( id=reservation_line.id, date=datetime.combine( reservation_line.date, datetime.min.time() ).isoformat(), price=round(reservation_line.price, 2), discount=round(reservation_line.discount, 2), cancelDiscount=round(reservation_line.cancel_discount, 2), roomId=reservation_line.room_id.id, reservationId=reservation_line.reservation_id.id, pmsPropertyId=reservation_line.pms_property_id.id, ) ) return result_lines @restapi.method( [ ( [ "//reservation-lines", ], "POST", ) ], input_param=Datamodel("pms.reservation.line.info", is_list=False), auth="jwt_api_pms", ) def create_reservation_line(self, reservation_id, reservation_line_info): reservation = self.env["pms.reservation"].search([("id", "=", reservation_id)]) date = datetime.strptime(reservation_line_info.date, "%Y-%m-%d").date() if not reservation: raise MissingError(_("Reservation not found")) if not reservation_line_info.date or not reservation_line_info.price: raise MissingError(_("Date and price are required")) if ( date != reservation.checkin - timedelta(days=1) and date != reservation.checkout ): raise MissingError(_("It is only allowed to create contiguous nights to the reservation")) vals = dict() vals.update({ "reservation_id": reservation.id, "date": date, "price": reservation_line_info.price, "room_id": reservation_line_info.roomId if reservation_line_info.roomId else reservation.preferred_room_id.id, }) self.env["pms.reservation.line"].create(vals) @restapi.method( [ ( [ "//reservation-lines/", ], "DELETE", ) ], auth="jwt_api_pms", ) def delete_reservation_line(self, reservation_id, reservation_line_id): reservation = self.env["pms.reservation"].search([("id", "=", reservation_id)]) line = reservation.reservation_line_ids.filtered(lambda l: l.id == reservation_line_id) if ( line and len(reservation.reservation_line_ids) == 1 and line.date > min(reservation.reservation_line_ids.mapped("date")) and line.date < max(reservation.reservation_line_ids.mapped("date")) ): line.unlink() else: raise MissingError(_("It was not possible to remove the reservation line")) @restapi.method( [ ( [ "//services", ], "GET", ) ], output_param=Datamodel("pms.service.info", is_list=True), auth="jwt_api_pms", ) def get_reservation_services(self, reservation_id): reservation = self.env["pms.reservation"].search([("id", "=", reservation_id)]) if not reservation: raise MissingError(_("Reservation not found")) result_services = [] PmsServiceInfo = self.env.datamodels["pms.service.info"] for service in reservation.service_ids: result_services.append( PmsServiceInfo( id=service.id, name=service.name, quantity=service.product_qty, priceTotal=round(service.price_total, 2), priceSubtotal=round(service.price_subtotal, 2), priceTaxes=round(service.price_tax, 2), discount=round(service.discount, 2), isBoardService=service.is_board_service, ) ) return result_services @restapi.method( [ ( [ "//reservation-lines/", ], "PATCH", ) ], input_param=Datamodel("pms.reservation.line.info", is_list=False), auth="jwt_api_pms", ) def update_reservation_lines( self, _reservation_id, reservation_line_id, reservation_line_param ): if reservation_line_param.roomId: reservation_line_id = self.env["pms.reservation.line"].browse( reservation_line_id ) reservation_line_id.room_id = reservation_line_param.roomId @restapi.method( [ ( [ "//checkin-partners", ], "GET", ) ], output_param=Datamodel("pms.checkin.partner.info", is_list=True), auth="jwt_api_pms", ) def get_checkin_partners(self, reservation_id): reservation = self.env["pms.reservation"].browse(reservation_id) checkin_partners = [] PmsCheckinPartnerInfo = self.env.datamodels["pms.checkin.partner.info"] if not reservation: pass else: # TODO Review state draft for checkin_partner in reservation.checkin_partner_ids.filtered( lambda ch: ch.state != "dummy" ): if checkin_partner.document_expedition_date: document_expedition_date = ( checkin_partner.document_expedition_date.strftime("%d/%m/%Y") ) if checkin_partner.birthdate_date: birthdate_date = checkin_partner.birthdate_date.strftime("%d/%m/%Y") checkin_partners.append( PmsCheckinPartnerInfo( id=checkin_partner.id, reservationId=checkin_partner.reservation_id.id, name=checkin_partner.name if checkin_partner.name else "", firstname=checkin_partner.firstname if checkin_partner.firstname else None, lastname=checkin_partner.lastname if checkin_partner.lastname else None, lastname2=checkin_partner.lastname2 if checkin_partner.lastname2 else None, email=checkin_partner.email if checkin_partner.email else "", mobile=checkin_partner.mobile if checkin_partner.mobile else "", documentType=checkin_partner.document_type.id if checkin_partner.document_type else None, documentNumber=checkin_partner.document_number if checkin_partner.document_number else None, documentExpeditionDate=document_expedition_date if checkin_partner.document_expedition_date else None, documentSupportNumber=checkin_partner.support_number if checkin_partner.support_number else None, gender=checkin_partner.gender if checkin_partner.gender else "", birthdate=birthdate_date if checkin_partner.birthdate_date else None, residenceStreet=checkin_partner.residence_street if checkin_partner.residence_street else None, zip=checkin_partner.residence_zip if checkin_partner.residence_zip else None, residenceCity=checkin_partner.residence_city if checkin_partner.residence_city else None, nationality=checkin_partner.residence_country_id.id if checkin_partner.residence_country_id else None, countryState=checkin_partner.residence_state_id.id if checkin_partner.residence_state_id else None, checkinPartnerState=checkin_partner.state, ) ) return checkin_partners @restapi.method( [ ( [ "//checkin-partners/", ], "PATCH", ) ], input_param=Datamodel("pms.checkin.partner.info", is_list=False), auth="jwt_api_pms", ) def write_reservation_checkin_partner( self, reservation_id, checkin_partner_id, pms_checkin_partner_info ): checkin_partner = self.env["pms.checkin.partner"].search( [("id", "=", checkin_partner_id), ("reservation_id", "=", reservation_id)] ) if checkin_partner: checkin_partner.write( self._get_checkin_partner_values(pms_checkin_partner_info) ) @restapi.method( [ ( [ "//checkin-partners", ], "POST", ) ], input_param=Datamodel("pms.checkin.partner.info", is_list=False), auth="jwt_api_pms", ) def create_reservation_checkin_partner( self, reservation_id, pms_checkin_partner_info ): reservation_rec = self.env["pms.reservation"].browse(reservation_id) if any( reservation_rec.checkin_partner_ids.filtered(lambda ch: ch.state == "dummy") ): checkin_partner_last_id = max( reservation_rec.checkin_partner_ids.filtered( lambda ch: ch.state == "dummy" ) ).id checkin_partner = self.env["pms.checkin.partner"].browse( checkin_partner_last_id ) checkin_partner.write( self._get_checkin_partner_values(pms_checkin_partner_info) ) @restapi.method( [ ( [ "//checkin-partners/", ], "DELETE", ) ], auth="jwt_api_pms", ) def delete_reservation_checkin_partner(self, reservation_id, checkin_partner_id): reservation = self.env["pms.reservation"].browse(reservation_id) reservation.adults = reservation.adults - 1 def _get_checkin_partner_values(self, pms_checkin_partner_info): vals = dict() if pms_checkin_partner_info.firstname: vals.update({"firstname": pms_checkin_partner_info.firstname}) if pms_checkin_partner_info.lastname: vals.update({"lastname": pms_checkin_partner_info.lastname}) if pms_checkin_partner_info.lastname2: vals.update({"lastname2": pms_checkin_partner_info.lastname2}) if pms_checkin_partner_info.email: vals.update({"email": pms_checkin_partner_info.email}) if pms_checkin_partner_info.mobile: vals.update({"mobile": pms_checkin_partner_info.mobile}) if ( pms_checkin_partner_info.documentType and pms_checkin_partner_info.documentType != -1 ): document_type = pms_checkin_partner_info.documentType vals.update({"document_type": document_type}) if pms_checkin_partner_info.documentNumber: vals.update({"document_number": pms_checkin_partner_info.documentNumber}) if pms_checkin_partner_info.documentExpeditionDate: document_expedition_date = datetime.strptime( pms_checkin_partner_info.documentExpeditionDate, "%d/%m/%Y" ) document_expedition_date = document_expedition_date.strftime("%Y-%m-%d") vals.update({"document_expedition_date": document_expedition_date}) if pms_checkin_partner_info.documentSupportNumber: vals.update( {"support_number": pms_checkin_partner_info.documentSupportNumber} ) if pms_checkin_partner_info.gender: vals.update({"gender": pms_checkin_partner_info.gender}) if pms_checkin_partner_info.birthdate: birthdate = datetime.strptime( pms_checkin_partner_info.birthdate, "%d/%m/%Y" ) birthdate = birthdate.strftime("%Y-%m-%d") vals.update({"birthdate_date": birthdate}) if pms_checkin_partner_info.residenceStreet: vals.update({"residence_street": pms_checkin_partner_info.residenceStreet}) if pms_checkin_partner_info.zip: vals.update({"residence_zip": pms_checkin_partner_info.zip}) if pms_checkin_partner_info.residenceCity: vals.update({"residence_city": pms_checkin_partner_info.residenceCity}) if ( pms_checkin_partner_info.nationality and pms_checkin_partner_info.nationality != -1 ): vals.update({"nationality_id": pms_checkin_partner_info.nationality}) vals.update({"residence_country_id": pms_checkin_partner_info.nationality}) if ( pms_checkin_partner_info.countryState and pms_checkin_partner_info.countryState != -1 ): vals.update({"residence_state_id": pms_checkin_partner_info.countryState}) return vals