]> git.parisson.com Git - mezzo.git/commitdiff
[Timesheet] : project import + model updates
authorEmilie Zawadzki <zawadzki@ircam.fr>
Fri, 6 Jan 2017 16:41:59 +0000 (17:41 +0100)
committerEmilie Zawadzki <zawadzki@ircam.fr>
Fri, 6 Jan 2017 16:41:59 +0000 (17:41 +0100)
app/organization/network/management/commands/import-ircam-project.py [new file with mode: 0644]
app/organization/network/management/commands/import-ircam-timesheet-xls.py
app/organization/network/migrations/0078_auto_20170106_1142.py [new file with mode: 0644]
app/organization/network/migrations/0079_auto_20170106_1149.py [new file with mode: 0644]
app/organization/network/migrations/0080_auto_20170106_1642.py [new file with mode: 0644]
app/organization/network/migrations/0081_auto_20170106_1645.py [new file with mode: 0644]
app/organization/projects/migrations/0035_auto_20170106_1149.py [new file with mode: 0644]
app/organization/projects/migrations/0036_auto_20170106_1645.py [new file with mode: 0644]
app/organization/projects/models.py

diff --git a/app/organization/network/management/commands/import-ircam-project.py b/app/organization/network/management/commands/import-ircam-project.py
new file mode 100644 (file)
index 0000000..9436201
--- /dev/null
@@ -0,0 +1,204 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2016-2017 Ircam
+# Copyright (c) 2016-2017 Guillaume Pellerin
+# Copyright (c) 2016-2017 Emilie Zawadzki
+
+# This file is part of mezzanine-organization.
+
+# 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/>.
+
+import os
+import sys
+import csv
+import re
+import logging
+import datetime
+from optparse import make_option
+import xlrd
+from itertools import takewhile
+from re import findall
+import dateutil.parser
+# from string import split
+from django.conf import settings
+from django.core.management.base import BaseCommand, CommandError
+from django.contrib.auth.models import User
+from django.db.models import Q
+
+from organization.core.models import *
+from organization.network.models import *
+from organization.projects.models import *
+
+
+class Logger:
+
+    def __init__(self, file):
+        self.logger = logging.getLogger('myapp')
+        self.hdlr = logging.FileHandler(file)
+        self.formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
+        self.hdlr.setFormatter(self.formatter)
+        self.logger.addHandler(self.hdlr)
+        self.logger.setLevel(logging.INFO)
+
+    def info(self, prefix, message):
+        self.logger.info(' ' + prefix + ' : ' + message)
+
+    def error(self, prefix, message):
+        self.logger.error(prefix + ' : ' + message)
+
+
+def get_instance(model, field, value):
+    models = model.objects.filter(field=value)
+    if models:
+        return models[0]
+    else:
+        model = model()
+        model.field = value
+        return model
+
+
+class IrcamXLS:
+
+    sheet_id = 0
+    project_table_1_first_row = 12
+    project_table_1_last_row = 25
+    project_table_2_first_row = 34
+    project_table_2_last_row = 89
+    nb_col_max = 9
+    nb_col_min = 0
+    avoid_col = 3
+
+    def __init__(self, file):
+        self.sheet = self.book.sheet_by_index(self.sheet_id)
+
+
+class IrcamProjects(object):
+
+    def __init__(self, project_name):
+        project, is_created = Project.object.get_or_create(title__icontains=project_name)
+        self.project = project
+        self.is_created = is_created
+
+
+    def set_external_id(self, external_id):
+        if external_id and not self.project.external_id:
+            external_id = re.sub(r'((\s)*(-)(\s)*)|(\s)', '-', external_id)
+            self.project.external_id = external_id
+
+
+    def set_call_project(self, call):
+        if call and not self.project.call:
+            self.project.call = ProjectCall.objects.get_or_create(name__icontains=call)
+
+
+    def set_date_from(self, date_from):
+        if date_from and not self.project.date_from:
+            self.project.date_from = date_from
+
+
+    def set_date_to(self, date_to):
+        if date_to and not self.project.date_to:
+            self.project.date_to = date_to
+
+
+    def set_lead_organization(self, lead_organization):
+        if lead_organization and not self.project.lead_organization:
+            self.project.lead_organization.add(Organization.objects.get_or_create(title__icontains=lead_organization))
+
+
+    def set_referring_person(self, referring_person):
+        if referring_person and not self.project.referring_person:
+            referring_person_list = re.split(r'(\s)*/(\s)*', referring_person)
+            person_list = ()
+            for rp in referring_person_list:
+                rp_whole_name = re.split(r'(\s)*', rp)
+                last_name = max(rp_whole_name, key=len)
+                self.project.referring_person.add(Person.objects.get_or_create(last_name__icontains=last_name))
+
+
+    def set_teams(self, lead_teams):
+        if lead_teams and not self.project.lead_team:
+            lead_teams_list = re.split(r'(\s)*(,|/)(\s)*', lead_teams)
+                self.project.lead_team.add(lead_teams)
+
+
+    def set_manager(self, manager):
+        if manager:
+            if not self.project.manager:
+                self.project.manager = Person.objects.get_or_create(last_name__icontains=manager)
+
+
+    def save_project():
+        self.project.save()
+
+
+class Command(BaseCommand):
+    help = """Import Person data from IRCAM's legacy XLS management file.
+              python manage.py import-ircam-timesheet-xls -s /srv/backup/TemplateInputTimeSheet2015-16.xlsx
+    """
+
+    option_list = BaseCommand.option_list + (
+          make_option('-d', '--dry-run',
+            action='store_true',
+            dest='dry-run',
+            help='Do NOT write anything'),
+          make_option('-f', '--force',
+            action='store_true',
+            dest='force',
+            help='Force overwrite data'),
+          make_option('-s', '--source',
+            dest='source_file',
+            help='define the XLS source file'),
+          make_option('-l', '--log',
+            dest='log',
+            help='define log file'),
+    )
+
+    def handle(self, *args, **kwargs):
+        self.logger = Logger(kwargs.get('log'))
+        self.pattern = kwargs.get('pattern')
+        self.source_file = os.path.abspath(kwargs.get('source_file'))
+        self.dry_run =  kwargs.get('dry-run')
+        self.force = kwargs.get('force')
+
+        xls = IrcamXLS(self.source_file)
+
+        # Table 1
+        for row_index in range(xls.project_table_1_first_row, xls.project_table_1_last_row):
+
+            ip = IrcamProjects(sheet.cell_value(0, row_index))
+            ip.set_external_id(sheet.cell_value(1, row_index))
+            ip.set_call_project(sheet.cell_value(2, row_index))
+            ip.set_date_from(xlrd.xldate.xldate_as_datetime(sheet.cell_value(4, row_index)), 1))
+            ip.set_date_to(xlrd.xldate.xldate_as_datetime(sheet.cell_value(5, row_index))
+            ip.set_lead_organization(sheet.cell_value(6, row_index))
+            ip.set_referring_person(sheet.cell_value(7, row_index))
+            ip.set_teams(sheet.cell_value(8, row_index))
+            ip.set_manager(sheet.cell_value(9, row_index))
+            ip.save_project()
+
+
+        # Table 2
+        for row_index in range(xls.project_table_2_first_row, xls.project_table_2_last_row):
+
+            ip = IrcamProjects(sheet.cell_value(0, row_index))
+            ip.set_external_id(sheet.cell_value(1, row_index))
+            ip.set_call_project(sheet.cell_value(2, row_index))
+            ip.set_date_from(xlrd.xldate.xldate_as_datetime(sheet.cell_value(4, row_index), 1))
+            ip.set_date_to(xlrd.xldate.xldate_as_datetime(sheet.cell_value(5, row_index), 1))
+            ip.set_lead_organization(sheet.cell_value(6, row_index))
+            ip.set_referring_person(sheet.cell_value(7, row_index))
+            ip.set_teams(sheet.cell_value(8, row_index))
+            ip.set_manager(sheet.cell_value(9, row_index))
+            ip.save_project()
index 11ea39824778193fc92eb208a2ad0592bd3d257a..7e5a44e3ba274ff1628a336fc996bcba549e580f 100644 (file)
@@ -250,4 +250,4 @@ class Command(BaseCommand):
                             pat.validation = date_validation
                             pat.save()
 
-                self.logger.info('Processing', '_________________________ Number of record : ' + str(processing_counter) + ' _________________________')                
+                self.logger.info('Processing', '_________________________ Number of record : ' + str(processing_counter) + ' _________________________')
diff --git a/app/organization/network/migrations/0078_auto_20170106_1142.py b/app/organization/network/migrations/0078_auto_20170106_1142.py
new file mode 100644 (file)
index 0000000..08c1163
--- /dev/null
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.11 on 2017-01-06 10:42
+from __future__ import unicode_literals
+
+import datetime
+from django.db import migrations, models
+from django.utils.timezone import utc
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organization-network', '0077_auto_20170104_1837'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='personactivitytimesheet',
+            name='accounting',
+            field=models.DateField(blank=True, default=datetime.datetime(2017, 1, 6, 10, 40, 49, 573524, tzinfo=utc)),
+        ),
+        migrations.AlterField(
+            model_name='personactivitytimesheet',
+            name='validation',
+            field=models.DateField(blank=True, default=datetime.datetime(2017, 1, 6, 10, 40, 49, 573558, tzinfo=utc)),
+        ),
+    ]
diff --git a/app/organization/network/migrations/0079_auto_20170106_1149.py b/app/organization/network/migrations/0079_auto_20170106_1149.py
new file mode 100644 (file)
index 0000000..e3c17f8
--- /dev/null
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.11 on 2017-01-06 10:49
+from __future__ import unicode_literals
+
+import datetime
+from django.db import migrations, models
+from django.utils.timezone import utc
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organization-network', '0078_auto_20170106_1142'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='personactivitytimesheet',
+            name='accounting',
+            field=models.DateField(blank=True, default=datetime.datetime(2017, 1, 6, 10, 47, 54, 649097, tzinfo=utc)),
+        ),
+        migrations.AlterField(
+            model_name='personactivitytimesheet',
+            name='validation',
+            field=models.DateField(blank=True, default=datetime.datetime(2017, 1, 6, 10, 47, 54, 649141, tzinfo=utc)),
+        ),
+    ]
diff --git a/app/organization/network/migrations/0080_auto_20170106_1642.py b/app/organization/network/migrations/0080_auto_20170106_1642.py
new file mode 100644 (file)
index 0000000..92f0610
--- /dev/null
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.11 on 2017-01-06 15:42
+from __future__ import unicode_literals
+
+import datetime
+from django.db import migrations, models
+from django.utils.timezone import utc
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organization-network', '0079_auto_20170106_1149'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='personactivitytimesheet',
+            name='accounting',
+            field=models.DateField(blank=True, default=datetime.datetime(2017, 1, 6, 15, 40, 39, 279343, tzinfo=utc)),
+        ),
+        migrations.AlterField(
+            model_name='personactivitytimesheet',
+            name='validation',
+            field=models.DateField(blank=True, default=datetime.datetime(2017, 1, 6, 15, 40, 39, 279377, tzinfo=utc)),
+        ),
+    ]
diff --git a/app/organization/network/migrations/0081_auto_20170106_1645.py b/app/organization/network/migrations/0081_auto_20170106_1645.py
new file mode 100644 (file)
index 0000000..2f86275
--- /dev/null
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.11 on 2017-01-06 15:45
+from __future__ import unicode_literals
+
+import datetime
+from django.db import migrations, models
+from django.utils.timezone import utc
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organization-network', '0080_auto_20170106_1642'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='personactivitytimesheet',
+            name='accounting',
+            field=models.DateField(blank=True, default=datetime.datetime(2017, 1, 6, 15, 43, 11, 224739, tzinfo=utc)),
+        ),
+        migrations.AlterField(
+            model_name='personactivitytimesheet',
+            name='validation',
+            field=models.DateField(blank=True, default=datetime.datetime(2017, 1, 6, 15, 43, 11, 224774, tzinfo=utc)),
+        ),
+    ]
diff --git a/app/organization/projects/migrations/0035_auto_20170106_1149.py b/app/organization/projects/migrations/0035_auto_20170106_1149.py
new file mode 100644 (file)
index 0000000..bbe7133
--- /dev/null
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.11 on 2017-01-06 10:49
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organization-network', '0079_auto_20170106_1149'),
+        ('organization-projects', '0034_auto_20161230_1839'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='project',
+            name='manager',
+            field=models.ManyToManyField(blank=True, null=True, related_name='projects_manager', to='organization-network.Person', verbose_name='Manager'),
+        ),
+        migrations.AddField(
+            model_name='project',
+            name='referring_person',
+            field=models.ManyToManyField(blank=True, null=True, related_name='projects_referring_person', to='organization-network.Person', verbose_name='Referring Person'),
+        ),
+    ]
diff --git a/app/organization/projects/migrations/0036_auto_20170106_1645.py b/app/organization/projects/migrations/0036_auto_20170106_1645.py
new file mode 100644 (file)
index 0000000..7eb89cd
--- /dev/null
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.11 on 2017-01-06 15:45
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organization-projects', '0035_auto_20170106_1149'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='ProjectCall',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=512, verbose_name='name')),
+                ('description', models.TextField(blank=True, verbose_name='description')),
+            ],
+            options={
+                'verbose_name': 'project call',
+                'ordering': ['name'],
+                'verbose_name_plural': 'project calls',
+            },
+        ),
+        migrations.AlterField(
+            model_name='project',
+            name='referring_person',
+            field=models.ManyToManyField(blank=True, related_name='projects_referring_person', to='organization-network.Person', verbose_name='Referring Person'),
+        ),
+        migrations.AddField(
+            model_name='project',
+            name='call',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='projects', to='organization-projects.ProjectCall', verbose_name='project call'),
+        ),
+    ]
index af207b34b312003fe34ee1c0f98c844ee6020d5c..0231902e8a9fd3361d39a299c09575940b85bead 100644 (file)
@@ -53,12 +53,15 @@ class Project(Displayable, Period, RichText):
     external_id = models.CharField(_('external ID'), blank=True, null=True, max_length=128)
     program = models.ForeignKey('ProjectProgram', verbose_name=_('project program'), related_name='projects', blank=True, null=True, on_delete=models.SET_NULL)
     program_type = models.ForeignKey('ProjectProgramType', verbose_name=_('project program type'), related_name='projects', blank=True, null=True, on_delete=models.SET_NULL)
