diff --git a/connector_jira_tempo/__init__.py b/connector_jira_tempo/__init__.py index 4b76c7b2..17a16161 100644 --- a/connector_jira_tempo/__init__.py +++ b/connector_jira_tempo/__init__.py @@ -1,3 +1,5 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import components from . import models +from . import reports diff --git a/connector_jira_tempo/__manifest__.py b/connector_jira_tempo/__manifest__.py index df6f6ee2..79d89e3d 100644 --- a/connector_jira_tempo/__manifest__.py +++ b/connector_jira_tempo/__manifest__.py @@ -2,7 +2,7 @@ { "name": "JIRA Connector Tempo", - "version": "15.0.1.0.0", + "version": "17.0.1.0.0", "author": "Camptocamp, Odoo Community Association (OCA)", "license": "AGPL-3", "category": "Connector", @@ -10,8 +10,8 @@ "website": "https://github.com/OCA/connector-jira", "data": [ "data/cron.xml", - "views/jira_backend_view.xml", - "views/timesheet_account_analytic_line.xml", + "views/account_analytic_line.xml", + "views/jira_backend.xml", ], "installable": True, } diff --git a/connector_jira_tempo/components/__init__.py b/connector_jira_tempo/components/__init__.py new file mode 100644 index 00000000..ef6b869e --- /dev/null +++ b/connector_jira_tempo/components/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import jira_analytic_line_mapper +from . import jira_worklog_adapter diff --git a/connector_jira_tempo/models/account_analytic_line/importer.py b/connector_jira_tempo/components/jira_analytic_line_mapper.py similarity index 75% rename from connector_jira_tempo/models/account_analytic_line/importer.py rename to connector_jira_tempo/components/jira_analytic_line_mapper.py index 8d96bf6d..b021ff85 100644 --- a/connector_jira_tempo/models/account_analytic_line/importer.py +++ b/connector_jira_tempo/components/jira_analytic_line_mapper.py @@ -6,13 +6,10 @@ from odoo.addons.connector.components.mapper import mapping -class AnalyticLineMapper(Component): +class JiraAnalyticLineMapper(Component): _inherit = "jira.analytic.line.mapper" @mapping def tempo_timesheets_approval(self, record): approval = record.get("_tempo_timesheets_approval", {"status": {"key": "OPEN"}}) - values = { - "jira_tempo_status": approval["status"]["key"].lower(), - } - return values + return {"jira_tempo_status": approval["status"]["key"].lower()} diff --git a/connector_jira_tempo/components/jira_worklog_adapter.py b/connector_jira_tempo/components/jira_worklog_adapter.py new file mode 100644 index 00000000..8d30e370 --- /dev/null +++ b/connector_jira_tempo/components/jira_worklog_adapter.py @@ -0,0 +1,32 @@ +# 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 datetime +import json + +from odoo.addons.component.core import Component + + +class JiraWorklogAdapter(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(): + approval = self.tempo_timesheets_approval_read(worklog) + worklog["_tempo_timesheets_approval"] = approval + return worklog + + def tempo_timesheets_approval_read(self, worklog): + backend = self._tempo_timesheets_get_webservice() + account_id = worklog["author"]["accountId"] + period_start = datetime.date.today().isoformat() + endpoint = f"timesheet-approvals/user/{account_id}?from={period_start}" + return json.loads(backend.call("get", url_params={"endpoint": endpoint})) + + def tempo_timesheets_approval_read_status_by_team(self, team_id, period_start): + backend = self._tempo_timesheets_get_webservice() + endpoint = f"timesheet-approvals/team/{team_id}?from={period_start}" + return json.loads(backend.call("get", url_params={"endpoint": endpoint})) diff --git a/connector_jira_tempo/data/cron.xml b/connector_jira_tempo/data/cron.xml index 42670e3e..9e13cd41 100644 --- a/connector_jira_tempo/data/cron.xml +++ b/connector_jira_tempo/data/cron.xml @@ -10,11 +10,11 @@ model.search([])._scheduler_sync_tempo_timesheets_approval_status() - + 1 days -1 - + diff --git a/connector_jira_tempo/models/account_analytic_line.py b/connector_jira_tempo/models/account_analytic_line.py new file mode 100644 index 00000000..96d214b8 --- /dev/null +++ b/connector_jira_tempo/models/account_analytic_line.py @@ -0,0 +1,21 @@ +# 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 + + +class AccountAnalyticLine(models.Model): + _inherit = "account.analytic.line" + + jira_tempo_status = fields.Selection( + selection=[ + ("approved", "Approved"), + ("in_review", "In Review"), + # no longer used on cloud version + ("waiting_for_approval", "Waiting for approval"), + # no longer used on cloud version + ("ready_to_submit", "Ready to submit"), + ("open", "Open"), + ] + ) diff --git a/connector_jira_tempo/models/account_analytic_line/__init__.py b/connector_jira_tempo/models/account_analytic_line/__init__.py deleted file mode 100644 index ea8197b1..00000000 --- a/connector_jira_tempo/models/account_analytic_line/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). - -from . import common -from . import importer diff --git a/connector_jira_tempo/models/account_analytic_line/common.py b/connector_jira_tempo/models/account_analytic_line/common.py deleted file mode 100644 index b3c17dda..00000000 --- a/connector_jira_tempo/models/account_analytic_line/common.py +++ /dev/null @@ -1,62 +0,0 @@ -# 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 datetime -import json - -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"), - ("in_review", "In Review"), - ( - "waiting_for_approval", - "Waiting for approval", - ), # no longer used on cloud version - ("ready_to_submit", "Ready to submit"), # no longer used on cloud version - ("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): - backend = self._tempo_timesheets_get_webservice() - account_id = worklog["author"]["accountId"] - period_start = datetime.date.today().isoformat() - response = backend.call( - "get", - url_params={ - "endpoint": f"timesheet-approvals/user/{account_id}?from={period_start}" - }, - ) - return json.loads(response) - - def tempo_timesheets_approval_read_status_by_team(self, team_id, period_start): # noqa - backend = self._tempo_timesheets_get_webservice() - response = backend.call( - "get", - url_params={ - "endpoint": f"timesheet-approvals/team/{team_id}?from={period_start}" - }, - ) - return json.loads(response) diff --git a/connector_jira_tempo/models/jira_backend/common.py b/connector_jira_tempo/models/jira_backend.py similarity index 90% rename from connector_jira_tempo/models/jira_backend/common.py rename to connector_jira_tempo/models/jira_backend.py index 53fd37ea..879ecebf 100644 --- a/connector_jira_tempo/models/jira_backend/common.py +++ b/connector_jira_tempo/models/jira_backend.py @@ -13,8 +13,7 @@ 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") + return (today - timedelta(weeks=1, days=today.weekday() % 7)).strftime("%Y-%m-%d") class JiraBackend(models.Model): @@ -47,7 +46,7 @@ def _scheduler_sync_tempo_timesheets_approval_status(self, period_start=None): 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 + # If you don't pass the very beginning 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 @@ -62,8 +61,7 @@ def _sync_tempo_timesheets_approval_status(self, period_start): with self.work_on("jira.account.analytic.line") as work: importer = work.component(usage="backend.adapter") response = importer.tempo_timesheets_approval_read_status_by_team( - team_id, - period_start, + team_id, period_start ) user_binder = importer.binder_for("jira.res.users") mapping = defaultdict(list) @@ -76,18 +74,22 @@ def _sync_tempo_timesheets_approval_status(self, period_start): except ValueError: _logger.error("User %s not found", user_data) continue - status = result["status"]["key"].lower() - mapping[(date_from, date_to, status)].append(user.id) + mapping[(date_from, date_to, result["status"]["key"].lower())] += [user.id] for (date_from, date_to, 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}) + lines.jira_bind_ids.write({"jira_tempo_status": state}) self._validate_ts(date_from, date_to, state, user_ids) + 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 _get_ts_lines_domain(self, date_from, date_to, user_ids): - domain = [ + return [ # 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: @@ -97,12 +99,6 @@ def _get_ts_lines_domain(self, date_from, date_to, user_ids): ("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 diff --git a/connector_jira_tempo/models/jira_backend/__init__.py b/connector_jira_tempo/models/jira_backend/__init__.py deleted file mode 100644 index e4193cf0..00000000 --- a/connector_jira_tempo/models/jira_backend/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import common diff --git a/connector_jira_tempo/reports/__init__.py b/connector_jira_tempo/reports/__init__.py new file mode 100644 index 00000000..2e30f148 --- /dev/null +++ b/connector_jira_tempo/reports/__init__.py @@ -0,0 +1 @@ +from . import timesheet_analysis_report diff --git a/connector_jira_tempo/reports/timesheet_analysis_report.py b/connector_jira_tempo/reports/timesheet_analysis_report.py new file mode 100644 index 00000000..02120c8d --- /dev/null +++ b/connector_jira_tempo/reports/timesheet_analysis_report.py @@ -0,0 +1,24 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models + + +class TimesheetsAnalysisReport(models.Model): + _inherit = "timesheets.analysis.report" + + jira_tempo_status = fields.Selection( + selection=[ + ("approved", "Approved"), + ("in_review", "In Review"), + # no longer used on cloud version + ("waiting_for_approval", "Waiting for approval"), + # no longer used on cloud version + ("ready_to_submit", "Ready to submit"), + ("open", "Open"), + ], + readonly=True, + ) + + @api.model + def _select(self): + return super()._select() + ", A.jira_tempo_status AS jira_tempo_status" diff --git a/connector_jira_tempo/views/timesheet_account_analytic_line.xml b/connector_jira_tempo/views/account_analytic_line.xml similarity index 79% rename from connector_jira_tempo/views/timesheet_account_analytic_line.xml rename to connector_jira_tempo/views/account_analytic_line.xml index 997041e1..45c94540 100644 --- a/connector_jira_tempo/views/timesheet_account_analytic_line.xml +++ b/connector_jira_tempo/views/account_analytic_line.xml @@ -9,7 +9,7 @@ - + @@ -23,7 +23,7 @@ - jira_tempo_status=='open' + jira_tempo_status == 'open' @@ -36,8 +36,13 @@ - - + + diff --git a/connector_jira_tempo/views/jira_backend_view.xml b/connector_jira_tempo/views/jira_backend.xml similarity index 100% rename from connector_jira_tempo/views/jira_backend_view.xml rename to connector_jira_tempo/views/jira_backend.xml