From aac22ef43fa4ec9eb40998735d6a6a0c9d06f0a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dar=C3=ADo=20Lodeiros?= Date: Sat, 1 Aug 2020 22:34:47 +0200 Subject: [PATCH] [RFC] Clean reposiroty --- call_center_report/README.rst | 6 - call_center_report/__init__.py | 21 - call_center_report/__manifest__.py | 48 - call_center_report/data/menus.xml | 11 - call_center_report/i18n/es.po | 171 - call_center_report/wizard/__init__.py | 21 - .../wizard/call_center_report.py | 348 -- .../wizard/call_center_report.xml | 41 - cash_daily_report/README.rst | 13 - cash_daily_report/__init__.py | 21 - cash_daily_report/__manifest__.py | 51 - cash_daily_report/data/cron_jobs.xml | 23 - cash_daily_report/data/menus.xml | 43 - cash_daily_report/i18n/es.po | 203 -- cash_daily_report/wizard/__init__.py | 21 - cash_daily_report/wizard/cash_daily_report.py | 307 -- .../wizard/cash_daily_report.xml | 41 - glasof_exporter/README.rst | 15 - glasof_exporter/__init__.py | 21 - glasof_exporter/__manifest__.py | 48 - glasof_exporter/data/menus.xml | 11 - glasof_exporter/wizard/__init__.py | 21 - glasof_exporter/wizard/glasof_wizard.py | 256 -- glasof_exporter/wizard/glasof_wizard.xml | 52 - hotel_calendar/README.rst | 61 - hotel_calendar/__init__.py | 4 - hotel_calendar/__manifest__.py | 42 - hotel_calendar/controllers/__init__.py | 3 - hotel_calendar/controllers/bus.py | 21 - hotel_calendar/data/menus.xml | 29 - hotel_calendar/i18n/es.po | 1383 -------- hotel_calendar/models/__init__.py | 14 - hotel_calendar/models/bus_hotel_calendar.py | 137 - hotel_calendar/models/hotel_calendar.py | 23 - .../models/hotel_calendar_management.py | 277 -- .../models/inherited_hotel_folio.py | 34 - .../models/inherited_hotel_property.py | 51 - .../models/inherited_hotel_reservation.py | 521 --- ...erited_hotel_room_type_restriction_item.py | 76 - .../inherited_product_pricelist_item.py | 122 - .../models/inherited_res_company.py | 29 - hotel_calendar/models/inherited_res_users.py | 34 - .../models/ir_actions_act_window_view.py | 10 - hotel_calendar/models/ir_ui_view.py | 10 - hotel_calendar/readme/CONFIGURE.rst | 8 - hotel_calendar/readme/CONTRIBUTORS.rst | 2 - hotel_calendar/readme/CREDITS.rst | 2 - hotel_calendar/readme/DESCRIPTION.rst | 10 - hotel_calendar/readme/INSTALL.rst | 5 - hotel_calendar/readme/ROADMAP.rst | 5 - hotel_calendar/readme/USAGE.rst | 14 - hotel_calendar/security/ir.model.access.csv | 4 - hotel_calendar/static/description/icon.png | Bin 4155 -> 0 bytes .../icon_calendar_configurator.png | Bin 5221 -> 0 bytes hotel_calendar/static/src/css/view.css | 396 --- .../calendar/hotel_calendar_controller.js | 1113 ------ .../js/views/calendar/hotel_calendar_model.js | 192 - .../views/calendar/hotel_calendar_renderer.js | 284 -- .../js/views/calendar/hotel_calendar_view.js | 179 - .../hotel_calendar_management_controller.js | 176 - .../hotel_calendar_management_model.js | 72 - .../hotel_calendar_management_renderer.js | 512 --- .../hotel_calendar_management_v_deprecated.js | 661 ---- .../hotel_calendar_management_view.js | 93 - .../static/src/js/views/constants.js | 20 - .../static/src/js/widgets/MultiCalendar.js | 398 --- hotel_calendar/static/src/lib/bootbox.js | 985 ------ .../src/lib/hcalendar/css/hcalendar.css | 537 --- .../hcalendar/css/hcalendar_management.css | 198 -- .../static/src/lib/hcalendar/js/hcalendar.js | 3126 ----------------- .../lib/hcalendar/js/hcalendar_management.js | 1147 ------ hotel_calendar/static/src/lib/moment.js | 551 --- .../xml/hotel_calendar_management_view.xml | 81 - .../src/xml/hotel_calendar_templates.xml | 378 -- .../static/src/xml/hotel_calendar_view.xml | 146 - hotel_calendar/tests/__init__.py | 2 - hotel_calendar/tests/common.py | 41 - .../tests/test_management_calendar.py | 424 --- .../tests/test_product_pricelist.py | 66 - .../tests/test_reservations_calendar.py | 289 -- hotel_calendar/views/actions.xml | 28 - hotel_calendar/views/general.xml | 32 - .../views/hotel_calendar_management_views.xml | 12 - hotel_calendar/views/hotel_calendar_views.xml | 38 - .../views/hotel_reservation_views.xml | 12 - .../views/inherited_hotel_property_views.xml | 31 - .../views/inherited_hotel_room_type_views.xml | 14 - .../views/inherited_hotel_room_views.xml | 14 - .../views/inherited_res_company_views.xml | 43 - .../views/inherited_res_users_views.xml | 20 - hotel_calendar_channel_connector/README.md | 12 - hotel_calendar_channel_connector/__init__.py | 3 - .../__manifest__.py | 33 - hotel_calendar_channel_connector/i18n/es.po | 88 - .../models/__init__.py | 6 - .../models/inherited_bus_hotel_calendar.py | 80 - .../inherited_hotel_calendar_management.py | 107 - .../models/inherited_hotel_reservation.py | 58 - .../inherited_hotel_room_type_availability.py | 50 - .../readme/CONTRIBUTORS.rst | 1 - .../readme/DESCRIPTION.rst | 7 - .../readme/ROADMAP.rst | 0 .../readme/USAGE.rst | 1 - .../static/description/eiqui_logo.png | Bin 6240 -> 0 bytes .../static/description/index.html | 22 - .../static/sfx/book_cancelled.mp3 | Bin 10152 -> 0 bytes .../static/sfx/book_new.mp3 | Bin 10176 -> 0 bytes .../static/src/css/view.css | 52 - .../src/js/views/hotel_calendar_controller.js | 102 - .../hotel_calendar_management_controller.js | 47 - .../hotel_calendar_management_renderer.js | 28 - .../src/js/views/hotel_calendar_renderer.js | 66 - .../src/xml/hotel_calendar_templates.xml | 25 - .../static/src/xml/hotel_calendar_view.xml | 35 - .../tests/__init__.py | 3 - .../tests/test_folio.py | 11 - .../views/actions.xml | 23 - .../views/general.xml | 15 - .../views/hotel_reservation.xml | 38 - hotel_channel_connector/README.md | 14 - hotel_channel_connector/__init__.py | 6 - hotel_channel_connector/__manifest__.py | 51 - .../components/__init__.py | 10 - .../components/backend_adapter.py | 126 - hotel_channel_connector/components/binder.py | 19 - hotel_channel_connector/components/core.py | 28 - hotel_channel_connector/components/deleter.py | 10 - .../components/exporter.py | 10 - .../components/importer.py | 10 - hotel_channel_connector/components/mapper.py | 16 - hotel_channel_connector/data/cron_jobs.xml | 17 - .../data/email_availability_watchdog.xml | 13 - hotel_channel_connector/data/menus.xml | 30 - hotel_channel_connector/i18n/es.po | 2805 --------------- hotel_channel_connector/models/__init__.py | 18 - .../models/channel_backend/__init__.py | 4 - .../models/channel_backend/common.py | 299 -- .../models/channel_binding/__init__.py | 4 - .../models/channel_binding/common.py | 23 - .../models/channel_ota_info/__init__.py | 5 - .../models/channel_ota_info/common.py | 28 - .../models/channel_ota_info/importer.py | 20 - .../models/hotel_channel_connector_issue.py | 63 - .../models/hotel_reservation/__init__.py | 6 - .../models/hotel_reservation/common.py | 328 -- .../models/hotel_reservation/exporter.py | 24 - .../models/hotel_reservation/importer.py | 22 - .../models/hotel_room_type/__init__.py | 7 - .../models/hotel_room_type/common.py | 227 -- .../models/hotel_room_type/deleter.py | 16 - .../models/hotel_room_type/exporter.py | 20 - .../models/hotel_room_type/importer.py | 16 - .../hotel_room_type_availability/__init__.py | 6 - .../hotel_room_type_availability/common.py | 327 -- .../hotel_room_type_availability/exporter.py | 15 - .../hotel_room_type_availability/importer.py | 16 - .../hotel_room_type_restriction/__init__.py | 7 - .../hotel_room_type_restriction/common.py | 141 - .../hotel_room_type_restriction/deleter.py | 16 - .../hotel_room_type_restriction/exporter.py | 20 - .../hotel_room_type_restriction/importer.py | 16 - .../__init__.py | 6 - .../common.py | 101 - .../exporter.py | 20 - .../importer.py | 21 - ...inherited_hotel_board_service_room_type.py | 16 - .../models/inherited_hotel_folio.py | 91 - .../models/inherited_hotel_room.py | 129 - .../models/inherited_hotel_room_type_class.py | 25 - .../models/product_pricelist/__init__.py | 7 - .../models/product_pricelist/common.py | 189 - .../models/product_pricelist/deleter.py | 16 - .../models/product_pricelist/exporter.py | 28 - .../models/product_pricelist/importer.py | 16 - .../models/product_pricelist_item/__init__.py | 6 - .../models/product_pricelist_item/common.py | 102 - .../models/product_pricelist_item/exporter.py | 16 - .../models/product_pricelist_item/importer.py | 20 - .../readme/CONTRIBUTORS.rst | 1 - .../readme/DESCRIPTION.rst | 6 - hotel_channel_connector/readme/ROADMAP.rst | 0 hotel_channel_connector/readme/USAGE.rst | 1 - .../security/ir.model.access.csv | 34 - .../security/wubook_security.xml | 21 - .../static/description/eiqui_logo.png | Bin 6240 -> 0 bytes .../static/description/index.html | 22 - hotel_channel_connector/tests/__init__.py | 2 - hotel_channel_connector/tests/common.py | 310 -- .../test_hotel_calendar_management_model.py | 152 - .../tests/test_hotel_folio_model.py | 125 - .../tests/test_hotel_reservation_model.py | 181 - .../tests/test_hotel_virtual_room_model.py | 73 - .../test_product_pricelist_item_model.py | 75 - .../tests/test_product_pricelist_model.py | 70 - .../tests/test_res_partner_model.py | 84 - ...test_reservation_restriction_item_model.py | 45 - .../test_reservation_restriction_model.py | 99 - .../test_virtual_room_availability_model.py | 43 - hotel_channel_connector/tests/test_wubook.py | 608 ---- .../tests/test_wubook_channel_info_model.py | 38 - .../tests/test_wubook_issue_model.py | 57 - .../views/channel_connector_backend_views.xml | 212 -- .../views/channel_hotel_reservation_views.xml | 30 - ...nel_hotel_room_type_availability_views.xml | 37 - ...hotel_room_type_restriction_item_views.xml | 30 - ...nnel_hotel_room_type_restriction_views.xml | 37 - .../views/channel_hotel_room_type_views.xml | 69 - .../views/channel_ota_info_views.xml | 36 - .../channel_product_pricelist_item_views.xml | 27 - .../views/channel_product_pricelist_views.xml | 39 - .../hotel_channel_connector_issue_views.xml | 85 - .../hotel_room_type_availability_views.xml | 66 - .../views/inherited_hotel_folio_views.xml | 33 - .../inherited_hotel_reservation_views.xml | 118 - ...hotel_room_type_restriction_item_views.xml | 24 - ...ited_hotel_room_type_restriction_views.xml | 46 - .../views/inherited_hotel_room_type_views.xml | 59 - ...inherited_product_pricelist_item_views.xml | 25 - .../inherited_product_pricelist_views.xml | 46 - hotel_channel_connector/wizard/__init__.py | 4 - .../wizard/inherited_massive_changes.py | 82 - .../wizard/inherited_massive_changes.xml | 30 - ...nherited_massive_price_reservation_days.py | 23 - hotel_channel_connector_wubook/README.md | 13 - hotel_channel_connector_wubook/__init__.py | 6 - .../__manifest__.py | 32 - .../components/__init__.py | 4 - .../components/backend_adapter.py | 569 --- .../controllers/__init__.py | 4 - .../controllers/main.py | 77 - .../data/cron_jobs.xml | 27 - .../data/records.xml | 44 - .../data/sequences.xml | 11 - hotel_channel_connector_wubook/i18n/es.po | 341 -- .../models/__init__.py | 15 - .../models/channel_backend/__init__.py | 4 - .../models/channel_backend/common.py | 50 - .../models/channel_ota_info/__init__.py | 5 - .../models/channel_ota_info/common.py | 23 - .../models/channel_ota_info/importer.py | 84 - .../models/hotel_reservation/__init__.py | 6 - .../models/hotel_reservation/common.py | 119 - .../models/hotel_reservation/exporter.py | 48 - .../models/hotel_reservation/importer.py | 689 ---- .../models/hotel_room_type/__init__.py | 7 - .../models/hotel_room_type/common.py | 40 - .../models/hotel_room_type/deleter.py | 22 - .../models/hotel_room_type/exporter.py | 90 - .../models/hotel_room_type/importer.py | 70 - .../hotel_room_type_availability/__init__.py | 6 - .../hotel_room_type_availability/common.py | 20 - .../hotel_room_type_availability/exporter.py | 72 - .../hotel_room_type_availability/importer.py | 118 - .../hotel_room_type_restriction/__init__.py | 7 - .../hotel_room_type_restriction/common.py | 22 - .../hotel_room_type_restriction/deleter.py | 22 - .../hotel_room_type_restriction/exporter.py | 40 - .../hotel_room_type_restriction/importer.py | 58 - .../__init__.py | 6 - .../common.py | 16 - .../exporter.py | 129 - .../importer.py | 131 - ...inherited_hotel_board_service_room_type.py | 17 - .../models/inherited_hotel_folio.py | 10 - .../models/inherited_hotel_room_type_class.py | 25 - .../models/product_pricelist/__init__.py | 7 - .../models/product_pricelist/common.py | 28 - .../models/product_pricelist/deleter.py | 22 - .../models/product_pricelist/exporter.py | 109 - .../models/product_pricelist/importer.py | 71 - .../models/product_pricelist_item/__init__.py | 6 - .../models/product_pricelist_item/common.py | 17 - .../models/product_pricelist_item/exporter.py | 81 - .../models/product_pricelist_item/importer.py | 143 - .../readme/CONTRIBUTORS.rst | 1 - .../readme/DESCRIPTION.rst | 11 - .../readme/ROADMAP.rst | 0 .../readme/USAGE.rst | 16 - .../security/wubook_security.xml | 21 - .../static/description/eiqui_logo.png | Bin 6240 -> 0 bytes .../static/description/index.html | 22 - .../tests/README.rst | 285 -- .../tests/__init__.py | 3 - .../tests/common.py | 322 -- ...t_channel_hotel_room_type_adapter_model.py | 84 - .../test_hotel_calendar_management_model.py | 152 - .../tests/test_hotel_folio_model.py | 125 - .../tests/test_hotel_reservation_model.py | 181 - .../test_product_pricelist_item_model.py | 75 - .../tests/test_product_pricelist_model.py | 70 - .../tests/test_res_partner_model.py | 84 - ...test_reservation_restriction_item_model.py | 45 - .../test_reservation_restriction_model.py | 99 - .../test_virtual_room_availability_model.py | 43 - .../tests/test_wubook.py | 608 ---- .../tests/test_wubook_channel_info_model.py | 38 - .../tests/test_wubook_issue_model.py | 57 - ...erited_channel_connector_backend_views.xml | 24 - ...nnel_hotel_room_type_restriction_views.xml | 15 - .../inherited_channel_ota_info_views.xml | 15 - hotel_data_bi/README.rst | 74 - hotel_data_bi/__init__.py | 1 - hotel_data_bi/__manifest__.py | 32 - hotel_data_bi/models/__init__.py | 3 - hotel_data_bi/models/budget.py | 48 - hotel_data_bi/models/data_bi.py | 705 ---- hotel_data_bi/models/inherit_res_company.py | 24 - hotel_data_bi/security/data_bi.xml | 10 - hotel_data_bi/security/ir.model.access.csv | 17 - hotel_data_bi/static/description/icon.png | Bin 66994 -> 0 bytes hotel_data_bi/views/budget.xml | 71 - hotel_data_bi/views/inherit_res_company.xml | 23 - hotel_door_codes/README.rst | 13 - hotel_door_codes/__init__.py | 22 - hotel_door_codes/__manifest__.py | 48 - hotel_door_codes/data/menus.xml | 13 - hotel_door_codes/i18n/es.po | 162 - hotel_door_codes/models/__init__.py | 23 - .../models/inherit_hotel_property.py | 29 - .../models/inherit_hotel_reservation.py | 79 - hotel_door_codes/static/description/icon.png | Bin 24484 -> 0 bytes .../views/inherit_hotel_property.xml | 20 - .../views/inherit_hotel_reservation.xml | 23 - hotel_door_codes/wizard/__init__.py | 21 - hotel_door_codes/wizard/door_code.py | 77 - hotel_door_codes/wizard/door_code.xml | 33 - hotel_ine/__init__.py | 23 - hotel_ine/__manifest__.py | 41 - hotel_ine/models/__init__.py | 1 - hotel_ine/models/inherited_hotel_room.py | 9 - hotel_ine/static/description/icon.png | Bin 24576 -> 0 bytes hotel_ine/views/inherited_hotel_room_view.xml | 18 - hotel_ine/wizard/__init__.py | 23 - hotel_ine/wizard/inewizard.py | 321 -- hotel_ine/wizard/inewizard.xml | 54 - hotel_l10n_es/README.rst | 22 - hotel_l10n_es/__init__.py | 24 - hotel_l10n_es/__manifest__.py | 66 - hotel_l10n_es/data/code.ine.csv | 309 -- .../data/report_viajero_paperformat.xml | 22 - hotel_l10n_es/data/tourism.category.csv | 54 - hotel_l10n_es/i18n/es.po | 812 ----- hotel_l10n_es/models/__init__.py | 28 - hotel_l10n_es/models/category_type.py | 37 - hotel_l10n_es/models/code_ine.py | 41 - .../models/inherit_hotel_checkin_partner.py | 127 - .../models/inherit_hotel_reservation.py | 35 - hotel_l10n_es/models/inherit_res_company.py | 57 - hotel_l10n_es/models/inherit_res_partner.py | 450 --- hotel_l10n_es/report/report_parte_viajero.xml | 13 - hotel_l10n_es/security/ir.model.access.csv | 7 - hotel_l10n_es/static/description/icon.png | Bin 19995 -> 0 bytes .../static/src/css/hotel_l10n_es.css | 5 - hotel_l10n_es/static/src/img/logo_bn.png | Bin 33801 -> 0 bytes hotel_l10n_es/static/src/img/watermark.jpg | Bin 10643 -> 0 bytes .../src/xml/hotel_l10n_es_templates.xml | 13 - hotel_l10n_es/views/category_tourism.xml | 51 - hotel_l10n_es/views/code_ine.xml | 53 - .../views/hotel_l10n_es_hotel_name.xml | 13 - .../inherit_hotel_checkin_partner_views.xml | 109 - hotel_l10n_es/views/inherit_res_company.xml | 32 - hotel_l10n_es/views/inherit_res_partner.xml | 40 - .../inherited_hotel_reservation_views.xml | 17 - hotel_l10n_es/views/report_viajero.xml | 10 - hotel_l10n_es/views/report_viajero_data.xml | 103 - .../views/report_viajero_document.xml | 64 - .../views/report_viajero_document_new.xml | 101 - hotel_l10n_es/views/report_viajero_head.xml | 93 - hotel_l10n_es/wizard/__init__.py | 23 - hotel_l10n_es/wizard/police_wizard.py | 123 - hotel_l10n_es/wizard/police_wizard.xml | 51 - hotel_roommatik/__init__.py | 1 - hotel_roommatik/__manifest__.py | 29 - hotel_roommatik/data/res_users_data.xml | 25 - hotel_roommatik/models/__init__.py | 6 - .../models/inherited_account_payment.py | 46 - .../models/inherited_hotel_checkin_partner.py | 140 - .../models/inherited_hotel_reservation.py | 79 - .../models/inherited_hotel_room_type.py | 71 - .../models/inherited_res_partner.py | 146 - hotel_roommatik/models/roommatik.py | 110 - hotel_roommatik/static/description/icon.png | Bin 44610 -> 0 bytes hotel_roommatik/static/img/avatar.png | Bin 44610 -> 0 bytes kellys_daily_report/README.rst | 13 - kellys_daily_report/__init__.py | 22 - kellys_daily_report/__manifest__.py | 51 - kellys_daily_report/data/menus.xml | 13 - .../data/report_kellys_paperformat.xml | 22 - kellys_daily_report/models/__init__.py | 23 - kellys_daily_report/models/kellysnames.py | 28 - kellys_daily_report/report/report_kellys.xml | 205 -- .../security/ir.model.access.csv | 4 - .../static/description/icon.png | Bin 36423 -> 0 bytes .../static/src/css/kellys_daily_report.css | 1 - kellys_daily_report/views/kellysnames.xml | 16 - kellys_daily_report/wizard/__init__.py | 22 - .../wizard/kellys_daily_pdf.py | 123 - .../wizard/kellys_daily_pdf.xml | 31 - .../wizard/kellys_daily_rooms.py | 36 - .../wizard/kellys_daily_rooms.xml | 20 - mail_reply_to_sender/__init__.py | 3 - mail_reply_to_sender/__manifest__.py | 22 - mail_reply_to_sender/models/__init__.py | 2 - mail_reply_to_sender/models/ir_mail_server.py | 17 - .../static/description/banner.png | Bin 232656 -> 0 bytes .../static/description/icon.png | Bin 46313 -> 0 bytes .../static/description/index.html | 44 - .../static/description/mail_reply_to_1.png | Bin 80902 -> 0 bytes .../static/description/mail_reply_to_2.png | Bin 84619 -> 0 bytes .../static/description/reply_to.png | Bin 27416 -> 0 bytes setup/pms/odoo/addons/pms | 1 + setup/pms/setup.py | 6 + 412 files changed, 7 insertions(+), 39258 deletions(-) delete mode 100644 call_center_report/README.rst delete mode 100644 call_center_report/__init__.py delete mode 100644 call_center_report/__manifest__.py delete mode 100644 call_center_report/data/menus.xml delete mode 100644 call_center_report/i18n/es.po delete mode 100644 call_center_report/wizard/__init__.py delete mode 100644 call_center_report/wizard/call_center_report.py delete mode 100644 call_center_report/wizard/call_center_report.xml delete mode 100644 cash_daily_report/README.rst delete mode 100644 cash_daily_report/__init__.py delete mode 100644 cash_daily_report/__manifest__.py delete mode 100644 cash_daily_report/data/cron_jobs.xml delete mode 100644 cash_daily_report/data/menus.xml delete mode 100644 cash_daily_report/i18n/es.po delete mode 100644 cash_daily_report/wizard/__init__.py delete mode 100644 cash_daily_report/wizard/cash_daily_report.py delete mode 100644 cash_daily_report/wizard/cash_daily_report.xml delete mode 100644 glasof_exporter/README.rst delete mode 100644 glasof_exporter/__init__.py delete mode 100644 glasof_exporter/__manifest__.py delete mode 100644 glasof_exporter/data/menus.xml delete mode 100644 glasof_exporter/wizard/__init__.py delete mode 100644 glasof_exporter/wizard/glasof_wizard.py delete mode 100644 glasof_exporter/wizard/glasof_wizard.xml delete mode 100644 hotel_calendar/README.rst delete mode 100644 hotel_calendar/__init__.py delete mode 100644 hotel_calendar/__manifest__.py delete mode 100644 hotel_calendar/controllers/__init__.py delete mode 100644 hotel_calendar/controllers/bus.py delete mode 100644 hotel_calendar/data/menus.xml delete mode 100644 hotel_calendar/i18n/es.po delete mode 100644 hotel_calendar/models/__init__.py delete mode 100644 hotel_calendar/models/bus_hotel_calendar.py delete mode 100644 hotel_calendar/models/hotel_calendar.py delete mode 100644 hotel_calendar/models/hotel_calendar_management.py delete mode 100644 hotel_calendar/models/inherited_hotel_folio.py delete mode 100644 hotel_calendar/models/inherited_hotel_property.py delete mode 100644 hotel_calendar/models/inherited_hotel_reservation.py delete mode 100644 hotel_calendar/models/inherited_hotel_room_type_restriction_item.py delete mode 100644 hotel_calendar/models/inherited_product_pricelist_item.py delete mode 100644 hotel_calendar/models/inherited_res_company.py delete mode 100644 hotel_calendar/models/inherited_res_users.py delete mode 100644 hotel_calendar/models/ir_actions_act_window_view.py delete mode 100644 hotel_calendar/models/ir_ui_view.py delete mode 100644 hotel_calendar/readme/CONFIGURE.rst delete mode 100644 hotel_calendar/readme/CONTRIBUTORS.rst delete mode 100644 hotel_calendar/readme/CREDITS.rst delete mode 100644 hotel_calendar/readme/DESCRIPTION.rst delete mode 100644 hotel_calendar/readme/INSTALL.rst delete mode 100644 hotel_calendar/readme/ROADMAP.rst delete mode 100644 hotel_calendar/readme/USAGE.rst delete mode 100644 hotel_calendar/security/ir.model.access.csv delete mode 100644 hotel_calendar/static/description/icon.png delete mode 100644 hotel_calendar/static/description/icon_calendar_configurator.png delete mode 100644 hotel_calendar/static/src/css/view.css delete mode 100644 hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js delete mode 100644 hotel_calendar/static/src/js/views/calendar/hotel_calendar_model.js delete mode 100644 hotel_calendar/static/src/js/views/calendar/hotel_calendar_renderer.js delete mode 100644 hotel_calendar/static/src/js/views/calendar/hotel_calendar_view.js delete mode 100644 hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_controller.js delete mode 100644 hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_model.js delete mode 100644 hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js delete mode 100644 hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v_deprecated.js delete mode 100644 hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_view.js delete mode 100644 hotel_calendar/static/src/js/views/constants.js delete mode 100644 hotel_calendar/static/src/js/widgets/MultiCalendar.js delete mode 100644 hotel_calendar/static/src/lib/bootbox.js delete mode 100644 hotel_calendar/static/src/lib/hcalendar/css/hcalendar.css delete mode 100644 hotel_calendar/static/src/lib/hcalendar/css/hcalendar_management.css delete mode 100644 hotel_calendar/static/src/lib/hcalendar/js/hcalendar.js delete mode 100644 hotel_calendar/static/src/lib/hcalendar/js/hcalendar_management.js delete mode 100644 hotel_calendar/static/src/lib/moment.js delete mode 100644 hotel_calendar/static/src/xml/hotel_calendar_management_view.xml delete mode 100644 hotel_calendar/static/src/xml/hotel_calendar_templates.xml delete mode 100644 hotel_calendar/static/src/xml/hotel_calendar_view.xml delete mode 100644 hotel_calendar/tests/__init__.py delete mode 100644 hotel_calendar/tests/common.py delete mode 100644 hotel_calendar/tests/test_management_calendar.py delete mode 100644 hotel_calendar/tests/test_product_pricelist.py delete mode 100644 hotel_calendar/tests/test_reservations_calendar.py delete mode 100644 hotel_calendar/views/actions.xml delete mode 100644 hotel_calendar/views/general.xml delete mode 100644 hotel_calendar/views/hotel_calendar_management_views.xml delete mode 100644 hotel_calendar/views/hotel_calendar_views.xml delete mode 100644 hotel_calendar/views/hotel_reservation_views.xml delete mode 100644 hotel_calendar/views/inherited_hotel_property_views.xml delete mode 100644 hotel_calendar/views/inherited_hotel_room_type_views.xml delete mode 100644 hotel_calendar/views/inherited_hotel_room_views.xml delete mode 100644 hotel_calendar/views/inherited_res_company_views.xml delete mode 100644 hotel_calendar/views/inherited_res_users_views.xml delete mode 100644 hotel_calendar_channel_connector/README.md delete mode 100644 hotel_calendar_channel_connector/__init__.py delete mode 100644 hotel_calendar_channel_connector/__manifest__.py delete mode 100644 hotel_calendar_channel_connector/i18n/es.po delete mode 100644 hotel_calendar_channel_connector/models/__init__.py delete mode 100644 hotel_calendar_channel_connector/models/inherited_bus_hotel_calendar.py delete mode 100644 hotel_calendar_channel_connector/models/inherited_hotel_calendar_management.py delete mode 100644 hotel_calendar_channel_connector/models/inherited_hotel_reservation.py delete mode 100644 hotel_calendar_channel_connector/models/inherited_hotel_room_type_availability.py delete mode 100644 hotel_calendar_channel_connector/readme/CONTRIBUTORS.rst delete mode 100644 hotel_calendar_channel_connector/readme/DESCRIPTION.rst delete mode 100644 hotel_calendar_channel_connector/readme/ROADMAP.rst delete mode 100644 hotel_calendar_channel_connector/readme/USAGE.rst delete mode 100644 hotel_calendar_channel_connector/static/description/eiqui_logo.png delete mode 100644 hotel_calendar_channel_connector/static/description/index.html delete mode 100644 hotel_calendar_channel_connector/static/sfx/book_cancelled.mp3 delete mode 100644 hotel_calendar_channel_connector/static/sfx/book_new.mp3 delete mode 100644 hotel_calendar_channel_connector/static/src/css/view.css delete mode 100644 hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_controller.js delete mode 100644 hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_management_controller.js delete mode 100644 hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_management_renderer.js delete mode 100644 hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_renderer.js delete mode 100644 hotel_calendar_channel_connector/static/src/xml/hotel_calendar_templates.xml delete mode 100644 hotel_calendar_channel_connector/static/src/xml/hotel_calendar_view.xml delete mode 100644 hotel_calendar_channel_connector/tests/__init__.py delete mode 100644 hotel_calendar_channel_connector/tests/test_folio.py delete mode 100644 hotel_calendar_channel_connector/views/actions.xml delete mode 100644 hotel_calendar_channel_connector/views/general.xml delete mode 100644 hotel_calendar_channel_connector/views/hotel_reservation.xml delete mode 100644 hotel_channel_connector/README.md delete mode 100644 hotel_channel_connector/__init__.py delete mode 100644 hotel_channel_connector/__manifest__.py delete mode 100644 hotel_channel_connector/components/__init__.py delete mode 100644 hotel_channel_connector/components/backend_adapter.py delete mode 100644 hotel_channel_connector/components/binder.py delete mode 100644 hotel_channel_connector/components/core.py delete mode 100644 hotel_channel_connector/components/deleter.py delete mode 100644 hotel_channel_connector/components/exporter.py delete mode 100644 hotel_channel_connector/components/importer.py delete mode 100644 hotel_channel_connector/components/mapper.py delete mode 100644 hotel_channel_connector/data/cron_jobs.xml delete mode 100644 hotel_channel_connector/data/email_availability_watchdog.xml delete mode 100644 hotel_channel_connector/data/menus.xml delete mode 100644 hotel_channel_connector/i18n/es.po delete mode 100644 hotel_channel_connector/models/__init__.py delete mode 100644 hotel_channel_connector/models/channel_backend/__init__.py delete mode 100644 hotel_channel_connector/models/channel_backend/common.py delete mode 100644 hotel_channel_connector/models/channel_binding/__init__.py delete mode 100644 hotel_channel_connector/models/channel_binding/common.py delete mode 100644 hotel_channel_connector/models/channel_ota_info/__init__.py delete mode 100644 hotel_channel_connector/models/channel_ota_info/common.py delete mode 100644 hotel_channel_connector/models/channel_ota_info/importer.py delete mode 100644 hotel_channel_connector/models/hotel_channel_connector_issue.py delete mode 100644 hotel_channel_connector/models/hotel_reservation/__init__.py delete mode 100644 hotel_channel_connector/models/hotel_reservation/common.py delete mode 100644 hotel_channel_connector/models/hotel_reservation/exporter.py delete mode 100644 hotel_channel_connector/models/hotel_reservation/importer.py delete mode 100644 hotel_channel_connector/models/hotel_room_type/__init__.py delete mode 100644 hotel_channel_connector/models/hotel_room_type/common.py delete mode 100644 hotel_channel_connector/models/hotel_room_type/deleter.py delete mode 100644 hotel_channel_connector/models/hotel_room_type/exporter.py delete mode 100644 hotel_channel_connector/models/hotel_room_type/importer.py delete mode 100644 hotel_channel_connector/models/hotel_room_type_availability/__init__.py delete mode 100644 hotel_channel_connector/models/hotel_room_type_availability/common.py delete mode 100644 hotel_channel_connector/models/hotel_room_type_availability/exporter.py delete mode 100644 hotel_channel_connector/models/hotel_room_type_availability/importer.py delete mode 100644 hotel_channel_connector/models/hotel_room_type_restriction/__init__.py delete mode 100644 hotel_channel_connector/models/hotel_room_type_restriction/common.py delete mode 100644 hotel_channel_connector/models/hotel_room_type_restriction/deleter.py delete mode 100644 hotel_channel_connector/models/hotel_room_type_restriction/exporter.py delete mode 100644 hotel_channel_connector/models/hotel_room_type_restriction/importer.py delete mode 100644 hotel_channel_connector/models/hotel_room_type_restriction_item/__init__.py delete mode 100644 hotel_channel_connector/models/hotel_room_type_restriction_item/common.py delete mode 100644 hotel_channel_connector/models/hotel_room_type_restriction_item/exporter.py delete mode 100644 hotel_channel_connector/models/hotel_room_type_restriction_item/importer.py delete mode 100644 hotel_channel_connector/models/inherited_hotel_board_service_room_type.py delete mode 100644 hotel_channel_connector/models/inherited_hotel_folio.py delete mode 100644 hotel_channel_connector/models/inherited_hotel_room.py delete mode 100644 hotel_channel_connector/models/inherited_hotel_room_type_class.py delete mode 100644 hotel_channel_connector/models/product_pricelist/__init__.py delete mode 100644 hotel_channel_connector/models/product_pricelist/common.py delete mode 100644 hotel_channel_connector/models/product_pricelist/deleter.py delete mode 100644 hotel_channel_connector/models/product_pricelist/exporter.py delete mode 100644 hotel_channel_connector/models/product_pricelist/importer.py delete mode 100644 hotel_channel_connector/models/product_pricelist_item/__init__.py delete mode 100644 hotel_channel_connector/models/product_pricelist_item/common.py delete mode 100644 hotel_channel_connector/models/product_pricelist_item/exporter.py delete mode 100644 hotel_channel_connector/models/product_pricelist_item/importer.py delete mode 100644 hotel_channel_connector/readme/CONTRIBUTORS.rst delete mode 100644 hotel_channel_connector/readme/DESCRIPTION.rst delete mode 100644 hotel_channel_connector/readme/ROADMAP.rst delete mode 100644 hotel_channel_connector/readme/USAGE.rst delete mode 100644 hotel_channel_connector/security/ir.model.access.csv delete mode 100644 hotel_channel_connector/security/wubook_security.xml delete mode 100644 hotel_channel_connector/static/description/eiqui_logo.png delete mode 100644 hotel_channel_connector/static/description/index.html delete mode 100644 hotel_channel_connector/tests/__init__.py delete mode 100644 hotel_channel_connector/tests/common.py delete mode 100644 hotel_channel_connector/tests/test_hotel_calendar_management_model.py delete mode 100644 hotel_channel_connector/tests/test_hotel_folio_model.py delete mode 100644 hotel_channel_connector/tests/test_hotel_reservation_model.py delete mode 100644 hotel_channel_connector/tests/test_hotel_virtual_room_model.py delete mode 100644 hotel_channel_connector/tests/test_product_pricelist_item_model.py delete mode 100644 hotel_channel_connector/tests/test_product_pricelist_model.py delete mode 100644 hotel_channel_connector/tests/test_res_partner_model.py delete mode 100644 hotel_channel_connector/tests/test_reservation_restriction_item_model.py delete mode 100644 hotel_channel_connector/tests/test_reservation_restriction_model.py delete mode 100644 hotel_channel_connector/tests/test_virtual_room_availability_model.py delete mode 100644 hotel_channel_connector/tests/test_wubook.py delete mode 100644 hotel_channel_connector/tests/test_wubook_channel_info_model.py delete mode 100644 hotel_channel_connector/tests/test_wubook_issue_model.py delete mode 100644 hotel_channel_connector/views/channel_connector_backend_views.xml delete mode 100644 hotel_channel_connector/views/channel_hotel_reservation_views.xml delete mode 100644 hotel_channel_connector/views/channel_hotel_room_type_availability_views.xml delete mode 100644 hotel_channel_connector/views/channel_hotel_room_type_restriction_item_views.xml delete mode 100644 hotel_channel_connector/views/channel_hotel_room_type_restriction_views.xml delete mode 100644 hotel_channel_connector/views/channel_hotel_room_type_views.xml delete mode 100644 hotel_channel_connector/views/channel_ota_info_views.xml delete mode 100644 hotel_channel_connector/views/channel_product_pricelist_item_views.xml delete mode 100644 hotel_channel_connector/views/channel_product_pricelist_views.xml delete mode 100644 hotel_channel_connector/views/hotel_channel_connector_issue_views.xml delete mode 100644 hotel_channel_connector/views/hotel_room_type_availability_views.xml delete mode 100644 hotel_channel_connector/views/inherited_hotel_folio_views.xml delete mode 100644 hotel_channel_connector/views/inherited_hotel_reservation_views.xml delete mode 100644 hotel_channel_connector/views/inherited_hotel_room_type_restriction_item_views.xml delete mode 100644 hotel_channel_connector/views/inherited_hotel_room_type_restriction_views.xml delete mode 100644 hotel_channel_connector/views/inherited_hotel_room_type_views.xml delete mode 100644 hotel_channel_connector/views/inherited_product_pricelist_item_views.xml delete mode 100644 hotel_channel_connector/views/inherited_product_pricelist_views.xml delete mode 100644 hotel_channel_connector/wizard/__init__.py delete mode 100644 hotel_channel_connector/wizard/inherited_massive_changes.py delete mode 100644 hotel_channel_connector/wizard/inherited_massive_changes.xml delete mode 100644 hotel_channel_connector/wizard/inherited_massive_price_reservation_days.py delete mode 100644 hotel_channel_connector_wubook/README.md delete mode 100644 hotel_channel_connector_wubook/__init__.py delete mode 100644 hotel_channel_connector_wubook/__manifest__.py delete mode 100644 hotel_channel_connector_wubook/components/__init__.py delete mode 100644 hotel_channel_connector_wubook/components/backend_adapter.py delete mode 100644 hotel_channel_connector_wubook/controllers/__init__.py delete mode 100644 hotel_channel_connector_wubook/controllers/main.py delete mode 100644 hotel_channel_connector_wubook/data/cron_jobs.xml delete mode 100644 hotel_channel_connector_wubook/data/records.xml delete mode 100644 hotel_channel_connector_wubook/data/sequences.xml delete mode 100644 hotel_channel_connector_wubook/i18n/es.po delete mode 100644 hotel_channel_connector_wubook/models/__init__.py delete mode 100644 hotel_channel_connector_wubook/models/channel_backend/__init__.py delete mode 100644 hotel_channel_connector_wubook/models/channel_backend/common.py delete mode 100644 hotel_channel_connector_wubook/models/channel_ota_info/__init__.py delete mode 100644 hotel_channel_connector_wubook/models/channel_ota_info/common.py delete mode 100644 hotel_channel_connector_wubook/models/channel_ota_info/importer.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_reservation/__init__.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_reservation/common.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_reservation/exporter.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_reservation/importer.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type/__init__.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type/common.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type/deleter.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type/exporter.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type/importer.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type_availability/__init__.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type_availability/common.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type_availability/exporter.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type_availability/importer.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type_restriction/__init__.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type_restriction/common.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type_restriction/deleter.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type_restriction/exporter.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type_restriction/importer.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type_restriction_item/__init__.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type_restriction_item/common.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type_restriction_item/exporter.py delete mode 100644 hotel_channel_connector_wubook/models/hotel_room_type_restriction_item/importer.py delete mode 100644 hotel_channel_connector_wubook/models/inherited_hotel_board_service_room_type.py delete mode 100644 hotel_channel_connector_wubook/models/inherited_hotel_folio.py delete mode 100644 hotel_channel_connector_wubook/models/inherited_hotel_room_type_class.py delete mode 100644 hotel_channel_connector_wubook/models/product_pricelist/__init__.py delete mode 100644 hotel_channel_connector_wubook/models/product_pricelist/common.py delete mode 100644 hotel_channel_connector_wubook/models/product_pricelist/deleter.py delete mode 100644 hotel_channel_connector_wubook/models/product_pricelist/exporter.py delete mode 100644 hotel_channel_connector_wubook/models/product_pricelist/importer.py delete mode 100644 hotel_channel_connector_wubook/models/product_pricelist_item/__init__.py delete mode 100644 hotel_channel_connector_wubook/models/product_pricelist_item/common.py delete mode 100644 hotel_channel_connector_wubook/models/product_pricelist_item/exporter.py delete mode 100644 hotel_channel_connector_wubook/models/product_pricelist_item/importer.py delete mode 100644 hotel_channel_connector_wubook/readme/CONTRIBUTORS.rst delete mode 100644 hotel_channel_connector_wubook/readme/DESCRIPTION.rst delete mode 100644 hotel_channel_connector_wubook/readme/ROADMAP.rst delete mode 100644 hotel_channel_connector_wubook/readme/USAGE.rst delete mode 100644 hotel_channel_connector_wubook/security/wubook_security.xml delete mode 100644 hotel_channel_connector_wubook/static/description/eiqui_logo.png delete mode 100644 hotel_channel_connector_wubook/static/description/index.html delete mode 100644 hotel_channel_connector_wubook/tests/README.rst delete mode 100644 hotel_channel_connector_wubook/tests/__init__.py delete mode 100644 hotel_channel_connector_wubook/tests/common.py delete mode 100644 hotel_channel_connector_wubook/tests/test_channel_hotel_room_type_adapter_model.py delete mode 100644 hotel_channel_connector_wubook/tests/test_hotel_calendar_management_model.py delete mode 100644 hotel_channel_connector_wubook/tests/test_hotel_folio_model.py delete mode 100644 hotel_channel_connector_wubook/tests/test_hotel_reservation_model.py delete mode 100644 hotel_channel_connector_wubook/tests/test_product_pricelist_item_model.py delete mode 100644 hotel_channel_connector_wubook/tests/test_product_pricelist_model.py delete mode 100644 hotel_channel_connector_wubook/tests/test_res_partner_model.py delete mode 100644 hotel_channel_connector_wubook/tests/test_reservation_restriction_item_model.py delete mode 100644 hotel_channel_connector_wubook/tests/test_reservation_restriction_model.py delete mode 100644 hotel_channel_connector_wubook/tests/test_virtual_room_availability_model.py delete mode 100644 hotel_channel_connector_wubook/tests/test_wubook.py delete mode 100644 hotel_channel_connector_wubook/tests/test_wubook_channel_info_model.py delete mode 100644 hotel_channel_connector_wubook/tests/test_wubook_issue_model.py delete mode 100644 hotel_channel_connector_wubook/views/inherited_channel_connector_backend_views.xml delete mode 100644 hotel_channel_connector_wubook/views/inherited_channel_hotel_room_type_restriction_views.xml delete mode 100644 hotel_channel_connector_wubook/views/inherited_channel_ota_info_views.xml delete mode 100644 hotel_data_bi/README.rst delete mode 100644 hotel_data_bi/__init__.py delete mode 100644 hotel_data_bi/__manifest__.py delete mode 100644 hotel_data_bi/models/__init__.py delete mode 100644 hotel_data_bi/models/budget.py delete mode 100644 hotel_data_bi/models/data_bi.py delete mode 100644 hotel_data_bi/models/inherit_res_company.py delete mode 100644 hotel_data_bi/security/data_bi.xml delete mode 100644 hotel_data_bi/security/ir.model.access.csv delete mode 100644 hotel_data_bi/static/description/icon.png delete mode 100644 hotel_data_bi/views/budget.xml delete mode 100644 hotel_data_bi/views/inherit_res_company.xml delete mode 100644 hotel_door_codes/README.rst delete mode 100644 hotel_door_codes/__init__.py delete mode 100644 hotel_door_codes/__manifest__.py delete mode 100644 hotel_door_codes/data/menus.xml delete mode 100644 hotel_door_codes/i18n/es.po delete mode 100644 hotel_door_codes/models/__init__.py delete mode 100644 hotel_door_codes/models/inherit_hotel_property.py delete mode 100644 hotel_door_codes/models/inherit_hotel_reservation.py delete mode 100644 hotel_door_codes/static/description/icon.png delete mode 100644 hotel_door_codes/views/inherit_hotel_property.xml delete mode 100644 hotel_door_codes/views/inherit_hotel_reservation.xml delete mode 100644 hotel_door_codes/wizard/__init__.py delete mode 100644 hotel_door_codes/wizard/door_code.py delete mode 100644 hotel_door_codes/wizard/door_code.xml delete mode 100644 hotel_ine/__init__.py delete mode 100644 hotel_ine/__manifest__.py delete mode 100644 hotel_ine/models/__init__.py delete mode 100644 hotel_ine/models/inherited_hotel_room.py delete mode 100755 hotel_ine/static/description/icon.png delete mode 100644 hotel_ine/views/inherited_hotel_room_view.xml delete mode 100644 hotel_ine/wizard/__init__.py delete mode 100644 hotel_ine/wizard/inewizard.py delete mode 100644 hotel_ine/wizard/inewizard.xml delete mode 100755 hotel_l10n_es/README.rst delete mode 100755 hotel_l10n_es/__init__.py delete mode 100755 hotel_l10n_es/__manifest__.py delete mode 100755 hotel_l10n_es/data/code.ine.csv delete mode 100755 hotel_l10n_es/data/report_viajero_paperformat.xml delete mode 100755 hotel_l10n_es/data/tourism.category.csv delete mode 100755 hotel_l10n_es/i18n/es.po delete mode 100755 hotel_l10n_es/models/__init__.py delete mode 100755 hotel_l10n_es/models/category_type.py delete mode 100755 hotel_l10n_es/models/code_ine.py delete mode 100755 hotel_l10n_es/models/inherit_hotel_checkin_partner.py delete mode 100644 hotel_l10n_es/models/inherit_hotel_reservation.py delete mode 100755 hotel_l10n_es/models/inherit_res_company.py delete mode 100755 hotel_l10n_es/models/inherit_res_partner.py delete mode 100755 hotel_l10n_es/report/report_parte_viajero.xml delete mode 100755 hotel_l10n_es/security/ir.model.access.csv delete mode 100755 hotel_l10n_es/static/description/icon.png delete mode 100755 hotel_l10n_es/static/src/css/hotel_l10n_es.css delete mode 100755 hotel_l10n_es/static/src/img/logo_bn.png delete mode 100755 hotel_l10n_es/static/src/img/watermark.jpg delete mode 100644 hotel_l10n_es/static/src/xml/hotel_l10n_es_templates.xml delete mode 100755 hotel_l10n_es/views/category_tourism.xml delete mode 100755 hotel_l10n_es/views/code_ine.xml delete mode 100755 hotel_l10n_es/views/hotel_l10n_es_hotel_name.xml delete mode 100755 hotel_l10n_es/views/inherit_hotel_checkin_partner_views.xml delete mode 100755 hotel_l10n_es/views/inherit_res_company.xml delete mode 100755 hotel_l10n_es/views/inherit_res_partner.xml delete mode 100644 hotel_l10n_es/views/inherited_hotel_reservation_views.xml delete mode 100755 hotel_l10n_es/views/report_viajero.xml delete mode 100755 hotel_l10n_es/views/report_viajero_data.xml delete mode 100755 hotel_l10n_es/views/report_viajero_document.xml delete mode 100755 hotel_l10n_es/views/report_viajero_document_new.xml delete mode 100755 hotel_l10n_es/views/report_viajero_head.xml delete mode 100755 hotel_l10n_es/wizard/__init__.py delete mode 100755 hotel_l10n_es/wizard/police_wizard.py delete mode 100755 hotel_l10n_es/wizard/police_wizard.xml delete mode 100755 hotel_roommatik/__init__.py delete mode 100755 hotel_roommatik/__manifest__.py delete mode 100644 hotel_roommatik/data/res_users_data.xml delete mode 100755 hotel_roommatik/models/__init__.py delete mode 100644 hotel_roommatik/models/inherited_account_payment.py delete mode 100644 hotel_roommatik/models/inherited_hotel_checkin_partner.py delete mode 100644 hotel_roommatik/models/inherited_hotel_reservation.py delete mode 100644 hotel_roommatik/models/inherited_hotel_room_type.py delete mode 100755 hotel_roommatik/models/inherited_res_partner.py delete mode 100755 hotel_roommatik/models/roommatik.py delete mode 100755 hotel_roommatik/static/description/icon.png delete mode 100644 hotel_roommatik/static/img/avatar.png delete mode 100644 kellys_daily_report/README.rst delete mode 100644 kellys_daily_report/__init__.py delete mode 100644 kellys_daily_report/__manifest__.py delete mode 100644 kellys_daily_report/data/menus.xml delete mode 100644 kellys_daily_report/data/report_kellys_paperformat.xml delete mode 100644 kellys_daily_report/models/__init__.py delete mode 100644 kellys_daily_report/models/kellysnames.py delete mode 100644 kellys_daily_report/report/report_kellys.xml delete mode 100644 kellys_daily_report/security/ir.model.access.csv delete mode 100644 kellys_daily_report/static/description/icon.png delete mode 100644 kellys_daily_report/static/src/css/kellys_daily_report.css delete mode 100644 kellys_daily_report/views/kellysnames.xml delete mode 100644 kellys_daily_report/wizard/__init__.py delete mode 100644 kellys_daily_report/wizard/kellys_daily_pdf.py delete mode 100644 kellys_daily_report/wizard/kellys_daily_pdf.xml delete mode 100644 kellys_daily_report/wizard/kellys_daily_rooms.py delete mode 100644 kellys_daily_report/wizard/kellys_daily_rooms.xml delete mode 100644 mail_reply_to_sender/__init__.py delete mode 100644 mail_reply_to_sender/__manifest__.py delete mode 100644 mail_reply_to_sender/models/__init__.py delete mode 100644 mail_reply_to_sender/models/ir_mail_server.py delete mode 100644 mail_reply_to_sender/static/description/banner.png delete mode 100755 mail_reply_to_sender/static/description/icon.png delete mode 100644 mail_reply_to_sender/static/description/index.html delete mode 100644 mail_reply_to_sender/static/description/mail_reply_to_1.png delete mode 100644 mail_reply_to_sender/static/description/mail_reply_to_2.png delete mode 100644 mail_reply_to_sender/static/description/reply_to.png create mode 120000 setup/pms/odoo/addons/pms create mode 100644 setup/pms/setup.py diff --git a/call_center_report/README.rst b/call_center_report/README.rst deleted file mode 100644 index ec06d16ac..000000000 --- a/call_center_report/README.rst +++ /dev/null @@ -1,6 +0,0 @@ -CALL CENTER REPORT -============= - -Export call center report in xls format - - diff --git a/call_center_report/__init__.py b/call_center_report/__init__.py deleted file mode 100644 index 351d1ee57..000000000 --- a/call_center_report/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from . import wizard diff --git a/call_center_report/__manifest__.py b/call_center_report/__manifest__.py deleted file mode 100644 index 8204bbb7e..000000000 --- a/call_center_report/__manifest__.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - -{ - 'name': 'Call Center Report', - 'version': '1.0', - 'author': "Dario Lodeiros", - 'website': 'https://www.eiqui.com', - 'category': 'reports', - 'summary': "Export services and reservation report in xls format", - 'description': "Call Center Report", - 'depends': [ - 'hotel', - ], - 'external_dependencies': { - 'python': ['xlsxwriter'] - }, - 'data': [ - 'wizard/call_center_report.xml', - 'data/menus.xml', - ], - 'qweb': [], - 'test': [ - ], - - 'installable': True, - 'auto_install': False, - 'application': False, - 'license': 'AGPL-3', -} diff --git a/call_center_report/data/menus.xml b/call_center_report/data/menus.xml deleted file mode 100644 index d48c886eb..000000000 --- a/call_center_report/data/menus.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - diff --git a/call_center_report/i18n/es.po b/call_center_report/i18n/es.po deleted file mode 100644 index 0f9b0fa66..000000000 --- a/call_center_report/i18n/es.po +++ /dev/null @@ -1,171 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * cash_daily_report -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 10.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-05-20 07:33+0000\n" -"PO-Revision-Date: 2018-05-20 09:34+0200\n" -"Last-Translator: <>\n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: \n" -"Language: es\n" -"X-Generator: Poedit 1.8.7.1\n" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:85 -#, python-format -msgid "Amount" -msgstr "Importe" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:78 -#: model:ir.ui.view,arch_db:cash_daily_report.view_cash_daily_report_wizard -#, python-format -msgid "Cash Daily Report" -msgstr "Informe de caja" - -#. module: cash_daily_report -#: model:ir.actions.act_window,name:cash_daily_report.action_open_cash_daily_report_wizard -#: model:ir.ui.menu,name:cash_daily_report.cash_daily_report_wizard -msgid "Cash Daily Report Wizard" -msgstr "Informe de caja diaria" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:82 -#, python-format -msgid "Client" -msgstr "Cliente" - -#. module: cash_daily_report -#: model:ir.ui.view,arch_db:cash_daily_report.view_cash_daily_report_wizard -msgid "Close" -msgstr "Cerrar" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_create_uid -msgid "Created by" -msgstr "Creado por" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_create_date -msgid "Created on" -msgstr "Creado en" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:83 -#, python-format -msgid "Date" -msgstr "Fecha" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_display_name -msgid "Display Name" -msgstr "Mostrar Nombre" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_date_end -msgid "End Date" -msgstr "Fecha finalización" - -#. module: cash_daily_report -#: model:ir.ui.view,arch_db:cash_daily_report.view_cash_daily_report_wizard -msgid "Generate XLS" -msgstr "Generar XLS" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_id -msgid "ID" -msgstr "ID" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:84 -#, python-format -msgid "Journal" -msgstr "Diario" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard___last_update -msgid "Last Modified on" -msgstr "Última modificación en" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_write_uid -msgid "Last Updated by" -msgstr "Última actualización por" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_write_date -msgid "Last Updated on" -msgstr "Última actualización en" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:80 -#, python-format -msgid "Name" -msgstr "Nombre" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:128 -#, python-format -msgid "Not Any Payments" -msgstr "No hay movimientos" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:81 -#, python-format -msgid "Reference" -msgstr "Referencia" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_date_start -msgid "Start Date" -msgstr "Fecha de inicio" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:143 -#, python-format -msgid "TOTAL" -msgstr "TOTAL" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:139 -#, python-format -msgid "TOTAL PAYMENT RETURNS" -msgstr "TOTAL DEVOLUCIONES" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:134 -#, python-format -msgid "TOTAL PAYMENTS" -msgstr "TOTAL PAGOS" - -#. module: cash_daily_report -#: model:ir.ui.menu,name:cash_daily_report.menu_account_finance_xls_reports -msgid "XLS Reports" -msgstr "XLS Reports" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_xls_binary -msgid "Xls binary" -msgstr "Xls archivo" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_xls_filename -msgid "Xls filename" -msgstr "Xls nombre de archivo" - -#. module: cash_daily_report -#: model:ir.model,name:cash_daily_report.model_cash_daily_report_wizard -msgid "cash.daily.report.wizard" -msgstr "cash.daily.report.wizard" - -#. module: cash_daily_report -#: model:ir.ui.view,arch_db:cash_daily_report.view_cash_daily_report_wizard -msgid "or" -msgstr "o" diff --git a/call_center_report/wizard/__init__.py b/call_center_report/wizard/__init__.py deleted file mode 100644 index f3c151d2d..000000000 --- a/call_center_report/wizard/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from . import call_center_report diff --git a/call_center_report/wizard/call_center_report.py b/call_center_report/wizard/call_center_report.py deleted file mode 100644 index 114aee314..000000000 --- a/call_center_report/wizard/call_center_report.py +++ /dev/null @@ -1,348 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from io import BytesIO -from datetime import datetime, date -import xlsxwriter -import base64 -from odoo import api, fields, models, _ -from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT - - -class CallCenterReportWizard(models.TransientModel): - _name = 'call.center.report.wizard' - - @api.model - def _get_default_date_start(self): - return datetime.now().strftime(DEFAULT_SERVER_DATE_FORMAT) - - @api.model - def _get_default_date_end(self): - return datetime.now().strftime(DEFAULT_SERVER_DATE_FORMAT) - - date_start = fields.Date("Start Date", default=_get_default_date_start) - date_end = fields.Date("End Date", default=_get_default_date_end) - xls_filename = fields.Char() - xls_binary = fields.Binary() - - @api.model - def _export(self): - date_format = "%d-%m-%Y" - time_format = "%H:%M" - file_data = BytesIO() - workbook = xlsxwriter.Workbook(file_data, { - 'strings_to_numbers': True, - 'default_date_format': 'dd/mm/yyyy' - }) - - company_id = self.env.user.company_id - workbook.set_properties({ - 'title': 'Exported data from ' + company_id.name, - 'subject': 'Payments Data from Odoo of ' + company_id.name, - 'author': 'Odoo', - 'manager': u'Call Center', - 'company': company_id.name, - 'category': 'Hoja de Calculo', - 'keywords': 'payments, odoo, data, ' + company_id.name, - 'comments': 'Created with Python in Odoo and XlsxWriter'}) - workbook.use_zip64() - - xls_cell_format_date = workbook.add_format({ - 'num_format': 'dd/mm/yyyy' - }) - xls_cell_format_money = workbook.add_format({ - 'num_format': '#,##0.00' - }) - xls_cell_format_header = workbook.add_format({ - 'bg_color': '#CCCCCC' - }) - - worksheet = workbook.add_worksheet(_('Call Center Report - Production')) - - worksheet.write('A1', _('Ficha'), xls_cell_format_header) - worksheet.write('B1', _('Fecha de Pedido'), xls_cell_format_header) - worksheet.write('C1', _('Cliente'), xls_cell_format_header) - worksheet.write('D1', _('Producto'), xls_cell_format_header) - worksheet.write('E1', _('Noches/Uds'), xls_cell_format_header) - worksheet.write('F1', _('Adultos'), xls_cell_format_header) - worksheet.write('G1', _('Checkin'), xls_cell_format_header) - worksheet.write('H1', _('In-Hora'), xls_cell_format_header) - worksheet.write('I1', _('Checkout'), xls_cell_format_header) - worksheet.write('J1', _('Creado por'), xls_cell_format_header) - worksheet.write('K1', _('Total'), xls_cell_format_header) - - worksheet.set_column('B:B', 20) - worksheet.set_column('C:C', 20) - worksheet.set_column('D:D', 20) - worksheet.set_column('E:E', 20) - worksheet.set_column('F:F', 13) - - reservations_obj = self.env['hotel.reservation'] - reservations = reservations_obj.search([ - ('checkin', '>=', self.date_start), - ('checkout', '<=', self.date_end), - ('state', '=', 'done'), - ('channel_type', '=', 'call'), - ('folio_id.pending_amount', '<', 1), - ]) - offset = 1 - total_reservation_amount = 0.0 - for k_res, v_res in enumerate(reservations): - checkin_date = datetime.strptime(v_res.checkin, DEFAULT_SERVER_DATE_FORMAT) - checkout_date = datetime.strptime(v_res.checkout, DEFAULT_SERVER_DATE_FORMAT) - worksheet.write(k_res+offset, 0, v_res.folio_id.name) - worksheet.write(k_res+offset, 1, v_res.folio_id.date_order, - xls_cell_format_date) - worksheet.write(k_res+offset, 2, v_res.partner_id.name) - worksheet.write(k_res+offset, 3, v_res.room_type_id.name) - worksheet.write(k_res+offset, 4, v_res.nights) - worksheet.write(k_res+offset, 5, v_res.adults) - worksheet.write(k_res+offset, 6, checkin_date.strftime(date_format), - xls_cell_format_date) - worksheet.write(k_res+offset, 7, v_res.arrival_hour) - worksheet.write(k_res+offset, 8, checkout_date.strftime(date_format), - xls_cell_format_date) - worksheet.write(k_res+offset, 9, v_res.create_uid.name) - worksheet.write(k_res+offset, 10, v_res.price_total, - xls_cell_format_money) - total_reservation_amount += v_res.price_total - - folio_ids = reservations.mapped('folio_id.id') - folios = self.env['hotel.folio'].browse(folio_ids) - services = self.env['hotel.service'].browse() - for folio in folios: - services += folio.service_ids.filtered(lambda r: - r.channel_type == 'call' and r.folio_id.pending_amount < 1) - offset += len(reservations) - total_service_amount = k_line = 0.0 - for k_service, v_service in enumerate(services): - worksheet.write(k_service+offset, 0, v_service.folio_id.name) - worksheet.write(k_service+offset, 1, v_service.folio_id.date_order, - xls_cell_format_date) - worksheet.write(k_service+offset, 2, v_service.folio_id.partner_id.name) - worksheet.write(k_service+offset, 3, v_service.product_id.name) - worksheet.write(k_service+offset, 4, v_service.product_qty) - worksheet.write(k_service+offset, 5, '') - worksheet.write(k_service+offset, 6, '') - worksheet.write(k_service+offset, 7, '') - worksheet.write(k_service+offset, 8, '') - worksheet.write(k_service+offset, 9, v_service .create_uid.name) - worksheet.write(k_service+offset, 10, v_service.price_total, - xls_cell_format_money) - total_service_amount += v_service.price_total - offset += len(services) - #~ if total_reservation_amount == 0 and total_service_amount == 0: - #~ raise UserError(_('No Hay reservas de Call Center')) - line = offset - if k_line: - line = k_line + offset - if total_reservation_amount > 0: - line += 1 - worksheet.write(line, 9, _('TOTAL RESERVAS')) - worksheet.write(line, 10, total_reservation_amount, - xls_cell_format_money) - if total_service_amount > 0: - line += 1 - worksheet.write(line, 9, _('TOTAL SERVICIOS')) - worksheet.write(line, 10, total_service_amount, - xls_cell_format_money) - line += 1 - worksheet.write(line, 9, _('TOTAL')) - worksheet.write(line, 10 , total_reservation_amount + total_service_amount, - xls_cell_format_money) - - worksheet = workbook.add_worksheet(_('Call Center Report - Sales')) - - worksheet.write('A1', _('Estado'), xls_cell_format_header) - worksheet.write('B1', _('Ficha'), xls_cell_format_header) - worksheet.write('C1', _('Fecha de Pedido'), xls_cell_format_header) - worksheet.write('D1', _('Cliente'), xls_cell_format_header) - worksheet.write('E1', _('Producto'), xls_cell_format_header) - worksheet.write('F1', _('Noches/Uds'), xls_cell_format_header) - worksheet.write('G1', _('Adultos'), xls_cell_format_header) - worksheet.write('H1', _('Checkin'), xls_cell_format_header) - worksheet.write('I1', _('In-Hora'), xls_cell_format_header) - worksheet.write('J1', _('Checkout'), xls_cell_format_header) - worksheet.write('K1', _('Creado por'), xls_cell_format_header) - worksheet.write('L1', _('Total'), xls_cell_format_header) - - worksheet.set_column('B:B', 20) - worksheet.set_column('C:C', 20) - worksheet.set_column('D:D', 20) - worksheet.set_column('E:E', 20) - worksheet.set_column('F:F', 13) - - reservations_obj = self.env['hotel.reservation'] - reservations = reservations_obj.search([ - ('folio_id.date_order', '>=', self.date_start), - ('folio_id.date_order', '<=', self.date_end), - ('channel_type','=','call'), - ]) - offset = 1 - total_reservation_amount = 0.0 - for k_res, v_res in enumerate(reservations): - checkin_date = datetime.strptime(v_res.checkin, DEFAULT_SERVER_DATE_FORMAT) - checkout_date = datetime.strptime(v_res.checkout, DEFAULT_SERVER_DATE_FORMAT) - worksheet.write(k_res+offset, 0, v_res.state) - worksheet.write(k_res+offset, 1, v_res.folio_id.name) - worksheet.write(k_res+offset, 2, v_res.folio_id.date_order, - xls_cell_format_date) - worksheet.write(k_res+offset, 3, v_res.partner_id.name) - worksheet.write(k_res+offset, 4, v_res.room_type_id.name) - worksheet.write(k_res+offset, 5, v_res.nights) - worksheet.write(k_res+offset, 6, v_res.adults) - worksheet.write(k_res+offset, 7, checkin_date.strftime(date_format), - xls_cell_format_date) - worksheet.write(k_res+offset, 8, v_res.arrival_hour) - worksheet.write(k_res+offset, 9, checkout_date.strftime(date_format), - xls_cell_format_date) - worksheet.write(k_res+offset, 10, v_res.create_uid.name) - worksheet.write(k_res+offset, 11, v_res.price_total, - xls_cell_format_money) - total_reservation_amount += v_res.price_total - - folio_ids = reservations.mapped('folio_id.id') - folios = self.env['hotel.folio'].browse(folio_ids) - services = self.env['hotel.service'].browse() - for folio in folios: - services += folio.service_ids.filtered(lambda r: - r.channel_type == 'call' and r.folio_id.pending_amount < 1) - offset += len(reservations) - total_service_amount = k_line = 0.0 - for k_service, v_service in enumerate(services): - worksheet.write(k_service+offset, 1, v_service.folio_id.state) - worksheet.write(k_service+offset, 1, v_service.folio_id.name) - worksheet.write(k_service+offset, 2, v_service.folio_id.date_order, - xls_cell_format_date) - worksheet.write(k_service+offset, 3, v_service.folio_id.partner_id.name) - worksheet.write(k_service+offset, 4, v_service.product_id.name) - worksheet.write(k_service+offset, 5, v_service.product_qty) - worksheet.write(k_service+offset, 6, '') - worksheet.write(k_service+offset, 7, '') - worksheet.write(k_service+offset, 8, '') - worksheet.write(k_service+offset, 9, '') - worksheet.write(k_service+offset, 10, v_service .create_uid.name) - worksheet.write(k_service+offset, 11, v_service.price_total, - xls_cell_format_money) - total_service_amount += v_service.price_total - offset += len(services) - #~ if total_reservation_amount == 0 and total_service_amount == 0: - #~ raise UserError(_('No Hay reservas de Call Center')) - line = offset - if k_line: - line = k_line + offset - if total_reservation_amount > 0: - line += 1 - worksheet.write(line, 10, _('TOTAL RESERVAS')) - worksheet.write(line, 11, total_reservation_amount, - xls_cell_format_money) - if total_service_amount > 0: - line += 1 - worksheet.write(line, 10, _('TOTAL SERVICIOS')) - worksheet.write(line, 11, total_service_amount, - xls_cell_format_money) - line += 1 - worksheet.write(line, 10, _('TOTAL')) - worksheet.write(line, 11 , total_reservation_amount + total_service_amount, - xls_cell_format_money) - - worksheet = workbook.add_worksheet(_('Call Center Report - Cancelations')) - - worksheet.write('A1', _('Estado'), xls_cell_format_header) - worksheet.write('B1', _('Ficha'), xls_cell_format_header) - worksheet.write('C1', _('Fecha de Pedido'), xls_cell_format_header) - worksheet.write('D1', _('Cliente'), xls_cell_format_header) - worksheet.write('E1', _('Producto'), xls_cell_format_header) - worksheet.write('F1', _('Noches/Uds'), xls_cell_format_header) - worksheet.write('G1', _('Adultos'), xls_cell_format_header) - worksheet.write('H1', _('Checkin'), xls_cell_format_header) - worksheet.write('I1', _('In-Hora'), xls_cell_format_header) - worksheet.write('J1', _('Checkout'), xls_cell_format_header) - worksheet.write('K1', _('Creado por'), xls_cell_format_header) - worksheet.write('K1', _('Cancelado en'), xls_cell_format_header) - worksheet.write('L1', _('Precio Final'), xls_cell_format_header) - worksheet.write('M1', _('Precio Original'), xls_cell_format_header) - - worksheet.set_column('B:B', 20) - worksheet.set_column('C:C', 20) - worksheet.set_column('D:D', 20) - worksheet.set_column('E:E', 20) - worksheet.set_column('F:F', 13) - - reservations_obj = self.env['hotel.reservation'] - reservations = reservations_obj.search([ - ('last_updated_res', '>=', self.date_start), - ('last_updated_res', '<=', self.date_end), - ('channel_type','=','call'), - ('state','=','cancelled'), - ]) - offset = 1 - total_reservation_amount = 0.0 - for k_res, v_res in enumerate(reservations): - checkin_date = datetime.strptime(v_res.checkin, DEFAULT_SERVER_DATE_FORMAT) - checkout_date = datetime.strptime(v_res.checkout, DEFAULT_SERVER_DATE_FORMAT) - worksheet.write(k_res+offset, 0, v_res.state) - worksheet.write(k_res+offset, 1, v_res.folio_id.name) - worksheet.write(k_res+offset, 2, v_res.folio_id.date_order, - xls_cell_format_date) - worksheet.write(k_res+offset, 3, v_res.partner_id.name) - worksheet.write(k_res+offset, 4, v_res.room_type_id.name) - worksheet.write(k_res+offset, 5, v_res.nights) - worksheet.write(k_res+offset, 6, v_res.adults) - worksheet.write(k_res+offset, 7, checkin_date.strftime(date_format), - xls_cell_format_date) - worksheet.write(k_res+offset, 8, v_res.arrival_hour) - worksheet.write(k_res+offset, 9, checkout_date.strftime(date_format), - xls_cell_format_date) - worksheet.write(k_res+offset, 10, v_res.create_uid.name) - worksheet.write(k_res+offset, 9, v_res.last_updated_res, - xls_cell_format_date) - worksheet.write(k_res+offset, 11, v_res.price_total, - xls_cell_format_money) - worksheet.write(k_res+offset, 12, v_res.price_total - v_res.discount, - xls_cell_format_money) - total_reservation_amount += v_res.price_total - - offset += len(reservations) - - #~ if total_reservation_amount == 0 and total_service_amount == 0: - #~ raise UserError(_('No Hay reservas de Call Center')) - line = offset - if k_line: - line = k_line + offset - if total_reservation_amount > 0: - line += 1 - worksheet.write(line, 11, _('TOTAL RESERVAS')) - worksheet.write(line, 12, total_reservation_amount, - xls_cell_format_money) - - workbook.close() - file_data.seek(0) - tnow = fields.Datetime.now().replace(' ', '_') - return { - 'xls_filename': 'call_%s.xlsx' %self.env.user.company_id.property_name, - 'xls_binary': base64.encodestring(file_data.read()), - } - - def export(self): - self.write(self._export()) - return { - "type": "ir.actions.do_nothing", - } diff --git a/call_center_report/wizard/call_center_report.xml b/call_center_report/wizard/call_center_report.xml deleted file mode 100644 index 598a137d1..000000000 --- a/call_center_report/wizard/call_center_report.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - call.center.report.wizard - call.center.report.wizard - -
- - - - - - - - - - - - - - -
-
-
-
-
- - - Call Center Report Wizard - ir.actions.act_window - call.center.report.wizard - - form - new - - -
diff --git a/cash_daily_report/README.rst b/cash_daily_report/README.rst deleted file mode 100644 index be9027c75..000000000 --- a/cash_daily_report/README.rst +++ /dev/null @@ -1,13 +0,0 @@ -CASH DAILY REPORT -============= - -Export payments report in xls format - - -Credits -======= - -Creator ------------- - -* Alexandre Díaz diff --git a/cash_daily_report/__init__.py b/cash_daily_report/__init__.py deleted file mode 100644 index 351d1ee57..000000000 --- a/cash_daily_report/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from . import wizard diff --git a/cash_daily_report/__manifest__.py b/cash_daily_report/__manifest__.py deleted file mode 100644 index 33c4fc38a..000000000 --- a/cash_daily_report/__manifest__.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - -{ - 'name': 'Cash Daily Report', - 'version': '1.0', - 'author': "Alexandre Díaz ", - 'website': 'https://www.eiqui.com', - 'category': 'reports', - 'summary': "Export payments report in xls format", - 'description': "Cash Daily Report", - 'depends': [ - 'account', - 'account_payment_return', - 'hotel', - ], - 'external_dependencies': { - 'python': ['xlsxwriter'] - }, - 'data': [ - 'wizard/cash_daily_report.xml', - 'data/menus.xml', - 'data/cron_jobs.xml', - ], - 'qweb': [], - 'test': [ - ], - - 'installable': True, - 'auto_install': False, - 'application': False, - 'license': 'AGPL-3', -} diff --git a/cash_daily_report/data/cron_jobs.xml b/cash_daily_report/data/cron_jobs.xml deleted file mode 100644 index bb556d2f2..000000000 --- a/cash_daily_report/data/cron_jobs.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - Automatic Period Lock Date - 1 - - days - -1 - - code - - - model.automatic_period_lock_date() - - - - - - diff --git a/cash_daily_report/data/menus.xml b/cash_daily_report/data/menus.xml deleted file mode 100644 index ef93963a4..000000000 --- a/cash_daily_report/data/menus.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - Internal Transfers - account.payment - tree,kanban,form,graph - {'default_payment_type': 'transfer', 'search_default_transfers_filter': 1} - [] - - -

- Click to register a payment -

- Payments are used to register liquidity movements (send, collect or transfer money). - You can then process those payments by your own means or by using installed facilities. -

-
-
- - - -
diff --git a/cash_daily_report/i18n/es.po b/cash_daily_report/i18n/es.po deleted file mode 100644 index 9b4a07faa..000000000 --- a/cash_daily_report/i18n/es.po +++ /dev/null @@ -1,203 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * cash_daily_report -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 11.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-08-02 10:07+0000\n" -"PO-Revision-Date: 2019-08-02 10:07+0000\n" -"Last-Translator: <>\n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: \n" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:85 -#, python-format -msgid "Amount" -msgstr "Importe" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:78 -#: model:ir.ui.view,arch_db:cash_daily_report.view_cash_daily_report_wizard -#, python-format -msgid "Cash Daily Report" -msgstr "Informe de caja" - -#. module: cash_daily_report -#: model:ir.actions.act_window,name:cash_daily_report.action_open_cash_daily_report_wizard -#: model:ir.ui.menu,name:cash_daily_report.cash_daily_report_wizard -msgid "Cash Daily Report Wizard" -msgstr "Informe de caja diaria" - -#. module: cash_daily_report -#: model:ir.actions.act_window,help:cash_daily_report.action_account_payments_internal -msgid "Click to register a payment" -msgstr "Pulse para registrar un pago" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:82 -#, python-format -msgid "Client/Supplier" -msgstr "Client/Supplier" - -#. module: cash_daily_report -#: model:ir.ui.view,arch_db:cash_daily_report.view_cash_daily_report_wizard -msgid "Close" -msgstr "Cerrar" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_create_uid -msgid "Created by" -msgstr "Creado por" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_create_date -msgid "Created on" -msgstr "Creado en" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:83 -#, python-format -msgid "Date" -msgstr "Fecha" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_display_name -msgid "Display Name" -msgstr "Nombre mostrado" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_date_end -msgid "End Date" -msgstr "Fecha de finalización" - -#. module: cash_daily_report -#: model:ir.ui.view,arch_db:cash_daily_report.view_cash_daily_report_wizard -msgid "Generate XLS" -msgstr "Generar XLS" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_id -msgid "ID" -msgstr "ID (identificación)" - -#. module: cash_daily_report -#: model:ir.ui.menu,name:cash_daily_report.hotel_transfer_menu -msgid "Internal Transfer" -msgstr "Transferencias Internas" - -#. module: cash_daily_report -#: model:ir.actions.act_window,name:cash_daily_report.action_account_payments_internal -msgid "Internal Transfers" -msgstr "Internal Transfers" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:84 -#, python-format -msgid "Journal" -msgstr "Diario" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard___last_update -msgid "Last Modified on" -msgstr "Última modificación en" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_write_uid -msgid "Last Updated by" -msgstr "Última actualización de" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_write_date -msgid "Last Updated on" -msgstr "Última actualización en" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:80 -#, python-format -msgid "Name" -msgstr "Nombre" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:159 -#, python-format -msgid "Not Any Payments" -msgstr "No hay movimientos" - -#. module: cash_daily_report -#: model:ir.ui.menu,name:cash_daily_report.hotel_payments_menu -msgid "Payments" -msgstr "Pagos" - -#. module: cash_daily_report -#: model:ir.actions.act_window,help:cash_daily_report.action_account_payments_internal -msgid "Payments are used to register liquidity movements (send, collect or transfer money).\n" -" You can then process those payments by your own means or by using installed facilities." -msgstr "Los pagos se utilizan para registrar movimientos de liquidez (enviar, recibir o transferir dinero).\n" -"Puede procesar esos pagos por sus propios medios o utilizando los servicios instalados." - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:81 -#, python-format -msgid "Reference" -msgstr "Referencia" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_date_start -msgid "Start Date" -msgstr "Fecha de Inicio" - -#. module: cash_daily_report -#: model:ir.ui.menu,name:cash_daily_report.hotel_supplier_payment_menu -msgid "Supplier Payments" -msgstr "Pagos a Proveedor" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:216 -#, python-format -msgid "TOTAL" -msgstr "TOTAL" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:201 -#, python-format -msgid "TOTAL EXPENSES" -msgstr "TOTAL EXPENSES" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:185 -#, python-format -msgid "TOTAL PAYMENT RETURNS" -msgstr "TOTAL DEVOLUCIONES" - -#. module: cash_daily_report -#: code:addons/cash_daily_report/wizard/cash_daily_report.py:169 -#, python-format -msgid "TOTAL PAYMENTS" -msgstr "TOTAL PAGOS" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_xls_binary -msgid "Xls Binary" -msgstr "Xls Binary" - -#. module: cash_daily_report -#: model:ir.model.fields,field_description:cash_daily_report.field_cash_daily_report_wizard_xls_filename -msgid "Xls Filename" -msgstr "Xls Filename" - -#. module: cash_daily_report -#: model:ir.model,name:cash_daily_report.model_cash_daily_report_wizard -msgid "cash.daily.report.wizard" -msgstr "cash.daily.report.wizard" - -#. module: cash_daily_report -#: model:ir.ui.view,arch_db:cash_daily_report.view_cash_daily_report_wizard -msgid "or" -msgstr "o" - diff --git a/cash_daily_report/wizard/__init__.py b/cash_daily_report/wizard/__init__.py deleted file mode 100644 index 7fb535a50..000000000 --- a/cash_daily_report/wizard/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from . import cash_daily_report diff --git a/cash_daily_report/wizard/cash_daily_report.py b/cash_daily_report/wizard/cash_daily_report.py deleted file mode 100644 index b08382146..000000000 --- a/cash_daily_report/wizard/cash_daily_report.py +++ /dev/null @@ -1,307 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from io import BytesIO -import datetime -import xlsxwriter -import base64 -from odoo import api, fields, models, _ -from openerp.exceptions import UserError -from openerp.tools import DEFAULT_SERVER_DATE_FORMAT - - -class CashDailyReportWizard(models.TransientModel): - FILENAME = 'cash_daily_report.xls' - _name = 'cash.daily.report.wizard' - - @api.model - def automatic_period_lock_date(self): - # The secong month day close the mont previous - days = 2 - closeday = datetime.date.today().replace(day=days) - if datetime.date.today() >= closeday: - companies = self.env['res.company'].search([]) - for record in companies: - lastday = datetime.date.today().replace(day=1) + \ - datetime.timedelta(days=-1) - if record.period_lock_date != lastday: - record.write({ - 'period_lock_date': lastday - }) - - @api.model - @api.model - def _get_default_date_start(self): - return datetime.datetime.now().strftime(DEFAULT_SERVER_DATE_FORMAT) - - @api.model - def _get_default_date_end(self): - return datetime.datetime.now().strftime(DEFAULT_SERVER_DATE_FORMAT) - - date_start = fields.Date("Start Date", default=_get_default_date_start) - date_end = fields.Date("End Date", default=_get_default_date_end) - xls_filename = fields.Char() - xls_binary = fields.Binary() - - @api.model - def _export(self): - file_data = BytesIO() - workbook = xlsxwriter.Workbook(file_data, { - 'strings_to_numbers': True, - 'default_date_format': 'dd/mm/yyyy' - }) - - company_id = self.env.user.company_id - workbook.set_properties({ - 'title': 'Exported data from ' + company_id.name, - 'subject': 'Payments Data from Odoo of ' + company_id.name, - 'author': 'Odoo', - 'manager': u'Alexandre Díaz Cuadrado', - 'company': company_id.name, - 'category': 'Hoja de Calculo', - 'keywords': 'payments, odoo, data, ' + company_id.name, - 'comments': 'Created with Python in Odoo and XlsxWriter'}) - workbook.use_zip64() - - xls_cell_format_date = workbook.add_format({ - 'num_format': 'dd/mm/yyyy' - }) - xls_cell_format_money = workbook.add_format({ - 'num_format': '#,##0.00' - }) - xls_cell_format_header = workbook.add_format({ - 'bg_color': '#CCCCCC' - }) - - worksheet = workbook.add_worksheet(_('Cash Daily Report')) - - worksheet.write('A1', _('Name'), xls_cell_format_header) - worksheet.write('B1', _('Reference'), xls_cell_format_header) - worksheet.write('C1', _('Client/Supplier'), xls_cell_format_header) - worksheet.write('D1', _('Date'), xls_cell_format_header) - worksheet.write('E1', _('Journal'), xls_cell_format_header) - worksheet.write('F1', _('Amount'), xls_cell_format_header) - - worksheet.set_column('C:C', 50) - worksheet.set_column('D:D', 11) - - account_payments_obj = self.env['account.payment'] - account_payments = account_payments_obj.search([ - ('payment_date', '>=', self.date_start), - ('payment_date', '<=', self.date_end), - ]) - offset = 1 - total_account_payment_amount = 0.0 - total_account_payment = 0.0 - total_account_expenses = 0.0 - payment_journals = {} - expense_journals = {} - total_dates = {} - for k_payment, v_payment in enumerate(account_payments): - where = v_payment.partner_id.name - amount = v_payment.amount if v_payment.payment_type in ('inbound') \ - else -v_payment.amount - if v_payment.payment_type == 'transfer': - where = v_payment.destination_journal_id.name - total_account_payment += -amount - if v_payment.destination_journal_id.name not in payment_journals: - payment_journals.update({v_payment.destination_journal_id.name: -amount}) - else: - payment_journals[v_payment.destination_journal_id.name] += -amount - if v_payment.payment_date not in total_dates: - total_dates.update({v_payment.payment_date: {v_payment.destination_journal_id.name: -amount}}) - else: - if v_payment.destination_journal_id.name not in total_dates[v_payment.payment_date]: - total_dates[v_payment.payment_date].update({v_payment.destination_journal_id.name: -amount}) - else: - total_dates[v_payment.payment_date][v_payment.destination_journal_id.name] += -amount - if amount < 0: - total_account_expenses += -amount - if v_payment.journal_id.name not in expense_journals: - expense_journals.update({v_payment.journal_id.name: amount}) - else: - expense_journals[v_payment.journal_id.name] += amount - if v_payment.payment_date not in total_dates: - total_dates.update({v_payment.payment_date: {v_payment.journal_id.name: amount}}) - else: - if v_payment.journal_id.name not in total_dates[v_payment.payment_date]: - total_dates[v_payment.payment_date].update({v_payment.journal_id.name: amount}) - else: - total_dates[v_payment.payment_date][v_payment.journal_id.name] += amount - else: - total_account_payment += amount - if v_payment.journal_id.name not in payment_journals: - payment_journals.update({v_payment.journal_id.name: amount}) - else: - payment_journals[v_payment.journal_id.name] += amount - if v_payment.payment_date not in total_dates: - total_dates.update({v_payment.payment_date: {v_payment.journal_id.name: amount}}) - else: - if v_payment.journal_id.name not in total_dates[v_payment.payment_date]: - total_dates[v_payment.payment_date].update({v_payment.journal_id.name: amount}) - else: - total_dates[v_payment.payment_date][v_payment.journal_id.name] += amount - - worksheet.write(k_payment+offset, 0, v_payment.create_uid.login) - worksheet.write(k_payment+offset, 1, v_payment.communication) - worksheet.write(k_payment+offset, 2, where) - worksheet.write(k_payment+offset, 3, v_payment.payment_date, - xls_cell_format_date) - worksheet.write(k_payment+offset, 4, v_payment.journal_id.name) - worksheet.write(k_payment+offset, 5, amount, - xls_cell_format_money) - total_account_payment_amount += amount - - payment_returns_obj = self.env['payment.return'] - payment_returns = payment_returns_obj.search([ - ('date', '>=', self.date_start), - ('date', '<=', self.date_end), - ]) - offset += len(account_payments) - total_payment_returns_amount = k_line = 0.0 - return_journals = {} - for k_payment, v_payment in enumerate(payment_returns): - for k_line, v_line in enumerate(v_payment.line_ids): - if v_payment.journal_id.name not in return_journals: - return_journals.update({v_payment.journal_id.name: -v_line.amount}) - else: - return_journals[v_payment.journal_id.name] += -v_line.amount - - if v_payment.date not in total_dates: - total_dates.update({v_payment.date: {v_payment.journal_id.name: -v_line.amount}}) - else: - if v_payment.journal_id.name not in total_dates[v_payment.date]: - total_dates[v_payment.date].update({v_payment.journal_id.name: -v_line.amount}) - else: - total_dates[v_payment.date][v_payment.journal_id.name] += -v_line.amount - - worksheet.write(k_line+offset, 0, v_payment.create_uid.login) - worksheet.write(k_line+offset, 1, v_line.reference) - worksheet.write(k_line+offset, 2, v_line.partner_id.name) - worksheet.write(k_line+offset, 3, v_payment.date, - xls_cell_format_date) - worksheet.write(k_line+offset, 4, v_payment.journal_id.name) - worksheet.write(k_line+offset, 5, -v_line.amount, - xls_cell_format_money) - total_payment_returns_amount += -v_line.amount - offset += len(v_payment.line_ids) - if total_account_payment_amount == 0 and total_payment_returns_amount == 0: - raise UserError(_('Not Any Payments')) - line = offset - if k_line: - line = k_line + offset - - result_journals = {} - # NORMAL PAYMENTS - if total_account_payment != 0: - line += 1 - worksheet.write(line, 4, _('TOTAL PAYMENTS'), xls_cell_format_header) - worksheet.write(line, 5, total_account_payment, - xls_cell_format_header) - for journal in payment_journals: - line += 1 - worksheet.write(line, 4, _(journal)) - worksheet.write(line, 5, payment_journals[journal], - xls_cell_format_money) - if journal not in result_journals: - result_journals.update({journal: payment_journals[journal]}) - else: - result_journals[journal] += payment_journals[journal] - - # RETURNS - if total_payment_returns_amount != 0: - line += 1 - worksheet.write(line, 4, _('TOTAL PAYMENT RETURNS'), xls_cell_format_header) - worksheet.write(line, 5, total_payment_returns_amount, - xls_cell_format_header) - for journal in return_journals: - line += 1 - worksheet.write(line, 4, _(journal)) - worksheet.write(line, 5, return_journals[journal], - xls_cell_format_money) - if journal not in result_journals: - result_journals.update({journal: return_journals[journal]}) - else: - result_journals[journal] += return_journals[journal] - - # EXPENSES - if total_account_expenses != 0: - line += 1 - worksheet.write(line, 4, _('TOTAL EXPENSES'), xls_cell_format_header) - worksheet.write(line, 5, -total_account_expenses, - xls_cell_format_header) - for journal in expense_journals: - line += 1 - worksheet.write(line, 4, _(journal)) - worksheet.write(line, 5, -expense_journals[journal], - xls_cell_format_money) - if journal not in result_journals: - result_journals.update({journal: expense_journals[journal]}) - else: - result_journals[journal] += expense_journals[journal] - - #TOTALS - line += 1 - worksheet.write(line, 4, _('TOTAL'), xls_cell_format_header) - worksheet.write( - line, - 5, - total_account_payment + total_payment_returns_amount - total_account_expenses, - xls_cell_format_header) - for journal in result_journals: - line += 1 - worksheet.write(line, 4, _(journal)) - worksheet.write(line, 5, result_journals[journal], - xls_cell_format_money) - - worksheet = workbook.add_worksheet(_('Por dia')) - worksheet.write('A1', _('Date'), xls_cell_format_header) - columns = ('B1','C1','D1','E1','F1','G1','H1') - i = 0 - column_journal = {} - for journal in result_journals: - worksheet.write(columns[i], _(journal), xls_cell_format_header) - i += 1 - column_journal.update({journal: i}) - - worksheet.set_column('C:C', 50) - worksheet.set_column('D:D', 11) - - offset = 1 - total_dates = sorted(total_dates.items(), key=lambda x: x[0]) - for k_day, v_day in enumerate(total_dates): - worksheet.write(k_day+offset, 0, v_day[0]) - for journal in v_day[1]: - worksheet.write(k_day+offset, column_journal[journal], v_day[1][journal]) - - workbook.close() - file_data.seek(0) - tnow = fields.Datetime.now().replace(' ', '_') - return { - 'xls_filename': 'cash_daily_report_%s.xlsx' % tnow, - 'xls_binary': base64.encodestring(file_data.read()), - } - - - def export(self): - self.write(self._export()) - return { - "type": "ir.actions.do_nothing", - } diff --git a/cash_daily_report/wizard/cash_daily_report.xml b/cash_daily_report/wizard/cash_daily_report.xml deleted file mode 100644 index caab7f860..000000000 --- a/cash_daily_report/wizard/cash_daily_report.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - cash.daily.report.wizard - cash.daily.report.wizard - -
- - - - - - - - - - - - - - -
-
-
-
-
- - - Cash Daily Report Wizard - ir.actions.act_window - cash.daily.report.wizard - - form - new - - -
diff --git a/glasof_exporter/README.rst b/glasof_exporter/README.rst deleted file mode 100644 index 58b7e6f48..000000000 --- a/glasof_exporter/README.rst +++ /dev/null @@ -1,15 +0,0 @@ -GLASOF EXPORTER -============= - -** UNDER DEVELOPMENT: NOT USE IN PRODUCTION ** - -Export Odoo data to glasof xls format - - -Credits -======= - -Creator ------------- - -* Alexandre Díaz diff --git a/glasof_exporter/__init__.py b/glasof_exporter/__init__.py deleted file mode 100644 index 351d1ee57..000000000 --- a/glasof_exporter/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from . import wizard diff --git a/glasof_exporter/__manifest__.py b/glasof_exporter/__manifest__.py deleted file mode 100644 index 475fb102f..000000000 --- a/glasof_exporter/__manifest__.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - -{ - 'name': 'Glasof Exporter', - 'version': '1.0', - 'author': "Alexandre Díaz ", - 'website': 'https://www.eiqui.com', - 'category': 'hotel/glasof', - 'summary': "Export Odoo Data to xls compatible with Glasof", - 'description': "Glasof Exporter", - 'depends': [ - 'account', - ], - 'external_dependencies': { - 'python': ['xlsxwriter'] - }, - 'data': [ - 'wizard/glasof_wizard.xml', - 'data/menus.xml', - ], - 'qweb': [], - 'test': [ - ], - - 'installable': True, - 'auto_install': False, - 'application': False, - 'license': 'AGPL-3', -} diff --git a/glasof_exporter/data/menus.xml b/glasof_exporter/data/menus.xml deleted file mode 100644 index 7b791eeaf..000000000 --- a/glasof_exporter/data/menus.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - diff --git a/glasof_exporter/wizard/__init__.py b/glasof_exporter/wizard/__init__.py deleted file mode 100644 index 2b033f952..000000000 --- a/glasof_exporter/wizard/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from . import glasof_wizard diff --git a/glasof_exporter/wizard/glasof_wizard.py b/glasof_exporter/wizard/glasof_wizard.py deleted file mode 100644 index 1e9ddc12d..000000000 --- a/glasof_exporter/wizard/glasof_wizard.py +++ /dev/null @@ -1,256 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from io import BytesIO -import xlsxwriter -import base64 -from odoo import api, fields, models, _ - - -class GlassofExporterWizard(models.TransientModel): - FILENAME = 'invoices_glasof.xls' - _name = 'glasof.exporter.wizard' - - date_start = fields.Date("Start Date") - date_end = fields.Date("End Date") - export_journals = fields.Boolean("Export Account Movements?", default=True) - export_invoices = fields.Boolean("Export Invoices?", default=True) - seat_num = fields.Integer("Seat Number Start", default=1) - xls_journals_filename = fields.Char() - xls_journals_binary = fields.Binary() - xls_invoices_filename = fields.Char() - xls_invoices_binary = fields.Binary() - - @api.model - def _export_journals(self): - file_data = BytesIO() - workbook = xlsxwriter.Workbook(file_data, { - 'strings_to_numbers': True, - 'default_date_format': 'dd/mm/yyyy' - }) - - company_id = self.env.user.company_id - workbook.set_properties({ - 'title': 'Exported data from ' + company_id.name, - 'subject': 'PMS Data from Odoo of ' + company_id.name, - 'author': 'Odoo ALDA PMS', - 'manager': 'Jose Luis Algara', - 'company': company_id.name, - 'category': 'Hoja de Calculo', - 'keywords': 'pms, odoo, alda, data, ' + company_id.name, - 'comments': 'Created with Python in Odoo and XlsxWriter'}) - workbook.use_zip64() - - xls_cell_format_seat = workbook.add_format({'num_format': '#'}) - xls_cell_format_date = workbook.add_format({ - 'num_format': 'dd/mm/yyyy' - }) - xls_cell_format_saccount = workbook.add_format({ - 'num_format': '000000' - }) - xls_cell_format_money = workbook.add_format({ - 'num_format': '#,##0.00' - }) - xls_cell_format_header = workbook.add_format({ - 'bg_color': '#CCCCCC' - }) - - worksheet = workbook.add_worksheet('Simples-1') - - worksheet.write('A1', _('Seat'), xls_cell_format_header) - worksheet.write('B1', _('Date'), xls_cell_format_header) - worksheet.write('C1', _('SubAccount'), xls_cell_format_header) - worksheet.write('D1', _('Description'), xls_cell_format_header) - worksheet.write('E1', _('Concept'), xls_cell_format_header) - worksheet.write('F1', _('Debit'), xls_cell_format_header) - worksheet.write('G1', _('Credit'), xls_cell_format_header) - worksheet.write('H1', _('Seat Type'), xls_cell_format_header) - - worksheet.set_column('B:B', 11) - worksheet.set_column('E:E', 50) - - account_move_obj = self.env['account.move'] - account_moves = account_move_obj.search([ - ('date', '>=', self.date_start), - ('date', '<=', self.date_end), - ]) - start_seat = self.seat_num - nrow = 1 - for move in account_moves: - nmove = True - for line in move.line_ids: - if line.journal_id.type in ('cash', 'bank'): - worksheet.write(nrow, 0, nmove and start_seat or '', - xls_cell_format_seat) - worksheet.write(nrow, 1, nmove and line.date or '', - xls_cell_format_date) - worksheet.write(nrow, 2, line.account_id.code, - xls_cell_format_saccount) - worksheet.write(nrow, 3, '') - worksheet.write(nrow, 4, line.ref and line.ref[:50] or '') - worksheet.write(nrow, 5, line.debit, xls_cell_format_money) - worksheet.write(nrow, 6, line.credit, - xls_cell_format_money) - worksheet.write(nrow, 7, '') - nmove = False - nrow += 1 - start_seat += 1 - - workbook.close() - file_data.seek(0) - tnow = fields.Datetime.now().replace(' ', '_') - return { - 'xls_journals_filename': 'journals_glasof_%s.xlsx' % tnow, - 'xls_journals_binary': base64.encodestring(file_data.read()), - } - - @api.model - def _export_invoices(self): - file_data = BytesIO() - workbook = xlsxwriter.Workbook(file_data, { - 'strings_to_numbers': True, - 'default_date_format': 'dd/mm/yyyy' - }) - - company_id = self.env.user.company_id - workbook.set_properties({ - 'title': 'Exported data from ' + company_id.name, - 'subject': 'PMS Data from Odoo of ' + company_id.name, - 'author': 'Odoo ALDA PMS', - 'manager': 'Jose Luis Algara', - 'company': company_id.name, - 'category': 'Hoja de Calculo', - 'keywords': 'pms, odoo, alda, data, ' + company_id.name, - 'comments': 'Created with Python in Odoo and XlsxWriter'}) - workbook.use_zip64() - - xls_cell_format_seat = workbook.add_format({'num_format': '#'}) - xls_cell_format_date = workbook.add_format({ - 'num_format': 'dd/mm/yyyy' - }) - xls_cell_format_saccount = workbook.add_format({ - 'num_format': '000000' - }) - xls_cell_format_money = workbook.add_format({ - 'num_format': '#,##0.00' - }) - xls_cell_format_odec = workbook.add_format({ - 'num_format': '#,#0.0' - }) - xls_cell_format_header = workbook.add_format({ - 'bg_color': '#CCCCCC' - }) - - worksheet = workbook.add_worksheet('ventas') - - account_inv_obj = self.env['account.invoice'] - account_invs = account_inv_obj.search([ - ('date', '>=', self.date_start), - ('date', '<=', self.date_end), - ]) - - nrow = 1 - for inv in account_invs: - if inv.partner_id.parent_id: - firstname = inv.partner_id.parent_id.firstname or '' - lastname = inv.partner_id.parent_id.lastname or '' - else: - firstname = inv.partner_id.firstname or '' - lastname = inv.partner_id.lastname or '' - - worksheet.write(nrow, 0, inv.number) - worksheet.write(nrow, 1, inv.date_invoice, xls_cell_format_date) - worksheet.write(nrow, 2, '') - worksheet.write(nrow, 3, inv.partner_id.vat and - inv.partner_id.vat[:2] or '') - worksheet.write(nrow, 4, inv.partner_id.vat and - inv.partner_id.vat[2:] or '') - worksheet.write(nrow, 5, lastname) - worksheet.write(nrow, 6, '') - worksheet.write(nrow, 7, firstname) - worksheet.write(nrow, 8, 705.0, xls_cell_format_odec) - worksheet.write(nrow, 9, inv.amount_untaxed, xls_cell_format_money) - if any(inv.tax_line_ids): - worksheet.write(nrow, - 10, - inv.tax_line_ids[0].tax_id.amount, - xls_cell_format_money) - else: - worksheet.write(nrow, 10, '') - worksheet.write(nrow, 11, inv.tax_line_ids and - inv.tax_line_ids[0].amount or '', - xls_cell_format_money) - worksheet.write(nrow, 12, '') - worksheet.write(nrow, 13, '') - worksheet.write(nrow, 14, '') - worksheet.write(nrow, 15, '') - worksheet.write(nrow, 16, '') - worksheet.write(nrow, 17, '') - worksheet.write(nrow, 18, '') - worksheet.write(nrow, 19, '') - worksheet.write(nrow, 20, '') - worksheet.write(nrow, 21, 'S') - worksheet.write(nrow, 22, '') - if inv.type == 'out_refund': - worksheet.write(nrow, 23, inv.invoice_origin) - else: - worksheet.write(nrow, 23, '') - worksheet.write(nrow, 24, '') - worksheet.write(nrow, 25, '') - worksheet.write(nrow, 27, '') - worksheet.write(nrow, 28, '') - worksheet.write(nrow, 29, '') - worksheet.write(nrow, 30, '') - worksheet.write(nrow, 31, '') - worksheet.write(nrow, 32, '') - worksheet.write(nrow, 33, '') - worksheet.write(nrow, 34, '') - worksheet.write(nrow, 35, '') - worksheet.write(nrow, 36, '') - worksheet.write(nrow, 37, '') - worksheet.write(nrow, 38, '') - worksheet.write(nrow, 39, '') - worksheet.write(nrow, 40, '') - worksheet.write(nrow, 41, '') - worksheet.write(nrow, 42, '') - worksheet.write(nrow, 43, '430') - nrow += 1 - - workbook.add_worksheet('compras') - workbook.close() - file_data.seek(0) - tnow = fields.Datetime.now().replace(' ', '_') - return { - 'xls_invoices_filename': 'invoices_glasof_%s.xlsx' % tnow, - 'xls_invoices_binary': base64.encodestring(file_data.read()), - } - - - def export(self): - towrite = {} - if self.export_journals: - towrite.update(self._export_journals()) - if self.export_invoices: - towrite.update(self._export_invoices()) - if any(towrite): - self.write(towrite) - return { - "type": "ir.actions.do_nothing", - } diff --git a/glasof_exporter/wizard/glasof_wizard.xml b/glasof_exporter/wizard/glasof_wizard.xml deleted file mode 100644 index 4b0939968..000000000 --- a/glasof_exporter/wizard/glasof_wizard.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - glasof.exporter.wizard - glasof.exporter.wizard - -
- - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
- - - Export to Glasof - ir.actions.act_window - glasof.exporter.wizard - - form - new - - -
diff --git a/hotel_calendar/README.rst b/hotel_calendar/README.rst deleted file mode 100644 index 9a77798c3..000000000 --- a/hotel_calendar/README.rst +++ /dev/null @@ -1,61 +0,0 @@ -.. This file is going to be generated by oca-gen-addon-readme. Manual changes will be overwritten. - -HOTEL CALENDAR -============== -This module allows you to handle reservations, prices and restriction plans in a user friendly calendar view. - -Description ------------- -This module extends the functionality of roomdoo. - -The calendar displays your rooms in a range of dates. -The rooms can be filtered by class, type or even amenities creating new calendars for easily manage all your reservations. -You can manage prices and restrictions day by day using the calendar management view. - -This module adds two new view types: ``pms`` and ``mpms``. -The module also incorporates a longpolling for delivering instant notification when using the calendar. - -Installation ------------- -This module depends on modules ``hotel``, ``bus``, ``web``, ``calendar``, and ``web_widget_color``. -Ensure yourself to have all them in your addons list. - -Configuration -------------- -No action required. The module is pre-configured with default values. - -You will find the hotel calendar settings in `Settings > Users & Companies > Hotels > Your Hotel > Calendar Settings Tab`. - -Reservation colors can be configured by company in `Settings > Users & Companies > Companies > Your Company > Hotel Preferences Tab.` - -Usage ------ -To use this module, you need to: - -* Go to Hotel Calendar menu for managing reservations. -* Go to Hotel Calendar Management for managing prices and restrictions. -* Go to Hotel Management/Configuration/Calendars menu for managing calendar tabs. - -Shortcuts -_________ -* ``CTRL + LEFT MOUSE CLICK`` on a reservation - start reservation swap -* ``ESC`` - cancel active action (ie. swap) - - -Credits -------- - -Authors -_______ -- Alexandre Díaz - -Contributors -____________ -* Pablo Quesada - -Roadmap -------- -* [ ] Implement the calendar view as an Odoo native view type. -* [ ] Re-design the calendar using SVG or other Odoo native approach. - -Do you want to contribute? Please, do not hesitate to contact any of the authors or contributors. \ No newline at end of file diff --git a/hotel_calendar/__init__.py b/hotel_calendar/__init__.py deleted file mode 100644 index bc60815fd..000000000 --- a/hotel_calendar/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from . import models -from . import controllers diff --git a/hotel_calendar/__manifest__.py b/hotel_calendar/__manifest__.py deleted file mode 100644 index 3008030fa..000000000 --- a/hotel_calendar/__manifest__.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -{ - 'name': 'Roomdoo Calendar', - 'summary': 'A calendar view for user friendly handling your roomdoo property.', - 'version': '11.0.2.0', - 'development_status': 'Beta', - 'category': 'Generic Modules/Hotel Management', - 'website': 'https://github.com/hootel/hootel', - 'author': 'Alexandre Díaz ', - 'license': "AGPL-3", - 'application': False, - 'installable': True, - 'depends': [ - 'bus', - 'web', - 'calendar', - 'hotel', - 'web_widget_color', - ], - # 'external_dependencies': { - # 'python': [] - # }, - 'data': [ - 'views/general.xml', - 'views/actions.xml', - 'views/inherited_hotel_property_views.xml', - 'views/inherited_res_company_views.xml', - 'views/inherited_res_users_views.xml', - 'views/hotel_reservation_views.xml', - 'views/hotel_calendar_management_views.xml', - 'views/hotel_calendar_views.xml', - 'data/menus.xml', - 'security/ir.model.access.csv', - ], - 'qweb': [ - 'static/src/xml/hotel_calendar_management_view.xml', - 'static/src/xml/hotel_calendar_templates.xml', - 'static/src/xml/hotel_calendar_view.xml', - ], -} diff --git a/hotel_calendar/controllers/__init__.py b/hotel_calendar/controllers/__init__.py deleted file mode 100644 index de7342fae..000000000 --- a/hotel_calendar/controllers/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from . import bus diff --git a/hotel_calendar/controllers/bus.py b/hotel_calendar/controllers/bus.py deleted file mode 100644 index ebb36b2e8..000000000 --- a/hotel_calendar/controllers/bus.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo.http import request -from odoo.addons.bus.controllers.main import BusController - -HOTEL_BUS_CHANNEL_ID = 'hpublic' - - -# More info... -# https://github.com/odoo/odoo/commit/092cf33f93830daf5e704b964724bdf8586da8d9 -class Controller(BusController): - def _poll(self, dbname, channels, last, options): - if request.session.uid: - # registry, cr, uid, context = request.registry, request.cr, \ - # request.session.uid, request.context - channels = channels + [( - request.db, - 'hotel.reservation', - HOTEL_BUS_CHANNEL_ID - )] - return super(Controller, self)._poll(dbname, channels, last, options) diff --git a/hotel_calendar/data/menus.xml b/hotel_calendar/data/menus.xml deleted file mode 100644 index 9860b6d56..000000000 --- a/hotel_calendar/data/menus.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Hotel Calendar - hotel.reservation - pms - - - - Hotel Calendar Management - hotel.calendar.management - mpms - - - - - - - - - diff --git a/hotel_calendar/i18n/es.po b/hotel_calendar/i18n/es.po deleted file mode 100644 index 110018e03..000000000 --- a/hotel_calendar/i18n/es.po +++ /dev/null @@ -1,1383 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * hotel_calendar -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 11.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-03-09 18:34+0000\n" -"PO-Revision-Date: 2019-03-10 10:05+0100\n" -"Last-Translator: <>\n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Language: es\n" -"X-Generator: Poedit 1.8.7.1\n" - -#. module: hotel_calendar -#: selection:res.users,npms_end_day_week_offset:0 -#: selection:res.users,pms_end_day_week_offset:0 -msgid "0 Days" -msgstr "0 Días" - -#. module: hotel_calendar -#: selection:res.users,npms_end_day_week_offset:0 -#: selection:res.users,pms_end_day_week_offset:0 -msgid "1 Days" -msgstr "1 Día" - -#. module: hotel_calendar -#: selection:res.users,npms_default_num_days:0 -#: selection:res.users,pms_default_num_days:0 -msgid "1 Month" -msgstr "1 Mes" - -#. module: hotel_calendar -#: selection:res.users,npms_default_num_days:0 -#: selection:res.users,pms_default_num_days:0 -msgid "1 Week" -msgstr "1 Semana" - -#. module: hotel_calendar -#: selection:res.users,npms_end_day_week_offset:0 -#: selection:res.users,pms_end_day_week_offset:0 -msgid "2 Days" -msgstr "2 Días" - -#. module: hotel_calendar -#: selection:res.users,npms_default_num_days:0 -#: selection:res.users,pms_default_num_days:0 -msgid "2 Weeks" -msgstr "2 Semanas" - -#. module: hotel_calendar -#: selection:res.users,npms_end_day_week_offset:0 -#: selection:res.users,pms_end_day_week_offset:0 -msgid "3 Days" -msgstr "3 Días" - -#. module: hotel_calendar -#: selection:res.users,npms_default_num_days:0 -#: selection:res.users,pms_default_num_days:0 -msgid "3 Weeks" -msgstr "3 Semanas" - -#. module: hotel_calendar -#: selection:res.users,npms_end_day_week_offset:0 -#: selection:res.users,pms_end_day_week_offset:0 -msgid "4 Days" -msgstr "4 Días" - -#. module: hotel_calendar -#: selection:res.users,npms_end_day_week_offset:0 -#: selection:res.users,pms_end_day_week_offset:0 -msgid "5 Days" -msgstr "5 Días" - -#. module: hotel_calendar -#: selection:res.users,npms_end_day_week_offset:0 -#: selection:res.users,pms_end_day_week_offset:0 -msgid "6 Days" -msgstr "6 Días" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:21 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:43 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:134 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:262 -#, python-format -msgid "Adults:" -msgstr "Adultos:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_management_view.xml:49 -#, python-format -msgid "All" -msgstr "Todo" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_npms_allowed_events_tags -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_pms_allowed_events_tags -msgid "Allow Calander Event Tags" -msgstr "Permitir Eventos etiquetados en el Calendario" - -#. module: hotel_calendar -#: selection:res.users,pms_type_move:0 -msgid "Allow Invalid" -msgstr "Permitir Inválidas" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_npms_end_day_week_offset -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_pms_end_day_week_offset -msgid "Also illuminate the previous" -msgstr "Sombrear también los previos" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_amenity_ids -msgid "Amenity" -msgstr "Característica" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:59 -#, python-format -msgid "Are you sure you want to change these prices?" -msgstr "Estás seguro de que quieres modificar estos precios?" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:53 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:67 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:81 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:89 -#, python-format -msgid "Are you sure you want to make this changes?" -msgstr "¿Estás seguo de que quieres confirmar estos cambios?" - -#. module: hotel_calendar -#: selection:res.users,pms_type_move:0 -msgid "Assisted" -msgstr "Asistido" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:117 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:276 -#, python-format -msgid "Availability" -msgstr "Disponibilidad" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:102 -#, python-format -msgid "Books" -msgstr "Reservas" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:115 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:274 -#, python-format -msgid "C. Arrival" -msgstr "Cerrar Llegada" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:114 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:273 -#, python-format -msgid "C. Departure" -msgstr "Cerrar Salida" - -#. module: hotel_calendar -#: model:ir.ui.view,arch_db:hotel_calendar.res_users_view_form -msgid "Calendar (PMS)" -msgstr "Calendario (PMS)" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_view.js:43 -#, python-format -msgid "Calendar MPMS" -msgstr "Calendario MPMS" - -#. module: hotel_calendar -#: model:ir.ui.view,arch_db:hotel_calendar.res_users_view_form -msgid "Calendar Management (Revenue PMS)" -msgstr "Calendario de Configuración (Revenue PMS)" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_view.js:163 -#, python-format -msgid "Calendar PMS" -msgstr "Calendario (PMS)" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:365 -#, python-format -msgid "Calendar Settings" -msgstr "Configuración Calendario" - -#. module: hotel_calendar -#: model:ir.ui.menu,name:hotel_calendar.hotel_calendar_record_menu -msgid "Calendars" -msgstr "Calendarios" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:130 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:289 -#, python-format -msgid "Cancel" -msgstr "Cancelar" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:72 -#, python-format -msgid "Cancelled" -msgstr "Canceladas" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:350 -#, python-format -msgid "Check-In:" -msgstr "Entrada:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:351 -#, python-format -msgid "Check-Out:" -msgstr "Salida:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:206 -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_stay -#, python-format -msgid "Checkin" -msgstr "Checkin" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:12 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:34 -#, python-format -msgid "Checkin:" -msgstr "Entrada:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_renderer.js:241 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:35 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:105 -#, python-format -msgid "Checkins" -msgstr "Checkins" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_checkout -msgid "Checkout" -msgstr "Checkout" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:15 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:37 -#, python-format -msgid "Checkout:" -msgstr "Salida" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:26 -#, python-format -msgid "Checkouts" -msgstr "Checkouts" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:135 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:263 -#, python-format -msgid "Children:" -msgstr "Niños:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:129 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:288 -#, python-format -msgid "Clone" -msgstr "Clonar" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:113 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:272 -#, python-format -msgid "Closed" -msgstr "Cerrado" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:335 -#, python-format -msgid "Closed Arrival:" -msgstr "Cerrar Llegada:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:336 -#, python-format -msgid "Closed Departure:" -msgstr "Cerrar Salida:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:334 -#, python-format -msgid "Closed:" -msgstr "Cerrado:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:122 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:281 -#, python-format -msgid "Clousure" -msgstr "Cerrado" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_reservation_reserve_color -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_reservation_reserve_color_text -msgid "Color" -msgstr "Color" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:648 -#, python-format -msgid "Confirm Reservation Changes" -msgstr "Confirmar cambios de reserva" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:568 -#, python-format -msgid "Confirm Reservation Swap" -msgstr "Confirmar intercambio de reservas" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:516 -#, python-format -msgid "Confirm Split Reservation" -msgstr "Confirmar división de reserva" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:547 -#, python-format -msgid "Confirm Unify Reservations" -msgstr "Confirmar fusión de reservas" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_reservation -msgid "Confirmed Reservation " -msgstr "Reservas Confirmada" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:274 -#, python-format -msgid "Continue" -msgstr "Continuar" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:127 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:286 -#, python-format -msgid "Copy" -msgstr "Copar" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:768 -#, python-format -msgid "Create: " -msgstr "Creado: " - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_bus_hotel_calendar_create_uid -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_create_uid -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_management_create_uid -msgid "Created by" -msgstr "Creado por" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_bus_hotel_calendar_create_date -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_create_date -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_management_create_date -msgid "Created on" -msgstr "Creado en" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_npms_default_num_days -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_pms_default_num_days -msgid "Default number of days" -msgstr "Num. por defecto de días" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_npms_denied_events_tags -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_pms_denied_events_tags -msgid "Deny Calander Event Tags" -msgstr "Denegar Eventos etiquetados en el Calendario" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_bus_hotel_calendar_display_name -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_display_name -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_management_display_name -msgid "Display Name" -msgstr "Nombre mostrado" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:81 -#, python-format -msgid "Divide" -msgstr "Dividir" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:378 -#, python-format -msgid "Divide Rooms by Capacity" -msgstr "Dividir las filas por capacidad" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_pms_divide_rooms_by_capacity -msgid "Divide rooms by capacity" -msgstr "Dividir las filas por capacidad" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:342 -#, python-format -msgid "Do you want to confirm this folio?" -msgstr "Deseas confirmar la ficha?" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:359 -#, python-format -msgid "Do you want to save these changes?" -msgstr "Deseas confirmar la ficha?" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_dontsell -msgid "Dont Sell" -msgstr "No vender" - -#. module: hotel_calendar -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:106 -#, python-format -msgid "Email not provided" -msgstr "Email no proporcionado" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:279 -#, python-format -msgid "End" -msgstr "Fin" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_npms_end_day_week -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_pms_end_day_week -msgid "End day of week" -msgstr "Último día de Semana" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_management_view.xml:25 -#, python-format -msgid "FROM" -msgstr "DE" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:116 -#, python-format -msgid "Filters" -msgstr "Filtros" - -#. module: hotel_calendar -#: code:addons/hotel_calendar/models/inherited_hotel_folio.py:24 -#, python-format -msgid "Folio Deleted" -msgstr "Ficha Eliminada" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:214 -#, python-format -msgid "Folio Payments" -msgstr "Pagos en Ficha" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:146 -#, python-format -msgid "Folio Pending" -msgstr "Pendiente en Ficha" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_renderer.js:247 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:111 -#, python-format -msgid "Folios" -msgstr "Fichas" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:123 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:282 -#, python-format -msgid "Free Rooms" -msgstr "Habitaciones Libres" - -#. module: hotel_calendar -#: selection:res.users,npms_end_day_week:0 -#: selection:res.users,pms_end_day_week:0 -msgid "Friday" -msgstr "Viernes" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:358 -#, python-format -msgid "Have unsaved changes!" -msgstr "Tienes cambios sin guardar!" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_renderer.js:22 -#: model:ir.actions.act_window,name:hotel_calendar.action_hotel_calendar -#: model:ir.actions.act_window,name:hotel_calendar.hotel_calendar_action_form_tree -#: model:ir.ui.menu,name:hotel_calendar.hotel_calendar_menu -#: model:ir.ui.view,arch_db:hotel_calendar.hotel_calendar_view_form -#: model:ir.ui.view,arch_db:hotel_calendar.hotel_calendar_view_tree -#, python-format -msgid "Hotel Calendar" -msgstr "Calendario del Hotel" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:22 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:57 -#: model:ir.actions.act_window,name:hotel_calendar.action_hotel_calendar_management -#: model:ir.ui.menu,name:hotel_calendar.hotel_calendar_management_menu -#, python-format -msgid "Hotel Calendar Management" -msgstr "Calendario de Configuración del Hotel" - -#. module: hotel_calendar -#: model:ir.model,name:hotel_calendar.model_hotel_folio -msgid "Hotel Folio" -msgstr "Ficha de reservas" - -#. module: hotel_calendar -#: model:ir.model,name:hotel_calendar.model_hotel_reservation -msgid "Hotel Reservation" -msgstr "Reserva del hotel" - -#. module: hotel_calendar -#: model:ir.actions.act_window,name:hotel_calendar.hotel_reservation_action_checkin -msgid "Hotel folio checkin" -msgstr "Hotel Ficha Checkin" - -#. module: hotel_calendar -#: model:ir.actions.act_window,name:hotel_calendar.hotel_reservation_action_checkout -msgid "Hotel folio checkout" -msgstr "Hotel Ficha Checkout" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_bus_hotel_calendar_id -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_id -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_management_id -msgid "ID" -msgstr "ID (identificación)" - -#. module: hotel_calendar -#: code:addons/hotel_calendar/models/hotel_calendar_management.py:198 -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:367 -#, python-format -msgid "Input Error: No dates defined!" -msgstr "Error de entrada: ¡no hay fechas definidas!" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:592 -#, python-format -msgid "Invalid Reservation Swap" -msgstr "Intercambio no válido" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:73 -#, python-format -msgid "Invalid Swap Operation, can't make this movement :/" -msgstr "No podemos hacer la operación, movimiento no válido de reservas :/" - -#. module: hotel_calendar -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:452 -#, python-format -msgid "Invalid swap parameters" -msgstr "Valores incorrectos para el swap" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:221 -#, python-format -msgid "Invoice Folio" -msgstr "Facturar Ficha" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_renderer.js:244 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:108 -#, python-format -msgid "Invoices" -msgstr "Facturas" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_bus_hotel_calendar___last_update -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar___last_update -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_management___last_update -msgid "Last Modified on" -msgstr "Última modificación en" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_bus_hotel_calendar_write_uid -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_management_write_uid -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_write_uid -msgid "Last Updated by" -msgstr "Última actualización de" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_bus_hotel_calendar_write_date -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_management_write_date -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_write_date -msgid "Last Updated on" -msgstr "Última actualización en" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_management_view.xml:62 -#, python-format -msgid "Launch Massive Changes" -msgstr "Guardar Cambios Masivos" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_letter_reservation -msgid "Letter Confirmed Reservation " -msgstr "Texto de Reserva confirmada" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_letter_pre_reservation -msgid "Letter Pre-reservation" -msgstr "Texto de Reserva sin confirmar" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_letter_stay -msgid "Letter Checkin" -msgstr "Texto de Checkin (Dentro) " - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_letter_checkout -msgid "Letter Checkout" -msgstr "Texto de Checkout (Fuera)" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_letter_dontsell -msgid "Letter Dont Sell" -msgstr "Texto de Fuera de Servicio " - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_letter_to_assign -msgid "Letter Ota to Assign" -msgstr "Texto de Por Asignar" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_letter_reservation_pay -msgid "Letter Paid Reservation" -msgstr "Texto de Reserva Pagada" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_letter_payment_pending -msgid "Letter Payment Pending" -msgstr "Texto de Pagos Pendientes" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_letter_staff -msgid "Letter Staff" -msgstr "Texto de Staff" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_letter_stay_pay -msgid "Letter Stay Pay" -msgstr "Texto de Checkin Pagado" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_location_ids -msgid "Location" -msgstr "Ubicación" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_management_view.xml:51 -#, python-format -msgid "Low" -msgstr "Bajo" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:352 -#, python-format -msgid "Made by:" -msgstr "Hecho por:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:119 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:278 -#, python-format -msgid "Max. Stay" -msgstr "Max. Estancia" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:121 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:280 -#, python-format -msgid "Max. Stay Arrival" -msgstr "Max. Stay Arrival" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:333 -#, python-format -msgid "Max. Stay Arrival:" -msgstr "Max. Est. Llegada:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:332 -#, python-format -msgid "Max. Stay:" -msgstr "Max. Estancia:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_management_view.xml:50 -#, python-format -msgid "Medium" -msgstr "Medio" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:118 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:277 -#, python-format -msgid "Min. Stay" -msgstr "Min. Estancia" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:120 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:279 -#, python-format -msgid "Min. Stay Arrival" -msgstr "Min. Estancia Llegada" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:331 -#, python-format -msgid "Min. Stay:" -msgstr "Min. Estancia:" - -#. module: hotel_calendar -#: selection:res.users,npms_end_day_week:0 -#: selection:res.users,pms_end_day_week:0 -msgid "Monday" -msgstr "Lunes" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_name -msgid "Name" -msgstr "Nombre" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:97 -#, python-format -msgid "Name, Mail, Vat, Book..." -msgstr "Nombre, Mail, NIF, Nº Reserva..." - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:348 -#, python-format -msgid "Name:" -msgstr "Nombre:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:326 -#, python-format -msgid "Nights:" -msgstr "Noches" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:527 -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:558 -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:606 -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:678 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:448 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:590 -#, python-format -msgid "No" -msgstr "No" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:124 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:283 -#, python-format -msgid "No OTA" -msgstr "No OTA" - -#. module: hotel_calendar -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:124 -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:431 -#, python-format -msgid "No board services" -msgstr "Sin servicios incluidos" - -#. module: hotel_calendar -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:120 -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:428 -#, python-format -msgid "No reason given" -msgstr "Sin motivo explícito" - -#. module: hotel_calendar -#: selection:res.users,pms_type_move:0 -msgid "Normal" -msgstr "Normal" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:595 -#, python-format -msgid "Oops, Ok!" -msgstr "Oops, Ok!" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:112 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:271 -#, python-format -msgid "Open" -msgstr "Abrir" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:125 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:284 -#, python-format -msgid "Options" -msgstr "Opciones" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_to_assign -msgid "Ota Reservation to Assign" -msgstr "Reserva por Asignar" - -#. module: hotel_calendar -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:78 -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:101 -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:400 -#, python-format -msgid "Out of service" -msgstr "Fuera de Servicio" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:62 -#, python-format -msgid "Overbook." -msgstr "Overbook." - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:321 -#, python-format -msgid "Overbooking Management" -msgstr "Gestión de Overbooking" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_stay_pay -msgid "Paid Checkin" -msgstr "Checkin Pagado" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_reservation_pay -msgid "Paid Reservation" -msgstr "Reserva Pagada" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:128 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:287 -#, python-format -msgid "Paste" -msgstr "Pegar" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_payment_pending -msgid "Payment Pending" -msgstr "Pagos Pendientes" - -#. module: hotel_calendar -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:105 -#, python-format -msgid "Phone not provided" -msgstr "Teléfono no disponible" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_pre_reservation -msgid "Pre-reservation" -msgstr "Reserva sin Confirmar" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:116 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:275 -#, python-format -msgid "Price" -msgstr "Precio" - -#. module: hotel_calendar -#: model:ir.model,name:hotel_calendar.model_product_pricelist -msgid "Pricelist" -msgstr "Tarifas" - -#. module: hotel_calendar -#: model:ir.model,name:hotel_calendar.model_product_pricelist_item -msgid "Pricelist item" -msgstr "Elemento Tarifa" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:768 -#, python-format -msgid "Reservation" -msgstr "Reserva" - -#. module: hotel_calendar -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:486 -#, python-format -msgid "Reservation Created" -msgstr "Reserva Creada" - -#. module: hotel_calendar -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:500 -#, python-format -msgid "Reservation Deleted" -msgstr "Reserva Eliminada" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:216 -#, python-format -msgid "Reservation Payments" -msgstr "Pagos de la reserva" - -#. module: hotel_calendar -#: model:ir.ui.view,arch_db:hotel_calendar.res_users_view_form -msgid "Reservation States Colours" -msgstr "Colores por estado de la Reserva" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_pms_type_move -msgid "Reservation move mode" -msgstr "Modo de Movimiento de Reservas" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_renderer.js:238 -#, python-format -msgid "Reservations" -msgstr "Reservas" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:31 -#, python-format -msgid "Reserve changed:" -msgstr "Reserva modificada:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:9 -#, python-format -msgid "Reserve unchanged:" -msgstr "Reserva no modificada:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:126 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:285 -#, python-format -msgid "Reset" -msgstr "Restablecer" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_room_type_ids -msgid "Room Type" -msgstr "Tipo de Habitación" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:307 -#, python-format -msgid "Room Type:" -msgstr "Tipo de Habitación:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:18 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:40 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:349 -#, python-format -msgid "Room:" -msgstr "Habitación:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:99 -#, python-format -msgid "Sales Channel:" -msgstr "Canal de Venta:" - -#. module: hotel_calendar -#: selection:res.users,npms_end_day_week:0 -#: selection:res.users,pms_end_day_week:0 -msgid "Saturday" -msgstr "Sábado" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_management_view.xml:12 -#, python-format -msgid "Save Changes" -msgstr "Guardar Cambios" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_hotel_calendar_segmentation_ids -msgid "Segmentation" -msgstr "Segmentación" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:120 -#, python-format -msgid "Select Amenities..." -msgstr "Seleccionar caraterísticas..." - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:119 -#, python-format -msgid "Select Location..." -msgstr "Selecciones ubicación..." - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:118 -#, python-format -msgid "Select Segmentation..." -msgstr "Seleccionar Segmentación..." - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:121 -#, python-format -msgid "Select Type..." -msgstr "Seleccionar Tipo..." - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:210 -#, python-format -msgid "Send Reservation Email" -msgstr "Enviar Mail de Reserva" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:377 -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_pms_show_availability -#, python-format -msgid "Show Availability" -msgstr "Mostrar Disponibilidad" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:375 -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_pms_show_notifications -#, python-format -msgid "Show Notifications" -msgstr "Mostrar Notificaciones" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_pms_show_num_rooms -msgid "Show Num. Rooms" -msgstr "Num. Habitaciones a mostrar" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:376 -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_pms_show_pricelist -#, python-format -msgid "Show Pricelist" -msgstr "Mostrar Tarifas" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:80 -#, python-format -msgid "Split Reservation" -msgstr "Dividir Reserva" - -#. module: hotel_calendar -#: model:ir.model.fields,field_description:hotel_calendar.field_res_users_color_staff -msgid "Staff" -msgstr "Staff" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:284 -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:614 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:44 -#, python-format -msgid "Start Swap" -msgstr "Comenzar Intercambio" - -#. module: hotel_calendar -#: selection:res.users,npms_end_day_week:0 -#: selection:res.users,pms_end_day_week:0 -msgid "Sunday" -msgstr "Domingo" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:66 -#, python-format -msgid "Swap Reservations" -msgstr "Intercambio reservas" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_management_view.xml:34 -#, python-format -msgid "TO" -msgstr "A" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:105 -#, python-format -msgid "TODO: add call center information" -msgstr "TODO: add call center information" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:5 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:65 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:79 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:87 -#, python-format -msgid "The following changes will be made..." -msgstr "Los próximos cambios serán realizados..." - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:6 -#, python-format -msgid "This reservation belongs to a folio with more reservations!" -msgstr "Esta reserva pertenece a un folio con más reservas!" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:233 -#, python-format -msgid "This reservation is part of splitted reservation." -msgstr "Ésta reserva es solo una parte de una reserva dividida." - -#. module: hotel_calendar -#: selection:res.users,npms_end_day_week:0 -#: selection:res.users,pms_end_day_week:0 -msgid "Thursday" -msgstr "Jueves" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:373 -#, python-format -msgid "Toggle Advance Controls" -msgstr "Mostrar Controles Avanzados (Alt+x)" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:161 -#, python-format -msgid "Total Paid" -msgstr "Total Pagado" - -#. module: hotel_calendar -#: selection:res.users,npms_end_day_week:0 -#: selection:res.users,pms_end_day_week:0 -msgid "Tuesday" -msgstr "Martes" - -#. module: hotel_calendar -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:417 -#: code:addons/hotel_calendar/models/inherited_hotel_reservation.py:418 -#, python-format -msgid "Undefined" -msgstr "Indefinido" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:90 -#, python-format -msgid "Unify" -msgstr "Fusionar" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:88 -#, python-format -msgid "Unify Reservations" -msgstr "Fusionar Reservas" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:436 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:578 -#, python-format -msgid "Unsaved Changes!" -msgstr "Tienes cambios sin guardar!" - -#. module: hotel_calendar -#: model:ir.model,name:hotel_calendar.model_res_users -msgid "Users" -msgstr "Usuarios" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:198 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:290 -#, python-format -msgid "View Folio Details" -msgstr "Ver detalles de la Ficha" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_management_view.xml:47 -#, python-format -msgid "View Mode:" -msgstr "Modo de Visualización:" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:202 -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_templates.xml:294 -#, python-format -msgid "View Reservation Details" -msgstr "Ver detalles de la reserva" - -#. module: hotel_calendar -#: selection:res.users,npms_end_day_week:0 -#: selection:res.users,pms_end_day_week:0 -msgid "Wednesday" -msgstr "Miércoles" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/xml/hotel_calendar_view.xml:52 -#, python-format -msgid "Wizard" -msgstr "Wizard" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:651 -#, python-format -msgid "Yes, change it" -msgstr "Sí, Cambiálo!" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js:439 -#: code:addons/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v.js:581 -#, python-format -msgid "Yes, save it" -msgstr "Sí, Guardálo!" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:519 -#, python-format -msgid "Yes, split it" -msgstr "Sí, Divídela!" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:571 -#, python-format -msgid "Yes, swap it" -msgstr "Sí, Intercámbialas!" - -#. module: hotel_calendar -#. openerp-web -#: code:addons/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js:550 -#, python-format -msgid "Yes, unify it" -msgstr "Sí, Fusionálas!" - -#. module: hotel_calendar -#: model:ir.model,name:hotel_calendar.model_bus_hotel_calendar -msgid "bus.hotel.calendar" -msgstr "bus.hotel.calendar" - -#. module: hotel_calendar -#: model:ir.model,name:hotel_calendar.model_hotel_calendar -msgid "hotel.calendar" -msgstr "hotel.calendar" - -#. module: hotel_calendar -#: model:ir.model,name:hotel_calendar.model_hotel_calendar_management -msgid "hotel.calendar.management" -msgstr "hotel.calendar.management" - -#. module: hotel_calendar -#: model:ir.model,name:hotel_calendar.model_hotel_room_type_restriction_item -msgid "hotel.room.type.restriction.item" -msgstr "hotel.room.type.restriction.item" - -#. module: hotel_calendar -#: model:ir.model,name:hotel_calendar.model_ir_actions_act_window_view -msgid "ir.actions.act_window.view" -msgstr "ir.actions.act_window.view" - -#. module: hotel_calendar -#: model:ir.model,name:hotel_calendar.model_ir_ui_view -msgid "ir.ui.view" -msgstr "ir.ui.view" diff --git a/hotel_calendar/models/__init__.py b/hotel_calendar/models/__init__.py deleted file mode 100644 index 714a80ba9..000000000 --- a/hotel_calendar/models/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from . import inherited_hotel_property -from . import hotel_calendar -from . import bus_hotel_calendar -from . import hotel_calendar_management -from . import inherited_hotel_reservation -from . import inherited_res_company -from . import inherited_res_users -from . import inherited_hotel_room_type_restriction_item -from . import inherited_product_pricelist_item -from . import inherited_hotel_folio -from . import ir_actions_act_window_view -from . import ir_ui_view diff --git a/hotel_calendar/models/bus_hotel_calendar.py b/hotel_calendar/models/bus_hotel_calendar.py deleted file mode 100644 index c0bffeef3..000000000 --- a/hotel_calendar/models/bus_hotel_calendar.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from datetime import datetime -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT -from odoo import models, api -from odoo.addons.hotel_calendar.controllers.bus import HOTEL_BUS_CHANNEL_ID - - -class BusHotelCalendar(models.TransientModel): - _name = 'bus.hotel.calendar' - - ''' - action: - - create - - write - - unlink - - cancelled - ntype: - - notif : Show a normal notification - - warn : Show a warning notification - - noshow : Don't show any notification - ''' - # Business methods - @api.model - def _generate_reservation_notif(self, vals): - user_id = self.env['res.users'].browse(self.env.uid) - return { - 'type': 'reservation', - 'action': vals['action'], - 'subtype': vals['type'], - 'title': vals['title'], - 'username': user_id.partner_id.name, - 'userid': user_id.id, - 'reservation': { - 'room_id': vals['room_id'], - 'id': vals['reserv_id'], - 'name': vals['partner_name'], - 'adults': vals['adults'], - 'childer': vals['children'], - 'checkin': vals['checkin'], - 'checkout': vals['checkout'], - 'folio_id': vals['folio_id'], - 'bgcolor': vals['reserve_color'], - 'color': vals['reserve_color_text'], - 'splitted': vals['splitted'], - 'parent_reservation': vals['parent_reservation'], - 'room_name': vals['room_name'], - 'state': vals['state'], - 'only_read': False, - 'fix_days': vals['fix_days'], - 'fix_room': False, - 'overbooking': vals['overbooking'], - 'price_room_services_set': vals['price_room_services_set'], - 'amount_total': vals['pending_amount'] + vals['invoices_paid'], - 'real_dates': vals['real_dates'], - 'channel_type': vals['channel_type'], - }, - 'tooltip': { - 'folio_name': vals['folio_name'], - 'name': vals['partner_name'], - 'phone': vals['partner_phone'], - 'email': vals['partner_email'], - 'room_type_name': vals['room_type_name'], - 'adults': vals['adults'], - 'children': vals['children'], - 'checkin': vals['checkin'], - 'checkout': vals['checkout'], - 'arrival_hour': vals['arrival_hour'], - 'departure_hour': vals['departure_hour'], - 'price_room_services_set': vals['price_room_services_set'], - 'invoices_paid': vals['invoices_paid'], - 'pending_amount': vals['pending_amount'], - 'type': vals['reservation_type'], - 'closure_reason': vals['closure_reason'], - 'out_service_description': vals['out_service_description'], - 'splitted': vals['splitted'], - 'real_dates': vals['real_dates'], - 'channel_type': vals['channel_type'], - 'board_service_name': vals['board_service_name'], - 'services': vals['services'], - } - } - - @api.model - def _generate_pricelist_notification(self, vals): - date_dt = datetime.strptime(vals['date'], DEFAULT_SERVER_DATE_FORMAT) - return { - 'type': 'pricelist', - 'price': { - vals['pricelist_id']: [{ - 'days': { - date_dt.strftime("%d/%m/%Y"): vals['price'], - }, - 'room': vals['room_id'], - 'id': vals['id'], - }], - }, - } - - @api.model - def _generate_restriction_notification(self, vals): - date_dt = datetime.strptime(vals['date'], DEFAULT_SERVER_DATE_FORMAT) - return { - 'type': 'restriction', - 'restriction': { - vals['room_type_id']: { - date_dt.strftime("%d/%m/%Y"): [ - vals['min_stay'], - vals['min_stay_arrival'], - vals['max_stay'], - vals['max_stay_arrival'], - vals['closed'], - vals['closed_arrival'], - vals['closed_departure'], - vals['id'], - ], - }, - }, - } - - @api.model - def send_reservation_notification(self, vals): - notif = self._generate_reservation_notif(vals) - self.env['bus.bus'].sendone((self._cr.dbname, 'hotel.reservation', - HOTEL_BUS_CHANNEL_ID), notif) - - @api.model - def send_pricelist_notification(self, vals): - notif = self._generate_pricelist_notification(vals) - self.env['bus.bus'].sendone((self._cr.dbname, 'hotel.reservation', - HOTEL_BUS_CHANNEL_ID), notif) - - @api.model - def send_restriction_notification(self, vals): - notif = self._generate_restriction_notification(vals) - self.env['bus.bus'].sendone((self._cr.dbname, 'hotel.reservation', - HOTEL_BUS_CHANNEL_ID), notif) diff --git a/hotel_calendar/models/hotel_calendar.py b/hotel_calendar/models/hotel_calendar.py deleted file mode 100644 index 68938f2ff..000000000 --- a/hotel_calendar/models/hotel_calendar.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, fields, api - - -class HotelCalendar(models.Model): - """ Used to show and filter rooms and reservations in the PMS Calendar. """ - _name = 'hotel.calendar' - - # Default methods - @api.model - def _get_default_hotel(self): - return self.env.user.hotel_id - - # Fields declaration - name = fields.Char('Name', required=True) - hotel_id = fields.Many2one('hotel.property', 'Hotel', required=True, ondelete='restrict', - default=_get_default_hotel) - room_type_ids = fields.Many2many('hotel.room.type', string='Room Type') - segmentation_ids = fields.Many2many('hotel.room.type.class', string='Segmentation') - location_ids = fields.Many2many('hotel.floor', string='Location') - amenity_ids = fields.Many2many('hotel.amenity', string='Amenity') - diff --git a/hotel_calendar/models/hotel_calendar_management.py b/hotel_calendar/models/hotel_calendar_management.py deleted file mode 100644 index afa137340..000000000 --- a/hotel_calendar/models/hotel_calendar_management.py +++ /dev/null @@ -1,277 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -import logging -from datetime import timedelta -from odoo.tools import ( - DEFAULT_SERVER_DATE_FORMAT, - DEFAULT_SERVER_DATETIME_FORMAT) -from odoo import models, api, _, fields -from odoo.exceptions import AccessError, ValidationError -_logger = logging.getLogger(__name__) - - -class HotelCalendarManagement(models.TransientModel): - _name = 'hotel.calendar.management' - - # Business methods - - def get_hcalendar_settings(self): - return { - 'eday_week': self.env.user.hotel_id.pms_end_day_week, - 'eday_week_offset': self.env.user.hotel_id.pms_end_day_week_offset, - 'days': self.env.user.hotel_id.pms_default_num_days, - 'show_notifications': self.env.user.pms_show_notifications, - 'show_num_rooms': self.env.user.hotel_id.pms_show_num_rooms, - } - - @api.model - def _get_prices_values(self, price): - vals = { - 'fixed_price': price['price'], - } - return vals - - @api.model - def _get_restrictions_values(self, restriction): - vals = { - 'min_stay': restriction['min_stay'], - 'min_stay_arrival': restriction['min_stay_arrival'], - 'max_stay': restriction['max_stay'], - 'max_stay_arrival': restriction['max_stay_arrival'], - 'closed': restriction['closed'], - 'closed_arrival': restriction['closed_arrival'], - 'closed_departure': restriction['closed_departure'], - } - return vals - - @api.model - def _hcalendar_room_json_data(self, rooms): - json_data = [] - for room in rooms: - json_data.append({ - 'id': room.id, - 'name': room.name, - 'capacity': room.get_capacity(), - 'price': room.list_price, - 'total_rooms': room.total_rooms_count, - }) - return json_data - - @api.model - def _hcalendar_pricelist_json_data(self, prices): - json_data = {} - room_type_obj = self.env['hotel.room.type'] - for rec in prices: - room_type_id = room_type_obj.search([ - ('product_id.product_tmpl_id', '=', rec.product_tmpl_id.id) - ], limit=1) - if not room_type_id: - continue - - # TODO: date_end - date_start loop - json_data.setdefault(room_type_id.id, []).append({ - 'id': rec.id, - 'price': rec.fixed_price, - 'date': rec.date_start, - }) - return json_data - - @api.model - def _hcalendar_restriction_json_data(self, restrictions): - json_data = {} - for rec in restrictions: - json_data.setdefault(rec.room_type_id.id, []).append({ - 'id': rec.id, - 'date': rec.date, - 'min_stay': rec.min_stay, - 'min_stay_arrival': rec.min_stay_arrival, - 'max_stay': rec.max_stay, - 'max_stay_arrival': rec.max_stay_arrival, - 'closed': rec.closed, - 'closed_departure': rec.closed_departure, - 'closed_arrival': rec.closed_arrival, - }) - return json_data - - @api.model - def _hcalendar_events_json_data(self, dfrom, dto): - date_start = fields.Date.from_string(dfrom) - timedelta(days=1) - date_start_str = date_start.strftime(DEFAULT_SERVER_DATETIME_FORMAT) - user_id = self.env['res.users'].browse(self.env.uid) - domain = [] - if self.env.user.hotel_id.pms_allowed_events_tags: - domain.append(('categ_ids', 'in', self.env.user.hotel_id.pms_allowed_events_tags)) - if self.env.user.hotel_id.pms_denied_events_tags: - domain.append( - ('categ_ids', 'not in', self.env.user.hotel_id.pms_denied_events_tags)) - events_raw = self.env['calendar.event'].search(domain) - events_ll = self.env['calendar.event'].search([ - ('start', '<=', dto), - ('stop', '>=', date_start_str) - ]) - events_lr = self.env['calendar.event'].search([ - ('start', '>=', date_start_str), - ('stop', '<=', dto) - ]) - events = (events_ll | events_lr) & events_raw - json_data = [] - for event in events: - json_data.append([ - event.id, - event.name, - event.start, - event.location, - ]) - return json_data - - @api.model - def _hcalendar_get_count_reservations_json_data(self, dfrom, dto): - date_start = fields.Date.from_string(dfrom) - date_end = fields.Date.from_string(dto) - date_diff = abs((date_end - date_start).days) + 1 - room_type_obj = self.env['hotel.room.type'] - room_types = room_type_obj.search([]) - json_data = {} - - for room_type in room_types: - for i in range(0, date_diff): - cur_date = date_start + timedelta(days=i) - cur_date_str = cur_date.strftime(DEFAULT_SERVER_DATE_FORMAT) - self.env.cr.execute(''' - SELECT - hrl.id - FROM hotel_reservation_line AS hrl - WHERE date = %s - ''', ((cur_date_str),)) - line_ids = [r[0] for r in self.env.cr.fetchall()] - reservation_ids = self.env['hotel.reservation.line'].browse(line_ids).\ - mapped('reservation_id.id') - reservations = self.env['hotel.reservation'].\ - browse(reservation_ids).filtered( - lambda r: r.state != 'cancelled' - and not r.overbooking and not r.reselling - ) - reservations_rooms = reservations.mapped('room_id.id') - free_rooms = self.env['hotel.room'].search([ - ('id', 'not in', reservations_rooms), - ]) - rooms_linked = self.env['hotel.room.type'].search([ - ('id', '=', room_type.id) - ]).room_ids - free_rooms = free_rooms & rooms_linked - json_data.setdefault(room_type.id, []).append({ - 'date': cur_date_str, - 'num': len(free_rooms), - }) - - return json_data - - @api.model - def get_hcalendar_all_data(self, dfrom, dto, pricelist_id, restriction_id, - withRooms): - hotel_id = self.env.user.hotel_id.id - - if not dfrom or not dto: - raise ValidationError(_('Input Error: No dates defined!')) - vals = {} - # TODO: refactoring res.config.settings', 'default_pricelist_id' by the current hotel.property.pricelist_id - if not pricelist_id: - pricelist_id = self.env.user.hotel_id.default_pricelist_id.id - # TODO: refactoring res.config.settings', 'default_restriction_id by the current hotel.property.restriction_id - if not restriction_id: - restriction_id = self.env.user.hotel_id.default_restriction_id.id - - # TODO: ensure pricelist_id and restriction_id belong to the current hotel - vals.update({'pricelist_id': pricelist_id}) - vals.update({'restriction_id': restriction_id}) - - restriction_item_ids = self.env['hotel.room.type.restriction.item'].search([ - ('date', '>=', dfrom), ('date', '<=', dto), - ('restriction_id', '=', restriction_id), - ]) - pricelist_item_ids = self.env['product.pricelist.item'].search([ - ('date_start', '>=', dfrom), ('date_end', '<=', dto), - ('pricelist_id', '=', pricelist_id), - ('applied_on', '=', '1_product'), - ('compute_price', '=', 'fixed'), - ]) - - json_prices = self._hcalendar_pricelist_json_data(pricelist_item_ids) - json_rest = self._hcalendar_restriction_json_data(restriction_item_ids) - # TODO REVIEW: what are json_rc and json_events used for in calendar management ¿? - json_rc = self._hcalendar_get_count_reservations_json_data(dfrom, dto) - json_events = self._hcalendar_events_json_data(dfrom, dto) - vals.update({ - 'prices': json_prices or [], - 'restrictions': json_rest or [], - 'count_reservations': json_rc or [], - 'events': json_events or [], - }) - - if withRooms: - room_ids = self.env['hotel.room.type'].search([ - ('hotel_id', '=', hotel_id) - ], order='sequence ASC') or None - - if not room_ids: - raise AccessError( - _("Wrong hotel and company access settings for this user. " - "No room types found for hotel %s") % self.env.user.hotel_id.name) - - json_rooms = self._hcalendar_room_json_data(room_ids) - vals.update({'rooms': json_rooms or []}) - - return vals - - @api.model - def save_changes(self, pricelist_id, restriction_id, pricelist, - restrictions, availability=False): - room_type_obj = self.env['hotel.room.type'] - product_pricelist_item_obj = self.env['product.pricelist.item'] - room_type_rest_item_obj = self.env['hotel.room.type.restriction.item'] - - # Save Pricelist - for k_price in pricelist.keys(): - room_type_id = room_type_obj.browse([int(k_price)]) - room_type_prod_tmpl_id = room_type_id.product_id.product_tmpl_id - for price in pricelist[k_price]: - price_id = product_pricelist_item_obj.search([ - ('date_start', '>=', price['date']), - ('date_end', '<=', price['date']), - ('pricelist_id', '=', int(pricelist_id)), - ('applied_on', '=', '1_product'), - ('compute_price', '=', 'fixed'), - ('product_tmpl_id', '=', room_type_prod_tmpl_id.id), - ], limit=1) - vals = self._get_prices_values(price) - if not price_id: - vals.update({ - 'date_start': price['date'], - 'date_end': price['date'], - 'pricelist_id': int(pricelist_id), - 'applied_on': '1_product', - 'compute_price': 'fixed', - 'product_tmpl_id': room_type_prod_tmpl_id.id, - }) - price_id = product_pricelist_item_obj.create(vals) - else: - price_id.write(vals) - - # Save Restrictions - for k_res in restrictions.keys(): - for restriction in restrictions[k_res]: - res_id = room_type_rest_item_obj.search([ - ('date', '=', restriction['date']), - ('restriction_id', '=', int(restriction_id)), - ('room_type_id', '=', int(k_res)), - ], limit=1) - vals = self._get_restrictions_values(restriction) - if not res_id: - vals.update({ - 'date': restriction['date'], - 'restriction_id': int(restriction_id), - 'room_type_id': int(k_res), - }) - res_id = room_type_rest_item_obj.create(vals) - else: - res_id.write(vals) diff --git a/hotel_calendar/models/inherited_hotel_folio.py b/hotel_calendar/models/inherited_hotel_folio.py deleted file mode 100644 index 01929f3de..000000000 --- a/hotel_calendar/models/inherited_hotel_folio.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2018-2019 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, api, _ - - -class HotelFolio(models.Model): - _inherit = 'hotel.folio' - - # ORM overrides - - def write(self, vals): - ret = super(HotelFolio, self).write(vals) - fields_to_check = ('reservation_ids', 'service_ids', 'pending_amount') - fields_checked = [elm for elm in fields_to_check if elm in vals] - if any(fields_checked): - for record in self: - record.reservation_ids.send_bus_notification('write', 'noshow') - return ret - - - def unlink(self): - for record in self: - record.reservation_ids.send_bus_notification('unlink', 'warn', - _("Folio Deleted")) - return super(HotelFolio, self).unlink() - - # Business methods - - def compute_amount(self): - ret = super(HotelFolio, self).compute_amount() - with self.env.norecompute(): - for record in self: - record.reservation_ids.send_bus_notification('write', 'noshow') - return ret diff --git a/hotel_calendar/models/inherited_hotel_property.py b/hotel_calendar/models/inherited_hotel_property.py deleted file mode 100644 index 77a5093e7..000000000 --- a/hotel_calendar/models/inherited_hotel_property.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2019 Pablo Quesada -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, fields - - -class HotelProperty(models.Model): - _inherit = 'hotel.property' - - # Fields declaration - pms_show_num_rooms = fields.Integer('Number of rooms to show', - default=0) - pms_divide_rooms_by_capacity = fields.Boolean('Divide rooms by capacity', - default=True) - pms_end_day_week = fields.Selection([ - ('1', 'Monday'), - ('2', 'Tuesday'), - ('3', 'Wednesday'), - ('4', 'Thursday'), - ('5', 'Friday'), - ('6', 'Saturday'), - ('7', 'Sunday') - ], string='Highlight column of day', default='6') - pms_end_day_week_offset = fields.Selection([ - ('0', '0 Days'), - ('1', '1 Days'), - ('2', '2 Days'), - ('3', '3 Days'), - ('4', '4 Days'), - ('5', '5 Days'), - ('6', '6 Days') - ], string='Also illuminate the previous', default='0') - pms_default_num_days = fields.Selection([ - ('month', '1 Month'), - ('21', '3 Weeks'), - ('14', '2 Weeks'), - ('7', '1 Week') - ], string='Default number of days', default='month') - # TODO: review the use of the following option in the calendar js functions - pms_type_move = fields.Selection([ - ('normal', 'Normal'), - ('assisted', 'Assisted'), - ('allow_invalid', 'Allow Invalid') - ], string='Reservation move mode', default='normal') - - pms_allowed_events_tags = fields.Many2many( - 'calendar.event.type', - string="Allow Calendar Event Tags") - pms_denied_events_tags = fields.Many2many( - 'calendar.event.type', - string="Deny Calendar Event Tags") - diff --git a/hotel_calendar/models/inherited_hotel_reservation.py b/hotel_calendar/models/inherited_hotel_reservation.py deleted file mode 100644 index ba48b1b99..000000000 --- a/hotel_calendar/models/inherited_hotel_reservation.py +++ /dev/null @@ -1,521 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -import logging -from datetime import timedelta -from odoo import models, fields, api, _ -from odoo.models import operator -from odoo.exceptions import AccessError, ValidationError -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT -_logger = logging.getLogger(__name__) - - -class HotelReservation(models.Model): - _inherit = 'hotel.reservation' - - # Fields declaration - reserve_color = fields.Char(compute='_compute_color', string='Color', - store=True) - reserve_color_text = fields.Char(compute='_compute_color', string='Color', - store=True) - - # TODO: Add the following method into _compute_color - - def _generate_color(self): - self.ensure_one() - company_id = self.env.user.company_id - if self.reservation_type == 'staff': - reserv_color = company_id.color_staff - reserv_color_text = company_id.color_letter_staff - elif self.reservation_type == 'out': - reserv_color = company_id.color_dontsell - reserv_color_text = company_id.color_letter_dontsell - elif self.to_assign: - reserv_color = company_id.color_to_assign - reserv_color_text = company_id.color_letter_to_assign - elif self.state == 'draft': - reserv_color = company_id.color_pre_reservation - reserv_color_text = company_id.color_letter_pre_reservation - elif self.state == 'confirm': - if self.folio_id.pending_amount <= 0: - reserv_color = company_id.color_reservation_pay - reserv_color_text = company_id.color_letter_reservation_pay - else: - reserv_color = company_id.color_reservation - reserv_color_text = company_id.color_letter_reservation - elif self.state == 'booking': - if self.folio_id.pending_amount <= 0: - reserv_color = company_id.color_stay_pay - reserv_color_text = company_id.color_letter_stay_pay - else: - reserv_color = company_id.color_stay - reserv_color_text = company_id.color_letter_stay - else: - if self.folio_id.pending_amount <= 0: - reserv_color = company_id.color_checkout - reserv_color_text = company_id.color_letter_checkout - else: - reserv_color = company_id.color_payment_pending - reserv_color_text = company_id.color_letter_payment_pending - return reserv_color, reserv_color_text - - # Constraints and onchanges - @api.depends('state', 'reservation_type', 'folio_id.pending_amount', 'to_assign') - def _compute_color(self): - for record in self: - colors = record._generate_color() - record.update({ - 'reserve_color': colors[0], - 'reserve_color_text': colors[1], - }) - - # ORM overrides - @api.model - def create(self, vals): - reservation_id = super(HotelReservation, self).create(vals) - reservation_id.send_bus_notification('create', - 'notify', - _("Reservation Created")) - return reservation_id - - - def write(self, vals): - _logger.info("RESERV WRITE") - ret = super(HotelReservation, self).write(vals) - self.send_bus_notification('write', 'noshow') - return ret - - - def unlink(self): - self.send_bus_notification('unlink', - 'warn', - _("Reservation Deleted")) - return super(HotelReservation, self).unlink() - - # Business methods - @api.model - def _hcalendar_room_data(self, rooms): - _logger.warning('_found [%s] rooms for hotel [%s]', len(rooms), self.env.user.hotel_id.id) - # TODO: refactoring res.config.settings', 'default_pricelist_id' by the current hotel.property.pricelist_id - pricelist_id = self.env.user.hotel_id.default_pricelist_id.id - json_rooms = [ - { - 'id': room.id, - 'name': room.name, - 'capacity': room.capacity, - 'class_name': room.room_type_id.class_id.name, - 'class_id': room.room_type_id.class_id.id, - 'shared_id': room.shared_room_id, - 'price': room.room_type_id - and ['pricelist', room.room_type_id.id, pricelist_id, - room.room_type_id.name] or 0, - 'room_type_name': room.room_type_id.name, - 'room_type_id': room.room_type_id.id, - 'floor_id': room.floor_id.id, - 'amentity_ids': room.room_type_id.room_amenity_ids.ids, - } for room in rooms] - return json_rooms - - @api.model - def _hcalendar_reservation_data(self, reservations): - _logger.warning('_found [%s] reservations for hotel [%s]', len(reservations), self.env.user.hotel_id.id) - json_reservations = [] - json_reservation_tooltips = {} - for reserv in reservations: - json_reservations.append({ - 'room_id': reserv['room_id'], - 'id': reserv['id'], - 'name': reserv['closure_reason'] or _('Out of service') - if reserv['reservation_type'] == 'out' - else reserv['partner_name'], - 'adults': reserv['adults'], - 'childrens': reserv['children'], - 'checkin': reserv['checkin'], - 'checkout': reserv['checkout'], - 'folio_id': reserv['folio_id'], - 'bgcolor': reserv['reserve_color'], - 'color': reserv['reserve_color_text'], - 'splitted': reserv['splitted'], - 'parent_reservation': reserv['parent_reservation'] or False, - 'read_only': False, # Read-Only - 'fix_days': reserv['splitted'], # Fix Days - 'fix_room': False, # Fix Rooms - 'overbooking': reserv['overbooking'], - 'state': reserv['state'], - 'price_room_services_set': reserv['price_room_services_set'], - 'amount_total': reserv['amount_total'], - 'real_dates': [reserv['real_checkin'], reserv['real_checkout']], - 'channel_type': reserv['channel_type'], - }) - json_reservation_tooltips.update({ - reserv['id']: { - 'folio_name': reserv['folio_name'], - 'name': _('Out of service') - if reserv['reservation_type'] == 'out' - else reserv['partner_name'], - 'phone': reserv['mobile'] or reserv['phone'] - or _('Phone not provided'), - 'email': reserv['email'] or _('Email not provided'), - 'room_type_name': reserv['room_type'], - 'adults': reserv['adults'], - 'children': reserv['children'], - 'checkin': reserv['checkin'], - 'checkout': reserv['checkout'], - 'arrival_hour': reserv['arrival_hour'], - 'departure_hour': reserv['departure_hour'], - 'price_room_services_set': reserv['price_room_services_set'], - 'invoices_paid': reserv['invoices_paid'], - 'pending_amount': reserv['pending_amount'], - 'type': reserv['reservation_type'] or 'normal', - 'closure_reason': reserv['closure_reason'], - 'out_service_description': reserv['out_service_description'] - or _('No reason given'), - 'splitted': reserv['splitted'], - 'channel_type': reserv['channel_type'], - 'real_dates': [reserv['real_checkin'], reserv['real_checkout']], - 'board_service_name': reserv['board_service_name'] or _('No board services'), - 'services': reserv['services'], - } - }) - return json_reservations, json_reservation_tooltips - - @api.model - def _hcalendar_event_data(self, events): - # TODO: Filter events by hotel - json_events = [ - { - 'id': event.id, - 'name': event.name, - 'date': event.start, - 'location': event.location, - } for event in events] - return json_events - - @api.model - def _hcalendar_calendar_data(self, calendars): - _logger.warning('_found [%s] calendars for hotel [%s]', len(calendars), self.env.user.hotel_id.id) - return [ - { - 'id': calendar.id, - 'name': calendar.name, - 'segmentation_ids': calendar.segmentation_ids.ids, - 'location_ids': calendar.location_ids.ids, - 'amenity_ids': calendar.amenity_ids.ids, - 'room_type_ids': calendar.room_type_ids.ids, - } for calendar in calendars] - - @api.model - def get_hcalendar_reservations_data(self, dfrom_dt, dto_dt, rooms): - rdfrom_dt = dfrom_dt + timedelta(days=1) # Ignore checkout - rdfrom_str = rdfrom_dt.strftime(DEFAULT_SERVER_DATE_FORMAT) - dto_str = dto_dt.strftime(DEFAULT_SERVER_DATE_FORMAT) - self.env.cr.execute(''' - SELECT - hr.id, hr.room_id, hr.adults, hr.children, hr.checkin, hr.checkout, hr.reserve_color, hr.reserve_color_text, - hr.splitted, hr.parent_reservation, hr.overbooking, hr.state, hr.real_checkin, hr.real_checkout, - hr.out_service_description, hr.arrival_hour, hr.departure_hour, hr.channel_type, - hr.price_room_services_set, - - hf.id as folio_id, hf.name as folio_name, hf.reservation_type, hf.invoices_paid, hf.pending_amount, - hf.amount_total, - - rp.mobile, rp.phone, rp.email, rp.name as partner_name, - - pt.name as room_type, - - array_agg(pt2.name) FILTER (WHERE pt2.show_in_calendar = TRUE) as services, - - rcr.name as closure_reason, - - hbs.name as board_service_name - FROM hotel_reservation AS hr - LEFT JOIN hotel_folio AS hf ON hr.folio_id = hf.id - LEFT JOIN hotel_room_type AS hrt ON hr.room_type_id = hrt.id - LEFT JOIN product_product AS pp ON hrt.product_id = pp.id - LEFT JOIN product_template AS pt ON pp.product_tmpl_id = pt.id - LEFT JOIN res_partner AS rp ON hf.partner_id = rp.id - LEFT JOIN room_closure_reason as rcr - ON hf.closure_reason_id = rcr.id - LEFT JOIN hotel_board_service_room_type_rel AS hbsrt ON hr.board_service_room_id = hbsrt.id - LEFT JOIN hotel_board_service AS hbs ON hbsrt.hotel_board_service_id = hbs.id - LEFT JOIN hotel_service AS hs ON hr.id = hs.reservation_id - LEFT JOIN product_product AS pp2 ON hs.product_id = pp2.id - LEFT JOIN product_template AS pt2 ON pp2.product_tmpl_id = pt2.id - WHERE room_id IN %s AND ( - (checkin <= %s AND checkout >= %s AND checkout <= %s) - OR (checkin >= %s AND checkout <= %s) - OR (checkin >= %s AND checkin <= %s AND checkout >= %s) - OR (checkin <= %s AND checkout >= %s)) - GROUP BY hr.id, hf.id, pt.name, rcr.name, hbs.name, rp.mobile, rp.phone, rp.email, rp.name - ORDER BY checkin DESC, checkout ASC, adults DESC, children DESC - ''', (tuple(rooms.ids), - rdfrom_str, rdfrom_str, dto_str, - rdfrom_str, dto_str, - rdfrom_str, dto_str, dto_str, - rdfrom_str, dto_str)) - return self._hcalendar_reservation_data(self.env.cr.dictfetchall()) - - @api.model - def get_hcalendar_pricelist_data(self, dfrom_dt, dto_dt): - # TODO: refactoring res.config.settings', 'default_pricelist_id' by the current hotel.property.pricelist_id - pricelist_id = self.env.user.hotel_id.default_pricelist_id.id - hotel_id = self.env.user.hotel_id.id - room_types_ids = self.env['hotel.room.type'].search([ - ('hotel_id', '=', hotel_id) - ]) - - dfrom_str = dfrom_dt.strftime(DEFAULT_SERVER_DATE_FORMAT) - dto_str = dto_dt.strftime(DEFAULT_SERVER_DATE_FORMAT) - - self.env.cr.execute(''' - WITH RECURSIVE gen_table_days AS ( - SELECT hrt.id, %s::Date AS date, hrt.sequence - FROM hotel_room_type AS hrt - UNION ALL - SELECT hrt.id, (td.date + INTERVAL '1 day')::Date, hrt.sequence - FROM gen_table_days as td - LEFT JOIN hotel_room_type AS hrt ON hrt.id=td.id - WHERE td.date < %s - ) - SELECT - TO_CHAR(gtd.date, 'DD/MM/YYYY') as date, gtd.id as room_type_id, gtd.sequence, - pt.name, ppi.fixed_price as price, pt.list_price - FROM gen_table_days AS gtd - LEFT JOIN hotel_room_type AS hrt ON hrt.id = gtd.id - LEFT JOIN product_product AS pp ON pp.id = hrt.product_id - LEFT JOIN product_template AS pt ON pt.id = pp.product_tmpl_id - LEFT JOIN product_pricelist_item AS ppi ON ppi.date_start = gtd.date AND ppi.date_end = gtd.date AND ppi.product_tmpl_id = pt.id - WHERE gtd.id IN %s - ORDER BY gtd.id ASC, gtd.date ASC - ''', (dfrom_str, dto_str, tuple(room_types_ids.ids))) - query_results = self.env.cr.dictfetchall() - - json_data = {} - for results in query_results: - if results['room_type_id'] not in json_data: - json_data.setdefault(results['room_type_id'], {}).update({ - 'title': results['name'], - 'room': results['room_type_id'], - 'sequence': results['sequence'], - }) - json_data[results['room_type_id']].setdefault('days', {}).update({ - results['date']: results['price'] or results['list_price'] - }) - - json_data_by_sequence = list(json_data.values()) - json_data_by_sequence.sort(key=operator.itemgetter('sequence')) - - json_rooms_prices = {} - for prices in json_data_by_sequence: - json_rooms_prices.setdefault(pricelist_id, []).append(prices) - return json_rooms_prices - - @api.model - def get_hcalendar_restrictions_data(self, dfrom_dt, dto_dt): - """ Returns the room type restrictions between dfrom_dt and dto_dt - for the room types of the current_hotel within the default restriction plan - """ - hotel_id = self.env.user.hotel_id.id - restriction_id = self.env.user.hotel_id.default_restriction_id.id - - json_rooms_rests = {} - room_typed_ids = self.env['hotel.room.type'].search([ - ('hotel_id', '=', hotel_id) - ], order='sequence ASC') - - room_type_rest_obj = self.env['hotel.room.type.restriction.item'] - rtype_rest_ids = room_type_rest_obj.search([ - ('room_type_id', 'in', room_typed_ids.ids), - ('date', '>=', dfrom_dt), - ('date', '<=', dto_dt), - ('restriction_id', '=', restriction_id) - ]) - - for room_type in room_typed_ids: - days = {} - rest_ids = rtype_rest_ids.filtered( - lambda x: x.room_type_id == room_type) - for rest_id in rest_ids: - days.update({ - fields.Date.from_string(rest_id.date).strftime("%d/%m/%Y"): ( - rest_id.min_stay, - rest_id.min_stay_arrival, - rest_id.max_stay, - rest_id.max_stay_arrival, - rest_id.closed, - rest_id.closed_arrival, - rest_id.closed_departure) - }) - json_rooms_rests.update({room_type.id: days}) - return json_rooms_rests - - @api.model - def get_hcalendar_events_data(self, dfrom_dt, dto_dt): - user_id = self.env['res.users'].browse(self.env.uid) - domain = [ - '|', '&', - ('start', '<=', dto_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)), - ('stop', '>=', dfrom_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)), - '&', - ('start', '>=', dfrom_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)), - ('stop', '<=', dto_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)) - ] - if self.env.user.hotel_id.pms_allowed_events_tags: - domain.append(('categ_ids', 'in', self.env.user.hotel_id.pms_allowed_events_tags)) - if self.env.user.hotel_id.pms_denied_events_tags: - domain.append( - ('categ_ids', 'not in', self.env.user.hotel_id.pms_denied_events_tags)) - events_raw = self.env['calendar.event'].search(domain) - return self._hcalendar_event_data(events_raw) - - @api.model - def get_hcalendar_calendar_data(self): - hotel_id = self.env.user.hotel_id.id - calendars = self.env['hotel.calendar'].search([ - ('hotel_id', '=', hotel_id) - ]) - res = self._hcalendar_calendar_data(calendars) - return res - - @api.model - def get_hcalendar_all_data(self, dfrom, dto, withRooms=True): - if not dfrom or not dto: - raise ValidationError(_('Input Error: No dates defined!')) - - hotel_id = self.env.user.hotel_id.id - - dfrom_dt = fields.Date.from_string(dfrom) - dto_dt = fields.Date.from_string(dto) - - rooms = self.env['hotel.room'].search([ - ('hotel_id', '=', hotel_id) - ], order='sequence ASC') or None - - if not rooms: - raise AccessError( - _("No rooms found for hotel %s. " - "Please, review the rooms configured for this hotel.") % self.env.user.hotel_id.name) - - json_res, json_res_tooltips = self.get_hcalendar_reservations_data( - dfrom_dt, dto_dt, rooms) - - vals = { - 'rooms': withRooms and self._hcalendar_room_data(rooms) or [], - 'reservations': json_res, - 'tooltips': json_res_tooltips, - 'pricelist': self.get_hcalendar_pricelist_data(dfrom_dt, dto_dt), - 'restrictions': self.get_hcalendar_restrictions_data(dfrom_dt, - dto_dt), - 'events': self.get_hcalendar_events_data(dfrom_dt, dto_dt), - 'calendars': withRooms and self.get_hcalendar_calendar_data() - or [] - } - return vals - - @api.model - def get_hcalendar_settings(self): - type_move = self.env.user.hotel_id.pms_type_move - return { - 'divide_rooms_by_capacity': self.env.user.hotel_id.pms_divide_rooms_by_capacity, - 'eday_week': self.env.user.hotel_id.pms_end_day_week, - 'eday_week_offset': self.env.user.hotel_id.pms_end_day_week_offset, - 'days': self.env.user.hotel_id.pms_default_num_days, - 'allow_invalid_actions': type_move == 'allow_invalid', - 'assisted_movement': type_move == 'assisted', - 'default_arrival_hour': self.env.user.hotel_id.default_arrival_hour, - 'default_departure_hour': self.env.user.hotel_id.default_departure_hour, - 'show_notifications': self.env.user.pms_show_notifications, - 'show_pricelist': self.env.user.pms_show_pricelist, - 'show_availability': self.env.user.pms_show_availability, - 'show_num_rooms': self.env.user.hotel_id.pms_show_num_rooms, - } - - - def generate_bus_values(self, naction, ntype, ntitle=''): - self.ensure_one() - return { - 'action': naction, - 'type': ntype, - 'title': ntitle, - 'room_id': self.room_id.id, - 'reserv_id': self.id, - 'folio_name': self.folio_id.name, - 'partner_name': (self.closure_reason_id.name or _('Out of service')) - if self.reservation_type == 'out' else self.partner_id.name, - 'adults': self.adults, - 'children': self.children, - 'checkin': self.checkin, - 'checkout': self.checkout, - 'arrival_hour': self.arrival_hour, - 'departure_hour': self.departure_hour, - 'folio_id': self.folio_id.id, - 'reserve_color': self.reserve_color, - 'reserve_color_text': self.reserve_color_text, - 'splitted': self.splitted, - 'parent_reservation': self.parent_reservation - and self.parent_reservation.id or 0, - 'room_name': self.room_id.name, - 'room_type_name': self.room_type_id.name, - 'partner_phone': self.partner_id.mobile - or self.partner_id.phone or _('Undefined'), - 'partner_email': self.partner_id.email or _('Undefined'), - 'state': self.state, - 'fix_days': self.splitted, - 'overbooking': self.overbooking, - 'price_room_services_set': self.price_room_services_set, - 'invoices_paid': self.folio_id.invoices_paid, - 'pending_amount': self.folio_id.pending_amount, - 'reservation_type': self.reservation_type or 'normal', - 'closure_reason': self.closure_reason_id.name, - 'out_service_description': self.out_service_description - or _('No reason given'), - 'real_dates': [self.real_checkin, self.real_checkout], - 'channel_type': self.channel_type, - 'board_service_name': self.board_service_room_id.hotel_board_service_id.name or _('No board services'), - 'services': [service.product_id.name for service in self.service_ids - if service.product_id.show_in_calendar] or False, - } - - - def send_bus_notification(self, naction, ntype, ntitle=''): - hotel_cal_obj = self.env['bus.hotel.calendar'] - for record in self: - if not isinstance(record.id, models.NewId) \ - and not isinstance(record.folio_id.id, models.NewId) \ - and not isinstance(record.partner_id.id, models.NewId): - hotel_cal_obj.send_reservation_notification( - record.generate_bus_values(naction, ntype, ntitle)) - - @api.model - def swap_reservations(self, fromReservsIds, toReservsIds): - from_reservs = self.env['hotel.reservation'].browse(fromReservsIds) - to_reservs = self.env['hotel.reservation'].browse(toReservsIds) - - if not any(from_reservs) or not any(to_reservs): - raise ValidationError(_("Invalid swap parameters")) - - max_from_persons = max( - from_reservs.mapped(lambda x: x.adults)) - max_to_persons = max( - to_reservs.mapped(lambda x: x.adults)) - - from_room = from_reservs[0].room_id - to_room = to_reservs[0].room_id - from_overbooking = from_reservs[0].overbooking - to_overbooking = to_reservs[0].overbooking - - if max_from_persons > to_room.capacity or \ - max_to_persons > from_room.capacity: - raise ValidationError("Invalid swap operation: wrong capacity") - - for record in from_reservs: - record.with_context({'ignore_avail_restrictions': True}).write({ - 'room_id': to_room.id, - 'overbooking': to_overbooking, - }) - for record in to_reservs: - record.with_context({'ignore_avail_restrictions': True}).write({ - 'room_id': from_room.id, - 'overbooking': from_overbooking, - }) - - return True diff --git a/hotel_calendar/models/inherited_hotel_room_type_restriction_item.py b/hotel_calendar/models/inherited_hotel_room_type_restriction_item.py deleted file mode 100644 index d24cc7b5c..000000000 --- a/hotel_calendar/models/inherited_hotel_room_type_restriction_item.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -import logging -from odoo import models, api -_logger = logging.getLogger(__name__) - - -class HotelRoomTypeRestrictionItem(models.Model): - _inherit = 'hotel.room.type.restriction.item' - - # ORM overrides - @api.model - def create(self, vals): - res = super(HotelRoomTypeRestrictionItem, self).create(vals) - if res.restriction_id.id == self.env.user.hotel_id.default_restriction_id.id: - self.env['bus.hotel.calendar'].send_restriction_notification({ - 'restriction_id': res.restriction_id.id, - 'date': res.date, - 'min_stay': res.min_stay, - 'min_stay_arrival': res.min_stay_arrival, - 'max_stay': res.max_stay, - 'max_stay_arrival': res.max_stay_arrival, - 'closed': res.closed, - 'closed_departure': res.closed_departure, - 'closed_arrival': res.closed_arrival, - 'room_type_id': res.room_type_id.id, - 'id': res.id, - }) - return res - - - def write(self, vals): - ret_vals = super(HotelRoomTypeRestrictionItem, self).write(vals) - bus_hotel_calendar_obj = self.env['bus.hotel.calendar'] - for record in self: - bus_hotel_calendar_obj.send_restriction_notification({ - 'restriction_id': record.restriction_id.id, - 'date': record.date, - 'min_stay': record.min_stay, - 'min_stay_arrival': record.min_stay_arrival, - 'max_stay': record.max_stay, - 'max_stay_arrival': record.max_stay_arrival, - 'closed': record.closed, - 'closed_departure': record.closed_departure, - 'closed_arrival': record.closed_arrival, - 'room_type_id': record.room_type_id.id, - 'id': record.id, - }) - return ret_vals - - - def unlink(self): - default_restriction_id = self.env.user.hotel_id.default_restriction_id.id - # Construct dictionary with relevant info of removed records - unlink_vals = [] - for record in self: - if record.restriction_id.id != default_restriction_id: - continue - unlink_vals.append({ - 'restriction_id': record.restriction_id.id, - 'date': record.date, - 'min_stay': 0, - 'min_stay_arrival': 0, - 'max_stay': 0, - 'max_stay_arrival': 0, - 'closed': False, - 'closed_departure': False, - 'closed_arrival': False, - 'room_type_id': record.room_type_id.id, - 'id': record.id, - }) - res = super(HotelRoomTypeRestrictionItem, self).unlink() - bus_hotel_calendar_obj = self.env['bus.hotel.calendar'] - for uval in unlink_vals: - bus_hotel_calendar_obj.send_restriction_notification(uval) - return res diff --git a/hotel_calendar/models/inherited_product_pricelist_item.py b/hotel_calendar/models/inherited_product_pricelist_item.py deleted file mode 100644 index e55cb0cb8..000000000 --- a/hotel_calendar/models/inherited_product_pricelist_item.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, api - - -class ProductPricelistItem(models.Model): - _inherit = 'product.pricelist.item' - - # ORM overrides - @api.model - def create(self, vals): - res = super(ProductPricelistItem, self).create(vals) - # TODO: refactoring res.config.settings', 'default_pricelist_id' by the current hotel.property.pricelist_id - pricelist_default_id = self.env['ir.default'].sudo().get( - 'res.config.settings', 'default_pricelist_id') - if pricelist_default_id: - pricelist_default_id = int(pricelist_default_id) - pricelist_id = res.pricelist_id.id - product_tmpl_id = res.product_tmpl_id.id - date_start = res.date_start - room_type = self.env['hotel.room.type'].search([ - ('product_id.product_tmpl_id', '=', product_tmpl_id) - ], limit=1) - if pricelist_id == pricelist_default_id and room_type: - prod = room_type.product_id.with_context( - quantity=1, - date=date_start, - pricelist=pricelist_id) - prod_price = prod.price - - self.env['bus.hotel.calendar'].send_pricelist_notification({ - 'pricelist_id': pricelist_id, - 'date': date_start, - 'room_id': room_type.id, - 'price': prod_price, - 'id': self.id, - }) - return res - - - def write(self, vals): - # TODO: refactoring res.config.settings', 'default_pricelist_id' by the current hotel.property.pricelist_id - pricelist_default_id = self.env['ir.default'].sudo().get( - 'res.config.settings', 'default_pricelist_id') - if pricelist_default_id: - pricelist_default_id = int(pricelist_default_id) - ret_vals = super(ProductPricelistItem, self).write(vals) - - bus_calendar_obj = self.env['bus.hotel.calendar'] - room_type_obj = self.env['hotel.room.type'] - if vals.get('fixed_price'): - for record in self: - pricelist_id = vals.get('pricelist_id') or \ - record.pricelist_id.id - if pricelist_id != pricelist_default_id: - continue - date_start = vals.get('date_start') or record.date_start - product_tmpl_id = vals.get('product_tmpl_id') or \ - record.product_tmpl_id.id - room_type = room_type_obj.search([ - ('product_id.product_tmpl_id', '=', product_tmpl_id) - ], limit=1) - - if room_type and date_start: - prod = room_type.product_id.with_context( - quantity=1, - date=date_start, - pricelist=pricelist_id) - prod_price = prod.price - - bus_calendar_obj.send_pricelist_notification({ - 'pricelist_id': pricelist_id, - 'date': date_start, - 'room_id': room_type.id, - 'price': prod_price, - 'id': record.id, - }) - return ret_vals - - - def unlink(self): - # TODO: refactoring res.config.settings', 'default_pricelist_id' by the current hotel.property.pricelist_id - pricelist_default_id = self.env['ir.default'].sudo().get( - 'res.config.settings', 'default_pricelist_id') - if pricelist_default_id: - pricelist_default_id = int(pricelist_default_id) - # Construct dictionary with relevant info of removed records - unlink_vals = [] - for record in self: - if record.pricelist_id.id != pricelist_default_id: - continue - room_type = self.env['hotel.room.type'].search([ - ('product_id.product_tmpl_id', '=', record.product_tmpl_id.id) - ], limit=1) - unlink_vals.append({ - 'pricelist_id': record.pricelist_id.id, - 'date': record.date_start, - 'room': room_type, - 'id': record.id, - }) - # Do Normal Stuff - res = super(ProductPricelistItem, self).unlink() - # Do extra operations - bus_calendar_obj = self.env['bus.hotel.calendar'] - for vals in unlink_vals: - pricelist_id = vals['pricelist_id'] - date_start = vals['date'] - room_type = vals['room'] - prod = room_type.product_id.with_context( - quantity=1, - date=date_start, - pricelist=pricelist_id) - - # Send Notification to update calendar pricelist - bus_calendar_obj.send_pricelist_notification({ - 'pricelist_id': pricelist_id, - 'date': date_start, - 'room_id': room_type.id, - 'price': prod.price, - 'id': vals['id'], - }) - return res diff --git a/hotel_calendar/models/inherited_res_company.py b/hotel_calendar/models/inherited_res_company.py deleted file mode 100644 index 34dcf8068..000000000 --- a/hotel_calendar/models/inherited_res_company.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2019 Pablo Quesada -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, fields - - -class ResCompany(models.Model): - _inherit = 'res.company' - - # Fields declaration - color_pre_reservation = fields.Char('Pre-reservation', default='#A24680') - color_reservation = fields.Char('Confirmed Reservation ', default='#7C7BAD') - color_reservation_pay = fields.Char('Paid Reservation', default='#584D76') - color_stay = fields.Char('Checkin', default='#FF4040') - color_stay_pay = fields.Char('Paid Checkin', default='#82BF07') - color_checkout = fields.Char('Checkout', default='#7E7E7E') - color_dontsell = fields.Char('Dont Sell', default='#000000') - color_staff = fields.Char('Staff', default='#C08686') - color_to_assign = fields.Char('Ota Reservation to Assign', default='#ED722E') - color_payment_pending = fields.Char('Payment Pending', default='#A24689') - color_letter_pre_reservation = fields.Char('Letter Pre-reservation', default='#FFFFFF') - color_letter_reservation = fields.Char('Letter Confirmed Reservation ', default='#FFFFFF') - color_letter_reservation_pay = fields.Char('Letter Paid Reservation', default='#FFFFFF') - color_letter_stay = fields.Char('Letter Checkin', default='#FFFFFF') - color_letter_stay_pay = fields.Char('Letter Stay Pay', default='#FFFFFF') - color_letter_checkout = fields.Char('Letter Checkout', default='#FFFFFF') - color_letter_dontsell = fields.Char('Letter Dont Sell', default='#FFFFFF') - color_letter_staff = fields.Char('Letter Staff', default='#FFFFFF') - color_letter_to_assign = fields.Char('Letter Ota to Assign', default='#FFFFFF') - color_letter_payment_pending = fields.Char('Letter Payment Pending', default='#FFFFFF') diff --git a/hotel_calendar/models/inherited_res_users.py b/hotel_calendar/models/inherited_res_users.py deleted file mode 100644 index 55725cf5b..000000000 --- a/hotel_calendar/models/inherited_res_users.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, fields - - -class ResUsers(models.Model): - _inherit = 'res.users' - - # Fields declaration - pms_show_notifications = fields.Boolean('Show Notifications', default=True) - pms_show_pricelist = fields.Boolean('Show Pricelist', default=True) - pms_show_availability = fields.Boolean('Show Availability', default=True) - - # ORM overrides - def __init__(self, pool, cr): - """ Override of __init__ to add access rights. - Access rights are disabled by default, but allowed on some specific - fields defined in self.SELF_{READ/WRITE}ABLE_FIELDS. - """ - super(ResUsers, self).__init__(pool, cr) - # duplicate list to avoid modifying the original reference - type(self).SELF_WRITEABLE_FIELDS = list(self.SELF_WRITEABLE_FIELDS) - type(self).SELF_WRITEABLE_FIELDS.extend([ - 'pms_show_notifications', - 'pms_show_pricelist', - 'pms_show_availability', - ]) - # duplicate list to avoid modifying the original reference - type(self).SELF_READABLE_FIELDS = list(self.SELF_READABLE_FIELDS) - type(self).SELF_READABLE_FIELDS.extend([ - 'pms_show_notifications', - 'pms_show_pricelist', - 'pms_show_availability', - ]) diff --git a/hotel_calendar/models/ir_actions_act_window_view.py b/hotel_calendar/models/ir_actions_act_window_view.py deleted file mode 100644 index 44022e3dc..000000000 --- a/hotel_calendar/models/ir_actions_act_window_view.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, fields - - -class ActWindowView(models.Model): - _inherit = 'ir.actions.act_window.view' - - # Fields declaration - view_mode = fields.Selection(selection_add=[('pms', "PMS"), ('mpms', 'Management PMS')]) diff --git a/hotel_calendar/models/ir_ui_view.py b/hotel_calendar/models/ir_ui_view.py deleted file mode 100644 index e878c9d6e..000000000 --- a/hotel_calendar/models/ir_ui_view.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, fields - - -class View(models.Model): - _inherit = 'ir.ui.view' - - # Fields declaration - type = fields.Selection(selection_add=[('pms', "PMS"), ('mpms', 'Management PMS')]) diff --git a/hotel_calendar/readme/CONFIGURE.rst b/hotel_calendar/readme/CONFIGURE.rst deleted file mode 100644 index a3c81f46a..000000000 --- a/hotel_calendar/readme/CONFIGURE.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. [ This file is optional, it should explain how to configure -the module before using it; it is aimed at advanced users. ] - -No action required. The module is pre-configured with default values. - -You will find the hotel calendar settings in `Settings > Users & Companies > Hotels > Your Hotel > Calendar Settings Tab`. - -Reservation colors can be configured by company in `Settings > Users & Companies > Companies > Your Company > Hotel Preferences Tab.` \ No newline at end of file diff --git a/hotel_calendar/readme/CONTRIBUTORS.rst b/hotel_calendar/readme/CONTRIBUTORS.rst deleted file mode 100644 index c0ca43ca9..000000000 --- a/hotel_calendar/readme/CONTRIBUTORS.rst +++ /dev/null @@ -1,2 +0,0 @@ -# authors are taken from the __manifest__.py file -* Pablo Quesada \ No newline at end of file diff --git a/hotel_calendar/readme/CREDITS.rst b/hotel_calendar/readme/CREDITS.rst deleted file mode 100644 index 61d2f78cc..000000000 --- a/hotel_calendar/readme/CREDITS.rst +++ /dev/null @@ -1,2 +0,0 @@ -.. [ This file is optional and contains additional credits, other than -authors, contributors, and maintainers. ] \ No newline at end of file diff --git a/hotel_calendar/readme/DESCRIPTION.rst b/hotel_calendar/readme/DESCRIPTION.rst deleted file mode 100644 index a44f8af2a..000000000 --- a/hotel_calendar/readme/DESCRIPTION.rst +++ /dev/null @@ -1,10 +0,0 @@ -.. [ This file must be max 2-3 paragraphs, and is required. ] - -This module extends the functionality of roomdoo. - -The calendar displays your rooms in a range of dates. -The rooms can be filtered by class, type or even amenities creating new calendars for easily manage all your reservations. -You can manage prices and restrictions day by day using the calendar management view. - -This module adds two new view types: ``pms`` and ``mpms``. -The module also incorporates a longpolling for delivering instant notification when using the calendar. \ No newline at end of file diff --git a/hotel_calendar/readme/INSTALL.rst b/hotel_calendar/readme/INSTALL.rst deleted file mode 100644 index 96fe22619..000000000 --- a/hotel_calendar/readme/INSTALL.rst +++ /dev/null @@ -1,5 +0,0 @@ -.. [ This file must only be present if there are very specific -installation instructions, such as installing non-python dependencies. The audience is systems administrators. ] - -This module depends on modules ``hotel``, ``bus``, ``web``, ``calendar``, and ``web_widget_color``. -Ensure yourself to have all them in your addons list. \ No newline at end of file diff --git a/hotel_calendar/readme/ROADMAP.rst b/hotel_calendar/readme/ROADMAP.rst deleted file mode 100644 index 3f8c38c78..000000000 --- a/hotel_calendar/readme/ROADMAP.rst +++ /dev/null @@ -1,5 +0,0 @@ -.. [ Enumerate known caveats and future potential improvements. -It is mostly intended for end-users, and can also help potential new contributors discovering new features to implement. ] - -- [ ] Implement the calendar view as an Odoo native view type. -- [ ] Re-design the calendar using SVG or other Odoo native approach. \ No newline at end of file diff --git a/hotel_calendar/readme/USAGE.rst b/hotel_calendar/readme/USAGE.rst deleted file mode 100644 index e704b7dd3..000000000 --- a/hotel_calendar/readme/USAGE.rst +++ /dev/null @@ -1,14 +0,0 @@ -.. [ This file must be present and contains the usage instructions -for end-users. As all other rst files included in the README, it MUST NOT contain reStructuredText sections -only body text (paragraphs, lists, tables, etc). Should you need a more elaborate structure to explain the addon, -please create a Sphinx documentation (which may include this file as a "quick start" section). ] - -To use this module, you need to: - -* Go to Hotel Calendar menu for managing reservations. -* Go to Hotel Calendar Management for managing prices and restrictions. -* Go to Hotel Management/Configuration/Calendars menu for managing calendar tabs. - -Shortcuts -* `CTRL + LEFT MOUSE CLICK`` on a reservation - Start reservation swap -* ``ESC`` - cancel active action (ie. swap) diff --git a/hotel_calendar/security/ir.model.access.csv b/hotel_calendar/security/ir.model.access.csv deleted file mode 100644 index c8305754e..000000000 --- a/hotel_calendar/security/ir.model.access.csv +++ /dev/null @@ -1,4 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_hotel_product_pricelist_item_call,hotel_calendar.pricelist_item_call,hotel_calendar.model_product_pricelist_item,hotel.group_hotel_call,1,1,1,1 -access_hotel_product_pricelist_item_user,hotel_calendar.pricelist_item_use,hotel_calendar.model_product_pricelist_item,hotel.group_hotel_user,1,1,1,1 -access_hotel_calendar,access_hotel_calendar,model_hotel_calendar,base.group_user,1,0,0,0 diff --git a/hotel_calendar/static/description/icon.png b/hotel_calendar/static/description/icon.png deleted file mode 100644 index 45ab4dc2931dc4e4d40244268a9a071e73a08778..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4155 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 diff --git a/hotel_calendar/static/description/icon_calendar_configurator.png b/hotel_calendar/static/description/icon_calendar_configurator.png deleted file mode 100644 index bce8eb8f191c8de2cbf5b05a070194e7079edbde..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5221 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 g`D^Hx{JOih - * Alexandre Díaz - */ - - -/* .openerp .oe-view-manager { - overflow: initial !important; -} - */ - -.o_hotel_calendar_view { - display: flex; - height: 100%; -} - -.nopadding { - padding: 0 !important; - margin: 0 !important; -} - - - -#pms-menu { - overflow: auto; - background-color: #f8f8f8; - height: 100%; - padding: 0 2.5em; -} - -#pms-menu .input-group span, #pms-menu input { - border-radius: 0; -} - -#pms-menu button { - border-radius: 0; - border: 1px solid lightgray; - font-size: x-small; -} - -#pms-calendar: { - flex: 1 1 auto; - overflow: auto; -} - -#pms-search { - position: fixed; - z-index: 9; -} - -#hcal_widget { - max-height: 100%; -} - -#multicalendar_panels { - background-color: white; - border-left: 1px solid #ddd; -} - -.nav-tabs > li > a { - border-radius: 0; -} - -.nav-tabs { - padding-top: 4px; -} - -/* BUTTON STATES */ -.navbar-default { - border-color: #f8f8f8; -} - - -.unify-enabled { - background-color: #43A200; - color: white; -} - -.divide-enabled { - background-color: #43A200; - color: white; -} - -.overbooking-enabled { - background-color: #43A200; - color: white; -} - -.cancelled-enabled { - background-color: #43A200; -} - -.swap-from { - background-color: #E7CF1D; - color: #7C7BAD; -} - -.swap-to { - background-color: #43A200; - color: white; -} - -.unify-enabled i, .divide-enabled i, .cancelled-enabled i, .overbooking-enabled i, .swap-to i { - color: white; -} - -.swap-from i { - color: #7C7BAD; -} - -/* END: BUTTON STATES */ - -input#bookings_search { - border-top-left-radius: 0; - border-top-right-radius: 0; - border: 1px solid lightgray; -} - -#pms-menu .menu-date-box { - margin-top: 2px !important; -} - -#pms-menu .menu-button-box, #pms-menu .menu-search-box, #pms-menu .menu-filter-box { - margin-top: 1em !important; -} - -#pms-menu .menu-filter-box .filter-record { - margin-top: 1em; -} - -#pms-menu .menu-filter-box h4 { - cursor: pointer; -} -#pms-menu .menu-filter-box h4 i { - transition: all 0.5s ease; -} - -#pms-menu .button-box { - text-align: left; - min-height: 3.5em; - padding: 3px; - transition: all 0.5s ease; - overflow: hidden; -} - -.overbooking-highlight { - color: white; - background-color: #FFA500; -} - -.overbooking-highlight i { - color: white; -} - -.multi-calendar-tab-plus { - background-color: darkgray; - font-weight: bold; - color: white; -} - -#pms-menu div[id^=btn_] { - padding: 2px; -} - -.warn-message { - text-align: center; - line-height: 100vh; - font-size: xx-large; - color: gray; -} - -/** SELECT 2 **/ -#pms-menu .select2-container, #pms-menu .select2-choice { - border-radius: 0; -} -#pms-menu .select2-choice { - height: 100%; - padding: 2px; -} - -/** BOOTSTRAP **/ -.badge-danger { - background-color: #d34f2a !important; -} - -/** ODOO **/ -.o_chat_window { - z-index: 8 !important; -} - -.o_button_icon { - display: inline-block; - width: 37px; - padding: 0px 3px; - text-align: center; - vertical-align: middle; - color: #7C7BAD; - font-size: 24px; -} - -.o_button_text { - display: inline-block; - vertical-align: middle; - max-width: 70%; - line-height: 1.2; - text-align: left; -} - -.text-hidden-xs { - overflow: hidden; - text-overflow: ellipsis; -} - -/** POPOVER **/ -.popover-content { - font-family: Garuda, sans-serif; - font-size: 12px; - padding: 0px; -} -.popover .h3, .popover h3 { - margin-top: 2px; - margin-bottom: 2px; -} -.popover { - max-width: 400px; - border-radius: 0px; - padding: 0px; -} -.popover .container { - max-width: 100%; -} -.popover .container p { - margin-top: 2px; - margin-bottom: 0px; -} -.popover .container p.email { - word-wrap: break-word; -} -.popover .container p.board { - margin-top: 0px; -} -.popover header { - font-size: 1.2em; -} - -.fa-1_5x { - font-size: 1.5em; -} -.fa-2_5x { - font-size: 2.5em; -} -.fa-text-inside { - font-family: Garuda, sans-serif; - font-size: 12px; -} -.popover .col-sm-2, .popover .col-sm-4, .popover .col-sm-6, .popover .col-sm-12 { - padding-top: 3px; - padding-bottom: 3px; -} -/* custom styles for popover info */ -.popover .circle { - height:35px; - min-width:35px; - line-height:35px; - border-radius:50px; - text-align:center; - color:#fff; - background:#777; - margin-right: .65em; - padding: 0 5px; -} - -.popover .bg-gray-lighter { - background-color: #ddd; - color: #777; -} -.popover .text-gray-dark { - color: #777; -} - - -/* Spacing in Bootstrap v4.0 */ -.mt-3 { - margin-top: 3px; -} -.mt-5 { - margin-top: 5px; -} -.mt-10 { - margin-top: 10px !important; -} -.my-10 { - margin-top: 10px !important; - margin-bottom: 10px !important; -} -.mt-25 { - margin-top: 25px; -} -.mr-5 { - margin-right: 5px; -} -.mx-15 { - margin-left: 15px; - margin-right: 15px; -} -.mx-25 { - margin-left: 25px; - margin-right: 25px; -} -.px-0 { - padding-left: 0px; - padding-right: 0px; -} -.py-5 { - padding-top: 5px; - padding-bottom: 5px; -} -.pt-9 { - padding-top: 9px; -} -.pb-3 { - padding-bottom: 3px; -} -.pb-10 { - padding-bottom: 10px; -} -.pl-5 { - padding-left: 5px; -} -.pr-0 { - padding-right: 0px; -} - -/* WARNING: The .row-eq-height class uses CSS3's flexbox layout mode, - which is not supported in Internet Explorer 9 and below. */ -.row-eq-height { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; -} - -/* TODO: Use Odoo Colours based on http://www.odoo.com/openerp_website/static/src/less/variables.less */ - -div.diagonal { - overflow: hidden; - background-color: #777; -} -.diagonal:before { - content: ""; - border-top: 700px solid #777; - border-right: 500px solid #ddd; - position: absolute; - left: 40%; - bottom: 0; -} -div.diagonal_pending_amount { - background-color: #A24689; -} -.diagonal_pending_amount::before { - border-top-color: #A24689; -} - -div.triangle-right { - overflow: hidden; - color: white; - background-color: #7c7bad; -} -.triangle-right:before { - content: ""; - position: absolute; - border: 26px solid #ddd; - height: 0; - width: 100%; - left: 47%; - top: 0; - bottom: 0; - margin: auto; - border-left-color: transparent; -} - -div.on-top { - position: inherit; -} -div.pull-right-custom { - float: right !important; - margin-right: 15px; - color: #777; - text-align: right; -} - -@keyframes blinker { - 50% { opacity: 0; } -} \ No newline at end of file diff --git a/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js b/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js deleted file mode 100644 index db93063ec..000000000 --- a/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js +++ /dev/null @@ -1,1113 +0,0 @@ -// Copyright 2018 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar.PMSCalendarController', function (require) { -"use strict"; - -var AbstractController = require('web.AbstractController'), - ViewDialogs = require('web.view_dialogs'), - Dialog = require('web.Dialog'), - Core = require('web.core'), - Bus = require('bus.bus').bus, - HotelConstants = require('hotel_calendar.Constants'), - MultiCalendar = require('hotel_calendar.MultiCalendar'), - - _t = Core._t, - QWeb = Core.qweb; - -var PMSCalendarController = AbstractController.extend({ - custom_events: _.extend({}, AbstractController.prototype.custom_events, { - onLoadViewFilters: '_onLoadViewFilters', - onViewAttached: '_onViewAttached', - onApplyFilters: '_onApplyFilters', - }), - - _last_dates: [], - - init: function (parent, model, renderer, params) { - this._super.apply(this, arguments); - this.displayName = params.displayName; - this.formViewId = params.formViewId; - this.context = params.context; - - this._multi_calendar = new MultiCalendar(this); - - Bus.on("notification", this, this._onBusNotification); - }, - - start: function() { - this._super.apply(this, arguments); - var self = this; - - this._multi_calendar.setElement(this.renderer.$el.find('#hcal_widget')); - this._multi_calendar.reset(); - this._multi_calendar.start(); - - this._assign_multi_calendar_events(); - this._load_calendar_settings(); - }, - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- - savePricelist: function (calendar, pricelist_id, pricelist) { - var self = this; - var oparams = [pricelist_id, false, pricelist, {}, {}]; - this.model.save_changes(oparams).then(function(results){ - $(calendar.btnSaveChanges).removeClass('need-save'); - $(calendar.edtable).find('.hcal-input-changed').removeClass('hcal-input-changed'); - }); - }, - - updateReservations: function (calendar, ids, values, oldReserv, newReserv) { - var self = this; - return this.model.update_records(ids, values).then(function(result){ - // Remove OB Room Row? - if ((oldReserv.room.overbooking && !newReserv.room.overbooking) || (oldReserv.room.cancelled && !newReserv.room.cancelled)) { - self._multi_calendar.remove_extra_room_row(oldReserv, true); - } - }).fail(function(err, errev){ - calendar.replaceReservation(newReserv, oldReserv); - }); - }, - - swapReservations: function (fromIds, toIds, detail, refFromReservDiv, refToReservDiv) { - var self = this; - return this.model.swap_reservations(fromIds, toIds).then(function(results){ - var allReservs = detail.inReservs.concat(detail.outReservs); - for (var nreserv of allReservs) { - self.renderer.$el.find(nreserv._html).stop(true); - } - }).fail(function(err, errev){ - for (var nreserv of detail.inReservs) { - self.renderer.$el.find(nreserv._html).animate({'top': refFromReservDiv.style.top}, 'fast'); - } - for (var nreserv of detail.outReservs) { - self.renderer.$el.find(nreserv._html).animate({'top': refToReservDiv.style.top}, 'fast'); - } - - self._multi_calendar.swap_reservations(detail.outReservs, detail.inReservs); - }); - }, - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - _updateRecord: function (record) { - return this.model.updateRecord(record).then(this.reload.bind(this)); - }, - - _load_calendars: function (ev) { - var self = this; - - /** DO MAGIC **/ - var hcal_dates = this.renderer.get_view_filter_dates(); - var oparams = [ - hcal_dates[0].subtract(1, 'd').format(HotelConstants.ODOO_DATETIME_MOMENT_FORMAT), - hcal_dates[1].format(HotelConstants.ODOO_DATETIME_MOMENT_FORMAT) - ]; - - this.model.get_calendar_data(oparams).then(function(results){ - self._multi_calendar._days_tooltips = results['events']; - self._multi_calendar._reserv_tooltips = results['tooltips']; - var rooms = []; - for (var r of results['rooms']) { - var nroom = new HRoom( - r['id'], - r['name'], - r['capacity'], - r['class_name'], - r['shared'], - r['price'] - ); - nroom.addUserData({ - 'room_type_name': r['room_type_name'], - 'room_type_id': r['room_type_id'], - 'floor_id': r['floor_id'], - 'amenities': r['amenity_ids'], - 'class_id': r['class_id'], - }); - rooms.push(nroom); - } - - var reservs = []; - for (var r of results['reservations']) { - var nreserv = self._create_reservation_obj(r); - reservs.push(nreserv); - } - - var options = { - startDate: HotelCalendar.toMomentUTC(self._last_dates[0], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT), - days: self._view_options['days'], - rooms: rooms, - endOfWeek: parseInt(self._view_options['eday_week']) || 6, - divideRoomsByCapacity: self._view_options['divide_rooms_by_capacity'] || false, - allowInvalidActions: self._view_options['allow_invalid_actions'] || false, - assistedMovement: self._view_options['assisted_movement'] || false, - showPricelist: self._view_options['show_pricelist'] || false, - showAvailability: self._view_options['show_availability'] || false, - showNumRooms: self._view_options['show_num_rooms'] || 0, - endOfWeekOffset: self._view_options['eday_week_offset'] || 0 - }; - - self._multi_calendar.set_options(options); - self._multi_calendar.set_datasets(results['pricelist'], results['restrictions'], reservs); - self._multi_calendar.set_base_element(self.renderer.$el[0]); - - for (var calendar_record of results['calendars']) { - var calendar_index = self._multi_calendar.create_calendar(calendar_record); - var domain = self._generate_calendar_filters_domain(calendar_record); - var calendar = self._multi_calendar.get_calendar(calendar_index+1); - calendar.setDomain(HotelCalendar.DOMAIN.ROOMS, domain); - } - - self._multi_calendar.set_active_calendar(self._multi_calendar._calendars.length-1); - self._update_buttons_counter(); - }); - }, - - _generate_calendar_filters_domain: function(calendar) { - var domain = []; - if (calendar['segmentation_ids'] && calendar['segmentation_ids'].length > 0) { - domain.push(['class_id', 'in', calendar['segmentation_ids']]); - } - if (calendar['location_ids'] && calendar['location_ids'].length > 0) { - domain.push(['floor_id', 'in', calendar['location_ids']]); - } - if (calendar['amenity_ids'] && calendar['amenity_ids'].length > 0) { - domain.push(['amenities', 'in', calendar['amenity_ids']]); - } - if (calendar['room_type_ids'] && calendar['room_type_ids'].length > 0) { - domain.push(['room_type_id', 'some', calendar['room_type_ids']]); - } - return domain; - }, - - _load_calendar_settings: function (ev) { - var self = this; - return this.model.get_hcalendar_settings().then(function(options){ - self._view_options = options; - - if (['xs', 'md'].indexOf(self._find_bootstrap_environment()) >= 0) { - self._view_options['days'] = 7; - } - - var date_begin = moment().local().startOf('day'); - var days = self._view_options['days']; - if (self._view_options['days'] === 'month') { - days = date_begin.daysInMonth(); - } - self._last_dates[0] = date_begin.clone(); - self._last_dates[1] = date_begin.clone().add(days, 'd'); - - var $dateTimePickerBegin = self.renderer.$el.find('#pms-menu #date_begin'); - var $dateEndDays = self.renderer.$el.find('#pms-menu #date_end_days'); - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").date(date_begin); - $dateEndDays.val(self._view_options['days']); - - self._load_calendars(); - self._assign_view_events(); - }); - }, - - _reload_active_calendar: function() { - var self = this; - var active_calendar = this._multi_calendar.get_active_calendar(); - var filterDates = active_calendar.getDates(); - // Clip dates - var dfrom = filterDates[0].clone(), - dto = filterDates[1].clone(); - - if (filterDates[0].isBetween(this._last_dates[0], this._last_dates[1], 'days') && filterDates[1].isAfter(this._last_dates[1], 'day')) { - dfrom = this._last_dates[1].clone(); - } else if (this._last_dates[0].isBetween(filterDates[0], filterDates[1], 'days') && this._last_dates[1].isAfter(filterDates[0], 'day')) { - dto = this._last_dates[0].clone(); - } - - var oparams = [ - dfrom.subtract(1, 'd').format(HotelConstants.ODOO_DATETIME_MOMENT_FORMAT), - dto.format(HotelConstants.ODOO_DATETIME_MOMENT_FORMAT), - false - ]; - - this.model.get_calendar_data(oparams).then(function(results){ - var reservs = []; - for (var r of results['reservations']) { - var nreserv = self._create_reservation_obj(r); - reservs.push(nreserv); - } - - self._multi_calendar._reserv_tooltips = _.extend(this._multi_calendar._reserv_tooltips, results['tooltips']); - _.defer(function(){ - self._multi_calendar.merge_days_tooltips(results['events']); - self._multi_calendar.merge_pricelist(results['pricelist'], active_calendar); - self._multi_calendar.merge_restrictions(results['restrictions'], active_calendar); - self._multi_calendar.merge_reservations(reservs, active_calendar); - - self._multi_calendar._assign_extra_info(active_calendar); - self._update_buttons_counter(); - }); - }.bind(this)).then(function(){ - self._last_dates = filterDates; - }); - }, - - _assign_view_events: function() { - var self = this; - var $dateTimePickerBegin = this.renderer.$el.find('#pms-menu #date_begin'); - var $dateEndDays = this.renderer.$el.find('#pms-menu #date_end_days'); - $dateTimePickerBegin.on("dp.change", function (e) { - $dateTimePickerBegin.data("DateTimePicker").hide(); - self._on_change_filter_date(); - }); - $dateEndDays.on("change", function (e) { - self._on_change_filter_date(); - }); - - this.renderer.$el.find("#btn_swap > button").on('click', function(ev){ - var active_calendar = self._multi_calendar.get_active_calendar(); - var hcalSwapMode = active_calendar.getSwapMode(); - var $btn = $(this); - if (hcalSwapMode === HotelCalendar.MODE.NONE) { - active_calendar.setSwapMode(HotelCalendar.MODE.SWAP_FROM); - $("#btn_swap span.ntext").html(_t("Continue")); - $btn.removeClass('swap-to'); - $btn.addClass('swap-from'); - } else if (active_calendar.getReservationAction().inReservations.length > 0 && hcalSwapMode === HotelCalendar.MODE.SWAP_FROM) { - active_calendar.setSwapMode(HotelCalendar.MODE.SWAP_TO); - $("#btn_swap span.ntext").html(_t("End")); - $btn.removeClass('swap-from'); - $btn.addClass('swap-to'); - } else { - active_calendar.setSwapMode(HotelCalendar.MODE.NONE); - $("#btn_swap span.ntext").html(_t("Start Swap")); - $btn.removeClass('swap-from swap-to'); - } - }); - - this.renderer.$el.find('#pms-menu #btn_action_overbooking > button').on('click', function(ev){ - var active_calendar = self._multi_calendar.get_active_calendar(); - active_calendar.toggleOverbookingsVisibility(); - if (active_calendar.options.showOverbookings) { - $(this).addClass('overbooking-enabled'); - } else { - $(this).removeClass('overbooking-enabled'); - } - active_calendar.addReservations(_.reject(self._multi_calendar._dataset['reservations'], {overbooking:false})); - }); - - this.renderer.$el.find('#pms-menu #btn_action_cancelled > button').on('click', function(ev){ - var active_calendar = self._multi_calendar.get_active_calendar(); - active_calendar.toggleCancelledVisibility(); - if (active_calendar.options.showCancelled) { - $(this).addClass('cancelled-enabled'); - } else { - $(this).removeClass('cancelled-enabled'); - } - active_calendar.addReservations(_.reject(self._multi_calendar._dataset['reservations'], {cancelled:false})); - }); - - this.renderer.$el.find('#pms-menu #btn_action_divide > button').on('click', function(ev){ - var active_calendar = self._multi_calendar.get_active_calendar(); - var cur_mode = active_calendar.getSelectionMode(); - active_calendar.setSelectionMode(cur_mode===HotelCalendar.ACTION.DIVIDE?HotelCalendar.MODE.NONE:HotelCalendar.ACTION.DIVIDE); - }); - - this.renderer.$el.find('#pms-menu #btn_action_unify > button').on('click', function(ev){ - var active_calendar = self._multi_calendar.get_active_calendar(); - var cur_mode = active_calendar.getSelectionMode(); - active_calendar.setSelectionMode(cur_mode===HotelCalendar.ACTION.UNIFY?HotelCalendar.MODE.NONE:HotelCalendar.ACTION.UNIFY); - }); - - this.renderer.$el.find('#pms-menu #btn_save_calendar_record').on('click', function(ev){ - var active_calendar_record = self._multi_calendar.get_calendar_record(self._multi_calendar.get_active_index()); - - var name = self.renderer.$el.find('#pms-menu #calendar_name').val(); - var category = _.map(self.renderer.$el.find('#pms-menu #type_list').val(), function(item){ return +item; }); - var floor = _.map(self.renderer.$el.find('#pms-menu #floor_list').val(), function(item){ return +item; }); - var amenities = _.map(self.renderer.$el.find('#pms-menu #amenities_list').val(), function(item){ return +item; }); - var types = _.map(self.renderer.$el.find('#pms-menu #virtual_list').val(), function(item){ return +item; }); - var oparams = { - 'name': name, - 'segmentation_ids': [[6, false, category]], - 'location_ids': [[6, false, floor]], - 'amenity_ids': [[6, false, amenities]], - 'room_type_ids': [[6, false, types]], - } - - self._multi_calendar.update_active_tab_name(name); - self.model.update_or_create_calendar_record(active_calendar_record['id'], oparams).then(function(){ - active_calendar_record.name = name; - active_calendar_record.segmentation_ids = category; - active_calendar_record.location_ids = floor; - active_calendar_record.amenity_ids = amenities; - active_calendar_record.room_type_ids = types; - }).fail(function(){ - self._multi_calendar.update_active_tab_name(active_calendar_record.name); - }); - }); - - this.renderer.$el.find('#pms-menu #btn_reload_calendar_filters').on('click', function(ev){ - var active_calendar_record = self._multi_calendar.get_calendar_record(self._multi_calendar.get_active_index()); - self._multi_calendar.update_active_tab_name(active_calendar_record.name); - var $calendar_name = this.renderer.$el.find('#pms-menu .menu-filter-box #calendar_name'); - $calendar_name.val(active_calendar_record.name); - self._refresh_filters({ - 'class_id': active_calendar_record['segmentation_ids'], - 'floor_id': active_calendar_record['location_ids'], - 'amenities': active_calendar_record['amenity_ids'], - 'room_type_id': active_calendar_record['room_type_ids'], - }); - }); - - this.renderer.$el.find('#pms-menu .menu-filter-box #filters').on('show.bs.collapse', function(ev){ - self.renderer.$el.find('#pms-menu .menu-filter-box h4 i.fa').css({transform: 'rotate(90deg)'}); - }).on('hide.bs.collapse', function(ev){ - self.renderer.$el.find('#pms-menu .menu-filter-box h4 i.fa').css({transform: 'rotate(0deg)'}); - }); - this._multi_calendar.on('tab_changed', function(ev, active_index){ - if (active_index) { - self._refresh_view_options(active_index); - } - }); - }, - - _assign_multi_calendar_events: function() { - var self = this; - this._multi_calendar.on_calendar('hcalOnSavePricelist', function(ev){ - document.getElementById("btn_save_changes").disabled = true; - self.savePricelist(ev.detail.calendar_obj, ev.detail.pricelist_id, ev.detail.pricelist); - }); - - $('.hcal-reservation noselect').popover(); - var _destroy_and_clear_popover_mark = function(ev){ - $(".marked-as-having-a-popover").popover('destroy'); - $('.hcal-reservation').removeClass("marked-as-having-a-popover"); - }; - - /* destroy popover if mouse click is done out the popover */ - /* except if you click in the payment button */ - /* TODO: Review because this event is trigger anywhere, even if you click in other buttons! */ - $('html').on('click', function(e) { - if (!$(e.target).hasClass("marked-as-having-a-popover") && - !$(e.target).parents().is('.popover.in') && - (e.target.id !== 'payment_folio')) { - _destroy_and_clear_popover_mark(); - } - }); - this._multi_calendar.on_calendar('hcalOnClickReservation', function(ev){ - var active_calendar = self._multi_calendar.get_active_calendar(); - if ( active_calendar.getSelectionMode() !== HotelCalendar.MODE.NONE - || active_calendar.getSwapMode() !== HotelCalendar.MODE.NONE ) - { - return; - } - if (ev.detail.reservationObj) { - var tp = self._multi_calendar._reserv_tooltips[ev.detail.reservationObj.id]; - var qdict = self._generate_reservation_tooltip_dict(tp); - $(".marked-as-having-a-popover").popover('destroy'); - $(ev.detail.reservationDiv).addClass('marked-as-having-a-popover'); - var $reservationPopover = $(ev.detail.reservationDiv).popover({ - trigger: 'manual', - container: 'body', - animation: false, - html: true, - placement: 'auto bottom', - content: QWeb.render('HotelCalendar.TooltipReservation', qdict) - }).popover('show'); - /* add actions */ - $reservationPopover.data('bs.popover').tip().find(".btn_popover_open_folio").on('click', - {folio_id: ev.detail.reservationObj._userData.folio_id}, function(ev){ - _destroy_and_clear_popover_mark(); - self.do_action({ - type: 'ir.actions.act_window', - res_model: 'hotel.folio', - res_id: ev.data.folio_id, - views: [[false, 'form']], - }); - }); - $reservationPopover.data('bs.popover').tip().find(".btn_popover_open_reservation").on('click', - {reservation_id: ev.detail.reservationObj.id}, function(ev){ - _destroy_and_clear_popover_mark(); - self.do_action({ - type: 'ir.actions.act_window', - res_model: 'hotel.reservation', - res_id: ev.data.reservation_id, - views: [[false, 'form']] - }); - }); - $reservationPopover.data('bs.popover').tip().find(".btn_popover_open_payment_folio").on('click', - {reservation: ev.detail.reservationObj}, function(ev){ - if (ev.data.reservation.total_folio <= ev.data.reservation.total_reservation || - $('#payment_reservation').hasClass('in')) { - _destroy_and_clear_popover_mark(); - var x = self._rpc({ - model: 'hotel.reservation', - method: 'action_pay_folio', - args: [ev.data.reservation.id], - }).then(function (result){ - return self.do_action({ - name: result.name, - view_type: result.view_type, - view_mode: result.view_mode, - type: result.type, - res_model: result.res_model, - views: [[result.view_id, 'form']], - context: result.context, - target: result.target, - }); - }); - } else { - $('#payment_folio').css('color', '#A24689'); - $('#folio_pending_amount').css('animation', 'blinker 1s linear'); - $('#price_room').css('animation', 'blinker 1s linear'); - } - }); - $reservationPopover.data('bs.popover').tip().find(".btn_popover_open_payment_reservation").on('click', - {reservation_id: ev.detail.reservationObj.id}, function(ev){ - _destroy_and_clear_popover_mark(); - var x = self._rpc({ - model: 'hotel.reservation', - method: 'action_pay_reservation', - args: [ev.data.reservation_id], - }).then(function (result){ - return self.do_action({ - name: result.name, - view_type: result.view_type, - view_mode: result.view_mode, - type: result.type, - res_model: result.res_model, - views: [[result.view_id, 'form']], - context: result.context, - target: result.target, - }); - }); - }); - $reservationPopover.data('bs.popover').tip().find(".btn_popover_open_checkin").on('click', - {reservation_id: ev.detail.reservationObj.id}, function(ev){ - _destroy_and_clear_popover_mark(); - var x = self._rpc({ - model: 'hotel.reservation', - method: 'action_checks', - args: [ev.data.reservation_id], - }).then(function (result){ - return self.do_action(result); - }); - }); - $reservationPopover.data('bs.popover').tip().find(".btn_popover_open_invoice").on('click', - {reservation_id: ev.detail.reservationObj.id}, function(ev){ - _destroy_and_clear_popover_mark(); - var x = self._rpc({ - model: 'hotel.reservation', - method: 'open_invoices_reservation', - args: [ev.data.reservation_id], - }).then(function (result){ - return self.do_action(result); - }); - }); - $reservationPopover.data('bs.popover').tip().find(".btn_popover_close").on('click', function(ev){ - _destroy_and_clear_popover_mark(); - }); - } - }); - this._multi_calendar.on_calendar('hcalOnSplitReservation', function(ev){ - var qdict = {}; - var dialog = new Dialog(self, { - title: _t("Confirm Split Reservation"), - buttons: [ - { - text: _t("Yes, split it"), - classes: 'btn-primary', - close: true, - click: function () { - self.model.split_reservation(ev.detail.obj_id, ev.detail.nights); - } - }, - { - text: _t("No"), - close: true - } - ], - $content: QWeb.render('HotelCalendar.ConfirmSplitOperation', qdict) - }).open(); - }); - this._multi_calendar.on_calendar('hcalOnDblClickReservation', function(ev){ - //var res_id = ev.detail.reservationObj.getUserData('folio_id'); - $(ev.detail.reservationDiv).popover('destroy'); - self.do_action({ - type: 'ir.actions.act_window', - res_model: 'hotel.reservation', - res_id: ev.detail.reservationObj.id, - views: [[false, 'form']] - }); - }); - this._multi_calendar.on_calendar('hcalOnUnifyReservations', function(ev){ - var qdict = {}; - var dialog = new Dialog(self, { - title: _t("Confirm Unify Reservations"), - buttons: [ - { - text: _t("Yes, unify it"), - classes: 'btn-primary', - close: true, - click: function () { - self.model.unify_reservations(_.map(ev.detail.toUnify, 'id')); - } - }, - { - text: _t("No"), - close: true - } - ], - $content: QWeb.render('HotelCalendar.ConfirmUnifyOperation', qdict) - }).open(); - }); - this._multi_calendar.on_calendar('hcalOnSwapReservations', function(ev){ - var qdict = {}; - var dialog = new Dialog(self, { - title: _t("Confirm Reservation Swap"), - buttons: [ - { - text: _t("Yes, swap it"), - classes: 'btn-primary', - close: true, - click: function () { - if (ev.detail.calendar_obj.swapReservations(ev.detail.inReservs, ev.detail.outReservs)) { - var fromIds = _.pluck(ev.detail.inReservs, 'id'); - var toIds = _.pluck(ev.detail.outReservs, 'id'); - var refFromReservDiv = ev.detail.inReservs[0]._html; - var refToReservDiv = ev.detail.outReservs[0]._html; - - // Animate Movement - for (var nreserv of ev.detail.inReservs) { - $(nreserv._html).animate({'top': refToReservDiv.style.top}); - } - for (var nreserv of ev.detail.outReservs) { - $(nreserv._html).animate({'top': refFromReservDiv.style.top}); - } - self.swapReservations(fromIds, toIds, ev.detail, refFromReservDiv, refToReservDiv); - } else { - var qdict = {}; - var dialog = new Dialog(self, { - title: _t("Invalid Reservation Swap"), - buttons: [ - { - text: _t("Oops, Ok!"), - classes: 'btn-primary', - close: true - } - ], - $content: QWeb.render('HotelCalendar.InvalidSwapOperation', qdict) - }).open(); - } - } - }, - { - text: _t("No"), - close: true - } - ], - $content: QWeb.render('HotelCalendar.ConfirmSwapOperation', qdict) - }).open(); - }); - this._multi_calendar.on_calendar('hcalOnCancelSwapReservations', function(ev){ - $("#btn_swap span.ntext").html(_t("Start Swap")); - var $btn = $("#btn_swap > button"); - $btn.removeClass('swap-from swap-to'); - }); - this._multi_calendar.on_calendar('hcalOnChangeReservation', function(ev){ - var newReservation = ev.detail.newReserv; - var oldReservation = ev.detail.oldReserv; - var oldPrice = ev.detail.oldPrice; - var newPrice = ev.detail.newPrice; - var folio_id = newReservation.getUserData('folio_id'); - - var qdict = { - ncheckin: newReservation.startDate.clone().local().format(HotelConstants.L10N_DATE_MOMENT_FORMAT), - ncheckout: newReservation.endDate.clone().local().format(HotelConstants.L10N_DATE_MOMENT_FORMAT), - nroom: newReservation.room.number, - nprice: newPrice, - nadults: newReservation.adults, - ocheckin: oldReservation.startDate.clone().local().format(HotelConstants.L10N_DATE_MOMENT_FORMAT), - ocheckout: oldReservation.endDate.clone().local().format(HotelConstants.L10N_DATE_MOMENT_FORMAT), - oroom: oldReservation.room.number, - oprice: oldPrice, - oadults: oldReservation.adults - }; - - if (qdict['ncheckin'] !== qdict['ocheckin'] || qdict['ncheckout'] !== qdict['ocheckout'] - || qdict['nroom'] !== qdict['oroom'] || qdict['nadults'] !== qdict['oadults']) { - var linkedReservs = _.find(ev.detail.calendar_obj._reservations, function(item){ - return item.id !== newReservation.id && !item.unusedZone && item.getUserData('folio_id') === folio_id; - }); - qdict['hasReservsLinked'] = (linkedReservs && linkedReservs.length !== 0)?true:false; - - var hasChanged = false; - - var dialog = new Dialog(self, { - title: _t("Confirm Reservation Changes"), - buttons: [ - { - text: _t("Yes, change it"), - classes: 'btn-primary', - close: true, - disabled: !newReservation.id, - click: function () { - var roomId = newReservation.room.id; - if (newReservation.room.overbooking || newReservation.room.cancelled) { - roomId = +newReservation.room.id.substr(newReservation.room.id.indexOf('@')+1); - } - var write_values = { - 'checkin': newReservation.startDate.format(HotelConstants.ODOO_DATETIME_MOMENT_FORMAT), - 'checkout': newReservation.endDate.format(HotelConstants.ODOO_DATETIME_MOMENT_FORMAT), - 'room_id': roomId, - 'adults': newReservation.adults, - 'overbooking': newReservation.room.overbooking - }; - if (newReservation.room.cancelled) { - write_values['state'] = 'cancelled'; - } else if (!newReservation.room.cancelled && oldReservation.cancelled) { - write_values['state'] = 'draft'; - } - self.updateReservations(ev.detail.calendar_obj, [newReservation.id], - write_values, oldReservation, newReservation); - hasChanged = true; - } - }, - { - text: _t("No"), - close: true, - } - ], - $content: QWeb.render('HotelCalendar.ConfirmReservationChanges', qdict) - }).open(); - dialog.on('closed', this, function(e){ - if (!hasChanged) { - ev.detail.calendar_obj.replaceReservation(newReservation, oldReservation); - } - }); - } - }); - this._multi_calendar.on_calendar('hcalOnUpdateSelection', function(ev){ - for (var td of ev.detail.old_cells) { - $(td).tooltip('destroy'); - } - if (ev.detail.cells.length) { - var last_cell = ev.detail.cells[ev.detail.cells.length-1]; - var date_cell_start = HotelCalendar.toMoment(ev.detail.calendar_obj.etable.querySelector(`#${ev.detail.cells[0].dataset.hcalParentCell}`).dataset.hcalDate); - var date_cell_end = HotelCalendar.toMoment(ev.detail.calendar_obj.etable.querySelector(`#${last_cell.dataset.hcalParentCell}`).dataset.hcalDate).add(1, 'd'); - var parentRow = document.querySelector(`#${ev.detail.cells[0].dataset.hcalParentRow}`); - var room = ev.detail.calendar_obj.getRoom(parentRow.dataset.hcalRoomObjId); - if (room.overbooking || room.cancelled) { - return; - } - var nights = date_cell_end.diff(date_cell_start, 'days'); - var qdict = { - 'total_price': Number(ev.detail.totalPrice).toLocaleString(), - 'nights': nights - }; - $(last_cell).tooltip({ - animation: false, - html: true, - placement: 'top', - title: QWeb.render('HotelCalendar.TooltipSelection', qdict) - }).tooltip('show'); - } - }); - this._multi_calendar.on_calendar('hcalOnChangeSelectionMode', function(ev){ - var $btnDivide = this.renderer.$el.find('#pms-menu #btn_action_divide > button'); - var $btnUnify = this.renderer.$el.find('#pms-menu #btn_action_unify > button'); - if (ev.detail.newMode === HotelCalendar.ACTION.DIVIDE) { - $btnDivide.addClass('divide-enabled'); - } else { - $btnDivide.removeClass('divide-enabled'); - } - if (ev.detail.newMode === HotelCalendar.ACTION.UNIFY) { - $btnUnify.addClass('unify-enabled'); - } else { - $btnUnify.removeClass('unify-enabled'); - } - }.bind(this)); - this._multi_calendar.on_calendar('hcalOnChangeSelection', function(ev){ - var parentRow = document.querySelector(`#${ev.detail.cellStart.dataset.hcalParentRow}`); - var parentCellStart = document.querySelector(`#${ev.detail.cellStart.dataset.hcalParentCell}`); - var parentCellEnd = document.querySelector(`#${ev.detail.cellEnd.dataset.hcalParentCell}`); - var startDate = HotelCalendar.toMoment(parentCellStart.dataset.hcalDate); - var endDate = HotelCalendar.toMoment(parentCellEnd.dataset.hcalDate).add(1, 'd'); - var room = ev.detail.calendar_obj.getRoom(parentRow.dataset.hcalRoomObjId); - if (room.overbooking || room.cancelled) { - return; - } - var numBeds = (room.shared || ev.detail.calendar_obj.getOptions('divideRoomsByCapacity'))?(ev.detail.cellEnd.dataset.hcalBedNum - ev.detail.cellStart.dataset.hcalBedNum)+1:room.capacity; - if (numBeds <= 0) { - return; - } - - // Normalize Dates - if (startDate.isAfter(endDate)) { - var tt = endDate; - endDate = startDate; - startDate = tt; - } - - var def_arrival_hour = self._view_options['default_arrival_hour'].split(':'); - var def_departure_hour = self._view_options['default_departure_hour'].split(':'); - startDate.set({'hour': def_arrival_hour[0], 'minute': def_arrival_hour[1], 'second': 0}); - endDate.set({'hour': def_departure_hour[0], 'minute': def_departure_hour[1], 'second': 0}); - - var popCreate = new ViewDialogs.FormViewDialog(self, { - res_model: 'hotel.reservation', - context: { - 'default_checkin': startDate.utc().format(HotelConstants.ODOO_DATETIME_MOMENT_FORMAT), - 'default_checkout': endDate.utc().format(HotelConstants.ODOO_DATETIME_MOMENT_FORMAT), - 'default_adults': numBeds, - 'default_children': 0, - 'default_room_id': room.id, - 'default_room_type_id': room.getUserData('room_type_id'), - }, - title: _t("Create: ") + _t("Reservation"), - initial_view: "form", - disable_multiple_selection: true, - }).open(); - }); - - this._multi_calendar.on_calendar('hcalOnKeyPressed', function(ev){ - /* add actions */ - }); - - this._multi_calendar.on_calendar('hcalOnDateChanged', function(ev){ - var $dateTimePickerBegin = this.renderer.$el.find('#pms-menu #date_begin'); - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").date(ev.detail.date_begin.local()); - this._reload_active_calendar(); - }.bind(this)); - }, - - _create_reservation_obj: function(json_reserv) { - var nreserv = new HReservation({ - 'id': json_reserv['id'], - 'room_id': json_reserv['room_id'], - 'title': json_reserv['name'], - 'adults': json_reserv['adults'], - 'childrens': json_reserv['childrens'], - 'startDate': HotelCalendar.toMoment(json_reserv['checkin'], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT), - 'endDate': HotelCalendar.toMoment(json_reserv['checkout'], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT), - 'color': json_reserv['bgcolor'], - 'colorText': json_reserv['color'], - 'splitted': json_reserv['splitted'] || false, - 'readOnly': json_reserv['read_only'] || false, - 'fixDays': json_reserv['fix_days'] || false, - 'fixRooms': json_reserv['fix_room'], - 'unusedZone': false, - 'linkedId': false, - 'overbooking': json_reserv['overbooking'], - 'cancelled': json_reserv['state'] === 'cancelled', - 'total_reservation': json_reserv['price_room_services_set'], - 'total_folio': json_reserv['amount_total'], - }); - nreserv.addUserData({ - 'folio_id': json_reserv['folio_id'], - 'parent_reservation': json_reserv['parent_reservation'], - 'realDates': [ - HotelCalendar.toMoment(json_reserv['real_dates'][0], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT), - HotelCalendar.toMoment(json_reserv['real_dates'][1], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT) - ] - }); - - return nreserv; - }, - - _generate_reservation_tooltip_dict: function(tp) { - return { - 'folio_name': tp['folio_name'], - 'name': tp['name'], - 'phone': tp['phone'], - 'email': tp['email'], - 'room_type_name': tp['room_type_name'], - 'adults': tp['adults'], - 'children': tp['children'], - 'checkin': HotelCalendar.toMomentUTC(tp['real_dates'][0], '').format("DD MMMM"), - 'checkin_day_of_week': HotelCalendar.toMomentUTC(tp['real_dates'][0], '').format("dddd"), - 'checkout': HotelCalendar.toMomentUTC(tp['real_dates'][1], '').format("DD MMMM"), - 'checkout_day_of_week': HotelCalendar.toMomentUTC(tp['real_dates'][1], '').format("dddd"), - 'arrival_hour': tp['arrival_hour'], - 'departure_hour': tp['departure_hour'], - 'price_room_services_set': Number(tp['price_room_services_set']).toLocaleString(), - 'invoices_paid': Number(tp['invoices_paid']).toLocaleString(), - 'pending_amount': Number(tp['pending_amount']).toLocaleString(), - 'reservation_type': tp['type'], - 'closure_reason': tp['closure_reason'], - 'out_service_description': tp['out_service_description'], - 'splitted': tp['splitted'], - 'channel_type': tp['channel_type'], - 'board_service_name': tp['board_service_name'], - 'services': tp['services'], - }; - }, - - _update_buttons_counter: function (ev) { - var self = this; - var active_calendar = this._multi_calendar.get_active_calendar(); - - var filterDates = active_calendar.getDates(); - var dfrom_fmt = filterDates[0].format(HotelConstants.ODOO_DATE_MOMENT_FORMAT), - dto_fmt = filterDates[1].format(HotelConstants.ODOO_DATE_MOMENT_FORMAT), - now_fmt = moment().format(HotelConstants.ODOO_DATE_MOMENT_FORMAT); - - var domain_checkouts = [ - ['real_checkout', '=', now_fmt], - ['state', 'in', ['booking']], - ['reservation_type', 'not in', ['out']] - ]; - var domain_checkins = [ - ['real_checkin', '=', now_fmt], - ['state', 'in', ['confirm']], - ['reservation_type', 'not in', ['out']] - ]; - var domain_overbookings = [ - ['real_checkin', '>=', dfrom_fmt], - ['overbooking', '=', true], ['state', 'not in', ['cancelled']] - ]; - var domain_cancelled = [ - '|', '&', - ['real_checkout', '>', dfrom_fmt], - ['real_checkout', '<', dto_fmt], - ['real_checkin', '>=', dfrom_fmt], - ['real_checkin', '<=', dto_fmt], - ['state', '=', 'cancelled'] - ]; - - $.when( - this.model.search_count(domain_checkouts), - this.model.search_count(domain_checkins), - this.model.search_count(domain_overbookings), - this.model.search_count(domain_cancelled), - ).then(function(a1, a2, a3, a4){ - self.renderer.update_buttons_counter(a1, a2, a3, a4); - }); - }, - - //-------------------------------------------------------------------------- - // Handlers - //-------------------------------------------------------------------------- - _onViewAttached: function (ev) { - this._multi_calendar.recalculate_reservation_positions(); - }, - - _onLoadViewFilters: function (ev) { - var self = this; - $.when( - this.model.get_room_type_class(), - this.model.get_floors(), - this.model.get_amenities(), - this.model.get_room_types() - ).then(function(a1, a2, a3, a4){ - self.renderer.loadViewFilters(a1, a2, a3, a4); - }); - }, - - _onBusNotification: function(notifications) { - var need_reload_pricelists = false; - var need_update_counters = false; - var nreservs = [] - for (var notif of notifications) { - if (notif[0][1] === 'hotel.reservation') { - switch (notif[1]['type']) { - case 'reservation': - var reserv = notif[1]['reservation']; - // Only show notifications of other users - // if (notif[1]['subtype'] !== 'noshow' && this._view_options['show_notifications'] && notif[1]['userid'] != this.dataset.context.uid) { - // var qdict = _.clone(reserv); - // qdict = _.extend(qdict, { - // 'checkin': HotelCalendar.toMomentUTC(qdict['checkin'], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT).clone().local().format(HotelConstants.L10N_DATETIME_MOMENT_FORMAT), // UTC -> Local - // 'checkout': HotelCalendar.toMomentUTC(qdict['checkout'], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT).clone().local().format(HotelConstants.L10N_DATETIME_MOMENT_FORMAT), // UTC -> Local - // 'username': notif[1]['username'], - // 'userid': notif[1]['userid'] - // }); - // var msg = QWeb.render('HotelCalendar.Notification', qdict); - // if (notif[1]['subtype'] === "notify") { - // this.do_notify(notif[1]['title'], msg, true); - // } else if (notif[1]['subtype'] === "warn") { - // this.do_warn(notif[1]['title'], msg, true); - // } - // } - - // Create/Update/Delete reservation - if (notif[1]['action'] === 'unlink') { - this._multi_calendar.remove_reservation(reserv['id']); - this._multi_calendar._reserv_tooltips = _.pick(this._multi_calendar._reserv_tooltips, function(value, key, obj){ return key != reserv['id']; }); - nreservs = _.reject(nreservs, function(item){ return item.id == reserv['id']; }); - } else { - nreservs = _.reject(nreservs, {'id': reserv['id']}); // Only like last changes - var nreserv = this._create_reservation_obj(reserv); - this._multi_calendar._reserv_tooltips[reserv['id']] = notif[1]['tooltip']; - nreservs.push(nreserv); - } - need_update_counters = true; - break; - case 'pricelist': - this._multi_calendar.merge_pricelist(notif[1]['price']); - break; - case 'restriction': - this._multi_calendar.merge_restrictions(notif[1]['restriction']); - break; - default: - // Do Nothing - } - } - } - if (nreservs.length > 0) { - this._multi_calendar.merge_reservations(nreservs); - } - if (need_update_counters) { - this._update_buttons_counter(); - } - }, - - _onApplyFilters: function() { - var category = _.map(this.renderer.$el.find('#pms-menu #type_list').val(), function(item){ return +item; }); - var floor = _.map(this.renderer.$el.find('#pms-menu #floor_list').val(), function(item){ return +item; }); - var amenities = _.map(this.renderer.$el.find('#pms-menu #amenities_list').val(), function(item){ return +item; }); - var virtual = _.map(this.renderer.$el.find('#pms-menu #virtual_list').val(), function(item){ return +item; }); - var domain = []; - if (category && category.length > 0) { - domain.push(['class_id', 'in', category]); - } - if (floor && floor.length > 0) { - domain.push(['floor_id', 'in', floor]); - } - if (amenities && amenities.length > 0) { - domain.push(['amenities', 'in', amenities]); - } - if (virtual && virtual.length > 0) { - domain.push(['room_type_id', 'some', virtual]); - } - this._multi_calendar.get_active_calendar().setDomain(HotelCalendar.DOMAIN.ROOMS, domain); - }, - - _on_change_filter_date: function() { - var $dateTimePickerBegin = this.renderer.$el.find('#pms-menu #date_begin'); - var $dateEndDays = this.renderer.$el.find('#pms-menu #date_end_days'); - - // FIXME: Hackish onchange ignore (Used when change dates from code) - if ($dateTimePickerBegin.data("ignore_onchange") || $dateEndDays.data("ignore_onchange")) { - $dateTimePickerBegin.data("ignore_onchange", false); - $dateEndDays.data("ignore_onchange", false); - return true; - } - - var date_begin = $dateTimePickerBegin.data("DateTimePicker").date().set({'hour': 0, 'minute': 0, 'second': 0}).clone(); - - var active_calendar = this._multi_calendar.get_active_calendar(); - if (active_calendar && date_begin) { - var days = $dateEndDays.val(); - if (days === 'month') { - days = date_begin.daysInMonth(); - } - var date_end = date_begin.clone().add(days, 'd'); - if (!date_begin.isSame(this._last_dates[0].clone(), 'd') || !date_end.isSame(this._last_dates[1].clone(), 'd')) { - active_calendar.setStartDate(date_begin, $dateEndDays.val(), false, function(){ - this._reload_active_calendar(); - }.bind(this)); - } - } - }, - - _refresh_view_options: function(active_index) { - var active_calendar = this._multi_calendar.get_calendar(active_index); - - /* Dates */ - var $dateTimePickerBegin = this.renderer.$el.find('#pms-menu #date_begin'); - var $dateEndDays = this.renderer.$el.find('#pms-menu #date_end_days'); - - var start_date = active_calendar.getOptions('startDate'); - start_date = start_date.clone().add(1, 'd'); - - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").date(start_date.local()); - $dateEndDays.data("ignore_onchange", true); - $dateEndDays.val(active_calendar.getOptions('orig_days')); - $dateEndDays.trigger('change'); - - /* Overbooking */ - var $led = this.renderer.$el.find('#pms-menu #btn_action_overbooking > button'); - if (active_calendar.options.showOverbookings) { - $led.addClass('overbooking-enabled'); - } else { - $led.removeClass('overbooking-enabled'); - } - - /* Cancelled */ - $led = this.renderer.$el.find('#pms-menu #btn_action_cancelled > button'); - if (active_calendar.options.showCancelled) { - $led.addClass('cancelled-enabled'); - } else { - $led.removeClass('cancelled-enabled'); - } - - /* Divide */ - $led = this.renderer.$el.find('#pms-menu #btn_action_divide > button'); - if (active_calendar.getSelectionMode() === HotelCalendar.ACTION.DIVIDE) { - $led.addClass('divide-enabled'); - } else { - $led.removeClass('divide-enabled'); - } - - /* Unify Led */ - $led = this.renderer.$el.find('#pms-menu #btn_action_unify > button'); - if (active_calendar.getSelectionMode() === HotelCalendar.ACTION.UNIFY) { - $led.addClass('unify-enabled'); - } else { - $led.removeClass('unify-enabled'); - } - - /* Calendar Record */ - var active_calendar_record = this._multi_calendar.get_calendar_record(active_index); - var $calendar_name = this.renderer.$el.find('#pms-menu .menu-filter-box #calendar_name'); - $calendar_name.val(active_calendar_record['name']); - - /* Calendar Filters */ - this._refresh_filters(this._multi_calendar.get_active_filters()); - this._update_buttons_counter(); - }, - - _refresh_filters: function(calendar_filters) { - var $segmentation = this.renderer.$el.find('#pms-menu #type_list'); - var $location = this.renderer.$el.find('#pms-menu #floor_list'); - var $amenities = this.renderer.$el.find('#pms-menu #amenities_list'); - var $types = this.renderer.$el.find('#pms-menu #virtual_list'); - $segmentation.val(calendar_filters['class_id']); - $segmentation.trigger('change'); - $location.val(calendar_filters['floor_id']); - $location.trigger('change'); - $amenities.val(calendar_filters['amenities']); - $amenities.trigger('change'); - $types.val(calendar_filters['room_type_id']); - $types.trigger('change'); - }, - - //-------------------------------------------------------------------------- - // Helpers - //-------------------------------------------------------------------------- - _find_bootstrap_environment: function() { - var envs = ['xs', 'sm', 'md', 'lg']; - - var $el = $('
'); - $el.appendTo($('body')); - - for (var i = envs.length - 1; i >= 0; i--) { - var env = envs[i]; - - $el.addClass('hidden-'+env); - if ($el.is(':hidden')) { - $el.remove(); - return env; - } - } - }, -}); - -return PMSCalendarController; - -}); diff --git a/hotel_calendar/static/src/js/views/calendar/hotel_calendar_model.js b/hotel_calendar/static/src/js/views/calendar/hotel_calendar_model.js deleted file mode 100644 index 96eb3b4aa..000000000 --- a/hotel_calendar/static/src/js/views/calendar/hotel_calendar_model.js +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2018 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar.PMSCalendarModel', function (require) { -"use strict"; - -var AbstractModel = require('web.AbstractModel'), - Context = require('web.Context'), - Core = require('web.core'), - FieldUtils = require('web.field_utils'), - Session = require('web.session'); - - -return AbstractModel.extend({ - init: function () { - this._super.apply(this, arguments); - }, - - load: function (params) { - this.modelName = params.modelName; - this.modelManagementName = 'hotel.calendar.management' - }, - - swap_reservations: function(fromIds, toIds) { - return this._rpc({ - model: this.modelName, - method: 'swap_reservations', - args: [fromIds, toIds], - context: Session.user_context, - }); - }, - - get_calendar_data: function(oparams) { - var dialog = bootbox.dialog({ - message: '
Getting Calendar Data From Server...
', - onEscape: false, - closeButton: false, - size: 'small', - backdrop: false, - }); - return this._rpc({ - model: this.modelName, - method: 'get_hcalendar_all_data', - args: oparams, - context: Session.user_context, - }, { - xhr: function () { - var xhr = new window.XMLHttpRequest(); - //Download progress - xhr.addEventListener("readystatechange", function() { - if (this.readyState == this.DONE) { - console.log(`[HotelCalendar] Downloaded ${(parseInt(xhr.getResponseHeader("Content-Length"), 10)/1024).toFixed(3)}KiB of data`); - } - }, false); - return xhr; - }, - success: function() { - dialog.modal('hide'); - }, - shadow: true, - }); - }, - - get_hcalendar_settings: function() { - return this._rpc({ - model: this.modelName, - method: 'get_hcalendar_settings', - args: [false], - }); - }, - - get_room_types: function() { - var domain = [['hotel_id', '=', Session.hotel_id]]; - return this._rpc({ - model: 'hotel.room.type', - method: 'search_read', - args: [domain, ['id','name']], - context: Session.user_context, - }); - }, - get_floors: function() { - var domain = [('|', - ['hotel_ids', 'in', Session.hotel_id], - ['hotel_ids', '=', false] - )]; - return this._rpc({ - model: 'hotel.floor', - method: 'search_read', - args: [domain, ['id','name']], - context: Session.user_context, - }); - }, - get_amenities: function() { - var domain = [('|', - ['hotel_ids', 'in', Session.hotel_id], - ['hotel_ids', '=', false] - )]; - // TODO: Filter rooms by amenities is not working - return this._rpc({ - model: 'hotel.amenity', - method: 'search_read', - args: [domain, ['id','name']], - context: Session.user_context, - }); - }, - get_room_type_class: function() { - var domain = [('|', - ['hotel_ids', 'in', Session.hotel_id], - ['hotel_ids', '=', false] - )]; - return this._rpc({ - model: 'hotel.room.type.class', - method: 'search_read', - args: [domain, ['id','name']], - context: Session.user_context, - }); - }, - - search_count: function(domain) { - domain.push(['hotel_id', '=', Session.hotel_id]); - return this._rpc({ - model: this.modelName, - method: 'search_count', - args: [domain], - context: Session.user_context, - }); - }, - - update_records: function(ids, vals) { - return this._rpc({ - model: this.modelName, - method: 'write', - args: [ids, vals], - context: Session.user_context, - }); - }, - - update_or_create_calendar_record: function(ids, vals) { - if (!ids) { - return this._rpc({ - model: 'hotel.calendar', - method: 'create', - args: [vals], - context: Session.user_context, - }); - } - return this._rpc({ - model: 'hotel.calendar', - method: 'write', - args: [ids, vals], - context: Session.user_context, - }); - }, - - folio_search_count: function(domain) { - return this._rpc({ - model: 'hotel.folio', - method: 'search_count', - args: [domain], - context: Session.user_context, - }); - }, - - split_reservation: function(id, nights) { - return this._rpc({ - model: this.modelName, - method: 'split', - args: [[id], nights], - context: Session.user_context, - }) - }, - - unify_reservations: function(reserv_ids) { - return this._rpc({ - model: this.modelName, - method: 'unify_ids', - args: [reserv_ids], - context: Session.user_context, - }) - }, - - save_changes: function(params) { - // params.splice(0, 0, false); // FIXME: ID=False because first parameter its an integer - return this._rpc({ - model: 'hotel.calendar.management', - method: 'save_changes', - args: params, - context: Session.user_context, - }) - } -}); - -}); diff --git a/hotel_calendar/static/src/js/views/calendar/hotel_calendar_renderer.js b/hotel_calendar/static/src/js/views/calendar/hotel_calendar_renderer.js deleted file mode 100644 index 74f1d7de5..000000000 --- a/hotel_calendar/static/src/js/views/calendar/hotel_calendar_renderer.js +++ /dev/null @@ -1,284 +0,0 @@ -/* global $, odoo, _, HotelCalendar, moment */ -// Copyright 2018 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar.PMSCalendarRenderer', function (require) { -"use strict"; - -var Core = require('web.core'), - ViewDialogs = require('web.view_dialogs'), - Dialog = require('web.Dialog'), - Session = require('web.session'), - AbstractRenderer = require('web.AbstractRenderer'), - HotelConstants = require('hotel_calendar.Constants'), - //Formats = require('web.formats'), - - _t = Core._t, - _lt = Core._lt, - QWeb = Core.qweb; - -var HotelCalendarView = AbstractRenderer.extend({ - /** VIEW OPTIONS **/ - template: "hotel_calendar.HotelCalendarView", - display_name: _lt('Hotel Calendar'), - icon: 'fa fa-map-marker', - searchable: false, - searchview_hidden: true, - - - /** VIEW METHODS **/ - init: function(parent, state, params) { - this._super.apply(this, arguments); - }, - - start: function () { - this.init_calendar_view(); - return this._super(); - }, - - on_attach_callback: function() { - this._super(); - - if (!this._is_visible) { - // FIXME: Workaround for restore "lost" reservations (Drawn when the view is hidden) - this.trigger_up('onViewAttached'); - } - }, - - /** CUSTOM METHODS **/ - get_view_filter_dates: function () { - var $dateTimePickerBegin = this.$el.find('#pms-menu #date_begin'); - var $dateEndDays = this.$el.find('#pms-menu #date_end_days'); - var date_begin = $dateTimePickerBegin.data("DateTimePicker").date().clone(); - var days = $dateEndDays.val(); - if (days === 'month') { - days = date_begin.daysInMonth(); - } - var date_end = date_begin.clone().add(days, 'd'); - return [date_begin, date_end]; - }, - - update_buttons_counter: function(ncheckouts, ncheckins, noverbookings, ncancelled) { - var self = this; - // Checkouts Button - var $ninfo = self.$el.find('#pms-menu #btn_action_checkout span.ninfo'); - $ninfo.text(ncheckouts); - - // Checkins Button - $ninfo = self.$el.find('#pms-menu #btn_action_checkin span.ninfo'); - $ninfo.text(ncheckins); - - // OverBookings - $ninfo = self.$el.find('#pms-menu #btn_action_overbooking span.ninfo'); - $ninfo.text(noverbookings); - if (noverbookings) { - $ninfo.parent().parent().addClass('overbooking-highlight'); - } else { - $ninfo.parent().parent().removeClass('overbooking-highlight'); - } - - // Cancelled - $ninfo = self.$el.find('#pms-menu #btn_action_cancelled span.ninfo'); - $ninfo.text(ncancelled); - if (ncancelled) { - $ninfo.parent().parent().addClass('cancelled-highlight'); - } else { - $ninfo.parent().parent().removeClass('cancelled-highlight'); - } - }, - - init_calendar_view: function(){ - var self = this; - - /** VIEW CONTROLS INITIALIZATION **/ - // DATE TIME PICKERS - var DTPickerOptions = { - viewMode: 'months', - icons : { - time: 'fa fa-clock-o', - date: 'fa fa-calendar', - up: 'fa fa-chevron-up', - down: 'fa fa-chevron-down' - }, - //language : moment.locale(), - locale : moment.locale(), - format : HotelConstants.L10N_DATE_MOMENT_FORMAT, - widgetPositioning:{ - horizontal: 'auto', - vertical: 'bottom' - } - }; - var $dateTimePickerBegin = this.$el.find('#pms-menu #date_begin'); - var $dateEndDays = this.$el.find('#pms-menu #date_end_days'); - $dateTimePickerBegin.datetimepicker(DTPickerOptions); - $dateEndDays.select2({ - data: [ - {id:7, text: '1w'}, - {id:12, text: '2w'}, - {id:21, text: '3w'}, - {id:'month', text: '1m'}, - {id:60, text: '2m'}, - {id:90, text: '3m'}, - ], - allowClear: true, - minimumResultsForSearch: -1 - }); - - /* TOUCH EVENTS */ - this.$el.on('touchstart', function(ev){ - var orgEvent = ev.originalEvent; - this._mouseEventStartPos = [orgEvent.touches[0].screenX, orgEvent.touches[0].screenY]; - }); - this.$el.on('touchend', function(ev){ - var orgEvent = ev.originalEvent; - if (orgEvent.changedTouches.length > 2) { - var mousePos = [orgEvent.changedTouches[0].screenX, orgEvent.changedTouches[0].screenY]; - var mouseDiffX = mousePos[0] - this._mouseEventStartPos[0]; - var moveLength = 40; - var date_begin = false; - var days = orgEvent.changedTouches.length == 3 && 7 || 1; - if (mouseDiffX < -moveLength) { - date_begin = $dateTimePickerBegin.data("DateTimePicker").date().set({'hour': 0, 'minute': 0, 'second': 0}).clone().add(days, 'd'); - } - else if (mouseDiffX > moveLength) { - date_begin = $dateTimePickerBegin.data("DateTimePicker").date().set({'hour': 0, 'minute': 0, 'second': 0}).clone().subtract(days, 'd'); - } - if (date_begin) { - $dateTimePickerBegin.data("DateTimePicker").date(date_begin); - } - } - }); - - /* BUTTONS */ - var $button = this.$el.find('#pms-menu #btn_action_bookings'); - $button.on('click', function(ev){ self._open_search_tree('book'); }); - $button = this.$el.find('#pms-menu #btn_action_checkins'); - $button.on('click', function(ev){ self._open_search_tree('checkin'); }); - $button = this.$el.find('#pms-menu #btn_action_invoices'); - $button.on('click', function(ev){ self._open_search_tree('invoice'); }); - $button = this.$el.find('#pms-menu #btn_action_folios'); - $button.on('click', function(ev){ self._open_search_tree('folio'); }); - // $button = this.$el.find('#pms-menu #bookings_search'); - // $button.on('keypress', function(ev){ - // if (ev.keyCode === 13) { - // self._open_bookings_tree(); - // } - // }); - - this.$el.find("button[data-action]").on('click', function(ev){ - self.do_action(this.dataset.action); - }); - - return $.when( - this.trigger_up('onUpdateButtonsCounter'), - this.trigger_up('onLoadViewFilters'), - ); - }, - - loadViewFilters: function(resultsHotelRoomType, resultsHotelFloor, resultsHotelRoomAmenities, resultsHotelVirtualRooms) { - var $list = this.$el.find('#pms-menu #type_list'); - $list.html(''); - resultsHotelRoomType.forEach(function(item, index){ - $list.append(``); - }); - $list.select2(); - $list.on('change', function(ev){ - this.trigger_up('onApplyFilters'); - }.bind(this)); - - // Get Floors - $list = this.$el.find('#pms-menu #floor_list'); - $list.html(''); - resultsHotelFloor.forEach(function(item, index){ - $list.append(``); - }); - $list.select2(); - $list.on('change', function(ev){ - this.trigger_up('onApplyFilters'); - }.bind(this)); - - // Get Amenities - $list = this.$el.find('#pms-menu #amenities_list'); - $list.html(''); - resultsHotelRoomAmenities.forEach(function(item, index){ - $list.append(``); - }); - $list.select2(); - $list.on('change', function(ev){ - this.trigger_up('onApplyFilters'); - }.bind(this)); - - // Get Virtual Rooms - $list = this.$el.find('#pms-menu #virtual_list'); - $list.html(''); - resultsHotelVirtualRooms.forEach(function(item, index){ - $list.append(``); - }); - $list.select2(); - $list.on('change', function(ev){ - this.trigger_up('onApplyFilters'); - }.bind(this)); - }, - - _generate_search_domain: function(tsearch, type) { - var domain = []; - domain.push('|', '|', '|', '|', - ['partner_id.name', 'ilike', tsearch], - ['partner_id.mobile', 'ilike', tsearch], - ['partner_id.vat', 'ilike', tsearch], - ['partner_id.email', 'ilike', tsearch], - ['partner_id.phone', 'ilike', tsearch]); - if (type === 'invoice') { - domain.splice(0, 0, '|'); - domain.push(['number', 'ilike', tsearch]); - } - return domain; - }, - - _generate_search_res_model: function(type) { - var model = ''; - var title = ''; - if (type === 'book') { - model = 'hotel.reservation'; - title = _t('Reservations'); - } else if (type === 'checkin') { - model = 'hotel.checkin.partner'; - title = _t('Checkins'); - } else if (type === 'invoice') { - model = 'account.invoice'; - title = _t('Invoices'); - } else if (type === 'folio') { - model = 'hotel.folio' - title = _t('Folios'); - } - return [model, title]; - }, - - _open_search_tree: function(type) { - var $elm = this.$el.find('#pms-menu #bookings_search'); - var searchQuery = $elm.val(); - var domain = false; - if (searchQuery) { - domain = this._generate_search_domain(searchQuery, type); - } else { - domain = []; - } - - var [model, title] = this._generate_search_res_model(type); - - this.do_action({ - type: 'ir.actions.act_window', - view_mode: 'form', - view_type: 'tree,form', - res_model: model, - views: [[false, 'list'], [false, 'form']], - domain: domain, - name: searchQuery?`${title} for ${searchQuery}`:`All ${title}` - }); - - $elm.val(''); - }, -}); - -return HotelCalendarView; - -}); diff --git a/hotel_calendar/static/src/js/views/calendar/hotel_calendar_view.js b/hotel_calendar/static/src/js/views/calendar/hotel_calendar_view.js deleted file mode 100644 index 757f38e50..000000000 --- a/hotel_calendar/static/src/js/views/calendar/hotel_calendar_view.js +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2018 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar.PMSCalendarView', function (require) { -"use strict"; - -var AbstractView = require('web.AbstractView'), - PMSCalendarModel = require('hotel_calendar.PMSCalendarModel'), - PMSCalendarController = require('hotel_calendar.PMSCalendarController'), - PMSCalendarRenderer = require('hotel_calendar.PMSCalendarRenderer'), - ViewRegistry = require('web.view_registry'), - SystrayMenu = require('web.SystrayMenu'), - ControlPanel = require('web.ControlPanel'), - Widget = require('web.Widget'), - Session = require('web.session'), - Core = require('web.core'), - - _lt = Core._lt, - QWeb = Core.qweb; - -/* HIDE CONTROL PANEL */ -/* FIXME: Look's like a hackish solution */ -ControlPanel.include({ - update: function(status, options) { - if (typeof options === 'undefined') { - options = {}; - } - if (typeof options.toHide === 'undefined') - options.toHide = false; - var action_stack = this.getParent().action_stack; - if (action_stack && action_stack.length) { - var active_action = action_stack[action_stack.length-1]; - if (active_action.widget && active_action.widget.active_view && - active_action.widget.active_view.type === 'pms'){ - options.toHide = true; - } - } - this._super(status, options); - this._toggle_visibility(!options.toHide); - } -}); - -/** SYSTRAY **/ -var CalendarMenu = Widget.extend({ - template: 'HotelCalendar.SettingsMenu', - events: { - "click a[data-action]": "perform_callback", - }, - - start: function(){ - this.$dropdown = this.$(".o_calendar_settings_dropdown"); - return $.when( - this._rpc({ - model: 'res.users', - method: 'read', - args: [[Session.uid], ["pms_show_notifications", "pms_show_pricelist", "pms_show_availability"]], - context: Session.user_context, - }) - ).then(function(result) { - this._show_notifications = result[0]['pms_show_notifications']; - this._show_pricelist = result[0]['pms_show_pricelist']; - this._show_availability = result[0]['pms_show_availability']; - return this.update(); - }.bind(this)); - }, - - perform_callback: function (evt) { - evt.preventDefault(); - var params = $(evt.target).data(); - var callback = params.action; - - if (callback && this[callback]) { - this[callback](params, evt); - } else { - console.warn("No handler for ", callback); - } - }, - - update: function() { - // var view_type = this.getParent().getParent()._current_state.view_type; - // if (view_type === 'pms') { - // this.do_show(); - this.$dropdown - .empty() - .append(QWeb.render('HotelCalendar.SettingsMenu.Global', { - manager: this, - })); - // } - // else { - // this.do_hide(); - // } - return $.when(); - }, - - toggle_show_notification: function() { - this._show_notifications = !this._show_notifications; - this._rpc({ - model: 'res.users', - method: 'write', - args: [[Session.uid], {pms_show_notifications: this._show_notifications}], - context: Session.user_context, - }).then(function () { - window.location.reload(); - }); - }, - - toggle_show_pricelist: function() { - this._show_pricelist = !this._show_pricelist; - this._rpc({ - model: 'res.users', - method: 'write', - args: [[Session.uid], {pms_show_pricelist: this._show_pricelist}], - context: Session.user_context, - }).then(function () { - window.location.reload(); - }); - }, - - toggle_show_availability: function() { - this._show_availability = !this._show_availability; - this._rpc({ - model: 'res.users', - method: 'write', - args: [[Session.uid], {pms_show_availability: this._show_availability}], - context: Session.user_context, - }).then(function () { - window.location.reload(); - }); - }, -}); - -var PMSCalendarView = AbstractView.extend({ - display_name: _lt('Calendar PMS'), - icon: 'fa-calendar', - //jsLibs: [], - cssLibs: ['/hotel_calendar/static/src/lib/hcalendar/css/hcalendar.css'], - config: { - Model: PMSCalendarModel, - Controller: PMSCalendarController, - Renderer: PMSCalendarRenderer, - }, - - init: function (viewInfo, params) { - this._super.apply(this, arguments); - var arch = viewInfo.arch; - var fields = viewInfo.fields; - var attrs = arch.attrs; - - // If form_view_id is set, then the calendar view will open a form view - // with this id, when it needs to edit or create an event. - this.controllerParams.formViewId = - attrs.form_view_id ? parseInt(attrs.form_view_id, 10) : false; - if (!this.controllerParams.formViewId && params.action) { - var formViewDescr = _.find(params.action.views, function (v) { - return v[1] === 'form'; - }); - if (formViewDescr) { - this.controllerParams.formViewId = formViewDescr[0]; - } - } - - this.controllerParams.readonlyFormViewId = !attrs.readonly_form_view_id || !utils.toBoolElse(attrs.readonly_form_view_id, true) ? false : attrs.readonly_form_view_id; - this.controllerParams.context = params.context || {}; - this.controllerParams.displayName = params.action && params.action.name; - - this.loadParams.fields = fields; - this.loadParams.fieldsInfo = viewInfo.fieldsInfo; - this.loadParams.creatable = false; - - this.loadParams.mode = attrs.mode; - }, -}); - -SystrayMenu.Items.push(CalendarMenu); -ViewRegistry.add('pms', PMSCalendarView); -//Core.view_registry.add('pms', HotelCalendarView); - -return PMSCalendarView; - -}); diff --git a/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_controller.js b/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_controller.js deleted file mode 100644 index 08bbdb913..000000000 --- a/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_controller.js +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2018 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar.MPMSCalendarController', function (require) { -"use strict"; - -var AbstractController = require('web.AbstractController'), - Core = require('web.core'), - Bus = require('bus.bus').bus, - HotelConstants = require('hotel_calendar.Constants'), - - _t = Core._t, - QWeb = Core.qweb; - -var MPMSCalendarController = AbstractController.extend({ - custom_events: _.extend({}, AbstractController.prototype.custom_events, { - viewUpdated: '_onViewUpdated', - onSaveChanges: '_onSaveChanges', - onLoadCalendar: '_onLoadCalendar', - onLoadCalendarSettings: '_onLoadCalendarSettings', - onLoadNewContentCalendar: '_onLoadNewContentCalendar', - }), - /** - * @override - * @param {Widget} parent - * @param {AbstractModel} model - * @param {AbstractRenderer} renderer - * @param {Object} params - */ - init: function (parent, model, renderer, params) { - this._super.apply(this, arguments); - this.displayName = params.displayName; - this.formViewId = params.formViewId; - this.context = params.context; - - Bus.on("notification", this, this._onBusNotification); - }, - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- - - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - /** - * @param {Object} record - * @param {integer} record.id - * @returns {Deferred} - */ - _updateRecord: function (record) { - return this.model.updateRecord(record).then(this.reload.bind(this)); - }, - - //-------------------------------------------------------------------------- - // Handlers - //-------------------------------------------------------------------------- - _onSaveChanges: function (ev) { - var self = this; - this.model.save_changes(_.toArray(ev.data)).then(function(results){ - self.renderer.resetSaveState(); - }); - }, - - _onLoadNewContentCalendar: function (ev) { - var self = this; - var params = this.renderer.generate_params(); - var oparams = [params['dates'][0], params['dates'][1], params['prices'], params['restrictions'], false]; - - this.model.get_hcalendar_data(oparams).then(function(results){ - self.renderer._days_tooltips = results['events']; - self.renderer._hcalendar.setData(results['prices'], results['restrictions'], results['availability'], results['count_reservations']); - self.renderer._assign_extra_info(); - }); - this.renderer._last_dates = params['dates']; - this.renderer.$CalendarHeaderDays = this.renderer.$el.find("div.table-room_type-data-header"); - this.renderer._on_scroll(); // FIXME: Workaround for update sticky header - }, - - _onLoadCalendar: function (ev) { - var self = this; - - /** DO MAGIC **/ - var params = this.renderer.generate_params(); - var oparams = [params['dates'][0], params['dates'][1], false, false, true]; - this.model.get_hcalendar_data(oparams).then(function(results){ - self.renderer._days_tooltips = results['events']; - var rooms = []; - for (var r of results['rooms']) { - var nroom = new HRoomType( - r['id'], - r['name'], - r['capacity'], - r['price'], - ); - rooms.push(nroom); - } - - // Get Pricelists - self.renderer._pricelist_id = results['pricelist_id']; - self.renderer._restriction_id = results['restriction_id']; - $.when( - self.model.get_pricelist_plans(), - self.model.get_restriction_plans(), - ).then(function(a1, a2){ - self.renderer.loadViewFilters(a1, a2); - }) - - self.renderer.create_calendar(rooms); - self.renderer.setCalendarData(results['prices'], results['restrictions'], results['availability'], results['count_reservations']); - }); - }, - - _onLoadCalendarSettings: function (ev) { - var self = this; - this.model.get_hcalendar_settings().then(function(results){ - self.renderer.setHCalendarSettings(results); - }); - }, - - _onBusNotification: function (notifications) { - if (!this.renderer._hcalendar) { - return; - } - for (var notif of notifications) { - if (notif[0][1] === 'hotel.reservation') { - switch (notif[1]['type']) { - case 'pricelist': - var prices = notif[1]['price']; - var pricelist_id = Object.keys(prices)[0]; - var pr = {}; - for (var price of prices[pricelist_id]) { - pr[price['room']] = []; - var days = Object.keys(price['days']); - for (var day of days) { - var dt = HotelCalendarManagement.toMoment(day); - pr[price['room']].push({ - 'date': dt.format(HotelConstants.ODOO_DATE_MOMENT_FORMAT), - 'price': price['days'][day], - 'id': price['id'] - }); - } - } - this.renderer._hcalendar.addPricelist(pr); - break; - case 'restriction': - // FIXME: Expected one day and one room_type - var restriction = notif[1]['restriction']; - var room_type = Object.keys(restriction)[0]; - var day = Object.keys(restriction[room_type])[0]; - var dt = HotelCalendarManagement.toMoment(day); - var rest = {}; - rest[room_type] = [{ - 'date': dt.format(HotelConstants.ODOO_DATE_MOMENT_FORMAT), - 'min_stay': restriction[room_type][day][0], - 'min_stay_arrival': restriction[room_type][day][1], - 'max_stay': restriction[room_type][day][2], - 'max_stay_arrival': restriction[room_type][day][3], - 'closed': restriction[room_type][day][4], - 'closed_arrival': restriction[room_type][day][5], - 'closed_departure': restriction[room_type][day][6], - 'id': restriction[room_type][day][7] - }]; - this.renderer._hcalendar.addRestrictions(rest); - break; - } - } - } - }, - -}); - -return MPMSCalendarController; - -}); diff --git a/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_model.js b/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_model.js deleted file mode 100644 index 7167dbd32..000000000 --- a/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_model.js +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2018 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar.MPMSCalendarModel', function (require) { -"use strict"; - -var AbstractModel = require('web.AbstractModel'), - Context = require('web.Context'), - Core = require('web.core'), - FieldUtils = require('web.field_utils'), - Session = require('web.session'); - - -return AbstractModel.extend({ - init: function () { - this._super.apply(this, arguments); - this.end_date = null; - }, - - load: function (params) { - this.modelName = params.modelName; - }, - - save_changes: function (params) { - // params.splice(0, 0, false); // FIXME: ID=False because first parameter its an integer - return this._rpc({ - model: this.modelName, - method: 'save_changes', - args: params, - context: Session.user_context, - }); - }, - - get_hcalendar_data: function (params) { - return this._rpc({ - model: this.modelName, - method: 'get_hcalendar_all_data', - args: params, - context: Session.user_context, - }); - }, - - get_pricelist_plans: function () { - var domain = [['pricelist_type', '=', 'daily']]; - domain.push('|',['hotel_ids', 'in', Session.hotel_id], - ['hotel_ids', '=', false]); - return this._rpc({ - model: 'product.pricelist', - method: 'search_read', - args: [domain, ['id','name']], - context: Session.user_context, - }); - }, - - get_restriction_plans: function () { - var domain = [['hotel_id', '=', Session.hotel_id]]; - return this._rpc({ - model: 'hotel.room.type.restriction', - method: 'search_read', - args: [domain, ['id','name']], - context: Session.user_context, - }); - }, - - get_hcalendar_settings: function () { - return this._rpc({ - model: this.modelName, - method: 'get_hcalendar_settings', - args: [false], - }); - }, -}); -}); diff --git a/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js b/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js deleted file mode 100644 index be035d910..000000000 --- a/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_renderer.js +++ /dev/null @@ -1,512 +0,0 @@ -/* global $, odoo, _, HotelCalendar, moment */ -// Copyright 2018 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar.MPMSCalendarRenderer', function (require) { -"use strict"; - -var Core = require('web.core'), - ViewDialogs = require('web.view_dialogs'), - Dialog = require('web.Dialog'), - Session = require('web.session'), - AbstractRenderer = require('web.AbstractRenderer'), - HotelConstants = require('hotel_calendar.Constants'), - //Formats = require('web.formats'), - - _t = Core._t, - _lt = Core._lt, - QWeb = Core.qweb; - -var HotelCalendarManagementView = AbstractRenderer.extend({ - /** VIEW OPTIONS **/ - template: "hotel_calendar.HotelCalendarManagementView", - display_name: _lt('Hotel Calendar Management'), - icon: 'fa fa-map-marker', - searchable: false, - searchview_hidden: true, - - // Custom Options - _view_options: {}, - _hcalendar: null, - _last_dates: [false, false], - _pricelist_id: null, - _restriction_id: null, - _days_tooltips: [], - - - /** VIEW METHODS **/ - init: function(parent, state, params) { - this._super.apply(this, arguments); - - this.model = params.model; - }, - - start: function () { - var self = this; - return this._super().then(function() { - self.init_calendar_view(); - $(window).trigger('resize'); - }); - }, - - do_show: function() { - if (this.$ehcal) { - this.$ehcal.show(); - $('.o_content').css('overflow', 'hidden'); - } - this.do_push_state({}); - return this._super(); - }, - do_hide: function () { - if (this.$ehcal) { - this.$ehcal.hide(); - $('.o_content').css('overflow', ''); - } - return this._super(); - }, - - destroy: function () { - return this._super.apply(this, arguments); - }, - - /** CUSTOM METHODS **/ - get_values_to_save: function() { - var btn_save = this.$el.find('#btn_save_changes'); - if (!btn_save.hasClass('need-save')) { - return false; - } - - var pricelist = this._hcalendar.getPricelist(true); - var restrictions = this._hcalendar.getRestrictions(true); - - var params = this.generate_params(); - return [params['prices'], params['restrictions'], pricelist, restrictions]; - }, - - save_changes: function() { - var oparams = this.get_values_to_save(); - if (oparams) { - this.trigger_up('onSaveChanges', oparams); - } - }, - - resetSaveState: function() { - this.$el.find('#btn_save_changes').removeClass('need-save'); - $('.hcal-management-record-changed').removeClass('hcal-management-record-changed'); - $('.hcal-management-input-changed').removeClass('hcal-management-input-changed'); - }, - - create_calendar: function(rooms) { - var self = this; - // CALENDAR - if (this._hcalendar) { - delete this._hcalendar; - } - this.$ehcal.empty(); - - var options = { - rooms: rooms, - days: self._view_options['days'], - endOfWeek: parseInt(self._view_options['eday_week']) || 6, - endOfWeekOffset: self._view_options['eday_week_offset'] || 0, - dateFormatLong: HotelConstants.ODOO_DATETIME_MOMENT_FORMAT, - dateFormatShort: HotelConstants.ODOO_DATE_MOMENT_FORMAT, - translations: { - 'Open': _t('Open'), - 'Closed': _t('Closed'), - 'C. Departure': _t('C. Departure'), - 'C. Arrival': _t('C. Arrival'), - 'Price': _t('Price'), - 'Availability': _t('Availability'), - 'Min. Stay': _t('Min. Stay'), - 'Max. Stay': _t('Max. Stay'), - 'Min. Stay Arrival': _t('Min. Stay Arrival'), - 'Max. Stay Arrival': _t('Max. Stay Arrival'), - 'Clousure': _t('Clousure'), - 'Free Rooms': _t('Free Rooms'), - 'No OTA': _t('No OTA'), - 'Options': _t('Options'), - 'Reset': _t('Reset'), - 'Copy': _t('Copy'), - 'Paste': _t('Paste'), - 'Clone': _t('Clone'), - 'Cancel': _t('Cancel') - } - }; - - this._hcalendar = new HotelCalendarManagement('#hcal_management_widget', options, this.$el[0]); - this._assignHCalendarEvents(); - - this.$CalendarHeaderDays = this.$el.find("div.table-room_type-data-header"); - - // Sticky Header Days - $('.o_content').scroll(this._on_scroll.bind(this)); - - // Initialize Save Button state to disable - document.getElementById("btn_save_changes").disabled = true; - }, - - setCalendarData: function (prices, restrictions, availability, count_reservations) { - this._hcalendar.setData(prices, restrictions, availability, count_reservations); - this._assign_extra_info(); - }, - - _assignHCalendarEvents: function () { - var self = this; - this._hcalendar.addEventListener('hcOnChangeDate', function(ev){ - var date_begin = moment(ev.detail.newDate); - var $dateTimePickerBegin = self.$el.find('#mpms-search #date_begin'); - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").date(date_begin); - self.reload_hcalendar_management(); - }); - this._hcalendar.addEventListener('hcmOnInputChanged', function(ev){ - var btn_save = self.$el.find('#btn_save_changes'); - if (self._hcalendar.hasChangesToSave()) { - btn_save.addClass('need-save'); - document.getElementById("btn_save_changes").disabled = false; - } else { - btn_save.removeClass('need-save'); - document.getElementById("btn_save_changes").disabled = true; - } - }); - }, - - _on_scroll: function() { - var curScrollPos = $('.o_content').scrollTop(); - if (curScrollPos > 0) { - this.$CalendarHeaderDays.css({ - top: `${curScrollPos-this.$ehcal.position().top}px`, - position: 'sticky' - }); - } else { - this.$CalendarHeaderDays.css({ - top: '0px', - position: 'initial' - }); - } - }, - - loadViewFilters: function (resultsPricelist, resultsRestrictions) { - var self = this; - - var $list = self.$el.find('#mpms-search #price_list'); - $list.html(''); - resultsPricelist.forEach(function(item, index){ - $list.append(``); - }); - $list.select2(); - $list.on('change', function(ev){ - self._check_unsaved_changes(function(){ - self.reload_hcalendar_management(); - }); - }); - - $list = self.$el.find('#mpms-search #restriction_list'); - $list.html(''); - resultsRestrictions.forEach(function(item, index){ - $list.append(``); - }); - $list.select2(); - $list.on('change', function(ev){ - self._check_unsaved_changes(function(){ - self.reload_hcalendar_management(); - }); - }); - - $list = self.$el.find('#mpms-search #mode_list'); - $list.select2({ - minimumResultsForSearch: -1 - }); - $list.on('change', function(ev){ - var mode = HotelCalendarManagement.MODE.ALL; - if (this.value === 'low') { - mode = HotelCalendarManagement.MODE.LOW; - } else if (this.value === 'medium') { - mode = HotelCalendarManagement.MODE.MEDIUM; - } - self._hcalendar.setMode(mode); - }); - }, - - call_action: function(action) { - this.do_action(action); - }, - - init_calendar_view: function(){ - var self = this; - - this.$ehcal = this.$el.find("div#hcal_management_widget"); - - /** VIEW CONTROLS INITIALIZATION **/ - // DATE TIME PICKERS - var DTPickerOptions = { - viewMode: 'months', - icons : { - time: 'fa fa-clock-o', - date: 'fa fa-calendar', - up: 'fa fa-chevron-up', - down: 'fa fa-chevron-down' - }, - locale : moment.locale(), - format : HotelConstants.L10N_DATE_MOMENT_FORMAT, - //disabledHours: [0, 1, 2, 3, 4, 5, 6, 7, 8, 18, 19, 20, 21, 22, 23] - }; - - var $dateTimePickerBegin = this.$el.find('#mpms-search #date_begin'); - $dateTimePickerBegin.datetimepicker(DTPickerOptions); - $dateTimePickerBegin.on("dp.change", function (e) { - $dateTimePickerBegin.data("DateTimePicker").hide(); // TODO: Odoo uses old datetimepicker version - self.on_change_filter_date(e, true); - }); - - var $dateEndDays = this.$el.find('#mpms-search #date_end_days'); - $dateEndDays.select2({ - data: [ - {id:7, text: '1w'}, - {id:12, text: '2w'}, - {id:21, text: '3w'}, - {id:'month', text: '1m'}, - {id:60, text: '2m'}, - {id:90, text: '3m'}, - ], - allowClear: true, - minimumResultsForSearch: -1 - }); - - $dateEndDays.on("change", function (e) { - self.on_change_filter_date(); - }); - - // View Events - this.$el.find("#mpms-search #cal-pag-prev-plus").on('click', function(ev){ - // FIXME: Ugly repeated code. Change place. - var $dateTimePickerBegin = self.$el.find('#mpms-search #date_begin'); - var date_begin = $dateTimePickerBegin.data("DateTimePicker").date().subtract(14, 'd'); - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").date(date_begin); - self.on_change_filter_date(ev, true); - ev.preventDefault(); - }); - this.$el.find("#mpms-search #cal-pag-prev").on('click', function(ev){ - // FIXME: Ugly repeated code. Change place. - var $dateTimePickerBegin = self.$el.find('#mpms-search #date_begin'); - var date_begin = $dateTimePickerBegin.data("DateTimePicker").date().subtract(7, 'd'); - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").date(date_begin); - self.on_change_filter_date(ev, true); - ev.preventDefault(); - }); - this.$el.find("#mpms-search #cal-pag-next-plus").on('click', function(ev){ - // FIXME: Ugly repeated code. Change place. - var $dateTimePickerBegin = self.$el.find('#mpms-search #date_begin'); - var date_begin = $dateTimePickerBegin.data("DateTimePicker").date().add(14, 'd'); - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").date(date_begin); - self.on_change_filter_date(ev, true); - ev.preventDefault(); - }); - this.$el.find("#mpms-search #cal-pag-next").on('click', function(ev){ - // FIXME: Ugly repeated code. Change place. - var $dateTimePickerBegin = self.$el.find('#mpms-search #date_begin'); - var date_begin = $dateTimePickerBegin.data("DateTimePicker").date().add(7, 'd'); - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").date(date_begin); - self.on_change_filter_date(ev, true); - ev.preventDefault(); - }); - this.$el.find("#mpms-search #cal-pag-selector").on('click', function(ev){ - // FIXME: Ugly repeated code. Change place. - var $dateTimePickerBegin = self.$el.find('#mpms-search #date_begin'); - var date_begin = moment().startOf('day'); - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").date(date_begin); - self.on_change_filter_date(ev, true); - ev.preventDefault(); - }); - - // Save Button - this.$el.find("#btn_save_changes").on('click', function(ev) { - document.getElementById(this.id).disabled = true; - self.save_changes(); - }); - - // Launch Massive Changes - this.$el.find("#btn_massive_changes").on('click', function(ev){ - self.call_action("hotel.action_hotel_massive_change"); - }); - - /** RENDER CALENDAR **/ - this.trigger_up('onLoadCalendarSettings'); - }, - - setHCalendarSettings: function (results) { - this._view_options = results; - var date_begin = moment().startOf('day'); - if (['xs', 'md'].indexOf(this._findBootstrapEnvironment()) >= 0) { - this._view_options['days'] = 7; - } else { - this._view_options['days'] = (this._view_options['days'] !== 'month')?parseInt(this._view_options['days']):date_begin.daysInMonth(); - } - - var $dateTimePickerBegin = this.$el.find('#mpms-search #date_begin'); - $dateTimePickerBegin.data("DateTimePicker").date(date_begin); - - var $dateEndDays = this.$el.find('#mpms-search #date_end_days'); - $dateEndDays.val('month'); - $dateEndDays.trigger('change'); - - this._last_dates = this.generate_params()['dates']; - this.trigger_up('onLoadCalendar'); - }, - - on_change_filter_date: function(ev, isStartDate) { - var self = this; - isStartDate = isStartDate || false; - var $dateTimePickerBegin = this.$el.find('#mpms-search #date_begin'); - var $dateEndDays = this.$el.find('#mpms-search #date_end_days'); - - // FIXME: Hackish onchange ignore (Used when change dates from code) - if ($dateTimePickerBegin.data("ignore_onchange") || $dateEndDays.data("ignore_onchange")) { - $dateTimePickerBegin.data("ignore_onchange", false); - $dateEndDays.data("ignore_onchange", false); - return true; - } - - var date_begin = $dateTimePickerBegin.data("DateTimePicker").date().set({'hour': 0, 'minute': 0, 'second': 0}).clone(); - - if (this._hcalendar && date_begin) { - var days = $dateEndDays.val(); - if (days === 'month') { - days = date_begin.daysInMonth(); - } - var date_end = date_begin.set({'hour': 23, 'minute': 59, 'second': 59}).clone().add(days, 'd'); - - this._check_unsaved_changes(function(){ - self._hcalendar.setStartDate(date_begin, self._hcalendar.getDateDiffDays(date_begin, date_end)); - self.reload_hcalendar_management(); - }); - } - }, - - reload_hcalendar_management: function() { - this.trigger_up('onLoadNewContentCalendar'); - }, - - generate_params: function() { - var fullDomain = []; - var prices = this.$el.find('#mpms-search #price_list').val(); - var restrictions = this.$el.find('#mpms-search #restriction_list').val(); - - var $dateTimePickerBegin = this.$el.find('#mpms-search #date_begin'); - var $dateEndDays = this.$el.find('#mpms-search #date_end_days'); - - var date_begin = $dateTimePickerBegin.data("DateTimePicker").date().set({'hour': 0, 'minute': 0, 'second': 0}).clone(); - - var days = $dateEndDays.val(); - if (days === 'month') { - days = date_begin.daysInMonth(); - } - var date_end = date_begin.set({'hour': 23, 'minute': 59, 'second': 59}).clone().add(days, 'd'); - return { - 'dates': [date_begin, date_end], - 'prices': prices, - 'restrictions': restrictions - }; - }, - - _check_unsaved_changes: function(fnCallback) { - var self = this; - var btn_save = this.$el.find("#btn_save_changes"); - if (!btn_save.hasClass('need-save')) { - btn_save.removeClass('need-save'); - document.getElementById("btn_save_changes").disabled = true; - fnCallback(); - return; - } - - new Dialog(self, { - title: _t("Unsaved Changes!"), - buttons: [ - { - text: _t("Yes, save it"), - classes: 'btn-primary', - close: true, - click: function() { - document.getElementById("btn_save_changes").disabled = true; - self.save_changes(); - fnCallback(); - } - }, - { - text: _t("No"), - close: true, - click: function() { - btn_save.removeClass('need-save'); - document.getElementById("btn_save_changes").disabled = true; - fnCallback(); - } - } - ], - $content: QWeb.render('HotelCalendarManagement.UnsavedChanges', {}) - }).open(); - }, - - _findBootstrapEnvironment: function() { - var envs = ['xs', 'sm', 'md', 'lg']; - - var $el = $('
'); - $el.appendTo($('body')); - - for (var i = envs.length - 1; i >= 0; i--) { - var env = envs[i]; - - $el.addClass('hidden-'+env); - if ($el.is(':hidden')) { - $el.remove(); - return env; - } - } - }, - - _assign_extra_info: function() { - var self = this; - - $(this._hcalendar.etableHeader).find('.hcal-cell-header-day').each(function(index, elm){ - var $elm = $(elm); - var cdate = HotelCalendarManagement.toMoment($elm.data('hcalDate'), HotelConstants.L10N_DATE_MOMENT_FORMAT); - var data = _.filter(self._days_tooltips, function(item) { - var ndate = HotelCalendarManagement.toMoment(item[2], HotelConstants.ODOO_DATE_MOMENT_FORMAT); - return ndate.isSame(cdate, 'd'); - }); - if (data.length > 0) { - $elm.addClass('hcal-event-day'); - $elm.on("mouseenter", function(data){ - var $this = $(this); - if (data.length > 0) { - var qdict = { - 'date': $this.data('hcalDate'), - 'events': _.map(data, function(item){ - return { - 'name': item[1], - 'date': item[2], - 'location': item[3] - }; - }) - }; - $this.attr('title', ''); - $this.tooltip({ - animation: true, - html: true, - placement: 'bottom', - title: QWeb.render('HotelCalendar.TooltipEvent', qdict) - }).tooltip('show'); - } - }.bind(elm, data)); - } - }); - }, -}); - -return HotelCalendarManagementView; - -}); diff --git a/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v_deprecated.js b/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v_deprecated.js deleted file mode 100644 index 096866cb2..000000000 --- a/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_v_deprecated.js +++ /dev/null @@ -1,661 +0,0 @@ -/* global $, odoo, _, HotelCalendarManagement, moment */ -// Copyright 2018 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar.HotelCalendarManagementView', function (require) { -"use strict"; - -var Core = require('web.core'), - Bus = require('bus.bus').bus, - //Data = require('web.data'), - Time = require('web.time'), - Model = require('web.DataModel'), - View = require('web.View'), - Widgets = require('web_calendar.widgets'), - //Common = require('web.form_common'), - //Pyeval = require('web.pyeval'), - ActionManager = require('web.ActionManager'), - Utils = require('web.utils'), - Dialog = require('web.Dialog'), - //Ajax = require('web.ajax'), - ControlPanel = require('web.ControlPanel'), - //Session = require('web.session'), - formats = require('web.formats'), - - _t = Core._t, - _lt = Core._lt, - QWeb = Core.qweb, - l10n = _t.database.parameters, - - ODOO_DATETIME_MOMENT_FORMAT = "YYYY-MM-DD HH:mm:ss", - ODOO_DATE_MOMENT_FORMAT = "YYYY-MM-DD", - L10N_DATE_MOMENT_FORMAT = "DD/MM/YYYY", //FIXME: Time.strftime_to_moment_format(l10n.date_format); - L10N_DATETIME_MOMENT_FORMAT = L10N_DATE_MOMENT_FORMAT + ' ' + Time.strftime_to_moment_format(l10n.time_format); - - -/* HIDE CONTROL PANEL */ -/* FIXME: Look's like a hackish solution */ -ControlPanel.include({ - update: function(status, options) { - if (typeof options.toHide === 'undefined') - options.toHide = false; - var action_stack = this.getParent().action_stack; - if (action_stack && action_stack.length) { - var active_action = action_stack[action_stack.length-1]; - if (active_action.widget && active_action.widget.active_view && - active_action.widget.active_view.type === 'mpms'){ - options.toHide = true; - } - } - this._super(status, options); - this._toggle_visibility(!options.toHide); - } -}); - -var HotelCalendarManagementView = View.extend({ - /** VIEW OPTIONS **/ - template: "hotel_calendar.HotelCalendarManagementView", - display_name: _lt('Hotel Calendar Management'), - icon: 'fa fa-map-marker', - //view_type: "mpms", - searchable: false, - searchview_hidden: true, - quick_create_instance: Widgets.QuickCreate, - defaults: _.extend({}, View.prototype.defaults, { - confirm_on_delete: true, - }), - - // Custom Options - _model: null, - _hcalendar: null, - _action_manager: null, - _last_dates: [false, false], - _pricelist_id: null, - _restriction_id: null, - _days_tooltips: [], - - /** VIEW METHODS **/ - init: function(parent, dataset, fields_view, options) { - this._super.apply(this, arguments); - this.shown = $.Deferred(); - this.dataset = dataset; - this.model = dataset.model; - this.view_type = 'mpms'; - this.selected_filters = []; - this.mutex = new Utils.Mutex(); - this._model = new Model(this.dataset.model); - this._action_manager = this.findAncestor(function(ancestor){ return ancestor instanceof ActionManager; }); - - Bus.on("notification", this, this._on_bus_signal); - }, - - start: function () { - this.shown.done(this._do_show_init.bind(this)); - return this._super(); - }, - - _do_show_init: function () { - this.init_calendar_view().then(function() { - $(window).trigger('resize'); - }); - }, - - do_show: function() { - if (this.$ehcal) { - this.$ehcal.show(); - $('.o_content').css('overflow', 'hidden'); - } - this.do_push_state({}); - this.shown.resolve(); - return this._super(); - }, - do_hide: function () { - if (this.$ehcal) { - this.$ehcal.hide(); - $('.o_content').css('overflow', ''); - } - return this._super(); - }, - - destroy: function () { - return this._super.apply(this, arguments); - }, - - /** CUSTOM METHODS **/ - save_changes: function() { - var self = this; - var btn_save = this.$el.find('#btn_save_changes'); - if (!btn_save.hasClass('need-save')) { - return; - } - - var pricelist = this._hcalendar.getPricelist(true); - var restrictions = this._hcalendar.getRestrictions(true); - var availability = this._hcalendar.getAvailability(true); - - var params = this.generate_params(); - var oparams = [false, params['prices'], params['restrictions'], pricelist, restrictions, availability]; - this._model.call('save_changes', oparams).then(function(results){ - btn_save.removeClass('need-save'); - $('.hcal-management-record-changed').removeClass('hcal-management-record-changed'); - $('.hcal-management-input-changed').removeClass('hcal-management-input-changed'); - }); - }, - - create_calendar: function(options) { - var self = this; - // CALENDAR - if (this._hcalendar) { - delete this._hcalendar; - } - - this.$ehcal.empty(); - - this._hcalendar = new HotelCalendarManagement('#hcal_management_widget', options, this.$el[0]); - this._hcalendar.addEventListener('hcOnChangeDate', function(ev){ - var date_begin = moment(ev.detail.newDate); - var days = self._hcalendar.getOptions('days')-1; - var date_end = date_begin.clone().add(days, 'd'); - - var $dateTimePickerBegin = self.$el.find('#mpms-search #date_begin'); - var $dateTimePickerEnd = self.$el.find('#mpms-search #date_end'); - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").setDate(date_begin); - $dateTimePickerEnd.data("DateTimePicker").setDate(date_end); - - self.reload_hcalendar_management(); - }); - this._hcalendar.addEventListener('hcmOnInputChanged', function(ev){ - var btn_save = self.$el.find('#btn_save_changes'); - if (self._hcalendar.hasChangesToSave()) { - btn_save.addClass('need-save'); - } else { - btn_save.removeClass('need-save'); - } - }); - - this.$CalendarHeaderDays = this.$el.find("div.table-room_type-data-header"); - - // Sticky Header Days - this.$ehcal.scroll(this._on_scroll.bind(this)); - }, - - _on_scroll: function() { - var curScrollPos = this.$ehcal.scrollTop(); - if (curScrollPos > 0) { - this.$CalendarHeaderDays.css({ - top: `${curScrollPos}px`, - position: 'sticky' - }); - } else { - this.$CalendarHeaderDays.css({ - top: '0px', - position: 'initial' - }); - } - }, - - generate_hotel_calendar: function(){ - var self = this; - debugger; - /** DO MAGIC **/ - var params = this.generate_params(); - var oparams = [params['dates'][0], params['dates'][1], false, false, true]; - this._model.call('get_hcalendar_all_data', oparams).then(function(results){ - self._days_tooltips = results['events']; - var rooms = []; - for (var r of results['rooms']) { - var nroom = new HRoomType( - r[0], // Id - r[1], // Name - r[2], // Capacity - r[3], // Price - ); - rooms.push(nroom); - } - - // Get Pricelists - self._pricelist_id = results['pricelist_id']; - new Model('product.pricelist').query(['id','name']).all().then(function(resultsPricelist){ - var $list = self.$el.find('#mpms-search #price_list'); - $list.html(''); - resultsPricelist.forEach(function(item, index){ - $list.append(``); - }); - $list.select2(); - $list.on('change', function(ev){ - self._check_unsaved_changes(function(){ - self.reload_hcalendar_management(); - }); - }); - }); - - // Get Restrictions - self._restriction_id = results['restriction_id']; - new Model('hotel.room.type.restriction').query(['id','name']).all().then(function(resultsRestrictions){ - var $list = self.$el.find('#mpms-search #restriction_list'); - $list.html(''); - resultsRestrictions.forEach(function(item, index){ - $list.append(``); - }); - $list.select2(); - $list.on('change', function(ev){ - self._check_unsaved_changes(function(){ - self.reload_hcalendar_management(); - }); - }); - }); - - // Calendar Mode - var $list = self.$el.find('#mpms-search #mode_list'); - $list.select2({ - minimumResultsForSearch: -1 - }); - $list.on('change', function(ev){ - var mode = HotelCalendarManagement.MODE.ALL; - if (this.value === 'low') { - mode = HotelCalendarManagement.MODE.LOW; - } else if (this.value === 'medium') { - mode = HotelCalendarManagement.MODE.MEDIUM; - } - self._hcalendar.setMode(mode); - }); - - self.create_calendar({ - rooms: rooms, - days: self._view_options['days'], - endOfWeek: parseInt(self._view_options['eday_week']) || 6, - endOfWeekOffset: self._view_options['eday_week_offset'] || 0, - dateFormatLong: ODOO_DATETIME_MOMENT_FORMAT, - dateFormatShort: ODOO_DATE_MOMENT_FORMAT, - translations: { - 'Open': _t('Open'), - 'Closed': _t('Closed'), - 'C. Departure': _t('C. Departure'), - 'C. Arrival': _t('C. Arrival'), - 'Price': _t('Price'), - 'Availability': _t('Availability'), - 'Min. Stay': _t('Min. Stay'), - 'Max. Stay': _t('Max. Stay'), - 'Min. Stay Arrival': _t('Min. Stay Arrival'), - 'Max. Stay Arrival': _t('Max. Stay Arrival'), - 'Clousure': _t('Clousure'), - 'Free Rooms': _t('Free Rooms'), - 'No OTA': _t('No OTA'), - 'Options': _t('Options'), - 'Reset': _t('Reset'), - 'Copy': _t('Copy'), - 'Paste': _t('Paste'), - 'Clone': _t('Clone'), - 'Cancel': _t('Cancel') - } - }); - self._hcalendar.setData(results['prices'], results['restrictions'], results['availability'], results['count_reservations']); - self._assign_extra_info(); - }); - }, - - call_action: function(action) { - this._action_manager.do_action(action); - }, - - init_calendar_view: function(){ - var self = this; - - this.$ehcal = this.$el.find("div#hcal_management_widget"); - - /** VIEW CONTROLS INITIALIZATION **/ - // DATE TIME PICKERS - var l10nn = _t.database.parameters - var DTPickerOptions = { - viewMode: 'months', - icons : { - time: 'fa fa-clock-o', - date: 'fa fa-calendar', - up: 'fa fa-chevron-up', - down: 'fa fa-chevron-down' - }, - language : moment.locale(), - format : L10N_DATE_MOMENT_FORMAT, - disabledHours: true // TODO: Odoo uses old datetimepicker version - }; - var $dateTimePickerBegin = this.$el.find('#mpms-search #date_begin'); - var $dateTimePickerEnd = this.$el.find('#mpms-search #date_end'); - $dateTimePickerBegin.datetimepicker(DTPickerOptions); - $dateTimePickerEnd.datetimepicker($.extend({}, DTPickerOptions, { 'useCurrent': false })); - $dateTimePickerBegin.on("dp.change", function (e) { - $dateTimePickerEnd.data("DateTimePicker").setMinDate(e.date.add(3,'d')); - $dateTimePickerEnd.data("DateTimePicker").setMaxDate(e.date.add(2,'M')); - $dateTimePickerBegin.data("DateTimePicker").hide(); // TODO: Odoo uses old datetimepicker version - self.on_change_filter_date(e, true); - }); - $dateTimePickerEnd.on("dp.change", function (e) { - self.on_change_filter_date(e, false); - $dateTimePickerEnd.data("DateTimePicker").hide(); // TODO: Odoo uses old datetimepicker version - }); - - // var date_begin = moment().startOf('day'); - // var date_end = date_begin.clone().add(this._view_options['days'], 'd').endOf('day'); - // $dateTimePickerBegin.data("ignore_onchange", true); - // $dateTimePickerBegin.data("DateTimePicker").setDate(date_begin); - // $dateTimePickerEnd.data("DateTimePicker").setDate(date_end); - // this._last_dates = this.generate_params()['dates']; - - // View Events - this.$el.find("#mpms-search #cal-pag-prev-plus").on('click', function(ev){ - // FIXME: Ugly repeated code. Change place. - var $dateTimePickerBegin = self.$el.find('#mpms-search #date_begin'); - var $dateTimePickerEnd = self.$el.find('#mpms-search #date_end'); - //var days = moment($dateTimePickerBegin.data("DateTimePicker").getDate()).clone().local().daysInMonth(); - var date_begin = $dateTimePickerBegin.data("DateTimePicker").getDate().subtract(14, 'd'); - var date_end = $dateTimePickerEnd.data("DateTimePicker").getDate().subtract(14, 'd'); - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").setDate(date_begin); - $dateTimePickerEnd.data("DateTimePicker").setDate(date_end); - - ev.preventDefault(); - }); - this.$el.find("#mpms-search #cal-pag-prev").on('click', function(ev){ - // FIXME: Ugly repeated code. Change place. - var $dateTimePickerBegin = self.$el.find('#mpms-search #date_begin'); - var $dateTimePickerEnd = self.$el.find('#mpms-search #date_end'); - var date_begin = $dateTimePickerBegin.data("DateTimePicker").getDate().subtract(7, 'd'); - var date_end = $dateTimePickerEnd.data("DateTimePicker").getDate().subtract(7, 'd'); - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").setDate(date_begin); - $dateTimePickerEnd.data("DateTimePicker").setDate(date_end); - - ev.preventDefault(); - }); - this.$el.find("#mpms-search #cal-pag-next-plus").on('click', function(ev){ - // FIXME: Ugly repeated code. Change place. - var $dateTimePickerBegin = self.$el.find('#mpms-search #date_begin'); - var $dateTimePickerEnd = self.$el.find('#mpms-search #date_end'); - //var days = moment($dateTimePickerBegin.data("DateTimePicker").getDate()).clone().local().daysInMonth(); - var date_begin = $dateTimePickerBegin.data("DateTimePicker").getDate().add(14, 'd'); - var date_end = $dateTimePickerEnd.data("DateTimePicker").getDate().add(14, 'd'); - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").setDate(date_begin); - $dateTimePickerEnd.data("DateTimePicker").setDate(date_end); - - ev.preventDefault(); - }); - this.$el.find("#mpms-search #cal-pag-next").on('click', function(ev){ - // FIXME: Ugly repeated code. Change place. - var $dateTimePickerBegin = self.$el.find('#mpms-search #date_begin'); - var $dateTimePickerEnd = self.$el.find('#mpms-search #date_end'); - var date_begin = $dateTimePickerBegin.data("DateTimePicker").getDate().add(7, 'd'); - var date_end = $dateTimePickerEnd.data("DateTimePicker").getDate().add(7, 'd'); - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").setDate(date_begin); - $dateTimePickerEnd.data("DateTimePicker").setDate(date_end); - - ev.preventDefault(); - }); - this.$el.find("#mpms-search #cal-pag-selector").on('click', function(ev){ - // FIXME: Ugly repeated code. Change place. - var $dateTimePickerBegin = self.$el.find('#mpms-search #date_begin'); - var $dateTimePickerEnd = self.$el.find('#mpms-search #date_end'); - var date_begin = moment().startOf('day'); - var date_end = date_begin.clone().add(self._view_options['days'], 'd').endOf('day'); - $dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").setDate(date_begin); - $dateTimePickerEnd.data("DateTimePicker").setDate(date_end); - - ev.preventDefault(); - }); - - // Save Button - this.$el.find("#btn_save_changes").on('click', function(ev){ - self.save_changes(); - }); - - // Launch Massive Changes - this.$el.find("#btn_massive_changes").on('click', function(ev){ - self.call_action("hotel.action_hotel_massive_change"); - }); - - /** RENDER CALENDAR **/ - this._model.call('get_hcalendar_settings', [false]).then(function(results){ - self._view_options = results; - var date_begin = moment().startOf('day'); - if (['xs', 'md'].indexOf(self._findBootstrapEnvironment()) >= 0) { - self._view_options['days'] = 7; - } else { - self._view_options['days'] = (self._view_options['days'] !== 'month')?parseInt(self._view_options['days']):date_begin.daysInMonth(); - } - var date_end = date_begin.clone().add(self._view_options['days'], 'd').endOf('day'); - var $dateTimePickerBegin = self.$el.find('#mpms-search #date_begin'); - var $dateTimePickerEnd = self.$el.find('#mpms-search #date_end'); - //$dateTimePickerBegin.data("ignore_onchange", true); - $dateTimePickerBegin.data("DateTimePicker").setDate(date_begin); - //$dateTimePickerEnd.data("ignore_onchange", true); - $dateTimePickerEnd.data("DateTimePicker").setDate(date_end); - self._last_dates = self.generate_params()['dates']; - - self.generate_hotel_calendar(); - }); - - return $.when(); - }, - - on_change_filter_date: function(ev, isStartDate) { - var self = this; - isStartDate = isStartDate || false; - var $dateTimePickerBegin = this.$el.find('#mpms-search #date_begin'); - var $dateTimePickerEnd = this.$el.find('#mpms-search #date_end'); - - // FIXME: Hackish onchange ignore (Used when change dates from code) - if ($dateTimePickerBegin.data("ignore_onchange") || $dateTimePickerEnd.data("ignore_onchange")) { - $dateTimePickerBegin.data("ignore_onchange", false); - $dateTimePickerEnd.data("ignore_onchange", false) - return true; - } - - var date_begin = $dateTimePickerBegin.data("DateTimePicker").getDate().set({'hour': 0, 'minute': 0, 'second': 0}).clone(); - - if (this._hcalendar && date_begin) { - if (isStartDate) { - var ndate_end = date_begin.clone().add(this._view_options['days'], 'd'); - $dateTimePickerEnd.data("ignore_onchange", true); - $dateTimePickerEnd.data("DateTimePicker").setDate(ndate_end.local()); - } - - var date_end = $dateTimePickerEnd.data("DateTimePicker").getDate().set({'hour': 23, 'minute': 59, 'second': 59}).clone(); - - this._check_unsaved_changes(function(){ - self._hcalendar.setStartDate(date_begin, self._hcalendar.getDateDiffDays(date_begin, date_end)); - self.reload_hcalendar_management(); - }); - } - }, - - _on_bus_signal: function(notifications) { - if (!this._hcalendar) { - return; - } - for (var notif of notifications) { - if (notif[0][1] === 'hotel.reservation') { - switch (notif[1]['type']) { - case 'availability': - var avail = notif[1]['availability']; - var room_type = Object.keys(avail)[0]; - var day = Object.keys(avail[room_type])[0]; - var dt = HotelCalendarManagement.toMoment(day); - var availability = {}; - availability[room_type] = [{ - 'date': dt.format(ODOO_DATE_MOMENT_FORMAT), - 'avail': avail[room_type][day][0], - 'no_ota': avail[room_type][day][1], - 'id': avail[room_type][day][2] - }]; - this._hcalendar.addAvailability(availability); - break; - case 'pricelist': - var prices = notif[1]['price']; - var pricelist_id = Object.keys(prices)[0]; - var pr = {}; - for (var price of prices[pricelist_id]) { - pr[price['room']] = []; - var days = Object.keys(price['days']); - for (var day of days) { - var dt = HotelCalendarManagement.toMoment(day); - pr[price['room']].push({ - 'date': dt.format(ODOO_DATE_MOMENT_FORMAT), - 'price': price['days'][day], - 'id': price['id'] - }); - } - } - this._hcalendar.addPricelist(pr); - break; - case 'restriction': - // FIXME: Expected one day and one room_type - var restriction = notif[1]['restriction']; - var room_type = Object.keys(restriction)[0]; - var day = Object.keys(restriction[room_type])[0]; - var dt = HotelCalendarManagement.toMoment(day); - var rest = {}; - rest[room_type] = [{ - 'date': dt.format(ODOO_DATE_MOMENT_FORMAT), - 'min_stay': restriction[room_type][day][0], - 'min_stay_arrival': restriction[room_type][day][1], - 'max_stay': restriction[room_type][day][2], - 'max_stay_arrival': restriction[room_type][day][3], - 'closed': restriction[room_type][day][4], - 'closed_arrival': restriction[room_type][day][5], - 'closed_departure': restriction[room_type][day][6], - 'id': restriction[room_type][day][7] - }]; - this._hcalendar.addRestrictions(rest); - break; - } - } - } - }, - - reload_hcalendar_management: function() { - var self = this; - var params = this.generate_params(); - var oparams = [params['dates'][0], params['dates'][1], params['prices'], params['restrictions'], false]; - this._model.call('get_hcalendar_all_data', oparams).then(function(results){ - self._days_tooltips = results['events']; - self._hcalendar.setData(results['prices'], results['restrictions'], results['availability'], results['count_reservations']); - self._assign_extra_info(); - }); - this._last_dates = params['dates']; - this.$CalendarHeaderDays = this.$el.find("div.table-room_type-data-header"); - this._on_scroll(); // FIXME: Workaround for update sticky header - }, - - generate_params: function() { - var fullDomain = []; - var prices = this.$el.find('#mpms-search #price_list').val(); - var restrictions = this.$el.find('#mpms-search #restriction_list').val(); - - var $dateTimePickerBegin = this.$el.find('#mpms-search #date_begin'); - var $dateTimePickerEnd = this.$el.find('#mpms-search #date_end'); - - var date_begin = $dateTimePickerBegin.data("DateTimePicker").getDate().set({'hour': 0, 'minute': 0, 'second': 0}).clone().utc().format(ODOO_DATE_MOMENT_FORMAT); - var date_end = $dateTimePickerEnd.data("DateTimePicker").getDate().set({'hour': 23, 'minute': 59, 'second': 59}).clone().utc().format(ODOO_DATE_MOMENT_FORMAT); - - return { - 'dates': [date_begin, date_end], - 'prices': prices, - 'restrictions': restrictions - }; - }, - - _check_unsaved_changes: function(fnCallback) { - var self = this; - var btn_save = this.$el.find("#btn_save_changes"); - if (!btn_save.hasClass('need-save')) { - btn_save.removeClass('need-save'); - fnCallback(); - return; - } - - new Dialog(self, { - title: _t("Unsaved Changes!"), - buttons: [ - { - text: _t("Yes, save it"), - classes: 'btn-primary', - close: true, - click: function() { - self.save_changes(); - fnCallback(); - } - }, - { - text: _t("No"), - close: true, - click: function() { - btn_save.removeClass('need-save'); - fnCallback(); - } - } - ], - $content: QWeb.render('HotelCalendarManagement.UnsavedChanges', {}) - }).open(); - }, - - _findBootstrapEnvironment: function() { - var envs = ['xs', 'sm', 'md', 'lg']; - - var $el = $('
'); - $el.appendTo($('body')); - - for (var i = envs.length - 1; i >= 0; i--) { - var env = envs[i]; - - $el.addClass('hidden-'+env); - if ($el.is(':hidden')) { - $el.remove(); - return env; - } - } - }, - - _assign_extra_info: function() { - var self = this; - - $(this._hcalendar.etableHeader).find('.hcal-cell-header-day').each(function(index, elm){ - var $elm = $(elm); - var cdate = HotelCalendar.toMoment($elm.data('hcalDate'), L10N_DATE_MOMENT_FORMAT); - var data = _.filter(self._days_tooltips, function(item) { - var ndate = HotelCalendar.toMoment(item[2], ODOO_DATE_MOMENT_FORMAT); - return ndate.isSame(cdate, 'd'); - }); - if (data.length > 0) { - $elm.addClass('hcal-event-day'); - $elm.on("mouseenter", function(data){ - var $this = $(this); - if (data.length > 0) { - var qdict = { - 'date': $this.data('hcalDate'), - 'events': _.map(data, function(item){ - return { - 'name': item[1], - 'date': item[2], - 'location': item[3] - }; - }) - }; - $this.attr('title', ''); - $this.tooltip({ - animation: true, - html: true, - placement: 'bottom', - title: QWeb.render('HotelCalendar.TooltipEvent', qdict) - }).tooltip('show'); - } - }.bind(elm, data)); - } - }); - }, -}); - -Core.view_registry.add('mpms', HotelCalendarManagementView); -return HotelCalendarManagementView; - -}); diff --git a/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_view.js b/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_view.js deleted file mode 100644 index 9e3af7d12..000000000 --- a/hotel_calendar/static/src/js/views/calendar_management/hotel_calendar_management_view.js +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2018 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar.MPMSCalendarView', function (require) { -"use strict"; - -var AbstractView = require('web.AbstractView'), - MPMSCalendarModel = require('hotel_calendar.MPMSCalendarModel'), - MPMSCalendarController = require('hotel_calendar.MPMSCalendarController'), - MPMSCalendarRenderer = require('hotel_calendar.MPMSCalendarRenderer'), - ViewRegistry = require('web.view_registry'), - SystrayMenu = require('web.SystrayMenu'), - ControlPanel = require('web.ControlPanel'), - Widget = require('web.Widget'), - Session = require('web.session'), - Core = require('web.core'), - - _lt = Core._lt, - QWeb = Core.qweb; - -/* HIDE CONTROL PANEL */ -/* FIXME: Look's like a hackish solution */ -ControlPanel.include({ - update: function(status, options) { - if (typeof options === 'undefined') { - options = {}; - } - if (typeof options.toHide === 'undefined') - options.toHide = false; - var action_stack = this.getParent().action_stack; - if (action_stack && action_stack.length) { - var active_action = action_stack[action_stack.length-1]; - if (active_action.widget && active_action.widget.active_view && - active_action.widget.active_view.type === 'mpms'){ - options.toHide = true; - } - } - this._super(status, options); - this._toggle_visibility(!options.toHide); - } -}); - -var MPMSCalendarView = AbstractView.extend({ - display_name: _lt('Calendar MPMS'), - icon: 'fa-calendar', - jsLibs: ['/hotel_calendar/static/src/lib/hcalendar/js/hcalendar_management.js'], - cssLibs: [ - '/hotel_calendar/static/src/lib/hcalendar/css/hcalendar.css', - '/hotel_calendar/static/src/lib/hcalendar/css/hcalendar_management.css' - ], - config: { - Model: MPMSCalendarModel, - Controller: MPMSCalendarController, - Renderer: MPMSCalendarRenderer, - }, - - init: function (viewInfo, params) { - this._super.apply(this, arguments); - var arch = viewInfo.arch; - var fields = viewInfo.fields; - var attrs = arch.attrs; - - // If form_view_id is set, then the calendar view will open a form view - // with this id, when it needs to edit or create an event. - this.controllerParams.formViewId = - attrs.form_view_id ? parseInt(attrs.form_view_id, 10) : false; - if (!this.controllerParams.formViewId && params.action) { - var formViewDescr = _.find(params.action.views, function (v) { - return v[1] === 'form'; - }); - if (formViewDescr) { - this.controllerParams.formViewId = formViewDescr[0]; - } - } - - this.controllerParams.readonlyFormViewId = !attrs.readonly_form_view_id || !utils.toBoolElse(attrs.readonly_form_view_id, true) ? false : attrs.readonly_form_view_id; - this.controllerParams.context = params.context || {}; - this.controllerParams.displayName = params.action && params.action.name; - - this.rendererParams.model = viewInfo.model; - - this.loadParams.fields = fields; - this.loadParams.fieldsInfo = viewInfo.fieldsInfo; - this.loadParams.creatable = false; - - this.loadParams.mode = attrs.mode; - }, -}); - -ViewRegistry.add('mpms', MPMSCalendarView); - -return MPMSCalendarView; - -}); diff --git a/hotel_calendar/static/src/js/views/constants.js b/hotel_calendar/static/src/js/views/constants.js deleted file mode 100644 index f52526b83..000000000 --- a/hotel_calendar/static/src/js/views/constants.js +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2018 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar.Constants', function (require) { -"use strict"; - - var Core = require('web.core'), - Time = require('web.time'), - - l10n = Core._t.database.parameters; - - return { - ODOO_DATE_MOMENT_FORMAT: 'YYYY-MM-DD', - ODOO_DATETIME_MOMENT_FORMAT: 'YYYY-MM-DD HH:mm:ss', - L10N_DATE_MOMENT_FORMAT: "DD/MM/YYYY", //FIXME: Time.strftime_to_moment_format(l10n.date_format), - L10N_DATETIME_MOMENT_FORMAT: 'DD/MM/YYYY ' + Time.strftime_to_moment_format(l10n.time_format), - - CURRENCY_SYMBOL: "€", - }; - -}); diff --git a/hotel_calendar/static/src/js/widgets/MultiCalendar.js b/hotel_calendar/static/src/js/widgets/MultiCalendar.js deleted file mode 100644 index 086cde1f5..000000000 --- a/hotel_calendar/static/src/js/widgets/MultiCalendar.js +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2018 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar.MultiCalendar', function(require) { - 'use strict'; - - var core = require('web.core'); - var session = require('web.session'); - var Widget = require('web.Widget'); - var HotelConstants = require('hotel_calendar.Constants'); - - var QWeb = core.qweb; - - var MultiCalendar = Widget.extend({ - _calendars: [], - _calendar_records: [], - _active_index: -1, - _events: {}, - _tabs: [], - _dataset: {}, - _base: null, - - - init: function(parent) { - this._super.apply(this, arguments); - }, - - start: function() { - this._super.apply(this, arguments); - - this._create_tabs_panel(); - }, - - on: function(event_name, callback) { - this.$el.on(event_name, callback.bind(this)); - }, - - reset: function() { - for (var i in this._calendars) { - delete this._calendars[i]; - } - for (var [$tab, $panel] of this._tabs) { - $tab.remove(); - $panel.remove(); - } - $('#multicalendar_tabs').remove(); - $('#multicalendar_panels').remove(); - this._calendars = []; - this._calendar_records = []; - this._tabs = []; - this._datasets = {}; - this._active_index = -1; - this._events = {}; - }, - - get_calendar: function(index) { - return this._calendars[index-1]; - }, - - get_calendar_record: function(index) { - return this._calendar_records[index-1]; - }, - - get_tab: function(index) { - return this._tabs[index]; - }, - - get_active_index: function() { - return this._active_index; - }, - - get_active_calendar: function() { - return this._calendars[this._active_index-1]; - }, - - get_active_tab: function() { - return this._tabs[this._active_index]; - }, - - update_active_tab_name: function(name) { - var [$tab, $panel] = this.get_tab(this.get_active_index()); - $tab.text(name); - }, - - get_active_filters: function() { - var calendar = this.get_active_calendar(); - var domain = calendar.getDomain(HotelCalendar.DOMAIN.ROOMS); - - var filters = {}; - for (var rule of domain) { - filters[rule[0]] = rule[2]; - } - - return filters; - }, - - recalculate_reservation_positions: function() { - var active_calendar = this.get_active_calendar(); - if (active_calendar) { - setTimeout(function(calendar){ - calendar._updateOffsets(); - calendar._updateReservations(false); - }.bind(this, active_calendar), 200); - } - }, - - remove_reservation: function(reserv_id) { - this._dataset['reservations'] = _.reject(this._dataset['reservations'], {id: reserv_id}); - for (var calendar of this._calendars) { - var reserv = calendar.getReservation(reserv_id); - if (reserv) { - calendar.removeReservation(reserv); - } - } - }, - - remove_extra_room_row: function(reserv, only_active_calendar) { - if (only_active_calendar) { - this.get_active_calendar().removeExtraRoomRow(reserv); - } else { - for (var calendar of this._calendars) { - calendar.removeExtraRoomRow(reserv); - } - } - }, - - swap_reservations: function(outReservs, inReservs) { - for (var calendar of this._calendars) { - calendar.swapReservations(outReservs, inReservs); - } - }, - - set_active_calendar: function(index) { - this._tabs[index+1][0].tab('show'); - }, - - set_datasets: function(pricelist, restrictions, reservations) { - this._dataset = { - pricelist: pricelist, - restrictions: restrictions, - reservations: reservations, - }; - }, - - set_options: function(options) { - this._options = options; - }, - - set_base_element: function(element) { - this._base = element; - }, - - merge_pricelist: function(pricelist, calendar) { - var keys = _.keys(pricelist); - for (var k of keys) { - var pr = pricelist[k]; - for (var pr_k in pr) { - var pr_item = pricelist[k][pr_k]; - var pr_fk = _.findKey(this._dataset['pricelist'][k], {'room': pr_item.room}); - if (pr_fk) { - this._dataset['pricelist'][k][pr_fk].room = pr_item.room; - this._dataset['pricelist'][k][pr_fk].days = _.extend(this._dataset['pricelist'][k][pr_fk].days, pr_item.days); - if (pr_item.title) { - this._dataset['pricelist'][k][pr_fk].title = pr_item.title; - } - } else { - if (!(k in this._dataset['pricelist'])) { - this._dataset['pricelist'][k] = []; - } - this._dataset['pricelist'][k].push({ - 'room': pr_item.room, - 'days': pr_item.days, - 'title': pr_item.title - }); - } - } - } - - if (!calendar) { - for (var calendar of this._calendars) { - calendar.setPricelist(this._dataset['pricelist']); - } - } else { - calendar.setPricelist(this._dataset['pricelist']); - } - }, - - merge_restrictions: function(restrictions, calendar) { - var room_type_ids = Object.keys(restrictions); - for (var vid of room_type_ids) { - if (vid in this._dataset['restrictions']) { - this._dataset['restrictions'][vid] = _.extend(this._dataset['restrictions'][vid], restrictions[vid]); - } - else { - this._dataset['restrictions'][vid] = restrictions[vid]; - } - } - - if (!calendar) { - for (var calendar of this._calendars) { - calendar.setRestrictions(this._dataset['restrictions']); - } - } else { - calendar.setRestrictions(this._dataset['restrictions']); - } - }, - - merge_reservations: function(reservations, calendar) { - for (var r of reservations) { - var rindex = _.findKey(this._dataset['reservations'], {'id': r.id}); - if (rindex) { - this._dataset['reservations'][rindex] = r; - } else { - this._dataset['reservations'].push(r); - } - } - - if (!calendar) { - for (var calendar of this._calendars) { - calendar.addReservations(reservations); - } - } else { - calendar.addReservations(reservations); - } - }, - - merge_days_tooltips: function(new_tooltips) { - for (var nt of new_tooltips) { - var fnt = _.find(this._days_tooltips, function(item) { return item['id'] === nt['id']}); - if (fnt) { - fnt = nt; - } else { - this._days_tooltips.push(nt); - } - } - }, - - create_calendar: function(calendar_record) { - var [$tab, $panel] = this._create_tab(calendar_record['name'], `calendar-pane-${calendar_record['name']}`); - var calendar = new HotelCalendar( - $panel[0], - this._options, - this._dataset['pricelist'], - this._dataset['restrictions'], - this._base); - this._assign_calendar_events(calendar); - this._assign_extra_info(calendar); - calendar.setReservations(this._dataset['reservations']); - this._calendars.push(calendar); - this._calendar_records.push(calendar_record); - return this._calendars.length-1; - }, - - on_calendar: function(event_name, callback) { - this._events[event_name] = callback; - }, - - - _create_tab: function(name, id, options) { - var self = this; - var sanitized_id = this._sanitizeId(id); - - var $tab = $('', _.extend({ - id: this._sanitizeId(name), - href: `#${sanitized_id}`, - text: name, - role: 'tab', - }, options)).data('tabindex', this._tabs.length).appendTo($('
  • ').prependTo(this.$tabs)); - $tab.on('shown.bs.tab', function(ev){ - self._active_index = $(ev.target).data('tabindex'); - self.recalculate_reservation_positions(); - if (ev.relatedTarget) { - var prev_index = $(ev.relatedTarget).data('tabindex'); - if (prev_index) { - self.get_calendar(prev_index).cancelSwap(); - } - } - - self.$el.trigger('tab_changed', [self._active_index]); - }); - $tab[0].dataset.toggle = 'tab'; - var $panel = $('
    ', { - id: sanitized_id, - class: 'tab-pane', - role: 'tabpanel' - }).appendTo(this.$tabs_content); - - this._tabs.push([$tab, $panel]); - return this._tabs[this._tabs.length-1]; - }, - - _create_tabs_panel: function() { - var self = this; - this.$el.empty(); - this.$tabs = $('
      ', { - class: 'nav nav-tabs', - id: 'multicalendar_tabs' - }).appendTo(this.$el); - this.$tabs_content = $('
      ', { - class: 'tab-content', - id: 'multicalendar_panels' - }).appendTo(this.$el); - - // '+' Tab - var [$tab, $panel] = this._create_tab('+', 'default', {class: 'multi-calendar-tab-plus'}); - $tab.on('shown.bs.tab', function(ev){ - ev.preventDefault(); - var calendar_record = { - id: false, - name: `Calendar #${self._calendars.length}`, - segmentation_ids: [], - location_ids: [], - amenity_ids: [], - room_type_ids: [] - }; - var new_calendar_id = self.create_calendar(calendar_record); - self.set_active_calendar(new_calendar_id); - }); - $('

      ', { - class: 'warn-message', - text: "NO CALENDAR DEFINED!", - }).appendTo($panel); - }, - - _assign_calendar_events: function(calendar) { - for (var event_name in this._events) { - calendar.addEventListener(event_name, this._events[event_name]); - } - }, - - _assign_extra_info: function(calendar) { - var self = this; - $(calendar.etable).find('.hcal-cell-room-type-group-item.btn-hcal-left').on("mouseenter", function(){ - var $this = $(this); - var room = calendar.getRoom($this.parent().data("hcalRoomObjId")); - if (room.overbooking) { - $this.tooltip({ - animation: true, - html: true, - placement: 'right', - title: QWeb.render('HotelCalendar.TooltipRoomOverbooking', {'name': room.number}) - }).tooltip('show'); - } else { - var qdict = { - 'room_type_name': room.getUserData('room_type_name'), - 'name': room.number - }; - $this.tooltip({ - animation: true, - html: true, - placement: 'right', - title: QWeb.render('HotelCalendar.TooltipRoom', qdict) - }).tooltip('show'); - } - }); - - $(calendar.etableHeader).find('.hcal-cell-header-day').each(function(index, elm){ - var $elm = $(elm); - var cdate = HotelCalendar.toMoment($elm.data('hcalDate'), HotelConstants.L10N_DATE_MOMENT_FORMAT); - var data = _.filter(self._days_tooltips, function(item) { - var ndate = HotelCalendar.toMoment(item['date'], HotelConstants.ODOO_DATE_MOMENT_FORMAT); - return ndate.isSame(cdate, 'd'); - }); - if (data.length > 0) { - $elm.addClass('hcal-event-day'); - $elm.append(""); - $elm.on("mouseenter", function(data){ - var $this = $(this); - if (data.length > 0) { - var qdict = { - 'date': $this.data('hcalDate'), - 'events': _.map(data, function(item){ - return { - 'name': item['name'], - 'date': item['date'], - 'location': item['location'] - }; - }) - }; - $this.attr('title', ''); - $this.tooltip({ - animation: true, - html: true, - placement: 'bottom', - title: QWeb.render('HotelCalendar.TooltipEvent', qdict) - }).tooltip('show'); - } - }.bind(elm, data)); - } - }); - }, - - _sanitizeId: function(/*String*/str) { - return str.replace(/[^a-zA-Z0-9\-_]/g, '_'); - }, - }); - - return MultiCalendar; -}); diff --git a/hotel_calendar/static/src/lib/bootbox.js b/hotel_calendar/static/src/lib/bootbox.js deleted file mode 100644 index 3e8312a85..000000000 --- a/hotel_calendar/static/src/lib/bootbox.js +++ /dev/null @@ -1,985 +0,0 @@ -/** - * bootbox.js [v4.4.0] - * - * http://bootboxjs.com/license.txt - */ - -// @see https://github.com/makeusabrew/bootbox/issues/180 -// @see https://github.com/makeusabrew/bootbox/issues/186 -(function (root, factory) { - - "use strict"; - if (typeof define === "function" && define.amd) { - // AMD. Register as an anonymous module. - define(["jquery"], factory); - } else if (typeof exports === "object") { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(require("jquery")); - } else { - // Browser globals (root is window) - root.bootbox = factory(root.jQuery); - } - -}(this, function init($, undefined) { - - "use strict"; - - // the base DOM structure needed to create a modal - var templates = { - dialog: - "

      ", - header: - "", - footer: - "", - closeButton: - "", - form: - "
      ", - inputs: { - text: - "", - textarea: - "", - email: - "", - select: - "", - checkbox: - "
      ", - date: - "", - time: - "", - number: - "", - password: - "" - } - }; - - var defaults = { - // default language - locale: "en", - // show backdrop or not. Default to static so user has to interact with dialog - backdrop: "static", - // animate the modal in/out - animate: true, - // additional class string applied to the top level dialog - className: null, - // whether or not to include a close button - closeButton: true, - // show the dialog immediately by default - show: true, - // dialog container - container: "body" - }; - - // our public object; augmented after our private API - var exports = {}; - - /** - * @private - */ - function _t(key) { - var locale = locales[defaults.locale]; - return locale ? locale[key] : locales.en[key]; - } - - function processCallback(e, dialog, callback) { - e.stopPropagation(); - e.preventDefault(); - - // by default we assume a callback will get rid of the dialog, - // although it is given the opportunity to override this - - // so, if the callback can be invoked and it *explicitly returns false* - // then we'll set a flag to keep the dialog active... - var preserveDialog = $.isFunction(callback) && callback.call(dialog, e) === false; - - // ... otherwise we'll bin it - if (!preserveDialog) { - dialog.modal("hide"); - } - } - - function getKeyLength(obj) { - // @TODO defer to Object.keys(x).length if available? - var k, t = 0; - for (k in obj) { - t ++; - } - return t; - } - - function each(collection, iterator) { - var index = 0; - $.each(collection, function(key, value) { - iterator(key, value, index++); - }); - } - - function sanitize(options) { - var buttons; - var total; - - if (typeof options !== "object") { - throw new Error("Please supply an object of options"); - } - - if (!options.message) { - throw new Error("Please specify a message"); - } - - // make sure any supplied options take precedence over defaults - options = $.extend({}, defaults, options); - - if (!options.buttons) { - options.buttons = {}; - } - - buttons = options.buttons; - - total = getKeyLength(buttons); - - each(buttons, function(key, button, index) { - - if ($.isFunction(button)) { - // short form, assume value is our callback. Since button - // isn't an object it isn't a reference either so re-assign it - button = buttons[key] = { - callback: button - }; - } - - // before any further checks make sure by now button is the correct type - if ($.type(button) !== "object") { - throw new Error("button with key " + key + " must be an object"); - } - - if (!button.label) { - // the lack of an explicit label means we'll assume the key is good enough - button.label = key; - } - - if (!button.className) { - if (total <= 2 && index === total-1) { - // always add a primary to the main option in a two-button dialog - button.className = "btn-primary"; - } else { - button.className = "btn-default"; - } - } - }); - - return options; - } - - /** - * map a flexible set of arguments into a single returned object - * if args.length is already one just return it, otherwise - * use the properties argument to map the unnamed args to - * object properties - * so in the latter case: - * mapArguments(["foo", $.noop], ["message", "callback"]) - * -> { message: "foo", callback: $.noop } - */ - function mapArguments(args, properties) { - var argn = args.length; - var options = {}; - - if (argn < 1 || argn > 2) { - throw new Error("Invalid argument length"); - } - - if (argn === 2 || typeof args[0] === "string") { - options[properties[0]] = args[0]; - options[properties[1]] = args[1]; - } else { - options = args[0]; - } - - return options; - } - - /** - * merge a set of default dialog options with user supplied arguments - */ - function mergeArguments(defaults, args, properties) { - return $.extend( - // deep merge - true, - // ensure the target is an empty, unreferenced object - {}, - // the base options object for this type of dialog (often just buttons) - defaults, - // args could be an object or array; if it's an array properties will - // map it to a proper options object - mapArguments( - args, - properties - ) - ); - } - - /** - * this entry-level method makes heavy use of composition to take a simple - * range of inputs and return valid options suitable for passing to bootbox.dialog - */ - function mergeDialogOptions(className, labels, properties, args) { - // build up a base set of dialog properties - var baseOptions = { - className: "bootbox-" + className, - buttons: createLabels.apply(null, labels) - }; - - // ensure the buttons properties generated, *after* merging - // with user args are still valid against the supplied labels - return validateButtons( - // merge the generated base properties with user supplied arguments - mergeArguments( - baseOptions, - args, - // if args.length > 1, properties specify how each arg maps to an object key - properties - ), - labels - ); - } - - /** - * from a given list of arguments return a suitable object of button labels - * all this does is normalise the given labels and translate them where possible - * e.g. "ok", "confirm" -> { ok: "OK, cancel: "Annuleren" } - */ - function createLabels() { - var buttons = {}; - - for (var i = 0, j = arguments.length; i < j; i++) { - var argument = arguments[i]; - var key = argument.toLowerCase(); - var value = argument.toUpperCase(); - - buttons[key] = { - label: _t(value) - }; - } - - return buttons; - } - - function validateButtons(options, buttons) { - var allowedButtons = {}; - each(buttons, function(key, value) { - allowedButtons[value] = true; - }); - - each(options.buttons, function(key) { - if (allowedButtons[key] === undefined) { - throw new Error("button key " + key + " is not allowed (options are " + buttons.join("\n") + ")"); - } - }); - - return options; - } - - exports.alert = function() { - var options; - - options = mergeDialogOptions("alert", ["ok"], ["message", "callback"], arguments); - - if (options.callback && !$.isFunction(options.callback)) { - throw new Error("alert requires callback property to be a function when provided"); - } - - /** - * overrides - */ - options.buttons.ok.callback = options.onEscape = function() { - if ($.isFunction(options.callback)) { - return options.callback.call(this); - } - return true; - }; - - return exports.dialog(options); - }; - - exports.confirm = function() { - var options; - - options = mergeDialogOptions("confirm", ["cancel", "confirm"], ["message", "callback"], arguments); - - /** - * overrides; undo anything the user tried to set they shouldn't have - */ - options.buttons.cancel.callback = options.onEscape = function() { - return options.callback.call(this, false); - }; - - options.buttons.confirm.callback = function() { - return options.callback.call(this, true); - }; - - // confirm specific validation - if (!$.isFunction(options.callback)) { - throw new Error("confirm requires a callback"); - } - - return exports.dialog(options); - }; - - exports.prompt = function() { - var options; - var defaults; - var dialog; - var form; - var input; - var shouldShow; - var inputOptions; - - // we have to create our form first otherwise - // its value is undefined when gearing up our options - // @TODO this could be solved by allowing message to - // be a function instead... - form = $(templates.form); - - // prompt defaults are more complex than others in that - // users can override more defaults - // @TODO I don't like that prompt has to do a lot of heavy - // lifting which mergeDialogOptions can *almost* support already - // just because of 'value' and 'inputType' - can we refactor? - defaults = { - className: "bootbox-prompt", - buttons: createLabels("cancel", "confirm"), - value: "", - inputType: "text" - }; - - options = validateButtons( - mergeArguments(defaults, arguments, ["title", "callback"]), - ["cancel", "confirm"] - ); - - // capture the user's show value; we always set this to false before - // spawning the dialog to give us a chance to attach some handlers to - // it, but we need to make sure we respect a preference not to show it - shouldShow = (options.show === undefined) ? true : options.show; - - /** - * overrides; undo anything the user tried to set they shouldn't have - */ - options.message = form; - - options.buttons.cancel.callback = options.onEscape = function() { - return options.callback.call(this, null); - }; - - options.buttons.confirm.callback = function() { - var value; - - switch (options.inputType) { - case "text": - case "textarea": - case "email": - case "select": - case "date": - case "time": - case "number": - case "password": - value = input.val(); - break; - - case "checkbox": - var checkedItems = input.find("input:checked"); - - // we assume that checkboxes are always multiple, - // hence we default to an empty array - value = []; - - each(checkedItems, function(_, item) { - value.push($(item).val()); - }); - break; - } - - return options.callback.call(this, value); - }; - - options.show = false; - - // prompt specific validation - if (!options.title) { - throw new Error("prompt requires a title"); - } - - if (!$.isFunction(options.callback)) { - throw new Error("prompt requires a callback"); - } - - if (!templates.inputs[options.inputType]) { - throw new Error("invalid prompt type"); - } - - // create the input based on the supplied type - input = $(templates.inputs[options.inputType]); - - switch (options.inputType) { - case "text": - case "textarea": - case "email": - case "date": - case "time": - case "number": - case "password": - input.val(options.value); - break; - - case "select": - var groups = {}; - inputOptions = options.inputOptions || []; - - if (!$.isArray(inputOptions)) { - throw new Error("Please pass an array of input options"); - } - - if (!inputOptions.length) { - throw new Error("prompt with select requires options"); - } - - each(inputOptions, function(_, option) { - - // assume the element to attach to is the input... - var elem = input; - - if (option.value === undefined || option.text === undefined) { - throw new Error("given options in wrong format"); - } - - // ... but override that element if this option sits in a group - - if (option.group) { - // initialise group if necessary - if (!groups[option.group]) { - groups[option.group] = $("").attr("label", option.group); - } - - elem = groups[option.group]; - } - - elem.append(""); - }); - - each(groups, function(_, group) { - input.append(group); - }); - - // safe to set a select's value as per a normal input - input.val(options.value); - break; - - case "checkbox": - var values = $.isArray(options.value) ? options.value : [options.value]; - inputOptions = options.inputOptions || []; - - if (!inputOptions.length) { - throw new Error("prompt with checkbox requires options"); - } - - if (!inputOptions[0].value || !inputOptions[0].text) { - throw new Error("given options in wrong format"); - } - - // checkboxes have to nest within a containing element, so - // they break the rules a bit and we end up re-assigning - // our 'input' element to this container instead - input = $("
      "); - - each(inputOptions, function(_, option) { - var checkbox = $(templates.inputs[options.inputType]); - - checkbox.find("input").attr("value", option.value); - checkbox.find("label").append(option.text); - - // we've ensured values is an array so we can always iterate over it - each(values, function(_, value) { - if (value === option.value) { - checkbox.find("input").prop("checked", true); - } - }); - - input.append(checkbox); - }); - break; - } - - // @TODO provide an attributes option instead - // and simply map that as keys: vals - if (options.placeholder) { - input.attr("placeholder", options.placeholder); - } - - if (options.pattern) { - input.attr("pattern", options.pattern); - } - - if (options.maxlength) { - input.attr("maxlength", options.maxlength); - } - - // now place it in our form - form.append(input); - - form.on("submit", function(e) { - e.preventDefault(); - // Fix for SammyJS (or similar JS routing library) hijacking the form post. - e.stopPropagation(); - // @TODO can we actually click *the* button object instead? - // e.g. buttons.confirm.click() or similar - dialog.find(".btn-primary").click(); - }); - - dialog = exports.dialog(options); - - // clear the existing handler focusing the submit button... - dialog.off("shown.bs.modal"); - - // ...and replace it with one focusing our input, if possible - dialog.on("shown.bs.modal", function() { - // need the closure here since input isn't - // an object otherwise - input.focus(); - }); - - if (shouldShow === true) { - dialog.modal("show"); - } - - return dialog; - }; - - exports.dialog = function(options) { - options = sanitize(options); - - var dialog = $(templates.dialog); - var innerDialog = dialog.find(".modal-dialog"); - var body = dialog.find(".modal-body"); - var buttons = options.buttons; - var buttonStr = ""; - var callbacks = { - onEscape: options.onEscape - }; - - if ($.fn.modal === undefined) { - throw new Error( - "$.fn.modal is not defined; please double check you have included " + - "the Bootstrap JavaScript library. See http://getbootstrap.com/javascript/ " + - "for more details." - ); - } - - each(buttons, function(key, button) { - - // @TODO I don't like this string appending to itself; bit dirty. Needs reworking - // can we just build up button elements instead? slower but neater. Then button - // can just become a template too - buttonStr += ""; - callbacks[key] = button.callback; - }); - - body.find(".bootbox-body").html(options.message); - - if (options.animate === true) { - dialog.addClass("fade"); - } - - if (options.className) { - dialog.addClass(options.className); - } - - if (options.size === "large") { - innerDialog.addClass("modal-lg"); - } else if (options.size === "small") { - innerDialog.addClass("modal-sm"); - } - - if (options.title) { - body.before(templates.header); - } - - if (options.closeButton) { - var closeButton = $(templates.closeButton); - - if (options.title) { - dialog.find(".modal-header").prepend(closeButton); - } else { - closeButton.css("margin-top", "-10px").prependTo(body); - } - } - - if (options.title) { - dialog.find(".modal-title").html(options.title); - } - - if (buttonStr.length) { - body.after(templates.footer); - dialog.find(".modal-footer").html(buttonStr); - } - - - /** - * Bootstrap event listeners; used handle extra - * setup & teardown required after the underlying - * modal has performed certain actions - */ - - dialog.on("hidden.bs.modal", function(e) { - // ensure we don't accidentally intercept hidden events triggered - // by children of the current dialog. We shouldn't anymore now BS - // namespaces its events; but still worth doing - if (e.target === this) { - dialog.remove(); - } - }); - - /* - dialog.on("show.bs.modal", function() { - // sadly this doesn't work; show is called *just* before - // the backdrop is added so we'd need a setTimeout hack or - // otherwise... leaving in as would be nice - if (options.backdrop) { - dialog.next(".modal-backdrop").addClass("bootbox-backdrop"); - } - }); - */ - - dialog.on("shown.bs.modal", function() { - dialog.find(".btn-primary:first").focus(); - }); - - /** - * Bootbox event listeners; experimental and may not last - * just an attempt to decouple some behaviours from their - * respective triggers - */ - - if (options.backdrop !== "static") { - // A boolean true/false according to the Bootstrap docs - // should show a dialog the user can dismiss by clicking on - // the background. - // We always only ever pass static/false to the actual - // $.modal function because with `true` we can't trap - // this event (the .modal-backdrop swallows it) - // However, we still want to sort of respect true - // and invoke the escape mechanism instead - dialog.on("click.dismiss.bs.modal", function(e) { - // @NOTE: the target varies in >= 3.3.x releases since the modal backdrop - // moved *inside* the outer dialog rather than *alongside* it - if (dialog.children(".modal-backdrop").length) { - e.currentTarget = dialog.children(".modal-backdrop").get(0); - } - - if (e.target !== e.currentTarget) { - return; - } - - dialog.trigger("escape.close.bb"); - }); - } - - dialog.on("escape.close.bb", function(e) { - if (callbacks.onEscape) { - processCallback(e, dialog, callbacks.onEscape); - } - }); - - /** - * Standard jQuery event listeners; used to handle user - * interaction with our dialog - */ - - dialog.on("click", ".modal-footer button", function(e) { - var callbackKey = $(this).data("bb-handler"); - - processCallback(e, dialog, callbacks[callbackKey]); - }); - - dialog.on("click", ".bootbox-close-button", function(e) { - // onEscape might be falsy but that's fine; the fact is - // if the user has managed to click the close button we - // have to close the dialog, callback or not - processCallback(e, dialog, callbacks.onEscape); - }); - - dialog.on("keyup", function(e) { - if (e.which === 27) { - dialog.trigger("escape.close.bb"); - } - }); - - // the remainder of this method simply deals with adding our - // dialogent to the DOM, augmenting it with Bootstrap's modal - // functionality and then giving the resulting object back - // to our caller - - $(options.container).append(dialog); - - dialog.modal({ - backdrop: options.backdrop ? "static": false, - keyboard: false, - show: false - }); - - if (options.show) { - dialog.modal("show"); - } - - // @TODO should we return the raw element here or should - // we wrap it in an object on which we can expose some neater - // methods, e.g. var d = bootbox.alert(); d.hide(); instead - // of d.modal("hide"); - - /* - function BBDialog(elem) { - this.elem = elem; - } - - BBDialog.prototype = { - hide: function() { - return this.elem.modal("hide"); - }, - show: function() { - return this.elem.modal("show"); - } - }; - */ - - return dialog; - - }; - - exports.setDefaults = function() { - var values = {}; - - if (arguments.length === 2) { - // allow passing of single key/value... - values[arguments[0]] = arguments[1]; - } else { - // ... and as an object too - values = arguments[0]; - } - - $.extend(defaults, values); - }; - - exports.hideAll = function() { - $(".bootbox").modal("hide"); - - return exports; - }; - - - /** - * standard locales. Please add more according to ISO 639-1 standard. Multiple language variants are - * unlikely to be required. If this gets too large it can be split out into separate JS files. - */ - var locales = { - bg_BG : { - OK : "Ок", - CANCEL : "Отказ", - CONFIRM : "Потвърждавам" - }, - br : { - OK : "OK", - CANCEL : "Cancelar", - CONFIRM : "Sim" - }, - cs : { - OK : "OK", - CANCEL : "Zrušit", - CONFIRM : "Potvrdit" - }, - da : { - OK : "OK", - CANCEL : "Annuller", - CONFIRM : "Accepter" - }, - de : { - OK : "OK", - CANCEL : "Abbrechen", - CONFIRM : "Akzeptieren" - }, - el : { - OK : "Εντάξει", - CANCEL : "Ακύρωση", - CONFIRM : "Επιβεβαίωση" - }, - en : { - OK : "OK", - CANCEL : "Cancel", - CONFIRM : "OK" - }, - es : { - OK : "OK", - CANCEL : "Cancelar", - CONFIRM : "Aceptar" - }, - et : { - OK : "OK", - CANCEL : "Katkesta", - CONFIRM : "OK" - }, - fa : { - OK : "قبول", - CANCEL : "لغو", - CONFIRM : "تایید" - }, - fi : { - OK : "OK", - CANCEL : "Peruuta", - CONFIRM : "OK" - }, - fr : { - OK : "OK", - CANCEL : "Annuler", - CONFIRM : "D'accord" - }, - he : { - OK : "אישור", - CANCEL : "ביטול", - CONFIRM : "אישור" - }, - hu : { - OK : "OK", - CANCEL : "Mégsem", - CONFIRM : "Megerősít" - }, - hr : { - OK : "OK", - CANCEL : "Odustani", - CONFIRM : "Potvrdi" - }, - id : { - OK : "OK", - CANCEL : "Batal", - CONFIRM : "OK" - }, - it : { - OK : "OK", - CANCEL : "Annulla", - CONFIRM : "Conferma" - }, - ja : { - OK : "OK", - CANCEL : "キャンセル", - CONFIRM : "確認" - }, - lt : { - OK : "Gerai", - CANCEL : "Atšaukti", - CONFIRM : "Patvirtinti" - }, - lv : { - OK : "Labi", - CANCEL : "Atcelt", - CONFIRM : "Apstiprināt" - }, - nl : { - OK : "OK", - CANCEL : "Annuleren", - CONFIRM : "Accepteren" - }, - no : { - OK : "OK", - CANCEL : "Avbryt", - CONFIRM : "OK" - }, - pl : { - OK : "OK", - CANCEL : "Anuluj", - CONFIRM : "Potwierdź" - }, - pt : { - OK : "OK", - CANCEL : "Cancelar", - CONFIRM : "Confirmar" - }, - ru : { - OK : "OK", - CANCEL : "Отмена", - CONFIRM : "Применить" - }, - sq : { - OK : "OK", - CANCEL : "Anulo", - CONFIRM : "Prano" - }, - sv : { - OK : "OK", - CANCEL : "Avbryt", - CONFIRM : "OK" - }, - th : { - OK : "ตกลง", - CANCEL : "ยกเลิก", - CONFIRM : "ยืนยัน" - }, - tr : { - OK : "Tamam", - CANCEL : "İptal", - CONFIRM : "Onayla" - }, - zh_CN : { - OK : "OK", - CANCEL : "取消", - CONFIRM : "确认" - }, - zh_TW : { - OK : "OK", - CANCEL : "取消", - CONFIRM : "確認" - } - }; - - exports.addLocale = function(name, values) { - $.each(["OK", "CANCEL", "CONFIRM"], function(_, v) { - if (!values[v]) { - throw new Error("Please supply a translation for '" + v + "'"); - } - }); - - locales[name] = { - OK: values.OK, - CANCEL: values.CANCEL, - CONFIRM: values.CONFIRM - }; - - return exports; - }; - - exports.removeLocale = function(name) { - delete locales[name]; - - return exports; - }; - - exports.setLocale = function(name) { - return exports.setDefaults("locale", name); - }; - - exports.init = function(_$) { - return init(_$ || $); - }; - - return exports; -})); diff --git a/hotel_calendar/static/src/lib/hcalendar/css/hcalendar.css b/hotel_calendar/static/src/lib/hcalendar/css/hcalendar.css deleted file mode 100644 index 6543527bf..000000000 --- a/hotel_calendar/static/src/lib/hcalendar/css/hcalendar.css +++ /dev/null @@ -1,537 +0,0 @@ -/* - * Hotel Calendar JS v0.0.1a - 2017-2018 - * GNU Public License - * Aloxa Solucions S.L. - * Alexandre Díaz - */ - - -/** ANIMATIONS **/ -@keyframes cell-invalid { - 0% { - background: #ff0000; - background: repeating-linear-gradient(141deg,#ff0000 10%, #ff0000 40%, rgba(255,0,0,0.51) 30%, rgba(255,0,0,0.51) 50%); - background: -webkit-repeating-linear-gradient(141deg,#ff0000 10%, #ff0000 40%, rgba(255,0,0,0.51) 30%, rgba(255,0,0,0.51) 50%); - background: -moz-repeating-linear-gradient(141deg,#ff0000 10%, #ff0000 40%, rgba(255,0,0,0.51) 30%, rgba(255,0,0,0.51) 50%); - } - 50% { - background: #ff0000; - background: repeating-linear-gradient(141deg,#ff0000 10%, #ff0000 40%, rgba(255,0,0,0.51) 30%, rgba(255,0,0,0.51) 50%); - background: -webkit-repeating-linear-gradient(141deg,#ff0000 10%, #ff0000 35%, rgba(255,0,0,0.51) 30%, rgba(255,0,0,0.51) 50%); - background: -moz-repeating-linear-gradient(141deg,#ff0000 10%, #ff0000 40%, rgba(255,0,0,0.51) 30%, rgba(255,0,0,0.51) 50%); - } - 100% { - background: #ff0000; - background: repeating-linear-gradient(141deg,#ff0000 10%, #ff0000 30%, rgba(255,0,0,0.51) 30%, rgba(255,0,0,0.51) 50%); - background: -webkit-repeating-linear-gradient(141deg,#ff0000 10%, #ff0000 30%, rgba(255,0,0,0.51) 30%, rgba(255,0,0,0.51) 50%); - background: -moz-repeating-linear-gradient(141deg,#ff0000 10%, #ff0000 30%, rgba(255,0,0,0.51) 30%, rgba(255,0,0,0.51) 50%); - } -} - -#hcal_load { - width: 100%; - height: 90vh; - text-align: center; - line-height: 90vh; - color: darkgray; -} -#hcal_load > span { - line-height: 24px; - display: inline-block; - vertical-align: middle; -} - -#cal-pag-prev-plus, #cal-pag-prev, #cal-pag-selector, #cal-pag-next, #cal-pag-next-plus { - min-height: 0px; -} - -.hcalendar-container { - display: flex; - flex-flow: column; -} - -.table-reservations-header { - order: 1; - flex-grow: 1; - overflow-y: scroll; - overflow-x: hidden; -} -.table-reservations { - order: 2; - flex-grow: 2; - overflow-y: scroll; - overflow-x: hidden; - position: relative; - max-height: 57vh; -} -.table-calcs-header { - order: 3; - flex-grow: 1; - overflow-y: scroll; - overflow-x: hidden; -} -.table-calcs { - order: 4; - flex-grow: 2; - overflow-y: scroll; - overflow-x: hidden; - font-size: 12px; - max-height: 20vh; -} -.table-calcs input, .table-reservations-header input { - border-radius: 0; - border: 1px solid lightgray; - width: 100%; -} -.table-calcs input { - text-align: center; -} - -.btn-hcal { } -.btn-hcal.hcal-cell-current-day { - background-color: #7c7bad66; - color: #654a37; -} -.btn-hcal.hcal-cell-end-week { - background-color: #EDEDED83; -} -.btn-hcal-3d { - border: 1px solid #eaeaea; - border-top-width: 0; - border-bottom-width: 0; - /*border-color: white black black white !important;*/ -} -.btn-hcal-flat { - background-color: white; - border: 1px solid #eaeaea; -} -.btn-hcal-left { - background-color: white; - border: 1px solid #eaeaea; - border-left-width: 0; -} - -.hcal-warn-ob-indicator { - position: absolute; - background-color: red; - color: yellow; - border: 1px solid black; - z-index: 9; - width: 25px; - height: 20px; - text-align: center; -} - -.table-calcs-header .hcal-table, .table-reservations-header .hcal-table { - height: 46px; -} - -.hcal-table, .hcal-table-day { - border-collapse: initial !important; - width: 100%; - table-layout: fixed; -} -.hcal-table > tbody { - max-height: 50vh; - overflow: scroll; -} -.hcal-table td { - text-align: center; - min-width: 100px; - white-space: nowrap; - overflow: hidden; -} -.hcal-table a { - text-decoration: none; -} -.hcal-table tr:hover td:not(.hcal-unused-zone):not(.hcal-cell-highlight):not(.hcal-cell-current-day):not(.hcal-cell-end-week):not(.btn-hcal):not(.hcal-cell-invalid) { - /*background-color: #F6F6F6; - border: 5px solid red;*/ -} - -.hcal-table tr:hover td.hcal-cell-room-type-group-item { - background-color: #7c7bad80; - color: white; -} - -.hcal-restriction-room-day { - background-color: #9b18704d !important; -} - -.hcal-table-day { - height: 100%; - border-collapse: collapse !important; - border: 0 dotted #eaeaea; - border-width: 1px 0; -} -/*.hcal-table-day tr:first-child td{ - border: 1px solid #727272 !important; - border-width: 0 1px 0 0 !important; -} -.hcal-table tr:not(:last-child) .hcal-table-day tr:last-child td { - border-style: solid; - border-color: #727272 !important; - border-bottom-width: 1px !important; -} -.hcal-table-day tr:not(:last-child):not(:first-child) td { - border-width: 0; -}*/ -.hcal-table-day td { - padding: 2px; - height: 3em; - font-size: 7px; - vertical-align: middle; - font-weight: bold; - border: 0.5px solid #eaeaea !important; -} -.hcal-table-day td:hover:not(.hcal-cell-highlight):not(.hcal-cell-invalid) { - background-color: #FCFEE1 !important; -} - -.hcal-cell-current-day { - background-color: #7C7BADA5; -} -.hcal-cell-end-week { - background-color: #EDEDED83; -} - -.hcal-cell-day-selector { - text-align: center; - vertical-align: center; - max-width: 140px; -} -.hcal-cell-day-selector a { - font-size: 22px; - padding: 0 0.5em; -} -.hcal-cell-day-selector span { - cursor: pointer; -} -.hcal-cell-day-selector input { - border: 1px solid lightgray; - width: 120px; - font-size: large; - text-align: center; -} - -.hcal-cell-month { - overflow: hidden; - max-width: 0; - text-align: center !important; - vertical-align: middle; - white-space: nowrap; - font-size: 12px; -} -.hcal-cell-month:nth-child(n+3) { - border-left-width: 2px !important; -} - -.hcal-cell-start-month { - border-left-width: 2px !important; -} - -.hcal-room-type:hover { - cursor:pointer; -} - -.hcal-cell-highlight { - background-color: #F8FD9C; -} - -.hcal-cell-invalid { - background-color: #e58e92; -} - - -.hcal-cell-room-type-group-item-day { - padding: 0 !important; - height: 100%; -} - -.hcal-input-changed { - background-color: rgb(237,110,110); - border: 1px solid gray; -} - -.hcal-cell-room-type-group-item-day-occupied { - /*background-color: #227eaf;*/ -} -.hcal-cell-room-type-group-item-day-occupied[data-hcal-reservation-cell-type=soft-start] { - background-color: #729fcf; - /*border: 2px solid #3465a4;*/ -} - -.hcal-cell-pagination button { - padding: 0.1em; - border-radius: 0; - background-color: initial; -} - -#btn_save_changes.need-save { - color: yellow; - background: orange; -} - -.hcal-hidden { - display: none; -} - -.hcal-reservation-unselect { - opacity: 0.3; - pointer-events: none; -} - -.hcal-reservation { - position: absolute; - text-align: center; - /*background-color: #729fcf;*/ - /*transform: skewX(-25deg);*/ - /*border-radius: 5px;*/ - border: 0 double #3465a4; - color: white; - white-space: nowrap; - overflow: hidden; - z-index: 8; -} -.hcal-reservation:hover { - background-color: #4e97bf; -} -.hcal-reservation span { - position: relative; -} - -.hcal-reservation-splitted { - border-width: 0 6px; - border-style: solid; -} - -.hcal-reservation-invalid { - background-color: #c8543b !important; - border-color: #6c3624 !important; -} -.hcal-reservation-invalid:hover { - background-color: #f5b595 !important; - border-color: #c8543b !important; -} - -.hcal-reservation-foreground { - pointer-events: none; - opacity: 0.9; - color: transparent !important; - background: repeating-linear-gradient( - 45deg, - #606dbc, - #606dbc 10px, - #465298 10px, - #465298 20px - ); -} - -.hcal-reservation-invalid-swap { - pointer-events: none; - opacity: 0.9; - color: transparent !important; - background: repeating-linear-gradient( - 45deg, - #BA6359, - #BA6359 10px, - #dfe066 10px, - #dfe066 20px - ); -} - -.hcal-reservation-invalid-unify { - pointer-events: none; - opacity: 0.9; - color: transparent !important; - background: repeating-linear-gradient( - 45deg, - #BA6359, - #BA6359 10px, - #dfe066 10px, - #dfe066 20px - ); -} - -.hcal-reservation-action { - border: 2px dashed #3465a4; - opacity: 0.9; - pointer-events: none; - z-index:10; -} - -.hcal-reservation-readonly:not(.hcal-unused-zone) { - border: 2px solid #99995b; - color: white !important; - font-weight: bold; - background: #ffee00; - background: repeating-radial-gradient(circle farthest-corner at right center, #ffee00 0%, #2c2c2c 5%, #ffff00 10%, #2c2c2c 20%, #2c2c2c 100%); - background: -webkit-repeating-radial-gradient(circle farthest-corner at right center, #ffee00 0%, #2c2c2c 5%, #ffff00 10%, #2c2c2c 20%, #2c2c2c 100%); - background: -moz-repeating-radial-gradient(circle farthest-corner at right center, #ffee00 0%, #2c2c2c 5%, #ffff00 10%, #2c2c2c 20%, #2c2c2c 100%); -} - -.hcal-reservation-unify-selected { - background-color: #005B96 !important; - border-color: #99bdd5 !important; -} - -.hcal-reservation-swap-in-selected { - background-color: #005B96 !important; - border-color: #99bdd5 !important; -} - -.hcal-reservation-swap-out-selected { - border-color: #005B96 !important; - background-color: #99bdd5 !important; -} - -.hcal-reservation-unify-selected { - background-color: #005B96 !important; - border-color: #99bdd5 !important; -} - -.hcal-reservation-to-divide { - pointer-events: none; -} - -.hcal-reservation-divide-l { - background-color: transparent; - border: 2px dashed black; - cursor: copy; - pointer-events: none; - border-color: black; - border-right-style: solid; - position: absolute; - z-index: 9; -} - -.hcal-reservation-divide-r { - background-color: transparent; - border: 2px dashed black; - cursor: copy; - pointer-events: none; - border-color: black; - border-left-style: solid; - position: absolute; - z-index: 9; -} - -.hcal-row-room-type-group-item { - text-align: center; -} - -tr.hcal-row-room-type-group-overbooking-item td { - background-color: #fccc9f; -} - -tr.hcal-row-room-type-group-cancelled-item td { - background-color: #fcebeb; -} - -.hcal-cell-month-day { - text-align: center !important; -} - -.hcal-cell-room-type-group-day { - text-align: center !important; -} - -.hcal-table-type-group-day { - border-collapse: collapse; - width:100%; -} -.hcal-table-type-group-day td { - border-width: 0; -} -.hcal-table-type-group-day tr:not(:last-child) td { - border-bottom-width: 1px; -} - -.hcal-cell-room-type { - cursor: pointer; -} -td.hcal-cell-room-type { - border-right-width: 2px; -} - -td.hcal-cell-room-type-group-day, td.hcal-cell-room-type { - border-top-width: 2px; -} -td.hcal-cell-room-type-group-day { - padding: 0; -} - -td.hcal-cell-room-type-group-item { - text-align: center !important; - vertical-align: middle; - font-size: smaller; - white-space: nowrap; - text-overflow: ellipsis; -} -td.hcal-cell-room-type-group-item:last-child { - border-right-width: 2px; -} - -.hcal-cell-type-group-day-free { - text-align: center; - font-weight: bold; - padding: 0 !important; -} -.hcal-cell-type-group-day-price { - text-align: center; -} - -td.hcal-cell-header-day { - padding: 0; - vertical-align: middle; - font-size: 10px; -} - -td.hcal-cell-month-day-occupied { - padding: 0; - text-align: center; -} - -.hcal-cell-detail-room-free-type-group-item-day, -.hcal-cell-detail-room-free-total-group-item-day, -.hcal-cell-detail-room-perc-occup-group-item-day, -.hcal-cell-detail-room-price-type-group-item-day, -.hcal-cell-detail-room-min-stay-group-item-day { - border: 1px solid lightgray; -} -.hcal-cell-detail-room-min-stay-group-item-day { - border-color: #307CB0 lightgray lightgray lightgray; - border-width: 2px 1px 1px 1px; -} - -.hcal-cell-detail-room-group-item { - white-space: nowrap; - text-align: right !important; - text-overflow: '...'; -} - -/* FIXME: Workaround for work with other currencies */ -.hcal-cell-detail-room-group-item[data-currency-symbol='€'] { - text-overflow: '... €'; -} - -.hcal-unused-zone { - border-radius: 0px; -} - -.input-price { - width: 100%; - border-style: none !important; - border-radius: 0 !important; - text-align: center; -} - -.noselect { - -webkit-touch-callout: none; /* iOS Safari */ - -webkit-user-select: none; /* Safari */ - -khtml-user-select: none; /* Konqueror HTML */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* Internet Explorer/Edge */ - user-select: none; /* Non-prefixed version, currently - supported by Chrome and Opera */ -} diff --git a/hotel_calendar/static/src/lib/hcalendar/css/hcalendar_management.css b/hotel_calendar/static/src/lib/hcalendar/css/hcalendar_management.css deleted file mode 100644 index 74bfe841d..000000000 --- a/hotel_calendar/static/src/lib/hcalendar/css/hcalendar_management.css +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Hotel Calendar Management JS v0.0.1a - 2017 - * GNU Public License - * Aloxa Solucions S.L. - * Alexandre Díaz - */ - - #pms-search-cal-pag { - text-align: center; - } - -#mpms-search { - padding: 0.5em; -} - -.hcal-management-table, .hcal-management-table-day { - border-collapse: collapse !important; - table-layout: fixed; -} -.hcal-management-table > tbody { - max-height: 50vh; - overflow: scroll; -} -.hcal-management-table > thead > tr > td { - /*text-align: center !important;*/ - width: 110px !important; - vertical-align: center; - min-width: 110px; - height: 1.5em; - min-height: 1.5em; - white-space: nowrap; - /*overflow: hidden;*/ - border: 1px solid black !important; -} -.hcal-management-table > tbody > tr > td { - /*text-align: center !important;*/ - width: 110px !important; - vertical-align: center; - min-width: 110px; - height: 130px; - min-height: 100px; - white-space: nowrap; - /*overflow: hidden;*/ - padding: 5px !important; - border: 1px solid black; -} -.hcal-management-table thead td { - text-align: center !important; -} -.hcal-management-table a { - text-decoration: none; -} -.hcal-management-table tr:hover td:not(.hcal-cell-highlight):not(.hcal-cell-current-day):not(.hcal-cell-end-week):not(.btn-hcal):not(.hcal-cell-invalid) { - background-color: #F6F6F6; -} - -.hcal-management-table tr:hover td.hcal-cell-room-type-group-item { - background-color: #9bcd9b; - color: black; -} - -.hcal-management-table input[type='edit'] { - width: 100%; - font-size: 10px; - text-align: center; -} -.hcal-management-table select { - font-size: 9px; -} - -.hcal-management-table-day { - height: 100%; - border-collapse: collapse !important; -} -.hcal-management-table-day td { - padding: 2px; - height: 2.3em; - font-size: 7px; - vertical-align: middle; - font-weight: bold; - border: 0; -} -.hcal-management-table-day td:hover:not(.hcal-cell-highlight):not(.hcal-cell-invalid) { - background-color: #FCFEE1 !important; -} - -.hcal-management-low > tbody > tr > td, .hcal-management-low > table > tbody > tr > td { - height: 58px !important; -} - -.hcal-management-medium > tbody > tr > td, .hcal-management-medium > table > tbody > tr > td { - height: 80px !important; -} - -.hcal-management-medium tr[name='rest_b'], .hcal-management-medium tr[name='rest_c'], - .hcal-management-low tr[name='rest_a'], .hcal-management-low tr[name='rest_b'], .hcal-management-low tr[name='rest_c'] { - display: none; - visibility: hidden; -} - -.table-room_types { - flex: 1 1 auto; - margin-top: 1.2em; -} - -.table-room_type-data-header { - z-index: 1; -} - -.table-room_type-data-header .hcal-management-table tr td { - background-color: white; -} - -#hcal_management_widget { - overflow: auto; - display: flex; -} - -#hcal-management-container-dd { - overflow: auto; - flex: 1 1 auto; -} - -#btn_save_changes, #btn_massive_changes { - height: 56px; -} -#btn_save_changes i, #btn_massive_changes i { - top: 22%; -} - -.hcal-management-input-changed { - background-color: rgb(237,110,110); - border: 1px solid gray; -} - -.hcal-management-record-changed { - background-color: #FFFF66 !important; -} - -table.hcal-management-table input { - border: 1px solid lightgray; -} - -.hcal-border-radius-right { - border-top-right-radius: 25px; - border-bottom-right-radius: 25px; -} - -.hcal-border-radius-left { - border-top-left-radius: 25px; - border-bottom-left-radius: 25px; -} - -.hcal-management-record-options { - padding: 0.5em; -} - -.filter-title { - overflow: hidden; - text-overflow: ellipsis; -} - -button.hcal-management-input { - font-size: 9px; - border: 1px solid gray; - padding: 0.5em 2em 0.2em 2em; - border-radius: 3px; - margin: 0.2em; - - background: rgba(255,255,255,1); - background: -moz-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(227,227,227,1) 47%, rgba(194,194,194,1) 100%); - background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(255,255,255,1)), color-stop(47%, rgba(227,227,227,1)), color-stop(100%, rgba(194,194,194,1))); - background: -webkit-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(227,227,227,1) 47%, rgba(194,194,194,1) 100%); - background: -o-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(227,227,227,1) 47%, rgba(194,194,194,1) 100%); - background: -ms-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(227,227,227,1) 47%, rgba(194,194,194,1) 100%); - background: linear-gradient(to bottom, rgba(255,255,255,1) 0%, rgba(227,227,227,1) 47%, rgba(194,194,194,1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#c2c2c2', GradientType=0 ); -} -button.hcal-management-input:hover { - background: rgba(255,255,255,1); - background: -moz-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%); - background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(255,255,255,1)), color-stop(47%, rgba(246,246,246,1)), color-stop(100%, rgba(237,237,237,1))); - background: -webkit-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%); - background: -o-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%); - background: -ms-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%); - background: linear-gradient(to bottom, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#ededed', GradientType=0 ); -} -button.hcal-management-input-active { - background: rgba(245,215,93,1) !important; - background: -moz-linear-gradient(top, rgba(245,215,93,1) 0%, rgba(245,165,44,1) 47%, rgba(255,153,0,1) 100%) !important; - background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(245,215,93,1)), color-stop(47%, rgba(245,165,44,1)), color-stop(100%, rgba(255,153,0,1))) !important; - background: -webkit-linear-gradient(top, rgba(245,215,93,1) 0%, rgba(245,165,44,1) 47%, rgba(255,153,0,1) 100%) !important; - background: -o-linear-gradient(top, rgba(245,215,93,1) 0%, rgba(245,165,44,1) 47%, rgba(255,153,0,1) 100%) !important; - background: -ms-linear-gradient(top, rgba(245,215,93,1) 0%, rgba(245,165,44,1) 47%, rgba(255,153,0,1) 100%) !important; - background: linear-gradient(to bottom, rgba(245,215,93,1) 0%, rgba(245,165,44,1) 47%, rgba(255,153,0,1) 100%) !important; - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f5d75d', endColorstr='#ff9900', GradientType=0 ) !important; -} diff --git a/hotel_calendar/static/src/lib/hcalendar/js/hcalendar.js b/hotel_calendar/static/src/lib/hcalendar/js/hcalendar.js deleted file mode 100644 index c4efbc271..000000000 --- a/hotel_calendar/static/src/lib/hcalendar/js/hcalendar.js +++ /dev/null @@ -1,3126 +0,0 @@ -/* global _, moment */ -'use strict'; -/* - * Hotel Calendar JS - 2017-2018 - * GNU Public License - * Alexandre Díaz - * - * Dependencies: - * - moment - * - underscore - * - awesomeicons - * - bootstrap - * - jquery - */ - -function HotelCalendar(/*String*/querySelector, /*Dictionary*/options, /*List*/pricelist, /*restrictions*/restrictions, /*HTMLObject?*/_base) { - if (window === this) { - return new HotelCalendar(querySelector, options, pricelist, _base); - } - - this.$base = (_base === 'undefined') ? document : _base; - - if (typeof querySelector === 'string') { - this.e = this.$base.querySelector(querySelector); - if (!this.e) { - return false; - } - } else if (typeof querySelector === 'object') { - this.e = querySelector; - } else { - return { - Version: '0.5', - Author: "Alexandre Díaz", - Created: "20/04/2017", - Updated: "19/07/2018" - }; - } - - /** Strings **/ - this._strings = { - 'Save Changes': 'Save Changes' - }; - - /** Options **/ - var now_utc = moment(new Date()).utc(); - this.options = _.extend({ - startDate: now_utc, - days: now_utc.daysInMonth(), - rooms: [], - room_types: [], - room_classes: [], - allowInvalidActions: false, - assistedMovement: false, - endOfWeek: 6, - endOfWeekOffset: 0, - divideRoomsByCapacity: false, - currencySymbol: '€', - showPricelist: false, - showAvailability: false, - showNumRooms: 0, - paginatorStepsMin: 1, - paginatorStepsMax: 15, - showOverbookings: false, - showCancelled: false, - }, options); - - this.options.startDate = this.options.startDate.clone(); - this.options.startDate.subtract('1', 'd'); - this.options.orig_days = this.options.days; - this.options.days = this.parseDays(this.options.days) + 1; - this.options.rooms = _.map(this.options.rooms, function(item){ return item.clone(); }); - // Check correct values - if (this.options.rooms.length > 0 && !(this.options.rooms[0] instanceof HRoom)) { - this.options.rooms = []; - console.warn("[Hotel Calendar][init] Invalid Room definiton!"); - } - - /** Internal Values **/ - this._pricelist = pricelist || []; // Store Prices - this._pricelist_id = -1; // Store Price Plan ID (Because can be edited) - this._restrictions = restrictions || {}; // Store Restrictions - this._reservations = []; // Store Reservations - this._reservationsMap = {}; // Store Reservations Mapped by Room for Search Purposes - this._modeSwap = HotelCalendar.MODE.NONE; // Store Swap Mode - this._selectionMode = HotelCalendar.MODE.NONE; - this._endDate = this.options.startDate.clone().add(this.options.days, 'd'); // Store End Calendar Day - this._tableCreated = false; // Store Flag to Know Calendar Creation - this._cellSelection = {start:false, end:false, current:false}; // Store Info About Selected Cells - this._lazyModeReservationsSelection = false; // Store Info About Timer for Selection Action - this._domains = {}; // Store domains for filter rooms & reservations - this._divideDivs = false; - this._extraRowIndicators = ['EX-', '/#']; - - // Support - var self = this; - this._supportsPassive = false; - try { - var opts = Object.defineProperty({}, 'passive', { - get: function() { - self._supportsPassive = true; - } - }); - window.addEventListener("testPassive", null, opts); - window.removeEventListener("testPassive", null, opts); - } catch (e) {} - - // Calculate Capacities - this._roomCapacityTotal = 0; - this._roomCapacities = {}; - this._roomsMap = _.groupBy(this.options.rooms, 'type'); - var room_types = this.getRoomTypes(); - for (var rt of room_types) { - this._roomsMap[rt] = _.filter(this._roomsMap[rt], {overbooking: false, cancelled: false}); - this._roomCapacities[rt] = _.reduce(this._roomsMap[rt], function(memo, tr){ return memo + (tr.shared?tr.capacity:1); }, 0); - this._roomCapacityTotal += this._roomCapacities[rt]; - } - - /***/ - this._reset_action_reservation(); - if (!this._create()) { - return false; - } - - - /** Main Events **/ - document.addEventListener('mouseup', this.onMainMouseUp.bind(this), false); - document.addEventListener('touchend', this.onMainMouseUp.bind(this), false); - document.addEventListener('keyup', this.onMainKeyUp.bind(this), false); - document.addEventListener('keydown', this.onMainKeyDown.bind(this), false); - window.addEventListener('resize', _.debounce(this.onMainResize.bind(this), 300), false); - - return this; -} - -HotelCalendar.prototype = { - /** PUBLIC MEMBERS **/ - addEventListener: function(/*String*/event, /*Function*/callback) { - this.e.addEventListener(event, callback); - }, - - //==== CALENDAR - setStartDate: function(/*String,MomentObject*/date, /*Int*/days, /*Bool*/fullUpdate, /*Functions*/callback) { - if (moment.isMoment(date)) { - this.options.startDate = date; - } else if (typeof date === 'string'){ - this.options.startDate = HotelCalendar.toMoment(date); - } else { - console.warn("[Hotel Calendar][setStartDate] Invalid date format!"); - return; - } - - this.options.startDate.subtract('1','d'); - if (typeof days !== 'undefined') { - this.options.orig_days = days; - this.options.days = this.parseDays(days) + 1; - } - this._endDate = this.options.startDate.clone().add(this.options.days, 'd'); - - /*this.e.dispatchEvent(new CustomEvent( - 'hcOnChangeDate', - {'detail': {'prevDate':curDate, 'newDate': $this.options.startDate}}));*/ - this._updateView(!fullUpdate, callback); - }, - - getOptions: function(/*String?*/key) { - if (typeof key !== 'undefined') { - return this.options[key]; - } - return this.options; - }, - - parseDays: function(/*Int/String*/days) { - if (days === 'month') { - return moment().daysInMonth(); - } - return +days; - }, - - toggleOverbookingsVisibility: function(/*Bool*/show) { - this.options.showOverbookings = !this.options.showOverbookings; - }, - - toggleCancelledVisibility: function(/*Bool*/show) { - this.options.showCancelled = !this.options.showCancelled; - }, - - setSwapMode: function(/*Int*/mode) { - if (mode !== this._modeSwap) { - this._modeSwap = mode; - if (this._modeSwap === HotelCalendar.MODE.NONE) { - this._dispatchSwapReservations(); - this._reset_action_reservation(); - } else { - this.setSelectionMode(HotelCalendar.MODE.NONE); - } - - this._updateHighlightSwapReservations(); - } - }, - - setSelectionMode: function(/*Int*/mode) { - if (this._modeSwap === HotelCalendar.MODE.NONE) { - this._selectionMode = mode; - if (this._selectionMode === HotelCalendar.ACTION.DIVIDE) { - this.reservationAction.action = HotelCalendar.ACTION.DIVIDE; - for (var reserv of this._reservations) { - reserv._html.classList.add('hcal-reservation-to-divide'); - } - } else if (this._selectionMode === HotelCalendar.ACTION.UNIFY) { - this.reservationAction.action = HotelCalendar.ACTION.UNIFY; - this.reservationAction.toUnify = []; - } else { - for (var reserv of this._reservations) { - reserv._html.classList.remove('hcal-reservation-to-divide'); - } - if (this._divideDivs) { - this._divideDivs[0].remove(); - this._divideDivs[1].remove(); - this._divideDivs = false; - } - - - this._dispatchUnifyReservations(); - this._reset_action_reservation(); - this._updateHighlightUnifyReservations(); - } - - this._dispatchEvent('hcalOnChangeSelectionMode', { - 'newMode': this._selectionMode, - }); - } - }, - - getSelectionMode: function() { - return this._selectionMode; - }, - - getSwapMode: function() { - return this._modeSwap; - }, - - cancelSwap: function() { - if (this._modeSwap !== HotelCalendar.MODE.NONE) { - this._modeSwap = HotelCalendar.MODE.NONE; - this._dispatchEvent('hcalOnCancelSwapReservations'); - this._reset_action_reservation(); - this._updateHighlightSwapReservations(); - } - }, - - _updateOffsets: function() { - this._etableOffset = this.loopedOffsetOptimized(this.etable); - this._eOffset = this.loopedOffsetOptimized(this.e); - this._edivrOffset = this.loopedOffsetOptimized(this.edivr); - }, - - //==== DOMAINS - setDomain: function(/*Int*/section, /*Array*/domain) { - if (this._domains[section] !== domain) { - this._domains[section] = domain; - if (section === HotelCalendar.DOMAIN.RESERVATIONS) { - this._filterReservations(); - } else if (section === HotelCalendar.DOMAIN.ROOMS) { - this._filterRooms(); - } - } - }, - - getDomain: function(/*Int*/section) { - return this._domains[section] || []; - }, - - //==== RESERVATIONS - _filterReservations: function() { - for (var r of this._reservations) { - r._active = this._in_domain(r, this._domains[HotelCalendar.DOMAIN.RESERVATIONS]); - this._updateReservation(r, true); - } - - //_.defer(function(){ this._updateReservationOccupation() }.bind(this)); - }, - - getReservationAction: function() { - return this.reservationAction; - }, - - getReservation: function(/*Int,String*/id) { - return _.find(this._reservations, function(item){ return item.id == id; }); - }, - - // getReservationDiv: function(/*HReservationObject*/reservationObj) { - // var reservDiv = this.e.querySelector(`div.hcal-reservation[data-hcal-reservation-obj-id='${reservationObj.id}']`); - // return reservDiv; - // }, - - setReservations: function(/*List*/reservations) { - for (var reservation of this._reservations) { - this.removeReservation(reservation); - } - - this._reservations = []; - this.addReservations(reservations); - }, - - addReservations: function(/*List*/reservations) { - reservations = reservations || []; - - if (reservations.length > 0 && !(reservations[0] instanceof HReservation)) { - console.warn("[HotelCalendar][addReservations] Invalid Reservation definition!"); - } else { - var isCalendarEmpty = (this._reservations.length>0); - // Merge - var addedReservations = []; - for (var r of reservations) { - var rindex = _.findKey(this._reservations, {'id': r.id}); - if ((!this.options.showOverbookings && r.overbooking) || (!this.options.showCancelled && r.cancelled)) { - if (rindex) { - this.removeReservation(this._reservations[rindex]); - } - continue; - } - - var hasCreatedExtraRows = false; - r = r.clone(); // HOT-FIX: Multi-Calendar Support - r.room = this.getRoom(r.room_id, r.overbooking || r.cancelled, r.id); - // need create a overbooking row? - if (!r.room) { - if (r.overbooking || r.cancelled) { - r.room = this.createExtraRoom(this.getRoom(r.room_id), r.id, { - overbooking: r.overbooking, - cancelled: r.cancelled, - }); - this.createExtraRoomRow(r.room); - hasCreatedExtraRows = true; - } else { - console.warn(`Can't found the room '${r.room_id}' for the reservation '${r.id}' (${r.title})!`); - continue; - } - } - - if (rindex) { - var reserv = this._reservations[rindex]; - r._html = reserv._html; - if ((reserv.overbooking && !r.overbooking) || (reserv.cancelled && !r.cancelled)) { - if (this.getReservationsByRoom(reserv.room).length === 1) { - this.removeExtraRoomRow(reserv); - } - } - this._reservations[rindex] = r; - if (!r.unusedZone) { - this._cleanUnusedZones(r); - } - } else { - this._reservations.push(r); - } - - addedReservations.push(r); - } - - // Create & Render New Reservations - _.defer(function(reservs){ - // Update offsets (New Rooms change positions?) - this._updateOffsets(); - - var unusedZones = this._createUnusedZones(reservs); - // Add Unused Zones - this._reservations = this._reservations.concat(unusedZones); - // Create Map - this._updateReservationsMap(); - - var toAssignEvents = []; - reservs = reservs.concat(unusedZones); - for (var r of reservs) { - r._active = this._in_domain(r, this._domains[HotelCalendar.DOMAIN.RESERVATIONS]); - this._calcReservationCellLimits(r); - if (r._html) { - r._html.innerText = r.title; - } else if (r._limits.isValid()) { - r._html = document.createElement('div'); - r._html.dataset.hcalReservationObjId = r.id; - r._html.classList.add('hcal-reservation'); - r._html.classList.add('noselect'); - r._html.innerText = r.title; - this.edivr.appendChild(r._html); - - if (r.unusedZone) { - r._html.classList.add('hcal-unused-zone'); - } else { - toAssignEvents.push(r._html); - } - } - this._updateReservation(r); - } - - this._assignReservationsEvents(toAssignEvents); - }.bind(this), addedReservations); - - _.defer(function(){ this._updateReservationOccupation(); }.bind(this)); - } - }, - - removeReservation: function(/*HReservationObject*/reserv) { - if (reserv) { - // Remove all related content... - var elms = [reserv._html, this.e.querySelector(`.hcal-warn-ob-indicator[data-hcal-reservation-obj-id='${reserv.id}']`)]; - for (var elm of elms) { - if (elm && elm.parentNode) { - elm.parentNode.removeChild(elm); - } - } - // Remove OB Row - if (reserv.overbooking || reserv.cancelled) { - if (this.getReservationsByRoom(reserv.room).length === 1) { - this.removeExtraRoomRow(reserv); - } - } - // Remove Unused Zones - if (!reserv.unusedZone) { - this._cleanUnusedZones(reserv); - } - - this._reservations = _.reject(this._reservations, {id: reserv.id}); - this._updateReservationsMap(); - } else { - console.warn(`[HotelCalendar][removeReservation] Can't remove '${reserv.id}' reservation!`); - } - }, - - getReservationsByDay: function(/*MomentObject*/day, /*Bool?*/noCheckouts, /*Bool?*/includeUnusedZones, /*Int?*/nroom, /*Int?*/nbed, /*HReservation?*/ignoreThis) { - var inclusivity = noCheckouts?'[)':'[]'; - - if (typeof nroom !== 'undefined') { - return _.filter(this._reservationsMap[nroom], function(item){ - return day.isBetween(item.startDate, item.endDate, 'day', inclusivity) && - (typeof nbed === 'undefined' || item._beds.includes(nbed)) && - ((includeUnusedZones && item.unusedZone) || !item.unusedZone) && - item !== ignoreThis && !item.overbooking && !item.cancelled; - }); - } else { - return _.filter(this._reservations, function(item){ - return day.isBetween(item.startDate, item.endDate, 'day', inclusivity) && - (typeof nbed === 'undefined' || item._beds.includes(nbed)) && - ((includeUnusedZones && item.unusedZone) || !item.unusedZone) && - item !== ignoreThis && !item.overbooking && !item.cancelled; - }); - } - }, - - getReservationsByRoom: function(/*Int,HRoomObject*/room, /*Boolean*/includeUnusedZones) { - if (!(room instanceof HRoom)) { room = this.getRoom(room); } - if (room) { - return _.filter(this._reservationsMap[room.id], function(item){ - return (includeUnusedZones || (!includeUnusedZones && !item.unusedZone)); - }); - } - - return []; - }, - - _updateReservationsMap: function() { - this._reservationsMap = {}; - this._reservations.map(function(current){ - if (!(current.room.id in this._reservationsMap)) { - this._reservationsMap[current.room.id] = []; - } - this._reservationsMap[current.room.id].push(current); - }.bind(this)); - }, - - _calcReservationCellLimits: function(/*HReservationObject*/reservation, /*Int?*/nbed, /*Bool?*/notCheck) { - var limits = new HLimit(); - if (!reservation.startDate || !reservation.endDate || - (!reservation.startDate.isBetween(this.options.startDate, this._endDate, 'day', '[]') && - !reservation.endDate.isBetween(this.options.startDate, this._endDate, 'day', '[]') && - !reservation.startDate.isBefore(this.options.startDate, 'day', '()') && - !reservation.endDate.isAfter(this._endDate, 'day', '()'))) { - return limits; - } - - var notFound; - do { - notFound = false; - - // Num of beds - var bedNum; - if (typeof nbed === 'undefined') { - if (reservation._beds && reservation._beds.length) { - bedNum = reservation._beds[0]; - } else { - bedNum = (reservation.unusedZone)?1:0; - } - } else { - bedNum = nbed; - } - - // Search Initial Cell - if (reservation.startDate.clone().local().isSameOrAfter(this.options.startDate, 'd')) { - reservation._drawModes[0] = 'hard-start'; - limits.left = this.getCell(reservation.startDate.clone().local(), - reservation.room, - bedNum); - } - else { - reservation._drawModes[0] = 'soft-start'; - limits.left = this.getCell(this.options.startDate.clone().local(), - reservation.room, - bedNum); - } - - // More Beds? - var rpersons = (reservation.room.shared || this.options.divideRoomsByCapacity)?reservation.room.capacity:1; - var reservPersons = reservation.getTotalPersons(false); - if ((reservation.room.shared || this.options.divideRoomsByCapacity) && reservPersons > 1 && bedNum+reservPersons <= rpersons) { - bedNum += reservPersons-1; - } - - // Search End Cell - if (reservation.endDate.clone().subtract(1, 'd').local().isSameOrBefore(this._endDate, 'd')) { - reservation._drawModes[1] = 'hard-end'; - limits.right = this.getCell(reservation.endDate.clone().subtract(1, 'd').local(), - reservation.room, - bedNum); - } - else { - reservation._drawModes[1] = 'soft-end'; - limits.right = this.getCell(this._endDate.clone().local(), - reservation.room, - bedNum); - } - - // Exists other reservation in the same place? - if (!notCheck && limits.isValid()) { - var diff_date = this.getDateDiffDays(reservation.startDate, reservation.endDate); - var numBeds = +limits.right.dataset.hcalBedNum - +limits.left.dataset.hcalBedNum; - var ndate = reservation.startDate.clone().local(); - for (var i=0; i= this.options.endOfWeek-this.options.endOfWeekOffset && dd_local.format('e') <= this.options.endOfWeek) { - cell.classList.add('hcal-cell-end-week'); - } - } - - // Update Reservations Position - var bounds = this.loopedOffsetOptimized(row); - var cheight = bounds.height; - var start_index = _.indexOf(this.options.rooms, ex_room) + 1; - for (var i=start_index; i 0) - humantext += `Min. Stay: ${restr[0]}\n`; - if (restr[1] > 0) - humantext += `Min. Stay Arrival: ${restr[1]}\n`; - if (restr[2] > 0) - humantext += `Max. Stay: ${restr[2]}\n`; - if (restr[3] > 0) - humantext += `Max. Stay Arrival: ${restr[3]}\n`; - if (restr[4]) - humantext += `Closed: ${restr[4]}\n`; - if (restr[5]) - humantext += `Closed Arrival: ${restr[5]}\n`; - if (restr[6]) - humantext += `Closed Departure: ${restr[6]}`; - cell.title = humantext; - } - else { - cell.classList.remove('hcal-restriction-room-day'); - cell.title = ''; - } - } - } - } - } - } - } - }, - - //==== DETAIL CALCS - calcDayRoomTypeReservations: function(/*String,MomentObject*/day, /*String*/room_type) { - var day = HotelCalendar.toMoment(day); - if (!day) { return false; } - - var num_rooms = this._roomCapacities[room_type]; - num_rooms -= _.reduce(this.getDayRoomTypeReservations(day, room_type), function(memo, r){ return memo + ((r.room && r.room.shared)?r.getTotalPersons(false):1); }, 0); - return num_rooms; - }, - - calcDayRoomTotalReservations: function(/*String,MomentObject*/day) { - var day = HotelCalendar.toMoment(day); - if (!day) { return false; } - - var num_rooms = this._roomCapacityTotal; - num_rooms -= _.reduce(this.getReservationsByDay(day, true), function(memo, r){ return memo + ((r.room && r.room.shared)?r.getTotalPersons(false):1); }, 0); - return num_rooms; - }, - - - /** PRIVATE MEMBERS **/ - //==== MAIN FUNCTIONS - _reset_action_reservation: function() { - if (this._lazyModeReservationsSelection) { - clearTimeout(this._lazyModeReservationsSelection); - this._lazyModeReservationsSelection = false; - } - - this.reservationAction = { - action: HotelCalendar.ACTION.NONE, - reservation: null, - oldReservationObj: null, - newReservationObj: null, - mousePos: false, - inReservations: [], - outReservations: [], - }; - }, - - get_normalized_rooms_: function() { - var rooms = {}; - if (this.options.rooms) { - var keys = Object.keys(this.options.rooms); - - for (var r of this.options.rooms) { - rooms[r.number] = [r.type, r.capacity]; - } - } - return rooms; - }, - - //==== RENDER FUNCTIONS - _create: function() { - var $this = this; - while (this.e.hasChildNodes()) { - this.e.removeChild(this.e.lastChild); - } - - if (this._tableCreated) { - console.warn("[Hotel Calendar][_create] Already created!"); - return false; - } - - var scrollThrottle = _.throttle(this._updateOBIndicators.bind(this), 100); - - - this.edivcontainer = document.createElement("div"); - this.edivcontainer.classList.add('hcalendar-container'); - - // Reservations Table - this.edivrh = document.createElement("div"); - this.edivrh.classList.add('table-reservations-header'); - this.edivcontainer.appendChild(this.edivrh); - this.etableHeader = document.createElement("table"); - this.etableHeader.classList.add('hcal-table'); - this.etableHeader.classList.add('noselect'); - this.edivrh.appendChild(this.etableHeader); - this.edivr = document.createElement("div"); - this.edivr.classList.add('table-reservations'); - this.edivcontainer.appendChild(this.edivr); - this.etable = document.createElement("table"); - this.etable.classList.add('hcal-table'); - this.etable.classList.add('noselect'); - this.edivr.appendChild(this.etable); - this.edivr.addEventListener("scroll", scrollThrottle, false); - // Detail Calcs Table - this.edivch = document.createElement("div"); - this.edivch.classList.add('table-calcs-header'); - this.edivcontainer.appendChild(this.edivch); - this.edtableHeader = document.createElement("table"); - this.edtableHeader.classList.add('hcal-table'); - this.edtableHeader.classList.add('noselect'); - this.edivch.appendChild(this.edtableHeader); - this.edivc = document.createElement("div"); - this.edivc.classList.add('table-calcs'); - this.edivcontainer.appendChild(this.edivc); - this.edtable = document.createElement("table"); - this.edtable.classList.add('hcal-table'); - this.edtable.classList.add('noselect'); - this.edivc.appendChild(this.edtable); - - var observer = new MutationObserver(function(mutationsList){ - $this._updateOBIndicators(); - }); - observer.observe(this.edivr, { childList: true }); - - this.e.appendChild(this.edivcontainer); - - this._updateView(); - //_.defer(function(self){ self._updateView(); }, this); - this._tableCreated = true; - - return true; - }, - - _generateTableDay: function(/*HTMLObject*/parentCell, /*HRoomObject*/room) { - var $this = this; - var table = document.createElement("table"); - table.classList.add('hcal-table-day'); - table.classList.add('noselect'); - var row = false; - var cell = false; - var num = ((room.shared || this.options.divideRoomsByCapacity)?room.capacity:1); - for (var i=0; i${dd_local.format('D')}`; - cell.setAttribute('title', dd_local.format('dddd')) - var day = +dd_local.format('D'); - if (day == 1) { - cell.classList.add('hcal-cell-start-month'); - cur_month = dd_local.format('MMMM'); - months[cur_month] = {}; - months[cur_month].year = dd_local.format('YYYY'); - months[cur_month].colspan = 0; - } - if (dd_local.isSame(now, 'day')) { - cell.classList.add('hcal-cell-current-day'); - } else if (dd_local.format('e') >= this.options.endOfWeek-this.options.endOfWeekOffset && dd_local.format('e') <= this.options.endOfWeek) { - cell.classList.add('hcal-cell-end-week'); - } - ++months[cur_month].colspan; - } - // Render Months - var month_keys = Object.keys(months); - for (var m of month_keys) { - var cell_month = row_init.insertCell(); - cell_month.setAttribute('colspan', months[m].colspan); - cell_month.innerText = m+' '+months[m].year; - cell_month.classList.add('hcal-cell-month'); - cell_month.classList.add('btn-hcal'); - cell_month.classList.add('btn-hcal-3d'); - } - - /** ROOM LINES **/ - var tbody = document.createElement("tbody"); - this.etable.appendChild(tbody); - for (var itemRoom of this.options.rooms) { - // Room Number - row = tbody.insertRow(); - row.dataset.hcalRoomObjId = itemRoom.id; - row.classList.add('hcal-row-room-type-group-item'); - if ((this.options.showOverbookings && itemRoom.overbooking) || (this.options.showCancelled && itemRoom.cancelled)) { - var reservId = this.parseExtraRoomId(itemRoom.id)[0]; - var cnumber = this.getExtraRoomRealNumber(itemRoom); - row.setAttribute('id', this._sanitizeId(`ROW_${cnumber}_${itemRoom.type}_EXTRA${reservId}`)); - row.classList.add('hcal-row-room-type-group-overbooking-item'); - } else { - row.setAttribute('id', $this._sanitizeId(`ROW_${itemRoom.number}_${itemRoom.type}`)); - } - cell = row.insertCell(); - cell.textContent = itemRoom.number; - cell.classList.add('hcal-cell-room-type-group-item'); - cell.classList.add('btn-hcal'); - cell.classList.add('btn-hcal-left'); - cell.setAttribute('colspan', '3'); - /* - cell = row.insertCell(); - cell.textContent = itemRoom.type; - cell.classList.add('hcal-cell-room-type-group-item'); - cell.classList.add('btn-hcal'); - cell.classList.add('btn-hcal-flat'); - */ - for (var i=0; i<=$this.options.days; i++) { - var dd = $this.options.startDate.clone().local().startOf('day').add(i,'d').utc(); - var dd_local = dd.clone().local(); - cell = row.insertCell(); - cell.setAttribute('id', $this._sanitizeId(`${itemRoom.type}_${itemRoom.number}_${dd_local.format(HotelCalendar.DATE_FORMAT_SHORT_)}`)); - cell.classList.add('hcal-cell-room-type-group-item-day'); - cell.dataset.hcalParentRow = row.getAttribute('id'); - cell.dataset.hcalDate = dd_local.format(HotelCalendar.DATE_FORMAT_SHORT_); - cell.dataset.hcalRoomObjId = itemRoom.id; - // Generate Interactive Table - cell.appendChild($this._generateTableDay(cell, itemRoom)); - //cell.innerHTML = dd.format("DD"); - var day = +dd_local.format("D"); - if (day == 1) { - cell.classList.add('hcal-cell-start-month'); - } - if (dd_local.isSame(now, 'day')) { - cell.classList.add('hcal-cell-current-day'); - } else if (dd_local.format('e') >= this.options.endOfWeek-this.options.endOfWeekOffset && dd_local.format('e') <= this.options.endOfWeek) { - cell.classList.add('hcal-cell-end-week'); - } - } - - itemRoom._html = row; - } - - this._filterRooms(); - this._calcViewHeight(); - }, - - _calcViewHeight: function() { - if (this.options.showNumRooms > 0) { - var rows = this.edivr.querySelectorAll('tr.hcal-row-room-type-group-item'); - var cheight = 0.0; - for (var i=0; i${dd_local.format('D')}`; - cell.setAttribute('title', dd_local.format("dddd")) - var day = +dd_local.format("D"); - if (day == 1) { - cell.classList.add('hcal-cell-start-month'); - } - if (dd_local.isSame(now, 'day')) { - cell.classList.add('hcal-cell-current-day'); - } else if (dd_local.format('e') >= this.options.endOfWeek-this.options.endOfWeekOffset && dd_local.format('e') <= this.options.endOfWeek) { - cell.classList.add('hcal-cell-end-week'); - } - } - - /** DETAIL LINES **/ - var tbody = document.createElement("tbody"); - this.edtable.appendChild(tbody); - if (this.options.showAvailability) { - // Rooms Free Types - if (this.options.rooms) { - var room_types = this.getRoomTypes(); - for (var rt of room_types) { - if (rt || room_types.length > 1) { - row = tbody.insertRow(); - row.setAttribute('id', this._sanitizeId(`ROW_DETAIL_FREE_TYPE_${rt}`)); - row.dataset.hcalRoomType = rt; - row.classList.add('hcal-row-detail-room-free-type-group-item'); - cell = row.insertCell(); - cell.textContent = rt; - cell.classList.add('hcal-cell-detail-room-free-type-group-item'); - cell.classList.add('btn-hcal'); - cell.classList.add('btn-hcal-left'); - cell.setAttribute("colspan", "3"); - for (var i=0; i<=this.options.days; i++) { - var dd = this.options.startDate.clone().local().startOf('day').add(i,'d').utc(); - var dd_local = dd.clone().local(); - cell = row.insertCell(); - cell.setAttribute('id', this._sanitizeId(`CELL_FREE_${rt}_${dd_local.format(HotelCalendar.DATE_FORMAT_SHORT_)}`)); - cell.classList.add('hcal-cell-detail-room-free-type-group-item-day'); - cell.dataset.hcalParentRow = row.getAttribute('id'); - cell.dataset.hcalDate = dd_local.format(HotelCalendar.DATE_FORMAT_SHORT_); - cell.textContent = '0'; - var day = +dd_local.format("D"); - if (day == 1) { - cell.classList.add('hcal-cell-start-month'); - } - if (dd_local.isSame(now, 'day')) { - cell.classList.add('hcal-cell-current-day'); - } else if (dd_local.format('e') >= this.options.endOfWeek-this.options.endOfWeekOffset && dd_local.format('e') <= this.options.endOfWeek) { - cell.classList.add('hcal-cell-end-week'); - } - } - } - } - } - // Total Free - row = tbody.insertRow(); - row.setAttribute('id', "ROW_DETAIL_TOTAL_FREE"); - row.classList.add('hcal-row-detail-room-free-total-group-item'); - cell = row.insertCell(); - cell.textContent = 'FREE TOTAL'; - cell.classList.add('hcal-cell-detail-room-free-total-group-item'); - cell.classList.add('btn-hcal'); - cell.classList.add('btn-hcal-left'); - cell.setAttribute("colspan", "3"); - for (var i=0; i<=this.options.days; i++) { - var dd = this.options.startDate.clone().local().startOf('day').add(i,'d').utc(); - var dd_local = dd.clone().local(); - cell = row.insertCell(); - cell.setAttribute('id', this._sanitizeId(`CELL_DETAIL_TOTAL_FREE_${dd_local.format(HotelCalendar.DATE_FORMAT_SHORT_)}`)); - cell.classList.add('hcal-cell-detail-room-free-total-group-item-day'); - cell.dataset.hcalParentRow = row.getAttribute('id'); - cell.dataset.hcalDate = dd_local.format(HotelCalendar.DATE_FORMAT_SHORT_); - cell.textContent = '0'; - var day = +dd_local.format("D"); - if (day == 1) { - cell.classList.add('hcal-cell-start-month'); - } - if (dd_local.isSame(now, 'day')) { - cell.classList.add('hcal-cell-current-day'); - } else if (dd_local.format('e') >= this.options.endOfWeek-this.options.endOfWeekOffset && dd_local.format('e') <= this.options.endOfWeek) { - cell.classList.add('hcal-cell-end-week'); - } - } - // Percentage Occupied - row = tbody.insertRow(); - row.setAttribute('id', "ROW_DETAIL_PERC_OCCUP"); - row.classList.add('hcal-row-detail-room-perc-occup-group-item'); - cell = row.insertCell(); - cell.textContent = '% OCCUP.'; - cell.classList.add('hcal-cell-detail-room-perc-occup-group-item'); - cell.classList.add('btn-hcal'); - cell.classList.add('btn-hcal-left'); - cell.setAttribute("colspan", "3"); - for (var i=0; i<=this.options.days; i++) { - var dd = this.options.startDate.clone().local().startOf('day').add(i,'d').utc(); - var dd_local = dd.clone().local(); - cell = row.insertCell(); - cell.setAttribute('id', this._sanitizeId(`CELL_DETAIL_PERC_OCCUP_${dd_local.format(HotelCalendar.DATE_FORMAT_SHORT_)}`)); - cell.classList.add('hcal-cell-detail-room-perc-occup-group-item-day'); - cell.dataset.hcalParentRow = row.getAttribute('id'); - cell.dataset.hcalDate = dd_local.format(HotelCalendar.DATE_FORMAT_SHORT_); - cell.textContent = '0'; - var day = +dd_local.format("D"); - if (day == 1) { - cell.classList.add('hcal-cell-start-month'); - } - if (dd_local.isSame(now, 'day')) { - cell.classList.add('hcal-cell-current-day'); - } else if (dd_local.format('e') >= this.options.endOfWeek-this.options.endOfWeekOffset && dd_local.format('e') <= this.options.endOfWeek) { - cell.classList.add('hcal-cell-end-week'); - } - } - } - // Rooms Pricelist - this._pricelist_id = _.keys(this._pricelist)[0]; - if (this.options.showPricelist && this._pricelist) { - //var pricelists_keys = _.keys(this._pricelist) - //for (var key of pricelists_keys) { - var key = this._pricelist_id; - var pricelist = this._pricelist[key]; - for (var listitem of pricelist) { - row = tbody.insertRow(); - row.setAttribute('id', this._sanitizeId(`ROW_DETAIL_PRICE_ROOM_${key}_${listitem.room}`)); - row.dataset.hcalPricelist = key; - row.dataset.hcalRoomTypeId = listitem.room - row.classList.add('hcal-row-detail-room-price-group-item'); - cell = row.insertCell(); - var span = document.createElement('span'); - cell.title = cell.textContent = listitem.title + ' ' + this.options.currencySymbol; - cell.classList.add('hcal-cell-detail-room-group-item', 'btn-hcal', 'btn-hcal-left'); - cell.dataset.currencySymbol = this.options.currencySymbol; - cell.setAttribute("colspan", "3"); - for (var i=0; i<=$this.options.days; i++) { - var dd = this.options.startDate.clone().local().startOf('day').add(i,'d').utc(); - var dd_local = dd.clone().local(); - cell = row.insertCell(); - cell.setAttribute('id', this._sanitizeId(`CELL_PRICE_${key}_${listitem.room}_${dd_local.format(HotelCalendar.DATE_FORMAT_SHORT_)}`)); - cell.classList.add('hcal-cell-detail-room-price-group-item-day'); - cell.dataset.hcalParentRow = row.getAttribute('id'); - cell.dataset.hcalDate = dd_local.format(HotelCalendar.DATE_FORMAT_SHORT_); - var day = +dd_local.format("D"); - if (day == 1) { - cell.classList.add('hcal-cell-start-month'); - } - if (dd_local.isSame(now, 'day')) { - cell.classList.add('hcal-cell-current-day'); - } else if (dd_local.format('e') >= this.options.endOfWeek-this.options.endOfWeekOffset && dd_local.format('e') <= this.options.endOfWeek) { - cell.classList.add('hcal-cell-end-week'); - } - - var input = document.createElement('input'); - input.setAttribute('id', this._sanitizeId(`INPUT_PRICE_${key}_${listitem.room}_${dd_local.format(HotelCalendar.DATE_FORMAT_SHORT_)}`)); - input.setAttribute('type', 'edit'); - input.setAttribute('title', 'Price'); - input.setAttribute('name', 'room_type_price_day'); - input.dataset.hcalParentCell = cell.getAttribute('id'); - var dd_fmrt = dd_local.format(HotelCalendar.DATE_FORMAT_SHORT_); - input.dataset.orgValue = input.value = _.has(listitem['days'], dd_fmrt)?Number(listitem['days'][dd_fmrt]).toLocaleString():'...'; - input.addEventListener('change', function(ev){ $this._onInputChange(ev, this); }, false); - cell.appendChild(input); - } - } - //} - } - }, - - //==== UPDATE FUNCTIONS - _updateView: function(/*Bool*/notData, /*function*/callback) { - this._createTableReservationDays(); - if (typeof callback !== 'undefined') { - callback(); - } - this._updateCellSelection(); - this._createTableDetailDays(); - - _.defer(function(self){ - self._updateOffsets(); - self._updateReservations(true); - if (!notData) { - _.defer(function(self){ - self._updateRestrictions(); - self._updatePriceList(); - self._updateReservationOccupation(); - }, self); - } - }, this); - // if (!notData) { - // _.defer(function(self){ - // self._createTableDetailDays(); - // self._updateRestrictions(); - // self._updatePriceList(); - // self._updateReservationOccupation(); - // }, this); - // } - }, - - _updateOBIndicators: function() { - var mainBounds = this._edivrOffset; - for (var reserv of this._reservations) { - if (reserv.overbooking && reserv._html) { - var eOffset = this._eOffset; - var bounds = this.loopedOffsetOptimized(reserv._html); - if (bounds.top > mainBounds.height) { - var warnDiv = this.e.querySelector(`div.hcal-warn-ob-indicator[data-hcal-reservation-obj-id='${reserv.id}']`); - if (!warnDiv) { - var warnDiv = document.createElement("DIV"); - warnDiv.innerHTML = ""; - warnDiv.classList.add('hcal-warn-ob-indicator'); - warnDiv.style.borderTopLeftRadius = warnDiv.style.borderTopRightRadius = "50px"; - warnDiv.dataset.hcalReservationObjId = reserv.id; - this.edivcontainer.appendChild(warnDiv); - var warnComputedStyle = window.getComputedStyle(warnDiv, null); - warnDiv.style.top = `${mainBounds.height - eOffset.top - parseInt(warnComputedStyle.getPropertyValue("height"), 10)}px`; - warnDiv.style.left = `${(bounds.left + (bounds.right - bounds.left)/2.0 - parseInt(warnComputedStyle.getPropertyValue("width"), 10)/2.0) - mainBounds.left}px`; - } - } else if (bounds.height < mainBounds.top) { - var warnDiv = this.e.querySelector(`div.hcal-warn-ob-indicator[data-hcal-reservation-obj-id='${reserv.id}']`); - if (!warnDiv) { - var warnDiv = document.createElement("DIV"); - warnDiv.innerHTML = ""; - warnDiv.classList.add('hcal-warn-ob-indicator'); - warnDiv.style.borderBottomLeftRadius = warnDiv.style.borderBottomRightRadius = "50px"; - warnDiv.style.top = `${mainBounds.top - eOffset.top}px`; - warnDiv.dataset.hcalReservationObjId = reserv.id; - this.edivcontainer.appendChild(warnDiv); - var warnComputedStyle = window.getComputedStyle(warnDiv, null); - warnDiv.style.left = `${(bounds.left + (bounds.right - bounds.left)/2.0 - parseInt(warnComputedStyle.getPropertyValue("width"), 10)/2.0) - mainBounds.left}px`; - } - } else { - var warnDiv = this.e.querySelector(`div.hcal-warn-ob-indicator[data-hcal-reservation-obj-id='${reserv.id}']`); - if (warnDiv) { - warnDiv.parentNode.removeChild(warnDiv); - } - } - } - } - }, - - _updateHighlightUnifyReservations: function() { - var $this = this; - if (!this.reservationAction.toUnify || this.reservationAction.toUnify.length === 0) { - var elms = this.e.querySelectorAll("div.hcal-reservation-invalid-unify"); - for (var elm of elms) { elm.classList.remove('hcal-reservation-invalid-unify'); } - elms = this.e.querySelectorAll("div.hcal-reservation-unify-selected"); - for (var elm of elms) { elm.classList.remove('hcal-reservation-unify-selected'); } - } - else { - var dateLimits = this.getDateLimits(this.reservationAction.toUnify, false); - var refUnifyReservation = this.reservationAction.toUnify[0]; - var uniRoom = refUnifyReservation?refUnifyReservation.room.id:false; - for (var nreserv of this._reservations) { - if (nreserv.unusedZone || nreserv._html.classList.contains('hcal-reservation-unify-selected')) { - continue; - } - - // Invalid? - if (nreserv.room.id !== uniRoom || (!nreserv.startDate.isSame(dateLimits[1], 'day') && !nreserv.endDate.isSame(dateLimits[0], 'day')) || - (nreserv.id !== refUnifyReservation.id && nreserv.getUserData('parent_reservation') !== refUnifyReservation.id)) - { - nreserv._html.classList.add('hcal-reservation-invalid-unify'); - } - else { - nreserv._html.classList.remove('hcal-reservation-invalid-unify'); - } - } - } - }, - - _updateHighlightSwapReservations: function() { - var $this = this; - if (this.reservationAction.inReservations.length === 0 && this.reservationAction.outReservations.length === 0) { - var elms = this.e.querySelectorAll("div.hcal-reservation-invalid-swap"); - for (var elm of elms) { elm.classList.remove('hcal-reservation-invalid-swap'); } - elms = this.e.querySelectorAll("div.hcal-reservation-swap-in-selected"); - for (var elm of elms) { elm.classList.remove('hcal-reservation-swap-in-selected'); } - elms = this.e.querySelectorAll("div.hcal-reservation-swap-out-selected"); - for (var elm of elms) { elm.classList.remove('hcal-reservation-swap-out-selected'); } - } - else { - var dateLimits = this.getDateLimits(this.reservationAction.inReservations, true); - var refInReservation = this.reservationAction.inReservations[0]; - var refOutReservation = this.reservationAction.outReservations[0]; - var inCapacity = refInReservation?refInReservation.room.capacity:false; - var outCapacity = refOutReservation?refOutReservation.room.capacity:false; - var realDateLimits = this.getFreeDatesByRoom(dateLimits[0], dateLimits[1], refInReservation?refInReservation.room.id:refOutReservation.room.id); - for (var nreserv of this._reservations) { - if (nreserv.unusedZone || nreserv._html.classList.contains('hcal-reservation-swap-in-selected') || nreserv._html.classList.contains('hcal-reservation-swap-out-selected')) { - continue; - } - - // Invalid capacity - var totalReservPerson = nreserv.getTotalPersons(false); - if (totalReservPerson > inCapacity || (outCapacity && totalReservPerson > outCapacity) || nreserv.room.capacity < refInReservation.getTotalPersons(false)) - { - nreserv._html.classList.add('hcal-reservation-invalid-swap'); - } - else if (this._modeSwap === HotelCalendar.MODE.SWAP_FROM && this.reservationAction.inReservations.length !== 0 && refInReservation.room.id !== nreserv.room.id) { - if (!_.find(this.reservationAction.outReservations, {'id': nreserv.linkedId})) { - nreserv._html.classList.add('hcal-reservation-invalid-swap'); - } - } else if (this._modeSwap === HotelCalendar.MODE.SWAP_TO && this.reservationAction.outReservations.length !== 0 && refOutReservation.room.id !== nreserv.room.id) { - if (!_.find(this.reservationAction.inReservations, {'id': nreserv.linkedId})) { - nreserv._html.classList.add('hcal-reservation-invalid-swap'); - } - } - // Invalid reservations out of dates - else if (nreserv.startDate.isBefore(realDateLimits[0], 'day') || nreserv.endDate.clone().subtract('1', 'd').isAfter(realDateLimits[1], 'day')) { - if (nreserv.room.id !== refInReservation.room.id) { - nreserv._html.classList.add('hcal-reservation-invalid-swap'); - } - } - else { - nreserv._html.classList.remove('hcal-reservation-invalid-swap'); - } - } - } - }, - - _updateHighlightInvalidZones: function(/*HReservation*/reserv) { - if (typeof reserv === 'undefined') { - var elms = this.etable.querySelectorAll("td[data-hcal-date] table td"); - for (var tdCell of elms) { - tdCell.classList.remove('hcal-cell-invalid'); - } - return; - } - - if (reserv.readOnly) { - var elms = this.etable.querySelectorAll("td[data-hcal-date] table td"); - for (var tdCell of elms) { - tdCell.classList.add('hcal-cell-invalid'); - } - } else if (reserv.fixDays) { - var limitLeftDate = this.etable.querySelector(`#${reserv._limits.left.dataset.hcalParentCell}`).dataset.hcalDate; - var limitRightDate = this.etable.querySelector(`#${reserv._limits.right.dataset.hcalParentCell}`).dataset.hcalDate; - var limitLeftDateMoment = HotelCalendar.toMoment(limitLeftDate); - var limitRightDateMoment = HotelCalendar.toMoment(limitRightDate); - var diff_date = this.getDateDiffDays(limitLeftDateMoment, limitRightDateMoment); - var date = limitLeftDateMoment.clone().startOf('day'); - var selector = []; - for (var i=0; i<=diff_date; i++) { - selector.push("not([data-hcal-date='"+date.format(HotelCalendar.DATE_FORMAT_SHORT_)+"'])"); - date.add(1, 'd'); - } - if (selector.length) { - var elms = this.etable.querySelectorAll(`td:${selector.join(':')}`+ ' table td'); - for (var tdCell of elms) { - tdCell.classList.add('hcal-cell-invalid'); - } - } - } else if (reserv.fixRooms) { - var parentCell = this.etable.querySelector(`#${reserv._limits.left.dataset.hcalParentCell}`); - var parent_row = parentCell.dataset.hcalParentRow; - var elms = this.etable.querySelectorAll("td:not([data-hcal-parent-row='"+parent_row+"']) table td"); - for (var tdCell of elms) { - tdCell.classList.add('hcal-cell-invalid'); - } - } else { - var limitLeftDate = this.etable.querySelector(`#${reserv._limits.left.dataset.hcalParentCell}`).dataset.hcalDate; - var limitRightDate = this.etable.querySelector(`#${reserv._limits.right.dataset.hcalParentCell}`).dataset.hcalDate; - var limitLeftDateMoment = HotelCalendar.toMoment(limitLeftDate); - var limitRightDateMoment = HotelCalendar.toMoment(limitRightDate); - var diff_date = this.getDateDiffDays(limitLeftDateMoment, limitRightDateMoment)+1; - if (reserv._drawModes[1] === 'hard-end') { --diff_date; } - var date = limitLeftDateMoment.clone().startOf('day'); - var selector = []; - for (var i=0; i<=diff_date; i++) { - selector.push("td[data-hcal-date='"+date.format(HotelCalendar.DATE_FORMAT_SHORT_)+"'] table td"); - date.add(1, 'd'); - } - if (selector.length) { - var elms = this.etable.querySelectorAll(`${selector.join(', ')}`); - for (var tdCell of elms) { - tdCell.classList.add('hcal-cell-highlight'); - } - } - } - }, - - _updateScroll: function(/*HTMLObject*/reservationDiv) { - var reservBounds = this.loopedOffsetOptimized(reservationDiv); - var mainBounds = this._edivrOffset; - var eOffset = this._eOffset; - var bottom = mainBounds.height - eOffset.top; - var top = mainBounds.top + eOffset.top; - var offset = 10.0; - var scrollDisp = 10.0; - if (reservBounds.height >= bottom-offset) { - this.edivr.scrollBy(0, scrollDisp); - } - else if (reservBounds.top <= top+offset) { - this.edivr.scrollBy(0, -scrollDisp); - } - }, - - //==== SELECTION - _updateCellSelection: function() { - // Clear all - var highlighted_td = this.etable.querySelectorAll('td.hcal-cell-highlight'); - for (var td of highlighted_td) { - td.classList.remove('hcal-cell-highlight'); - td.textContent = ''; - } - - // Highlight Selected - if (this._cellSelection.current) { - this._cellSelection.current.classList.add('hcal-cell-highlight'); - } - // Highlight Range Cells - var cells = false; - var total_price = 0.0; - var limits = new HLimit(this._cellSelection.start, - this._cellSelection.end?this._cellSelection.end:this._cellSelection.current); - if (limits.isValid()) { - // Normalize - // TODO: Multi-Directional Selection. Now only support normal or inverse. - var limitLeftDate = HotelCalendar.toMoment(this.etable.querySelector(`#${limits.left.dataset.hcalParentCell}`).dataset.hcalDate); - var limitRightDate = HotelCalendar.toMoment(this.etable.querySelector(`#${limits.right.dataset.hcalParentCell}`).dataset.hcalDate); - if (limitLeftDate.isAfter(limitRightDate)) { - limits.swap(); - } - cells = this.getCells(limits); - for (var c of cells) { - var parentRow = this.$base.querySelector(`#${c.dataset.hcalParentRow}`); - var room = this.getRoom(parentRow.dataset.hcalRoomObjId); - if (room.overbooking || room.cancelled) { - continue; - } - c.classList.add('hcal-cell-highlight'); - if (this._pricelist) { - // FIXME: Normalize data calendar (gmt) vs extra info (utc) - var date_cell = HotelCalendar.toMoment(this.etable.querySelector(`#${c.dataset.hcalParentCell}`).dataset.hcalDate); - var room_price = this.getRoomPrice(parentRow.dataset.hcalRoomObjId, date_cell); - c.textContent = room_price + ' ' + this.options.currencySymbol; - if (!room.shared && c.dataset.hcalBedNum > limits.left.dataset.hcalBedNum) { - c.style.color = 'lightgray'; - } - else { - c.style.color = 'black'; - total_price += room_price; - } - } - } - } - - this._dispatchEvent( - 'hcalOnUpdateSelection', - { - 'limits': limits, - 'cells': cells, - 'old_cells': highlighted_td, - 'totalPrice': total_price - }); - }, - - _resetCellSelection: function() { - this._cellSelection = { current: false, end: false, start: false }; - }, - - //==== RESERVATIONS - _updateDivReservation: function(/*HReservationObject*/reserv, /*Bool?*/noRefresh) { - if (!reserv._limits.isValid() || !reserv._html) { - return; - } - - if (reserv.readOnly) { - reserv._html.classList.add('hcal-reservation-readonly'); - } else { - reserv._html.classList.remove('hcal-reservation-readonly'); - } - - if (reserv.room._active) { - reserv._html.classList.remove('hcal-hidden'); - } else { - reserv._html.classList.add('hcal-hidden'); - } - - if (reserv._active) { - reserv._html.classList.remove('hcal-reservation-unselect'); - } else { - reserv._html.classList.add('hcal-reservation-unselect'); - } - - if (!noRefresh) { - var boundsInit = this.loopedOffsetOptimized(reserv._limits.left); - var boundsEnd = this.loopedOffsetOptimized(reserv._limits.right); - var divHeight = (boundsEnd.top+boundsEnd.height)-boundsInit.top-4; - var has_changed = false; - - var reservStyles = { - backgroundColor: reserv.color, - color: reserv.colorText, - lineHeight: `${divHeight}px`, - fontSize: '12px', - top: `${boundsInit.top-this._etableOffset.top+2}px`, - left: `${boundsInit.left-this._etableOffset.left+2}px`, - width: `${(boundsEnd.left-boundsInit.left)+boundsEnd.width-4}px`, - height: `${divHeight}px`, - borderLeftWidth: '', - borderLeftStyle: '', - borderRightWidth: '', - borderRightStyle: '', - }; - - if (reserv._drawModes[0] === 'soft-start') { - has_changed = true; - reservStyles.borderLeftWidth = '3px'; - reservStyles.borderLeftStyle = 'double'; - reservStyles.left = `${boundsInit.left-this._etableOffset.left}px`; - reservStyles.width = `${(boundsEnd.left-boundsInit.left)+boundsEnd.width-2}px`; - } else if (reserv.splitted && reserv.startDate.isSame(reserv.getUserData('realDates')[0], 'day')) { - has_changed = true; - reservStyles.borderLeftWidth = '0'; - reservStyles.width = `${(boundsEnd.left-boundsInit.left)+boundsEnd.width-2}px`; - } - - if (reserv._drawModes[1] === 'soft-end') { - has_changed = true; - reservStyles.borderRightWidth = '3px'; - reservStyles.borderRightStyle = 'double'; - reservStyles.width = `${(boundsEnd.left-boundsInit.left)+boundsEnd.width-2}px`; - } else if (reserv.splitted && reserv.endDate.isSame(reserv.getUserData('realDates')[1], 'day')) { - has_changed = true; - reservStyles.borderRightWidth = '0'; - reservStyles.left = `${boundsInit.left-this._etableOffset.left-1}px`; - reservStyles.width = `${(boundsEnd.left-boundsInit.left)+boundsEnd.width-1}px`; - } - - if (reserv.splitted) { - reserv._html.classList.add('hcal-reservation-splitted'); - // 1. Use reservation ID as seed - // 2. Use sinusiudal function - // 3. Only use positive values (This decrease longitude) - // 4. Use the first 5 decimals to make the integer value - // 5. Get integer value (Bitwise tilde method) - // TODO: Improve pseudo-random number generator - var magicNumber = ~~(Math.abs(Math.sin((reserv.getUserData('parent_reservation') || reserv.id))) * 100000); - var bbColor = this._intToRgb(magicNumber); - reservStyles.borderColor = `rgb(${bbColor[0]},${bbColor[1]},${bbColor[2]})`; - - if (!has_changed) { - reservStyles.left = `${boundsInit.left-this._etableOffset.left-1}px`; - reservStyles.width = `${(boundsEnd.left-boundsInit.left)+boundsEnd.width+2}px`; - } - } else { - reserv._html.classList.remove('hcal-reservation-splitted'); - } - - Object.assign(reserv._html.style, reservStyles); - } - }, - - swapReservations: function(/*List HReservationObject*/fromReservations, /*List HReservationObject*/toReservations) { - if (fromReservations.length === 0 || toReservations.length === 0) { - console.warn("[HotelCalendar][swapReservations] Invalid Swap Operation!"); - return false; - } - var fromDateLimits = this.getDateLimits(fromReservations, true); - var fromRealDateLimits = this.getFreeDatesByRoom(fromDateLimits[0], fromDateLimits[1], fromReservations[0].room.id); - var toDateLimits = this.getDateLimits(toReservations, true); - var toRealDateLimits = this.getFreeDatesByRoom(toDateLimits[0], toDateLimits[1], toReservations[0].room.id); - - if (fromDateLimits[0].clone().local().isSameOrAfter(toRealDateLimits[0].clone().local(), 'd') && fromDateLimits[1].clone().local().isSameOrBefore(toRealDateLimits[1].clone().local(), 'd') && - toDateLimits[0].clone().local().isSameOrAfter(fromRealDateLimits[0].clone().local(), 'd') && toDateLimits[1].clone().local().isSameOrBefore(fromRealDateLimits[1].clone().local(), 'd')) - { - // Change some critical values - var refFromReservs = fromReservations[0]; - var refToReservs = toReservations[0]; - var refFromRoom = refFromReservs.room; - var refToRoom = refToReservs.room; - var fromRoomRow = this.getExtraRoomRow(refFromReservs); - var toRoomRow = this.getExtraRoomRow(refToReservs); - var refFromRoomNewId = (refFromRoom.overbooking||refFromRoom.cancelled)?this.parseExtraRoomId(refFromRoom.id)[1]:refFromRoom.id; - refFromRoomNewId = `${refToReservs.id}@${refFromRoomNewId}`; - var refToRoomNewId = (refToRoom.overbooking||refToRoom.cancelled)?this.parseExtraRoomId(refToRoom.id)[1]:refToRoom.id; - refToRoomNewId = `${refFromReservs.id}@${refToRoomNewId}`; - - if (refFromRoom.overbooking || refFromRoom.cancelled) { - var cnumber = this.getExtraRoomRealNumber(refFromRoom); - refFromRoom.id = refFromRoomNewId; - var newRowId = `${this._sanitizeId(`ROW_${cnumber}_${refToRoom.type}_EXTRA${refToReservs.id}`)}`; - var elms = fromRoomRow.querySelectorAll(`td[data-hcal-parent-row='${fromRoomRow.id}']`); - for (var elm of elms) { elm.dataset.hcalParentRow = newRowId; } - fromRoomRow.setAttribute('id', `${newRowId}`); - fromRoomRow.dataset.hcalRoomObjId = refFromRoom.id; - } - if (refToRoom.overbooking || refToRoom.cancelled) { - var cnumber = this.getExtraRoomRealNumber(refToRoom); - refToRoom.id = refToRoomNewId; - var newRowId = `${this._sanitizeId(`ROW_${cnumber}_${refFromRoom.type}_EXTRA${refFromReservs.id}`)}`; - var elms = toRoomRow.querySelectorAll(`td[data-hcal-parent-row='${toRoomRow.id}']`); - for (var elm of elms) { elm.dataset.hcalParentRow = newRowId; } - toRoomRow.setAttribute('id', `${newRowId}`); - toRoomRow.dataset.hcalRoomObjId = refToRoom.id; - } - - for (var nreserv of fromReservations) { - nreserv.cancelled = refToRoom.cancelled; - nreserv.overbooking = refToRoom.overbooking; - nreserv.room = refToRoom; - } - for (var nreserv of toReservations) { - nreserv.cancelled = refFromRoom.cancelled; - nreserv.overbooking = refFromRoom.overbooking; - nreserv.room = refFromRoom; - } - } else { - console.warn("[HotelCalendar][swapReservations] Invalid Swap Operation!"); - return false; - } - - return true; - }, - - _dispatchSwapReservations: function() { - if (this.reservationAction.inReservations.length > 0 && this.reservationAction.outReservations.length > 0) { - this._dispatchEvent( - 'hcalOnSwapReservations', - { - 'inReservs': this.reservationAction.inReservations || [], - 'outReservs': this.reservationAction.outReservations || [], - } - ); - } - }, - - _dispatchUnifyReservations: function() { - if (this.reservationAction.hasOwnProperty('toUnify') && this.reservationAction.toUnify.length > 1) { - this._dispatchEvent( - 'hcalOnUnifyReservations', - { - 'toUnify': this.reservationAction.toUnify || [], - } - ); - } - }, - - replaceReservation: function(/*HReservationObject*/reservationObj, /*HReservationObject*/newReservationObj) { - if (!reservationObj._html) { - console.warn("[Hotel Calendar][updateReservation_] Invalid Reservation Object"); - return; - } - - var index = _.findKey(this._reservations, {'id': reservationObj.id}); - delete this._reservations[index]; - this._reservations[index] = newReservationObj; - reservationObj._html.dataset.hcalReservationObjId = newReservationObj.id; - this._updateReservationsMap(); - this._updateDivReservation(newReservationObj); - - var linkedReservations = this.getLinkedReservations(newReservationObj); - for (var lr of linkedReservations) { - lr.startDate = newReservationObj.startDate.clone(); - lr.endDate = newReservationObj.endDate.clone(); - - if (lr._html) { - this._calcReservationCellLimits(lr); - this._updateDivReservation(lr); - } - } - _.defer(function(){ this._updateReservationOccupation(); }.bind(this)); - }, - - getLinkedReservations: function(/*HReservationObject*/reservationObj) { - return _.reject(this._reservations, function(item){ return item.linkedId !== reservationObj.id; }); - }, - - _updateReservation: function(/*HReservationObject*/reservationObj, /*Bool?*/noRefresh) { - // Fill - if (reservationObj._limits.isValid()) { - this._updateDivReservation(reservationObj, noRefresh); - } else { - console.warn(`[Hotel Calendar][_updateReservation] Can't place reservation ID@${reservationObj.id} [${reservationObj.startDate.format(HotelCalendar.DATE_FORMAT_LONG_)} --> ${reservationObj.endDate.format(HotelCalendar.DATE_FORMAT_LONG_)}]`); - this.removeReservation(reservationObj); - } - }, - - _updateReservations: function(/*Bool*/updateLimits) { - for (var reservation of this._reservations){ - if (updateLimits) { - this._calcReservationCellLimits(reservation); - } - this._updateReservation(reservation); - } - //this._assignReservationsEvents(); - //this._updateReservationOccupation(); - this._updateOBIndicators(); - }, - - _assignReservationsEvents: function(reservDivs) { - var $this = this; - reservDivs = reservDivs || this.e.querySelectorAll('div.hcal-reservation'); - for (var rdiv of reservDivs) { - var bounds = this.loopedOffsetOptimized(rdiv); - rdiv.addEventListener('mousemove', function(ev){ - var posAction = $this._getRerservationPositionAction(this, ev.layerX, ev.layerY); - if (posAction == HotelCalendar.ACTION.MOVE_LEFT || posAction == HotelCalendar.ACTION.MOVE_RIGHT) { - this.style.cursor = 'col-resize'; - } else if (posAction == HotelCalendar.ACTION.MOVE_DOWN) { - this.style.cursor = 'ns-resize'; - } else { - this.style.cursor = 'pointer'; - } - }, false); - var _funcEvent = function(ev){ - if ($this._isLeftButtonPressed(ev)) { - // MODE UNIFY RESERVATIONS - if ($this._selectionMode === HotelCalendar.ACTION.UNIFY) { - var reserv = $this.getReservation(this.dataset.hcalReservationObjId); - var dateLimits = $this.getDateLimits($this.reservationAction.toUnify, false); - var refUnifyReserv = ($this.reservationAction.toUnify.length > 0)?$this.reservationAction.toUnify[0]:false; - if ($this.reservationAction.toUnify.indexOf(reserv) != -1) { - $this.reservationAction.toUnify = _.reject($this.reservationAction.toUnify, function(item){ return item === reserv}); - this.classList.remove('hcal-reservation-unify-selected'); - } - else { - $this.reservationAction.toUnify.push(reserv); - this.classList.add('hcal-reservation-unify-selected'); - } - $this._updateHighlightUnifyReservations(); - } - else { - // ENABLE SWAP SELECTION - if (ev.ctrlKey || $this._modeSwap === HotelCalendar.MODE.SWAP_FROM) { - $this.reservationAction.action = HotelCalendar.ACTION.SWAP; - $this.setSwapMode(HotelCalendar.MODE.SWAP_FROM); - } - // MODE SWAP RESERVATIONS - if ($this.reservationAction.action === HotelCalendar.ACTION.SWAP) { - var reserv = $this.getReservation(this.dataset.hcalReservationObjId); - var refFromReserv = ($this.reservationAction.inReservations.length > 0)?$this.reservationAction.inReservations[0]:false; - var refToReserv = ($this.reservationAction.outReservations.length > 0)?$this.reservationAction.outReservations[0]:false; - - if (ev.ctrlKey || $this._modeSwap === HotelCalendar.MODE.SWAP_FROM) { - var canAdd = !((!refFromReserv && refToReserv && reserv.room.id === refToReserv.room.id) || (refFromReserv && reserv.room.id !== refFromReserv.room.id)); - // Can unselect - if ($this.reservationAction.inReservations.indexOf(reserv) != -1 && (($this.reservationAction.outReservations.length > 0 && $this.reservationAction.inReservations.length > 1) || $this.reservationAction.outReservations.length === 0)) { - $this.reservationAction.inReservations = _.reject($this.reservationAction.inReservations, function(item){ return item === reserv}); - this.classList.remove('hcal-reservation-swap-in-selected'); - } - // Can't add a 'out' reservation in 'in' list - else if ($this.reservationAction.outReservations.indexOf(reserv) == -1 && canAdd) { - $this.reservationAction.inReservations.push(reserv); - this.classList.add('hcal-reservation-swap-in-selected'); - } - } else if (!ev.ctrlKey || $this._modeSwap === HotelCalendar.MODE.SWAP_TO) { - $this.setSwapMode(HotelCalendar.MODE.SWAP_TO); - var canAdd = !((!refToReserv && refFromReserv && reserv.room.id === refFromReserv.room.id) || (refToReserv && reserv.room.id !== refToReserv.room.id)); - // Can unselect - if ($this.reservationAction.outReservations.indexOf(reserv) != -1) { - $this.reservationAction.outReservations = _.reject($this.reservationAction.outReservations, function(item){ return item === reserv; }); - this.classList.remove('hcal-reservation-swap-out-selected'); - } - // Can't add a 'in' reservation in 'out' list - else if ($this.reservationAction.inReservations.indexOf(reserv) == -1 && canAdd) { - $this.reservationAction.outReservations.push(reserv); - this.classList.add('hcal-reservation-swap-out-selected'); - } - } - $this._updateHighlightSwapReservations(); - } - // MODE RESIZE/MOVE RESERVATION - else if (!$this.reservationAction.reservation) { - $this.reservationAction = { - reservation: this, - mousePos: [ev.x, ev.y], - action: $this._getRerservationPositionAction(this, ev.layerX, ev.layerY), - inReservations: [], - outReservations: [], - }; - - // FIXME: Workaround for lazy selection operation - if ($this._lazyModeReservationsSelection) { - clearTimeout($this._lazyModeReservationsSelection); - $this._lazyModeReservationsSelection = false; - } - - $this._lazyModeReservationsSelection = setTimeout(function($this){ - var reserv = $this.getReservation(this.dataset.hcalReservationObjId); - $this._updateHighlightInvalidZones(reserv); - if (reserv.readOnly || (reserv.fixDays && ($this.reservationAction.action == HotelCalendar.ACTION.MOVE_LEFT - || $this.reservationAction.action == HotelCalendar.ACTION.MOVE_RIGHT))) { - $this.reservationAction.action = HotelCalendar.ACTION.NONE; - return false; - } - var affectedReservations = [reserv].concat($this.getLinkedReservations(reserv)); - for (var areserv of affectedReservations) { - if (areserv._html) { - areserv._html.classList.add('hcal-reservation-action'); - } - } - - var otherReservs = _.difference($this._reservations, affectedReservations); - for (var oreserv of otherReservs) { - if (oreserv._html) { - oreserv._html.classList.add('hcal-reservation-foreground'); - } - } - - $this._lazyModeReservationsSelection = false; - }.bind(this, $this), 175); - } - } - } - }; - rdiv.addEventListener('mousedown', _funcEvent, this._supportsPassive ? { passive: true } : false); - rdiv.addEventListener('touchstart', _funcEvent, this._supportsPassive ? { passive: true } : false); - rdiv.addEventListener('click', function(ev){ - $this._dispatchEvent( - 'hcalOnClickReservation', - { - 'event': ev, - 'reservationDiv': this, - 'reservationObj': $this.getReservation(this.dataset.hcalReservationObjId) - }); - }, false); - rdiv.addEventListener('dblclick', function(ev){ - $this._dispatchEvent( - 'hcalOnDblClickReservation', - { - 'event': ev, - 'reservationDiv': this, - 'reservationObj': $this.getReservation(this.dataset.hcalReservationObjId) - }); - }, false); - /* - rdiv.addEventListener('mouseenter', function(ev){ - $this._dispatchEvent( - 'hcalOnMouseEnterReservation', - { - 'event': ev, - 'reservationDiv': this, - 'reservationObj': $this.getReservation(this.dataset.hcalReservationObjId) - }); - }, false); - rdiv.addEventListener('mouseleave', function(ev){ - $this._dispatchEvent( - 'hcalOnMouseLeaveReservation', - { - 'event': ev, - 'reservationDiv': this, - 'reservationObj': $this.getReservation(this.dataset.hcalReservationObjId) - }); - }, false); - */ - } - }, - - _getRerservationPositionAction: function(/*HTMLObject*/elm, /*Int*/posX, /*Int*/posY) { - var bounds = this.loopedOffsetOptimized(elm); - if (posX <= 4) { return HotelCalendar.ACTION.MOVE_LEFT; } - else if (posX >= bounds.width-8) { return HotelCalendar.ACTION.MOVE_RIGHT; } - else if (posY >= bounds.height-4) { return HotelCalendar.ACTION.MOVE_DOWN; } - return HotelCalendar.ACTION.MOVE_ALL; - }, - - _cleanUnusedZones: function(/*HReservationObject*/reserv) { - var unusedReservs = this.getLinkedReservations(reserv); - for (var unusedZone of unusedReservs) { - if (unusedZone._html && unusedZone._html.parentNode) { - unusedZone._html.parentNode.removeChild(unusedZone._html); - } - } - this._reservations = _.reject(this._reservations, {unusedZone: true, linkedId: reserv.id}); - }, - - _createUnusedZones: function(/*Array*/reservs) { - var nreservs = []; - for (var reserv of reservs) { - if (!reserv.unusedZone) { - var unused_id = 0; - var numBeds = reserv.getTotalPersons(false); - for (var e=numBeds; e reservationObj.room.capacity)) { - return false; - } - - if (reservationObj.room.id in this._reservationsMap) { - for (var r of this._reservationsMap[reservationObj.room.id]) { - if (!r.unusedZone && r !== reservationObj && reservationObj.room.number == r.room.number && - (_.difference(reservationObj._beds, r._beds).length != reservationObj._beds.length || this.options.divideRoomsByCapacity) && - (r.startDate.isBetween(reservationObj.startDate, reservationObj.endDate, 'day', '[)') || - r.endDate.isBetween(reservationObj.startDate, reservationObj.endDate, 'day', '(]') || - (reservationObj.startDate.isSameOrAfter(r.startDate, 'day') && reservationObj.endDate.isSameOrBefore(r.endDate, 'day')))) { - return false; - } - } - } - - return true; - }, - - getDates: function() { - return [this.options.startDate.clone(), this._endDate.clone()]; - }, - - //==== EVENT FUNCTIONS - _onInputChange: function(/*EventObject*/ev, /*HTMLObject*/elm) { - //var parentCell = this.edtable.querySelector(`#${elm.dataset.hcalParentCell}`); - //var parentRow = this.edtable.querySelector(`#${parentCell.dataset.hcalParentRow}`); - var value = elm.value; - var orgValue = elm.dataset.orgValue; - var name = elm.getAttribute('name'); - - if (name === 'room_type_price_day') { - if (!this._isNumeric(value)) { - elm.style.backgroundColor = 'red'; - } else if (orgValue !== value) { - elm.classList.add('hcal-input-changed'); - elm.style.backgroundColor = ''; - } else { - elm.classList.remove('hcal-input-changed'); - if (value == 0) { - elm.style.backgroundColor = 'rgb(255, 174, 174)'; - } - } - } - - var parentCell = this.edtable.querySelector(`#${elm.dataset.hcalParentCell}`); - var parentRow = this.edtable.querySelector(`#${parentCell.dataset.hcalParentRow}`); - var vals = { - 'room_type_id': +parentRow.dataset.hcalRoomTypeId, - 'date': HotelCalendar.toMoment(parentCell.dataset.hcalDate), - 'price': value, - 'old_price': orgValue, - 'pricelist_id': +parentRow.dataset.hcalPricelist - }; - //this.updateRoomTypePrice(vals['pricelist_id'], vals['room_type_id'], vals['date'], vals['price']); - this._dispatchEvent('hcalOnPricelistChanged', vals); - - if (this.edivc.querySelector('.hcal-input-changed') !== null) - { - this.btnSaveChanges.classList.add('need-save'); - this.btnSaveChanges.disabled = false; - } else { - this.btnSaveChanges.classList.remove('need-save'); - this.btnSaveChanges.disabled = true; - } - }, - - _onCellMouseUp: function(ev) { - if (this._selectionMode === HotelCalendar.ACTION.DIVIDE) { - if (this.reservationAction.reservation) { - var realEndDate = this.reservationAction.endDate.clone().subtract(1, 'd'); - if (this.reservationAction.action === HotelCalendar.ACTION.DIVIDE && !this.reservationAction.date.isSame(realEndDate, 'day')) { - var diff = this.getDateDiffDays(this.reservationAction.date, realEndDate); - this._dispatchEvent('hcalOnSplitReservation', { - reservation: this.reservationAction.reservation, - obj_id: this.reservationAction.obj_id, - date: this.reservationAction.date, - nights: diff - }) - this._reset_action_reservation(); - this.setSelectionMode(HotelCalendar.ACTION.NONE); - } - } - } - else if (this.reservationAction.action !== HotelCalendar.ACTION.NONE) { - return; - } - else if (this._cellSelection.start && - this._cellSelection.start.dataset.hcalParentRow === ev.target.dataset.hcalParentRow) { - this._cellSelection.end = ev.target; - this._dispatchEvent( - 'hcalOnChangeSelection', - { - 'cellStart': this._cellSelection.start, - 'cellEnd': this._cellSelection.end - }); - } - }, - - _onCellMouseDown: function(ev) { - if (this._selectionMode === HotelCalendar.ACTION.DIVIDE && this._splitReservation) { - this.reservationAction = { - reservation: this._splitReservation._html, - obj_id: this._splitReservation.id, - endDate: this._splitReservation.endDate, - action: this._selectionMode, - date: this._splitDate, - }; - this._splitReservation = false; - this._splitDate = false; - } else if ($(".marked-as-having-a-popover").length === 1) { - // TODO: better call _destroy_and_clear_popover_mark defined in hotel_calendar_controller.js - $(".marked-as-having-a-popover").popover('destroy'); - $('.hcal-reservation').removeClass("marked-as-having-a-popover"); - } else { - // FIXME: Prevent multiple clicks in a row - this._cellSelection.start = this._cellSelection.current = ev.target; - this._cellSelection.end = false; - this._updateCellSelection(); - } - }, - - _onCellMouseEnter: function(ev) { - var date_cell = HotelCalendar.toMoment(this.etable.querySelector(`#${ev.target.dataset.hcalParentCell}`).dataset.hcalDate); - var reserv; - if (this.reservationAction.reservation) { - reserv = this.getReservation(this.reservationAction.reservation.dataset.hcalReservationObjId); - if (!this.reservationAction.oldReservationObj) { - this.reservationAction.oldReservationObj = reserv.clone(); - this.reservationAction.daysOffset = this.getDateDiffDays(reserv.startDate.clone().local(), date_cell); - if (this.reservationAction.daysOffset < 0 ) { - this.reservationAction.daysOffset = 0; - } - } - } - if (this._selectionMode === HotelCalendar.MODE.NONE && this._isLeftButtonPressed(ev)) { - var toRoom = undefined; - var needUpdate = false; - if (!this.reservationAction.reservation) { - if (this._cellSelection.start && this._cellSelection.start.dataset.hcalParentRow === ev.target.dataset.hcalParentRow) { - this._cellSelection.current = ev.target; - } - this._updateCellSelection(); - } else if (this.reservationAction.mousePos) { - // workarround for not trigger reservation change - var a = this.reservationAction.mousePos[0] - ev.x; - var b = this.reservationAction.mousePos[1] - ev.y; - //var dist = Math.sqrt(a*a + b*b); - if (this.reservationAction.action == HotelCalendar.ACTION.MOVE_RIGHT) { - if (reserv.fixDays) { - this._reset_action_reservation(); - return true; - } - if (!date_cell.isAfter(reserv.startDate, 'd')) { - date_cell = reserv.startDate.clone().startOf('day'); - } - if (!this.reservationAction.oldReservationObj) { - this.reservationAction.oldReservationObj = reserv.clone(); - } - reserv.endDate.set({'date': date_cell.date(), 'month': date_cell.month(), 'year': date_cell.year()}).add(1, 'd'); - this.reservationAction.newReservationObj = reserv; - needUpdate = true; - } else if (this.reservationAction.action == HotelCalendar.ACTION.MOVE_LEFT) { - if (reserv.fixDays) { - this._reset_action_reservation(); - return true; - } - var ndate = reserv.endDate.clone().endOf('day').subtract(1, 'd'); - if (!date_cell.isBefore(ndate, 'd')) { - date_cell = ndate; - } - if (!this.reservationAction.oldReservationObj) { - this.reservationAction.oldReservationObj = reserv.clone(); - } - reserv.startDate.set({'date': date_cell.date(), 'month': date_cell.month(), 'year': date_cell.year()}); - this.reservationAction.newReservationObj = reserv; - needUpdate = true; - } else if (this.reservationAction.action == HotelCalendar.ACTION.MOVE_DOWN) { - var parentRow = ev.target.parentNode.parentNode.parentNode.parentNode; - var room = this.getRoom(parentRow.dataset.hcalRoomObjId); - - if (room.id === reserv.room.id) { - if (!this.reservationAction.oldReservationObj) { - this.reservationAction.oldReservationObj = reserv.clone(); - } - reserv.adults = +ev.target.dataset.hcalBedNum + 1; - this.reservationAction.newReservationObj = reserv; - needUpdate = true; - } - } else if (this.reservationAction.action == HotelCalendar.ACTION.MOVE_ALL) { - // Relative Movement - date_cell.subtract(this.reservationAction.daysOffset, 'd'); - - var parentRow = ev.target.parentNode.parentNode.parentNode.parentNode; - var room = this.getRoom(parentRow.dataset.hcalRoomObjId); - reserv.room = room; - var diff_date = this.getDateDiffDays(reserv.startDate, reserv.endDate); - reserv.startDate.set({'date': date_cell.date(), 'month': date_cell.month(), 'year': date_cell.year()}); - var date_end = reserv.startDate.clone().add(diff_date, 'd'); - reserv.endDate.set({'date': date_end.date(), 'month': date_end.month(), 'year': date_end.year()}); - this.reservationAction.newReservationObj = reserv; - toRoom = +ev.target.dataset.hcalBedNum; - needUpdate = true; - } - } - - if (needUpdate && reserv) { - _.defer(function(r){ this._updateScroll(r._html); }.bind(this), reserv) - - var affectedReservations = [reserv].concat(this.getLinkedReservations(this.reservationAction.newReservationObj)); - for (var areserv of affectedReservations) { - if (areserv !== reserv) { - areserv.startDate = reserv.startDate.clone(); - areserv.endDate = reserv.endDate.clone(); - } - - if (areserv._html) { - if (areserv.unusedZone) { - areserv._html.style.visibility = 'hidden'; - continue; - } - _.defer(function(ro, r, tro){ - this._calcReservationCellLimits( - r, - r===ro?tro:undefined, - !this.options.assistedMovement); - this._updateDivReservation(r); - - if (!r._limits.isValid() || !this.checkReservationPlace(r) || - (r.fixRooms && this.reservationAction.oldReservationObj.room.id != r.room.id) || - (r.fixDays && !this.reservationAction.oldReservationObj.startDate.isSame(r.startDate, 'day'))) { - r._html.classList.add('hcal-reservation-invalid'); - } - else { - r._html.classList.remove('hcal-reservation-invalid'); - } - }.bind(this), reserv, areserv, toRoom); - } - } - } - } else if (this._selectionMode === HotelCalendar.ACTION.DIVIDE) { - var parentRow = ev.target.parentNode.parentNode.parentNode.parentNode; - var room_id = parentRow.dataset.hcalRoomObjId; - var reservs = this.getReservationsByDay(date_cell, true, false, room_id); - if (this._divideDivs) { - this._divideDivs[0].remove(); - this._divideDivs[1].remove(); - this._divideDivs = false; - } - if (reservs.length) { - this._splitReservation = reservs[0]; - var defStyle = { - top: this._splitReservation._html.style.top, - left: this._splitReservation._html.style.left, - height: this._splitReservation._html.style.height, - }; - this._divideDivs = [ - $('
      ', {class: 'hcal-reservation-divide-l', css: defStyle}).appendTo(this.edivr), - $('
      ', {class: 'hcal-reservation-divide-r', css: defStyle}).appendTo(this.edivr) - ]; - var diff = this.getDateDiffDays(this._splitReservation.startDate, date_cell); - var boundsCell = false; - var beginCell = this.loopedOffsetOptimized(this._splitReservation._limits.left); - var endCell = this.loopedOffsetOptimized(this._splitReservation._limits.right); - this._splitDate = date_cell.clone(); - if (date_cell.isSame(this._splitReservation.endDate.clone().subtract(1, 'd'), 'day')) { - this._splitDate.subtract(1, 'd'); - var tcell = this.getCell(this._splitDate, this._splitReservation.room, 0); - if (tcell) { - boundsCell = this.loopedOffsetOptimized(tcell); - } else { - boundsCell = false; - this._splitReservation = false; - this._splitDate = false; - } - } else { - boundsCell = this.loopedOffsetOptimized(ev.target); - } - if (boundsCell) { - this._divideDivs[0][0].style.width = `${(boundsCell.left-beginCell.left)+boundsCell.width}px`; - this._divideDivs[1][0].style.left = `${(boundsCell.left-this._etableOffset.left)+boundsCell.width}px`; - this._divideDivs[1][0].style.width = `${(endCell.left-boundsCell.left)}px`; - } - } else { - this._splitReservation = false; - this._splitDate = false; - } - } - }, - - onMainKeyUp: function(/*EventObject*/ev) { - if (this.reservationAction.action === HotelCalendar.ACTION.SWAP || this.getSwapMode() !== HotelCalendar.MODE.NONE) { - var needReset = false; - if (ev.keyCode === 27) { - this.cancelSwap(); - } - else if (ev.keyCode === 13) { - this._dispatchSwapReservations(); - this._reset_action_reservation(); - this._updateHighlightSwapReservations(); - this._modeSwap = HotelCalendar.MODE.NONE; - } - else if (ev.keyCode === 17 && this.getSwapMode() === HotelCalendar.MODE.SWAP_FROM) { - this.setSwapMode(HotelCalendar.MODE.SWAP_TO); - } - } else if (this._selectionMode !== HotelCalendar.MODE.NONE) { - if (this._selectionMode === HotelCalendar.ACTION.UNIFY && (ev.keyCode === 13 || ev.keyCode === 27)) { - if (ev.keyCode === 13) { - this._dispatchUnifyReservations(); - } - this._reset_action_reservation(); - this._updateHighlightUnifyReservations(); - } - - if (ev.keyCode === 27 || ev.keyCode === 13) { - this.setSelectionMode(HotelCalendar.MODE.NONE); - } - } - }, - - onMainKeyDown: function(/*EventObject*/ev) { - if (this.reservationAction.action === HotelCalendar.ACTION.SWAP || this.getSwapMode() !== HotelCalendar.MODE.NONE) { - if (ev.keyCode === 17 && this.getSwapMode() === HotelCalendar.MODE.SWAP_TO) { - this.setSwapMode(HotelCalendar.MODE.SWAP_FROM); - } - } - }, - - onMainMouseUp: function(/*EventObject*/ev) { - if (this._lazyModeReservationsSelection) { - clearTimeout(this._lazyModeReservationsSelection); - this._lazyModeReservationsSelection = false; - } - _.defer(function(ev){ - if (this.reservationAction.reservation) { - var reservDiv = this.reservationAction.reservation; - reservDiv.classList.remove('hcal-reservation-action'); - this._updateHighlightInvalidZones(); - - var rdivs = this.e.querySelectorAll('div.hcal-reservation.hcal-reservation-foreground'); - for (var rd of rdivs) { rd.classList.remove('hcal-reservation-foreground'); } - - var reserv = this.getReservation(reservDiv.dataset.hcalReservationObjId); - var linkedReservations = this.getLinkedReservations(reserv); - var hasInvalidLink = false; - for (var r of linkedReservations) { - if (r._html) { - hasInvalidLink = !hasInvalidLink && r._html.classList.contains('hcal-reservation-invalid'); - r._html.classList.remove('hcal-reservation-action'); - r._html.classList.remove('hcal-reservation-invalid'); - r._html.style.visibility = ''; - } - } - - if (this.reservationAction.oldReservationObj && this.reservationAction.newReservationObj) { - if (!this.options.allowInvalidActions && (reservDiv.classList.contains('hcal-reservation-invalid') || hasInvalidLink)) { - this.replaceReservation(this.reservationAction.newReservationObj, this.reservationAction.oldReservationObj); - } else { - var oldReservation = this.reservationAction.oldReservationObj; - var newReservation = this.reservationAction.newReservationObj; - // Calc Old Reservation Price - var oldDiff = this.getDateDiffDays(oldReservation.startDate, oldReservation.endDate); - var oldPrice = 0.0 - for (var e=0; e> 16) & 255, (RGBint >> 8) & 255, RGBint & 255]; - }, - - _hueToRgb: function(/*Int*/v1, /*Int*/v2, /*Int*/h) { - if (h<0.0) { h+=1; } - if (h>1.0) { h-=1; } - if ((6.0*h) < 1.0) { return v1+(v2-v1)*6.0*h; } - if ((2.0*h) < 1.0) { return v2; } - if ((3.0*h) < 2.0) { return v1+(v2-v1)*((2.0/3.0)-h)*6.0; } - return v1; - }, - - _hslToRgb: function(/*Int*/h, /*Int*/s, /*Int*/l) { - if (s == 0.0) { - return [l,l,l]; - } - var v2 = l<0.5?l*(1.0+s):(l+s)-(s*l); - var v1 = 2.0*l-v2; - return [ - this._hueToRgb(v1,v2,h+(1.0/3.0)), - this._hueToRgb(v1,v2,h), - this._hueToRgb(v1,v2,h-(1.0/3.0))]; - }, - - _RGBToHex: function(/*Int*/r, /*Int*/g, /*Int*/b){ - var bin = r << 16 | g << 8 | b; - return (function(h){ - return new Array(7-h.length).join("0")+h; - })(bin.toString(16).toUpperCase()); - }, - - _hexToRGB: function(/*Int*/hex){ - var r = hex >> 16; - var g = hex >> 8 & 0xFF; - var b = hex & 0xFF; - return [r,g,b]; - }, - - _generateColor: function(/*Int*/value, /*Int*/max, /*Int*/offset, /*Bool*/reverse, /*Bool*/strmode) { - var rgb = [offset,1.0,0.5]; - if (value > max) { - if (!strmode) { - return rgb; - } - return "rgb("+Math.floor(rgb[0]*255)+","+Math.floor(rgb[1]*255)+","+Math.floor(rgb[2]*255)+")"; - } - if (reverse) { - value = max-value; - } - rgb = this._hslToRgb(((max-value)*offset)/max, 1.0, 0.8); - if (!strmode) { - return rgb; - } - return "rgb("+Math.floor(rgb[0]*255)+","+Math.floor(rgb[1]*255)+","+Math.floor(rgb[2]*255)+")"; - } -}; - -/** CONSTANTS **/ -HotelCalendar.DOMAIN = { NONE: -1, RESERVATIONS: 0, ROOMS: 1 }; -HotelCalendar.ACTION = { NONE: -1, MOVE_ALL: 0, MOVE_LEFT: 1, MOVE_RIGHT: 2, MOVE_DOWN: 3, SWAP: 4, DIVIDE: 5, UNIFY: 6 }; -HotelCalendar.MODE = { NONE: -1, SWAP_FROM: 0, SWAP_TO: 1 }; -HotelCalendar.DATE_FORMAT_SHORT_ = 'DD/MM/YYYY'; -HotelCalendar.DATE_FORMAT_LONG_ = HotelCalendar.DATE_FORMAT_SHORT_ + ' HH:mm:ss'; -/** STATIC METHODS **/ -HotelCalendar.toMoment = function(/*String,MomentObject*/ndate, /*String*/format) { - if (moment.isMoment(ndate)) { - return ndate; - } else if (typeof ndate === 'string' || ndate instanceof Date) { - ndate = moment(ndate, typeof format==='undefined'?HotelCalendar.DATE_FORMAT_LONG_:format); - if (moment.isMoment(ndate)) { - return ndate; - } - } - - //debugger; - console.warn('[Hotel Calendar][toMoment] Invalid date format!'); - return false; -} -HotelCalendar.toMomentUTC = function(/*String,MomentObject*/ndate, /*String*/format) { - if (moment.isMoment(ndate)) { - return ndate; - } else if (typeof ndate === 'string' || ndate instanceof Date) { - ndate = moment.utc(ndate, (typeof format==='undefined'?HotelCalendar.DATE_FORMAT_LONG_:format)); - if (moment.isMoment(ndate)) { - return ndate; - } - } - - //debugger; - console.warn('[Hotel Calendar][toMomentUTC] Invalid date format!'); - return false; -} - - -/** ROOM OBJECT **/ -function HRoom(/*Int*/id, /*String*/number, /*Int*/capacity, /*String*/type, /*Bool*/shared, /*List*/price) { - this.id = id || -1; - this.number = number || -1; - this.capacity = capacity || 1; - this.type = type || ''; - this.shared = shared; - this.price = price || false; - this.overbooking = false; - this.cancelled = false; - - this._html = false; - this._active = true; - this._userData = {}; -} -HRoom.prototype = { - clearUserData: function() { this._userData = {}; }, - getUserData: function(/*String?*/key) { - if (typeof key === 'undefined') { - return this._userData; - } - return key in this._userData && this._userData[key] || null; - }, - addUserData: function(/*Dictionary*/data) { - if (!_.isObject(data)) { - console.warn("[Hotel Calendar][HRoom][setUserData] Invalid Data! Need be a object!"); - } else { - this._userData = _.extend(this._userData, data); - } - }, - clone: function() { - var nroom = new HRoom( - this.id, - this.number, - this.capacity, - this.type, - this.shared, - this.price - ); - nroom.overbooking = this.overbooking; - nroom.cancelled = this.cancelled; - nroom._html = this._html; - nroom._active = this._active; - nroom.addUserData(this.getUserData()); - return nroom; - } -}; - -/** RESERVATION OBJECT **/ -function HReservation(/*Dictionary*/rValues) { - if (typeof rValues.room_id === 'undefined' && typeof rValues.room === 'undefined') { - delete this; - console.warn("[Hotel Calendar][HReservation] room can't be empty!"); - return; - } - - this.id = rValues.id; - this.room_id = rValues.room_id; - this.adults = rValues.adults || 1; - this.childrens = rValues.childrens || 0; - this.title = rValues.title || ''; - this.startDate = rValues.startDate || null; - this.endDate = rValues.endDate || null; - this.color = rValues.color || '#000'; - this.colorText = rValues.colorText || '#FFF'; - this.readOnly = rValues.readOnly || false; - this.fixRooms = rValues.fixRooms || false; - this.fixDays = rValues.fixDays || false; - this.unusedZone = rValues.unusedZone || false; - this.linkedId = rValues.linkedId || -1; - this.splitted = rValues.splitted || false; - this.overbooking = rValues.overbooking || false; - this.cancelled = rValues.cancelled || false; - this.room = rValues.room || null; - this.total_reservation = rValues.total_reservation || 0; - this.total_folio = rValues.total_folio || 0; - - this._drawModes = ['hard-start', 'hard-end']; - this._html = false; - this._limits = new HLimit(); - this._beds = []; - this._active = true; - this._userData = {}; -} -HReservation.prototype = { - setRoom: function(/*HRoomObject*/room) { this.room = room; }, - setStartDate: function(/*String,MomentObject*/date) { this.startDate = HotelCalendar.toMoment(date); }, - setEndDate: function(/*String,MomentObject*/date) { this.endDate = HotelCalendar.toMoment(date); }, - - clearUserData: function() { this._userData = {}; }, - getUserData: function(/*String?*/key) { - if (typeof key === 'undefined') { - return this._userData; - } - return key in this._userData && this._userData[key] || null; - }, - addUserData: function(/*Dictionary*/data) { - if (!_.isObject(data)) { - console.warn("[Hotel Calendar][HReservation][setUserData] Invalid Data! Need be a object!"); - } else { - this._userData = _.extend(this._userData, data); - } - }, - getTotalPersons: function(/*Boolean*/countChildrens) { - var persons = this.adults; - if (countChildrens) { - persons += this.childrens; - } - return persons; - }, - clone: function() { - var nreserv = new HReservation({ - 'id': this.id, - 'room': this.room?this.room.clone():null, - 'adults': this.adults, - 'childrens': this.childrens, - 'title': this.title, - 'startDate': this.startDate.clone(), - 'endDate': this.endDate.clone(), - 'color': this.color, - 'colorText': this.colorText, - 'readOnly': this.readOnly, - 'fixRooms': this.fixRooms, - 'fixDays': this.fixDays, - 'unusedZone': this.unusedZone, - 'linkedId': this.linkedId, - 'splitted': this.splitted, - 'overbooking': this.overbooking, - 'cancelled': this.cancelled, - 'room_id': this.room_id, - 'total_reservation': this.total_reservation, - 'total_folio': this.total_folio, - }); - nreserv._beds = _.clone(this._beds); - nreserv._html = this._html; - nreserv._drawModes = _.clone(this._drawModes); - nreserv._limits = this._limits.clone(); - nreserv._active = this._active; - nreserv.addUserData(this.getUserData()); - return nreserv; - } -}; - -/** LIMIT OBJECT **/ -function HLimit(/*HTMLObject*/left, /*HMTLObject*/right) { - this.left = left; - this.right = right; -} -HLimit.prototype = { - isSame: function() { - return this.left == this.right; - }, - isValid: function() { - return this.left && this.right; - }, - swap: function() { - var tt = this.left; - this.left = this.right; - this.right = tt; - }, - clone: function() { - return new HLimit(this.left, this.right); - } -}; diff --git a/hotel_calendar/static/src/lib/hcalendar/js/hcalendar_management.js b/hotel_calendar/static/src/lib/hcalendar/js/hcalendar_management.js deleted file mode 100644 index 35d28cca1..000000000 --- a/hotel_calendar/static/src/lib/hcalendar/js/hcalendar_management.js +++ /dev/null @@ -1,1147 +0,0 @@ -/* global _, moment */ -'use strict'; -/* - * Hotel Calendar Management JS v0.0.1a - 2017-2018 - * GNU Public License - * Alexandre Díaz - * - * Dependencies: - * - moment - * - underscore - * - jquery !shit - * - bootbox !shit - * - bootstrap !shit - */ - -function HotelCalendarManagement(/*String*/querySelector, /*Dictionary*/options, /*HTMLObject?*/_base) { - if (window === this) { - return new HotelCalendarManagement(querySelector, options, _base); - } - - this.$base = (_base === 'undefined') ? document : _base; - - if (typeof querySelector === 'string') { - this.e = this.$base.querySelector(querySelector); - if (!this.e) { - return false; - } - } else if (typeof querySelector === 'object') { - this.e = querySelector; - } else { - return { - Version: '0.0.1a', - Author: "Alexandre Díaz", - Created: "24/09/2017", - Updated: "21/04/2018" - }; - } - - /** Strings **/ - this._strings = { - 'Open': 'Open', - 'Closed': 'Closed', - 'C. Departure': 'C. Departure', - 'C. Arrival': 'C. Arrival', - 'Price': 'Price', - 'Availability': 'Availability', - 'Min. Stay': 'Min. Stay', - 'Max. Stay': 'Max. Stay', - 'Min. Stay Arrival': 'Min. Stay Arrival', - 'Max. Stay Arrival': 'Max. Stay Arrival', - 'Clousure': 'Clousure', - 'Free Rooms': 'Free Rooms', - 'No OTA': 'No OTA', - 'Options': 'Options', - 'Reset': 'Reset', - 'Copy': 'Copy', - 'Paste': 'Paste', - 'Clone': 'Clone', - 'Cancel': 'Cancel' - }; - - /** Options **/ - if (!options) { options = {}; } - this.options = { - startDate: moment(options.startDate || new Date()), - days: options.days || moment(options.startDate || new Date()).daysInMonth(), - rooms: options.rooms || [], - endOfWeek: options.endOfWeek || 6, - endOfWeekOffset: options.endOfWeekOffset || 0, - currencySymbol: options.currencySymbol || '€', - dateFormatLong: options.dateFormat || 'YYYY-MM-DD HH:mm:ss', - dateFormatShort: options.dateFormat || 'YYYY-MM-DD', - translations: options.translations || [] - }; - - // Check correct values - if (this.options.rooms.length > 0 && !(this.options.rooms[0] instanceof HRoomType)) { - this.options.rooms = []; - console.warn("[Hotel Calendar Management][init] Invalid Room definiton!"); - } - - // Merge Transalations - for (var key in this.options.translations) { - this._strings[key] = this.options.translations[key]; - } - - /** Internal Values **/ - this.tableCreated = false; - this._pricelist = {}; - this._restrictions = {}; - this._availability = {}; - this._copy_values = {}; - this._mode = HotelCalendarManagement.MODE.ALL; - - /***/ - if (!this._create()) { - return false; - } - - return this; -} - -HotelCalendarManagement.prototype = { - /** PUBLIC MEMBERS **/ - addEventListener: function(/*String*/event, /*Function*/callback) { - this.e.addEventListener(event, callback); - }, - - hasChangesToSave: function() { - return this.e.querySelector('.hcal-management-record-changed') !== null; - }, - - //==== CALENDAR - setStartDate: function(/*String,MomentObject*/date, /*Int?*/days) { - var curDate = this.options.startDate; - if (moment.isMoment(date)) { - this.options.startDate = date; - } else if (typeof date === 'string'){ - this.options.startDate = moment(date); - } else { - console.warn("[Hotel Calendar Management][setStartDate] Invalid date format!"); - return; - } - - if (typeof days !== 'undefined') { - this.options.days = days; - } - - /*this.e.dispatchEvent(new CustomEvent( - 'hcOnChangeDate', - {'detail': {'prevDate':curDate, 'newDate': $this.options.startDate}}));*/ - this._updateView(); - }, - - getOptions: function(/*String?*/key) { - if (typeof key !== 'undefined') { - return this.options[key]; - } - return this.options; - }, - - setMode: function(/*Int*/mode) { - if (typeof mode === 'undefined') { - mode = this._mode; - } - if (mode === HotelCalendarManagement.MODE.LOW) { - this.etable.classList.remove('hcal-management-medium'); - this.etable.classList.add('hcal-management-low'); - this.edivrhl.classList.remove('hcal-management-medium'); - this.edivrhl.classList.add('hcal-management-low'); - this._mode = HotelCalendarManagement.MODE.LOW; - } else if (mode === HotelCalendarManagement.MODE.MEDIUM) { - this.etable.classList.remove('hcal-management-low'); - this.etable.classList.add('hcal-management-medium'); - this.edivrhl.classList.remove('hcal-management-low'); - this.edivrhl.classList.add('hcal-management-medium'); - this._mode = HotelCalendarManagement.MODE.MEDIUM; - } else { - this.etable.classList.remove('hcal-management-low'); - this.etable.classList.remove('hcal-management-medium'); - this.edivrhl.classList.remove('hcal-management-low'); - this.edivrhl.classList.remove('hcal-management-medium'); - this._mode = HotelCalendarManagement.MODE.ALL; - } - }, - - - /** PRIVATE MEMBERS **/ - //==== MAIN FUNCTIONS - _create: function() { - this.e.innerHTML = ""; - if (this.tableCreated) { - console.warn("[Hotel Calendar Management] Already created!"); - return false; - } - - /** Main Table **/ - this.etable = document.createElement("table"); - this.etable.classList.add('hcal-management-table'); - this.etable.classList.add('noselect'); - this.e.appendChild(this.etable); - this._updateView(); - this.tableCreated = true; - - return true; - }, - - _generateTableDay: function(/*HTMLObject*/parentCell) { - var $this = this; - var table = document.createElement("table"); - table.classList.add('hcal-management-table-day'); - table.classList.add('noselect'); - var row = false; - var cell = false; - var telm = false; - var roomId = $this.$base.querySelector(`#${parentCell.dataset.hcalParentRow}`).dataset.hcalRoomObjId; - var room = $this.getRoom(roomId); - var dateCell = HotelCalendarManagement.toMoment(parentCell.dataset.hcalDate); - var dateShortStr = dateCell.format(HotelCalendarManagement._DATE_FORMAT_SHORT); - - row = table.insertRow(); - row.setAttribute('name', 'price'); - - cell = row.insertCell(); - cell.setAttribute('colspan', '4'); - telm = document.createElement("input"); - telm.setAttribute('id', this._sanitizeId(`PRICE_${roomId}_${dateShortStr}`)); - telm.setAttribute('name', 'price'); - telm.setAttribute('type', 'edit'); - telm.setAttribute('title', this._t('Price')); - telm.value = room.price; - telm.dataset.orgValue = room.price; - telm.dataset.hcalParentCell = parentCell.getAttribute('id'); - telm.classList.add('hcal-management-input'); - telm.addEventListener('change', function(ev){ $this.onInputChange(ev, this); }, false); - cell.appendChild(telm); - - row = table.insertRow(); - row.setAttribute('name', 'avail'); - row.style.display = 'none'; - - cell = row.insertCell(); - cell.setAttribute('colspan', '1'); - telm = document.createElement("input"); - telm.setAttribute('id', this._sanitizeId(`QUOTA_${roomId}_${dateShortStr}`)); - telm.setAttribute('name', 'quota'); - telm.setAttribute('type', 'edit'); - telm.setAttribute('title', this._t('Availability Quota')); - telm.value = telm.dataset.orgValue = 0; - telm.dataset.hcalParentCell = parentCell.getAttribute('id'); - telm.classList.add('hcal-management-input'); - telm.addEventListener('change', function(ev){ $this.onInputChange(ev, this); }, false); - cell.appendChild(telm); - - cell = row.insertCell(); - cell.setAttribute('colspan', '1'); - telm = document.createElement("input"); - telm.setAttribute('id', this._sanitizeId(`MAX_AVAIL_${roomId}_${dateShortStr}`)); - telm.setAttribute('name', 'max_avail'); - telm.setAttribute('type', 'edit'); - telm.setAttribute('title', this._t('Max. Availability')); - telm.value = telm.dataset.orgValue = 0; - telm.dataset.hcalParentCell = parentCell.getAttribute('id'); - telm.classList.add('hcal-management-input'); - telm.addEventListener('change', function(ev){ $this.onInputChange(ev, this); }, false); - cell.appendChild(telm); - - cell = row.insertCell(); - cell.setAttribute('colspan', '1'); - telm = document.createElement("input"); - telm.setAttribute('id', this._sanitizeId(`FREE_ROOMS_${roomId}_${dateShortStr}`)); - telm.setAttribute('name', 'free_rooms'); - telm.setAttribute('type', 'edit'); - telm.setAttribute('title', this._t('Free Rooms')); - telm.setAttribute('readonly', 'readonly'); - telm.setAttribute('disabled', 'disabled'); - telm.style.backgroundColor = 'lightgray'; - telm.dataset.hcalParentCell = parentCell.getAttribute('id'); - cell.appendChild(telm); - - cell = row.insertCell(); - cell.setAttribute('colspan', '1'); - telm = document.createElement("input"); - telm.setAttribute('id', this._sanitizeId(`CHANNEL_AVAIL_${roomId}_${dateShortStr}`)); - telm.setAttribute('name', 'channel_avail'); - telm.setAttribute('type', 'edit'); - telm.setAttribute('title', this._t('Channel Availability')); - telm.setAttribute('readonly', 'readonly'); - telm.setAttribute('disabled', 'disabled'); - telm.value = telm.dataset.orgValue = room.channel_avail; - telm.dataset.hcalParentCell = parentCell.getAttribute('id'); - telm.classList.add('hcal-management-input'); - cell.appendChild(telm); - - row = table.insertRow(); - row.setAttribute('name', 'rest_a'); - - cell = row.insertCell(); - telm = document.createElement("input"); - telm.setAttribute('id', this._sanitizeId(`MIN_STAY_${roomId}_${dateShortStr}`)); - telm.setAttribute('name', 'min_stay'); - telm.setAttribute('type', 'edit'); - telm.setAttribute('title', this._t('Min. Stay')); - telm.dataset.orgValue = telm.value = 0; - telm.dataset.hcalParentCell = parentCell.getAttribute('id'); - telm.classList.add('hcal-management-input'); - telm.classList.add('hcal-border-radius-left'); - telm.addEventListener('change', function(ev){ $this.onInputChange(ev, this); }, false); - cell.appendChild(telm); - - cell = row.insertCell(); - telm = document.createElement("input"); - telm.setAttribute('id', this._sanitizeId(`MAX_STAY_${roomId}_${dateShortStr}`)); - telm.setAttribute('name', 'max_stay'); - telm.setAttribute('type', 'edit'); - telm.setAttribute('title', this._t('Max. Stay')); - telm.dataset.orgValue = telm.value = 0; - telm.dataset.hcalParentCell = parentCell.getAttribute('id'); - telm.classList.add('hcal-management-input'); - telm.classList.add('hcal-border-radius-right'); - telm.addEventListener('change', function(ev){ $this.onInputChange(ev, this); }, false); - cell.appendChild(telm); - - cell = row.insertCell(); - telm = document.createElement("input"); - telm.setAttribute('id', this._sanitizeId(`MIN_STAY_ARRIVAL_${roomId}_${dateShortStr}`)); - telm.setAttribute('name', 'min_stay_arrival'); - telm.setAttribute('type', 'edit'); - telm.setAttribute('title', this._t('Min. Stay Arrival')); - telm.dataset.orgValue = telm.value = 0; - telm.dataset.hcalParentCell = parentCell.getAttribute('id'); - telm.classList.add('hcal-management-input'); - telm.classList.add('hcal-border-radius-left'); - telm.addEventListener('change', function(ev){ $this.onInputChange(ev, this); }, false); - cell.appendChild(telm); - - cell = row.insertCell(); - telm = document.createElement("input"); - telm.setAttribute('id', this._sanitizeId(`MAX_STAY_ARRIVAL_${roomId}_${dateShortStr}`)); - telm.setAttribute('name', 'max_stay_arrival'); - telm.setAttribute('type', 'edit'); - telm.setAttribute('title', this._t('Max. Stay Arrival')); - telm.dataset.orgValue = telm.value = 0; - telm.dataset.hcalParentCell = parentCell.getAttribute('id'); - telm.classList.add('hcal-management-input'); - telm.classList.add('hcal-border-radius-right'); - telm.addEventListener('change', function(ev){ $this.onInputChange(ev, this); }, false); - cell.appendChild(telm); - - row = table.insertRow(); - row.setAttribute('name', 'rest_b'); - cell = row.insertCell(); - cell.setAttribute('colspan', '3'); - telm = document.createElement("select"); - telm.classList.add('hcal-management-input'); - telm.addEventListener('change', function(ev){ $this.onInputChange(ev, this); }, false); - telm.setAttribute('id', this._sanitizeId(`CLOUSURE_${roomId}_${dateShortStr}`)); - telm.setAttribute('name', 'clousure'); - telm.setAttribute('title', this._t('Closure')); - telm.dataset.orgValue = 'open'; - telm.dataset.hcalParentCell = parentCell.getAttribute('id'); - var selectOpt = document.createElement("option"); - selectOpt.value = "open"; - selectOpt.textContent = this._t("Open"); - telm.appendChild(selectOpt); - selectOpt = document.createElement("option"); - selectOpt.value = "closed"; - selectOpt.textContent = this._t("Closed"); - telm.appendChild(selectOpt); - selectOpt = document.createElement("option"); - selectOpt.value = "closed_departure"; - selectOpt.textContent = this._t("C. Departure"); - telm.appendChild(selectOpt); - selectOpt = document.createElement("option"); - selectOpt.value = "closed_arrival"; - selectOpt.textContent = this._t("C. Arrival"); - telm.appendChild(selectOpt); - cell.appendChild(telm); - - row = table.insertRow(); - row.setAttribute('name', 'rest_c'); - - cell = row.insertCell(); - cell.style.textAlign = 'center'; - cell.setAttribute('colspan', '4'); - telm = document.createElement("button"); - telm.setAttribute('id', this._sanitizeId(`NO_OTA_${roomId}_${dateShortStr}`)); - telm.setAttribute('name', 'no_ota'); - telm.setAttribute('title', this._t('No OTA')); - telm.innerHTML = "No OTA"; - telm.dataset.orgValue = telm.dataset.state = 'false'; - telm.dataset.hcalParentCell = parentCell.getAttribute('id'); - telm.classList.add('hcal-management-input', 'pull-left'); - telm.addEventListener('click', function(ev){ $this.onInputChange(ev, this); }, false); - cell.appendChild(telm); - telm = document.createElement("span"); - telm.setAttribute('id', this._sanitizeId(`OPTIONS_${roomId}_${dateShortStr}`)); - telm.setAttribute('name', 'options'); - telm.setAttribute('title', this._t('Options')); - telm.classList.add('dropdown', 'pull-right', 'hcal-management-record-options'); - telm.innerHTML = ` - - `; - telm.dataset.hcalParentCell = parentCell.getAttribute('id'); - cell.appendChild(telm); - - cell.querySelector('.hcal-record-option-clone').addEventListener('click', function(ev){ $this.onOptionsRecord(ev, this); }, false); - cell.querySelector('.hcal-record-option-reset').addEventListener('click', function(ev){ $this.onOptionsRecord(ev, this); }, false); - cell.querySelector('.hcal-record-option-copy').addEventListener('click', function(ev){ $this.onOptionsRecord(ev, this); }, false); - cell.querySelector('.hcal-record-option-paste').addEventListener('click', function(ev){ $this.onOptionsRecord(ev, this); }, false); - - - parentCell.appendChild(table); - - return table; - }, - - _getCell: function(/*HRoomObject*/room, /*DateTimeObject*/sdate) { - return this.e.querySelector(`#${this._sanitizeId(`${room.name}_${room.id}_${sdate.format(HotelCalendarManagement._DATE_FORMAT_SHORT)}`)}`); - }, - - setData: function(prices, restrictions, avail, count_free_rooms) { - //this._updateView(); - if (typeof prices !== 'undefined' && prices) { - this._pricelist = prices; - this._updatePriceList(); - } - if (typeof restrictions !== 'undefined' && restrictions) { - this._restrictions = restrictions; - this._updateRestrictions(); - } - if (typeof avail !== 'undefined' && avail) { - this.setAvailability(avail); - } - if (typeof count_free_rooms !== 'undefined' && count_free_rooms) { - this._free_rooms = count_free_rooms; - this._updateNumFreeRooms(); - } - }, - - setAvailability: function(avails) { - this._availability = avails; - if (this._availability) { - for (var elm of this.etable.querySelectorAll("tr[name=avail]")) { - elm.style.display = ""; - } - } - this._updateAvailability(); - }, - - //==== ROOMS - getRoom: function(/*String*/id) { - return _.find(this.options.rooms, function(item){ return item.id == id; }); - }, - - //==== RENDER FUNCTIONS - _create_table_data_days: function() { - var $this = this; - while (this.e.hasChildNodes()) { - this.e.removeChild(this.e.lastChild); - } - - // RoomType Names - this.edivrhl = document.createElement("div"); - this.edivrhl.classList.add('table-room_types'); - this.e.appendChild(this.edivrhl); - this.etableRooms = document.createElement("table"); - this.etableRooms.classList.add('hcal-management-table'); - this.etableRooms.classList.add('noselect'); - this.edivrhl.appendChild(this.etableRooms); - - // Container: Days + Data - this.edivm = document.createElement("div"); - this.edivm.setAttribute('id', 'hcal-management-container-dd'); - this.e.appendChild(this.edivm); - // Days - this.edivrh = document.createElement("div"); - this.edivrh.classList.add('table-room_type-data-header'); - this.edivm.appendChild(this.edivrh); - this.etableHeader = document.createElement("table"); - this.etableHeader.classList.add('hcal-management-table'); - this.etableHeader.classList.add('noselect'); - this.edivrh.appendChild(this.etableHeader); - // Data - this.edivr = document.createElement("div"); - this.edivr.classList.add('table-room_type-data'); - this.edivm.appendChild(this.edivr); - this.etable = document.createElement("table"); - this.etable.classList.add('hcal-management-table'); - this.etable.classList.add('noselect'); - this.edivr.appendChild(this.etable); - - /** TABLE HEADER **/ - var thead = this.etableHeader.createTHead(); - - // Render Next Days - var row = thead.insertRow(); - var now = moment().local(); - for (var i=0; i<=this.options.days; i++) { - var dd = this.options.startDate.clone().add(i,'d'); - var dd_local = dd.clone().local(); - var cell = row.insertCell(); - cell.setAttribute('id', this._sanitizeId(`hday_${dd.format(HotelCalendarManagement._DATE_FORMAT_SHORT)}`)); - cell.classList.add('hcal-cell-header-day'); - cell.classList.add('btn-hcal'); - cell.classList.add('btn-hcal-3d'); - cell.dataset.hcalDate = dd.format(HotelCalendarManagement._DATE_FORMAT_SHORT); - cell.textContent = dd.format('D') + ' ' + dd.format('ddd') + ' (' + dd.format('MMM') + "'" + dd.format('YY') + ')'; - cell.setAttribute('title', dd.format('dddd')) - var day = +dd_local.format('D'); - if (day == 1) { - cell.classList.add('hcal-cell-start-month'); - } - if (dd_local.isSame(now, 'day')) { - cell.classList.add('hcal-cell-current-day'); - } else if (dd_local.format('e') >= this.options.endOfWeek-this.options.endOfWeekOffset && dd_local.format('e') <= this.options.endOfWeek) { - cell.classList.add('hcal-cell-end-week'); - } - } - - /** ROOM LINES **/ - var tbody = document.createElement("tbody"); - this.etableRooms.appendChild(tbody); - this.options.rooms.forEach(function(itemRoom, indexRoom){ - row = tbody.insertRow(); - cell = row.insertCell(); - cell.textContent = itemRoom.name; - cell.setAttribute('colspan', 2); - cell.classList.add('hcal-cell-room-type-group-item'); - cell.classList.add('btn-hcal'); - cell.classList.add('btn-hcal-3d'); - }); - - /** ROOM DATA LINES **/ - var tbody = document.createElement("tbody"); - this.etable.appendChild(tbody); - this.options.rooms.forEach(function(itemRoom, indexRoom){ - // Room Number - row = tbody.insertRow(); - row.setAttribute('id', $this._sanitizeId(`ROW_${itemRoom.name}_${itemRoom.id}`)); - row.dataset.hcalRoomObjId = itemRoom.id; - row.classList.add('hcal-row-room-type-group-item'); - for (var i=0; i<=$this.options.days; i++) { - var dd = $this.options.startDate.clone().add(i,'d'); - var dd_local = dd.clone().local(); - cell = row.insertCell(); - cell.setAttribute('id', $this._sanitizeId(`${itemRoom.name}_${itemRoom.id}_${dd.format(HotelCalendarManagement._DATE_FORMAT_SHORT)}`)); - cell.classList.add('hcal-cell-room-type-group-item-day'); - cell.dataset.hcalParentRow = row.getAttribute('id'); - cell.dataset.hcalDate = dd.format(HotelCalendarManagement._DATE_FORMAT_SHORT); - // Generate Interactive Table - cell.appendChild($this._generateTableDay(cell)); - //cell.innerHTML = dd.format("DD"); - var day = +dd_local.format("D"); - if (day == 1) { - cell.classList.add('hcal-cell-start-month'); - } - if (dd_local.isSame(now, 'day')) { - cell.classList.add('hcal-cell-current-day'); - } else if (dd_local.format('e') >= $this.options.endOfWeek-$this.options.endOfWeekOffset && dd_local.format('e') <= $this.options.endOfWeek) { - cell.classList.add('hcal-cell-end-week'); - } - } - }); - }, - - //==== PRICELIST - addPricelist: function(/*Object*/pricelist) { - var room_type_ids = Object.keys(pricelist); - for (var vid of room_type_ids) { - if (vid in this._pricelist) { - for (var price of pricelist[vid]) { - var index = _.findIndex(this._pricelist[vid], {date: price['date']}); - if (index >= 0) { - this._pricelist[vid][index] = price; - } else { - this._pricelist[vid].push(price); - } - } - } - else { - this._pricelist[vid] = pricelist[vid]; - } - } - this._updatePriceList(); - }, - - _updatePriceList: function() { - var keys = Object.keys(this._pricelist); - for (var room_typeId of keys) { - for (var price of this._pricelist[room_typeId]) { - var dd = HotelCalendarManagement.toMoment(price.date, this.options.dateFormatShort); - var inputId = this._sanitizeId(`PRICE_${room_typeId}_${dd.format(HotelCalendarManagement._DATE_FORMAT_SHORT)}`); - var input = this.etable.querySelector(`#${inputId}`); - if (input && !input.classList.contains('hcal-management-input-changed')) { - input.dataset.orgValue = price.price; - input.value = price.price; - } - } - } - }, - - getPricelist: function(onlyNew) { - var data = {}; - for (var room of this.options.rooms) { - for (var i=0; i<=this.options.days; i++) { - var ndate = this.options.startDate.clone().add(i, 'd'); - var ndateStr = ndate.format(HotelCalendarManagement._DATE_FORMAT_SHORT); - var inputId = this._sanitizeId(`PRICE_${room.id}_${ndateStr}`); - var input = this.etable.querySelector(`#${inputId}`); - if (!onlyNew || (onlyNew && input.value !== input.dataset.orgValue)) { - if (!(room.id in data)) { data[room.id] = []; } - data[room.id].push({ - 'date': ndate.format('YYYY-MM-DD'), - 'price': input.value - }); - } - } - } - return data; - }, - - //==== RESTRICTIONS - addRestrictions: function(/*Object*/restrictions) { - var room_type_ids = Object.keys(restrictions); - for (var vid of room_type_ids) { - if (vid in this._restrictions) { - for (var rest of restrictions[vid]) { - var index = _.findIndex(this._restrictions[vid], {date: rest['date']}); - if (index >= 0) { - this._restrictions[vid][index] = rest; - } else { - this._restrictions[vid].push(rest); - } - } - } - else { - this._restrictions[vid] = restrictions[vid]; - } - } - this._updateRestrictions(); - }, - - _updateRestrictions: function() { - var keys = Object.keys(this._restrictions); - for (var room_typeId of keys) { - var room = this.getRoom(room_typeId); - for (var restriction of this._restrictions[room_typeId]) { - var dd = HotelCalendarManagement.toMoment(restriction.date, this.options.dateFormatShort); - var inputIds = [ - this._sanitizeId(`MIN_STAY_${room_typeId}_${dd.format(HotelCalendarManagement._DATE_FORMAT_SHORT)}`), restriction.min_stay, - this._sanitizeId(`MIN_STAY_ARRIVAL_${room_typeId}_${dd.format(HotelCalendarManagement._DATE_FORMAT_SHORT)}`), restriction.min_stay_arrival, - this._sanitizeId(`MAX_STAY_${room_typeId}_${dd.format(HotelCalendarManagement._DATE_FORMAT_SHORT)}`), restriction.max_stay, - this._sanitizeId(`MAX_STAY_ARRIVAL_${room_typeId}_${dd.format(HotelCalendarManagement._DATE_FORMAT_SHORT)}`), restriction.max_stay_arrival, - ]; - for (var i=0; i= 0) { - this._availability[vid][index] = avail; - } else { - this._availability[vid].push(avail); - } - } - } - else { - this._availability[vid] = availability[vid]; - } - } - this._updateAvailability(); - }, - - _updateAvailability: function() { - var keys = Object.keys(this._availability); - for (var room_typeId of keys) { - for (var avail of this._availability[room_typeId]) { - var dd = HotelCalendarManagement.toMoment(avail.date, this.options.dateFormatShort); - var inputIds = [ - `QUOTA_${room_typeId}_${dd.format(HotelCalendarManagement._DATE_FORMAT_SHORT)}`, avail.quota, - `MAX_AVAIL_${room_typeId}_${dd.format(HotelCalendarManagement._DATE_FORMAT_SHORT)}`, avail.max_avail, - `CHANNEL_AVAIL_${room_typeId}_${dd.format(HotelCalendarManagement._DATE_FORMAT_SHORT)}`, avail.channel_avail, - `NO_OTA_${room_typeId}_${dd.format(HotelCalendarManagement._DATE_FORMAT_SHORT)}`, avail.no_ota - ]; - for (var i=0; i - - - -
      - Price: ${copy_values['price']}
      - Availability: ${copy_values['avail']}
      - Min. Stay: ${copy_values['min_stay']}
      - Max. Stay: ${copy_values['max_stay']}
      - Min. Stay Arrival: ${copy_values['min_stay_arrival']}
      - Max. Stay Arrival: ${copy_values['max_stay_arrival']}
      - Clousure: ${copy_values['clousure']}
      - No OTA: ${copy_values['no_ota']}
      -
      - - - - - FROM
      -
      - - - - -
      - - - TO
      -
      - - - - -
      - - - - - - - - - - `, - buttons: { - confirm : { - label: $this._t('Clone'), - className: "btn-success", - callback: function() { - var date_begin = $('table#hcal-management-clone-dates #date_begin').data("DateTimePicker").getDate().set({'hour': 0, 'minute': 0, 'second': 0}).clone(); - var date_end = $('table#hcal-management-clone-dates #date_end').data("DateTimePicker").getDate().set({'hour': 0, 'minute': 0, 'second': 0}).clone(); - var diff_days = $this.getDateDiffDays(date_begin, date_end) + 1; - var same_day = $('table#hcal-management-clone-dates #same_day').is(':checked'); - var cell_date = HotelCalendarManagement.toMoment(parentCell.dataset.hcalDate); - - var ndate = date_begin.clone(); - for (var i=0; i0)for(c in rd)d=rd[c],e=b[d],p(e)||(a[d]=e);return a} -// Moment prototype object -function r(b){q(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),this.isValid()||(this._d=new Date(NaN)), -// Prevent infinite loop in case updateOffset creates new moment -// objects. -sd===!1&&(sd=!0,a.updateOffset(this),sd=!1)}function s(a){return a instanceof r||null!=a&&null!=a._isAMomentObject}function t(a){return a<0?Math.ceil(a)||0:Math.floor(a)}function u(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=t(b)),c} -// compare two arrays, return the number of differences -function v(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;d0?"future":"past"];return z(c)?c(b):c.replace(/%s/i,b)}function J(a,b){var c=a.toLowerCase();Dd[c]=Dd[c+"s"]=Dd[b]=a}function K(a){return"string"==typeof a?Dd[a]||Dd[a.toLowerCase()]:void 0}function L(a){var b,c,d={};for(c in a)i(a,c)&&(b=K(c),b&&(d[b]=a[c]));return d}function M(a,b){Ed[a]=b}function N(a){var b=[];for(var c in a)b.push({unit:c,priority:Ed[c]});return b.sort(function(a,b){return a.priority-b.priority}),b}function O(b,c){return function(d){return null!=d?(Q(this,b,d),a.updateOffset(this,c),this):P(this,b)}}function P(a,b){return a.isValid()?a._d["get"+(a._isUTC?"UTC":"")+b]():NaN}function Q(a,b,c){a.isValid()&&a._d["set"+(a._isUTC?"UTC":"")+b](c)} -// MOMENTS -function R(a){return a=K(a),z(this[a])?this[a]():this}function S(a,b){if("object"==typeof a){a=L(a);for(var c=N(a),d=0;d=0;return(f?c?"+":"":"-")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d} -// token: 'M' -// padded: ['MM', 2] -// ordinal: 'Mo' -// callback: function () { this.month() + 1 } -function U(a,b,c,d){var e=d;"string"==typeof d&&(e=function(){return this[d]()}),a&&(Id[a]=e),b&&(Id[b[0]]=function(){return T(e.apply(this,arguments),b[1],b[2])}),c&&(Id[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function V(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function W(a){var b,c,d=a.match(Fd);for(b=0,c=d.length;b=0&&Gd.test(a);)a=a.replace(Gd,c),Gd.lastIndex=0,d-=1;return a}function Z(a,b,c){$d[a]=z(b)?b:function(a,d){return a&&c?c:b}}function $(a,b){return i($d,a)?$d[a](b._strict,b._locale):new RegExp(_(a))} -// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript -function _(a){return aa(a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}))}function aa(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function ba(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),f(b)&&(d=function(a,c){c[b]=u(a)}),c=0;c=0&&isFinite(h.getFullYear())&&h.setFullYear(a),h}function ta(a){var b=new Date(Date.UTC.apply(null,arguments)); -//the Date.UTC function remaps years 0-99 to 1900-1999 -return a<100&&a>=0&&isFinite(b.getUTCFullYear())&&b.setUTCFullYear(a),b} -// start-of-first-week - start-of-year -function ua(a,b,c){var// first-week day -- which january is always in the first week (4 for iso, 1 for other) -d=7+b-c, -// first-week day local weekday -- which local weekday is fwd -e=(7+ta(a,0,d).getUTCDay()-b)%7;return-e+d-1} -//http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday -function va(a,b,c,d,e){var f,g,h=(7+c-d)%7,i=ua(a,d,e),j=1+7*(b-1)+h+i;return j<=0?(f=a-1,g=pa(f)+j):j>pa(a)?(f=a+1,g=j-pa(a)):(f=a,g=j),{year:f,dayOfYear:g}}function wa(a,b,c){var d,e,f=ua(a.year(),b,c),g=Math.floor((a.dayOfYear()-f-1)/7)+1;return g<1?(e=a.year()-1,d=g+xa(e,b,c)):g>xa(a.year(),b,c)?(d=g-xa(a.year(),b,c),e=a.year()+1):(e=a.year(),d=g),{week:d,year:e}}function xa(a,b,c){var d=ua(a,b,c),e=ua(a+1,b,c);return(pa(a)-d+e)/7} -// HELPERS -// LOCALES -function ya(a){return wa(a,this._week.dow,this._week.doy).week}function za(){return this._week.dow}function Aa(){return this._week.doy} -// MOMENTS -function Ba(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function Ca(a){var b=wa(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")} -// HELPERS -function Da(a,b){return"string"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),"number"==typeof a?a:null):parseInt(a,10)}function Ea(a,b){return"string"==typeof a?b.weekdaysParse(a)%7||7:isNaN(a)?null:a}function Fa(a,b){return a?c(this._weekdays)?this._weekdays[a.day()]:this._weekdays[this._weekdays.isFormat.test(b)?"format":"standalone"][a.day()]:this._weekdays}function Ga(a){return a?this._weekdaysShort[a.day()]:this._weekdaysShort}function Ha(a){return a?this._weekdaysMin[a.day()]:this._weekdaysMin}function Ia(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],d=0;d<7;++d)f=k([2e3,1]).day(d),this._minWeekdaysParse[d]=this.weekdaysMin(f,"").toLocaleLowerCase(),this._shortWeekdaysParse[d]=this.weekdaysShort(f,"").toLocaleLowerCase(),this._weekdaysParse[d]=this.weekdays(f,"").toLocaleLowerCase();return c?"dddd"===b?(e=je.call(this._weekdaysParse,g),e!==-1?e:null):"ddd"===b?(e=je.call(this._shortWeekdaysParse,g),e!==-1?e:null):(e=je.call(this._minWeekdaysParse,g),e!==-1?e:null):"dddd"===b?(e=je.call(this._weekdaysParse,g),e!==-1?e:(e=je.call(this._shortWeekdaysParse,g),e!==-1?e:(e=je.call(this._minWeekdaysParse,g),e!==-1?e:null))):"ddd"===b?(e=je.call(this._shortWeekdaysParse,g),e!==-1?e:(e=je.call(this._weekdaysParse,g),e!==-1?e:(e=je.call(this._minWeekdaysParse,g),e!==-1?e:null))):(e=je.call(this._minWeekdaysParse,g),e!==-1?e:(e=je.call(this._weekdaysParse,g),e!==-1?e:(e=je.call(this._shortWeekdaysParse,g),e!==-1?e:null)))}function Ja(a,b,c){var d,e,f;if(this._weekdaysParseExact)return Ia.call(this,a,b,c);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),d=0;d<7;d++){ -// test the regex -if( -// make the regex if we don't have it already -e=k([2e3,1]).day(d),c&&!this._fullWeekdaysParse[d]&&(this._fullWeekdaysParse[d]=new RegExp("^"+this.weekdays(e,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[d]=new RegExp("^"+this.weekdaysShort(e,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[d]=new RegExp("^"+this.weekdaysMin(e,"").replace(".",".?")+"$","i")),this._weekdaysParse[d]||(f="^"+this.weekdays(e,"")+"|^"+this.weekdaysShort(e,"")+"|^"+this.weekdaysMin(e,""),this._weekdaysParse[d]=new RegExp(f.replace(".",""),"i")),c&&"dddd"===b&&this._fullWeekdaysParse[d].test(a))return d;if(c&&"ddd"===b&&this._shortWeekdaysParse[d].test(a))return d;if(c&&"dd"===b&&this._minWeekdaysParse[d].test(a))return d;if(!c&&this._weekdaysParse[d].test(a))return d}} -// MOMENTS -function Ka(a){if(!this.isValid())return null!=a?this:NaN;var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Da(a,this.localeData()),this.add(a-b,"d")):b}function La(a){if(!this.isValid())return null!=a?this:NaN;var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function Ma(a){if(!this.isValid())return null!=a?this:NaN; -// behaves the same as moment#day except -// as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) -// as a setter, sunday should belong to the previous week. -if(null!=a){var b=Ea(a,this.localeData());return this.day(this.day()%7?b:b-7)}return this.day()||7}function Na(a){return this._weekdaysParseExact?(i(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysStrictRegex:this._weekdaysRegex):(i(this,"_weekdaysRegex")||(this._weekdaysRegex=ue),this._weekdaysStrictRegex&&a?this._weekdaysStrictRegex:this._weekdaysRegex)}function Oa(a){return this._weekdaysParseExact?(i(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(i(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=ve),this._weekdaysShortStrictRegex&&a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Pa(a){return this._weekdaysParseExact?(i(this,"_weekdaysRegex")||Qa.call(this),a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(i(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=we),this._weekdaysMinStrictRegex&&a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function Qa(){function a(a,b){return b.length-a.length}var b,c,d,e,f,g=[],h=[],i=[],j=[];for(b=0;b<7;b++) -// make the regex if we don't have it already -c=k([2e3,1]).day(b),d=this.weekdaysMin(c,""),e=this.weekdaysShort(c,""),f=this.weekdays(c,""),g.push(d),h.push(e),i.push(f),j.push(d),j.push(e),j.push(f);for( -// Sorting makes sure if one weekday (or abbr) is a prefix of another it -// will match the longer piece. -g.sort(a),h.sort(a),i.sort(a),j.sort(a),b=0;b<7;b++)h[b]=aa(h[b]),i[b]=aa(i[b]),j[b]=aa(j[b]);this._weekdaysRegex=new RegExp("^("+j.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+i.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+h.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+g.join("|")+")","i")} -// FORMATTING -function Ra(){return this.hours()%12||12}function Sa(){return this.hours()||24}function Ta(a,b){U(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})} -// PARSING -function Ua(a,b){return b._meridiemParse} -// LOCALES -function Va(a){ -// IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays -// Using charAt should be more compatible. -return"p"===(a+"").toLowerCase().charAt(0)}function Wa(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Xa(a){return a?a.toLowerCase().replace("_","-"):a} -// pick the locale from the array -// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each -// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root -function Ya(a){for(var b,c,d,e,f=0;f0;){if(d=Za(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&v(e,c,!0)>=b-1) -//the next array item is better than a shallower substring of this one -break;b--}f++}return null}function Za(a){var b=null; -// TODO: Find a better way to register and load all the locales in Node -if(!Be[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=xe._abbr,require("./locale/"+a), -// because defineLocale currently also sets the global locale, we -// want to undo that for lazy loaded locales -$a(b)}catch(a){}return Be[a]} -// This function will load locale and then set the global locale. If -// no arguments are passed in, it will simply return the current global -// locale key. -function $a(a,b){var c; -// moment.duration._locale = moment._locale = data; -return a&&(c=p(b)?bb(a):_a(a,b),c&&(xe=c)),xe._abbr}function _a(a,b){if(null!==b){var c=Ae;if(b.abbr=a,null!=Be[a])y("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),c=Be[a]._config;else if(null!=b.parentLocale){if(null==Be[b.parentLocale])return Ce[b.parentLocale]||(Ce[b.parentLocale]=[]),Ce[b.parentLocale].push({name:a,config:b}),null;c=Be[b.parentLocale]._config} -// backwards compat for now: also set the locale -// make sure we set the locale AFTER all child locales have been -// created, so we won't end up with the child locale set. -return Be[a]=new C(B(c,b)),Ce[a]&&Ce[a].forEach(function(a){_a(a.name,a.config)}),$a(a),Be[a]} -// useful for testing -return delete Be[a],null}function ab(a,b){if(null!=b){var c,d=Ae; -// MERGE -null!=Be[a]&&(d=Be[a]._config),b=B(d,b),c=new C(b),c.parentLocale=Be[a],Be[a]=c, -// backwards compat for now: also set the locale -$a(a)}else -// pass null for config to unupdate, useful for tests -null!=Be[a]&&(null!=Be[a].parentLocale?Be[a]=Be[a].parentLocale:null!=Be[a]&&delete Be[a]);return Be[a]} -// returns locale data -function bb(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return xe;if(!c(a)){if( -//short-circuit everything else -b=Za(a))return b;a=[a]}return Ya(a)}function cb(){return wd(Be)}function db(a){var b,c=a._a;return c&&m(a).overflow===-2&&(b=c[be]<0||c[be]>11?be:c[ce]<1||c[ce]>ea(c[ae],c[be])?ce:c[de]<0||c[de]>24||24===c[de]&&(0!==c[ee]||0!==c[fe]||0!==c[ge])?de:c[ee]<0||c[ee]>59?ee:c[fe]<0||c[fe]>59?fe:c[ge]<0||c[ge]>999?ge:-1,m(a)._overflowDayOfYear&&(bce)&&(b=ce),m(a)._overflowWeeks&&b===-1&&(b=he),m(a)._overflowWeekday&&b===-1&&(b=ie),m(a).overflow=b),a} -// date from iso format -function eb(a){var b,c,d,e,f,g,h=a._i,i=De.exec(h)||Ee.exec(h);if(i){for(m(a).iso=!0,b=0,c=Ge.length;bpa(e)&&(m(a)._overflowDayOfYear=!0),c=ta(e,0,a._dayOfYear),a._a[be]=c.getUTCMonth(),a._a[ce]=c.getUTCDate()),b=0;b<3&&null==a._a[b];++b)a._a[b]=f[b]=d[b]; -// Zero out whatever was not defaulted, including time -for(;b<7;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b]; -// Check for 24:00:00.000 -24===a._a[de]&&0===a._a[ee]&&0===a._a[fe]&&0===a._a[ge]&&(a._nextDay=!0,a._a[de]=0),a._d=(a._useUTC?ta:sa).apply(null,f), -// Apply timezone offset from input. The actual utcOffset can be changed -// with parseZone. -null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[de]=24)}}function jb(a){var b,c,d,e,f,g,h,i;if(b=a._w,null!=b.GG||null!=b.W||null!=b.E)f=1,g=4, -// TODO: We need to take the current isoWeekYear, but that depends on -// how we interpret now (local, utc, fixed offset). So create -// a now version of current config (take local/utc/offset flags, and -// create now). -c=gb(b.GG,a._a[ae],wa(sb(),1,4).year),d=gb(b.W,1),e=gb(b.E,1),(e<1||e>7)&&(i=!0);else{f=a._locale._week.dow,g=a._locale._week.doy;var j=wa(sb(),f,g);c=gb(b.gg,a._a[ae],j.year), -// Default to current week. -d=gb(b.w,j.week),null!=b.d?( -// weekday -- low day numbers are considered next week -e=b.d,(e<0||e>6)&&(i=!0)):null!=b.e?( -// local weekday -- counting starts from begining of week -e=b.e+f,(b.e<0||b.e>6)&&(i=!0)): -// default to begining of week -e=f}d<1||d>xa(c,f,g)?m(a)._overflowWeeks=!0:null!=i?m(a)._overflowWeekday=!0:(h=va(c,d,e,f,g),a._a[ae]=h.year,a._dayOfYear=h.dayOfYear)} -// date from string and format string -function kb(b){ -// TODO: Move this to another part of the creation flow to prevent circular deps -if(b._f===a.ISO_8601)return void eb(b);b._a=[],m(b).empty=!0; -// This array is used to make a Date, either with `new Date` or `Date.UTC` -var c,d,e,f,g,h=""+b._i,i=h.length,j=0;for(e=Y(b._f,b._locale).match(Fd)||[],c=0;c0&&m(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length), -// don't parse if it's not a known token -Id[f]?(d?m(b).empty=!1:m(b).unusedTokens.push(f),da(f,d,b)):b._strict&&!d&&m(b).unusedTokens.push(f); -// add remaining unparsed input length to the string -m(b).charsLeftOver=i-j,h.length>0&&m(b).unusedInput.push(h), -// clear _12h flag if hour is <= 12 -b._a[de]<=12&&m(b).bigHour===!0&&b._a[de]>0&&(m(b).bigHour=void 0),m(b).parsedDateParts=b._a.slice(0),m(b).meridiem=b._meridiem, -// handle meridiem -b._a[de]=lb(b._locale,b._a[de],b._meridiem),ib(b),db(b)}function lb(a,b,c){var d; -// Fallback -return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&b<12&&(b+=12),d||12!==b||(b=0),b):b} -// date from string and array of format strings -function mb(a){var b,c,d,e,f;if(0===a._f.length)return m(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;e -// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset -// +0200, so we adjust the time as needed, to be valid. -// -// Keeping the time actually adds/subtracts (one hour) -// from the actual represented time. That is why we call updateOffset -// a second time. In case it wants us to change the offset again -// _changeInProgress == true case, then we have to adjust, because -// there is no such time in the given timezone. -function Db(b,c){var d,e=this._offset||0;if(!this.isValid())return null!=b?this:NaN;if(null!=b){if("string"==typeof b){if(b=Ab(Xd,b),null===b)return this}else Math.abs(b)<16&&(b=60*b);return!this._isUTC&&c&&(d=Cb(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?Tb(this,Ob(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this}return this._isUTC?e:Cb(this)}function Eb(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Fb(a){return this.utcOffset(0,a)}function Gb(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Cb(this),"m")),this}function Hb(){if(null!=this._tzm)this.utcOffset(this._tzm);else if("string"==typeof this._i){var a=Ab(Wd,this._i);null!=a?this.utcOffset(a):this.utcOffset(0,!0)}return this}function Ib(a){return!!this.isValid()&&(a=a?sb(a).utcOffset():0,(this.utcOffset()-a)%60===0)}function Jb(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Kb(){if(!p(this._isDSTShifted))return this._isDSTShifted;var a={};if(q(a,this),a=pb(a),a._a){var b=a._isUTC?k(a._a):sb(a._a);this._isDSTShifted=this.isValid()&&v(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Lb(){return!!this.isValid()&&!this._isUTC}function Mb(){return!!this.isValid()&&this._isUTC}function Nb(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function Ob(a,b){var c,d,e,g=a, -// matching against regexp is expensive, do it on demand -h=null;// checks for null or undefined -return xb(a)?g={ms:a._milliseconds,d:a._days,M:a._months}:f(a)?(g={},b?g[b]=a:g.milliseconds=a):(h=Ne.exec(a))?(c="-"===h[1]?-1:1,g={y:0,d:u(h[ce])*c,h:u(h[de])*c,m:u(h[ee])*c,s:u(h[fe])*c,ms:u(yb(1e3*h[ge]))*c}):(h=Oe.exec(a))?(c="-"===h[1]?-1:1,g={y:Pb(h[2],c),M:Pb(h[3],c),w:Pb(h[4],c),d:Pb(h[5],c),h:Pb(h[6],c),m:Pb(h[7],c),s:Pb(h[8],c)}):null==g?g={}:"object"==typeof g&&("from"in g||"to"in g)&&(e=Rb(sb(g.from),sb(g.to)),g={},g.ms=e.milliseconds,g.M=e.months),d=new wb(g),xb(a)&&i(a,"_locale")&&(d._locale=a._locale),d}function Pb(a,b){ -// We'd normally use ~~inp for this, but unfortunately it also -// converts floats to ints. -// inp may be undefined, so careful calling replace on it. -var c=a&&parseFloat(a.replace(",",".")); -// apply sign while we're at it -return(isNaN(c)?0:c)*b}function Qb(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function Rb(a,b){var c;return a.isValid()&&b.isValid()?(b=Bb(b,a),a.isBefore(b)?c=Qb(a,b):(c=Qb(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c):{milliseconds:0,months:0}} -// TODO: remove 'name' arg after deprecation is removed -function Sb(a,b){return function(c,d){var e,f; -//invert the arguments, but complain about it -return null===d||isNaN(+d)||(y(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Ob(c,d),Tb(this,e,a),this}}function Tb(b,c,d,e){var f=c._milliseconds,g=yb(c._days),h=yb(c._months);b.isValid()&&(e=null==e||e,f&&b._d.setTime(b._d.valueOf()+f*d),g&&Q(b,"Date",P(b,"Date")+g*d),h&&ja(b,P(b,"Month")+h*d),e&&a.updateOffset(b,g||h))}function Ub(a,b){var c=a.diff(b,"days",!0);return c<-6?"sameElse":c<-1?"lastWeek":c<0?"lastDay":c<1?"sameDay":c<2?"nextDay":c<7?"nextWeek":"sameElse"}function Vb(b,c){ -// We want to compare the start of today, vs this. -// Getting start-of-today depends on whether we're local/utc/offset or not. -var d=b||sb(),e=Bb(d,this).startOf("day"),f=a.calendarFormat(this,e)||"sameElse",g=c&&(z(c[f])?c[f].call(this,d):c[f]);return this.format(g||this.localeData().calendar(f,this,sb(d)))}function Wb(){return new r(this)}function Xb(a,b){var c=s(a)?a:sb(a);return!(!this.isValid()||!c.isValid())&&(b=K(p(b)?"millisecond":b),"millisecond"===b?this.valueOf()>c.valueOf():c.valueOf()f&&(b=f),Fc.call(this,a,b,c,d,e))}function Fc(a,b,c,d,e){var f=va(a,b,c,d,e),g=ta(f.year,0,f.dayOfYear);return this.year(g.getUTCFullYear()),this.month(g.getUTCMonth()),this.date(g.getUTCDate()),this} -// MOMENTS -function Gc(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)} -// HELPERS -// MOMENTS -function Hc(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function Ic(a,b){b[ge]=u(1e3*("0."+a))} -// MOMENTS -function Jc(){return this._isUTC?"UTC":""}function Kc(){return this._isUTC?"Coordinated Universal Time":""}function Lc(a){return sb(1e3*a)}function Mc(){return sb.apply(null,arguments).parseZone()}function Nc(a){return a}function Oc(a,b,c,d){var e=bb(),f=k().set(d,b);return e[c](f,a)}function Pc(a,b,c){if(f(a)&&(b=a,a=void 0),a=a||"",null!=b)return Oc(a,b,c,"month");var d,e=[];for(d=0;d<12;d++)e[d]=Oc(a,d,c,"month");return e} -// () -// (5) -// (fmt, 5) -// (fmt) -// (true) -// (true, 5) -// (true, fmt, 5) -// (true, fmt) -function Qc(a,b,c,d){"boolean"==typeof a?(f(b)&&(c=b,b=void 0),b=b||""):(b=a,c=b,a=!1,f(b)&&(c=b,b=void 0),b=b||"");var e=bb(),g=a?e._week.dow:0;if(null!=c)return Oc(b,(c+g)%7,d,"day");var h,i=[];for(h=0;h<7;h++)i[h]=Oc(b,(h+g)%7,d,"day");return i}function Rc(a,b){return Pc(a,b,"months")}function Sc(a,b){return Pc(a,b,"monthsShort")}function Tc(a,b,c){return Qc(a,b,c,"weekdays")}function Uc(a,b,c){return Qc(a,b,c,"weekdaysShort")}function Vc(a,b,c){return Qc(a,b,c,"weekdaysMin")}function Wc(){var a=this._data;return this._milliseconds=Ze(this._milliseconds),this._days=Ze(this._days),this._months=Ze(this._months),a.milliseconds=Ze(a.milliseconds),a.seconds=Ze(a.seconds),a.minutes=Ze(a.minutes),a.hours=Ze(a.hours),a.months=Ze(a.months),a.years=Ze(a.years),this}function Xc(a,b,c,d){var e=Ob(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()} -// supports only 2.0-style add(1, 's') or add(duration) -function Yc(a,b){return Xc(this,a,b,1)} -// supports only 2.0-style subtract(1, 's') or subtract(duration) -function Zc(a,b){return Xc(this,a,b,-1)}function $c(a){return a<0?Math.floor(a):Math.ceil(a)}function _c(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data; -// if we have a mix of positive and negative values, bubble down first -// check: https://github.com/moment/moment/issues/2166 -// The following code bubbles up values, see the tests for -// examples of what that means. -// convert days to months -// 12 months -> 1 year -return f>=0&&g>=0&&h>=0||f<=0&&g<=0&&h<=0||(f+=864e5*$c(bd(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=t(f/1e3),i.seconds=a%60,b=t(a/60),i.minutes=b%60,c=t(b/60),i.hours=c%24,g+=t(c/24),e=t(ad(g)),h+=e,g-=$c(bd(e)),d=t(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function ad(a){ -// 400 years have 146097 days (taking into account leap year rules) -// 400 years have 12 months === 4800 -return 4800*a/146097}function bd(a){ -// the reverse of daysToMonths -return 146097*a/4800}function cd(a){var b,c,d=this._milliseconds;if(a=K(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+ad(b),"month"===a?c:c/12;switch( -// handle milliseconds separately because of floating point math errors (issue #1867) -b=this._days+Math.round(bd(this._months)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3; -// Math.floor prevents floating point math errors here -case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}} -// TODO: Use this.as('ms')? -function dd(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*u(this._months/12)}function ed(a){return function(){return this.as(a)}}function fd(a){return a=K(a),this[a+"s"]()}function gd(a){return function(){return this._data[a]}}function hd(){return t(this.days()/7)} -// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize -function id(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function jd(a,b,c){var d=Ob(a).abs(),e=of(d.as("s")),f=of(d.as("m")),g=of(d.as("h")),h=of(d.as("d")),i=of(d.as("M")),j=of(d.as("y")),k=e0,k[4]=c,id.apply(null,k)} -// This function allows you to set the rounding function for relative time strings -function kd(a){return void 0===a?of:"function"==typeof a&&(of=a,!0)} -// This function allows you to set a threshold for relative time strings -function ld(a,b){return void 0!==pf[a]&&(void 0===b?pf[a]:(pf[a]=b,!0))}function md(a){var b=this.localeData(),c=jd(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function nd(){ -// for ISO strings we do not use the normal bubbling rules: -// * milliseconds bubble up until they become hours -// * days do not bubble at all -// * months bubble up until they become years -// This is because there is no context-free conversion between hours and days -// (think of clock changes) -// and also not between days and months (28-31 days per month) -var a,b,c,d=qf(this._milliseconds)/1e3,e=qf(this._days),f=qf(this._months); -// 3600 seconds -> 60 minutes -> 1 hour -a=t(d/60),b=t(a/60),d%=60,a%=60, -// 12 months -> 1 year -c=t(f/12),f%=12; -// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js -var g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(m<0?"-":"")+"P"+(g?g+"Y":"")+(h?h+"M":"")+(i?i+"D":"")+(j||k||l?"T":"")+(j?j+"H":"")+(k?k+"M":"")+(l?l+"S":""):"P0D"}var od,pd;pd=Array.prototype.some?Array.prototype.some:function(a){for(var b=Object(this),c=b.length>>>0,d=0;d68?1900:2e3)}; -// MOMENTS -var pe=O("FullYear",!0); -// FORMATTING -U("w",["ww",2],"wo","week"),U("W",["WW",2],"Wo","isoWeek"), -// ALIASES -J("week","w"),J("isoWeek","W"), -// PRIORITIES -M("week",5),M("isoWeek",5), -// PARSING -Z("w",Od),Z("ww",Od,Kd),Z("W",Od),Z("WW",Od,Kd),ca(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=u(a)});var qe={dow:0,// Sunday is the first day of the week. -doy:6}; -// FORMATTING -U("d",0,"do","day"),U("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),U("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),U("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),U("e",0,0,"weekday"),U("E",0,0,"isoWeekday"), -// ALIASES -J("day","d"),J("weekday","e"),J("isoWeekday","E"), -// PRIORITY -M("day",11),M("weekday",11),M("isoWeekday",11), -// PARSING -Z("d",Od),Z("e",Od),Z("E",Od),Z("dd",function(a,b){return b.weekdaysMinRegex(a)}),Z("ddd",function(a,b){return b.weekdaysShortRegex(a)}),Z("dddd",function(a,b){return b.weekdaysRegex(a)}),ca(["dd","ddd","dddd"],function(a,b,c,d){var e=c._locale.weekdaysParse(a,d,c._strict); -// if we didn't get a weekday name, mark the date as invalid -null!=e?b.d=e:m(c).invalidWeekday=a}),ca(["d","e","E"],function(a,b,c,d){b[d]=u(a)}); -// LOCALES -var re="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),se="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),te="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),ue=Zd,ve=Zd,we=Zd;U("H",["HH",2],0,"hour"),U("h",["hh",2],0,Ra),U("k",["kk",2],0,Sa),U("hmm",0,0,function(){return""+Ra.apply(this)+T(this.minutes(),2)}),U("hmmss",0,0,function(){return""+Ra.apply(this)+T(this.minutes(),2)+T(this.seconds(),2)}),U("Hmm",0,0,function(){return""+this.hours()+T(this.minutes(),2)}),U("Hmmss",0,0,function(){return""+this.hours()+T(this.minutes(),2)+T(this.seconds(),2)}),Ta("a",!0),Ta("A",!1), -// ALIASES -J("hour","h"), -// PRIORITY -M("hour",13),Z("a",Ua),Z("A",Ua),Z("H",Od),Z("h",Od),Z("HH",Od,Kd),Z("hh",Od,Kd),Z("hmm",Pd),Z("hmmss",Qd),Z("Hmm",Pd),Z("Hmmss",Qd),ba(["H","HH"],de),ba(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),ba(["h","hh"],function(a,b,c){b[de]=u(a),m(c).bigHour=!0}),ba("hmm",function(a,b,c){var d=a.length-2;b[de]=u(a.substr(0,d)),b[ee]=u(a.substr(d)),m(c).bigHour=!0}),ba("hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[de]=u(a.substr(0,d)),b[ee]=u(a.substr(d,2)),b[fe]=u(a.substr(e)),m(c).bigHour=!0}),ba("Hmm",function(a,b,c){var d=a.length-2;b[de]=u(a.substr(0,d)),b[ee]=u(a.substr(d))}),ba("Hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[de]=u(a.substr(0,d)),b[ee]=u(a.substr(d,2)),b[fe]=u(a.substr(e))});var xe,ye=/[ap]\.?m?\.?/i,ze=O("Hours",!0),Ae={calendar:xd,longDateFormat:yd,invalidDate:zd,ordinal:Ad,ordinalParse:Bd,relativeTime:Cd,months:le,monthsShort:me,week:qe,weekdays:re,weekdaysMin:te,weekdaysShort:se,meridiemParse:ye},Be={},Ce={},De=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Ee=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Fe=/Z|[+-]\d\d(?::?\d\d)?/,Ge=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/], -// YYYYMM is NOT allowed by the standard -["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],He=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Ie=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=x("value provided is not in a recognized ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}), -// constant that refers to the ISO standard -a.ISO_8601=function(){};var Je=x("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var a=sb.apply(null,arguments);return this.isValid()&&a.isValid()?athis?this:a:o()}),Le=function(){return Date.now?Date.now():+new Date};zb("Z",":"),zb("ZZ",""), -// PARSING -Z("Z",Xd),Z("ZZ",Xd),ba(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Ab(Xd,a)}); -// HELPERS -// timezone chunker -// '+10:00' > ['10', '00'] -// '-1530' > ['-15', '30'] -var Me=/([\+\-]|\d\d)/gi; -// HOOKS -// This function will be called whenever a moment is mutated. -// It is intended to keep the offset in sync with the timezone. -a.updateOffset=function(){}; -// ASP.NET json date format regex -var Ne=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,Oe=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;Ob.fn=wb.prototype;var Pe=Sb(1,"add"),Qe=Sb(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",a.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var Re=x("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)}); -// FORMATTING -U(0,["gg",2],0,function(){return this.weekYear()%100}),U(0,["GG",2],0,function(){return this.isoWeekYear()%100}),zc("gggg","weekYear"),zc("ggggg","weekYear"),zc("GGGG","isoWeekYear"),zc("GGGGG","isoWeekYear"), -// ALIASES -J("weekYear","gg"),J("isoWeekYear","GG"), -// PRIORITY -M("weekYear",1),M("isoWeekYear",1), -// PARSING -Z("G",Vd),Z("g",Vd),Z("GG",Od,Kd),Z("gg",Od,Kd),Z("GGGG",Sd,Md),Z("gggg",Sd,Md),Z("GGGGG",Td,Nd),Z("ggggg",Td,Nd),ca(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=u(a)}),ca(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}), -// FORMATTING -U("Q",0,"Qo","quarter"), -// ALIASES -J("quarter","Q"), -// PRIORITY -M("quarter",7), -// PARSING -Z("Q",Jd),ba("Q",function(a,b){b[be]=3*(u(a)-1)}), -// FORMATTING -U("D",["DD",2],"Do","date"), -// ALIASES -J("date","D"), -// PRIOROITY -M("date",9), -// PARSING -Z("D",Od),Z("DD",Od,Kd),Z("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),ba(["D","DD"],ce),ba("Do",function(a,b){b[ce]=u(a.match(Od)[0],10)}); -// MOMENTS -var Se=O("Date",!0); -// FORMATTING -U("DDD",["DDDD",3],"DDDo","dayOfYear"), -// ALIASES -J("dayOfYear","DDD"), -// PRIORITY -M("dayOfYear",4), -// PARSING -Z("DDD",Rd),Z("DDDD",Ld),ba(["DDD","DDDD"],function(a,b,c){c._dayOfYear=u(a)}), -// FORMATTING -U("m",["mm",2],0,"minute"), -// ALIASES -J("minute","m"), -// PRIORITY -M("minute",14), -// PARSING -Z("m",Od),Z("mm",Od,Kd),ba(["m","mm"],ee); -// MOMENTS -var Te=O("Minutes",!1); -// FORMATTING -U("s",["ss",2],0,"second"), -// ALIASES -J("second","s"), -// PRIORITY -M("second",15), -// PARSING -Z("s",Od),Z("ss",Od,Kd),ba(["s","ss"],fe); -// MOMENTS -var Ue=O("Seconds",!1); -// FORMATTING -U("S",0,0,function(){return~~(this.millisecond()/100)}),U(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),U(0,["SSS",3],0,"millisecond"),U(0,["SSSS",4],0,function(){return 10*this.millisecond()}),U(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),U(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),U(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),U(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),U(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}), -// ALIASES -J("millisecond","ms"), -// PRIORITY -M("millisecond",16), -// PARSING -Z("S",Rd,Jd),Z("SS",Rd,Kd),Z("SSS",Rd,Ld);var Ve;for(Ve="SSSS";Ve.length<=9;Ve+="S")Z(Ve,Ud);for(Ve="S";Ve.length<=9;Ve+="S")ba(Ve,Ic); -// MOMENTS -var We=O("Milliseconds",!1); -// FORMATTING -U("z",0,0,"zoneAbbr"),U("zz",0,0,"zoneName");var Xe=r.prototype;Xe.add=Pe,Xe.calendar=Vb,Xe.clone=Wb,Xe.diff=bc,Xe.endOf=oc,Xe.format=gc,Xe.from=hc,Xe.fromNow=ic,Xe.to=jc,Xe.toNow=kc,Xe.get=R,Xe.invalidAt=xc,Xe.isAfter=Xb,Xe.isBefore=Yb,Xe.isBetween=Zb,Xe.isSame=$b,Xe.isSameOrAfter=_b,Xe.isSameOrBefore=ac,Xe.isValid=vc,Xe.lang=Re,Xe.locale=lc,Xe.localeData=mc,Xe.max=Ke,Xe.min=Je,Xe.parsingFlags=wc,Xe.set=S,Xe.startOf=nc,Xe.subtract=Qe,Xe.toArray=sc,Xe.toObject=tc,Xe.toDate=rc,Xe.toISOString=ec,Xe.inspect=fc,Xe.toJSON=uc,Xe.toString=dc,Xe.unix=qc,Xe.valueOf=pc,Xe.creationData=yc, -// Year -Xe.year=pe,Xe.isLeapYear=ra, -// Week Year -Xe.weekYear=Ac,Xe.isoWeekYear=Bc, -// Quarter -Xe.quarter=Xe.quarters=Gc, -// Month -Xe.month=ka,Xe.daysInMonth=la, -// Week -Xe.week=Xe.weeks=Ba,Xe.isoWeek=Xe.isoWeeks=Ca,Xe.weeksInYear=Dc,Xe.isoWeeksInYear=Cc, -// Day -Xe.date=Se,Xe.day=Xe.days=Ka,Xe.weekday=La,Xe.isoWeekday=Ma,Xe.dayOfYear=Hc, -// Hour -Xe.hour=Xe.hours=ze, -// Minute -Xe.minute=Xe.minutes=Te, -// Second -Xe.second=Xe.seconds=Ue, -// Millisecond -Xe.millisecond=Xe.milliseconds=We, -// Offset -Xe.utcOffset=Db,Xe.utc=Fb,Xe.local=Gb,Xe.parseZone=Hb,Xe.hasAlignedHourOffset=Ib,Xe.isDST=Jb,Xe.isLocal=Lb,Xe.isUtcOffset=Mb,Xe.isUtc=Nb,Xe.isUTC=Nb, -// Timezone -Xe.zoneAbbr=Jc,Xe.zoneName=Kc, -// Deprecations -Xe.dates=x("dates accessor is deprecated. Use date instead.",Se),Xe.months=x("months accessor is deprecated. Use month instead",ka),Xe.years=x("years accessor is deprecated. Use year instead",pe),Xe.zone=x("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",Eb),Xe.isDSTShifted=x("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Kb);var Ye=C.prototype;Ye.calendar=D,Ye.longDateFormat=E,Ye.invalidDate=F,Ye.ordinal=G,Ye.preparse=Nc,Ye.postformat=Nc,Ye.relativeTime=H,Ye.pastFuture=I,Ye.set=A, -// Month -Ye.months=fa,Ye.monthsShort=ga,Ye.monthsParse=ia,Ye.monthsRegex=na,Ye.monthsShortRegex=ma, -// Week -Ye.week=ya,Ye.firstDayOfYear=Aa,Ye.firstDayOfWeek=za, -// Day of Week -Ye.weekdays=Fa,Ye.weekdaysMin=Ha,Ye.weekdaysShort=Ga,Ye.weekdaysParse=Ja,Ye.weekdaysRegex=Na,Ye.weekdaysShortRegex=Oa,Ye.weekdaysMinRegex=Pa, -// Hours -Ye.isPM=Va,Ye.meridiem=Wa,$a("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===u(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}), -// Side effect imports -a.lang=x("moment.lang is deprecated. Use moment.locale instead.",$a),a.langData=x("moment.langData is deprecated. Use moment.localeData instead.",bb);var Ze=Math.abs,$e=ed("ms"),_e=ed("s"),af=ed("m"),bf=ed("h"),cf=ed("d"),df=ed("w"),ef=ed("M"),ff=ed("y"),gf=gd("milliseconds"),hf=gd("seconds"),jf=gd("minutes"),kf=gd("hours"),lf=gd("days"),mf=gd("months"),nf=gd("years"),of=Math.round,pf={s:45,// seconds to minute -m:45,// minutes to hour -h:22,// hours to day -d:26,// days to month -M:11},qf=Math.abs,rf=wb.prototype; -// Deprecations -// Side effect imports -// FORMATTING -// PARSING -// Side effect imports -return rf.abs=Wc,rf.add=Yc,rf.subtract=Zc,rf.as=cd,rf.asMilliseconds=$e,rf.asSeconds=_e,rf.asMinutes=af,rf.asHours=bf,rf.asDays=cf,rf.asWeeks=df,rf.asMonths=ef,rf.asYears=ff,rf.valueOf=dd,rf._bubble=_c,rf.get=fd,rf.milliseconds=gf,rf.seconds=hf,rf.minutes=jf,rf.hours=kf,rf.days=lf,rf.weeks=hd,rf.months=mf,rf.years=nf,rf.humanize=md,rf.toISOString=nd,rf.toString=nd,rf.toJSON=nd,rf.locale=lc,rf.localeData=mc,rf.toIsoString=x("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",nd),rf.lang=Re,U("X",0,0,"unix"),U("x",0,0,"valueOf"),Z("x",Vd),Z("X",Yd),ba("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),ba("x",function(a,b,c){c._d=new Date(u(a))}),a.version="2.17.1",b(sb),a.fn=Xe,a.min=ub,a.max=vb,a.now=Le,a.utc=k,a.unix=Lc,a.months=Rc,a.isDate=g,a.locale=$a,a.invalid=o,a.duration=Ob,a.isMoment=s,a.weekdays=Tc,a.parseZone=Mc,a.localeData=bb,a.isDuration=xb,a.monthsShort=Sc,a.weekdaysMin=Vc,a.defineLocale=_a,a.updateLocale=ab,a.locales=cb,a.weekdaysShort=Uc,a.normalizeUnits=K,a.relativeTimeRounding=kd,a.relativeTimeThreshold=ld,a.calendarFormat=Ub,a.prototype=Xe,a}); \ No newline at end of file diff --git a/hotel_calendar/static/src/xml/hotel_calendar_management_view.xml b/hotel_calendar/static/src/xml/hotel_calendar_management_view.xml deleted file mode 100644 index c75e7ee68..000000000 --- a/hotel_calendar/static/src/xml/hotel_calendar_management_view.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - -
      -
      - -
      -
      -
      -
      - - - diff --git a/hotel_calendar/static/src/xml/hotel_calendar_templates.xml b/hotel_calendar/static/src/xml/hotel_calendar_templates.xml deleted file mode 100644 index 4b579fafc..000000000 --- a/hotel_calendar/static/src/xml/hotel_calendar_templates.xml +++ /dev/null @@ -1,378 +0,0 @@ - diff --git a/hotel_calendar/static/src/xml/hotel_calendar_view.xml b/hotel_calendar/static/src/xml/hotel_calendar_view.xml deleted file mode 100644 index 832bb8bd0..000000000 --- a/hotel_calendar/static/src/xml/hotel_calendar_view.xml +++ /dev/null @@ -1,146 +0,0 @@ - - - - -
      - -
      -
      -
      -
      - - - diff --git a/hotel_calendar/tests/__init__.py b/hotel_calendar/tests/__init__.py deleted file mode 100644 index c9580b6f0..000000000 --- a/hotel_calendar/tests/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/hotel_calendar/tests/common.py b/hotel_calendar/tests/common.py deleted file mode 100644 index a0e771b14..000000000 --- a/hotel_calendar/tests/common.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017 Solucións Aloxa S.L. -# Alexandre Díaz -# -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from odoo.addons.hotel.tests.common import TestHotel - - -class TestHotelCalendar(TestHotel): - - @classmethod - def setUpClass(cls): - super(TestHotelCalendar, cls).setUpClass() - - # Minimal Hotel Calendar Configuration - cls.tz_hotel = 'Europe/Madrid' - cls.default_pricelist_id = cls.pricelist_1.id - cls.default_restriction_id = cls.restriction_1.id - cls.env['ir.default'].sudo().set_default('res.config.settings', - 'default_arrival_hour', - '14:00') - cls.env['ir.default'].sudo().set_default('res.config.settings', - 'default_departure_hour', - '12:00') diff --git a/hotel_calendar/tests/test_management_calendar.py b/hotel_calendar/tests/test_management_calendar.py deleted file mode 100644 index 9a4b8b0e6..000000000 --- a/hotel_calendar/tests/test_management_calendar.py +++ /dev/null @@ -1,424 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017 Solucións Aloxa S.L. -# Alexandre Díaz -# -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from datetime import timedelta -from openerp.tools import ( - DEFAULT_SERVER_DATETIME_FORMAT, - DEFAULT_SERVER_DATE_FORMAT) -from openerp.exceptions import ValidationError -from .common import TestHotelCalendar -from odoo.addons.hotel import date_utils -import logging -_logger = logging.getLogger(__name__) - - -class TestManagementCalendar(TestHotelCalendar): - - def test_calendar_prices(self): - now_utc_dt = date_utils.now() - adv_utc_dt = now_utc_dt + timedelta(days=15) - - room_types = (self.hotel_room_type_budget, self.hotel_room_type_special) - - hotel_cal_mngt_obj = self.env['hotel.calendar.management'].sudo( - self.user_hotel_manager) - - hcal_data = hotel_cal_mngt_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - adv_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - self.default_pricelist_id, - self.default_restriction_id, - True) - for room_type in room_types: - for k_pr, v_pr in hcal_data['prices'].iteritems(): - if k_pr == room_type.id: # Only Check Test Cases - for k_info, v_info in enumerate(v_pr): - if k_info >= len(self.prices_tmp[room_type.id]): - break - self.assertEqual(v_info['price'], - self.prices_tmp[room_type.id][k_info], - "Hotel Calendar Management Prices \ - doesn't match!") - - # REMOVE PRICES - prices_obj = self.env['product.pricelist.item'].sudo( - self.user_hotel_manager) - prod_tmpl_ids = ( - self.hotel_room_type_budget.product_id.product_tmpl_id.id, - self.hotel_room_type_special.product_id.product_tmpl_id.id - ) - pr_ids = prices_obj.search([ - ('pricelist_id', '=', self.default_pricelist_id), - ('product_tmpl_id', 'in', prod_tmpl_ids), - ]) - pr_ids.sudo(self.user_hotel_manager).unlink() - - hcal_data = hotel_cal_mngt_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - adv_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - self.default_pricelist_id, - self.default_restriction_id, - True) - self.assertFalse(any(hcal_data['prices']), "Hotel Calendar Management \ - Prices doesn't match after remove!") - - def test_calendar_restrictions(self): - now_utc_dt = date_utils.now() - adv_utc_dt = now_utc_dt + timedelta(days=15) - room_types = (self.hotel_room_type_budget, self.hotel_room_type_special) - - hotel_cal_mngt_obj = self.env['hotel.calendar.management'].sudo( - self.user_hotel_manager) - - hcal_data = hotel_cal_mngt_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - adv_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - self.default_pricelist_id, - self.default_restriction_id, - True) - for room_type in room_types: - for k_pr, v_pr in hcal_data['restrictions'].iteritems(): - if k_pr == room_type.id: # Only Check Test Cases - for k_info, v_info in enumerate(v_pr): - rest_items = self.restrictions_min_stay_tmp[room_type.id] - if k_info >= len(rest_items): - break - self.assertEqual( - v_info['min_stay'], - self.restrictions_min_stay_tmp[room_type.id][k_info], - "Hotel Calendar Management Restrictions \ - doesn't match!") - - # REMOVE RESTRICTIONS - rest_it_obj = self.env['hotel.room.type.restriction.item'].sudo( - self.user_hotel_manager) - rest_ids = rest_it_obj.search([ - ('restriction_id', '=', self.default_restriction_id), - ('room_type_id', 'in', (self.hotel_room_type_budget.id, - self.hotel_room_type_special.id)), - ]) - rest_ids.sudo(self.user_hotel_manager).unlink() - - hcal_data = hotel_cal_mngt_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - adv_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - self.default_pricelist_id, - self.default_restriction_id, - True) - self.assertFalse( - any(hcal_data['restrictions']), - "Hotel Calendar Management Restrictions doesn't match \ - after remove!") - - def test_calendar_availability(self): - now_utc_dt = date_utils.now() - adv_utc_dt = now_utc_dt + timedelta(days=6) - room_types = (self.hotel_room_type_budget, self.hotel_room_type_special) - - hotel_cal_mngt_obj = self.env['hotel.calendar.management'].sudo( - self.user_hotel_manager) - room_type_avail_obj = self.env['hotel.room.type.availability'].sudo( - self.user_hotel_manager) - - hcal_data = hotel_cal_mngt_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - adv_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - self.default_pricelist_id, - self.default_restriction_id, - True) - for room_type in room_types: - for k_pr, v_pr in hcal_data['availability'].iteritems(): - if k_pr == room_type.id: # Only Check Test Cases - for k_info, v_info in enumerate(v_pr): - if k_info >= len(self.avails_tmp[room_type.id]): - break - self.assertEqual( - v_info['avail'], - self.avails_tmp[room_type.id][k_info], - "Hotel Calendar Management Availability \ - doesn't match!") - - # CHANGE AVAIL - avail_ids = room_type_avail_obj.search([ - ('room_type_id', 'in', (self.hotel_room_type_budget.id, - self.hotel_room_type_special.id)), - ]) - for avail_id in avail_ids: - avail_id.sudo(self.user_hotel_manager).write({'avail': 1}) - hcal_data = hotel_cal_mngt_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - adv_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - self.default_pricelist_id, - self.default_restriction_id, - True) - for room_type in room_types: - for k_pr, v_pr in hcal_data['availability'].iteritems(): - if k_pr == room_type.id: # Only Check Test Cases - for k_info, v_info in enumerate(v_pr): - self.assertEqual( - v_info['avail'], - 1, - "Hotel Calendar Management Availability \ - doesn't match!") - - # REMOVE AVAIL - avail_ids = room_type_avail_obj.search([ - ('room_type_id', 'in', (self.hotel_room_type_budget.id, - self.hotel_room_type_special.id)), - ]) - avail_ids.sudo(self.user_hotel_manager).unlink() - - hcal_data = hotel_cal_mngt_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - adv_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - self.default_pricelist_id, - self.default_restriction_id, - True) - for room_type in room_types: - for k_pr, v_pr in hcal_data['availability'].iteritems(): - if k_pr == room_type.id: # Only Check Test Cases - for k_info, v_info in enumerate(v_pr): - self.assertEqual( - v_info['avail'], - room_type.max_real_rooms, - "Hotel Calendar Management Availability \ - doesn't match!") - - def test_save_changes(self): - now_utc_dt = date_utils.now() - adv_utc_dt = now_utc_dt + timedelta(days=3) - room_types = (self.hotel_room_type_budget,) - - hotel_cal_mngt_obj = self.env['hotel.calendar.management'].sudo( - self.user_hotel_manager) - - # Generate new prices - prices = (144.0, 170.0, 30.0, 50.0) - cprices = {} - for k_item, v_item in enumerate(prices): - ndate_utc_dt = now_utc_dt + timedelta(days=k_item) - cprices.setdefault(self.hotel_room_type_budget.id, []).append({ - 'date': ndate_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT), - 'price': v_item - }) - - # Generate new restrictions - restrictions = { - 'min_stay': (3, 2, 4, 1), - 'max_stay': (5, 8, 9, 3), - 'min_stay_arrival': (2, 3, 6, 2), - 'max_stay_arrival': (4, 7, 7, 4), - 'closed_departure': (False, True, False, True), - 'closed_arrival': (True, False, False, False), - 'closed': (False, False, True, True), - } - crestrictions = {} - for i in range(0, 4): - ndate_utc_dt = now_utc_dt + timedelta(days=i) - crestrictions.setdefault(self.hotel_room_type_budget.id, []).append({ - 'date': ndate_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT), - 'closed_arrival': restrictions['closed_arrival'][i], - 'max_stay': restrictions['max_stay'][i], - 'min_stay': restrictions['min_stay'][i], - 'closed_departure': restrictions['closed_departure'][i], - 'closed': restrictions['closed'][i], - 'min_stay_arrival': restrictions['min_stay_arrival'][i], - 'max_stay_arrival': restrictions['max_stay_arrival'][i], - }) - - # Generate new availability - avails = (1, 2, 2, 1) - cavails = {} - for k_item, v_item in enumerate(avails): - ndate_utc_dt = now_utc_dt + timedelta(days=k_item) - ndate_dt = date_utils.dt_as_timezone(ndate_utc_dt, self.tz_hotel) - cavails.setdefault(self.hotel_room_type_budget.id, []).append({ - 'date': ndate_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - 'avail': v_item, - 'no_ota': False, - }) - - # Save new values - hotel_cal_mngt_obj.save_changes( - self.default_pricelist_id, - self.default_restriction_id, - cprices, - crestrictions, - cavails) - - # Check data integrity - hcal_data = hotel_cal_mngt_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - adv_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - self.default_pricelist_id, - self.default_restriction_id, - True) - - for room_type in room_types: - for k_pr, v_pr in hcal_data['availability'].iteritems(): - if k_pr == room_type.id: # Only Check Test Cases - for k_info, v_info in enumerate(v_pr): - self.assertEqual(v_info['avail'], - avails[k_info], - "Hotel Calendar Management \ - Availability doesn't match!") - for k_pr, v_pr in hcal_data['restrictions'].iteritems(): - if k_pr == room_type.id: # Only Check Test Cases - for k_info, v_info in enumerate(v_pr): - self.assertEqual(v_info['min_stay'], - restrictions['min_stay'][k_info], - "Hotel Calendar Management \ - Restrictions doesn't match!") - self.assertEqual(v_info['max_stay'], - restrictions['max_stay'][k_info], - "Hotel Calendar Management \ - Restrictions doesn't match!") - self.assertEqual( - v_info['min_stay_arrival'], - restrictions['min_stay_arrival'][k_info], - "Hotel Calendar Management Restrictions \ - doesn't match!") - self.assertEqual( - v_info['max_stay_arrival'], - restrictions['max_stay_arrival'][k_info], - "Hotel Calendar Management Restrictions \ - doesn't match!") - self.assertEqual( - v_info['closed_departure'], - restrictions['closed_departure'][k_info], - "Hotel Calendar Management Restrictions \ - doesn't match!") - self.assertEqual( - v_info['closed_arrival'], - restrictions['closed_arrival'][k_info], - "Hotel Calendar Management Restrictions \ - doesn't match!") - self.assertEqual( - v_info['closed'], - restrictions['closed'][k_info], - "Hotel Calendar Management Restrictions \ - doesn't match!") - for k_pr, v_pr in hcal_data['prices'].iteritems(): - if k_pr == room_type.id: # Only Check Test Cases - for k_info, v_info in enumerate(v_pr): - self.assertEqual(v_info['price'], - prices[k_info], "Hotel Calendar \ - Management Prices doesn't match!") - - def test_calendar_reservations(self): - now_utc_dt = date_utils.now() - adv_utc_dt = now_utc_dt + timedelta(days=15) - room_types = (self.hotel_room_type_budget,) - - hotel_cal_mngt_obj = self.env['hotel.calendar.management'].sudo( - self.user_hotel_manager) - - reserv_start_utc_dt = now_utc_dt + timedelta(days=3) - reserv_end_utc_dt = reserv_start_utc_dt + timedelta(days=3) - folio = self.create_folio(self.user_hotel_manager, self.partner_2) - reservation = self.create_reservation( - self.user_hotel_manager, - folio, - reserv_start_utc_dt, - reserv_end_utc_dt, - self.hotel_room_simple_100, - "Reservation Test #1") - - hcal_data = hotel_cal_mngt_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - adv_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - self.default_pricelist_id, - self.default_restriction_id, - True) - - avail_end_utc_dt = reserv_end_utc_dt - timedelta(days=1) - for room_type in room_types: - for k_pr, v_pr in hcal_data['count_reservations'].iteritems(): - if k_pr == room_type.id: # Only Check Test Cases - for k_info, v_info in enumerate(v_pr): - ndate = date_utils.get_datetime(v_info['date']) - if date_utils.date_in(ndate, - reserv_start_utc_dt, - avail_end_utc_dt) == 0: - self.assertEqual(v_info['num'], - 1, - "Hotel Calendar Management \ - Availability doesn't match!") - - def test_invalid_input_calendar_data(self): - now_utc_dt = date_utils.now() - adv_utc_dt = now_utc_dt + timedelta(days=15) - - hotel_cal_mngt_obj = self.env['hotel.calendar.management'].sudo( - self.user_hotel_manager) - - with self.assertRaises(ValidationError): - hcal_data = hotel_cal_mngt_obj.get_hcalendar_all_data( - False, - adv_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT), - self.default_pricelist_id, - self.default_restriction_id, - True) - with self.assertRaises(ValidationError): - hcal_data = hotel_cal_mngt_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT), - False, - self.default_pricelist_id, - self.default_restriction_id, - True) - with self.assertRaises(ValidationError): - hcal_data = hotel_cal_mngt_obj.get_hcalendar_all_data( - False, - False, - self.default_pricelist_id, - self.default_restriction_id, - True) - hcal_data = hotel_cal_mngt_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - adv_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - False, - False, - True) - self.assertTrue(any(hcal_data), "Hotel Calendar invalid default \ - management default models!") - - def test_calendar_settings(self): - hotel_cal_mngt_obj = self.env['hotel.calendar.management'].sudo( - self.user_hotel_manager) - settings = hotel_cal_mngt_obj.get_hcalendar_settings() - self.assertTrue(settings, "Hotel Calendar invalid settings") - - self.assertEqual(settings['eday_week'], - self.user_hotel_manager.npms_end_day_week, - "Hotel Calendar invalid settings") - self.assertEqual(settings['eday_week_offset'], - self.user_hotel_manager.npms_end_day_week_offset, - "Hotel Calendar invalid settings") - self.assertEqual(settings['days'], - self.user_hotel_manager.npms_default_num_days, - "Hotel Calendar invalid settings") - self.assertEqual(settings['show_notifications'], - self.user_hotel_manager.pms_show_notifications, - "Hotel Calendar invalid settings") - self.assertEqual(settings['show_num_rooms'], - self.user_hotel_manager.pms_show_num_rooms, - "Hotel Calendar invalid settings") diff --git a/hotel_calendar/tests/test_product_pricelist.py b/hotel_calendar/tests/test_product_pricelist.py deleted file mode 100644 index b1a86099a..000000000 --- a/hotel_calendar/tests/test_product_pricelist.py +++ /dev/null @@ -1,66 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from openerp.tools import DEFAULT_SERVER_DATE_FORMAT -from .common import TestHotelCalendar -from odoo.addons.hotel import date_utils - - -class TestProductPricelist(TestHotelCalendar): - - def test_update_price(self): - now_utc_dt = date_utils.now() - now_utc_str = now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT) - - room_type_tmpl_id = self.hotel_room_type_special.product_id.product_tmpl_id - - pritem_obj = self.env['product.pricelist.item'] - plitem = pritem_obj.search([ - ('pricelist_id', '=', self.default_pricelist_id), - ('product_tmpl_id', '=', room_type_tmpl_id.id), - ('date_start', '=', now_utc_str), - ('date_end', '=', now_utc_str), - ('applied_on', '=', '1_product'), - ('compute_price', '=', 'fixed') - ]) - old_price = plitem.fixed_price - - self.pricelist_1.update_price( - self.hotel_room_type_special.id, - now_utc_str, - 999.9) - - plitem = pritem_obj.search([ - ('pricelist_id', '=', self.default_pricelist_id), - ('product_tmpl_id', '=', room_type_tmpl_id.id), - ('date_start', '=', now_utc_str), - ('date_end', '=', now_utc_str), - ('applied_on', '=', '1_product'), - ('compute_price', '=', 'fixed') - ]) - new_price = plitem.fixed_price - - self.assertNotEqual(old_price, - new_price, - "Hotel Calendar can't change price") - self.assertEqual(new_price, - 999.9, - "Hotel Calendar can't change price") diff --git a/hotel_calendar/tests/test_reservations_calendar.py b/hotel_calendar/tests/test_reservations_calendar.py deleted file mode 100644 index fb149f2f1..000000000 --- a/hotel_calendar/tests/test_reservations_calendar.py +++ /dev/null @@ -1,289 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017 Solucións Aloxa S.L. -# Alexandre Díaz -# -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -import datetime -from datetime import timedelta -from odoo import fields -from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT -from openerp.exceptions import ValidationError -from .common import TestHotelCalendar -from odoo.addons.hotel import date_utils -import pytz - - -class TestReservationsCalendar(TestHotelCalendar): - - def test_calendar_pricelist(self): - now_utc_dt = date_utils.now() - real_start_utc_dt = (now_utc_dt - timedelta(days=1)) - adv_utc_dt = now_utc_dt + timedelta(days=15) - - hotel_reserv_obj = self.env['hotel.reservation'].sudo( - self.user_hotel_manager) - - hcal_data = hotel_reserv_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT), - adv_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)) - - # Check Pricelist Integrity - for k_pr, v_pr in hcal_data['pricelist'].iteritems(): - for room_type_pr in v_pr: - # Only Check Test Cases - if room_type_pr['room'] in self.prices_tmp.keys(): - sorted_dates = sorted( - room_type_pr['days'].keys(), - key=lambda x: datetime.datetime.strptime(x, '%d/%m/%Y') - ) - init_date_dt = datetime.datetime.strptime( - sorted_dates[0], - '%d/%m/%Y').replace(tzinfo=pytz.utc) - end_date_dt = datetime.datetime.strptime( - sorted_dates[-1], - '%d/%m/%Y').replace(tzinfo=pytz.utc) - - self.assertEqual(real_start_utc_dt, init_date_dt, - "Hotel Calendar don't start in \ - the correct date!") - self.assertEqual(adv_utc_dt, end_date_dt, - "Hotel Calendar don't end in \ - the correct date!") - - room_type_prices = self.prices_tmp[room_type_pr['room']] - for k_price, v_price in enumerate(room_type_prices): - self.assertEqual( - v_price, - room_type_pr['days'][sorted_dates[k_price+1]], - "Hotel Calendar Pricelist doesn't match!") - - # Check Pricelist Integrity after unlink - pricelist_item_obj = self.env['product.pricelist.item'].sudo( - self.user_hotel_manager) - pr_ids = pricelist_item_obj.search([ - ('pricelist_id', '=', self.default_pricelist_id), - ('product_tmpl_id', 'in', ( - self.hotel_room_type_budget.product_id.product_tmpl_id.id, - self.hotel_room_type_special.product_id.product_tmpl_id.id)), - ]) - pr_ids.sudo(self.user_hotel_manager).unlink() - reserv_obj = self.env['hotel.reservation'].sudo( - self.user_hotel_manager) - hcal_data = reserv_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT), - adv_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)) - room_types = (self.hotel_room_type_budget, self.hotel_room_type_special) - for room_type in room_types: - for k_pr, v_pr in hcal_data['pricelist'].iteritems(): - for room_type_pr in v_pr: - if room_type_pr['room'] == room_type.id: # Only Check Test Cases - self.assertEqual( - room_type.list_price, - room_type_pr['days'][sorted_dates[k_price+1]], - "Hotel Calendar Pricelist doesn't \ - match after remove!") - - def test_calendar_reservations(self): - now_utc_dt = date_utils.now() - adv_utc_dt = now_utc_dt + timedelta(days=15) - - hotel_reserv_obj = self.env['hotel.reservation'].sudo( - self.user_hotel_manager) - - def is_reservation_listed(reservation_id): - hcal_data = hotel_reserv_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT), - adv_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)) - # TODO: Perhaps not the best way to do this test... :/ - hasReservationTest = False - for reserv in hcal_data['reservations']: - if reserv[1] == reservation_id: - hasReservationTest = True - break - return hasReservationTest - - # CREATE COMPLETE RESERVATION (3 Nigths) - reserv_start_utc_dt = now_utc_dt + timedelta(days=3) - reserv_end_utc_dt = reserv_start_utc_dt + timedelta(days=3) - folio = self.create_folio(self.user_hotel_manager, self.partner_2) - reservation = self.create_reservation( - self.user_hotel_manager, - folio, - reserv_start_utc_dt, - reserv_end_utc_dt, - self.hotel_room_double_200, - "Reservation Test #1") - - # CHECK SUCCESSFULL CREATION - self.assertTrue(is_reservation_listed(reservation.id), - "Hotel Calendar can't found test reservation!") - - # CONFIRM FOLIO - folio.sudo(self.user_hotel_manager).action_confirm() - self.assertTrue(is_reservation_listed(reservation.id), - "Hotel Calendar can't found test reservation!") - - # CALENDAR LIMITS - now_utc_dt_tmp = now_utc_dt - adv_utc_dt_tmp = adv_utc_dt - # Start after reservation end - now_utc_dt = reserv_end_utc_dt + timedelta(days=2) - adv_utc_dt = now_utc_dt + timedelta(days=15) - self.assertFalse( - is_reservation_listed(reservation.id), - "Hotel Calendar found test reservation but expected not found it!") - - # Ends before reservation start - adv_utc_dt = reserv_start_utc_dt - timedelta(days=1) - now_utc_dt = adv_utc_dt - timedelta(days=15) - self.assertFalse( - is_reservation_listed(reservation.id), - "Hotel Calendar found test reservation but expected not found it!") - now_utc_dt = now_utc_dt_tmp - adv_utc_dt = adv_utc_dt_tmp - - # Start in the middle of the reservation days - now_utc_dt = reserv_end_utc_dt - timedelta(days=1) - adv_utc_dt = now_utc_dt + timedelta(days=15) - self.assertTrue( - is_reservation_listed(reservation.id), - "Hotel Calendar can't found test reservation!") - now_utc_dt = now_utc_dt_tmp - adv_utc_dt = adv_utc_dt_tmp - - # CANCEL FOLIO - folio.sudo(self.user_hotel_manager).action_cancel() - self.assertFalse( - is_reservation_listed(reservation.id), - "Hotel Calendar can't found test reservation!") - - # REMOVE FOLIO - folio.sudo().unlink() # FIXME: Can't use: self.user_hotel_manager - self.assertFalse( - is_reservation_listed(reservation.id), - "Hotel Calendar can't found test reservation!") - - def test_invalid_input_calendar_data(self): - now_utc_dt = date_utils.now() - adv_utc_dt = now_utc_dt + timedelta(days=15) - - hotel_reserv_obj = self.env['hotel.reservation'].sudo( - self.user_hotel_manager) - - with self.assertRaises(ValidationError): - hcal_data = hotel_reserv_obj.get_hcalendar_all_data( - False, - adv_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)) - with self.assertRaises(ValidationError): - hcal_data = hotel_reserv_obj.get_hcalendar_all_data( - now_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT), - False) - with self.assertRaises(ValidationError): - hcal_data = hotel_reserv_obj.get_hcalendar_all_data( - False, - False) - - def test_calendar_settings(self): - hcal_options = self.env['hotel.reservation'].sudo( - self.user_hotel_manager).get_hcalendar_settings() - - self.assertEqual(hcal_options['divide_rooms_by_capacity'], - self.user_hotel_manager.pms_divide_rooms_by_capacity, - "Hotel Calendar Invalid Options!") - self.assertEqual(hcal_options['eday_week'], - self.user_hotel_manager.pms_end_day_week, - "Hotel Calendar Invalid Options!") - self.assertEqual(hcal_options['days'], - self.user_hotel_manager.pms_default_num_days, - "Hotel Calendar Invalid Options!") - self.assertEqual( - hcal_options['allow_invalid_actions'], - self.user_hotel_manager.pms_type_move == 'allow_invalid', - "Hotel Calendar Invalid Options!") - self.assertEqual( - hcal_options['assisted_movement'], - self.user_hotel_manager.pms_type_move == 'assisted', - "Hotel Calendar Invalid Options!") - default_arrival_hour = self.env['ir.default'].sudo().get( - 'res.config.settings', 'default_arrival_hour') - self.assertEqual(hcal_options['default_arrival_hour'], - default_arrival_hour, - "Hotel Calendar Invalid Options!") - default_departure_hour = self.env['ir.default'].sudo().get( - 'res.config.settings', 'default_departure_hour') - self.assertEqual(hcal_options['default_departure_hour'], - default_departure_hour, - "Hotel Calendar Invalid Options!") - self.assertEqual(hcal_options['show_notifications'], - self.user_hotel_manager.pms_show_notifications, - "Hotel Calendar Invalid Options!") - self.assertEqual(hcal_options['show_num_rooms'], - self.user_hotel_manager.pms_show_num_rooms, - "Hotel Calendar Invalid Options!") - self.assertEqual(hcal_options['show_pricelist'], - self.user_hotel_manager.pms_show_pricelist, - "Hotel Calendar Invalid Options!") - self.assertEqual(hcal_options['show_availability'], - self.user_hotel_manager.pms_show_availability, - "Hotel Calendar Invalid Options!") - - def test_swap_reservation(self): - hcal_reserv_obj = self.env['hotel.reservation'].sudo( - self.user_hotel_manager) - now_utc_dt = date_utils.now() - - # CREATE RESERVATIONS - reserv_start_utc_dt = now_utc_dt + timedelta(days=3) - reserv_end_utc_dt = reserv_start_utc_dt + timedelta(days=3) - folio_a = self.create_folio(self.user_hotel_manager, self.partner_2) - reservation_a = self.create_reservation( - self.user_hotel_manager, - folio_a, - reserv_start_utc_dt, - reserv_end_utc_dt, - self.hotel_room_double_200, - "Reservation Test #1") - self.assertTrue(reservation_a, - "Hotel Calendar create test reservation!") - folio_a.sudo(self.user_hotel_manager).action_confirm() - - folio_b = self.create_folio(self.user_hotel_manager, self.partner_2) - reservation_b = self.create_reservation( - self.user_hotel_manager, - folio_b, - reserv_start_utc_dt, - reserv_end_utc_dt, - self.hotel_room_simple_101, - "Reservation Test #2") - self.assertTrue(reservation_b, - "Hotel Calendar can't create test reservation!") - folio_b.sudo(self.user_hotel_manager).action_confirm() - - self.assertTrue( - hcal_reserv_obj.swap_reservations(reservation_a.ids, - reservation_b.ids), - "Hotel Calendar invalid swap operation" - ) - self.assertEqual(reservation_a.product_id.id, - self.hotel_room_simple_101.product_id.id, - "Hotel Calendar wrong swap operation") - self.assertEqual(reservation_b.product_id.id, - self.hotel_room_double_200.product_id.id, - "Hotel Calendar wrong swap operation") diff --git a/hotel_calendar/views/actions.xml b/hotel_calendar/views/actions.xml deleted file mode 100644 index 9bdf06417..000000000 --- a/hotel_calendar/views/actions.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Hotel folio checkin - hotel.reservation - tree,form - [('real_checkin','=', datetime.datetime.now().strftime('%Y-%m-%d')), - ('state', 'in', ['confirm']), - ('reservation_type', 'not in', ['out'])] - - - - Hotel folio checkout - hotel.reservation - tree,form - [('real_checkout','=', datetime.datetime.now().strftime('%Y-%m-%d')), - ('state', 'in', ['booking']), - ('reservation_type', 'not in', ['out'])] - - - - Hotel Calendar - hotel.calendar - tree,form - - - diff --git a/hotel_calendar/views/general.xml b/hotel_calendar/views/general.xml deleted file mode 100644 index 3ab647615..000000000 --- a/hotel_calendar/views/general.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - diff --git a/hotel_calendar/views/hotel_calendar_management_views.xml b/hotel_calendar/views/hotel_calendar_management_views.xml deleted file mode 100644 index 6d12c3abb..000000000 --- a/hotel_calendar/views/hotel_calendar_management_views.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - hotel.calendar.management.mpms - hotel.calendar.management - - - - - - diff --git a/hotel_calendar/views/hotel_calendar_views.xml b/hotel_calendar/views/hotel_calendar_views.xml deleted file mode 100644 index 24a3c8bea..000000000 --- a/hotel_calendar/views/hotel_calendar_views.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - hotel.calendar.form - hotel.calendar - -
      - - - - - - - - - - - - -
      -
      -
      - - - - hotel.calendar.tree - hotel.calendar - - - - - - - - -
      diff --git a/hotel_calendar/views/hotel_reservation_views.xml b/hotel_calendar/views/hotel_reservation_views.xml deleted file mode 100644 index 6c32e0a8b..000000000 --- a/hotel_calendar/views/hotel_reservation_views.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - hotel.reservation.pms - hotel.reservation - - - - - - diff --git a/hotel_calendar/views/inherited_hotel_property_views.xml b/hotel_calendar/views/inherited_hotel_property_views.xml deleted file mode 100644 index b774bcbd4..000000000 --- a/hotel_calendar/views/inherited_hotel_property_views.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - hotel.property - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hotel_calendar/views/inherited_hotel_room_type_views.xml b/hotel_calendar/views/inherited_hotel_room_type_views.xml deleted file mode 100644 index 9726a0d71..000000000 --- a/hotel_calendar/views/inherited_hotel_room_type_views.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - hotel.room.type - - - - - - - - - diff --git a/hotel_calendar/views/inherited_hotel_room_views.xml b/hotel_calendar/views/inherited_hotel_room_views.xml deleted file mode 100644 index 3d84684cb..000000000 --- a/hotel_calendar/views/inherited_hotel_room_views.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - hotel.room - - - - - - - - - diff --git a/hotel_calendar/views/inherited_res_company_views.xml b/hotel_calendar/views/inherited_res_company_views.xml deleted file mode 100644 index de31ddf29..000000000 --- a/hotel_calendar/views/inherited_res_company_views.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - view.company.form - res.company - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hotel_calendar/views/inherited_res_users_views.xml b/hotel_calendar/views/inherited_res_users_views.xml deleted file mode 100644 index 12c33f265..000000000 --- a/hotel_calendar/views/inherited_res_users_views.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - res.users - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/hotel_calendar_channel_connector/README.md b/hotel_calendar_channel_connector/README.md deleted file mode 100644 index a102d4230..000000000 --- a/hotel_calendar_channel_connector/README.md +++ /dev/null @@ -1,12 +0,0 @@ -HOTEL CALENDAR CHANNEL CONNECTOR -=================================== -Unify 'hotel_calendar' and 'hotel_channel_connector' - - -Credits -======= - -Creator ------------- - -* Alexandre Díaz diff --git a/hotel_calendar_channel_connector/__init__.py b/hotel_calendar_channel_connector/__init__.py deleted file mode 100644 index 572903d95..000000000 --- a/hotel_calendar_channel_connector/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from . import models diff --git a/hotel_calendar_channel_connector/__manifest__.py b/hotel_calendar_channel_connector/__manifest__.py deleted file mode 100644 index a3cbe0835..000000000 --- a/hotel_calendar_channel_connector/__manifest__.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -{ - 'name': 'Hotel Calendar Channel Connector', - 'version': '11.0.2.0', - 'author': "Alexandre Díaz ", - 'website': 'https://github.com/hootel/hootel', - 'category': 'hotel/addon', - 'summary': "Hotel Calendar Channel Connector", - 'description': "Unify 'hotel_calendar' and 'hotel_channel_connector'", - 'depends': [ - 'hotel_calendar', - 'hotel_channel_connector', - ], - 'external_dependencies': { - 'python': [] - }, - 'data': [ - 'views/hotel_reservation.xml', - 'views/general.xml', - 'views/actions.xml', - ], - 'qweb': [ - 'static/src/xml/*.xml', - ], - 'test': [ - ], - - 'installable': True, - 'auto_install': True, - 'license': 'AGPL-3', -} diff --git a/hotel_calendar_channel_connector/i18n/es.po b/hotel_calendar_channel_connector/i18n/es.po deleted file mode 100644 index 9bcd96d2e..000000000 --- a/hotel_calendar_channel_connector/i18n/es.po +++ /dev/null @@ -1,88 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * hotel_calendar_channel_connector -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 11.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-03-13 21:59+0000\n" -"PO-Revision-Date: 2019-03-13 23:01+0100\n" -"Last-Translator: <>\n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Language: es\n" -"X-Generator: Poedit 1.8.7.1\n" - -#. module: hotel_calendar_channel_connector -#: model:ir.actions.act_window,name:hotel_calendar_channel_connector.calendar_channel_connector_issues_action -msgid "Channel Connector Issues" -msgstr "Aviso de Conexión" - -#. module: hotel_calendar_channel_connector -#. openerp-web -#: code:addons/hotel_calendar_channel_connector/static/src/xml/hotel_calendar_view.xml:30 -#, python-format -msgid "Channel:" -msgstr "Canal:" - -#. module: hotel_calendar_channel_connector -#: model:ir.model,name:hotel_calendar_channel_connector.model_hotel_reservation -msgid "Hotel Reservation" -msgstr "Reserva del hotel" - -#. module: hotel_calendar_channel_connector -#. openerp-web -#: code:addons/hotel_calendar_channel_connector/static/src/xml/hotel_calendar_view.xml:11 -#, python-format -msgid "Issues" -msgstr "Avisos" - -#. module: hotel_calendar_channel_connector -#: model:ir.ui.view,arch_db:hotel_calendar_channel_connector.hotel_reservation_view_form -msgid "Mark as Read" -msgstr "Marcar como leído" - -#. module: hotel_calendar_channel_connector -#: model:ir.actions.act_window,name:hotel_calendar_channel_connector.hotel_reservation_action_manager_request -msgid "Reservations to Assign from Channel" -msgstr "Reservas por asignar" - -#. module: hotel_calendar_channel_connector -#. openerp-web -#: code:addons/hotel_calendar_channel_connector/static/src/xml/hotel_calendar_templates.xml:4 -#, python-format -msgid "Section:" -msgstr "Sección:" - -#. module: hotel_calendar_channel_connector -#. openerp-web -#: code:addons/hotel_calendar_channel_connector/static/src/xml/hotel_calendar_view.xml:20 -#, python-format -msgid "To Assign" -msgstr "Por Asignar" - -#. module: hotel_calendar_channel_connector -#. openerp-web -#: code:addons/hotel_calendar_channel_connector/static/src/xml/hotel_calendar_templates.xml:11 -#, python-format -msgid "WuBook:" -msgstr "WuBook:" - -#. module: hotel_calendar_channel_connector -#: model:ir.model,name:hotel_calendar_channel_connector.model_bus_hotel_calendar -msgid "bus.hotel.calendar" -msgstr "bus.hotel.calendar" - -#. module: hotel_calendar_channel_connector -#: model:ir.model,name:hotel_calendar_channel_connector.model_hotel_calendar_management -msgid "hotel.calendar.management" -msgstr "hotel.calendar.management" - -#. module: hotel_calendar_channel_connector -#: model:ir.model,name:hotel_calendar_channel_connector.model_hotel_room_type_availability -msgid "hotel.room.type.availability" -msgstr "hotel.room.type.availability" diff --git a/hotel_calendar_channel_connector/models/__init__.py b/hotel_calendar_channel_connector/models/__init__.py deleted file mode 100644 index b67f6cb10..000000000 --- a/hotel_calendar_channel_connector/models/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright 2018-2019 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from . import inherited_hotel_reservation -from . import inherited_bus_hotel_calendar -from . import inherited_hotel_calendar_management -from . import inherited_hotel_room_type_availability diff --git a/hotel_calendar_channel_connector/models/inherited_bus_hotel_calendar.py b/hotel_calendar_channel_connector/models/inherited_bus_hotel_calendar.py deleted file mode 100644 index 19c3f56bb..000000000 --- a/hotel_calendar_channel_connector/models/inherited_bus_hotel_calendar.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2018-2019 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -import logging -from datetime import datetime -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT -from odoo import models, api -from odoo.addons.hotel_calendar.controllers.bus import HOTEL_BUS_CHANNEL_ID -_logger = logging.getLogger(__name__) - - -class BusHotelCalendar(models.TransientModel): - _inherit = 'bus.hotel.calendar' - - @api.model - def _generate_reservation_notif(self, vals): - notif = super(BusHotelCalendar, self)._generate_reservation_notif(vals) - reserv = self.env['hotel.reservation'].browse(vals['reserv_id']) - if any(reserv.channel_bind_ids): - notif['tooltip'].update({ - 'ota_name': reserv.channel_bind_ids[0].ota_id.name, - 'ota_reservation_id': reserv.channel_bind_ids[0].ota_reservation_id, - 'external_id': reserv.channel_bind_ids[0].external_id, - }) - elif reserv.splitted and reserv.parent_reservation.channel_bind_ids: - # chunks in splitted reservation has not channel_bind_ids - notif['tooltip'].update({ - 'ota_name': reserv.parent_reservation.channel_bind_ids[0].ota_id.name, - 'ota_reservation_id': reserv.parent_reservation.channel_bind_ids[0].ota_reservation_id, - 'external_id': reserv.parent_reservation.channel_bind_ids[0].external_id, - }) - return notif - - @api.model - def _generate_availability_notification(self, vals): - date_dt = datetime.strptime(vals['date'], DEFAULT_SERVER_DATE_FORMAT) - return { - 'type': 'availability', - 'availability': { - vals['room_type_id']: { - date_dt.strftime("%d/%m/%Y"): { - 'quota': vals['quota'], - 'max_avail': vals['max_avail'], - 'id': vals['id'], - 'no_ota': vals['no_ota'], - 'channel_avail': vals['channel_avail'], - }, - }, - }, - } - - @api.model - def send_availability_notification(self, vals): - notif = self._generate_availability_notification(vals) - self.env['bus.bus'].sendone((self._cr.dbname, 'hotel.reservation', - HOTEL_BUS_CHANNEL_ID), notif) - - @api.model - def _generate_issue_notification(self, ntype, title, issue_id, section, - message): - user_id = self.env['res.users'].browse(self.env.uid) - return { - 'type': 'issue', - 'subtype': ntype, - 'title': title, - 'username': user_id.partner_id.name, - 'userid': user_id.id, - 'issue': { - 'issue_id': issue_id, - 'section': section.upper(), - 'message': message, - }, - } - - @api.model - def send_issue_notification(self, ntype, title, issue_id, section, message): - notif = self._generate_issue_notification(ntype, title, issue_id, section, message) - self.env['bus.bus'].sendone( - (self._cr.dbname, 'hotel.reservation', - HOTEL_BUS_CHANNEL_ID), notif) - diff --git a/hotel_calendar_channel_connector/models/inherited_hotel_calendar_management.py b/hotel_calendar_channel_connector/models/inherited_hotel_calendar_management.py deleted file mode 100644 index b447e5a23..000000000 --- a/hotel_calendar_channel_connector/models/inherited_hotel_calendar_management.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2019 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from datetime import timedelta -from odoo import models, api, fields -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT - - -class HotelCalendarManagement(models.TransientModel): - _inherit = 'hotel.calendar.management' - - @api.model - def _hcalendar_availability_json_data(self, dfrom, dto): - date_start = fields.Date.from_string(dfrom) - date_end = fields.Date.from_string(dto) - date_diff = abs((date_end - date_start).days) + 1 - hotel_room_type_avail_obj = self.env['hotel.room.type.availability'] - room_types = self.env['hotel.room.type'].search([]) - json_data = {} - - for room_type in room_types: - json_data[room_type.id] = [] - for i in range(0, date_diff): - cur_date = date_start + timedelta(days=i) - cur_date_str = cur_date.strftime(DEFAULT_SERVER_DATE_FORMAT) - avail = hotel_room_type_avail_obj.search([ - ('date', '=', cur_date_str), - ('room_type_id', '=', room_type.id) - ]) - json_data[room_type.id].append( - self._generate_avalaibility_data(room_type, cur_date_str, avail)) - return json_data - - @api.model - def _generate_avalaibility_data(self, room_type, date, avail): - avalaibility_data = { - 'id': False, - 'date': date, - 'no_ota': False, - 'quota': room_type.channel_bind_ids.default_quota, - 'max_avail': room_type.channel_bind_ids.default_max_avail, - 'channel_avail': room_type.channel_bind_ids.default_availability - } - if avail: - avalaibility_data = { - 'id': avail.id, - 'date': avail.date, - 'no_ota': avail.no_ota, - 'quota': avail.quota, - 'max_avail': avail.max_avail, - 'channel_avail': avail.channel_bind_ids.channel_avail - } - return avalaibility_data - - @api.model - def _get_availability_values(self, vals): - vals = { - 'quota': vals['quota'], - 'max_avail': vals['max_avail'], - 'no_ota': vals['no_ota'], - } - return vals - - - def save_changes(self, pricelist_id, restriction_id, pricelist, - restrictions, availability={}): - res = super(HotelCalendarManagement, self).save_changes( - pricelist_id, - restriction_id, - pricelist, - restrictions, - availability=availability) - - room_type_obj = self.env['hotel.room.type'] - room_type_avail_obj = self.env['hotel.room.type.availability'] - # Save Availability - for k_avail in availability.keys(): - room_type_id = room_type_obj.browse(int(k_avail)) - for avail in availability[k_avail]: - vals = self._get_availability_values(avail) - avail_id = room_type_avail_obj.search([ - ('date', '=', avail['date']), - ('room_type_id', '=', room_type_id.id), - ], limit=1) - if not avail_id: - vals.update({ - 'date': avail['date'], - 'room_type_id': room_type_id.id, - }) - avail_id = room_type_avail_obj.with_context({ - 'mail_create_nosubscribe': True, - }).create(vals) - else: - avail_id.write(vals) - - self.env['channel.backend'].cron_push_changes() - return res - - @api.model - def get_hcalendar_all_data(self, dfrom, dto, pricelist_id, restriction_id, - withRooms): - res = super(HotelCalendarManagement, self).get_hcalendar_all_data( - dfrom, dto, pricelist_id, restriction_id, withRooms) - json_avails = self._hcalendar_availability_json_data(dfrom, dto) - res.update({ - 'availability': json_avails or [], - }) - return res diff --git a/hotel_calendar_channel_connector/models/inherited_hotel_reservation.py b/hotel_calendar_channel_connector/models/inherited_hotel_reservation.py deleted file mode 100644 index 1b2ca9477..000000000 --- a/hotel_calendar_channel_connector/models/inherited_hotel_reservation.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -import logging -from odoo import models, api -_logger = logging.getLogger(__name__) - - -class HotelReservation(models.Model): - _inherit = "hotel.reservation" - - - def _hcalendar_reservation_data(self, reservations): - vals = super(HotelReservation, self)._hcalendar_reservation_data(reservations) - # TODO: Improve performance by doing a SQL as in get_hcalendar_reservations_data() - hotel_reservation_obj = self.env['hotel.reservation'] - for v_rval in vals[0]: - reserv = hotel_reservation_obj.browse(v_rval['id']) - v_rval.update({ - 'fix_days': reserv.splitted or reserv.is_from_ota, - }) - # Update tooltips - if any(reserv.channel_bind_ids): - vals[1][reserv.id].update({ - 'ota_name': reserv.channel_bind_ids[0].ota_id.name, - 'ota_reservation_id': reserv.channel_bind_ids[0].ota_reservation_id, - 'external_id': reserv.channel_bind_ids[0].external_id, - }) - elif reserv.splitted and reserv.parent_reservation.channel_bind_ids: - # chunks in splitted reservation has not channel_bind_ids - vals[1][reserv.id].update({ - 'ota_name': reserv.parent_reservation.channel_bind_ids[0].ota_id.name, - 'ota_reservation_id': reserv.parent_reservation.channel_bind_ids[0].ota_reservation_id, - 'external_id': reserv.parent_reservation.channel_bind_ids[0].external_id, - }) - # REVIEW: What happens if the reservation is splitted and no parent with channel_bind_ids ¿? - return vals - - - def generate_bus_values(self, naction, ntype, ntitle=''): - self.ensure_one() - vals = super(HotelReservation, self).generate_bus_values(naction, ntype, ntitle) - vals.update({ - 'fix_days': self.splitted or self.is_from_ota, - }) - if any(self.channel_bind_ids): - vals.update({ - 'ota_name': self.channel_bind_ids[0].ota_id.name, - 'ota_reservation_id': self.channel_bind_ids[0].ota_reservation_id, - 'external_id': self.channel_bind_ids[0].external_id, - }) - return vals - - - def confirm(self): - for record in self: - if record.to_assign: - record.write({'to_assign': False}) - return super(HotelReservation, self).confirm() diff --git a/hotel_calendar_channel_connector/models/inherited_hotel_room_type_availability.py b/hotel_calendar_channel_connector/models/inherited_hotel_room_type_availability.py deleted file mode 100644 index 247cf6b78..000000000 --- a/hotel_calendar_channel_connector/models/inherited_hotel_room_type_availability.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2018-2019 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, api - - -class HotelRoomTypeAvailability(models.Model): - _inherit = 'hotel.room.type.availability' - - def _prepare_notif_values(self, record): - return { - 'date': record.date, - 'quota': record.quota, - 'no_ota': record.no_ota, - 'max_avail': record.max_avail, - 'room_type_id': record.room_type_id.id, - 'id': record.id, - 'channel_avail': record.channel_bind_ids.channel_avail, - } - - @api.model - def create(self, vals): - res = super(HotelRoomTypeAvailability, self).create(vals) - self.env['bus.hotel.calendar'].send_availability_notification( - self._prepare_notif_values(res) - ) - return res - - - def write(self, vals): - ret_vals = super(HotelRoomTypeAvailability, self).write(vals) - bus_hotel_calendar_obj = self.env['bus.hotel.calendar'] - for record in self: - bus_hotel_calendar_obj.send_availability_notification( - self._prepare_notif_values(record) - ) - return ret_vals - - - def unlink(self): - # Construct dictionary with relevant info of removed records - unlink_vals = [] - for record in self: - unlink_vals.append( - self._prepare_notif_values(record) - ) - res = super(HotelRoomTypeAvailability, self).unlink() - bus_hotel_calendar_obj = self.env['bus.hotel.calendar'] - for uval in unlink_vals: - bus_hotel_calendar_obj.send_availability_notification(uval) - return res diff --git a/hotel_calendar_channel_connector/readme/CONTRIBUTORS.rst b/hotel_calendar_channel_connector/readme/CONTRIBUTORS.rst deleted file mode 100644 index 55873688c..000000000 --- a/hotel_calendar_channel_connector/readme/CONTRIBUTORS.rst +++ /dev/null @@ -1 +0,0 @@ -* Alexandre Díaz diff --git a/hotel_calendar_channel_connector/readme/DESCRIPTION.rst b/hotel_calendar_channel_connector/readme/DESCRIPTION.rst deleted file mode 100644 index 10d829e13..000000000 --- a/hotel_calendar_channel_connector/readme/DESCRIPTION.rst +++ /dev/null @@ -1,7 +0,0 @@ -This module unify 'hotel_calendar' and 'hotel_channel_connector' - -Features: - - * Add 'cloud' button on calendar - * Adds restrictions to reservation management - * Call connector diff --git a/hotel_calendar_channel_connector/readme/ROADMAP.rst b/hotel_calendar_channel_connector/readme/ROADMAP.rst deleted file mode 100644 index e69de29bb..000000000 diff --git a/hotel_calendar_channel_connector/readme/USAGE.rst b/hotel_calendar_channel_connector/readme/USAGE.rst deleted file mode 100644 index ede695e0e..000000000 --- a/hotel_calendar_channel_connector/readme/USAGE.rst +++ /dev/null @@ -1 +0,0 @@ -No configuration required diff --git a/hotel_calendar_channel_connector/static/description/eiqui_logo.png b/hotel_calendar_channel_connector/static/description/eiqui_logo.png deleted file mode 100644 index ca3bd8c1321a85719347fea0ba79a2320b29eb69..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6240 zcmbuE`9GB3`^Rtl*fO$>Eru*3F(gaLGG!ZCW+KX-rI0k3P z%rUsiJX2Xo0JvH0V^7tfcm*M@oaGtOPA0!TaWJ?JM#RXxFnsV(O!B#UtjVithXIoX zb(!*C4YHDYJ9#_n+dR3_P6Xteo<^k!>U(jMoxJ+H)M@(hc3@c7v_QeX_tZp^4U7N( zj~GVrKl{kl&9=O7mDLlMFrggI@8m4UJ7hBXODwl2u_r$xGc(7`%#1a5wxFT3w7;sN zLUp{_PUF|s_S)3ImukDaq|D6QMk!)0z{ACNyf<&(_NumP8VTB4%9>#L)C1@Nsb(+K zbMY2J5FanEd0-=2;xIy7^I-({{`)d;EpIQc_nc+<%b`(U#>Z(I(3>^(3Bg;-g+)b- zPqu$)EzE(larVx|9lP^Mw99=f>+7<;=Y2oqT%;>llKBDWArhjjtPJ*`jz%skgWM>+ z-g0j#*(!D#DxDn7#xq(}B*hL`TU!^9ZpOJZD{%EzUZK7yAVs;rPKLEk%6+EH(B(`P zSN>Z0U1E}C6)<6Vw=|s9i=U2T_?9-j^e9>6;?KObsV1I~yzs-GXf}5YhBq&GSvUZX zk5p-d>aj$eV~6trVm9cbSe5OaJX&add%Kv7jErW`hGb%5B5Rh09uBwp$x7jGJJ#z@ z8K$_R$#-_<_)Mo1hhB|Cn_$=e=h~b%$SOI4*sz|Qsa|6jj646>at(UIlq=~ceSZ6vOjoq;eLKXyvDD7vGMIX z+O`0VVTjOvIM?01li!R04?D|UH9HF+-bBM8QH?n{IiA2jxP^X~HVILU2X4T}v9WqI z!djUCL=1}$1b0v<}zb=cpOQG+NscH$-Nx;V^Ff(*Jqso*c36MDhIjqd4X8z2WCNp{>`yWt5i6vH~x+T3ldn z@YCHpp~{I;P?R83_own3aXuH*T@mD@(AhZpLEeI9A(RmnuPh)WbQOYG4?ZI{ut}Lv zguo@bwkN%H8Gz*E^!K=MN) z*Z_o#48a&q_@ixc8U>C0zS-hWGk@Ue*+X$3h8pk!-T3L@D^w;pGqH}J%&!lf1MLxm z{qwk@rsfnF+q!p%)8a`o%m6ALToWNfCZ#Rz16KB7i>*q)w>vq@<)fomej%aCD^Iqe zV`{uvJ?wD3ljuS?`5KhDm_f3U(kn%`eWAjNif4#8N1oF>Sm|{cs{$x=Nk56To zasQDnZx}1Koc|d%3X1AQ@^{j&LN@6aFJ9CPSg{1!`CK%G>Zl>g5w}|GPu1z@BVv4} zm?I(Eu_&~#j1stbe9?-p!+1wqWu^B< z%L(gTN(`sa%=d%iNHE?)e=H8B7mz4OF6mxm5G~3Q-J~BCZ zJ7l{)-wZc0Xl>&_1`1xiinBz!ySf(hIPXWXaGntZuf*x^-@lRAp)1sAtk=l=+a%qi zK0b>>BKDFSf24m6Ao=3MqXBWWB|4jwMm%#xgpfL)dpS_Y$-yC6#x!%|Ty6VruGh@^ z(8h*_U-=rojyeA8fF3LsfU@X!htASl7g8?w-=CncV24a^cuGJ)o4vnOu`_^PdH{i^ zV$mpwJ5e8k`8+Yv;=eSM5wy|6#?bwwi847g~{~K$q*B8 zlV2a5V6P-6r0ht%uYOs&t_F?poKk1`Sm#e0q1jZ~MjAz=TV>{-mSVb%|H6o*A}KX}wKZHSN?B#SwvV|dT6fElZ}un=zFcz?ou;HiX!1TzB! zj^twMq@NgF%ALVY`7|XzK3HoSTUuIDP2lHZaV56Z9N1B}zHq=ZMPhNcpv>__5LCPt zXhRGw_!S$^TLP3>KcZB|)sOF|yRhki+g-noWhM*nyfGHZh! za@##4I2dhj&&r32z;ev)=z8TW2)=2njf6K)0S%EXC9*S z3~N~G`9|$S!c}$?1Ph$Ggp{9nbXS4whT-p_RD~x#70$fpG4c|@Aj#Exgn~d(@_+*Q z8o$A#klMR35)k-lVD!hIm{43WZ8^PfRoTF>A!fvN9tyuGz;oi(EO=h&s?4S{nIBFF zBGzG0@d<=f8)4Vf-`BY<(S@W|g)pbLJcI($u^=F8mZMhn)hF$jC0ZYG5$b9D=H6JT z+0~%shsE<$Gk}iw!_22wmMpNt8O4`&A8K7{W{@Wn{EshR(KA8xXh{fU?S%FsiD$hv zcQpZ{g)qGm(x{pl8q&f6%mghYyOc+(s9QQ7MqHNsiR9vqg@?@26C6Yp4)meS;i*>c z%{%>C7KYL6CTwPxR3lE%WNen3;^S*PR}z}#$zAc`3S@qHaw@h$KGEC=Ly&~bjG00r z?UiWkaKRAzli6qx5EhfT^wL<_$bWQQn+&jM7BYX$>IeXg5B*0&!0bUXwxY{YQ}~#4@YL-o0>ad zL0<`9I_LBZ=!PAbe0yh@2k|Sn^16R1S61R=cVKWpXSgN}|&lrlyL1JdjKLpL%)-?J_H1jPP|O!nv*rQzwjx4B*(fK(1|a zZ~P-IS&KYHzgAJyHshQSWiOt%G6j~r^ZvZ*1mEZw3Ce{*d| zz=Du2pP2UNH8={%B@+8R33xEm7FheWEl~LdSSl^Il-^z0`R4lV3B5xkRmT4L?5I+t99+-kd^^->8`l!KVJ5m`E5M9ldb4YZ}8lYe4Th31b58Pt8EP-m=3# z;lyCEI6JU@YIu2jGXSgOwXeWJT0S&{uBT8&@B8?eRXcSZa}5hyTpM!oH?HYA-uI9F zCQp9nrW!C_<6un2Qbl7K5M(LB$DpWB?sOU@i#1bfDxz*3l21$a2#l_Oh z1zsTRgA@I~RNX2Eaf>Np^0l{3bI6__1nwwH*a+H3usDOc*!-0!;QVLhUwVs~p{n#G zim5y2qBk?}XL~#Bg@5M+r78f*%u6QSt-ocP`8Uhx>6xQ?&?MytlMN%=YE`|M~H*M3FrsDg_LFZfU+eweh!VCh(z0AF)L@j2kjqp_nPoKZljr(@Re z(x)PWBw63t&ZCV+pDEVmpw5jqoIu3SpFceZKm;ixp;QF~Bf!Ibul6B)cRjG{z!VVT zZ&N;N*j~W!4#eoq($dm<>)%@HwP?yQF7G14y2iG&!L6~(?pPZb7-*0iap)MIQ&_f)(uci&6iop=Z|}-Lur&C>E_l2T-8?G?M69;{ zqv#z5Wv-~Is(P#TfeBqc3q|SB4vx98L#N?=pK&*TzwGqBpTPi-My1GBJg!7`_*poC zRUa795*r9^sjB*gAExB7ZrmV$Vn)3adV_rV^WgX*j+Ku9l_y_2&0RziJW=AtK!`zE zOaKV`MIBFeiYhBt!SoaM{<%uR(zDI8Axj53Z;*=Hq2c2{#$Gw;h8^yD*Q`EB$Bv{F zK|1NC03>S8C~zkD?tH$}$0G^tAZTuGE*LyV+1F)*?HD6y!6uBQN?F5eYpbhI-hyg} z9UhJ#w@>0;9zJwX`|3nJX)7rqG`@b_F{st`fl}4yD@1_yaSBKhc3o$8=pQ`lshTNU z&*=x8A+ufmI5C2YeERCck!%;3B|4N+U2T>@B5}d${CBA=YgR&p0tV;pUlX9z>|dX5 zJL%tQ_jOYhhN8-#sI%Du)GfkltLn%~58mN>u%kTL3Mio;Fu62`q;b8(4#iiCM1%=R z9_KQ4M>4T-0nN)f-X6&Q?SAnjG$ICzj&+g0Lgnm5k~aU6K}A46kUDiv&T}hJT-e*& zd$7W~a^ugKg{~2znxe>A>Pb0P_}eB^vzpj^AJihh+w{WO(y{2TjUN{F&gVZ_&b~Wi z``SwYjCFyCk}Yog3yz!M{pQV`=ws~duXmjs(TnTr{WGu?U~MTG^AwCLx~8auAQR`c z#+Z1SK`2znh$8)td#ba44_m@KGuVAA^RM?*V>&Y12omXjYh`UM<3HtQ$Pm%c(BKR* zP!qHM!$53Y&;z5>s{&ZGKE%Xcq#suNBOphmf9~M;oC!;8V%7B*>fBGYe?xA9_~X#_ zXbspv0HE`$`Tk8J7W4DMugNYU`|l}a%y-g@o0@inQWk960_kD+w}}Eli_eUZK9g$f zz<>OViNFr=qF^umk^SaO-EC%nLz$YJf30-pI}pzA6@H z&>q$LXtKeR=WUW}oPC8827`lkH)vi0DWoYsZ2yNq9FIh4{>dRNeSxhJX-jcq-{0SV z#G-FmNB$aW*}r3BTdyS{>ZS-bDXBdu3e;Yjv@4x-8=Zq+^>Gk*S!HGYd>KaqEp_W)y^UI3 zQxj&4z}p;lvjeq_O-)Oy{osDj$)4+{wfq6+z1__PU!6z4Y-ynQ4SX;` zaeuc!Z(UW=KHTU%4XlH|zzljE%x|Ef(tix?z6gZL5;ReW|3D;srWJnFDT4 zRC%PNpP!zSBLa>`L2#TAx~W+6RP1A7of8)Aq`|fD3JlNQ<1?nFrn*bPGk3_Jo`xT- zI)&3SY#g;tOr)Pj38;PSIs$V~QFBlb4;|$C_Li1g^A3vCIk(=uG@eaCh*v*RnD*LZ zdV1Orhr`)gTgTjZWu6OPL2}{1)=|38RHF;n1qs^vpg}9po!|oiSE6Q0Z?U|eHuZ@q z;`3ctEU0_Y<#&h)NG`K6wOY`_7PM%JkJ?6l@IA?sE0W*$gVC- zot-+AyVN}AvhtUEXY0Nf8$Erq)lNf@@A^3CA+GdJ&$V~4^99PyOnwh((z3j%O1=qU z7|{Z^#@(H-rmjwjjg5`s3(&V)K`pe<@?1edJ8v)e_**lsq@zO|>;$sX?B6E&%FLWR zl0uh%q$u__t_^^?jDG*#J*0@JD5uf^))JF~l4IvNbxKtB?6Vk?bXo34_;&|;iPGXE zDC5YU&RlMGN=&TaA2wsD70rL2wVUy6UP`&J5ghhqgo?a*4IbE z)#c?I3UqB3zxT%d04t&MtuNy~Q?c&1Jjc{rVEvOqP9ZpFp-~>Gx@W$*3vtw7y%Rw% z`oY^-IdGP9+TwLPyQv(oGc@}j5ilHj+S%E00^dMBW?Z2%hXFOLB_xIPL6Fx59<6^9 z2K$F&sMjMADSkxQyxB*#W5W&#@@T(b}6^BwZ5M3V2A!nV>;l5ev4Sy+YX_DAXLo%@C9YkukShV6C=gKny7=0C5mudmnK zZn(z_q?#JMj}ZJ5AA^0Y?@7~_%0$H*L*NMV+3Ywoh-Z^xQb0g}m}AG|iw`>YmLtQn zaODM|E6;|t&i|R4h&a;apBGR$>-flE;r#n<*wo>(ry+~A;4v})l{U2=FEo73Z#LOu z@996)PWxxVS>kbbn(Vv`;q2uM5u%E1=G%0W<5-t=&z$9PcKB26y~T7OVt@bfCGRha zSSu^5e{joNg$p00c{ucx?3*{7Eb?`ZUSarI2vEMDyXWTG*9P?tzhv|2d&itdmV0ty>x-wA6c&7xRJg&>0SG5wWiG+Y*nwPg}iICY$!02 zPq39U%PDz-?0cVmf$V;3Fq5+@>x<3*y~*Bkb}zi%$SkuAU#SQFa{!nam|v?wIY<2u DYa-VG diff --git a/hotel_calendar_channel_connector/static/description/index.html b/hotel_calendar_channel_connector/static/description/index.html deleted file mode 100644 index 9022331a1..000000000 --- a/hotel_calendar_channel_connector/static/description/index.html +++ /dev/null @@ -1,22 +0,0 @@ -
      -
      -
      -
      -

      HOTEL CALENDAR WUBOOK

      -

      Hotel Calendar WuBook

      -
      -
      -

      Hotel Calendar WuBook

      -
      - -
      - -
      -
      - - - -
      -
      -
      -
      diff --git a/hotel_calendar_channel_connector/static/sfx/book_cancelled.mp3 b/hotel_calendar_channel_connector/static/sfx/book_cancelled.mp3 deleted file mode 100644 index 10ffab8e7833cc8875b8d2c9950e52d74b395ed2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10152 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 - * Alexandre Díaz - */ - - /** ANIMATIONS **/ - @keyframes channel-manager-changes { - 0% { - color: red; - } - 5% { - transform: rotate(10deg); - } - 10% { - transform: rotate(0deg); - } - 15% { - transform: rotate(-10deg); - } - 20% { - transform: rotate(0deg); - } - 100% { - color: yellow; - } -} -@keyframes channel-manager-changes-text { - from { - color: white; - } - to { - color: black; - } -} - -#pms-menu #btn_channel_manager_request .incoming i { - animation-name: channel-manager-changes; - animation-duration: 2s; - animation-iteration-count: infinite; - animation-direction: alternate; -} - -#pms-menu #btn_channel_manager_request .button-highlight { - color: white; - background-color: #FFA500; -} - -#pms-menu #btn_channel_manager_request .button-highlight i { - color: white; -} \ No newline at end of file diff --git a/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_controller.js b/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_controller.js deleted file mode 100644 index 266291905..000000000 --- a/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_controller.js +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2018 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar_channel_connector.PMSHotelCalendarController', function (require) { -"use strict"; - -var PMSCalendarController = require('hotel_calendar.PMSCalendarController'); -var Core = require('web.core'); - -var QWeb = Core.qweb; - -var PMSHotelCalendarController = PMSCalendarController.include({ - _sounds: [], - SOUNDS: { NONE: 0, BOOK_NEW:1, BOOK_CANCELLED:2 }, - - init: function (parent, model, renderer, params) { - this._super.apply(this, arguments); - - this._sounds[this.SOUNDS.BOOK_NEW] = new Audio('hotel_calendar_channel_connector/static/sfx/book_new.mp3'); - this._sounds[this.SOUNDS.BOOK_CANCELLED] = new Audio('hotel_calendar_channel_connector/static/sfx/book_cancelled.mp3'); - }, - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- - - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - _play_sound: function(/*int*/SoundID) { - this._sounds[SoundID].play(); - }, - - _generate_reservation_tooltip_dict: function(tp) { - var qdict = this._super(tp); - qdict['ota_name'] = tp['ota_name']; - qdict['ota_reservation_id'] = tp['ota_reservation_id']; - qdict['external_id'] = tp['external_id']; - return qdict; - }, - - //-------------------------------------------------------------------------- - // Handlers - //-------------------------------------------------------------------------- - _update_buttons_counter: function (ev) { - this._super(ev); - var self = this; - var domain_reservations = [['to_assign', '=', true]]; - // FIXME: invalid domain search. Issues are in hotel_channel_connector_issue; - // var domain_issues = [['to_assign', '=', true]]; - var domain_issues = []; - $.when( - this.model.search_count(domain_reservations), - this.model.search_count(domain_issues), - ).then(function(a1, a2){ - self.renderer.update_buttons_counter_channel_connector(a1, a2); - }); - }, - - _onBusNotification: function(notifications) { - for (var notif of notifications) { - if (notif[0][1] === 'hotel.reservation') { - if (notif[1]['type'] === 'issue') { - if (notif[1]['userid'] === this.dataset.context.uid) { - continue; - } - - var issue = notif[1]['issue']; - var qdict = issue; - var msg = QWeb.render('HotelCalendarChannelConnector.NotificationIssue', qdict); - if (notif[1]['subtype'] === 'notify') { - this.do_notify(notif[1]['title'], msg, true); - } else if (notif[1]['subtype'] === 'warn') { - this.do_warn(notif[1]['title'], msg, true); - } - } - else if (notif[1]['type'] === 'reservation') { - var reserv = notif[1]['reservation']; - if (reserv['channel_type'] == 'web') { - if (notif[1]['action'] === 'create') { - this._play_sound(this.SOUNDS.BOOK_NEW); - } else if (notif[1]['action'] !== 'unlink' && reserv['state'] === 'cancelled') { - this._play_sound(this.SOUNDS.BOOK_CANCELLED); - } - } - } - } - } - this._super(notifications); - }, - - _refresh_view_options: function(active_index) { - /* btn_channel_manager_request */ - this._super(active_index); - - }, - -}); - -return PMSHotelCalendarController; - -}); diff --git a/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_management_controller.js b/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_management_controller.js deleted file mode 100644 index 89ed396e2..000000000 --- a/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_management_controller.js +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar_channel_connector.MPMSCalendarController', function (require) { -"use strict"; - -var MPMSCalendarController = require('hotel_calendar.MPMSCalendarController'); -var HotelConstants = require('hotel_calendar.Constants'); -var Core = require('web.core'); - -var QWeb = Core.qweb; - - -var MPMSCalendarController = MPMSCalendarController.include({ - - _onBusNotification: function (notifications) { - this._super.apply(this, arguments); - if (!this.renderer._hcalendar) { return; } - - for (var notif of notifications) { - if (notif[0][1] === 'hotel.reservation') { - switch (notif[1]['type']) { - case 'availability': - var avail = notif[1]['availability']; - var room_type = Object.keys(avail)[0]; - var day = Object.keys(avail[room_type])[0]; - var dt = HotelCalendarManagement.toMoment(day); - var availability = {}; - availability[room_type] = [{ - 'date': dt.format(HotelConstants.ODOO_DATE_MOMENT_FORMAT), - 'quota': avail[room_type][day]['quota'], - 'max_avail': avail[room_type][day]['max_avail'], - 'no_ota': avail[room_type][day]['no_ota'], - 'id': avail[room_type][day]['id'], - 'channel_avail': avail[room_type][day]['channel_avail'] - }]; - this.renderer._hcalendar.addAvailability(availability); - break; - } - } - } - }, - -}); - -return MPMSCalendarController; - -}); diff --git a/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_management_renderer.js b/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_management_renderer.js deleted file mode 100644 index 494d629f5..000000000 --- a/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_management_renderer.js +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2019 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar_channel_connector.MPMSCalendarRenderer', function (require) { -"use strict"; - -var MPMSCalendarRenderer = require('hotel_calendar.MPMSCalendarRenderer'); -var Core = require('web.core'); - -var QWeb = Core.qweb; - - -var MPMSCalendarRenderer = MPMSCalendarRenderer.include({ - - /** CUSTOM METHODS **/ - get_values_to_save: function() { - var values = this._super.apply(this, arguments); - if (values) { - var availability = this._hcalendar.getAvailability(true); - values.push(availability); - } - return values; - }, - -}); - -return MPMSCalendarRenderer; - -}); diff --git a/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_renderer.js b/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_renderer.js deleted file mode 100644 index 9c5c1b84d..000000000 --- a/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_renderer.js +++ /dev/null @@ -1,66 +0,0 @@ -/* global odoo, $ */ -// Copyright 2018 Alexandre Díaz -// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -odoo.define('hotel_calendar_channel_connector.PMSHotelCalendarRenderer', function (require) { - 'use strict'; - - var PMSCalendarRenderer = require('hotel_calendar.PMSCalendarRenderer'); - - var PMSHotelCalendarRenderer = PMSCalendarRenderer.include({ - - update_buttons_counter_channel_connector: function (nreservations, nissues) { - // Cloud Reservations - var $text = this.$el.find('#btn_channel_manager_request .cloud-text'); - $text.text(nreservations); - if (nreservations > 0) { - $text.parent().parent().addClass('button-highlight'); - $text.parent().addClass('incoming'); - } else { - $text.parent().parent().removeClass('button-highlight'); - $text.parent().removeClass('incoming'); - } - - // Issues - var $ninfo = this.$el.find('#pms-menu #btn_action_issues div.ninfo'); - $ninfo.text(nissues); - if (nissues) { - $ninfo.parent().parent().addClass('button-highlight'); - } else { - $ninfo.parent().parent().removeClass('button-highlight'); - } - }, - - init_calendar_view: function () { - var self = this; - return this._super().then(function () { - self.$el.find('#btn_channel_manager_request').on('click', function (ev) { - self.do_action("hotel_calendar_channel_connector.hotel_reservation_action_manager_request"); - }); - }); - }, - - _generate_search_domain: function(tsearch, type) { - var domain = this._super(tsearch, type); - - if (type === 'book') { - domain.splice(0, 0, '|'); - domain.push('|', - ['channel_bind_ids.external_id', 'ilike', tsearch], - ['channel_bind_ids.ota_reservation_id', 'ilike', tsearch]); - } - - return domain; - }, - - _generate_search_res_model: function(type) { - var [model, title] = this._super(type); - if (type === 'book') { - model = 'hotel.reservation'; - } - return [model, title]; - }, - - }); - - return PMSHotelCalendarRenderer; -}); diff --git a/hotel_calendar_channel_connector/static/src/xml/hotel_calendar_templates.xml b/hotel_calendar_channel_connector/static/src/xml/hotel_calendar_templates.xml deleted file mode 100644 index 9210f655e..000000000 --- a/hotel_calendar_channel_connector/static/src/xml/hotel_calendar_templates.xml +++ /dev/null @@ -1,25 +0,0 @@ - diff --git a/hotel_calendar_channel_connector/static/src/xml/hotel_calendar_view.xml b/hotel_calendar_channel_connector/static/src/xml/hotel_calendar_view.xml deleted file mode 100644 index 53cc525aa..000000000 --- a/hotel_calendar_channel_connector/static/src/xml/hotel_calendar_view.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - -
      - -
      -
      - -
      -
      -
      - - - - -
    • Channel:
    • -
      -
      -
      - -
      diff --git a/hotel_calendar_channel_connector/tests/__init__.py b/hotel_calendar_channel_connector/tests/__init__.py deleted file mode 100644 index 9920f3f1e..000000000 --- a/hotel_calendar_channel_connector/tests/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -#from . import test_folio diff --git a/hotel_calendar_channel_connector/tests/test_folio.py b/hotel_calendar_channel_connector/tests/test_folio.py deleted file mode 100644 index 824d9a05f..000000000 --- a/hotel_calendar_channel_connector/tests/test_folio.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2018 Alexandre Díaz -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from datetime import timedelta -from odoo.addons.hotel_calendar.tests.common import TestHotelCalendar -from odoo.addons.hotel import date_utils - - -class TestHotelReservations(TestHotelCalendar): - - def test_cancel_folio(self): - now_utc_dt = date_utils.now() diff --git a/hotel_calendar_channel_connector/views/actions.xml b/hotel_calendar_channel_connector/views/actions.xml deleted file mode 100644 index ee379e1f8..000000000 --- a/hotel_calendar_channel_connector/views/actions.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - Reservations to Assign from Channel - hotel.reservation - tree,form - - [('to_assign','=',True)] - - - - - - Channel Connector Issues - hotel.channel.connector.issue - tree,form - [('to_read','=',True)] - - - - diff --git a/hotel_calendar_channel_connector/views/general.xml b/hotel_calendar_channel_connector/views/general.xml deleted file mode 100644 index e221334b0..000000000 --- a/hotel_calendar_channel_connector/views/general.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - diff --git a/hotel_calendar_channel_connector/views/hotel_reservation.xml b/hotel_calendar_channel_connector/views/hotel_reservation.xml deleted file mode 100644 index 5c1d7aa76..000000000 --- a/hotel_calendar_channel_connector/views/hotel_reservation.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - hotel.toassign.reservation.tree - hotel.reservation - - - -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - channel.backend.tree - channel.backend - - - - - - - - - - Hotel Channel Backends - channel.backend - tree,form - - - - diff --git a/hotel_channel_connector/views/channel_hotel_reservation_views.xml b/hotel_channel_connector/views/channel_hotel_reservation_views.xml deleted file mode 100644 index 10bed411d..000000000 --- a/hotel_channel_connector/views/channel_hotel_reservation_views.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - channel.hotel.reservation.form - channel.hotel.reservation - -
      - - - - - - - -
      -
      -
      - - - channel.hotel.reservation.tree - channel.hotel.reservation - - - - - - - -
      diff --git a/hotel_channel_connector/views/channel_hotel_room_type_availability_views.xml b/hotel_channel_connector/views/channel_hotel_room_type_availability_views.xml deleted file mode 100644 index 1ded8cfed..000000000 --- a/hotel_channel_connector/views/channel_hotel_room_type_availability_views.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - channel.hotel.room.type.availability.form - channel.hotel.room.type.availability - -
      - - - - - - - - - - - - -
      -
      -
      - - - channel.hotel.room.type.availability.tree - channel.hotel.room.type.availability - - - - - - - - - -
      diff --git a/hotel_channel_connector/views/channel_hotel_room_type_restriction_item_views.xml b/hotel_channel_connector/views/channel_hotel_room_type_restriction_item_views.xml deleted file mode 100644 index 697439ae8..000000000 --- a/hotel_channel_connector/views/channel_hotel_room_type_restriction_item_views.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - channel.hotel.room.type.restriction.item.form - channel.hotel.room.type.restriction.item - -
      - - - - - - - -
      -
      -
      - - - channel.hotel.room.type.restriction.item.tree - channel.hotel.room.type.restriction.item - - - - - - - -
      diff --git a/hotel_channel_connector/views/channel_hotel_room_type_restriction_views.xml b/hotel_channel_connector/views/channel_hotel_room_type_restriction_views.xml deleted file mode 100644 index b468bce5e..000000000 --- a/hotel_channel_connector/views/channel_hotel_room_type_restriction_views.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - channel.hotel.room.type.restriction.form - channel.hotel.room.type.restriction - -
      - - - - - - - -
      -
      -
      - - - channel.hotel.room.type.restriction.tree - channel.hotel.room.type.restriction - - - - - - - - - Hotel Channel Connector Bindings - channel.hotel.room.type.restriction - tree,form - [] - - -
      diff --git a/hotel_channel_connector/views/channel_hotel_room_type_views.xml b/hotel_channel_connector/views/channel_hotel_room_type_views.xml deleted file mode 100644 index af7fe19ac..000000000 --- a/hotel_channel_connector/views/channel_hotel_room_type_views.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - channel.hotel.room.type.form - channel.hotel.room.type - -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      -
      -
      - - - channel.hotel.room.type.tree - channel.hotel.room.type - - - - - - - - - Hotel Channel Connector Bindings - channel.hotel.room.type - tree,form - [] - -
      diff --git a/hotel_channel_connector/views/channel_ota_info_views.xml b/hotel_channel_connector/views/channel_ota_info_views.xml deleted file mode 100644 index b0afa0036..000000000 --- a/hotel_channel_connector/views/channel_ota_info_views.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - channel.ota.info.form - channel.ota.info - -
      - - - - - - - - - - -
      -
      -
      - - - - channel.ota.info.tree - channel.ota.info - - - - - - - - -
      diff --git a/hotel_channel_connector/views/channel_product_pricelist_item_views.xml b/hotel_channel_connector/views/channel_product_pricelist_item_views.xml deleted file mode 100644 index 65329ae92..000000000 --- a/hotel_channel_connector/views/channel_product_pricelist_item_views.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - channel.product.pricelist.item.form - channel.product.pricelist.item - -
      - - - - -
      -
      -
      - - - channel.hotel.product.pricelist.item.tree - channel.product.pricelist.item - - - - - - - -
      diff --git a/hotel_channel_connector/views/channel_product_pricelist_views.xml b/hotel_channel_connector/views/channel_product_pricelist_views.xml deleted file mode 100644 index b0ae78574..000000000 --- a/hotel_channel_connector/views/channel_product_pricelist_views.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - channel.product.pricelist.form - channel.product.pricelist - -
      - - - - - - - - - -
      -
      -
      - - - channel.hotel.product.pricelist.tree - channel.product.pricelist - - - - - - - - - Hotel Channel Connector Bindings - channel.product.pricelist - tree,form - [] - - -
      diff --git a/hotel_channel_connector/views/hotel_channel_connector_issue_views.xml b/hotel_channel_connector/views/hotel_channel_connector_issue_views.xml deleted file mode 100644 index 0ed44f164..000000000 --- a/hotel_channel_connector/views/hotel_channel_connector_issue_views.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - hotel.channel.connector.issue.form - hotel.channel.connector.issue - -
      - -
      - -
      - - - - - - - - - - - - - - - -
      -
      -
      -
      - - - - hotel.channel.connector.issue.tree - hotel.channel.connector.issue - tree - - - - - - - - - - - - - - - - hotel.channel.connector.issue.search - hotel.channel.connector.issue - - - - - - - - - - - - - - - - Hotel Channel Connector Issues - hotel.channel.connector.issue - tree,form - - {"search_default_to_read":True} - - -
      diff --git a/hotel_channel_connector/views/hotel_room_type_availability_views.xml b/hotel_channel_connector/views/hotel_room_type_availability_views.xml deleted file mode 100644 index b7ac713cc..000000000 --- a/hotel_channel_connector/views/hotel_room_type_availability_views.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - hotel.room.type.availability.form - hotel.room.type.availability - -
      - - - -

      -
      - - - - - - - - - - - - - - - - -
      -
      - - -
      -
      -
      -
      - - - - hotel.room.type.availability.tree - hotel.room.type.availability - - - - - - - - - - - - - - Room Type Availability - hotel.room.type.availability - tree,form - - - - -
      diff --git a/hotel_channel_connector/views/inherited_hotel_folio_views.xml b/hotel_channel_connector/views/inherited_hotel_folio_views.xml deleted file mode 100644 index de8bb3a13..000000000 --- a/hotel_channel_connector/views/inherited_hotel_folio_views.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - hotel.folio - - - - - - - - - - - diff --git a/hotel_channel_connector/views/inherited_hotel_reservation_views.xml b/hotel_channel_connector/views/inherited_hotel_reservation_views.xml deleted file mode 100644 index 5a9c97e58..000000000 --- a/hotel_channel_connector/views/inherited_hotel_reservation_views.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - hotel.reservation - - - - - - - - - - - - - - - - - - - - - - - - - - - - {'readonly': [('is_from_ota','=',True),('able_to_modify_channel','=',False)]} - - - {'readonly': [('is_from_ota','=',True),('able_to_modify_channel','=',False)]} - - - {'readonly': [('is_from_ota','=',True),('able_to_modify_channel','=',False)]} - - - {'readonly': [('is_from_ota','=',True),('able_to_modify_channel','=',False)]} - - - {'readonly': [('is_from_ota','=',True),('able_to_modify_channel','=',False)]} - - - {'readonly': [('parent.is_from_ota','=',True),('parent.able_to_modify_channel','=',False)]} - True - - - - - - - - hotel.reservation - - - - - - - - - - - {'readonly': [('is_from_ota', '!=', False)]} - - - {'readonly': [('is_from_ota', '!=', False)]} - - - - - - - hotel.reservation - - - - - - - - - - - - - - - - view.hotel.reservation.graph - hotel.reservation - - - - - - - - - - - view.hotel.pivot.graph - hotel.reservation - - - - - - - - - - diff --git a/hotel_channel_connector/views/inherited_hotel_room_type_restriction_item_views.xml b/hotel_channel_connector/views/inherited_hotel_room_type_restriction_item_views.xml deleted file mode 100644 index 45f134e40..000000000 --- a/hotel_channel_connector/views/inherited_hotel_room_type_restriction_item_views.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - hotel.room.type.restriction.item - - - - - - - - - - - - - - - - - - - diff --git a/hotel_channel_connector/views/inherited_hotel_room_type_restriction_views.xml b/hotel_channel_connector/views/inherited_hotel_room_type_restriction_views.xml deleted file mode 100644 index 730b622f3..000000000 --- a/hotel_channel_connector/views/inherited_hotel_room_type_restriction_views.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - hotel.room.type.restriction - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - -
      - - - - - - - budget.tree (in hotel_data_bi) - budget - - - - - - - - - - - - diff --git a/hotel_data_bi/views/inherit_res_company.xml b/hotel_data_bi/views/inherit_res_company.xml deleted file mode 100644 index 7f610c7e0..000000000 --- a/hotel_data_bi/views/inherit_res_company.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - databi.config.view_company_form - res.company - - - - - - - - - - - - - - diff --git a/hotel_door_codes/README.rst b/hotel_door_codes/README.rst deleted file mode 100644 index 39b189275..000000000 --- a/hotel_door_codes/README.rst +++ /dev/null @@ -1,13 +0,0 @@ -DOOR CODES -========== - -Generate HOTEL DOOR CODES - - -Credits -======= - -Creator ------------- - -* Jose Luis Algara Toledo diff --git a/hotel_door_codes/__init__.py b/hotel_door_codes/__init__.py deleted file mode 100644 index d81805226..000000000 --- a/hotel_door_codes/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018-2019 Jose Luis Algara Toledo -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from . import models -from . import wizard diff --git a/hotel_door_codes/__manifest__.py b/hotel_door_codes/__manifest__.py deleted file mode 100644 index b08654307..000000000 --- a/hotel_door_codes/__manifest__.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Odoo, Open Source Management Solution -# Copyright (C) 2018-2019 Jose Luis Algara Toledo -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - -{ - 'name': 'Hotel Door Codes', - 'version': '3.0', - 'author': "Jose Luis Algara Toledo ", - 'website': 'https://www.aldahotels.com', - 'category': 'hotel code', - 'summary': "Generate Hotel door codes, in Pseudo random system", - 'description': "Hotel Door Codes. Now multihotel", - 'depends': [ - 'hotel', - # 'hotel_l10n_es' - ], - 'data': [ - 'wizard/door_code.xml', - 'data/menus.xml', - 'views/inherit_hotel_property.xml', - 'views/inherit_hotel_reservation.xml', - # 'views/inherit_report_viajero.xml', - ], - 'qweb': [], - 'test': [ - ], - 'installable': True, - 'auto_install': False, - 'application': False, - 'license': 'AGPL-3', -} diff --git a/hotel_door_codes/data/menus.xml b/hotel_door_codes/data/menus.xml deleted file mode 100644 index ca4aa8714..000000000 --- a/hotel_door_codes/data/menus.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - diff --git a/hotel_door_codes/i18n/es.po b/hotel_door_codes/i18n/es.po deleted file mode 100644 index 2dc9270f6..000000000 --- a/hotel_door_codes/i18n/es.po +++ /dev/null @@ -1,162 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * hotel_door_codes -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 11.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-11-27 12:40+0000\n" -"PO-Revision-Date: 2019-11-27 17:33+0100\n" -"Last-Translator: Jose Luis Algara Toledo \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: \n" -"Language: es\n" -"X-Generator: Poedit 2.0.6\n" - -#. module: hotel_door_codes -#: code:addons/hotel_door_codes/wizard/door_code.py:66 -#, python-format -msgid " to:" -msgstr " a:" - -#. module: hotel_door_codes -#: code:addons/hotel_door_codes/models/inherit_hotel_reservation.py:51 -#, python-format -msgid " to: " -msgstr " a: " - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_hotel_reservation_box_number -msgid "Box Number" -msgstr "Numero de caja" - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_hotel_reservation_box_code -msgid "Box code" -msgstr "Código de caja" - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_hotel_property_postcode -msgid "Characters after the code" -msgstr "Caracteres después del código" - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_hotel_property_precode -msgid "Characters before the door code" -msgstr "Caracteres antes del código de la puerta" - -#. module: hotel_door_codes -#: model:ir.ui.menu,name:hotel_door_codes.menu_hotel_door_code -msgid "Check door codes" -msgstr "Ver códigos de puertas" - -#. module: hotel_door_codes -#: model:ir.model,name:hotel_door_codes.model_res_company -msgid "Companies" -msgstr "Empresas" - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_door_code_create_uid -msgid "Created by" -msgstr "Creado por" - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_door_code_create_date -msgid "Created on" -msgstr "Creado en" - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_door_code_display_name -msgid "Display Name" -msgstr "Nombre para mostrar" - -#. module: hotel_door_codes -#: model:ir.actions.act_window,name:hotel_door_codes.door_code_act -#: model:ir.model,name:hotel_door_codes.model_door_code -#: model:ir.ui.view,arch_db:hotel_door_codes.hotel_door_code_view -msgid "Door Code Generator" -msgstr "Generador de códigos de puerta" - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_hotel_reservation_door_codes -#: model:ir.ui.view,arch_db:hotel_door_codes.door_code_view_property_form -msgid "Door Codes" -msgstr "Códigos de puerta" - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_door_code_door_code -msgid "Door code" -msgstr "Código de puerta" - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_door_code_date_end -msgid "End of period" -msgstr "Fin del periodo" - -#. module: hotel_door_codes -#: code:addons/hotel_door_codes/models/inherit_hotel_reservation.py:42 -#: code:addons/hotel_door_codes/wizard/door_code.py:57 -#, python-format -msgid "Entry Code: " -msgstr "Código de entrada: " - -#. module: hotel_door_codes -#: model:ir.ui.view,arch_db:hotel_door_codes.door_code_reservation_form -msgid "Entry Codes" -msgstr "Códigos de entrada" - -#. module: hotel_door_codes -#: model:ir.ui.view,arch_db:hotel_door_codes.hotel_door_code_view -msgid "Generate Code" -msgstr "Generar códigos" - -#. module: hotel_door_codes -#: model:ir.model,name:hotel_door_codes.model_hotel_property -msgid "Hotel" -msgstr "Hotel" - -#. module: hotel_door_codes -#: model:ir.model,name:hotel_door_codes.model_hotel_reservation -msgid "Hotel Reservation" -msgstr "Hotel Reservation" - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_door_code_id -msgid "ID" -msgstr "ID" - -#. module: hotel_door_codes -#: code:addons/hotel_door_codes/wizard/door_code.py:64 -#, python-format -msgid "It will change on " -msgstr "Cambiará el " - -#. module: hotel_door_codes -#: code:addons/hotel_door_codes/models/inherit_hotel_reservation.py:49 -#, python-format -msgid "It will change on Monday " -msgstr "Cambiará el lunes " - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_door_code___last_update -msgid "Last Modified on" -msgstr "Última modificación el" - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_door_code_write_uid -msgid "Last Updated by" -msgstr "Última actualización por" - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_door_code_write_date -msgid "Last Updated on" -msgstr "Ultima actualización en" - -#. module: hotel_door_codes -#: model:ir.model.fields,field_description:hotel_door_codes.field_door_code_date_start -msgid "Start of the period" -msgstr "Comienzo del periodo" diff --git a/hotel_door_codes/models/__init__.py b/hotel_door_codes/models/__init__.py deleted file mode 100644 index 6ec88ba49..000000000 --- a/hotel_door_codes/models/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018-2019 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from . import inherit_hotel_property -from . import inherit_hotel_reservation diff --git a/hotel_door_codes/models/inherit_hotel_property.py b/hotel_door_codes/models/inherit_hotel_property.py deleted file mode 100644 index adad5943b..000000000 --- a/hotel_door_codes/models/inherit_hotel_property.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018-2019 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from openerp import models, fields - - -class InheritHotelProperty(models.Model): - _inherit = 'hotel.property' - - precode = fields.Char('Characters before the door code', default=' ') - postcode = fields.Char('Characters after the code', default=' ') diff --git a/hotel_door_codes/models/inherit_hotel_reservation.py b/hotel_door_codes/models/inherit_hotel_reservation.py deleted file mode 100644 index 1353a279c..000000000 --- a/hotel_door_codes/models/inherit_hotel_reservation.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018-2019 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from openerp import models, fields, api, _ -from datetime import datetime, timedelta -from openerp.tools import DEFAULT_SERVER_DATE_FORMAT - - -class Inherit_hotel_reservation(models.Model): - _inherit = 'hotel.reservation' - - # Default methods - - def _compute_door_codes(self): - for res in self: - entrada = datetime.strptime( - res.checkin[:10], DEFAULT_SERVER_DATE_FORMAT) - if datetime.weekday(entrada) == 0: - entrada = entrada + timedelta(days=1) - salida = datetime.strptime( - res.checkout[:10], DEFAULT_SERVER_DATE_FORMAT) - if datetime.weekday(salida) == 0: - salida = salida - timedelta(days=1) - codes = (_('Entry Code: ') + - '' + - res.doorcode4(datetime.strftime(entrada, "%Y-%m-%d")) + - '') - while entrada <= salida: - if datetime.weekday(entrada) == 0: - codes += ("
      " + - _('It will change on Monday ') + - datetime.strftime(entrada, "%d-%m-%Y") + - _(' to: ') + - '' + - res.doorcode4(datetime.strftime( - entrada, "%Y-%m-%d")) + - '') - entrada = entrada + timedelta(days=1) - res.door_codes = codes - - # Fields declaration - door_codes = fields.Html( - 'Door Codes', - compute='_compute_door_codes') - box_number = fields.Integer('Box Number') - box_code = fields.Char('Box code') - - - def doorcode4(self, fecha): - # Calculate de Door Code... need a date in String format "%Y-%m-%d" - compan = self.env.user.hotel_id - if not compan.precode: - compan.precode = " " - if not compan.postcode: - compan.postcode = " " - d = datetime.strptime(fecha, DEFAULT_SERVER_DATE_FORMAT) - dia_semana = datetime.weekday(d) # Dias a restar y ponerlo en lunes - d = d - timedelta(days=dia_semana) - dtxt = d.strftime('%s.%%06d') % d.microsecond - dtxt = compan.precode + dtxt[4:8] + compan.postcode - return dtxt diff --git a/hotel_door_codes/static/description/icon.png b/hotel_door_codes/static/description/icon.png deleted file mode 100644 index 0d7c99f06fafe4f012cab618e056e8652ec140d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24484 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 KjTy_-E#^N^!qF`N diff --git a/hotel_door_codes/views/inherit_hotel_property.xml b/hotel_door_codes/views/inherit_hotel_property.xml deleted file mode 100644 index 602a1c46e..000000000 --- a/hotel_door_codes/views/inherit_hotel_property.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - door_code.config.view_property_form - hotel.property - - - - - - - - - - - - diff --git a/hotel_door_codes/views/inherit_hotel_reservation.xml b/hotel_door_codes/views/inherit_hotel_reservation.xml deleted file mode 100644 index cc66dfea7..000000000 --- a/hotel_door_codes/views/inherit_hotel_reservation.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - door_code.reservation_form - hotel.reservation - - - - - - - - - - - - - - - diff --git a/hotel_door_codes/wizard/__init__.py b/hotel_door_codes/wizard/__init__.py deleted file mode 100644 index 180966b56..000000000 --- a/hotel_door_codes/wizard/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018-2019 Jose Luis Algara Toledo -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from . import door_code diff --git a/hotel_door_codes/wizard/door_code.py b/hotel_door_codes/wizard/door_code.py deleted file mode 100644 index 2a4a8416c..000000000 --- a/hotel_door_codes/wizard/door_code.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Odoo, Open Source Management Solution -# Copyright (C) 2018-2019 Jose Luis Algara Toledo -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from datetime import datetime, timedelta -from odoo import api, fields, models, _ -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT - - -class DoorCodeWizard(models.TransientModel): - _name = 'door_code' - _description = 'Door Code Generator' - - # Default methods - - def _get_default_date_start(self): - return datetime.now().strftime(DEFAULT_SERVER_DATE_FORMAT) - - # Fields declaration - date_start = fields.Date( - "Start of the period", - default=_get_default_date_start) - date_end = fields.Date( - "End of period", - default=_get_default_date_start) - door_code = fields.Html("Door code") - - - def check_code(self): - reservation = self.env['hotel.reservation'] - - entrada = datetime.strptime( - self.date_start, DEFAULT_SERVER_DATE_FORMAT) - if datetime.weekday(entrada) == 0: - entrada = entrada + timedelta(days=1) - salida = datetime.strptime( - self.date_end, DEFAULT_SERVER_DATE_FORMAT) - if datetime.weekday(salida) == 0: - salida = salida - timedelta(days=1) - codes = (_('Entry Code: ') + - '' + - reservation.doorcode4(self.date_start) + - '') - while entrada <= salida: - if datetime.weekday(entrada) == 0: - codes += ("
      " + - _('It will change on ') + - datetime.strftime(entrada, "%d-%m-%Y") + - _(' to:') + - '' + - reservation.doorcode4(datetime.strftime( - entrada, "%Y-%m-%d")) + - '') - entrada = entrada + timedelta(days=1) - - return self.write({ - 'door_code': codes, - 'name': 'Ya te digo', - 'clear_breadcrumb': True, - 'target': 'current', - }) diff --git a/hotel_door_codes/wizard/door_code.xml b/hotel_door_codes/wizard/door_code.xml deleted file mode 100644 index ea1fc061c..000000000 --- a/hotel_door_codes/wizard/door_code.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Door codes - door_code - -
      - - - - - - - - - - -
      -
      -
      -
      -
      -
      - -
      -
      diff --git a/hotel_ine/__init__.py b/hotel_ine/__init__.py deleted file mode 100644 index c6369ae7d..000000000 --- a/hotel_ine/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2019 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from . import wizard -from . import models diff --git a/hotel_ine/__manifest__.py b/hotel_ine/__manifest__.py deleted file mode 100644 index 00247262e..000000000 --- a/hotel_ine/__manifest__.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Odoo, Open Source Management Solution -# Copyright (C) 2019 Jose Luis Algara Toledo -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -{ - 'name': 'Hotel Ine', - 'description': """ - Create de INE Report""", - 'version': '1.0.0', - 'license': 'AGPL-3', - 'summary': "Export hotel data for INE report", - 'author': "Jose Luis Algara (Alda hotels) ", - 'website': 'www.aldahotels.com', - 'depends': ['hotel', 'hotel_l10n_es'], - 'category': 'hotel/ine', - 'data': [ - 'wizard/inewizard.xml', - 'views/inherited_hotel_room_view.xml', - ], - 'demo': [ - ], - 'installable': True, - 'auto_install': False, - 'application': False, -} diff --git a/hotel_ine/models/__init__.py b/hotel_ine/models/__init__.py deleted file mode 100644 index c96e3b034..000000000 --- a/hotel_ine/models/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import inherited_hotel_room diff --git a/hotel_ine/models/inherited_hotel_room.py b/hotel_ine/models/inherited_hotel_room.py deleted file mode 100644 index cbd11348a..000000000 --- a/hotel_ine/models/inherited_hotel_room.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright 2019 Jose Luis Algara -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, fields - - -class HotelRoom(models.Model): - _inherit = 'hotel.room' - - in_ine = fields.Boolean('Included in the INE statistics', default=True) diff --git a/hotel_ine/static/description/icon.png b/hotel_ine/static/description/icon.png deleted file mode 100755 index c066d3473223c2250d2b12a81407b1fa68bc0470..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24576 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 - - - - hotel.room - - - - - - - - - - - - - diff --git a/hotel_ine/wizard/__init__.py b/hotel_ine/wizard/__init__.py deleted file mode 100644 index 53a5cd324..000000000 --- a/hotel_ine/wizard/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2019 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - -from . import inewizard diff --git a/hotel_ine/wizard/inewizard.py b/hotel_ine/wizard/inewizard.py deleted file mode 100644 index 56bd0962b..000000000 --- a/hotel_ine/wizard/inewizard.py +++ /dev/null @@ -1,321 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017-19 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp import models, fields, api -import base64 -import datetime -import calendar -import xml.etree.cElementTree as ET -from odoo.exceptions import UserError -import logging -_logger = logging.getLogger(__name__) - - -def get_years(): - year_list = [] - for i in range(2017, get_year()+1): - year_list.append((i, str(i))) - return year_list - - -def get_year(): - now = datetime.datetime.now() - return int(now.year) - - -def get_month(): - now = datetime.datetime.now() - month = int(now.month)-1 - if month <= 0: - month = 12 - return month - - -class Wizard(models.TransientModel): - _name = 'ine.wizard' - - txt_filename = fields.Char() - txt_binary = fields.Binary() - - ine_month = fields.Selection([(1, 'January'), (2, 'February'), - (3, 'March'), (4, 'April'), - (5, 'May'), (6, 'June'), (7, 'July'), - (8, 'August'), (9, 'September'), - (10, 'October'), (11, 'November'), - (12, 'December'), ], - string='Month', default=get_month()) - ine_year = fields.Selection(get_years(), default=get_year(), string='Year') - - adr_screen = fields.Char() - rev_screen = fields.Char() - - def generate_file(self): - _logger.warning("Start Export INE XML file") - last_day = calendar.monthrange(self.ine_year, self.ine_month)[1] - ine_start_search = datetime.date(self.ine_year, self.ine_month, 1) - ine_end_search = ine_start_search + datetime.timedelta(days=last_day) - compan = self.env.user.company_id - active_room = self.env['hotel.room'].search([('in_ine', '=', True)]) - message = "" - if not compan.property_name: - message = 'The NAME of the property is not established' - if not compan.name: - message = 'The NAME of the company is not established' - if not compan.vat: - message = 'The VAT is not established' - if not compan.ine_tourism: - message = 'The tourism number of the property is not established' - if message != "": - raise UserError(message) - return - encuesta = ET.Element("ENCUESTA") - cabezera = ET.SubElement(encuesta, "CABECERA") - fecha = ET.SubElement(cabezera, "FECHA_REFERENCIA") - ET.SubElement(fecha, "MES").text = "%02d" % (self.ine_month) - ET.SubElement(fecha, "ANYO").text = str(self.ine_year) - ET.SubElement(cabezera, "DIAS_ABIERTO_MES_REFERENCIA").text = ( - str(last_day)) - ET.SubElement(cabezera, "RAZON_SOCIAL").text = compan.name - ET.SubElement(cabezera, "NOMBRE_ESTABLECIMIENTO").text = ( - compan.property_name) - ET.SubElement(cabezera, "CIF_NIF").text = compan.vat[2:].strip() - ET.SubElement(cabezera, "NUMERO_REGISTRO").text = compan.ine_tourism - ET.SubElement(cabezera, "DIRECCION").text = compan.street - ET.SubElement(cabezera, "CODIGO_POSTAL").text = compan.zip - ET.SubElement(cabezera, "LOCALIDAD").text = compan.city - ET.SubElement(cabezera, "MUNICIPIO").text = compan.city - ET.SubElement(cabezera, "PROVINCIA" - ).text = compan.state_id.display_name - ET.SubElement(cabezera, "TELEFONO_1").text = ( - compan.phone.replace(' ', '')[0:12]) - ET.SubElement(cabezera, "TIPO").text = ( - compan.ine_category_id.category_type) - ET.SubElement(cabezera, "CATEGORIA").text = compan.ine_category_id.name - - ET.SubElement(cabezera, "HABITACIONES").text = str(len(active_room)) - ET.SubElement(cabezera, "PLAZAS_DISPONIBLES_SIN_SUPLETORIAS" - ).text = str(compan.ine_seats) - ET.SubElement(cabezera, "URL").text = compan.website - alojamiento = ET.SubElement(encuesta, "ALOJAMIENTO") - - all_room_nights = self.env['hotel.reservation.line'].search([ - ('date', '>=', ine_start_search), - ('date', '<', ine_end_search), - ('reservation_id.room_id.in_ine', '=', True), - ('reservation_id.state', '!=', "cancelled"), - ('reservation_id.reservation_type', '=', 'normal'), - ]) - room_nights = all_room_nights.filtered( - lambda n: (self.get_codeine(n.reservation_id))) - - # Creating the empty dictionary system - dic_tabla = [] - for room_night in room_nights: - ine_code = self.get_codeine(room_night.reservation_id) - if not next((item for item in dic_tabla if item["ine"] == ine_code), False): - for x in range(1, last_day+1): - dic_tabla.append({'ine': ine_code, - 'dia': x, - 'entradas': 0, - 'salidas': 0, - 'pernocta': 0 - }) - - # Adding overnight stays per day and INE code - pernocta_total = [] - for dia in range(1, last_day+1): - pernocta_total.append(0) - for room_night in room_nights.filtered( - lambda x: x.date == str(self.ine_year)+'-'+str( - self.ine_month).zfill(2)+'-'+str(dia).zfill(2)): - ine_code = self.get_codeine(room_night.reservation_id) - for idx, val in enumerate(dic_tabla): - if val['ine'] == ine_code and val['dia'] == dia: - dic_tabla[idx]['pernocta'] += room_night.reservation_id.adults - - # Calculating outputs and entries - last_stay = 0 - for idx, row in enumerate(dic_tabla): - if dic_tabla[idx]['dia'] == 1: - last_stay = 0 - - if last_stay < dic_tabla[idx]['pernocta']: - dic_tabla[idx]['entradas'] += dic_tabla[idx]['pernocta'] - last_stay - elif last_stay > dic_tabla[idx]['pernocta']: - dic_tabla[idx]['salidas'] += last_stay - dic_tabla[idx][ - 'pernocta'] - # _logger.warning("%s: %s Perenocta: %s In: %s Out: %s Last=%s", dic_tabla[idx]['ine'], dic_tabla[idx]['dia'], dic_tabla[idx]['pernocta'], dic_tabla[idx]['entradas'], dic_tabla[idx]['salidas'],last_stay) - last_stay = dic_tabla[idx]['pernocta'] - pernocta_total[(dic_tabla[idx]['dia'])-1] += dic_tabla[idx]['pernocta'] - - # "Print" outputs and entries - ine_residen = "" - for idx, row in enumerate(dic_tabla): - if ine_residen != dic_tabla[idx]['ine']: - ine_residen = dic_tabla[idx]['ine'] - residencia = ET.SubElement(alojamiento, "RESIDENCIA") - if len(dic_tabla[idx]['ine']) > 3: - ET.SubElement(residencia, "ID_PROVINCIA_ISLA" - ).text = str(dic_tabla[idx]['ine']) - else: - ET.SubElement(residencia, "ID_PAIS" - ).text = str(dic_tabla[idx]['ine']) - if ((dic_tabla[idx]['entradas'] != 0) - or (dic_tabla[idx]['salidas'] != 0) - or (dic_tabla[idx]['pernocta'] != 0)): - movimiento = ET.SubElement(residencia, "MOVIMIENTO") - ET.SubElement(movimiento, "N_DIA").text = ( - "%02d" % dic_tabla[idx]['dia']) - ET.SubElement(movimiento, "ENTRADAS").text = str( - dic_tabla[idx]['entradas']) - ET.SubElement(movimiento, "SALIDAS").text = str( - dic_tabla[idx]['salidas']) - ET.SubElement(movimiento, "PERNOCTACIONES").text = str( - dic_tabla[idx]['pernocta']) - - habitaciones = ET.SubElement(encuesta, "HABITACIONES") - # Bucle de HABITACIONES_MOVIMIENTO - - ingresos = 0 - habitaci = 0 - hab_vend = 0 - for dia in range(1, last_day+1): - suple = 0 - doble = 0 - dindi = 0 - otras = 0 - - habitaci += len(active_room) - habitaci -= self.env['hotel.reservation.line'].search([ - ('date', '=', str(self.ine_year)+'-'+str( - self.ine_month).zfill(2)+'-'+str(dia).zfill(2)), - ('reservation_id.reservation_type', '!=', 'normal'), - ], count=True) - for room_night in room_nights.filtered(lambda x: x.date == str( - self.ine_year)+'-'+str( - self.ine_month).zfill(2)+'-'+str( - dia).zfill(2)): - ingresos += room_night.price - hab_vend += 1 - - if room_night.reservation_id.room_id.capacity == 2: - if room_night.reservation_id.adults == 1: - dindi += 1 - else: - doble += 1 - else: - otras += 1 - if len(room_night.reservation_id.service_ids): - for service in room_night.reservation_id.service_ids: - if service.product_id.is_extra_bed: - suple += 1 - - # Here, we correct the extra beds - if pernocta_total[dia-1] > suple + compan.ine_seats: - suple = pernocta_total[dia-1] - compan.ine_seats - - habitaciones_m = ET.SubElement(habitaciones, - "HABITACIONES_MOVIMIENTO") - ET.SubElement(habitaciones_m, - "HABITACIONES_N_DIA").text = "%02d" % (dia) - ET.SubElement(habitaciones_m, - "PLAZAS_SUPLETORIAS").text = str(suple) - ET.SubElement(habitaciones_m, - "HABITACIONES_DOBLES_USO_DOBLE").text = str(doble) - ET.SubElement(habitaciones_m, - "HABITACIONES_DOBLES_USO_INDIVIDUAL").text = str( - dindi) - ET.SubElement(habitaciones_m, - "HABITACIONES_OTRAS").text = str(otras) - - precios = ET.SubElement(encuesta, "PRECIOS") - ET.SubElement(precios, - "REVPAR_MENSUAL").text = str(round(ingresos/habitaci, 2)) - ET.SubElement(precios, - "ADR_MENSUAL").text = str(round(ingresos/hab_vend, 2)) - ET.SubElement(precios, "ADR_TOUROPERADOR_TRADICIONAL").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_TOUROPERADOR_TRADICIONAL" - ).text = '0' - ET.SubElement(precios, - "ADR_TOUROPERADOR_ONLINE").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_TOUROPERADOR_ONLINE" - ).text = '0' - ET.SubElement(precios, - "ADR_EMPRESAS").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_EMPRESAS").text = '0' - ET.SubElement(precios, - "ADR_AGENCIA_DE_VIAJE_TRADICIONAL").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_AGENCIA_TRADICIONAL" - ).text = '0' - ET.SubElement(precios, "ADR_AGENCIA_DE_VIAJE_ONLINE").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_AGENCIA_ONLINE" - ).text = '0' - ET.SubElement(precios, "ADR_PARTICULARES").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_PARTICULARES").text = '0' - ET.SubElement(precios, - "ADR_GRUPOS").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_GRUPOS").text = '0' - ET.SubElement(precios, "ADR_INTERNET").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_INTERNET").text = '0' - ET.SubElement(precios, "ADR_OTROS").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_OTROS").text = '0' - - personal = ET.SubElement(encuesta, "PERSONAL_OCUPADO") - ET.SubElement(personal, "PERSONAL_NO_REMUNERADO").text = '0' - ET.SubElement(personal, - "PERSONAL_REMUNERADO_FIJO").text = str( - compan.ine_permanent_staff) - ET.SubElement(personal, - "PERSONAL_REMUNERADO_EVENTUAL").text = str( - compan.ine_eventual_staff) - - xmlstr = '' - xmlstr += ET.tostring(encuesta).decode('utf-8') - return self.write({ - 'txt_filename': 'INE_'+str(self.ine_month)+'_'+str( - self.ine_year) + '.' + 'xml', - 'adr_screen': 'ADR en el mes de la encuesta: '+str( - round(ingresos/habitaci, 2)) + '€ y ', - 'rev_screen': ' RevPar : '+str(round(ingresos/hab_vend, 2))+'€', - 'txt_binary': base64.encodestring(xmlstr.encode()) - }) - - @api.model - def get_codeine(self, reserva): - response = False - code = reserva[0].partner_id.code_ine_id - if code: - response = code.code - else: - for l in reserva[0].folio_id.checkin_partner_ids: - if l.code_ine_id: - response = l.code_ine_id.code - return response diff --git a/hotel_ine/wizard/inewizard.xml b/hotel_ine/wizard/inewizard.xml deleted file mode 100644 index 02a326938..000000000 --- a/hotel_ine/wizard/inewizard.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - INE File Download - ine.wizard - -
      - - - - - -
      -
      - - -
      - - -
      -
      - -
      - - -
      - - - - - - - - diff --git a/hotel_l10n_es/README.rst b/hotel_l10n_es/README.rst deleted file mode 100755 index bb1595313..000000000 --- a/hotel_l10n_es/README.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg - :alt: License: AGPL-3 - -Alda Hotels PMS-Checkin -============= -Checkin for Alda Hostels - - -Use -=== -Instal in Odoo and checkin - -Remember to complete the "hotel settings" configuration fields in the company file. - -Credits -======= - -Creator ------------- - -* Jose Luis Algara -* Darío Lodeiros diff --git a/hotel_l10n_es/__init__.py b/hotel_l10n_es/__init__.py deleted file mode 100755 index 18db0383d..000000000 --- a/hotel_l10n_es/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - -from . import models -from . import wizard diff --git a/hotel_l10n_es/__manifest__.py b/hotel_l10n_es/__manifest__.py deleted file mode 100755 index 5b9c8e978..000000000 --- a/hotel_l10n_es/__manifest__.py +++ /dev/null @@ -1,66 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - - -{ - 'name': 'Hotel l10n_es', - 'version': '9.0.0.3', - 'author': "Jose Luis Algara", - 'website': "http://www.aldahotels.com", - 'category': 'Hotel', - 'summary': "", - 'description': "", - 'depends': [ - 'hotel', - 'partner_contact_gender', - 'partner_contact_birthdate', - 'partner_firstname', - 'partner_vat_unique', - ], - 'data': [ - 'data/code.ine.csv', - 'data/tourism.category.csv', - 'data/report_viajero_paperformat.xml', - 'report/report_parte_viajero.xml', - 'views/report_viajero.xml', - 'wizard/police_wizard.xml', - 'views/category_tourism.xml', - 'views/code_ine.xml', - 'views/inherit_res_company.xml', - 'views/inherit_hotel_checkin_partner_views.xml', - 'security/ir.model.access.csv', - 'views/inherit_res_partner.xml', - 'views/inherited_hotel_reservation_views.xml', - 'views/report_viajero_document.xml', - 'views/report_viajero_head.xml', - 'views/report_viajero_data.xml', - 'views/report_viajero.xml', - 'views/hotel_l10n_es_hotel_name.xml' - ], - 'test': [ - ], - 'css': ['static/src/css/hotel_l10n_es.css'], - 'installable': True, - 'auto_install': False, - 'application': False, - 'license': 'AGPL-3', -} diff --git a/hotel_l10n_es/data/code.ine.csv b/hotel_l10n_es/data/code.ine.csv deleted file mode 100755 index 29f4a84a2..000000000 --- a/hotel_l10n_es/data/code.ine.csv +++ /dev/null @@ -1,309 +0,0 @@ -"id","code","name" -"__export__.code_ine_1","AFG","Afganistán" -"__export__.code_ine_2","ALB","Albania" -"__export__.code_ine_3","DEU","Alemania" -"__export__.code_ine_4","AND","Andorra" -"__export__.code_ine_5","AGO","Angola" -"__export__.code_ine_6","AIA","Anguila" -"__export__.code_ine_7","ATG","Antigua y Barbuda" -"__export__.code_ine_8","ANT","Antillas Neerlandesas" -"__export__.code_ine_9","ATA","Antártida" -"__export__.code_ine_10","SAU","Arabia Saudita" -"__export__.code_ine_11","DZA","Argelia" -"__export__.code_ine_12","ARG","Argentina" -"__export__.code_ine_13","ARM","Armenia" -"__export__.code_ine_14","ABW","Aruba" -"__export__.code_ine_15","AUS","Australia" -"__export__.code_ine_16","AUT","Austria" -"__export__.code_ine_17","AZE","Azerbaiyán" -"__export__.code_ine_18","BHS","Bahamas" -"__export__.code_ine_19","BHR","Bahrein" -"__export__.code_ine_20","BGD","Bangladesh" -"__export__.code_ine_21","BRB","Barbados" -"__export__.code_ine_22","BLZ","Belice" -"__export__.code_ine_23","BEN","Benin" -"__export__.code_ine_24","BMU","Bermudas" -"__export__.code_ine_25","BTN","Bhután" -"__export__.code_ine_26","BLR","Bielorrusia" -"__export__.code_ine_27","BOL","Bolivia" -"__export__.code_ine_28","BIH","Bosnia-Herzegovina" -"__export__.code_ine_29","BWA","Botswana" -"__export__.code_ine_30","BRA","Brasil" -"__export__.code_ine_31","BRN","Brunéi" -"__export__.code_ine_32","BGR","Bulgaria" -"__export__.code_ine_33","BFA","Burkina Fasso" -"__export__.code_ine_34","BDI","Burundi" -"__export__.code_ine_35","BEL","Bélgica" -"__export__.code_ine_36","CPV","Cabo Verde" -"__export__.code_ine_37","KHM","Camboya" -"__export__.code_ine_38","CMR","Camerún" -"__export__.code_ine_39","CAN","Canadá" -"__export__.code_ine_40","TCD","Chad" -"__export__.code_ine_41","CHL","Chile" -"__export__.code_ine_42","CHN","China" -"__export__.code_ine_43","CYP","Chipre" -"__export__.code_ine_44","COL","Colombia" -"__export__.code_ine_45","COM","Comoras" -"__export__.code_ine_46","COG","Congo, República del" -"__export__.code_ine_47","COD","Congo, República Democrática del" -"__export__.code_ine_48","PRK","Corea, Rep. Popular Democrática" -"__export__.code_ine_49","KOR","Corea, República de" -"__export__.code_ine_50","CIV","Costa de Marfil" -"__export__.code_ine_51","CRI","Costa Rica" -"__export__.code_ine_52","HRV","Croacia" -"__export__.code_ine_53","CUB","Cuba" -"__export__.code_ine_54","DNK","Dinamarca" -"__export__.code_ine_55","DMA","Dominica" -"__export__.code_ine_56","ECU","Ecuador" -"__export__.code_ine_57","EGY","Egipto" -"__export__.code_ine_58","SLV","El Salvador" -"__export__.code_ine_59","ARE","Emiratos Arabes Unidos" -"__export__.code_ine_60","ERI","Eritrea" -"__export__.code_ine_61","SVK","Eslovaquia" -"__export__.code_ine_62","SVN","Eslovenia" -"__export__.code_ine_63","USA","Estados Unidos de América" -"__export__.code_ine_64","EST","Estonia" -"__export__.code_ine_65","ETH","Etiopía" -"__export__.code_ine_66","PHL","Filipinas" -"__export__.code_ine_67","FIN","Finlandia" -"__export__.code_ine_68","FRA","Francia" -"__export__.code_ine_69","GAB","Gabón" -"__export__.code_ine_70","GMB","Gambia" -"__export__.code_ine_71","GEO","Georgia" -"__export__.code_ine_72","GHA","Ghana" -"__export__.code_ine_73","GIB","Gibraltar" -"__export__.code_ine_74","GRD","Granada" -"__export__.code_ine_75","GRC","Grecia" -"__export__.code_ine_76","GRL","Groenlandia" -"__export__.code_ine_77","GLP","Guadalupe" -"__export__.code_ine_78","GUM","Guam" -"__export__.code_ine_79","GTM","Guatemala" -"__export__.code_ine_80","GUF","Guayana Francesa" -"__export__.code_ine_81","GIN","Guinea" -"__export__.code_ine_82","GNQ","Guinea Ecuatorial" -"__export__.code_ine_83","GNB","Guinea-Bissau" -"__export__.code_ine_84","GUY","Guyana" -"__export__.code_ine_85","HTI","Haití" -"__export__.code_ine_86","HND","Honduras" -"__export__.code_ine_87","HKG","Hong-Kong" -"__export__.code_ine_88","HUN","Hungría" -"__export__.code_ine_89","IND","India" -"__export__.code_ine_90","IDN","Indonesia" -"__export__.code_ine_91","IRQ","Irak" -"__export__.code_ine_92","IRL","Irlanda" -"__export__.code_ine_93","IRN","Irán" -"__export__.code_ine_94","BVT","Isla Bouvert" -"__export__.code_ine_95","GGY","Isla de Guernesey" -"__export__.code_ine_96","JEY","Isla de Jersey" -"__export__.code_ine_97","IMN","Isla de Man" -"__export__.code_ine_98","CXR","Isla de Navidad" -"__export__.code_ine_99","ISL","Islandia" -"__export__.code_ine_100","CYM","Islas Caimán" -"__export__.code_ine_101","CCK","Islas Cocos" -"__export__.code_ine_102","COK","Islas Cook" -"__export__.code_ine_103","FLK","Islas Falkland (Malvinas)" -"__export__.code_ine_104","FRO","Islas Feroé" -"__export__.code_ine_105","FJI","Islas Fidji" -"__export__.code_ine_106","SGS","Islas Georgias del Sur y Sandwich" -"__export__.code_ine_107","HMD","Islas Heard e Mcdonald" -"__export__.code_ine_108","MNP","Islas Marianas del Norte" -"__export__.code_ine_109","MHL","Islas Marshall" -"__export__.code_ine_110","UMI","Islas Menores de EEUU" -"__export__.code_ine_111","NFK","Islas Norfolk" -"__export__.code_ine_112","PCN","Islas Pitcairn" -"__export__.code_ine_113","SLB","Islas Salomón" -"__export__.code_ine_114","TCA","Islas Turcas y Caicos" -"__export__.code_ine_115","VGB","Islas Vírgenes Británicas" -"__export__.code_ine_116","VIR","Islas Vírgenes de los EEUU" -"__export__.code_ine_117","WLF","Islas Wallis y Futura" -"__export__.code_ine_118","ALA","Islas Åland" -"__export__.code_ine_119","ISR","Israel" -"__export__.code_ine_120","ITA","Italia" -"__export__.code_ine_121","JAM","Jamaica" -"__export__.code_ine_122","JPN","Japón" -"__export__.code_ine_123","JOR","Jordania" -"__export__.code_ine_124","KAZ","Kazajstán" -"__export__.code_ine_125","KEN","Kenia" -"__export__.code_ine_126","KGZ","Kirguistán" -"__export__.code_ine_127","KIR","Kiribati" -"__export__.code_ine_128","KWT","Kuwait" -"__export__.code_ine_129","LAO","Laos" -"__export__.code_ine_130","LSO","Lesotho" -"__export__.code_ine_131","LVA","Letonia" -"__export__.code_ine_132","LBY","Libia" -"__export__.code_ine_133","LBR","Libéria" -"__export__.code_ine_134","LIE","Liechtenstein" -"__export__.code_ine_135","LTU","Lituania" -"__export__.code_ine_136","LUX","Luxemburgo" -"__export__.code_ine_137","LBN","Líbano" -"__export__.code_ine_138","MAC","Macao" -"__export__.code_ine_139","MKD","Macedonia, ARY" -"__export__.code_ine_140","MDG","Madagascar" -"__export__.code_ine_141","MYS","Malasia" -"__export__.code_ine_142","MWI","Malawi" -"__export__.code_ine_143","MDV","Maldivas" -"__export__.code_ine_144","MLT","Malta" -"__export__.code_ine_145","MLI","Malí" -"__export__.code_ine_146","MAR","Marruecos" -"__export__.code_ine_147","MTQ","Martinica" -"__export__.code_ine_148","MUS","Mauricio" -"__export__.code_ine_149","MRT","Mauritania" -"__export__.code_ine_150","MYT","Mayotte" -"__export__.code_ine_151","FSM","Micronesia" -"__export__.code_ine_152","MDA","Moldavia" -"__export__.code_ine_153","MNG","Mongolia" -"__export__.code_ine_154","MNE","Montenegro" -"__export__.code_ine_155","MSR","Montserrat" -"__export__.code_ine_156","MOZ","Mozambique" -"__export__.code_ine_157","MMR","Myanmar" -"__export__.code_ine_158","MEX","México" -"__export__.code_ine_159","MCO","Mónaco" -"__export__.code_ine_160","NAM","Namibia" -"__export__.code_ine_161","NRU","Naurú" -"__export__.code_ine_162","NPL","Nepal" -"__export__.code_ine_163","NIC","Nicaragua" -"__export__.code_ine_164","NGA","Nigeria" -"__export__.code_ine_165","NIU","Niue" -"__export__.code_ine_166","NOR","Noruega" -"__export__.code_ine_167","NCL","Nueva Caledonia" -"__export__.code_ine_168","NZL","Nueva Zelanda" -"__export__.code_ine_169","NER","Níger" -"__export__.code_ine_170","OMN","Omán" -"__export__.code_ine_171","PAK","Pakistán" -"__export__.code_ine_172","PLW","Palau" -"__export__.code_ine_173","PSE","Palestina, Territorio ocupado" -"__export__.code_ine_174","PAN","Panamá" -"__export__.code_ine_175","PNG","Papua Nueva Guinea" -"__export__.code_ine_176","PRY","Paraguay" -"__export__.code_ine_177","NLD","Países Bajos" -"__export__.code_ine_178","PER","Perú" -"__export__.code_ine_179","PYF","Polinesia Francesa" -"__export__.code_ine_180","POL","Polonia" -"__export__.code_ine_181","PRT","Portugal" -"__export__.code_ine_182","PRI","Puerto Rico" -"__export__.code_ine_183","QAT","Qatar" -"__export__.code_ine_184","GBR","Reino Unido" -"__export__.code_ine_185","CAF","República Centroafricana" -"__export__.code_ine_186","CZE","República Checa" -"__export__.code_ine_187","DOM","República Dominicana" -"__export__.code_ine_188","REU","Reunión" -"__export__.code_ine_189","ROU","Rumania" -"__export__.code_ine_190","RUS","Rusia" -"__export__.code_ine_191","RWA","Rwanda" -"__export__.code_ine_192","ESH","Sahara Occidental" -"__export__.code_ine_193","KNA","Saint Kitts y Nevis" -"__export__.code_ine_194","WSM","Samoa" -"__export__.code_ine_195","ASM","Samoa Americana" -"__export__.code_ine_196","BLM","San Bartolomé" -"__export__.code_ine_197","SMR","San Marino" -"__export__.code_ine_198","MAF","San Martín" -"__export__.code_ine_199","SPM","San Pedro y Miquelón" -"__export__.code_ine_200","VCT","San Vicente y las Granadinas" -"__export__.code_ine_201","SHN","Santa Elena" -"__export__.code_ine_202","LCA","Santa Lucía" -"__export__.code_ine_203","STP","Santo Tomé y Príncipe" -"__export__.code_ine_204","SEN","Senegal" -"__export__.code_ine_205","SRB","Serbia" -"__export__.code_ine_206","SYC","Seychelles" -"__export__.code_ine_207","SLE","Sierra Leona" -"__export__.code_ine_208","SGP","Singapur" -"__export__.code_ine_209","SYR","Siria" -"__export__.code_ine_210","SOM","Somalia" -"__export__.code_ine_211","LKA","Sri Lanka" -"__export__.code_ine_212","SWZ","Suazilandia" -"__export__.code_ine_213","ZAF","Sudáfrica" -"__export__.code_ine_214","SDN","Sudán" -"__export__.code_ine_215","SWE","Suecia" -"__export__.code_ine_216","CHE","Suiza" -"__export__.code_ine_217","SUR","Suriname" -"__export__.code_ine_218","SJM","Svalbard e Islas de Jan Mayen" -"__export__.code_ine_219","THA","Tailandia" -"__export__.code_ine_220","TWN","Taiwán" -"__export__.code_ine_221","TZA","Tanzania" -"__export__.code_ine_222","TJK","Tayikistan" -"__export__.code_ine_223","IOT","Terr. Británico del Oc. Indico" -"__export__.code_ine_224","ATF","Tierras Australes Francesas" -"__export__.code_ine_225","TLS","Timor Oriental" -"__export__.code_ine_226","TGO","Togo" -"__export__.code_ine_227","TKL","Tokelau" -"__export__.code_ine_228","TON","Tonga" -"__export__.code_ine_229","TTO","Trinidad y Tobago" -"__export__.code_ine_230","TKM","Turkmenistán" -"__export__.code_ine_231","TUR","Turquía" -"__export__.code_ine_232","TUV","Tuvalu" -"__export__.code_ine_233","TUN","Túnez" -"__export__.code_ine_234","UKR","Ucrania" -"__export__.code_ine_235","UGA","Uganda" -"__export__.code_ine_236","URY","Uruguay" -"__export__.code_ine_237","UZB","Uzbekistán" -"__export__.code_ine_238","VUT","Vanuatu" -"__export__.code_ine_239","VAT","Vaticano, Santa Sede" -"__export__.code_ine_240","VEN","Venezuela" -"__export__.code_ine_241","VNM","Vietnam" -"__export__.code_ine_242","YEM","Yemen" -"__export__.code_ine_243","DJI","Yibuti" -"__export__.code_ine_244","ZMB","Zambia" -"__export__.code_ine_245","ZWE","Zimbabwe" -"__export__.code_ine_246","KOS","Kosovo" -"__export__.code_ine_247","ES111","A Coruña" -"__export__.code_ine_248","ES112","Lugo" -"__export__.code_ine_249","ES113","Ourense" -"__export__.code_ine_250","ES114","Pontevedra" -"__export__.code_ine_251","ES120","Asturias" -"__export__.code_ine_252","ES130","Cantabria" -"__export__.code_ine_253","ES211","Araba/Álava" -"__export__.code_ine_254","ES212","Gipuzkoa" -"__export__.code_ine_255","ES213","Bizkaia" -"__export__.code_ine_256","ES220","Navarra" -"__export__.code_ine_257","ES230","La Rioja" -"__export__.code_ine_258","ES241","Huesca" -"__export__.code_ine_259","ES242","Teruel" -"__export__.code_ine_260","ES243","Zaragoza" -"__export__.code_ine_261","ES300","Madrid" -"__export__.code_ine_262","ES411","Ávila" -"__export__.code_ine_263","ES412","Burgos" -"__export__.code_ine_264","ES413","León" -"__export__.code_ine_265","ES414","Palencia" -"__export__.code_ine_266","ES415","Salamanca" -"__export__.code_ine_267","ES416","Segovia" -"__export__.code_ine_268","ES417","Soria" -"__export__.code_ine_269","ES418","Valladolid" -"__export__.code_ine_270","ES419","Zamora" -"__export__.code_ine_271","ES421","Albacete" -"__export__.code_ine_272","ES422","Ciudad Real" -"__export__.code_ine_273","ES423","Cuenca" -"__export__.code_ine_274","ES424","Guadalajara" -"__export__.code_ine_275","ES425","Toledo" -"__export__.code_ine_276","ES431","Badajoz" -"__export__.code_ine_277","ES432","Cáceres" -"__export__.code_ine_278","ES511","Barcelona" -"__export__.code_ine_279","ES512","Girona" -"__export__.code_ine_280","ES513","Lleida" -"__export__.code_ine_281","ES514","Tarragona" -"__export__.code_ine_282","ES521","Alicante / Alacant" -"__export__.code_ine_283","ES522","Castellón / Castelló" -"__export__.code_ine_284","ES523","Valencia / València" -"__export__.code_ine_285","ES530","Illes Balears" -"__export__.code_ine_286","ES531","Eivissa y Formentera" -"__export__.code_ine_287","ES532","Mallorca" -"__export__.code_ine_288","ES533","Menorca" -"__export__.code_ine_289","ES611","Almería" -"__export__.code_ine_290","ES612","Cádiz" -"__export__.code_ine_291","ES613","Córdoba" -"__export__.code_ine_292","ES614","Granada" -"__export__.code_ine_293","ES615","Huelva" -"__export__.code_ine_294","ES616","Jaén" -"__export__.code_ine_295","ES617","Málaga" -"__export__.code_ine_296","ES618","Sevilla" -"__export__.code_ine_297","ES620","Murcia" -"__export__.code_ine_298","ES630","Ceuta" -"__export__.code_ine_299","ES640","Melilla" -"__export__.code_ine_300","ES701","Las Palmas" -"__export__.code_ine_301","ES702","Santa Cruz de Tenerife" -"__export__.code_ine_302","ES703","El Hierro" -"__export__.code_ine_303","ES704","Fuerteventura" -"__export__.code_ine_304","ES705","Gran Canaria" -"__export__.code_ine_305","ES706","La Gomera" -"__export__.code_ine_306","ES707","La Palma" -"__export__.code_ine_307","ES708","Lanzarote" -"__export__.code_ine_308","ES709","Tenerife" diff --git a/hotel_l10n_es/data/report_viajero_paperformat.xml b/hotel_l10n_es/data/report_viajero_paperformat.xml deleted file mode 100755 index 3d1cfb282..000000000 --- a/hotel_l10n_es/data/report_viajero_paperformat.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - Parte de Viajero - - custom - 200 - 75 - Portrait - 1 - 3 - 0 - 0 - - 1 - 201 - - - - diff --git a/hotel_l10n_es/data/tourism.category.csv b/hotel_l10n_es/data/tourism.category.csv deleted file mode 100755 index f91ca57d3..000000000 --- a/hotel_l10n_es/data/tourism.category.csv +++ /dev/null @@ -1,54 +0,0 @@ -"id","name","category_type" -"__export__.category_1","H1","Hoteles" -"__export__.category_2","H2","Hoteles" -"__export__.category_3","H3","Hoteles" -"__export__.category_4","H4","Hoteles" -"__export__.category_5","H5","Hoteles" -"__export__.category_6","AP","Hoteles-apartamentos" -"__export__.category_7","HA","Hoteles-apartamentos" -"__export__.category_8","HA1","Hoteles-apartamentos" -"__export__.category_9","HA2","Hoteles-apartamentos" -"__export__.category_10","HA3","Hoteles-apartamentos" -"__export__.category_11","HA4","Hoteles-apartamentos" -"__export__.category_12","HA5","Hoteles-apartamentos" -"__export__.category_13","HR","Hoteles-residencias" -"__export__.category_14","HR1","Hoteles-residencias" -"__export__.category_15","HR2","Hoteles-residencias" -"__export__.category_16","HR3","Hoteles-residencias" -"__export__.category_17","HR4","Hoteles-residencias" -"__export__.category_18","HR5","Hoteles-residencias" -"__export__.category_19","M1","Moteles" -"__export__.category_20","M2","Moteles" -"__export__.category_21","M3","Moteles" -"__export__.category_22","PN3","Paradores Nacionales" -"__export__.category_23","PN4","Paradores Nacionales" -"__export__.category_24","PN5","Paradores Nacionales" -"__export__.category_25","CV1","Ciudades de vacaciones" -"__export__.category_26","CV2","Ciudades de vacaciones" -"__export__.category_27","CV3","Ciudades de vacaciones" -"__export__.category_28","RA1","Residencias-apartamentos" -"__export__.category_29","RA2","Residencias-apartamentos" -"__export__.category_30","RA3","Residencias-apartamentos" -"__export__.category_31","RA4","Residencias-apartamentos" -"__export__.category_32","HS","Hostales" -"__export__.category_33","HS1","Hostales" -"__export__.category_34","HS2","Hostales" -"__export__.category_35","HS3","Hostales" -"__export__.category_36","HSR","Hostales" -"__export__.category_37","HSR1","Hostales" -"__export__.category_38","HSR2","Hostales" -"__export__.category_39","HSR3","Hostales" -"__export__.category_40","HSE","Hostales generales" -"__export__.category_41","HSG","Hostales especiales" -"__export__.category_42","CH","Casas de Huéspedes" -"__export__.category_43","CH1","Casas de Huéspedes" -"__export__.category_44","F1","Fondas" -"__export__.category_45","F2","Fondas" -"__export__.category_46","F3","Fondas" -"__export__.category_47","P","Pensiones" -"__export__.category_48","P1","Pensiones" -"__export__.category_49","P2","Pensiones" -"__export__.category_50","P3","Pensiones" -"__export__.category_51","PA","Pensiones" -"__export__.category_52","PT","Pensiones" -"__export__.category_53","Otras","Otros" diff --git a/hotel_l10n_es/i18n/es.po b/hotel_l10n_es/i18n/es.po deleted file mode 100755 index 85a97a2f3..000000000 --- a/hotel_l10n_es/i18n/es.po +++ /dev/null @@ -1,812 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * hotel_l10n_es -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 11.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-04-28 21:46+0000\n" -"PO-Revision-Date: 2019-04-28 23:52+0200\n" -"Last-Translator: <>\n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: \n" -"Language: es\n" -"X-Generator: Poedit 1.8.7.1\n" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/wizard/police_wizard.py:113 -#, python-format -msgid " records added from " -msgstr "registros añadidos desde" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/wizard/police_wizard.py:114 -#, python-format -msgid " records processed." -msgstr "registros procesados." - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_document -msgid ", at" -msgstr ", a" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_year:0 -msgid "2017" -msgstr "2017" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_year:0 -msgid "2018" -msgstr "2018" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_year:0 -msgid "2019" -msgstr "2019" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_document -msgid "COPY TO THE USER" -msgstr "COPIA PARA EL USUARIO" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/wizard/ine_wizard.py:432 -#, python-format -msgid "ADR in the month of the survey: " -msgstr "ADR en el mes de la solicitud:" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.ine_wizard_form -msgid "ADR y RevPar" -msgstr "ADR y RevPar" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.view_police_download -msgid "Abrir web de la Guardia Civil para entregar el fichero generado:" -msgstr "Abrir web de la Guardia Civil para entregar el fichero generado:" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.view_police_download -msgid "Abrir web de la Polícia para entregar el fichero generado:" -msgstr "Abrir web de la Polícia para entregar el fichero generado:" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.ine_wizard_form -msgid "Abrir web del I.N.E.:" -msgstr "Abrir web del I.N.E.:" - -#. module: hotel_l10n_es -#: model:ir.actions.act_window,name:hotel_l10n_es.action_ine_download -msgid "Action INE File Download" -msgstr "Descargar archivo INE" - -#. module: hotel_l10n_es -#: model:ir.actions.act_window,name:hotel_l10n_es.action_police_download -msgid "Action Police File Download" -msgstr "Descargar archivo policía" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_ine_wizard_adr_screen -msgid "Adr Screen" -msgstr "Adr Screen" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_month:0 -msgid "April" -msgstr "Abril" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_month:0 -msgid "August" -msgstr "Agosto" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_company_ine_seats -msgid "Beds available" -msgstr "Camas disponibles" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_hotel_checkin_partner_birthdate_date -msgid "Birhdate" -msgstr "Fecha de Nacimiento" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.hotel_checkin_partner_reservation_view_tree -#: model:ir.ui.view,arch_db:hotel_l10n_es.hotel_checkin_partner_view_tree -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_data -msgid "Birthdate" -msgstr "F. de nacimiento" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_head -msgid "CIF:" -msgstr "CIF:" - -#. module: hotel_l10n_es -#: selection:res.partner,document_type:0 -msgid "Carta o Doc. de Identidad" -msgstr "Carta o Doc. de Identidad" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_tourism_category_name -msgid "Category" -msgstr "Categoría" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_tourism_category_category_type -msgid "Category type" -msgstr "Tipo de Categoría" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_code_ine_code -msgid "Code" -msgstr "Código" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_hotel_checkin_partner_code_ine_id -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_partner_code_ine_id -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_users_code_ine_id -msgid "Code Ine" -msgstr "Code Ine" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.view_partner_form -msgid "Code in INE" -msgstr "Código en INE" - -#. module: hotel_l10n_es -#: model:ir.model,name:hotel_l10n_es.model_res_company -msgid "Companies" -msgstr "Compañías" - -#. module: hotel_l10n_es -#: model:ir.model,name:hotel_l10n_es.model_res_partner -msgid "Contact" -msgstr "Contacto" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_police_wizard_download_num -msgid "Correlative number" -msgstr "Núm Correlativo" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/models/inherit_res_partner.py:51 -#: model:ir.model.fields,help:hotel_l10n_es.field_hotel_checkin_partner_code_ine_id -#: model:ir.model.fields,help:hotel_l10n_es.field_res_partner_code_ine_id -#: model:ir.model.fields,help:hotel_l10n_es.field_res_users_code_ine_id -#, python-format -msgid "Country or province of origin. Used for INE statistics." -msgstr "País o provincia de origen. Usado para estadísticas INE." - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.view_police_download -msgid "Create Police File" -msgstr "Archivo de Policía Creado" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_code_ine_create_uid -#: model:ir.model.fields,field_description:hotel_l10n_es.field_ine_wizard_create_uid -#: model:ir.model.fields,field_description:hotel_l10n_es.field_police_wizard_create_uid -#: model:ir.model.fields,field_description:hotel_l10n_es.field_tourism_category_create_uid -msgid "Created by" -msgstr "Creado por" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_code_ine_create_date -#: model:ir.model.fields,field_description:hotel_l10n_es.field_ine_wizard_create_date -#: model:ir.model.fields,field_description:hotel_l10n_es.field_police_wizard_create_date -#: model:ir.model.fields,field_description:hotel_l10n_es.field_tourism_category_create_date -msgid "Created on" -msgstr "Creado en" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.view_partner_form -msgid "Customer Link" -msgstr "Enlace Cliente" - -#. module: hotel_l10n_es -#: selection:res.partner,document_type:0 -msgid "DNI" -msgstr "DNI" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_police_wizard_download_date -msgid "Date" -msgstr "Fecha" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_month:0 -msgid "December" -msgstr "Diciembre" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_code_ine_display_name -#: model:ir.model.fields,field_description:hotel_l10n_es.field_ine_wizard_display_name -#: model:ir.model.fields,field_description:hotel_l10n_es.field_police_wizard_display_name -#: model:ir.model.fields,field_description:hotel_l10n_es.field_tourism_category_display_name -msgid "Display Name" -msgstr "Nombre mostrado" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.hotel_checkin_partner_reservation_view_tree -#: model:ir.ui.view,arch_db:hotel_l10n_es.hotel_checkin_partner_view_tree -msgid "Doc. Number" -msgstr "Núm. de Documento" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_hotel_checkin_partner_document_type -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_partner_document_type -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_users_document_type -msgid "Doc. type" -msgstr "Tipo de Documento" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_hotel_checkin_partner_document_expedition_date -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_partner_document_expedition_date -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_users_document_expedition_date -msgid "Document expedition date" -msgstr "Fecha de Expedición" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_hotel_checkin_partner_document_number -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_partner_document_number -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_users_document_number -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_data -msgid "Document number" -msgstr "Nº de documento:" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_head -msgid "Document number:" -msgstr "Nº de documento:" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/wizard/ine_wizard.py:142 -#, python-format -msgid "ERROR: Usuario sin codigo de INE: " -msgstr "ERROR: Usuario sin codigo de INE: " - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_document -msgid "" -"En nombre de la empresa\n" -" GRUPO ALDA HOTELS\n" -" compuesto por Alda Rías Baixas SL, Alda Compostela SL, Alda Castilla SL, Hoteles Rías Altas SL, Comphostel Gestión Patrimonial SL y Consultores Hoteleros Integrales SL, tratamos la información que nos facilita, con el fin de prestarle el servicio\n" -" solicitado y realizar la facturación del mismo. Se conservarán mientras se mantenga la relación comercial o durante los años necesarios para cumplir con las obligaciones legales. No se cederán a terceros salvo en los casos en que exista una\n" -" obligación legal. Usted tiene derecho a obtener información sobre el tratamiento de sus datos personales, acceder, rectificar los inexactos o solicitar su supresión cuando ya no sean necesarios, en la dirección\n" -" protecciondatos@aldahotels.com\n" -" Asimismo hemos solicitado que confirme esta autorización para ofrecerle nuestros servicios y poder fidelizarle como cliente." -msgstr "" -"En nombre de la empresa\n" -" GRUPO ALDA HOTELS\n" -" compuesto por Alda Rías Baixas SL, Alda Compostela SL, Alda Castilla SL, Hoteles Rías Altas SL, Comphostel Gestión Patrimonial SL y Consultores Hoteleros Integrales SL, tratamos la información que nos facilita, con el fin de prestarle el servicio\n" -" solicitado y realizar la facturación del mismo. Se conservarán mientras se mantenga la relación comercial o durante los años necesarios para cumplir con las obligaciones legales. No se cederán a terceros salvo en los casos en que exista una\n" -" obligación legal. Usted tiene derecho a obtener información sobre el tratamiento de sus datos personales, acceder, rectificar los inexactos o solicitar su supresión cuando ya no sean necesarios, en la dirección\n" -" protecciondatos@aldahotels.com\n" -" Asimismo hemos solicitado que confirme esta autorización para ofrecerle nuestros servicios y poder fidelizarle como cliente." - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_document -msgid "" -"En nombre de la empresa\n" -" GRUPO ALDA HOTELS\n" -" compuesto por Alda Rías Baixas SL, Alda Compostela SL, Alda Castilla SL, Hoteles Rías Altas SL, Comphostel Gestión Patrimonial SL y Consultores Hoteleros Integrales SL, tratamos la información que nos facilita, con el fin de prestarle el servicio\n" -" solicitado y realizar la facturación del mismo. Se conservarán mientras se mantenga la relación comercial o durante los años necesarios para cumplir con las obligaciones legales. No se cederán a terceros salvo en los casos en que exista una\n" -" obligación legal. Usted tiene derecho a obtener información sobre el tratamiento de sus datos personales, acceder, rectificar los inexactos o solicitar su supresión cuando ya no sean necesarios, en la dirección\n" -" protecciondatos@aldahotels.com\n" -" Asimismo solicito confirme esta autorización para ofrecerle nuestros servicios y poder fidelizarle como cliente.
      Si ___ No ___" -msgstr "" -"En nombre de la empresa\n" -" GRUPO ALDA HOTELS\n" -" compuesto por Alda Rías Baixas SL, Alda Compostela SL, Alda Castilla SL, Hoteles Rías Altas SL, Comphostel Gestión Patrimonial SL y Consultores Hoteleros Integrales SL, tratamos la información que nos facilita, con el fin de prestarle el servicio\n" -" solicitado y realizar la facturación del mismo. Se conservarán mientras se mantenga la relación comercial o durante los años necesarios para cumplir con las obligaciones legales. No se cederán a terceros salvo en los casos en que exista una\n" -" obligación legal. Usted tiene derecho a obtener información sobre el tratamiento de sus datos personales, acceder, rectificar los inexactos o solicitar su supresión cuando ya no sean necesarios, en la dirección\n" -" protecciondatos@aldahotels.com\n" -" Asimismo solicito confirme esta autorización para ofrecerle nuestros servicios y poder fidelizarle como cliente.
      Si ___ No ___" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_data -msgid "Entry date" -msgstr "Fecha de entrada" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_police_wizard_error_partner -msgid "Error Partner" -msgstr "Error Cliente" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_company_ine_eventual_staff -msgid "Eventual Staff" -msgstr "Staff eventual" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_data -msgid "Exit date" -msgstr "Fecha Salida" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.hotel_checkin_partner_reservation_view_tree -#: model:ir.ui.view,arch_db:hotel_l10n_es.hotel_checkin_partner_view_tree -msgid "Exp. Date" -msgstr "Fecha de Expedición" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_data -msgid "Expedition date" -msgstr "Fecha expedición" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_month:0 -msgid "February" -msgstr "Febrero" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/wizard/police_wizard.py:123 -#, python-format -msgid "File not generated by configuration error." -msgstr "Archivo no generado por errores de configuración." - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_hotel_checkin_partner_firstname -msgid "First name" -msgstr "Nombre" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/models/inherit_res_partner.py:235 -#, python-format -msgid "For safety reasons, you cannot merge more than 3 contacts together. You can re-open the wizard several times if needed." -msgstr "Por razones de seguridad no se pudo fusionar a los contactos" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_hotel_checkin_partner_gender -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_data -msgid "Gender" -msgstr "Género" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.ine_wizard_form -msgid "Generar estadistica para el I.N.E." -msgstr "Generar estadistica para el I.N.E." - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.view_police_download -msgid "Generate Police file" -msgstr "Generar fichero para la Policía" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.ine_wizard_form -msgid "Generate file" -msgstr "Archivo creado!" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/wizard/police_wizard.py:118 -#, python-format -msgid "Generated file. Download it and give it to the police." -msgstr "Archivo creado!. Descargalo para entregarlo a la Policía." - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.view_police_download -msgid "Guardia Civil " -msgstr "Guardia Civil " - -#. module: hotel_l10n_es -#: model:ir.model,name:hotel_l10n_es.model_hotel_reservation -msgid "Hotel Reservation" -msgstr "Reserva del hotel" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.view_company_form -msgid "Hotel Settings" -msgstr "Configuración del Hotel" - -#. module: hotel_l10n_es -#: model:ir.model.fields,help:hotel_l10n_es.field_res_company_ine_category_id -msgid "Hotel category in the Ministry of Tourism. Used for INE statistics." -msgstr "Categoría del Hotel en el Ministerio de Turismo. Usado para las estadísticas del INE." - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_code_ine_id -#: model:ir.model.fields,field_description:hotel_l10n_es.field_ine_wizard_id -#: model:ir.model.fields,field_description:hotel_l10n_es.field_police_wizard_id -#: model:ir.model.fields,field_description:hotel_l10n_es.field_tourism_category_id -msgid "ID" -msgstr "ID (identificación)" - -#. module: hotel_l10n_es -#: model:ir.ui.menu,name:hotel_l10n_es.menu_ine_download -msgid "INE File Download" -msgstr "Descargar Archivo INE" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.view_company_form -msgid "INE and Police data" -msgstr "INE y Datos Policía" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_company_checkin_img -msgid "Image in checkin" -msgstr "Imagen en Checkin" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/models/inherit_hotel_checkin_partner.py:102 -#, python-format -msgid "Incorrect DNI" -msgstr "DNI Incorrecto" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_company_ine_category_id -msgid "Ine Category" -msgstr "Categoría Ine" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_month:0 -msgid "January" -msgstr "Enero" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_month:0 -msgid "July" -msgstr "Julio" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_month:0 -msgid "June" -msgstr "Junio" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_code_ine___last_update -#: model:ir.model.fields,field_description:hotel_l10n_es.field_ine_wizard___last_update -#: model:ir.model.fields,field_description:hotel_l10n_es.field_police_wizard___last_update -#: model:ir.model.fields,field_description:hotel_l10n_es.field_tourism_category___last_update -msgid "Last Modified on" -msgstr "Última modificación en" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_code_ine_write_uid -#: model:ir.model.fields,field_description:hotel_l10n_es.field_ine_wizard_write_uid -#: model:ir.model.fields,field_description:hotel_l10n_es.field_police_wizard_write_uid -#: model:ir.model.fields,field_description:hotel_l10n_es.field_tourism_category_write_uid -msgid "Last Updated by" -msgstr "Última actualización de" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_code_ine_write_date -#: model:ir.model.fields,field_description:hotel_l10n_es.field_ine_wizard_write_date -#: model:ir.model.fields,field_description:hotel_l10n_es.field_police_wizard_write_date -#: model:ir.model.fields,field_description:hotel_l10n_es.field_tourism_category_write_date -msgid "Last Updated on" -msgstr "Última actualización en" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_hotel_checkin_partner_lastname -msgid "Last name" -msgstr "Apellido" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_police_wizard_log_police -msgid "Log Police" -msgstr "Log Policía" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_month:0 -msgid "March" -msgstr "Marzo" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_month:0 -msgid "May" -msgstr "Mayo" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/models/inherit_res_partner.py:259 -#, python-format -msgid "Merged with the following partners:" -msgstr "Fusionado con los siguientes contactos:" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_ine_wizard_ine_month -msgid "Month" -msgstr "Mes" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_hotel_checkin_partner_name -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_data -msgid "Name" -msgstr "Nombre" - -#. module: hotel_l10n_es -#: model:ir.model.fields,help:hotel_l10n_es.field_res_company_property_name -msgid "Name of the Hotel/Property." -msgstr "Nombre del Hotel/Propiedad." - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/wizard/ine_wizard.py:440 -#, python-format -msgid "No data in this month" -msgstr "No hay información este mes" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_month:0 -msgid "November" -msgstr "Noviembre" - -#. module: hotel_l10n_es -#: model:ir.model.fields,help:hotel_l10n_es.field_police_wizard_download_num -msgid "Number provided by the police" -msgstr "Núm. provisto por la policía" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_month:0 -msgid "October" -msgstr "Octubre" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_data -msgid "Origin" -msgstr "Origen" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_head -msgid "PART OF TRAVELERS ENTRY" -msgstr "PARTE DE ENTRADA DE VIAJEROS" - -#. module: hotel_l10n_es -#: model:ir.actions.report,name:hotel_l10n_es.action_report_viajero -msgid "Parte de Viajero" -msgstr "Parte de Viajero" - -#. module: hotel_l10n_es -#: selection:res.partner,document_type:0 -msgid "Pasaporte" -msgstr "Pasaporte" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_company_ine_permanent_staff -msgid "Permanent Staff" -msgstr "Permanent Staff" - -#. module: hotel_l10n_es -#: selection:res.partner,document_type:0 -msgid "Permiso Residencia Español" -msgstr "Permiso Residencia Español" - -#. module: hotel_l10n_es -#: selection:res.partner,document_type:0 -msgid "Permiso Residencia Europeo" -msgstr "Permiso Residencia Europeo" - -#. module: hotel_l10n_es -#: selection:res.partner,document_type:0 -msgid "Permiso de Conducir" -msgstr "Permiso de Conducir" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_code_ine_name -msgid "Place" -msgstr "Sitio" - -#. module: hotel_l10n_es -#: model:ir.ui.menu,name:hotel_l10n_es.menu_police_download -msgid "Police File Download" -msgstr "Desacargar Archivo Policía" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_company_police_number -msgid "Police number" -msgstr "Número Policía" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.view_police_download -msgid "Policia " -msgstr "Policia " - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.ine_wizard_form -msgid "Presentar encuesta I.N.E. " -msgstr "Presentar encuesta I.N.E. " - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.hotel_reservation_view_form -msgid "Print All Checkins" -msgstr "Imprimir todos los Checkins" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.hotel_checkin_partner_view_form -#: model:ir.ui.view,arch_db:hotel_l10n_es.hotel_checkin_partner_view_tree -msgid "Print in PDF" -msgstr "Imprimir en PDF" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/wizard/police_wizard.py:110 -#, python-format -msgid "Problem generating the file. Checkin without data, or incorrect data: " -msgstr "Problema generando el archivo. Checkin sin datos, o con datos incorrectos: " - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_company_property_name -msgid "Property name" -msgstr "Nombre propiedad" - -#. module: hotel_l10n_es -#: model:ir.model.fields,help:hotel_l10n_es.field_res_company_ine_tourism -msgid "Registration number in the Ministry of Tourism. Used for INE statistics." -msgstr "Núm. de Registro en el Ministerio de Turismo. Usado en las estadísticas del INE." - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_ine_wizard_rev_screen -msgid "Rev Screen" -msgstr "Rev Screen" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_company_ine_rooms -msgid "Rooms Available" -msgstr "Habitaciones Disponibles" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.hotel_checkin_partner_reservation_view_tree -msgid "Search" -msgstr "Búsqueda" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/models/inherit_res_partner.py:44 -#: model:ir.model.fields,help:hotel_l10n_es.field_hotel_checkin_partner_document_type -#: model:ir.model.fields,help:hotel_l10n_es.field_res_partner_document_type -#: model:ir.model.fields,help:hotel_l10n_es.field_res_users_document_type -#, python-format -msgid "Select a valid document type" -msgstr "Seleccione un tipo de documento válido" - -#. module: hotel_l10n_es -#: selection:ine.wizard,ine_month:0 -msgid "September" -msgstr "Septiembre" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_data -msgid "Surnames" -msgstr "Apellidos" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_head -msgid "TRAVELER'S DOCUMENT" -msgstr "DOCUMENTO DEL VIAJERO" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/models/inherit_res_partner.py:186 -#, python-format -msgid "The Document Number %s already exists in another partner." -msgstr "El número de Documento %s ya existe en otro contacto confirmado." - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.view_partner_form -msgid "This partner was deactivated and merged with another client to avoid duplicity, you can see the active client in" -msgstr "Este cliente fue desactivado y fusionado con otro cliente para evitar duplicados, puedes ver el cliente activo en" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/models/inherit_hotel_checkin_partner.py:125 -#, python-format -msgid "To perform the checkin the following data are missing: %s" -msgstr "Para realizar el checkin faltan los siguientes datos: %s" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/models/inherit_hotel_checkin_partner.py:129 -#, python-format -msgid "To perform the checkin the segmentation is required" -msgstr "Para realizar el checkin es olbigatoria la segmentación de la reserva" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_head -msgid "Total amount (Reservation Card):" -msgstr "Importe total (Ficha de Reserva):" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_res_company_ine_tourism -msgid "Tourism number" -msgstr "Núm. de Turismo" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_document -msgid "Traveler's signature" -msgstr "Firma del viajero" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_ine_wizard_txt_binary -#: model:ir.model.fields,field_description:hotel_l10n_es.field_police_wizard_txt_binary -msgid "Txt Binary" -msgstr "Txt Binary" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_ine_wizard_txt_filename -#: model:ir.model.fields,field_description:hotel_l10n_es.field_police_wizard_txt_filename -msgid "Txt Filename" -msgstr "Txt Nombre de archivo" - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_police_wizard_txt_message -msgid "Txt Message" -msgstr "Txt Mensaje" - -#. module: hotel_l10n_es -#: model:ir.ui.view,arch_db:hotel_l10n_es.report_viajero_data -msgid "Type" -msgstr "Tipo" - -#. module: hotel_l10n_es -#: model:ir.model.fields,help:hotel_l10n_es.field_res_company_ine_eventual_staff -#: model:ir.model.fields,help:hotel_l10n_es.field_res_company_ine_permanent_staff -#: model:ir.model.fields,help:hotel_l10n_es.field_res_company_ine_rooms -#: model:ir.model.fields,help:hotel_l10n_es.field_res_company_ine_seats -msgid "Used for INE statistics." -msgstr "Usado en las estadísticas del INE." - -#. module: hotel_l10n_es -#: model:ir.model.fields,help:hotel_l10n_es.field_res_company_police_number -msgid "Used to generate the name of the file that will be given to the police. 10 Caracters" -msgstr "Usado para general el nombre del archivo que será entregado a la policía. 10 Caracteres." - -#. module: hotel_l10n_es -#: model:ir.model.fields,field_description:hotel_l10n_es.field_ine_wizard_ine_year -msgid "Year" -msgstr "Año" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/models/inherit_res_partner.py:242 -#, python-format -msgid "You cannot merge a contact with one of his parent." -msgstr "No se puede fusionar un contacto con su empresa relacionada." - -#. module: hotel_l10n_es -#: model:ir.actions.act_window,name:hotel_l10n_es.action_code_ine -msgid "action.code.ine" -msgstr "action.code.ine" - -#. module: hotel_l10n_es -#: model:ir.actions.act_window,name:hotel_l10n_es.action_tourism_category -msgid "action.tourism.category" -msgstr "Categorías de Turismo" - -#. module: hotel_l10n_es -#: model:ir.model,name:hotel_l10n_es.model_code_ine -msgid "code.ine" -msgstr "code.ine" - -#. module: hotel_l10n_es -#: model:ir.model,name:hotel_l10n_es.model_hotel_checkin_partner -msgid "hotel.checkin.partner" -msgstr "Checkins" - -#. module: hotel_l10n_es -#: model:ir.model,name:hotel_l10n_es.model_ine_wizard -msgid "ine.wizard" -msgstr "ine.wizard" - -#. module: hotel_l10n_es -#: model:ir.ui.menu,name:hotel_l10n_es.menu_code_ine -msgid "menu.code.ine" -msgstr "menu.code.ine" - -#. module: hotel_l10n_es -#: model:ir.ui.menu,name:hotel_l10n_es.menu_tourism_category -msgid "menu.tourism.category" -msgstr "Categorías de Turismo" - -#. module: hotel_l10n_es -#: model:ir.model,name:hotel_l10n_es.model_police_wizard -msgid "police.wizard" -msgstr "police.wizard" - -#. module: hotel_l10n_es -#: model:ir.model,name:hotel_l10n_es.model_tourism_category -msgid "tourism.category" -msgstr "Categoría de Turismo" - -#. module: hotel_l10n_es -#: code:addons/hotel_l10n_es/wizard/ine_wizard.py:433 -#, python-format -msgid "€ and " -msgstr "€ y" diff --git a/hotel_l10n_es/models/__init__.py b/hotel_l10n_es/models/__init__.py deleted file mode 100755 index 9a800ac78..000000000 --- a/hotel_l10n_es/models/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - -from . import category_type -from . import code_ine -from . import inherit_res_company -from . import inherit_res_partner -from . import inherit_hotel_checkin_partner -from . import inherit_hotel_reservation diff --git a/hotel_l10n_es/models/category_type.py b/hotel_l10n_es/models/category_type.py deleted file mode 100755 index 9f59cfbe3..000000000 --- a/hotel_l10n_es/models/category_type.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from odoo import models, fields, api - - -class TourismCategory(models.Model): - _name = 'tourism.category' - - name = fields.Char('Category', required=True) - category_type = fields.Char('Category type', required=True) - - - def name_get(self): - data = [] - for record in self: - display_value = record.category_type + " (" + record.name + ") " - data.append((record.id, display_value)) - return data diff --git a/hotel_l10n_es/models/code_ine.py b/hotel_l10n_es/models/code_ine.py deleted file mode 100755 index 7d00be2d4..000000000 --- a/hotel_l10n_es/models/code_ine.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp import models, fields, api - - -class CodeIne(models.Model): - _name = 'code.ine' - - name = fields.Char('Place', required=True) - code = fields.Char('Code', required=True) - - - def name_get(self): - data = [] - for record in self: - subcode = record.code - if len(record.code) > 3: - subcode = 'ESP' - display_value = record.name + " (" + subcode + ")" - data.append((record.id, display_value)) - return data diff --git a/hotel_l10n_es/models/inherit_hotel_checkin_partner.py b/hotel_l10n_es/models/inherit_hotel_checkin_partner.py deleted file mode 100755 index f8cb4cfb5..000000000 --- a/hotel_l10n_es/models/inherit_hotel_checkin_partner.py +++ /dev/null @@ -1,127 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from openerp import models, fields, api, _ -from odoo.exceptions import UserError -import logging -_logger = logging.getLogger(__name__) - - -class HotelCheckinPartner(models.Model): - _inherit = 'hotel.checkin.partner' - - document_type = fields.Selection(related='partner_id.document_type') - document_number = fields.Char(related='partner_id.document_number') - document_expedition_date = fields.Date( - related='partner_id.document_expedition_date') - gender = fields.Selection('Gender', related='partner_id.gender') - birthdate_date = fields.Date('Birhdate', - related='partner_id.birthdate_date') - code_ine_id = fields.Many2one(related="partner_id.code_ine_id") - name = fields.Char(related='partner_id.name') - lastname = fields.Char(related='partner_id.lastname') - firstname = fields.Char(related='partner_id.firstname') - - @api.model - def create(self, vals): - if not vals.get('partner_id'): - name = self.env['res.partner']._get_computed_name( - vals.get('lastname'), - vals.get('firstname') - ) - partner = self.env['res.partner'].create({ - 'name': name, - }) - vals.update({'partner_id': partner.id}) - vals.pop('firstname') - vals.pop('lastname') - return super(HotelCheckinPartner, self).create(vals) - - - def write(self, vals): - for record in self: - if not vals.get('partner_id') and not record.partner_id: - name = self.env['res.partner']._get_computed_name( - vals.get('lastname'), - vals.get('firstname') - ) - partner = self.env['res.partner'].create({ - 'name': name, - }) - record.update({'partner_id': partner.id}) - vals.pop('firstname') - vals.pop('lastname') - return super(HotelCheckinPartner, self).write(vals) - - - def action_on_board(self): - self.check_required_fields() - return super(HotelCheckinPartner, self).action_on_board() - - @api.model - def check_dni(self, dni): - digits = "TRWAGMYFPDXBNJZSQVHLCKE" - dig_ext = "XYZ" - reemp_dig_ext = {'X': '0', 'Y': '1', 'Z': '2'} - numbers = "1234567890" - dni = dni.upper() - if len(dni) == 9: - dig_control = dni[8] - dni = dni[:8] - if dni[0] in dig_ext: - dni = dni.replace(dni[0], reemp_dig_ext[dni[0]]) - return len(dni) == len([n for n in dni if n in numbers]) \ - and digits[int(dni) % 23] == dig_control - else: - return False - - @api.onchange('document_number', 'document_type') - def onchange_document_number(self): - for record in self: - if record.document_type == 'D' and record.document_number: - if not record.check_dni(record.document_number): - record.document_number = False - raise UserError(_('Incorrect DNI')) - if not record.partner_id and record.document_number: - partner = self.env['res.partner'].search([ - ('document_number', '=', record.document_number) - ], limit=1) - if partner: - record.update({'partner_id': partner}) - - - def check_required_fields(self): - for record in self: - missing_fields = [] - required_fields = ['document_type', 'document_number', - 'document_expedition_date', 'gender', - 'birthdate_date', 'code_ine_id', - 'lastname', 'firstname'] - for field in required_fields: - if not record[field]: - missing_fields.append(record._fields[field].string) - if missing_fields: - raise UserError( - _('To perform the checkin the following data are missing:\ - %s') % (', '.join(missing_fields))) - if not record.reservation_id.segmentation_ids: - raise UserError( - _('To perform the checkin the segmentation is required')) diff --git a/hotel_l10n_es/models/inherit_hotel_reservation.py b/hotel_l10n_es/models/inherit_hotel_reservation.py deleted file mode 100644 index 640e5f199..000000000 --- a/hotel_l10n_es/models/inherit_hotel_reservation.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017 Darío Lodeiros -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from openerp import models, api - - -class HotelReservation(models.Model): - _inherit = 'hotel.reservation' - - - def print_all_checkins(self): - checkins = self.env['hotel.checkin.partner'] - for record in self: - checkins += record.checkin_partner_ids.filtered( - lambda s: s.state in ('booking', 'done')) - if checkins: - return self.env.ref('hotel_l10n_es.action_report_viajero').\ - report_action(checkins) diff --git a/hotel_l10n_es/models/inherit_res_company.py b/hotel_l10n_es/models/inherit_res_company.py deleted file mode 100755 index 4e70c4b01..000000000 --- a/hotel_l10n_es/models/inherit_res_company.py +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -import base64 -from odoo import models, fields -from odoo import modules - - -def get_default_img(): - with open(modules.get_module_resource('hotel_l10n_es', 'static/src/img', - 'logo_bn.png'), - 'rb') as f: - return base64.b64encode(f.read()) - - -class Inherit_res_company(models.Model): - _inherit = 'res.company' - - property_name = fields.Char('Property name', - help='Name of the Hotel/Property.') - ine_tourism = fields.Char('Tourism number', - help='Registration number in the Ministry of \ - Tourism. Used for INE statistics.') - ine_rooms = fields.Integer('Rooms Available', default=0, - help='Used for INE statistics.') - ine_seats = fields.Integer('Beds available', default=0, - help='Used for INE statistics.') - ine_permanent_staff = fields.Integer('Permanent Staff', default=0, - help='Used for INE statistics.') - ine_eventual_staff = fields.Integer('Eventual Staff', default=0, - help='Used for INE statistics.') - police_number = fields.Char('Police number', size=10, - help='Used to generate the name of the file that \ - will be given to the police. 10 Caracters') - ine_category_id = fields.Many2one('tourism.category', - help='Hotel category in the Ministry of \ - Tourism. Used for INE statistics.') - checkin_img = fields.Binary(string="Image in checkin", - default=get_default_img()) diff --git a/hotel_l10n_es/models/inherit_res_partner.py b/hotel_l10n_es/models/inherit_res_partner.py deleted file mode 100755 index d9102b6d9..000000000 --- a/hotel_l10n_es/models/inherit_res_partner.py +++ /dev/null @@ -1,450 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -import functools -import itertools -import logging -import psycopg2 - -from odoo import api, fields, models, _ -from odoo.osv.expression import get_unaccent_wrapper -from odoo.exceptions import ValidationError, UserError -from odoo.tools import mute_logger -_logger = logging.getLogger(__name__) - - -class ResPartner(models.Model): - _inherit = 'res.partner' - - document_type = fields.Selection([ - ('D', 'DNI'), - ('P', 'Pasaporte'), - ('C', 'Permiso de Conducir'), - ('I', 'Carta o Doc. de Identidad'), - ('N', 'Permiso Residencia Español'), - ('X', 'Permiso Residencia Europeo')], - help=_('Select a valid document type'), - string='Doc. type', - ) - document_number = fields.Char('Document number', index=True) - document_expedition_date = fields.Date('Document expedition date') - code_ine_id = fields.Many2one('code.ine', - help=_('Country or province of origin. Used for INE statistics.')) - unconfirmed = fields.Boolean('Unconfirmed', default=True) - main_partner_id = fields.Many2one('res.partner') - - @api.model - def name_search(self, name, args=None, operator='ilike', limit=100): - if not args: - args = [] - domain = ['|', - ('document_number', operator, name), - ('vat', operator, name), - ] - partners = self.search(domain + args, limit=limit,) - res = partners.name_get() - if limit: - limit_rest = limit - len(partners) - else: - limit_rest = limit - if limit_rest or not limit: - args += [('id', 'not in', partners.ids)] - res += super(ResPartner, self).name_search( - name, args=args, operator=operator, limit=limit_rest) - return res - - @api.model - def _get_duplicated_ids(self, partner): - partner_ids = [] - if partner.vat: - partner_ids += self.env['res.partner'].search([ - ('vat', '=', partner.vat), - ('parent_id', '=', False) - ]).ids - if partner.document_number: - partner_ids += self.env['res.partner'].search([ - ('document_number', '=', partner.document_number), - ('child_ids', '=', False) - ]).ids - if partner_ids: - return partner_ids - - def _merge_fields(self): - duplicated_fields = ['vat', 'document_number'] - return duplicated_fields - - - def write(self, vals): - if vals.get('vat') and not self._context.get( - "ignore_vat_update", False): - for record in self: - vat = vals.get('vat') - if self.env.context.get('company_id'): - company = self.env['res.company'].browse(self.env.context['company_id']) - else: - company = self.env.user.company_id - if company.vat_check_vies: - # force full VIES online check - check_func = self.vies_vat_check - else: - # quick and partial off-line checksum validation - check_func = self.simple_vat_check - vat_country, vat_number = self._split_vat(vat) - #check with country code as prefix of the TIN - if not check_func(vat_country, vat_number): - country_id = vals.get('country_id') or record.country_id.id - vals['vat'] = record.fix_eu_vat_number(country_id, vat) - return super(ResPartner, self).write(vals) - - @api.constrains('country_id') - def update_vat_code_country(self): - for record in self: - country_id = record.country_id.id - vat = record.vat - #check with country code as prefix of the TIN - if vat: - if self.env.context.get('company_id'): - company = self.env['res.company'].browse(self.env.context['company_id']) - else: - company = self.env.user.company_id - if company.vat_check_vies: - # force full VIES online check - check_func = self.vies_vat_check - else: - # quick and partial off-line checksum validation - check_func = self.simple_vat_check - vat_country, vat_number = self._split_vat(vat) - if not check_func(vat_country, vat_number): - vat_with_code = record.fix_eu_vat_number(country_id, vat) - if country_id and vat != vat_with_code: - record.with_context({'ignore_vat_update': True}).write({ - 'vat': vat_with_code - }) - - @api.constrains('vat', 'commercial_partner_country_id') - def check_vat(self): - spain = self.env['res.country'].search([ - ('code', '=', 'ES') - ]) - from_spain = False - for partner in self: - if partner.country_id == spain: - from_spain = True - if from_spain: - return super(ResPartner, self).check_vat() - - @api.constrains('vat') - def _check_vat_unique(self): - for record in self: - if record.unconfirmed: - if record.vat: - record.update({'unconfirmed': False}) - partner_ids = self.env['res.partner'].search([ - ('vat', '=', record.vat), - ('parent_id', '=', False) - ]).ids - if len(partner_ids) > 1: - partners = self.env['res.partner'].browse(partner_ids) - record._merge(partners._ids) - else: - return super(ResPartner, self)._check_vat_unique() - return True - - @api.constrains('document_number', 'document_type') - def _check_document_number_unique(self): - for record in self: - if not record.document_number: - continue - if record.unconfirmed: - if record.document_number: - record.update({'unconfirmed': False}) - partner_ids = self.env['res.partner'].search([ - ('document_number', '=', record.document_number), - ]).ids - if len(partner_ids) > 1: - partners = self.env['res.partner'].browse(partner_ids) - record._merge(partners._ids) - if not record.parent_id and record.document_type == 'D' \ - and not record.vat: - record.update({ - 'vat': record.document_number, - }) - else: - results = self.env['res.partner'].search_count([ - ('document_type', '=', record.document_type), - ('document_number', '=', record.document_number), - ('id', '!=', record.id) - ]) - if results: - raise ValidationError(_( - "The Document Number %s already exists in another " - "partner.") % record.document_number) - - - def open_main_partner(self): - self.ensure_one() - action = self.env.ref('base.action_partner_form').read()[0] - if self.main_partner_id: - action['views'] = [(self.env.ref('base.view_partner_form').id, 'form')] - action['res_id'] = self.main_partner_id.id - else: - action = {'type': 'ir.actions.act_window_close'} - return action - - def _get_fk_on(self, table): - """ return a list of many2one relation with the given table. - :param table : the name of the sql table to return relations - :returns a list of tuple 'table name', 'column name'. - """ - query = """ - SELECT cl1.relname as table, att1.attname as column - FROM pg_constraint as con, pg_class as cl1, pg_class as cl2, pg_attribute as att1, pg_attribute as att2 - WHERE con.conrelid = cl1.oid - AND con.confrelid = cl2.oid - AND array_lower(con.conkey, 1) = 1 - AND con.conkey[1] = att1.attnum - AND att1.attrelid = cl1.oid - AND cl2.relname = %s - AND att2.attname = 'id' - AND array_lower(con.confkey, 1) = 1 - AND con.confkey[1] = att2.attnum - AND att2.attrelid = cl2.oid - AND con.contype = 'f' - """ - self._cr.execute(query, (table,)) - return self._cr.fetchall() - - def _merge(self, partner_ids, dst_partner=None): - """ private implementation of merge partner - :param partner_ids : ids of partner to merge - :param dst_partner : record of destination res.partner - """ - partner = self.env['res.partner'] - partner_ids = partner.browse(partner_ids).exists() - if len(partner_ids) < 2: - return - - if len(partner_ids) > 3: - raise UserError(_("For safety reasons, you cannot merge more than 3 contacts together. You can re-open the wizard several times if needed.")) - - # check if the list of partners to merge contains child/parent relation - child_ids = self.env['res.partner'] - for partner_id in partner_ids: - child_ids |= partner.search([('id', 'child_of', [partner_id.id])]) - partner_id - if partner_ids & child_ids: - raise UserError(_("You cannot merge a contact with one of his parent.")) - - # remove dst_partner from partners to merge - if dst_partner and dst_partner in partner_ids: - src_partners = partner_ids - dst_partner - else: - ordered_partners = self._get_ordered_partner(partner_ids.ids) - dst_partner = ordered_partners[-1] - src_partners = ordered_partners[:-1] - _logger.info("dst_partner: %s", dst_partner.id) - - # call sub methods to do the merge - self._update_foreign_keys(src_partners, dst_partner) - self._update_reference_fields(src_partners, dst_partner) - self._update_values(src_partners, dst_partner) - - _logger.info('(uid = %s) merged the partners %r with %s', self._uid, src_partners.ids, dst_partner.id) - dst_partner.message_post(body='%s %s' % (_("Merged with the following partners:"), ", ".join('%s <%s> (ID %s)' % (p.name, p.email or 'n/a', p.id) for p in src_partners))) - - return dst_partner - - @api.model - def _update_foreign_keys(self, src_partners, dst_partner): - """ Update all foreign key from the src_partner to dst_partner. All many2one fields will be updated. - :param src_partners : merge source res.partner recordset (does not include destination one) - :param dst_partner : record of destination res.partner - """ - _logger.debug('_update_foreign_keys for dst_partner: %s for src_partners: %s', dst_partner.id, str(src_partners.ids)) - - # find the many2one relation to a partner - partner = self.env['res.partner'] - relations = self._get_fk_on('res_partner') - - for table, column in relations: - # get list of columns of current table (exept the current fk column) - query = "SELECT column_name FROM information_schema.columns WHERE table_name LIKE '%s'" % (table) - self._cr.execute(query, ()) - columns = [] - for data in self._cr.fetchall(): - if data[0] != column: - columns.append(data[0]) - - # do the update for the current table/column in SQL - query_dic = { - 'table': table, - 'column': column, - 'value': columns[0], - } - if len(columns) <= 1: - # unique key treated - query = """ - UPDATE "%(table)s" as ___tu - SET %(column)s = %%s - WHERE - %(column)s = %%s AND - NOT EXISTS ( - SELECT 1 - FROM "%(table)s" as ___tw - WHERE - %(column)s = %%s AND - ___tu.%(value)s = ___tw.%(value)s - )""" % query_dic - for partner in src_partners: - self._cr.execute(query, (dst_partner.id, partner.id, dst_partner.id)) - else: - try: - with mute_logger('odoo.sql_db'), self._cr.savepoint(): - query = 'UPDATE "%(table)s" SET %(column)s = %%s WHERE %(column)s IN %%s' % query_dic - self._cr.execute(query, (dst_partner.id, tuple(src_partners.ids),)) - - # handle the recursivity with parent relation - if column == partner._parent_name and table == 'res_partner': - query = """ - WITH RECURSIVE cycle(id, parent_id) AS ( - SELECT id, parent_id FROM res_partner - UNION - SELECT cycle.id, res_partner.parent_id - FROM res_partner, cycle - WHERE res_partner.id = cycle.parent_id AND - cycle.id != cycle.parent_id - ) - SELECT id FROM cycle WHERE id = parent_id AND id = %s - """ - self._cr.execute(query, (dst_partner.id,)) - # NOTE JEM : shouldn't we fetch the data ? - except psycopg2.Error: - # updating fails, most likely due to a violated unique constraint - # keeping record with nonexistent partner_id is useless, better delete it - query = 'DELETE FROM "%(table)s" WHERE "%(column)s" IN %%s' % query_dic - self._cr.execute(query, (tuple(src_partners.ids),)) - - @api.model - def _update_reference_fields(self, src_partners, dst_partner): - """ Update all reference fields from the src_partner to dst_partner. - :param src_partners : merge source res.partner recordset (does not include destination one) - :param dst_partner : record of destination res.partner - """ - _logger.debug('_update_reference_fields for dst_partner: %s for src_partners: %r', dst_partner.id, src_partners.ids) - - def update_records(model, src, field_model='model', field_id='res_id'): - Model = self.env[model] if model in self.env else None - if Model is None: - return - records = Model.sudo().search([(field_model, '=', 'res.partner'), (field_id, '=', src.id)]) - try: - with mute_logger('odoo.sql_db'), self._cr.savepoint(): - return records.sudo().write({field_id: dst_partner.id}) - except psycopg2.Error: - # updating fails, most likely due to a violated unique constraint - # keeping record with nonexistent partner_id is useless, better delete it - return records.sudo().unlink() - - update_records = functools.partial(update_records) - - for partner in src_partners: - update_records('calendar', src=partner, field_model='model_id.model') - update_records('ir.attachment', src=partner, field_model='res_model') - update_records('mail.followers', src=partner, field_model='res_model') - update_records('mail.message', src=partner) - update_records('ir.model.data', src=partner) - - records = self.env['ir.model.fields'].search([('ttype', '=', 'reference')]) - for record in records.sudo(): - try: - Model = self.env[record.model] - field = Model._fields[record.name] - except KeyError: - # unknown model or field => skip - continue - - if field.compute is not None: - continue - - for partner in src_partners: - records_ref = Model.sudo().search([(record.name, '=', 'res.partner,%d' % partner.id)]) - values = { - record.name: 'res.partner,%d' % dst_partner.id, - } - records_ref.sudo().write(values) - - @api.model - def _update_values(self, src_partners, dst_partner): - """ Update values of dst_partner with the ones from the src_partners. - :param src_partners : recordset of source res.partner - :param dst_partner : record of destination res.partner - """ - _logger.debug('_update_values for dst_partner: %s for src_partners: %r', dst_partner.id, src_partners.ids) - - model_fields = dst_partner.fields_get().keys() - - def write_serializer(item): - if isinstance(item, models.BaseModel): - return item.id - else: - return item - # get all fields that are not computed or x2many - values = dict() - for column in model_fields: - field = dst_partner._fields[column] - if field.type not in ('many2many', 'one2many') and field.compute is None: - for item in itertools.chain(src_partners, [dst_partner]): - if item[column]: - values[column] = write_serializer(item[column]) - # remove fields that can not be updated (id and parent_id) - values.pop('id', None) - parent_id = values.pop('parent_id', None) - src_partners.update({ - 'active': False, - 'document_number': False, - 'vat': False, - 'main_partner_id': dst_partner.id}) - dst_partner.write(values) - # try to update the parent_id - if parent_id and parent_id != dst_partner.id: - try: - dst_partner.write({'parent_id': parent_id}) - except ValidationError: - _logger.info('Skip recursive partner hierarchies for parent_id %s of partner: %s', parent_id, dst_partner.id) - - @api.model - def _get_ordered_partner(self, partner_ids): - """ Helper : returns a `res.partner` recordset ordered by create_date/active fields - :param partner_ids : list of partner ids to sort - """ - return self.env['res.partner'].browse(partner_ids).sorted( - key=lambda p: (p.active, (p.create_date or '')), - reverse=True, - ) - - - def _compute_models(self): - """ Compute the different models needed by the system if you want to exclude some partners. """ - model_mapping = {} - if self.exclude_contact: - model_mapping['res.users'] = 'partner_id' - if 'account.move.line' in self.env and self.exclude_journal_item: - model_mapping['account.move.line'] = 'partner_id' - return model_mapping diff --git a/hotel_l10n_es/report/report_parte_viajero.xml b/hotel_l10n_es/report/report_parte_viajero.xml deleted file mode 100755 index cfaaf4b2d..000000000 --- a/hotel_l10n_es/report/report_parte_viajero.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - diff --git a/hotel_l10n_es/security/ir.model.access.csv b/hotel_l10n_es/security/ir.model.access.csv deleted file mode 100755 index 7a6b2cc1c..000000000 --- a/hotel_l10n_es/security/ir.model.access.csv +++ /dev/null @@ -1,7 +0,0 @@ -"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" -"access_hotel_l10n_es.model_category_user","hotell10n.category_ine.user","hotel_l10n_es.model_tourism_category","hotel.group_hotel_user",1,0,0,0 -"access_hotel_l10n_es.code_ine_user","hotell10n.code_ine.user","hotel_l10n_es.model_code_ine","hotel.group_hotel_user",1,0,0,0 -"access_hotel_l10n_es.model_category_manager","hotell10n.category_ine.manager","hotel_l10n_es.model_tourism_category","hotel.group_hotel_manager",1,1,1,1 -"access_hotel_l10n_es.code_ine_manager","hotell10n.code_ine.manager","hotel_l10n_es.model_code_ine","hotel.group_hotel_manager",1,1,1,1 -"access_hotel_l10n_es.model_category_call","hotell10n.category_ine.call","hotel_l10n_es.model_tourism_category","hotel.group_hotel_call",1,0,0,0 -"access_hotel_l10n_es.code_ine_call","hotell10n.code_ine.call","hotel_l10n_es.model_code_ine","hotel.group_hotel_call",1,0,0,0 diff --git a/hotel_l10n_es/static/description/icon.png b/hotel_l10n_es/static/description/icon.png deleted file mode 100755 index 367e0ad234cc47c00bf2e0b28b70d5b4a894fe88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19995 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 - - - diff --git a/hotel_l10n_es/views/category_tourism.xml b/hotel_l10n_es/views/category_tourism.xml deleted file mode 100755 index fff2798a2..000000000 --- a/hotel_l10n_es/views/category_tourism.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - tourism.category.view.form - tourism.category - -

      - - - - - - - - - - - - - -
      - - - - - tourism.category.view.tree - tourism.category - - - - - - - - diff --git a/hotel_l10n_es/views/code_ine.xml b/hotel_l10n_es/views/code_ine.xml deleted file mode 100755 index d2f5b831b..000000000 --- a/hotel_l10n_es/views/code_ine.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - code.ine.view.form - code.ine - -
      - - - - - - - - - - - - - -
      -
      -
      - - - code.ine.view.tree - code.ine - - - - - - - - -
      diff --git a/hotel_l10n_es/views/hotel_l10n_es_hotel_name.xml b/hotel_l10n_es/views/hotel_l10n_es_hotel_name.xml deleted file mode 100755 index c808e8ebd..000000000 --- a/hotel_l10n_es/views/hotel_l10n_es_hotel_name.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - diff --git a/hotel_l10n_es/views/inherit_hotel_checkin_partner_views.xml b/hotel_l10n_es/views/inherit_hotel_checkin_partner_views.xml deleted file mode 100755 index 853dd6c65..000000000 --- a/hotel_l10n_es/views/inherit_hotel_checkin_partner_views.xml +++ /dev/null @@ -1,109 +0,0 @@ - - - - - hotel.checkin.partner.view.form - hotel.checkin.partner - - - - - - - - - - - - - - - -
      - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hotel_l10n_es/views/inherited_hotel_reservation_views.xml b/hotel_l10n_es/views/inherited_hotel_reservation_views.xml deleted file mode 100644 index bbf2979e7..000000000 --- a/hotel_l10n_es/views/inherited_hotel_reservation_views.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - hotel.reservation - - - -
      - -
      -

      -

      -
      -
      - -
      -

      Abrir web de la Polícia para entregar el fichero generado: Policia

      -

      Abrir web de la Guardia Civil para entregar el fichero generado: Guardia Civil

      -
      -
      - - - - - - - - diff --git a/hotel_roommatik/__init__.py b/hotel_roommatik/__init__.py deleted file mode 100755 index 0650744f6..000000000 --- a/hotel_roommatik/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import models diff --git a/hotel_roommatik/__manifest__.py b/hotel_roommatik/__manifest__.py deleted file mode 100755 index 30719f197..000000000 --- a/hotel_roommatik/__manifest__.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2018 Jose Luis Algara (Alda hotels) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -{ - 'name': 'Hotel RoomMatik', - 'description': """ - Integration of Hootel with the RoomMatik kiosk""", - 'summary': """ - The integration of Hootel with the RoomMatik kiosk. - A series of requests/responses that provide the basic - information needed by the kiosk.""", - 'version': '11.0.1.0.0', - 'license': 'AGPL-3', - 'author': 'Jose Luis Algara (Alda hotels) ', - 'website': 'https://www.aldahotels.com', - 'category': 'Generic Modules/Hotel Management', - 'depends': [ - 'hotel', - 'partner_contact_gender', - 'partner_contact_birthdate', - 'base_iso3166', - 'base_location', - ], - 'data': [ - 'data/res_users_data.xml' - ], - 'demo': [ - ], -} diff --git a/hotel_roommatik/data/res_users_data.xml b/hotel_roommatik/data/res_users_data.xml deleted file mode 100644 index d22fa0178..000000000 --- a/hotel_roommatik/data/res_users_data.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - Roommatik - - - - - - - roommatik@roommatik.com - - - - - - - --
      -Roommatik]]>
      - -
      -
      -
      diff --git a/hotel_roommatik/models/__init__.py b/hotel_roommatik/models/__init__.py deleted file mode 100755 index 6a96de1e6..000000000 --- a/hotel_roommatik/models/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from . import inherited_hotel_checkin_partner -from . import inherited_res_partner -from . import inherited_hotel_room_type -from . import roommatik -from . import inherited_hotel_reservation -from . import inherited_account_payment diff --git a/hotel_roommatik/models/inherited_account_payment.py b/hotel_roommatik/models/inherited_account_payment.py deleted file mode 100644 index e6c2ef37e..000000000 --- a/hotel_roommatik/models/inherited_account_payment.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2017 Dario Lodeiros -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo.exceptions import except_orm -from odoo import models, fields, api, _ - -class AccountPayment(models.Model): - _inherit = 'account.payment' - - @api.model - def rm_add_payment(self, code, payment): - reservation = self.env['hotel.reservation'].search([ - '|', ('localizator', '=', code), - ('folio_id.name', '=', code)]) - if not reservation: - return False - if reservation: - for cashpay in payment['CashPayments']: - vals = { - 'journal_id': 7, # TODO:config setting - 'partner_id': reservation.partner_invoice_id.id, - 'amount': cashpay['Amount'], - 'payment_date': cashpay['DateTime'], - 'communication': reservation.name, - 'folio_id': reservation.folio_id.id, - 'payment_type': 'inbound', - 'payment_method_id': 1, - 'partner_type': 'customer', - 'state': 'draft', - } - pay = self.create(vals) - for cashpay in payment['CreditCardPayments']: - vals = { - 'journal_id': 15, # TODO:config setting - 'partner_id': reservation.partner_invoice_id.id, - 'amount': cashpay['Amount'], - 'payment_date': cashpay['DateTime'], - 'communication': reservation.name, - 'folio_id': reservation.folio_id.id, - 'payment_type': 'inbound', - 'payment_method_id': 1, - 'partner_type': 'customer', - 'state': 'draft', - } - pay = self.create(vals) - pay.post() - return True diff --git a/hotel_roommatik/models/inherited_hotel_checkin_partner.py b/hotel_roommatik/models/inherited_hotel_checkin_partner.py deleted file mode 100644 index d3e83a21e..000000000 --- a/hotel_roommatik/models/inherited_hotel_checkin_partner.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2019 Jose Luis Algara (Alda hotels) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -import json -from odoo import api, models -from odoo.addons.hotel_roommatik.models.roommatik import ( - DEFAULT_ROOMMATIK_DATE_FORMAT, - DEFAULT_ROOMMATIK_DATETIME_FORMAT) -from datetime import datetime -import logging - - -class HotelCheckinPartner(models.Model): - - _inherit = 'hotel.checkin.partner' - - @api.model - def rm_checkin_partner(self, stay): - _logger = logging.getLogger(__name__) - if not stay.get('ReservationCode'): - reservation_obj = self.env['hotel.reservation'] - vals = { - 'checkin': stay["Arrival"], - 'checkout': stay["Departure"], - 'adults': stay['Adults'], - 'arrival_hour': stay['Arrival_hour'], - 'room_type_id': stay['RoomType']['Id'], - 'partner_id': stay["Customers"][0]["Id"], - 'segmentation_ids': [(6, 0, [stay['Segmentation']])], - 'channel_type': 'virtualdoor', - } - reservation_rm = reservation_obj.create(vals) - stay['ReservationCode'] = reservation_rm.localizator - else: - reservation_rm = self.env['hotel.reservation'].search([ - ('localizator', '=', stay['ReservationCode']) - ]) - total_chekins = reservation_rm.checkin_partner_pending_count - stay['Total'] = reservation_rm.folio_pending_amount - stay['Paid'] = reservation_rm._computed_deposit_roommatik(stay['ReservationCode']) - if total_chekins > 0 and len(stay["Customers"]) <= total_chekins: - _logger.info('ROOMMATIK checkin %s customer in %s Reservation.', - total_chekins, - reservation_rm.id) - for room_partner in stay["Customers"]: - if room_partner['Address']['Nationality'] == 'ESP': - code_ine = room_partner['Address']['Province'] - else: - code_ine = room_partner['Address']['Nationality'] - province = self.env['code.ine'].search( - [('name', '=', code_ine)], limit=1) - code_ine = province.id - - checkin_partner_val = { - 'folio_id': reservation_rm.folio_id.id, - 'reservation_id': reservation_rm.id, - 'partner_id': room_partner["Id"], - 'enter_date': stay["Arrival"], - 'exit_date': stay["Departure"], - 'code_ine_id': code_ine, - } - try: - record = self.env['hotel.checkin.partner'].create( - checkin_partner_val) - _logger.info('ROOMMATIK check-in partner: %s in \ - (%s Reservation) ID:%s.', - checkin_partner_val['partner_id'], - checkin_partner_val['reservation_id'], - record.id) - if not record.reservation_id.segmentation_ids: - record.reservation_id.update({ - 'segmentation_ids': [(6, 0, [stay['Segmentation']])] - }) - record.action_on_board() - stay['Id'] = record.id - stay['Room'] = {} - stay['Room']['Id'] = reservation_rm.room_id.id - stay['Room']['Name'] = reservation_rm.room_id.name - json_response = stay - except Exception as e: - error_name = 'Error not create Checkin ' - error_name += str(e) - json_response = {'State': error_name} - _logger.error('ROOMMATIK writing %s in reservation: %s).', - checkin_partner_val['partner_id'], - checkin_partner_val['reservation_id']) - return json_response - - else: - json_response = {'State': 'Error checkin_partner_pending_count \ - values do not match.'} - _logger.error('ROOMMATIK checkin pending count do not match for \ - Reservation ID %s.', reservation_rm.id) - json_response = json.dumps(json_response) - return json_response - - @api.model - def rm_get_stay(self, code): - # BUSQUEDA POR LOCALIZADOR - checkin_partner = self.search([('id', '=', code)]) - # TODO: refactoring 'res.config.settings', 'default_arrival_hour' by the current self.env.user.hotel_id.arrival_hour - default_arrival_hour = self.env['ir.default'].sudo().get( - 'res.config.settings', 'default_arrival_hour') - # TODO: refactoring 'res.config.settings', 'default_departure_hour' by the current self.env.user.hotel_id.departure_hour - default_departure_hour = self.env['ir.default'].sudo().get( - 'res.config.settings', 'default_departure_hour') - if any(checkin_partner): - arrival = checkin_partner.enter_date or default_arrival_hour - departure = checkin_partner.exit_date or default_departure_hour - stay = {'Code': checkin_partner.id} - stay['Id'] = checkin_partner.id - stay['Room'] = {} - stay['Room']['Id'] = checkin_partner.reservation_id.room_id.id - stay['Room']['Name'] = checkin_partner.reservation_id.room_id.name - stay['RoomType'] = {} - stay['RoomType']['Id'] = checkin_partner.reservation_id.room_type_id.id - stay['RoomType']['Name'] = checkin_partner.reservation_id.room_type_id.name - stay['Arrival'] = arrival - stay['Departure'] = departure - stay['Customers'] = [] - for idx, cpi in enumerate(checkin_partner.reservation_id.checkin_partner_ids): - stay['Customers'].append({'Customer': {}}) - stay['Customers'][idx]['Customer'] = self.env[ - 'res.partner'].rm_get_a_customer(cpi.partner_id.id) - stay['TimeInterval'] = {} - stay['TimeInterval']['Id'] = {} - stay['TimeInterval']['Name'] = {} - stay['TimeInterval']['Minutes'] = {} - stay['Adults'] = checkin_partner.reservation_id.adults - stay['ReservationCode'] = checkin_partner.reservation_id.localizator - stay['Total'] = checkin_partner.reservation_id.price_total - stay['Paid'] = checkin_partner.reservation_id.folio_id.invoices_paid - stay['Outstanding'] = checkin_partner.reservation_id.folio_id.pending_amount - stay['Taxable'] = checkin_partner.reservation_id.price_tax - - else: - stay = {'Code': ""} - - json_response = json.dumps(stay) - return json_response diff --git a/hotel_roommatik/models/inherited_hotel_reservation.py b/hotel_roommatik/models/inherited_hotel_reservation.py deleted file mode 100644 index 1938f3612..000000000 --- a/hotel_roommatik/models/inherited_hotel_reservation.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2019 Jose Luis Algara (Alda hotels) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import api, models -import json -import logging -_logger = logging.getLogger(__name__) - - -class HotelReservation(models.Model): - - _inherit = 'hotel.reservation' - - @api.model - def _computed_deposit_roommatik(self, rm_localizator): - reservations = self.env['hotel.reservation'].search([ - ('localizator', '=', rm_localizator)]) - folio = reservations[0].folio_id - # We dont have the payments by room, that's why we have to computed - # the proportional deposit part if the folio has more rooms that the - # reservations code (this happens when in the same folio are - # reservations with different checkins/outs convinations) - if len(folio.reservation_ids) > len(reservations) and folio.invoices_paid > 0: - - total_reservations = sum(reservations.mapped('price_total')) - paid_in_folio = folio.invoices_paid - total_in_folio = folio.amount_total - deposit = total_reservations * paid_in_folio / total_in_folio - return deposit - return folio.invoices_paid - - @api.model - def rm_get_reservation(self, code): - # Search by localizator - reservations = self._get_reservations_roommatik(code) - reservations = reservations.filtered( - lambda x: x.state in ('draft', 'confirm')) - if any(reservations): - # TODO: refactoring 'res.config.settings', 'default_arrival_hour' by the current self.env.user.hotel_id.arrival_hour - default_arrival_hour = self.env['ir.default'].sudo().get( - 'res.config.settings', 'default_arrival_hour') - checkin = "%s %s" % (reservations[0].checkin, - default_arrival_hour) - # TODO: refactoring 'res.config.settings', 'default_departure_hour' by the current self.env.user.hotel_id.departure_hour - default_departure_hour = self.env['ir.default'].sudo().get( - 'res.config.settings', 'default_departure_hour') - checkout = "%s %s" % (reservations[0].checkout, - default_departure_hour) - _logger.info('ROOMMATIK serving Folio: %s', reservations.ids) - json_response = { - 'Reservation': { - 'Id': reservations[0].localizator, - 'Arrival': checkin, - 'Departure': checkout, - 'Deposit': self._computed_deposit_roommatik(code) - } - } - for i, line in enumerate(reservations): - total_chekins = line.checkin_partner_pending_count - json_response['Reservation'].setdefault('Rooms', []).append({ - 'Id': line.id, - 'Adults': line.adults, - 'IsAvailable': total_chekins > 0, - # IsAvailable “false” Rooms not need check-in - 'Price': line.price_total, - 'RoomTypeId': line.room_type_id.id, - 'RoomTypeName': line.room_type_id.name, - 'RoomName': line.room_id.name, - }) - else: - _logger.warning('ROOMMATIK Not Found reservation search %s', code) - json_response = {'Error': 'Not Found ' + str(code)} - return json.dumps(json_response) - - @api.model - def _get_reservations_roommatik(self, code): - return self.env['hotel.reservation'].search([ - '|', ('localizator', '=', code), - ('folio_id.name', '=', code)]) diff --git a/hotel_roommatik/models/inherited_hotel_room_type.py b/hotel_roommatik/models/inherited_hotel_room_type.py deleted file mode 100644 index d6110edb4..000000000 --- a/hotel_roommatik/models/inherited_hotel_room_type.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2019 Jose Luis Algara (Alda hotels) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import api, models, fields -from datetime import datetime, timedelta -import json -from odoo.addons.hotel_roommatik.models.roommatik import ( - DEFAULT_ROOMMATIK_DATE_FORMAT,) -import logging -_logger = logging.getLogger(__name__) - - -class HotelRoomType(models.Model): - - _inherit = "hotel.room.type" - - @api.model - def rm_get_all_room_type_rates(self): - room_types = self.env['hotel.room.type'].search([]) - # TODO: refactoring 'res.config.settings', 'default_departure_hour' by the current self.env.user.hotel_id - tz_hotel = self.env['ir.default'].sudo().get( - 'res.config.settings', 'tz_hotel') - dfrom = fields.Date.context_today(self.with_context( - tz=tz_hotel)) - dto = (fields.Date.from_string(dfrom) + timedelta(days=1)).strftime( - DEFAULT_ROOMMATIK_DATE_FORMAT) - room_type_rates = [] - for room_type in room_types: - free_rooms = self.check_availability_room_type(dfrom, dto, - room_type.id) - rates = self.get_rate_room_types( - room_type_ids=room_type.id, - date_from=dfrom, - days=1, - partner_id=False) - room_type_rates.append({ - "RoomType": { - "Id": room_type.id, - "Name": room_type.name, - "GuestNumber": room_type.get_capacity() - }, - "TimeInterval": { - "Id": "1", - "Name": "1 day", - "Minutes": "1440" - }, - "Price": rates[room_type.id][0].get('price'), - "IsAvailable": any(free_rooms), - }) - json_response = json.dumps(room_type_rates) - return json_response - - @api.model - def rm_get_prices(self, start_date, number_intervals, - room_type, guest_number): - start_date = fields.Date.from_string(start_date) - end_date = start_date + timedelta(days=int(number_intervals)) - dfrom = start_date.strftime( - DEFAULT_ROOMMATIK_DATE_FORMAT) - dto = end_date.strftime( - DEFAULT_ROOMMATIK_DATE_FORMAT) - free_rooms = self.check_availability_room_type(dfrom, dto, - room_type.id) - if free_rooms: - rates = self.get_rate_room_types( - room_type_ids=room_type.id, - date_from=dfrom, - days=int(number_intervals), - partner_id=False) - return [item['price'] for item in rates.get(room_type.id)] - return [] diff --git a/hotel_roommatik/models/inherited_res_partner.py b/hotel_roommatik/models/inherited_res_partner.py deleted file mode 100755 index c806401da..000000000 --- a/hotel_roommatik/models/inherited_res_partner.py +++ /dev/null @@ -1,146 +0,0 @@ -# Copyright 2019 Jose Luis Algara (Alda hotels) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -import json -from odoo import api, models -from datetime import datetime -import logging -from odoo.addons.hotel_roommatik.models.roommatik import ( - DEFAULT_ROOMMATIK_DATE_FORMAT) - - -class ResPartner(models.Model): - - _inherit = 'res.partner' - - @api.model - def rm_add_customer(self, customer): - # RoomMatik API CREACIÓN DE CLIENTE - _logger = logging.getLogger(__name__) - - partner_res = self.env['res.partner'].search([( - 'document_number', '=', - customer['IdentityDocument']['Number'])]) - - json_response = {'Id': 0} - write_customer = False - if any(partner_res): - # Change customer data - try: - partner_res[0].update(self.rm_prepare_customer(customer)) - write_customer = partner_res[0] - _logger.info('ROOMMATIK %s exist in BD [ %s ] Rewriting', - partner_res[0].document_number, - partner_res[0].id,) - except Exception as e: - if 'args' in e.__dir__(): - error_name = e.args - else: - error_name = e.name - else: - # Create new customer - try: - self.create(self.rm_prepare_customer(customer)) - _logger.info('ROOMMATIK Created %s Name: %s', - customer['IdentityDocument']['Number'], - customer['FirstName']) - write_customer = self.env['res.partner'].search([ - ('document_number', '=', - customer['IdentityDocument']['Number'])]) - except Exception as e: - if 'args' in e.__dir__(): - error_name = e.args - else: - error_name = e.name - - partner_res = self.env['res.partner'].search([( - 'document_number', '=', - customer['IdentityDocument']['Number'])]) - partner_res.unlink() - - - if write_customer: - json_response = self.rm_get_a_customer(write_customer.id) - json_response = json.dumps(json_response) - return json_response - else: - _logger.error(error_name) - return [False, error_name] - - def rm_prepare_customer(self, customer): - zip = self.env['res.better.zip'].search([ - ('name', 'ilike', customer['Address']['ZipCode'])]) - # Check Sex string - if customer['Sex'] not in {'male', 'female'}: - customer['Sex'] = '' - # Check state_id - state = self.env['res.country.state'].search([ - ('name', 'ilike', customer['Address']['Province'])]) - if not state and zip: - state = zip.state_id - country = self.env['res.country'].search([ - ('code_alpha3', '=', customer['Address']['Country'])]) - if not country and zip: - country = zip.country_id - # Create Street2s - street_2 = customer['Address']['House'] - street_2 += ' ' + customer['Address']['Flat'] - street_2 += ' ' + customer['Address']['Number'] - metadata = { - 'firstname': customer['FirstName'], - 'lastname': customer['LastName1'] + ' ' + customer['LastName2'], - 'lastname2': '', - 'birthdate_date': datetime.strptime( - customer['Birthday'], DEFAULT_ROOMMATIK_DATE_FORMAT).date(), - 'gender': customer['Sex'], - 'zip': zip, - 'city': customer['Address']['City'], - 'street': customer['Address']['Street'], - 'street2': street_2, - 'state_id': state.id if state else False, - 'country_id': country.id if country else False, - 'phone': customer['Contact']['Telephone'], - 'mobile': customer['Contact']['Mobile'], - 'email': customer['Contact']['Email'], - 'document_number': customer['IdentityDocument']['Number'], - 'document_type': customer['IdentityDocument']['Type'], - 'document_expedition_date': datetime.strptime( - customer['IdentityDocument']['ExpeditionDate'], - DEFAULT_ROOMMATIK_DATE_FORMAT).date(), - } - return {k: v for k, v in metadata.items() if v != ""} - - def rm_get_a_customer(self, customer): - # Prepare a Customer for RoomMatik - partner = self.search([('id', '=', customer)]) - response = {} - response['Id'] = partner.id - response['FirstName'] = partner.firstname - response['LastName1'] = partner.lastname - response['LastName2'] = '' - response['Birthday'] = partner.birthdate_date - response['Sex'] = partner.gender - response['Address'] = { - # 'Nationality': 'xxxxx' - 'Country': partner.country_id.code_alpha3, - 'ZipCode': partner.zip if partner.zip else "", - 'City': partner.city if partner.city else "", - 'Street': partner.street if partner.street else "", - 'House': partner.street2 if partner.street2 else "", - # 'Flat': "xxxxxxx", - # 'Number': "xxxxxxx", - 'Province': partner.state_id.name if partner.state_id.name else "", - } - response['IdentityDocument'] = { - 'Number': partner.document_number, - 'Type': partner.document_type, - 'ExpiryDate': "", - 'ExpeditionDate': partner.document_expedition_date, - } - response['Contact'] = { - 'Telephone': partner.phone if partner.phone else "", - # 'Fax': 'xxxxxxx', - 'Mobile': partner.mobile if partner.mobile else "", - 'Email': partner.email if partner.email else "", - } - return response diff --git a/hotel_roommatik/models/roommatik.py b/hotel_roommatik/models/roommatik.py deleted file mode 100755 index 01e55ae17..000000000 --- a/hotel_roommatik/models/roommatik.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright 2019 Jose Luis Algara (Alda hotels) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -import json -from datetime import datetime -from odoo import api, models, fields -# from odoo.tools import ( -# DEFAULT_SERVER_DATE_FORMAT, -# DEFAULT_SERVER_DATETIME_FORMAT) -import logging -_logger = logging.getLogger(__name__) - -DEFAULT_ROOMMATIK_DATE_FORMAT = "%Y-%m-%d" -DEFAULT_ROOMMATIK_TIME_FORMAT = "%H:%M:%S" -DEFAULT_ROOMMATIK_DATETIME_FORMAT = "%s %s" % ( - DEFAULT_ROOMMATIK_DATE_FORMAT, - DEFAULT_ROOMMATIK_TIME_FORMAT) - -class RoomMatik(models.Model): - _name = 'roommatik.api' - - @api.model - def rm_get_date(self): - # RoomMatik API Gets the current business date/time. (MANDATORY) - # TODO: refactoring 'res.config.settings', 'default_departure_hour' by the current self.env.user.hotel_id - tz_hotel = self.env['ir.default'].sudo().get( - 'res.config.settings', 'tz_hotel') - self_tz = self.with_context(tz=tz_hotel) - mynow = fields.Datetime.context_timestamp(self_tz, datetime.now()).\ - strftime(DEFAULT_ROOMMATIK_DATETIME_FORMAT) - json_response = { - 'dateTime': mynow - } - json_response = json.dumps(json_response) - return json_response - - @api.model - def rm_get_reservation(self, reservation_code): - # RoomMatik Gets a reservation ready for check-in - # through the provided code. (MANDATORY) - apidata = self.env['hotel.reservation'] - return apidata.sudo().rm_get_reservation(reservation_code) - - @api.model - def rm_add_customer(self, customer): - # RoomMatik API Adds a new PMS customer through the provided parameters - # Addition will be ok if the returned customer has ID. (MANDATORY) - _logger.info('ROOMMATIK Customer Creation') - apidata = self.env['res.partner'] - return apidata.sudo().rm_add_customer(customer) - - @api.model - def rm_checkin_partner(self, stay): - # RoomMatik API Check-in a stay. - # Addition will be ok if the returned stay has ID. (MANDATORY) - _logger.info('ROOMMATIK Check-IN') - apidata = self.env['hotel.checkin.partner'] - return apidata.sudo().rm_checkin_partner(stay) - - @api.model - def rm_get_stay(self, check_in_code): - # RoomMatik API Gets stay information through check-in code - # (if code is related to a current stay) - # (MANDATORY for check-out kiosk) - apidata = self.env['hotel.checkin.partner'] - return apidata.sudo().rm_get_stay(check_in_code) - - @api.model - def rm_get_all_room_type_rates(self): - # Gets the current room rates and availability. (MANDATORY) - # return ArrayOfRoomTypeRate - _logger.info('ROOMMATIK Get Rooms and Rates') - apidata = self.env['hotel.room.type'] - return apidata.sudo().rm_get_all_room_type_rates() - - @api.model - def rm_get_prices(self, start_date, number_intervals, room_type, guest_number): - # Gets some prices related to different dates of the same stay. - # return ArrayOfDecimal - apidata = self.env['hotel.room.type'] - room_type = apidata.browse(int(room_type)) - _logger.info('ROOMMATIK Get Prices') - if not room_type: - return {'State': 'Error Room Type not Found'} - return apidata.sudo().rm_get_prices(start_date, number_intervals, room_type, guest_number) - - @api.model - def rm_get_segmentation(self): - # Gets segmentation list - # return ArrayOfSegmentation - segmentations = self.env['res.partner.category'].sudo().search([]) - _logger.info('ROOMMATIK Get segmentation') - response = [] - for segmentation in segmentations: - response.append({ - "Segmentation": { - "Id": segmentation.id, - "Name": segmentation.display_name, - }, - }) - json_response = json.dumps(response) - return json_response - - @api.model - def rm_add_payment(self, code, payment): - apidata = self.env['account.payment'] - return apidata.sudo().rm_add_payment(code, payment) - # Debug Stop ------------------- - # import wdb; wdb.set_trace() - # Debug Stop ------------------- diff --git a/hotel_roommatik/static/description/icon.png b/hotel_roommatik/static/description/icon.png deleted file mode 100755 index 2f06baf5512a6218c8e1ec8d112061675e7fcbaa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44610 zcmaI71yqz>+cr#yC>>G~B1m_4h~&`2kdngC-QA!lA>EQptXQ#Icq5@2pZejuo}U~u)5pW z15YC$2#dMf8yQM5r`*6xkK+-$BhSWIY|BYMx3EV^1q% z0TU`QQA%NVL0|$KsIw8JyN$K2lc2i@)!%sqf#2a@vr$q09pY>yLiNw4v=mh+-`P1r zDS23VS&TV2I4Jo9SUGt3xj1>4DLL6Wc-Ytl*f`i(*f|6_*abP+DgXUP1+3<1Vk!uh zl>T=u;FAcIxwEsqARC*Tn;WYe7ptA485@UyfB+jiCmSax3owGk$-~y!$eqR3iTXb? zNJ5>A9WCsgE$nP5;WHY2uyb)1p#paL&k=0w|2wU%)4yT@1jgoWWY5OI$__u$e+DWl z{{IiPvH9<4CucD9|L*sHoY)ECVGm^kL!Ing9F2jCGo^+vWiR;75o+XY=LoU0v;L11 zRm|<2?VQZ*>?z;9`ztj{dQA&k6FWC2hQH4!DhkTkIyoEJ8bjqIMW}#TSS>6}1mE%s z@bJBT$15$#`;LP{iXZqSA`wJzsDA|_}}-!{lCul@3SWV`(Akd*Js&)&9K2Q_y2R*|M?0) z5d7EwLKpb(U+_b10mM53&=!1t)QNylSRp6*7UDj)-|XQ`Hko{7F!@F2w&f^+<$WV_ zZ%o4^3mXn{z!PGwC%?pH4f&BxI0Fo|hi)IZoQ7_NqQ52wn;f* zW+6uB3sgISxj&&KxBAFSzT|NCCVpZCv9{qL!LHi2wk7k=9~`;E_bx?{E45*#BPZ?6 z>&KqI3hJNwE|B$~-yn$apW=moKT)dx{eb{R`TG+F=L7`*|7Qq74xBm={>LE*vIKws z_CF0l_{#YAZ~xNz}jnll)tA~0ZV3Dl`|o!K-oa;- z3V!;U3E{6C(gSr65#XDzd$AAv1*I+RpF`r6S$+bf_Gu;WtR1%u>92V08DTua72I?UqNTTeBAs~dKH9r9sYX|{m@;6m2Xr2(Lsw3Xp z%3n&BUgvu8??J@tl?Gp8h>4B=IvE(fnM2Ff>El%XO@wlNBT@3t)|_`kwb+S$9X6|? zYo7^TT$iC+<{HvGCbjmwviwK5hLFhXck)h;9UV>=JeR&JD7m!l%a0FDNbUeA06_UG zmAt#!-u5%t{Y~;Z^GCd8mngI1xd<2h! zzkjFq>F6j$m;wD70VYy3nKE?0U6{3~gehpQ@3&UJB<^Q_EuwkYKdZO}ztAbfXhwvZ zC(b_$UN)Acy?i<2uQUtJ9ovtHU<1u6tve9{g8F-Fak6Rq`{u;2j77ij;(n8W5k9a+ zewxcnP})Hzaz*i%34+5U*EuTE*M1|W{ln`5HI3p|TDfD+6N(EzeCVq20qJC*0XN`I z3oN!|CF134o0nDvtOkSRqdZ+sZ%qB!!@8#a4*+18XSRE@=uTW1qu!au#j|Y_{%!9X z&lr3jfU_Ml!>|35{6X$e=%_0Co?v=~BM<4Hqq*I+0(!w(tS1QWcmSqWUaJsi>#!3) zEQ~I-n$WwI0Be1N^myDZq$Vq_KJb3hL_`48wk?(>4{yIO;6dWE- z8LZlw;DOLjzU7>4wn!d*{dz(q4i0SKUS}#;p&Pk^2f{t7rE1d!@nw=X}>f|lKH7TXf|B7yP3+FJW1DkFc&LjkMrG z+Oy)%I3Z4NkS;M{z8#ig3`r!K05k#^AWcK~D&6iVDZ^7E|6+gW@mnD`^_z2fl4QJu z5I|@E9>nuyIr(`mOl4A&w?sI_t6AeggF!naVXL^@qK)4){$AqY23RBgX7HLfV^%`Y zB_1s|1*&B^3D;Y7!*@^wf4y)frd9zb&pB(xva;C}5yJ~vhW;o0zaPJ9io>yqz``Z~ zTx0pp2uZf(&cU^bxItb~J4yvO7hIHWtS;m__J>}k2@Nh5dj>R%@x8~n=|Qdm!htJ+ zJc)W8>hqf5oTlG4aiZf!nh4euaDI9qy6^g9!0N(kpWwJX;pv@#X=3#hwI!{>M@E79 z<_W@as~ry`Ia8NyZAM86Ieb1piwC(B*ACy;d%QTb3j+86z{Lvq!-=VrTBZ^1 zD8m}07&b{A(j6yy0-Wko*b_a3wuH6CsmdP9LL&&(>+{`_)0mOYqcoAAB?QAFI9-1i zHww43x7_WNPsh(A_BTI}#~ZkoU_Q4O^Nrf6Y3@MkQxaMHi)lz40P)~Z{=AZUP{0kkOmvvjuS);`I7M<6aDqua{I z!ZCia*4s0*mA~ZSucX@5wXm>P!a}>xyRHFfA~?Z=pNmiM%@crrflby;&~jO^-~NOzivT^uV-jF7aWBU?2e+XLlv-HEr*g`XV)b@+=d<};s zQEVbYHNk?m(l$bAfHD0kmh8l?Botki*O0=|X5Q8DJxxr^nAT`@y2S8AMrhDy#DO8b z$3ZiOsGXhp2`=**>AdxDwhsa>Yt^x=EGJh6MXlC_5?BnlZ)Zy<_vRnIGj-wHFJ_W- zLi&Cy7fi%OasbvH&Q%*Pm&`4Rb@e}xJVj(IH)4#p%rK(*tsli8{|_E!9Hl2`d^QHQ zkJDx`(vc(!{*q?XFZ0Pr$Upj3^I5gIxCqx7?OK#FROebgN10JR2h0%h4r?C`@b>(b zqSw0T)TFBOgsn8oii>NmbbZOU}wW|I>NAG$rxwJ&@UVlFK;x9@)RHx_%U48nMotq zc&1W`t(Q=Fwc(r`bsh4yr6mqas+?&B7hn|O7qJ#j^R>r!q>7lvO#RRihVogh^bE5< zILXs|moHT7TqqGT5UJGLxFSA3iaj=j9qhq91dkR4)O4f?2Zh{vr}@kCI`@~TZvd4C z;7L5GE}fTeU}Xm_uftYR2mudr4tygQa_i~>3v#xX`g;XZvLAD2fAGBJ{c*pXCWe}g z6n8dz-~05^)z3v!TGyN&&<4&UWB@qWT#OH9t#b?6{0`r;JsdIW#a0L*unDh@?92Sz zaeh(2uLR77H8i_|lY{T7=gelj=>5pVN*_WWOr_NJr|t_1IU6aa83KDEz_w=?L&7aW zVmhB=V|YvCwg?M%aR~=mQ)ZFw-D~HLRhbuI)6xKX1}D)Kbijvg15o=oX-6+C__pL> z3p8y+E}_wei8I02JN$S!U=0{HmrjDeU~1FgEmV#gwSKtR`N?pGMyrEZnXQtqtUmIPXT7tfv`bU{-GbOdIhAcL@_o4bcS5q}9_4CsVEow7M@kBC0tt{pQ8a&l-^cJ5y7ts<$zD(_m5A z+i|v`!n8tbdEqR_kZVjjfoA$S;WKxqFX z1VPh0fs7tWrWHa<8t5$D8Tvg80!IVpj0#CzvZ@XF;Xq$~tPwyu%ov)-jN$^Bi{HIt z4BDD!>z#*;P{p0yWOC5z5>>;9@+|8dwS|P~p-FV~Uh_4_ck^b$=gb4tq|X)tjTr~i z=WFtNy2tr9{{f^lO^s?vP;J%l9wsyq_(Qj4w>wtwJYr<9PvrLF9>fJNoxVKM<&sJ5`)XbpD|~Yn>%T z*vU>me5^2f0d%GqTB8`X~$j zjPcS0B)Rao1Ls*a{Gn{B{x8+}8L;uW+e00yAc5jpWp%NLA%({W@7tJeuznPv9pqL! z)yNLdr5NTJ$k74k0E|-eNi~d7-Hw|FgOyESC{MdG;DK|8?+m?}0L@dd*vt7my;Lbq z55e|rJcz~kO)V`gl#cdo;a|hW#RzyxM?ylj-n(w`U^P5)wU~z3!VIgwURKao0(<=G zv3-nZHz1|bU?|}50j`XE1PB82)b|>j6-1eWDq=%Nct-o`Do%T9rrK#bjfyd!9Qq%7 z#SsvDYaZHyK1$CJ%-|FZKLt>izP-Pa{;2twYQCOamTUGVRPDzH-PMf?!?&wl3uHa$ zJt6Sptr8M6?E*GMNp{92S$i92g@h6~Vu5PJ@W5SR$px*NX*@{L)_gm0j1ypQ5fMQ_ zuKT@9jrP(k4S(M!)t^<}m*W#~35jJF5yIRF0FQ@wGQwWLt0MfX)3a;|3uk5<{1PB8 zndcER`^^HNpU{$E>)_1Zh$EMp25t!a-;>4{fG<9mnoe2Mnv-^XZR0Fv-BK5JtJzA4+&_vg=yvv;3bOzo!^T_ThqXVM9}H ztqdPG`|#Tme^Qknc^Z#75H&4VL{~tW+S0?}7f@Th(XmiG^TDX(Rr>BLd-^i}!j?y< z&tjd06meePH;p#(i9Q3W` zqVDe->_$P-`LusynOS3$_aiy{O#W2acYp&FKNEPnSCJ=kcB!K7YBXzp=Op8G)gcUUDT+Gd#k4DwR$5ZU-MX9!xWNo-2wd}k zAV%v*qyA-9jCX#{1k7z2AjQX)5!*Eus9?U7qzV&Tf{#XJRH4=6*u2ws13M!=(EtpD zM5Dn%v6OhPAT|lW_#@>Ew7(xgHyn=utr#3NE9YeY$=dq7j)qj*L+7Jh8Rf#6inG0* zt)PHrLL>KpXz*G2&OPh#=VQrnCt$X=&wXxAeiYB}gIF~c>_0Iwco_MCWE%7|+)+?qk>ECJ;zU}u!BlARph+sh*>btnQ`KGe(Z_&6#5 z=Ji=Nxb@^K7pbhq8*cvVtwQvgqlRj06%;AqObg1*4Lh0wxukoo z%79v$Hybo|+0Jz#dNznA+eqd0(ll$TNrRZi+0$Xw$HK6_v?a9e?CwJCpa6W)iC!v{ z4s1=v$)2i7$LF`s4q>{|-E5{HNZfJ0;&RW4@cNyl41#Xh#Y0@hJ{_{pmF;phHSJR$ zB;L2_fH_UIf~C7YfDHj%oz! zsT5&fGy@j5HVc%ig#E0Ah3iYqRV*7u!zWFENpX4$x?&42eeb=R7qQavBw$OgNDZ2N zKDwu$XgI008vQ8trM5y2X?-;`@Xhl3WX0&8`Gie|v%aSqLP#r~!OPiABld4g=*fMI zG&7!!`5AIWfP_W2_Z-M*K9ER5vhm!rvPL@2IG&OyQ9@Cfs|PDoNV2W9sde zs0imVC#R(vlMqVHAl^T#Em%=EtDX#5#YG+C8hPDDP#P{vFe90b$DnXApBMVDLDOSY z_;HL2zf%t)U=M(McpS5zu>Yy#@1#O*7WzM>`(%Zsmn#z!spK|rdIaJfRkWirSC4)wq6i+|od$Abn3-H#ltf7@2Mq z5OBVL@-sd@k#sMj31wDXT&&|Ar7Z1yVp19fk@Di#zsGGWpyw!@?GDi#N^=!1eJqze z3s3n>e$^lyTIJJ>&&0GrszZ@PO6G|Q#V^tE^m2ZOd`5;^jb!^x;~VGodLLd`?5$dR zDPVC`OdxA=lVydiRq0;&8`Xp35WHl3r4Mgez>G{rprUpl{CBhVWxo@K^R zgF9(hmIU;%BDrHKf)eja7BHVTAk@tiNPge+zU{iu=g-AhSDro1ygj`lo7$g0+_H<$ zAqAYalH+_YhqqsomQFZ4hqmS7^O~Gn*;NF*q!H>URuj#atRE~&F7Gd$wlT%qf&is} ztM6w1tK0b==pZJRZx#r4ongwB{>|64WWPgbYe=y4$?A%YP;bvwyNDDdJ=*ufU1zDh znkjxofWL3?`&7T8tdZ&Y)Y7*v+W|K4SFP77e8~UtFm^f?{j{;Z6_o3l`RiglEUS5D zmYtXJPG7L`bvO_6i-YQhM@n_G^PyR;Mf5W=Mjb?e{u%ncHDTW@{Yc?>Yb(%YR3FxS zENN2RT0wNYHwG`2PyJnGx=t$Xv@ zy97S#v^_g(Wb?xYB&WYOds&~1nTCtNn&;?}K(I$0?ak%KwN*|H-e5IMeYt{`jpw`z z7?r3$-!PTJ`NAW}UXj@w5=h~y_Lk1^Yrmli3gnjS6(y9nG(0{*ypMS7j6%H$$sCUQ zY)ihajPdOJ>g3z+a93#=bTbnztzVc?_PgN-_8c8-qcX@hSGTtkx!_mmukf1$QYDS> zN!<{4#3&n7!+Pw5=A!u1G7njz_m$xl*x(DnI_gVjdE+c+VSGhkCHD-lHG^75 z%By@m7hseHl$=NZZE2dZ@2#1W>5NvzZibMzoZ1fHiY>il1iR&!uHQC@0UT&Y@7M7~ zDYjeN{mciSK4>qKb{vC;@QCmvdP%xNf-PfWn)z)t?b!h>FfEq1I$OurUFPQWhdcCm z{RK;-lMyA_fz7Y#xL)rFO)z`o2Z_JRjLG>uTVLNaX(4y7bU%-Mdohn3w0rA?B9Ofm z{-nC^dDOu3XAr3#?M@F!~#Pqe)gzus6J?&ICO*9mwL7>#WK{aB|eo1@QFKj{@mV(YN-@t5^s?_ z1?&ZlmecqSB0Q%lZ3j4{Gi2F#QJPBL6~FEA!&K_;BCSvDV%a7w1Tsdku(5^)mtreZ zW5!ZCjL29Q%{Wt=X=0#XHhxOw+&PJ9 zY4K95^im)YAYpctVfUAN8Lxi<*JSen6z^WFim9v=F0X|eRCG-54a$AJbeNh?N~Dp` zT0%|Lv9~YovzTtt_#v>9ekYf1+H+-tr`pl=`{XXkiTC{WuWxCKOK2#V`Ps*(p3;?W z?S?Alcm)LZ0jlJmG&|zgOW_h(GG{ge>F;h&v zvHh8&06z}_<5dc02|o=L)N1|#!ps&gDV=x-%Kq(q=i`G?ZMola`ijPjh?#5x4QDF} z6pQ=9`@J-wx==Lo6_VFud%>@s0?C-dtCSSM1j5LfOvQ`!nC4~GL_E8zlFgs`L8}ef zbv)~Y|HMw}ntvklLZdgJ=$(l|tu9%|ZoXQ7+QXR(hqeJDhSa0&oI$ivx zjP$sg>uRA6CM%l_Wt$poEVzFoSFRT}`U8?as%%;PG`P4;aW5_oN-;DLk(Wovn$uST z)C8rg*9cK>Yo`dm+$VWUIfTU-g^|X$9q9}MDHoQ-{8{nb1|RQz2O6o=-@>|D!j*MN z`+L(?TFxNJJ~5$e@^|kb8+@(Vta^iXeZK)a2V_Y6iQ-a#0@TG2w=)XmX3HlCASo*8 zq`mTLX#~6${0i@r-u!Qn(pl0+Z<3mVd;(YkjC&=4EplHMxowM7S zuqh<^(AJJE+$y8(x}vdmAX-+!T2@w{tc*jktdGab^(MT=Lhe;nx>b7ehqUF+I#6zO zWih8l&p%l^$;M=i7!S*?;rDF-F(v&+aNzP&j_0`;*z z0~}FpcH$4sKB2taE*RD*>8D0CZnn!msA&nC5rM$V5+E0YbX#UCTl-^Vj^e6M=Y4*$ zv))Fw2@^Bc_h}xHv77^|WB2Fh2YRytLNe09(WYTrea=dnRWA*+pU3rf(PPwb0N{Pa zz&xdQ==m1*qkQ1!X-ylo3qUo|Xh$;i?~~Dmv2z{`Aze7s;Oe@nbFf--5GPv4`svC3 z;%a-l$-EB`IA=sHwI0TL>P_0W?V4bPV#f4mW?5i0ig(8M(|vqOyj2-c^d+B|w|#mm zAdm`xFgD8|;Fpl{Q?GbP12x`Z^UH>N^N90TIcV18*?4k=zRqiZD)UJXL|MPcdk-wM zE}YU-M7UyMwaoj>E?F}cNiSr?HHmQcP0!!%PGk1>V>T}it{X30JUyMvZweNvVxr~{ z4lMM_sn5Ud%36Ybot)%Ci|c(56=4djT3mYLXJaM8$AwuoS0PC7CRQXZ_2_7C?|C*) zP9M2AfN-fY)oK?vQmCVhGD!xVEd-!qtl>d*V8w$6F>_A&K0# zgoC=toJ=U*Qr}hjLms-jgxV|{4{^?an5DDY^!$8LK`ZY#crkHC?;m-I^+}j^TFp)3x@}l ze5?=D1@Wk=xnm2dao#;O2L_;F6YVMLVcdV5h3xOq2APGXGkZ-jOEKw+HKQlV$>^18 zH9N1{3v5j@O<|B5^BdC#GaD&$4)8DfENc2-PpG)aJ<;F z2ncY4Zpa?kxov|0AFng_mI&kNs(Bi?sEBCPWYwvYo{=dNkHCeWargAN+_^f9ps6n+ zf{};vc;wK#FtX6fWIHzFP`gq1W zR*j;PZtQQJMX8zLR(hxqOarOOM?NNIP+q>Vvr}}xHr4mWUHow~p4A{DvAFn6aEPko zdyn3Yj`se+&El^k_YO)5RUf8KQ4B}c(Bv((6MGr&{5xS5w>L;K_*6p1-+~4N87Rg zgq3d}Md>9@MMNwnwtjSfe>*-VU!QJ@Zfrz`@;h>B8cjo!Pf!F z;`3U6JTQ?Yf14OEdMx!UyU5ku2C6nX&;8!JoAw+Z+cb{d!x-M2q?s-kw^Kq<4mz`B z*?{V|g+kirbF}!>oYlUKo9J)QFDPzUa5k%U==ycv>~$jH0Wf#s#9H}r+%|C_i;nw4 z^%PePZgwMH>_ffeLJ3O_UKpnX&$k4kmoOZpNA>xlQ6H=YvEiXX6E=akDp76nP~_eDRuf#Phm66?~t;ALKT zPBVV>C&2T>1h@dg{*5Q4*-sA%mhtu$ItyGa$R=_2m}ujo<}@ zP1(ug-(93z^N};liJLMgQp?R7l(W+F=RQYQ7rJMkiovj}V3`AD`TSM1)~PH~Z4N=- zPv}%@EYa3y*jbD}sgIT9ou)g0lq8zdTT36BnD7yMP-%y{{^;ZYl?e^4)wSrQ?2c$* zq@}6D$>N#KIup}Jmmx)hj}V);aQDonMOE9FR3^n4i=w*E{?rK~w!c?RPPtJWoblss z^h12FwbJFq0S_^maur^Kxr*jl$(@8o%zsS*ySeUdRRql(&G+6vr{3!X645z)#J)c+C%AZB4185RR~-5> z_A|GDi#`C7L7n+`yKyflhR1E$+5PC zG3EGtIh%QTT14>Xa6`$=0NMKOjU9TREJ3&>mrGw?9OTpo^~(b@;hOYCf2bh-@Vw~q zt6#HTXnjzZh(hhIXtwXot09 zc_=^pJ%7LB-UEd&LmBhgeoAJLj*WOeP`$n7toR=Iu0XIHJ6JPu)}o6NF$Yb0BY|75 zVSA-^)|}SmvfvVmfGQ7uMAvhlMGtbvbf)*WcOMf(MJ7Y5ppPMnNxnf^`b`n(!O0LIdUb~CSKZ4loqLp*Gr0I? z=}AdI^+2eF%>SBMoMxdJLOyvCc{$Z97usEo3=mDckeX9VdTc-Wop=-W^~h*gfbYDF znZLrWYqKWYvgO0_8$nPvq}xg6*F9Xdbnx~7RmWr4=;+7n>_!CRW+m|lf;ipJ#Q23n z;gMuEw&hogTj=p_M7a8@kC(~gd(1a#mK1%xPUDT)_U}QS5a&Bf@-rx^i*w(uRWQC^ zYuVQ7Kw9013J6P-hH=;4#3ZInxzz|ZaBXcE(tT=Vz@~mZ2=wmljB;=+i5g3WNW%L_olVa=~mX7W2Gd%=5(g`1nT_2*fV@bus1D`p@^AP@T_s=9S}(ly~GHV zbQ=2fYqB_Ew&N)5)AxLPE7uR-kGD>bzs5mpHlMh*7sPnqQ!vx#>=rc0$cXLKb3%0j zln^<-a-!P3Wos)S>wMhhd-Oc=$x$AH2yxp_=-U*o;lXBgD{O>jrK7HN8ET)a0gmxT zH=X-{9zIY9QvzkAB(r|{BrG~&chn>La^xuTQ}Os!-@vB3WktY}qlX;$bZjlq{`hts zPqfDGZcle1;Ng5^`vJ7g< zpjM;iVpz6qITRk{Q+pVvRy!3c5SJG7u2lT4b<%=FTm&Ba^M2%Wagib2pUzuj{wQ~J zp5HuEKg5Q>RKi@zMY(;b+W>0OzOpeX=fxKsJs=YntRG&T;dYPd3+hWNhW3EoAofH#gJK zcm<-RydkA<(zK>82s6a8Kw_vgi1^FHl7*#v-vhYp^IFV))(Sbtk04~t ztzei3w^=RQ=U>}Lz4M0RX@4nV4}XX#L--rK^# zNQg&j28DwWqyRcUo8LGxcu9H$>D$aky!X3uzCHCu=$Awt1qUxKd+`YDbvq=tzkcPZ z!dni?z1|AnN3C$=w3x&40IFGXJ~l^d9Zn4|r+?p;BJQ-ZJfl(v+G!0Z>h^yjE10gK zh8Tpo278Ahe}Vr=nC4Jfl<46KHD*btK*^6WnVOcFjnq3GfB*1%qlKzlFN82Y>bY;#0)&B8e01d1DOP%eVJWQock?sl%`!`X zV~xarIFH&QS>BC3H&i{Opf~;@9^|C;&ON_%>EvYDV4uF0;k%8`H)Zr^O=fPQ>eE;0 z37h@s=#g}a@3BQY`oGlh!~iv&;SvHN7N-i!`ipSzJu+6b634PNBpYVr?veZ;u&>To z9T@M+!o~DC4`+X(gKVk-yQf5(OMH&}jX)-m97XqNcY(JoIy%O)I?F_xmSB6vGwB>>(sF2yft-R%^LKyrl> z?)cS5q63|rANS^)rmCA zK*M^iBURn8NfXOrF(HMGX8Elxjs7uV8o|0YR6UnF$Z^3!QhHmu#PQ3nM~hM^M-qr$?N3*223+?+MK}(cBKHX4brH zwlD|}Q`j`w3YnFjAF_GBG-s5%GwNASG8gIOz-ge%;R zCCVtqH30WLduycBj#vlJ_ak`BxZ=(!k zd8pr8!%b~!1B%{$iSOK5mR_+rleu!H9iR9=bRzornn1RGsYpxags0##G4U$J#t94Y zCE`;UmFa&!zF0^0geq9~i~E5Lzh>6*(V&(oD7;Kh`xW)swPq~aUJyuah4ec(xSN}q zCnf4C^^$D->_$&C25cfFXJ7mVQ^<0U7k;fsT(Z-ADR*IpJfJ7a7~7e!aSFGOV=(%M zdK7rPwShK3*3(PAXkFZ0!Ig3Bj9EFT&)1>iplr!Fs{xd_2M3ZqByOYVYXP>IMALII?S>YcD_%8bGz`BY~xX0}m!OrtHiQPbFFNY5Ebkl+#gXjs+3|f(YnR+>unsz}&_WPkO z*we@0XvUnEr_nq3`j&|Hjbnd*ql83=uM18h?b8|OcVfl9b&mzHFcK#Uk-_5*zLK!6{V=U@A%*_5^VM*5 zm69Ub5lhdaeUYT>B;k`CG2-~`Dpv#7uM|b}tS4Nly*2I?XMr|f9200-I`+~d&z{8M zW|jgZvV2tUSm!JzqFMgN#mx5uIK0EF%iOu#`+m0J9Hbn6AQ=S-FuXK>*kv9A6?A$4!b(`m0bAK1s` z-XN9gD~)~~3Uyzy-3U}}9V&e|I%x_t6l)z6G<+Kbw4%p0kO3KjCA?lSrpY)+RYiiH z`OZOfxn<<1=Y9gUh=uwNNz&`5gRdI*!BNUafg}9^4$IzFT zY-~8@6jaN=7FebxF*e(GzfJ1-vF}fZB{bNkG8jL9);O4v>ph5mN$&MVu*S_>p|1kV zG)B9XrcTpVYo=r;IYu$XJojt)6SkgR5{?cMDKg4tzKzgc`6b#ri}5RtA?0Pl!%{7~ zOd0dJnP_d6??TtUTitTwAOUB1M`9ysJaLoLY#Rf*QrBC*T0{iS-f1BmR2W3!^6Tl zbkVaz^IG@gaLTeZ#jEA>yUnd$C51T>@>l}m1pzTH>RgdvqHvt#CVJkCn$vBuvND(Q zUOpf?ET4=38IG>HF6K)u@8REM8Cqux~_#t^a-&|b9z0m?xU)SXY!fwp?U9;-^zNYjKQ zDtQmgzOu^^Hb~1*0&oKrFEi-slqCObnXFnIOT~^D_+@iW#cb`jt{?OEpGWe7H^W?`} z`Ed}5_IHXH%30P%s#m*ScFH;Qtsayj#;=AenT^*x)J@_%>GT>0@5=K$QNH}6q-kHH zszqq_Rn=9zv3ErNy!p;H7{ZbvF*U@^2FfjUYfk zYzP^0STHggV25$jGN&0j9aV8V@p>JTtHm#+DAmPCv>HXnP_RyGUlnr2OZLR&9e!W^ zdiZNdTiEHQLBG2=mouc5X<+mI3wrmw8;)2Ekk(``W!W&)a}u=BVfYMxvoVscjYnZ< z@V@W@Xr!Uef!&{*ASA)HmHlk7?6$AMGJZHk{(?cmLMWiH4 zeFbDooleJ1^t$B@4A7QkErf8^7_g2jOZ~7pH)`!$l+hq>DWEk!TTSxIE2 ztasHD{LY77EpBA4Nbw@|utk%tr)_@#IAP7oyDY`!tLc`d)a7&>1U`vCR)5v7=-c&! zBOEFWu4Q_v`X4{KKdg$@CVq-%%r!M&US(W5GN_mIdywGoD7~%+9rP~q^4YE#b=~Tk z9eU@2S+wkcw@Xg)#Dtf58)4CfR;)c6-6*S$O;cI(g34V$gQzjjB#>flD`?X|js_CZ z9@#gr&Ql1|gXGn0Nxggfl*@0t1naqtwd0YB?lr>cbIY5Zkd)oP<4^agsxLsk&7MhM zjng#gxN3_;Gt&ac`%?(O zGN%Oi?KJ~r)BL=qw-@Gib`^BFlUEJX-1Co$VuQneJY4hLP$KWr#3f9+l*i`2;XSKF z_m_*c`<4BpTtZIDo`fRrQDg4N>w#7`(GPml&jGu_ZwK*VFSHtsisWxtjrYzk=FBoIRzJVKy7sW%UVF1lgEU8I0sYb5T zFGo*%S_95>0Ozb4V?@v0)U=D$lAIiDcsUuakJ+VgD`^zOH<{qwNcG>C8d4g$~eZYO_@Bq3m;U7 zupEc1Me|C0t6PSUop+NiO%}Jy?ZNDf2sp60F=;7piOHGs^Q_JhJ+jdc<7RAbEOKvZ zj4u=Aj{G`KY#-4cEPjDtzEYZJZac}U?XSP{^0lzr9lZx9u*@V#G<9qE95v1EyC$wf z^#&8&_7x&OIX4OcFQ$oA*PIg*_OE~eAR9tH9Q(fC`zI2E6kg@UrsdwMwzk|kHxDKa ze#KO4cDfAj(WTte61C#>l7I94&}fWHsPb^S2$C|E#LuB4Jh}|Lh>(4oZwcjPV%2k( zZXS+^yaVFJ(u=+Wq<^amG1`^ca@zr>k^2o|`n1*Lm1=j-j+$IOe1|%pVy`-f1O0%P zzx!Q2u#BeE;Fq5p(R_H(=?zl?LYG4?0S)FRdja4*#tq$SgVj)Y-^Y)X-F`qwQ-3il z7hasrxN9&c?a19M%w3mZ#$m$bTzh_bn&FW~y5f;xlXfv-C zmiZ-QYfE6Lq~}i&2QQZ$L*!=$xkb6vw^&MwJ~NX7Efq-V@V6whD@L)$@C$wKYNJ>< zWh$fGx_a=f4?DjQMP{_rn0r0j3AxGth$`a#EV{y4$DRKq%7*M!~2oUQY3Qf&d;_V#nKnZ1aM&Y#fj7x0X5{1>g5c^2hrL0^0pId*=I z7RuOJtod$-6BA|26fTcrnzKZZyqa6|y+Y*rfU5>*DLqx@?gbFrRhm}P>Afhbd*(xL zOtU8Wv1=Z_fFWPrAdr=vrmDx) zxoCC?LOz4oQenZTm%{CG^79k++BA<{d?|~D4maE7^#R=|^G3HtjnC{5Dy)CFAKT+G z#%|HlM&A#VMt`fnSd#`jbU=XAUpOK9dc78(7mSlxG%lLur)b#a3cu3Vb%B2cvln6M zXln~z+g23(+4HgdkbRn$?#{0wTdAmJILPh*lzWpJ(%mI?X<`?3z|LHyPDaA=Q+vQR zLbX*vliEyMRo>7$1E5@w%e^Q6q~0eCn*Q8BZLI#r6t~-yV-h&1?sFQw@dbY@!8ae*coZw-HB7XE)Vc57}yCutGprr1ZS5QXSIv)E2jH+BDg>1^7<~D7{=Y$Cte=d zT|+#}WDek_TDD3p?2Pn$!;j31Gt!1Z5y)LJc!wbb3!f&n8#X$!CI6zpPf+8#7N&D? zOTGU{?Ucx2+n)IC_TqpdxpG}~AIUi~oOcMFYThCK&#<$8Qam2lFX&U5n+gozyZM;& zoAOhyiVM%fyID&NzTf^!Xl+`!VzG%?_z|1l z3rZl%kD7U1h`==ab1g|o(o2-J4i=#)uO(b7Ff)06UVXWkbv#DMh?Q$aKR;-jLYg25 zmR1L*Vb?Y#n_uQ#8_^1j@OqFB*p zQ;p7FR%b5_8Sr`zC7^J-9CW%ZNjrX1bEcmVbVrVl7jPZ+{`>dOjcIxkQPpw9mn5mM zT5qK$<()hLw6Na34Zd7|dXfF|%d6)+cjYZKjo+hs;-nEoyze?TzRaiIu)O!Vvc&bE zsP}+Gg7{YV7U*POK)Uv;#iX&JUY!Nj5`_4(K}hrqeHIm&Cj&ucB_;y(#ViOZ$j|y` zcvX4*=k@YYM}&z28N;b5#Y2o$H~#OV*gzYC<+`9_v%dQE64kIB&@WikW%E-hnSfBd zxdf61Qf=kh$%8)EOnsjYLgkit(-&|J(0(3%{bzwrjDNPEl*bBwSD~B!gNO(%_@o;a zSTz#ZR{z^U)E?Dx$4F$Za>OxJeCN?`h_W}UZI1NNx&_bxZu2&9H>_K-iqzNZL_BG~ z(BYZ)=+5=a!H3@x+`V{@t0|=5Pc$RVUSVW+s%;y?%j0kK#(cFGRV`i+5aP1FjRxiE zFf%YwwqgUF2!POKZAk7A9~bi8E_6Bm!v)KS{gr<_T8)E!f-3+BcNyGS_L!;s&}GmAVWh`dA9#0*?LaEbsTBviF7%bL)!ZQpTJ+ei8Hv4L}D5au@O^ zep;=9ji3)vwYMHXwf=)|;$!9UqUXHe&C#KA%KtrvZoY>;*qKhK>RX zyydiTjp)=*?%J#4jMeZ|7Ui|xyp)A;%0 z;@3eb))>@Epau7!k@Z2TC1G(U4XE9Hb9-&zd9FDkz3CeG3PFK3LjH7ntvfWuKkNC_O6SUhx+xG!^_k+7Zl?3Y>JNBi`?9hh z0$PITem)*fON^RS$J=Qcp$vSF6OYfs4Y1fa6ZqxAnp$_vN%>Q7ZQ>Gt2d&gE=n|0IX?1+3=qp z+lRjk`=$^Rd~|Ow=3p(LOhk)W@SWhO^rUse&GrK5*KtO@svp@z~!g|d#H?7)1O z5&FL;>};x$)BEP%&|VKboffuh8Be+@b*SBHOVc1{7dDn6Dw+ZRg_K+>kSCwZjPLfZ zNccOGFDruU!Mdq+W4T6%{$h&vFBP&4MWYI%^q)_ycZwP??8#wPR;hWmLFPBOgU2*= zxxCkPkqd0IHaB1GCF=eEnLIQ+q*}Moy5uPosC-x3pjfJ_mf8A^PboDc$Y){Ok!%-< zli_)3r+-#C0dxT`nX=bcUjB^L7u7g}S$L(1vo<6AbP(VJNEhxe5O)TvrA;~9Ivqkl z_U-6pvQ(;;^JS<9_t5Z;&$17C$EO3`R9L&NRs3yfvK{e2W2xlfqGsZ9=*?N%)QtHU zSUmvfqsnj%1qRv>UyCO1%`@iYhFsDGUmu-PR91E0Y>jqwpiZH6Dgl!^W8pxdv0H!H zyTLDH12>+!fnRfMkMA~A4|V;s{{WupxtO~f-qWztltgsR71)Rrr~&iB2}Q$DmX(W* z2_sypHLHGQxdW}whQ3`vKFodgfDZE}`=y?vj+wqvI>wp$0p{#O1+#~r*~pm5I@RJI z?6)H2!92+%%x@0$3AM3(HEZ*tABJ5tlINu9b8e8aL65p=<_>GG(1Q15O91^~I|mN5 zS@oc+15V7Aj@et9X?V7mkzw=i7KC@z?85%Y(mm_7IBn%RKW0>2@rRUxJ2v2VLkLg z@`*reU;l3x&Hoti`3D)D*2{-pzFrw?S=0&6MGt9df|TS8;VusS^?K|GXxMHXAqdF-t8$#w}p3*v2SsRSQ@N{jk&}q$J@b2_Ut5qrY z+XmJ%)DMy+0xj7OU#A22TwUyKcJ`8bEnA5!D0xjKmz*Z3*%X!7*BK8=6!EqXF=l8B z{Lq=xj+)ucxp^OnSGOJ4DuH4G==i~%VQ9Iz66NEaQl>)KrYC&Z925N!AZ8u;%f3V3 zeiOjOlnay+dTDX3B4U16iDx%eIiPaen^;YEIrsosfiuXbGNYk!ilQxoSj06-_j2yD zko!sq5>vCW;vF{=rMPL4L6aw6e6Hl|+){_QE zgR2sGpjoIN0r#+<>&I@JKsy3N)tC(_?=lJ!KY3u`kgt63>oX@GFHD~PC4w&w@~dnz zk0VyVUW22pv?}VZZE_wI+Sk}Rp>wNcb!pr>z=|gL4KC;gQeCqWM4(3Wm{@yfx8FK) zur<9mUztxt%*1g)kS8FvSNDJ#Z18T9jr4$kIWYsXeP{EL7GF<^RbSuU-q%s-yBF4k z@Btp~HC(s&_V)J%ZY5q}Zi3)(dVx{_ba<2&o|Jbtx4IrA ziYXPx!va%|iTr=fWb0i4TZ{Mq z$e%x7J;U8JQYvhTDCC57{%7L-wQv0 zzl!ma*9g7%i|)cyfRMfT=J6qBvw8WXq!V|gz`DEM3f{vW5Er%d;rMqbp@6x8ZO)Hu z$`-k&GP2{^{RzgLohYi#oc2hU>I)v#Ac#8y1_A4T^ZCuv4X@T$g)m#;;Z)~W!1V0U z;`)nWS>&JG%ZxyDSS*f!MN>Q&{Q5nH$3josvNr26*9Hs>>)|0vBFQ%Ly}&hRosiC* zn|4ksDF*NiTUUFYLr}E)jUQG6JCA08;H`>d_95FZ;o3*0z;W|mALVtld>m_uJ?{VW zvIdIK!<=8G4px!pvtd%cBkJ=`Cj<3%26%;hNO#0ogGne|*Qzc#0OJ9aRl-%9OU_oJKMyYxe_6KLF17CnmlZX zHWa7%FWtqPrr4#V)IL|N-*?j!q_8~o_lhlwi3^z50JAomU7h{jx$JrrHR_iMYwTS$ z9CT7!k}4XiI4Ww>$Jx}nOdn{-H8c~jAx?Zi)Ez}b#mR1%O=6&V#y#t|pMWmA26pa^ zwI+!IQ!8tkuMleFG9K~53JJw(lBAMV-g)w{(x_=2 z?lQ|BwZ*L=vpS?JUMc>GF55bygC}8ZQrF63+v02pA`VF!1itadOX5!PR#SYCk*vzc z&`xT0KGyeFc!2Gzcas8p=75z+l>c*q?Rd}mNvmqmlnN2A!sdoV4HtLIXuya=R%ox! z!rzO3!Uy{Q(BBo8OtxKz_9^ASa!rBK5zwSq%784FTXdUVnro^5xO?R^Bvz45lRc!H z=%QAjg#0}Rr(+AkF@L74F0+o;+{{Y}0b`DoFb+OFW=1MW?FvE*YD9*-s z>~s@t*o0s>x}stx~6RPtGKc>Eh*RHyJaEBDB(q~W3QY^f1-BIo~5jNh(W z*lZC^13u`yC;4o>y}!QCDeBQgn0&xv&i&iuu;BbR{Lgo<<`xOAvxHI1$fR{9^ z=%FhBH>~@tyqygBI|nM~NWdwr4Ix+D`Q>(#rKKqX9ZzP{UXQK#MzHiW^KLBHS-m|j zB6biN!d)ga;OkkzKtagLzWgY3Z@k{D(Ydl;V}l_{4-bzHD=AW;V3OwM24GH*3{czX z^#B#~9ncx9K!x0?55zm5Km_c1smCZm^{Qz-xmd8b)MEqMM{hE{?J|Kq6+bn2y|7e!N{VC!Two zoUE>OpKzq4nBVxn;zqlS64^4?j(a^a zDTHqCBkEGkcZYQ~p4#}eiD&>NrWFW3%ZMbm|EE_@Ly?m2J+`zs?rRYFO z)1h(ww74-nm7SW;tqfk_f>Y9GFv3k&_cx)5(*Kh!ErQD6hwq%Kw{@8(&?K6Vm&vjy z!&MJ0S;)_7+cbKqc$1Dyo!OY@8+~K-6|=JkxWUr?QiBz{vWHa0NkAUk9r-IDE*b$L zZ+?0PaPN>Lc7C*Dnt*^P3$qo0Y+qV8Q<;eh0zrhFt&gaR0ZFD6TzSc%j%&2Gz zR1X8&5nDdJ54!2IU~`_VQaFDyh05G#*PnPo=VliP{b>ID!4B=ABB(OkkJk`Jr*bu* zAN|Y|Q}O)Qq_of5fS;VEgW|NAnX>XT&)JA$Owv|dl7!C1aEqJGM;^ybBAQ=+#(l#$ zO!^X~i(jISuWBpH{)!I!O;FSmrKJ7f)^@3IPbH`ARM>Q|w3~WIhER*8Ov6aZ?~&uU zLHqQP@L#Zd32ZE!!%ZEJPkP0!d+y-?nQ1V1WoKz5-0<4JSV|HPF5DHMzCG@##|7D) zv&L>+h$uazVSK+gJb6kHJh-|D5~{1Jach23y}H$6)t5Z?va<{`Kpwz}O7#!yue>Q3 zhk+k5`Rnjk4BmE3l$=dV=4p5b^6&}Cj{~bU?4sIT>C^S2)x+RVfyJ2b9flR zm9Q5gB4T!9cj3zGLjp9?ExuK^0b+Vld@W;PK8LgW#Io}cRXea{%lf=b!Uxe?OPAKu zk@Wo*RZ$-NFZopRyuWSl&nhh=`oX)CJrmjng^)G@!Ee)&)mp7bVQ@u*M9Cv0 zEN30^G^gmUSFomL$D@2jQ$_U*e`fm_^ryX*O$rCpmngtnA^R7iKI#4n-aS(D9|fj_ zPz2&x#osExr30V)S~vtzU!1v+C)5J?a>lv?2G!SBqTt!tY8Qag({G9pMuJeT@7KuC3*8 z_uXSn%$rHu8VQ+Rs){8}v61mg9pj>L{9=|SQkVoL8N4c)?HkzKV+i45>X#ljHE`;M ze-)O>U7FJiEnL3VL+H;5KC192cvhEhOq-T!JGK*7;M!!3TNHsT%s=)G@>zW%UWhm7Fs8BSfc6{-V&Z@2P=cUOBE^YqK5 z%T1(5dD*?24_Z486-&*>7vZJr_JBC%IvEcA1Y6>?WSD3*4wi0+VAZw=Ng;(f`+2+F*4)cg0(?j&{FEA zf?|Z^miN*(CQlGU@uUpQS55mz1yu5{GehxMZwXnzFPl!>KTlcaGT4!A>(F+R70jdSsTC z^$I?aMo1v!BjXDgn|34n-40pi2LnR5RdVr%%C*+6jGCJ7S#_xG44J@9 zR2To9;?d{ue|^?zbK2M2*o3YVEQ)a_S0fDWI60B`?>JFaP`gi@SLFp?h{fUcJz5C( z>uO)rpN{B|k$?~67@qyezZ5p+qs9BkH^@Z}O&0A$3dYoJ;k(1y4M|_Xo3^+>zlaYC zoKJ zg{1q^F26L*&Lp(aPAKCVO4%!vr^jG0&@{Ee@mX&O>*XCt$Q4q6^?+~0Owcrv-r9=i z0%cD@d#@Cg|1RIQvojr?I$N|w&U8-NaGC~pW_Jjeu+W0^8p-KjrOmnzT{Z6H+Bi{$ zv~sjAE4I2sW?kFU;`m=`5ZQpfzU1y0VbcgC{j*rsfBtPs!X1Wsa&}@oB+@b-n7|s* zn(!~cA6+0G^+zI7s8Xil^wahOOsvi=jIKWAAT6ekj90MV{V7y?e9_@?Cp;7pQOg;D z9_P$YAb5}?)1tG0-F!oZuW1DWy2Bz2O^Nk7v>7K)eX;lW?~ zu9&PSn&ps%+DQC1Q}Wyi6XW>E>|rY-Kbppl%y>wV*Gc;Sj_w}3XDbtqW32vCdqQ$m zni2r77}~ze%3FJg9AzYRq)kv+aA#LL+0Z0l!69`Kd&*=UVB01{^Ng##*nPKfMKx4; zihB^Q%Fm>s7K`-!tW--qyDZ;u{i)`~!^@JErpF4Y!`&4agp?TLO$g~zW0>g6x?0$D zFvqM~?CZLl+a{M(SZ4kJ8}nPi6bn1Ees;G5EW6?_JI{|gy!Ycm$>monnDPW`&e|3; zGAX-SGgmxtFx7nm2E>pB2OXr#3daZK^J=t;z2YpM&LY6US$H$|JJ`$!YYogJywH zLp$`{ktJ^1)w5B_yWi>t&ZHPhQWv45l>j<+s%1N%cTyW>WxZ+*q2xcs!^z3d(5?G= z#Es?Y86Wug^UpI~(Zp4|onjArM9p}u$qf>nwoGgGvYbt^QC<{2+`ZYBtYlVQC{QyF z+w+%e44_D7R6RZ;0M$xedQ6zd_!X-#swYx9r_l5Bvt3n9Qeba9gX7Cl?FI#2@0DN4 z&G&KW{wzt8WnmoQvhk*wWroUkoyH6W4EpOl0mw|4i&;;4#+_QfG~s#IvlEAy1(m7X zs#`_PGu05c3>4+~Su`)L_VbiT&_*Wcef2l|U`9@@MlN}%e0^!tD~u zs4KZMa=G2#e7<}L1W>ep?*y8%_9Tr-c>QmFgkR7QiBM75^z3xEw_AlEUJJTEYt&;) zQiWeaASPNcwTxNG{8R!wvyY#R|6IM6eolzh`8UMY++nLQ2!TB7PrjXLC*FgaK~_Ft zrdRKv_1|4s(f%(_;gXTouJmQ|atNxH&m zWbtDg#CFv-iuj}ww+R;#rCBEi^{J-&$O>Ld{^$C zo1hkBM0-pg}+qDUwMa-vyiBXV44nj*_) z-y?e3)UHA10W$-x#nPhKzSlr za&4AGHtmQa?njB>n8qKvQ{`2QMO(h2ojm+xbP=|U``@`@zki^8`7rTa>8rRE&kRO} z?e1^;Iu6@U!NTw`9R?PV{kmr{#7B0Dj!4cUJKK7GTf=R8aLSDw&IyMQywz!SvMk+c zJcgmZ!zcz2>$~O$JCLTWmXBHU0AHkj2y?AY*I)h5R_8TTL!Ak-CtTp%d_+o7N_qd! zD_k}uAJyk{Kd|D!9n?b!+O#xU<>Xzq-B-bcVX(Pk&541`j^y3|A3?Kh4+VFFjapCW z;C#J?Y-YYrk(s)B9P3A=@Dq}Xjn2bWgI{d+CwESPUTDS3#I)|%&9}qmtZZNQ{26ia zdp#VbmfCw9SF=K*N9-GgzH(ML#9cYA^4zyH3YO5z%;%}6>$KT>$lF`E`u)+0BW82J z9qTDg`859WIDw6?B<065iO|X@KJHa+Echvx4H!Ck*La>2oGl?9>kTFyNiT~iG4%RV z<%djs-BHff@~p&1b94*!S*7YzYSjI+_f#oAjxbDUSRO~|cz zP@U^#v6*J8lpU@AlnZoH`nBJCe>xQ7mg^6aH{kT$6k|;V>08ANj3bq}#g?`z;Y6>+ za-;3Sx#kp=-X2YUit(R+Pm?oDOLa-JLmCTrSaHLD=qeFAv(?ktxj1#~}RqWVSKV}VmO z{se4=71HJPor~PorWdf8v##IBVAG!0%JGEsV|evnGa$BHIEFr7%nWYW{;lj~nB9yi zO{*^y6^n-IvM}l5k@27XOm>2hDAj0RdH6K8bqGl(^U<%z-FJ?l6M7w({hep91X)^6 z0Hm}}Ga@(y_lD6W*R3Z#DdBzfd7&{hc$0<^_zF3&OQ#I-H)U_RHq+Yc<0{?;Wl`Eg zLj(FCI)2TRBFq}CgdFJ1F|Yl4vloeT*GA9msE^6|2CB2S1h}|ewV7Aoew_1(B$7wm zj6y1MlK`po%C&80l(4?zv7-aay|JMjfiiTx?LBpQYNIZY(~A@=hA_`e)vm43Sg-s^ zTbcR<`C~)W7?;s|&reN;IKz6(Ly=Z9;6CgVroyD40E7>1GNNVg@-tbR-P_f?*;2gQ zULs4SQlp&y1z~6^Sc78tyxvvR%x9e~lDxp+)(H3}Y%u&}g$%3ki}caucIeR5Clh;6 z%+9b|X8qPfm8lfd%fa)AvmsWcCUgtfoTL!sX?x`@L#a|nc2G!=D=RFhSTIQZREH6?~jq=OYt&XhplnMWf z;xR3ghtzsIoyV?EKMjwL=|67dR)b-K%G~A$m)+fkSg_K_wa~eo@4avuA>-49&o&F0HWfajm_=)sRnKHPVA@{P^L{q>h zp~md2^3oq2zsAul-yqfLFH0P>Mm5m?xXEp^tWqV9mUii1hvF`c5<&d^!2@g*b`_!x zg{D8AcD6hRHi7HJ_Jo^ySbEIr{R}zOlw#;DK#^UbN*tnO@0BPyuP|kt^E(N57PVm~ z*B>>v7^Rgnt_Ym2F8eEw=BCN;2=sYqC9ZBWygbvqvSy|Zc|um!5-<9)xtx;5D_Al% z3AAyRgjyaRlyYBw$w$+62}Gv9<$=nop1VRyAyp;i^V<#!`n$lT+%`>)sMDU?)$^= zuw{04uHz)yq@?|QZeG9X?tcKXLf@Ut*KpLGw_Kk+E?y%?V(5%Nr0lZwYgcsY@1D&c zmjaIMt`pLpuy>BZ&%iP5ik6{6=RkHCs?F2nCB({rfTEmfIgjG1V67|}!yqx(@JUxE zDvkrxLx)`H^vyYGjF6S-A(`=MAABWCQh+V*vS}f4E&w0a_W`#w`Y4&5ny`GwtMTdr zFV?H1?o~`YP-GZ#<0A+wf4`94H{qQ$%-rj3R?K@8;HRhKTg2?!aA?r+lFPJkS!u#6 zZsj@OZE_H#w^^RA929e$&pR@;X33`K@3Ba3cgN`KBhh(daY04ZV{)AQIO3<4=K-xU2dcn#;*WsyA0GEARO#G9r+>m48e z=0&5D%dAUv-cXAOgqD44-9rXXD$AO7j7LfFrZJ;vzMpWlTspt82kJSFN}F9Lp3+%P z?j!hGkXMAI#E%1}oNY&^Y`VUS+$O!|HWSfOYOj{r(Wi4g$J2BXw_@M5AqBti;p=M{ z?4U7b^%^~!D%+1BKo9~^wg1C-@O;7}a<5apn3B~%)^$y*rI4uwrzs)vx{`mzm0-tM z-3(U=lfzwV$e)#X%+%(6?+;}U8*cQpNQWck#-aonUIuq{ecI$1roLp$d4+0(&buF&-`H(_glcNoPrYVt?dQ+>(=f)arED+ zK>VweG`eN&;$*|PR7^)}r{K6J%tE4dt@@!rBG}ucMhX zQy_b0mW?Y{p}D=kI=;f+UDZa90H|&rE%3Fp(89dXv+QC13nUWjh{EwTQOaJuoi~_5 z!goA9u`c-;#Nk9*=az%< zd>C-~YdbH}%CirHS6Z8v95WwG&~9ki$EiFS|1)*^cdsCu#J zsI%d44jNtv{`>tr*`K(%uJ3JWzbKOm+VYwU=FumbLB$vEmA)pY6Dx1dFDz z`%KHt8Rz8lVKtGg6gmX^ZqGr7B6`5~5j z2LpIZp&_PT8Mc@h5u+G@-t%&5HFAu1zk$1A1^9Iq{#y}5qVROaVQ@9c__TI72FN16 zYD_1Gj?S8CAvHswZD&dh5o2K4OAi7l-BnG)SMa*A#}`^O(^NYG0d7U}RaLi++B-e2{L9QxRjpaW4l zaA-KfD_IuO4JgzmAur{d{fyThKG7l%2ZAudVwbYSpu)yOWlnK2yf3zD$z22aAsYCB?@5Z z-cWa2C?@|53ef_w@<$%JF(#d+Q96&fq;#FAbnmk}t{zSd_4Lmg47ssf^y|UOMKk83 z{)Pk!ScGY$cTT(0_fo-c7Xo32)PaHTl(6xCs!1tfiLP{g<6bV};ak*jZ*-Y~wzwA! z33&jZpJSl7f0sDFC@}WQrzC5;U9s(<4rp&AZ*kSvfbBlLd$J1y%C=PK1y6MVgUj0r zAdy|)rO;)w`<(|}H8v+f*v!mhe0xRA-D3Rc{Y6^Qxb5+N^H2dV#;Vd#lgG%GQ-jSIZ*{8v4y09$rtIS~z>N1>doy5VxD!r#H zvvc^ebYI?*>MKR63N&2wo%e_8lqw%o>iyb{)M(=^SZ}pG6E!OhYSJ^n~Q{V zrIC@ix62E*5o9H1ZuKeudKK&KCk$4nv(@tkTFipmF)w7K2U_uNOOUh zrSwe0x&}3JN79(=EX8dgxdQk^7gk;U~q=@qVJ~bG_kTUEYR^^JIVe6w^=B4cvWgYi2-Ycu$aGsxgWsm;ftw2s>Pc)N^;yS>25yWRj@ z@{>f@-#~Sx>T&VaYfL~!-}MLdX1_zkhf&uUO%}!2bV|G5$2_GR*T`#%K*Vy-`~l-% z`@kr!V(i>7>b!E}(5hN7auK#9@cQ?+Zw2c(s)0y-Uficx*}s4on~=r{ayg3*I(_OF z1K8lMty9`bqZ{xe7Y3cA4f;QH)5>Ygzwp^YPOfj$&gdfLXSmQs0~jfkr(a+fvTH!r zei}v?)6{5jUiydJrPlS+c^K2uFdbHVgRh%jiwaG>D?@-$P|xk9mq<8=_@PQiKY8D6 zCCU;aWgo@9&f<}nkVWug4ExA=zE4BQsO*sza+vZUfnW;_-$ z+`F-?Lq!tVn|4lHSt**B>{EwG5kn}BM&N**h*kMU4dXz@I~n{_!EPcKeJX?-8uvnB znWweCidfeFhVnF`HXiOIb5f4040V?i9d{PvXjJD}+RA>6J2b2O(9B34gx^x`JWvt# zyyP)U`>cWAPBWp1?||ggR)sYlqT-@tJlEPtF$=93(_xWRKXsDrX!L8C!Hd^U6i|-N z)%pRhZnHIa?p;t7Eh9M9q2~gD>&+)zI4Xp?E6qWRMkk3551$ zN;v*gu`{7r<5`38P<*6v`2?Dp|7;{pT8rlbC&tP)T7IPI78_QR7Kir}z)ZP$w}MVj z+lB|=r<0;gFZZH}&B~N(`cfEd2HJ{NRz``|6=-g^Uq;1o*Vl%@I7DeUMP-nY5Zh@8tr5I*ZqFWM}sDV_f?~EQ(Jel!o zND19-_%~a~a?sLg4)XrI{Mp{RNZEaJtVG&K$L0g9M*PBHsw3Qaz47r-*UQpS=S!Kf zXndPT*>P7#>xz?y%}R@9hFH0Svae_c5WDh`Qab3Ys?85%%<=FE2vs zI8$&7(7qt-6`=77Ee)qvbapf*&R-=B<(}G>_*~sg_7y*kYbT!tChf~BeTEo#flJp>_hRjYgIQ!utuY2mjDbIz>na0 zQxWRr-K9oKkHIG``B)xq+lt3c07sDS*jJ!Wm8EPUVRsh-k+PJk7eKfhK2Dv+5&PtnJ_I0C{utDq}4gUk=Q}fJ0 za>c^ZSAL=T#bwq`XKAtCz#GzFLEVTpX8VMDy z$DN}3m6K(frbn{z67~#K^h#F;0f?(JK>oX{T8vxY0V~tp)_Cz=4qyYkSxhprX9S5C zdSbC^W44T?%q#Em4u8cnLnbDTa^ijXVG~PN9*yqqN9XIYP(qY>9i`&$=k$>u#AfPW zg~fBbl;%sXoV2*~L3f{@_#B$rFz7-PbCcp@1*A!R8mgOZ_1??#*cAMV)6RF7Q?FK? zT6V+@nJcXtW2kaa-aTI82wAjT&UlQidoOJ^=-jzQSy42_naZne{|5jhVVET&oflTk zSJk+kjMavTiKr;H_}G%j;1wY6rEAwIDvZyKPd@YYc!LU zHBgX;2I=`oYUX`jz^AkOJ%^;0jMN@`V#E2uL}xhcRnv10@?%mK#uFBnCfzz`v1L2E zwOu#YqS<;=Q6rhK_;2M=V|@A%bXO)Fj;Z!nEXt^Y<&zbO=l2&<`wo78KEVa?I2MO< zZV9>LlZ{PfA*>W@6nf0e!Wy5o94nY;O+~ zteWgIzEV0NC<1v!|HQYe_BmGVyC3Ga$$M%{G_R*EYqE0&?r!IyaFvHuAJFtkB2t6% zZUkauL9t>3vm4MiA*9s)5&*RJd7+dT51-7I#QB4E`f^*)v;+7rlpcNny}aW4%OC@( z-}#w6Ze(0hF9)caBJ}t_3v{E*eC4QzsyiNdkJ4LLZv((xeBHx#D6t<8%PtL zrt8^UHUBQ{qF=|DrPXg3Grh7oon9dqB0HvXHiJ1h2ntQk+?BbvS&u7P2Hecn`SfGMv|)+vQhfRjb}sekS| zRlh?^W5vdLc(5Pk)HOZ*CA3_#?iM=Rmhy?M#_ozFg`xoQK+~dU1+ybAwcy$nF}X+JJfVa$ zegn@_$abLot}!{D>J_Y;Ie0Q$ftV%#IrQY8uVF~ ztK;w6RE$e|5rK5aH6!44eyeO*d^~(t@%gVTom9LcF0P1m$^J6X3k1Y6;h!#wCL2P@ zgpwz0(igw)7$T4w!PGMGPm0bqzT-X0FCC_EilzhzNa^h?O;4OJR*`^ z9>!*T)~mNAwIDUqa?SXV-JHg%N)zKH@Y(U7 z4VWO||ASAkin28_X=CXeCwFzafY619_biT}a}q!OL8m!+@ib z=*uZD3~Ic2L>2;#m;{Jt&V?hBsxj;LlnSp_$>1T7Q&EQcvs(01uvt#a;Nj6t(eN+c zbN-;w=EXV}GL(=$dNJHy%ALVmlG5=|?mN?8QOIcbnHS|HwV6q^i4atxLHe%#_o5EcSzj}Z1ArvR0MgT zR%r2Xf3A1&Rve&5*;gKp3JQajDza1L*9Tug*LkR3zE`?@i%!A+dqtWS?Kac?*w%83 ztLRvzl%vT{w=j=FKqSIBHCyX196s?qZ1Kv_ZlM!m{BacVu(OBUx>iO?UK(_y+cpi6 z^=Aaw>Y9*fG$7v)JDcnGMS4{gFAMS4I(@qiI5`pN+T$J>ypA7u>WUIYDnf=&QBk!; z9}?6{_5t)`jiYYMF3OStD5iYbV?jkZm!lOV5+a?QK6to-6fJFD+*(!IUf|;DFtaX2 zr^_F+qJX_f4}m5#2}~6Py)?Pwnk`+Pt(`lJ8P7WwF=cj9-x#-7H_Gsn`$2d#AR`6cmdRku_AJ@bx)aT8XG_fx1uK=08 zk_Jv&FCZ%}PLDub^Mv#xcr`WX+S*|cfcEs_MZUna$wMg_xx0nL&S2P^l%qJn)w$zpGlXg^ z4Q;kPUQFNL8&>myFM6kjRG1|th%d^nu3>GC=Qj(jI)U3r33Nx%PItXdLS%rke`#l2 z#5@Q&ZyWWwG`h=rj<`l;4hd!Rr+^|mB&5t`>~@am+eQJ2mD(ScI0P9eUv2wlJ>9Nm zhCX<8`Q(d;@(g#EUcx4yp|{=V&-MTT8WAdSp$%B8@uuO56nAse`V3WR#x~x%;?dA$ zCH+gN|Kl0koNIFv)=^Ui8HN7GrV;gUyt3eCos}#2%?$$ZiBJ0dD8+XQ+nI2u&yd)W z<@#6fSnYBvHYSkQt--%B(Awn7W1~W}Uos5J(TK^JpbE&lhj!T+S%fTkg%=$oX|?6t za~CE*Es3C3)*lZT8>vsnhUySJjf@%|3V3dJ4{Zwe!r%=lZpxdK8b$2~Ir zjk|q;?i?ZG0qr*|v!mjTuNZk2(t=LMgE0#Y+zd^6ZY|)U_O&&wmHHA!Dc%H;vTUp5 zH;>OZx!Dq@e8p=!0leFjO|6HTA`>EG32$Y<+4!2m$W@MK(=ILW5p3I1y-*L%wO{4Pbt3E<7-`=dS#cMcOf7vIcdv}soaGAQUfFR04s;9>6+(W zxpfYxn`{LE(+=A4xc9w~*!TrnwGV?;t6AB*qoOA8z?bhJZ=Cm|V3VyHDvyawo@kpX9Zb~T5&6;> zm>6d-UIA*N<8so1!R$$K@nBYTXZJsb*s4M^kn6;_k6PQDiZS8;NwUP`IA{%ne7*P= ziXzs>3NAb=N(i~AT|SAgzg5XMv^QCd-2M6`S~$B;T54vSbPu|JAn8qRgk?_w67f7O9FY8gZ9ziY+3m)g+_ zkHyp>*c#VWOQ2z7>~>Cl8GI9Qc${Qa6Jn@>LTy59NpR4kb1nb4$W3^}EJVAh(gWHA z#Ngwpe=6U-x;7tlds19>UEf^@MH%06LFwc*ErlGDonl`|QMebf^PdzR*h2U(yL(d? zR>J8W9VL;FXa?TRR{vzw2nVC=>zA@;JlUSN0J(v)nR3F=6*xVw>M)mbDB#m<9ZvGE z2=Iy?nK6KZpGQV#cUE}Q>8;A?Rmks57UKE6T9S2PP1RrMH6*YG9ofP|yy@E7>8w-Y zW3}WJoB@SZJzh!??ZAw-maS#1>|z2Dn>m5`J%YEiSJ8=f%8`^Oco-5FXDclYFIzbI za`;xMdCs{Pq@~#g161E@^VP6hhB$xP+kp$q-%Up^yPObwkpz_!xnLQ27p`rZPbY^t znpTyPho2JELAG6>$NA^!%(R~IF+?>h}dzV#3v$?eNOItzQCBuW-m7H4gfl|~& z;;mZ3rUjB8aWL9Bv+~fYQi}qVj!PO{BGdUzGg{n%q{~3j+)p<{80R{q_IKOo>yAj$ z>qS#c4GqtmU`vIHCfe6lQ4>AO0MT;DpJgbeZKYKY0l@q+ zVM}{@>Y!3i%W~&lDH3sRbRid45R$R{aew^r*1?$G+kNE#3A}bUjG5|xrbG~T{k)JY z$p@OQz^$h*_j#YkoH*-RcA1Umm#Oj%%+)&Bc(0JR{%%^wl-Q|-1l5uLoObY zXElkyT~pyGpQCh_+_!(S46O&>iXPm(^<}E&;luSbJnkjsak@)3+ul0ZZllUYjK*;G z$!k}&?^UHyDa|drGkhTWEFV6!I7TTl^dr-cU4M16R`TnOf#Thhs|!%mP*T2Hlb`uf zT4H*j&%JW+AvP8GKo1;V*FvmS#{Sr9TOKGuof8~uv%(3H9CkXdWMs(RlQSi`3)?q{ zEBmf@TMz(HsAkmYmvZB(NBWq)O7=I{jFM_RM~DL*_^rA=8QKo9*unon3tGVR?w z*5tuzbEaTR#GpE!c${@>x`x_Nuowyq8N>_=%lnG2mm>KL4jX zCM%%ZSuDcq@$H3l&QsJUquvDnk}@&vs<19(E$WmCw1^|fz6gTgDX!1rfp zfLXA17*JvU{zJxkDS*lqbSZeo_vGdA@$ss}?OKg8_44-{3LV?<$;+!G4ar1qX7}AU zh~ia=Qu-kE>!;=kYr4xQQ72sLetP^>>Kx*KLvQTP)|NT?Rgy{(l?T02ay{ggJ9BtN zFVRsQAhpNI zHwhJs8!C6EHb7MB3h(5-qdcx8FtS(RavxmbJtbaG*a z1rF1ki-M|<@*e|b`;NKXvY#t!4`eldpI#JIVSo1woNjB7?&_VSI3jC(kN5;v{ii;Q z&)^50Mk>!V73OA~jyggqMYtTzJhfD-t8JBp_O$X9z-ypmX_1a^6-VIB_0^iKB`hk9 zgrsM&3J$X?5sP34iEn0z%s&*f_U+mO4f5u?fMTn;|JNJbUml!CHSZ1F9hFD3=a}@C ztx5~3pMh%}+KfLbf4)f~ikzFS1k=ZFP)#Darqr$)x_By#{n3A3Bq?M(O06Dw5sSoT zr!(wqH6%tQt9z+DDY?5hGbleklok+TRaV zH#`OjR6-kRPetXl?7Ge;pS;l7XE*&WTD6H^JSuQ~`=QX6Y&+t3TO5zr-eVCe;e04j z{5oO(=zZ+t`JS;^U9{T+h2P^dvqk130t5HP`b&=1*6PL2D)Mvho!a*)<5ZsNvn`64 zb0EnU1c1AnUICCqZHO&4coDI9-PS#j&^_friThTcIprS^)ZaNb>{)yU3=+q1$V;9X zxP3tyYLiPleWIX0*40V_s^XugufAsLW#<(-rO=t?I9Oi!s6Y-S8Zaj3pFk{q)cz=S zPuoz{x?0V1smI1bLzl!ZiH*F-ZPGrg{LuZ}IfA&$&WhmhFO=0m87z&KuHD7)lethW zNw4<;WAQ8h7mN6i@Q0nb*(%%{Db|=Hr?cPcX>k}e##o;fEO#M4*NOhwy=dad6d&A^dQwn2XI*k z{k|BbX0{4v(w{_gTS!B#V-K}zCo1M*b0+0HTWlR37e4iK0}AahXW>cDHshM(wZ;uVgA$hfW#BS?IgalAf8s^GtjTis;hdgm+Ro{`7PPp zhG}z2OOpbYEZ@1f9T)d=sapF6kf^S5r#)6J71dI?}`_A~rTrBmNR$B40!+-XqIa zPIDKL`1dS17PX0szm=14l|r_y$NMeppkT%F>43dVlC7?cBy^KO>8H~5hIwW+K20ko z#^|jF9o>0!8m92PYG*y-0GlPjMt_)fxb0Xmge|J|1`31CbNTWkQ-~L#SbG$H>&@Iy z*)Y*_bv8gtqk6SHbVSN4i59o^Yu)zIME ziT#q0#Wrxg(I)Ki$AANdss-^Aw5H-;b*O-4P?6eDxze>=l^Nc>mSW>H*|~|Ao7?Yu zgGzD)%rdB3^ug`N%bs#Iu2Iy-7|=WpYk4LTHkv5W&@nkv*JotGX$~@nAiIOZ+5DEj z!{_g-MK8|#>R;AGi!_mldL4EvJ+**z1e)}}a3~H_E&0sG#%ZO2)x2{D0nJLFX6k#R z87plNzhK+H`g5guVnbY3`hp){6Y+Hf?f1$%O9+!~1Pe@Pp?3yFfxo?cd zwIiR|_JbV0J41+ilNYRd|Gb2ol<~KFN!1n3j2~q-B(i6!0#MDgfxD=9g!uwB7aaU9 znfBZUO2{8S;G>bp4o4LAi9+a z`0(5w1IR>YxHUBHFvhjG|L0f0OX1>6Lg|z!4dMn+vg+7@%N@y8P!s2}t&!&E|LS90 zx#|}9mV0F{BQ~Y+oAnyvAKzKP_H<88x*5#~;NoI|0%);=)zfU#l*xQL;5XS zlWiJ($^+K1jDQYV(K!=Q&1rD(@5S3OIUcfyqtPl9sC}FH!WA`&I=D*_({)2>gb}8P zqA|_KAPfc6rHuur=WIfj6go8tYx}`hdUCH|5JFu1GTHwz(CLmm=z}*(H|GE5lBr|a}?)w zbdOG#sEE8L)FmlswBq=3(}T&r9HpT9mJr>{aVHc|jCj z5^1wCS|<;}Hpu_D7X;-_(?5t<$^SSXpu{O;P3~@umCGg#sJgK_Kys$yz$?9ld+*Fy z>%q16Ga)ZOX~&q!V8wWlj=xT7U*H@d0TPTXoPLa|TE^lr>gR~H;lP)RdHfr6W^l~6 zB|T7H^^?2E2k||4Yy>a2vNb5JN>qt5&wF`pU*!5@(^yX>SMtk`m1`S z;vF0)kqbZ)eOh-qu|JIc7{g_IdLlgm9CP9_b4ijcHa>bGdh!)?M)NU#p0Z0M(O~gr zH{nw;H4QclfW&<76|cJ!I}Rw7Tk`ZM*{+5^nK=jAd#r_$FF?gM>8$qyTmjcMxTq5M zb?|$(^r)kn>LF(&gx=tXq~hQl<+GWf=NDu3r0VeIH?YJfx~O02*?F(R1AnJ3vwi30 z`pU|I8Pl;4y5{L}xqrHeMSary_RXt%DC9jvhOOhKOmd9l<6;!;eQ%(%C-SzV)+2oq z$5?QQiCR&KPJae3UKlVTks9?;^o_2!o41$9EE(Q1S6}X?y~SwV?4|SPyTl5Z2UG#Kh3%F-d6{WB{28M@XKidj zImVWjp2%?%z{A$u_{LxP49r)HDMx1|(PK;7UH!{|27P6Xxg;g}=+Rb5ZDE~b3OBc& z!%p*g!EEvP00j!ka~kCbU}QKZhHZmB=6EhX9t;(O2a!JCdhx))y8N9hZsk7;DMu3& zCx2H2dfjo@IjByd5LMUGDC#?|b;Q!Mk2$H0WqRrGTQLIK*ECcI(1bfx@w4J=uN;Y^ zAAXsHP4XGeg*Huk04(aIHfz{7Z|6pFhDQFYdk5~<_VF@njSoN_QNi3-{DT?O0v>%e zHo|*tv`;?h)*F=H#|CbGl8CXuD>X|J%I(jNK z;77B{DwwzGcCUEeS`4y#$SYTy*&8BZC6(a^RFU_w0lOlHY|8M#L6OtSaQn33=ju zULsnON&)RxUo?DbX0#9R17QToId%s*mjZ2Gx=<6GmYpBPkqFa1RjK1Teh&n5UkC--yvbWv*B3gV% zi4pyV_VWAET-qj5?!YK^rHKgMx!r7#j zFF5a19TJ_64*xN_y&NJMlao!}yC!)flER$tOHJHVF#deX_H zmqoo8`Y|t#2_VU%BAtAy+C+9#L!^16q-b2D6_qmlPWQQr-33}ohs=DjKmz4Sa&sQpCF~|+|-0hGvS~r$H)9{-tMmeP5 z@oBmBh2r$O@fVdG%?q0C9}-6}$M@S|eS@Hksp|RiTRL{+Nsqr#zOG!Gf}x)xi$2dr{^hTI}XLM8%=|1u4yG5*iyB zB8NPPzj*cNDpRu{xds@KB`JACD~er!okp@Le%_C(PCy??R!&&JWMPOr&g=!>H^k-a z2leKJ!p<_&N`Bb>E!$!AlXg?Prl)m8R0R{`tH31R++|VkRg&@6PG_1@=R~Y01xE%` z*LlI_4aLX|`pzGj3Z^|rDwhppYBS$%4p##*r+(h;JS)xKcsOW-(~_(8PNvg~-#@y^ z6+{cVv(9G@>POGE`5`UB?U37SJbx-|SjPF|a3C@RMX%>Y12&@_?uqFq6|-1F%Yu!ldNtLJcg9KQfc;#s z6!jc=&1#O-qRz%;Vo?9KdE$IK-!Z!4b;E08POsMXBoC?SgM)I>1(NopTaS-3lE=RqeW}t#zr3h$P`mq~`N{dlWlU+=-8A1= zD0&y!8r#hWqs0fyc)Oo+YCXIWaI8|HPtX9SR8)G$>8;tJ#(Q0y1hj~=6Q9EQUFRB! z^QS&={+%oRN%kc>eRnvRuM)1VWF|%*quX^Nk1!+b(5(LKsdMK;WON@Kyr_x|qp=3s z_bi?Iz*kw;YDA+&)Sa#`uP3$`-1Zurec*Bm>G-vpp6gRxI8HQtP2G@@!O84(Eg|`N z$KEG}_U7}8zn-K&y`I3FehmbgV!UPnyR5oCJX|BIqjeB#DMo)Ej@9N(^_UD`Zh5^u ze*ZofA3f2uO!$fGOkr?PNbcFb2kChd&EMHvK?&b=e#7{;txA-iU~9b^?Vr6*lkj0; za{;QHT&IjfsQf9%BaU@Jus}i8C1B#XK}=~?bvgjdB1D5iN{!W`x1=y zS@ANWDU~(R*D$Lxuf7*}`{X%>E|jJM^XfAkKdkN*W9ksh(flZp{0XMfdX?jx2M!N z@o-ij@B%r*viE^mEl(C+BRfQup2lyel;ysEzX`w4wz}tLu2E?2S?M6%yA`aVdfm&j zYZoD&@>fhCzucSxC6lBVDG-}|wBb1JkYe=VuZ-`1Q^$j}whvZgGJ`?kmDzg37N^?b)5!ciCRko+gnNZM9)cLnDl){G*D$Om$K6d z7?!ZP~Z3qe))2`kCw@0`_;mODs-;2@h2;IIMR! z&eZ3^#l*e(8=8IY`wI#&urfs&Z10<8Wzd*Pl^;sE2DnI>eGps>Lsy<5i6J zMRZzZ<7xI#MfS^dYfP&3P15z18NB}cKtvCAZ>={%#m05VC=!{n)f}Hgoz3!9I|Dy~ zk#o<2Lv%HmW?zd-3zI}@0luvGr+qI@3Sx(JwY$9*5(S#P)jkoF_%{3n2pS_YRNAv|1Z=5{GoI@rN z@#jh3TZ1yg9elAA;hx0y9g}pv*!-tBJj~qh4|I% z6AHa61HJO@3@g}gacZT0JqWrQ`iHyM5vLnWa1b8&*0X%K_Rh7_24)6~*k>cV*KNyN z~kwcN;2y zO0eJ0*M8Sj2$q!>367I3wbozPB@TF?ZxefX1SHWlsfR_FybY zK5#c}6s|o{l_J`lK+18Lfb&fdqOq<5e*&*>Rvd2jEj4aNHU6kDStoiI z_)9=WY78*5;L+>dTP2PcGWDM82VWR9#-RD#eRj*1tX*Nb4tlPT*9-&yFuSEy^g>RA z4Z7d8{D4KRkLtz;7gf<92vuNR_htk0Yvy~|0z2!mKW6eGd!Hw4JgCeSH)kP#?dd&M z3jTFUF0mvYXis=Pc#hflE!)q9ze z9xVX5$Yp!7ekZ(xz_7eY@1~q`>nrRam71wr46gjdKt1n3j*2`Y!Zhu8%QBl1N82g$ zC7lk;+|OUXR<1mwrmpUHSS2(x2v1Cu8wq_of(Rr^l#fSh1K0&!hPaBfxJztDi$M{U zdQ2LZZ=QM4&4HL5$)wxLdvus0`JP_Swn<%gsZC?d@#ELXlpX2mu|D&$zJFZ?3;@q& zrrDgFDXqg>$Jc*Mr{5je;{~cfrKLLTJ&olI{|2@0=$&!7y;=$P=r&J0eV%$rDu`AC zP%e>Al_7M_U83t$-rL^qc}!wJF{IBBuO;nvwHP{V4)bVH0D#OqF9W_Vj#yLR4m^q1 zKbNM32vKw2FmRmN2Yp08J?O9PmZw+D0!(hs(l7*Kqu9BVcWo8k!Kqxeb(**Kj_cvYuec+KAFV{|I?&r$?Q(`*1ly= zSelA#D=CnCXBRKSFII7Wh?(-`^4qPp!FIQ`0HyAZTLR+3me%LV%l5cmksqVDHO(9O3e><}R6~l&& z?Qt)cXVe<|vaq5@miyF|#Hh&I*3o{>w2br)xSS7UO^943QEG&!7|BVYh8rcq-#yVv z1#_EWif}^>>TwEqAb!X@y9nPlPAl6LEgg)`3bwg`g+wN9#3ZJW!)=}RUyqzb{7^;v zzL^2YlNhtk@3ToEod5!F1!p`60(lcE=w_j|tLFW1c~fF;4urH(UtRn8XZXbd(^PHg z+Ky`&z&&V!5b;~KaGWn}VmZCNkx#@FvrmXUxBe^gVI@+6ys^mI0@_lae@Uip&&OrE9=vqb$-fgg1P;##lKd8Xyj!F^ z>oZ5^|GIZmo`q*miteOMw2BZw%V;

      (lw z5vUO#kPu8=-DSeYv;@iiN6reBjQ!#L&P64T|tTgZz6Dx&+n;|FG9bJb_!<6~?H9oCvU;MH($gdX;K@ZHB z!=T0QTggl?_cTE4BY2jEh$DE_K{#oyHe;Lzh<(#-&vq4zeEtm^N{%0dsG%xMh5P3; z?dUc+?Z+}UfKRX`&vYl=;pZI(SL>?`fg62xd81>s?j48W_C6QU?uFWPTk(^0#os!O zaJx$-GjN2O6Z{U!EXjoIcR21taI6nUQ^o?{un`NL8IvE%2-h-0B>Y2o0~n{OyT4D$ zF6SY3bo#2@&0go>Q;0ayKTYIA`9Y!v6icluxRTHISwj5wK2!1S2U6oNDwCIB)C~4% zP*>X(B2{ce-u0<$*uhSh9laA>~IJh_PTWV(Q5M1g35z!M}4oG!SS~oWjqrfL9J_rT+ z3C(4^zWPGI1w|=v*$6;M3P#k>A1*rPpzvMc(xNyeMEM6p@w$opcaX&=x*s82hxX)) zPa*B41HBeiNSUJuO&T2o_bhV4Bd0-|yc@nYO5n69M1#lVP$<~I-*ds>_CcoMG3C_x*ij*9p(MU=S?T6)_;KdlceH%I>s&53Zk!w=i{&_39uILkM>M-@$f?}GlZj3eljn?&FCR}%AFN~swf ztA6@K)DiTrR&A=+utQY71j_$>D5Bv}5seC_{m%zI79Qc_EZ=`V<39^QK`ooaA=f@l7?cgf~nvC0S3O4mH+?% diff --git a/hotel_roommatik/static/img/avatar.png b/hotel_roommatik/static/img/avatar.png deleted file mode 100644 index 2f06baf5512a6218c8e1ec8d112061675e7fcbaa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44610 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

      (lw z5vUO#kPu8=-DSeYv;@iiN6reBjQ!#L&P64T|tTgZz6Dx&+n;|FG9bJb_!<6~?H9oCvU;MH($gdX;K@ZHB z!=T0QTggl?_cTE4BY2jEh$DE_K{#oyHe;Lzh<(#-&vq4zeEtm^N{%0dsG%xMh5P3; z?dUc+?Z+}UfKRX`&vYl=;pZI(SL>?`fg62xd81>s?j48W_C6QU?uFWPTk(^0#os!O zaJx$-GjN2O6Z{U!EXjoIcR21taI6nUQ^o?{un`NL8IvE%2-h-0B>Y2o0~n{OyT4D$ zF6SY3bo#2@&0go>Q;0ayKTYIA`9Y!v6icluxRTHISwj5wK2!1S2U6oNDwCIB)C~4% zP*>X(B2{ce-u0<$*uhSh9laA>~IJh_PTWV(Q5M1g35z!M}4oG!SS~oWjqrfL9J_rT+ z3C(4^zWPGI1w|=v*$6;M3P#k>A1*rPpzvMc(xNyeMEM6p@w$opcaX&=x*s82hxX)) zPa*B41HBeiNSUJuO&T2o_bhV4Bd0-|yc@nYO5n69M1#lVP$<~I-*ds>_CcoMG3C_x*ij*9p(MU=S?T6)_;KdlceH%I>s&53Zk!w=i{&_39uILkM>M-@$f?}GlZj3eljn?&FCR}%AFN~swf ztA6@K)DiTrR&A=+utQY71j_$>D5Bv}5seC_{m%zI79Qc_EZ=`V<39^QK`ooaA=f@l7?cgf~nvC0S3O4mH+?% diff --git a/kellys_daily_report/README.rst b/kellys_daily_report/README.rst deleted file mode 100644 index 7bf0177f1..000000000 --- a/kellys_daily_report/README.rst +++ /dev/null @@ -1,13 +0,0 @@ -KELLYS DAILY REPORT -============= - -Export PDF KELLYS REPORT - - -Credits -======= - -Creator ------------- - -* Jose Luis Algara Toledo diff --git a/kellys_daily_report/__init__.py b/kellys_daily_report/__init__.py deleted file mode 100644 index e73c9c829..000000000 --- a/kellys_daily_report/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from . import models -from . import wizard diff --git a/kellys_daily_report/__manifest__.py b/kellys_daily_report/__manifest__.py deleted file mode 100644 index 1bb6cf00a..000000000 --- a/kellys_daily_report/__manifest__.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Odoo, Open Source Management Solution -# Copyright (C) 2018 Jose Luis Algara Toledo -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - -{ - 'name': 'Hotel Kellys Daily Report', - 'version': '2.1', - 'author': "Jose Luis Algara Toledo ", - 'website': 'https://www.aldahotels.com', - 'category': 'hotel report kellys', - 'summary': "Export daily report in PDF format", - 'description': "Kellys Daily Report", - 'depends': [ - 'hotel', - ], - 'data': [ - 'data/report_kellys_paperformat.xml', - 'views/kellysnames.xml', - 'wizard/kellys_daily_rooms.xml', - 'wizard/kellys_daily_pdf.xml', - 'data/menus.xml', - 'report/report_kellys.xml', - 'security/ir.model.access.csv', - ], - 'qweb': [], - 'test': [ - ], - 'css': ['static/src/css/kellys_daily_report.css'], - - 'installable': True, - 'auto_install': False, - 'application': False, - 'license': 'AGPL-3', -} diff --git a/kellys_daily_report/data/menus.xml b/kellys_daily_report/data/menus.xml deleted file mode 100644 index 0bf4c2c43..000000000 --- a/kellys_daily_report/data/menus.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - diff --git a/kellys_daily_report/data/report_kellys_paperformat.xml b/kellys_daily_report/data/report_kellys_paperformat.xml deleted file mode 100644 index 5f6040689..000000000 --- a/kellys_daily_report/data/report_kellys_paperformat.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - Kellys report - - custom - 360 - 60 - Portrait - 1 - 3 - 0 - 0 - - 1 - 201 - - - - diff --git a/kellys_daily_report/models/__init__.py b/kellys_daily_report/models/__init__.py deleted file mode 100644 index 9bba13048..000000000 --- a/kellys_daily_report/models/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## - -from . import kellysnames diff --git a/kellys_daily_report/models/kellysnames.py b/kellys_daily_report/models/kellysnames.py deleted file mode 100644 index d2b996067..000000000 --- a/kellys_daily_report/models/kellysnames.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alda Hotels -# Jose Luis Algara -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from openerp import models, fields, api - - -class KellysNames(models.Model): - _name = 'kellysnames' - - name = fields.Char('Limpiador/a') diff --git a/kellys_daily_report/report/report_kellys.xml b/kellys_daily_report/report/report_kellys.xml deleted file mode 100644 index 96ecc5af1..000000000 --- a/kellys_daily_report/report/report_kellys.xml +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - - - diff --git a/kellys_daily_report/security/ir.model.access.csv b/kellys_daily_report/security/ir.model.access.csv deleted file mode 100644 index dcc559a56..000000000 --- a/kellys_daily_report/security/ir.model.access.csv +++ /dev/null @@ -1,4 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_kellys.model_category_manager,access_kellys.manager,kellys_daily_report.model_kellysnames,hotel.group_hotel_manager,1,1,1,1 -access_kellys.model_category_call,access_kellys.call,kellys_daily_report.model_kellysnames,hotel.group_hotel_call,0,0,0,0 -access_kellys.model_category_user,access_kellys.user,kellys_daily_report.model_kellysnames,hotel.group_hotel_user,1,1,1,1 diff --git a/kellys_daily_report/static/description/icon.png b/kellys_daily_report/static/description/icon.png deleted file mode 100644 index 946adacbee4c4d1725c6fa55d831bd67c46de4ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36423 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 RyDUBX+8^jVh_!u4PvYi}|BT5~S`%@AJ(l zbgHY{iovAQD4tw;{S2Z(Ev7{1g&Dn0z^YBb% z?gB24-Z-}#s;Th3@|*~63=K|nM{~GPcYf!wFz(X4uWw|h4S?8D=$XcY+)9bfMcxx_ zafEl9k|7rVAg88ulqj^!acdbsXcar$vaK0?I_kVzk1S@d_p=pV?A=-cdLw2Qr3Ct>peeX#DqK*f4g z1f`N7F{@@7aPS5l2QSEhcLLe!l1HQ>2Zka*C(pWIDa z76h))z)xTIiD~hmtUB=mXF}Y-Ber^X{apGNuPK049xj?9$j{#)7oPAPM*`RgR-S!N z%O?DGMVv5!tdKzw(2p>j{JLQ@SfKqheK` zy}n39jmsXT-`A4B71gA4hzEN!U=2c15N$JP@?n8f32LK9^G`c&jVdwEiZCO_N%$|0 zSLXd6MD6w8QXisAa{OB5n;kX9$NFv;ZoB1{2tVA+u%5j>5r_-oWkTTwh`dQIHN}K^ zYW84q;_Rq>!XafijAe`N^uRLgU>x#i}wS}EXcsq{!-~hs?V$vP9tJR zTETC5ywPt?hek{ljPza*=HKM5#UwtXRMt1?yAvjqouGd)q|RT?=!g>zShL! z2ouc6zt_yk>$JrPAaS=>?z{zGQ2;nN)p3s>z;8J#;iE5KBJ8j!+|;87>^pN70Hsmw&vW=XH27|txY1&8iWMD(r(Y3!w<48k^vj3Q z_u!8WZ_W9h|C7aXT8M)|%=;L8} zDZnXK`E<>xr__K0DBtw@w%9NGa>wFlFW2`o*&g5mk9T)T&b{r+ANRZ2?%pb4vS1SM zX!~92pHFPO)N^LX*W0W8*Y4txmkHWl_Srfwx90WPsr6Sk>hCw7HVrtCIDP(4 zyZU4a6^4p{skTjeE;F8`*YK|+`r()`|jVj$69+Y zWErfH{F}o&Tleve$oP4a#HY$Izhd~WxW9J!ibo}uv*%Z>T(m($-R|U*XV3dU-7f|P zheeY(r>$gUXmDY55@lde(E_e5WMBZgk(GhLBLuki6{vz~Ar}LK5O6CL15g=o6);Sh zLLg|>9z!P=#2_W0VyLnSD}a}t!^{NrB0y$>m7$mkYOI6IM6w!cCa6&XavYM?5Hq1J zM6nuTCN`^K-odmQ<{eC{Vcx;88tP6gRzuy1;%kW23W31O{IG^3@Gu=jfTNiSJck8q zNUCTxAOajEB!z&-n8E`bW;HZ+Fd`A;&PBjOQ?P0RySI}IizbkJfngv3j7%)<1%|<$ dxBoc}7^F`##szzwbOA;=gQu&X%Q~loCIBh|33LDe diff --git a/kellys_daily_report/static/src/css/kellys_daily_report.css b/kellys_daily_report/static/src/css/kellys_daily_report.css deleted file mode 100644 index 1a2def628..000000000 --- a/kellys_daily_report/static/src/css/kellys_daily_report.css +++ /dev/null @@ -1 +0,0 @@ -.o_datepicker {max-width: 9.5em} diff --git a/kellys_daily_report/views/kellysnames.xml b/kellys_daily_report/views/kellysnames.xml deleted file mode 100644 index 3676787f5..000000000 --- a/kellys_daily_report/views/kellysnames.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - kellysnames - kellysnames.tree.view - - - - - - - - - - diff --git a/kellys_daily_report/wizard/__init__.py b/kellys_daily_report/wizard/__init__.py deleted file mode 100644 index a3dfd1cbe..000000000 --- a/kellys_daily_report/wizard/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2018 Alexandre Díaz -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from . import kellys_daily_pdf -from . import kellys_daily_rooms diff --git a/kellys_daily_report/wizard/kellys_daily_pdf.py b/kellys_daily_report/wizard/kellys_daily_pdf.py deleted file mode 100644 index 9a7eb33eb..000000000 --- a/kellys_daily_report/wizard/kellys_daily_pdf.py +++ /dev/null @@ -1,123 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Odoo, Open Source Management Solution -# Copyright (C) 2018-2019 Jose Luis Algara Toledo -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -############################################################################## -from datetime import datetime, date -from odoo import api, fields, models - - -class KellysWizard(models.TransientModel): - _name = 'kellysreport' - - @api.model - def _get_default_date(self): - return date.today() - - def _get_default_habitaciones(self): - return self.calculalimpiar(datetime.now()) - - date_start = fields.Date("Fecha del listado", default=_get_default_date) - habitaciones = fields.Many2many('kellysrooms', string="Limpieza:", - default=_get_default_habitaciones) - order = fields.Selection([ - ('kelly ASC', 'Calendario'), - ('kelly ASC, tipo ASC', 'Limpiar como... y orden en el Calendario'), - ('kelly ASC, tipo ASC, checkin ASC', - 'Limpiar como... y Hora de entrada'), - ], 'Orden de impresión', - default='kelly ASC, tipo ASC, checkin ASC', - required=True, - help='Establece el orden en el que se imprimira el listado') - - - def calculate_report(self): - self.habitaciones = self.calculalimpiar( - datetime.strptime(self.date_start, "%Y-%m-%d")) - return - - - def calculalimpiar(self, fechalimpieza=datetime.now()): - dates = datetime.strftime(fechalimpieza, "%Y-%m-%d") - grids = self.env['hotel.room'].search([], order='sequence ASC') - grids2 = self.env['kellysrooms'] - listid = [] - for x in grids: - rooms = self.env['hotel.reservation'].search( - ['&', '&', ('checkin', '<=', dates), - ('checkout', '>=', dates), - ('state', '<>', 'cancelled'), - ('room_id', '=', x.id) - ], order='checkin ASC') - - tipos = False - if len(rooms) != 0: - if len(rooms) == 2: - tipos = 1 - # Salida y etrada - checkinhour = rooms[1].checkin - checkouthour = rooms[1].checkout[:10] - else: - if rooms[0].checkin[:10] == dates: - checkinhour = rooms[0].checkin - checkouthour = rooms[0].checkout[:10] - tipos = 3 - # Revisar - elif rooms[0].checkout[:10] == dates: - checkinhour = 'no prevista' - checkouthour = '' - tipos = 1 - # Salida - else: - checkinhour = rooms[0].checkin[:10] - checkouthour = rooms[0].checkout[:10] - tipos = 2 - # Cliente - if rooms[0].reservation_type == 'staff': - checkinhour = rooms[0].checkin[:10] - checkouthour = rooms[0].checkout[:10] - tipos = 4 - # Staff - if rooms[0].reservation_type == 'out': - checkinhour = rooms[0].checkin[:10] - checkouthour = rooms[0].checkout[:10] - tipos = 5 - # Averiada - if tipos is not False: - listid.append(grids2.create( - {'habitacion': rooms[0].room_id.name, - 'habitacionid': rooms[0].room_id.id, - 'tipo': tipos, - 'notas': '', - 'checkin': checkinhour, - # 'checkin': rooms[0].checkin[:10], - # 'checkout': rooms[0].checkout[:10], - 'checkout': checkouthour, - # 'kelly': 5, - 'clean_date': fechalimpieza - }).id) - return self.env['kellysrooms'].search([('id', 'in', listid)]) - - - def print_rooms_report(self): - rooms = self.env['kellysrooms'].search([('id', 'in', - self.habitaciones.ids)], - order=self.order) - - return self.env.ref( - 'kellys_daily_report.report_kellysrooms').report_action(rooms) diff --git a/kellys_daily_report/wizard/kellys_daily_pdf.xml b/kellys_daily_report/wizard/kellys_daily_pdf.xml deleted file mode 100644 index 458fcc17b..000000000 --- a/kellys_daily_report/wizard/kellys_daily_pdf.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - kellys_daily_report_view - kellysreport - -

      - - - -