Skip to content
This repository was archived by the owner on Jan 24, 2018. It is now read-only.

Commit bca9547

Browse files
committed
Create metric and billing interface outline
1 parent 5b44438 commit bca9547

14 files changed

+345
-0
lines changed

clouder_metric/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4+
5+
from . import models

clouder_metric/__openerp__.py

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4+
{
5+
"name": "Clouder - Metrics",
6+
"summary": "Provides Usage Metric Interface for Clouder",
7+
"version": "9.0.1.0.0",
8+
"category": "Clouder",
9+
"website": "https://github.com/clouder-community/clouder",
10+
"author": "LasLabs",
11+
"license": "AGPL-3",
12+
"application": False,
13+
"installable": True,
14+
"depends": [
15+
"clouder",
16+
"contract_variable_quantity",
17+
"sale",
18+
],
19+
}

clouder_metric/models/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4+
5+
from . import clouder_metric_interface
6+
from . import clouder_metric_type
7+
from . import clouder_metric_value
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4+
5+
from odoo import api, fields, models
6+
7+
8+
class ClouderMetricInterface(models.Model):
9+
""" It provides a common interface for Clouder Usage metrics """
10+
11+
_name = 'clouder.metric.interface'
12+
_inherits = {'clouder.metric.type': 'type_id'}
13+
14+
service_id = fields.Many2one(
15+
string='Service',
16+
comodel_name='clouder.service',
17+
required=True,
18+
)
19+
type_id = fields.Many2one(
20+
string='Metric Trype',
21+
comodel_name='clouder.metric.type',
22+
required=True,
23+
ondelete='restrict',
24+
)
25+
metric_ids = fields.One2many(
26+
string='Metric Values',
27+
comodel_name='clouder.metric.value',
28+
inverse_name='interface_id',
29+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4+
5+
from odoo import api, fields, models
6+
7+
8+
class ClouderMetricType(models.Model):
9+
""" It provides context for usage metric types """
10+
11+
_name = 'clouder.metric.type'
12+
13+
name = fields.Char()
14+
code = fields.Char()
15+
uom_id = fields.Many2one(
16+
string='Unit of Measure',
17+
comodel_name='product.uom',
18+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4+
5+
from odoo import api, fields, models
6+
7+
8+
class ClouderMetricValue(models.Model):
9+
""" It provides a record of metric values used in billin """
10+
11+
_name = 'clouder.metric.value'
12+
13+
interface_id = fields.Many2one(
14+
string='Interface',
15+
comodel_name='clouder.metric.interface',
16+
required=True,
17+
)
18+
value = fields.Float(
19+
required=True,
20+
)
21+
uom_id = fields.Many2one(
22+
string='Unit of Measure',
23+
comodel_name='product.uom',
24+
related='interface_id.uom_id',
25+
)

oca_dependencies.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
connector
2+
# LasLabs repo pending OCA/contract#44 merge
3+
contract https://github.com/laslabs/contract release/10.0/contract_variable_quantity

sale_clouder/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4+
5+
from . import models

sale_clouder/__openerp__.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4+
{
5+
"name": "Sale - Clouder",
6+
"summary": "Provides the ability to sell Clouder instances.",
7+
"version": "9.0.1.0.0",
8+
"category": "Clouder",
9+
"website": "https://github.com/clouder-community/clouder",
10+
"author": "LasLabs",
11+
"license": "AGPL-3",
12+
"application": False,
13+
"installable": True,
14+
"depends": [
15+
"clouder",
16+
"contract",
17+
"sale",
18+
],
19+
"data": [
20+
"data/contract_line_qty_formula.xml",
21+
],
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!-- Copyright 2016 LasLabs Inc.
3+
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
4+
5+
<odoo>
6+
7+
<record id="contract_line_qty_formula_clouder"
8+
model="contract.line.qty.formula"
9+
>
10+
<field name="name">Clouder Billing</field>
11+
<field name="code">result = env['clouder.contract'].get_invoice_line_quantity(contract, line, invoice)</field>
12+
</record>
13+
14+
</odoo>

sale_clouder/models/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4+
5+
from . import clouder_contract
6+
from . import clouder_contract_line
7+
from . import product_template
+145
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4+
5+
import logging
6+
7+
from odoo import _, api, fields, models
8+
9+
10+
_logger = logging.getLogger(__name__)
11+
12+
13+
class ClouderContract(models.Model):
14+
""" It provides formulas specific to billing Clouder contracts. """
15+
16+
_name = 'clouder.contract'
17+
_inherits = {'account.analytic.account': 'ref_contract_id'}
18+
19+
ref_contract_id = fields.Many2one(
20+
string='Related Contract',
21+
comodel_name='account.analytic.account',
22+
index=True,
23+
require=True,
24+
ondelete='restrict',
25+
)
26+
27+
_sql_constraints = [
28+
('ref_contract_id_unique', 'UNIQUE(ref_contract_id)',
29+
'Cannot assign two ClouderContracts to the same Analytic Account.'),
30+
]
31+
32+
@property
33+
@api.model
34+
def invoice_policy_map(self):
35+
""" It returns a mapping of invoice policies to processing methods.
36+
37+
Returns:
38+
(dict) Mapping keyed by invoice policy type, pointing to the
39+
method that should determine the quantity to use for
40+
invoicing.
41+
The method will receive the recurring contract line and the
42+
invoice as arguments.
43+
See one of the methods that are already mapped for examples.
44+
"""
45+
return {
46+
'threshold': self._get_quantity_threshold,
47+
'usage': self._get_quantity_usage,
48+
'cost': self._get_quantity_usage,
49+
'order': self._get_quantity_flat,
50+
'delivery': self._get_quantity_usage,
51+
}
52+
53+
@api.model
54+
def get_invoice_line_quantity(self, account, account_line, invoice):
55+
""" It returns the Qty to be used for contract billing formula.
56+
57+
This method should be called from ``contract.line.qty.formula`` by
58+
adding the following into the ``code`` field:
59+
60+
.. code-block:: python
61+
62+
result = env['clouder.contract'].get_invoice_line_quantity(
63+
contract, line, invoice,
64+
)
65+
66+
Args:
67+
account: (account.analytic.account) Contract that recurring
68+
invoice line belongs to. This is called
69+
account_line: (account.analytic.invoice.line) Recurring invoice
70+
line being referenced.
71+
invoice: (account.invoice) Invoice that is being created.
72+
Returns:
73+
(int) Quantity to use on invoice line in the UOM defined on the
74+
``contract_line``.
75+
"""
76+
contract = self._get_contract_by_account(account, create=True)
77+
invoice_policy = account_line.product_id.invoice_policy
78+
invoice_policy_map = self.invoice_policy_map
79+
try:
80+
invoice
81+
method = invoice_policy_map[invoice_policy]
82+
except KeyError:
83+
_logger.info(_(
84+
'No calculation method found for invoice policy "%s". '
85+
'Defaulting to Flat Rate instead.'
86+
) % (
87+
invoice_policy,
88+
))
89+
method = invoice_policy_map['order']
90+
return method(account_line, invoice)
91+
92+
@api.model
93+
def _create_default_vals(self, account):
94+
""" It returns default values to create and link new ClouderContracts.
95+
96+
Args:
97+
account: (account.analytic.account) Account that ClouderContract
98+
will reference.
99+
Returns:
100+
(dict) Values fed to ``create`` in ``_get_contract_by_account``.
101+
"""
102+
return {
103+
'ref_contract_id': account.id,
104+
}
105+
106+
@api.model
107+
def _get_contract_by_account(self, account, create=False):
108+
""" It returns the ClouderContract or possibly creates a new one.
109+
110+
Args:
111+
account: (account.analytic.account) Contract to search by.
112+
create: (bool) True will create a new ClouderContract if one does
113+
not already exist.
114+
Returns:
115+
(clouder.contract) Clouder contract associated with ``account``.
116+
"""
117+
contract = self.search([('ref_contract_id', '=', account.id)])
118+
if create and not contract:
119+
contract = self.create(self._create_default_vals())
120+
return contract
121+
122+
@api.multi
123+
def _get_quantity_flat(self, account_line, invoice):
124+
""" It returns the base quantity with no calculations """
125+
return account_line.quantity
126+
127+
@api.multi
128+
def _get_quantity_threshold(self, account_line, invoice):
129+
""" It functions like flat rate for the most part
130+
131+
Args:
132+
account_line: (account.analytic.invoice.line) Recurring invoice
133+
line being referenced.
134+
invoice: (account.invoice) Invoice that is being created.
135+
Returns:
136+
(int) Quantity to use on invoice line in the UOM defined on the
137+
``contract_line``.
138+
"""
139+
raise NotImplementedError
140+
self.get_quantity_flat(account_line, invoice)
141+
142+
@api.multi
143+
def _get_quantity_usage(self, account_line, invoice):
144+
""" It provides a quantity based on unbilled and used metrics """
145+
raise NotImplementedError
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4+
5+
from odoo import api, fields, models
6+
7+
8+
class ClouderContractLine(models.Model):
9+
""" It provides the link between billing and Clouder Services. """
10+
11+
_name = 'clouder.contract.line'
12+
_inherits = {'account.analytic.invoice.line': 'contract_line_id'}
13+
14+
contract_line_id = fields.Many2one(
15+
string='Recurring Line',
16+
comodel_name='account.analytic.invoice.line',
17+
index=True,
18+
required=True,
19+
ondelete='restrict',
20+
)
21+
service_id = fields.Many2one(
22+
string='Clouder Service',
23+
comodel_name='clouder.service',
24+
related='metric_interface_id.service_id',
25+
required=True,
26+
)
27+
metric_interface_id = fields.Many2one(
28+
string='Metric Interface',
29+
comodel_name='clouder.metric.interface',
30+
required=True,
31+
)
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4+
5+
from openerp import fields, models
6+
7+
8+
class ProductTemplate(models.Model):
9+
_inherit = 'product.template'
10+
11+
invoice_policy = fields.Selection(
12+
selection_add=[
13+
('threshold', 'Invoice and Enforce a Threshold'),
14+
('usage', 'Invoice Based on Usage'),
15+
],
16+
)

0 commit comments

Comments
 (0)