evolution.charge : ajout de nouveaux champs date et quantité
[OpenERP/cmmi.git] / axes.py
diff --git a/axes.py b/axes.py
index 3236651..23437c1 100644 (file)
--- a/axes.py
+++ b/axes.py
 from openerp.osv import osv, fields
 from datetime import date, timedelta, datetime
 
 from openerp.osv import osv, fields
 from datetime import date, timedelta, datetime
 
-
+# ================================ MESURABLE ================================ #
 class Mesurable(osv.Model):
     _name = "cmmi.axes.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")]
 
                 ("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):
     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
 
             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
 
+
+    def _nb_jours_plan(self, cr, uid, ids, field, arg, context=None):
+        result = {}
+        for m in self.browse(cr, uid, ids, context=context):
+            if not m.date_plan_deb or not m.date_plan_fin:
+                result[m.id] = 0
+                continue
+            result[m.id] = Mesurable._nb_jours_ouvre_entre_2_dates(
+                        datetime.strptime(m.date_plan_deb, "%Y-%m-%d").date(),
+                        datetime.strptime(m.date_plan_fin, "%Y-%m-%d").date())
+        return result
+
+
+    def _nb_jours_reel(self, cr, uid, ids, field, arg, context=None):
+        result = {}
+        for m in self.browse(cr, uid, ids, context=context):
+            if not m.date_reel_deb or not m.date_reel_fin:
+                result[m.id] = 0
+                continue
+            result[m.id] = Mesurable._nb_jours_ouvre_entre_2_dates(
+                        datetime.strptime(m.date_reel_deb, "%Y-%m-%d").date(),
+                        datetime.strptime(m.date_reel_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"),
     _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"),
         "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"),
-        "nb_jours_projets": fields.function(_nb_jours_init,
-                                            type="integer",
-                                            string="Nombre de jour"),
+        "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_init": fields.function(_nb_jours_init,
+                                         type="integer",
+                                         string="Nombre de jours initials"),
+        "nb_jours_plan": fields.function(_nb_jours_plan,
+                                         type="integer",
+                                         string="Nombre de jours planifiés"),
+        "nb_jours_reel": fields.function(_nb_jours_reel,
+                                         type="integer",
+                                         string="Nombre de jours réels"),
+    }
+
+    _defaults = {
+        "state": "cree",
     }
 
     _sql_constraints = [
         (
             "date_init_deb_before_date_init_fin",
     }
 
     _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",
             "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",
             "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",
         ),
     ]
 
 
             "The date_reel_deb should be previous date_reel_fin",
         ),
     ]
 
 
-#=============== TODO TRAVAIL CALCUL JOURS OUVRES =============================
+    def action_commencer(self, cr, uid, ids, context=None):
+        if type(ids) == list:
+            if len(ids) != 1:
+                return
+            ids = ids[0]
+
+        palier = self.read(cr, uid, ids, ['date_plan_deb', 'date_plan_fin', 'state'], context)
+
+        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
     @staticmethod
