]> git.parisson.com Git - mezzo.git/commitdiff
Add ProjectProgram and ProjectProgramType, add test version of IRCAM's person data
authorGuillaume Pellerin <guillaume.pellerin@ircam.fr>
Tue, 6 Sep 2016 20:35:22 +0000 (22:35 +0200)
committerGuillaume Pellerin <guillaume.pellerin@ircam.fr>
Tue, 6 Sep 2016 20:35:22 +0000 (22:35 +0200)
app/organization/magazine/models.py
app/organization/network/management/commands/import-ircam-person-xls.py [new file with mode: 0644]
app/organization/network/migrations/0005_auto_20160905_1853.py [new file with mode: 0644]
app/organization/network/models.py
app/organization/projects/admin.py
app/organization/projects/migrations/0004_auto_20160905_1853.py [new file with mode: 0644]
app/organization/projects/models.py

index 647c47ef129f2cb62c6e34b3f920d78a6e94b774..d3de1d8e4ec8abfe4da0640a29b8c3ae952b8bf1 100644 (file)
@@ -16,8 +16,7 @@ from organization.core.models import *
 
 class Article(BlogPost, SubTitled):
 
-    related_articles = models.ManyToManyField("self",
-                                 verbose_name=_("Related articles"), blank=True)
+    related_articles = models.ManyToManyField("self", verbose_name=_("Related articles"), blank=True)
     department = models.ForeignKey(Department, verbose_name=_('department'), related_name='articles', limit_choices_to=dict(id__in=Department.objects.all()), blank=True, null=True, on_delete=models.SET_NULL)
     topics = models.ManyToManyField("Topic", verbose_name=_('topics'), related_name="articles", blank=True)
 
