SciPost Code Repository

Skip to content
Snippets Groups Projects
Commit 2c32c51e authored by Jean-Sébastien Caux's avatar Jean-Sébastien Caux
Browse files

Merge branch 'dev_JSC_20170603' into development

parents 9c30af0b cb2cf243
No related branches found
No related tags found
No related merge requests found
Showing
with 619 additions and 113 deletions
from django.contrib import admin
from .models import ContactPerson, Partner, Consortium,\
from .models import Contact, Partner, Consortium,\
ProspectivePartner, MembershipAgreement
admin.site.register(ContactPerson)
admin.site.register(Contact)
class PartnerAdmin(admin.ModelAdmin):
search_fields = ['institution', 'institution_acronym',
'institution_address', 'contact_person']
search_fields = ['institution', ]
admin.site.register(Partner, PartnerAdmin)
......
import datetime
PARTNER_TYPES = (
PARTNER_KINDS = (
('Res. Inst.', 'Research Institute'),
('Int. Fund. Agency', 'International Funding Agency'),
('Nat. Fund. Agency', 'National Funding Agency'),
('Nat. Lab.', 'National Laboratory'),
('Nat. Library', 'National Library'),
('Univ. Library', 'University Library'),
('Nat. Acad.', 'National Academy'),
('Univ. Library', 'University (and its Library)'),
('Res. Library', 'Research Library'),
('Prof. Soc.', 'Professional Society'),
('Foundation', 'Foundation'),
('Individual', 'Individual'),
)
PROSPECTIVE_PARTNER_STATUS = (
('requested', 'Requested (from online form)'),
('added', 'Added internally'),
('processed', 'Processed into Partner object'),
)
PROSPECTIVE_PARTNER_EVENTS = (
('comment', 'Comment added'),
)
PARTNER_STATUS = (
('Prospective', 'Prospective'),
('Initiated', 'Initiated'),
('Contacted', 'Contacted'),
('Negotiating', 'Negotiating'),
('Uninterested', 'Uninterested'),
('Active', 'Active'),
('Inactive', 'Inactive'),
)
......@@ -26,6 +44,13 @@ CONSORTIUM_STATUS = (
)
PARTNER_EVENTS = (
('initial', 'Contacted (initial)'),
('status_update', 'Status updated'),
('comment', 'Comment added'),
)
MEMBERSHIP_AGREEMENT_STATUS = (
('Submitted', 'Request submitted by Partner'),
('Pending', 'Sent to Partner, response pending'),
......
......@@ -5,8 +5,9 @@ from django_countries import countries
from django_countries.widgets import CountrySelectWidget
from django_countries.fields import LazyTypedChoiceField
from .constants import PARTNER_TYPES
from .models import ContactPerson, Partner, ProspectivePartner, MembershipAgreement
from .constants import PARTNER_KINDS
from .models import Partner, ProspectivePartner, ProspectiveContact, \
ProspectivePartnerEvent, MembershipAgreement
from scipost.models import TITLE_CHOICES
......@@ -22,9 +23,31 @@ class PartnerForm(forms.ModelForm):
class ProspectivePartnerForm(forms.ModelForm):
"""
This form is used to internally add a ProspectivePartner.
If an external agent requests membership of the SPB,
the MembershipQueryForm below is used instead.
"""
class Meta:
model = ProspectivePartner
exclude = ['date_received', 'date_processed', 'processed']
exclude = ['date_received', 'date_processed']
widgets = {'status': forms.HiddenInput()}
class ProspectiveContactForm(forms.ModelForm):
class Meta:
model = ProspectiveContact
fields = '__all__'
widgets = {'prospartner': forms.HiddenInput()}
class ProspectivePartnerEventForm(forms.ModelForm):
class Meta:
model = ProspectivePartnerEvent
exclude = ['prospartner', 'noted_on', 'noted_by']
widgets = {
'comments': forms.Textarea(attrs={'cols': 16, 'rows': 3}),
}
class MembershipQueryForm(forms.Form):
......@@ -37,7 +60,7 @@ class MembershipQueryForm(forms.Form):
last_name = forms.CharField(label='* Your last name', max_length=100)
email = forms.EmailField(label='* Your email address')
role = forms.CharField(label='* Your role in your organization')
partner_type = forms.ChoiceField(choices=PARTNER_TYPES, label='* Partner type')
partner_kind = forms.ChoiceField(choices=PARTNER_KINDS, label='* Partner kind')
institution_name = forms.CharField(label='* Name of your institution')
country = LazyTypedChoiceField(
choices=countries, label='* Country', initial='NL',
......
# -*- coding: utf-8 -*-
# Generated by Django 1.10.3 on 2017-06-03 14:46
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import django_countries.fields
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('scipost', '0055_auto_20170519_0937'),
('partners', '0004_auto_20170519_1425'),
]
operations = [
migrations.CreateModel(
name='Contact',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('kind', models.CharField(max_length=128)),
('title', models.CharField(choices=[('PR', 'Prof.'), ('DR', 'Dr'), ('MR', 'Mr'), ('MRS', 'Mrs')], max_length=4)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='Institution',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('kind', models.CharField(choices=[('Res. Inst.', 'Research Institute'), ('Int. Fund. Agency', 'International Funding Agency'), ('Nat. Fund. Agency', 'National Funding Agency'), ('Nat. Lab.', 'National Laboratory'), ('Nat. Library', 'National Library'), ('Nat. Acad.', 'National Academy'), ('Univ. Library', 'University (and its Library)'), ('Res. Library', 'Research Library'), ('Prof. Soc.', 'Professional Society'), ('Foundation', 'Foundation'), ('Individual', 'Individual')], max_length=32)),
('name', models.CharField(max_length=256)),
('acronym', models.CharField(max_length=16)),
('address', models.CharField(blank=True, max_length=1000, null=True)),
('country', django_countries.fields.CountryField(max_length=2)),
],
),
migrations.CreateModel(
name='PartnerEvent',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('event', models.CharField(choices=[('initial', 'Contacted (initial)'), ('status_update', 'Status updated'), ('comment', 'Comment added')], max_length=64)),
('comments', models.TextField(blank=True, null=True)),
('noted_on', models.DateTimeField(default=django.utils.timezone.now)),
('noted_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
],
),
migrations.CreateModel(
name='ProspectiveContact',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(choices=[('PR', 'Prof.'), ('DR', 'Dr'), ('MR', 'Mr'), ('MRS', 'Mrs')], max_length=4)),
('first_name', models.CharField(max_length=64)),
('last_name', models.CharField(max_length=64)),
('email', models.EmailField(max_length=254)),
('role', models.CharField(max_length=128)),
],
),
migrations.CreateModel(
name='ProspectivePartnerEvent',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('event', models.CharField(choices=[('comment', 'Comment added')], max_length=64)),
('comments', models.TextField(blank=True, null=True)),
('noted_on', models.DateTimeField(default=django.utils.timezone.now)),
('duration', models.DurationField(blank=True, null=True)),
('noted_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
],
),
migrations.RemoveField(
model_name='contactperson',
name='user',
),
migrations.RemoveField(
model_name='partner',
name='country',
),
migrations.RemoveField(
model_name='partner',
name='institution_acronym',
),
migrations.RemoveField(
model_name='partner',
name='institution_address',
),
migrations.RemoveField(
model_name='partner',
name='institution_name',
),
migrations.RemoveField(
model_name='partner',
name='partner_type',
),
migrations.RemoveField(
model_name='prospectivepartner',
name='email',
),
migrations.RemoveField(
model_name='prospectivepartner',
name='first_name',
),
migrations.RemoveField(
model_name='prospectivepartner',
name='last_name',
),
migrations.RemoveField(
model_name='prospectivepartner',
name='partner_type',
),
migrations.RemoveField(
model_name='prospectivepartner',
name='role',
),
migrations.RemoveField(
model_name='prospectivepartner',
name='title',
),
migrations.AddField(
model_name='prospectivepartner',
name='kind',
field=models.CharField(choices=[('Res. Inst.', 'Research Institute'), ('Int. Fund. Agency', 'International Funding Agency'), ('Nat. Fund. Agency', 'National Funding Agency'), ('Nat. Lab.', 'National Laboratory'), ('Nat. Library', 'National Library'), ('Nat. Acad.', 'National Academy'), ('Univ. Library', 'University (and its Library)'), ('Res. Library', 'Research Library'), ('Prof. Soc.', 'Professional Society'), ('Foundation', 'Foundation'), ('Individual', 'Individual')], default='Univ. Library', max_length=32),
),
migrations.AlterField(
model_name='partner',
name='financial_contact',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='partner_financial_contact', to='partners.Contact'),
),
migrations.AlterField(
model_name='partner',
name='main_contact',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='partner_main_contact', to='partners.Contact'),
),
migrations.AlterField(
model_name='partner',
name='technical_contact',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='partner_technical_contact', to='partners.Contact'),
),
migrations.DeleteModel(
name='ContactPerson',
),
migrations.AddField(
model_name='prospectivepartnerevent',
name='prospective_partner',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='partners.ProspectivePartner'),
),
migrations.AddField(
model_name='prospectivecontact',
name='institution',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='partners.ProspectivePartner'),
),
migrations.AddField(
model_name='partnerevent',
name='partner',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='partners.Partner'),
),
migrations.AddField(
model_name='partner',
name='institution',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='partners.Institution'),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10.3 on 2017-06-04 02:59
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('partners', '0005_auto_20170603_1646'),
]
operations = [
migrations.RenameField(
model_name='prospectivecontact',
old_name='institution',
new_name='prospartner',
),
migrations.RemoveField(
model_name='prospectivepartner',
name='processed',
),
migrations.AddField(
model_name='prospectivepartner',
name='status',
field=models.CharField(choices=[('requested', 'Requested (from online form)'), ('added', 'Added internally'), ('processed', 'Processed into Partner object')], default='added', max_length=32),
),
migrations.AlterField(
model_name='partner',
name='status',
field=models.CharField(choices=[('Initiated', 'Initiated'), ('Contacted', 'Contacted'), ('Negotiating', 'Negotiating'), ('Uninterested', 'Uninterested'), ('Active', 'Active'), ('Inactive', 'Inactive')], max_length=16),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10.3 on 2017-06-04 04:29
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('partners', '0006_auto_20170604_0459'),
]
operations = [
migrations.RenameField(
model_name='prospectivepartnerevent',
old_name='prospective_partner',
new_name='prospartner',
),
migrations.RemoveField(
model_name='prospectivepartnerevent',
name='duration',
),
]
......@@ -4,20 +4,89 @@ from django.utils import timezone
from django_countries.fields import CountryField
from .constants import PARTNER_TYPES, PARTNER_STATUS, CONSORTIUM_STATUS,\
from .constants import PARTNER_KINDS, PARTNER_STATUS, CONSORTIUM_STATUS,\
PROSPECTIVE_PARTNER_STATUS, PROSPECTIVE_PARTNER_EVENTS, PARTNER_EVENTS,\
MEMBERSHIP_AGREEMENT_STATUS, MEMBERSHIP_DURATION
from scipost.constants import TITLE_CHOICES
from scipost.models import Contributor
class ContactPerson(models.Model):
########################
# Prospective Partners #
########################
class ProspectivePartner(models.Model):
"""
Created from the membership_request page, after submitting a query form.
"""
kind = models.CharField(max_length=32, choices=PARTNER_KINDS,
default='Univ. Library')
institution_name = models.CharField(max_length=256)
country = CountryField()
date_received = models.DateTimeField(default=timezone.now)
date_processed = models.DateTimeField(blank=True, null=True)
status = models.CharField(max_length=32, choices=PROSPECTIVE_PARTNER_STATUS,
default='added')
def __str__(self):
return '%s (received %s), %s' % (self.institution_name,
self.date_received.strftime("%Y-%m-%d"),
self.get_status_display())
class ProspectiveContact(models.Model):
"""
A ProspectiveContact is a person's name and contact details, with a
link to a Prospective Partner and a role within it.
It does not have a corresponding User object.
It is meant to be used internally at SciPost, during Partner mining.
"""
prospartner = models.ForeignKey(ProspectivePartner, on_delete=models.CASCADE)
title = models.CharField(max_length=4, choices=TITLE_CHOICES)
first_name = models.CharField(max_length=64)
last_name = models.CharField(max_length=64)
email = models.EmailField()
role = models.CharField(max_length=128)
class ProspectivePartnerEvent(models.Model):
prospartner = models.ForeignKey(ProspectivePartner, on_delete=models.CASCADE)
event = models.CharField(max_length=64, choices=PROSPECTIVE_PARTNER_EVENTS)
comments = models.TextField(blank=True, null=True)
noted_on = models.DateTimeField(default=timezone.now)
noted_by = models.ForeignKey(Contributor, on_delete=models.CASCADE)
def __str__(self):
return '%s: %s' % (str(self.prospective_partner), self.get_event_display())
###########################
# Partner-related objects #
###########################
class Institution(models.Model):
"""
An Institution is any form of academic organization which SciPost interacts with.
"""
kind = models.CharField(max_length=32, choices=PARTNER_KINDS)
name = models.CharField(max_length=256)
acronym = models.CharField(max_length=16)
address = models.CharField(max_length=1000, blank=True, null=True)
country = CountryField()
def __str__(self):
return '%s (%s)' % (self.name, self.get_kind_display())
class Contact(models.Model):
"""
A ContactPerson is a simple form of User which is meant
A Contact is a simple form of User which is meant
to be associated to Partner objects
(main contact, financial/technical contact etc).
ContactPersons and Contributors have different rights.
Contacts and Contributors have different rights.
"""
user = models.OneToOneField(User, on_delete=models.CASCADE, unique=True)
kind = models.CharField(max_length=128)
title = models.CharField(max_length=4, choices=TITLE_CHOICES)
def __str__(self):
......@@ -29,24 +98,34 @@ class Partner(models.Model):
Supporting Partners.
These are the official Partner objects created by SciPost Admin.
"""
partner_type = models.CharField(max_length=32, choices=PARTNER_TYPES)
institution = models.ForeignKey(Institution, on_delete=models.CASCADE,
blank=True, null=True)
status = models.CharField(max_length=16, choices=PARTNER_STATUS)
institution_name = models.CharField(max_length=256)
institution_acronym = models.CharField(max_length=10)
institution_address = models.CharField(max_length=1000, blank=True, null=True)
country = CountryField()
main_contact = models.ForeignKey(ContactPerson, on_delete=models.CASCADE,
main_contact = models.ForeignKey(Contact, on_delete=models.CASCADE,
blank=True, null=True,
related_name='partner_main_contact')
financial_contact = models.ForeignKey(ContactPerson, on_delete=models.CASCADE,
financial_contact = models.ForeignKey(Contact, on_delete=models.CASCADE,
blank=True, null=True,
related_name='partner_financial_contact')
technical_contact = models.ForeignKey(ContactPerson, on_delete=models.CASCADE,
technical_contact = models.ForeignKey(Contact, on_delete=models.CASCADE,
blank=True, null=True,
related_name='partner_technical_contact')
def __str__(self):
return self.institution_acronym + ' (' + self.get_status_display() + ')'
if self.institution:
return self.institution.acronym + ' (' + self.get_status_display() + ')'
return self.get_status_display()
class PartnerEvent(models.Model):
partner = models.ForeignKey(Partner, on_delete=models.CASCADE)
event = models.CharField(max_length=64, choices=PARTNER_EVENTS)
comments = models.TextField(blank=True, null=True)
noted_on = models.DateTimeField(default=timezone.now)
noted_by = models.ForeignKey(Contributor, on_delete=models.CASCADE)
def __str__(self):
return '%s: %s' % (str(self.partner), self.get_event_display())
class Consortium(models.Model):
......@@ -61,31 +140,6 @@ class Consortium(models.Model):
verbose_name_plural = 'consortia'
class ProspectivePartner(models.Model):
"""
Created from the membership_request page, after submitting a query form.
"""
title = models.CharField(max_length=4, choices=TITLE_CHOICES)
first_name = models.CharField(max_length=32)
last_name = models.CharField(max_length=32)
email = models.EmailField()
role = models.CharField(max_length=128)
partner_type = models.CharField(max_length=32, choices=PARTNER_TYPES)
institution_name = models.CharField(max_length=256)
country = CountryField()
date_received = models.DateTimeField(default=timezone.now)
date_processed = models.DateTimeField(blank=True, null=True)
processed = models.BooleanField(default=False)
def __str__(self):
resp = "processed"
if not self.processed:
resp = "unprocessed"
return '%s (received %s), %s' % (self.institution_name,
self.date_received.strftime("%Y-%m-%d"),
resp)
class MembershipAgreement(models.Model):
"""
Agreement for membership of the Supporting Partners Board.
......
......@@ -3,12 +3,12 @@
<div class="card-block">
<div class="row">
<div class="col-1">
<p>{{ partner.country }}</p>
<p>{{ partner.institution.country }}</p>
</div>
<div class="col-4">
<h3>{{ partner.institution_name }}</h3>
<p>{{ partner.institution_acronym }}</p>
<p>({{ pp.get_partner_type_display }})</p>
<h3>{{ partner.institution.name }}</h3>
<p>{{ partner.institution.acronym }}</p>
<p>({{ pp.get_kind_display }})</p>
</div>
<div class="col-4">
{% if partner.main_contact %}
......
<li id="{{ event.id }}">
<div class="font-weight-bold">{{ event.get_event_display }} <small class="text-muted">noted {{ event.noted_on }} by {{ event.noted_by }}</small>
</div>
{% if event.comments %}
<div>{{ event.comments|linebreaks }}</div>
{% endif %}
</li>
......@@ -7,16 +7,53 @@
</div>
<div class="col-4">
<h3>{{ pp.institution_name }}</h3>
<p>({{ pp.get_partner_type_display }})</p>
<p>({{ pp.get_kind_display }})</p>
<p>Received {{ pp.date_received }}</p>
{% if pp.date_processed %}
<p>Processed {{ pp.date_processed }}</p>
{% endif %}
<p>{{ pp.get_status_display }}</p>
</div>
<div class="col-4">
<p>Contact: {{ pp.get_title_display }} {{ pp.first_name }} {{ pp.last_name }}</p>
<p>(role: {{ pp.role }})</p>
<p>{{ pp.email }}</p>
<h3>Contacts:</h3>
<ul class="list-group list-group-flush">
{% for contact in pp.prospectivecontact_set.all %}
<li class="list-group-item flex-column align-items-start">
<p>Role: {{ contact.role }}</p>
<p>{{ contact.get_title_display }} {{ contact.first_name }} {{ contact.last_name }}</p>
<p>{{ contact.email }}</p>
</li>
{% endfor %}
</ul>
</div>
<div class="col-3">
<p>Edit</p>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<a href="{% url 'partners:add_prospartner_contact' prospartner_id=pp.id %}">Add a contact</a>
</li>
</ul>
</div>
</div>
<div class="row">
<div class="col-1"></div>
<div class="col-6">
<h3>Events</h3>
<ul>
{% for event in pp.prospectivepartnerevent_set.all %}
{% include 'partners/_prospartner_event_li.html' with event=event %}
{% empty %}
<li>No events were found.</li>
{% endfor %}
</ul>
</div>
<div class="col-5">
<h3>Add an event</h3>
<form action="{% url 'partners:add_prospartner_event' prospartner_id=pp.id %}" method="post">
{% csrf_token %}
{{ ppevent_form|bootstrap }}
<input type="submit" name="submit" value="Submit">
</form>
</div>
</div>
</div>
{% extends 'scipost/base.html' %}
{% block pagetitle %}: Supporting Partners: add contact{% endblock pagetitle %}
{% load bootstrap %}
{% block content %}
<section>
<div class="flex-container">
<div class="flex-greybox">
<h1>Add a Contact for a Prospective Partner</h1>
</div>
</div>
<h3>Add a contact for {{ prospartner.institution_name }}:</h3>
<br/>
<form action="{% url 'partners:add_prospartner_contact' prospartner_id=prospartner.id %}" method="post">
{% csrf_token %}
{{ form|bootstrap }}
<input class="btn btn-primary" type="submit" value="Submit"/>
</form>
{% if errormessage %}
<p class="text-danger">{{ errormessage }}</p>
{% endif %}
</section>
{% endblock content %}
......@@ -5,51 +5,100 @@
{% block content %}
<div class="flex-container">
<div class="flex-greybox">
<h1>Partners Management Page</h1>
<div class="row">
<div class="col-12">
<h1 class="highlight">Partners Management Page</h1>
</div>
</div>
</div>
<section>
<div class="flex-container">
<div class="flex-greybox">
<h2>Partners</h2>
<div class="row">
<div class="col-12">
<div class="tab-nav-container">
<div class="tab-nav-inner">
<ul class="nav btn-group personal-page-nav" role="tablist">
<li class="nav-item btn btn-secondary">
<a href="#prospartners" class="nav-link active" data-toggle="tab">Prospective Partners</a>
</li>
<li class="nav-item btn btn-secondary">
<a href="#partners" class="nav-link" data-toggle="tab">Partners</a>
</li>
<li class="nav-item btn btn-secondary">
<a href="#agreements" class="nav-link" data-toggle="tab">Agreements</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<ul class="list-group list-group-flush">
{% for partner in partners %}
<li class="list-group-item">{% include 'partners/_partner_card.html' with partner=partner %}</li>
{% endfor %}
</ul>
</section>
<section>
<div class="flex-container">
<div class="flex-greybox">
<h2>Prospective Partners (not yet processed)</h2>
<div class="tab-content">
<div class="tab-pane active" id="prospartners" role="tabpanel">
<div class="row">
<div class="col-12">
<h2 class="highlight">Prospective Partners</h2>
</div>
</div>
<h3><a href="{% url 'partners:add_prospective_partner' %}">Add a prospective partner</a></h3>
<br/>
<div class="row">
<div class="col-2">Country</div>
<div class="col-3">Institution name</div>
<div class="col-3">Kind</div>
<div class="col-3">Status</div>
<div class="col-1">Date received</div>
</div>
<div id="accordion" role="tablist" aria-multiselectable="true">
{% for partner in prospective_partners %}
<div class="card">
<div class="card-header" role="tab" id="heading{{ partner.id }}">
<h4 class="mb-0">
<a data-toggle="collapse" data-parent="#accordion" href="#collapse{{ partner.id }}" aria-expanded="true" aria-controls="collapse{{ partner.id }}">
<div class="row">
<div class="col-2">{{ partner.get_country_display }}</div>
<div class="col-3">{{ partner.institution_name }}</div>
<div class="col-3">{{ partner.get_kind_display }}</div>
<div class="col-3">{{ partner.get_status_display }}</div>
<div class="col-1">{{ partner.date_received|date:"Y-m-d" }}</div>
</div>
</a>
</h4>
</div>
<div id="collapse{{ partner.id }}" class="collapse" role="tabpanel" aria-labelledby="heading{{ partner.id}}">
{% include 'partners/_prospective_partner_card.html' with pp=partner %}
</div>
</div>
{% endfor %}
</div>
</div>
</div>
<h3><a href="{% url 'partners:add_prospective_partner' %}">Add a prospective partner</a></h3>
<br/>
<ul class="list-group list-group-flush">
{% for partner in prospective_partners %}
<li class="list-group-item">{% include 'partners/_prospective_partner_card.html' with pp=partner %}</li>
{% endfor %}
</ul>
</section>
<section>
<div class="flex-container">
<div class="flex-greybox">
<h2>Agreements</h2>
<div class="tab-pane" id="partners" role="tabpanel">
<div class="row">
<div class="col-12">
<h2 class="highlight">Partners</h2>
</div>
</div>
<ul class="list-group list-group-flush">
{% for partner in partners %}
<li class="list-group-item">{% include 'partners/_partner_card.html' with partner=partner %}</li>
{% endfor %}
</ul>
</div>
<div class="tab-pane" id="agreements" role="tabpanel">
<div class="row">
<div class="col-12">
<h2 class="highlight">Agreements</h2>
</div>
</div>
<ul>
{% for agreement in agreements %}
<li>{{ agreement }}</li>
{% endfor %}
</ul>
</div>
</div>
<ul>
{% for agreement in agreements %}
<li>{{ agreement }}</li>
{% endfor %}
</ul>
</section>
{% endblock content %}
......@@ -11,4 +11,10 @@ urlpatterns = [
url(r'^manage$', views.manage, name='manage'),
url(r'^add_prospective_partner$', views.add_prospective_partner,
name='add_prospective_partner'),
url(r'^add_prospective_contact/(?P<prospartner_id>[0-9]+)$',
views.add_prospartner_contact,
name='add_prospartner_contact'),
url(r'^add_prospartner_event/(?P<prospartner_id>[0-9]+)$',
views.add_prospartner_event,
name='add_prospartner_event'),
]
from django.contrib import messages
from django.shortcuts import render, reverse, redirect
from django.db import transaction
from django.shortcuts import get_object_or_404, render, reverse, redirect
from django.utils import timezone
from guardian.decorators import permission_required
from .models import Partner, ProspectivePartner, MembershipAgreement
from .forms import ProspectivePartnerForm, MembershipQueryForm
from .models import Partner, ProspectivePartner, ProspectiveContact, \
ProspectivePartnerEvent, MembershipAgreement
from .forms import ProspectivePartnerForm, ProspectiveContactForm, \
ProspectivePartnerEventForm, MembershipQueryForm
def supporting_partners(request):
......@@ -15,20 +18,26 @@ def supporting_partners(request):
return render(request, 'partners/supporting_partners.html', context)
@transaction.atomic
def membership_request(request):
query_form = MembershipQueryForm(request.POST or None)
if query_form.is_valid():
query = ProspectivePartner(
prospartner = ProspectivePartner(
kind=query_form.cleaned_data['partner_kind'],
institution_name=query_form.cleaned_data['institution_name'],
country=query_form.cleaned_data['country'],
date_received=timezone.now(),
status = 'requested',
)
prospartner.save()
contact = ProspectiveContact(
prospartner=prospartner,
title=query_form.cleaned_data['title'],
first_name=query_form.cleaned_data['first_name'],
last_name=query_form.cleaned_data['last_name'],
email=query_form.cleaned_data['email'],
partner_type=query_form.cleaned_data['partner_type'],
institution_name=query_form.cleaned_data['institution_hame'],
country=query_form.cleaned_data['country'],
date_received=timezone.now(),
)
query.save()
contact.save()
ack_message = ('Thank you for your SPB Membership query. '
'We will get back to you in the very near future '
'with further details.')
......@@ -43,22 +52,67 @@ def manage(request):
"""
Lists relevant info regarding management of Supporting Partners Board.
"""
partners = Partner.objects.all().order_by('country', 'institution_name')
prospective_partners = ProspectivePartner.objects.filter(
processed=False).order_by('date_received')
partners = Partner.objects.all()
prospective_partners = ProspectivePartner.objects.all(
).order_by('country', 'institution_name')
ppevent_form = ProspectivePartnerEventForm()
agreements = MembershipAgreement.objects.all().order_by('date_requested')
context = {'partners': partners,
'prospective_partners': prospective_partners,
'ppevent_form': ppevent_form,
'agreements': agreements, }
return render(request, 'partners/manage_partners.html', context)
@permission_required('scipost.can_manage_SPB', return_403=True)
@transaction.atomic
def add_prospective_partner(request):
form = ProspectivePartnerForm(request.POST or None)
form = ProspectivePartnerForm(request.POST or None,
initial={'status': 'added',
'kind': 'Univ. Library'})
if form.is_valid():
form.save()
messages.success(request, 'Prospective Partners successfully added')
return redirect(reverse('partners:manage'))
pp = form.save()
messages.success(request, 'Prospective Partner successfully added')
# return redirect(reverse('partners:manage'))
return redirect(reverse('partners:add_prospartner_contact',
kwargs={'prospartner_id': pp.id}))
context = {'form': form}
return render(request, 'partners/add_prospective_partner.html', context)
@permission_required('scipost.can_manage_SPB', return_403=True)
@transaction.atomic
def add_prospartner_contact(request, prospartner_id):
prospartner = get_object_or_404(ProspectivePartner, pk=prospartner_id)
form = ProspectiveContactForm(
request.POST or None, initial={'prospartner': prospartner })
if form.is_valid():
form.save()
messages.success(request, 'Contact successfully added to Prospective Partner')
return redirect(reverse('partners:manage'))
context = {'form': form,
'prospartner': prospartner }
return render(request, 'partners/add_prospartner_contact.html', context)
@permission_required('scipost.can_manage_SPB', return_403=True)
@transaction.atomic
def add_prospartner_event(request, prospartner_id):
prospartner = get_object_or_404(ProspectivePartner, pk=prospartner_id)
if request.method == 'POST':
ppevent_form = ProspectivePartnerEventForm(request.POST)
if ppevent_form.is_valid():
ppevent = ProspectivePartnerEvent(
prospartner=prospartner,
event=ppevent_form.cleaned_data['event'],
comments=ppevent_form.cleaned_data['comments'],
noted_on=timezone.now(),
noted_by=request.user.contributor,)
ppevent.save()
return redirect(reverse('partners:manage'))
else:
errormessage = 'The form was invalidly filled.'
return render(request, 'scipost/error.html', {'errormessage': errormessage})
else:
errormessage = 'This view can only be posted to.'
return render(request, 'scipost/error.html', {'errormessage': errormessage})
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment