EDI

edi_core_oca
REPOSITORY
REPOSITORYOCA/edi-framework
GIT
GIThttps://github.com/OCA/edi-framework.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/edi-framework/tree/19.0/edi_core_oca
VERSION
VERSION 1.2.5
CATEGORY
CATEGORYUncategorized
LICENSE
LICENSELGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), Dixmit, Camptocamp, ACSONE
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), Dixmit, Camptocamp, ACSONE
COMMITTERS
COMMITTERSGuewen Baconnier, Enric Tobella, Weblate, OCA-git-bot, Iván Todorovich, SilvioC2C, oca-ci, Ricardoalso, ThiagoMForgeFlow
WEBSITE
WEBSITEhttps://github.com/OCA/edi-framework
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 19:40:48
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/edi:
    - base_edi
odoo/odoo:
    - base
    - mail
    - base_setup
    - web
    - bus
    - web_tour
    - html_editor
    - base_sparse_field
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES PyYAML
openupgradelib
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
Base EDI backend.

Provides following models:

1.  EDI Backend, to centralize configuration
2.  EDI Backend Type, to classify EDI backends (eg: UBL, GS1, e-invoice,
    pick-yours)
3.  EDI Exchange Type, to define file types of exchange
4.  EDI Exchange Record, to define a record exchanged between systems

Also define a mixin to be inherited by records that will generate EDIs.

In addition, the module ships an ``edi.configuration`` mechanism that lets
users react to EDI events declaratively, by writing small Python snippets
attached to event triggers. This can be used as a lightweight alternative
to component event listeners: configurations can react globally (on any
exchange) or be scoped to a specific partner (or any related record),
exchange type, backend and target model. See ``CONFIGURE.md`` for details.

Code Analysis

Views touched (24)
XML IDNameModelTypeStatus
edi_backend_type_view_form edi.backend.type form New
edi_backend_type_view_search edi.backend.type search New
edi_backend_type_view_tree edi.backend.type list New
edi_backend_view_form edi.backend form New
edi_backend_view_search edi.backend search New
edi_backend_view_tree edi.backend list New
edi_configuration_trigger_view_form edi.configuration.trigger form New
edi_configuration_trigger_view_tree edi.configuration.trigger list New
edi_configuration_view_form edi.configuration form New
edi_configuration_view_search edi.configuration.view.search edi.configuration search New
edi_configuration_view_tree edi.configuration list New
edi_exchange_consumer_mixin_buttons edi_exchange_consumer_mixin_buttons ir.ui.view qweb New
edi_exchange_record_create_form_view edi.exchange.record.create.wiz.form (in edi) edi.exchange.record.create.wiz form New
edi_exchange_record_view_form edi.exchange.record form New
edi_exchange_record_view_search edi.exchange.record search New
edi_exchange_record_view_tree edi.exchange.record list New
edi_exchange_type_rule_view_form edi.exchange.type.rule form New
edi_exchange_type_rule_view_search edi.exchange.type.rule search New
edi_exchange_type_rule_view_tree edi.exchange.type.rule list New
edi_exchange_type_view_form edi.exchange.type form New
edi_exchange_type_view_search edi.exchange.type search New
edi_exchange_type_view_tree edi.exchange.type list New
message_edi_exchange_link message_edi_exchange_link ir.ui.view qweb New
view_partner_form res.partner.view.form res.partner xpath Inherits base.view_partner_form
Models touched (19)

New fields (8)
  • active Boolean
    default=True
  • auto_archive_records_after_days Integer
    default=0 help='Automatically archive EDI exchange records after X days. Set to <= 0 to disable auto-archiving.' string='Auto-archive records after (days)'
  • auto_delete_records_after_days Integer
    default=0 help='Automatically delete archived EDI exchange records after X days. Set to <= 0 to disable auto-deletion.' string='Auto-delete archived records after (days)'
  • backend_type_code Char
    related='backend_type_id.code'
  • backend_type_id Many2one → edi.backend.type
    comodel_name='edi.backend.type' ondelete='restrict' required=True string='EDI Backend type'
  • company_id Many2one → res.company
    string='Company' args: 'res.company'
  • name Char
    required=True
  • output_sent_processed_auto Boolean
    help='\n Automatically set the record as processed after sending.\n Usecase: the web service you send the file to processes it on the fly.\n '
Public methods (9)
  • action_view_exchange_types(self)
  • action_view_exchanges(self)
  • create_record(self, type_code, values)
    Create an exchange record for current backend. :param type_code: edi.exchange.type code :param values: edi.exchange.record values :return: edi.exchange.record record
  • exchange_generate(self, exchange_record, store=True, force=False, **kw)
    Generate output content for given exchange record. :param exchange_record: edi.exchange.record recordset :param store: store output on the record itself :param force: allow to re-generate the content :param kw: keyword args to be propagated to output generate handler
  • exchange_generate_send(self, recordset, skip_generate=False, skip_send=False)
    Generate and send output files for given records. If both are False, the record will be generated and sent right away with chained jobs. If both `skip_generate` and `skip_send` are True, nothing will be done. :param recordset: edi.exchange.record recordset :param skip_generate: only send records :param skip_send: only generate missing output
  • exchange_process(self, exchange_record)
    Process an incoming document.
  • exchange_receive(self, exchange_record)
    Retrieve an incoming document.
  • exchange_record_model(self)
    @property
  • exchange_send(self, exchange_record)
    Send exchange file.

New fields (2)
  • code Char
    inverse='_inverse_code' required=True
  • name Char
    required=True
Public methods (1)
  • copy_data(self, default=None)

