Skip to content

Conversation

@mega-odoo
Copy link
Contributor

Purpose: Rework of the industry based on feedback, as well as to generate more traction on the combo of industries real estate, estate management, and condominium

This commit adds new features to the condominium module, including managing co-ownership properties, Split analytic items in case of owner change, general meeting animation with votes, delegation, and report, and improving the report for the general meetings agenda and report. Added Building tab and fields to the contact form, captures the history of owners and tenants

Rework on Contacts, Condominium app, Accounts, Calendar events, Invoices, Distribution key, and Automations

TASK-4743607

@robodoo
Copy link
Collaborator

robodoo commented Nov 13, 2025

Pull request status dashboard

@mega-odoo mega-odoo force-pushed the 19.0-condominium-industry-v3-update-mega branch 4 times, most recently from ac72cbc to 14556f0 Compare November 14, 2025 06:19
Copy link
Contributor

@pgu-odoo pgu-odoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mega-odoo Huge great work!
I will wait for your commit to resume review.

Thanks!

@@ -4,62 +4,90 @@
'category': 'Services',
'depends': [
'account_check_printing',
'account_followup',
'account_peppol',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'account_peppol',

I think it is auto installed for a few countries.

fname = plan._column_name()

for line in records.x_line_ids:
original_analytic = line.x_analytic_line_id or original_analytic
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

original_analytic is used before assigned. If line.x_analytic_line_id is false, it will raise error.

Comment on lines 57 to 68
for original_id, new_lines in occupied_cells.items():
for new_analytic_line in list(new_lines):
for Aid, values in note_details.items():
if original_id == Aid:
note_html = f"""
<i>{datetime.date.today().strftime("%d %B %Y")}</i><br/>
<p><b>Analytic item coming from a split</b><br/>
{'<br/>'.join(list(values))}<br/>
See <a href='/odoo/analytic-items/{original_id}' target='_blank'> original analytic item</a>
</p>
"""
new_analytic_line.write({"x_notes": note_html.strip()})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for original_id, new_lines in occupied_cells.items():
for new_analytic_line in list(new_lines):
for Aid, values in note_details.items():
if original_id == Aid:
note_html = f"""
<i>{datetime.date.today().strftime("%d %B %Y")}</i><br/>
<p><b>Analytic item coming from a split</b><br/>
{'<br/>'.join(list(values))}<br/>
See <a href='/odoo/analytic-items/{original_id}' target='_blank'> original analytic item</a>
</p>
"""
new_analytic_line.write({"x_notes": note_html.strip()})
for original_id, new_lines in occupied_cells.items():
values = note_details.get(original_id)
if not values:
continue
note_html = f"""
<i>{datetime.date.today().strftime("%d %B %Y")}</i><br/>
<p><b>Analytic item coming from a split</b><br/>
{'<br/>'.join(list(values))}<br/>
See <a href='/odoo/analytic-items/{original_id}' target='_blank'> original analytic item</a>
</p>
"""
for new_analytic_line in new_lines:
new_analytic_line.write({"x_notes": note_html})

Can't be improve like this?

Original amount: {original_item.amount}
</p>
"""
new_analytic_item.browse(original_id).write({"x_notes": note_html.strip(), "amount": 0.0,})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are browsing the record twice. new_analytic_item.browse(original_id)


if original_analytic:
new_analytic_item_id = original_analytic.copy({
fname: analytic_id.id or '',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fname: analytic_id.id or '',
fname: analytic_id.id or False

or

Suggested change
fname: analytic_id.id or '',
fname: analytic_id.id,

because if analytic_id is false then analytic_id.id will also b false.

<record id="ir_act_server_split_per_property" model="ir.actions.server">
<field name="code"><![CDATA[distributions = record.x_distribution_key.x_ratio_ids
total_distribution = sum(distributions.mapped('x_ratio'))
if total_distribution == 0: raise UserError("Cannot split the Sales Orders because there is not distribution key total is null.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if total_distribution == 0: raise UserError("Cannot split the Sales Orders because there is not distribution key total is null.")
if total_distribution == 0: raise UserError("Cannot split the Sales Orders because there is no distribution key and total is null.")

total_distribution = sum(distributions.mapped('x_ratio'))
if total_distribution == 0: raise UserError("Cannot split the Sales Orders because there is not distribution key total is null.")
for owner in env['res.partner'].search([('x_companies', 'in', record.company_id.id)]): # One SO per owner
new_so = record.copy(); new_so_lines = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
new_so = record.copy(); new_so_lines = [];
new_so = record.copy({'order_line': False}); new_so_lines = [];

if total_distribution == 0: raise UserError("Cannot split the Sales Orders because there is not distribution key total is null.")
for owner in env['res.partner'].search([('x_companies', 'in', record.company_id.id)]): # One SO per owner
new_so = record.copy(); new_so_lines = [];
new_so['x_source_sales_order'] = record.id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new_so.write({
    'x_source_sales_order': record.id,
    'partner_id': owner.id,
})

new_so = record.copy(); new_so_lines = [];
new_so['x_source_sales_order'] = record.id
new_so['partner_id'] = owner.id
new_so.order_line.unlink() # Remove the lines that were copied from the source SO
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
new_so.order_line.unlink() # Remove the lines that were copied from the source SO

If unset during copying, there will be no need of it.

<field name="code"><![CDATA[for line in record.x_property_id.x_owner_ids:
if not line.x_end_date: record['x_property_id']['x_current_owner'] = line.x_owner
account = env['account.analytic.account'].search([('x_property','=',record.x_property_id.id),('partner_id','=',line.x_owner.id)])
if not account and line.x_owner.id: line['x_account'] = env['account.analytic.account'].create({ 'name': str(record.x_property_id.x_name) + " - " + str(line.x_owner.name), 'x_property': record.x_property_id.id, 'partner_id': line.x_owner.id, 'x_owner_line': line.id}).id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole method can be improved, to avoid create in for loop.

analytic = env['account.analytic.account']
accounts_to_create = []

for line in record.x_property_id.x_owner_ids:
    if not line.x_end_date:
        record.x_property_id.write({'x_current_owner': line.x_owner.id})
    if line.x_owner:
        existing = Analytic.search([
        ('x_property', '=', record.x_property_id.id),
        ('partner_id', '=', line.x_owner.id)
        ], limit=1)

    if not existing:
        accounts_to_create.append({
        'name': f"{record.x_property_id.x_name} - {line.x_owner.name}",
        'x_property': record.x_property_id.id,
        'partner_id': line.x_owner.id,
        'x_owner_line': line.id,
        })
    if accounts_to_create:
        new_accounts = Analytic.create(accounts_to_create)

@mega-odoo mega-odoo force-pushed the 19.0-condominium-industry-v3-update-mega branch 16 times, most recently from 17d7462 to 33eb5ef Compare November 26, 2025 09:53
Copy link
Contributor

@pgu-odoo pgu-odoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mega-odoo A few suggestions are here. Thanks.

analytic_account = env['account.analytic.account']
for line in property_id.x_owner_ids:
owner = line.x_owner
owner_id = owner.id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
owner_id = owner.id

use owner.id whenever needed.

<field name="name">x_condominium_account_analytic_account_count</field>
<field name="compute"><![CDATA[
for record in self:
record['x_condominium_account_analytic_account_count'] = self.env['account.analytic.account'].search_count([('partner_id', '=', record.id)])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of search_count in for loop. You can user read_group method.

<field name="field_description">Source Sales Order count</field>
<field name="compute"><![CDATA[
for record in self:
record['x_source_sales_order_sale_order_count'] = self.env['sale.order'].search_count([('x_source_sales_order', 'in', record.ids)])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above. Using read_group is better.

Comment on lines 861 to 862
accounts = self.env['account.analytic.account'].search([('partner_id','=',record.x_owner),('x_property','=',record.x_property),('x_end_date','=',False)])
record['x_account'] = accounts.id]]></field>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if search returns multiple analytic accounts? accounts.id will break.
if you want only one analytic account, use the limit=1 in search and change the name account from accounts.
if expecting multiple, then handle the assignation proper.

Comment on lines 1445 to 1451
<field name="compute"><![CDATA[for record in self:
is_distributed = False
for invoice_line in record.invoice_line_ids:
if invoice_line.analytic_distribution != False:
is_distributed = True
break
record['x_is_distributed'] = is_distributed]]></field>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for record in self:
    record.x_is_distributed = any(
        bool(line.analytic_distribution)
        for line in record.invoice_line_ids
    )

would be better

<field optional="show" name="x_end_date"/>
<field optional="show" name="x_owner" required="True" widget="many2one_avatar_user"/>
<field optional="show" name="x_co_owners" widget="many2many_tags_avatar"/>
<field optional="show" name="x_account" options="{&quot;no_create&quot;:true}" readonly="True" widget="many2one_tax_tags" column_invisible="True"/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<field optional="show" name="x_account" options="{&quot;no_create&quot;:true}" readonly="True" widget="many2one_tax_tags" column_invisible="True"/>
<field optional="show" name="x_account" options="{'no_create':true}" readonly="True" widget="many2one_tax_tags" column_invisible="True"/>

<field name="x_owner_ids">
<list editable="top">
<field name="x_sequence" widget="handle"/>
<field optional="show" name="x_start_date" required="True"/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it is required, we should not put it in optional="show"

<field name="name">x_period.form.condominium</field>
<field name="type">form</field>
</record>
<record id="default_search_view__357f8b9e-0127-48a6-97ac-45ad1fce0030" model="ir.ui.view">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<record id="default_search_view__357f8b9e-0127-48a6-97ac-45ad1fce0030" model="ir.ui.view">
<record id="default_search_view" model="ir.ui.view">

<field name="arch" type="xml">
<form>
<header>
<button string="Populate" name="%(action_populate_distribution_key)d" type="action" class="btn-primary" invisible="x_based_on != &quot;Shares&quot;"/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<button string="Populate" name="%(action_populate_distribution_key)d" type="action" class="btn-primary" invisible="x_based_on != &quot;Shares&quot;"/>
<button string="Populate" name="%(action_populate_distribution_key)d" type="action" class="btn-primary" invisible="x_based_on != 'Shares'"/>

<field name="key">condominium.report_calendar_event_general_meeting_document</field>
<field name="active" eval="True" />
<field name="name">condominium.report_calendar_event_general_meeting_document</field>
<field name="priority">9999999</field>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it needed?

@pgu-odoo
Copy link
Contributor

pgu-odoo commented Dec 1, 2025

@vava-odoo I have given a few suggestions and @mega-odoo is working with those but I think meanwhile you can also start the code review for this PR.

Thanks

@mega-odoo mega-odoo force-pushed the 19.0-condominium-industry-v3-update-mega branch 6 times, most recently from d0eacec to f63ac54 Compare December 2, 2025 07:21
@mega-odoo mega-odoo force-pushed the 19.0-condominium-industry-v3-update-mega branch 6 times, most recently from 4084925 to ba070ca Compare December 22, 2025 09:41
@mega-odoo mega-odoo force-pushed the 19.0-condominium-industry-v3-update-mega branch 2 times, most recently from 66a26d8 to 71d45bb Compare December 31, 2025 06:51
@mega-odoo mega-odoo force-pushed the 19.0-condominium-industry-v3-update-mega branch 11 times, most recently from c982587 to 737d042 Compare January 12, 2026 08:39
@mega-odoo mega-odoo force-pushed the 19.0-condominium-industry-v3-update-mega branch 2 times, most recently from 7063be3 to 2e635c4 Compare January 13, 2026 10:38
@vava-odoo vava-odoo force-pushed the 19.0-condominium-industry-v3-update-mega branch from 2e635c4 to 4a7383a Compare January 26, 2026 21:10
@vava-odoo vava-odoo force-pushed the 19.0-condominium-industry-v3-update-mega branch 3 times, most recently from f0fb09d to 323db55 Compare January 29, 2026 15:34
@vava-odoo vava-odoo force-pushed the 19.0-condominium-industry-v3-update-mega branch from 323db55 to 56921fb Compare January 29, 2026 15:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants