Repository navigation
Conversation
Preserve email_cc on the lead description, store stage duration in the v20 duration_tracking shape, and turn assignment opt-out into a zero cap. Co-authored-by: André de Kock <adekock11@users.noreply.github.com>
Drop the v19 reveal-id industries before the new CSV loads. Deactivate website reveal rules that filtered on those industries so an empty filter does not match every visitor. Co-authored-by: André de Kock <adekock11@users.noreply.github.com>
Map create_lead_and_forward to create_lead, keep the historical Livechat utm.source under utm.utm_source_livechat, and backfill lead utm_reference from the chatbot source map. Co-authored-by: André de Kock <adekock11@users.noreply.github.com>
Copy chatbot.script.source_id before this module drops the column. The rest of the im_livechat 20.0 analysis is left for a dedicated migration. Co-authored-by: André de Kock <adekock11@users.noreply.github.com>
The 20.0 module ships no data files. Delete the server action that called the removed crm.lead._form_view_auto_fill method. Co-authored-by: André de Kock <adekock11@users.noreply.github.com>
ir.model.access and ir.rule rows are recreated as ir.access by the base migration and the modules' new CSV files. No further script is required. Co-authored-by: André de Kock <adekock11@users.noreply.github.com>
Status lines for crm and the modules migrated with it. The table itself comes from OCA#6068. Co-authored-by: André de Kock <adekock11@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Migration scripts and annotated analysis for the CRM family from Odoo 19.0 to 20.0:
crm20.0.1.9crm_iap_mine20.0.1.2crm_livechat20.0.1.0crm_mail_plugin20.0.1.0crm_sms20.0.1.1sales_team20.0.1.1crm_iap_enrichim_livechat20.0.1.0upgrade_analysis.txtfiles are copied from OCA/OpenUpgrade#6068 (hbrunn/OpenUpgrade20.0-base,2d9eb6bab7e7e579953e38d7ad3b96aad6fcc44d).upgrade_analysis_work.txtannotates every line.docsource/modules190-200.rstis that same file with the rows above filled in. This branch does not contain the OCA#6068 commits. It depends on them: base renamesir.model.access/ir.rulexmlids and buildsir.accessfor custom rules. Standard access rows are then recreated from each module'sir.access.csv.crm
Sources:
addons/crmonodoo/odoo19.0 vs 20.0.crm.lead.email_ccdeletedcrm.leadno longer inheritsmail.thread.cc. The mixin module was removed in odoo/odoo@3c26c0553754 ([IMP] mail,*: remove MailThreadCC, part of odoo/odoo#238694, related odoo/upgrade#9007). Carbon-copy addresses stored on the lead have nowhere to go.Without a script the column is left behind unread (Odoo 20 does not
DROPremoved columns) and disappears from the form.Pre-migration HTML-escapes a non-empty
email_cc, appends it todescription(Email cc preserved from previous version: …), then drops the column.duration_trackingis now storedDefined on
mail.tracking.duration.mixin. v19 computed a non-stored{stage_id: seconds}map frommail.tracking.valueon every read. v20 stores JSON and the compute only rolls that dict forward: odoo/odoo@d5e8a68f4b ([IMP] (test_, mail), crm, project: store stage duration in duration tracking). The stored shape, confirmed bymail/tests/common_tracking.py, is:s: currentstage_id(0 if empty)d:YYYY-MM-DD HH:MM:SSwhen the current stage was entered<stage id>: minutes spent on completed visits onlyThe open visit is not stored under the stage key. The web client adds
now - d.Field.update_dbrecomputes only when the column is missing (odoo/orm/fields.py). A recompute of NULL setss/dto "now" and drops history, which is what the rainbow-man check and the stage-duration widget read.Pre-migration adds
crm_lead.duration_tracking jsonband fills NULL rows frommail.tracking.value(fieldstage_id), converting each completed interval to minutes.disdate_last_stage_update, thencreate_date. A second run does not add the minutes again.The same mixin change hits every model that uses it (project, helpdesk, …). Those belong in their own module scripts, not here. If the mail migration later fills
crm_leadthe same way, running both is safe only while both skip non-NULL values. This script already does.assignment_optoutremoved,assignment_rulesaddedodoo/odoo@553fbd1afa (
[IMP] crm,sales_team: update lead assignment for sales teams).assignment_rulesis a non-stored compute ofassignment_max:>= 30000→unlimited(new default for new members)== 0→opt-outlimitedv19 stored opt-out as a boolean beside a cap (default 30). Leaving opted-out members at cap 30 would put them back into rotation.
Pre-migration sets
assignment_max = 0whereassignment_optoutis true, then drops the boolean. Everyone else keeps their cap, so they stay "limited". The unlimited sentinel is not written onto existing rows.commercial_partner_iddeletedNon-stored compute used only to pick a company on the lead form. No column. Nothing to do.
utm_referencenewNew optional
Referenceonutm.mixin(present on 20.0utm/models/utm_mixin.py, absent on the 19.0 branch; introduced historically by odoo/odoo@d2cc73ebe7bb). No backfill incrm.crm_livechatfills it for chatbot leads.website_message_idsdeletedNon-stored one2many of
mail.message. It is not declared on current 19.0 or 20.0mail.thread/crm.lead, so there is no column. Messages stay onmail.message. Nothing to do.crm.stage.colordeletedodoo/odoo@3cce5fbeba01 (
[IMP] project, crm: remove the color field from stages).crm_stage_data.xmlno longer sets colors. No successor field. The integer column is left in the table by the ORM and is not read. Nothing to do.Obsolete
crm.lead2opportunity.partnerTransient wizard. The mass wizard remains and no longer inherits it. No stored rows. Base pre-migration already calls
clean_transient_models. Nothing to do.XML: access, rules, actions, views
Every
NEW ir.access/DEL ir.model.access/DEL ir.ruleline is the base merge of access and rules intoir.access. Nothing to do incrm, including the noupdate lead and activity rules. Their v20 definitions (managercrudon all leads, salesmancruon own leads, activity-plancudlimited tocrm.lead) are loaded fromcrm/security/ir.access.csvbecause base renames the old xmlids first. Customizations of those noupdate rules are the known base gap, not reimplemented here.Post-migration deletes xmlids whose files left the manifest, before view validation:
crm.action_your_pipelineandcrm.action_opportunity_forecast(data/ir_action_data.xmlremoved). They call methods that no longer exist.crm.action_crm_lead2opportunity_partnerandcrm.view_crm_lead2opportunity_partner(wizard file removed). The view's model is the deleted transient.crm.crm_lead_all_leads_view_calendar(calendar binding removed from a file that still loads; delete is a no-op if already gone).New views (
crm_lead_creation_message, simplified list, access-request template) load from module data.crm_iap_mine
odoo/odoo@57b8a7d360 (
[IMP] crm_iap_mine, website_crm_iap_reveal: restructure crm_iap_lead_industry, odoo/odoo#246985, related odoo/upgrade#9405).v19 industries are IAP reveal ids (
reveal_ids, names like "Consumer Discretionary"). v20 industries are SIC major groups (sic_grouprequired) grouped by a newcrm.iap.lead.industry.division(division_idrequired). The commit does not publish a mapping. Sending old reveal ids assic_groupswould call IAP with the wrong catalog.Pre-migration, only while
reveal_idsstill exists (so a retry after the new CSV has loaded does not delete the SIC rows):crm_iap_lead_industry.crm.reveal.rulerows that had an industry filter are setactive = Falsebefore the link is removed. An emptyindustry_tag_idsmeans "match every industry" (website_crm_iap_reveal), which would widen a paid cron. Rules that already had no industry filter stay active.ir.model.dataforcrm.iap.lead.industryand the rows themselves, thenDROP COLUMN reveal_ids.Module data then loads
crm.iap.lead.industry.division.csvand the new industry CSV. User-created industries are removed too: they cannot satisfy the required SIC columns.People-search fields on
crm.iap.lead.mining.request(search_type,contact_number,contact_filter_type,preferred_role_id,role_ids,seniority_id) are gone. v20 always sendssearch_type = companies. There is no target field. Odoo 20 does not drop the columns, so the values remain on the table for a DBA. Generated leads are untouched.crm.iap.lead.roleandcrm.iap.lead.senioritymaster data stay._orderis not stored. Division rows and the new unique constraint come from module data / the ORM. Access xmlids are the baseir.accessmerge.Post-migration deletes the lead views from
crm_lead_views.xml, which left the manifest (crm_case_kanban_view_leads, both lead trees,view_crm_lead_kanban), before view validation.company_size_maxdefault changed from 1000 to 100 in Python only. Existing rows keep 1000. Not in the analysis. Left as user data.crm_livechat
create_lead_and_forwardremovedodoo/odoo@895154fd1725 (
[REM] crm_livechat, im_livechat: remove "create lead & forward" step). The 20.0 selection has noondeletefor that key, and_process_ondeleteskips keys that are not infield.ondelete, so the old value would stay inchatbot_script_step.step_typeand break the next read.Pre-migration sets those steps to
create_lead. The lead is still created and assigned. The automatic forward-to-operator half is not rebuilt: inserting a step would rewritetriggering_answer_idsand sequences. Add aforward_operatorstep by hand if that behavior is still needed.utm_source_livechatmoved toutmv19 data:
crm_livechat.utm_source_livechat(noupdate, name "Livechat"). v20 data:utm.utm_source_livechatinutm/data/utm_source_data.xml(noupdate).utmis updated beforecrm_livechat. If the old xmlid is still there, utm creates a second source.utm.sourcenames are unique, so the new row is typically "Livechat [2]", and new/leadcommands would tag that duplicate.Post-migration keeps the historical row, repoints foreign keys (and other xmlids) from the duplicate, deletes the duplicate, and renames the xmlid to
utm.utm_source_livechatwithnoupdate = true. A dangling old xmlid is deleted instead. A second run finds nocrm_livechatxmlid and returns.Doing the rename in
utmpre-migration would avoid creating the duplicate. That belongs with the utm PR. This post-migration still cleans up if utm did not rename it.Chatbot leads and
utm_referencev19
chatbot.scriptinheritsutm.source.mixin. Leads stored that per-scriptsource_id. v20 setssource_idto the sharedim_livechat.utm_source_chatbotandutm_referencetochatbot.script,<id>, and the lead counter filters onutm_reference.source_idis dropped when im_livechat updates, which is beforecrm_livechat. The map is saved in im_livechat's pre-migration (below). Post-migration setsutm_referencewhere it is empty andsource_idmatches a saved script source (lowest script id if two scripts shared a source). The lead'ssource_idis not rewritten to the shared Chatbot source: the old per-script source is still a validutm.sourceand is more specific. New leads use the shared source. The map table is then dropped.Discuss-channel
/leadrows use the Livechat source, not a script source, so they are not given a chatbot reference.Record rules (
ir_rule_discuss_channel_*) moved toir.access.csvwith the same domains: channelr, membercr, salesman group. Nothing to do beyond base.im_livechat (partial, on purpose)
chatbot.scriptdropsutm.source.mixin, sosource_idis removed during this module's update, beforecrm_livechatruns.Pre-migration runs only when
crm_livechatisinstalled,to upgrade, orto install, andchatbot_script.source_idstill exists. It copies(id, source_id)intoou_crm_livechat_chatbot_source. It does not deleteutm.sourcerows.Everything else in
im_livechat/20.0.1.0/upgrade_analysis.txtis marked DEFERRED, not "nothing to do": obsoleteim_livechat.conversation.tag,livechat_operator_idremoved, rating changed from float to selection,livechat_statuslostwaiting, storedlivechat_looking_for_help_since_dt, and the access/menu/view churn. That is a livechat migration and should be its own PR. If that PR addspre-migration.py, merge_preserve_chatbot_script_sourceinto it.docsourceleaves the im_livechat status blank and notes "Partial: chatbot source map only."crm_mail_plugin
20.0 manifest has no
datafiles. v19 had:lead_creation_prefilled_action(server action, deprecated since saas-14.3) callingcrm.lead._form_view_auto_fill(), which is gonecrm_lead_action_form_edit(window action opening the lead form)Post-migration deletes both xmlids. No model or column changes.
crm_sms
Only the access merge. v19 gave sale managers full CRUD on every
sms.template. v20's CSV gives them read on all templates and create/write/unlink only when the template's model iscrm.leadorres.partner. That is what the new file loads after base renames the old xmlids. No script.sales_team
No column changes.
crm_rule_all_salesteammoves fromgroup_sale_salesman_all_leadstogroup_sale_managerwith operationcrudand no domain. Writes were already manager-only (access_crm_team_manager); salesman access was read-only. v20 grantscrm.teamread tobase.group_user.sale_team_comp_rulekeeps[('company_id', 'in', company_ids + [False])]. Both are loaded fromir.access.csv.sales_team.crm_team_action_saleswas removed fromcrm_team_views.xml, which is still loaded, and it is not noupdate. End-of-registry cleanup removes it. It is a window action, not a call into a deleted method. Nothing to do.crm_iap_enrich
Python-only (
get_param→get_str, enrich batch helper). No field or XML change in the OCA#6068 analysis. Nothing to do.Deliberately not in this PR
These showed up next to CRM in the 19→20 analysis and should be their own PRs:
im_livechatremainder (see above). Real data: conversation tags, operator, ratings.website_crm,website_crm_iap_reveal,website_crm_partner_assign,website_crm_livechat,website_crm_sms. Partner-assign movesres.partner.gradewebsite fields towebsite_partnership. This PR does touch reveal rules, but only to deactivate ones whose industry filter cannot be mapped.sale_crm. Access xmlid only. Belongs with sale.event_crm. Access xmlids and two removed window actions. Belongs with event.survey_crm. Deletescrm.lead.origin_survey_idand the team/survey inverses. Real data loss; belongs with survey.crm_sale_project. New module (project.project.lead_id,crm.lead.project_ids). Belongs with sale/project. Nothing to migrate until those modules exist on the upgraded database; new columns start empty.gamification_sale_crm,mass_mailing_crm,mass_mailing_crm_sms,iap_crm,event_crm_sale,website_event_crm. Analysis says no DB layout changes.Dependency on OCA#6068
No commit from OCA#6068 is in this branch. Required behavior from that PR:
basepre-migration suffixesir.model.accessandir.rulexmlids (name || '_' || model) so the newir.accessxmlids can be created.basepost-migration buildsir.accessfor manual access and rules only.openupgrade_frameworkloads these scripts.Do not merge this ahead of that framework if you expect the scripts to run inside Odoo. The SQL itself does not import the framework.
Tests
Not a full Odoo 19 database upgraded with Odoo 20. That needs OCA#6068's framework on the branch and both Odoo trees installed. What was run:
ruff checkon the migration scripts (clean).ruff formatapplied.PostgreSQL 16 fixture that loads the migration functions (Odoo import stubbed) and runs them on hand-built tables:
email_ccAnn <a@x.com>appended and escaped; column dropped.duration_tracking: no history →{s, d}only; one day in stage 10 →{"10": 1440, ...}; 10 then 20 then back to 10 →10: 1440,20: 2880, open visit not added to10. Second run does not double the minutes.reveal_idsdropped. Second run is a no-op.create_lead_and_forward→create_lead.utm.utm_source_livechatmerged into the historical source, including a lead FK that pointed at the duplicate. Chatbot lead getsutm_reference = chatbot.script,<id>. Livechat-source lead does not. Map table dropped. Second post-migration is a no-op.Known gaps
mail.tracking.valuestill pointing atcrm.lead/stage_id. Tracking that was never written (or whosefield_idwas rewritten) is not reconstructed.dthen falls back todate_last_stage_update.create_lead_and_forwardno longer forwards to an operator.source_id. Counts and the "view leads" action useutm_reference, which is backfilled. Reporting that filters on the new shared "Chatbot" source will not see old rows.source_id, leads are attributed to the lowest script id.crm_stageif you need to read it by SQL.ir.accessrows. That is the base migration's gap. Un-xmlid'd custom rules are handled by base.im_livechatdata other thansource_idis not migrated.