New fields (12)
  • active Boolean
    default=True
  • backend_id Many2one → edi.backend
    comodel_name='edi.backend'
  • description Char
    help='Describe what the conf is for'
  • is_global Boolean
    default=False help='If checked, this configuration will be executed for all records, regardless of the partner relation.' string='Global Configuration'
  • model_id Many2one → ir.model
    help='Model the conf applies to. Leave blank to apply for all models' string='Model' args: 'ir.model'
  • model_name Char
    related='model_id.model' store=True string='Model tech name'
  • name Char
    required=True
  • snippet_before_do Text
    help='Snippet to validate the state and collect records to do'
  • snippet_do Text
    help='Used to do something specific here.\n Receives: operation, edi_action, vals, old_vals.'
  • trigger Char
    related='trigger_id.code'
  • trigger_id Many2one → edi.configuration.trigger
    comodel_name='edi.configuration.trigger' domain="['|', ('model_id', '=', model_id), ('model_id', '=', False)]" help='Trigger that activates this configuration'
  • type_id Many2one → edi.exchange.type
    bypass_search_access=True comodel_name='edi.exchange.type' index=True ondelete='cascade' string='Exchange Type'
Public methods (5)
  • action_view_partners(self)
  • edi_exec_snippet_before_do(self, record, **kwargs)
  • edi_exec_snippet_do(self, record, **kwargs)
  • edi_get_conf(self, trigger, backend=None)
  • edi_get_conf_global(self, exchange_record, trigger)
    @api.model
    Return active global configurations matching the given event. Unlike :meth:`edi_get_conf` -- which runs on a recordset of configurations already linked to a partner -- global configurations are not bound to any partner. We therefore have to derive the filtering keys from the originating exchange record: * ``trigger`` must match the event code * ``is_global`` must be True * ``type_id`` must match the exchange type or be empty (applies to all) * ``backend_id`` must match the backend or be empty (applies to all) * ``model_name`` must match the related record model or be empty (applies to all)

New fields (5)
  • active Boolean
    default=True
  • code Char
    copy=False required=True
  • description Char
    help='Describe what the conf is for'
  • model_id Many2one → ir.model
    help='Model the conf applies to. Leave blank to apply for all models' args: 'ir.model'
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (7)
  • edi_disable_auto Boolean
    help='When marked, EDI automatic processing will be avoided' string='Disable auto'
  • edi_has_form_config Boolean
    compute='_compute_edi_config'
  • exchange_record_count Integer
    compute='_compute_exchange_record_count'
  • exchange_record_ids One2many → edi.exchange.record
    compute='_compute_exchange_record_ids' args: 'edi.exchange.record'
  • exchange_related_record_ids One2many → edi.exchange.related.record
    domain=<expr> inverse_name='res_id' args: 'edi.exchange.related.record'
  • origin_exchange_record_id Many2one → edi.exchange.record
    comodel_name='edi.exchange.record' copy=False help='EDI record that originated this document.' ondelete='set null' string='EDI origin record'
  • origin_exchange_type_id Many2one → edi.exchange.type
    comodel_name='edi.exchange.type' copy=False ondelete='set null' related='origin_exchange_record_id.type_id' store=True string='EDI origin exchange type'
Public methods (6)
  • action_view_edi_records(self)
  • create(self, mvals)
    @api.model_create_multi
  • edi_create_exchange_record(self, exchange_type_id)
  • get_edi_access(self, doc_ids, operation, model_name=False)
    @api.model
    Retrieve access policy. The behavior is similar to `mail.thread` and `mail.message` and it relies on the access rules defines on the related record. The behavior can be customized on the related model by defining `_edi_exchange_record_access`. By default `write`, otherwise the custom permission is returned.
  • get_view(self, view_id=None, view_type='form', **options)
    @api.model
  • write(self, vals)

New fields (26)
  • ack_exchange_id Many2one → edi.exchange.record
    comodel_name='edi.exchange.record' compute='_compute_ack_exchange_id' help='ACK generated for current exchange.' index=True store=True string='ACK exchange'
  • ack_expected Boolean
    compute='_compute_ack_expected'
  • ack_received_on Datetime
    related='ack_exchange_id.exchanged_on' string='ACK received on'
  • active Boolean
    default=True
  • backend_id Many2one → edi.backend
    comodel_name='edi.backend' required=True
  • company_id Many2one → res.company
    string='Company' args: 'res.company'
  • direction Selection
    related='type_id.direction'
  • edi_exchange_state Selection
    copy=False default='new' index=True readonly=True selection=[('new', 'New'), ('validate_error', 'Error on validation'), ('output_pending', 'Waiting to be sent'), ('output_error_on_send', 'error on send'), ('output_sent', 'Sent'), ('output_sent_and_processed', 'Sent and processed'), ('output_sent_and_error', 'Sent and error'), ('input_pending', 'Waiting to be received'), ('input_received', 'Received'), ('input_receive_error', 'Error on reception'), ('input_processed', 'Processed'), ('input_processed_error', 'Error on process')] string='Exchange state'
  • exchange_error Text
    copy=False readonly=True string='Exchange error'
  • exchange_error_traceback Text
    copy=False readonly=True string='Exchange error traceback'
  • exchange_file Binary
    attachment=True copy=False
  • exchange_file_frozen Boolean
    compute='_compute_exchange_file_frozen' compute_sudo=True help='Not allowed to change the file anymore.'
  • exchange_filechecksum Char
    compute='_compute_exchange_filechecksum' readonly=True store=True tracking=True
  • exchange_filename Char
    compute='_compute_exchange_filename' readonly=False store=True
  • exchanged_on Datetime
    compute='_compute_exchanged_on' help='Sent or received on this date.' readonly=True store=True
  • external_identifier Char
    copy=False index=True readonly=True
  • identifier Char
    copy=False index=True readonly=True required=True
  • model Char
    compute='_compute_record' copy=False index=True inverse='_inverse_record' readonly=False required=False store=True
  • parent_id Many2one → edi.exchange.record
    comodel_name='edi.exchange.record' help='Original exchange which originated this record' index=True
  • related_exchange_ids One2many → edi.exchange.record
    comodel_name='edi.exchange.record' inverse_name='parent_id' string='Related exchanges'
  • related_name Char
    compute='_compute_related_name' compute_sudo=True
  • related_record_exists Boolean
    compute='_compute_related_record_exists'
  • related_record_ids One2many → edi.exchange.related.record
    comodel_name='edi.exchange.related.record' inverse_name='exchange_record_id' string='Related records'
  • res_id Many2oneReference
    compute='_compute_record' copy=False index=True inverse='_inverse_record' model_field='model' readonly=False required=False store=True string='Record'
  • retryable Boolean
    compute='_compute_retryable' help='The record state can be rolled back manually in case of failure.'
  • type_id Many2one → edi.exchange.type
    bypass_search_access=True comodel_name='edi.exchange.type' index=True ondelete='cascade' required=True string='Exchange type'
