Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • coopdevs/comunitats-energetiques/odoo-ce
1 result
Show changes
Showing
with 534 additions and 10 deletions
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record
id="selfconsumption_energy_delivered_invoicing_reminder"
model="mail.template"
>
<field name="name">Selfconsumption Energy Delivered Invoicing Reminder</field>
<field name="email_from">${object.company_id.email}</field>
<field
name="subject"
>Selfconsumption - Energy Delivered Invoicing Reminder</field>
<field
name="model_id"
ref="energy_selfconsumption.model_energy_selfconsumption_selfconsumption"
/>
<field name="body_html">
<![CDATA[
<p>Hi,</p>
<p>
Remember that the collective self-consumption project
<b>${ object.name }</b>
of the energy community
<b>${ object.project_id.company_id.name }</b>
must invoice on the day <b>${ ctx['next_invoicing'] }</b>.
</p>
<p>
It is necessary, therefore, that you enter into Odoo the energy generated in kWh during the period
<b>${ ctx['first_date'] }</b>
- <b>${ ctx['last_date'] }</b>.
</p>
<p>
To do so, go to the project file, enter the contracts view, select the contracts that must be invoiced and
press the Invoice button.</br>
</p>
<p>
For any questions or incidents, contact the support team; support@somcomunitats.coop.
</p>
]]>
</field>
</record>
</odoo>
......@@ -13,4 +13,61 @@ class Contract(models.Model):
ondelete="restrict",
string="Energy Project",
related="supply_point_assignation_id.distribution_table_id.selfconsumption_project_id.project_id",
store=True,
auto_join=True,
)
code = fields.Char(related="supply_point_assignation_id.supply_point_id.code")
supply_point_name = fields.Char(
related="supply_point_assignation_id.supply_point_id.name"
)
last_period_date_start = fields.Date(
string="Last Period Start",
readonly=True,
)
last_period_date_end = fields.Date(
string="Last Period End",
readonly=True,
)
def invoicing_wizard_action(self):
"""
We create the wizard first, so it triggers the constraint of the contract_ids
:return: Window action with the wizard already created
"""
wizard_id = self.env["energy_selfconsumption.invoicing.wizard"].create(
{"contract_ids": [(6, 0, self.ids)]}
)
action = self.env.ref(
"energy_selfconsumption.invoicing_wizard_act_window"
).read()[0]
action["res_id"] = wizard_id.id
return action
def _recurring_create_invoice(self, date_ref=False):
last_period_date_start = last_period_date_end = False
if len(self) > 1:
last_period_date_start = self[0].next_period_date_start
last_period_date_end = self[0].next_period_date_end
res = super()._recurring_create_invoice(date_ref=date_ref)
if res and last_period_date_start and last_period_date_end:
self.write(
{
"last_period_date_start": last_period_date_start,
"last_period_date_end": last_period_date_end,
}
)
return res
def _get_contracts_to_invoice_domain(self, date_ref=None):
domain = super()._get_contracts_to_invoice_domain(date_ref)
domain.extend(
[("project_id.selfconsumption_id.invoicing_mode", "!=", "energy_delivered")]
)
return domain
class ContractRecurrencyMixin(models.AbstractModel):
_inherit = "contract.recurrency.mixin"
next_period_date_start = fields.Date(store=True)
next_period_date_end = fields.Date(store=True)
......@@ -7,3 +7,4 @@ class EnergyProject(models.Model):
selfconsumption_id = fields.One2many(
"energy_selfconsumption.selfconsumption", "project_id"
)
contract_ids = fields.One2many("contract.contract", "project_id", readonly=True)
from datetime import datetime
from datetime import datetime, timedelta
from odoo import _, fields, models
from odoo.exceptions import ValidationError
......@@ -125,10 +125,18 @@ class Selfconsumption(models.Model):
return {
"type": "ir.actions.act_window",
"name": "Contracts",
"view_mode": "tree,form",
"views": [
[self.env.ref("energy_selfconsumption.contract_tree_view").id, "tree"],
[False, "form"],
],
"res_model": "contract.contract",
"domain": [("project_id", "=", self.id)],
"context": {"create": True, "default_project_id": self.id},
"context": {
"create": True,
"default_project_id": self.id,
"search_default_filter_next_period_date_start": True,
"search_default_filter_next_period_date_end": True,
},
}
def distribution_table_state(self, actual_state, new_state):
......@@ -261,6 +269,41 @@ class Selfconsumption(models.Model):
"target": "self",
}
def send_energy_delivery_invoicing_reminder(self):
today = fields.date.today()
date_validation = today + timedelta(days=3)
projects = self.env["contract.contract"].read_group(
[
(
"project_id.selfconsumption_id.invoicing_mode",
"=",
"energy_delivered",
),
("recurring_next_date", "=", date_validation),
],
["project_id"],
["project_id"],
)
template = self.env.ref(
"energy_selfconsumption.selfconsumption_energy_delivered_invoicing_reminder",
True,
)
for project in projects:
selfconsumption_id = self.browse(project["project_id"][0])
contract = selfconsumption_id.contract_ids[0]
first_date = contract.next_period_date_start
last_date = contract.next_period_date_end
next_invoicing = contract.recurring_next_date
ctx = {
"next_invoicing": next_invoicing.strftime("%d-%m-%Y"),
"first_date": first_date.strftime("%d-%m-%Y"),
"last_date": last_date.strftime("%d-%m-%Y"),
}
selfconsumption_id.with_context(ctx).message_post_with_template(template.id)
return True
class CoefficientReport(models.TransientModel):
_name = "energy_selfconsumption.coefficient_report"
......
......@@ -11,4 +11,5 @@ access_energy_selfconsumption_selfconsumption_import_wizard_admin,energy_selfcon
access_energy_selfconsumption_distribution_table_import_wizard_admin,energy_selfconsumption.distribution_table_import.wizard.admin,model_energy_selfconsumption_distribution_table_import_wizard,energy_project.group_admin,1,1,1,1
access_energy_selfconsumption_contract_generation_wizard_admin,energy_selfconsumption.contract_generation.wizard.admin,model_energy_selfconsumption_contract_generation_wizard,energy_project.group_admin,1,1,1,1
accces_energy_selfconsumption_coefficient_report,energy_selfconsumption.coefficient_report.admin,model_energy_selfconsumption_coefficient_report,energy_project.group_admin,1,1,1,1
access_energy_elfconsumptionn_define_invoicing_mode_admin,energy_selfconsumption.define_invoicing_mode.wizard.admin,model_energy_selfconsumption_define_invoicing_mode_wizard,energy_project.group_admin,1,1,1,1
access_energy_selfconsumption_define_invoicing_mode_wizard_admin,energy_selfconsumption.define_invoicing_mode.wizard.admin,model_energy_selfconsumption_define_invoicing_mode_wizard,energy_project.group_admin,1,1,1,1
access_energy_selfconsumption_invoicing_wizard_admin,energy_selfconsumption.invoicing.wizard.admin,model_energy_selfconsumption_invoicing_wizard,energy_project.group_admin,1,1,1,1
from . import test_contract_generation_wizard
from . import test_invoicing_reminder
......@@ -66,7 +66,7 @@ class TestContractGenerationWizard(TransactionCase):
"coefficient": 1,
}
)
self.define_invoicing_mode_wizard = self.env[
self.define_invoicing_mode_power_acquired_wizard = self.env[
"energy_selfconsumption.define_invoicing_mode.wizard"
].create(
{
......@@ -77,6 +77,17 @@ class TestContractGenerationWizard(TransactionCase):
"invoicing_mode": "power_acquired",
}
)
self.define_invoicing_mode_energy_delivered_wizard = self.env[
"energy_selfconsumption.define_invoicing_mode.wizard"
].create(
{
"selfconsumption_id": self.selfconsumption.id,
"price": 0.1,
"recurring_interval": 1,
"recurring_rule_type": "monthly",
"invoicing_mode": "energy_delivered",
}
)
self.contract_generation_wizard = self.env[
"energy_selfconsumption.contract_generation.wizard"
].create(
......@@ -85,8 +96,10 @@ class TestContractGenerationWizard(TransactionCase):
}
)
def test_generation_contracts(self):
res = self.define_invoicing_mode_wizard.save_data_to_selfconsumption()
def test_power_acquired_generation_contracts(self):
res = (
self.define_invoicing_mode_power_acquired_wizard.save_data_to_selfconsumption()
)
self.assertEqual(
res,
{
......@@ -109,3 +122,34 @@ class TestContractGenerationWizard(TransactionCase):
invoice = related_contract._get_related_invoices()
self.assertEqual(invoice.invoice_line_ids[0].quantity, expected_quantity)
self.assertEqual(invoice.invoice_line_ids[0].price_unit, 0.1)
def test_energy_delivered_generation_contracts(self):
res = (
self.define_invoicing_mode_energy_delivered_wizard.save_data_to_selfconsumption()
)
self.assertEqual(
res,
{
"type": "ir.actions.act_window_close",
},
)
res = self.contract_generation_wizard.generate_contracts_button()
self.assertEqual(res, True)
related_contract = self.env["contract.contract"].search(
[("project_id", "=", self.selfconsumption.project_id.id)]
)
wizard_id = self.env["energy_selfconsumption.invoicing.wizard"].create(
{
"contract_ids": [(6, 0, related_contract.ids)],
"power": 200,
}
)
expected_quantity = 200 * 1
wizard_id.generate_invoices()
invoice = related_contract._get_related_invoices()
self.assertEqual(invoice.invoice_line_ids[0].quantity, expected_quantity)
self.assertEqual(invoice.invoice_line_ids[0].price_unit, 0.1)
from datetime import date, datetime, timedelta
from odoo.tests import TransactionCase
class TestInvoicingReminder(TransactionCase):
def setUp(self):
super().setUp()
self.partner = self.env["res.partner"].create({"name": "test partner"})
self.selfconsumption = self.env[
"energy_selfconsumption.selfconsumption"
].create(
{
"name": "test Selfconsumption Project",
"type": self.env.ref(
"energy_selfconsumption.selfconsumption_project_type"
).id,
"code": "ES0397277816188340VL",
"cil": "001ES0397277816188340VL",
"state": "activation",
"power": 100,
"street": "Carrer de Sants, 79",
"zip": "08014",
"city": "Barcelona",
"state_id": self.env.ref("base.state_es_b").id,
"country_id": self.env.ref("base.es").id,
"invoicing_mode": "energy_delivered",
}
)
self.inscription = self.env["energy_project.inscription"].create(
{
"project_id": self.selfconsumption.project_id.id,
"partner_id": self.partner.id,
"effective_date": datetime.today(),
}
)
self.supply_point = self.env["energy_selfconsumption.supply_point"].create(
{
"code": "ES0029542181297829TM",
"street": "C. de Sta. Catalina",
"street2": "55º B",
"zip": "08014",
"city": "Barcelona",
"state_id": self.env.ref("base.state_es_b").id,
"country_id": self.env.ref("base.es").id,
"owner_id": self.partner.id,
"partner_id": self.partner.id,
}
)
self.distribution_table = self.env[
"energy_selfconsumption.distribution_table"
].create(
{
"name": "DT001",
"selfconsumption_project_id": self.selfconsumption.id,
"type": "fixed",
"state": "process",
}
)
self.supply_point_assignation = self.env[
"energy_selfconsumption.supply_point_assignation"
].create(
{
"distribution_table_id": self.distribution_table.id,
"supply_point_id": self.supply_point.id,
"coefficient": 1,
}
)
self.define_invoicing_mode_wizard = self.env[
"energy_selfconsumption.define_invoicing_mode.wizard"
].create(
{
"selfconsumption_id": self.selfconsumption.id,
"price": 0.1,
"recurring_interval": 1,
"recurring_rule_type": "monthly",
"invoicing_mode": "energy_delivered",
}
)
self.contract_generation_wizard = self.env[
"energy_selfconsumption.contract_generation.wizard"
].create(
{
"selfconsumption_id": self.selfconsumption.id,
}
)
def test_send_energy_delivery_invoicing_reminder(self):
# Test using send_energy_delivery_invoicing_reminder() method to send correctly email
validation_date = date.today() + timedelta(days=3)
self.define_invoicing_mode_wizard.save_data_to_selfconsumption()
self.contract_generation_wizard.generate_contracts_button()
contract = self.env["contract.contract"].search(
[("name", "=", "Contract - test Selfconsumption Project - test partner")]
)
contract.recurring_next_date = validation_date
self.env[
"energy_selfconsumption.selfconsumption"
].send_energy_delivery_invoicing_reminder()
reminder_mail = self.env["mail.mail"].search(
[("subject", "=", "Selfconsumption - Energy Delivered Invoicing Reminder")]
)
self.assertTrue(reminder_mail, "El correo de recordatorio no se envió.")
# Delete sent email to make other test
reminder_mail.unlink()
# Test using the send_energy_delivery_invoicing_reminder() method with a record with a date outside the parameter (3 days)
contract.recurring_next_date = validation_date + timedelta(days=1)
self.env[
"energy_selfconsumption.selfconsumption"
].send_energy_delivery_invoicing_reminder()
reminder_mail = self.env["mail.mail"].search(
[("subject", "=", "Selfconsumption - Energy Delivered Invoicing Reminder")]
)
self.assertFalse(reminder_mail, "El correo de recordatorio no se envió.")
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<record id="contract_tree_view" model="ir.ui.view">
<field name="name">energy_selfconsumption.contract.tree</field>
<field name="model">contract.contract</field>
<field name="arch" type="xml">
<tree string="Contracts" expand="1">
<field name="partner_id" />
<field name="supply_point_name" />
<field name="code" />
<field name="next_period_date_start" />
<field name="next_period_date_end" />
<field name="last_period_date_start" />
<field name="last_period_date_end" />
</tree>
</field>
</record>
<record id="contract_search_view" model="ir.ui.view">
<field name="name">energy_selfconsumption.contract.search</field>
<field name="model">contract.contract</field>
<field name="inherit_id" ref="contract.contract_contract_search_view" />
<field name="arch" type="xml">
<xpath expr="/search" position="inside">
<group expand="1" string="Group By">
<filter
string="Next Period Date Start"
name="filter_next_period_date_start"
domain="[]"
context="{'group_by':'next_period_date_start'}"
/>
<filter
string="Next Period Date End"
name="filter_next_period_date_end"
domain="[]"
context="{'group_by':'next_period_date_end'}"
/>
</group>
</xpath>
</field>
</record>
<record id="contract_invoicing_wizard_action" model="ir.actions.server">
<field name="name">Invoice Energy Recurrency</field>
<field name="model_id" ref="model_contract_contract" />
<field name="binding_model_id" ref="contract.model_contract_contract" />
<field name="binding_type">action</field>
<field name="binding_view_types">list,form</field>
<field name="groups_id" eval="[(4,ref('energy_project.group_admin'))]" />
<field name="state">code</field>
<field name="code">action = records.invoicing_wizard_action()</field>
</record>
</data>
</odoo>
......@@ -2,3 +2,4 @@ from . import selfconsumption_import_wizard
from . import distribution_table_import_wizard
from . import contract_generation_wizard
from . import define_invoicing_mode_wizard
from . import invoicing_wizard
......@@ -71,7 +71,7 @@ class ContractGenerationWizard(models.TransientModel):
"qty_formula_id": formula_contract_id.id,
"uom_id": product_id.uom_id.id,
# Values are formatted in contract_generation_wizard
"name": """CUPS: {code}\nOwner: {owner_id}\nInvoicing period: #START# - #END#""",
"name": """CUPS: {code}\nOwner: {owner_id}\nInvoicing period: #START# - #END#\n""",
}
def save_data_to_selfconsumption(self):
......
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class InvoicingWizard(models.TransientModel):
_name = "energy_selfconsumption.invoicing.wizard"
power = fields.Float(string="Total Energy Generated (kWh)")
contract_ids = fields.Many2many("contract.contract", readonly=True)
next_period_date_start = fields.Date(
string="Next Period Start",
compute="_compute_next_period_date_start_and_end",
readonly=True,
)
next_period_date_end = fields.Date(
string="Next Period End",
compute="_compute_next_period_date_start_and_end",
readonly=True,
)
@api.depends("contract_ids")
def _compute_next_period_date_start_and_end(self):
for record in self:
if len(record.contract_ids) > 0:
record.next_period_date_start = record.contract_ids[
0
].next_period_date_start
record.next_period_date_end = record.contract_ids[
0
].next_period_date_end
@api.constrains("contract_ids")
def constraint_contract_ids(self):
for record in self:
contract_list = record.contract_ids
all_same_project = all(
element.project_id == contract_list[0].project_id
for element in contract_list
)
if not all_same_project:
raise ValidationError(
_(
"""
Some of the contract selected are not of the same self-consumption project.
Please make sure that you are invoicing for only the same self-consumption project ({project_name}.
"""
).format(
project_name=contract_list[0].project_id.selfconsumption_id.name
)
)
valid_invoicing_mode = ["energy_delivered"]
all_invoicing_mode = all(
element.project_id.selfconsumption_id.invoicing_mode
in valid_invoicing_mode
for element in contract_list
)
if not all_invoicing_mode:
raise ValidationError(
_(
"""
Some of the contract selected are not defined as energy delivered self-consumption projects.
Please make sure that you are invoicing the correct self-consumption project.
"""
)
)
all_equal_period = all(
element.next_period_date_start
== contract_list[0].next_period_date_start
and element.next_period_date_end
== contract_list[0].next_period_date_end
for element in contract_list
)
if not all_equal_period:
raise ValidationError(
_(
"""
Select only contracts with the same period of invoicing.
Make sure that all the selected contracts have the same next period start and end.
Next period start: {next_period_date_start}
Next period end: {next_period_date_end}"""
).format(
next_period_date_start=contract_list[0].next_period_date_start,
next_period_date_end=contract_list[0].next_period_date_end,
)
)
@api.constrains("power")
def constraint_power(self):
for record in self:
if not record.power or record.power <= 0:
raise ValidationError(
_("You must enter a valid total energy generated (kWh).")
)
def generate_invoices(self):
for contract in self.contract_ids:
template_name = contract.contract_template_id.contract_line_ids[0].name
template_name += _("Energy Delivered: {energy_delivered} kWh")
contract.contract_line_ids.write(
{
"name": template_name.format(
energy_delivered=self.power,
code=contract.supply_point_assignation_id.supply_point_id.code,
owner_id=contract.supply_point_assignation_id.supply_point_id.owner_id.display_name,
)
}
)
return self.with_context(
{"energy_delivered": self.power}
).contract_ids._recurring_create_invoice()
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<record id="invoicing_wizard_form_view" model="ir.ui.view">
<field name="name">energy_selfconsumption.invoicing_wizard.form
</field>
<field name="model">energy_selfconsumption.invoicing.wizard</field>
<field name="arch" type="xml">
<form string="Invoicing Energy Delivered">
<sheet>
<group>
<field name="next_period_date_start" />
<field name="next_period_date_end" />
</group>
<group>
<field name="power" />
<field name="contract_ids">
<tree>
<field name="partner_id" />
<field name="supply_point_name" />
<field name="code" />
<field name="next_period_date_start" />
<field name="next_period_date_end" />
</tree>
</field>
</group>
</sheet>
<footer>
<button type="object" name="generate_invoices">Generate</button>
</footer>
</form>
</field>
</record>
<record id="invoicing_wizard_act_window" model="ir.actions.act_window">
<field name="name">Invoice Energy Delivered</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">energy_selfconsumption.invoicing.wizard</field>
<field name="groups_id" eval="[(4,ref('energy_project.group_admin'))]" />
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</odoo>
......@@ -9,7 +9,7 @@ setuptools.setup(
"community_maps": "odoo14-addon-community-maps==14.0.0.1.13",
"cooperator_account_payment": "odoo14-addon-cooperator-account-payment==14.0.1.1.0",
"cooperator_account_banking_mandate": "odoo14-addon-cooperator-account-banking-mandate==14.0.1.1.0",
"energy_selfconsumption": "odoo14-addon-energy-selfconsumption==14.0.2.2.0",
"energy_selfconsumption": "odoo14-addon-energy-selfconsumption==14.0.3.0.0",
"crm_metadata": "odoo14-addon-crm-metadata==14.0.1.0.0",
"crm_metadata_rest_api": "odoo14-addon-crm-metadata-rest-api==14.0.1.0.2",
"crm_rest_api": "odoo14-addon-crm-rest-api==14.0.1.0.2",
......
......@@ -4,7 +4,7 @@ setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon={
"depends_override": {
"energy_project": "odoo14-addon-energy-project==14.0.2.0.0",
"energy_project": "odoo14-addon-energy-project==14.0.2.1.0",
"web_m2x_options": "odoo14-addon-web-m2x-options==14.0.1.1.1",
"contract_queue_job": "odoo14-addon-contract-queue-job==14.0.1.0.1.dev3",
}
......