-    def _get_date_paques(annee): # TODO vérifier le besoin de self
+    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.
         """
         Retourne la date du dimanque de pâques pour une année donnée
             sous la forme d'un objet date.
@@ -117,6 +252,8 @@ class Mesurable(osv.Model):
         >>> nb_jours_ouvre_entre_2_dates(date(2013, 7, 31), date(2013, 5, 1))
         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
         if d1>d2:
             d1, d2 = d2, d1 #Switch les 2 dates pour que d1 soit la plus petite
         tmp = d1
@@ -127,41 +264,191 @@ class Mesurable(osv.Model):
             tmp += timedelta(days=1)
         return jour_ouvres
 
             tmp += timedelta(days=1)
         return jour_ouvres
 
-#==============================================================================
 
 
 
 
-class Chantier(osv.Model):
-    _name = "cmmi.axes.chantier"
+# ================================= PALIER ================================== #
+class Palier(osv.Model):
+    _name = "cmmi.axes.palier"
+
+    _description = "Palier d'un projet."
 
     _inherit = "cmmi.axes.mesurable"
 
 
     _inherit = "cmmi.axes.mesurable"
 
+    _types_palier = [("normal", "Normal"), ("exceptionnel", "Exceptionnel"),
+                     ("correctif", "Correctif"), ("autre", "Autre")]
+
+
+    def _get_charge_init(self, cr, uid, ids, field, arg, context=None):
+        result = {}
+        for palier in self.browse(cr, uid, ids, context=context):
+            result[palier.id] = sum([e.charge_init for e in palier.evolutions])
+        return result
+
+
+    def _get_charge_plan(self, cr, uid, ids, field, arg, context=None):
+        result = {}
+        for palier in self.browse(cr, uid, ids, context=context):
+            result[palier.id] = sum([e.charge_plan for e in palier.evolutions])
+        return result
+
+
     _columns = {
     _columns = {
+        "type_palier": fields.selection(_types_palier, string="Type"),
         "projet_id": fields.many2one("cmmi.projet",
                                      string="Projet",
                                      required=True),
         "evolutions": fields.one2many("cmmi.evolution",
         "projet_id": fields.many2one("cmmi.projet",
                                      string="Projet",
                                      required=True),
         "evolutions": fields.one2many("cmmi.evolution",
-                                      "chantier_id",
+                                      "palier_id",
                                       string="Evolutions"),
                                       string="Evolutions"),
+        "phases": fields.one2many("cmmi.axes.palier.phase",
+                                  "palier_id",
+                                  string="Phases"),
+        "charge_init": fields.function(_get_charge_init,
+                                       type="integer",
+                                       string="Charge initiale"),
+        "charge_plan": fields.function(_get_charge_plan,
+                                       type="integer",
+                                       string="Charge plannifiée"),
     }
 
     }
 
+    _defaults = {
+        "type_palier": "normal",
+    }
 
 
-class Palier(osv.Model):
-    _name = "cmmi.axes.palier"
+
+    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"
 
 
     _inherit = "cmmi.axes.mesurable"
 
-    _types_palier = [("normal", "Normal"), ("exceptionnel", "Exceptionnel"),
-                     ("correctif", "Correctif"), ("autre", "Autre")]
+    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))])
+
+
+    def _get_charge_init(self, cr, uid, ids, field, arg, context=None):
+        result = {}
+        for pp in self.browse(cr, uid, ids, context=context):
+            result[pp.id] = sum([p.charge_init for p in pp.phases])
+        return result
+
+
+    def _get_charge_plan(self, cr, uid, ids, field, arg, context=None):
+        result = {}
+        for pp in self.browse(cr, uid, ids, context=context):
+            result[pp.id] = sum([p.charge_plan for p in pp.phases])
+        return result
+
+
+    _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"),
+        "charge_init": fields.function(_get_charge_init,
+                                       type="integer",
+                                       string="Charge initiale"),
+        "charge_plan": fields.function(_get_charge_plan,
+                                       type="integer",
+                                       string="Charge plannifiée"),
+        # backrefs
+        "charges": fields.one2many("cmmi.evolution.charge",
+                                   "phase_id",
+                                   string="Charges"),
+        "phases": fields.one2many("cmmi.evolution.phase",
+                                  "phase_id",
+                                  string="Phases"),
+#        "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"
+
+
+    def _get_charge_init(self, cr, uid, ids, field, arg, context=None):
+        result = {}
+        for chantier in self.browse(cr, uid, ids, context=context):
+            result[chantier.id] = sum([e.charge_init for e in chantier.evolutions])
+        return result
+
+
+    def _get_charge_plan(self, cr, uid, ids, field, arg, context=None):
+        result = {}
+        for chantier in self.browse(cr, uid, ids, context=context):
+            result[chantier.id] = sum([e.charge_plan for e in chantier.evolutions])
+        return result
+
 
     _columns = {
 
     _columns = {
-        "type_palier": fields.selection(_types_palier, string="Type"),
         "projet_id": fields.many2one("cmmi.projet",
                                      string="Projet",
                                      required=True),
         "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",
         "evolutions": fields.one2many("cmmi.evolution",
-                                      "palier_id",
+                                      "chantier_id",
                                       string="Evolutions"),
                                       string="Evolutions"),
-        "phases": fields.one2many("cmmi.phase",
-                                  "palier_id",
-                                  string="Phases"),
+        "charge_init": fields.function(_get_charge_init,
+                                       type="integer",
+                                       string="Charge initiale"),
+        "charge_plan": fields.function(_get_charge_plan,
+                                       type="integer",
+                                       string="Charge plannifiée"),
     }
     }