Public methods (19)
  • action_exchange_generate(self, **kw)
  • action_exchange_generate_send(self, **kw)
  • action_exchange_generate_send_chained(self)
  • action_exchange_process(self)
  • action_exchange_receive(self)
  • action_exchange_send(self)
  • action_open_related_exchanges(self)
  • action_open_related_record(self)
  • action_regenerate(self)
  • action_retry(self)
  • check_access(self, operation)
    In order to check if we can access a record, we are checking if we can access the related document
  • create(self, vals_list)
    @api.model_create_multi
  • exchange_create_ack_record(self, **kw)
  • exchange_create_child_record(self, exc_type=None, **kw)
  • needs_ack(self)
  • notify_action_complete(self, action, message=None)
    Notify current record that an edi action has been completed. Implementers should take care of calling this method if they work on records w/o calling edi_backend methods (eg: action_send). Implementers can hook to this method to do something after any action ends.
  • read(self, fields=None, load='_classic_read')
    Override to explicitely call check_access_rule, that is not called by the ORM. It instead directly fetches ir.rules and apply them.
  • record(self)
    @property
  • write(self, vals)

New fields (5)
  • backend_id Many2one → edi.backend
    required=True args: 'edi.backend'
  • backend_type_id Many2one → edi.backend.type
    related='exchange_type_id.backend_type_id' args: 'edi.backend.type'
  • exchange_type_id Many2one → edi.exchange.type
    required=True args: 'edi.exchange.type'
  • model Char
    required=True
  • res_id Integer
    required=True
Public methods (1)
  • create_edi(self)

New fields (3)
  • exchange_record_id Many2one → edi.exchange.record
    comodel_name='edi.exchange.record' index=True ondelete='cascade' required=True
  • model Char
    index=True readonly=True required=True
  • res_id Many2oneReference
    copy=False index=True model_field='model' readonly=True required=True string='Record'
Public methods (2)
  • action_open_related_record(self)
  • record(self)
    @property

