X-Git-Url: http://git.inspyration.org/?a=blobdiff_plain;f=axes.py;h=84cf5c956e7da79968fc06758d19196168802c68;hb=2a083da23e74be5ac98cf7d5c8c3d743249515da;hp=7989c5bc3aaa429bcabf09fa99135ec671d1d3e6;hpb=5115fe3c592a50a93ff740ba11b8737cdedc68ef;p=OpenERP%2Fcmmi.git diff --git a/axes.py b/axes.py index 7989c5b..84cf5c9 100644 --- a/axes.py +++ b/axes.py @@ -3,67 +3,243 @@ ''' from openerp.osv import osv, fields +from datetime import date, timedelta, datetime - +# ================================ MESURABLE ================================ # class Mesurable(osv.Model): _name = "cmmi.axes.mesurable" - _statuts = [("cree", "Crée"), ("encours", "En cours"), + _description = "Table de reference des mesusrables." + + _states = [("cree", "Crée"), ("encours", "En cours"), ("termine", "Terminé"), ("abandonne", "Abandonné"), ("suspendu", "Suspendu"), ("generique", "Générique")] + def _nb_jours_init(self, cr, uid, ids, field, arg, context=None): + result = {} + for m in self.browse(cr, uid, ids, context=context): + if not m.date_init_deb or not m.date_init_fin: + result[m.id] = 0 + continue + result[m.id] = Mesurable._nb_jours_ouvre_entre_2_dates( + datetime.strptime(m.date_init_deb, "%Y-%m-%d").date(), + datetime.strptime(m.date_init_fin, "%Y-%m-%d").date()) + return result + _columns = { "name": fields.char(string="Title", size=64, required=True), "description": fields.text(string="Description"), "commentaire": fields.text(string="Commentaire"), - "statut": fields.selection(_statuts, string="Statut"), + "state": fields.selection(_states, string="State"), "version": fields.char(string="Version", size=16), "date_jalon": fields.date(string="Jalon"), - "date_init_deb": fields.date(string="Date initiale début"), - "date_init_fin": fields.date(string="Date initiale de fin"), - "date_plan_deb": fields.date(string="Date plannifiée début"), - "date_plan_fin": fields.date(string="Date plannifiée de fin"), - "date_reel_deb": fields.date(string="Data réelle début"), - "date_reel_fin": fields.date(string="Data réelle fin"), + "date_init_deb": fields.date(string="Init début"), + "date_init_fin": fields.date(string="Init fin"), + "date_plan_deb": fields.date(string="Plan début"), + "date_plan_fin": fields.date(string="Plan fin"), + "date_reel_deb": fields.date(string="Réel début"), + "date_reel_fin": fields.date(string="Réel fin"), + "nb_jours_initial": fields.function(_nb_jours_init, + type="integer", + string="Nombre de jour"), + } + + _defaults = { + "state": "cree", } _sql_constraints = [ ( "date_init_deb_before_date_init_fin", - "CHECK(date_init_deb<> date_init_fin)", + "CHECK(date_init_deb <= date_init_fin)", "The date_init_deb should be previous date_init_fin", ), ( "date_plan_deb_before_date_plan_fin", - "CHECK(date_plan_deb <> date_plan_fin)", + "CHECK(date_plan_deb <= date_plan_fin)", "The date_plan_deb should be previous date_plan_fin", ), ( "date_reel_deb_before_date_reel_fin", - "CHECK(date_reel_deb<> date_reel_fin)", + "CHECK(date_reel_deb <= date_reel_fin)", "The date_reel_deb should be previous date_reel_fin", ), ] -class Chantier(osv.Model): - _name = "cmmi.axes.chantier" + def action_commencer(self, cr, uid, ids, context=None): + if type(ids) == list: + if len(ids) != 1: + return + ids = ids[0] - _inherit = "cmmi.axes.mesurable" + palier = self.read(cr, uid, ids, ['date_plan_deb', 'date_plan_fin', 'state'], context) - _columns = { - "projet_id": fields.many2one("cmmi.projet", - string="Projet", - required=True), - "evolutions": fields.one2many("cmmi.evolution", - "chantier_id", - string="Evolutions"), - } + if palier['state'] != 'cree': + return + + self.write( + cr, + uid, + ids, { + 'date_init_deb' : palier['date_plan_deb'], + 'date_init_fin' : palier['date_plan_fin'], + 'state': 'encours' + }, + context) + return self + + + def action_suspendre(self, cr, uid, ids, context=None): + if type(ids) == list: + if len(ids) != 1: + return # TODO: message d'avertissement + ids = ids[0] + mesurable = self.read(cr, uid, ids, ['state'], context) + if mesurable['state'] != 'encours': + return + self.write( + cr, + uid, + ids, + {'state': 'suspendu'}, + context, + ) + return self + def action_terminer(self, cr, uid, ids, context=None): + if type(ids) == list: + if len(ids) != 1: + return # TODO: message d'avertissement + ids = ids[0] + + mesurable = self.read(cr, uid, ids, ['state'], context) + if mesurable['state'] != 'encours': + return + self.write( + cr, + uid, + ids, + {'state': 'termine'}, + context, + ) + return self + + def action_abandonner(self, cr, uid, ids, context=None): + if type(ids) == list: + if len(ids) != 1: + return # TODO: message d'avertissement + ids = ids[0] + + mesurable = self.read(cr, uid, ids, ['state'], context) + if not ('encours', 'cree').__contains__(mesurable['state']): + return + self.write( + cr, + uid, + ids, + {'state': 'abandonne'}, + context, + ) + return self + + def action_reprendre(self, cr, uid, ids, context=None): + if type(ids) == list: + if len(ids) != 1: + return # TODO: message d'avertissement + ids = ids[0] + + mesurable = self.read(cr, uid, ids, ['state'], context) + if mesurable['state'] != 'suspendu': + return + self.write( + cr, + uid, + ids, + {'state': 'encours'}, + context, + ) + return self + +#------------ TRAVAIL CALCUL JOURS OUVRES ------------ + @staticmethod + def _get_date_paques(annee): + """ + Retourne la date du dimanque de pâques pour une année donnée + sous la forme d'un objet date. + """ + a = annee % 19 + b = annee // 100 + c = annee % 100 + d = (19 * a + b - b // 4 - ((b - (b + 8) // 25 + 1) // 3) + 15) % 30 + e = (32 + 2 * (b % 4) + 2 * (c // 4) - d - (c % 4)) % 7 + f = d + e - 7 * ((a + 11 * d + 22 * e) // 451) + 114 + mois = f // 31 + jours = f % 31 + 1 + return date(annee, mois, jours) + + + @staticmethod + def _get_jours_feries(annee): + """ + Retourne une liste contenant les jours fériés d'une année donnée. + """ + date_paques = Mesurable._get_date_paques(annee) + return [ + date_paques+timedelta(days=1), # Lundi de Pâques + date_paques+timedelta(days=39), # Jeudi de l'Ascension + date_paques+timedelta(days=50), # Lundi de Pentecôte + date(annee, 1, 1), # Jour de l'An + date(annee, 5, 1), # Fête du travail + date(annee, 5, 8), # Armistice 1945 + date(annee, 7, 14), # Fête Nationale + date(annee, 8, 15), # Assomption + date(annee, 11, 1), # Toussaint + date(annee, 11, 11), # Armistice 1918 + date(annee, 12, 25), # Noël + ] + + + @staticmethod + def _jour_ouvre(d): + """ Retourne vrai si la date est un jour ouvre, faux sinon.""" + if (5,6).__contains__(d.weekday()) or Mesurable._get_jours_feries(d.year).__contains__(d): + return False + else: + return True + + + @staticmethod + def _nb_jours_ouvre_entre_2_dates(d1, d2): + """ + Retourne le nombre de jours ouvres entre deux dates données. + + >>> nb_jours_ouvre_entre_2_dates(date(2013, 5, 1), date(2013, 7, 31)) + 62 + >>> nb_jours_ouvre_entre_2_dates(date(2013, 7, 31), date(2013, 5, 1)) + 62 + """ + if not d1 or not d2: + return 0 + if d1>d2: + d1, d2 = d2, d1 #Switch les 2 dates pour que d1 soit la plus petite + tmp = d1 + jour_ouvres = 0 + while tmp <= d2: + if Mesurable._jour_ouvre(tmp): # Si tmp est un jour ouvre + jour_ouvres += 1 + tmp += timedelta(days=1) + return jour_ouvres + + + +# ================================= PALIER ================================== # class Palier(osv.Model): _name = "cmmi.axes.palier" + _description = "Palier d'un projet." + _inherit = "cmmi.axes.mesurable" _types_palier = [("normal", "Normal"), ("exceptionnel", "Exceptionnel"), @@ -77,7 +253,105 @@ class Palier(osv.Model): "evolutions": fields.one2many("cmmi.evolution", "palier_id", string="Evolutions"), - "phases": fields.one2many("cmmi.phase", + "phases": fields.one2many("cmmi.axes.palier.phase", "palier_id", string="Phases"), } + + _defaults = { + "type_palier": "normal", + } + + + def create(self, cr, uid, vals, context=None): + palier_id = osv.Model.create(self, cr, uid, vals, context=context) + + # Récupération des ids de toutes les phases + phase_model = self.pool.get("cmmi.projet.phase") + phases_ids = phase_model.search(cr, uid, [('selectionne', '=', True)]) + + palier_model = self.pool.get("cmmi.axes.palier") + palier = palier_model.read(cr, uid, palier_id, ['date_plan_deb', 'date_plan_fin']) + + # Création des PalierPhase + palier_phase_model = self.pool.get("cmmi.axes.palier.phase") + for phase_id in phases_ids: + palier_phase_model.create( + cr, + uid, + { + 'phase_id': phase_id, + 'palier_id': palier_id, + 'date_plan_deb': palier['date_plan_deb'], + 'date_plan_fin': palier['date_plan_fin'], + } + ) + return palier_id + + + +# =============================== PALIER-PHASE ============================== # +class PalierPhase(osv.Model): + _name = "cmmi.axes.palier.phase" + + _description = "Phase d'un palier" + + _inherit = "cmmi.axes.mesurable" + + def _get_name(self, cr, uid, ids, field_name=None, arg=None, context=None): + if isinstance(ids, (int, long)): + ids = [ids] + return dict([(i, r.phase_id.name) for i, r in + zip(ids, self.browse(cr, uid, ids, context=context))]) + + + _columns = { + "name": fields.function(_get_name, + type='char', + store=True, + string="Nom de la phase"), + "phase_id": fields.many2one("cmmi.projet.phase", + string="Phase du projet"), + "palier_id": fields.many2one("cmmi.axes.palier", + string="Palier"), + # backrefs + "charges": fields.one2many("cmmi.evolution.charge", + "phase_id", + string="Charges"), +# "evolutions": fields.one2many("cmmi.evolution", #Supprimé ! +# "phase_id", +# string="Evolutions"), + } + + def create(self, cr, uid, vals, context=None): + # TODO: gérer la création d'une phase de palier. + # Vérifier les valeurs contenues dans vals et les modifier / rajouter si nécessaire selon les cas suivants + + # Si description est vide, alors par défaut, recopie de la description du palier et de la phase (concaténés avec un retour à la ligne entre les deux). + # Si commentaire est vide, alors par défaut, recopie du commentaire du palier. + # Si version est vide, alors par dégaut, recopie de la version du palier. + + return osv.Model.create(self, cr, uid, vals, context=context) + + +# ================================ CHANTIER ================================= # +class Chantier(osv.Model): + _name = "cmmi.axes.chantier" + + _description = "Chantiers d'un projet." + + _inherit = "cmmi.axes.mesurable" + + _columns = { + "projet_id": fields.many2one("cmmi.projet", + string="Projet", + required=True), + "module_ids": fields.many2many("cmmi.description.module", + "cmmi_module_chantier_rel", + "chantier_id", + "module_id", + "Modules"), + "evolutions": fields.one2many("cmmi.evolution", + "chantier_id", + string="Evolutions"), + }