From 78a2e864a644c7adbd3570e99842cd511201ab93 Mon Sep 17 00:00:00 2001 From: expert Date: Mon, 24 Jun 2024 14:26:02 +0300 Subject: [PATCH] Add odex25_transactions --- README.md | 2 +- .../inspectionProfiles/Project_Default.xml | 29 + .../inspectionProfiles/profiles_settings.xml | 6 + odex25_transactions/.idea/modules.xml | 8 + .../.idea/odex25_transactions.iml | 8 + odex25_transactions/README.rst | 4 + .../cm_entity_sync_odex/__init__.py | 4 + .../cm_entity_sync_odex/__manifest__.py | 41 + .../controllers/__init__.py | 2 + .../cm_entity_sync_odex/controllers/sync.py | 312 ++ .../cm_entity_sync_odex/data/data.xml | 18 + .../cm_entity_sync_odex/i18n/ar_SY.po | 345 ++ .../cm_entity_sync_odex/models/__init__.py | 4 + .../cm_entity_sync_odex/models/entity.py | 448 +++ .../cm_entity_sync_odex/models/outgoing.py | 60 + .../cm_entity_sync_odex/models/settings.py | 79 + .../security/ir.model.access.csv | 6 + .../static/description/icon.png | Bin 0 -> 32929 bytes .../views/actions_and_menus.xml | 15 + .../cm_entity_sync_odex/views/entity_view.xml | 60 + .../views/settings_view.xml | 36 + .../cm_entity_sync_odex/wizards/__init__.py | 2 + .../wizards/inter_entity_wizard.xml | 53 + .../cm_entity_sync_odex/wizards/wizards.py | 72 + .../cm_odex_barcode/__init__.py | 2 + .../cm_odex_barcode/__manifest__.py | 32 + .../cm_odex_barcode/i18n/ar_SY.po | 106 + .../cm_odex_barcode/models/__init__.py | 2 + .../cm_odex_barcode/models/arabic_reshaper.py | 359 ++ .../cm_odex_barcode/models/barcode.py | 132 + .../cm_odex_barcode/models/bidi/__init__.py | 86 + .../cm_odex_barcode/models/bidi/algorithm.py | 658 ++++ .../cm_odex_barcode/models/bidi/mirror.py | 388 ++ .../models/img/ArmWrestler.ttf | Bin 0 -> 90116 bytes .../models/img/KacstOffice.ttf | Bin 0 -> 73680 bytes .../models/img/amiri-regular.ttf | Bin 0 -> 547000 bytes .../cm_odex_barcode/models/img/ar_bold.otf | Bin 0 -> 227488 bytes .../cm_odex_barcode/reports/barcodes.xml | 251 ++ .../extend_transaction_detail_report.xml | 57 + .../static/src/js/cm_odex_barcode.js | 51 + .../cm_odex_barcode/views/assets.xml | 16 + .../views/transactions_views.xml | 71 + .../exp_cm_mail_odex/__init__.py | 2 + .../exp_cm_mail_odex/__manifest__.py | 32 + .../exp_cm_mail_odex/i18n/ar_SY.po | 98 + .../exp_cm_mail_odex/models/__init__.py | 3 + .../exp_cm_mail_odex/models/extend_related.py | 14 + .../models/extend_transaction.py | 83 + .../views/actions_and_menus.xml | 32 + .../exp_late_mail_reminder/__init__.py | 4 + .../exp_late_mail_reminder/__manifest__.py | 34 + .../controllers/__init__.py | 1 + .../controllers/main.py | 44 + .../data/late_email_data.xml | 9 + .../exp_late_mail_reminder/data/mail_data.xml | 15 + .../exp_late_mail_reminder/models/__init__.py | 2 + .../models/late_mail_remainder.py | 106 + .../static/description/icon.png | Bin 0 -> 83374 bytes .../static/description/icon1.png | Bin 0 -> 57827 bytes .../css/fonts/FSAlbertArabic-ExtraBold.ttf | Bin 0 -> 129136 bytes .../src/css/fonts/FSAlbertArabic-Regular.ttf | Bin 0 -> 125180 bytes .../src/css/fonts/fsalbert light italic.otf | Bin 0 -> 31420 bytes .../static/src/css/fonts/fsalbert light.otf | Bin 0 -> 27420 bytes .../static/src/css/fonts/fsalbert regular.otf | Bin 0 -> 30432 bytes .../src/css/fonts/fsalbert thin italic.otf | Bin 0 -> 29896 bytes .../static/src/css/fonts/fsalbert thin.otf | Bin 0 -> 28192 bytes .../static/src/css/fonts/fsalbert-bold.otf | Bin 0 -> 30532 bytes .../src/css/fonts/fsalbert-extrabold.otf | Bin 0 -> 28756 bytes .../static/src/css/fonts/fsalbert-italic.otf | Bin 0 -> 31148 bytes .../static/src/css/fonts/fsalbertitalic.png | Bin 0 -> 1167 bytes .../static/src/css/style.css | 247 ++ .../static/src/js/notification_popup.js | 147 + .../static/src/xml/notification_dialog.xml | 28 + .../exp_late_mail_reminder/views/assets.xml | 10 + .../views/late_mail_reminder_views.xml | 66 + .../exp_multi_level_manage/__init__.py | 3 + .../exp_multi_level_manage/__manifest__.py | 30 + .../exp_multi_level_manage/models/__init__.py | 2 + .../models/extend_entity.py | 15 + .../static/description/icon.png | Bin 0 -> 3077 bytes .../views/extend_entity.xml | 18 + .../.idea/exp_transaction.iml | 11 + .../exp_transaction_documents/.idea/misc.xml | 4 + .../.idea/modules.xml | 8 + .../.idea/workspace.xml | 131 + .../exp_transaction_documents/__init__.py | 4 + .../exp_transaction_documents/__manifest__.py | 52 + .../data/cm_data.xml | 38 + .../data/ir_cron.xml | 15 + .../email_templates/incoming_templates.xml | 65 + .../email_templates/internal_templates.xml | 719 ++++ .../email_templates/out_templates.xml | 249 ++ .../exp_transaction_documents/i18n/ar_001.po | 3441 +++++++++++++++++ .../models/__init__.py | 9 + .../models/configuration.py | 119 + .../models/entity.py | 170 + .../models/incoming_transaction.py | 173 + .../models/internal_transaction.py | 212 + .../models/outgoing_transaction.py | 129 + .../models/res_config_settings.py | 46 + .../exp_transaction_documents/models/tools.py | 45 + .../models/transaction.py | 442 +++ .../reports/barcodes.xml | 76 + .../receiver_transaction_report_template.xml | 175 + .../transaction_details_report_template.xml | 290 ++ .../security/groups.xml | 82 + .../security/ir.model.access.csv | 88 + .../static/description/icon.png | Bin 0 -> 3077 bytes .../static/src/css/barcode.css | 17 + .../tools/__init__.py | 11 + .../tools/barcode/DejaVuSansMono.ttf | Bin 0 -> 321524 bytes .../tools/barcode/__init__.py | 103 + .../tools/barcode/base.py | 103 + .../tools/barcode/charsets/__init__.py | 0 .../tools/barcode/charsets/code128.py | 64 + .../tools/barcode/charsets/code39.py | 34 + .../tools/barcode/charsets/ean.py | 17 + .../tools/barcode/codex.py | 251 ++ .../tools/barcode/ean.py | 196 + .../tools/barcode/errors.py | 33 + .../tools/barcode/isxn.py | 136 + .../tools/barcode/pybarcode.py | 116 + .../tools/barcode/upc.py | 44 + .../tools/barcode/writer.py | 303 ++ .../views/actions_and_menus.xml | 622 +++ .../views/assets.xml | 16 + .../views/configuration.xml | 39 + .../views/entity.xml | 104 + .../views/incoming.xml | 186 + .../views/internal.xml | 222 ++ .../views/outgoing.xml | 199 + .../views/settings_config_view.xml | 56 + .../views/transcation_common_view.xml | 393 ++ .../wizard/__init__.py | 7 + .../wizard/archive_transaction.py | 47 + .../wizard/archive_transaction.xml | 28 + .../wizard/forward_transaction.xml | 38 + .../wizard/forward_trasaction.py | 94 + .../wizard/reject_transaction_reson.xml | 41 + .../wizard/reject_transaction_resons.py | 61 + .../wizard/reopen_transaction_wizard.py | 49 + .../wizard/reopen_transaction_wizard.xml | 28 + .../wizard/transaction_reply_wizard.py | 75 + .../wizard/transaction_reply_wizard.xml | 33 + .../exp_transaction_holiday/__init__.py | 3 + .../exp_transaction_holiday/__manifest__.py | 33 + .../exp_transaction_holiday/i18n/ar_001.po | 213 + .../exp_transaction_holiday/i18n/ar_SY.po | 213 + .../models/__init__.py | 3 + .../models/extend_trasnaction.py | 56 + .../models/transaction_holiday.py | 65 + .../security/groups.xml | 8 + .../security/ir.model.access.csv | 22 + .../static/description/icon.png | Bin 0 -> 3077 bytes .../views/transaction_holiday.xml | 79 + .../.idea/exp_transaction.iml | 11 + .../exp_transaction_leave/.idea/misc.xml | 4 + .../exp_transaction_leave/.idea/modules.xml | 8 + .../exp_transaction_leave/.idea/workspace.xml | 131 + .../exp_transaction_leave/__init__.py | 4 + .../exp_transaction_leave/__manifest__.py | 32 + .../data/state_expired_corn.xml | 15 + .../exp_transaction_leave/i18n/ar_001.po | 359 ++ .../exp_transaction_leave/models/__init__.py | 2 + .../exp_transaction_leave/models/leave.py | 189 + .../security/ir.model.access.csv | 18 + .../static/description/icon.png | Bin 0 -> 3077 bytes .../exp_transaction_leave/views/leave.xml | 105 + .../exp_transaction_leave/wizard/__init__.py | 3 + .../wizard/forward_trasaction.py | 83 + .../.idea/exp_transaction.iml | 11 + .../exp_transaction_report/.idea/misc.xml | 4 + .../exp_transaction_report/.idea/modules.xml | 8 + .../.idea/workspace.xml | 131 + .../exp_transaction_report/__init__.py | 2 + .../exp_transaction_report/__manifest__.py | 45 + .../exp_transaction_report/i18n/ar_001.po | 732 ++++ .../exp_transaction_report/i18n/ar_SY.po | 784 ++++ .../exp_transaction_report/models/__init__.py | 1 + ...chievement_transaction_report_template.xml | 147 + .../close_transaction_report_template.xml | 121 + .../forward_transaction_report_template.xml | 117 + .../incoming_transaction_report_template.xml | 99 + .../late_transaction_report_template.xml | 96 + .../outgoing_transaction_report_template.xml | 93 + ...utstanding_transaction_report_template.xml | 150 + .../security/ir.model.access.csv | 9 + .../static/fonts/ae_AlMohanad.ttf | Bin 0 -> 120920 bytes .../exp_transaction_report/wizard/__init__.py | 9 + ...chievement_transaction_report_view_wiz.xml | 38 + .../achievement_transaction_report_wiz.py | 193 + .../wizard/close_transaction_view_wiz.xml | 35 + .../wizard/close_transaction_wiz.py | 210 + .../wizard/forward_transaction_report_wiz.py | 138 + .../forward_transaction_report_wiz_view.xml | 33 + .../wizard/incoming_transaction_report_wiz.py | 157 + .../incoming_transaction_report_wiz_view.xml | 32 + .../wizard/late_transaction_report_wiz.py | 158 + .../wizard/late_transaction_report_wiz.xml | 35 + .../wizard/outgoing_transaction_report_wiz.py | 137 + .../outgoing_transaction_report_wiz_view.xml | 32 + ...utstanding_transaction_report_view_wiz.xml | 33 + .../outstanding_transaction_report_wiz.py | 119 + .../wizard/transaction_common_report.py | 27 + .../wizard/transaction_common_report_view.xml | 28 + .../exp_transation_letters/__init__.py | 3 + .../exp_transation_letters/__manifest__.py | 32 + .../exp_transation_letters/i18n/ar_001.po | 241 ++ .../exp_transation_letters/models/__init__.py | 2 + .../exp_transation_letters/models/letter.py | 114 + .../reports/letter_template.xml | 232 ++ .../security/groups.xml | 8 + .../security/ir.model.access.csv | 3 + .../views/letters_view.xml | 115 + odex25_transactions/html_text/README.rst | 118 + odex25_transactions/html_text/__init__.py | 3 + odex25_transactions/html_text/__manifest__.py | 19 + odex25_transactions/html_text/i18n/ca.po | 45 + odex25_transactions/html_text/i18n/de.po | 45 + odex25_transactions/html_text/i18n/es.po | 45 + odex25_transactions/html_text/i18n/es_ES.po | 46 + odex25_transactions/html_text/i18n/hr.po | 43 + odex25_transactions/html_text/i18n/it.po | 45 + odex25_transactions/html_text/i18n/tr.po | 45 + odex25_transactions/html_text/i18n/zh_CN.po | 42 + .../html_text/models/__init__.py | 3 + .../html_text/models/ir_fields_converter.py | 74 + .../html_text/readme/CONTRIBUTORS.rst | 7 + .../html_text/readme/DESCRIPTION.rst | 7 + .../html_text/readme/ROADMAP.rst | 2 + .../html_text/readme/USAGE.rst | 21 + .../html_text/static/description/icon.png | Bin 0 -> 9455 bytes .../html_text/static/description/index.html | 463 +++ .../html_text/tests/__init__.py | 3 + .../html_text/tests/test_extractor.py | 54 + odex25_transactions/odex_sms/__init__.py | 1 + odex25_transactions/odex_sms/__manifest__.py | 20 + odex25_transactions/odex_sms/i18n/ar_SY.po | 226 ++ .../odex_sms/models/__init__.py | 2 + .../odex_sms/models/res_company.py | 59 + .../odex_sms/security/ir.model.access.csv | 2 + .../odex_sms/static/description/icon.png | Bin 0 -> 32929 bytes .../odex_sms/views/res_company_view.xml | 24 + .../transaction_cmis/__init__.py | 1 + .../transaction_cmis/__manifest__.py | 29 + .../transaction_cmis/models/__init__.py | 1 + .../models/internal_transaction.py | 8 + .../views/internal_transaction.xml | 15 + 248 files changed, 23319 insertions(+), 1 deletion(-) create mode 100644 odex25_transactions/.idea/inspectionProfiles/Project_Default.xml create mode 100644 odex25_transactions/.idea/inspectionProfiles/profiles_settings.xml create mode 100644 odex25_transactions/.idea/modules.xml create mode 100644 odex25_transactions/.idea/odex25_transactions.iml create mode 100644 odex25_transactions/README.rst create mode 100644 odex25_transactions/cm_entity_sync_odex/__init__.py create mode 100644 odex25_transactions/cm_entity_sync_odex/__manifest__.py create mode 100644 odex25_transactions/cm_entity_sync_odex/controllers/__init__.py create mode 100644 odex25_transactions/cm_entity_sync_odex/controllers/sync.py create mode 100644 odex25_transactions/cm_entity_sync_odex/data/data.xml create mode 100644 odex25_transactions/cm_entity_sync_odex/i18n/ar_SY.po create mode 100644 odex25_transactions/cm_entity_sync_odex/models/__init__.py create mode 100644 odex25_transactions/cm_entity_sync_odex/models/entity.py create mode 100644 odex25_transactions/cm_entity_sync_odex/models/outgoing.py create mode 100644 odex25_transactions/cm_entity_sync_odex/models/settings.py create mode 100644 odex25_transactions/cm_entity_sync_odex/security/ir.model.access.csv create mode 100644 odex25_transactions/cm_entity_sync_odex/static/description/icon.png create mode 100644 odex25_transactions/cm_entity_sync_odex/views/actions_and_menus.xml create mode 100644 odex25_transactions/cm_entity_sync_odex/views/entity_view.xml create mode 100644 odex25_transactions/cm_entity_sync_odex/views/settings_view.xml create mode 100644 odex25_transactions/cm_entity_sync_odex/wizards/__init__.py create mode 100644 odex25_transactions/cm_entity_sync_odex/wizards/inter_entity_wizard.xml create mode 100644 odex25_transactions/cm_entity_sync_odex/wizards/wizards.py create mode 100644 odex25_transactions/cm_odex_barcode/__init__.py create mode 100644 odex25_transactions/cm_odex_barcode/__manifest__.py create mode 100644 odex25_transactions/cm_odex_barcode/i18n/ar_SY.po create mode 100644 odex25_transactions/cm_odex_barcode/models/__init__.py create mode 100644 odex25_transactions/cm_odex_barcode/models/arabic_reshaper.py create mode 100644 odex25_transactions/cm_odex_barcode/models/barcode.py create mode 100644 odex25_transactions/cm_odex_barcode/models/bidi/__init__.py create mode 100644 odex25_transactions/cm_odex_barcode/models/bidi/algorithm.py create mode 100644 odex25_transactions/cm_odex_barcode/models/bidi/mirror.py create mode 100644 odex25_transactions/cm_odex_barcode/models/img/ArmWrestler.ttf create mode 100644 odex25_transactions/cm_odex_barcode/models/img/KacstOffice.ttf create mode 100644 odex25_transactions/cm_odex_barcode/models/img/amiri-regular.ttf create mode 100644 odex25_transactions/cm_odex_barcode/models/img/ar_bold.otf create mode 100644 odex25_transactions/cm_odex_barcode/reports/barcodes.xml create mode 100644 odex25_transactions/cm_odex_barcode/reports/extend_transaction_detail_report.xml create mode 100644 odex25_transactions/cm_odex_barcode/static/src/js/cm_odex_barcode.js create mode 100644 odex25_transactions/cm_odex_barcode/views/assets.xml create mode 100644 odex25_transactions/cm_odex_barcode/views/transactions_views.xml create mode 100644 odex25_transactions/exp_cm_mail_odex/__init__.py create mode 100644 odex25_transactions/exp_cm_mail_odex/__manifest__.py create mode 100644 odex25_transactions/exp_cm_mail_odex/i18n/ar_SY.po create mode 100644 odex25_transactions/exp_cm_mail_odex/models/__init__.py create mode 100644 odex25_transactions/exp_cm_mail_odex/models/extend_related.py create mode 100644 odex25_transactions/exp_cm_mail_odex/models/extend_transaction.py create mode 100644 odex25_transactions/exp_cm_mail_odex/views/actions_and_menus.xml create mode 100644 odex25_transactions/exp_late_mail_reminder/__init__.py create mode 100644 odex25_transactions/exp_late_mail_reminder/__manifest__.py create mode 100644 odex25_transactions/exp_late_mail_reminder/controllers/__init__.py create mode 100644 odex25_transactions/exp_late_mail_reminder/controllers/main.py create mode 100644 odex25_transactions/exp_late_mail_reminder/data/late_email_data.xml create mode 100644 odex25_transactions/exp_late_mail_reminder/data/mail_data.xml create mode 100644 odex25_transactions/exp_late_mail_reminder/models/__init__.py create mode 100644 odex25_transactions/exp_late_mail_reminder/models/late_mail_remainder.py create mode 100644 odex25_transactions/exp_late_mail_reminder/static/description/icon.png create mode 100644 odex25_transactions/exp_late_mail_reminder/static/description/icon1.png create mode 100644 odex25_transactions/exp_late_mail_reminder/static/src/css/fonts/FSAlbertArabic-ExtraBold.ttf create mode 100644 odex25_transactions/exp_late_mail_reminder/static/src/css/fonts/FSAlbertArabic-Regular.ttf create mode 100644 odex25_transactions/exp_late_mail_reminder/static/src/css/fonts/fsalbert light italic.otf create mode 100644 odex25_transactions/exp_late_mail_reminder/static/src/css/fonts/fsalbert light.otf create mode 100644 odex25_transactions/exp_late_mail_reminder/static/src/css/fonts/fsalbert regular.otf create mode 100644 odex25_transactions/exp_late_mail_reminder/static/src/css/fonts/fsalbert thin italic.otf create mode 100644 odex25_transactions/exp_late_mail_reminder/static/src/css/fonts/fsalbert thin.otf create mode 100644 odex25_transactions/exp_late_mail_reminder/static/src/css/fonts/fsalbert-bold.otf create mode 100644 odex25_transactions/exp_late_mail_reminder/static/src/css/fonts/fsalbert-extrabold.otf create mode 100644 odex25_transactions/exp_late_mail_reminder/static/src/css/fonts/fsalbert-italic.otf create mode 100644 odex25_transactions/exp_late_mail_reminder/static/src/css/fonts/fsalbertitalic.png create mode 100644 odex25_transactions/exp_late_mail_reminder/static/src/css/style.css create mode 100644 odex25_transactions/exp_late_mail_reminder/static/src/js/notification_popup.js create mode 100644 odex25_transactions/exp_late_mail_reminder/static/src/xml/notification_dialog.xml create mode 100644 odex25_transactions/exp_late_mail_reminder/views/assets.xml create mode 100644 odex25_transactions/exp_late_mail_reminder/views/late_mail_reminder_views.xml create mode 100644 odex25_transactions/exp_multi_level_manage/__init__.py create mode 100644 odex25_transactions/exp_multi_level_manage/__manifest__.py create mode 100644 odex25_transactions/exp_multi_level_manage/models/__init__.py create mode 100644 odex25_transactions/exp_multi_level_manage/models/extend_entity.py create mode 100644 odex25_transactions/exp_multi_level_manage/static/description/icon.png create mode 100644 odex25_transactions/exp_multi_level_manage/views/extend_entity.xml create mode 100644 odex25_transactions/exp_transaction_documents/.idea/exp_transaction.iml create mode 100644 odex25_transactions/exp_transaction_documents/.idea/misc.xml create mode 100644 odex25_transactions/exp_transaction_documents/.idea/modules.xml create mode 100644 odex25_transactions/exp_transaction_documents/.idea/workspace.xml create mode 100644 odex25_transactions/exp_transaction_documents/__init__.py create mode 100644 odex25_transactions/exp_transaction_documents/__manifest__.py create mode 100644 odex25_transactions/exp_transaction_documents/data/cm_data.xml create mode 100644 odex25_transactions/exp_transaction_documents/data/ir_cron.xml create mode 100644 odex25_transactions/exp_transaction_documents/email_templates/incoming_templates.xml create mode 100644 odex25_transactions/exp_transaction_documents/email_templates/internal_templates.xml create mode 100644 odex25_transactions/exp_transaction_documents/email_templates/out_templates.xml create mode 100644 odex25_transactions/exp_transaction_documents/i18n/ar_001.po create mode 100644 odex25_transactions/exp_transaction_documents/models/__init__.py create mode 100644 odex25_transactions/exp_transaction_documents/models/configuration.py create mode 100644 odex25_transactions/exp_transaction_documents/models/entity.py create mode 100644 odex25_transactions/exp_transaction_documents/models/incoming_transaction.py create mode 100644 odex25_transactions/exp_transaction_documents/models/internal_transaction.py create mode 100644 odex25_transactions/exp_transaction_documents/models/outgoing_transaction.py create mode 100644 odex25_transactions/exp_transaction_documents/models/res_config_settings.py create mode 100644 odex25_transactions/exp_transaction_documents/models/tools.py create mode 100644 odex25_transactions/exp_transaction_documents/models/transaction.py create mode 100644 odex25_transactions/exp_transaction_documents/reports/barcodes.xml create mode 100644 odex25_transactions/exp_transaction_documents/reports/receiver_transaction_report_template.xml create mode 100644 odex25_transactions/exp_transaction_documents/reports/transaction_details_report_template.xml create mode 100644 odex25_transactions/exp_transaction_documents/security/groups.xml create mode 100644 odex25_transactions/exp_transaction_documents/security/ir.model.access.csv create mode 100644 odex25_transactions/exp_transaction_documents/static/description/icon.png create mode 100644 odex25_transactions/exp_transaction_documents/static/src/css/barcode.css create mode 100644 odex25_transactions/exp_transaction_documents/tools/__init__.py create mode 100644 odex25_transactions/exp_transaction_documents/tools/barcode/DejaVuSansMono.ttf create mode 100644 odex25_transactions/exp_transaction_documents/tools/barcode/__init__.py create mode 100644 odex25_transactions/exp_transaction_documents/tools/barcode/base.py create mode 100644 odex25_transactions/exp_transaction_documents/tools/barcode/charsets/__init__.py create mode 100644 odex25_transactions/exp_transaction_documents/tools/barcode/charsets/code128.py create mode 100644 odex25_transactions/exp_transaction_documents/tools/barcode/charsets/code39.py create mode 100644 odex25_transactions/exp_transaction_documents/tools/barcode/charsets/ean.py create mode 100644 odex25_transactions/exp_transaction_documents/tools/barcode/codex.py create mode 100644 odex25_transactions/exp_transaction_documents/tools/barcode/ean.py create mode 100644 odex25_transactions/exp_transaction_documents/tools/barcode/errors.py create mode 100644 odex25_transactions/exp_transaction_documents/tools/barcode/isxn.py create mode 100644 odex25_transactions/exp_transaction_documents/tools/barcode/pybarcode.py create mode 100644 odex25_transactions/exp_transaction_documents/tools/barcode/upc.py create mode 100644 odex25_transactions/exp_transaction_documents/tools/barcode/writer.py create mode 100644 odex25_transactions/exp_transaction_documents/views/actions_and_menus.xml create mode 100644 odex25_transactions/exp_transaction_documents/views/assets.xml create mode 100644 odex25_transactions/exp_transaction_documents/views/configuration.xml create mode 100644 odex25_transactions/exp_transaction_documents/views/entity.xml create mode 100644 odex25_transactions/exp_transaction_documents/views/incoming.xml create mode 100644 odex25_transactions/exp_transaction_documents/views/internal.xml create mode 100644 odex25_transactions/exp_transaction_documents/views/outgoing.xml create mode 100644 odex25_transactions/exp_transaction_documents/views/settings_config_view.xml create mode 100644 odex25_transactions/exp_transaction_documents/views/transcation_common_view.xml create mode 100644 odex25_transactions/exp_transaction_documents/wizard/__init__.py create mode 100644 odex25_transactions/exp_transaction_documents/wizard/archive_transaction.py create mode 100644 odex25_transactions/exp_transaction_documents/wizard/archive_transaction.xml create mode 100644 odex25_transactions/exp_transaction_documents/wizard/forward_transaction.xml create mode 100644 odex25_transactions/exp_transaction_documents/wizard/forward_trasaction.py create mode 100644 odex25_transactions/exp_transaction_documents/wizard/reject_transaction_reson.xml create mode 100644 odex25_transactions/exp_transaction_documents/wizard/reject_transaction_resons.py create mode 100644 odex25_transactions/exp_transaction_documents/wizard/reopen_transaction_wizard.py create mode 100644 odex25_transactions/exp_transaction_documents/wizard/reopen_transaction_wizard.xml create mode 100644 odex25_transactions/exp_transaction_documents/wizard/transaction_reply_wizard.py create mode 100644 odex25_transactions/exp_transaction_documents/wizard/transaction_reply_wizard.xml create mode 100644 odex25_transactions/exp_transaction_holiday/__init__.py create mode 100644 odex25_transactions/exp_transaction_holiday/__manifest__.py create mode 100644 odex25_transactions/exp_transaction_holiday/i18n/ar_001.po create mode 100644 odex25_transactions/exp_transaction_holiday/i18n/ar_SY.po create mode 100644 odex25_transactions/exp_transaction_holiday/models/__init__.py create mode 100644 odex25_transactions/exp_transaction_holiday/models/extend_trasnaction.py create mode 100644 odex25_transactions/exp_transaction_holiday/models/transaction_holiday.py create mode 100644 odex25_transactions/exp_transaction_holiday/security/groups.xml create mode 100644 odex25_transactions/exp_transaction_holiday/security/ir.model.access.csv create mode 100644 odex25_transactions/exp_transaction_holiday/static/description/icon.png create mode 100644 odex25_transactions/exp_transaction_holiday/views/transaction_holiday.xml create mode 100644 odex25_transactions/exp_transaction_leave/.idea/exp_transaction.iml create mode 100644 odex25_transactions/exp_transaction_leave/.idea/misc.xml create mode 100644 odex25_transactions/exp_transaction_leave/.idea/modules.xml create mode 100644 odex25_transactions/exp_transaction_leave/.idea/workspace.xml create mode 100644 odex25_transactions/exp_transaction_leave/__init__.py create mode 100644 odex25_transactions/exp_transaction_leave/__manifest__.py create mode 100644 odex25_transactions/exp_transaction_leave/data/state_expired_corn.xml create mode 100644 odex25_transactions/exp_transaction_leave/i18n/ar_001.po create mode 100644 odex25_transactions/exp_transaction_leave/models/__init__.py create mode 100644 odex25_transactions/exp_transaction_leave/models/leave.py create mode 100644 odex25_transactions/exp_transaction_leave/security/ir.model.access.csv create mode 100644 odex25_transactions/exp_transaction_leave/static/description/icon.png create mode 100644 odex25_transactions/exp_transaction_leave/views/leave.xml create mode 100644 odex25_transactions/exp_transaction_leave/wizard/__init__.py create mode 100644 odex25_transactions/exp_transaction_leave/wizard/forward_trasaction.py create mode 100644 odex25_transactions/exp_transaction_report/.idea/exp_transaction.iml create mode 100644 odex25_transactions/exp_transaction_report/.idea/misc.xml create mode 100644 odex25_transactions/exp_transaction_report/.idea/modules.xml create mode 100644 odex25_transactions/exp_transaction_report/.idea/workspace.xml create mode 100644 odex25_transactions/exp_transaction_report/__init__.py create mode 100644 odex25_transactions/exp_transaction_report/__manifest__.py create mode 100644 odex25_transactions/exp_transaction_report/i18n/ar_001.po create mode 100644 odex25_transactions/exp_transaction_report/i18n/ar_SY.po create mode 100644 odex25_transactions/exp_transaction_report/models/__init__.py create mode 100644 odex25_transactions/exp_transaction_report/report/achievement_transaction_report_template.xml create mode 100644 odex25_transactions/exp_transaction_report/report/close_transaction_report_template.xml create mode 100644 odex25_transactions/exp_transaction_report/report/forward_transaction_report_template.xml create mode 100644 odex25_transactions/exp_transaction_report/report/incoming_transaction_report_template.xml create mode 100644 odex25_transactions/exp_transaction_report/report/late_transaction_report_template.xml create mode 100644 odex25_transactions/exp_transaction_report/report/outgoing_transaction_report_template.xml create mode 100644 odex25_transactions/exp_transaction_report/report/outstanding_transaction_report_template.xml create mode 100644 odex25_transactions/exp_transaction_report/security/ir.model.access.csv create mode 100644 odex25_transactions/exp_transaction_report/static/fonts/ae_AlMohanad.ttf create mode 100644 odex25_transactions/exp_transaction_report/wizard/__init__.py create mode 100644 odex25_transactions/exp_transaction_report/wizard/achievement_transaction_report_view_wiz.xml create mode 100644 odex25_transactions/exp_transaction_report/wizard/achievement_transaction_report_wiz.py create mode 100644 odex25_transactions/exp_transaction_report/wizard/close_transaction_view_wiz.xml create mode 100644 odex25_transactions/exp_transaction_report/wizard/close_transaction_wiz.py create mode 100644 odex25_transactions/exp_transaction_report/wizard/forward_transaction_report_wiz.py create mode 100644 odex25_transactions/exp_transaction_report/wizard/forward_transaction_report_wiz_view.xml create mode 100644 odex25_transactions/exp_transaction_report/wizard/incoming_transaction_report_wiz.py create mode 100644 odex25_transactions/exp_transaction_report/wizard/incoming_transaction_report_wiz_view.xml create mode 100644 odex25_transactions/exp_transaction_report/wizard/late_transaction_report_wiz.py create mode 100644 odex25_transactions/exp_transaction_report/wizard/late_transaction_report_wiz.xml create mode 100644 odex25_transactions/exp_transaction_report/wizard/outgoing_transaction_report_wiz.py create mode 100644 odex25_transactions/exp_transaction_report/wizard/outgoing_transaction_report_wiz_view.xml create mode 100644 odex25_transactions/exp_transaction_report/wizard/outstanding_transaction_report_view_wiz.xml create mode 100644 odex25_transactions/exp_transaction_report/wizard/outstanding_transaction_report_wiz.py create mode 100644 odex25_transactions/exp_transaction_report/wizard/transaction_common_report.py create mode 100644 odex25_transactions/exp_transaction_report/wizard/transaction_common_report_view.xml create mode 100644 odex25_transactions/exp_transation_letters/__init__.py create mode 100644 odex25_transactions/exp_transation_letters/__manifest__.py create mode 100644 odex25_transactions/exp_transation_letters/i18n/ar_001.po create mode 100644 odex25_transactions/exp_transation_letters/models/__init__.py create mode 100644 odex25_transactions/exp_transation_letters/models/letter.py create mode 100644 odex25_transactions/exp_transation_letters/reports/letter_template.xml create mode 100644 odex25_transactions/exp_transation_letters/security/groups.xml create mode 100644 odex25_transactions/exp_transation_letters/security/ir.model.access.csv create mode 100644 odex25_transactions/exp_transation_letters/views/letters_view.xml create mode 100644 odex25_transactions/html_text/README.rst create mode 100644 odex25_transactions/html_text/__init__.py create mode 100644 odex25_transactions/html_text/__manifest__.py create mode 100644 odex25_transactions/html_text/i18n/ca.po create mode 100644 odex25_transactions/html_text/i18n/de.po create mode 100644 odex25_transactions/html_text/i18n/es.po create mode 100644 odex25_transactions/html_text/i18n/es_ES.po create mode 100644 odex25_transactions/html_text/i18n/hr.po create mode 100644 odex25_transactions/html_text/i18n/it.po create mode 100644 odex25_transactions/html_text/i18n/tr.po create mode 100644 odex25_transactions/html_text/i18n/zh_CN.po create mode 100644 odex25_transactions/html_text/models/__init__.py create mode 100644 odex25_transactions/html_text/models/ir_fields_converter.py create mode 100644 odex25_transactions/html_text/readme/CONTRIBUTORS.rst create mode 100644 odex25_transactions/html_text/readme/DESCRIPTION.rst create mode 100644 odex25_transactions/html_text/readme/ROADMAP.rst create mode 100644 odex25_transactions/html_text/readme/USAGE.rst create mode 100644 odex25_transactions/html_text/static/description/icon.png create mode 100644 odex25_transactions/html_text/static/description/index.html create mode 100644 odex25_transactions/html_text/tests/__init__.py create mode 100644 odex25_transactions/html_text/tests/test_extractor.py create mode 100644 odex25_transactions/odex_sms/__init__.py create mode 100644 odex25_transactions/odex_sms/__manifest__.py create mode 100644 odex25_transactions/odex_sms/i18n/ar_SY.po create mode 100644 odex25_transactions/odex_sms/models/__init__.py create mode 100644 odex25_transactions/odex_sms/models/res_company.py create mode 100644 odex25_transactions/odex_sms/security/ir.model.access.csv create mode 100644 odex25_transactions/odex_sms/static/description/icon.png create mode 100644 odex25_transactions/odex_sms/views/res_company_view.xml create mode 100644 odex25_transactions/transaction_cmis/__init__.py create mode 100644 odex25_transactions/transaction_cmis/__manifest__.py create mode 100644 odex25_transactions/transaction_cmis/models/__init__.py create mode 100644 odex25_transactions/transaction_cmis/models/internal_transaction.py create mode 100644 odex25_transactions/transaction_cmis/views/internal_transaction.xml diff --git a/README.md b/README.md index 8b10e6960..6864725ce 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -# odex25-standard-moduless +# odex25-standard-modules This Repo contains general standard modules for all projects. diff --git a/odex25_transactions/.idea/inspectionProfiles/Project_Default.xml b/odex25_transactions/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 000000000..480ffc0b0 --- /dev/null +++ b/odex25_transactions/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,29 @@ + + + + \ No newline at end of file diff --git a/odex25_transactions/.idea/inspectionProfiles/profiles_settings.xml b/odex25_transactions/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 000000000..105ce2da2 --- /dev/null +++ b/odex25_transactions/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/odex25_transactions/.idea/modules.xml b/odex25_transactions/.idea/modules.xml new file mode 100644 index 000000000..a57643433 --- /dev/null +++ b/odex25_transactions/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/odex25_transactions/.idea/odex25_transactions.iml b/odex25_transactions/.idea/odex25_transactions.iml new file mode 100644 index 000000000..d0876a78d --- /dev/null +++ b/odex25_transactions/.idea/odex25_transactions.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/odex25_transactions/README.rst b/odex25_transactions/README.rst new file mode 100644 index 000000000..d64cf9a56 --- /dev/null +++ b/odex25_transactions/README.rst @@ -0,0 +1,4 @@ +*pip install arabic-reshaper +*pip install python-bidi +pip install python-barcode + diff --git a/odex25_transactions/cm_entity_sync_odex/__init__.py b/odex25_transactions/cm_entity_sync_odex/__init__.py new file mode 100644 index 000000000..3e0935305 --- /dev/null +++ b/odex25_transactions/cm_entity_sync_odex/__init__.py @@ -0,0 +1,4 @@ +#-*- coding: utf-8 -*- +from . import models +from . import wizards +from . import controllers diff --git a/odex25_transactions/cm_entity_sync_odex/__manifest__.py b/odex25_transactions/cm_entity_sync_odex/__manifest__.py new file mode 100644 index 000000000..186e57b1a --- /dev/null +++ b/odex25_transactions/cm_entity_sync_odex/__manifest__.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Odex - Communications Management System. +# Copyright (C) 2020 Expert Co. Ltd. (). +# +############################################################################## +{ + 'name' : 'C.M. Entity Sync', + 'version' : '0.1', + 'sequence' : 4, + 'author' : 'Expert Co. Ltd.', + 'category' : 'Odex25-Transactions/Odex25-Transactions', + 'summary' : 'Correspondence Management, Entity Sync', + 'description' : """ +Odex - Correspondence Management, Entity Syncronization +======================================================== + +Intercompanies entity syncronization + """, + 'website': 'http://www.exp-sa.com', + 'depends': ['exp_transaction_documents'], + 'data': [ + 'security/ir.model.access.csv', + # data + 'data/data.xml', + # views + 'views/entity_view.xml', + 'views/settings_view.xml', + # wizards + 'wizards/inter_entity_wizard.xml', + # actions amd menus + 'views/actions_and_menus.xml', + ], + 'qweb' : [ + ], + 'installable': True, + 'auto_install': False, + 'application': False, +} + diff --git a/odex25_transactions/cm_entity_sync_odex/controllers/__init__.py b/odex25_transactions/cm_entity_sync_odex/controllers/__init__.py new file mode 100644 index 000000000..398e67254 --- /dev/null +++ b/odex25_transactions/cm_entity_sync_odex/controllers/__init__.py @@ -0,0 +1,2 @@ +#-*- coding: utf-8 -*- +from . import sync diff --git a/odex25_transactions/cm_entity_sync_odex/controllers/sync.py b/odex25_transactions/cm_entity_sync_odex/controllers/sync.py new file mode 100644 index 000000000..e4b270a1c --- /dev/null +++ b/odex25_transactions/cm_entity_sync_odex/controllers/sync.py @@ -0,0 +1,312 @@ +#-*- coding: utf-8 -*- +import logging +import datetime +import base64 +from odoo import http +from odoo.http import request +from odoo import models, api, fields, _,exceptions,SUPERUSER_ID + + +_logger = logging.getLogger(__name__) + + +class Sync(http.Controller): + @http.route('/cm/sync/broadcast', type='json', auth='public', methods=['POST']) + def add_new(self, **kw): + keys = [ + 'url', + 'name', + 'code', + 'key', + 'auth', + ] + for k in keys: + if not kw.get(k, False): + return { + 'error': 'Bad Request 1', + } + inter_entity = request.env['cm.inter_entity'].sudo() + if not inter_entity.authenticate(kw.get('auth', '')): + return { + 'error': 'Bad Request 2', + 'req': kw, + } + data = { + 'url': kw.get('url', ''), + 'name': kw.get('name', ''), + 'code': kw.get('code', ''), + 'uuid': kw.get('key', ''), + } + entities = inter_entity.add_new(data) + return { + 'success': True, + 'entities': entities, + } + + @http.route('/cm/sync/update_from', type='json', auth='public', methods=['POST']) + def update_from(self, **kw): + keys = [ + 'key', + 'auth', + ] + for k in keys: + if not kw.get(k, False): + return { + 'error': 'Bad Request 1', + } + inter_entity = request.env['cm.inter_entity'].sudo() + if not inter_entity.authenticate(kw.get('auth', '')): + return { + 'error': 'Bad Request 2', + 'req': kw, + } + return { + 'success': True, + 'entities': inter_entity.get_entities() + } + data = { + 'url': kw.get('url', ''), + 'name': kw.get('name', ''), + 'code': kw.get('code', ''), + 'uuid': kw.get('key', ''), + } + entities = inter_entity.add_new(data) + return { + 'success': True, + 'entities': entities, + } + + @http.route('/cm/sync/new_key', type='json', auth='public', methods=['POST']) + def new_key(self, **kw): + keys = [ + 'old', + 'key', + 'auth', + ] + for k in keys: + if not kw.get(k, False): + return { + 'error': 'Bad Request 1', + } + inter_entity = request.env['cm.inter_entity'].sudo() + if not inter_entity.authenticate(kw.get('auth', '')): + return { + 'error': 'Bad Request 2', + } + old = inter_entity.search([('uuid', '=', kw.get('old'))], limit=1) + if len(old): + data = { + 'uuid': kw.get('key'), + 'code': kw.get('key').split('-')[0], + } + old.write(data) + return { + 'success': True, + } + + @http.route('/cm/sync/update_entity', type='json', auth='public', methods=['POST']) + def update_entity(self, **kw): + keys = [ + 'data', + 'auth', + ] + for k in keys: + if not kw.get(k, False): + return { + 'error': 'Bad Request 1', + } + inter_entity = request.env['cm.inter_entity'].sudo() + inter_entity_set = request.env['cm.inter_entity.sync'].sudo() + if not inter_entity.authenticate(kw.get('auth', '')): + return { + 'error': 'Bad Request 2', + } + data = kw['data'] + key = data['key'] + entity = inter_entity.search([('uuid', '=', key)], limit=1) + ecode = data['details']['code'] + is_new = data['details'].get('is_new', False) + if len(entity): + en = request.env['cm.entity'].sudo().search( + [('inter_entity_code', '=', ecode), ('inter_entity_id', '=', entity.id)]) + if len(en): + d = data['details']['data'] + d['broadcasted'] = True + en.write(d) + elif is_new: + d = data['details']['data'] + dd = { + 'name': d.get('name', ''), + # 'code': d.get('code', ''), + 'type': 'external', + 'is_inter_entity': True, + 'inter_entity_code': d.get('inter_entity_code', ''), + 'inter_entity_id': entity.id, + } + request.env['cm.entity'].sudo().create(dd) + else: + return { + 'error': 'No Record' + } + return { + 'success': True, + } + + @http.route('/cm/sync/push_new', type='json', auth='public', methods=['POST']) + def push_new(self, **kw): + keys = [ + 'data', + 'auth', + ] + for k in keys: + if not kw.get(k, False): + return { + 'error': 'Bad Request 1', + } + inter_entity = request.env['cm.inter_entity'].sudo() + if not inter_entity.authenticate(kw.get('auth', '')): + return { + 'error': 'Bad Request 2', + } + data = kw['data'] + key = data['key'] + entity = inter_entity.search([('uuid', '=', key)], limit=1) + + if len(entity): + + d = data['data'] + dd = { + 'name': d.get('name', ''), + # 'code': d.get('code', ''), + 'type': 'external', + 'is_inter_entity': True, + 'inter_entity_code': d.get('inter_entity_code', ''), + 'inter_entity_id': entity.id, + } + try: + request.env['cm.entity'].sudo().with_context( + broacasted=True).create(dd) + return { + 'success': True, + } + except Exception as e: + return { + 'error': 'No Record' + } + else: + return { + 'error': 'No Record' + } + return { + 'success': True, + } + + @http.route('/cm/sync/send_transaction', type='json', auth='public', methods=['POST']) + def send_transaction(self, **kw): + keys = [ + 'data', + 'code', + 'key', + 'auth', + ] + for k in keys: + if not kw.get(k, False): + return { + 'error': 'Bad Request 1', + } + inter_entity = request.env['cm.inter_entity'].sudo() + Entity = request.env['cm.entity'].sudo() + if not inter_entity.authenticate(kw.get('auth', '')): + return { + 'error': 'Bad Request 2', + } + data = kw['data'] + code = kw['code'] + key = kw['key'] + auth = kw['auth'] + from_id = data['from_id'] + ie = inter_entity.search([('uuid', '=', auth)], limit=1) + extie = inter_entity.search([('uuid', '=', key)], limit=1) + setting = inter_entity.get_settings() + if not len(ie) or not len(extie): + return { + 'error': 'No Record 1' + } + if not from_id: + from_id = Entity.search([('is_master_entity', '=', True), + ('type', '=', 'external'), ('inter_entity_id', '=', extie.id)], limit=1) + if not len(from_id): + return { + 'error': 'No Record 2' + } + else: + from_id = Entity.search([('inter_entity_code', '=', from_id), ( + 'type', '=', 'external'), ('inter_entity_id', '=', extie.id)], limit=1) + if not len(from_id): + return { + 'error': 'No Record 3' + } + entity = Entity.search([('inter_entity_code', '=', code),('type', '=', 'unit')], limit=1) + if len(entity) > 0 and len(from_id) > 0: + Incoming = request.env['incoming.transaction'].sudo() + d = data + d['from_id'] = from_id.id + d['inter_entity_id'] = extie.id + d['important_id'] = setting.important_id.id + d['subject_type_id'] = setting.subject_type_id.id + if len(entity.secretary_id): + d['employee_id'] = entity.secretary_id.id + d['preparation_id'] = entity.id + else: + d['employee_id'] = setting.employee_id.id + d['preparation_id'] = setting.id + d['to_ids'] = [(4, entity.id), ] + # if entity.body: + # d['body'] = entity.body + d['due_date'] = fields.date.today() + attachment_rule_ids = d.get('attachment_rule_ids') + d.pop('attachment_rule_ids') + inc = Incoming.create(d) + for attachment in attachment_rule_ids: + attachement_rule = request.env['cm.attachment.rule'].sudo().create({ + 'employee_id': entity.secretary_id.id if len(entity.secretary_id) else setting.employee_id.id, + 'entity_id': entity.id, + 'file_save': attachment['file_save'], + 'attachment_filename': attachment['attachment_filename'], + 'incoming_transaction_id': inc.id if inc.id else False, + 'date': attachment['date'], + 'description': attachment['description'], + }) + attachment_data = { + 'name': attachment['attachment_filename'], + 'datas_fname': attachment['attachment_filename'], + 'datas': attachment['file_save'], + 'res_model': 'cm.attachment.rule', + 'res_id': attachement_rule.id, + } + request.env['ir.attachment'].sudo().create(attachment_data) + inc.preparation_id = inc.entity_id + # notification system and mailing + employee = inc.from_id + subj = _('Message Has been send !') + msg = _(u'{} ← {}.{}').format(employee and employee.name or '#', + u' / '.join([k.name for k in inc.to_ids]), + u'رابط المعاملة ' % (inc.get_url())) + partner_ids = [] + for partner in inc.to_ids: + if partner.type == 'unit': + partner_ids.append(partner.secretary_id.user_id.partner_id.id) + elif partner.type == 'employee': + partner_ids.append(partner.user_id.partner_id.id) + # thread_obj = request.env['mail.thread'] + # thread_obj.message_post(type="notification", subject=subj, body=msg, + # partner_ids=partner_ids, + # subtype="mail.mt_comment") + # inc.send_message(template='exp_transaction_documents.incoming_notify_send_send_email') + else: + return { + 'error': 'No Record 4' + } + return { + 'success': True, + } \ No newline at end of file diff --git a/odex25_transactions/cm_entity_sync_odex/data/data.xml b/odex25_transactions/cm_entity_sync_odex/data/data.xml new file mode 100644 index 000000000..41e3ed549 --- /dev/null +++ b/odex25_transactions/cm_entity_sync_odex/data/data.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + Inter-Entities Seq + cm.inter.entity + + + 6 + + + diff --git a/odex25_transactions/cm_entity_sync_odex/i18n/ar_SY.po b/odex25_transactions/cm_entity_sync_odex/i18n/ar_SY.po new file mode 100644 index 000000000..522c0331c --- /dev/null +++ b/odex25_transactions/cm_entity_sync_odex/i18n/ar_SY.po @@ -0,0 +1,345 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * cm_entity_sync_odex +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-05-16 03:24+0000\n" +"PO-Revision-Date: 2020-05-16 03:24+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: cm_entity_sync_odex +#: model:ir.model.fields,help:cm_entity_sync_odex.field_cm_entity_is_inter_entity +#: model:ir.model.fields,help:cm_entity_sync_odex.field_cm_entity_is_master_entity +msgid "\n" +" If checked, this entity will be syncronized by other entities in the group.\n" +" " +msgstr "\n" +" اذا تمّ اختياره، سيتم مشاركة المؤسسة مع بقية المؤسسات في المجموعة.\n" +" " + +#. module: cm_entity_sync_odex +#: code:addons/cm_entity_sync_odex/models/entity.py:278 +#: code:addons/cm_entity_sync_odex/models/entity.py:280 +#, python-format +msgid "Access Error" +msgstr "ليس لديك صلاحية !" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_activated +#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_sync_config +msgid "Activate Syncronization" +msgstr "تفعيل نظام المزامنة" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_broadcast +msgid "Broadcast" +msgstr "مزامنة" + +#. module: cm_entity_sync_odex +#: code:addons/cm_entity_sync_odex/wizards/wizards.py:34 +#, python-format +msgid "Broadcast Error !Error While Broadcast new Server, please check server key and url." +msgstr "خطا في المزامنة ! خطا عند مزامنة مخدم الجديد , الرجاء التأكد من عنوان الويب او مفتاح المخدم." + +#. module: cm_entity_sync_odex +#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_inter_entity_update_wizard +#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_inter_entity_wizard +msgid "Cancel" +msgstr "إلغاء" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_code +msgid "Code" +msgstr "رمز" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_create_uid +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_create_uid +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_create_uid +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_create_uid +msgid "Created by" +msgstr "أنشئ بواسطة" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_create_date +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_create_date +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_create_date +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_create_date +msgid "Created on" +msgstr "أنشئ في" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_server_id +msgid "Current Server" +msgstr "السيرفر (النظام) الحالي" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_employee_id +msgid "Default Created By" +msgstr "مدخل المعاملة الافتراضي" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_important_id +msgid "Default Important Degree" +msgstr "درجة الأهمية الافتراضية" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_subject_type_id +msgid "Default Transaction Type" +msgstr "نوع المعاملة الافتراضي" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_name +msgid "Description" +msgstr "الوصف" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_display_name +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_display_name +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_display_name +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_display_name +msgid "Display Name" +msgstr "الاسم المعروض" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_document_id +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_document_id +msgid "Document" +msgstr "مستند" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_entities +msgid "Entities" +msgstr "العناوين و الجهات" + +#. module: cm_entity_sync_odex +#: model:ir.model,name:cm_entity_sync_odex.model_cm_inter_entity_sync +msgid "Entity Syncronization" +msgstr "الوحدات المتزامنه" + +#. module: cm_entity_sync_odex +#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_inter_entity_wizard +msgid "Generate" +msgstr "توليــد" + +#. module: cm_entity_sync_odex +#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_sync_config +msgid "Generate Key" +msgstr "توليد مفتاح مزامنة" + +#. module: cm_entity_sync_odex +#: code:addons/cm_entity_sync_odex/models/settings.py:36 +#, python-format +msgid "Generate new Key" +msgstr "توليد مفتاح مزامنة جديدة" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_id +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_id +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_id +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_id +msgid "ID" +msgstr "المعرف" + +#. module: cm_entity_sync_odex +#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_sync_config +msgid "Inter Entities" +msgstr "المؤسسات المتزامنة" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_incoming_transaction_inter_entity_id +msgid "Inter Entity" +msgstr "مؤسسة متزامنة" + +#. module: cm_entity_sync_odex +#: model:ir.actions.act_window,name:cm_entity_sync_odex.cm_inter_entity_sync_action +#: model:ir.ui.menu,name:cm_entity_sync_odex.cm_inter_entity_sync_menu +msgid "Inter Entity Sync" +msgstr "إعدادات المؤسسات المتزامنة" + +#. module: cm_entity_sync_odex +#: model:ir.ui.view,arch_db:cm_entity_sync_odex.cm_inter_entity_tree +msgid "Inter-Entities" +msgstr "المؤسسات المتزامنة" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_entity_inter_entity_code +msgid "Inter-Entities Code" +msgstr "رمز التزامن" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_entity_inter_entity_id +msgid "Inter-Entities Ref" +msgstr "مرجع المؤسسة المتزامنة" + +#. module: cm_entity_sync_odex +#: model:ir.ui.view,arch_db:cm_entity_sync_odex.cm_inter_entity_form +msgid "Inter-Entity" +msgstr "مؤسسة متزامنة" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_entity_is_inter_entity +msgid "Is Inter-Entity ?" +msgstr "مؤسسة متزامنة ؟" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_entity_is_master_entity +msgid "Is Master-Entity ?" +msgstr "مؤسسة متزمنة رئيسية ؟" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity___last_update +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync___last_update +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard___last_update +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard___last_update +msgid "Last Modified on" +msgstr "آخر تعديل في" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_write_uid +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_write_uid +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_write_uid +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_write_uid +msgid "Last Updated by" +msgstr "آخر تحديث بواسطة" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_write_date +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_write_date +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_write_date +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_write_date +msgid "Last Updated on" +msgstr "آخر تحديث في" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_primary_id +msgid "Main Server" +msgstr "الخادم الرئيسي" + +#. module: cm_entity_sync_odex +#: code:addons/cm_entity_sync_odex/controllers/sync.py:290 +#, python-format +msgid "Message Has been send !" +msgstr "تم ارسال الرساله" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_uuid +msgid "Secret Key" +msgstr "الرمز السري" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_server_key +msgid "Server Key" +msgstr "مفتاح التزامن للسيرفر" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_url +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_server_url +msgid "Server URL" +msgstr "رابط السيرفر" + +#. module: cm_entity_sync_odex +#: code:addons/cm_entity_sync_odex/models/entity.py:165 +#: code:addons/cm_entity_sync_odex/models/entity.py:266 +#: code:addons/cm_entity_sync_odex/models/entity.py:294 +#, python-format +msgid "Sync Error Cannot Syncronize new key to Server {}, URL \"{}\"" +msgstr "مشكلة في التزامن , غير قادر على مزامنة المفتاح الجديد Server {}, URL \"{}\"" + +#. module: cm_entity_sync_odex +#: code:addons/cm_entity_sync_odex/models/entity.py:242 +#, python-format +msgid "Sync Error Cannot send Transaction to server {}" +msgstr "مشكلة تزامن , لا يمكن ارسال المعاملة لمخدم {}" + +#. module: cm_entity_sync_odex +#: code:addons/cm_entity_sync_odex/models/entity.py:150 +#, python-format +msgid "Sync ErrorCannot Syncronize new key to Server {}, URL \"{}\"" +msgstr "مشكلة في التزامن , غير قادر على مزامنة المفتاح الجديد Server {}, URL \"{}\"" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_sync_sync_key +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_wizard_key +msgid "Sync Key" +msgstr "مفتاح التزامن" + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_incoming_transaction_syncronized +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_outgoing_transaction_syncronized +msgid "Syncronized ?" +msgstr "متزامن ؟" + +#. module: cm_entity_sync_odex +#: model:ir.model,name:cm_entity_sync_odex.model_cm_entity +msgid "Transactions Contacts" +msgstr "Transactions Contacts" + +#. module: cm_entity_sync_odex +#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_inter_entity_update_wizard +msgid "Update" +msgstr "تحديث الخوادم" + +#. module: cm_entity_sync_odex +#: code:addons/cm_entity_sync_odex/models/settings.py:63 +#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_sync_config +#, python-format +msgid "Update From ..." +msgstr "تحديث من ..." + +#. module: cm_entity_sync_odex +#: model:ir.model.fields,field_description:cm_entity_sync_odex.field_cm_inter_entity_update_wizard_server_id +msgid "Update Server" +msgstr "خادم التحديث" + +#. module: cm_entity_sync_odex +#: code:addons/cm_entity_sync_odex/models/entity.py:280 +#, python-format +msgid "You cannot change syncronized entity data !" +msgstr "لا يمكنك تعديل بيانات المؤسسات المتزامنة !" + +#. module: cm_entity_sync_odex +#: model:ir.model,name:cm_entity_sync_odex.model_cm_inter_entity_update_wizard +msgid "cm.inter.entity.update.wizard" +msgstr "cm.inter.entity.update.wizard" + +#. module: cm_entity_sync_odex +#: model:ir.model,name:cm_entity_sync_odex.model_cm_inter_entity_wizard +msgid "cm.inter.entity.wizard" +msgstr "cm.inter.entity.wizard" + +#. module: cm_entity_sync_odex +#: model:ir.model,name:cm_entity_sync_odex.model_cm_inter_entity +msgid "cm.inter_entity" +msgstr "cm.inter_entity" + +#. module: cm_entity_sync_odex +#: model:ir.model,name:cm_entity_sync_odex.model_incoming_transaction +msgid "incoming Transaction" +msgstr "معاملات الوارد الخارجي" + +#. module: cm_entity_sync_odex +#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_inter_entity_update_wizard +#: model:ir.ui.view,arch_db:cm_entity_sync_odex.view_cm_inter_entity_wizard +msgid "or" +msgstr "أو" + +#. module: cm_entity_sync_odex +#: model:ir.model,name:cm_entity_sync_odex.model_outgoing_transaction +msgid "outgoing Transaction" +msgstr "معاملات الصادر الخارجي" + +#. module: cm_entity_sync_odex +#: code:addons/cm_entity_sync_odex/controllers/sync.py:291 +#, python-format +msgid "{} ← {}.{}" +msgstr "{} ← {}.{}" + diff --git a/odex25_transactions/cm_entity_sync_odex/models/__init__.py b/odex25_transactions/cm_entity_sync_odex/models/__init__.py new file mode 100644 index 000000000..da014f8d0 --- /dev/null +++ b/odex25_transactions/cm_entity_sync_odex/models/__init__.py @@ -0,0 +1,4 @@ +#-*- coding: utf-8 -*- +from . import entity +from . import settings +from . import outgoing diff --git a/odex25_transactions/cm_entity_sync_odex/models/entity.py b/odex25_transactions/cm_entity_sync_odex/models/entity.py new file mode 100644 index 000000000..44d966d86 --- /dev/null +++ b/odex25_transactions/cm_entity_sync_odex/models/entity.py @@ -0,0 +1,448 @@ +#-*- coding: utf-8 -*- +import logging +import uuid +import requests +# from odoo import _, api, exceptions, fields, models +from odoo import models, api, fields,_ +from odoo.exceptions import Warning,AccessError + + + +_logger = logging.getLogger(__name__) + + +class EntityMatrix(models.Model): + _name = 'cm.inter_entity' + + code = fields.Char(string='Code') + name = fields.Char(string='Description') + url = fields.Char(string='Server URL') + uuid = fields.Char(string='Secret Key') + + @api.model + def generate_key(self): + key = uuid.uuid4() + return str(key) + + @api.model + def broadcast(self, key=None, url=None, new_key=None): + if url.endswith('/'): + url = u'{}{}'.format(url[:-1], '/cm/sync/broadcast') + else: + url = u'{}{}'.format(url, '/cm/sync/broadcast') + code = new_key.split('-')[0] + company_name = self.env.user.company_id.name + new_url = self.env['ir.config_parameter'].sudo( + ).get_param('web.base.url') + new_url = new_url.replace('http://', 'http://') + data = { + 'code': code, + 'name': company_name, + 'url': new_url, + 'key': new_key, + 'auth': key, + } + try: + json = { + 'jsonrpc': '2.0', + 'method': 'call', + 'id': None, + 'params': data, + } + result = requests.post(url, json=json) + r = result.json() + if 'success' not in r.get('result', {}): + _logger.error(r) + return False + entities = r.get('result', {}).get('entities', []) + handle = [] + cm_entity = self.env['cm.entity'].sudo() + for e in entities: + ie = self.sudo().create(e) + if len(e.get('entities', [])): + for ce in e.get('entities', []): + O = ce.copy() + O['inter_entity_id'] = ie.id + cm_entity.create(O) + T = { + 'name': ie.name, + 'inter_entity_code': e['uuid'].split('-')[0], + 'type': 'external', + 'is_inter_entity': True, + 'is_master_entity': True, + 'inter_entity_id': ie.id, + } + cm_entity.with_context(broadcasted=True).create(T) + handle.append((4, ie.id)) + if handle: + sync = self.env['cm.inter_entity.sync'].sudo() + setting = sync.search([], limit=1) + setting.write({ + 'entities': handle, + }) + + except Exception as e: + _logger.error(e) + return False + return True + + @api.model + def add_new(self, arch): + sync = self.env['cm.inter_entity.sync'].sudo() + setting = sync.search([], limit=1) + entities = self.sudo().get_entities() + entity = self.sudo().create(arch) + T = { + 'name': arch['name'], + 'inter_entity_code': arch['uuid'].split('-')[0], + 'type': 'external', + 'is_inter_entity': True, + 'is_master_entity': True, + 'inter_entity_id': entity.id, + } + self.env['cm.entity'].sudo().with_context(broadcasted=True).create(T) + setting.write({ + 'entities': [(4, entity.id)], + }) + return entities + + @api.model + def wrap_jsonrpc(self, data): + return { + 'jsonrpc': '2.0', + 'method': 'call', + 'id': None, + 'params': data, + } + + @api.model + def post(self, url, data): + result = requests.post(url, json=data) + + return result + + @api.model + def is_success(self, result): + r = result.json() or {} + return 'success' in r.get('result', {}) + + @api.model + def get_settings(self): + sync = self.env['cm.inter_entity.sync'].sudo() + setting = sync.search([], limit=1) + return setting + + @api.model + def sync_new_key(self, key): + sync = self.env['cm.inter_entity.sync'].sudo() + setting = sync.search([], limit=1) + SUBURL = u'/cm/sync/new_key' + + for e in setting.entities.filtered(lambda k: k.uuid != setting.sync_key): + data = self.wrap_jsonrpc({ + 'key': key, + 'old': setting.sync_key, + 'auth': e.uuid, + }) + url = u'{}{}'.format(e.url, SUBURL) + result = self.post(url, data) + if not self.is_success(result): + raise Warning(_('Sync Error'u'Cannot Syncronize new key to Server {}, URL "{}"').format(e.name, e.url)) + return True + + @api.model + def update_from(self, server): + setting = self.sudo().get_settings() + SUBURL = u'/cm/sync/update_from' + + data = self.wrap_jsonrpc({ + 'auth': server.uuid, + 'key': setting.sync_key, + }) + url = u'{}{}'.format(server.url, SUBURL) + result = self.post(url, data) + if not self.is_success(result): + raise Warning(_('Sync Error Cannot Syncronize new key to Server {}, URL "{}"').format(server.name, server.url)) + try: + r = result.json() + entities = r.get('result', {}).get('entities', []) + handle = [] + cm_entity = self.env['cm.entity'].sudo() + for e in entities: + exists = setting.entities.filtered(lambda k: k.uuid == e['uuid']) + if len(exists): + exists.write(e) + continue + ie = self.sudo().create(e) + if len(e.get('entities', [])): + for ce in e.get('entities', []): + O = ce.copy() + O['inter_entity_id'] = ie.id + cm_entity.create(O) + try: + T = { + 'name': ie.name, + 'inter_entity_code': e['uuid'].split('-')[0], + 'type': 'external', + 'is_inter_entity': True, + 'is_master_entity': True, + 'inter_entity_id': ie.id, + } + cm_entity.with_context(broadcasted=True).create(T) + except Exception as e: + _logger.error(e) + handle.append((4, ie.id)) + if handle: + sync = self.env['cm.inter_entity.sync'].sudo() + setting = sync.search([], limit=1) + setting.write({ + 'entities': handle, + }) + except Exception as ee: + _logger.error(ee) + return False + return True + + @api.model + def send_transaction(self, trasaction, instance, to_send): + setting = self.sudo().get_settings() + SUBURL = u'/cm/sync/send_transaction' + for e in to_send: + # trasaction['to_ids'] = e.inter_entity_code + from_id = False + K = instance.employee_id + K = K.parent_id + if K.is_inter_entity: + from_id = K + # while True: + # if not len(K.parent_id): + # break + # K = K.parent_id + # if K.is_inter_entity: + # _logger.warning( + # '----ccxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccc---------sendtransaction %s', + # K.is_inter_entity) + # from_id = K + # break + if from_id: + trasaction['from_id'] = from_id.inter_entity_code + else: + trasaction['from_id'] = False + data = self.wrap_jsonrpc({ + 'data': trasaction, + 'key': setting.sync_key, + 'code': e.inter_entity_code, + 'auth': e.sudo().inter_entity_id.uuid, + }) + url = u'{}{}'.format(e.sudo().inter_entity_id.url, SUBURL) + result = self.post(url, data) + # 'http://localhost:8069/cm/sync/send_transaction' + if not self.is_success(result): + _logger.error(result.json()) + raise Warning(_('Sync Error Cannot send Transaction to server {}').format(e.name)) + + @api.model + def sync(self, entities): + raise NotImplementedError('Not NotImplemented !') + + @api.model + def activate(self, arch): + raise NotImplementedError('Not NotImplemented !') + + @api.model + def push_new(self, vals): + """here we have bug""" + setting = self.sudo().get_settings() + SUBURL = u'/cm/sync/push_new' + for e in setting.entities.filtered(lambda k: + k.uuid != setting.sync_key): + data = self.wrap_jsonrpc({ + 'data': vals, + 'auth': e.uuid, + }) + url = u'{}{}'.format(e.url, SUBURL) + result = self.post(url, data) + if not self.is_success(result): + raise Warning(_('Sync Error Cannot Syncronize new key to Server {}, URL "{}"').format(e.name, e.url)) + return True + + @api.model + def clone(self, entity): + raise NotImplementedError('Not NotImplemented !') + + @api.model + def update(self, vals): + setting = self.sudo().get_settings() + if vals['key'] != setting.sync_key: + if not vals.get('broadcasted', False) and not vals.get('dont_appear_in_send', False): + e = AccessError(_('Access Error')) + e.args = ( + _('Access Error'), _('You cannot change syncronized entity data !')) + raise e + else: + return True + SUBURL = u'/cm/sync/update_entity' + for e in setting.entities.filtered(lambda k: + k.uuid != setting.sync_key): + data = self.wrap_jsonrpc({ + 'data': vals, + 'auth': e.uuid, + }) + url = u'{}{}'.format(e.url, SUBURL) + result = self.post(url, data) + if not self.is_success(result): + raise Warning(_('Sync Error Cannot Syncronize new key to Server {}, URL "{}"').format(e.name, e.url)) + return True + + @api.model + def remove(self, vals): + raise NotImplementedError('Not NotImplemented !') + + @api.model + def get_cm_entities(self, e): + entity = self.env['cm.entity'].sudo() + entities = entity.search( + [('is_inter_entity', '=', True), ('inter_entity_id', '=', e.id)]) + result = [] + for ce in entities: + result.append({ + 'inter_entity_code': ce.inter_entity_code, + 'name': ce.name, + 'code': ce.code, + 'type': 'external', + 'is_inter_entity': True, + }) + return result + + @api.model + def get_entities(self): + sync = self.env['cm.inter_entity.sync'].sudo() + setting = sync.search([], limit=1) + data = [] + for e in setting.entities: + if e.id == setting.server_id.id: + cm_entities = self.sudo().get_cm_entities(e) + data.append({ + 'name': e.name, + 'code': e.code, + 'uuid': e.uuid, + 'url': e.url, + 'entities': cm_entities, + }) + return data + + @api.model + def authenticate(self, key): + # add by Fatima 7/5/2020 for clean older code + """to check key of entity before sync using in controller method receive key and return true if right key""" + sync = self.env['cm.inter_entity.sync'].sudo() + setting = sync.search([], limit=1) + try: + if setting.sync_key == key.strip(): + return True + except Exception as e: + return False + return False + + +class Entity(models.Model): + _inherit = 'cm.entity' + + inter_entity_id = fields.Many2one('cm.inter_entity', string='Inter-Entities Ref') + inter_entity_code = fields.Char( + string='Inter-Entities Code') + is_inter_entity = fields.Boolean(string='Is Inter-Entity ?', help=''' + If checked, this entity will be syncronized by other entities in the group. + ''') + is_master_entity = fields.Boolean(string='Is Master-Entity ?', help=''' + If checked, this entity will be syncronized by other entities in the group. + ''') + + @api.model + def name_search(self, name='', args=None, operator='ilike', limit=100): + args = args or [] + if not (name == '' and operator == 'ilike'): + search = self.env['cm.inter_entity'].sudo().search([('name', 'ilike', name)]) + if len(search): + args += ['|', ('inter_entity_id', 'in', search.ids)] + return super(Entity, self).name_search(name=name, args=args, operator=operator, limit=limit) + + def name_get(self): + result = [] + for r in self: + if r.is_inter_entity: + if r.type == 'external': + result.append((r.id, u'{} \u21E6 {}'.format( + r.inter_entity_id.name or u'**', r.name))) + continue + result.append((r.id, r.name)) + return result + + @api.model + def create(self, vals): + setting = self.env['cm.inter_entity'].sudo().get_settings() + if vals.get('type', False) == 'unit' and vals.get('is_inter_entity', False): + if not vals.get('inter_entity_code', False): + vals['inter_entity_id'] = setting.server_id.id + vals['inter_entity_code'] = u'{}-{}'.format(setting.sync_key.split('-')[0] if setting.sync_key else False, + self.env['ir.sequence'].sudo().next_by_code('cm.inter.entity')) + obj = super(Entity, self).create(vals) + IE = self.env['cm.inter_entity'].sudo() + if vals.get('type', False) == 'unit' and vals.get('is_inter_entity', False): + if not self.env.context.get('broadcasted', False): + IE.push_new({ + 'data': vals, + 'key': setting.sync_key, + }) + return obj + + # def unlink(self, cr, uid, ids, context=None): + # return super(Entity, self).unlink(cr, uid, ids, context=context) + + def write(self, vals): + data = {} + values = vals.copy() + is_inter_entity = False + setting = self.env['cm.inter_entity'].sudo().get_settings() + if vals.get('is_inter_entity', False): + values['inter_entity_id'] = setting.server_id.id + values['inter_entity_code'] = u'{}-{}'.format(setting.sync_key.split( + '-')[0], self.env['ir.sequence'].sudo().next_by_code('cm.inter.entity')) + vals['inter_entity_id'] = values['inter_entity_id'] + vals['inter_entity_code'] = values['inter_entity_code'] + is_inter_entity = True + for r in self: + if r.is_inter_entity: + data = { + 'details': {'code': r.inter_entity_code, 'data': vals}, + 'key': r.inter_entity_id.uuid, + 'broadcasted': vals.get('broadcasted', False) + } + if not is_inter_entity: + data['details']['remove'] = True + elif is_inter_entity: + vals1 = r.read([]) + vals1 = vals1[0] + lister = [ + 'name', 'inter_entity_code', + 'is_inter_entity', + ] + vals2, vals3 = {}, {} + for l in lister: + if l in vals1: + vals2[l] = vals1[l] + if l in vals: + vals3[l] = vals[l] + vals2.update(vals3) + if vals2: + code = vals2.get('inter_entity_code', r.inter_entity_code) + data = { + 'details': {'code': code, 'data': vals2, 'is_new': True}, + 'key': setting.sync_key, + 'broadcasted': vals.get('broadcasted', False) + } + u = super(Entity, self).write(values) + if data: + IE = self.env['cm.inter_entity'].sudo() + IE.update(data) + return u diff --git a/odex25_transactions/cm_entity_sync_odex/models/outgoing.py b/odex25_transactions/cm_entity_sync_odex/models/outgoing.py new file mode 100644 index 000000000..2b77fc85e --- /dev/null +++ b/odex25_transactions/cm_entity_sync_odex/models/outgoing.py @@ -0,0 +1,60 @@ +#-*- coding: utf-8 -*- + +import logging +import base64 +from odoo import api, models, fields, _, exceptions + + +_logger = logging.getLogger(__name__) + + +class Transaction(models.Model): + _inherit = 'outgoing.transaction' + + syncronized = fields.Boolean(string='Syncronized ?') + + + def action_draft(self): + super(Transaction, self).action_draft() + to_send = [] + inter_entity = self.env['cm.inter_entity'].sudo() + for r in self: + r.write({ + 'syncronized': True, + }) + for e in r.to_ids: + if e.is_inter_entity: + to_send.append(e) + attachment_rule_data = [] + for attachment in r.attachment_rule_ids: + attachment_rule_data.append({ + 'id': attachment.id if attachment else '', + 'file_save': attachment.file_save.decode('utf-8') if attachment.file_save else '', + 'attachment_filename': u"".join(u'%s'%attachment.attachment_filename) if attachment.attachment_filename else '', + 'outgoing_id': False, + 'incoming_transaction_id': r.id if r else False, + 'internal_id': False, + 'date': attachment.date if attachment.date else '', + 'description': attachment.description if attachment.description else '', + }) + if len(to_send): + trasaction = { + # 'out_date': r.out_date, + 'to_ids': None, + 'type': 'new', + 'subject': r.subject, + 'incoming_number': r.name, + 'incoming_date': r.transaction_date, + 'syncronized': True, + 'body': r.body, + 'attachment_rule_ids': attachment_rule_data, + } + inter_entity.send_transaction(trasaction, r, to_send) + + +class Incoming(models.Model): + _inherit = 'incoming.transaction' + + syncronized = fields.Boolean(string='Syncronized ?') + inter_entity_id = fields.Many2one('cm.inter_entity', string='Inter Entity') + diff --git a/odex25_transactions/cm_entity_sync_odex/models/settings.py b/odex25_transactions/cm_entity_sync_odex/models/settings.py new file mode 100644 index 000000000..aa24733d5 --- /dev/null +++ b/odex25_transactions/cm_entity_sync_odex/models/settings.py @@ -0,0 +1,79 @@ +#-*- coding: utf-8 -*- +'''Doc''' +import logging +from odoo import api, models, fields, _ + + +_logger = logging.getLogger(__name__) + + +class Sync(models.Model): + '''Doc''' + _name = 'cm.inter_entity.sync' + _description = 'Entity Syncronization' + + activated = fields.Boolean(string='Activate Syncronization') + sync_key = fields.Char(string='Sync Key', related='server_id.uuid') + server_id = fields.Many2one('cm.inter_entity', string='Current Server', store=True) + entities = fields.Many2many( + 'cm.inter_entity', 'inter_entity_sync_rel', 'sync_id', 'inter_entity_id') + + important_id = fields.Many2one( + 'cm.transaction.important', string='Default Important Degree') + subject_type_id = fields.Many2one( + 'cm.subject.type', string='Default Transaction Type') + employee_id = fields.Many2one( + 'cm.entity', string='Default Created By') + + def generate_key(self): + '''Doc''' + inter_entity = self.env['cm.inter_entity'].sudo() + for rec in self: + # if not len(rec.entities.filtered(lambda k: k.uuid != rec.sync_key)): + # first time + return { + 'name': _('Generate new Key'), + 'view_type': 'form', + 'view_mode': 'form', + 'res_id': False, + 'res_model': 'cm.inter.entity.wizard', + 'target': 'new', + 'type': 'ir.actions.act_window', + 'context': { + 'default_document_id': rec.id, + 'default_broadcast': True, + }, + } + # k = inter_entity.generate_key() + # synced = inter_entity.sync_new_key(k) + # print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>synced",synced) + # if synced: + # rec.write({ + # 'sync_key': k, + # }) + + def update_from(self): + '''Doc''' + inter_entity = self.env['cm.inter_entity'].sudo() + for rec in self: + if len(rec.entities.filtered(lambda k: k.uuid != rec.sync_key)): + # first time + return { + 'name': _('Update From ...'), + 'view_type': 'form', + 'view_mode': 'form', + 'res_id': False, + 'res_model': 'cm.inter.entity.update.wizard', + 'target': 'new', + 'type': 'ir.actions.act_window', + 'context': { + 'default_document_id': rec.id, + 'default_broadcast': True, + }, + } + k = inter_entity.generate_key() + synced = inter_entity.sync_new_key(k) + if synced: + rec.write({ + 'sync_key': k, + }) diff --git a/odex25_transactions/cm_entity_sync_odex/security/ir.model.access.csv b/odex25_transactions/cm_entity_sync_odex/security/ir.model.access.csv new file mode 100644 index 000000000..1283e91b3 --- /dev/null +++ b/odex25_transactions/cm_entity_sync_odex/security/ir.model.access.csv @@ -0,0 +1,6 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_inter_objects_manager,access_outgoing_inter_objects_manager,model_cm_inter_entity,exp_transaction_documents.group_cm_employee_group,1,1,1,1 +access_inter_objects_reviewer,access_outgoing_inter_objects_reviewer_manager,model_cm_inter_entity,exp_transaction_documents.group_cm_user,1,1,1,1 +access_inter_objects_unit_manager,access_outgoing_inter_objects_unit_manager,model_cm_inter_entity,exp_transaction_documents.group_cm_reviewer,1,1,1,1 +access_inter_objects_dep,access_outgoing_inter_objects_dep,model_cm_inter_entity,exp_transaction_documents.group_cm_department_manager,1,1,1,1 +access_outgoing_inter_objects_exe,access_outgoing_inter_objects_exe,model_cm_inter_entity,exp_transaction_documents.group_cm_executive_manager,1,1,1,1 diff --git a/odex25_transactions/cm_entity_sync_odex/static/description/icon.png b/odex25_transactions/cm_entity_sync_odex/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4141f52daab6a780510b5f4e3dd762511add78fa GIT binary patch literal 32929 zcmcF~Wm6oy`}OYPR(5eM%Ob^Z++~5qi#sjuRw$I>Qrz8Li@UoODee@90)^u4^7QxO z{}G-SnPf7ViJeT6bIui}q9lWZNrnjk0C41F5o!Pc@Lv%KKnMNHX2D_{|1u0mSzTuU z01N+r2?$8fB>7i~_C-!n3T+F7jrE4^4n5Ts0DuDI5aJqc%SZaInPyVw)nzAqT4h=s`$KoWEP{9#b>FtMMiKjot_Wx*&YkY{Ri`FN;5iK=*5JT0YcyrV0H>(JU@ z+M@pTW5LGN%~i(IO3+H{<);U(oX*ZAJ_n2S^0KN2t@&mZL~f&=?PvYDHss2AHNOR$ z%4AT3mTe=!zv}WLK;^t1D~eU+f(;|wwoyv~s8`;ohdHJ9|Gz0~OA&EQwROgwK^dLq zzaiLv`Cp$XZIK*$j}9S~LTh?1#B60(`(whMH%B)Z_;5}XqX}PiWUvGQ0EP?%0s*dy zU@)MpI<768;AMl7+61N0v=5nx-tJhqlF~?=P{Y&Z}Kl7Pc8-fSB~ zTqO)?>eRf+z#O;lPZYE2gN$?*bX-blaF^XB)WBMWa(bRBwrEy$Aa?CUruB;qF_DW& zOJq+#>NJdfWeb`Viui%?Z^JA*DkpD%2-m)YU}*oO(fGXcBu$+$iiKmswOGet^at87 z*q0Ad3Ml_pb1n&U-^u2!$If~CiTiuvaMVDE>fj0v5a~oph;ur)&Yj_c;+!Cc$ZpI^#+x{ab@=I_KbA3~&X2TZ?tkc5SJTV;rTpn4 zPTAoGvgIRzEKcf+0tW!UOAO6Uc75Ki_DSJH&qyBohpGE>KwK{9?#Qy~mtDfOPDQQ- zh3|$kK`x{WE-@*__c$T+YNs3c!P)u)=G2ianqPyOT>QSiSo6=|@@ni|CvnmU+E75Q zd8R)QsM-^VZEZs3_Pa>z>Df?ntmmjl%i1PR&6d?i+|frjA-S@3`{a?z{fNg-oncdb zV7r|(7Y2;)jd7^E`6Ofqj0LHbJ5@Czaf`f#>NEXT60)nE7A*h1YaoGz?!QE)tYC^V z1^?SCV|aIo^jd+A`3uF$8)5dj-n)_#+I|VJikuGX`jfmNc0WcibIcO{tIzRgKmVPP z3Xlal$jhZCp<6;a{efv)#KDYOpNs>Kz>MF43^3RgU7d31;oexV@1OiRR!ZiZsg!gE`FS6F#hKOHKv6o?sDAVZ2n=xJIws&lrRXRxw z5)x2Aof;|-!blq=pRVNjxSQd7UNEoyK`D^P9Yw`5%Vog?8wh|x=l~aCQ485O3k`p{ zHtPQ8}$L-i*!{d=sVl5H7768bTp4t^SrSv-66KfkB z>A|Mr7lXnUmT9_u1~VM4^W^;=cp6Ae6V#!K5~F>P6?fea8;OymKbnYPy}jd0Xll`JbZuZc@sIn!JDl)y;+FMP=e` zXr?*=Dk`AIByE7?{@CHQrlf7;-$2_jtO$7jZmP&hq&%@2NKGt<-8Kkz3J1SAnD zAar(sr9o*qRd#huq#9Gfn)R8VYEG26n?Z=VYy?WpW|#i>0MuYzRDdty^Sk& z`#fq-1~AgKriG*n8I9~-{BB1=r@>;^!TSCXc_-sCS?NvxpX0o?d!^H43o++n{>h1^ zRS4C`Q{ibYmOg)I^v-y<%lNq!u(Afop3J-?RWg+1j|k=e?6ik5bkb~Q`N3afp2%84 z7_K2ZyYv0SKWuORNBW*s!)R{aDZ15mFj6dR>izSnsMTcw4m@VEQzH!nxJIo_dql!+6GOH~O{ zmXoC=QMZJ%0BMaPWT8i2kHW~V z2#jB^YnPW|t$&i8nC4i719g$-a}_^z@4e6^AL&{L{X{0xot!npXdy=)B(b1Zdvh0J z(_0_mCrLc~?-lhmq;>O`z8MV9;@gn%U4Wx%TKS@e5iM$JH z(%!*i@558|Gx9D|fAo$m=oM3^ITlQcf~d)w5F>x_v>l`gfd~ME2xihG&uBrd)>{dS zvsuSf<$Oja0+uoX&|zWd)SNAz*0b`hF5w-;m(41%`(1~} zhmkRC#VOEx6g+8p)#nW!*W>1m8{4Wn;mG9|BzUO~g5oN!GsO*teNNTKVPSzW6q zN>;lp2%BmlDU$QWz95=@@&;82NM z<5E3TEvB#fK1=h9A3e)w=m1FqR=-r-goGmYGM}%VHYk33P*3ppskLR6VX<}Cd=g_{ zvgrgz1ByXCdbZWQO?YirpP0XX`w#i*JGJyq)lQ8N9rh0eHXaT+ydP4rTVGffuzqBO zgXNt^4QI=qhu=7AcN{EQkjhwm-3)LTb0!w?;tV`qy`&D`%Q@e>_4FuG!3qP`cN7?ppk-$<6c#k}8MT;PiZ%g@jzKZ25 zyqm-~YDYRId=+gxt8AyifFskkK7h-b7~?Iuw|4=LTuMF<_Jy;m(JrkRQB`DnZS%KTEV9e`v|qK44tuyz1x7!?q4?E3U@>Y$j# z2Nu~`uwZ?2tJOK8;!){JL^QJCwzmhk%0}^uR zWYO;F-}#DlTzn4)+RjR!`vu@&woT2>em=qQtQ2njz*3yHAIT(k_R>P)?*`aN6T0iC z+ITwEF6R6NNJ^3gsu;&_PRpDuZis2KFhfzA!U^W&tb=U+KIuS==ZxGpIz_eL;~|1d z2FWg2^f&;1JcD5^DfPo`flaM($a8LK^V(4=-ze7EtKa4YAOi1cWa<-PhJ@;N%+DvT zw`)#^YlZZoM!ZU>hrTGt9K6p5+T9ITg-Th3V@rR2AfaQJJkGzmUS=9#jetmd9-a?F zTb9epKQ;8GV@4t+tTp~LJlKzRJB^#V`jXPLW-%(&BAzPkJ`bEm$)3Q%+YhAm}vt3@i*=MPFXBwC^ zK(pgzuX)4!_BpgnP&w=nlL%mgqMvmTi}W>Zu8N&G(F#=p26~SfU&YnsJ#e%xzeHlC z^4|{I@W5UUx97r&ojN>8jAhy7nfS}=@p0C9)@kPQtiE0#hPU-xFdA#U`DmXi1%>|9 zu!6BgWuqs(!!~nLc=ho0&5F=TUOQekuV9i8f95sbE3z2i4r1I~o71~qLcUJE=2i5x&p?rk3p!%& z(Ns+5ueoX?TE`-=HgYlp_^qDlSTEXf{n(5M%p7dsMF>ZHq$dQTPa9UW-3+?FPW%!& zccBYWLc3U3-Ea47#qD1$u_1;?*}!dY+ZWOUG7fOMH$waTCQoUL3Uk4#xh42D^7!F8 zGXoC#U!J{jg^gJ=!U;>c!_m+&1Ix@(+PWDnDqV%p-QPk_)HG1(QeS@r8Eg?1BSTPVv>t{p&3J-1cFKkG^To($V ztQ%VQw5t{mXux2rn?=aX<41$Gitx>IU(wbBoANI%gs~(P8ZqFL1kl%+oovdl zckg|DPi?C^KdH%T$R*ZVRgypfEI=k|ydN*?X@}ll8Y9?*z58)Qj~uRGV>ldbC90cA ziw0}2JzVYY*r>;pnj~b*D}Yw^gS8eZXC6XrWt3~$zC z0$@n+L$ugS=&|TChpjH-ZD|QmREuctbZo!fCUw<*1mc&EeEez1U&?WLwZb=?nj*F8qtR@R2A zMH;c#77?AR9+;~5A-xeSFDRE`#w`CXojl!Ps=nyow)v~TAwqw7y=?*2MZ{cgh zyf-|oCKQYZEllddR~Ft;&sjy5n(O%W8DVztfvfsuAj_Lk*VKkExWEA@e&ZpE?3^x$ zbzmFf)mj`7`bEqAa4?<+J5Ht#gD8RLyB>7!&rp+quVSai9h|q}cK!G~WS1sz$`-eG zoFt|i^mXhgAmND;$MEd{k^#Q(&4F6+o43Y)Bx?6Eox3~_t9|qp-Nv^uSv&1+snJfF z#_;rGmn{~s(&nyk6018N9$w#Pp)kO)0qp-J8|Fj@4!A^Nl)?=MDRk=?d@6rtp$L54 z``vEZ(N6U(dtJPFp^fa1u-cBfV8s{9XnUP~(ff_gqFeE=>)_yf>;CWco@p7M+V-Z0 zvcI+*%W5Zt60nGrI#240W~oU1fMFPYWP_aOUD`9hYsmfcrbp5B$@m1Wr!+pyLzeo1 z6@^4fkmc;}W$JfjklWb0CdXaCB}1_cZGZfioL_akRmG{6!db+nkb}5B@*HA+Y#QxB z&YFfC-*rM|(fh&~4}*0R36tb(?yVZh8x>4;g*V(tGQ=vV@viITUbl5QhlNn14@iuA zF(C9%XZAo_zxy_czZIT3p+qBASK2vHEQ}1{k-wxkeVl_OvCP~zCzkt)Qr4U3=$PJ3 zQ%{c@jWZ_f)X1BKbDy8AiN(&Q5&%65pv3a%sIdPSh-Ck2YU%vhTocs~#AGZ|0WSZK zZGw@+X;fS#-#==vb81K@`_wcoD`z(Sct&c2^N5=nAWMG6O=y8goW|X;W4j3X;b!GE z`3X2~9Jb)ZA#r^ik=SV}m>LYx6*l}&zuBiWoq}$3K~6>cQOz>*Yj1|SWt`eV{AqgS zUMv_;(Y1^zL)EpBnKoM=mNp4J#Qej&qDXaJUMU)T#3~?U;g~ixa z@~s=3NRA#Cv0l{_uz_yh)7BX`#x$;P?+rg8!Q*L_f-zH%jJqL5(Y`@!5^iCI0xJ zj)X$=_O)>JcO4S85c?@oU&KcUT2G8hTIx_7=Z}68{Yhfw**Wv9tn_C^g?8e{bYeWXWA&VN>~54#EEi==bgZ$IR}R1CX1Wre$Iiw3&p@961c zQ3g@H)x+Uo4g8YZqy@u`mmZMn((L%IE~CSU@RNuae)_?M6cBJ&S~w6B+uy;O3iy;?U6Pk%n>D&#$)w~d+<2|3s@{EabV<63;g+9ue3(s?_H-~R6C zewQ+&)wm`OvPGDj)iJu){Itc>thk>}yYTx-;oG?FBCAr)wC|q&?dfyUB-1eFwWD3s z6GOhvCUN&uQYqB0Zg{`DA`&D}v6hkFt@TPV+;g^XL9u^oXgnZixN048p03IHT`hFt zLWc!*Yp0wp*a! zv~ScWA8Ty_z-JErMi1P~D@x8hi>f}h=bsN`$Mm7T%>xdTFyd-P^FLg9aHu7kHFA> z$Q_#cRzMEUxV$E>7mgY@j#I`?cV_J$}3TW!qklagUapfG!De;iS+&>C$tuo9Be@ zTpbM2p;O<;@_bkl%U=0Fs-WjzX>QDa9yn_`MlmP%&RP)zGb~m`0uH53gxZ)jl&BCA zlpM*;FfhDVo07+8^7p5I9~-Ayz{Efe#Cs3MCoqA22j!uvz{Bc{7IhuQ6O^Alia61Y zh8RPs8bPvA1P^_3hLS||9wLG}tX~QaD1DoTX<`oCB{D^?TJl3-8+L!c^fYF>FGX3I zcuQLR`hL`v_4<^@$;CxYCatlob8>X_a*yNNv3HB>H?yEdv-MBq!IZ0f$=khIwyu|V z=Y`TL_61@4K?%{&eZAJQBrCA7k#F8Rp;>kg^70@K`V^{t?3V$ID1rW|dJ1q_bS+tx z0txAc5;!B&1c7P-qsN1Z)v5!WfECV4E@L)b@RLr}3!Buk*Ky5>f9D;xWxrkeY!$bn%vaung#=!v zO6P*W@++5$_$CFm){DjN`+#w2Yq;bo2@uG;;cx1DoHymcT%|R;Mk+(l0k|( zEOzf~xL(NJ7u7#K0$po_M!|TQ`f5aCD6G=O%ZQX4+d^V*hq=1r<+j^5mvbjQs^~=c zTO@X*QGkoqbDt$23I%q?xAa&jKGPWKrb6}IF5Guu?)2T)Re3um#}gDWx4#>+E;GHn z*JDUkQtT|8w>F#67_31K7tu}6CE;Tm=4iq!?Phzf{|T1r#7l^GD#OywSAc(hPGzNd zmKbMV%@CRLsAhqXldz0;!1^smK|0$AO-e3f3$>A3Z}$&-cU!Ow4d*{ zyWpHWaiASDtIN`@kIyA*H|$5;V;D-3W83}U;Zf(|*M;RjyJ%DBdJ5d-zGvZ7t8@R* zZ^8c7fDj@}fFEcUcNTi6c93a4dfAPqdgk2a9jZ!U9yVYy>GC2Y}+7Ym7-?Ivlr zJse;$CyByowsShatI7#`^b#vGlO}(C08O^(|EH>m5RJfQkVOuZ7?X|Mr;wE<$RB%G z>5=r_3>Y~4`LVsf0-XUR91cNJ$tTrK%$0^hXvOP7i699-KxW;{IP&eTpZ7RGCHS{& zg*@A5Lq-T{V?6p=qa^u6rC0(e^?Lw}eq~|Jd&Pn3ar+q;3qVc^RDsK*I|lG*t+_u& zdF)NVHNqmhg+`X=|Ac8e+$1@4KEBk6+oJU@v#>WUq!R%C>$oa=SKOg1-xe5xV1m-2 zgtGjI*Wk#UdK(m$UPH?vmY92z`36$kGq%blp5@Ue3X7*b4qrBUQtab>&I-&K>d*=io6?cmA&7-dA>fB$Wr5) zMUnH{s1kdiF>C8P@4Y;F`$)urOI;oJ5B?DnoBgjgIa8G3E?pS3PF9ymJM)&SM!~^f z7golTQV#FeZzr@+P_1l;FGx6h^Xw2JQN{zlYj9pp&*=ooU4a#^uk}B(=wizl%Sef6 z8lmB0a-vxz2Ilb{u?tL!B_^Di-d?XO)~Gb{FhFvMG?#8t7{TyDh6B5`)1-3Mt9Pk} zjh3(q1Wf;&^OvjYlc z=3@~5Q`;MBC@j@aVE9V%f6qhei6ov^Xhrl<17%o<@_}#hbY-x zThjYKFF?3@@pUpY%1_WaQ=@l4*-EDJhlH0~H`R5GAV#Q#bZ^*NQMIr4>(2xs;<<4u zZ+e}B-@7hc?Z#o^`t`@J>9k?y5q{f-&{madrufv8_MtZ`J~rNQd4Hz3&G_DYqb?=U zab9zIg5x7-i=es6K_5Q^g}jPrCf?fQvv`(pbw!sK3$>o*t80HSPYW~>SEMSq_Yof= z=-2$~R4!+tQ;~v#C)d3CP)!^tq4AGtS)ibxsAwv-xMje;zYxzN zK4KZ;00OCv6AxWdev)jrZC(FX+e=n*uhkyMKD#3zXT6#Nicwg;ApM zprF)-M&g@a?uV6PH(L#>qcD%BJvA7ajnCpz}E z^xA0W>CO$i)iBYU!oZ?t*Fi$<%&x76L#y}bm{?O6Q79-Q7@zNE?GvlOf*bcJjXQy= zl~x}-Z~yZ-KU9OL5MZ}=&mUFK0iMzVS@tW792~I5O9#rKoa|~$h~rS zEMvaVux3Rd^8NfJ7Qhje8-=yI1gg#S9}HnMJMw15q4Vhie`&&Woq_AL_OQtwpMLdr zYL<|Zds2u1s_~2zK<;pHPMq!gCekm%G{U813KmQ^T#Ey5{5Zhnr(+v77l`rDp7L>S zP2VX&hxn*UC>)WB4(qx&utj_O#X_c$s%KH5E&M)~nQoc+uyIn7S9iX-Btb%UfP|o~ z5Ke(BC5_k;o|cvqkBIyvn{EDX%BQ__9fNdXC{nc5Ln(rUcJWDhs33Mrf+c*I|6-8L zNeBhN@?MsO5l)C>=5($0!e!Y9B!Vxm?61}-Fz|!_)fG>SQpZIk}F-Si4|wvaj2KYqD+`QV$!p_rt0B>l0lG z5$&R|VKW88RiRBCGCIf{D8ZD+lq)f}@1y3Q3bujcydV3K2&NAuQ>CE~#fY8Uf?lx|pA3mh)2kX_t`lsAVkth;7B8_Fmc+ zCn+SI8BbOaQn~m%+$Je0sgsaUO8>Ep+^tJ+v|YqqiMw)sX^%qevk7o@>NE)GLlSj) zidOjWP+aEd>BU7~fV1Z%mA>7qz&9EfD~m^f0Ew%@PsAf>i%JPD5yzRIAN$!EVQ}bxS`Z-+5lPqAY}X+M8y<{MD^c&Oga!Q zQ3QuDo6W>BsG1Sh!nEQ+81Ya}SbzjA5TztemOvLJIX1~8Dw)6vMNb#Su5m_E(s6%l zuS3A)>p(h0@PG%B%anxadDL>PMef_e$xRIA;iZmx)tdbK ze-6|v(U6^OA42LqD`gM+GMChSJ?2{vD_Zp!8L4S&9LMy@W@ClVr|mTtY)4Wn8|C8p zi%V1u9S9We1;q{N2{o-A-c_0dsc93w`zYY-rJJ<{?&Nday7yUdXycQCoCirv>q-?T zsKzHS(%hYU{na)6>`pqA9|E1RpU}Scht+SCU*Qju6eT?h50d0IJ>QC5MDZ1mb|5c% z2d=r^k0obRy=%(kRahy{1*E#Mn2Us;DjIK2 z-%jXVQ^veabq;7RH)_HpoS96+Ui$NtAxMYo;68k|D@XVA;SrDVc0sFUPV|0+xhjLp z)oRDMZbGWT+C77n?`g_O-wrjM5srh|RG z5S0!KfYnR=&k*OkmhU{qBzQQjlCY`z6S)JAsF$(noo_Xf3)&wLNTy}8U3M)F22!usZ!!Mc{X*%m zu)N@SU-DMZdEWe^%wkH&1xN02Ju(UbM|X zAOI%P5T{v3%78%IH<8O8t8X^vIqi7flyc;krEW3z_*Vql#}kYs?M%^3qzbt9)EGBK z<-QFRZQTNvr?P!aI>Pj0SM{H*0l^EzTO0Y|} zn0QPIUWdk1cfZm5qN(<}CIl~eo~9kVjpK@@$hH!N(_$K1n(`AtS4HZgXY|Yjj|y<@ z-4PN8^$+u58@ihByXHf-VkbJO#U2M4d}O7(%n)OBV|V6D$I`Hd|3kDiv<&I@7xC)t@jlfl%0k!qq+Acu47BG|bsD+VM;&Xg6~ar)FBX{Lgxo~o_Q$qW zmvIg878_N|)Q~ks00~K^_XuCis#WJJu!3dm5^WG3aq*H|9!WyYbS4_GSLL7UDI$n! z^JsnH2H9a!?uYkL{e=`dUP<3+6YqQG|2=D%9*g!mncYQu_Px~fTbF^sn9ZdItY^_~ zmJb~fPAsZ46`V$%ADrfZo-FhF?-egeCiR5@p>k?EwpoqR{G5uj7gJLL8xMn)O)sgx zsDUV0=VTwS{Tf|4FgYZL_%go{2G{2yJj#it$^Xi(X&i$AZ;NeBO5%vthUG62@H?A8!_?0!YEN z>)BBc5ey&J{c@^}@Uk<$fyO|0ztQ-{TLt;ASnbCA45)N*jgjWpNd=VUDU_1xQ3$eM z6Y?mKYbxw19EeUY^POb3xG z^V79W7qq{r9m;t;)i#jii3bs&13vc!&h$QdTMrNlvg$?1Y5acso#v0HPmhl7r+Y$e zgL}!Ok=1_O*NfMaYZNo6jpX~64}(h4_Bnl-+{kYo6;D6XoC24;1 zx8LDQMaO)g6fh>47WGR(@@0)-g-VK`5!ng-TG~0phID`sv7=|V;a&V1O#X?Qq}ELu z9gq}!6a72I^=_;XLkdJQPS`=sj^8Hub@}tk@{%0PwmqkS3fUN{#ApEeHCs!etCAu9udq& z?84sQo+&>*E-$PmT?S1X^>>+W*b0Km)=sg95&v~^dfs@tE6vC@?`=C#{UTA9o6Y#t zvHiEW7|N8<+tOjh1i#yr!FQVP+;_2FIE?=prJ_N6l`^ntk=l8&H#r%OJqm+ubh05? z7yKPoHNro3F`i)avhNh7MgW(Yzsa4SL3{OqUC#DMYtH|R#2Yd<8mO;vfFZa}pf@_xV3nOzS zyFhtG)nTxpV=6NSJ+8>Z9INZI@o*c^xq2D67qcX95t-1o;qX~}VDq!yVrM^7ZH87p-CaK+U* zp9yNV2Gh%iACjBFNt4P?Z$>YkPIZN#M!o;Ukq~DxT5z_-Y0~_Z&~z&0I-NCd8GUt z7a3D-6D6GZA%ZO0Q-&D!55265MTD5m%x_#INGF6Y;ymU)Y`gFe8_-NU)=Gz(>=yS1 zcZawrs*DnFMq)vNdAzc+@IQ6l%M^|T3Y#>$kxt>!`L>?M**e?@sEPo}pu6AYu(4L; zcL#_Krb7E9bkB280UAUc)CVtr!uI}YzyBObhc=?ja9%1vpulLuToLMsC5G1%+1efW zyaF?!V7GQZ*bO!MTX*OdmgI70db3R5lD9F5Cl?zYQg?JpNPwR3WP zJs(M5J;*U4ecv+ttUwOVNivK&?91)9vCD>KdB!XN|UG z<~e9xd-y)?)yCLTf*bc=`~eC$l85Ev97=2+mA?CnJTog}!Pz#?Ok|q#WalPY>X*J@ zx%PV&1_l=7yD71^S65-N<7j9AM^kh;Mq6yy4Q@}$Ex(ab=yBiponWw9XwAKtGH|DG z!zEg}-S?PYB_UT+J}mG8^R0ClW>P=d%+z{FkMCTNPP2LOCn*)$T*!TSPVL?|#v+aM z@7esk6q97Z@H|_MjF0tWrC1`%%SZOj`uaBgYSd|bm}qA)Avqmq7q)H5AAeeArEAzb zpi~N9-z8Am+sCzHto-l}pJK0QxzH0jZP>V+>`wpwSArZjQVCe5W?LCHm=Sz4kGosx zs!;feS3pc)h?3L<(U|)#$h=UsQ;|R0#VmP7xDWr&Twk=A*c*YlBCmc+9|jf8@(`ro zV?1RN<$$Jw0=Ef)A?jpt7C2|jTzF4;b?42Yn8rcfBA2uM-0Lb3MM&_a2Xv%UG&HZPAszJC%7Np4`jm?L#o7QFVH?7kukFz0>E66&cruY%AU-fE>x?|5q(4w$A$ zP&;#c4rGl~`J>7AszMxNlW6fqJg<%J3q!G*6G z#)2PSgEcu^q?k5HHXDmR>9Owc|D06~@|5aQ7$rW~c^p4%iWFxJbGR#oeS1?7bms4- zkF&%fK}nyVl>E2rFR}J}gEsYdHfFf%$0d_pS2@g8okdf%1kt{pTW8Jm(6}alpR4H* ztZ<4b7Kj|!Tio73dJO`Gnp8BnvOEV(o?hqhZOF~evAqxbUAq7>ep`Ioyj0)2s~-np zyLDu&bKEiX_&X_^QpPlVG%RnkUzMxZO6g*K4-k1(^f#>Goh19vSawW93qtJu3XIk# z#1+p`iuR-N?W?N7u*`DD-U9nW(p=vy`o3J|*nVnVq!l63fGJ)))(b^EO%A433Hi6^DrvAW+3&K!B74I&BFYj!Y*c#sQ7+#4=Mg=?Mj?!Z3AY;TSf| zCEP$@M576^ZtOQ?LQJ|)o3M$UkPQ*{pXT)Mg1+|g+C<)xTi70}Pj=h|9G(E#=&{Wd z@olnHzby=Z&zCZAyJ*ED?9JCf9v#jP%hfa9bv`y$OyRR3V=OR}0*&@Cf^KhC)RkV> z4;>U0T3O=Rurb+#4b+Nc8Jm&Rc8Eem<<{~@Tp*oH=@azFud93i^aCJ@6o=&!0PRYk zznY8F2N^)~TTc~^fP;Iqu+$Yk*HiDWy7|RX!oM|;y5GD5*OgOIsa*;jzE{S95EhS}BV(cO zH7Iyfv`l!KcjwPNBR*2rZgrvL6G8$jB-*JrKe2+wQh6M&8=F&FancF-EpCS$ODm7h zWvHCT?NsG|7@LT8oZku-VqEzKtqx-&5Jek@JpW$&y}M%k)x|X5P{z}wOzUy3g|~(4 zNIBhjFCJ}yJ~%xLj5X+FsQpGi78@;{S%aUQNT#^?=&ksNxHhnN%^@!?LL&!UO@bjooM= z$ReKT=z^ZPAW(&9kG0y35tYT}*)5eQ7YJk_ZESCIWI648>EwgOIdo{jIfKqEE2LR8F*z8KOPmPN{r|`xIr@{n2D${(-d6YZ>e@J zBR}i@`(JFd>|f+u*MItMZ8n7tV^DrNTC56WSNy3IoxMm2ROm(ug zpS|Zs`qUR%t{Z+}FH*Lp_g`N-)!LGKI47*Gk;zzPAmvqL+wVE%9{N#PQT!W4vNk0e zk$gpQum9Ev)o0p=dyg?Nx1(fGWh3Rl&VX-s5&^PG1JZBMKV=q-eU3>nXi=8?W(W{# z^rj1gk2jK?YD`?XAjL!inV=~Y+uGc5yix05Kb?P4yGTt*MKMeCam4nMw*6Wkh{2D0 zUFrwA9mjN!LgLjH+K~o>Q(mmsUI+dJ|DKaAk6N!uSuj=_^ays5r=NNjtXFo{mfB~4?_E?#xfbU<=UUEiXzL-4$8T1mmgCh z8dl%(;BN}gvwWztD*prFgpt@_&OwzDq!QHP2sz^zw5`53N_+_vW9bur)t6O) zLIgT%Xa*8k&qLd4zu0ww5*MXWgG|LT z6~;6L$jAISc8eM#w6)5&k!@iw#qu9Q2)?$X(1p)8f{GZD{A48`RZRFpv#V*Hg#6-l zZh*@F&GwkoXCY<%$b63r!8Ku=)M$2)m%T>uxY^9h^@5>ycl8M`*=-gwOZkVBhuI@> zG;;2rXDLaj>`Ynpk9*A@zb=`}++_}?@+^LI?)LtAa+pzu9@w}eNEIyLeR!>a5R%rf z{vJ$P=YbVIFq6pWU~qf6!c@xsD@YQEtP-1e!Hr4%`%u4!K`egpdWt=8l|K$$uz93= zwUO+x`O<-4q98^mtPeY2a#DtCymLByxjnZjjX$3ib9dbvuM)o|Am?dEMp=qPc;uAag+?wZu(h7X!IO#u!({rS>*Uv?}g_)$bdYkb*qr#UB$JP^7g?`Z~}VBdYk8XJc#i1GAC_A_}>5DT@h4B z(8qYr{-U`^ZmmIasQ+4{#ZBw@M&YMq>KN4@FU6D(p~H+4GzU#suUrR&O$%)gS!cUl zDO4t1$y-38?Aw7wbaX$Cp6?wKdd!(FgVTD9;J!icwo>$ZMbhe)lP1?kL7ZRg)yX}>)--WD7~ayp~ARqQy-~6`{VKRvR&l4+MpoNJLl^y#U;s1F7Jb#GdFRyH%^_VPuYG3>MF6Rq+ zMr$baV|d`Ne!o0Bz`vk_<^l1kt*kwZ%EKK7wa~k>{z*#rA3vS{yt%jo+ePJ(u>H;n zM+Hiif^lPl1H`Fi&WMtgLtN+^x!%{VhpL^W4YMo!zuL~Jxw0-=!`VqXHahHB9ox>1 zZQK50+eyc^Z5thS+#P$zwz+e1an4UT*K4k-xvEx;Iq<&EG#pu`G-G<8#i_Ji8Nx&E zLW;jnX%~TJGJ#z(@EJ+&_sS@Hm2doqY*Ci~{{E=#SLEt5zd;0)V^8$~@!SUrbal&W zAy^uKwE!L3Y1ZLWUdiFd?5n z+oMF~xXlZ8`RwapwB=kedXQ!0l^=kd?bhq;@BcEPb{{-c_98_&Fsd8Dhcj}Y4O4cl z&!aB5lX2FbH?AufzO4oQd?F`Z$X?P*xBoc-=A4LF5P!_jrf5yu%H?rAZ?v58v>f%F zMg5yW9~~Je9FpjmDgV%HfG@4iF7(5OM{I~}*ms88tbZbZ;;2xv!DYw)qO!H8&ufah zi&&l32Bz>gn5Vjy^<)?m#R-Cjz09J`WTXt}I$d`pM^T@5nO z`l_!xz+2Quv}FA{h zQOOvJ6GrByjAEe?T_k7`&@+}hI7{`bxA*F@`-&0A&{@LA$ES^tBM(+4p-6_Ya~J2+ z`()EXr8t#^v>__fXCbJ&wrPSk7L&=h_E>NDJLZHK z9E|tJ&D0O|6?}n10UMQGWso+-dZ+igyJbeAy)9MtJ$+W%nW=+%s-)Q5Md(;|y19K)wAHf2wq5 z?z`T8v5dEJf!@|y43tJ*7T0v!F)738u+|GR$A~&-BQ*3zO|glUV41}f(1$PIQuW>6 z-@j8`SV|Ptmrd=WooBk9ioGtBI{)3!q(>RM9IhuN|B~<%r!r=thMjTNCw%tnJwct zh5Yt+-dNcJVG0sEknCiDnjhy&?G`i2G!r@vHa#Q#R(K*TQo#q9C~Kv?BqbcvlHk9_ zO~|zf-vJ&g7BL}@A5%3v^9fji&K~s+_t+2cp@Ot(t8HQsYt#!H0zVWwbs*b-&lA=2 z@jQomBGbej`JPjMg&F3#_AL+M(EP$7kMvWls?wkK2;?>6h4V=0<1EEr6|pZB+!FH} zPDx!)fwCUM%&a@l?ibm%<%c^UT^bhC}n&zf>XnL!K=bl|B$cKLvD?0wj}8OxW~ zdJcqdQeK8M|H*r64l?FZ)58BD!CA=h;L|vH^6Ci+10=qnn$9bw6qEI=O(YvXR4Z)Y zhKCnr)$-SiU{$N34z#d()c3mc?ibY4G%+@_-KOH>w`hXzm#E8nVi&d+g8u!9y3hS@ z*uUD}O1qS%sp(E1P-R-YpHbZBJ-p+Ch{~#@c7R>BGZZEA&kaQvW$&436Y$lKGUmbtY^>Kzr;D7jf?5DQSHC#fnbXDm1Jh&CM9%oBA&kG{JGTrvz z3I|`6={OdMl*xl19vi2DA0Evr5}90EsDWHtFJm|c`QlZ`tDKI`=R!h8C4k zZSXqOVB*QPp7nJ1=fSvj4cf8^I_g4s_{3@ceD^#>iY(`(SyVG4E)CbY#|gTtJnspQ zlp?1sKvgzG3}q3!Jh>%r5o#n1XE-@?QBTd%8mjeu^iJ!fdOUFI1O3y%Y;x%D;4-B6 zvow}tsIdKGDO$$A5-44Vn?x~`jpW*I8st+KO(cUb=#FpGeu}-%X-n`yK{v$MSu*zT2OdZHr^e=fqhIaFHZRGu_2*@2duQ927_ZH>^R+i{5YT&7 zX!%aDN>%gK4*O2m{IqJG9q;RE4{>B^W3@|0i}oGuWjGn-^Iju=y9G&@OuA$C$VD)= zO(|bI_SEEbyID7@4%G+t^D{iwmO_D}w(u zF$BxKESxRTH)s0?NP@++j||_Ytd%!GArMxmd3sDy=)p?1QdX%S2R!zjN~goE-Zq1qk-sP#R;+)EC_el-9|*}y#{Q#T z2*y)*8l(_9`sbd6@qOoWk)s* z45W+n$xglDBN`%b1U7PucuaOyk#uX5ZjG)`^52F}%88Om(6JL;i>t>W2Ew7Qdfu1< z{GKU`I3X&3^*>OGKuV;nHXji-oTcTjxe7o_p`js?2FPJ*{_CYQ2ABx!;UI0%~KBI&m_5I9*f z;G%jo!>eeLVw8Ckyx#wDLaazFJ;&Y;qM=hs`dzpezvA`ruoMzzefk}Pq>u%wJjegp zJ%2TH-X91%8g(UOf2_y;2jNJb8oF4$K!+hSpn2u?r_2+vqnY`4&UYwv& za(r#95ri~}#Y}Y5?LXX&uD!)U>tW-SZ3+fkjkX-DZes7_Ou7KqkAVa{Wa+&(Xr)T` zPQ@$CIzqXB@C0EJgvlbtSpWWrniaddT$@`hpDCP7zS-@tg@i!)Ts({v_xl$}b#^(% zs;$F9v~T%=^1(M|D(6Zj+52uJ5CwIAE!(xP*mP@|lyF~M7$YemfJ&k?kf^y%YfjmA zO@+uSeL2&&Wz@I&`Y>!&!SL%x#ds%$M>#KZp&D}~e_zUlgq+7Ig{stO?-T*7STryK zVz5-9ti=tj4mggX=Mp@jzHrJobMTnsq>PnAh58b zl14R%h3T0EANONW`QNWp3NbT~m5Pa?UXEX&Sc_Ovf7fzpn@`Gfq1B-=hBhxdt$eQx z9@u7)ymEtL5JH^=>hAa`}iphSJl+H$_3hm?;k=DxH#|e^ZtG`wtIW{CBLlnwlBtsXa<#qtfU&pdNbLjc+5Ps|d(zh_ji%fsI89Cb z+PC@9ca+1cUVd6xUe?OtrEa47dn+!`6M1$YY5km5wzO;KFEj0K)w#d*`d1Jfhkn}n zJkJOFwrc_iPhqJaoj)taU-YaAdgu)LMHMmlJ{AeP$l3dNw}c>R+if@hn-1KIY>{n+ z(Llqa)cvhd%IvcgD%@(VRRw8a+*MPD?Popvdk!O5?fDM zv4gd+dq6*^L=bwIoo>)%wd3jrRaG~Lr`jAbP)DG5pr*uvwV1!wn&kPXfvyIb@#9g^ z9~=V$Xq-YFJ{AxKMvN&|$x7_H5krfZn`^cwRyi=K|9Gs7gZjnI_G{pEY}WALGq&Xy zc6$@AiykN35WONcaG_&xfHZ>sd61IWqfe{(yXCN%XKO!r(>|WR`8Sn8QTSqM3rx0X z-Ce=RJjiv>_N%i+nsUvG1CxjhML>1Wmj8Txf3jDYSiiQmn}g&2+eAJ8mA1OnWWTzy zoX%;`Mpngd3NdL~2z=8j^!%?r1M@+SJ$|$4=R!)c8tu&~g{hrab3A!ccw{U~xUAaP zkaiu~vf^-NoejrID^3pwXIvewDH5CTLH>4!pYF>HdxO^_X;=jWsJ^(Pf z^i59cLKQtrL6kBlI0l>{4vU?~Q+88Yc4PfI`74`HOULs@8`Lk!E3*Fo?#(icn~(Xz0hQQIlhdFT;y>RZ`B0fcD)g8 zrO1?4!No?LNb)S9Khgc&5oD2RSu}MxJTQg;L`C`xRe#U_Z&!I3-RN=6_QRGaR$T<0 zl>f?*NxRotR!{RVha4rmHW~p_F!hZy<H1 z(A`w>*27GInuuHO-wZ5aifBJ)iwX(}?YzZF`Li)N_wIyAC}r&93f{YmDzXQE53VPk z@Zg{S_!HgTkhPLAZq+}ms@|pWWqxbuikF?{{SMZV=dw9P0F*#tRG4M6Aqhi~-Embx zl#*8ifi2Cm`Y+9f=#atckGR^VYMWQ(O=Wb|DasB+Ri|{tqm&T!NPKdTBv6#tENQ(i zf8Vne1e_*P#)pEpO>Gml?`a@CmE%BzI<-o5eBLpL5YPyO8Q4NK<8 z=pHIIa$mj&i!v-gwII%P(&CmH4Pk%K^4XPkNd6+MDm`bXA2V=oB z5qz2(O)!^$vkZdt3M_!xpV+>JOz>p6gFv?aGpP>OphUD)%d>IBFD!Rk^S=PSRH=sYJ9Qp~K}0+CZ3chNXjAs?>1rB6 zkwPb_0SFZ6lr^!dp(Y&6asW_2;SWXDD34Q))K7wM%6^KLvsi(V1>%9EkQgeIjDT%u ztfOm#8yO`Ctr1KS9%!{4nSTxmfAY{%uDTm&#jw8xhG8L;^;Quu!g@tTCO{$Ws^uc2 zOJ`z<$SJT@ktJ53d6_`|sw&4Rj9f(%Tfo#4j>1!=LVm;^SYr`{kBS5^1Sh|pLPkkp z@z_FPn*@(RBr8ipUT=LfjfXZa~J`Fre(GF>uMx|qZ&MLAReRy9)$sF53gtS{m+x1m@8?%#z$PAZ_U~5b{`Ws zeZ(uShM#R9{ilFrDtX_388n|32Su~K)3!gU@dj&V(8snw z|Hu7E`sQ;vfe7=|vi`@%VOg0zHVMj2x-$p9z|HWQV!$QA2NXu=>W%$-YrP(~zaF9| zG4_Da%kXLQ=Yc3rne$7Ytl%ec49-lz86Su^L+*1X?@I6SfgDA@iHT8ZBRw5c(REqG8&ALgC_i=+1QuNGWs?MU_9Rec zQab-@6HLd>CnkhI`YfFREUs)DuPaGTLT6j6s!o}S4a0Jsi%YCRiVu`vOf%GCCK>Y* zszIC_7PQ)9G*c3>V-*02%NA=Zqy+xpkpIBF?(cey|KdRSQLQIQNhHm-wzfE4Y^?DL znvYf_w+6B1(U7I3Ib8^5D%?Af!7&upx@DE7C@WAQqXDp}U7kb%CM#9>tZwg7^?Vab zbFzg3+47Lo#83D`B8;GPnNmQ?jCTUdFD6vBdLLhbMZ*lWLDIN~SN(os(>^YI7E&@= z+L99W47hK=;eKw{pLH|$i;LBm@d2^$&7%IkF57y)wTzgUu@RI=Fyyo5{CA_tlSQhu z&Y}Jr2=0`I&#YBRL{<{5w`#?p4WeE&Mh*o6DCPsm=j67Z~&Vm5fCn4v<QkF&PZg)l}wsW%)fU)tS3{HcbqY+c` zQ2fqC7TrYW=a2UtCX5xi*Kl;e>L;W@9S%#G=VPa1Y-3Awpgeq89PRsugQ5dMg)qQ0 zxD=LNr^SpaB?Bvo&tZggjOdOQn@j?if^Ko`rjfd@eG5Ej-wt}ny?P%Gmo~8#{;}6g z4F21lPM`P9IXpz*1~@S(M5RP(LFNR>noKSKzP)Oh1P55cH$6T_1t)XkqKMk|;>0PQ z9hAA0n(Q|6Xz_5iSnsvf%>?O@-fo4!8DW#gks78)WZ!`MonAZ*R>y-(hHNGG;g#U?S~EZA6ytoV|VR zSFkB!=`e$ayM5`gTk9|{2>5RRn@2(l-m4g2)6=U7OT_$B95E}4wFrZpWx37|Jf^wz z-?}}jMH9nBp59Gsz2JEbYEGs?5L!x$lLt&?Xd9Ubo`nS57oRYXq=AgpbZxa z8ic|XRt4T_U5=D>5<=pyDP*D_N2!wwrc%-JI@gH*@da22G(RE^az}iDvr7 zn5VMI%w|ifd5<3RJu_GiF$N=2Ya{N$kGON2zd^JWZo0yfI5~HdpSj&?B(O}h&DERtYjkdGN z_i^zt3tRkz%p*NLMkBv$a;@pd)*k*x3Iw~tq-nw z%44zbkE;2O#`<{F|2+T0L+Em6jDzcA+b5qoTUo`5qUzIWhf8Oa>*)6K-39cel3_ny z!7?fcxTY5B#MmZ*(}oHr)hex_4T%OS{U;UVc~?yQamyje*bEcJoQS|C8pZtzg#HEu zn4|dp6Bp`xUp52}j_IQZybk3ClVnP<5CkXE!mB2Zowafn;cqu1C2~ zUrlN%0%+O^EDZX_n4f>)s_1u-e%^k2nep(yeqai~Fqc?Se)L}3{BpOY>wCXEEQ4$q zSWnIum;Kri#N;c@XpzK-sZ4Bc=iL8bg+>7fD^=G{*J)dF+hahtnb&HB0m#HlZ2p9AF{6hFr*ypE8tQvo z$VZt~vmpF=e?e5_I~aC5^X9bc@cT1$*6`D;EbZ`c2vrEe%;cR3F!Cqgc_K3k=pvZ^ z1?4cEeLL1hf+c|)1d_oMkpCC)u3~G?ns|R51$5S;CbdF?9tWzFNSTKbCque=Jh^*Z zAtl=fKAR|%T7^K!w+lCwQVWkna7A&S}-2l^D0v zYVQrOtgEgrPY4MglzR#43q%e}jk^Qdk^D53+jmAnH2Fv4JVFD~hvSdkKUKN%<>V8= zGH`oaGEh^gR~E!SM`uMKb{uu06egv`O_nOl$|-L>YX^C+i%Al@p^+ebTeZydiu+lJ zX4=y4A*o7Bc@v~XD!i|c%bpC+Z?$=sT^x)$xWdVnif@4sWGWc!j4n?pt~a}nIAC1% zbDc9NbM6F-_S&{g<}Iqp{^xw)Xy_79?AYl+4ls=EtRJkBBgk3V_^C^?ue$nG%{QFn z8@yyEEBa0!V^sj}7m{c3P{JbdUVi^D&iFeQPjCPkT5BEco4F*Dx>^BUI6YdjOQL_b zf%y5b_&Hi(uFj$_sX5#BWw0IGix+@AjYJwU)8R`RZ!5@XucTi{VbI=S@&-Oe$qWJJ zX!}!WN5XM6c-c5{q*BHsX);iB+wO}L!L}UQO)k&xmY*OoMFCi{MX5rs{I`#*0E3~J zX>7*lXUa3qdxRQcadIYc6AhCi7!bHE`ST@Tk@zOjqyH!voVyib(({dNIQ&uKq9J&Rr2jfN+og3kV4irwVS|H=NJ890MYNRA#fZu2^9Op||iE|Ryvterq(*A_;tsGx9RmAmne-%Hf}biYhGxmlIEq};uP zy1ksLy}V3eLLoOLmz9Oh+{8l1MCX@>1rP&fu;%ZI;*uwY z{9;lW22vNyYq{@=lIj;jCvSkc#Y}Ry?;^FiqsT6#1;eD$r>xxg-%XN`PTpIW8`!5Q zvuysPaY%PBa<|DG_T$D9fg$Suv;b+TDN=6kj~6TdIIMS{(Q(un>%5CoWbqF@dom!1 z@!N7W%ef@Lxu;{9r|xHfznqMGZfpB>c|FG6kDaljD=eQucs3d@fQ01;Lw+ zJx#))DV5Ub8nMFvDiIiES=O3*k9L{-yUWLtgQ`-hZlomnUvW9Xjb^Qn!;nZLERh8j zE#>qt^XeeU;<~mD{?5ZZH4{J;ey+;BeCh-_OIpMpZC>Z;v+RYg3CuqcSfL(FaRB>OCQtjVu zQX+%eu~JQeZG)n(04=2k_kKO3n3nw1^(OyC%8$U{wkV-D4>HP7t!(JzNt|A>qq3R^ zmCt0(hG$!4PDako!jPAbDzjV3Vdw>|W$ADS^cNfWHFztl->^uUl)@z;HCG@7G|YkN zig;Vf$N2qZhE(%Yedi--wYRE!qiE$s$aKVnDkVa7#br)KTd~^gBqZ!@6(F&de;8b_ z+1c18Z2zONB&Z->UdkD#s^tjXPK?N}7#^AQH6ZUabd7{lt_~=;pV!$eGGTg|*n^N= zJ=4S%Klx94%hmeNx21_Rwbzr0E&eY2XX|7^Ig{0PS$OQmvVL=k&0oZGRwUQTcR%G|xUo;T<;zk%ejU!7brI87>5~;e~ zbZM%zQrIxx2%~KHXa&R!4~9zpV9qQ~q={J=Y3L|0aQcYcobkm>G?C8c=Y?KYl1j2u zksb&F5guI)7hkm-afQlieTgU`E>b*n7}`w&K~6Leowa*{|Ej5lTP|FN7H&cN}dN0ZPuP9X2Y{2rFm zs}f(+MU9l|+_0WRTXB6vf)V*H$4Q#I*$YX`1!FYh>T#vUz#6gM{-AdGUy6nNlpXg* zzz(5_B;mkX1hH2VjZ)Mp^$8LMmSS*)a}0|;apWRCHVjg>FPfG~AbsR-XvS2_RFwsb zV~%q_MhK(idn|N1w7??PCK^tg-Bfm@KWNQigJQ#h^!8f)sWe9Ja)8Dtgl`z?93gxj zk4FgGkbu#G{{8`t&=o5!Uf{1p!#P|F7`D>+@vBcz{bkQn5VJ7}0ItC5?eX$R!=7_o zi4@2zXPnS=Ja32+LREZPO#&an_ogY>MkQsTPG%|^Y|QHPtEIB?05kvfHb@o+#yBZ* zPatjl{&7SBO)B(vf6px{s?cNTB}M~Xx;W3?VM zo-4NoV%j(!t^Ufl=KMDa(sWRR(_P#pfPmAh$nGq(y?3vNQr03GQEjI;-Y;u$wl>CN zx@a#(@Wsu--(fMl?_HsgeQ13EDf6Tk4lauB@TO8R02AW?#w8?dFnPAd+CF=mj3W3j zJ}2NN8e1|_$xxv4I(9F~F(~drGJTc!HOsE32An5c3pvKLFOE{$h&U7`+RD(iB zMRsTdtdIRW5J)gVB-LoJOm-VKNXYFq>Rx$)L>-?upBv9^8XKS66OT^GJ*u3)IhH{k ztv;{>hEr#wu>@@no0(EAyjML`;15Hg?$6!TEs<}iLbsl_wh@8A=qMl>Xf^|jBoV23 z)ojbloc#qNT)5)0F_+zAvPS8LTM7jW$#g=nmgGLypuV!)+!Y%ZC<914qK&M zMT$9jk;FE}Nt$Key5NRmOn@i@27rZ)({AH-ST(yR5q}10;50QwzCw@;v(DEJ`L}TF ze{QHfv>S0&8(<8XaO~aG3$ge*bD$DIxO^~8Ci6%n%&qrTNOdes!3r2-frgN!fMQhe z=H6R9SjQA2P}$JR+TMf{t-Rv&Uc;hu)m|P6VDOwMsmX@NsT6;B7-y0~u)MIbtZC(N z+3^InG?_BYz{jba3=O*5wSRqa+q7NsNI%bBB9|q*Z5%2N-x)?m+WvYyR#c16*rb|F zCBc|aYa5o>zioJ!3dz%a2jh9X#@_*RKqsQd8`{?SU`dN7?>{jBnoD3Bck@KK2=mKj z-S4eSx4`hs8wzDxRcFh90J6>ZzeCllBvgj*Lx%$@5K+D>Txgp2ZIxvj$@$;qh1IH?TK%!AZ%hp==^8FWpN=!afWR1 zjj(ELr1q4WSR*T6Q&h2cNZObspkN8?K#ezh#BbXzco!20m~f(i5PJ%TnVg@*JfD70 zVfM^PDoHvw2RAf{%@Y2|29yF20 zRb&}DBL*^PWFVHpgJ13a=I_skvVsBNe6VLk%u1q~#V`_|SGsd6!gQHRGF80L?jKaw zU$Znvg~pt@I;=h_w2QmGE=aO9hUgk(tm@xbvfcWI1D>?`%OUHgINmO1`O@Nzzqw|#HzTjqV;HP)q2veF_K zG?wCHImzZsRww>}AY?_JD}6+qnfDFxBLlAyWCAXSUoO{6q0L8fLJ#s|tt}<9LQfwa zn|_9BXajIP=E>6*meW~o8#l0x03+*~jRHmo-^$|T-D=vP91mzyiR%CEiqJ`wPr^j# zvC{vYlU;d#zHIi!<>dLkqZ9KVxr$0Lk@6G_RxAB-Tq%x^inghAtbDSWLbGsFW8{U+ z`0P8s1#NkHNJY7ly)@JH=?OR(ylShE*#)1{I;*?YZ4Z#NEnNz@h6sDn*K=y{J ze^eRlNZap!R66o(YA;LbHrqlAIHLfK7 z!hM$HEuu~AlVrH9EjX$rM^SBe#nCB{HhALULFh~vi}-R99G?Q^4$aDe&5Z&cO>8nD zHECj@G_ApI-*^`m)P$($Eq)jXIoxtvp70gKaNf&aH*{Os6(#L@n~6Z|gIMfzv6#wZ zOXbnN+iKZrPL3CIx04u$cEN)z@&RR={&EpvIbu_zsk7Fgy!rYvGIiKnXj3GBojrsa z>_$qaOpF2Mkb)p3@Vud8JC8pq%Xo;J3`Bs6p#I4)TA+CVFI`oXJ~R)|aiR{^Bki}C z*7@?gDb^4WqJ>d9ACMJucj@?eS1N=DSt-tk>l_?DJNF4(CiisDq7cAp`Ww`ll-7wz zivpp(5Kf$SGsuVezPmg(K`hEIT<7ur?hlW(0+777kq0g~7f*Y10nKi*3aiAG30B{5?lz+n;zJE^{sOczw2}5^JhB_D*?yEh-O7E*+51JEecD>!As6O|Eee6w!EF zEYe=7iHoSfKsx;tl{r9eIV`pj&nXC0#W$849D4Or;m$A%GEOfgoKN#}6RH#+k|;VW&^) zjW;p$KNHEJbA57vqJz(1zkNym(#Hgb;G}d8^Mki299Rh+o{(&Yoy2BJ-`e}nesRTk z3x8g`H&_3M3l<~x4p4`vN>DJL`8-}#zv6!NS;5BLe}i@Zuka@dZRDL}zU`% z)1mlYWB{IXNLP@5yUjE&0qz+O9Cs!>mFq9I!m7~Gj1H9RD_OvTkI-L3y>|bQ#!-BQ z@_7dNOjoMkqod}p=B->#+Rk|CB15ROrE+K=0=QDdQT%u3E)q46<7Q;J3a#kXCy3|+?8P+y7z3GYL5^ge%s-0<|p+osjcu$Hc zE9W;fIH>>5rR7Vd6aiusXb|rR=N#nt>F)?bzl6Cj4{nG>&3DNnsjc*+gGk?z{!MC0 zLmL4|WFT*$8BGtznr5pJSZMX(;M6a-F9SO6!c{XD+q)%& z8MCJd(OfuXI_RQ=gl3upYP^PF<`X^?@KSX)N=dkiv|^Da6h<6*IMlWTpBRskiegw9)DBLLH@v&`M~1ht>GE z$ZOuPfA?>%;6aZas#h^iN<#D<0)p@`8B_GP$S3^r!><#i<0NkE^$ix-!{Kh?bNDdU z>;3tSZNbZQjJJySuerehgQ_{or-m=5QJTJ5z37+w=G!=B^~Ne}!^ zdhF3vBh%-5)FsZCdvj2jB3ODJNwoRmVejhSWTt%9B=g*}h2o$RQ+0oo{_1u8)Hy#L zH+=5=jAnmd>3<(eqLh7Pxemjv6n|{GGHi6eFe>8VIUe>Q4&-!ybM(8yiD1nCRCE+F zuW@kE1H8>$F_b{tU7Vkt7Sa$eTgG()zFF-Z*3BBe|3JUX$LaIxJ;dWdg9JDa%l*{$r%PBwlna4 z{)g3wOXgnkoADJ>QZ$OAOqd4h4?QAX&gfV?KKn7cQGwdeK{~eWsMkm&oPj9bE_@ut zu^)X4F_so45+zv`7PfU+%Cp8~*%wCgBvR;=(XdzM!DYh~RbcAn&G+-y+;Ouaa$7}h zr~79od40aN&zCsKX!#2df$MXp`b|Mo8%gC{j9Hy+IC|{|hm2IZ-e=lkoB-q%hr~&##rs(KmNY#v}FbnWL7>bmrxdw#a zXf#!EQ;$=Yi3Nv4$P$AWlCAV}JPiYO+I%#rl1}Vsx$Ra7)n{;=z6L*8SX>dV!^V?P z58YeT=m*X(KE%GGG1(lpHma)g^>y9S2><|3jo&pygR6IaF3DpaE~e66wA? zyW|BwI!#j(x|m7Yk_DLvn3kS;JmL^}A8Y^D;d*k9tlQ<-`4Ts;;Jtais%mS{@1P0_ zQLGaqE1aOybUZu1LQn$n~D|`JiY#Q)pM1|k=-^0avZ#&i?h%jMiWCYU`G@-BK!U@ zHMPi1p@6o%Bgx{NDQ7adWUpAarAGryre>GlbbS5Pzlmu*>sm$5@wnt8QJ!ki5d++I z5;*iM`?MSFr>57tNAQR{htg(cVWeZ9u?vk^Db$KC?6ZqIS<=XOn>d*bS4Ak#b_+%nR!9Yh>&6{XE5dyhA zeJIwhrCHljb_judmw!oT9z;yl9=-ZFDb}pr7t{Gq5(2jzJi#ZDMC(?A(Esv8MjlB} z3xcJJ;{6W0)weis?(~WIKK)dAvrgNJmN#@iZ}t`aZurLK9#3r@cpo1mgW$+@)4n=UgJ$HUl-W~BjEmU>qtu1U$3iZ5aq4r%78*GV~_Z&=93-(t&P2_{r zu1B8w_7*CWS&IoFYNY)>C575E;lpS=j+1Wos2Kasz++wA9^uBPOob3EZzVkOf$;rne;NiTzopXD`ltNVF`3^fYnP8)1 z4w;_+Q1_==+w?vxy(tKu{Nat@qQsaBZPMm${Rp|@p@d_FRIl7}=rqC9Wvx8HM0*}c zBwi+x%Vz;>H8#FA*xCea1wmqfa^!|NoU0&31F^OTc7Ic}?pY+tuy5z-EdL1o9dyUL zaze=qe967Ds8`9}dQzRMGQPyW9o zX=%S9#T1BWS)3{F|87lfxxBQdA3Sgxx7j}C)MV|-LtsYoF7yzV)> z>OehFb5wLv8Iw(?SnZBi3*=$>Fql3-@9(#lRWzD6Gy6S=CkzeEFwJmraq*EWP`bUd z(q!dR0rA!1Vu;rs+tslPboDsHWsZWV_g)P8x>82gmnD1roXfsw>GG%Ap5zcPI1>)$ z@8Mw?w+Swfrb~`GWps4aMBB?aHCOZiGA6d0<*XF|DY`p~C8@H6#iBhMj-?Vo zeLdeVlAm?H5A1~S%IRYjw@KvooQ`p zTFQ7E3n|gocrdUCO!}fEWk_o=@`X975{wr2WSpPD}v_>#4cC@Zl?ASp@ zj}$$bAVZv9oUn}2s;YA85_~VPa&UOujR~uB5xQ>6OdbQslmH@%iYU78hDd!H!jO+3 z)Xx!#fI*pTWnC3knB$Vf0jHtGsI}+ly-;DY0rzKmGt=2iPFukrHdisiw5cj2aKW{@ zZL?YYq*SOIjkRNIXrXeCOrV^OXd=SJuq}1#>aOlQ6HSXbWzOWoL#m?~jieALaaV}Y zq8M)&gs7E8?z^~BhDW$@ub;Sck@?zyhvV$ zq9R}ieO^zv(n^)vS)G4AedO!E&VxWsv!=yn|Ak_as6aXYMcY@(XEu}qYPZ6rCTNMs zyq&_8V(=U5xfms%wcmr>Cx?JvRI#_SGw^;&Y-w>kFIG1*Te`m0GK;xMFhZr;9kFBI zI<5wW*!x@dr4038TbZkit?mb=!S8Okt!|on+NR|Ty;K=!Wc(_r%2iZ$g#%A?G@heV zJmfHhMpZY8B^Wf7O3OO8rH!9;+;FA3SDt}1(34rn>unBatTI^b&_tEiD&87M6)|6A zU96oC+@S)PZ7Il`6IA`@T4T<93e$s_eBS!Y?X2TRpC$fBpk-oFJ7K_|cgj1V&r)LQ zY~6tOYJyqsr|ep8QyYsn6Lu*zwPuIO0cyd|{$xwJl?Er<--Z1F*8*33VShrP)z8UO z`B+0kP%}J^#Hxw)I&I$Ka;N22W6#=9fg>9O;Q`<=>|&t`YIi#km95wg@J!*^{yZM6ubv!P;WoI|%<_d61!F|<*I(>Eq z0<#&yY1dig=^rm?5pS(0n1-()_#X_q?N0|TI)AVYJf7zs)0BmQqshIWJJjE=gs5$w z0Q@42=xRkpg`xN^mjV8|V>@QB4H5MD7t-~yB))4@!E&5-TD5fouH4) z+0m8P?wVlnMPldUCOvUALho(=^O$Td z55ZO&eaAY(_W|uIKUpgCGbX{v$at8Nl~Rl=ZT_qc}|Y^d1#cRzX|yWd9j*) z{qf?fMt|RHJc91XeFJCP+BfOI1fKAye}0HHe0}wB>D(~Tg@{@&5284|3uDwgHic0Y z#$x^kZ7Wyd#tMZHe47%5$vPe!b)GieiJT2{dO-y&p(O^Vx0lMJkga$7EZ3~E`+cDV z=GRMB%Kr)17JJH7*PSife=Okiee@E499G#nkPVsAM&9gxaVI*95V7JaoqLRNDI+^7 zF~<@sdo^I*?y|eP?TvI)Di7t7vjneHb=zI>v&r)F`K^2K7k-htxx4ut%-I5qzal%& z&hgNt&$YHXmy_sQO{OXd(G)&g+TDL#7-&b4{2A>IX93_aWXODL1qN;Ic#_k_h05|c zVDF^I<)0A0F3Qa;q$p4JVDyJzDS>()f5|+4Rj14I54i9rKmfVYV+oq&d-JSdznhCD zmNhN*OrC)G={`zi@M$`*GB}4;M4t3YQ}E99--{XAR4!jLLo(!UnqTWfz<&jvU`r-> z&Q{e0m#sI&Tu%G7Ex;R@XSIa#MxTHt5U3=zfmgM_o*k*9%QkM-M3n-y+vC}^qdMD1 zGF%B{_IULyYA8d57H)+LovqX9@AZ+i)m`8H*4$=yhBccB-5zU;@t4tMNBsD4o#_2Q zJ|0HI#KiW$-~D~|atI^`Ti?a(Y{ihWOF0=IAZ&_8WK_jc3y@R@U&FK9>dEF-S06?u z{TaRmY_Px*1#C2-MX6+Gu()zQZLy5~K(B^O$8P((W-S;ijW~AuL4(6MhP6{1a7V;9 zSL9SkWPA+d8toob60!D5k0xb7pgiCujey+mvUTkHXnRX%(7kWtBF>khc>K1C@6tSa zZ@ze8wmVP~`3s{o3LbZlfN0Wl6m8Ua)sRCcx?#Dmue$ndZZcpQ)Vx>gDCqPO6!Ta> z(eyfT3cH>=dmKUhpY5>g*}+^ssA&jtRn1$^*4xloE}+utX%c&~w_MmNvB>66X&5z= z%uoLZf%k);RaP=Gu8A%cbz>;y?+k7&e(=p?Ek~%26V>c*bW)i-3HPbWX(zHj_&%wk zcirmM%1M1%rq!qoz*Oe5n$nfEIw9Car1fUj+_=crG+)B-IidW51r}Q^=Iih*$0|s`Tp_ OgtWK + + + Inter Entity Sync + cm.inter_entity.sync + form + + + + + + + + diff --git a/odex25_transactions/cm_entity_sync_odex/views/entity_view.xml b/odex25_transactions/cm_entity_sync_odex/views/entity_view.xml new file mode 100644 index 000000000..ea700e527 --- /dev/null +++ b/odex25_transactions/cm_entity_sync_odex/views/entity_view.xml @@ -0,0 +1,60 @@ + + + + + cm.inter_entity.tree + cm.inter_entity + + + + + + + + + + + + cm.inter_entity.form + cm.inter_entity + +
+ + + + + + + + + + +
+
+
+ + + cm.entity.form + cm.entity + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/odex25_transactions/cm_entity_sync_odex/views/settings_view.xml b/odex25_transactions/cm_entity_sync_odex/views/settings_view.xml new file mode 100644 index 000000000..8172eda88 --- /dev/null +++ b/odex25_transactions/cm_entity_sync_odex/views/settings_view.xml @@ -0,0 +1,36 @@ + + + + CM Settings Ext + cm.inter_entity.sync + +
+ + + + + +