New fields (29)
  • ack_for_type_ids Many2many → edi.exchange.type
    comodel_name='edi.exchange.type' compute='_compute_ack_for_type_ids' string='Ack for exchange type'
  • ack_type_id Many2one → edi.exchange.type
    comodel_name='edi.exchange.type' help='Identify the type of the ack. If this field is valued it means an hack is expected.' ondelete='set null' string='Ack exchange type'
  • active Boolean
    default=True inverse='_inverse_active'
  • advanced_settings_edit Text
    help='\n Advanced technical settings as YAML format.\n The YAML structure should reproduce a dictionary.\n The backend might use these settings for automated operations.\n\n Currently supported conf:\n\n components:\n generate:\n usage: $comp_usage\n # set a value for component work context\n work_ctx:\n opt1: True\n validate:\n usage: $comp_usage\n env_ctx:\n # set a value for the whole processing env\n opt2: False\n check:\n usage: $comp_usage\n send:\n usage: $comp_usage\n receive:\n usage: $comp_usage\n process:\n usage: $comp_usage\n\n filename_pattern:\n force_tz: Europe/Rome\n date_pattern: %Y-%m-%d-%H-%M-%S\n\n In any case, you can use these settings\n to provide your own configuration for whatever need you might have.\n ' string='Advanced YAML settings'
  • allow_empty_files_on_receive Boolean
    string='Allow Empty Files'
  • backend_id Many2one → edi.backend
    comodel_name='edi.backend' ondelete='set null' string='Backend'
  • backend_type_id Many2one → edi.backend.type
    comodel_name='edi.backend.type' ondelete='restrict' required=True string='Backend type'
  • check_model_id Many2one → ir.model
    domain=[('is_edi_checker', '=', True)] string='Checker' args: 'ir.model'
  • code Char
    copy=False required=True
  • direction Selection
    required=True selection=[('input', 'Input'), ('output', 'Output')]
  • encoding Char
    help="Encoding to be applied to generate/process the exchanged file.\nExample: UTF-8, Windows-1252, ASCII...(default is always 'UTF-8')"
  • encoding_in_error_handler Selection
    help="Handling of decoding errors on process (default is always 'Raise Error')." selection=[('strict', 'Raise Error'), ('ignore', 'Ignore'), ('replace', 'Replace with Replacement Marker'), ('backslashreplace', 'Replace with Backslashed Escape Sequences'), ('surrogateescape', 'Replace Byte with Individual Surrogate Code')] string='Decoding Error Handler'
  • encoding_out_error_handler Selection
    help="Handling of encoding errors on generate (default is always 'Raise Error')." selection=[('strict', 'Raise Error'), ('ignore', 'Ignore'), ('replace', 'Replace with Replacement Marker'), ('backslashreplace', 'Replace with Backslashed Escape Sequences'), ('surrogateescape', 'Replace Byte with Individual Surrogate Code'), ('xmlcharrefreplace', 'Replace with XML/HTML Numeric Character Reference')] string='Encoding Error Handler'
  • exchange_file_auto_generate Boolean
    help='Auto generate output for records missing their payload. If active, a cron will take care of generating the output when not set yet. '
  • exchange_file_ext Char
  • exchange_filename_pattern Char
    default='{record_name}-{type.code}-{dt}' help='For output exchange types this should be a formatting string with the following variables available (to be used between brackets, `{}`): `exchange_record`, `record_name`, `type`, `dt` and `seq`. For instance, a valid string would be {record_name}-{type.code}-{dt}-{seq}\nFor more information:\n- `exchange_record` means exchange record\n- `record_name` means name of the exchange record\n- `type` means code of the exchange record type\n- `dt` means datetime\n- `seq` means sequence. You need a sequence to be defined in `Exchange Filename Sequence` to use `seq`\n'
  • exchange_filename_sequence_id Many2one → ir.sequence
    help='If the `Exchange Filename Pattern` has `{seq}`, you should define a sequence in this field to show the sequence in your filename' args: 'ir.sequence', 'Exchange Filename Sequence'
  • exchange_record_count Integer
    compute='_compute_exchange_record_count' string='# Exchange Records'
  • exchange_record_ids One2many → edi.exchange.record
    comodel_name='edi.exchange.record' inverse_name='type_id'
  • generate_model_id Many2one → ir.model
    domain=[('is_edi_generator', '=', True)] string='Generator' args: 'ir.model'
  • input_validate_model_id Many2one → ir.model
    domain=[('is_edi_input_validator', '=', True)] string='Input Validator' args: 'ir.model'
  • name Char
    required=True
  • output_validate_model_id Many2one → ir.model
    domain=[('is_edi_output_validator', '=', True)] string='Output Validator' args: 'ir.model'
  • partner_ids Many2many → res.partner
    comodel_name='res.partner' help='You can use this field to limit generating/processing exchanges for specific partners. Use it directly or within models rules (domain or snippet).' string='Enabled for partners'
  • process_model_id Many2one → ir.model
    domain=[('is_edi_processor', '=', True)] string='Processor' args: 'ir.model'
  • quick_exec Boolean
    help='When active, records of this type will be processed immediately without waiting for the cron to pass by. Requires auto generate flag to be active as well. The cron will skip these records unless forced.' string='Quick execution'
  • receive_model_id Many2one → ir.model
    domain=[('is_edi_receiver', '=', True)] string='Receiver' args: 'ir.model'
  • rule_ids One2many → edi.exchange.type.rule
    comodel_name='edi.exchange.type.rule' help='Rules to handle exchanges and UI automatically' inverse_name='type_id'
  • send_model_id Many2one → ir.model
    domain=[('is_edi_sender', '=', True)] string='Sender' args: 'ir.model'
Public methods (5)
  • action_view_exchange_records(self)
  • copy_data(self, default=None)
  • get_settings(self)
  • is_partner_enabled(self, partner)
    Check if given partner record is allowed for the current type. You can leverage this in your own logic to trigger or not certain exchanges for specific partners. For instance: a customer might require an ORDRSP while another does not.
  • set_settings(self, val)

New fields (10)
  • active Boolean
    default=True
  • enable_domain Char
    help='Filter domain to be checked on Models' string='Enable on domain'
  • enable_snippet Char
    help='Snippet of code to be checked on Models,\n You can use `record` and `exchange_type` here.\n It will be executed if variable result has been defined as True\n ' string='Enable on snippet'
  • form_btn_label Char
    help='Type name used by default' string='Form button label' translate=True
  • form_btn_tooltip Text
    help='Help message visible as tooltip on button h-over' string='Form button tooltip' translate=True
  • kind Selection
    default='form_btn' help=KIND_HELP required=True selection=[('form_btn', 'Form button'), ('custom', 'Custom')]
  • model Char
    related='model_id.model' args: 'Model code'
  • model_id Many2one → ir.model
    comodel_name='ir.model' help='Apply to this model' ondelete='cascade'
  • name Char
    required=True
  • type_id Many2one → edi.exchange.type
    comodel_name='edi.exchange.type' ondelete='cascade' required=True
Public methods (0)

No public methods.

New fields (1)
  • edi_id Char
    help='Internal or external identifier for records.' string='EDI ID'
Public methods (0)

No public methods.

New fields (0)

No new fields.

Public methods (1)
  • check(self, exchange_record)

New fields (0)

No new fields.

Public methods (1)
  • generate(self, exchange_record)

New fields (0)

No new fields.

Public methods (1)
  • input_validate(self, exchange_record, **kw)

New fields (0)

No new fields.

Public methods (1)
  • output_validate(self, exchange_record, **kw)

New fields (0)

No new fields.

Public methods (1)
  • process(self, exchange_record)

New fields (0)

No new fields.

Public methods (1)
  • receive(self, exchange_record)

New fields (0)

No new fields.

Public methods (1)
  • send(self, exchange_record)

New fields (7)
  • is_edi_checker Boolean
  • is_edi_generator Boolean
  • is_edi_input_validator Boolean
  • is_edi_output_validator Boolean
  • is_edi_processor Boolean
  • is_edi_receiver Boolean
  • is_edi_sender Boolean
Public methods (0)

No public methods.