+    call = models.ForeignKey('ProjectCall', verbose_name=_('project call'), related_name='projects', blank=True, null=True, on_delete=models.SET_NULL)
     lead_team = models.ForeignKey('organization-network.Team', verbose_name=_('lead team'), related_name='leader_projects', blank=True, null=True)
     lead_organization = models.ForeignKey('organization-network.Organization', verbose_name=_('lead organization'), related_name='leader_projects', blank=True, null=True)
     teams = models.ManyToManyField('organization-network.Team', verbose_name=_('teams'), related_name='partner_projects', blank=True)
     organizations = models.ManyToManyField('organization-network.Organization', verbose_name=_('organizations'), blank=True)
     website = models.URLField(_('website'), max_length=512, blank=True)
     topic = models.ForeignKey('ProjectTopic', verbose_name=_('topic'), related_name='projects', blank=True, null=True)
+    referring_person = models.ManyToManyField('organization-network.Person', verbose_name=_('Referring Person'), related_name='projects_referring_person', blank=True)
+    manager =  models.ManyToManyField('organization-network.Person', verbose_name=_('Manager'), related_name='projects_manager', blank=True, null=True)
 
     class Meta:
         verbose_name = _('project')
@@ -115,6 +118,14 @@ class ProjectProgramType(Named):
         ordering = ['name',]
 
 
+class ProjectCall(Named):
+
+    class Meta:
+        verbose_name = _('project call')
+        verbose_name_plural = _("project calls")
+        ordering = ['name',]
+
+
 class ProjectWorkPackage(Titled, Period):
 
     project = models.ForeignKey(Project, verbose_name=_('project'), related_name='work_packages')