diff --git a/app/organization/network/management/commands/import-ircam-person-xls.py b/app/organization/network/management/commands/import-ircam-person-xls.py
new file mode 100644 (file)
index 0000000..86c9606
--- /dev/null
@@ -0,0 +1,155 @@
+import os
+import sys
+import csv
+import logging
+import datetime
+from optparse import make_option
+import xlrd
+from itertools import takewhile
+
+from django.conf import settings
+from django.core.management.base import BaseCommand, CommandError
+from django.contrib.auth.models import User
+
+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.decode('utf8'))
+
+    def error(self, prefix, message):
+        self.logger.error(prefix + ' : ' + message.decode('utf8'))
+
+
+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 = 2
+    first_row = 21
+
+    def __init__(self, file):
+        self.book = xlrd.open_workbook(file)
+        self.sheet = self.book.sheet_by_index(self.sheet_id)
+        self.size = self.column_len(0)
+
+    def column_len(self, index):
+        col_values = self.sheet.col_values(index)
+        col_len = len(col_values)
+        for _ in takewhile(lambda x: not x, reversed(col_values)):
+            col_len -= 1
+        return col_len
+
+class IrcamPerson(object):
+
+    organization = Organization.objects.get(name='Ircam')
+
+    def __init__(self, row, datemode):
+        self.row = row
+        self.datemode = datemode
+        last_name = self.row[0].value
+        first_name = self.row[1].value
+        title = ' '.join((first_name, last_name))
+
+        self.person, c = Person.objects.get_or_create(title=title, first_name=first_name, last_name=last_name)
+        self.activity = PersonActivity(person=self.person)
+
+    def get_identity(self, ):
+        gender = self.row[2].value
+        if gender == 'H':
+            self.person.gender = 'male'
+        elif gender == 'F':
+            self.person.gender = 'female'
+
+        birthday = self.row[3].value
+        if birthday:
+            self.person.birthday = datetime.datetime(*xlrd.xldate_as_tuple(birthday, self.datemode))
+
+        self.person.save()
+
+    def get_or_create_name(self, model, column_id):
+        return model.objects.get_or_create(name=self.row[column_id].value)[0] if self.row[column_id].value else None
+
+    def get_activity(self):
+        self.activity.status = self.get_or_create_name(ActivityStatus, 10)
+        self.activity.is_permanent = True if self.row[11].value else False
+        self.activity.framework = self.get_or_create_name(ActivityFramework, 12)
+        self.activity.grade = self.get_or_create_name(ActivityGrade, 13)
+
+        self.activity.employer = self.get_or_create_name(Organization, 14)
+        self.activity.attachment_organization = self.get_or_create_name(Organization, 15)
+        self.activity.second_employer = self.get_or_create_name(Organization, 16)
+        self.activity.umr = self.get_or_create_name(UMR, 17)
+
+        self.activity.team, c = Team.objects.get_or_create(name=self.row[18].value, organization=self.organization) if self.row[18].value else (None, False)
+        self.activity.second_team, c = Team.objects.get_or_create(name=self.row[19].value, organization=self.organization) if self.row[19].value else (None, False)
+        self.activity.project, c = Project.objects.get_or_create(title=self.row[19].value) if self.row[19].value else (None, False)
+
+        quota = self.row[21].value
+        try:
+            self.activity.rd_quota_float = float(quota)
+        except:
+            self.activity.rd_quota_text = str(quota)
+
+        self.activity.phd_doctoral_school = self.get_or_create_name(Organization, 23)
+        self.activity.phd_director, c = Person.objects.get_or_create(title=self.row[24].value.capitalize()) if self.row[24].value else (None, False)
+        self.activity.phd_officer_1, c = Person.objects.get_or_create(title=self.row[25].value.capitalize()) if self.row[25].value else (None, False)
+        self.activity.phd_officer_2, c = Person.objects.get_or_create(title=self.row[26].value.capitalize()) if self.row[26].value else (None, False)
+        # self.activity.phd_defense_date = datetime.datetime(*xlrd.xldate_as_tuple(self.row[27].value, self.datemode)) if self.row[27].value else None
+        # self.activity.phd_title = self.row[28].value
+
+        self.activity.save()
+
+
+class Command(BaseCommand):
+    help = """Import Person data from IRCAM's legacy XLS management file"""
+
+    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)
+        for i in range(xls.first_row, xls.size):
+            p = IrcamPerson(xls.sheet.row(i), xls.book.datemode)
+            p.get_identity()
+            p.get_activity()
diff --git a/app/organization/network/migrations/0005_auto_20160905_1853.py b/app/organization/network/migrations/0005_auto_20160905_1853.py
new file mode 100644 (file)
index 0000000..3055818
--- /dev/null
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.7 on 2016-09-05 16:53
+from __future__ import unicode_literals
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organization-network', '0004_organizationaudio_organizationblock_organizationimage_organizationlink_organizationvideo'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='UMR',
+            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': 'UMR',
+            },
+        ),
+        migrations.RemoveField(
+            model_name='person',
+            name='permanent',
+        ),
+        migrations.RemoveField(
+            model_name='personactivity',
+            name='function',
+        ),
+        migrations.RemoveField(
+            model_name='personactivity',
+            name='rd_quota',
+        ),
+        migrations.AddField(
+            model_name='personactivity',
+            name='is_permanent',
+            field=models.BooleanField(default=False, verbose_name='permanent'),
+        ),
+        migrations.AddField(
+            model_name='personactivity',
+            name='rd_quota_float',
+            field=models.IntegerField(blank=True, null=True, verbose_name='R&D quota (float)'),
+        ),
+        migrations.AddField(
+            model_name='personactivity',
+            name='rd_quota_text',
+            field=models.CharField(blank=True, max_length=128, null=True, verbose_name='R&D quota (text)'),
+        ),
+        migrations.AlterField(
+            model_name='person',
+            name='user',
+            field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='user'),
+        ),
+        migrations.AddField(
+            model_name='personactivity',
+            name='umr',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='organization-network.UMR', verbose_name='training type'),
+        ),
+    ]
index 9f7e610da78771db6b51b74330d263fba08dd463..70e5923f8f377bf3999ec4575b6302ee59faf465 100644 (file)
@@ -163,14 +163,13 @@ class TeamPage(Page, SubTitled, RichText):
 class Person(Displayable, AdminThumbMixin):
     """(Person description)"""
 
-    user = models.ForeignKey(User, verbose_name=_('user'), blank=True, null=True, on_delete=models.SET_NULL)
+    user = models.OneToOneField(User, verbose_name=_('user'), blank=True, null=True, on_delete=models.SET_NULL)
     person_title = models.CharField(_('title'), max_length=16, choices=TITLE_CHOICES, blank=True)
     gender = models.CharField(_('gender'), max_length=16, choices=GENDER_CHOICES, blank=True)
     first_name = models.CharField(_('first name'), max_length=255, blank=True, null=True)
     last_name = models.CharField(_('last name'), max_length=255, blank=True, null=True)
     birthday = models.DateField(_('birthday'), blank=True, null=True)
     bio = RichTextField(_('biography'), blank=True)