REPOSITORY
REPOSITORYOCA/edi-framework
GIT
GIThttps://github.com/OCA/edi-framework.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/edi-framework/tree/18.0/edi_core_oca
VERSION
VERSION 1.7.7
CATEGORY
CATEGORYUncategorized
LICENSE
LICENSELGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), Dixmit, Camptocamp, ACSONE
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), Dixmit, Camptocamp, ACSONE
COMMITTERS
COMMITTERSGuewen Baconnier, Enric Tobella, Weblate, OCA-git-bot, Simone Orsi, SilvioC2C, oca-ci, Ricardoalso, ThiagoMForgeFlow, Hadrien Huvelle
WEBSITE
WEBSITEhttps://github.com/OCA/edi-framework
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 19:30:12
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/edi:
    - base_edi
odoo/odoo:
    - base
    - mail
    - base_setup
    - web
    - bus
    - web_tour
    - html_editor
    - base_sparse_field
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES PyYAML
openupgradelib
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
Base EDI backend.

Provides following models:

1.  EDI Backend, to centralize configuration
2.  EDI Backend Type, to classify EDI backends (eg: UBL, GS1, e-invoice,
    pick-yours)
3.  EDI Exchange Type, to define file types of exchange
4.  EDI Exchange Record, to define a record exchanged between systems

Also define a mixin to be inherited by records that will generate EDIs.

In addition, the module ships an ``edi.configuration`` mechanism that lets
users react to EDI events declaratively, by writing small Python snippets
attached to event triggers. This can be used as a lightweight alternative
to component event listeners: configurations can react globally (on any
exchange) or be scoped to a specific partner (or any related record),
exchange type, backend and target model. See ``CONFIGURE.md`` for details.

Code Analysis

Views touched (24)
XML IDNameModelTypeStatus
edi_backend_type_view_form edi.backend.type form New
edi_backend_type_view_search edi.backend.type search New
edi_backend_type_view_tree edi.backend.type list New
edi_backend_view_form edi.backend form New
edi_backend_view_search edi.backend search New
edi_backend_view_tree edi.backend list New
edi_configuration_trigger_view_form edi.configuration.trigger form New
edi_configuration_trigger_view_tree edi.configuration.trigger list New
edi_configuration_view_form edi.configuration form New
edi_configuration_view_search edi.configuration.view.search edi.configuration search New
edi_configuration_view_tree edi.configuration list New
edi_exchange_consumer_mixin_buttons edi_exchange_consumer_mixin_buttons ir.ui.view qweb New
edi_exchange_record_create_form_view edi.exchange.record.create.wiz.form (in edi) edi.exchange.record.create.wiz form New
edi_exchange_record_view_form edi.exchange.record form New
edi_exchange_record_view_search edi.exchange.record search New
edi_exchange_record_view_tree edi.exchange.record list New
edi_exchange_type_rule_view_form edi.exchange.type.rule form New
edi_exchange_type_rule_view_search edi.exchange.type.rule search New
edi_exchange_type_rule_view_tree edi.exchange.type.rule list New
edi_exchange_type_view_form edi.exchange.type form New
edi_exchange_type_view_search edi.exchange.type search New
edi_exchange_type_view_tree edi.exchange.type list New
message_edi_exchange_link message_edi_exchange_link ir.ui.view qweb New
view_partner_form res.partner.view.form res.partner xpath Inherits base.view_partner_form
Models touched (19)

New fields (8)
  • active Boolean
    default=True
  • auto_archive_records_after_days Integer
    default=0 help='Automatically archive EDI exchange records after X days. Set to <= 0 to disable auto-archiving.' string='Auto-archive records after (days)'
  • auto_delete_records_after_days Integer
    default=0 help='Automatically delete archived EDI exchange records after X days. Set to <= 0 to disable auto-deletion.' string='Auto-delete archived records after (days)'
  • backend_type_code Char
    related='backend_type_id.code'
  • backend_type_id Many2one → edi.backend.type
    comodel_name='edi.backend.type' ondelete='restrict' required=True string='EDI Backend type'
  • company_id Many2one → res.company
    string='Company' args: 'res.company'
  • name Char
    required=True
  • output_sent_processed_auto Boolean
    help='\n Automatically set the record as processed after sending.\n Usecase: the web service you send the file to processes it on the fly.\n '
Public methods (9)
  • action_view_exchange_types(self)
  • action_view_exchanges(self)
  • create_record(self, type_code, values)
    Create an exchange record for current backend. :param type_code: edi.exchange.type code :param values: edi.exchange.record values :return: edi.exchange.record record
  • exchange_generate(self, exchange_record, store=True, force=False, **kw)
    Generate output content for given exchange record. :param exchange_record: edi.exchange.record recordset :param store: store output on the record itself :param force: allow to re-generate the content :param kw: keyword args to be propagated to output generate handler
  • exchange_generate_send(self, recordset, skip_generate=False, skip_send=False)
    Generate and send output files for given records. If both are False, the record will be generated and sent right away with chained jobs. If both `skip_generate` and `skip_send` are True, nothing will be done. :param recordset: edi.exchange.record recordset :param skip_generate: only send records :param skip_send: only generate missing output
  • exchange_process(self, exchange_record)
    Process an incoming document.
  • exchange_receive(self, exchange_record)
    Retrieve an incoming document.
  • exchange_record_model(self)
    @property
  • exchange_send(self, exchange_record)
    Send exchange file.

New fields (2)
  • code Char
    inverse='_inverse_code' required=True
  • name Char
    required=True
Public methods (1)
  • copy_data(self, default=None)

