From 89d27e7dd4abf17333d28d004b9866b5581606c9 Mon Sep 17 00:00:00 2001 From: Jose Zambudio Date: Thu, 25 Jan 2024 07:53:47 +0100 Subject: [PATCH] [FIX] cryptography<23.2.0 instala cryptography==3.4.8 y esta a su vez es incompatible con la dependencia de edi>=36.0.0 --- README.md | 1 - auditlog/i18n/it.po | 42 +- auto_backup/i18n/es.po | 81 +-- fetchmail_attach_from_folder/README.rst | 95 ++++ fetchmail_attach_from_folder/__init__.py | 7 + fetchmail_attach_from_folder/__manifest__.py | 20 + fetchmail_attach_from_folder/i18n/es.po | 494 ++++++++++++++++++ .../i18n/fetchmail_attach_from_folder.pot | 476 +++++++++++++++++ .../match_algorithm/__init__.py | 7 + .../match_algorithm/base.py | 23 + .../match_algorithm/email_domain.py | 32 ++ .../match_algorithm/email_exact.py | 41 ++ .../match_algorithm/odoo_standard.py | 34 ++ .../models/__init__.py | 5 + .../models/fetchmail_server.py | 126 +++++ .../models/fetchmail_server_folder.py | 317 +++++++++++ .../security/ir.model.access.csv | 4 + .../static/description/icon.png | Bin 0 -> 12585 bytes .../tests/__init__.py | 4 + .../tests/test_match_algorithms.py | 157 ++++++ .../views/fetchmail_server.xml | 114 ++++ .../wizard/__init__.py | 3 + .../wizard/attach_mail_manually.py | 101 ++++ .../wizard/attach_mail_manually.xml | 43 ++ nsca_client/i18n/fr.po | 12 - nsca_client/i18n/nsca_client.pot | 12 - requirements.txt | 2 +- setup/_metapackage/VERSION.txt | 2 +- setup/_metapackage/setup.py | 1 - .../odoo/addons/fetchmail_attach_from_folder | 1 + setup/fetchmail_attach_from_folder/setup.py | 6 + 31 files changed, 2174 insertions(+), 89 deletions(-) create mode 100644 fetchmail_attach_from_folder/README.rst create mode 100644 fetchmail_attach_from_folder/__init__.py create mode 100644 fetchmail_attach_from_folder/__manifest__.py create mode 100644 fetchmail_attach_from_folder/i18n/es.po create mode 100644 fetchmail_attach_from_folder/i18n/fetchmail_attach_from_folder.pot create mode 100644 fetchmail_attach_from_folder/match_algorithm/__init__.py create mode 100644 fetchmail_attach_from_folder/match_algorithm/base.py create mode 100644 fetchmail_attach_from_folder/match_algorithm/email_domain.py create mode 100644 fetchmail_attach_from_folder/match_algorithm/email_exact.py create mode 100644 fetchmail_attach_from_folder/match_algorithm/odoo_standard.py create mode 100644 fetchmail_attach_from_folder/models/__init__.py create mode 100644 fetchmail_attach_from_folder/models/fetchmail_server.py create mode 100644 fetchmail_attach_from_folder/models/fetchmail_server_folder.py create mode 100644 fetchmail_attach_from_folder/security/ir.model.access.csv create mode 100644 fetchmail_attach_from_folder/static/description/icon.png create mode 100644 fetchmail_attach_from_folder/tests/__init__.py create mode 100644 fetchmail_attach_from_folder/tests/test_match_algorithms.py create mode 100644 fetchmail_attach_from_folder/views/fetchmail_server.xml create mode 100644 fetchmail_attach_from_folder/wizard/__init__.py create mode 100644 fetchmail_attach_from_folder/wizard/attach_mail_manually.py create mode 100644 fetchmail_attach_from_folder/wizard/attach_mail_manually.xml create mode 120000 setup/fetchmail_attach_from_folder/odoo/addons/fetchmail_attach_from_folder create mode 100644 setup/fetchmail_attach_from_folder/setup.py diff --git a/README.md b/README.md index f449188bab6..900013ee337 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,6 @@ addon | version | maintainers | summary [base_view_inheritance_extension](base_view_inheritance_extension/) | 14.0.1.1.2 | | Adds more operators for view inheritance [bus_alt_connection](bus_alt_connection/) | 14.0.1.0.0 | | Needed when using PgBouncer as a connection pooler [configuration_helper](configuration_helper/) | 14.0.1.0.1 | | Configuration Helper -[cron_daylight_saving_time_resistant](cron_daylight_saving_time_resistant/) | 14.0.1.0.0 | | Run cron on fixed hours [database_cleanup](database_cleanup/) | 14.0.1.0.3 | | Database cleanup [datetime_formatter](datetime_formatter/) | 14.0.1.0.0 | | Helper functions to give correct format to date[time] fields [dbfilter_from_header](dbfilter_from_header/) | 14.0.1.0.1 | | Filter databases with HTTP headers diff --git a/auditlog/i18n/it.po b/auditlog/i18n/it.po index 0636f868262..0fd6092e7d6 100644 --- a/auditlog/i18n/it.po +++ b/auditlog/i18n/it.po @@ -10,7 +10,7 @@ msgstr "" "Project-Id-Version: Odoo Server 9.0c\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-11-26 01:45+0000\n" -"PO-Revision-Date: 2024-04-17 14:08+0000\n" +"PO-Revision-Date: 2024-01-09 22:35+0000\n" "Last-Translator: mymage \n" "Language-Team: Italian (https://www.transifex.com/oca/teams/23907/it/)\n" "Language: it\n" @@ -28,45 +28,45 @@ msgstr "Azione" #. module: auditlog #: model:ir.ui.menu,name:auditlog.menu_audit msgid "Audit" -msgstr "Audit" +msgstr "Verifica" #. module: auditlog #: model:ir.model,name:auditlog.model_auditlog_autovacuum msgid "Auditlog - Delete old logs" -msgstr "Log autid - elimina vecchi log" +msgstr "Log verifica - elimina vecchi log" #. module: auditlog #: model:ir.model,name:auditlog.model_auditlog_http_session msgid "Auditlog - HTTP User session log" -msgstr "Log audit - log sessione utente HTTP" +msgstr "Log verifica - log sessione utente HTTP" #. module: auditlog #: model:ir.model,name:auditlog.model_auditlog_http_request msgid "Auditlog - HTTP request log" -msgstr "Log audit - log richiesta HTTP" +msgstr "Log verifica - log richiesta HTTP" #. module: auditlog #: model:ir.model,name:auditlog.model_auditlog_log msgid "Auditlog - Log" -msgstr "Log audit - log" +msgstr "Log verifica - log" #. module: auditlog #: model:ir.model,name:auditlog.model_auditlog_log_line #: model:ir.model,name:auditlog.model_auditlog_log_line_view msgid "Auditlog - Log details (fields updated)" -msgstr "Log audit - dettagli log (campi aggiornati)" +msgstr "Log verifica - dettagli log (campi aggiornati)" #. module: auditlog #: model:ir.model,name:auditlog.model_auditlog_rule msgid "Auditlog - Rule" -msgstr "Log audit - regola" +msgstr "Log verifica - regola" #. module: auditlog #: model:ir.actions.server,name:auditlog.ir_cron_auditlog_autovacuum_ir_actions_server #: model:ir.cron,cron_name:auditlog.ir_cron_auditlog_autovacuum #: model:ir.cron,name:auditlog.ir_cron_auditlog_autovacuum msgid "Auto-vacuum audit logs" -msgstr "Svuota automaticamente log audit" +msgstr "Svuota automaticamente log verifica" #. module: auditlog #: model:ir.model.fields,field_description:auditlog.field_auditlog_rule__capture_record @@ -209,7 +209,7 @@ msgstr "Richiesta HTTP" #: model_terms:ir.ui.view,arch_db:auditlog.view_auditlog_http_request_search #: model_terms:ir.ui.view,arch_db:auditlog.view_auditlog_http_session_form msgid "HTTP Requests" -msgstr "Richieste HTTP" +msgstr "Richiesta HTTP" #. module: auditlog #: model:ir.model.fields,field_description:auditlog.field_auditlog_autovacuum__id @@ -321,7 +321,7 @@ msgstr "Modello" #. module: auditlog #: model:ir.model.fields,field_description:auditlog.field_auditlog_log_line_view__model_model msgid "Model Model" -msgstr "Modello Model" +msgstr "Modello modello" #. module: auditlog #: model:ir.model.fields,field_description:auditlog.field_auditlog_log__model_name @@ -424,12 +424,12 @@ msgstr "Regole" #. module: auditlog #: model:ir.model.fields,help:auditlog.field_auditlog_rule__model_id msgid "Select model for which you want to generate log." -msgstr "Seleziona modello per il quale si vuole generare un log." +msgstr "Seleziona modello per il quale vuoi generare un log." #. module: auditlog #: model:ir.model.fields,help:auditlog.field_auditlog_rule__capture_record msgid "Select this if you want to keep track of Unlink Record" -msgstr "Selezionare se si vuole tenere traccia di Unlink Record" +msgstr "Seleziona se vuoi seguire \"scollega record\"" #. module: auditlog #: model:ir.model.fields,help:auditlog.field_auditlog_rule__log_create @@ -437,8 +437,8 @@ msgid "" "Select this if you want to keep track of creation on any record of the model " "of this rule" msgstr "" -"Selezionare se si vuole tenere traccia della creazione di qualsiasi record " -"del modello di questa regola" +"Seleziona se vuoi tenere traccia della creazione di qualsiasi record del " +"modello di questa regola" #. module: auditlog #: model:ir.model.fields,help:auditlog.field_auditlog_rule__log_unlink @@ -446,8 +446,8 @@ msgid "" "Select this if you want to keep track of deletion on any record of the model " "of this rule" msgstr "" -"Selezionare se si vuole tenere traccia dell'eliminazione di qualsiasi record " -"del modello di questa regola" +"Seleziona se vuoi tenere traccia dell'eliminazione di qualsiasi record del " +"modello di questa regola" #. module: auditlog #: model:ir.model.fields,help:auditlog.field_auditlog_rule__log_write @@ -455,8 +455,8 @@ msgid "" "Select this if you want to keep track of modification on any record of the " "model of this rule" msgstr "" -"Selezionare se si vuole tenere traccia della modifica di qualsiasi record " -"del modello di questa regola" +"Seleziona se vuoi tenere traccia della modifica di qualsiasi record del " +"modello di questa regola" #. module: auditlog #: model:ir.model.fields,help:auditlog.field_auditlog_rule__log_read @@ -464,8 +464,8 @@ msgid "" "Select this if you want to keep track of read/open on any record of the " "model of this rule" msgstr "" -"Selezionare se si vuole tenere traccia della lettura/apertura di qualsiasi " -"record del modello di questa regola" +"Seleziona se vuoi tenere traccia della lettura/apertura di qualsiasi record " +"del modello di questa regola" #. module: auditlog #: model:ir.model.fields,field_description:auditlog.field_auditlog_http_request__http_session_id diff --git a/auto_backup/i18n/es.po b/auto_backup/i18n/es.po index 6b7abbce589..302bb75ace2 100644 --- a/auto_backup/i18n/es.po +++ b/auto_backup/i18n/es.po @@ -9,15 +9,14 @@ msgstr "" "Project-Id-Version: Odoo Server 11.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-03-03 10:08+0000\n" -"PO-Revision-Date: 2024-04-18 19:36+0000\n" -"Last-Translator: Ivorra78 \n" +"PO-Revision-Date: 2018-03-03 10:08+0000\n" +"Last-Translator: OCA Transbot , 2018\n" "Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.17\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #. module: auto_backup #: model_terms:ir.ui.view,arch_db:auto_backup.view_backup_conf_form @@ -32,12 +31,12 @@ msgstr "Ruta absoluta para almacenar las copias de seguridad" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__message_needaction msgid "Action Needed" -msgstr "Acción Necesaria" +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__message_attachment_count msgid "Attachment Count" -msgstr "Contador de Archivos Adjuntos" +msgstr "" #. module: auto_backup #: model:ir.actions.act_window,name:auto_backup.action_backup_conf_form @@ -59,15 +58,16 @@ msgstr "Error de copia de seguridad" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__backup_format +#, fuzzy msgid "Backup Format" -msgstr "Formato de copia de Seguridad" +msgstr "Error de copia de seguridad" #. module: auto_backup #: model:ir.actions.server,name:auto_backup.ir_cron_backup_scheduler_0_ir_actions_server #: model:ir.cron,cron_name:auto_backup.ir_cron_backup_scheduler_0 #: model:ir.cron,name:auto_backup.ir_cron_backup_scheduler_0 msgid "Backup Scheduler" -msgstr "Planificador de Copia de Seguridad" +msgstr "" #. module: auto_backup #: model:mail.message.subtype,name:auto_backup.mail_message_subtype_success @@ -96,17 +96,18 @@ msgstr "No se puede duplicar una configuración." #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__changeset_change_ids msgid "Changeset Changes" -msgstr "Cambios en el conjunto de cambios" +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__changeset_ids msgid "Changesets" -msgstr "Conjuntos de cambios" +msgstr "" #. module: auto_backup #: model:ir.model.fields,help:auto_backup.field_db_backup__backup_format +#, fuzzy msgid "Choose the format for this backup." -msgstr "Elija el formato para esta copia de seguridad." +msgstr "Elija el método de almacenamiento para esta copia de seguridad." #. module: auto_backup #: model:ir.model.fields,help:auto_backup.field_db_backup__method @@ -136,12 +137,12 @@ msgstr "Prueba de conexión correcta!" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__count_pending_changeset_changes msgid "Count Pending Changeset Changes" -msgstr "Contar los Cambios del Conjunto de Cambios Pendientes" +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__count_pending_changesets msgid "Count Pending Changesets" -msgstr "Contar Conjuntos de Cambios Pendientes" +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__create_uid @@ -156,7 +157,7 @@ msgstr "Creado el" #. module: auto_backup #: model:ir.model,name:auto_backup.model_db_backup msgid "Database Backup" -msgstr "Copia de Seguridad de la base de datos" +msgstr "" #. module: auto_backup #: code:addons/auto_backup/models/db_backup.py:0 @@ -170,12 +171,12 @@ msgstr "La copia de seguridad de la base de datos ha fallado." #: model:mail.message.subtype,description:auto_backup.mail_message_subtype_success #, python-format msgid "Database backup succeeded." -msgstr "La copia de seguridad de la base de datos se realizo correctamente." +msgstr "La copia de seguridad de la base de datos se realizo correctamente" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__days_to_keep msgid "Days To Keep" -msgstr "Días Para Guardar" +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__display_name @@ -194,7 +195,7 @@ msgstr "" #. module: auto_backup #: model_terms:ir.ui.view,arch_db:auto_backup.view_backup_conf_form msgid "Execute backup" -msgstr "Ejecutar copia de seguridad" +msgstr "" #. module: auto_backup #: model:ir.actions.server,name:auto_backup.action_server_backup @@ -209,22 +210,22 @@ msgstr "Carpeta" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__message_follower_ids msgid "Followers" -msgstr "Seguidores" +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__message_channel_ids msgid "Followers (Channels)" -msgstr "Seguidores/as (Canales)" +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__message_partner_ids msgid "Followers (Partners)" -msgstr "Seguidores (Socios)" +msgstr "" #. module: auto_backup #: model_terms:ir.ui.view,arch_db:auto_backup.view_backup_conf_form msgid "Go to Settings / Technical / Automation / Scheduled Actions." -msgstr "Ir a Configuración / Técnico / Automatización / Acciones Planificadas." +msgstr "Ir a Configuración / Técnico / Automatización / Acciones Planificadas" #. module: auto_backup #: model_terms:ir.ui.view,arch_db:auto_backup.view_backup_conf_form @@ -247,17 +248,17 @@ msgstr "ID" #: model:ir.model.fields,help:auto_backup.field_db_backup__message_needaction #: model:ir.model.fields,help:auto_backup.field_db_backup__message_unread msgid "If checked, new messages require your attention." -msgstr "Si está marcado, nuevos mensajes requieren su atención." +msgstr "" #. module: auto_backup #: model:ir.model.fields,help:auto_backup.field_db_backup__message_has_error msgid "If checked, some messages have a delivery error." -msgstr "Si está marcado algunos mensajes requieren su atención." +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__message_is_follower msgid "Is Follower" -msgstr "Es Seguidor/a" +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup____last_update @@ -282,17 +283,17 @@ msgstr "Disco local" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__message_main_attachment_id msgid "Main Attachment" -msgstr "Archivo Adjunto Principal" +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__message_has_error msgid "Message Delivery error" -msgstr "Error de Entrega de Mensajes" +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__message_ids msgid "Messages" -msgstr "Mensajes" +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__method @@ -307,27 +308,27 @@ msgstr "Nombre" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__message_needaction_counter msgid "Number of Actions" -msgstr "Número de Acciones" +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__message_has_error_counter msgid "Number of errors" -msgstr "Número de errores" +msgstr "" #. module: auto_backup #: model:ir.model.fields,help:auto_backup.field_db_backup__message_needaction_counter msgid "Number of messages which requires an action" -msgstr "Número de mensajes que requiere una acción" +msgstr "" #. module: auto_backup #: model:ir.model.fields,help:auto_backup.field_db_backup__message_has_error_counter msgid "Number of messages with delivery error" -msgstr "Número de mensajes con errores de envío" +msgstr "" #. module: auto_backup #: model:ir.model.fields,help:auto_backup.field_db_backup__message_unread_counter msgid "Number of unread messages" -msgstr "Número de mensajes sin leer" +msgstr "" #. module: auto_backup #: model:ir.model.fields,help:auto_backup.field_db_backup__sftp_private_key @@ -384,7 +385,7 @@ msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__smart_search msgid "Smart Search" -msgstr "Búsqueda Inteligente" +msgstr "" #. module: auto_backup #: model:ir.model.fields,help:auto_backup.field_db_backup__name @@ -430,12 +431,12 @@ msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__message_unread msgid "Unread Messages" -msgstr "Número de Mensajes no Leídos" +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__message_unread_counter msgid "Unread Messages Counter" -msgstr "Contador de Mensajes no Leídos" +msgstr "" #. module: auto_backup #: model_terms:ir.ui.view,arch_db:auto_backup.view_backup_conf_form @@ -449,7 +450,7 @@ msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__user_can_see_changeset msgid "User Can See Changeset" -msgstr "El Usuario Puede Ver el Conjunto de Cambios" +msgstr "" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__sftp_user @@ -464,12 +465,12 @@ msgstr "Advertencia:" #. module: auto_backup #: model:ir.model.fields,field_description:auto_backup.field_db_backup__website_message_ids msgid "Website Messages" -msgstr "Mensajes de Sitio Web" +msgstr "" #. module: auto_backup #: model:ir.model.fields,help:auto_backup.field_db_backup__website_message_ids msgid "Website communication history" -msgstr "Histórico de mensajes del sitio web" +msgstr "" #. module: auto_backup #: model_terms:ir.ui.view,arch_db:auto_backup.view_backup_conf_form @@ -479,7 +480,7 @@ msgstr "john" #. module: auto_backup #: model:ir.model.fields.selection,name:auto_backup.selection__db_backup__backup_format__dump msgid "pg_dump custom format (without filestore)" -msgstr "pg_dump formato personalizado (sin filestore)" +msgstr "" #. module: auto_backup #: model_terms:ir.ui.view,arch_db:auto_backup.view_backup_conf_form @@ -489,4 +490,4 @@ msgstr "sftp.example.com" #. module: auto_backup #: model:ir.model.fields.selection,name:auto_backup.selection__db_backup__backup_format__zip msgid "zip (includes filestore)" -msgstr "zip (incluye filestore)" +msgstr "" diff --git a/fetchmail_attach_from_folder/README.rst b/fetchmail_attach_from_folder/README.rst new file mode 100644 index 00000000000..6be026a7101 --- /dev/null +++ b/fetchmail_attach_from_folder/README.rst @@ -0,0 +1,95 @@ +Email gateway - folders +======================= + +Adds the possibility to attach emails from a certain IMAP folder to objects, +ie partners. Matching is done via several algorithms, ie email address, email +address's domain or the original Odoo algorithm. + +This gives a simple possibility to archive emails in Odoo without a mail +client integration. + +Configuration +============= + +In your fetchmail configuration, you'll find a new list field `Folders to +monitor`. Add your folders here in IMAP notation (usually something like +`INBOX.your_folder_name.your_subfolder_name`), choose a model to attach mails +to and a matching algorithm to use. + +Exact mailaddress +----------------- + +Fill in a field to search for the email address in `Field (model)`. For +partners, this would be `email`. Also fill in the header field from the email +to look at in `Field (email)`. If you want to match incoming mails from your +customers, this would be `from`. You can also list header fields, so to match +partners receiving this email, you might fill in `to,cc,bcc`. + +Domain of email addresses +------------------------- + +Match the domain of the email address(es) found in `Field (email)`. This would +attach a mail to `test1@example.com` to a record with `Field (model)` set to +`test2@example.com`. Given that this is a fuzzy match, you probably want to +check `Use 1st match`, because otherwise nothing happens if multiple possible +matches are found. + +Odoo standard +------------- + +This is stricly speaking no matching algorithm, but calls the model's standard +action on new incoming mail, which is usually creating a new record. + +Usage +===== + +A widespread configuration is to have a shared mailbox with several folders, +i.e. one where users drop mails they want to attach to partners. Let this +folder be called `From partners`. Then create a folder configuration for your +server with path `"INBOX.From partners"` (note the quotes because of the space, +this is server dependent). Choose model `Partners`, set `Field (model)` to +`email` and `Field (email)` to `from`. In `Domain`, you could fill in +`[('customer', '=', True)]` to be sure to only match customer records. + +Now when your users drop mails into this folder, they will be fetched by Odoo +and attached to the partner in question. After some testing, you might want to +check `Delete matches` in your folder configuration so that this folder doesn't +grow indefinitely. + + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed feedback. + +Credits +======= + +Contributors +------------ + +* Holger Brunn +* Ronald Portier + +Icon +---- + +http://commons.wikimedia.org/wiki/File:Crystal_Clear_filesystem_folder_favorites.png + +Maintainer +---------- + +.. image:: http://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: http://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit http://odoo-community.org. diff --git a/fetchmail_attach_from_folder/__init__.py b/fetchmail_attach_from_folder/__init__.py new file mode 100644 index 00000000000..afe69370892 --- /dev/null +++ b/fetchmail_attach_from_folder/__init__.py @@ -0,0 +1,7 @@ +# Copyright - 2013-2018 Therp BV . +# Copyright - 2020 Aures Tic Consultors S.L . +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import match_algorithm +from . import models +from . import wizard diff --git a/fetchmail_attach_from_folder/__manifest__.py b/fetchmail_attach_from_folder/__manifest__.py new file mode 100644 index 00000000000..ceb6f5d68b6 --- /dev/null +++ b/fetchmail_attach_from_folder/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright - 2013-2018 Therp BV . +# Copyright - 2022 Aures Tic Consultors S.L . +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + "name": "Email gateway - folders", + "summary": "Attach mails in an IMAP folder to existing objects", + "version": "14.0.1.0.0", + "author": "Aures Tic, Therp BV,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/server-tools", + "license": "AGPL-3", + "category": "Tools", + "depends": ["fetchmail"], + "data": [ + "views/fetchmail_server.xml", + "wizard/attach_mail_manually.xml", + "security/ir.model.access.csv", + ], + "installable": True, + "auto_install": False, +} diff --git a/fetchmail_attach_from_folder/i18n/es.po b/fetchmail_attach_from_folder/i18n/es.po new file mode 100644 index 00000000000..744708acbce --- /dev/null +++ b/fetchmail_attach_from_folder/i18n/es.po @@ -0,0 +1,494 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * fetchmail_attach_from_folder +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-03-24 07:30+0000\n" +"PO-Revision-Date: 2023-03-24 07:30+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: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__action_id +msgid "Action" +msgstr "Acción" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__active +msgid "Active" +msgstr "Activo" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "Archived" +msgstr "Archivado" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/wizard/attach_mail_manually.py:0 +#, python-format +msgid "Attach emails manually" +msgstr "Adjuntar emails automáticamente" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_attach_mail_manually +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "Attach mail manually" +msgstr "Adjuntar email manualmente" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server__folders_available +msgid "Available folders" +msgstr "Carpetas disponibles" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__body +msgid "Body" +msgstr "Cuerpo" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_attach_mail_manually +msgid "Cancel" +msgstr "Cancelar" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server__folders_only +msgid "" +"Check this field to leave imap inbox alone and only retrieve mail from " +"configured folders." +msgstr "" +"Active este campo para omitir la bandeja de entrada del imap y sólo recibir emails de " +"las carpetas configuradas." + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server.py:0 +#, python-format +msgid "Confirm connection first." +msgstr "Confirmar conexión primero" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields.selection,name:fetchmail_attach_from_folder.selection__fetchmail_server_folder__state__done +msgid "Confirmed" +msgstr "Confirmado" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server_folder.py:0 +#, python-format +msgid "Could not fetch %s in %s on %s" +msgstr "No se puede buscar %s en %s en %s" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server_folder.py:0 +#, python-format +msgid "Could not open mailbox %s on %s" +msgstr "No se puede abrir el correo %s en %s" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server_folder.py:0 +#, python-format +msgid "Could not search mailbox %s on %s" +msgstr "No se puede buscar el correo %s en %s" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server__object_id +msgid "Create a New Record" +msgstr "Crear un nuevo registro" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__create_uid +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__create_uid +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__create_uid +msgid "Created by" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__create_date +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__create_date +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__create_date +msgid "Created on" +msgstr "Creado por" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__date +msgid "Date" +msgstr "Fecha" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__delete_matching +msgid "Delete matched emails from server" +msgstr "Eliminar emails coincidentes del servidor" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__delete_matching +msgid "Delete matches" +msgstr "Eliminar coincidencias" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__display_name +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__display_name +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__display_name +msgid "Display Name" +msgstr "Nombre a mostrar" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__domain +msgid "Domain" +msgstr "Dominio" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__mail_ids +msgid "Emails" +msgstr "Emails" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "Fetch folder now" +msgstr "Buscar carpeta ahora" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__mail_field +msgid "Field (email)" +msgstr "Campo (email)" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__model_field +msgid "Field (model)" +msgstr "Campo (modelo)" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__model_order +msgid "" +"Field(s) to order by, this mostly useful in conjunction with 'Use 1st match'" +msgstr "" +"Campo(s) a ordenar, más útil si se usa junto con 'Usar 1ª coincidencia'" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__domain +msgid "Fill in a search filter to narrow down objects to match" +msgstr "Rellene un filtro de búsqueda para limitar los objetos para que coincidan" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__flag_nonmatching +msgid "Flag emails in the server that don't match any object in Odoo" +msgstr "Marcar correos electrónicos en el servidor que no coincidan con ningún objeto en Odoo" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__flag_nonmatching +msgid "Flag nonmatching" +msgstr "Marcar no coincidentes" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__folder_id +msgid "Folder" +msgstr "Carpeta" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server__folder_ids +msgid "Folders" +msgstr "Carpetas" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "Folders available on server" +msgstr "Carpetas disponibles en el servidor" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "Folders to monitor" +msgstr "Carpetas a revisar" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__email_from +msgid "From" +msgstr "De" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server_folder.py:0 +#, python-format +msgid "General failure when trying to connect to %s server %s." +msgstr "Error general al intentar conectarse al servidor %s %s" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__id +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__id +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__id +msgid "ID" +msgstr "ID" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "INBOX.subfolder1" +msgstr "ENTRADA.subcarpeta1" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__match_first +msgid "" +"If there are multiple matches, use the first one. If not checked, multiple " +"matches count as no match at all" +msgstr "" +"Si hay varias coincidencias, utilice la primera. Si no está marcada, múltiples " +"las coincidencias cuentan como ninguna coincidencia en absoluto" + +#. module: fetchmail_attach_from_folder +#: model:ir.model,name:fetchmail_attach_from_folder.model_fetchmail_server +msgid "Incoming Mail Server" +msgstr "Servidor de correo entrante" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server_folder.py:0 +#, python-format +msgid "Invalid folder %s!" +msgstr "Carpeta no válida folder %s!" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually____last_update +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail____last_update +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder____last_update +msgid "Last Modified on" +msgstr "Última actualización En" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__write_uid +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__write_uid +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__write_uid +msgid "Last Updated by" +msgstr "Última actualización de" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__write_date +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__write_date +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__write_date +msgid "Last Updated on" +msgstr "Última actualización en" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server_folder.py:0 +#, python-format +msgid "Mail attachment" +msgstr "Adjunto de Email" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__match_algorithm +msgid "Match algorithm" +msgstr "Algoritmo de coincidencias" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__msgid +msgid "Message id" +msgstr "Id Mensaje" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__msg_state +msgid "Message state" +msgstr "Estado Mensaje" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__model_id +msgid "Model" +msgstr "Modelo" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__name +msgid "Name" +msgstr "Nombre" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields.selection,name:fetchmail_attach_from_folder.selection__fetchmail_server_folder__state__draft +msgid "Not Confirmed" +msgstr "No Confirmado" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__object_id +msgid "Object" +msgstr "Objeto" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server__folders_only +msgid "Only folders, not inbox" +msgstr "Sólo carpetas, no Bandeja de Entrada" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__action_id +msgid "" +"Optional custom server action to trigger for each incoming mail, on the " +"record that was created or updated by this mail" +msgstr "" +"Acción de servidor personalizado opcional para activar para cada correo " +"entrante, en el registro que fue creado o actualizado por este correo" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__model_order +msgid "Order (model)" +msgstr "Órden (modelo)" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__path +msgid "Path" +msgstr "Ruta" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server__object_id +msgid "" +"Process each incoming mail as part of a conversation corresponding to this " +"document type. This will create new documents for new conversations, or " +"attach follow-up emails to the existing conversations (documents)." +msgstr "" +"Procesa cada correo entrante como parte de una conversación correspondiente " +"a este tipo de documento. Esto creará nuevos documentos para nuevas " +"conversaciones, o adjuntará correos electrónicos de seguimiento a las " +"conversaciones existentes (documentos)." + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields.selection,name:fetchmail_attach_from_folder.selection__fetchmail_server_folder__msg_state__received +msgid "Received" +msgstr "Recibido" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "Reset Confirmation" +msgstr "Resetear Confirmación" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_attach_mail_manually +msgid "Save" +msgstr "Guardar" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields.selection,name:fetchmail_attach_from_folder.selection__fetchmail_server_folder__msg_state__sent +msgid "Sent" +msgstr "Enviado" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__sequence +msgid "Sequence" +msgstr "Secuencia" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__server_id +msgid "Server" +msgstr "Servidor" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server__server_type +msgid "Server Type" +msgstr "Tipo de servidor" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__state +msgid "Status" +msgstr "Estado" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__subject +msgid "Subject" +msgstr "Asunto" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "Test & Confirm" +msgstr "Probar y Confirmar" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__match_algorithm +msgid "The algorithm used to determine which object an email matches." +msgstr "El algoritmo utilizado para determinar con qué objeto coincide un correo electrónico." + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__mail_field +msgid "" +"The field in the email used for matching. Typically this is 'to' or 'from'" +msgstr "" +"El campo del correo electrónico utilizado para la coincidencia. Por lo general, esto es 'para' o 'de'" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__model_field +msgid "" +"The field in your model that contains the field to match against.\n" +"Examples:\n" +"'email' if your model is res.partner, or 'partner_id.email' if you're matching sale orders" +msgstr "" +"El campo en su modelo que contiene el campo con el que comparar.\n" +"Ejemplos:\n" +"'email' si su modelo es res.partner, o 'partner_id.email' si está " +"buscando pedidos de venta coincidentes" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__model_id +msgid "The model to attach emails to" +msgstr "El modelo para adjuntar correos electrónicos" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__path +msgid "" +"The path to your mail folder. Typically would be something like " +"'INBOX.myfolder'" +msgstr "" +"La ruta a su carpeta de email. Algo como 'INBOX." +"micarpeta'" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__msg_state +msgid "The state messages fetched from this folder should be assigned in Odoo" +msgstr "Los mensajes de estado obtenidos de esta carpeta deben asignarse en Odoo" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server.py:0 +#, python-format +msgid "Unable to retrieve folders." +msgstr "No se pueden leer las carpetas" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__match_first +msgid "Use 1st match" +msgstr "Usar primera coincidencia" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__wizard_id +msgid "Wizard" +msgstr "Asistente" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "[('state', '=', 'open')]" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "email" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model,name:fetchmail_attach_from_folder.model_fetchmail_attach_mail_manually +msgid "fetchmail.attach.mail.manually" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model,name:fetchmail_attach_from_folder.model_fetchmail_attach_mail_manually_mail +msgid "fetchmail.attach.mail.manually.mail" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model,name:fetchmail_attach_from_folder.model_fetchmail_server_folder +msgid "fetchmail.server.folder" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "name asc,type desc" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_attach_mail_manually +msgid "or" +msgstr "o" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "to,from" +msgstr "para,de" diff --git a/fetchmail_attach_from_folder/i18n/fetchmail_attach_from_folder.pot b/fetchmail_attach_from_folder/i18n/fetchmail_attach_from_folder.pot new file mode 100644 index 00000000000..fee87bea433 --- /dev/null +++ b/fetchmail_attach_from_folder/i18n/fetchmail_attach_from_folder.pot @@ -0,0 +1,476 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * fetchmail_attach_from_folder +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-03-23 07:29+0000\n" +"PO-Revision-Date: 2023-03-23 07:29+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: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__action_id +msgid "Action" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__active +msgid "Active" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "Archived" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/wizard/attach_mail_manually.py:0 +#, python-format +msgid "Attach emails manually" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_attach_mail_manually +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "Attach mail manually" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server__folders_available +msgid "Available folders" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__body +msgid "Body" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_attach_mail_manually +msgid "Cancel" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server__folders_only +msgid "" +"Check this field to leave imap inbox alone and only retrieve mail from " +"configured folders." +msgstr "" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server.py:0 +#, python-format +msgid "Confirm connection first." +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields.selection,name:fetchmail_attach_from_folder.selection__fetchmail_server_folder__state__done +msgid "Confirmed" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server_folder.py:0 +#, python-format +msgid "Could not fetch %s in %s on %s" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server_folder.py:0 +#, python-format +msgid "Could not open mailbox %s on %s" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server_folder.py:0 +#, python-format +msgid "Could not search mailbox %s on %s" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server__object_id +msgid "Create a New Record" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__create_uid +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__create_uid +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__create_uid +msgid "Created by" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__create_date +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__create_date +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__create_date +msgid "Created on" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__date +msgid "Date" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__delete_matching +msgid "Delete matched emails from server" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__delete_matching +msgid "Delete matches" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__display_name +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__display_name +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__display_name +msgid "Display Name" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__domain +msgid "Domain" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__mail_ids +msgid "Emails" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "Fetch folder now" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__mail_field +msgid "Field (email)" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__model_field +msgid "Field (model)" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__model_order +msgid "" +"Field(s) to order by, this mostly useful in conjunction with 'Use 1st match'" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__domain +msgid "Fill in a search filter to narrow down objects to match" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__flag_nonmatching +msgid "Flag emails in the server that don't match any object in Odoo" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__flag_nonmatching +msgid "Flag nonmatching" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__folder_id +msgid "Folder" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server__folder_ids +msgid "Folders" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "Folders available on server" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "Folders to monitor" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__email_from +msgid "From" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server_folder.py:0 +#, python-format +msgid "General failure when trying to connect to %s server %s." +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__id +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__id +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__id +msgid "ID" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "INBOX.subfolder1" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__match_first +msgid "" +"If there are multiple matches, use the first one. If not checked, multiple " +"matches count as no match at all" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model,name:fetchmail_attach_from_folder.model_fetchmail_server +msgid "Incoming Mail Server" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server_folder.py:0 +#, python-format +msgid "Invalid folder %s!" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually____last_update +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail____last_update +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder____last_update +msgid "Last Modified on" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__write_uid +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__write_uid +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__write_date +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__write_date +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__write_date +msgid "Last Updated on" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server_folder.py:0 +#, python-format +msgid "Mail attachment" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__match_algorithm +msgid "Match algorithm" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__msgid +msgid "Message id" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__msg_state +msgid "Message state" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__model_id +msgid "Model" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually__name +msgid "Name" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields.selection,name:fetchmail_attach_from_folder.selection__fetchmail_server_folder__state__draft +msgid "Not Confirmed" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__object_id +msgid "Object" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server__folders_only +msgid "Only folders, not inbox" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__action_id +msgid "" +"Optional custom server action to trigger for each incoming mail, on the " +"record that was created or updated by this mail" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__model_order +msgid "Order (model)" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__path +msgid "Path" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server__object_id +msgid "" +"Process each incoming mail as part of a conversation corresponding to this " +"document type. This will create new documents for new conversations, or " +"attach follow-up emails to the existing conversations (documents)." +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields.selection,name:fetchmail_attach_from_folder.selection__fetchmail_server_folder__msg_state__received +msgid "Received" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "Reset Confirmation" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_attach_mail_manually +msgid "Save" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields.selection,name:fetchmail_attach_from_folder.selection__fetchmail_server_folder__msg_state__sent +msgid "Sent" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__sequence +msgid "Sequence" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__server_id +msgid "Server" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server__server_type +msgid "Server Type" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__state +msgid "Status" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__subject +msgid "Subject" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "Test & Confirm" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__match_algorithm +msgid "The algorithm used to determine which object an email matches." +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__mail_field +msgid "" +"The field in the email used for matching. Typically this is 'to' or 'from'" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__model_field +msgid "" +"The field in your model that contains the field to match against.\n" +"Examples:\n" +"'email' if your model is res.partner, or 'partner_id.email' if you're matching sale orders" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__model_id +msgid "The model to attach emails to" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__path +msgid "" +"The path to your mail folder. Typically would be something like " +"'INBOX.myfolder'" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,help:fetchmail_attach_from_folder.field_fetchmail_server_folder__msg_state +msgid "The state messages fetched from this folder should be assigned in Odoo" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: code:addons/fetchmail_attach_from_folder/models/fetchmail_server.py:0 +#, python-format +msgid "Unable to retrieve folders." +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_server_folder__match_first +msgid "Use 1st match" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model.fields,field_description:fetchmail_attach_from_folder.field_fetchmail_attach_mail_manually_mail__wizard_id +msgid "Wizard" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "[('state', '=', 'open')]" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "email" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model,name:fetchmail_attach_from_folder.model_fetchmail_attach_mail_manually +msgid "fetchmail.attach.mail.manually" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model,name:fetchmail_attach_from_folder.model_fetchmail_attach_mail_manually_mail +msgid "fetchmail.attach.mail.manually.mail" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model:ir.model,name:fetchmail_attach_from_folder.model_fetchmail_server_folder +msgid "fetchmail.server.folder" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "name asc,type desc" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_attach_mail_manually +msgid "or" +msgstr "" + +#. module: fetchmail_attach_from_folder +#: model_terms:ir.ui.view,arch_db:fetchmail_attach_from_folder.view_email_server_form_inh_faff +msgid "to,from" +msgstr "" diff --git a/fetchmail_attach_from_folder/match_algorithm/__init__.py b/fetchmail_attach_from_folder/match_algorithm/__init__.py new file mode 100644 index 00000000000..9c036b169de --- /dev/null +++ b/fetchmail_attach_from_folder/match_algorithm/__init__.py @@ -0,0 +1,7 @@ +# Copyright - 2013-2018 Therp BV . +# Copyright - 2020 Aures Tic Consultors S.L . +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import base +from . import email_exact +from . import email_domain +from . import odoo_standard diff --git a/fetchmail_attach_from_folder/match_algorithm/base.py b/fetchmail_attach_from_folder/match_algorithm/base.py new file mode 100644 index 00000000000..336b81f4196 --- /dev/null +++ b/fetchmail_attach_from_folder/match_algorithm/base.py @@ -0,0 +1,23 @@ +# Copyright - 2013-2018 Therp BV . +# Copyright - 2020 Aures Tic Consultors S.L . +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +class Base(object): + name = None # Name shown to the user + + # Fields on fetchmail_server folder required for this algorithm + required_fields = [] + + # Fields on fetchmail_server folder readonly for this algorithm + readonly_fields = [] + + def search_matches(self, folder, mail_message): + """Returns recordset found for model with mail_message.""" + return [] + + def handle_match( + self, connection, match_object, folder, mail_message, mail_message_org, msgid + ): + """Do whatever it takes to handle a match""" + folder.attach_mail(match_object, mail_message) diff --git a/fetchmail_attach_from_folder/match_algorithm/email_domain.py b/fetchmail_attach_from_folder/match_algorithm/email_domain.py new file mode 100644 index 00000000000..dc300ca902d --- /dev/null +++ b/fetchmail_attach_from_folder/match_algorithm/email_domain.py @@ -0,0 +1,32 @@ +# Copyright - 2013-2018 Therp BV . +# Copyright - 2020 Aures Tic Consultors S.L . +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from .email_exact import EmailExact + + +class EmailDomain(EmailExact): + """Search objects by domain name of email address. + + Beware of match_first here, this is most likely to get it wrong (gmail). + """ + + name = "Domain of email address" + + def search_matches(self, folder, mail_message): + """Returns recordset of matching objects.""" + matches = super(EmailDomain, self).search_matches(folder, mail_message) + if not matches: + object_model = folder.env[folder.model_id.model] + domains = [] + for addr in self._get_mailaddresses(folder, mail_message): + domains.append(addr.split("@")[-1]) + matches = object_model.search( + self._get_mailaddress_search_domain( + folder, + mail_message, + operator="like", + values=["%@" + domain for domain in set(domains)], + ), + order=folder.model_order, + ) + return matches diff --git a/fetchmail_attach_from_folder/match_algorithm/email_exact.py b/fetchmail_attach_from_folder/match_algorithm/email_exact.py new file mode 100644 index 00000000000..6730b3bf316 --- /dev/null +++ b/fetchmail_attach_from_folder/match_algorithm/email_exact.py @@ -0,0 +1,41 @@ +# Copyright - 2013-2018 Therp BV . +# Copyright - 2020 Aures Tic Consultors S.L . +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from odoo.tools.mail import email_split +from odoo.tools.safe_eval import safe_eval + +from .base import Base + + +class EmailExact(Base): + """Search for exactly the mailadress as noted in the email""" + + name = "Exact mailadress" + required_fields = ["model_field", "mail_field"] + + def _get_mailaddresses(self, folder, mail_message): + mailaddresses = [] + fields = folder.mail_field.split(",") + for field in fields: + if field in mail_message: + mailaddresses += email_split(mail_message[field]) + return [addr.lower() for addr in mailaddresses] + + def _get_mailaddress_search_domain( + self, folder, mail_message, operator="=", values=None + ): + mailaddresses = values or self._get_mailaddresses(folder, mail_message) + if not mailaddresses: + return [(0, "=", 1)] + search_domain = ( + (["|"] * (len(mailaddresses) - 1)) + + [(folder.model_field, operator, addr) for addr in mailaddresses] + + safe_eval(folder.domain or "[]") + ) + return search_domain + + def search_matches(self, folder, mail_message): + """Returns recordset of matching objects.""" + object_model = folder.env[folder.model_id.model] + search_domain = self._get_mailaddress_search_domain(folder, mail_message) + return object_model.search(search_domain, order=folder.model_order) diff --git a/fetchmail_attach_from_folder/match_algorithm/odoo_standard.py b/fetchmail_attach_from_folder/match_algorithm/odoo_standard.py new file mode 100644 index 00000000000..eb1ebcc2488 --- /dev/null +++ b/fetchmail_attach_from_folder/match_algorithm/odoo_standard.py @@ -0,0 +1,34 @@ +# Copyright - 2013-2018 Therp BV . +# Copyright - 2020 Aures Tic Consultors S.L . +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from .base import Base + + +class OdooStandard(Base): + """No search at all. Use Odoo's standard mechanism to attach mails to + mail.thread objects. Note that this algorithm always matches.""" + + name = "Odoo standard" + readonly_fields = [ + "model_field", + "mail_field", + "match_first", + "domain", + "model_order", + "flag_nonmatching", + ] + + def search_matches(self, folder, mail_message): + """Always match. Duplicates will be fished out by message_id""" + return [True] + + def handle_match( + self, connection, match_object, folder, mail_message, mail_message_org, msgid + ): + thread_model = folder.env["mail.thread"] + return thread_model.message_process( + folder.model_id.model, + mail_message_org, + save_original=folder.server_id.original, + strip_attachments=(not folder.server_id.attach), + ) diff --git a/fetchmail_attach_from_folder/models/__init__.py b/fetchmail_attach_from_folder/models/__init__.py new file mode 100644 index 00000000000..cda3b9ef3f0 --- /dev/null +++ b/fetchmail_attach_from_folder/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright - 2013-2018 Therp BV . +# Copyright - 2020 Aures Tic Consultors S.L . +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import fetchmail_server +from . import fetchmail_server_folder diff --git a/fetchmail_attach_from_folder/models/fetchmail_server.py b/fetchmail_attach_from_folder/models/fetchmail_server.py new file mode 100644 index 00000000000..a4c11c6bd49 --- /dev/null +++ b/fetchmail_attach_from_folder/models/fetchmail_server.py @@ -0,0 +1,126 @@ +# Copyright - 2013-2018 Therp BV . +# Copyright - 2020 Aures Tic Consultors S.L . +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +import json +import logging +import re + +from lxml import etree + +from odoo import _, api, fields, models +from odoo.tools.misc import UnquoteEvalContext +from odoo.tools.safe_eval import safe_eval + +_logger = logging.getLogger(__name__) + +list_response_pattern = re.compile( + r'\((?P.*?)\) "(?P.*)" (?P.*)' +) + + +class FetchmailServer(models.Model): + _inherit = "fetchmail.server" + + folders_available = fields.Text( + string="Available folders", compute="_compute_folders_available", readonly=True + ) + folder_ids = fields.One2many( + comodel_name="fetchmail.server.folder", + inverse_name="server_id", + string="Folders", + context={"active_test": False}, + ) + object_id = fields.Many2one(required=False) # comodel_name='ir.model' + server_type = fields.Selection(default="imap") + folders_only = fields.Boolean( + string="Only folders, not inbox", + help="Check this field to leave imap inbox alone" + " and only retrieve mail from configured folders.", + ) + + def _compute_folders_available(self): + """Retrieve available folders from IMAP server.""" + + def parse_list_response(line): + flags, delimiter, mailbox_name = list_response_pattern.match( + line.decode("utf-8") + ).groups() + mailbox_name = mailbox_name.strip('"') + return (flags, delimiter, mailbox_name) + + for this in self: + if this.state != "done": + this.folders_available = _("Confirm connection first.") + continue + connection = this.connect() + list_result = connection.list() + if list_result[0] != "OK": + this.folders_available = _("Unable to retrieve folders.") + continue + folders_available = [] + for folder_entry in list_result[1]: + folders_available.append(parse_list_response(folder_entry)[2]) + this.folders_available = "\n".join(folders_available) + connection.logout() + + @api.onchange("server_type", "is_ssl", "object_id") + def onchange_server_type(self): + super(FetchmailServer, self).onchange_server_type() + self.state = "draft" + + def fetch_mail(self): + for this in self: + if not this.folders_only: + super(FetchmailServer, this).fetch_mail() + this.folder_ids.fetch_mail() + + @api.model + def fields_view_get( + self, view_id=None, view_type="form", toolbar=False, submenu=False + ): + """Set modifiers for form fields in folder_ids depending on algorithm. + + A field will be readonly and/or required if this is specified in the + algorithm. + """ + result = super(FetchmailServer, self).fields_view_get( + view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu + ) + if view_type == "form": + view = etree.fromstring( + result["fields"]["folder_ids"]["views"]["form"]["arch"] + ) + modifiers = {} + docstr = "" + folder_model = self.env["fetchmail.server.folder"] + match_algorithms = folder_model._get_match_algorithms() + for algorithm in list(match_algorithms.values()): + for modifier in ["required", "readonly"]: + for field in getattr(algorithm, modifier + "_fields"): + modifiers.setdefault(field, {}) + modifiers[field].setdefault(modifier, []) + if modifiers[field][modifier]: + modifiers[field][modifier].insert(0, "|") + modifiers[field][modifier].append( + ("match_algorithm", "==", algorithm.__name__) + ) + docstr += _(algorithm.name) + "\n" + _(algorithm.__doc__) + "\n\n" + for field in view.xpath("//field"): + if field.tag == "field" and field.get("name") in modifiers: + patched_modifiers = ( + field.attrib["modifiers"] + .replace("false", "False") + .replace("true", "True") + ) + original_dict = safe_eval( + patched_modifiers, UnquoteEvalContext({}), nocopy=True + ) + modifier_dict = modifiers[field.attrib["name"]] + combined_dict = dict(original_dict, **modifier_dict) + field.set("modifiers", json.dumps(combined_dict)) + if field.tag == "field" and field.get("name") == "match_algorithm": + field.set("help", docstr) + result["fields"]["folder_ids"]["views"]["form"]["arch"] = etree.tostring( + view + ) + return result diff --git a/fetchmail_attach_from_folder/models/fetchmail_server_folder.py b/fetchmail_attach_from_folder/models/fetchmail_server_folder.py new file mode 100644 index 00000000000..fe28f90d890 --- /dev/null +++ b/fetchmail_attach_from_folder/models/fetchmail_server_folder.py @@ -0,0 +1,317 @@ +# Copyright - 2013-2018 Therp BV . +# Copyright - 2020 Aures Tic Consultors S.L . +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +import base64 +import email +import email.policy +import logging + +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError + +from .. import match_algorithm + +_logger = logging.getLogger(__name__) + + +class FetchmailServerFolder(models.Model): + _name = "fetchmail.server.folder" + _rec_name = "path" + _order = "sequence" + + server_id = fields.Many2one(comodel_name="fetchmail.server", string="Server") + sequence = fields.Integer(string="Sequence") + state = fields.Selection( + selection=[("draft", "Not Confirmed"), ("done", "Confirmed")], + string="Status", + readonly=True, + required=True, + copy=False, + default="draft", + ) + path = fields.Char( + string="Path", + required=True, + help="The path to your mail folder." + " Typically would be something like 'INBOX.myfolder'", + ) + model_id = fields.Many2one( + comodel_name="ir.model", + string="Model", + required=True, + help="The model to attach emails to", + ondelete="cascade", + ) + model_field = fields.Char( + string="Field (model)", + help="The field in your model that contains the field to match " + "against.\nExamples:\n" + "'email' if your model is res.partner, or " + "'partner_id.email' if you're matching sale orders", + ) + model_order = fields.Char( + string="Order (model)", + help="Field(s) to order by, this mostly useful in conjunction " + "with 'Use 1st match'", + ) + match_algorithm = fields.Selection( + selection=lambda s: s._get_match_algorithms_sel(), + string="Match algorithm", + required=True, + help="The algorithm used to determine which object an email matches.", + ) + mail_field = fields.Char( + string="Field (email)", + help="The field in the email used for matching. Typically " + "this is 'to' or 'from'", + ) + delete_matching = fields.Boolean( + string="Delete matches", help="Delete matched emails from server" + ) + flag_nonmatching = fields.Boolean( + string="Flag nonmatching", + default=True, + help="Flag emails in the server that don't match any object in Odoo", + ) + match_first = fields.Boolean( + string="Use 1st match", + help="If there are multiple matches, use the first one. If " + "not checked, multiple matches count as no match at all", + ) + domain = fields.Char( + string="Domain", help="Fill in a search filter to narrow down objects to match" + ) + msg_state = fields.Selection( + selection=[("sent", "Sent"), ("received", "Received")], + string="Message state", + default="received", + help="The state messages fetched from this folder should be " + "assigned in Odoo", + ) + active = fields.Boolean(string="Active", default=True) + action_id = fields.Many2one( + comodel_name="ir.actions.server", + name="Server action", + help="Optional custom server action to trigger for each incoming " + "mail, on the record that was created or updated by this mail", + ) + + @api.model + def _get_match_algorithms(self): + def get_all_subclasses(cls): + return cls.__subclasses__() + [ + subsub + for sub in cls.__subclasses__() + for subsub in get_all_subclasses(sub) + ] + + return { + cls.__name__: cls for cls in get_all_subclasses(match_algorithm.base.Base) + } + + @api.model + def _get_match_algorithms_sel(self): + algorithms = [] + for cls in list(self._get_match_algorithms().values()): + algorithms.append((cls.__name__, cls.name)) + algorithms.sort() + return algorithms + + def get_algorithm(self): + return self._get_match_algorithms()[self.match_algorithm]() + + def button_confirm_folder(self): + for this in self: + this.write({"state": "draft"}) + if not this.active: + continue + connection = this.server_id.connect() + connection.select() + if connection.select(this.path)[0] != "OK": + raise ValidationError(_("Invalid folder %s!") % this.path) + connection.close() + this.write({"state": "done"}) + + def button_attach_mail_manually(self): + self.ensure_one() + return { + "type": "ir.actions.act_window", + "res_model": "fetchmail.attach.mail.manually", + "target": "new", + "context": dict(self.env.context, folder_id=self.id), + "view_mode": "form", + } + + def set_draft(self): + self.write({"state": "draft"}) + return True + + def get_msgids(self, connection, criteria): + """Return imap ids of messages to process""" + self.ensure_one() + server = self.server_id + _logger.info( + "start checking for emails in folder %s on server %s", + self.path, + server.name, + ) + if connection.select(self.path)[0] != "OK": + raise UserError( + _("Could not open mailbox %s on %s") % (self.path, server.name) + ) + result, msgids = connection.search(None, criteria) + if result != "OK": + raise UserError( + _("Could not search mailbox %s on %s") % (self.path, server.name) + ) + _logger.info( + "finished checking for emails in %s on server %s", self.path, server.name + ) + return msgids + + def fetch_msg(self, connection, msgid): + """Select a single message from a folder.""" + self.ensure_one() + server = self.server_id + result, msgdata = connection.fetch(msgid, "(RFC822)") + if result != "OK": + raise UserError( + _("Could not fetch %s in %s on %s") % (msgid, self.path, server.server) + ) + message_org = msgdata[0][1] # rfc822 message source + message = email.message_from_string(str(message_org), policy=email.policy.SMTP) + mail_message = self.env["mail.thread"].message_parse( + message, save_original=server.original + ) + return (mail_message, message_org) + + def retrieve_imap_folder(self, connection): + """Retrieve all mails for one IMAP folder.""" + self.ensure_one() + msgids = self.get_msgids(connection, "UNDELETED") + match_algorithm = self.get_algorithm() + for msgid in msgids[0].split(): + # We will accept exceptions for single messages + try: + self.env.cr.execute("savepoint apply_matching") + self.apply_matching(connection, msgid, match_algorithm) + self.env.cr.execute("release savepoint apply_matching") + except Exception: + self.env.cr.execute("rollback to savepoint apply_matching") + _logger.exception( + "Failed to fetch mail %s from %s", msgid, self.server_id.name + ) + + def fetch_mail(self): + """Retrieve all mails for IMAP folders. + + We will use a separate connection for each folder. + """ + for this in self: + if not this.active or this.state != "done": + continue + connection = None + try: + # New connection per folder + connection = this.server_id.connect() + this.retrieve_imap_folder(connection) + connection.close() + except Exception: + _logger.error( + _("General failure when trying to connect to %s server %s."), + this.server_id.server_type, + this.server_id.name, + exc_info=True, + ) + finally: + if connection: + connection.logout() + + def update_msg(self, connection, msgid, matched=True, flagged=False): + """Update msg in imap folder depending on match and settings.""" + if matched: + if self.delete_matching: + connection.store(msgid, "+FLAGS", "\\DELETED") + elif flagged and self.flag_nonmatching: + connection.store(msgid, "-FLAGS", "\\FLAGGED") + else: + if self.flag_nonmatching: + connection.store(msgid, "+FLAGS", "\\FLAGGED") + + def apply_matching(self, connection, msgid, match_algorithm): + """Return ids of objects matched""" + self.ensure_one() + mail_message, message_org = self.fetch_msg(connection, msgid) + if self.env["mail.message"].search( + [("message_id", "=", mail_message["message_id"])] + ): + # Ignore mails that have been handled already + return + matches = match_algorithm.search_matches(self, mail_message) + matched = matches and (len(matches) == 1 or self.match_first) + if matched: + thread_id = match_algorithm.handle_match( + connection, matches[0], self, mail_message, message_org, msgid + ) + self.run_server_action(thread_id) + self.update_msg(connection, msgid, matched=matched) + + def run_server_action(self, matched_object_ids): + self.ensure_one() + action = self.action_id + if not action: + return + records = self.env[self.model_id.model].browse(matched_object_ids) + for record in records: + if not record.exists(): + continue + action.with_context( + **{ + "active_id": record.id, + "active_ids": record.ids, + "active_model": self.model_id.model, + } + ).run() + + def attach_mail(self, match_object, mail_message): + """Attach mail to match_object.""" + self.ensure_one() + partner = False + model_name = self.model_id.model + if model_name == "res.partner": + partner = match_object + elif "partner_id" in self.env[model_name]._fields: + partner = match_object.partner_id + attachments = [] + if self.server_id.attach and mail_message.get("attachments"): + for attachment in mail_message["attachments"]: + # Attachment should at least have filename and data, but + # might have some extra element(s) + if len(attachment) < 2: + continue + fname, fcontent = attachment[:2] + if isinstance(fcontent, str): + fcontent = fcontent.encode("utf-8") + data_attach = { + "name": fname, + "datas": base64.b64encode(bytes(fcontent)), + "store_fname": fname, + "description": _("Mail attachment"), + "res_model": model_name, + "res_id": match_object.id, + } + attachments.append(self.env["ir.attachment"].create(data_attach)) + self.env["mail.message"].create( + { + "author_id": partner and partner.id or False, + "model": model_name, + "res_id": match_object.id, + "message_type": "email", + "body": mail_message.get("body"), + "subject": mail_message.get("subject"), + "email_from": mail_message.get("from"), + "date": mail_message.get("date"), + "message_id": mail_message.get("message_id"), + "attachment_ids": [(6, 0, [a.id for a in attachments])], + } + ) diff --git a/fetchmail_attach_from_folder/security/ir.model.access.csv b/fetchmail_attach_from_folder/security/ir.model.access.csv new file mode 100644 index 00000000000..aa76c3c87da --- /dev/null +++ b/fetchmail_attach_from_folder/security/ir.model.access.csv @@ -0,0 +1,4 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_model_fetchmail_server_folder,fetchmail.server.folder,model_fetchmail_server_folder,base.group_system,1,1,1,1 +access_model_fetchmail_attach_mail_manually,fetchmail.attach.mail.manually,model_fetchmail_attach_mail_manually,base.group_system,1,1,1,1 +access_model_fetchmail_attach_mail_manually_mail,fetchmail.attach.mail.manually.mail,model_fetchmail_attach_mail_manually_mail,base.group_system,1,1,1,1 diff --git a/fetchmail_attach_from_folder/static/description/icon.png b/fetchmail_attach_from_folder/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..be54e22b8851ded0aa8c0b0f1a016f2631b8f8a3 GIT binary patch literal 12585 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
    qqW8o`fjhYut8Px(1DfDuZqyuEthX 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 literal 0 HcmV?d00001 diff --git a/fetchmail_attach_from_folder/tests/__init__.py b/fetchmail_attach_from_folder/tests/__init__.py new file mode 100644 index 00000000000..fbaacb305be --- /dev/null +++ b/fetchmail_attach_from_folder/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright - 2015-2018 Therp BV . +# Copyright - 2020 Aures Tic Consultors S.L . +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import test_match_algorithms diff --git a/fetchmail_attach_from_folder/tests/test_match_algorithms.py b/fetchmail_attach_from_folder/tests/test_match_algorithms.py new file mode 100644 index 00000000000..e5709618610 --- /dev/null +++ b/fetchmail_attach_from_folder/tests/test_match_algorithms.py @@ -0,0 +1,157 @@ +# Copyright - 2015-2018 Therp BV . +# Copyright - 2020 Aures Tic Consultors S.L . +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from odoo import models +from odoo.tests.common import TransactionCase + +from ..match_algorithm import email_domain, email_exact, odoo_standard + +MSG_BODY = [ + ( + "1 (RFC822 {1149}", + "Return-Path: \r\n" + "Delivered-To: demo@yourcompany.example.com\r\n" + "Received: from localhost (localhost [127.0.0.1])\r\n" + "\tby vanaheim.acme.com (Postfix) with ESMTP id 14A3183163\r\n" + "\tfor ;" + " Mon, 26 Mar 2018 16:03:52 +0200 (CEST)\r\n" + "To: Test User \r\n" + "From: Ronald Portier \r\n" + "Subject: test\r\n" + "Message-ID: <485a8041-d560-a981-5afc-d31c1f136748@acme.com>\r\n" + "Date: Mon, 26 Mar 2018 16:03:51 +0200\r\n" + "User-Agent: Mock Test\r\n" + "MIME-Version: 1.0\r\n" + "Content-Type: text/plain; charset=utf-8\r\n" + "Content-Language: en-US\r\n" + "Content-Transfer-Encoding: 7bit\r\n\r\n" + "Hallo Wereld!\r\n", + ), + ")", +] + + +class MockConnection: + def select(self, path): + """Mock selecting a folder.""" + return ("OK",) + + def store(self, msgid, msg_item, value): + """Mock store command.""" + return "OK" + + def fetch(self, msgid, parts): + """Return RFC822 formatted message.""" + return ("OK", MSG_BODY) + + def search(self, charset, criteria): + """Return some msgid's.""" + return ("OK", ["123 456"]) + + +class TestMatchAlgorithms(TransactionCase): + def _get_base_folder(self): + server_model = self.env["fetchmail.server"] + folder_model = self.env["fetchmail.server.folder"] + folder = folder_model.browse([models.NewId()]) + folder.model_id = self.env.ref("base.model_res_partner").id + folder.model_field = "email" + folder.match_algorithm = "EmailExact" + folder.mail_field = "to,from" + folder.server_id = server_model.browse([models.NewId()]) + return folder + + def do_matching( + self, + match_algorithm, + expected_xmlid, + folder, + mail_message, + mail_message_org=None, + ): + matcher = match_algorithm() + matches = matcher.search_matches(folder, mail_message) + self.assertEqual(len(matches), 1) + self.assertEqual(matches[0], self.env.ref(expected_xmlid)) + connection = MockConnection() + matcher.handle_match( + connection, matches[0], folder, mail_message, mail_message_org, None + ) + + def test_email_exact(self): + mail_message = { + "subject": "Testsubject", + "to": "addison.olson28@example.com", + "from": "someone@else.com", + } + folder = self._get_base_folder() + folder.match_algorithm = "EmailExact" + self.do_matching( + email_exact.EmailExact, "base.res_partner_address_31", folder, mail_message + ) + self.assertEqual( + self.env.ref("base.res_partner_address_31").message_ids.subject, + mail_message["subject"], + ) + + def test_email_domain(self): + mail_message = { + "subject": "Testsubject", + "to": "addison.olson28@example.com", + "from": "someone@else.com", + "attachments": [("hello.txt", "Hello World!")], + } + folder = self._get_base_folder() + folder.match_algorithm = "EmailDomain" + self.do_matching( + email_domain.EmailDomain, + "base.res_partner_address_31", + folder, + mail_message, + ) + self.assertEqual( + self.env.ref("base.res_partner_address_31").message_ids.subject, + mail_message["subject"], + ) + + def test_odoo_standard(self): + mail_message_org = ( + "To: demo@yourcompany.example.com\n" + "From: someone@else.com\n" + "Subject: testsubject\n" + "Message-Id: 42\n" + "Hello world" + ) + folder = self._get_base_folder() + folder.match_algorithm = "OdooStandard" + matcher = odoo_standard.OdooStandard() + matches = matcher.search_matches(folder, None) + self.assertEqual(len(matches), 1) + matcher.handle_match(None, matches[0], folder, None, mail_message_org, None) + self.assertIn( + "Hello world", + self.env["mail.message"].search([("subject", "=", "testsubject")]).body, + ) + + def test_apply_matching_exact(self): + folder = self._get_base_folder() + folder.match_algorithm = "EmailExact" + connection = MockConnection() + msgid = "<485a8041-d560-a981-5afc-d31c1f136748@acme.com>" + matcher = email_exact.EmailExact() + folder.apply_matching(connection, msgid, matcher) + + def test_retrieve_imap_folder_domain(self): + folder = self._get_base_folder() + folder.match_algorithm = "EmailDomain" + connection = MockConnection() + folder.retrieve_imap_folder(connection) + + def test_field_view_get(self): + """For the moment just check execution withouth errors.""" + server_model = self.env["fetchmail.server"] + view = server_model.fields_view_get() + self.assertTrue(view) + self.assertIn( + b"match_algorithm", view["fields"]["folder_ids"]["views"]["form"]["arch"] + ) diff --git a/fetchmail_attach_from_folder/views/fetchmail_server.xml b/fetchmail_attach_from_folder/views/fetchmail_server.xml new file mode 100644 index 00000000000..ff5eb4be93d --- /dev/null +++ b/fetchmail_attach_from_folder/views/fetchmail_server.xml @@ -0,0 +1,114 @@ + + + + + fetchmail.server.form + fetchmail.server + + + + {'required': [('server_type', '!=', 'imap')]} + + + + + + + + + + + + + + + + + + + +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    +
    +
    +
    + +
    diff --git a/fetchmail_attach_from_folder/wizard/__init__.py b/fetchmail_attach_from_folder/wizard/__init__.py new file mode 100644 index 00000000000..adb296dfecb --- /dev/null +++ b/fetchmail_attach_from_folder/wizard/__init__.py @@ -0,0 +1,3 @@ +# Copyright - 2013-2018 Therp BV . +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import attach_mail_manually diff --git a/fetchmail_attach_from_folder/wizard/attach_mail_manually.py b/fetchmail_attach_from_folder/wizard/attach_mail_manually.py new file mode 100644 index 00000000000..ec0cf5d1b26 --- /dev/null +++ b/fetchmail_attach_from_folder/wizard/attach_mail_manually.py @@ -0,0 +1,101 @@ +# Copyright 2013-2018 Therp BV . +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +import logging + +from odoo import _, api, fields, models + +_logger = logging.getLogger(__name__) + + +class AttachMailManually(models.TransientModel): + _name = "fetchmail.attach.mail.manually" + + name = fields.Char() + folder_id = fields.Many2one("fetchmail.server.folder", "Folder", readonly=True) + mail_ids = fields.One2many( + "fetchmail.attach.mail.manually.mail", "wizard_id", "Emails" + ) + + @api.model + def _prepare_mail(self, folder, msgid, mail_message): + return { + "msgid": msgid, + "subject": mail_message.get("subject", ""), + "date": mail_message.get("date", ""), + "body": mail_message.get("body", ""), + "email_from": mail_message.get("from", ""), + "object_id": "%s,-1" % folder.model_id.model, + } + + @api.model + def default_get(self, fields_list): + defaults = super(AttachMailManually, self).default_get(fields_list) + if not fields_list or "name" in fields_list: + defaults["name"] = _("Attach emails manually") + defaults["mail_ids"] = [] + folder_model = self.env["fetchmail.server.folder"] + folder_id = self.env.context.get("folder_id") + defaults["folder_id"] = folder_id + folder = folder_model.browse([folder_id]) + connection = folder.server_id.connect() + connection.select(folder.path) + criteria = "FLAGGED" if folder.flag_nonmatching else "UNDELETED" + msgids = folder.get_msgids(connection, criteria) + for msgid in msgids[0].split(): + mail_message, message_org = folder.fetch_msg(connection, msgid) + defaults["mail_ids"].append( + (0, 0, self._prepare_mail(folder, msgid, mail_message)) + ) + connection.close() + return defaults + + def attach_mails(self): + self.ensure_one() + folder = self.folder_id + server = folder.server_id + connection = server.connect() + connection.select(folder.path) + for mail in self.mail_ids: + if not mail.object_id: + continue + msgid = mail.msgid + mail_message, message_org = folder.fetch_msg(connection, msgid) + folder.attach_mail(mail.object_id, mail_message) + folder.update_msg( + connection, msgid, matched=True, flagged=folder.flag_nonmatching + ) + connection.close() + return {"type": "ir.actions.act_window_close"} + + @api.model + def fields_view_get( + self, view_id=None, view_type="form", toolbar=False, submenu=False + ): + result = super(AttachMailManually, self).fields_view_get( + view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu + ) + if view_type != "form": + return result + folder_model = self.env["fetchmail.server.folder"] + folder_id = self.env.context.get("folder_id") + folder = folder_model.browse([folder_id]) + form = result["fields"]["mail_ids"]["views"]["form"] + form["fields"]["object_id"]["selection"] = [ + (folder.model_id.model, folder.model_id.name) + ] + return result + + +class AttachMailManuallyMail(models.TransientModel): + _name = "fetchmail.attach.mail.manually.mail" + + wizard_id = fields.Many2one("fetchmail.attach.mail.manually", readonly=True) + msgid = fields.Char("Message id", readonly=True) + subject = fields.Char("Subject", readonly=True) + date = fields.Datetime("Date", readonly=True) + email_from = fields.Char("From", readonly=True) + body = fields.Html("Body", readonly=True) + object_id = fields.Reference( + lambda self: [(m.model, m.name) for m in self.env["ir.model"].search([])], + string="Object", + ) diff --git a/fetchmail_attach_from_folder/wizard/attach_mail_manually.xml b/fetchmail_attach_from_folder/wizard/attach_mail_manually.xml new file mode 100644 index 00000000000..10750a2a91b --- /dev/null +++ b/fetchmail_attach_from_folder/wizard/attach_mail_manually.xml @@ -0,0 +1,43 @@ + + + + + fetchmail.attach.mail.manually + fetchmail.attach.mail.manually + +
    + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    + +
    diff --git a/nsca_client/i18n/fr.po b/nsca_client/i18n/fr.po index 63e2f21f9df..5540a6d09aa 100644 --- a/nsca_client/i18n/fr.po +++ b/nsca_client/i18n/fr.po @@ -81,13 +81,6 @@ msgstr "" msgid "Add Followers" msgstr "" -#. module: nsca_client -#: model:ir.model.fields,help:nsca_client.field_nsca_check__daylight_saving_time_resistant -msgid "" -"Adjust interval to run at the same hour after and beforedaylight saving time " -"change. It's used twice a year" -msgstr "" - #. module: nsca_client #: model:ir.model.fields,field_description:nsca_client.field_nsca_check__allow_void_result msgid "Allow void result" @@ -193,11 +186,6 @@ msgstr "Créé le" msgid "Cron" msgstr "Cron" -#. module: nsca_client -#: model:ir.model.fields,field_description:nsca_client.field_nsca_check__daylight_saving_time_resistant -msgid "Daylight Saving Time Resistant" -msgstr "" - #. module: nsca_client #: model:ir.model.fields,field_description:nsca_client.field_nsca_check__display_name #: model:ir.model.fields,field_description:nsca_client.field_nsca_server__display_name diff --git a/nsca_client/i18n/nsca_client.pot b/nsca_client/i18n/nsca_client.pot index a1547ee1d97..06f0e751695 100644 --- a/nsca_client/i18n/nsca_client.pot +++ b/nsca_client/i18n/nsca_client.pot @@ -78,13 +78,6 @@ msgstr "" msgid "Add Followers" msgstr "" -#. module: nsca_client -#: model:ir.model.fields,help:nsca_client.field_nsca_check__daylight_saving_time_resistant -msgid "" -"Adjust interval to run at the same hour after and beforedaylight saving time" -" change. It's used twice a year" -msgstr "" - #. module: nsca_client #: model:ir.model.fields,field_description:nsca_client.field_nsca_check__allow_void_result msgid "Allow void result" @@ -184,11 +177,6 @@ msgstr "" msgid "Cron" msgstr "" -#. module: nsca_client -#: model:ir.model.fields,field_description:nsca_client.field_nsca_check__daylight_saving_time_resistant -msgid "Daylight Saving Time Resistant" -msgstr "" - #. module: nsca_client #: model:ir.model.fields,field_description:nsca_client.field_nsca_check__display_name #: model:ir.model.fields,field_description:nsca_client.field_nsca_server__display_name diff --git a/requirements.txt b/requirements.txt index 1b8561a56a4..6b357692fa1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ acme astor contextvars; python_version < '3.7' -cryptography<23.2.0 +cryptography<39 dataclasses dnspython josepy diff --git a/setup/_metapackage/VERSION.txt b/setup/_metapackage/VERSION.txt index 4f19ff39fd0..26adf59211e 100644 --- a/setup/_metapackage/VERSION.txt +++ b/setup/_metapackage/VERSION.txt @@ -1 +1 @@ -14.0.20240404.0 \ No newline at end of file +14.0.20240223.0 \ No newline at end of file diff --git a/setup/_metapackage/setup.py b/setup/_metapackage/setup.py index 5758cae096e..6cceed3cdbd 100644 --- a/setup/_metapackage/setup.py +++ b/setup/_metapackage/setup.py @@ -48,7 +48,6 @@ 'odoo14-addon-base_view_inheritance_extension', 'odoo14-addon-bus_alt_connection', 'odoo14-addon-configuration_helper', - 'odoo14-addon-cron_daylight_saving_time_resistant', 'odoo14-addon-database_cleanup', 'odoo14-addon-datetime_formatter', 'odoo14-addon-dbfilter_from_header', diff --git a/setup/fetchmail_attach_from_folder/odoo/addons/fetchmail_attach_from_folder b/setup/fetchmail_attach_from_folder/odoo/addons/fetchmail_attach_from_folder new file mode 120000 index 00000000000..feaa017cea0 --- /dev/null +++ b/setup/fetchmail_attach_from_folder/odoo/addons/fetchmail_attach_from_folder @@ -0,0 +1 @@ +../../../../fetchmail_attach_from_folder \ No newline at end of file diff --git a/setup/fetchmail_attach_from_folder/setup.py b/setup/fetchmail_attach_from_folder/setup.py new file mode 100644 index 00000000000..28c57bb6403 --- /dev/null +++ b/setup/fetchmail_attach_from_folder/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)