Skip to content
Extraits de code Groupes Projets
Sélectionner une révision Git
  • e5a40ec97e4846fb1935e660ef4aad9892ac68c8
  • 12.0 par défaut protégée
  • 17.0
  • 18.0
  • 16.0
  • 14.0
  • 15.0
  • 13.0
  • 10.0
  • 9.0
10 résultats

tresorerie.js

Blame
  • res_users.py 10,48 Kio
    # Copyright 2021 Le Filament (https://le-filament.com)
    # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
    
    import logging
    
    from netbluemind.calendar.api.ICalendarUids import ICalendarUids
    from netbluemind.python.client import BMClient, ServerFault
    
    from odoo import _, api, fields, models
    from odoo.exceptions import UserError
    from odoo.loglevels import exception_to_unicode
    
    _logger = logging.getLogger(__name__)
    
    
    class ResUser(models.Model):
        _inherit = "res.users"
    
        """
        This inheriting class adds some fields and methods to res.users in order to store
        information for connecting user to Bluemind :
            * bluemind_login / bluemind_password
            * is_bm_connection_ok : boolean set when connection was successful
            * bluemind_user_id : to store the identifier of the user in Bluemind
            * bluemind_calendar_id : to store the main calendar id linked to user
            * last_sync_version : last version of calendar synced
              (Bluemind increments a versionning sequence at each change on calendar)
        """
        bluemind_login = fields.Char("Bluemind e-mail")
        bluemind_password = fields.Char("Bluemind password or API key")
        is_bm_connection_ok = fields.Boolean("Bluemind Connection OK", default=False)
        bluemind_user_id = fields.Char(
            "Bluemind user ID", compute="_compute_bluemind_user_id", store=True
        )
        bluemind_calendar_id = fields.Char(
            "Bluemind calendar ID", compute="_compute_bluemind_calendar_uid", store=True
        )
        last_sync_version = fields.Integer("Last sync version", readonly=True, default=0)
    
        @api.depends("company_id.bluemind_url", "bluemind_login", "bluemind_password")
        def bluemind_auth(self, force=False):
            """
            This method connect to Bluemind API and returns the client object
            This authentication is only performed if all the above conditions are met:
                * bluemind_url is set on company
                * bluemind_login and bluemind_password are set on user
                * connection was already successful with provided creds or force
                  parameter is given (allowing to make first auth) - this last condition
                  is here to avoid locking the account in case the creds are incorrect,
                  since this method is used in most other methods to retrieve client object
            """
            self.ensure_one()
            if (
                self.company_id.bluemind_url
                and self.bluemind_login
                and self.bluemind_password
                and (self.is_bm_connection_ok or force)
            ):
                try:
                    client = BMClient(self.company_id.bluemind_url + "/api")
                    client.login(self.bluemind_login, self.bluemind_password)
                    self.is_bm_connection_ok = True
                    return client
                # TODO: better manage exception
                except (ServerFault, Exception) as e:
                    self.is_bm_connection_ok = False
                    if force:
                        raise UserError(
                            _(
                                "Something went wrong during connection : [%s]",
                                exception_to_unicode(e),
                            )
                        )
                return False
    
        def force_auth(self):
            """
            This methods force authentication (or re-auth) mechanism with creds stored on user
            It is called from button on user view
            """
            # TODO : add notification that it works or not
            return self.bluemind_auth(force=True)
    
        @api.depends(
            "company_id.bluemind_domain",
            "bluemind_login",
            "bluemind_password",
            "is_bm_connection_ok",
        )
        def _compute_bluemind_user_id(self):
            """
            This method retrieves the user id from Bluemind client object
            """
            for user in self:
                if (
                    user.company_id.bluemind_url
                    and user.bluemind_login
                    and user.bluemind_password
                    and user.is_bm_connection_ok
                ):
                    client = user.bluemind_auth()
                    if client:
                        user.bluemind_user_id = (
                            client.directory(user.company_id.bluemind_domain)
                            .getByEmail(user.bluemind_login)
                            .entryUid
                        )
    
        @api.depends("bluemind_user_id")
        def _compute_bluemind_calendar_uid(self):
            """
            This method retrieves default calendar uid from Bluemind for the user
            """
            for user in self:
                client_bm = user.bluemind_auth()
                if client_bm and user.bluemind_user_id:
                    user.bluemind_calendar_id = ICalendarUids(
                        client_bm.apiKey, client_bm.baseUrl
                    ).getDefaultUserCalendar(user.bluemind_user_id)
    
        def sync_bluemind_calendar(self):
            """
            This methods retrieves last calendar changes from Bluemind
            These charges are grouped in 3 objects :
              * created : all events created since last sync
              * updated : all events updated since last sync
              * deleted : all events deleted since last sync
            Then it creates/updates/deletes Odoo events accordingly
            The parti pris here is the following : every event in Bluemind calendar
            is recreated in Odoo with organizer = user
            """
            self.ensure_one()
            # Retrieve emails from all internal & active Odoo users
            odoo_users_emails = (
                self.sudo()
                .env["res.users"]
                .search([("share", "=", False), ("active", "=", True)])
                .mapped("partner_id.email")
            )
    
            # TODO: add checks and error handling
            # Retrieve all events modified since last sync (followed by self.bluemind_id_version)
            bm_calendar = self.bluemind_auth().calendar(self.bluemind_calendar_id)
            # TODO : avoid retrieving all events from beginning, limit to 3 months in past ?
            # The following function actually retrieves only Blemind event ids, not the full events
            bm_changeset = bm_calendar.changeset(self.last_sync_version)
            bm_created_uids = bm_changeset.created
            bm_updated_uids = bm_changeset.updated
            bm_deleted_uids = bm_changeset.deleted
            bm_last_version = bm_changeset.version
    
            # Retrieve all events from Odoo with a bluemind_id
            # (= already synced at least once with Bluemind)
            Calendar = self.env["calendar.event"]
            odoo_events_bm_linked = Calendar.search([("bluemind_id", "!=", False)])
            odoo_events_bm_uids = odoo_events_bm_linked.mapped("bluemind_id")
    
            # Calendar entries created on Bluemind side, not already in Odoo
            # The events already in Odoo are ignored (probably already synced previously
            if bm_created_uids:
                events_to_create = []
                bm_events_to_create_uids = [
                    e for e in bm_created_uids if e not in odoo_events_bm_uids
                ]
                # Retrieve remaining full events from Bluemind
                bm_events_to_create = bm_calendar.multipleGet(bm_events_to_create_uids)
                # Create corresponding events in Odoo
                for bm_event in bm_events_to_create:
                    # Only if Organizer is the same as Odoo user or if is not linked to
                    # any active Odoo internal user
                    if (
                        bm_event.value.main.organizer
                        and (bm_event.value.main.organizer.mailto == self.partner_id.email
                        or bm_event.value.main.organizer.mailto not in odoo_users_emails)
                    ):
                        events_to_create.append(Calendar._bm_to_odoo_values(bm_event))
                if events_to_create:
                    Calendar.create(events_to_create)
    
            # Calendar entries that have been updated on Bluemind
            # Retrieve full events from Bluemind
            if bm_updated_uids:
                bm_events_to_update = bm_calendar.multipleGet(bm_updated_uids)
                # Update corresponding events
                for bm_event in bm_events_to_update:
                    odoo_event = odoo_events_bm_linked.filtered_domain(
                        [("bluemind_id", "=", bm_event.uid)]
                    )
                    # If related event exists in Odoo and belongs to the user, update it
                    if odoo_event:
                        if odoo_event.user_id == self:
                            odoo_event.update_odoo_event_from_bm(bm_event)
                    # If event does not exist in Odoo log an info
                    else:
                        _logger.info(
                            "Event %s updated in Bluemind does not exist in Odoo", bm_event.uid
                        )
    
            # Calendar entries that have been deleted on Bluemind to be deleted on Odoo
            # (only if belongs to user)
            if bm_deleted_uids:
                odoo_events_to_delete = odoo_events_bm_linked.filtered_domain(
                    [("bluemind_id", "in", bm_deleted_uids), ("user_id", "=", self.id)]
                )
                if odoo_events_to_delete:
                    odoo_events_to_delete.unlink(from_bluemind=True)
    
            # Update user last_sync_version with the latest one retrieved from Bluemind
            self.last_sync_version = bm_last_version
    
            # TODO : sync all Odoo events without bluemind_id
            # Should we sync only events on which user_id is the current user
            # Or also all events to which he was invited as participant ?
            # First we would sync only the ones where he is user_id
            # (because otherwise you would set bluemind_id on an event which
            # does not belong to the current user, and may have already been synced
            # - with different bluemind_id by the organizer (user_id))
            odoo_events_no_bm = Calendar.search(
                [("user_id", "=", self.id), ("bluemind_id", "=", False)]
            )
            odoo_events_no_bm.create_odoo_events_in_bm()
    
        @api.model
        def _sync_all_bm_calendar(self):
            """
            Cron job to sync calendars for all users with is_bm_connection_ok
            """
            users = self.env["res.users"].search([("is_bm_connection_ok", "!=", False)])
            for user in users:
                _logger.info("Calendar Synchro - Starting synchronization for %s", user)
                try:
                    user.with_user(user).sync_bluemind_calendar()
                    _logger.info(
                        "Calendar Synchro - Completed synchronization for %s", user
                    )
                except Exception as e:
                    _logger.exception(
                        "[%s] Calendar Synchro - Exception : %s !",
                        user,
                        exception_to_unicode(e),
                    )