New fields (12)
  • active Boolean
    default=True
  • backend_id Many2one → edi.backend
    comodel_name='edi.backend'
  • description Char
    help='Describe what the conf is for'
  • is_global Boolean
    default=False help='If checked, this configuration will be executed for all records, regardless of the partner relation.' string='Global Configuration'
  • model_id Many2one → ir.model
    help='Model the conf applies to. Leave blank to apply for all models' string='Model' args: 'ir.model'
  • model_name Char
    related='model_id.model' store=True string='Model tech name'
  • name Char
    required=True
  • snippet_before_do Text
    help='Snippet to validate the state and collect records to do'
  • snippet_do Text
    help='Used to do something specific here.\n Receives: operation, edi_action, vals, old_vals.'
  • trigger Char
    related='trigger_id.code'
  • trigger_id Many2one → edi.configuration.trigger
    comodel_name='edi.configuration.trigger' domain="['|', ('model_id', '=', model_id), ('model_id', '=', False)]" help='Trigger that activates this configuration'
  • type_id Many2one → edi.exchange.type
    auto_join=True comodel_name='edi.exchange.type' index=True ondelete='cascade' string='Exchange Type'
Public methods (5)
  • action_view_partners(self)
  • edi_exec_snippet_before_do(self, record, **kwargs)
  • edi_exec_snippet_do(self, record, **kwargs)
  • edi_get_conf(self, trigger, backend=None)
  • edi_get_conf_global(self, exchange_record, trigger)
    @api.model
    Return active global configurations matching the given event. Unlike :meth:`edi_get_conf` -- which runs on a recordset of configurations already linked to a partner -- global configurations are not bound to any partner. We therefore have to derive the filtering keys from the originating exchange record: * ``trigger`` must match the event code * ``is_global`` must be True * ``type_id`` must match the exchange type or be empty (applies to all) * ``backend_id`` must match the backend or be empty (applies to all) * ``model_name`` must match the related record model or be empty (applies to all)

New fields (5)
  • active Boolean
    default=True
  • code Char
    copy=False required=True
  • description Char
    help='Describe what the conf is for'
  • model_id Many2one → ir.model
    help='Model the conf applies to. Leave blank to apply for all models' args: 'ir.model'
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (7)
  • edi_disable_auto Boolean
    help='When marked, EDI automatic processing will be avoided' string='Disable auto'
  • edi_has_form_config Boolean
    compute='_compute_edi_config'
  • exchange_record_count Integer
    compute='_compute_exchange_record_count'
  • exchange_record_ids One2many → edi.exchange.record
    compute='_compute_exchange_record_ids' args: 'edi.exchange.record'
  • exchange_related_record_ids One2many → edi.exchange.related.record
    domain=<expr> inverse_name='res_id' args: 'edi.exchange.related.record'
  • origin_exchange_record_id Many2one → edi.exchange.record
    comodel_name='edi.exchange.record' copy=False help='EDI record that originated this document.' ondelete='set null' string='EDI origin record'
  • origin_exchange_type_id Many2one → edi.exchange.type
    comodel_name='edi.exchange.type' copy=False ondelete='set null' related='origin_exchange_record_id.type_id' store=True string='EDI origin exchange type'
Public methods (6)
  • action_view_edi_records(self)
  • create(self, mvals)
    @api.model_create_multi
  • edi_create_exchange_record(self, exchange_type_id)
  • get_edi_access(self, doc_ids, operation, model_name=False)
    @api.model
    Retrieve access policy. The behavior is similar to `mail.thread` and `mail.message` and it relies on the access rules defines on the related record. The behavior can be customized on the related model by defining `_edi_exchange_record_access`. By default `write`, otherwise the custom permission is returned.
  • get_view(self, view_id=None, view_type='form', **options)
    @api.model
  • write(self, vals)

New fields (26)
  • ack_exchange_id Many2one → edi.exchange.record
    comodel_name='edi.exchange.record' compute='_compute_ack_exchange_id' help='ACK generated for current exchange.' index=True store=True string='ACK exchange'
  • ack_expected Boolean
    compute='_compute_ack_expected'
  • ack_received_on Datetime
    related='ack_exchange_id.exchanged_on' string='ACK received on'
  • active Boolean
    default=True
  • backend_id Many2one → edi.backend
    comodel_name='edi.backend' required=True
  • company_id Many2one → res.company
    string='Company' args: 'res.company'
  • direction Selection
    related='type_id.direction'
  • edi_exchange_state Selection
    copy=False default='new' index=True readonly=True selection=[('new', 'New'), ('validate_error', 'Error on validation'), ('output_pending', 'Waiting to be sent'), ('output_error_on_send', 'error on send'), ('output_sent', 'Sent'), ('output_sent_and_processed', 'Sent and processed'), ('output_sent_and_error', 'Sent and error'), ('input_pending', 'Waiting to be received'), ('input_received', 'Received'), ('input_receive_error', 'Error on reception'), ('input_processed', 'Processed'), ('input_processed_error', 'Error on process')] string='Exchange state'
  • exchange_error Text
    copy=False readonly=True string='Exchange error'
  • exchange_error_traceback Text
    copy=False readonly=True string='Exchange error traceback'
  • exchange_file Binary
    attachment=True copy=False
  • exchange_file_frozen Boolean
    compute='_compute_exchange_file_frozen' compute_sudo=True help='Not allowed to change the file anymore.'
  • exchange_filechecksum Char
    compute='_compute_exchange_filechecksum' readonly=True store=True tracking=True
  • exchange_filename Char
    compute='_compute_exchange_filename' readonly=False store=True
  • exchanged_on Datetime
    compute='_compute_exchanged_on' help='Sent or received on this date.' readonly=True store=True
  • external_identifier Char
    copy=False index=True readonly=True
  • identifier Char
    copy=False index=True readonly=True required=True
  • model Char
    compute='_compute_record' copy=False index=True inverse='_inverse_record' readonly=False required=False store=True
  • parent_id Many2one → edi.exchange.record
    comodel_name='edi.exchange.record' help='Original exchange which originated this record' index=True
  • related_exchange_ids One2many → edi.exchange.record
    comodel_name='edi.exchange.record' inverse_name='parent_id' string='Related exchanges'
  • related_name Char
    compute='_compute_related_name' compute_sudo=True
  • related_record_exists Boolean
    compute='_compute_related_record_exists'
  • related_record_ids One2many → edi.exchange.related.record
    comodel_name='edi.exchange.related.record' inverse_name='exchange_record_id' string='Related records'
  • res_id Many2oneReference
    compute='_compute_record' copy=False index=True inverse='_inverse_record' model_field='model' readonly=False required=False store=True string='Record'
  • retryable Boolean
    compute='_compute_retryable' help='The record state can be rolled back manually in case of failure.'
  • type_id Many2one → edi.exchange.type
    auto_join=True comodel_name='edi.exchange.type' index=True ondelete='cascade' required=True string='Exchange type'
