From 0a7ae8db933fb88c6ae2c8b105b636e443a3e261 Mon Sep 17 00:00:00 2001 From: Ernad Husremovic Date: Fri, 3 Oct 2025 18:06:50 +0200 Subject: [PATCH] 18.0 vanilla --- odoo-bringout-oca-ocb-base/odoo/__init__.py | 100 +- .../odoo/_monkeypatches/__init__.py | 39 + .../odoo/_monkeypatches/codecs.py | 26 + .../odoo/_monkeypatches/email.py | 12 + .../odoo/_monkeypatches/evented.py | 39 + .../odoo/_monkeypatches/literal_eval.py | 32 + .../odoo/_monkeypatches/lxml.py | 13 + .../odoo/_monkeypatches/mimetypes.py | 15 + .../num2words.py} | 274 + .../pytz.py} | 13 +- .../odoo/_monkeypatches/stdnum.py | 57 + .../odoo/_monkeypatches/urllib3.py | 12 + .../werkzeug_urls.py} | 76 +- .../odoo/_monkeypatches/zeep.py | 9 + .../odoo/addons/base/__init__.py | 1 - .../odoo/addons/base/__manifest__.py | 3 +- .../odoo/addons/base/controllers/rpc.py | 33 +- .../base/data/ir_config_parameter_data.xml | 9 + .../odoo/addons/base/data/ir_cron_data.xml | 5 +- .../addons/base/data/ir_demo_failure_data.xml | 4 +- .../base/data/ir_module_category_data.xml | 2 +- .../addons/base/data/ir_module_module.xml | 29 +- .../base/data/report_paperformat_data.xml | 20 +- .../addons/base/data/res.country.state.csv | 33 +- .../odoo/addons/base/data/res.lang.csv | 185 +- .../addons/base/data/res_country_data.xml | 4 + .../addons/base/data/res_currency_data.xml | 184 +- .../base/data/res_currency_rate_demo.xml | 6 - .../odoo/addons/base/data/res_lang_data.xml | 8 + .../addons/base/data/res_partner_demo.xml | 14 + .../odoo/addons/base/data/res_users_data.xml | 4 + .../odoo/addons/base/data/res_users_demo.xml | 5 + .../odoo/addons/base/i18n/af.po | 423 - .../odoo/addons/base/i18n/am.po | 423 - .../odoo/addons/base/i18n/ar.po | 10838 +++-- .../odoo/addons/base/i18n/az.po | 9875 ++++- .../odoo/addons/base/i18n/base.pot | 9662 +++- .../odoo/addons/base/i18n/bg.po | 9947 ++++- .../odoo/addons/base/i18n/bs.po | 423 - .../odoo/addons/base/i18n/ca.po | 10362 +++-- .../odoo/addons/base/i18n/cs.po | 10716 +++-- .../odoo/addons/base/i18n/da.po | 10037 ++++- .../odoo/addons/base/i18n/de.po | 10990 +++-- .../odoo/addons/base/i18n/el.po | 9724 +++- .../odoo/addons/base/i18n/es.po | 11066 +++-- .../odoo/addons/base/i18n/es_419.po | 11383 +++-- .../odoo/addons/base/i18n/es_CL.po | 423 - .../odoo/addons/base/i18n/et.po | 10236 +++-- .../odoo/addons/base/i18n/eu.po | 423 - .../odoo/addons/base/i18n/fa.po | 9869 ++++- .../odoo/addons/base/i18n/fi.po | 11129 +++-- .../odoo/addons/base/i18n/fo.po | 423 - .../odoo/addons/base/i18n/fr.po | 11240 +++-- .../odoo/addons/base/i18n/fr_BE.po | 423 - .../odoo/addons/base/i18n/fr_CA.po | 423 - .../odoo/addons/base/i18n/gl.po | 423 - .../odoo/addons/base/i18n/gu.po | 423 - .../odoo/addons/base/i18n/he.po | 9998 ++++- .../odoo/addons/base/i18n/hi.po | 10092 ++++- .../odoo/addons/base/i18n/hr.po | 9947 ++++- .../odoo/addons/base/i18n/hu.po | 9913 ++++- .../odoo/addons/base/i18n/hy.po | 35011 --------------- .../odoo/addons/base/i18n/id.po | 10956 +++-- .../odoo/addons/base/i18n/is.po | 13729 +++--- .../odoo/addons/base/i18n/it.po | 10990 +++-- .../odoo/addons/base/i18n/ja.po | 11205 +++-- .../odoo/addons/base/i18n/ka.po | 423 - .../odoo/addons/base/i18n/kab.po | 423 - .../odoo/addons/base/i18n/km.po | 423 - .../odoo/addons/base/i18n/ko.po | 11020 +++-- .../odoo/addons/base/i18n/ku.po | 10233 +++-- .../odoo/addons/base/i18n/lb.po | 423 - .../odoo/addons/base/i18n/lo.po | 423 - .../odoo/addons/base/i18n/lt.po | 9837 ++++- .../odoo/addons/base/i18n/lv.po | 11495 +++-- .../odoo/addons/base/i18n/mk.po | 423 - .../odoo/addons/base/i18n/mn.po | 19437 +++++--- .../odoo/addons/base/i18n/my.po | 10368 +++-- .../odoo/addons/base/i18n/nb.po | 9784 +++- .../odoo/addons/base/i18n/nl.po | 12096 +++-- .../odoo/addons/base/i18n/pl.po | 11049 +++-- .../odoo/addons/base/i18n/pt.po | 9916 ++++- .../odoo/addons/base/i18n/pt_BR.po | 11172 +++-- .../odoo/addons/base/i18n/ro.po | 16169 ++++--- .../odoo/addons/base/i18n/ru.po | 21625 +++++---- .../odoo/addons/base/i18n/sk.po | 9814 +++- .../odoo/addons/base/i18n/sl.po | 10246 ++++- .../odoo/addons/base/i18n/sq.po | 423 - .../odoo/addons/base/i18n/sr.po | 36820 ---------------- .../odoo/addons/base/i18n/sr@latin.po | 12529 +++--- .../odoo/addons/base/i18n/sv.po | 11000 +++-- .../odoo/addons/base/i18n/th.po | 11171 +++-- .../odoo/addons/base/i18n/tr.po | 16175 +++++-- .../odoo/addons/base/i18n/uk.po | 10454 +++-- .../odoo/addons/base/i18n/vi.po | 11357 +++-- .../odoo/addons/base/i18n/zh_CN.po | 11851 +++-- .../odoo/addons/base/i18n/zh_TW.po | 10747 +++-- .../odoo/addons/base/models/__init__.py | 3 +- .../odoo/addons/base/models/assetsbundle.py | 273 +- .../odoo/addons/base/models/ir_actions.py | 104 +- .../addons/base/models/ir_actions_report.py | 226 +- .../odoo/addons/base/models/ir_attachment.py | 182 +- .../odoo/addons/base/models/ir_binary.py | 17 +- .../addons/base/models/ir_config_parameter.py | 2 +- .../odoo/addons/base/models/ir_cron.py | 535 +- .../odoo/addons/base/models/ir_default.py | 48 +- .../odoo/addons/base/models/ir_demo.py | 2 +- .../addons/base/models/ir_embedded_actions.py | 106 + .../odoo/addons/base/models/ir_fields.py | 121 +- .../odoo/addons/base/models/ir_filters.py | 73 +- .../odoo/addons/base/models/ir_http.py | 196 +- .../odoo/addons/base/models/ir_mail_server.py | 127 +- .../odoo/addons/base/models/ir_model.py | 483 +- .../odoo/addons/base/models/ir_module.py | 89 +- .../odoo/addons/base/models/ir_property.py | 475 - .../odoo/addons/base/models/ir_qweb.py | 26 +- .../odoo/addons/base/models/ir_qweb_fields.py | 100 +- .../odoo/addons/base/models/ir_rule.py | 62 +- .../odoo/addons/base/models/ir_sequence.py | 48 +- .../odoo/addons/base/models/ir_ui_menu.py | 31 +- .../odoo/addons/base/models/ir_ui_view.py | 994 +- .../addons/base/models/report_paperformat.py | 1 + .../odoo/addons/base/models/res_bank.py | 62 +- .../odoo/addons/base/models/res_company.py | 120 +- .../odoo/addons/base/models/res_config.py | 194 - .../odoo/addons/base/models/res_country.py | 103 +- .../odoo/addons/base/models/res_currency.py | 117 +- .../odoo/addons/base/models/res_device.py | 203 + .../odoo/addons/base/models/res_lang.py | 198 +- .../odoo/addons/base/models/res_partner.py | 249 +- .../odoo/addons/base/models/res_users.py | 669 +- .../addons/base/models/res_users_deletion.py | 9 +- .../addons/base/models/res_users_settings.py | 12 +- .../odoo/addons/base/populate/__init__.py | 5 - .../odoo/addons/base/populate/ir_filters.py | 28 - .../odoo/addons/base/populate/res_company.py | 42 - .../odoo/addons/base/populate/res_currency.py | 36 - .../odoo/addons/base/populate/res_partner.py | 165 - .../odoo/addons/base/populate/res_user.py | 52 - .../odoo/addons/base/rng/calendar_view.rng | 2 +- .../odoo/addons/base/rng/common.rng | 6 + .../odoo/addons/base/rng/graph_view.rng | 2 +- .../base/rng/{tree_view.rng => list_view.rng} | 9 +- .../odoo/addons/base/rng/pivot_view.rng | 1 + .../odoo/addons/base/security/base_groups.xml | 1 + .../addons/base/security/base_security.xml | 50 + .../addons/base/security/ir.model.access.csv | 7 +- .../static/img/bg_background_template.jpg | Bin 192515 -> 0 bytes .../base/static/img/demo_logo_report.png | Bin 0 -> 10252 bytes .../static/img/icons/website_twitter_wall.png | Bin 737 -> 0 bytes .../odoo/addons/base/static/img/money.png | Bin 5356 -> 11003 bytes .../base/static/img/partner_open_wood.png | Bin 0 -> 4724 bytes .../base/static/img/res_company_logo.png | Bin 15310 -> 11445 bytes .../odoo/addons/base/static/img/truck.png | Bin 4353 -> 8831 bytes .../addons/base/static/src/css/modules.css | 45 - .../base/static/src/scss/res_partner.scss | 14 - .../tests/test_ir_model_fields_translation.js | 13 +- .../odoo/addons/base/tests/__init__.py | 6 + .../odoo/addons/base/tests/common.py | 188 +- .../odoo/addons/base/tests/config/16.0.conf | 65 + .../odoo/addons/base/tests/config/cli | 82 + .../odoo/addons/base/tests/config/empty.conf | 1 + .../addons/base/tests/config/non_default.conf | 109 + .../addons/base/tests/config/save_posix.conf | 72 + .../odoo/addons/base/tests/test_acl.py | 101 +- .../odoo/addons/base/tests/test_api.py | 11 - .../odoo/addons/base/tests/test_barcode.py | 2 +- .../odoo/addons/base/tests/test_base.py | 8 +- .../odoo/addons/base/tests/test_cloc.py | 8 +- .../addons/base/tests/test_configmanager.py | 534 + .../odoo/addons/base/tests/test_db_cursor.py | 143 +- .../addons/base/tests/test_deprecation.py | 5 +- .../odoo/addons/base/tests/test_expression.py | 408 +- .../odoo/addons/base/tests/test_float.py | 34 +- .../odoo/addons/base/tests/test_groups.py | 698 + .../odoo/addons/base/tests/test_http_case.py | 21 +- .../odoo/addons/base/tests/test_i18n.py | 33 + .../odoo/addons/base/tests/test_image.py | 5 +- .../odoo/addons/base/tests/test_ir_actions.py | 10 +- .../addons/base/tests/test_ir_attachment.py | 16 +- .../odoo/addons/base/tests/test_ir_cron.py | 544 +- .../odoo/addons/base/tests/test_ir_default.py | 2 +- .../base/tests/test_ir_embedded_actions.py | 145 + .../odoo/addons/base/tests/test_ir_filters.py | 113 +- .../addons/base/tests/test_ir_mail_server.py | 17 +- .../base/tests/test_ir_mail_server_smtpd.py | 22 +- .../odoo/addons/base/tests/test_ir_model.py | 34 +- .../addons/base/tests/test_ir_sequence.py | 22 +- .../odoo/addons/base/tests/test_mail.py | 34 +- .../odoo/addons/base/tests/test_mimetypes.py | 35 +- .../odoo/addons/base/tests/test_misc.py | 66 +- .../odoo/addons/base/tests/test_module.py | 1 + .../odoo/addons/base/tests/test_orm.py | 120 +- .../odoo/addons/base/tests/test_ormcache.py | 23 +- .../odoo/addons/base/tests/test_osv.py | 34 +- .../odoo/addons/base/tests/test_pdf.py | 24 + .../odoo/addons/base/tests/test_reports.py | 70 +- .../addons/base/tests/test_res_company.py | 18 +- .../odoo/addons/base/tests/test_res_config.py | 5 +- .../addons/base/tests/test_res_currency.py | 6 +- .../odoo/addons/base/tests/test_res_lang.py | 106 + .../addons/base/tests/test_res_partner.py | 592 +- .../base/tests/test_res_partner_merge.py | 101 + .../odoo/addons/base/tests/test_res_users.py | 73 +- .../odoo/addons/base/tests/test_search.py | 23 +- .../odoo/addons/base/tests/test_sql.py | 3 +- .../odoo/addons/base/tests/test_test_retry.py | 90 +- .../odoo/addons/base/tests/test_test_suite.py | 21 +- .../odoo/addons/base/tests/test_translate.py | 329 +- .../odoo/addons/base/tests/test_tz.py | 2 +- .../odoo/addons/base/tests/test_uninstall.py | 4 +- .../addons/base/tests/test_upgrade_code.py | 49 + .../addons/base/tests/test_user_has_group.py | 38 +- .../odoo/addons/base/tests/test_views.py | 2234 +- .../odoo/addons/base/tests/test_xmlrpc.py | 36 +- .../base/views/decimal_precision_views.xml | 4 +- .../addons/base/views/ir_actions_views.xml | 109 +- .../odoo/addons/base/views/ir_asset_views.xml | 4 +- .../addons/base/views/ir_attachment_views.xml | 8 +- .../base/views/ir_config_parameter_views.xml | 5 +- .../base/views/ir_cron_trigger_views.xml | 8 +- .../odoo/addons/base/views/ir_cron_views.xml | 12 +- .../addons/base/views/ir_default_views.xml | 8 +- .../addons/base/views/ir_filters_views.xml | 4 +- .../addons/base/views/ir_logging_views.xml | 6 +- .../base/views/ir_mail_server_views.xml | 18 +- .../odoo/addons/base/views/ir_model_views.xml | 64 +- .../addons/base/views/ir_module_views.xml | 79 +- .../addons/base/views/ir_profile_views.xml | 8 +- .../addons/base/views/ir_property_views.xml | 65 - .../base/views/ir_qweb_widget_templates.xml | 17 +- .../odoo/addons/base/views/ir_rule_views.xml | 15 +- .../addons/base/views/ir_sequence_views.xml | 8 +- .../addons/base/views/ir_ui_menu_views.xml | 9 +- .../addons/base/views/ir_ui_view_views.xml | 26 +- .../base/views/report_paperformat_views.xml | 8 +- .../odoo/addons/base/views/res_bank_views.xml | 36 +- .../addons/base/views/res_company_views.xml | 68 +- .../addons/base/views/res_config_views.xml | 14 - .../addons/base/views/res_country_views.xml | 22 +- .../addons/base/views/res_currency_views.xml | 34 +- .../addons/base/views/res_device_views.xml | 90 + .../odoo/addons/base/views/res_lang_views.xml | 9 +- .../addons/base/views/res_partner_views.xml | 251 +- .../views/res_users_identitycheck_views.xml | 33 +- .../addons/base/views/res_users_views.xml | 124 +- .../base/wizard/base_export_language.py | 8 +- .../wizard/base_export_language_views.xml | 5 +- .../base/wizard/base_import_language.py | 8 +- .../wizard/base_import_language_views.xml | 2 +- .../wizard/base_language_install_views.xml | 2 +- .../wizard/base_module_uninstall_views.xml | 35 +- .../addons/base/wizard/base_module_update.py | 2 +- .../base/wizard/base_module_update_views.xml | 1 - .../addons/base/wizard/base_partner_merge.py | 199 +- .../base/wizard/base_partner_merge_views.xml | 5 +- odoo-bringout-oca-ocb-base/odoo/api.py | 430 +- .../odoo/cli/__init__.py | 1 + odoo-bringout-oca-ocb-base/odoo/cli/db.py | 2 +- .../odoo/cli/neutralize.py | 2 +- .../odoo/cli/obfuscate.py | 45 +- .../odoo/cli/populate.py | 155 +- odoo-bringout-oca-ocb-base/odoo/cli/server.py | 30 +- odoo-bringout-oca-ocb-base/odoo/cli/shell.py | 5 +- .../default/views/views.xml.template | 8 +- .../odoo/cli/upgrade_code.py | 231 + odoo-bringout-oca-ocb-base/odoo/exceptions.py | 10 - odoo-bringout-oca-ocb-base/odoo/fields.py | 781 +- odoo-bringout-oca-ocb-base/odoo/http.py | 581 +- odoo-bringout-oca-ocb-base/odoo/loglevels.py | 44 +- odoo-bringout-oca-ocb-base/odoo/models.py | 2859 +- odoo-bringout-oca-ocb-base/odoo/modules/db.py | 2 +- .../odoo/modules/loading.py | 18 +- .../odoo/modules/migration.py | 47 +- .../odoo/modules/module.py | 125 +- .../odoo/modules/registry.py | 152 +- odoo-bringout-oca-ocb-base/odoo/netsvc.py | 78 +- .../odoo/osv/__init__.py | 2 - .../odoo/osv/expression.py | 435 +- odoo-bringout-oca-ocb-base/odoo/osv/osv.py | 24 - odoo-bringout-oca-ocb-base/odoo/release.py | 2 +- .../odoo/service/__init__.py | 3 - .../odoo/service/common.py | 6 +- odoo-bringout-oca-ocb-base/odoo/service/db.py | 64 +- .../odoo/service/model.py | 76 +- .../odoo/service/security.py | 9 +- .../odoo/service/server.py | 86 +- .../odoo/service/wsgi_server.py | 11 - odoo-bringout-oca-ocb-base/odoo/sql_db.py | 173 +- .../odoo/tests/_odoo_checker_markup.py | 68 - .../odoo/tests/common.py | 726 +- odoo-bringout-oca-ocb-base/odoo/tests/form.py | 50 +- .../odoo/tests/loader.py | 68 +- .../odoo/tests/test_module_operations.py | 16 +- .../odoo/tests/test_security.py | 18 - .../odoo/tools/__init__.py | 28 +- .../odoo/tools/_monkeypatches.py | 167 - .../odoo/tools/_vendor/sessions.py | 10 +- .../odoo/tools/arabic_reshaper/__init__.py | 143 + .../odoo/tools/arabic_reshaper/letters.py | 539 + .../odoo/tools/barcode.py | 4 +- .../odoo/tools/cache.py | 57 +- odoo-bringout-oca-ocb-base/odoo/tools/cloc.py | 2 +- .../odoo/tools/config.py | 50 +- .../odoo/tools/convert.py | 153 +- .../odoo/tools/date_utils.py | 99 +- .../odoo/tools/float_utils.py | 182 +- odoo-bringout-oca-ocb-base/odoo/tools/func.py | 94 +- odoo-bringout-oca-ocb-base/odoo/tools/i18n.py | 104 + .../odoo/tools/image.py | 112 +- .../odoo/tools/js_transpiler.py | 72 +- odoo-bringout-oca-ocb-base/odoo/tools/json.py | 18 + odoo-bringout-oca-ocb-base/odoo/tools/lru.py | 37 +- odoo-bringout-oca-ocb-base/odoo/tools/mail.py | 168 +- .../odoo/tools/mimetypes.py | 61 +- odoo-bringout-oca-ocb-base/odoo/tools/misc.py | 852 +- .../odoo/tools/osutil.py | 18 - .../odoo/tools/parse_version.py | 8 +- .../odoo/tools/pdf/__init__.py | 62 +- .../odoo/tools/pdf/_pypdf.py | 3 + .../odoo/tools/pdf/_pypdf2_1.py | 6 + .../odoo/tools/populate.py | 568 +- .../odoo/tools/profiler.py | 38 +- .../odoo/tools/pycompat.py | 16 +- .../odoo/tools/query.py | 124 +- .../odoo/tools/rendering_tools.py | 15 +- .../odoo/tools/safe_eval.py | 14 +- .../odoo/tools/set_expression.py | 559 + odoo-bringout-oca-ocb-base/odoo/tools/sql.py | 124 +- .../odoo/tools/template_inheritance.py | 122 +- .../odoo/tools/test_reports.py | 12 +- .../odoo/tools/translate.py | 494 +- .../odoo/tools/view_validation.py | 10 +- .../odoo/tools/xml_utils.py | 44 +- .../odoo/tools/zeep/client.py | 2 +- .../odoo/upgrade_code/17.5-00-example.py | 76 + .../odoo/upgrade_code/17.5-01-tree-to-list.py | 35 + 337 files changed, 399651 insertions(+), 232598 deletions(-) create mode 100644 odoo-bringout-oca-ocb-base/odoo/_monkeypatches/__init__.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/_monkeypatches/codecs.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/_monkeypatches/email.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/_monkeypatches/evented.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/_monkeypatches/literal_eval.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/_monkeypatches/lxml.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/_monkeypatches/mimetypes.py rename odoo-bringout-oca-ocb-base/odoo/{tools/num2words_patch.py => _monkeypatches/num2words.py} (71%) rename odoo-bringout-oca-ocb-base/odoo/{tools/_monkeypatches_pytz.py => _monkeypatches/pytz.py} (95%) create mode 100644 odoo-bringout-oca-ocb-base/odoo/_monkeypatches/stdnum.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/_monkeypatches/urllib3.py rename odoo-bringout-oca-ocb-base/odoo/{tools/_monkeypatches_urls.py => _monkeypatches/werkzeug_urls.py} (95%) create mode 100644 odoo-bringout-oca-ocb-base/odoo/_monkeypatches/zeep.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/data/ir_config_parameter_data.xml delete mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/i18n/hy.po delete mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/i18n/sr.po create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/models/ir_embedded_actions.py delete mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/models/ir_property.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/models/res_device.py delete mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/populate/__init__.py delete mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/populate/ir_filters.py delete mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/populate/res_company.py delete mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/populate/res_currency.py delete mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/populate/res_partner.py delete mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/populate/res_user.py rename odoo-bringout-oca-ocb-base/odoo/addons/base/rng/{tree_view.rng => list_view.rng} (95%) delete mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/static/img/bg_background_template.jpg create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/static/img/demo_logo_report.png delete mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/static/img/icons/website_twitter_wall.png create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/static/img/partner_open_wood.png create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/tests/config/16.0.conf create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/tests/config/cli create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/tests/config/empty.conf create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/tests/config/non_default.conf create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/tests/config/save_posix.conf create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/tests/test_configmanager.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/tests/test_groups.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/tests/test_i18n.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/tests/test_ir_embedded_actions.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/tests/test_res_partner_merge.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/tests/test_upgrade_code.py delete mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/views/ir_property_views.xml create mode 100644 odoo-bringout-oca-ocb-base/odoo/addons/base/views/res_device_views.xml create mode 100755 odoo-bringout-oca-ocb-base/odoo/cli/upgrade_code.py delete mode 100644 odoo-bringout-oca-ocb-base/odoo/osv/osv.py delete mode 100644 odoo-bringout-oca-ocb-base/odoo/service/wsgi_server.py delete mode 100644 odoo-bringout-oca-ocb-base/odoo/tests/_odoo_checker_markup.py delete mode 100644 odoo-bringout-oca-ocb-base/odoo/tests/test_security.py delete mode 100644 odoo-bringout-oca-ocb-base/odoo/tools/_monkeypatches.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/tools/arabic_reshaper/__init__.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/tools/arabic_reshaper/letters.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/tools/i18n.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/tools/set_expression.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/upgrade_code/17.5-00-example.py create mode 100644 odoo-bringout-oca-ocb-base/odoo/upgrade_code/17.5-01-tree-to-list.py diff --git a/odoo-bringout-oca-ocb-base/odoo/__init__.py b/odoo-bringout-oca-ocb-base/odoo/__init__.py index d90780dd..6885a6f8 100644 --- a/odoo-bringout-oca-ocb-base/odoo/__init__.py +++ b/odoo-bringout-oca-ocb-base/odoo/__init__.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- +# ruff: noqa: E402, F401 # Part of Odoo. See LICENSE file for full copyright and licensing details. """ OpenERP core library.""" - -#---------------------------------------------------------- +# ---------------------------------------------------------- # odoo must be a namespace package for odoo.addons to become one too # https://packaging.python.org/guides/packaging-namespace-packages/ -#---------------------------------------------------------- +# ---------------------------------------------------------- import pkgutil import os.path __path__ = [ @@ -20,76 +20,9 @@ MIN_PY_VERSION = (3, 10) MAX_PY_VERSION = (3, 13) assert sys.version_info > MIN_PY_VERSION, f"Outdated python version detected, Odoo requires Python >= {'.'.join(map(str, MIN_PY_VERSION))} to run." -#---------------------------------------------------------- -# Running mode flags (gevent, prefork) -#---------------------------------------------------------- -# Is the server running with gevent. -evented = False -if len(sys.argv) > 1 and sys.argv[1] == 'gevent': - sys.argv.remove('gevent') - import gevent.monkey - import psycopg2 - from gevent.socket import wait_read, wait_write - gevent.monkey.patch_all() - - def gevent_wait_callback(conn, timeout=None): - """A wait callback useful to allow gevent to work with Psycopg.""" - # Copyright (C) 2010-2012 Daniele Varrazzo - # This function is borrowed from psycogreen module which is licensed - # under the BSD license (see in odoo/debian/copyright) - while 1: - state = conn.poll() - if state == psycopg2.extensions.POLL_OK: - break - elif state == psycopg2.extensions.POLL_READ: - wait_read(conn.fileno(), timeout=timeout) - elif state == psycopg2.extensions.POLL_WRITE: - wait_write(conn.fileno(), timeout=timeout) - else: - raise psycopg2.OperationalError( - "Bad result from poll: %r" % state) - psycopg2.extensions.set_wait_callback(gevent_wait_callback) - evented = True - -# Is the server running in prefork mode (e.g. behind Gunicorn). -# If this is True, the processes have to communicate some events, -# e.g. database update or cache invalidation. Each process has also -# its own copy of the data structure and we don't need to care about -# locks between threads. -multi_process = False - -#---------------------------------------------------------- -# libc UTC hack -#---------------------------------------------------------- -# Make sure the OpenERP server runs in UTC. -import os -os.environ['TZ'] = 'UTC' # Set the timezone -import time -if hasattr(time, 'tzset'): - time.tzset() - -# --------------------------------------------------------- -# some charset are known by Python under a different name -# --------------------------------------------------------- -import encodings.aliases # noqa: E402 - -encodings.aliases.aliases['874'] = 'cp874' -encodings.aliases.aliases['windows_874'] = 'cp874' - -#---------------------------------------------------------- -# alias hebrew iso-8859-8-i and iso-8859-8-e on iso-8859-8 -# https://bugs.python.org/issue18624 -#---------------------------------------------------------- -import codecs -import re - -iso8859_8 = codecs.lookup('iso8859_8') -iso8859_8ie_re = re.compile(r'iso[-_]?8859[-_]8[-_]?[ei]', re.IGNORECASE) -codecs.register(lambda charset: iso8859_8 if iso8859_8ie_re.match(charset) else None) - -#---------------------------------------------------------- +# ---------------------------------------------------------- # Shortcuts -#---------------------------------------------------------- +# ---------------------------------------------------------- # The hard-coded super-user id (a.k.a. administrator, or root user). SUPERUSER_ID = 1 @@ -100,14 +33,25 @@ def registry(database_name=None): on the current thread. If the registry does not exist yet, it is created on the fly. """ + import warnings # noqa: PLC0415 + warnings.warn("Use directly odoo.modules.registry.Registry", DeprecationWarning, 2) if database_name is None: import threading database_name = threading.current_thread().dbname return modules.registry.Registry(database_name) -#---------------------------------------------------------- + +# ---------------------------------------------------------- +# Import tools to patch code and libraries +# required to do as early as possible for evented and timezone +# ---------------------------------------------------------- +from . import _monkeypatches +_monkeypatches.patch_all() + + +# ---------------------------------------------------------- # Imports -#---------------------------------------------------------- +# ---------------------------------------------------------- from . import upgrade # this namespace must be imported first from . import addons from . import conf @@ -120,17 +64,17 @@ from . import service from . import sql_db from . import tools -#---------------------------------------------------------- +# ---------------------------------------------------------- # Model classes, fields, api decorators, and translations -#---------------------------------------------------------- +# ---------------------------------------------------------- from . import models from . import fields from . import api from odoo.tools.translate import _, _lt from odoo.fields import Command -#---------------------------------------------------------- +# ---------------------------------------------------------- # Other imports, which may require stuff from above -#---------------------------------------------------------- +# ---------------------------------------------------------- from . import cli from . import http diff --git a/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/__init__.py b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/__init__.py new file mode 100644 index 00000000..7bc43f0a --- /dev/null +++ b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/__init__.py @@ -0,0 +1,39 @@ +# ruff: noqa: F401, PLC0415 +# ignore import not at top of the file +import os +import time +from .evented import patch_evented + + +def set_timezone_utc(): + os.environ['TZ'] = 'UTC' # Set the timezone + if hasattr(time, 'tzset'): + time.tzset() + + +def patch_all(): + patch_evented() + set_timezone_utc() + + from .codecs import patch_codecs + patch_codecs() + from .email import patch_email + patch_email() + from .mimetypes import patch_mimetypes + patch_mimetypes() + from .pytz import patch_pytz + patch_pytz() + from .literal_eval import patch_literal_eval + patch_literal_eval() + from .lxml import patch_lxml + patch_lxml() + from .num2words import patch_num2words + patch_num2words() + from .stdnum import patch_stdnum + patch_stdnum() + from .urllib3 import patch_urllib3 + patch_urllib3() + from .werkzeug_urls import patch_werkzeug + patch_werkzeug() + from .zeep import patch_zeep + patch_zeep() diff --git a/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/codecs.py b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/codecs.py new file mode 100644 index 00000000..84e4290f --- /dev/null +++ b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/codecs.py @@ -0,0 +1,26 @@ +import codecs +import encodings.aliases +import re + +import babel.core + + +def patch_codecs(): + # --------------------------------------------------------- + # some charset are known by Python under a different name + # --------------------------------------------------------- + + encodings.aliases.aliases['874'] = 'cp874' + encodings.aliases.aliases['windows_874'] = 'cp874' + + # --------------------------------------------------------- + # alias hebrew iso-8859-8-i and iso-8859-8-e on iso-8859-8 + # https://bugs.python.org/issue18624 + # --------------------------------------------------------- + + iso8859_8 = codecs.lookup('iso8859_8') + iso8859_8ie_re = re.compile(r'iso[-_]?8859[-_]8[-_]?[ei]', re.IGNORECASE) + codecs.register(lambda charset: iso8859_8 if iso8859_8ie_re.match(charset) else None) + + # To remove when corrected in Babel + babel.core.LOCALE_ALIASES['nb'] = 'nb_NO' diff --git a/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/email.py b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/email.py new file mode 100644 index 00000000..a3bc3dde --- /dev/null +++ b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/email.py @@ -0,0 +1,12 @@ +from email._policybase import _PolicyBase + + +def patch_email(): + def policy_clone(self, **kwargs): + for arg in kwargs: + if arg.startswith("_") or "__" in arg: + raise AttributeError(f"{self.__class__.__name__!r} object has no attribute {arg!r}") + return orig_policy_clone(self, **kwargs) + + orig_policy_clone = _PolicyBase.clone + _PolicyBase.clone = policy_clone diff --git a/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/evented.py b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/evented.py new file mode 100644 index 00000000..af21cd04 --- /dev/null +++ b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/evented.py @@ -0,0 +1,39 @@ +""" +Running mode flags (gevent, prefork) + +This should be imported as early as possible. +It will initialize the `odoo.evented` variable. +""" +import odoo +import sys + +odoo.evented = False + + +def patch_evented(): + if odoo.evented or not (len(sys.argv) > 1 and sys.argv[1] == 'gevent'): + return + sys.argv.remove('gevent') + import gevent.monkey # noqa: PLC0415 + import psycopg2 # noqa: PLC0415 + from gevent.socket import wait_read, wait_write # noqa: PLC0415 + gevent.monkey.patch_all() + + def gevent_wait_callback(conn, timeout=None): + """A wait callback useful to allow gevent to work with Psycopg.""" + # Copyright (C) 2010-2012 Daniele Varrazzo + # This function is borrowed from psycogreen module which is licensed + # under the BSD license (see in odoo/debian/copyright) + while 1: + state = conn.poll() + if state == psycopg2.extensions.POLL_OK: + break + elif state == psycopg2.extensions.POLL_READ: + wait_read(conn.fileno(), timeout=timeout) + elif state == psycopg2.extensions.POLL_WRITE: + wait_write(conn.fileno(), timeout=timeout) + else: + raise psycopg2.OperationalError( + "Bad result from poll: %r" % state) + psycopg2.extensions.set_wait_callback(gevent_wait_callback) + odoo.evented = True diff --git a/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/literal_eval.py b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/literal_eval.py new file mode 100644 index 00000000..3279e05c --- /dev/null +++ b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/literal_eval.py @@ -0,0 +1,32 @@ +# ruff: noqa: E402, PLC0415 +# ignore import not at top of the file +import ast +import logging +import os + +_logger = logging.getLogger(__name__) +orig_literal_eval = ast.literal_eval + + +def literal_eval(expr): + # limit the size of the expression to avoid segmentation faults + # the default limit is set to 100KiB + # can be overridden by setting the ODOO_LIMIT_LITEVAL_BUFFER buffer_size_environment variable + + buffer_size = 102400 + buffer_size_env = os.getenv("ODOO_LIMIT_LITEVAL_BUFFER") + + if buffer_size_env: + if buffer_size_env.isdigit(): + buffer_size = int(buffer_size_env) + else: + _logger.error("ODOO_LIMIT_LITEVAL_BUFFER has to be an integer, defaulting to 100KiB") + + if isinstance(expr, str) and len(expr) > buffer_size: + raise ValueError("expression can't exceed buffer limit") + + return orig_literal_eval(expr) + + +def patch_literal_eval(): + ast.literal_eval = literal_eval diff --git a/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/lxml.py b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/lxml.py new file mode 100644 index 00000000..58c5bb11 --- /dev/null +++ b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/lxml.py @@ -0,0 +1,13 @@ +import lxml.html.clean +import re + +from importlib.metadata import version + +from odoo.tools import parse_version + + +def patch_lxml(): + # between these versions having a couple data urls in a style attribute + # or style node removes the attribute or node erroneously + if parse_version("4.6.0") <= parse_version(version('lxml')) < parse_version("5.2.0"): + lxml.html.clean._find_image_dataurls = re.compile(r'data:image/(.+?);base64,').findall diff --git a/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/mimetypes.py b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/mimetypes.py new file mode 100644 index 00000000..d803a77d --- /dev/null +++ b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/mimetypes.py @@ -0,0 +1,15 @@ +import mimetypes + + +def patch_mimetypes(): + # if extension is already knows, the new definition will remplace the existing one + # Add potentially missing (older ubuntu) font mime types + mimetypes.add_type('application/font-woff', '.woff') + mimetypes.add_type('application/vnd.ms-fontobject', '.eot') + mimetypes.add_type('application/x-font-ttf', '.ttf') + mimetypes.add_type('image/webp', '.webp') + # Add potentially wrong (detected on windows) svg mime types + mimetypes.add_type('image/svg+xml', '.svg') + # this one can be present on windows with the value 'text/plain' which + # breaks loading js files from an addon's static folder + mimetypes.add_type('text/javascript', '.js') diff --git a/odoo-bringout-oca-ocb-base/odoo/tools/num2words_patch.py b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/num2words.py similarity index 71% rename from odoo-bringout-oca-ocb-base/odoo/tools/num2words_patch.py rename to odoo-bringout-oca-ocb-base/odoo/_monkeypatches/num2words.py index dbfd55b1..7f942304 100644 --- a/odoo-bringout-oca-ocb-base/odoo/tools/num2words_patch.py +++ b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/num2words.py @@ -1,10 +1,13 @@ import decimal +import logging import math import re from collections import OrderedDict from decimal import ROUND_HALF_UP, Decimal from math import floor +from odoo import MIN_PY_VERSION + # The following section of the code is used to monkey patch # the Arabic class of num2words package as there are some problems # upgrading the package to the newer version that fixed the bugs @@ -708,3 +711,274 @@ def to_s(val): return unicode(val) except NameError: return str(val) + + +# Derived from num2cyrillic licensed under LGPL-3.0-only +# Copyright 2018 ClaimCompass, Inc (num2cyrillic authored by Velizar Shulev) https://github.com/ClaimCompass/num2cyrillic +# Copyright 1997 The PHP Group (PEAR::Numbers_Words, authored by Kouber Saparev) https://github.com/pear/Numbers_Words/blob/master/Numbers/Words/Locale/bg.php + + +class NumberToWords_BG(Num2Word_Base): + locale = 'bg' + lang = 'Bulgarian' + lang_native = 'Български' + _misc_strings = { + 'deset': 'десет', + 'edinadeset': 'единадесет', + 'na': 'на', + 'sto': 'сто', + 'sta': 'ста', + 'stotin': 'стотин', + 'hiliadi': 'хиляди', + } + _digits = { + 0: [None, 'едно', 'две', 'три', 'четири', 'пет', 'шест', 'седем', 'осем', 'девет'], + } + _digits[1] = [None, 'един', 'два'] + _digits[0][3:] + _digits[-1] = [None, 'една'] + _digits[0][2:] + _last_and = False + _zero = 'нула' + _infinity = 'безкрайност' + _and = 'и' + _sep = ' ' + _minus = 'минус' + _plural = 'а' + _exponent = { + 0: '', + 3: 'хиляда', + 6: 'милион', + 9: 'милиард', + 12: 'трилион', + 15: 'квадрилион', + 18: 'квинтилион', + 21: 'секстилион', + 24: 'септилион', + 27: 'октилион', + 30: 'ноналион', + 33: 'декалион', + 36: 'ундекалион', + 39: 'дуодекалион', + 42: 'тредекалион', + 45: 'кватордекалион', + 48: 'квинтдекалион', + 51: 'сексдекалион', + 54: 'септдекалион', + 57: 'октодекалион', + 60: 'новемдекалион', + 63: 'вигинтилион', + 66: 'унвигинтилион', + 69: 'дуовигинтилион', + 72: 'тревигинтилион', + 75: 'кваторвигинтилион', + 78: 'квинвигинтилион', + 81: 'сексвигинтилион', + 84: 'септенвигинтилион', + 87: 'октовигинтилион', + 90: 'новемвигинтилион', + 93: 'тригинтилион', + 96: 'унтригинтилион', + 99: 'дуотригинтилион', + 102: 'третригинтилион', + 105: 'кватортригинтилион', + 108: 'квинтригинтилион', + 111: 'секстригинтилион', + 114: 'септентригинтилион', + 117: 'октотригинтилион', + 120: 'новемтригинтилион', + 123: 'квадрагинтилион', + 126: 'унквадрагинтилион', + 129: 'дуоквадрагинтилион', + 132: 'треквадрагинтилион', + 135: 'кваторквадрагинтилион', + 138: 'квинквадрагинтилион', + 141: 'сексквадрагинтилион', + 144: 'септенквадрагинтилион', + 147: 'октоквадрагинтилион', + 150: 'новемквадрагинтилион', + 153: 'квинквагинтилион', + 156: 'унквинкагинтилион', + 159: 'дуоквинкагинтилион', + 162: 'треквинкагинтилион', + 165: 'кваторквинкагинтилион', + 168: 'квинквинкагинтилион', + 171: 'сексквинкагинтилион', + 174: 'септенквинкагинтилион', + 177: 'октоквинкагинтилион', + 180: 'новемквинкагинтилион', + 183: 'сексагинтилион', + 186: 'унсексагинтилион', + 189: 'дуосексагинтилион', + 192: 'тресексагинтилион', + 195: 'кваторсексагинтилион', + 198: 'квинсексагинтилион', + 201: 'секссексагинтилион', + 204: 'септенсексагинтилион', + 207: 'октосексагинтилион', + 210: 'новемсексагинтилион', + 213: 'септагинтилион', + 216: 'унсептагинтилион', + 219: 'дуосептагинтилион', + 222: 'тресептагинтилион', + 225: 'кваторсептагинтилион', + 228: 'квинсептагинтилион', + 231: 'секссептагинтилион', + 234: 'септенсептагинтилион', + 237: 'октосептагинтилион', + 240: 'новемсептагинтилион', + 243: 'октогинтилион', + 246: 'уноктогинтилион', + 249: 'дуооктогинтилион', + 252: 'треоктогинтилион', + 255: 'кватороктогинтилион', + 258: 'квиноктогинтилион', + 261: 'сексоктогинтилион', + 264: 'септоктогинтилион', + 267: 'октооктогинтилион', + 270: 'новемоктогинтилион', + 273: 'нонагинтилион', + 276: 'уннонагинтилион', + 279: 'дуононагинтилион', + 282: 'тренонагинтилион', + 285: 'кваторнонагинтилион', + 288: 'квиннонагинтилион', + 291: 'секснонагинтилион', + 294: 'септеннонагинтилион', + 297: 'октононагинтилион', + 300: 'новемнонагинтилион', + 303: 'центилион', + } + + def to_cardinal(self, value): + return '' if value is None else self._to_words(value).strip() + + def to_ordinal(self, _): + raise NotImplementedError + + def to_ordinal_num(self, _): + raise NotImplementedError + + def to_year(self, _): + raise NotImplementedError + + def to_currency(self, _): + raise NotImplementedError + + def _split_number(self, num): + if isinstance(num, int): + num = str(num) + first = [] + if len(num) % 3 != 0: + if len(num[1:]) % 3 == 0: + first = [num[0:1]] + num = num[1:] + elif len(num[2:]) % 3 == 0: + first = [num[0:2]] + num = num[2:] + ret = [num[i:i + 3] for i in range(0, len(num), 3)] + return first + ret + + def _discard_empties(self, ls): + return list(filter(lambda x: x is not None, ls)) + + def _show_digits_group(self, num, gender=0, last=False): + num = int(num) + e = int(num % 10) # ones + d = int((num - e) % 100 / 10) # tens + s = int((num - d * 10 - e) % 1000 / 100) # hundreds + ret = [None] * 6 + + if s: + if s == 1: + ret[1] = self._misc_strings['sto'] + elif s == 2 or s == 3: + ret[1] = self._digits[0][s] + self._misc_strings['sta'] + else: + ret[1] = self._digits[0][s] + self._misc_strings['stotin'] + + if d: + if d == 1: + if not e: + ret[3] = self._misc_strings['deset'] + else: + if e == 1: + ret[3] = self._misc_strings['edinadeset'] + else: + ret[3] = self._digits[1][e] + self._misc_strings['na'] + self._misc_strings['deset'] + e = 0 + else: + ret[3] = self._digits[1][d] + self._misc_strings['deset'] + + if e: + ret[5] = self._digits[gender][e] + + if len(self._discard_empties(ret)) > 1: + if e: + ret[4] = self._and + else: + ret[2] = self._and + + if last: + if not s or len(self._discard_empties(ret)) == 1: + ret[0] = self._and + self._last_and = True + + return self._sep.join(self._discard_empties(ret)) + + def _to_words(self, num=0): + num_groups = self._split_number(num) + sizeof_num_groups = len(num_groups) + + ret = [None] * (sizeof_num_groups + 1) + ret_minus = '' + + if num < 0: + ret_minus = self._minus + self._sep + elif num == 0: + return self._zero + + i = sizeof_num_groups - 1 + j = 1 + while i >= 0: + if ret[j] is None: + ret[j] = '' + + _pow = sizeof_num_groups - i + + if num_groups[i] != '000': + if int(num_groups[i]) > 1: + if _pow == 1: + ret[j] += self._show_digits_group(num_groups[i], 0, not self._last_and and i) + self._sep + ret[j] += self._exponent[(_pow - 1) * 3] + elif _pow == 2: + ret[j] += self._show_digits_group(num_groups[i], -1, not self._last_and and i) + self._sep + ret[j] += self._misc_strings['hiliadi'] + self._sep + else: + ret[j] += self._show_digits_group(num_groups[i], 1, not self._last_and and i) + self._sep + ret[j] += self._exponent[(_pow - 1) * 3] + self._plural + self._sep + else: + if _pow == 1: + ret[j] += self._show_digits_group(num_groups[i], 0, not self._last_and and i) + self._sep + elif _pow == 2: + ret[j] += self._exponent[(_pow - 1) * 3] + self._sep + else: + ret[j] += self._digits[1][1] + self._sep + self._exponent[(_pow - 1) * 3] + self._sep + + i -= 1 + j += 1 + + ret = self._discard_empties(ret) + ret.reverse() + return ret_minus + ''.join(ret) + + +def patch_num2words(): + try: + import num2words # noqa: PLC0415 + except ImportError: + _logger = logging.getLogger(__name__) + _logger.warning("num2words is not available, Arabic number to words conversion will not work") + return + if MIN_PY_VERSION >= (3, 12): + raise RuntimeError("The num2words monkey patch is obsolete. Bump the version of the library to the latest available in the official package repository, if it hasn't already been done, and remove the patch.") + num2words.CONVERTER_CLASSES["ar"] = Num2Word_AR_Fixed() + num2words.CONVERTER_CLASSES["bg"] = NumberToWords_BG() diff --git a/odoo-bringout-oca-ocb-base/odoo/tools/_monkeypatches_pytz.py b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/pytz.py similarity index 95% rename from odoo-bringout-oca-ocb-base/odoo/tools/_monkeypatches_pytz.py rename to odoo-bringout-oca-ocb-base/odoo/_monkeypatches/pytz.py index 9c0a49ad..848d84c6 100644 --- a/odoo-bringout-oca-ocb-base/odoo/tools/_monkeypatches_pytz.py +++ b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/pytz.py @@ -119,14 +119,13 @@ _tz_mapping = { "Zulu": "Etc/UTC", } - original_pytz_timezone = pytz.timezone -def timezone(name): - if name not in pytz.all_timezones_set and name in _tz_mapping: - name = _tz_mapping[name] - return original_pytz_timezone(name) +def patch_pytz(): + def timezone(name): + if name not in pytz.all_timezones_set and name in _tz_mapping: + name = _tz_mapping[name] + return original_pytz_timezone(name) - -pytz.timezone = timezone + pytz.timezone = timezone diff --git a/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/stdnum.py b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/stdnum.py new file mode 100644 index 00000000..793faec1 --- /dev/null +++ b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/stdnum.py @@ -0,0 +1,57 @@ +# ruff: noqa: PLC0415 + +_soap_clients = {} + + +def new_get_soap_client(wsdlurl, timeout=30): + # stdnum library does not set the timeout for the zeep Transport class correctly + # (timeout is to fetch the wsdl and operation_timeout is to perform the call), + # requiring us to monkey patch the get_soap_client function. + # Can be removed when https://github.com/arthurdejong/python-stdnum/issues/444 is + # resolved and the version of the dependency is updated. + # The code is a copy of the original apart for the line related to the Transport class. + # This was done to keep the code as similar to the original and to reduce the possibility + # of introducing import errors, even though some imports are not in the requirements. + # See https://github.com/odoo/odoo/pull/173359 for a more thorough explanation. + if (wsdlurl, timeout) not in _soap_clients: + try: + from zeep.transports import Transport + transport = Transport(operation_timeout=timeout, timeout=timeout) # operational_timeout added here + from zeep import CachingClient + client = CachingClient(wsdlurl, transport=transport).service + except ImportError: + # fall back to non-caching zeep client + try: + from zeep import Client + client = Client(wsdlurl, transport=transport).service + except ImportError: + # other implementations require passing the proxy config + try: + from urllib import getproxies + except ImportError: + from urllib.request import getproxies + # fall back to suds + try: + from suds.client import Client + client = Client( + wsdlurl, proxy=getproxies(), timeout=timeout).service + except ImportError: + # use pysimplesoap as last resort + try: + from pysimplesoap.client import SoapClient + client = SoapClient( + wsdl=wsdlurl, proxy=getproxies(), timeout=timeout) + except ImportError: + raise ImportError( + 'No SOAP library (such as zeep) found') + _soap_clients[(wsdlurl, timeout)] = client + return _soap_clients[(wsdlurl, timeout)] + + +def patch_stdnum(): + try: + from stdnum import util + except ImportError: + return # nothing to patch + + util.get_soap_client = new_get_soap_client diff --git a/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/urllib3.py b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/urllib3.py new file mode 100644 index 00000000..011d57a5 --- /dev/null +++ b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/urllib3.py @@ -0,0 +1,12 @@ +from urllib3 import PoolManager + +orig_pool_init = PoolManager.__init__ + + +def pool_init(self, *args, **kwargs): + orig_pool_init(self, *args, **kwargs) + self.pool_classes_by_scheme = {**self.pool_classes_by_scheme} + + +def patch_urllib3(): + PoolManager.__init__ = pool_init diff --git a/odoo-bringout-oca-ocb-base/odoo/tools/_monkeypatches_urls.py b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/werkzeug_urls.py similarity index 95% rename from odoo-bringout-oca-ocb-base/odoo/tools/_monkeypatches_urls.py rename to odoo-bringout-oca-ocb-base/odoo/_monkeypatches/werkzeug_urls.py index 53bc8297..6104159c 100644 --- a/odoo-bringout-oca-ocb-base/odoo/tools/_monkeypatches_urls.py +++ b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/werkzeug_urls.py @@ -1,14 +1,24 @@ +# ruff: noqa: PLC0415 (import in function not at top-level) from __future__ import annotations +import contextlib +import operator import os -import sys import re +import sys import typing as t import warnings -from werkzeug.datastructures import iter_multi_items -from werkzeug.urls import _decode_idna +from shutil import copyfileobj +from types import CodeType + +from werkzeug import urls +from werkzeug.datastructures import FileStorage, MultiDict +from werkzeug.routing import Rule +from werkzeug.urls import _decode_idna +from werkzeug.wrappers import Request, Response + +Rule_get_func_code = hasattr(Rule, '_get_func_code') and Rule._get_func_code -import operator def _check_str_tuple(value: t.Tuple[t.AnyStr, ...]) -> None: """Ensure tuple items are all strings or all bytes.""" @@ -30,8 +40,10 @@ def _make_encode_wrapper(reference: t.AnyStr) -> t.Callable[[str], t.AnyStr]: return operator.methodcaller("encode", "latin1") + _default_encoding = sys.getdefaultencoding() + def _to_str( x: t.Optional[t.Any], charset: t.Optional[str] = _default_encoding, @@ -51,7 +63,6 @@ def _to_str( return x.decode(charset, errors) # type: ignore - if t.TYPE_CHECKING: from werkzeug import datastructures as ds @@ -98,7 +109,7 @@ class BaseURL(_URLTuple): _lbracket: str _rbracket: str - def __new__(cls, *args: t.Any, **kwargs: t.Any) -> BaseURL: + def __new__(cls, *args: t.Any, **kwargs: t.Any) -> BaseURL: # noqa: PYI034 return super().__new__(cls, *args, **kwargs) def __str__(self) -> str: @@ -126,10 +137,8 @@ class BaseURL(_URLTuple): """ rv = self.host if rv is not None and isinstance(rv, str): - try: + with contextlib.suppress(UnicodeError): rv = rv.encode("idna").decode("ascii") - except UnicodeError: - pass return rv @property @@ -985,7 +994,7 @@ def url_join( if not url: return base - bscheme, bnetloc, bpath, bquery, bfragment = url_parse( + bscheme, bnetloc, bpath, bquery, _bfragment = url_parse( base, allow_fragments=allow_fragments ) scheme, netloc, path, query, fragment = url_parse(url, bscheme, allow_fragments) @@ -1031,16 +1040,37 @@ def url_join( return url_unparse((scheme, netloc, path, query, fragment)) -from werkzeug import urls -# see https://github.com/pallets/werkzeug/compare/2.3.0..3.0.0 -# see https://github.com/pallets/werkzeug/blob/2.3.0/src/werkzeug/urls.py for replacement -urls.url_decode = url_decode -urls.url_encode = url_encode -urls.url_join = url_join -urls.url_parse = url_parse -urls.url_quote = url_quote -urls.url_unquote = url_unquote -urls.url_quote_plus = url_quote_plus -urls.url_unquote_plus = url_unquote_plus -urls.url_unparse = url_unparse -urls.URL = URL +def patch_werkzeug(): + from ..tools.json import scriptsafe # noqa: PLC0415 + Request.json_module = Response.json_module = scriptsafe + + FileStorage.save = lambda self, dst, buffer_size=(1 << 20): copyfileobj(self.stream, dst, buffer_size) + + def _multidict_deepcopy(self, memo=None): + return orig_deepcopy(self) + + orig_deepcopy = MultiDict.deepcopy + MultiDict.deepcopy = _multidict_deepcopy + + if Rule_get_func_code: + @staticmethod + def _get_func_code(code, name): + assert isinstance(code, CodeType) + return Rule_get_func_code(code, name) + Rule._get_func_code = _get_func_code + + if hasattr(urls, 'url_join'): + # URLs are already patched + return + # see https://github.com/pallets/werkzeug/compare/2.3.0..3.0.0 + # see https://github.com/pallets/werkzeug/blob/2.3.0/src/werkzeug/urls.py for replacement + urls.url_decode = url_decode + urls.url_encode = url_encode + urls.url_join = url_join + urls.url_parse = url_parse + urls.url_quote = url_quote + urls.url_unquote = url_unquote + urls.url_quote_plus = url_quote_plus + urls.url_unquote_plus = url_unquote_plus + urls.url_unparse = url_unparse + urls.URL = URL diff --git a/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/zeep.py b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/zeep.py new file mode 100644 index 00000000..e724ef6e --- /dev/null +++ b/odoo-bringout-oca-ocb-base/odoo/_monkeypatches/zeep.py @@ -0,0 +1,9 @@ +from zeep.xsd import visitor +from zeep.xsd.const import xsd_ns + + +def patch_zeep(): + # see https://github.com/mvantellingen/python-zeep/issues/1185 + if visitor.tags.notation.localname != 'notation': + visitor.tags.notation = xsd_ns('notation') + visitor.SchemaVisitor.visitors[visitor.tags.notation] = visitor.SchemaVisitor.visit_notation diff --git a/odoo-bringout-oca-ocb-base/odoo/addons/base/__init__.py b/odoo-bringout-oca-ocb-base/odoo/addons/base/__init__.py index 842de58a..c434abed 100644 --- a/odoo-bringout-oca-ocb-base/odoo/addons/base/__init__.py +++ b/odoo-bringout-oca-ocb-base/odoo/addons/base/__init__.py @@ -3,7 +3,6 @@ from . import controllers from . import models -from . import populate from . import report from . import wizard diff --git a/odoo-bringout-oca-ocb-base/odoo/addons/base/__manifest__.py b/odoo-bringout-oca-ocb-base/odoo/addons/base/__manifest__.py index 66ccda83..03e8471d 100644 --- a/odoo-bringout-oca-ocb-base/odoo/addons/base/__manifest__.py +++ b/odoo-bringout-oca-ocb-base/odoo/addons/base/__manifest__.py @@ -41,6 +41,7 @@ The kernel of Odoo, needed for all installation. 'views/ir_ui_menu_views.xml', 'views/ir_ui_view_views.xml', 'views/ir_default_views.xml', + 'data/ir_config_parameter_data.xml', 'data/ir_cron_data.xml', 'report/ir_model_report.xml', 'report/ir_model_templates.xml', @@ -67,8 +68,8 @@ The kernel of Odoo, needed for all installation. 'views/res_country_views.xml', 'views/res_currency_views.xml', 'views/res_users_views.xml', + 'views/res_device_views.xml', 'views/res_users_identitycheck_views.xml', - 'views/ir_property_views.xml', 'views/res_config_settings_views.xml', 'views/report_paperformat_views.xml', 'security/ir.model.access.csv', diff --git a/odoo-bringout-oca-ocb-base/odoo/addons/base/controllers/rpc.py b/odoo-bringout-oca-ocb-base/odoo/addons/base/controllers/rpc.py index 757e0392..5d57cf91 100644 --- a/odoo-bringout-oca-ocb-base/odoo/addons/base/controllers/rpc.py +++ b/odoo-bringout-oca-ocb-base/odoo/addons/base/controllers/rpc.py @@ -10,7 +10,7 @@ from markupsafe import Markup import odoo from odoo.http import Controller, route, dispatch_rpc, request, Response from odoo.fields import Date, Datetime, Command -from odoo.tools import lazy, ustr +from odoo.tools import lazy from odoo.tools.misc import frozendict # ========================================================== @@ -45,7 +45,7 @@ def xmlrpc_handle_exception_int(e): formatted_info = "".join(traceback.format_exception(*info)) fault = xmlrpc.client.Fault(RPC_FAULT_CODE_APPLICATION_ERROR, formatted_info) - return xmlrpc.client.dumps(fault, allow_none=None) + return dumps(fault) def xmlrpc_handle_exception_string(e): @@ -65,7 +65,7 @@ def xmlrpc_handle_exception_string(e): formatted_info = "".join(traceback.format_exception(*info)) fault = xmlrpc.client.Fault(odoo.tools.exception_to_unicode(e), formatted_info) - return xmlrpc.client.dumps(fault, allow_none=None, encoding=None) + return dumps(fault) class OdooMarshaller(xmlrpc.client.Marshaller): @@ -78,9 +78,8 @@ class OdooMarshaller(xmlrpc.client.Marshaller): # By default, in xmlrpc, bytes are converted to xmlrpc.client.Binary object. # Historically, odoo is sending binary as base64 string. # In python 3, base64.b64{de,en}code() methods now works on bytes. - # Convert them to str to have a consistent behavior between python 2 and python 3. def dump_bytes(self, value, write): - self.dump_unicode(ustr(value), write) + self.dump_unicode(value.decode(), write) def dump_datetime(self, value, write): # override to marshall as a string for backwards compatibility @@ -111,21 +110,34 @@ class OdooMarshaller(xmlrpc.client.Marshaller): dispatch[Markup] = lambda self, value, write: self.dispatch[str](self, str(value), write) -# monkey-patch xmlrpc.client's marshaller -xmlrpc.client.Marshaller = OdooMarshaller +def dumps(params: list | tuple | xmlrpc.client.Fault) -> str: + response = OdooMarshaller(allow_none=False).dumps(params) + return f"""\ + + +{response} + +""" # ========================================================== # RPC Controller # ========================================================== + + +def _check_request(): + if request.db: + request.env.cr.close() + class RPC(Controller): """Handle RPC connections.""" def _xmlrpc(self, service): """Common method to handle an XML-RPC request.""" + _check_request() data = request.httprequest.get_data() - params, method = xmlrpc.client.loads(data) + params, method = xmlrpc.client.loads(data, use_datetime=True) result = dispatch_rpc(service, method, params) - return xmlrpc.client.dumps((result,), methodresponse=1, allow_none=False) + return dumps((result,)) @route("/xmlrpc/", auth="none", methods=["POST"], csrf=False, save_session=False) def xmlrpc_1(self, service): @@ -134,6 +146,7 @@ class RPC(Controller): This entrypoint is historical and non-compliant, but kept for backwards-compatibility. """ + _check_request() try: response = self._xmlrpc(service) except Exception as error: @@ -147,6 +160,7 @@ class RPC(Controller): @route("/xmlrpc/2/", auth="none", methods=["POST"], csrf=False, save_session=False) def xmlrpc_2(self, service): """XML-RPC service that returns faultCode as int.""" + _check_request() try: response = self._xmlrpc(service) except Exception as error: @@ -160,4 +174,5 @@ class RPC(Controller): @route('/jsonrpc', type='json', auth="none", save_session=False) def jsonrpc(self, service, method, args): """ Method used by client APIs to contact OpenERP. """ + _check_request() return dispatch_rpc(service, method, args) diff --git a/odoo-bringout-oca-ocb-base/odoo/addons/base/data/ir_config_parameter_data.xml b/odoo-bringout-oca-ocb-base/odoo/addons/base/data/ir_config_parameter_data.xml new file mode 100644 index 00000000..847602ca --- /dev/null +++ b/odoo-bringout-oca-ocb-base/odoo/addons/base/data/ir_config_parameter_data.xml @@ -0,0 +1,9 @@ + + + + + base.default_max_email_size + 10 + + + diff --git a/odoo-bringout-oca-ocb-base/odoo/addons/base/data/ir_cron_data.xml b/odoo-bringout-oca-ocb-base/odoo/addons/base/data/ir_cron_data.xml index badab78b..0676236b 100644 --- a/odoo-bringout-oca-ocb-base/odoo/addons/base/data/ir_cron_data.xml +++ b/odoo-bringout-oca-ocb-base/odoo/addons/base/data/ir_cron_data.xml @@ -7,7 +7,6 @@ model._run_vacuum_cleaner() 1 days - -1 3 @@ -15,9 +14,9 @@ Base: Portal Users Deletion code - model._gc_portal_users() + model._gc_portal_users(batch_size=50) 1 days - -1 + 8 diff --git a/odoo-bringout-oca-ocb-base/odoo/addons/base/data/ir_demo_failure_data.xml b/odoo-bringout-oca-ocb-base/odoo/addons/base/data/ir_demo_failure_data.xml index 5ea6d2bd..4cd62023 100644 --- a/odoo-bringout-oca-ocb-base/odoo/addons/base/data/ir_demo_failure_data.xml +++ b/odoo-bringout-oca-ocb-base/odoo/addons/base/data/ir_demo_failure_data.xml @@ -30,10 +30,10 @@ action = { module(s) failed to install and were disabled - + - +