Merge branch 'golem_resource_pack'

This commit is contained in:
Fabien BOURGEOIS 2018-04-17 08:48:59 +02:00
commit e8d6336bca
19 changed files with 929 additions and 0 deletions

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
from . import models, wizard

View File

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
{
'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': False,
'installable': True,
'depends': ['golem_resource'],
'data': ['views/golem_resource_pack_views.xml',
'wizard/golem_pack_rejection_views.xml',
'security/ir.model.access.csv']
}

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
from . import golem_resource_pack, golem_resource_reservation

View File

@ -0,0 +1,127 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
""" 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(required=True)
reservation_ids = fields.One2many('golem.resource.reservation', 'pack_id',
readonly=True, string='Reservations',
states={'draft': [('readonly', False)]})
note = fields.Text(help='Notes, optional subject for the reservation, reason',
track_visibility='onchange', readonly=True,
states={'draft': [('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)]})
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')
rejection_reason = fields.Text(readonly=True, track_visibility='onchange')
@api.depends('reservation_ids')
def _compute_reservation_count(self):
for pack in self:
pack.reservation_count = len(pack.reservation_ids)
@api.depends('reservation_ids', 'reservation_ids.state')
def _compute_pack_state(self):
""" get pack state """
for pack in self:
if not pack.reservation_ids:
pack.state = 'draft'
else:
reservation_states = pack.mapped('reservation_ids.state')
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'
@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.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.constrains('reservation_ids')
def check_reservation_partner(self):
""" Check reservation partner """
for pack in self:
if len(pack.reservation_ids.mapped('partner_id')) > 1:
raise ValidationError(_('Pack partner should be the same for '
'all reservations'))

View File

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
""" 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.pack', 'Reservation Pack',
index=True)

View File

@ -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,1,1,0
access_golem_resource_pack_manager,Access GOLEM Resource Pack Manager,model_golem_resource_pack,golem_base.group_golem_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_golem_resource_pack_user Access GOLEM Resource Pack User model_golem_resource_pack golem_base.group_golem_user 1 1 1 0
3 access_golem_resource_pack_manager Access GOLEM Resource Pack Manager model_golem_resource_pack golem_base.group_golem_manager 1 1 1 1

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
from . import test_golem_resource_pack

View File

@ -0,0 +1,145 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
""" 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 = {
'name': 'Pack Test',
'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')

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
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 <http://www.gnu.org/licenses/>.
-->
<odoo>
<data>
<!-- Trees -->
<record model="ir.ui.view" id="golem_resource_pack_view_tree">
<field name="name">GOLEM Resource Pack Tree</field>
<field name="model">golem.resource.pack</field>
<field name="arch" type="xml">
<tree colors="black: state=='draft'; blue: state=='validated'; green : state=='validated'; grey: state=='canceled'; orange: state=='rejected'">
<field name="name" />
<field name="partner_id" />
<field name="state" />
<field name="reservation_count" />
</tree>
</field>
</record>
<!-- Forms -->
<record model="ir.ui.view" id="golem_resource_pack_view_form">
<field name="name">GOLEM Resource Pack Form</field>
<field name="model">golem.resource.pack</field>
<field name="arch" type="xml">
<form>
<header>
<button name="state_confirm" type="object" string="Confirm" class="oe_highlight"
attrs="{'invisible': ['|', ('state', 'not in', 'draft'), ('id', '=', False)]}" />
<button name="state_canceled" type="object"
string="Cancel" states="confirmed,validated" />
<button name="state_draft" type="object" string="Set to draft"
states="canceled,confirmed,validated,rejected" />
<button name="state_validated" type="object" string="Validate"
states="confirmed" class="oe_highlight"
groups="golem_base.group_golem_manager" />
<button name="state_rejected" type="object" string="Reject"
states="confirmed" class="oe_highlight"
groups="golem_base.group_golem_manager" />
<field name="state" widget="statusbar" />
</header>
<sheet>
<group>
<group name="general" string="Pack" colspan="2">
<field name="id" invisible="1"/>
<field name="user_id" />
<field name="partner_id" />
<field name="note" />
<field name="rejection_reason"
attrs="{'invisible': [('state', '!=', 'rejected')]}"/>
</group>
<group colspan="2" name="reservations">
<field name="reservation_ids" widget="many2many"
context="{'default_partner_id' : partner_id, 'default_pack_id': active_id, 'search_default_state_draft': 1, 'search_default_partner_id': partner_id}" />
</group>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" />
<field name="message_ids" widget="mail_thread" />
</div>
</form>
</field>
</record>
<!-- Actions -->
<act_window id="golem_resource_pack_action" name="Reservation Pack"
res_model="golem.resource.pack" view_mode="tree,form" />
<!-- Menus -->
<menuitem id="golem_resource_packs_menu" name="Reservation Packs"
parent="golem_resource.golem_resource_menu" action="golem_resource_pack_action"
sequence="20" />
</data>
</odoo>

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
from . import golem_pack_rejection

View File

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
""" 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()
rdata = {'state': 'rejected',
'rejection_reason': self[0].reason}
self[0].pack_id.reservation_ids.filtered(lambda r: r.state == 'confirmed').write(rdata)
self[0].pack_id.rejection_reason = self[0].reason

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
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 <http://www.gnu.org/licenses/>.
-->
<odoo>
<data>
<!-- Forms -->
<record model="ir.ui.view" id="golem_pack_rejection_wizard_view_form">
<field name="name">GOLEM Pack Rejection Wizard Form</field>
<field name="model">golem.pack.rejection.wizard</field>
<field name="arch" type="xml">
<form string="Rejection reason">
<sheet>
<group>
<field name="pack_id" readonly="1" />
<field name="reason" />
</group>
</sheet>
<footer>
<button name="reject" string="Reject" type="object"
class="oe_highlight" />
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
from . import models