Public methods (19)
  • action_exchange_generate(self, **kw)
  • action_exchange_generate_send(self, **kw)
  • action_exchange_generate_send_chained(self)
  • action_exchange_process(self)
  • action_exchange_receive(self)
  • action_exchange_send(self)
  • action_open_related_exchanges(self)
  • action_open_related_record(self)
  • action_regenerate(self)
  • action_retry(self)
  • check_access(self, operation)
    In order to check if we can access a record, we are checking if we can access the related document
  • create(self, vals_list)
    @api.model_create_multi
  • exchange_create_ack_record(self, **kw)
  • exchange_create_child_record(self, exc_type=None, **kw)
  • needs_ack(self)
  • notify_action_complete(self, action, message=None)
    Notify current record that an edi action has been completed. Implementers should take care of calling this method if they work on records w/o calling edi_backend methods (eg: action_send). Implementers can hook to this method to do something after any action ends.
  • read(self, fields=None, load='_classic_read')
    Override to explicitely call check_access_rule, that is not called by the ORM. It instead directly fetches ir.rules and apply them.
  • record(self)
    @property
  • write(self, vals)

New fields (5)
  • backend_id Many2one → edi.backend
    required=True args: 'edi.backend'
  • backend_type_id Many2one → edi.backend.type
    related='exchange_type_id.backend_type_id' args: 'edi.backend.type'
  • exchange_type_id Many2one → edi.exchange.type
    required=True args: 'edi.exchange.type'
  • model Char
    required=True
  • res_id Integer
    required=True
Public methods (1)
  • create_edi(self)

New fields (3)
  • exchange_record_id Many2one → edi.exchange.record
    comodel_name='edi.exchange.record' index=True ondelete='cascade' required=True
  • model Char
    index=True readonly=True required=True
  • res_id Many2oneReference
    copy=False index=True model_field='model' readonly=True required=True string='Record'
Public methods (2)
  • action_open_related_record(self)
  • record(self)
    @property

