diff --git a/golem_resource_pack/__init__.py b/golem_resource_pack/__init__.py new file mode 100644 index 0000000..f95e908 --- /dev/null +++ b/golem_resource_pack/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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 . import models, wizard diff --git a/golem_resource_pack/__manifest__.py b/golem_resource_pack/__manifest__.py new file mode 100644 index 0000000..7bfea4b --- /dev/null +++ b/golem_resource_pack/__manifest__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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': 'GOLEM resources pack', + 'summary': 'GOLEM resources pack', + 'description': ''' GOLEM resources pack ''', + 'version': '10.0.0.0.4', + 'category': 'GOLEM', + 'author': 'Youssef El Ouahby, Fabien Bourgeois', + 'license': 'AGPL-3', + 'application': True, + 'installable': True, + 'depends': ['golem_resource'], + 'data': ['views/golem_resource_pack_views.xml', + 'wizard/golem_pack_rejection_views.xml', + 'security/ir.model.access.csv'] +} diff --git a/golem_resource_pack/models/__init__.py b/golem_resource_pack/models/__init__.py new file mode 100644 index 0000000..ea2f68b --- /dev/null +++ b/golem_resource_pack/models/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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 . import golem_resource_pack, \ + golem_resource_reservation diff --git a/golem_resource_pack/models/golem_resource_pack.py b/golem_resource_pack/models/golem_resource_pack.py new file mode 100644 index 0000000..ad51f7e --- /dev/null +++ b/golem_resource_pack/models/golem_resource_pack.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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 . + +""" GOLEM Resource Packs """ + +from odoo import models, fields, api, _ +from odoo.exceptions import ValidationError + + +class GolemResourcePack(models.Model): + """ GOLEM Resource Pack Model """ + _name = 'golem.resource.pack' + _description = 'GOLEM Resource Pack Model' + _inherit = 'mail.thread' + + name = fields.Char(compute='_compute_name', store=True) + reservation_ids = fields.One2many('golem.resource.reservation', 'pack_id', + readonly=True, track_visibility='onchange', + states={'draft': [('readonly', False)], + False : [('readonly', False)]}) + + note = fields.Text(help='Notes, optional subject for the reservation, reason', + track_visibility='onchange', readonly=True, + states={'draft': [('readonly', False)], + False : [('readonly', False)]}) + + user_id = fields.Many2one('res.users', required=True, index=True, readonly=True, + string='User', default=lambda self: self.env.user) + partner_id = fields.Many2one('res.partner', string='On behalf of', required=True, + index=True, track_visibility='onchange', readonly=True, + states={'draft': [('readonly', False)], + False : [('readonly', False)]}) + state = fields.Selection([('canceled', 'Canceled'), + ('draft', 'Draft'), + ('confirmed', 'Confirmed'), + ('validated', 'Validated'), + ('rejected', 'Rejected')], + default='draft', compute="_compute_pack_state", + track_visibility='onchange') + reservation_count = fields.Integer(compute="_compute_reservation_count", + string="Reservation count") + rejection_reason = fields.Text(readonly=True, track_visibility='onchange') + + @api.multi + @api.constrains('partner_id') + def set_reservation_partner(self): + """ Set reservation partner """ + for pack in self: + pack.reservation_ids.write({'partner_id': pack.partner_id.id}) + + @api.multi + @api.depends('reservation_ids') + def _compute_reservation_count(self): + for pack in self: + pack.reservation_count = len(pack.reservation_ids) + + @api.multi + def state_confirm(self): + """ pack confirm """ + for pack in self: + pack.reservation_ids.state_confirm() + + @api.multi + def state_draft(self): + """ pack canceled """ + for pack in self: + pack.reservation_ids.state_draft() + + @api.multi + def state_canceled(self): + """ pack canceled """ + for pack in self: + pack.reservation_ids.state_canceled() + + @api.multi + def state_validated(self): + """ pack validated """ + for pack in self: + pack.reservation_ids.state_validated() + + @api.multi + def state_rejected(self): + """ Wizard call for pack reject """ + self.ensure_one() + pack_id = self[0] + return {'name' : _('Please enter the rejection reason'), + 'type' : 'ir.actions.act_window', + 'res_model' : 'golem.pack.rejection.wizard', + 'context': {'default_pack_id': pack_id.id}, + 'view_mode': 'form', + 'target': 'new'} + + + @api.depends('partner_id') + def _compute_name(self): + """ Compute pack name """ + for pack in self: + pack.name = u'{}/{}'.format(pack.partner_id.name, + pack.create_date) + @api.multi + @api.constrains('reservation_ids') + def check_reservation_partner(self): + """ Check reservation partner """ + for pack in self: + if len(filter(lambda x: x.partner_id == pack.partner_id, pack.reservation_ids)) < len(pack.reservation_ids): + raise ValidationError(_('Pack client should be the same for all reservations')) + + @api.multi + @api.depends('reservation_ids') + def _compute_pack_state(self): + """ get pack state """ + for pack in self: + reservation_states = list(map(lambda x: x.state, pack.reservation_ids)) + if "rejected" in reservation_states: + pack.state = 'rejected' + elif "canceled" in reservation_states: + pack.state = 'canceled' + elif "draft" in reservation_states: + pack.state = 'draft' + elif "confirmed" in reservation_states: + pack.state = 'confirmed' + elif "validated" in reservation_states: + pack.state = 'validated' diff --git a/golem_resource_pack/models/golem_resource_reservation.py b/golem_resource_pack/models/golem_resource_reservation.py new file mode 100644 index 0000000..2644175 --- /dev/null +++ b/golem_resource_pack/models/golem_resource_reservation.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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 . + +""" GOLEM Resource Reservation """ + +from odoo import models, fields + + +class GolemResourceReservation(models.Model): + """ GOLEM Resource Reservation Model """ + _inherit = 'golem.resource.reservation' + + pack_id = fields.Many2one('golem_resource_reservation', 'Reservation Pack') diff --git a/golem_resource_pack/security/ir.model.access.csv b/golem_resource_pack/security/ir.model.access.csv new file mode 100644 index 0000000..796d31b --- /dev/null +++ b/golem_resource_pack/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_golem_resource_pack_user,Access GOLEM Resource Pack User,model_golem_resource_pack,golem_base.group_golem_user,1,0,0,0 +access_golem_resource_pack_manager,Access GOLEM Resource Pack Manager,model_golem_resource_pack,golem_base.group_golem_manager,1,1,1,1 diff --git a/golem_resource_pack/tests/__init__.py b/golem_resource_pack/tests/__init__.py new file mode 100644 index 0000000..cbb2d37 --- /dev/null +++ b/golem_resource_pack/tests/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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 . import test_golem_resource_pack diff --git a/golem_resource_pack/tests/test_golem_resource_pack.py b/golem_resource_pack/tests/test_golem_resource_pack.py new file mode 100644 index 0000000..1cc5274 --- /dev/null +++ b/golem_resource_pack/tests/test_golem_resource_pack.py @@ -0,0 +1,144 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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 . + +""" GOLEM Resource Pack testing """ + +import logging +from odoo.tests.common import TransactionCase +_LOGGER = logging.getLogger(__name__) + + +class TestGolemResourcePack(TransactionCase): + """ GOLEM Resource Reservation testing """ + + def setUp(self, *args, **kwargs): + """ Bootstrap Resource Reservation """ + super(TestGolemResourcePack, self).setUp(*args, **kwargs) + + self.resource = self.env['golem.resource'].create({ + 'name': 'Resource', + 'avaibility_start': '2018-01-01', + 'avaibility_stop': '2020-01-01', + 'availibility_24_7': True + }) + self.resource_val = self.env['golem.resource'].create({ + 'name': 'Resource to validate', + 'avaibility_start': '2018-01-01', + 'avaibility_stop': '2020-01-01', + 'validation_required': True, + 'availibility_24_7': True + }) + + self.partner = self.env['res.partner'].create({'firstname': 'John', + 'lastname': 'DOE', + 'is_company': False}) + + reservation_obj = self.env['golem.resource.reservation'] + self.reservation_1 = reservation_obj.create({ + 'resource_id': self.resource.id, + 'date_start': '2018-02-05 11:00:00', + 'date_stop': '2018-02-05 12:00:00', + 'partner_id': self.partner.id + }) + self.reservation_2 = reservation_obj.create({ + 'resource_id': self.resource.id, + 'date_start': '2018-02-06 11:00:00', + 'date_stop': '2018-02-06 12:00:00', + 'partner_id': self.partner.id + }) + self.reservation_3 = reservation_obj.create({ + 'resource_id': self.resource_val.id, + 'date_start': '2018-02-05 11:00:00', # is monday + 'date_stop': '2018-02-05 12:00:00', + 'partner_id': self.partner.id + }) + self.pack_obj = self.env['golem.resource.pack'] + self.pack_data = { + 'partner_id': self.partner.id + } + + + def test_pack_basic(self): + """ Test pack bases """ + pack = self.pack_obj.create(self.pack_data) + self.assertFalse(pack.reservation_ids) + self.assertFalse(self.reservation_1.pack_id) + pack.reservation_ids = [(4, self.reservation_1.id, 0), + (4, self.reservation_2.id, 0)] + self.assertEqual(pack.reservation_ids[0].state, "draft") + self.assertEqual(self.reservation_1.pack_id.id, pack.id) + self.assertEqual(pack.state, "draft") + self.assertEqual(pack.reservation_count, 2) + #confirm pack ==> all validated + pack.state_confirm()#no validation required + self.assertEqual(pack.reservation_ids[0].state, "validated") + self.assertEqual(pack.state, "validated") + #pack draft ==> all draft + pack.state_draft() + self.assertEqual(pack.reservation_ids[0].state, "draft") + self.assertEqual(pack.state, "draft") + # confirm pack and draft reservation ==> pack draft + pack.state_confirm() + pack.reservation_ids[0].state_draft() + self.assertEqual(pack.reservation_ids[0].state, "draft") + self.assertEqual(pack.state, "draft") + #confirm reservation ==> pack validated + pack.reservation_ids[0].state_confirm() + self.assertEqual(pack.reservation_ids[0].state, "validated") + self.assertEqual(pack.state, "validated") + pack.reservation_ids = [(5, 0, 0)] + self.assertFalse(pack.reservation_ids) + self.assertEqual(pack.reservation_count, 0) + + + def test_pack_validation(self): + """ Test pack validation """ + pack = self.pack_obj.create(self.pack_data) + self.assertFalse(pack.reservation_ids) + self.assertFalse(self.reservation_1.pack_id) + pack.reservation_ids = [(4, self.reservation_1.id, 0), + (4, self.reservation_3.id, 0)] + self.assertEqual(pack.reservation_ids[0].state, "draft") + self.assertEqual(self.reservation_1.pack_id.id, pack.id) + self.assertEqual(pack.state, "draft") + pack.state_confirm()#validation required + self.assertEqual(pack.state, "confirmed") + pack.state_validated() + self.assertEqual(pack.state, "validated") + self.assertEqual(pack.reservation_ids[0].state, "validated") + self.assertEqual(pack.reservation_ids[1].state, "validated") + + def test_pack_rejection(self): + """ test pack rejection """ + pack = self.pack_obj.create(self.pack_data) + self.assertFalse(pack.reservation_ids) + self.assertFalse(self.reservation_1.pack_id) + pack.reservation_ids = [(4, self.reservation_1.id, 0), + (4, self.reservation_3.id, 0)] + self.assertEqual(pack.reservation_ids[0].state, "draft") + self.assertEqual(self.reservation_1.pack_id.id, pack.id) + self.assertEqual(pack.state, "draft") + pack.state_confirm()#validation required + rej_wizard = self.env['golem.pack.rejection.wizard'].create({ + 'pack_id': pack.id, + 'reason' : 'reason1' + }) + rej_wizard.reject() + self.assertEqual(pack.state, "rejected") + self.assertEqual(self.reservation_3.state, "rejected") + self.assertEqual(pack.rejection_reason, 'reason1') diff --git a/golem_resource_pack/views/golem_resource_pack_views.xml b/golem_resource_pack/views/golem_resource_pack_views.xml new file mode 100644 index 0000000..37d929d --- /dev/null +++ b/golem_resource_pack/views/golem_resource_pack_views.xml @@ -0,0 +1,87 @@ + + + + + + + GOLEM Resource Pack Tree + golem.resource.pack + + + + + + + + + + + + + GOLEM Resource Pack Form + golem.resource.pack + +
+
+
+ + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + +
+
diff --git a/golem_resource_pack/wizard/__init__.py b/golem_resource_pack/wizard/__init__.py new file mode 100644 index 0000000..6fa8cf7 --- /dev/null +++ b/golem_resource_pack/wizard/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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 . import golem_pack_rejection diff --git a/golem_resource_pack/wizard/golem_pack_rejection.py b/golem_resource_pack/wizard/golem_pack_rejection.py new file mode 100644 index 0000000..2dcb6d8 --- /dev/null +++ b/golem_resource_pack/wizard/golem_pack_rejection.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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 . + +""" GOLEM Resources Pack management """ + +from odoo import models, fields, api + +class GolemReservationRejectionWizard(models.TransientModel): + """GOLEM Resource wizard : refusal reason for a pack """ + _name = "golem.pack.rejection.wizard" + + pack_id = fields.Many2one('golem.resource.pack', required=True) + reason = fields.Text(required=True) + + @api.multi + def reject(self): + """ Sets pack status to rejected and add reason """ + self.ensure_one() + rejection = self[0] + for reservation in rejection.pack_id.reservation_ids: + if reservation.state == "confirmed": + reservation.write({'state' :'rejected'}) + rejection.pack_id.write({'rejection_reason': rejection.reason}) diff --git a/golem_resource_pack/wizard/golem_pack_rejection_views.xml b/golem_resource_pack/wizard/golem_pack_rejection_views.xml new file mode 100644 index 0000000..b0b01ec --- /dev/null +++ b/golem_resource_pack/wizard/golem_pack_rejection_views.xml @@ -0,0 +1,41 @@ + + + + + + + + GOLEM Pack Rejection Wizard Form + golem.pack.rejection.wizard + +
+ + + + +
+
+
+
+
+
+
diff --git a/golem_resource_pack_account/__init__.py b/golem_resource_pack_account/__init__.py new file mode 100644 index 0000000..1fced20 --- /dev/null +++ b/golem_resource_pack_account/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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 . import models diff --git a/golem_resource_pack_account/__manifest__.py b/golem_resource_pack_account/__manifest__.py new file mode 100644 index 0000000..05c4042 --- /dev/null +++ b/golem_resource_pack_account/__manifest__.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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': 'GOLEM resources pack invoicing', + 'summary': 'GOLEM resources pack invoicing', + 'description': ''' GOLEM resources pack invoicing ''', + 'version': '10.0.0.0.1', + 'category': 'GOLEM', + 'author': 'Youssef El Ouahby, Fabien Bourgeois', + 'license': 'AGPL-3', + 'application': True, + 'installable': True, + 'depends': ['golem_resource_pack', 'golem_resource_account'], + 'data': ['views/golem_resource_pack_views.xml'] + #'security/ir.model.access.csv'] +} diff --git a/golem_resource_pack_account/models/__init__.py b/golem_resource_pack_account/models/__init__.py new file mode 100644 index 0000000..35a9273 --- /dev/null +++ b/golem_resource_pack_account/models/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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 . import golem_resource_pack diff --git a/golem_resource_pack_account/models/golem_resource_pack.py b/golem_resource_pack_account/models/golem_resource_pack.py new file mode 100644 index 0000000..c541dad --- /dev/null +++ b/golem_resource_pack_account/models/golem_resource_pack.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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 . + +""" GOLEM Resource Pack Invoicing """ + +from odoo import models, fields, api, _ +from odoo.exceptions import ValidationError + + +class GolemResourcePack(models.Model): + """ GOLEM Resource Pack invoice extention """ + _inherit = 'golem.resource.pack' + + invoice_id = fields.Many2one('account.invoice', string="Invoice") + + invoice_state = fields.Selection(related='invoice_id.state', store=True, + copy=False) + invoice_amount_total = fields.Monetary(related='invoice_id.amount_total') + currency_id = fields.Many2one(related='invoice_id.currency_id') + is_products_set = fields.Boolean(compute="_compute_is_products_set") + + @api.multi + def _compute_is_products_set(self): + """ compute is_products_set """ + for pack in self: + if len(filter(lambda x: x.resource_product_id.id is False, pack.reservation_ids)) \ + > 0: + pack.is_products_set = False + else: + pack.is_products_set = True + + @api.multi + def chek_pack_to_invoice(self): + """ chek pack before invoicing """ + for pack in self: + if pack.state != 'validated': + raise ValidationError(_('The current pack is not validated, please validate ' + 'it before creating invoice')) + elif not pack.is_products_set: + raise ValidationError(_('You can not create an invoice for a pack without ' + 'linked product on every resource reserved.')) + elif pack.invoice_id.id: + raise ValidationError(_('You can not create an invoice as there ' + 'is already one.')) + + + @api.multi + def create_invoice(self): + """ Invoice creation """ + for pack in self: + pack.chek_pack_to_invoice() + pack.reservation_ids.check_before_invoicing() + inv_obj = self.env['account.invoice'] + partner_id = pack.partner_id + invoice_id = inv_obj.create({ + 'origin': pack.name, + 'type': 'out_invoice', + 'reference': False, + 'account_id': partner_id.property_account_receivable_id.id, + 'partner_id': partner_id.id + }) + pack.invoice_id = invoice_id.id + pack.reservation_ids.create_invoice_line(invoice_id) + + @api.multi + def show_invoice(self): + """ Redirects to linked invoice """ + self.ensure_one() + pack = self[0] + if pack.invoice_id: + return {'type': 'ir.actions.act_window', + 'res_model': 'account.invoice', + 'res_id': pack.invoice_id.id, + 'view_mode': 'form', + 'view_id': self.env.ref('account.invoice_form').id} diff --git a/golem_resource_pack_account/tests/__init__.py b/golem_resource_pack_account/tests/__init__.py new file mode 100644 index 0000000..69aaa1d --- /dev/null +++ b/golem_resource_pack_account/tests/__init__.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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 . import test_golem_pack_invoice diff --git a/golem_resource_pack_account/tests/test_golem_pack_invoice.py b/golem_resource_pack_account/tests/test_golem_pack_invoice.py new file mode 100644 index 0000000..29961a5 --- /dev/null +++ b/golem_resource_pack_account/tests/test_golem_pack_invoice.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Youssef El Ouahby +# Copyright 2018 Fabien Bourgeois +# +# 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 . + +""" GOLEM Resource Reservation testing """ + +import logging +from odoo.tests.common import TransactionCase +from odoo.exceptions import ValidationError +_LOGGER = logging.getLogger(__name__) + + +class TestGolemResourcePack(TransactionCase): + """ GOLEM Resource Pack testing """ + + def setUp(self, *args, **kwargs): + """ Bootstrap Resource Reservation """ + super(TestGolemResourcePack, self).setUp(*args, **kwargs) + # set product + self.product = self.env['product.template'].create({ + 'name': 'Product', + 'categ_id': self.env.ref('product.product_category_all').id, + 'list_price': 7.0, + 'type': 'service', + 'uom_id': self.env.ref('product.product_uom_hour').id, + 'uom_po_id': self.env.ref('product.product_uom_hour').id, + 'property_account_income_id': self.env.ref('l10n_fr.pcg_706').id + }) + #set resources + self.resource_1 = self.env['golem.resource'].create({ + 'name': 'Resource1', + 'product_tmpl_id': self.product.id, + 'avaibility_start': '2018-01-01', + 'avaibility_stop': '2020-01-01', + 'availibility_24_7': True + }) + self.resource_2 = self.env['golem.resource'].create({ + 'name': 'Resource2', + 'avaibility_start': '2018-01-01', + 'avaibility_stop': '2020-01-01', + 'availibility_24_7': True + }) + + #set partners + self.partner_1 = self.env['res.partner'].create({'firstname': 'John', + 'lastname': 'DOE', + 'is_company': False}) + self.partner_2 = self.env['res.partner'].create({'firstname': 'John2', + 'lastname': 'DOE2', + 'is_company': False}) + + # set reservations + self.reservation_1 = self.env['golem.resource.reservation'].create({ + 'resource_id': self.resource_1.id, + 'date_start': '2018-02-05 11:00:00', + 'date_stop': '2018-02-05 12:00:00', + 'partner_id': self.partner_1.id + }) + self.reservation_2 = self.env['golem.resource.reservation'].create({ + 'resource_id': self.resource_1.id, + 'date_start': '2018-02-06 11:00:00', + 'date_stop': '2018-02-06 12:00:00', + 'partner_id': self.partner_1.id + }) + + #set pack env + self.pack_obj = self.env['golem.resource.pack'] + self.pack_data = { + 'partner_id': self.partner_1.id, + 'reservation_ids': [(4, self.reservation_1.id, 0), + (4, self.reservation_2.id, 0)]} + + + def test_pack_invoice_basic(self): + """ Test pack invoice basic """ + pack = self.pack_obj.create(self.pack_data) + pack.state_confirm() + pack.create_invoice() + self.assertTrue(pack.invoice_id.id) + self.assertEqual(pack.invoice_state, 'draft') + + def test_unallowed_pack_invoice(self): + """ Test unallowed pack invoice cases """ + pack = self.pack_obj.create(self.pack_data) + with self.assertRaises(ValidationError) as err: + pack.create_invoice() + self.assertIn(u'current pack is not validated', err.exception.args[0]) + self.reservation_2.write({'resource_id': self.resource_2.id})#no product linked + pack.state_confirm() + with self.assertRaises(ValidationError) as err: + pack.create_invoice() + self.assertIn(u'linked product on every resource', err.exception.args[0]) + pack.state_draft() + self.reservation_2.write({'resource_id': self.resource_1.id})# with product linked + pack.state_confirm() + pack.create_invoice() + self.assertTrue(pack.invoice_id.id) + with self.assertRaises(ValidationError) as err: + pack.create_invoice() + self.assertIn(u'can not create an invoice as there', err.exception.args[0]) diff --git a/golem_resource_pack_account/views/golem_resource_pack_views.xml b/golem_resource_pack_account/views/golem_resource_pack_views.xml new file mode 100644 index 0000000..6d37fcd --- /dev/null +++ b/golem_resource_pack_account/views/golem_resource_pack_views.xml @@ -0,0 +1,56 @@ + + + + + + + GOLEM Resource Pack Account extention Tree + golem.resource.pack + + + + + + + + + + GOLEM Resource Pack Account extention Form + golem.resource.pack + + + + + + + + + + + + + + +