diff --git a/pms_api_rest/datamodels/pms_dashboard.py b/pms_api_rest/datamodels/pms_dashboard.py index 6b24b4bc8..fa6bf8cc9 100644 --- a/pms_api_rest/datamodels/pms_dashboard.py +++ b/pms_api_rest/datamodels/pms_dashboard.py @@ -3,15 +3,30 @@ from marshmallow import fields from odoo.addons.datamodel.core import Datamodel -class PmsDashboardPendingReservationsSearchParam(Datamodel): - _name = "pms.dashboard.pending.reservations.search.param" +class PmsDashboardSearchParam(Datamodel): + _name = "pms.dashboard.search.param" date = fields.String(required=False, allow_none=True) pmsPropertyId = fields.Integer(required=False, allow_none=True) +class PmsDashboardRangeDatesSearchParam(Datamodel): + _name = "pms.dashboard.range.dates.search.param" + dateFrom = fields.String(required=False, allow_none=True) + dateTo = fields.String(required=False, allow_none=True) + pmsPropertyId = fields.Integer(required=False, allow_none=True) + + + class PmsDashboardPendingReservations(Datamodel): _name = "pms.dashboard.pending.reservations" - pendingReservations = fields.Integer(required=False, allow_none=True) - completedReservations = fields.Integer(required=False, allow_none=True) + date = fields.String(required=False, allow_none=True) + pendingArrivalReservations = fields.Integer(required=False, allow_none=True) + completedArrivalReservations = fields.Integer(required=False, allow_none=True) + pendingDepartureReservations = fields.Integer(required=False, allow_none=True) + completedDepartureReservations = fields.Integer(required=False, allow_none=True) + +class PmsDashboardNumericResponse(Datamodel): + _name = "pms.dashboard.numeric.response" + value = fields.Float(required=False, allow_none=True) diff --git a/pms_api_rest/services/pms_dashboard_service.py b/pms_api_rest/services/pms_dashboard_service.py index d0b4cead7..96bc1fd5c 100644 --- a/pms_api_rest/services/pms_dashboard_service.py +++ b/pms_api_rest/services/pms_dashboard_service.py @@ -16,74 +16,207 @@ class PmsDashboardServices(Component): [ ( [ - "/pending-checkins", + "/pending-reservations", ], "GET", ) ], - input_param=Datamodel("pms.dashboard.pending.reservations.search.param"), - output_param=Datamodel("pms.dashboard.pending.reservations"), + input_param=Datamodel("pms.dashboard.range.dates.search.param"), + output_param=Datamodel("pms.dashboard.pending.reservations", is_list=True), auth="jwt_api_pms", ) - def get_pending_checkin_reservations(self, pms_reservations_search_param): - date = fields.Date.from_string(pms_reservations_search_param.date) + def get_pending_reservations(self, pms_dashboard_search_param): + dateFrom = fields.Date.from_string(pms_dashboard_search_param.dateFrom) + dateTo = fields.Date.from_string(pms_dashboard_search_param.dateTo) - - pendingReservations = self.env["pms.reservation"].search_count( - [ - ("checkin", "=", date), - ("state", "in", ("confirm", "arrival_delayed")), - ("reservation_type", "!=", "out") - ] + self.env.cr.execute( + f""" + SELECT + d.date, + SUM(CASE WHEN r.checkin = d.date AND r.state IN ('confirm', 'arrival_delayed') THEN 1 ELSE 0 + END) AS reservations_pending_arrival, + SUM(CASE WHEN r.checkin = d.date AND r.state = 'onboard' THEN 1 ELSE 0 + END) AS + reservations_on_board, + SUM(CASE WHEN r.checkout = d.date AND r.state IN ('onboard', 'departure_delayed') THEN 1 ELSE 0 + END) AS reservations_pending_departure, + SUM(CASE WHEN r.checkout = d.date AND r.state = 'done' THEN 1 ELSE 0 END) AS reservations_completed + FROM ( SELECT CURRENT_DATE + date AS date + FROM generate_series(date '2023-08-30' - CURRENT_DATE, date '2023-09-30' - CURRENT_DATE) date) d + LEFT JOIN pms_reservation r + ON (r.checkin = d.date OR r.checkout = d.date) + AND r.pms_property_id = 1 + AND r.reservation_type != 'out' + GROUP BY d.date + ORDER BY d.date; + """, + ( + dateFrom, + dateTo, + pms_dashboard_search_param.pmsPropertyId, + ), ) - completedReservations = self.env["pms.reservation"].search_count( - [ - ("checkin", "=", date), - ("state", "=", "onboard"), - ] - ) - PmsDashboardPendingReservations = self.env.datamodels["pms.dashboard.pending.reservations"] - return PmsDashboardPendingReservations( - pendingReservations=pendingReservations, - completedReservations=completedReservations, + + result = self.env.cr.dictfetchall() + pending_reservations = [] + DashboardPendingReservations = self.env.datamodels["pms.dashboard.pending.reservations"] + + for item in result: + pending_reservations.append( + DashboardPendingReservations( + date=datetime.combine(item['date'], datetime.min.time()).isoformat(), + pendingArrivalReservations=item["reservations_pending_arrival"] if item["reservations_pending_arrival"] else 0, + completedArrivalReservations=item["reservations_on_board"] if item["reservations_on_board"] else 0, + pendingDepartureReservations=item["reservations_pending_departure"] if item["reservations_pending_departure"] else 0, + completedDepartureReservations=item["reservations_completed"] if item["reservations_completed"] else 0, + ) + ) + return pending_reservations + + + @restapi.method( + [ + ( + [ + "/occupancy", + ], + "GET", + ) + ], + input_param=Datamodel("pms.dashboard.search.param"), + output_param=Datamodel("pms.dashboard.numeric.response"), + auth="jwt_api_pms", + ) + def get_occupancy(self, pms_dashboard_search_param): + date_occupancy = fields.Date.from_string(pms_dashboard_search_param.date) + + self.env.cr.execute( + f""" + SELECT CEIL(l.num * 100.00 / tr.num_total_rooms) + FROM + ( + SELECT COUNT(1) num_total_rooms + FROM pms_room + WHERE pms_property_id = %s + ) tr, + ( + SELECT COUNT(1) num + FROM pms_reservation_line l + INNER JOIN pms_reservation r ON r.id = l.reservation_id + WHERE r.reservation_type NOT IN ('out', 'staff') + AND l.occupies_availability = true + AND l.state != 'cancel' + AND l.date = %s + AND r.pms_property_id = %s + ) l + """, + ( + date_occupancy, + pms_dashboard_search_param.pmsPropertyId, + pms_dashboard_search_param.pmsPropertyId, + ), + ) + + result = self.env.cr.dictfetchall() + DashboardNumericResponse = self.env.datamodels["pms.dashboard.numeric.response"] + + return DashboardNumericResponse( + value=result[0]["occupancy"] if result else 0, ) @restapi.method( [ ( [ - "/pending-checkouts", + "/billing", ], "GET", ) ], - input_param=Datamodel("pms.dashboard.pending.reservations.search.param"), - output_param=Datamodel("pms.dashboard.pending.reservations"), + input_param=Datamodel("pms.dashboard.range.dates.search.param"), + output_param=Datamodel("pms.dashboard.numeric.response"), auth="jwt_api_pms", ) - def get_pending_checkout_reservations(self, pms_reservations_search_param): - date = fields.Date.from_string(pms_reservations_search_param.date) + def get_billing(self, pms_dashboard_search_param): + date_from = fields.Date.from_string(pms_dashboard_search_param.dateFrom) + date_to = fields.Date.from_string(pms_dashboard_search_param.dateTo) - - pending_reservations = self.env["pms.reservation"].search_count( - [ - ("checkout", "=", date), - ("state", "in", ("onboard", "departure_delayed")), - ("reservation_type", "!=", "out"), - ] + self.env.cr.execute( + f""" + SELECT SUM(l.price_day_total) billing + FROM pms_reservation_line l INNER JOIN pms_reservation r ON l.reservation_id = r.id + WHERE l.date BETWEEN %s AND %s + AND l.occupies_availability = true + AND l.state != 'cancel' + AND l.pms_property_id = %s + AND r.reservation_type NOT IN ('out', 'staff') + """, + ( + date_from, + date_to, + pms_dashboard_search_param.pmsPropertyId, + ), ) - completed_reservations = self.env["pms.reservation"].search_count( - [ - ("checkout", "=", date), - ("state", "=", "done"), - ] - ) - PmsDashboardPendingReservations = self.env.datamodels["pms.dashboard.pending.reservations"] - return PmsDashboardPendingReservations( - pendingReservations=pending_reservations, - completedReservations=completed_reservations, + result = self.env.cr.dictfetchall() + DashboardNumericResponse = self.env.datamodels["pms.dashboard.numeric.response"] + + return DashboardNumericResponse( + value=result[0]["billing"] if result else 0, ) + @restapi.method( + [ + ( + [ + "/adr", + ], + "GET", + ) + ], + input_param=Datamodel("pms.dashboard.range.dates.search.param"), + output_param=Datamodel("pms.dashboard.numeric.response"), + auth="jwt_api_pms", + ) + def get_adr(self, pms_dashboard_search_param): + date_from = fields.Date.from_string(pms_dashboard_search_param.dateFrom) + date_to = fields.Date.from_string(pms_dashboard_search_param.dateTo) + + pms_property = self.env["pms.property"].search([("id", "=", pms_dashboard_search_param.pmsPropertyId)]) + + adr = pms_property._get_adr(date_from, date_to) + + DashboardNumericResponse = self.env.datamodels["pms.dashboard.numeric.response"] + + return DashboardNumericResponse( + value=adr, + ) + + @restapi.method( + [ + ( + [ + "/revpar", + ], + "GET", + ) + ], + input_param=Datamodel("pms.dashboard.range.dates.search.param"), + output_param=Datamodel("pms.dashboard.numeric.response"), + auth="jwt_api_pms", + ) + def get_revpar(self, pms_dashboard_search_param): + date_from = fields.Date.from_string(pms_dashboard_search_param.dateFrom) + date_to = fields.Date.from_string(pms_dashboard_search_param.dateTo) + + pms_property = self.env["pms.property"].search([("id", "=", pms_dashboard_search_param.pmsPropertyId)]) + + revpar = pms_property._get_revpar(date_from, date_to) + + DashboardNumericResponse = self.env.datamodels["pms.dashboard.numeric.response"] + + return DashboardNumericResponse( + value=revpar, + )