-    permanent = models.BooleanField(_('permanent'), default=False)
 
     class Meta:
         verbose_name = _('person')
@@ -282,25 +281,32 @@ class TrainingSpectiality(Named):
         verbose_name = _('training speciality')
 
 
+class UMR(Named):
+
+    class Meta:
+        verbose_name = _('UMR')
+
+
 class PersonActivity(Description, Period, RichText):
     """(Activity description)"""
 
     person = models.ForeignKey('Person', verbose_name=_('person'))
-    team = models.ForeignKey('Team', verbose_name=_('team'), related_name='team_activity', blank=True, null=True, on_delete=models.SET_NULL)
-    second_team = models.ForeignKey('Team', verbose_name=_('second team'), related_name='second_team_activity', blank=True, null=True, on_delete=models.SET_NULL)
-    function = models.CharField(_('fonction'), blank=True, max_length=1024)
 
     status = models.ForeignKey(ActivityStatus, verbose_name=_('status'), blank=True, null=True, on_delete=models.SET_NULL)
-    grade = models.ForeignKey(ActivityGrade, verbose_name=_('grade'), blank=True, null=True, on_delete=models.SET_NULL)
+    is_permanent = models.BooleanField(_('permanent'), default=False)
     framework = models.ForeignKey(ActivityFramework, verbose_name=_('framework'), blank=True, null=True, on_delete=models.SET_NULL)
-    hdr = models.BooleanField(_('HDR'), default=False)
+    grade = models.ForeignKey(ActivityGrade, verbose_name=_('grade'), blank=True, null=True, on_delete=models.SET_NULL)
 
     employer = models.ForeignKey(Organization, verbose_name=_('employer'), related_name='employer_activity', blank=True, null=True, on_delete=models.SET_NULL)
-    second_employer = models.ForeignKey(Organization, verbose_name=_('second employer'), related_name='second_employer_activity', blank=True, null=True, on_delete=models.SET_NULL)
     attachment_organization = models.ForeignKey(Organization, verbose_name=_('attachment organization'), related_name='attachment_activity', blank=True, null=True, on_delete=models.SET_NULL)
+    second_employer = models.ForeignKey(Organization, verbose_name=_('second employer'), related_name='second_employer_activity', blank=True, null=True, on_delete=models.SET_NULL)
+    umr = models.ForeignKey(UMR, verbose_name=_('training type'), blank=True, null=True, on_delete=models.SET_NULL)
+    team = models.ForeignKey('Team', verbose_name=_('team'), related_name='team_activity', blank=True, null=True, on_delete=models.SET_NULL)
+    second_team = models.ForeignKey('Team', verbose_name=_('second team'), related_name='second_team_activity', blank=True, null=True, on_delete=models.SET_NULL)
 
     project = models.ForeignKey('organization-projects.Project', verbose_name=_('project'), blank=True, null=True, on_delete=models.SET_NULL)
-    rd_quota = models.IntegerField(_('R&D quota'), blank=True, null=True)
+    rd_quota_float = models.IntegerField(_('R&D quota (float)'), blank=True, null=True)
+    rd_quota_text = models.CharField(_('R&D quota (text)'), blank=True, null=True, max_length=128)
     rd_program = models.TextField(_('R&D program'), blank=True)
     budget_code = models.ForeignKey(BudgetCode, blank=True, null=True, on_delete=models.SET_NULL)
 
@@ -311,6 +317,7 @@ class PersonActivity(Description, Period, RichText):
     phd_defense_date = models.DateField(_('PhD defense date'), blank=True, null=True)
     phd_title = models.TextField(_('PhD title'), blank=True)
     phd_postdoctoralsituation =  models.CharField(_('post-doctoral situation'), blank=True, max_length=256)
+    hdr = models.BooleanField(_('HDR'), default=False)
 
     training_type = models.ForeignKey(TrainingType, verbose_name=_('training type'), blank=True, null=True, on_delete=models.SET_NULL)
     training_level = models.ForeignKey(TrainingLevel, verbose_name=_('training level'), blank=True, null=True, on_delete=models.SET_NULL)
@@ -318,13 +325,13 @@ class PersonActivity(Description, Period, RichText):
     training_speciality = models.ForeignKey(TrainingSpectiality, verbose_name=_('training speciality'), blank=True, null=True, on_delete=models.SET_NULL)
     training_title = models.TextField(_('Training title'), blank=True)
 
