Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion account_payment_receivable_email/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

{
'name': 'Account Payment Receivable Email',
'version': '14.0.1.3.0',
'version': '14.0.2.0.0',
'category': 'Accounting',
'author': 'Numigi',
"maintainer": "Numigi",
Expand Down
39 changes: 16 additions & 23 deletions account_payment_receivable_email/i18n/fr.po
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-02-11 15:14+0000\n"
"PO-Revision-Date: 2026-02-11 15:14+0000\n"
"POT-Creation-Date: 2026-04-08 15:14+0000\n"
"PO-Revision-Date: 2026-04-08 15:14+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: fr\n"
Expand All @@ -16,12 +16,6 @@ msgstr ""
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: account_payment_receivable_email
#: code:addons/account_payment_receivable_email/models/res_partner.py:0
#, python-format
msgid "Automatically created from the Receivable Accounts Email field."
msgstr "Créé automatiquement à partir du champ Email Comptes Recevables."

#. module: account_payment_receivable_email
#: model:ir.model,name:account_payment_receivable_email.model_res_partner
msgid "Contact"
Expand All @@ -34,12 +28,6 @@ msgstr "Contact"
msgid "Display Name"
msgstr "Nom affiché"

#. module: account_payment_receivable_email
#: model:ir.model.fields,help:account_payment_receivable_email.field_res_partner__payment_email
#: model:ir.model.fields,help:account_payment_receivable_email.field_res_users__payment_email
msgid "Email address to send payment notifications and receipts"
msgstr "Adresse email pour envoyer les notifications de paiement et les reçus"

#. module: account_payment_receivable_email
#: model:ir.model,name:account_payment_receivable_email.model_mail_compose_message
msgid "Email composition wizard"
Expand All @@ -65,14 +53,19 @@ msgid "Payments"
msgstr "Paiements"

#. module: account_payment_receivable_email
#: code:addons/account_payment_receivable_email/models/res_partner.py:0
#: code:addons/account_payment_receivable_email/models/res_partner.py:0
#, python-format
msgid "Receivable Accounts"
msgstr "Comptes Recevables"
#: model:ir.model.fields,field_description:account_payment_receivable_email.field_res_partner__is_receivable_account
#: model:ir.model.fields,field_description:account_payment_receivable_email.field_res_users__is_receivable_account
msgid "Is Receivable Account"
msgstr "Est un Compte Recevable"

#. module: account_payment_receivable_email
#: model:ir.model.fields,field_description:account_payment_receivable_email.field_res_partner__payment_email_id
#: model:ir.model.fields,field_description:account_payment_receivable_email.field_res_users__payment_email_id
msgid "Receivable Accounts Contact"
msgstr "Contact Comptes Recevables"

#. module: account_payment_receivable_email
#: model:ir.model.fields,field_description:account_payment_receivable_email.field_res_partner__payment_email
#: model:ir.model.fields,field_description:account_payment_receivable_email.field_res_users__payment_email
msgid "Receivable Accounts Email"
msgstr "Email Comptes Recevables"
#: model:ir.model.fields,help:account_payment_receivable_email.field_res_partner__payment_email_id
#: model:ir.model.fields,help:account_payment_receivable_email.field_res_users__payment_email_id
msgid "Select the specific contact to receive payment notifications."
msgstr "Sélectionnez le contact spécifique qui recevra les notifications de paiement et les reçus."
1 change: 0 additions & 1 deletion account_payment_receivable_email/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@

from . import account_payment
from . import mail_compose_message
from . import mail_mail
from . import res_partner
3 changes: 1 addition & 2 deletions account_payment_receivable_email/models/account_payment.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ class AccountPayment(models.Model):
_inherit = "account.payment"

def _notify_get_recipients(self, message, groups):
""" Voir logique ci-dessus pour account.move """
if self.partner_id.payment_email:
if self.partner_id.payment_email_id:
return []
return super(AccountPayment, self)._notify_get_recipients(message, groups)
40 changes: 11 additions & 29 deletions account_payment_receivable_email/models/mail_compose_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,54 +17,36 @@ def onchange_template_id(self, template_id, composition_mode, model, res_id):
res = super(MailComposer, self).onchange_template_id(
template_id, composition_mode, model, res_id)

# Check model: we target Payment and Invoices
if model not in ['account.payment', 'account.move'] or not res_id:
return res

record = self.env[model].browse(res_id)
partner = getattr(record, 'partner_id', False)

if partner and partner.payment_email:
child = self.env['res.partner'].search([
('parent_id', '=', partner.id),
('is_receivable_account', '=', True)
], limit=1)
if child:
if 'value' not in res:
res['value'] = {}
res['value']['partner_ids'] = [(6, 0, [child.id])]
if partner and partner.payment_email_id:
if 'value' not in res:
res['value'] = {}
res['value']['partner_ids'] = [(6, 0, [partner.payment_email_id.id])]

return res

def get_mail_values(self, res_ids):
"""
Override to inject the specific recipient at sending time.
COMPATIBLE WITH:
- Standard Send (Comment mode)
- Mass Mailing (Batch Send)
- Canada Bank Transfer (EFT Wizards)
"""
self.ensure_one()
results = super(MailComposer, self).get_mail_values(res_ids)

# Safety check on model
if self.model not in ["account.payment", "account.move"]:
return results

for res_id, mail_values in results.items():
record = self.env[self.model].browse(res_id)
partner = getattr(record, 'partner_id', False)

if partner and partner.payment_email:
child = self.env['res.partner'].search([
('parent_id', '=', partner.id),
('is_receivable_account', '=', True)
], limit=1)
if partner and partner.payment_email_id:
target_id = partner.payment_email_id.id

if child:
if 'partner_ids' in mail_values:
mail_values['partner_ids'] = [child.id]
if 'partner_ids' in mail_values:
mail_values['partner_ids'] = [target_id]

if 'recipient_ids' in mail_values:
mail_values['recipient_ids'] = [(5, 0, 0), (4, child.id)]
if 'recipient_ids' in mail_values:
mail_values['recipient_ids'] = [(5, 0, 0), (4, target_id)]

return results
67 changes: 0 additions & 67 deletions account_payment_receivable_email/models/mail_mail.py

This file was deleted.

83 changes: 6 additions & 77 deletions account_payment_receivable_email/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# © Numigi (tm) and all its contributors (https://numigi.com/r/home)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models, _
from odoo import fields, models


class ResPartner(models.Model):
Expand All @@ -13,80 +13,9 @@ class ResPartner(models.Model):
copy=False,
)

