Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[15.0][MIG] connector_jira_tempo: Migrate to version 15.0 #82

Merged
merged 18 commits into from
Jul 25, 2022
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
26 changes: 16 additions & 10 deletions connector_jira_tempo/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ JIRA Connector Tempo
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fconnector--jira-lightgray.png?logo=github
:target: https://github.com/OCA/connector-jira/tree/13.0/connector_jira_tempo
:target: https://github.com/OCA/connector-jira/tree/15.0/connector_jira_tempo
:alt: OCA/connector-jira
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/connector-jira-13-0/connector-jira-13-0-connector_jira_tempo
:target: https://translation.odoo-community.org/projects/connector-jira-15-0/connector-jira-15-0-connector_jira_tempo
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/233/13.0
:target: https://runbot.odoo-community.org/runbot/233/15.0
:alt: Try me on Runbot

|badge1| |badge2| |badge3| |badge4| |badge5|
|badge1| |badge2| |badge3| |badge4| |badge5|

This module adds Jira Tempo synchronization feature.

Expand All @@ -38,7 +38,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/OCA/connector-jira/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/connector-jira/issues/new?body=module:%20connector_jira_tempo%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
`feedback <https://github.com/OCA/connector-jira/issues/new?body=module:%20connector_jira_tempo%0Aversion:%2015.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Expand All @@ -53,14 +53,20 @@ Authors
Contributors
~~~~~~~~~~~~

* Guewen Baconnier <guewen.baconnier@camptocamp.com>
* Simone Orsi <simahawk@gmail.com>
* `Camptocamp <https://www.camptocamp.com>`_:

* Simone Orsi <simahawk@gmail.com>
* Guewen Baconnier <guewen.baconnier@camptocamp.com>
* Akim Juillerat <akim.juillerat@camptocamp.com>
* Denis Leemann <denis.leemann@camptocamp.com>

* `CorporateHub <https://corporatehub.eu/>`__

* Alexey Pelykh <alexey.pelykh@corphub.eu>

* Akim Juillerat <akim.juillerat@camptocamp.com>
* Denis Leemann <denis.leemann@camptocamp.com>
* `Trobz <https://trobz.com>`_:

* Son Ho <sonhd@trobz.com>