View File

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
{
'name': 'GOLEM resources pack invoicing',
'summary': 'GOLEM resources pack invoicing',
'description': ''' GOLEM resources pack invoicing ''',
'version': '10.0.0.1.0',
'category': 'GOLEM',
'author': 'Youssef El Ouahby, Fabien Bourgeois',
'license': 'AGPL-3',
'application': False,
'installable': True,
'auto_install': True,
'depends': ['golem_resource_pack', 'golem_resource_account'],
'data': ['views/golem_resource_pack_views.xml']
}

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
from . import golem_resource_pack

View File

@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
""" 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')
are_products_set = fields.Boolean(compute="_compute_are_products_set")
@api.depends('reservation_ids.resource_product_id')
def _compute_are_products_set(self):
""" Computes are_products_set """
for pack in self:
pack.are_products_set = all([r.resource_product_id.id for r in pack.reservation_ids])
@api.multi
def chek_pack_to_invoice(self):
""" Cheks 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.are_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 """
self.chek_pack_to_invoice()
for pack in self:
pack.reservation_ids.check_before_invoicing()
partner_id = pack.partner_id
invoice_id = self.env['account.invoice'].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}

View File

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
from . import test_golem_pack_invoice

View File

@ -0,0 +1,115 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
# Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
#
# 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 <http://www.gnu.org/licenses/>.
""" 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 = {
'name': 'Pack test',
'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])

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018 Youssef El Ouahby <youssef@yaltik.com>
Copyright 2018 Fabien Bourgeois <fabien@yaltik.com>
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 <http://www.gnu.org/licenses/>.
-->
<odoo>
<data>
<!-- Tree -->
<record model="ir.ui.view" id="golem_resource_pack_inherit_account_tree">
<field name="name">GOLEM Resource Pack Account extention Tree</field>
<field name="model">golem.resource.pack</field>
<field name="inherit_id" ref="golem_resource_pack.golem_resource_pack_view_tree"/>
<field name="arch" type="xml">
<field name="reservation_count" position="after">
<field name="invoice_state" />
</field>
</field>
</record>
<!-- Forms -->
<record model="ir.ui.view" id="golem_resource_pack_inherit_account_form">
<field name="name">GOLEM Resource Pack Account extention Form</field>
<field name="model">golem.resource.pack</field>
<field name="inherit_id" ref="golem_resource_pack.golem_resource_pack_view_form"/>
<field name="arch" type="xml">
<button name="state_rejected" position="after">
<button name="create_invoice" type="object" string="Create Invoice" class="oe_highlight"
attrs="{'invisible': ['|', ('state', '!=', 'validated'), '|', ('invoice_id', '!=', False), ('are_products_set', '=', False)]}" />
<button name="show_invoice" type="object" string="Show invoice" class="oe_highlight"
attrs="{'invisible': [('invoice_id', '=', False)]}" />
</button>
<group name="general" position="after">
<group name="invoicing" string="Invoicing"
attrs="{'invisible': [('invoice_id', '=', False)]}">
<field name="are_products_set" invisible="1"/>
<field name="invoice_id" />
<field name="invoice_state" />
<field name="invoice_amount_total" />
</group>
</group>
</field>
</record>
</data>
</odoo>