payment_email = fields.Char(
string="Receivable Accounts Email",
help="Email address to send payment notifications and receipts",
inverse="_inverse_payment_email"
payment_email_id = fields.Many2one(
'res.partner',
string="Receivable Accounts Contact",
domain="[('is_receivable_account', '=', True)]",
help="Select the specific contact to receive payment notifications."
)

def _inverse_payment_email(self):
"""
Sync from Parent Field -> Child Contact.
Uses the 'is_receivable_account' boolean to identify the target.
"""
for partner in self:
# --- ANTI- UNLIMITED LOOP ---
if partner.is_receivable_account:
continue

if partner.payment_email:
child_partner = self.env['res.partner'].with_context(active_test=False).search([
('parent_id', '=', partner.id),
('is_receivable_account', '=', True)
], limit=1)

unique_fake_email = f"{partner.payment_email}.{partner.id}"

if child_partner:
# Update existing contact
if child_partner.payment_email != partner.payment_email:
child_partner.payment_email = partner.payment_email
child_partner.email = unique_fake_email

# Reactivate if it was archived
if not child_partner.active:
child_partner.active = True
else:
# Create NEW contact with the Boolean set to True
self.env['res.partner'].create({
'name': _('Receivable Accounts'),
'parent_id': partner.id,
'type': 'other',
'company_type': 'person',
'email': unique_fake_email,
'payment_email': partner.payment_email,
'is_receivable_account': True,
'comment': _('Automatically created from the '
'Receivable Accounts Email field.'),
})

else:
# Field Cleared -> Find the boolean contact and Archive it
child_to_archive = self.env['res.partner'].search([
('parent_id', '=', partner.id),
('is_receivable_account', '=', True)
], limit=1)

if child_to_archive:
child_to_archive.active = False

def write(self, vals):
"""
Sync from Child Contact -> Parent Field.
We strictly listen to contacts marked with 'is_receivable_account'.
"""
records_to_sync = self.env['res.partner']
if 'payment_email' in vals:
for record in self:
if record.parent_id and record.is_receivable_account:
records_to_sync += record

# Perform Standard Write
res = super(ResPartner, self).write(vals)

# Propagate to parents
for record in records_to_sync:
if record.parent_id.payment_email != vals['payment_email']:
record.parent_id.payment_email = vals['payment_email']

return res
Loading
Loading