# -*- coding: utf-8 -*- # Copyright 2026 Nexa Systems Inc. # License OPL-1 from odoo import api, fields, models class FusionBillingAccountLink(models.Model): """Identity resolution: maps an app's external account id to one res.partner. Folds the NexaCloud user / NexaDesk tenant / NexaMaps client for the same real-world client onto a single partner (the unified customer). See spec §5.1. """ _name = "fusion.billing.account.link" _description = "Fusion Billing — External Account → Partner Link" _order = "service_id, external_id" service_id = fields.Many2one( "fusion.billing.service", required=True, ondelete="cascade", index=True, ) external_id = fields.Char( required=True, index=True, help="The app's own account id (NexaCloud user, NexaDesk tenant, Maps client).", ) external_email = fields.Char() partner_id = fields.Many2one( "res.partner", required=True, ondelete="restrict", index=True, ) _service_external_uniq = models.Constraint( "unique(service_id, external_id)", "An external account can only link to one partner per service.", ) @api.model def _resolve_or_create_partner(self, service, external_id, name=None, email=None, extra=None): """Return the link for (service, external_id), creating partner+link if needed. Unifies customers: if a link for this external_id exists, reuse it; else if a partner with the same email already exists (possibly from another service), link to it; else create a new partner. """ existing = self.search( [('service_id', '=', service.id), ('external_id', '=', external_id)], limit=1) if existing: return existing partner = self.env['res.partner'] if email: partner = partner.search([('email', '=', email)], limit=1) if not partner: partner = partner.create({'name': name or external_id, 'email': email, **(extra or {})}) return self.create({ 'service_id': service.id, 'external_id': external_id, 'external_email': email, 'partner_id': partner.id, })