Maintainers
~~~~~~~~~~~
Expand All @@ -75,6 +81,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/connector-jira <https://github.com/OCA/connector-jira/tree/13.0/connector_jira_tempo>`_ project on GitHub.
This module is part of the `OCA/connector-jira <https://github.com/OCA/connector-jira/tree/15.0/connector_jira_tempo>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
3 changes: 3 additions & 0 deletions connector_jira_tempo/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from . import models
17 changes: 17 additions & 0 deletions connector_jira_tempo/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

{
"name": "JIRA Connector Tempo",
"version": "15.0.1.0.0",
"author": "Camptocamp, Odoo Community Association (OCA)",
"license": "AGPL-3",
"category": "Connector",
"depends": ["connector_jira_tempo_base", "hr_timesheet"],
"website": "https://github.com/OCA/connector-jira",
"data": [
"data/cron.xml",
"views/jira_backend_view.xml",
"views/timesheet_account_analytic_line.xml",
],
"installable": True,
}
20 changes: 20 additions & 0 deletions connector_jira_tempo/data/cron.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
-->
<odoo noupdate="1">
<record id="ir_cron_jira_sync_tempo_timesheets_approval_status" model="ir.cron">
<field name="name">JIRA - Sync Tempo Timesheet approval status</field>
<field name="model_id" ref="model_jira_backend" />
<field name="state">code</field>
<field name="code">
model.search([])._scheduler_sync_tempo_timesheets_approval_status()
</field>
<field eval="False" name="active" />
<field name="user_id" ref="base.user_root" />
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
</record>
</odoo>
81 changes: 81 additions & 0 deletions connector_jira_tempo/i18n/connector_jira_tempo.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * connector_jira_tempo
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: connector_jira_tempo
#: model:ir.model,name:connector_jira_tempo.model_account_analytic_line
msgid "Analytic Line"
msgstr ""

#. module: connector_jira_tempo
#: model:ir.model.fields.selection,name:connector_jira_tempo.selection__account_analytic_line__jira_tempo_status__approved
msgid "Approved"
msgstr ""

#. module: connector_jira_tempo
#: model:ir.model.fields,help:connector_jira_tempo.field_jira_backend__validate_approved_ts
msgid ""
"If this flag is ON, once the status is sync'ed from Jira, all approved "
"timesheets will be validated on Odoo as well."
msgstr ""

#. module: connector_jira_tempo
#: model:ir.actions.server,name:connector_jira_tempo.ir_cron_jira_sync_tempo_timesheets_approval_status_ir_actions_server
#: model:ir.cron,cron_name:connector_jira_tempo.ir_cron_jira_sync_tempo_timesheets_approval_status
#: model:ir.cron,name:connector_jira_tempo.ir_cron_jira_sync_tempo_timesheets_approval_status
msgid "JIRA - Sync Tempo Timesheet approval status"
msgstr ""

#. module: connector_jira_tempo
#: model:ir.model,name:connector_jira_tempo.model_jira_backend
msgid "Jira Backend"
msgstr ""

#. module: connector_jira_tempo
#: model:ir.model.fields,field_description:connector_jira_tempo.field_jira_backend__jira_company_team_id
msgid "Jira Company Team"
msgstr ""

#. module: connector_jira_tempo
#: model:ir.model.fields,field_description:connector_jira_tempo.field_account_analytic_line__jira_tempo_status
#: model:ir.model.fields,field_description:connector_jira_tempo.field_jira_account_analytic_line__jira_tempo_status
msgid "Jira Tempo Status"
msgstr ""

#. module: connector_jira_tempo
#: model:ir.model.fields.selection,name:connector_jira_tempo.selection__account_analytic_line__jira_tempo_status__open
msgid "Open"
msgstr ""

#. module: connector_jira_tempo
#: model:ir.model.fields.selection,name:connector_jira_tempo.selection__account_analytic_line__jira_tempo_status__ready_to_submit
msgid "Ready to submit"
msgstr ""

#. module: connector_jira_tempo
#: model:ir.model.fields,help:connector_jira_tempo.field_jira_backend__jira_company_team_id
msgid ""
"This field contains the ID of a company wide group on JIRA. Its main usage "
"is to fetch tempo statuses for ALL employees."
msgstr ""

#. module: connector_jira_tempo
#: model:ir.model.fields,field_description:connector_jira_tempo.field_jira_backend__validate_approved_ts
msgid "Validate Approved Ts"
msgstr ""

#. module: connector_jira_tempo
#: model:ir.model.fields.selection,name:connector_jira_tempo.selection__account_analytic_line__jira_tempo_status__waiting_for_approval
msgid "Waiting for approval"
msgstr ""
4 changes: 4 additions & 0 deletions connector_jira_tempo/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from . import account_analytic_line
from . import jira_backend
4 changes: 4 additions & 0 deletions connector_jira_tempo/models/account_analytic_line/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from . import common
from . import importer
59 changes: 59 additions & 0 deletions connector_jira_tempo/models/account_analytic_line/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright 2019 Camptocamp SA
# Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models

from odoo.addons.component.core import Component


class AccountAnalyticLine(models.Model):
_inherit = "account.analytic.line"

jira_tempo_status = fields.Selection(
selection=[
("approved", "Approved"),
("waiting_for_approval", "Waiting for approval"),
("ready_to_submit", "Ready to submit"),
("open", "Open"),
]
)


class WorklogAdapter(Component):
_inherit = "jira.worklog.adapter"

def read(self, issue_id, worklog_id):
worklog = super().read(issue_id, worklog_id)
if self.env.context.get("jira_worklog_no_tempo_timesheets_approval_data"):
return worklog
with self.handle_404():
worklog["_tempo_timesheets_approval"] = self.tempo_timesheets_approval_read(
worklog
)
return worklog

def tempo_timesheets_approval_read(self, worklog):
url = self._tempo_timesheets_get_url("timesheet-approval/current")
with self.handle_404():
response = self.client._session.get(
url,
params={
"username": worklog["author"]["name"],
}, # noqa
)
return response.json()

def tempo_timesheets_approval_read_status_by_team(
self, team_id, period_start
): # noqa
url = self._tempo_timesheets_get_url("timesheet-approval")
with self.handle_404():
response = self.client._session.get(
url,
params={
"teamId": team_id,
"periodStartDate": period_start,
}, # noqa
)
return response.json()
18 changes: 18 additions & 0 deletions connector_jira_tempo/models/account_analytic_line/importer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2018 Camptocamp SA
# Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo.addons.component.core import Component
from odoo.addons.connector.components.mapper import mapping


class AnalyticLineMapper(Component):
_inherit = "jira.analytic.line.mapper"

@mapping
def tempo_timesheets_approval(self, record):
approval = record["_tempo_timesheets_approval"]
values = {
"jira_tempo_status": approval["status"],
}
return values
1 change: 1 addition & 0 deletions connector_jira_tempo/models/jira_backend/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import common
112 changes: 112 additions & 0 deletions connector_jira_tempo/models/jira_backend/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Copyright 2019 Camptocamp SA
# Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

import logging
from collections import defaultdict
from datetime import datetime, timedelta

from odoo import fields, models

_logger = logging.getLogger(__name__)


def get_past_week_1st_day():
today = datetime.today()
date = today - timedelta(days=today.weekday() % 7) - timedelta(weeks=1)
return date.strftime("%Y-%m-%d")


class JiraBackend(models.Model):
_inherit = "jira.backend"

# TODO: shall we sync Odoo groups w/ JIRA groups?
# shall we sync JIRA groups only as independent records
# and replace this field w/ a m2o?
# ATM (2019-05-08) we don't have time and we don't care.
# We just need to pull all the TS statuses
# but we need the ID of a JIRA groups containing ALL employees.
jira_company_team_id = fields.Integer(
help="This field contains the ID of a company wide group on JIRA. "
"Its main usage is to fetch tempo statuses for ALL employees."
)
validate_approved_ts = fields.Boolean(
help="If this flag is ON, once the status is sync'ed from Jira, "
"all approved timesheets will be validated on Odoo as well."
)

def _scheduler_sync_tempo_timesheets_approval_status(self, period_start=None):
"""Synchronize JIRA Tempo timesheet status on Odoo TS lines.

Look up for previous week timesheets and update Odoo status.
If `period_start` is given, it will be used as look up date.

:param period_start: custom date (server format) for the beginning
of the period
"""
if period_start is None:
# NOTE: it seems that the preciseness of this date
# is not really important.
# If you don't pass the very begin date of the period
# but a date in the middle, the api will give you back
# the right period range matching that date.
# Still, we want to put clear that we want to retrieve
# the past week period.
period_start = get_past_week_1st_day()
for backend in self:
backend._sync_tempo_timesheets_approval_status(period_start)

def _sync_tempo_timesheets_approval_status(self, period_start):
"""Find users and TS lines and update tempo status."""
team_id = self.jira_company_team_id
with self.work_on("jira.account.analytic.line") as work:
importer = work.component(usage="backend.adapter")
result = importer.tempo_timesheets_approval_read_status_by_team(
team_id,
period_start,
)
user_binder = importer.binder_for("jira.res.users")
# Pick the date range from the Tempo period.
# In this way we make sure we affect only the dates we want.
date_from = result["period"]["dateFrom"]
date_to = result["period"]["dateTo"]
approvals = result.get("approvals", [])
mapping = defaultdict(list)
for entry in approvals:
user_data = entry["user"]
try:
user = user_binder.to_internal(user_data["key"], unwrap=True)
except ValueError:
_logger.error("User %(key)s not found" % user_data)
continue
mapping[entry["status"]].append(user.id)
for state, user_ids in mapping.items():
self._update_ts_line_status(date_from, date_to, state, user_ids)

def _update_ts_line_status(self, date_from, date_to, state, user_ids):
lines = self._get_ts_lines(date_from, date_to, user_ids)
lines.mapped("jira_bind_ids").write({"jira_tempo_status": state})
self._validate_ts(date_from, date_to, state, user_ids)

def _get_ts_lines_domain(self, date_from, date_to, user_ids):
domain = [
# TODO: any better filter here?
# `is_timesheet` is not available since we don't use ts_grid
# But `is_timesheet` is a computed field with value:
# project_id setted
("project_id", "!=", False),
("date", ">=", date_from),
("date", "<=", date_to),
("user_id", "in", user_ids),
]
return domain

def _get_ts_lines(self, date_from, date_to, user_ids):
ts_line_model = self.env["account.analytic.line"]
domain = self._get_ts_lines_domain(date_from, date_to, user_ids)
return ts_line_model.search(domain)

def _validate_ts(self, date_from, date_to, state, user_ids):
# hook here and do what you want depending on the state
# eg: if self.validate_approved_ts and state == 'approved'
pass
Loading