From 4ed7e31439c886fc2132df0533e0540c7e1e05fc Mon Sep 17 00:00:00 2001 From: Dario Lodeiros Date: Thu, 10 Jun 2021 13:03:58 +0200 Subject: [PATCH 01/23] [RFC] Basic setUp structure --- pms/tests/test_pms_folio.py | 9 ++------- pms/tests/test_pms_folio_invoice.py | 9 +-------- pms/tests/test_pms_folio_sale_line.py | 29 ++------------------------- 3 files changed, 5 insertions(+), 42 deletions(-) diff --git a/pms/tests/test_pms_folio.py b/pms/tests/test_pms_folio.py index 7fdeef8c0..920a2c001 100644 --- a/pms/tests/test_pms_folio.py +++ b/pms/tests/test_pms_folio.py @@ -10,7 +10,8 @@ freeze_time("2000-02-02") class TestPmsFolio(common.SavepointCase): - def create_common_scenario(self): + def setUp(self): + super().setUp() # create a room type availability self.room_type_availability = self.env["pms.availability.plan"].create( {"name": "Availability plan for TEST"} @@ -88,7 +89,6 @@ class TestPmsFolio(common.SavepointCase): ) def create_multiproperty_scenario(self): - self.create_common_scenario() self.property1 = self.env["pms.property"].create( { "name": "Property_1", @@ -124,7 +124,6 @@ class TestPmsFolio(common.SavepointCase): def test_commission_and_partner_correct(self): # ARRANGE - self.create_common_scenario() PmsFolio = self.env["pms.folio"] PmsReservation = self.env["pms.reservation"] PmsPartner = self.env["res.partner"] @@ -175,7 +174,6 @@ class TestPmsFolio(common.SavepointCase): ) def test_compute_folio_priority(self): - self.create_common_scenario() r1 = self.env["pms.reservation"].create( { "checkin": fields.date.today(), @@ -209,7 +207,6 @@ class TestPmsFolio(common.SavepointCase): # Folio is paid after execute # # ARRANGE - self.create_common_scenario() r_test = self.env["pms.reservation"].create( { "pms_property_id": self.property.id, @@ -241,7 +238,6 @@ class TestPmsFolio(common.SavepointCase): # # ARRANGE left_to_pay = 1 - self.create_common_scenario() r_test = self.env["pms.reservation"].create( { "pms_property_id": self.property.id, @@ -288,7 +284,6 @@ class TestPmsFolio(common.SavepointCase): ) def _test_compute_currency(self): - self.create_common_scenario() self.currency1 = self.env["res.currency"].create( { "name": "currency1", diff --git a/pms/tests/test_pms_folio_invoice.py b/pms/tests/test_pms_folio_invoice.py index f2da8e3b6..67754d22b 100644 --- a/pms/tests/test_pms_folio_invoice.py +++ b/pms/tests/test_pms_folio_invoice.py @@ -6,10 +6,7 @@ from odoo.tests import common class TestPmsFolioInvoice(common.SavepointCase): def setUp(self): super(TestPmsFolioInvoice, self).setUp() - - def create_common_scenario(self): - # create a room type availability - # sequences + # create a room type availability and sequences self.folio_sequence = self.env["ir.sequence"].create( { "name": "PMS Folio", @@ -95,7 +92,6 @@ class TestPmsFolioInvoice(common.SavepointCase): def test_invoice_full_folio(self): # ARRANGE - self.create_common_scenario() r1 = self.env["pms.reservation"].create( { "pms_property_id": self.property.id, @@ -121,7 +117,6 @@ class TestPmsFolioInvoice(common.SavepointCase): def test_invoice_partial_folio_by_steps(self): # ARRANGE - self.create_common_scenario() r1 = self.env["pms.reservation"].create( { "pms_property_id": self.property.id, @@ -162,7 +157,6 @@ class TestPmsFolioInvoice(common.SavepointCase): def test_invoice_partial_folio_diferent_partners(self): # ARRANGE - self.create_common_scenario() r1 = self.env["pms.reservation"].create( { "pms_property_id": self.property.id, @@ -208,7 +202,6 @@ class TestPmsFolioInvoice(common.SavepointCase): def test_invoice_partial_folio_wrong_qtys(self): # ARRANGE - self.create_common_scenario() r1 = self.env["pms.reservation"].create( { "pms_property_id": self.property.id, diff --git a/pms/tests/test_pms_folio_sale_line.py b/pms/tests/test_pms_folio_sale_line.py index 8e80126e0..a3ce98f0f 100644 --- a/pms/tests/test_pms_folio_sale_line.py +++ b/pms/tests/test_pms_folio_sale_line.py @@ -4,7 +4,8 @@ from .common import TestPms class TestPmsFolioSaleLine(TestPms): - def create_common_scenario(self): + def setUp(self): + super().setUp() # create a room type availability self.room_type_availability = self.env["pms.availability.plan"].create( {"name": "Availability plan for TEST"} @@ -53,7 +54,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_sale_lines = 1 - self.create_common_scenario() # ACT r_test = self.env["pms.reservation"].create( @@ -81,7 +81,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_sale_lines = 2 - self.create_common_scenario() r_test = self.env["pms.reservation"].create( { "pms_property_id": self.property.id, @@ -112,7 +111,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_sale_lines = 2 - self.create_common_scenario() r_test = self.env["pms.reservation"].create( { "pms_property_id": self.property.id, @@ -143,7 +141,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_sale_lines = 2 - self.create_common_scenario() r_test = self.env["pms.reservation"].create( { "pms_property_id": self.property.id, @@ -175,7 +172,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_sale_lines = 1 - self.create_common_scenario() r_test = self.env["pms.reservation"].create( { "pms_property_id": self.property.id, @@ -207,7 +203,6 @@ class TestPmsFolioSaleLine(TestPms): # Should keep the same reservation sales line record. # ARRANGE - self.create_common_scenario() r_test = self.env["pms.reservation"].create( { "pms_property_id": self.property.id, @@ -242,7 +237,6 @@ class TestPmsFolioSaleLine(TestPms): # Should keep the same reservation sales line record. # ARRANGE - self.create_common_scenario() r_test = self.env["pms.reservation"].create( { "pms_property_id": self.property.id, @@ -278,7 +272,6 @@ class TestPmsFolioSaleLine(TestPms): # Should keep the same reservation sales line record. # ARRANGE - self.create_common_scenario() r_test = self.env["pms.reservation"].create( { "pms_property_id": self.property.id, @@ -315,7 +308,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_board_service_sale_lines = 1 - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -375,7 +367,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_board_service_sale_lines = 2 - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -435,7 +426,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_board_service_sale_lines = 2 - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -498,7 +488,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_board_service_sale_lines = 2 - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -561,7 +550,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_board_service_sale_lines = 1 - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -623,7 +611,6 @@ class TestPmsFolioSaleLine(TestPms): # Should keep the same board service sales line record. # ARRANGE - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -684,7 +671,6 @@ class TestPmsFolioSaleLine(TestPms): # Should keep the same board service sales line record. # ARRANGE - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -751,7 +737,6 @@ class TestPmsFolioSaleLine(TestPms): # Should keep the same board service sales line record. # ARRANGE - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -821,7 +806,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_extra_service_sale_lines = 1 - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -871,7 +855,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_extra_service_sale_lines = 2 - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -923,7 +906,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_extra_service_sale_lines = 2 - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -976,7 +958,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_extra_service_sale_lines = 2 - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -1030,7 +1011,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_extra_service_sale_lines = 1 - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -1082,7 +1062,6 @@ class TestPmsFolioSaleLine(TestPms): # Should keep the same reservation service sales line record. # ARRANGE - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -1134,7 +1113,6 @@ class TestPmsFolioSaleLine(TestPms): # Should keep the same reservation service sales line record. # ARRANGE - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -1187,7 +1165,6 @@ class TestPmsFolioSaleLine(TestPms): # Should keep the same reservation service sales line record. # ARRANGE - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -1242,7 +1219,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_folio_service_sale_lines = 1 - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", @@ -1289,7 +1265,6 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE expected_folio_service_sale_lines = 2 - self.create_common_scenario() product_test1 = self.env["product.product"].create( { "name": "Test Product 1", From 7b6e626a24ac5ee2fa4eaf0aa683071a7af0a00a Mon Sep 17 00:00:00 2001 From: Dario Lodeiros Date: Thu, 10 Jun 2021 13:21:10 +0200 Subject: [PATCH 02/23] [RFC] Del unnecessary freeze_time --- pms/tests/test_pms_folio.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pms/tests/test_pms_folio.py b/pms/tests/test_pms_folio.py index 920a2c001..f6219901a 100644 --- a/pms/tests/test_pms_folio.py +++ b/pms/tests/test_pms_folio.py @@ -1,13 +1,9 @@ import datetime -from freezegun import freeze_time - from odoo import fields from odoo.exceptions import UserError from odoo.tests import common -freeze_time("2000-02-02") - class TestPmsFolio(common.SavepointCase): def setUp(self): From 5b475b98c7b0c64f890d5630e3601da34ddd1faf Mon Sep 17 00:00:00 2001 From: Dario Lodeiros Date: Sun, 13 Jun 2021 19:34:13 +0200 Subject: [PATCH 03/23] [WIP] Refactoring test_pms_folios: missing payments and agency commission --- pms/models/pms_folio.py | 3 +- pms/models/pms_reservation.py | 1 + pms/models/pms_reservation_line.py | 8 +- pms/tests/test_pms_folio.py | 453 +++++++++++++++++------------ 4 files changed, 275 insertions(+), 190 deletions(-) diff --git a/pms/models/pms_folio.py b/pms/models/pms_folio.py index 1899af850..802eca458 100644 --- a/pms/models/pms_folio.py +++ b/pms/models/pms_folio.py @@ -140,7 +140,6 @@ class PmsFolio(models.Model): commission = fields.Float( string="Commission", readonly=True, - default=0, store=True, compute="_compute_commission", ) @@ -642,7 +641,7 @@ class PmsFolio(models.Model): or False ) - @api.depends("reservation_ids") + @api.depends("reservation_ids", "reservation_ids.commission_amount") def _compute_commission(self): for folio in self: for reservation in folio.reservation_ids: diff --git a/pms/models/pms_reservation.py b/pms/models/pms_reservation.py index f62d4d13b..d423b0ed1 100644 --- a/pms/models/pms_reservation.py +++ b/pms/models/pms_reservation.py @@ -108,6 +108,7 @@ class PmsReservation(models.Model): readonly=False, store=True, related="folio_id.agency_id", + depends=["folio_id.agency_id"], tracking=True, ) channel_type_id = fields.Many2one( diff --git a/pms/models/pms_reservation_line.py b/pms/models/pms_reservation_line.py index 1719581e6..1252efb33 100644 --- a/pms/models/pms_reservation_line.py +++ b/pms/models/pms_reservation_line.py @@ -197,8 +197,12 @@ class PmsReservationLine(models.Model): # if the preferred room is NOT available else: raise ValidationError( - _("%s: No room available.") - % (reservation.preferred_room_id.name) + _("%s: No room available in %s <-> %s.") + % ( + reservation.preferred_room_id.name, + line.reservation_id.checkin, + line.reservation_id.checkout, + ) ) # otherwise we assign the first of those diff --git a/pms/tests/test_pms_folio.py b/pms/tests/test_pms_folio.py index f6219901a..9fd2b3307 100644 --- a/pms/tests/test_pms_folio.py +++ b/pms/tests/test_pms_folio.py @@ -1,73 +1,37 @@ import datetime +from freezegun import freeze_time + from odoo import fields from odoo.exceptions import UserError -from odoo.tests import common + +from .common import TestPms -class TestPmsFolio(common.SavepointCase): +class TestPmsFolio(TestPms): + + # SetUp and Common Scenarios methods + def setUp(self): + """ + - common + room_type_double with 2 rooms (double1 and double2) in pms_property1 + """ super().setUp() - # create a room type availability - self.room_type_availability = self.env["pms.availability.plan"].create( - {"name": "Availability plan for TEST"} - ) - # sequences - self.folio_sequence = self.env["ir.sequence"].create( - { - "name": "PMS Folio", - "code": "pms.folio", - "padding": 4, - "company_id": self.env.ref("base.main_company").id, - } - ) - self.reservation_sequence = self.env["ir.sequence"].create( - { - "name": "PMS Reservation", - "code": "pms.reservation", - "padding": 4, - "company_id": self.env.ref("base.main_company").id, - } - ) - self.checkin_sequence = self.env["ir.sequence"].create( - { - "name": "PMS Checkin", - "code": "pms.checkin.partner", - "padding": 4, - "company_id": self.env.ref("base.main_company").id, - } - ) - # create a property - self.property = self.env["pms.property"].create( - { - "name": "MY PMS TEST", - "company_id": self.env.ref("base.main_company").id, - "default_pricelist_id": self.env.ref("product.list0").id, - "folio_sequence_id": self.folio_sequence.id, - "reservation_sequence_id": self.reservation_sequence.id, - "checkin_sequence_id": self.checkin_sequence.id, - } - ) - - # create room type class - self.room_type_class = self.env["pms.room.type.class"].create( - {"name": "Room", "default_code": "ROOM"} - ) # create room type self.room_type_double = self.env["pms.room.type"].create( { - "pms_property_ids": [self.property.id], + "pms_property_ids": [self.pms_property1.id], "name": "Double Test", "default_code": "DBL_Test", - "class_id": self.room_type_class.id, + "class_id": self.room_type_class1.id, "price": 25, } ) # create room - self.room1 = self.env["pms.room"].create( + self.double1 = self.env["pms.room"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "name": "Double 101", "room_type_id": self.room_type_double.id, "capacity": 2, @@ -75,9 +39,9 @@ class TestPmsFolio(common.SavepointCase): ) # create room - self.room2 = self.env["pms.room"].create( + self.double2 = self.env["pms.room"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "name": "Double 102", "room_type_id": self.room_type_double.id, "capacity": 2, @@ -85,227 +49,344 @@ class TestPmsFolio(common.SavepointCase): ) def create_multiproperty_scenario(self): - self.property1 = self.env["pms.property"].create( - { - "name": "Property_1", - "company_id": self.env.ref("base.main_company").id, - "default_pricelist_id": self.env.ref("product.list0").id, - "folio_sequence_id": self.folio_sequence.id, - "reservation_sequence_id": self.reservation_sequence.id, - "checkin_sequence_id": self.checkin_sequence.id, - } - ) - - self.property2 = self.env["pms.property"].create( + """ + Just 2 properties to majors + """ + self.pms_property2 = self.env["pms.property"].create( { "name": "Property_2", "company_id": self.env.ref("base.main_company").id, "default_pricelist_id": self.env.ref("product.list0").id, - "folio_sequence_id": self.folio_sequence.id, - "reservation_sequence_id": self.reservation_sequence.id, - "checkin_sequence_id": self.checkin_sequence.id, } ) - self.property3 = self.env["pms.property"].create( + self.pms_property3 = self.env["pms.property"].create( { "name": "Property_3", "company_id": self.env.ref("base.main_company").id, "default_pricelist_id": self.env.ref("product.list0").id, - "folio_sequence_id": self.folio_sequence.id, - "reservation_sequence_id": self.reservation_sequence.id, - "checkin_sequence_id": self.checkin_sequence.id, } ) - def test_commission_and_partner_correct(self): - # ARRANGE - PmsFolio = self.env["pms.folio"] - PmsReservation = self.env["pms.reservation"] + def create_sale_channel_scenario(self): + """ + Method to simplified scenario on sale channel tests: + - create a sale_channel1 like indirect + - create a agency1 like sale_channel1 agency + """ PmsPartner = self.env["res.partner"] PmsSaleChannel = self.env["pms.sale.channel"] - # ACT - saleChannel = PmsSaleChannel.create( + + self.sale_channel1 = PmsSaleChannel.create( {"name": "saleChannel1", "channel_type": "indirect"} ) - agency = PmsPartner.create( + self.agency1 = PmsPartner.create( { "name": "partner1", "is_agency": True, "invoice_to_agency": True, "default_commission": 15, - "sale_channel_id": saleChannel.id, + "sale_channel_id": self.sale_channel1.id, } ) - folio = PmsFolio.create( + def create_configuration_accounting_scenario(self): + """ + Method to simplified scenario to payments and accounting: + # REVIEW: + - Use new property with odoo demo data company to avoid account configuration + - Emule SetUp with new property: + - create demo_room_type_double + - Create 2 rooms room_type_double + """ + self.pms_property_demo = self.env["pms.property"].create( { - "agency_id": agency.id, - "pms_property_id": self.property.id, + "name": "Property Based on Comapany Demo", + "company_id": self.env.ref("base.main_company").id, + "default_pricelist_id": self.env.ref("product.list0").id, } ) - - reservation = PmsReservation.create( + # create room type + self.demo_room_type_double = self.env["pms.room.type"].create( { - "checkin": datetime.datetime.now(), - "checkout": datetime.datetime.now() + datetime.timedelta(days=3), - "agency_id": agency.id, - "folio_id": folio.id, + "pms_property_ids": [self.pms_property_demo.id], + "name": "Double Test", + "default_code": "Demo_DBL_Test", + "class_id": self.room_type_class1.id, + "price": 25, } ) - - commission = 0 - for reservation in folio.reservation_ids: - commission += reservation.commission_amount - - # ASSERT - self.assertEqual( - folio.commission, - commission, - "Folio commission don't math with his reservation commission", - ) - if folio.agency_id: - self.assertEqual( - folio.agency_id, folio.partner_id, "Agency has to be the partner" - ) - - def test_compute_folio_priority(self): - r1 = self.env["pms.reservation"].create( + # create rooms + self.double1 = self.env["pms.room"].create( { - "checkin": fields.date.today(), - "checkout": fields.date.today() + datetime.timedelta(days=1), - "room_type_id": self.room_type_double.id, - "partner_id": self.env.ref("base.res_partner_12").id, - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property_demo.id, + "name": "Double 101", + "room_type_id": self.demo_room_type_double.id, + "capacity": 2, + } + ) + self.double2 = self.env["pms.room"].create( + { + "pms_property_id": self.pms_property_demo.id, + "name": "Double 102", + "room_type_id": self.demo_room_type_double.id, + "capacity": 2, + } + ) + + # TestCases: Sale Channels + + def test_default_agency_commission(self): + """ + Check the total commission of a folio with agency based on the + reservation night price and the preconfigured commission in the agency. + ------- + Agency with 15% default commision, folio with one reservation + and 3 nights at 20$ by night (60$ total) + """ + # ARRANGE + self.create_sale_channel_scenario() + commission = (20 + 20 + 20) * 0.15 + + # ACT + folio1 = self.env["pms.folio"].create( + { + "agency_id": self.agency1.id, + "pms_property_id": self.pms_property1.id, } ) - r1.allowed_checkin = False self.env["pms.reservation"].create( { - "folio_id": r1.folio_id.id, + "checkin": fields.date.today(), + "checkout": fields.date.today() + datetime.timedelta(days=3), + "reservation_line_ids": [ + ( + 0, + False, + { + "date": fields.date.today(), + "price": 20, + }, + ), + ( + 0, + False, + { + "date": fields.date.today() + datetime.timedelta(days=1), + "price": 20, + }, + ), + ( + 0, + False, + { + "date": fields.date.today() + datetime.timedelta(days=2), + "price": 20, + }, + ), + ], + "folio_id": folio1.id, + } + ) + # ASSERT + self.assertEqual( + commission, folio1.commission, "The folio compute commission is wrong" + ) + + def test_reservation_agency_without_partner(self): + """ + Check that a reservation / folio created with an agency + and without a partner will automatically take the partner. + ------- + Create the folio1 and the reservation1, only set agency_id, + and the partner_id should be the agency itself. + """ + # ARRANGE + self.create_sale_channel_scenario() + + # ACT + folio1 = self.env["pms.folio"].create( + { + "agency_id": self.agency1.id, + "pms_property_id": self.pms_property1.id, + } + ) + + reservation1 = self.env["pms.reservation"].create( + { "checkin": fields.date.today(), "checkout": fields.date.today() + datetime.timedelta(days=1), - "room_type_id": self.room_type_double.id, - "partner_id": self.env.ref("base.res_partner_12").id, - "pms_property_id": self.property.id, + "folio_id": folio1.id, } ) + # ASSERT self.assertEqual( - r1.priority, - r1.folio_id.max_reservation_prior, - "The max. reservation priority on the whole folio is incorrect", + reservation1.agency_id, folio1.partner_id, "Agency has to be the partner" ) + # TestCases: Priority + + def test_compute_folio_priority(self): + """ + Check the priority of a folio based on its reservations + #TODO: Commented test waiting to redefine the priority calculation + """ + # reservation1 = self.env["pms.reservation"].create( + # { + # "checkin": fields.date.today(), + # "checkout": fields.date.today() + datetime.timedelta(days=1), + # "room_type_id": self.room_type_double.id, + # "partner_id": self.env.ref("base.res_partner_12").id, + # "pms_property_id": self.property.id, + # } + # ) + # reservation1.allowed_checkin = False + + # self.env["pms.reservation"].create( + # { + # "folio_id": reservation1.folio_id.id, + # "checkin": fields.date.today(), + # "checkout": fields.date.today() + datetime.timedelta(days=1), + # "room_type_id": self.room_type_double.id, + # "partner_id": self.env.ref("base.res_partner_12").id, + # "pms_property_id": self.property.id, + # } + # ) + + # self.assertEqual( + # reservation1.priority, + # reservation1.folio_id.max_reservation_prior, + # "The max. reservation priority on the whole folio is incorrect", + # ) + + # TestCases: Payments + @freeze_time("1980-11-01") def test_full_pay_folio(self): - # TEST CASE - # Folio is paid after execute - # + """ + After making the payment of a folio for the entire amount, + check that there is nothing pending. + ----- + We create a reservation (autocalculates the amounts) and + then make the payment using the do_payment method of the folio, + directly indicating the pending amount on the folio of the newly + created reservation + """ # ARRANGE - r_test = self.env["pms.reservation"].create( + self.create_configuration_accounting_scenario() + reservation1 = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property_demo.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=1), "adults": 2, "partner_id": self.env.ref("base.res_partner_12").id, - "room_type_id": self.room_type_double.id, + "room_type_id": self.demo_room_type_double.id, } ) + + # ACTION self.env["pms.folio"].do_payment( - self.env["account.journal"].browse( - r_test.folio_id.pms_property_id._get_payment_methods().ids[0] + journal=self.env["account.journal"].browse( + reservation1.folio_id.pms_property_id._get_payment_methods().ids[0] ), - self.env["account.journal"] - .browse(r_test.folio_id.pms_property_id._get_payment_methods().ids[0]) + receivable_account=self.env["account.journal"] + .browse(reservation1.folio_id.pms_property_id._get_payment_methods().ids[0]) .suspense_account_id, - self.env.user, - r_test.folio_id.pending_amount, - r_test.folio_id, - partner=r_test.partner_id, + user=self.env.user, + amount=reservation1.folio_id.pending_amount, + folio=reservation1.folio_id, + partner=reservation1.partner_id, date=fields.date.today(), ) - self.assertFalse(r_test.folio_id.pending_amount) + # ASSERT + self.assertFalse( + reservation1.folio_id.pending_amount, + "The pending amount of a folio paid in full has not been zero", + ) + + @freeze_time("1980-11-01") def test_partial_pay_folio(self): - # TEST CASE - # Folio is partially paid after execute - # + """ + After making the payment of a folio for the partial amount, + We check that the pending amount is the one that corresponds to it. + ----- + We create a reservation (autocalculates the amounts) and + then make the payment using the do_payment method of the folio, + directly indicating the pending amount on the folio MINUS 1$ + of the newly created reservation + """ # ARRANGE + self.create_configuration_accounting_scenario() left_to_pay = 1 - r_test = self.env["pms.reservation"].create( + reservation1 = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property_demo.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=1), "adults": 2, "partner_id": self.env.ref("base.res_partner_12").id, - "room_type_id": self.room_type_double.id, + "room_type_id": self.demo_room_type_double.id, } ) + + # ACTION self.env["pms.folio"].do_payment( - self.env["account.journal"].browse( - r_test.folio_id.pms_property_id._get_payment_methods().ids[0] + journal=self.env["account.journal"].browse( + reservation1.folio_id.pms_property_id._get_payment_methods().ids[0] ), - self.env["account.journal"] - .browse(r_test.folio_id.pms_property_id._get_payment_methods().ids[0]) + receivable_account=self.env["account.journal"] + .browse(reservation1.folio_id.pms_property_id._get_payment_methods().ids[0]) .suspense_account_id, - self.env.user, - r_test.folio_id.pending_amount - left_to_pay, - r_test.folio_id, - partner=r_test.partner_id, + user=self.env.user, + amount=reservation1.folio_id.pending_amount - left_to_pay, + folio=reservation1.folio_id, + partner=reservation1.partner_id, date=fields.date.today(), ) - self.assertEqual(r_test.folio_id.pending_amount, left_to_pay) - def test_closure_reason_property(self): + # ASSERT + self.assertEqual( + reservation1.folio_id.pending_amount, + left_to_pay, + "The pending amount on a partially paid folio it \ + does not correspond to the amount that it should", + ) + + # TestCases: Property Consistencies + + def test_folio_closure_reason_consistency_properties(self): + """ + Check the multioproperty consistencia between + clousure reasons and folios + ------- + create multiproperty scenario (3 properties in total) and + a new clousure reason in pms_property1 and pms_property2, then, create + a new folio in property3 and try to set the clousure_reason + waiting a error property consistency. + """ + # ARRANGE self.create_multiproperty_scenario() cl_reason = self.env["room.closure.reason"].create( { "name": "closure_reason_test", "pms_property_ids": [ - (4, self.property1.id), - (4, self.property2.id), + (4, self.pms_property1.id), + (4, self.pms_property2.id), ], } ) - with self.assertRaises(UserError): + # ACTION & ASSERT + with self.assertRaises( + UserError, + msg="Folio created with clousure_reason_id with properties inconsistence", + ): self.env["pms.folio"].create( { - "pms_property_id": self.property3.id, + "pms_property_id": self.pms_property3.id, "closure_reason_id": cl_reason.id, } ) - - def _test_compute_currency(self): - self.currency1 = self.env["res.currency"].create( - { - "name": "currency1", - "symbol": "C", - } - ) - self.pricelist = self.env["product.pricelist"].create( - { - "name": "pricelist 1", - "pms_property_ids": [ - (4, self.property.id), - ], - "currency_id": self.currency1.id, - } - ) - self.reservation1 = self.env["pms.reservation"].create( - { - "pms_property_id": self.property.id, - "checkin": datetime.datetime.now(), - "checkout": datetime.datetime.now() + datetime.timedelta(days=1), - "partner_id": self.env.ref("base.res_partner_12").id, - "pricelist_id": self.pricelist.id, - } - ) - self.assertEqual( - self.currency1.id, - self.reservation1.folio_id.currency_id.id, - "Currency must match", - ) From 950b7846d30abe7e079886cf4b50e9c9bfb6de23 Mon Sep 17 00:00:00 2001 From: Dario Lodeiros Date: Tue, 15 Jun 2021 23:12:14 +0200 Subject: [PATCH 04/23] [FIX] compute commission percent --- pms/models/pms_reservation.py | 81 +++++++++++++++++++++++------------ pms/tests/test_pms_folio.py | 6 +-- 2 files changed, 57 insertions(+), 30 deletions(-) diff --git a/pms/models/pms_reservation.py b/pms/models/pms_reservation.py index d423b0ed1..6eecc4195 100644 --- a/pms/models/pms_reservation.py +++ b/pms/models/pms_reservation.py @@ -376,16 +376,18 @@ class PmsReservation(models.Model): checkin = fields.Date( string="Check In", help="It is the checkin date of the reservation, ", - required=True, - default=lambda self: self._get_default_checkin(), + compute="_compute_checkin", + readonly=False, + store=True, copy=False, tracking=True, ) checkout = fields.Date( string="Check Out", help="It is the checkout date of the reservation, ", - required=True, - default=lambda self: self._get_default_checkout(), + compute="_compute_checkout", + readonly=False, + store=True, copy=False, tracking=True, ) @@ -918,6 +920,53 @@ class PmsReservation(models.Model): for reservation in self: reservation.access_url = "/my/reservations/%s" % (reservation.id) + @api.depends("reservation_line_ids") + def _compute_checkin(self): + """ + Allows to calculate the checkin by default or when the create + specifically indicates the lines of the reservation + """ + for record in self: + if record.reservation_line_ids: + checkin_line_date = min(record.reservation_line_ids.mapped("date")) + # check if the checkin was created directly as reservation_line_id: + if checkin_line_date != record.checkin: + record.checkin = checkin_line_date + elif not record.checkin: + # default checkout other folio reservations or today + if len(record.folio_id.reservation_ids) > 1: + record.checkin = record.folio_id.reservation_ids[0].checkin + else: + record.checkin = fields.date.today() + + @api.depends("reservation_line_ids", "checkin") + def _compute_checkout(self): + """ + Allows to calculate the checkout by default or when the create + specifically indicates the lines of the reservation + """ + for record in self: + if record.reservation_line_ids: + checkout_line_date = max( + record.reservation_line_ids.mapped("date") + ) + datetime.timedelta(days=1) + # check if the checkout was created directly as reservation_line_id: + if checkout_line_date != record.checkout: + record.checkout = checkout_line_date + # default checkout if checkin is set + elif record.checkin and not record.checkout: + if len(record.folio_id.reservation_ids) > 1: + record.checkin = record.folio_id.reservation_ids[0].checkout + else: + record.checkout = record.checkin + datetime.timedelta(days=1) + elif not record.checkout: + record.checkout = False + # date checking + if record.checkin and record.checkout and record.checkin >= record.checkout: + raise UserError( + _("The checkout date must be greater than the checkin date") + ) + @api.depends("pms_property_id", "folio_id") def _compute_arrival_hour(self): for record in self: @@ -969,7 +1018,7 @@ class PmsReservation(models.Model): for reservation in self: if reservation.commission_percent > 0: reservation.commission_amount = ( - reservation.price_total * reservation.commission_percent + reservation.price_total * reservation.commission_percent / 100 ) else: reservation.commission_amount = 0 @@ -1178,28 +1227,6 @@ class PmsReservation(models.Model): recs = self.search([]).filtered(lambda x: x.checkin_partner_pending_count > 0) return [("id", "in", [x.id for x in recs])] if recs else [] - def _get_default_checkin(self): - folio = False - if "folio_id" in self._context: - folio = self.env["pms.folio"].search( - [("id", "=", self._context["folio_id"])] - ) - if folio and folio.reservation_ids: - return folio.reservation_ids[0].checkin - else: - return fields.Date.today() - - def _get_default_checkout(self): - folio = False - if "folio_id" in self._context: - folio = self.env["pms.folio"].search( - [("id", "=", self._context["folio_id"])] - ) - if folio and folio.reservation_ids: - return folio.reservation_ids[0].checkout - else: - return fields.Date.today() + datetime.timedelta(1) - def _get_default_segmentation(self): folio = False segmentation_ids = False diff --git a/pms/tests/test_pms_folio.py b/pms/tests/test_pms_folio.py index 9fd2b3307..a2a68af27 100644 --- a/pms/tests/test_pms_folio.py +++ b/pms/tests/test_pms_folio.py @@ -158,8 +158,8 @@ class TestPmsFolio(TestPms): self.env["pms.reservation"].create( { - "checkin": fields.date.today(), - "checkout": fields.date.today() + datetime.timedelta(days=3), + "folio_id": folio1.id, + "room_type_id": self.room_type_double.id, "reservation_line_ids": [ ( 0, @@ -186,7 +186,6 @@ class TestPmsFolio(TestPms): }, ), ], - "folio_id": folio1.id, } ) # ASSERT @@ -215,6 +214,7 @@ class TestPmsFolio(TestPms): reservation1 = self.env["pms.reservation"].create( { + "room_type_id": self.demo_room_type_double.id, "checkin": fields.date.today(), "checkout": fields.date.today() + datetime.timedelta(days=1), "folio_id": folio1.id, From 1d2b6c154bce4371de59fcee026c85831b5cfb3c Mon Sep 17 00:00:00 2001 From: Dario Lodeiros Date: Tue, 15 Jun 2021 23:14:48 +0200 Subject: [PATCH 05/23] [FIX] test folio room_type assign --- pms/tests/test_pms_folio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pms/tests/test_pms_folio.py b/pms/tests/test_pms_folio.py index a2a68af27..3c823dff2 100644 --- a/pms/tests/test_pms_folio.py +++ b/pms/tests/test_pms_folio.py @@ -214,7 +214,7 @@ class TestPmsFolio(TestPms): reservation1 = self.env["pms.reservation"].create( { - "room_type_id": self.demo_room_type_double.id, + "room_type_id": self.room_type_double.id, "checkin": fields.date.today(), "checkout": fields.date.today() + datetime.timedelta(days=1), "folio_id": folio1.id, From e7d7cf131febf8d297993e5f07b726484ac2d1f2 Mon Sep 17 00:00:00 2001 From: Dario Lodeiros Date: Tue, 15 Jun 2021 23:15:39 +0200 Subject: [PATCH 06/23] [FIX] test folio compare apples and oranges --- pms/tests/test_pms_folio_sale_line.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pms/tests/test_pms_folio_sale_line.py b/pms/tests/test_pms_folio_sale_line.py index a3ce98f0f..bb549cecd 100644 --- a/pms/tests/test_pms_folio_sale_line.py +++ b/pms/tests/test_pms_folio_sale_line.py @@ -1197,7 +1197,7 @@ class TestPmsFolioSaleLine(TestPms): # ACT r_test.service_ids.filtered( - lambda x: x.id == extra_service + lambda x: x.id == extra_service.id ).service_line_ids.price_unit = 50 r_test.service_ids.service_line_ids.flush() From 455f299f03919d264f43a8a9fdbe14fe396f3fac Mon Sep 17 00:00:00 2001 From: Dario Lodeiros Date: Tue, 15 Jun 2021 23:21:13 +0200 Subject: [PATCH 07/23] [RFC] test folio sale line summarize scenario using common --- pms/tests/test_pms_folio_sale_line.py | 79 +++++++++++---------------- 1 file changed, 32 insertions(+), 47 deletions(-) diff --git a/pms/tests/test_pms_folio_sale_line.py b/pms/tests/test_pms_folio_sale_line.py index bb549cecd..a342aab9f 100644 --- a/pms/tests/test_pms_folio_sale_line.py +++ b/pms/tests/test_pms_folio_sale_line.py @@ -5,40 +5,25 @@ from .common import TestPms class TestPmsFolioSaleLine(TestPms): def setUp(self): + """ + - common + room_type_avalability_plan + """ super().setUp() - # create a room type availability - self.room_type_availability = self.env["pms.availability.plan"].create( - {"name": "Availability plan for TEST"} - ) - - # create a property - self.property = self.env["pms.property"].create( - { - "name": "MY PMS TEST", - "company_id": self.env.ref("base.main_company").id, - "default_pricelist_id": self.env.ref("product.list0").id, - } - ) - - # create room type class - self.room_type_class = self.env["pms.room.type.class"].create( - {"name": "Room", "default_code": "ROOM"} - ) # create room type self.room_type_double = self.env["pms.room.type"].create( { - "pms_property_ids": [self.property.id], + "pms_property_ids": [self.pms_property1.id], "name": "Double Test", "default_code": "DBL_Test", - "class_id": self.room_type_class.id, + "class_id": self.room_type_class1.id, "price": 25, } ) # create room self.room1 = self.env["pms.room"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "name": "Double 101", "room_type_id": self.room_type_double.id, "capacity": 2, @@ -58,7 +43,7 @@ class TestPmsFolioSaleLine(TestPms): # ACT r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -83,7 +68,7 @@ class TestPmsFolioSaleLine(TestPms): expected_sale_lines = 2 r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -113,7 +98,7 @@ class TestPmsFolioSaleLine(TestPms): expected_sale_lines = 2 r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -143,7 +128,7 @@ class TestPmsFolioSaleLine(TestPms): expected_sale_lines = 2 r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -174,7 +159,7 @@ class TestPmsFolioSaleLine(TestPms): expected_sale_lines = 1 r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -205,7 +190,7 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -239,7 +224,7 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -274,7 +259,7 @@ class TestPmsFolioSaleLine(TestPms): # ARRANGE r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -337,7 +322,7 @@ class TestPmsFolioSaleLine(TestPms): # ACT r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -395,7 +380,7 @@ class TestPmsFolioSaleLine(TestPms): ) r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -454,7 +439,7 @@ class TestPmsFolioSaleLine(TestPms): ) r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -516,7 +501,7 @@ class TestPmsFolioSaleLine(TestPms): ) r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -578,7 +563,7 @@ class TestPmsFolioSaleLine(TestPms): ) r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -638,7 +623,7 @@ class TestPmsFolioSaleLine(TestPms): ) r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -702,7 +687,7 @@ class TestPmsFolioSaleLine(TestPms): r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -768,7 +753,7 @@ class TestPmsFolioSaleLine(TestPms): r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -816,7 +801,7 @@ class TestPmsFolioSaleLine(TestPms): ) r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -865,7 +850,7 @@ class TestPmsFolioSaleLine(TestPms): ) r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -916,7 +901,7 @@ class TestPmsFolioSaleLine(TestPms): ) r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -968,7 +953,7 @@ class TestPmsFolioSaleLine(TestPms): ) r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -1021,7 +1006,7 @@ class TestPmsFolioSaleLine(TestPms): ) r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -1072,7 +1057,7 @@ class TestPmsFolioSaleLine(TestPms): ) r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -1123,7 +1108,7 @@ class TestPmsFolioSaleLine(TestPms): ) r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -1175,7 +1160,7 @@ class TestPmsFolioSaleLine(TestPms): ) r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -1226,7 +1211,7 @@ class TestPmsFolioSaleLine(TestPms): ) r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, @@ -1278,7 +1263,7 @@ class TestPmsFolioSaleLine(TestPms): r_test = self.env["pms.reservation"].create( { - "pms_property_id": self.property.id, + "pms_property_id": self.pms_property1.id, "checkin": datetime.datetime.now(), "checkout": datetime.datetime.now() + datetime.timedelta(days=3), "adults": 2, From 686f37e966e30e76cee2da4db1b7d711c4583645 Mon Sep 17 00:00:00 2001 From: Dario Lodeiros Date: Tue, 15 Jun 2021 23:31:15 +0200 Subject: [PATCH 08/23] [RFC] testing group reservation lines in folio sale line --- pms/tests/test_pms_folio_sale_line.py | 45 ++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/pms/tests/test_pms_folio_sale_line.py b/pms/tests/test_pms_folio_sale_line.py index a342aab9f..500031caa 100644 --- a/pms/tests/test_pms_folio_sale_line.py +++ b/pms/tests/test_pms_folio_sale_line.py @@ -1,5 +1,7 @@ import datetime +from odoo import fields + from .common import TestPms @@ -32,11 +34,13 @@ class TestPmsFolioSaleLine(TestPms): # RESERVATION LINES def test_comp_fsl_rooms_all_same_group(self): - # TEST CASE - # 2-night reservation and same price, discount & cancel_discount for - # all nights - # should generate just 1 reservation sale line - + """ + check the grouping of the reservation lines on the sale line folio + when the price, discount match- + ------------ + reservation with 3 nights with the same price, + should generate just 1 reservation sale line + """ # ARRANGE expected_sale_lines = 1 @@ -44,8 +48,35 @@ class TestPmsFolioSaleLine(TestPms): r_test = self.env["pms.reservation"].create( { "pms_property_id": self.pms_property1.id, - "checkin": datetime.datetime.now(), - "checkout": datetime.datetime.now() + datetime.timedelta(days=3), + "reservation_line_ids": [ + ( + 0, + False, + { + "date": fields.date.today(), + "price": 20, + "discount": 10, + }, + ), + ( + 0, + False, + { + "date": fields.date.today() + datetime.timedelta(days=1), + "price": 20, + "discount": 10, + }, + ), + ( + 0, + False, + { + "date": fields.date.today() + datetime.timedelta(days=2), + "price": 20, + "discount": 10, + }, + ), + ], "adults": 2, "room_type_id": self.room_type_double.id, "partner_id": self.env.ref("base.res_partner_12").id, From 843c84c581005b1f776ff6aa104cb2ae78595277 Mon Sep 17 00:00:00 2001 From: Dario Lodeiros Date: Wed, 16 Jun 2021 00:05:53 +0200 Subject: [PATCH 09/23] [ADD] constrain consecutive reservation dates --- pms/models/pms_reservation.py | 14 ++++++ pms/tests/test_pms_reservation.py | 78 +++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/pms/models/pms_reservation.py b/pms/models/pms_reservation.py index 6eecc4195..c123e95a5 100644 --- a/pms/models/pms_reservation.py +++ b/pms/models/pms_reservation.py @@ -1255,6 +1255,20 @@ class PmsReservation(models.Model): ) ) + @api.constrains("reservation_line_ids") + def check_consecutive_dates(self): + """ + simply convert date objects to integers using the .toordinal() method + of datetime objects. The difference between the maximum and minimum value + of the set of ordinal dates is one more than the length of the set + """ + for record in self: + if record.reservation_line_ids and len(record.reservation_line_ids) > 1: + dates = record.reservation_line_ids.mapped("date") + date_ints = {d.toordinal() for d in dates} + if not (max(date_ints) - min(date_ints) == len(date_ints) - 1): + raise ValidationError(_("Reservation dates should be consecutives")) + # @api.constrains("checkin_partner_ids", "adults") # def _max_checkin_partner_ids(self): # for record in self: diff --git a/pms/tests/test_pms_reservation.py b/pms/tests/test_pms_reservation.py index c54c509da..42466fc05 100644 --- a/pms/tests/test_pms_reservation.py +++ b/pms/tests/test_pms_reservation.py @@ -150,6 +150,84 @@ class TestPmsReservations(common.SavepointCase): } ) + @freeze_time("1980-11-01") + def test_reservation_dates_not_consecutive(self): + """ + Check the constrain if not consecutive dates + ---------------- + Create correct reservation set 3 reservation lines consecutives (nights) + """ + # ARRANGE + self.create_common_scenario() + customer = self.env.ref("base.res_partner_12") + today = fields.date.today() + tomorrow = fields.date.today() + datetime.timedelta(days=1) + three_days_later = fields.date.today() + datetime.timedelta(days=3) + + # ACT & ASSERT + with self.assertRaises( + ValidationError, + msg="Error, it has been allowed to create a reservation with non-consecutive days", + ): + self.env["pms.reservation"].create( + { + "room_type_id": self.room_type_double.id, + "partner_id": customer.id, + "pms_property_id": self.property.id, + "reservation_line_ids": [ + (0, False, {"date": today}), + (0, False, {"date": tomorrow}), + (0, False, {"date": three_days_later}), + ], + } + ) + + @freeze_time("1980-11-01") + def test_reservation_dates_compute_checkin_out(self): + """ + Check the reservation creation with specific reservation lines + anc compute checkin checkout + ---------------- + Create reservation with correct reservation lines and check + the checkin and checkout fields. Take into account that the + checkout of the reservation must be the day after the last night + (view checkout assertEqual) + """ + # ARRANGE + self.create_common_scenario() + customer = self.env.ref("base.res_partner_12") + today = fields.date.today() + tomorrow = fields.date.today() + datetime.timedelta(days=1) + two_days_later = fields.date.today() + datetime.timedelta(days=2) + + # ACT + reservation = self.env["pms.reservation"].create( + { + "room_type_id": self.room_type_double.id, + "partner_id": customer.id, + "pms_property_id": self.property.id, + "reservation_line_ids": [ + (0, False, {"date": today}), + (0, False, {"date": tomorrow}), + (0, False, {"date": two_days_later}), + ], + } + ) + + # ASSERT + self.assertEqual( + reservation.checkin, + today, + "The calculated checkin of the reservation does \ + not correspond to the first day indicated in the dates", + ) + self.assertEqual( + reservation.checkout, + two_days_later + datetime.timedelta(days=1), + "The calculated checkout of the reservation does \ + not correspond to the last day indicated in the dates", + ) + @freeze_time("1980-11-01") def test_create_reservation_start_date(self): # TEST CASE From 6fb1d68fccdb3648d0a40448524c942f797d454a Mon Sep 17 00:00:00 2001 From: Dario Lodeiros Date: Wed, 16 Jun 2021 00:23:58 +0200 Subject: [PATCH 10/23] [RFC] test folio payment freeze_time magic line --- pms/tests/test_pms_folio.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pms/tests/test_pms_folio.py b/pms/tests/test_pms_folio.py index 3c823dff2..2fe41c34e 100644 --- a/pms/tests/test_pms_folio.py +++ b/pms/tests/test_pms_folio.py @@ -262,7 +262,7 @@ class TestPmsFolio(TestPms): # ) # TestCases: Payments - @freeze_time("1980-11-01") + @freeze_time("2000-02-02") def test_full_pay_folio(self): """ After making the payment of a folio for the entire amount, @@ -307,7 +307,7 @@ class TestPmsFolio(TestPms): "The pending amount of a folio paid in full has not been zero", ) - @freeze_time("1980-11-01") + @freeze_time("2000-02-02") def test_partial_pay_folio(self): """ After making the payment of a folio for the partial amount, From 01d09c9c471a2d9b3ebb3d967e59f3edba8e5b80 Mon Sep 17 00:00:00 2001 From: miguelpadin Date: Fri, 11 Jun 2021 19:19:42 +0200 Subject: [PATCH 11/23] [IMP] pms_l10n_es: spanish police travellers report sending --- pms_l10n_es/__manifest__.py | 7 +- pms_l10n_es/models/__init__.py | 1 + .../pms_log_institution_traveller_report.py | 18 ++ pms_l10n_es/models/pms_property.py | 93 ++++-- pms_l10n_es/security/ir.model.access.csv | 1 + ...log_institution_traveller_report_views.xml | 55 ++++ pms_l10n_es/views/pms_property_views.xml | 2 +- pms_l10n_es/wizards/traveller_report.py | 264 ++++++++++++++++-- pms_l10n_es/wizards/traveller_report.xml | 6 +- 9 files changed, 394 insertions(+), 53 deletions(-) create mode 100644 pms_l10n_es/models/pms_log_institution_traveller_report.py create mode 100644 pms_l10n_es/views/pms_log_institution_traveller_report_views.xml diff --git a/pms_l10n_es/__manifest__.py b/pms_l10n_es/__manifest__.py index 1ff4d1fc9..089287797 100644 --- a/pms_l10n_es/__manifest__.py +++ b/pms_l10n_es/__manifest__.py @@ -24,13 +24,14 @@ ], }, "data": [ - "data/cron_jobs.xml", - "data/queue_data.xml", - "data/queue_job_function_data.xml", + # "data/cron_jobs.xml", + # "data/queue_data.xml", + # "data/queue_job_function_data.xml", "security/ir.model.access.csv", "views/pms_checkin_partner_views.xml", "views/pms_property_views.xml", "views/res_partner_views.xml", + "views/pms_log_institution_traveller_report_views.xml", "wizards/traveller_report.xml", ], "installable": True, diff --git a/pms_l10n_es/models/__init__.py b/pms_l10n_es/models/__init__.py index ebd8614e3..c23c7b1fd 100644 --- a/pms_l10n_es/models/__init__.py +++ b/pms_l10n_es/models/__init__.py @@ -1,3 +1,4 @@ from . import res_partner from . import pms_checkin_partner from . import pms_property +from . import pms_log_institution_traveller_report diff --git a/pms_l10n_es/models/pms_log_institution_traveller_report.py b/pms_l10n_es/models/pms_log_institution_traveller_report.py new file mode 100644 index 000000000..857edded6 --- /dev/null +++ b/pms_l10n_es/models/pms_log_institution_traveller_report.py @@ -0,0 +1,18 @@ +from odoo import fields, models + + +class PmsLogInstitutionTravellerReport(models.Model): + _name = "pms.log.institution.traveller.report" + _description = "Report of daily sending files of travellers to institutions." + + date = fields.Datetime( + string="Date and time", + default=fields.Datetime.now, + ) + txtIncidenciesFromInstitution = fields.Text( + string="Detailed message", + ) + fileIncidenciesFromInstitution = fields.Binary( + string="Detailed file", + ) + txt_filename = fields.Text() diff --git a/pms_l10n_es/models/pms_property.py b/pms_l10n_es/models/pms_property.py index 9a0fba218..e34f02843 100644 --- a/pms_l10n_es/models/pms_property.py +++ b/pms_l10n_es/models/pms_property.py @@ -14,7 +14,7 @@ class PmsProperty(models.Model): institution = fields.Selection( [ ("guardia_civil", "Guardia Civil"), - ("policia_nacional", "Policía Nacional (soon)"), + ("policia_nacional", "Policía Nacional"), ("ertxaintxa", "Ertxaintxa (soon)"), ("mossos", "Mossos_d'esquadra (soon)"), ], @@ -24,7 +24,6 @@ class PmsProperty(models.Model): ) institution_property_id = fields.Char( string="Institution property id", - size=10, help="Id provided by institution to send data from property.", ) institution_user = fields.Char( @@ -35,30 +34,27 @@ class PmsProperty(models.Model): help="Password provided by institution to send the data.", ) - def test_gc_connection(self): - for pms_property in self: + def test_connection(self): + headers = { + "User-Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 " + "Build/MRA58N) AppleWebKit/537.36 (KHTML, like " + "Gecko) Chrome/90.0.4430.93 Mobile Safari/537.36", + } + for record in self: if ( - pms_property.institution == "guardia_civil" - and pms_property.institution_property_id - and pms_property.institution_user - and pms_property.institution_password + record.institution == "guardia_civil" + and record.institution_property_id + and record.institution_user + and record.institution_password ): - url = "https://hospederias.guardiacivil.es/" login_route = "/hospederias/login.do" logout_route = "/hospederias/logout.do" - - headers = { - "User-Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 " - "Build/MRA58N) AppleWebKit/537.36 (KHTML, like " - "Gecko) Chrome/90.0.4430.93 Mobile Safari/537.36", - } session = requests.session() login_payload = { - "usuario": pms_property.institution_user, - "pswd": pms_property.institution_password, + "usuario": record.institution_user, + "pswd": record.institution_password, } - # login response_login = session.post( url + login_route, @@ -66,7 +62,7 @@ class PmsProperty(models.Model): data=login_payload, verify=get_module_resource("pms_l10n_es", "static", "cert.pem"), ) - time.sleep(1) + time.sleep(0.1) # logout session.get( url + logout_route, @@ -96,3 +92,62 @@ class PmsProperty(models.Model): return message else: raise ValidationError(_("Connection could not be established")) + elif ( + record.institution == "policia_nacional" + and record.institution_property_id + and record.institution_user + and record.institution_password + ): + url = "https://webpol.policia.es/e-hotel" + pre_login_route = "/login" + login_route = "/execute_login" + home_route = "/inicio" + logout_route = "/execute_logout" + session = requests.session() + response_pre_login = session.post( + url + pre_login_route, + headers=headers, + verify=False, + ) + soup = bs(response_pre_login.text, "html.parser") + token = soup.select("input[name='_csrf']")[0]["value"] + time.sleep(0.1) + login_payload = { + "username": record.institution_user, + "password": record.institution_password, + "_csrf": token, + } + session.post( + url + login_route, + headers=headers, + data=login_payload, + verify=False, + ) + time.sleep(0.1) + response_home = session.get( + url + home_route, + headers=headers, + verify=False, + ) + soup = bs(response_home.text, "html.parser") + login_correct = soup.select("#datosUsuarioBanner") + if login_correct: + session.post( + url + logout_route, + headers=headers, + verify=False, + data={"_csrf": token}, + ) + + message = { + "type": "ir.actions.client", + "tag": "display_notification", + "params": { + "title": _("Connection Established!"), + "message": _("Connection established succesfully"), + "sticky": False, + }, + } + return message + else: + raise ValidationError(_("Connection could not be established")) diff --git a/pms_l10n_es/security/ir.model.access.csv b/pms_l10n_es/security/ir.model.access.csv index d8d1060d6..36ef563cc 100644 --- a/pms_l10n_es/security/ir.model.access.csv +++ b/pms_l10n_es/security/ir.model.access.csv @@ -1,2 +1,3 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink user_access_traveller_report_wizard,user_access_traveller_report_wizard,model_traveller_report_wizard,pms.group_pms_user,1,1,1,1 +user_access_traveller_report_logs,user_access_traveller_report_logs,model_pms_log_institution_traveller_report,pms.group_pms_user,1,1,1,1 diff --git a/pms_l10n_es/views/pms_log_institution_traveller_report_views.xml b/pms_l10n_es/views/pms_log_institution_traveller_report_views.xml new file mode 100644 index 000000000..152d1701a --- /dev/null +++ b/pms_l10n_es/views/pms_log_institution_traveller_report_views.xml @@ -0,0 +1,55 @@ + + + + pms.log.institution.traveller.report.form + pms.log.institution.traveller.report + +
+ + + + + + + + +
+
+
+ + pms.log.institution.traveller.report.tree + pms.log.institution.traveller.report + + + + + + + + + + + Log of sending files to institutions + pms.log.institution.traveller.report + tree,form + + +
diff --git a/pms_l10n_es/views/pms_property_views.xml b/pms_l10n_es/views/pms_property_views.xml index 53a3f0e34..117bc16e5 100644 --- a/pms_l10n_es/views/pms_property_views.xml +++ b/pms_l10n_es/views/pms_property_views.xml @@ -27,7 +27,7 @@