# -*- 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 . """ 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)