- [[ o.date_invoice and formatLang(o.date_invoice, date=True) or '' ]]
-
-
-
-
- Amount bought: [[ (o.type == 'amount' or removeParentNode('para')) and '' ]]
- Quantity of hours bought: [[ (o.type == 'hours' or removeParentNode('para')) and '' ]]
-
-
- [[ o.amount_hours_block ]]
-
-
-
-
- Amount used: [[ (o.type == 'amount' or removeParentNode('para')) and '' ]]
- Quantity of hours used: [[ (o.type == 'hours' or removeParentNode('para')) and '' ]]
-
-
- [[ round(o.amount_hours_block_done, 2) ]]
-
-
-
-
- Remaining amount: [[ (o.type == 'amount' or removeParentNode('para')) and '' ]]
- Remaining hours: [[ (o.type == 'hours' or removeParentNode('para')) and '' ]]
-
-
-
- [[ o.amount_hours_block and round(o.amount_hours_block_delta, 2) or '' ]]
-
-
-
-
-
-
-
-
-
- Date
-
-
- Description
-
-
- Quantity
-
-
- Invoicing
-
-
- Deduced
-
-
-
-
- [[ repeatIn(analytic_lines(o), 'l') ]]
-
- [[ l.date if formatLang(l.date, date=True) else '' ]]
-
-
- [[ l.name or '' ]]
-
-
- [[ round(l.unit_amount, 2) or '0.0' ]]
-
-
- [[ l.to_invoice.customer_name ]]
-
-
- [[ round((l.unit_amount and l.to_invoice) and (l.unit_amount - (l.unit_amount * l.to_invoice.factor) / 100 ), 2) or '0.0' ]]
-
-
-
-
-
-
-
diff --git a/__unported__/analytic_hours_block/security/hours_block_security.xml b/__unported__/analytic_hours_block/security/hours_block_security.xml
deleted file mode 100644
index 81c50c4d..00000000
--- a/__unported__/analytic_hours_block/security/hours_block_security.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
- Hours Block multi company rule
-
-
- []
-
-
-
diff --git a/__unported__/analytic_hours_block/security/ir.model.access.csv b/__unported__/analytic_hours_block/security/ir.model.access.csv
deleted file mode 100644
index 57d8a5c9..00000000
--- a/__unported__/analytic_hours_block/security/ir.model.access.csv
+++ /dev/null
@@ -1,3 +0,0 @@
-"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
-"access_hours_block_user","account.hours.block","model_account_hours_block","base.group_user",1,0,0,0
-"access_hours_block_invoice_manager","account.hours.block","model_account_hours_block","account.group_account_invoice",1,1,1,1
diff --git a/__unported__/project_sla/__init__.py b/__unported__/project_sla/__init__.py
deleted file mode 100644
index 9ea8fe78..00000000
--- a/__unported__/project_sla/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# -*- coding: utf-8 -*-
-import project_sla
-import analytic_account
-import project_sla_control
-import project_issue
diff --git a/__unported__/project_sla/__openerp__.py b/__unported__/project_sla/__openerp__.py
deleted file mode 100644
index e0f981a9..00000000
--- a/__unported__/project_sla/__openerp__.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# Copyright (C) 2013 Daniel Reis
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-{
- 'name': 'Service Level Agreements',
- 'summary': 'Define SLAs for your Contracts',
- 'version': '1.0',
- "category": "Project Management",
- 'description': """\
-Contract SLAs
-===============
-
-SLAs are assigned to Contracts, on the Analytic Account form, SLA Definition
-separator. This is also where new SLA Definitions are created.
-
-One Contract can have several SLA Definitions attached, allowing for
-"composite SLAs". For example, a contract could have a Response Time SLA (time
-to start resolution) and a Resolution Time SLA (time to close request).
-
-
-SLA Controlled Documents
-========================
-
-Only Project Issue documents are made SLA controllable.
-However, a framework is made available to easily build extensions to make
-other documents models SLA controlled.
-
-SLA controlled documents have attached information on the list of SLA rules
-they should meet (more than one in the case for composite SLAs) and a summary
-SLA status:
-
- * "watching" the service level (it has SLA requirements to meet)
- * under "warning" (limit dates are close, special attention is needed)
- * "failed" (one on the SLA limits has not been met)
- * "achieved" (all SLA limits have been met)
-
-Transient states, such as "watching" and "warning", are regularly updated by
-a hourly scheduled job, that reevaluates the warning and limit dates against
-the current time and changes the state when find dates that have been exceeded.
-
-To decide what SLA Definitions apply for a specific document, first a lookup
-is made for a ``analytic_account_id`` field. If not found, then it will
-look up for the ``project_id`` and it's corresponding ``analytic_account_id``.
-
-Specifically, the Service Desk module introduces a Analytic Account field for
-Project Issues. This makes it possible for a Service Team (a "Project") to
-have a generic SLA, but at the same time allow for some Contracts to have
-specific SLAs (such as the case for "premium" service conditions).
-
-
-SLA Definitions and Rules
-=========================
-
-New SLA Definitions are created from the Analytic Account form, SLA Definition
-field.
-
-Each definition can have one or more Rules.
-The particular rule to use is decided by conditions, so that you can set
-different service levels based on request attributes, such as Priority or
-Category.
-Each rule condition is evaluated in "sequence" order, and the first onea to met
-is the one to be used.
-In the simplest case, a single rule with no condition is just what is needed.
-
-Each rule sets a number of hours until the "limit date", and the number of
-hours until a "warning date". The former will be used to decide if the SLA
-was achieved, and the later can be used for automatic alarms or escalation
-procedures.
-
-Time will be counted from creation date, until the "Control Date" specified for
-the SLA Definition. That would usually be the "Close" (time until resolution)
-or the "Open" (time until response) dates.
-
-The working calendar set in the related Project definitions will be used (see
-the "Other Info" tab). If none is defined, a builtin "all days, 8-12 13-17"
-default calendar is used.
-
-A timezone and leave calendars will also used, based on either the assigned
-user (document's `user_id`) or on the current user.
-
-
-Setup checklist
-===============
-
-The basic steps to configure SLAs for a Project are:
-
- * Set Project's Working Calendar, at Project definitions, "Other Info" tab
- * Go to the Project's Analytic Account form; create and set SLA Definitions
- * Use the "Reapply SLAs" button on the Analytic Account form
- * See Project Issue's calculated SLAs in the new "Service Levels" tab
-
-
-Credits and Contributors
-========================
-
- * Daniel Reis (https://launchpad.net/~dreis-pt)
- * David Vignoni, author of the icon from the KDE 3.x Nuvola icon theme
-""",
- 'author': 'Daniel Reis',
- 'website': '',
- 'depends': [
- 'project_issue',
- ],
- 'data': [
- 'project_sla_view.xml',
- 'project_sla_control_view.xml',
- 'project_sla_control_data.xml',
- 'analytic_account_view.xml',
- 'project_view.xml',
- 'project_issue_view.xml',
- 'security/ir.model.access.csv',
- ],
- 'demo': ['project_sla_demo.xml'],
- 'test': ['test/project_sla.yml'],
- 'installable': False,
-}
diff --git a/__unported__/project_sla/analytic_account.py b/__unported__/project_sla/analytic_account.py
deleted file mode 100644
index fcfbb13f..00000000
--- a/__unported__/project_sla/analytic_account.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# Copyright (C) 2013 Daniel Reis
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-from openerp.osv import fields, orm
-
-
-class AnalyticAccount(orm.Model):
- """ Add SLA to Analytic Accounts """
- _inherit = 'account.analytic.account'
- _columns = {
- 'sla_ids': fields.many2many(
- 'project.sla', string='Service Level Agreement'),
- }
-
- def _reapply_sla(self, cr, uid, ids, recalc_closed=False, context=None):
- """
- Force SLA recalculation on open documents that already are subject to
- this SLA Definition.
- To use after changing a Contract SLA or it's Definitions.
- The ``recalc_closed`` flag allows to also recompute closed documents.
- """
- ctrl_obj = self.pool.get('project.sla.control')
- proj_obj = self.pool.get('project.project')
- exclude_states = ['cancelled'] + (not recalc_closed and ['done'] or [])
- for contract in self.browse(cr, uid, ids, context=context):
- # for each contract, and for each model under SLA control ...
- for m_name in set([sla.control_model for sla in contract.sla_ids]):
- model = self.pool.get(m_name)
- doc_ids = []
- if 'analytic_account_id' in model._columns:
- doc_ids += model.search(
- cr, uid,
- [('analytic_account_id', '=', contract.id),
- ('state', 'not in', exclude_states)],
- context=context)
- if 'project_id' in model._columns:
- proj_ids = proj_obj.search(
- cr, uid, [('analytic_account_id', '=', contract.id)],
- context=context)
- doc_ids += model.search(
- cr, uid,
- [('project_id', 'in', proj_ids),
- ('state', 'not in', exclude_states)],
- context=context)
- if doc_ids:
- docs = model.browse(cr, uid, doc_ids, context=context)
- ctrl_obj.store_sla_control(cr, uid, docs, context=context)
- return True
-
- def reapply_sla(self, cr, uid, ids, context=None):
- """ Reapply SLAs button action """
- return self._reapply_sla(cr, uid, ids, context=context)
diff --git a/__unported__/project_sla/analytic_account_view.xml b/__unported__/project_sla/analytic_account_view.xml
deleted file mode 100644
index 5b74a43c..00000000
--- a/__unported__/project_sla/analytic_account_view.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
- view_account_analytic_account_form_sla
- account.analytic.account
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/__unported__/project_sla/i18n/project_sla.pot b/__unported__/project_sla/i18n/project_sla.pot
deleted file mode 100644
index 3f727476..00000000
--- a/__unported__/project_sla/i18n/project_sla.pot
+++ /dev/null
@@ -1,296 +0,0 @@
-# Translation of OpenERP Server.
-# This file contains the translation of the following modules:
-# * project_sla
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: OpenERP Server 7.0\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2013-12-19 10:28+0000\n"
-"PO-Revision-Date: 2013-12-19 10:28+0000\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: project_sla
-#: model:project.sla,name:project_sla.sla_response
-msgid "Standard Response Time"
-msgstr ""
-
-#. module: project_sla
-#: help:project.sla,control_field_id:0
-msgid "Date field used to check if the SLA was achieved."
-msgstr ""
-
-#. module: project_sla
-#: model:ir.model,name:project_sla.model_project_issue
-msgid "Project Issue"
-msgstr ""
-
-#. module: project_sla
-#: model:ir.model,name:project_sla.model_project_sla_control
-msgid "SLA Control Registry"
-msgstr ""
-
-#. module: project_sla
-#: view:project.sla:0
-msgid "Reapply SLA on Contracts"
-msgstr ""
-
-#. module: project_sla
-#: view:project.project:0
-msgid "Administration"
-msgstr ""
-
-#. module: project_sla
-#: view:project.issue:0
-msgid "Priority"
-msgstr ""
-
-#. module: project_sla
-#: selection:project.issue,sla_state:0
-#: selection:project.sla.control,sla_state:0
-#: selection:project.sla.controlled,sla_state:0
-msgid "Failed"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla.control,sla_warn_date:0
-msgid "Warning Date"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla.line,warn_qty:0
-msgid "Hours to Warn"
-msgstr ""
-
-#. module: project_sla
-#: view:project.sla.control:0
-msgid "Service Level"
-msgstr ""
-
-#. module: project_sla
-#: selection:project.issue,sla_state:0
-#: selection:project.sla.control,sla_state:0
-#: selection:project.sla.controlled,sla_state:0
-msgid "Watching"
-msgstr ""
-
-#. module: project_sla
-#: view:project.sla:0
-#: field:project.sla,analytic_ids:0
-msgid "Contracts"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla,name:0
-#: field:project.sla.line,name:0
-msgid "Title"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla,active:0
-msgid "Active"
-msgstr ""
-
-#. module: project_sla
-#: field:project.issue,sla_control_ids:0
-#: field:project.sla.controlled,sla_control_ids:0
-msgid "SLA Control"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla.control,sla_achieved:0
-msgid "Achieved?"
-msgstr ""
-
-#. module: project_sla
-#: view:project.issue:0
-#: field:project.issue,sla_state:0
-#: field:project.sla.control,sla_state:0
-#: field:project.sla.controlled,sla_state:0
-msgid "SLA Status"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla.line,condition:0
-msgid "Condition"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla,control_model:0
-msgid "For documents"
-msgstr ""
-
-#. module: project_sla
-#: view:project.sla:0
-#: field:project.sla.line,sla_id:0
-msgid "SLA Definition"
-msgstr ""
-
-#. module: project_sla
-#: model:project.sla.line,name:project_sla.sla_response_rule2
-msgid "Response in two business days"
-msgstr ""
-
-#. module: project_sla
-#: selection:project.issue,sla_state:0
-#: selection:project.sla.control,sla_state:0
-#: selection:project.sla.controlled,sla_state:0
-msgid "Will Fail"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla.control,sla_line_id:0
-msgid "Service Agreement"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla.control,doc_id:0
-msgid "Document ID"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla.control,locked:0
-msgid "Recalculation disabled"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla.control,sla_limit_date:0
-msgid "Limit Date"
-msgstr ""
-
-#. module: project_sla
-#: help:project.sla.line,condition:0
-msgid "Apply only if this expression is evaluated to True. The document fields can be accessed using either o, obj or object. Example: obj.priority <= '2'"
-msgstr ""
-
-#. module: project_sla
-#: model:project.sla.line,name:project_sla.sla_resolution_rule1
-msgid "Resolution in two business days"
-msgstr ""
-
-#. module: project_sla
-#: view:account.analytic.account:0
-msgid "Reapply"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla.line,limit_qty:0
-msgid "Hours to Limit"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla,sla_line_ids:0
-#: view:project.sla.line:0
-msgid "Definitions"
-msgstr ""
-
-#. module: project_sla
-#: model:project.sla.line,name:project_sla.sla_resolution_rule2
-msgid "Resolution in three business days"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla.control,sla_close_date:0
-msgid "Close Date"
-msgstr ""
-
-#. module: project_sla
-#: model:ir.model,name:project_sla.model_project_sla
-msgid "project.sla"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla,control_field_id:0
-msgid "Control Date"
-msgstr ""
-
-#. module: project_sla
-#: model:project.sla.line,name:project_sla.sla_response_rule1
-msgid "Response in one business day"
-msgstr ""
-
-#. module: project_sla
-#: selection:project.issue,sla_state:0
-#: selection:project.sla.control,sla_state:0
-#: selection:project.sla.controlled,sla_state:0
-msgid "Achieved"
-msgstr ""
-
-#. module: project_sla
-#: view:account.analytic.account:0
-#: field:account.analytic.account,sla_ids:0
-msgid "Service Level Agreement"
-msgstr ""
-
-#. module: project_sla
-#: model:project.sla,name:project_sla.sla_resolution
-msgid "Standard Resolution Time"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla.line,sequence:0
-msgid "Sequence"
-msgstr ""
-
-#. module: project_sla
-#: view:project.issue:0
-msgid "Service Levels"
-msgstr ""
-
-#. module: project_sla
-#: model:ir.model,name:project_sla.model_account_analytic_account
-msgid "Analytic Account"
-msgstr ""
-
-#. module: project_sla
-#: view:project.sla:0
-msgid "Rules"
-msgstr ""
-
-#. module: project_sla
-#: help:project.sla.control,locked:0
-msgid "Safeguard manual changes from future automatic recomputations."
-msgstr ""
-
-#. module: project_sla
-#: selection:project.issue,sla_state:0
-#: selection:project.sla.control,sla_state:0
-#: selection:project.sla.controlled,sla_state:0
-msgid "Warning"
-msgstr ""
-
-#. module: project_sla
-#: view:project.issue:0
-msgid "Extra Info"
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla.control,doc_model:0
-msgid "Document Model"
-msgstr ""
-
-#. module: project_sla
-#: model:ir.model,name:project_sla.model_project_sla_line
-msgid "project.sla.line"
-msgstr ""
-
-#. module: project_sla
-#: view:account.analytic.account:0
-msgid "Reapply the SLAs to all Contract's documents."
-msgstr ""
-
-#. module: project_sla
-#: field:project.sla.control,sla_start_date:0
-msgid "Start Date"
-msgstr ""
-
-#. module: project_sla
-#: model:ir.model,name:project_sla.model_project_sla_controlled
-msgid "SLA Controlled Document"
-msgstr ""
-
diff --git a/__unported__/project_sla/images/10_sla_contract.png b/__unported__/project_sla/images/10_sla_contract.png
deleted file mode 100644
index e46f8b55..00000000
Binary files a/__unported__/project_sla/images/10_sla_contract.png and /dev/null differ
diff --git a/__unported__/project_sla/images/20_sla_definition.png b/__unported__/project_sla/images/20_sla_definition.png
deleted file mode 100644
index 7f05f2a8..00000000
Binary files a/__unported__/project_sla/images/20_sla_definition.png and /dev/null differ
diff --git a/__unported__/project_sla/images/30_sla_controlled.png b/__unported__/project_sla/images/30_sla_controlled.png
deleted file mode 100644
index 6ebf5dd3..00000000
Binary files a/__unported__/project_sla/images/30_sla_controlled.png and /dev/null differ
diff --git a/__unported__/project_sla/m2m.py b/__unported__/project_sla/m2m.py
deleted file mode 100644
index 39fe1e2c..00000000
--- a/__unported__/project_sla/m2m.py
+++ /dev/null
@@ -1,75 +0,0 @@
-"""
-Wrapper for OpenERP's cryptic write conventions for x2many fields.
-
-Example usage:
-
- import m2m
- browse_rec.write({'many_ids: m2m.clear())
- browse_rec.write({'many_ids: m2m.link(99))
- browse_rec.write({'many_ids: m2m.add({'name': 'Monty'}))
- browse_rec.write({'many_ids: m2m.replace([98, 99]))
-
-Since returned values are lists, the can be joined using the plus operator:
-
- browse_rec.write({'many_ids: m2m.clear() + m2m.link(99))
-
-(Source: https://github.com/dreispt/openerp-write2many)
-"""
-
-
-def create(values):
- """ Create a referenced record """
- assert isinstance(values, dict)
- return [(0, 0, values)]
-
-
-def add(values):
- """ Intuitive alias for create() """
- return create(values)
-
-
-def write(id, values):
- """ Write on referenced record """
- assert isinstance(id, int)
- assert isinstance(values, dict)
- return [(1, id, values)]
-
-
-def remove(id):
- """ Unlink and delete referenced record """
- assert isinstance(id, int)
- return [(2, id)]
-
-
-def unlink(id):
- """ Unlink but do not delete the referenced record """
- assert isinstance(id, int)
- return [(3, id)]
-
-
-def link(id):
- """ Link but do not delete the referenced record """
- assert isinstance(id, int)
- return [(4, id)]
-
-
-def clear():
- """ Unlink all referenced records (doesn't delete them) """
- return [(5, 0)]
-
-
-def replace(ids):
- """ Unlink all current records and replace them with a new list """
- assert isinstance(ids, list)
- return [(6, 0, ids)]
-
-
-if __name__ == "__main__":
- # Tests:
- assert create({'name': 'Monty'}) == [(0, 0, {'name': 'Monty'})]
- assert write(99, {'name': 'Monty'}) == [(1, 99, {'name': 'Monty'})]
- assert remove(99) == [(2, 99)]
- assert unlink(99) == [(3, 99)]
- assert clear() == [(5, 0)]
- assert replace([97, 98, 99]) == [(6, 0, [97, 98, 99])]
- print("Done!")
diff --git a/__unported__/project_sla/project_issue.py b/__unported__/project_sla/project_issue.py
deleted file mode 100644
index 9800f47a..00000000
--- a/__unported__/project_sla/project_issue.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# Copyright (C) 2013 Daniel Reis
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-from openerp.osv import orm
-
-
-class ProjectIssue(orm.Model):
- """
- Extend Project Issues to be SLA Controlled
- """
- _name = 'project.issue'
- _inherit = ['project.issue', 'project.sla.controlled']
diff --git a/__unported__/project_sla/project_issue_view.xml b/__unported__/project_sla/project_issue_view.xml
deleted file mode 100644
index eba74066..00000000
--- a/__unported__/project_sla/project_issue_view.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
-
-
-
- project_issue_form_view_sla
- project.issue
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- project_issue_tree_view_sla
- project.issue
-
-
-
-
-
-
-
-
-
-
-
-
-
- view_project_issue_filter_sdesk
- project.issue
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/__unported__/project_sla/project_sla.py b/__unported__/project_sla/project_sla.py
deleted file mode 100644
index 78978bb3..00000000
--- a/__unported__/project_sla/project_sla.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# Copyright (C) 2013 Daniel Reis
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-from openerp.osv import fields, orm
-
-
-class SLADefinition(orm.Model):
- """
- SLA Definition
- """
- _name = 'project.sla'
- _description = 'SLA Definition'
- _columns = {
- 'name': fields.char('Title', size=64, required=True, translate=True),
- 'active': fields.boolean('Active'),
- 'control_model': fields.char('For documents', size=128, required=True),
- 'control_field_id': fields.many2one(
- 'ir.model.fields', 'Control Date', required=True,
- domain="[('model_id.model', '=', control_model),"
- " ('ttype', 'in', ['date', 'datetime'])]",
- help="Date field used to check if the SLA was achieved."),
- 'sla_line_ids': fields.one2many(
- 'project.sla.line', 'sla_id', 'Definitions'),
- 'analytic_ids': fields.many2many(
- 'account.analytic.account', string='Contracts'),
- }
- _defaults = {
- 'active': True,
- }
-
- def _reapply_slas(self, cr, uid, ids, recalc_closed=False, context=None):
- """
- Force SLA recalculation on all _open_ Contracts for the selected SLAs.
- To use upon SLA Definition modifications.
- """
- contract_obj = self.pool.get('account.analytic.account')
- for sla in self.browse(cr, uid, ids, context=context):
- contr_ids = [x.id for x in sla.analytic_ids if x.state == 'open']
- contract_obj._reapply_sla(
- cr, uid, contr_ids, recalc_closed=recalc_closed,
- context=context)
- return True
-
- def reapply_slas(self, cr, uid, ids, context=None):
- """ Reapply SLAs button action """
- return self._reapply_slas(cr, uid, ids, context=context)
-
-
-class SLARules(orm.Model):
- """
- SLA Definition Rule Lines
- """
- _name = 'project.sla.line'
- _definition = 'SLA Definition Rule Lines'
- _order = 'sla_id,sequence'
- _columns = {
- 'sla_id': fields.many2one('project.sla', 'SLA Definition'),
- 'sequence': fields.integer('Sequence'),
- 'name': fields.char('Title', size=64, required=True, translate=True),
- 'condition': fields.char(
- 'Condition', size=256, help="Apply only if this expression is "
- "evaluated to True. The document fields can be accessed using "
- "either o, obj or object. Example: obj.priority <= '2'"),
- 'limit_qty': fields.integer('Hours to Limit'),
- 'warn_qty': fields.integer('Hours to Warn'),
- }
- _defaults = {
- 'sequence': 10,
- }
diff --git a/__unported__/project_sla/project_sla_control.py b/__unported__/project_sla/project_sla_control.py
deleted file mode 100644
index d807a36b..00000000
--- a/__unported__/project_sla/project_sla_control.py
+++ /dev/null
@@ -1,322 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# Copyright (C) 2013 Daniel Reis
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-from openerp.osv import fields, orm
-from openerp.tools.safe_eval import safe_eval
-from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT as DT_FMT
-from openerp import SUPERUSER_ID
-from datetime import timedelta
-from datetime import datetime as dt
-import m2m
-
-import logging
-_logger = logging.getLogger(__name__)
-
-
-SLA_STATES = [('5', 'Failed'), ('4', 'Will Fail'), ('3', 'Warning'),
- ('2', 'Watching'), ('1', 'Achieved')]
-
-
-def safe_getattr(obj, dotattr, default=False):
- """
- Follow an object attribute dot-notation chain to find the leaf value.
- If any attribute doesn't exist or has no value, just return False.
- Checks hasattr ahead, to avoid ORM Browse log warnings.
- """
- attrs = dotattr.split('.')
- while attrs:
- attr = attrs.pop(0)
- if attr in obj._model._columns:
- try:
- obj = getattr(obj, attr)
- except AttributeError:
- return default
- if not obj:
- return default
- else:
- return default
- return obj
-
-
-class SLAControl(orm.Model):
- """
- SLA Control Registry
- Each controlled document (Issue, Claim, ...) will have a record here.
- This model concentrates all the logic for Service Level calculation.
- """
- _name = 'project.sla.control'
- _description = 'SLA Control Registry'
-
- _columns = {
- 'doc_id': fields.integer('Document ID', readonly=True),
- 'doc_model': fields.char('Document Model', size=128, readonly=True),
- 'sla_line_id': fields.many2one(
- 'project.sla.line', 'Service Agreement'),
- 'sla_warn_date': fields.datetime('Warning Date'),
- 'sla_limit_date': fields.datetime('Limit Date'),
- 'sla_start_date': fields.datetime('Start Date'),
- 'sla_close_date': fields.datetime('Close Date'),
- 'sla_achieved': fields.integer('Achieved?'),
- 'sla_state': fields.selection(SLA_STATES, string="SLA Status"),
- 'locked': fields.boolean(
- 'Recalculation disabled',
- help="Safeguard manual changes from future automatic "
- "recomputations."),
- # Future: perfect SLA manual handling
- }
-
- def write(self, cr, uid, ids, vals, context=None):
- """
- Update the related Document's SLA State when any of the SLA Control
- lines changes state
- """
- res = super(SLAControl, self).write(
- cr, uid, ids, vals, context=context)
- new_state = vals.get('sla_state')
- if new_state:
- # just update sla_state without recomputing the whole thing
- context = context or {}
- context['__sla_stored__'] = 1
- for sla in self.browse(cr, uid, ids, context=context):
- doc = self.pool.get(sla.doc_model).browse(
- cr, uid, sla.doc_id, context=context)
- if doc.sla_state < new_state:
- doc.write({'sla_state': new_state})
- return res
-
- def update_sla_states(self, cr, uid, context=None):
- """
- Updates SLA States, given the current datetime:
- Only works on "open" sla states (watching, warning and will fail):
- - exceeded limit date are set to "will fail"
- - exceeded warning dates are set to "warning"
- To be used by a scheduled job.
- """
- now = dt.now().strftime(DT_FMT)
- # SLAs to mark as "will fail"
- control_ids = self.search(
- cr, uid,
- [('sla_state', 'in', ['2', '3']), ('sla_limit_date', '<', now)],
- context=context)
- self.write(cr, uid, control_ids, {'sla_state': '4'}, context=context)
- # SLAs to mark as "warning"
- control_ids = self.search(
- cr, uid,
- [('sla_state', 'in', ['2']), ('sla_warn_date', '<', now)],
- context=context)
- self.write(cr, uid, control_ids, {'sla_state': '3'}, context=context)
- return True
-
- def _compute_sla_date(self, cr, uid, working_hours, res_uid,
- start_date, hours, context=None):
- """
- Return a limit datetime by adding hours to a start_date, honoring
- a working_time calendar and a resource's (res_uid) timezone and
- availability (leaves)
-
- Currently implemented using a binary search using
- _interval_hours_get() from resource.calendar. This is
- resource.calendar agnostic, but could be more efficient if
- implemented based on it's logic.
-
- Known issue: the end date can be a non-working time; it would be
- best for it to be the latest working time possible. Example:
- if working time is 08:00 - 16:00 and start_date is 19:00, the +8h
- end date will be 19:00 of the next day, and it should rather be
- 16:00 of the next day.
- """
- assert isinstance(start_date, dt)
- assert isinstance(hours, int) and hours >= 0
-
- cal_obj = self.pool.get('resource.calendar')
- target, step = hours * 3600, 16 * 3600
- lo, hi = start_date, start_date
- while target > 0 and step > 60:
- hi = lo + timedelta(seconds=step)
- check = int(3600 * cal_obj._interval_hours_get(
- cr, uid, working_hours, lo, hi,
- timezone_from_uid=res_uid, exclude_leaves=False,
- context=context))
- if check <= target:
- target -= check
- lo = hi
- else:
- step = int(step / 4.0)
- return hi
-
- def _get_computed_slas(self, cr, uid, doc, context=None):
- """
- Returns a dict with the computed data for SLAs, given a browse record
- for the target document.
-
- * The SLA used is either from a related analytic_account_id or
- project_id, whatever is found first.
- * The work calendar is taken from the Project's definitions ("Other
- Info" tab -> Working Time).
- * The timezone used for the working time calculations are from the
- document's responsible User (user_id) or from the current User (uid).
-
- For the SLA Achieved calculation:
-
- * Creation date is used to start counting time
- * Control date, used to calculate SLA achievement, is defined in the
- SLA Definition rules.
- """
- def datetime2str(dt_value, fmt): # tolerant datetime to string
- return dt_value and dt.strftime(dt_value, fmt) or None
-
- res = []
- sla_ids = (safe_getattr(doc, 'analytic_account_id.sla_ids') or
- safe_getattr(doc, 'project_id.analytic_account_id.sla_ids'))
- if not sla_ids:
- return res
-
- for sla in sla_ids:
- if sla.control_model != doc._table_name:
- continue # SLA not for this model; skip
-
- for l in sla.sla_line_ids:
- eval_context = {'o': doc, 'obj': doc, 'object': doc}
- if not l.condition or safe_eval(l.condition, eval_context):
- start_date = dt.strptime(doc.create_date, DT_FMT)
- res_uid = doc.user_id.id or uid
- cal = safe_getattr(
- doc, 'project_id.resource_calendar_id.id')
- warn_date = self._compute_sla_date(
- cr, uid, cal, res_uid, start_date, l.warn_qty,
- context=context)
- lim_date = self._compute_sla_date(
- cr, uid, cal, res_uid, warn_date,
- l.limit_qty - l.warn_qty,
- context=context)
- # evaluate sla state
- control_val = getattr(doc, sla.control_field_id.name)
- if control_val:
- control_date = dt.strptime(control_val, DT_FMT)
- if control_date > lim_date:
- sla_val, sla_state = 0, '5' # failed
- else:
- sla_val, sla_state = 1, '1' # achieved
- else:
- control_date = None
- now = dt.now()
- if now > lim_date:
- sla_val, sla_state = 0, '4' # will fail
- elif now > warn_date:
- sla_val, sla_state = 0, '3' # warning
- else:
- sla_val, sla_state = 0, '2' # watching
-
- res.append(
- {'sla_line_id': l.id,
- 'sla_achieved': sla_val,
- 'sla_state': sla_state,
- 'sla_warn_date': datetime2str(warn_date, DT_FMT),
- 'sla_limit_date': datetime2str(lim_date, DT_FMT),
- 'sla_start_date': datetime2str(start_date, DT_FMT),
- 'sla_close_date': datetime2str(control_date, DT_FMT),
- 'doc_id': doc.id,
- 'doc_model': sla.control_model})
- break
-
- if sla_ids and not res:
- _logger.warning("No valid SLA rule found for %d, SLA Ids %s"
- % (doc.id, repr([x.id for x in sla_ids])))
- return res
-
- def store_sla_control(self, cr, uid, docs, context=None):
- """
- Used by controlled documents to ask for SLA calculation and storage.
- ``docs`` is a Browse object
- """
- # context flag to avoid infinite loops on further writes
- context = context or {}
- if '__sla_stored__' in context:
- return False
- else:
- context['__sla_stored__'] = 1
-
- res = []
- for ix, doc in enumerate(docs):
- if ix and ix % 50 == 0:
- _logger.info('...%d SLAs recomputed for %s' % (ix, doc._name))
- control = {x.sla_line_id.id: x
- for x in doc.sla_control_ids}
- sla_recs = self._get_computed_slas(cr, uid, doc, context=context)
- # calc sla control lines
- if sla_recs:
- slas = []
- for sla_rec in sla_recs:
- sla_line_id = sla_rec.get('sla_line_id')
- if sla_line_id in control:
- control_rec = control.get(sla_line_id)
- if not control_rec.locked:
- slas += m2m.write(control_rec.id, sla_rec)
- else:
- slas += m2m.add(sla_rec)
- else:
- slas = m2m.clear()
- # calc sla control summary
- vals = {'sla_state': None, 'sla_control_ids': slas}
- if sla_recs and doc.sla_control_ids:
- vals['sla_state'] = max(
- x.sla_state for x in doc.sla_control_ids)
- # store sla
- doc._model.write( # regular users can't write on SLA Control
- cr, SUPERUSER_ID, [doc.id], vals, context=context)
- return res
-
-
-class SLAControlled(orm.AbstractModel):
- """
- SLA Controlled documents: AbstractModel to apply SLA control on Models
- """
- _name = 'project.sla.controlled'
- _description = 'SLA Controlled Document'
- _columns = {
- 'sla_control_ids': fields.many2many(
- 'project.sla.control', string="SLA Control", ondelete='cascade'),
- 'sla_state': fields.selection(
- SLA_STATES, string="SLA Status", readonly=True),
- }
-
- def create(self, cr, uid, vals, context=None):
- res = super(SLAControlled, self).create(cr, uid, vals, context=context)
- docs = self.browse(cr, uid, [res], context=context)
- self.pool.get('project.sla.control').store_sla_control(
- cr, uid, docs, context=context)
- return res
-
- def write(self, cr, uid, ids, vals, context=None):
- res = super(SLAControlled, self).write(
- cr, uid, ids, vals, context=context)
- docs = [x for x in self.browse(cr, uid, ids, context=context)
- if (x.state != 'cancelled') and
- (x.state != 'done' or x.sla_state not in ['1', '5'])]
- self.pool.get('project.sla.control').store_sla_control(
- cr, uid, docs, context=context)
- return res
-
- def unlink(self, cr, uid, ids, context=None):
- # Unlink and delete all related Control records
- for doc in self.browse(cr, uid, ids, context=context):
- vals = [m2m.remove(x.id)[0] for x in doc.sla_control_ids]
- doc.write({'sla_control_ids': vals})
- return super(SLAControlled, self).unlink(cr, uid, ids, context=context)
diff --git a/__unported__/project_sla/project_sla_control_data.xml b/__unported__/project_sla/project_sla_control_data.xml
deleted file mode 100644
index edff4832..00000000
--- a/__unported__/project_sla/project_sla_control_data.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
- Update SLA States
-
- 1
- hours
- -1
-
- project.sla.control
- update_sla_states
- ()
-
-
-
-
diff --git a/__unported__/project_sla/project_sla_control_view.xml b/__unported__/project_sla/project_sla_control_view.xml
deleted file mode 100644
index cca647f5..00000000
--- a/__unported__/project_sla/project_sla_control_view.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
- view_sla_control_tree
- project.sla.control
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/__unported__/project_sla/project_sla_demo.xml b/__unported__/project_sla/project_sla_demo.xml
deleted file mode 100644
index 331c53d2..00000000
--- a/__unported__/project_sla/project_sla_demo.xml
+++ /dev/null
@@ -1,138 +0,0 @@
-
-
-
-
-
-
- Working Days 09-13 14-18
-
-
- 0
- Monday Morning
- 9
- 13
-
-
-
- 0
- Monday Afternoon
- 14
- 18
-
-
-
- 1
- Tuesday Morning
- 9
- 13
-
-
-
- 1
- Tuesday Afternoon
- 14
- 18
-
-
-
- 2
- Wednesday Morning
- 9
- 13
-
-
-
- 2
- Wednesday Afternoon
- 14
- 18
-
-
-
- 3
- Thursday Morning
- 9
- 13
-
-
-
- 3
- Thursday Afternoon
- 14
- 18
-
-
-
- 4
- Friday Morning
- 9
- 13
-
-
-
- 4
- Friday Afternoon
- 14
- 18
-
-
-
-
-
-
-
-
-
-
- Standard Resolution Time
- project.issue
-
-
-
-
- 10
- Resolution in two business days
- obj.priority <= '2'
- 16
- 8
-
-
-
- 20
- Resolution in three business days
-
- 24
- 16
-
-
-
- Standard Response Time
- project.issue
-
-
-
-
- 10
- Response in one business day
- obj.priority <= '2'
- 8
- 4
-
-
-
- 20
- Response in two business days
-
- 16
- 8
-
-
-
-
-
-
-
-
-
diff --git a/__unported__/project_sla/project_sla_view.xml b/__unported__/project_sla/project_sla_view.xml
deleted file mode 100644
index 0381ff4f..00000000
--- a/__unported__/project_sla/project_sla_view.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
- view_sla_lines_tree
- project.sla.line
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- view_sla_form
- project.sla
-
-
-
-
-
-
-
-
-
diff --git a/__unported__/project_sla/project_view.xml b/__unported__/project_sla/project_view.xml
deleted file mode 100644
index bc40c9d4..00000000
--- a/__unported__/project_sla/project_view.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
- edit_project_sla
- project.project
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/__unported__/project_sla/security/ir.model.access.csv b/__unported__/project_sla/security/ir.model.access.csv
deleted file mode 100644
index 55d41a65..00000000
--- a/__unported__/project_sla/security/ir.model.access.csv
+++ /dev/null
@@ -1,8 +0,0 @@
-id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-access_sla_manager,access_sla_manager,model_project_sla,project.group_project_manager,1,1,1,1
-access_sla_user,access_sla_user,model_project_sla,base.group_user,1,0,0,0
-access_sla_lines_manager,access_sla_lines_manager,model_project_sla_line,project.group_project_manager,1,1,1,1
-access_sla_lines_user,access_sla_lines_user,model_project_sla_line,base.group_user,1,0,0,0
-access_sla_control_manager,access_sla_control_manager,model_project_sla_control,project.group_project_manager,1,1,0,0
-access_sla_control_user,access_sla_control_user,model_project_sla_control,base.group_user,1,0,0,0
-access_sla_controlled_manager,access_sla_controlled_manager,model_project_sla_controlled,project.group_project_manager,1,1,1,1
diff --git a/__unported__/project_sla/static/src/img/icon.png b/__unported__/project_sla/static/src/img/icon.png
deleted file mode 100644
index 30df47a2..00000000
Binary files a/__unported__/project_sla/static/src/img/icon.png and /dev/null differ
diff --git a/__unported__/project_sla/test/project_sla.yml b/__unported__/project_sla/test/project_sla.yml
deleted file mode 100644
index 57231535..00000000
--- a/__unported__/project_sla/test/project_sla.yml
+++ /dev/null
@@ -1,66 +0,0 @@
--
- Cleanup previous test run
--
- !python {model: project.issue}: |
- res = self.search(cr, uid, [('name', '=', 'My monitor is flickering')])
- self.unlink(cr, uid, res)
--
- Create a new Issue
--
- !record {model: project.issue, id: issue1, view: False}:
- name: "My monitor is flickering"
- project_id: project.project_project_1
- priority: "3"
- user_id: base.user_root
- partner_id: base.res_partner_2
- email_from: agr@agrolait.com
- categ_ids:
- - project_issue.project_issue_category_01
--
- Close the Issue
--
- !python {model: project.issue}: |
- self.case_close(cr, uid, [ref("issue1")])
--
- Force the Issue's Create Date and Close Date
- Created friday before opening hour, closed on next monday near closing hour
--
- !python {model: project.issue}: |
- import time
- self.write(cr, uid, [ref("issue1"),], {
- 'create_date': time.strftime('2013-11-22 06:15:00'),
- 'date_closed': time.strftime('2013-11-25 16:45:00'),
- })
--
- There should be Service Level info generated on the Issue
--
- !assert {model: project.issue, id: issue1, string: Issue should have calculated service levels}:
- - len(sla_control_ids) == 2
--
- Assign an additional "Response SLA" to the Contract
--
- !python {model: account.analytic.account}: |
- self.write(cr, uid, [ref('project.project_project_1_account_analytic_account')],
- {'sla_ids': [(4, ref('sla_response'))]})
--
- Button to Reapply the SLA Definition
--
- !python {model: project.sla}: |
- self._reapply_slas(cr, uid, [ref('sla_resolution')], recalc_closed=True)
--
- There should be two Service Level lines generated on the Issue
--
- !assert {model: project.issue, id: issue1, string: Issue should have two calculated service levels}:
- - len(sla_control_ids) == 2
--
- The Issue's Resolution SLA should be "3 business days"
--
- !python {model: project.issue}: |
- issue = self.browse(cr, uid, ref('issue1'))
- for x in issue.sla_control_ids:
- print x.sla_line_id.name
- if x.sla_line_id.id == ref("sla_resolution_rule2"):
- assert x.sla_achieved == 1, "Issue resolution SLA should be achieved"
- break
- else:
- assert False, 'Issue Resolution SLA should be "3 business days"'