239 lines
12 KiB
Python
239 lines
12 KiB
Python
|
# -*- 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/>.
|
||
|
|
||
|
""" Grant File Management"""
|
||
|
|
||
|
from odoo import models, fields, api, _
|
||
|
from odoo.exceptions import ValidationError
|
||
|
|
||
|
|
||
|
class GrantFile(models.Model):
|
||
|
""" Grant File Management """
|
||
|
_name = 'grant.file'
|
||
|
_inherit = 'mail.thread'
|
||
|
_order = 'significance desc, reply_deadline asc, state asc'
|
||
|
_rec_name = 'title'
|
||
|
|
||
|
title = fields.Char(required=True, index=True, readonly=True,
|
||
|
states={'1_draft': [('readonly', False)],
|
||
|
'3_edited': [('readonly', False)]})
|
||
|
description = fields.Text()
|
||
|
note = fields.Text()
|
||
|
partner_id = fields.Many2one('res.partner', index=True, readonly=True,
|
||
|
auto_join=True, string='Main partner',
|
||
|
states={'1_draft': [('readonly', False)],
|
||
|
'3_edited': [('readonly', False)]})
|
||
|
partner_ids = fields.Many2many(
|
||
|
'res.partner', index=True, auto_join=True,
|
||
|
readonly=True, string='Other partners',
|
||
|
states={'1_draft': [('readonly', False)],
|
||
|
'3_edited': [('readonly', False)],
|
||
|
'4_grant_notification': [('readonly', False)]})
|
||
|
display_partner_ids = fields.Char(compute='_compute_display_partner_ids')
|
||
|
responsible_id = fields.Many2one('res.users', string='Responsible',
|
||
|
auto_join=True, index=True,
|
||
|
default=lambda self: self.env.user)
|
||
|
reply_deadline = fields.Date(index=True, readonly=True,
|
||
|
states={'1_draft': [('readonly', False)],
|
||
|
'3_edited': [('readonly', False)]})
|
||
|
assessment_deadline = fields.Date(index=True, readonly=True,
|
||
|
states={'1_draft': [('readonly', False)],
|
||
|
'3_edited': [('readonly', False)],
|
||
|
'4_grant_notification': [('readonly', False)]})
|
||
|
significance = fields.Selection([('0', 'Not evaluated'),
|
||
|
('1', 'Common'),
|
||
|
('2', 'Medium'),
|
||
|
('3', 'High'),
|
||
|
('4', 'Critical')],
|
||
|
default='0', copy=False)
|
||
|
|
||
|
state = fields.Selection([('0_refused', 'Refused'),
|
||
|
('1_draft', 'Draft'),
|
||
|
('2_sent', 'Sent'),
|
||
|
('3_edited', 'Edited'),
|
||
|
('4_grant_notification', 'Grant Notification'),
|
||
|
('6_first_paiement_received', 'First Paiement Received'),
|
||
|
('7_finished', 'Finished')],
|
||
|
default='1_draft', copy=False, track_visibility='onchange')
|
||
|
|
||
|
requested_amount = fields.Monetary(readonly=True, required=True,
|
||
|
states={'1_draft': [('readonly', False)],
|
||
|
'3_edited': [('readonly', False)]})
|
||
|
notified_amount = fields.Monetary(readonly=True, copy=False,
|
||
|
states={'4_grant_notification': [('readonly', False),
|
||
|
('required', True)]})
|
||
|
received_amount = fields.Monetary(readonly=False, copy=False,
|
||
|
track_visibility='onchange',
|
||
|
states={'0_refused': [('readonly', True)],
|
||
|
'1_draft': [('readonly', True)],
|
||
|
'7_finished': [('readonly', True)]})
|
||
|
currency_id = fields.Many2one('res.currency', string='Currency',
|
||
|
required=True, auto_join=True,
|
||
|
default=lambda self: self.env.user.company_id.currency_id)
|
||
|
amount_line_ids = fields.One2many('grant.file.amount.line', 'file_id',
|
||
|
string='Amount lines')
|
||
|
|
||
|
assessment_sent = fields.Boolean('Has assessment been sent ?', readonly=True,
|
||
|
copy=False, track_visibility='onchange')
|
||
|
|
||
|
color = fields.Integer('Color Index')
|
||
|
attachment_ids = fields.One2many(
|
||
|
'ir.attachment', 'res_id', string='Attachments', auto_join=True,
|
||
|
domain=[('res_model', '=', 'grant.file')])
|
||
|
doc_count = fields.Integer(compute='_compute_doc_count')
|
||
|
|
||
|
@api.depends('partner_ids')
|
||
|
def _compute_display_partner_ids(self):
|
||
|
""" Computes display partners """
|
||
|
for gfile in self:
|
||
|
if gfile.partner_ids:
|
||
|
gfile.display_partner_ids = u', '.join(gfile.partner_ids.mapped('name'))
|
||
|
else:
|
||
|
gfile.display_partner_ids = u''
|
||
|
|
||
|
@api.depends('attachment_ids')
|
||
|
def _compute_doc_count(self):
|
||
|
""" Computes doc count """
|
||
|
for gfile in self:
|
||
|
gfile.doc_count = len(gfile.attachment_ids)
|
||
|
|
||
|
@api.multi
|
||
|
def state_refused(self):
|
||
|
""" Updates state to refused """
|
||
|
self.write({'state': '0_refused'})
|
||
|
|
||
|
@api.multi
|
||
|
def state_draft(self):
|
||
|
""" Updates state to draft """
|
||
|
self.write({'state': '1_draft'})
|
||
|
|
||
|
@api.multi
|
||
|
def state_sent(self):
|
||
|
""" Updates state to sent """
|
||
|
self.write({'state': '2_sent'})
|
||
|
|
||
|
@api.multi
|
||
|
def state_grant_notification(self):
|
||
|
""" Updates state to notidication granted """
|
||
|
self.write({'state': '4_grant_notification'})
|
||
|
|
||
|
@api.multi
|
||
|
def sent_assessment(self):
|
||
|
""" Updates state to Assessment sent to True """
|
||
|
for gfile in self:
|
||
|
if gfile.state not in ('4_grant_notification',
|
||
|
'6_first_paiement_received', '7_finished'):
|
||
|
verr = _('You can only mark assessment as sent when grant had '
|
||
|
'been notified.')
|
||
|
raise ValidationError(verr)
|
||
|
self.write({'assessment_sent': True})
|
||
|
|
||
|
@api.multi
|
||
|
def unsent_assessment(self):
|
||
|
""" Updates state to Assessment sent to False """
|
||
|
self.write({'assessment_sent': False})
|
||
|
|
||
|
@api.multi
|
||
|
def state_edit(self):
|
||
|
""" Wizard to enter update reason """
|
||
|
self.ensure_one()
|
||
|
grant_file_id = self[0]
|
||
|
return {'name': _('Please enter the update reason'),
|
||
|
'type': 'ir.actions.act_window',
|
||
|
'res_model': 'grant.file.edit.wizard',
|
||
|
'context': {'default_grant_file_id': grant_file_id.id},
|
||
|
'view_mode': 'form',
|
||
|
'target': 'new'}
|
||
|
|
||
|
@api.constrains('requested_amount', 'notified_amount')
|
||
|
def check_notified_amount(self):
|
||
|
""" Checks notified amount is filled, according to file state """
|
||
|
for gfile in self:
|
||
|
if not gfile.requested_amount or gfile.requested_amount <= 0.0:
|
||
|
verr = _('You must enter a signed requested amount.')
|
||
|
raise ValidationError(verr)
|
||
|
if gfile.state == '4_grant_notification' and gfile.notified_amount <= 0.0:
|
||
|
verr = _('You must enter a signed notified amount.')
|
||
|
raise ValidationError(verr)
|
||
|
|
||
|
@api.constrains('received_amount')
|
||
|
def check_received_amount(self):
|
||
|
""" Check received amount to finish application """
|
||
|
for grant in self:
|
||
|
if grant.received_amount:
|
||
|
if 0 < grant.received_amount < grant.notified_amount:
|
||
|
grant.write({'state': '6_first_paiement_received'}, bypass=True)
|
||
|
elif grant.received_amount and \
|
||
|
(grant.received_amount == grant.notified_amount):
|
||
|
grant.write({'state': '7_finished'}, bypass=True)
|
||
|
else:
|
||
|
verr = _('Operation not allowed, received amount should be a '
|
||
|
'value between 0 and notified amount')
|
||
|
raise ValidationError(verr)
|
||
|
|
||
|
@api.constrains('amount_line_ids')
|
||
|
def check_amount_details(self):
|
||
|
""" Checks coherence between declared amounts and details """
|
||
|
for gfile in self:
|
||
|
if gfile.amount_line_ids:
|
||
|
if gfile.notified_amount != sum(gfile.amount_line_ids.mapped('notified_amount')):
|
||
|
verr = _('Sum of notified amounts on amount details is not '
|
||
|
'the same as global notified amount. Please check '
|
||
|
'your fills.')
|
||
|
raise ValidationError(verr)
|
||
|
if gfile.received_amount != sum(gfile.amount_line_ids.mapped('received_amount')):
|
||
|
verr = _('Sum of received amounts on amount details is not '
|
||
|
'the same as global received amount. Please check '
|
||
|
'your fills.')
|
||
|
raise ValidationError(verr)
|
||
|
|
||
|
@api.multi
|
||
|
def write(self, vals, bypass=False):
|
||
|
""" Check state update coherence """
|
||
|
notified_val = vals.get('notified_amount', 0.0)
|
||
|
if notified_val <= 0.0:
|
||
|
self.check_notified_amount()
|
||
|
if 'state' in vals:
|
||
|
vstate = vals.get('state')
|
||
|
for gfile in self:
|
||
|
if vstate == '0_refused' and gfile.state not in ('2_sent', '3_edited'):
|
||
|
verr = _('You are only allowed to update to refused from '
|
||
|
'sent or edited states.')
|
||
|
raise ValidationError(verr)
|
||
|
elif vstate == '1_draft' and gfile.state not in ('2_sent', '0_refused'):
|
||
|
verr = _('You are only allowed to update to draft from sent '
|
||
|
'or refused states.')
|
||
|
raise ValidationError(verr)
|
||
|
elif vstate == '2_sent' and gfile.state != '1_draft':
|
||
|
verr = _('You are only allowed to update to sent state from draft.')
|
||
|
raise ValidationError(verr)
|
||
|
elif vstate == '3_edited' and gfile.state not in ('2_sent', '3_edited'):
|
||
|
verr = _('You are only allowed to update to edit from sent '
|
||
|
'or edit states.')
|
||
|
raise ValidationError(verr)
|
||
|
elif vstate == '4_grant_notification' and \
|
||
|
gfile.state not in ('2_sent', '3_edited'):
|
||
|
verr = _('You are only allowed to update to notidied from '
|
||
|
'sent or edit states.')
|
||
|
raise ValidationError(verr)
|
||
|
elif vstate in ('6_first_paiement_received', '7_finished') and not bypass:
|
||
|
verr = _('You can not change manually to paid or finished '
|
||
|
'state : fill received amount to achieve this.')
|
||
|
raise ValidationError(verr)
|
||
|
return super(GrantFile, self).write(vals)
|