New fields (29)
  • ack_for_type_ids Many2many → edi.exchange.type
    comodel_name='edi.exchange.type' compute='_compute_ack_for_type_ids' string='Ack for exchange type'
  • ack_type_id Many2one → edi.exchange.type
    comodel_name='edi.exchange.type' help='Identify the type of the ack. If this field is valued it means an hack is expected.' ondelete='set null' string='Ack exchange type'
  • active Boolean
    default=True inverse='_inverse_active'
  • advanced_settings_edit Text
    help='\n Advanced technical settings as YAML format.\n The YAML structure should reproduce a dictionary.\n The backend might use these settings for automated operations.\n\n Currently supported conf:\n\n components:\n generate:\n usage: $comp_usage\n # set a value for component work context\n work_ctx:\n opt1: True\n validate:\n usage: $comp_usage\n env_ctx:\n # set a value for the whole processing env\n opt2: False\n check:\n usage: $comp_usage\n send:\n usage: $comp_usage\n receive:\n usage: $comp_usage\n process:\n usage: $comp_usage\n\n filename_pattern:\n force_tz: Europe/Rome\n date_pattern: %Y-%m-%d-%H-%M-%S\n\n In any case, you can use these settings\n to provide your own configuration for whatever need you might have.\n ' string='Advanced YAML settings'
  • allow_empty_files_on_receive Boolean
    string='Allow Empty Files'
  • backend_id Many2one → edi.backend
    comodel_name='edi.backend' ondelete='set null' string='Backend'
  • backend_type_id Many2one → edi.backend.type
    comodel_name='edi.backend.type' ondelete='restrict' required=True string='Backend type'
  • check_model_id Many2one → ir.model
    domain=[('is_edi_checker', '=', True)] string='Checker' args: 'ir.model'
  • code Char
    copy=False required=True
  • direction Selection
    required=True selection=[('input', 'Input'), ('output', 'Output')]
  • encoding Char
    help="Encoding to be applied to generate/process the exchanged file.\nExample: UTF-8, Windows-1252, ASCII...(default is always 'UTF-8')"
  • encoding_in_error_handler Selection
    help="Handling of decoding errors on process (default is always 'Raise Error')." selection=[('strict', 'Raise Error'), ('ignore', 'Ignore'), ('replace', 'Replace with Replacement Marker'), ('backslashreplace', 'Replace with Backslashed Escape Sequences'), ('surrogateescape', 'Replace Byte with Individual Surrogate Code')] string='Decoding Error Handler'
  • encoding_out_error_handler Selection
    help="Handling of encoding errors on generate (default is always 'Raise Error')." selection=[('strict', 'Raise Error'), ('ignore', 'Ignore'), ('replace', 'Replace with Replacement Marker'), ('backslashreplace', 'Replace with Backslashed Escape Sequences'), ('surrogateescape', 'Replace Byte with Individual Surrogate Code'), ('xmlcharrefreplace', 'Replace with XML/HTML Numeric Character Reference')] string='Encoding Error Handler'
  • exchange_file_auto_generate Boolean
    help='Auto generate output for records missing their payload. If active, a cron will take care of generating the output when not set yet. '
  • exchange_file_ext Char
  • exchange_filename_pattern Char
    default='{record_name}-{type.code}-{dt}' help='For output exchange types this should be a formatting string with the following variables available (to be used between brackets, `{}`): `exchange_record`, `record_name`, `type`, `dt` and `seq`. For instance, a valid string would be {record_name}-{type.code}-{dt}-{seq}\nFor more information:\n- `exchange_record` means exchange record\n- `record_name` means name of the exchange record\n- `type` means code of the exchange record type\n- `dt` means datetime\n- `seq` means sequence. You need a sequence to be defined in `Exchange Filename Sequence` to use `seq`\n'
  • exchange_filename_sequence_id Many2one → ir.sequence
    help='If the `Exchange Filename Pattern` has `{seq}`, you should define a sequence in this field to show the sequence in your filename' args: 'ir.sequence', 'Exchange Filename Sequence'
  • exchange_record_count Integer
    compute='_compute_exchange_record_count' string='# Exchange Records'
  • exchange_record_ids One2many → edi.exchange.record
    comodel_name='edi.exchange.record' inverse_name='type_id'
  • generate_model_id Many2one → ir.model
    domain=[('is_edi_generator', '=', True)] string='Generator' args: 'ir.model'
  • input_validate_model_id Many2one → ir.model
    domain=[('is_edi_input_validator', '=', True)] string='Input Validator' args: 'ir.model'
  • name Char
    required=True
  • output_validate_model_id Many2one → ir.model
    domain=[('is_edi_output_validator', '=', True)] string='Output Validator' args: 'ir.model'
  • partner_ids Many2many → res.partner
    comodel_name='res.partner' help='You can use this field to limit generating/processing exchanges for specific partners. Use it directly or within models rules (domain or snippet).' string='Enabled for partners'
  • process_model_id Many2one → ir.model
    domain=[('is_edi_processor', '=', True)] string='Processor' args: 'ir.model'
  • quick_exec Boolean
    help='When active, records of this type will be processed immediately without waiting for the cron to pass by. Requires auto generate flag to be active as well. The cron will skip these records unless forced.' string='Quick execution'
  • receive_model_id Many2one → ir.model
    domain=[('is_edi_receiver', '=', True)] string='Receiver' args: 'ir.model'
  • rule_ids One2many → edi.exchange.type.rule
    comodel_name='edi.exchange.type.rule' context={'active_test': False} help='Rules to handle exchanges and UI automatically' inverse_name='type_id'
  • send_model_id Many2one → ir.model
    domain=[('is_edi_sender', '=', True)] string='Sender' args: 'ir.model'
Public methods (5)
  • action_view_exchange_records(self)
  • copy_data(self, default=None)
  • get_settings(self)
  • is_partner_enabled(self, partner)
    Check if given partner record is allowed for the current type. You can leverage this in your own logic to trigger or not certain exchanges for specific partners. For instance: a customer might require an ORDRSP while another does not.
  • set_settings(self, val)

New fields (10)
  • active Boolean
    default=True
  • enable_domain Char
    help='Filter domain to be checked on Models' string='Enable on domain'
  • enable_snippet Char
    help='Snippet of code to be checked on Models,\n You can use `record` and `exchange_type` here.\n It will be executed if variable result has been defined as True\n ' string='Enable on snippet'
  • form_btn_label Char
    help='Type name used by default' string='Form button label' translate=True
  • form_btn_tooltip Text
    help='Help message visible as tooltip on button h-over' string='Form button tooltip' translate=True
  • kind Selection
    default='form_btn' help=KIND_HELP required=True selection=[('form_btn', 'Form button'), ('custom', 'Custom')]
  • model Char
    related='model_id.model' args: 'Model code'
  • model_id Many2one → ir.model
    comodel_name='ir.model' help='Apply to this model' ondelete='cascade'
  • name Char
    required=True
  • type_id Many2one → edi.exchange.type
    comodel_name='edi.exchange.type' ondelete='cascade' required=True
Public methods (0)

No public methods.

New fields (1)
  • edi_id Char
    help='Internal or external identifier for records.' string='EDI ID'
Public methods (0)

No public methods.

New fields (0)

No new fields.

Public methods (1)
  • check(self, exchange_record)

New fields (0)

No new fields.

Public methods (1)
  • generate(self, exchange_record)

New fields (0)

No new fields.

Public methods (1)
  • input_validate(self, exchange_record, **kw)

New fields (0)

No new fields.

Public methods (1)
  • output_validate(self, exchange_record, **kw)

New fields (0)

No new fields.

Public methods (1)
  • process(self, exchange_record)

New fields (0)

No new fields.

Public methods (1)
  • receive(self, exchange_record)

New fields (0)

No new fields.

Public methods (1)
  • send(self, exchange_record)

New fields (7)
  • is_edi_checker Boolean
  • is_edi_generator Boolean
  • is_edi_input_validator Boolean
  • is_edi_output_validator Boolean
  • is_edi_processor Boolean
  • is_edi_receiver Boolean
  • is_edi_sender Boolean
Public methods (0)

No public methods.