-    comments = models.TextField(_('comments'), blank=True)
-
     record_piece = models.ForeignKey(RecordPiece, blank=True, null=True, on_delete=models.SET_NULL)
     date_added = models.DateTimeField(_('add date'), auto_now_add=True)
     date_modified = models.DateTimeField(_('modification date'), auto_now=True)
     date_modified_manual = models.DateTimeField(_('manual modification date'), blank=True, null=True)
 
+    comments = models.TextField(_('comments'), blank=True)
+
     class Meta:
         verbose_name = _('activity')
         verbose_name_plural = _('activities')
index e79d505db53032d526469abb2af508f0cbde89f4..ada735ba1a5b2d1990216e888dcc3c035d8473d4 100644 (file)
@@ -45,6 +45,9 @@ class ProjectAdminDisplayable(DisplayableAdmin):
     fieldsets = deepcopy(ProjectAdmin.fieldsets)
     inlines = [ ProjectBlockInline, ProjectImageInline, ProjectAudioInline, ProjectVideoInline, ProjectLinkInline]
     filter_horizontal = ['persons', 'teams', 'organizations']
+    list_filter = ['type', 'program', 'program_type', ]
 
 
 admin.site.register(Project, ProjectAdminDisplayable)
+admin.site.register(ProjectProgram)
+admin.site.register(ProjectProgramType)
diff --git a/app/organization/projects/migrations/0004_auto_20160905_1853.py b/app/organization/projects/migrations/0004_auto_20160905_1853.py
new file mode 100644 (file)
index 0000000..c8f8044
--- /dev/null
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.7 on 2016-09-05 16:53
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('organization-projects', '0003_auto_20160901_1810'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='ProjectProgram',
+            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 programme',
+            },
+        ),
+        migrations.CreateModel(
+            name='ProjectProgramType',
+            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 programme type',
+            },
+        ),
+        migrations.AddField(
+            model_name='project',
+            name='type',
+            field=models.CharField(choices=[('research topic', 'research topic'), ('collaborative project', 'collaborative project')], default=1, max_length=128, verbose_name='type'),
+            preserve_default=False,
+        ),
+        migrations.AlterField(
+            model_name='project',
+            name='teams',
+            field=models.ManyToManyField(blank=True, related_name='partner_projects', to='organization-network.Team', verbose_name='teams'),
+        ),
+        migrations.AddField(
+            model_name='project',
+            name='program',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='projects', to='organization-projects.ProjectProgram', verbose_name='project program'),
+        ),
+        migrations.AddField(
+            model_name='project',
+            name='program_type',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='projects', to='organization-projects.ProjectProgramType', verbose_name='project program type'),
+        ),
+    ]
index 4ee2c20bc45c0069ba1b07cf1418c55ea01f76a9..cf658b06171e4c368f06cb23c73ce3db487ffd12 100644 (file)
@@ -9,12 +9,20 @@ from organization.core.models import *
 from organization.pages.models import *
 
 
+PROJECT_TYPE_CHOICES = [
+    ('internal project', _('internal project')),
+    ('external project', _('external project')),
+]
+
 class Project(Displayable, Period, RichText):
     """(Project description)"""
 
+    type = models.CharField(_('type'), max_length=128, choices=PROJECT_TYPE_CHOICES)
+    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)
     lead_team = models.ForeignKey('organization-network.Team', verbose_name=_('lead team'), related_name='leader_projects', blank=True, null=True)
     persons = models.ManyToManyField('organization-network.Person', verbose_name=_('persons'), blank=True)
-    teams = models.ManyToManyField('organization-network.Team', verbose_name=_('teams'), related_name='patner_projects', blank=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)
 
@@ -28,6 +36,18 @@ class Project(Displayable, Period, RichText):
         return reverse("organization-project-detail", kwargs={"slug": self.slug})
 
 
+class ProjectProgram(Named):
+
+    class Meta:
+        verbose_name = _('project programme')
+
+
+class ProjectProgramType(Named):
+
+    class Meta:
+        verbose_name = _('project programme type')
+
+
 class ProjectAudio(Audio):
 
     project = models.ForeignKey(Project, verbose_name=_('project'), related_name='audios', blank=True, null=True, on_delete=models.SET_NULL)