Skip to content

Commit

Permalink
fix PyAr#50 custom thankyou page and send application letter
Browse files Browse the repository at this point in the history
Signed-off-by: Matias Varela <[email protected]>
  • Loading branch information
matuu committed Jun 3, 2019
1 parent e35e1ea commit d4f2922
Show file tree
Hide file tree
Showing 13 changed files with 392 additions and 174 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,4 @@ scripts/*.csv
scripts/credentials.json
.idea
.vscode
/media/
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ RUN mkdir /code
RUN mkdir /config

# Install dependencies
RUN printf "deb http://archive.debian.org/debian/ jessie main\ndeb-src http://archive.debian.org/debian/ jessie main\ndeb http://security.debian.org jessie/updates main\ndeb-src http://security.debian.org jessie/updates main" > /etc/apt/sources.list
RUN apt-get update && apt-get install -y inkscape && apt-get clean
COPY /config/requirements.txt /config/
RUN pip install --no-cache-dir -r /config/requirements.txt
Expand Down
16 changes: 11 additions & 5 deletions website/members/forms.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django import forms
from django.db.transaction import atomic
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.utils.timezone import now
Expand Down Expand Up @@ -70,19 +71,24 @@ def __init__(self, *args, **kwargs):
),
)

@atomic
def save(self, commit=True):
# We need remove category before save person.
category = self.cleaned_data.pop('category', '')
person = super(SignupPersonForm, self).save(commit=False)
person.comments = (
"Se cargó a través del sitio web. Categoria seleccionada: %s." % category.name)
patron = Patron(
name=f"{person.first_name} {person.last_name}",
email=person.email, comments="Se cargó a través del sitio web")
patron, created = Patron.objects.get_or_create(
email=person.email,
defaults={
'name': f"{person.first_name} {person.last_name}",
'comments': "Se cargó a través del sitio web"
})
member = Member(registration_date=now(), category=category)
member.patron = patron
if commit:
patron.save()
member.patron = patron
file, filename = member._generate_letter(person)
member.application_letter.save(filename, file, save=True)
member.save()
person.membership = member
person.save()
Expand Down
18 changes: 18 additions & 0 deletions website/members/migrations/0021_member_application_letter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.0.4 on 2019-03-05 03:41

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('members', '0020_auto_20190209_1148'),
]

operations = [
migrations.AddField(
model_name='member',
name='application_letter',
field=models.FileField(blank=True, null=True, upload_to='application_letter', verbose_name='carta de afiliación'),
),
]
14 changes: 14 additions & 0 deletions website/members/migrations/0024_merge_20190602_1955.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Generated by Django 2.0.4 on 2019-06-02 19:55

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('members', '0021_member_application_letter'),
('members', '0023_auto_20190407_1624'),
]

operations = [
]
71 changes: 71 additions & 0 deletions website/members/models.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import os

import certg

from django.core.validators import MaxValueValidator, MinValueValidator
from django.core.files import File
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django_extensions.db.models import TimeStampedModel


DEFAULT_MAX_LEN = 317 # Almost random
LONG_MAX_LEN = 2048 # Random but bigger

Expand Down Expand Up @@ -60,6 +66,8 @@ class Member(TimeStampedModel):
null=True, blank=True)
first_payment_year = models.PositiveSmallIntegerField(
_('primer pago año'), validators=[MinValueValidator(2015)], null=True, blank=True)
application_letter = models.FileField(
_('carta de afiliación'), upload_to='application_letter', null=True, blank=True)

# Flags
has_student_certificate = models.BooleanField(
Expand All @@ -86,6 +94,69 @@ def __str__(self):
shutdown = "" if self.shutdown_date is None else ", DADO DE BAJA"
return f"{legal_id} - [{self.category}{shutdown}] {self.entity}"

def _generate_letter(self, person):
"""Generate the letter to be signed."""
letter_svg_template = os.path.join(
os.path.abspath('.'), 'members', 'templates', 'members', 'carta.svg')
path_prefix = "/tmp/letter"
person_info = {
'tiposocie': self.category.name,
'nombre': person.first_name,
'apellido': person.last_name,
'dni': person.document_number,
'email': person.email,
'nacionalidad': person.nationality,
'estadocivil': person.marital_status,
'profesion': person.occupation,
'fechanacimiento': person.birth_date.strftime("%Y-%m-%d"),
'domicilio': person.street_address,
'ciudad': person.city,
'codpostal': person.zip_code,
'provincia': person.province,
'pais': person.country,
}

# this could be optimized to generate all PDFs at once, but we're fine so far
(letter_filepath, ) = certg.process(
letter_svg_template, path_prefix, "dni", [person_info], images=None)
f_opened = open(letter_filepath, 'rb')
file = File(f_opened)
return file, letter_filepath.split('/')[-1]

def _analyze(self):
"""Analyze and indicate in which categories the member is missing somethhing."""
cat_student = Category.objects.get(name=Category.STUDENT)
cat_collab = Category.objects.get(name=Category.COLLABORATOR)

# simple flags with "Not Applicable" situation
missing_student_certif = (
self.category == cat_student and not self.has_student_certificate)
missing_collab_accept = (
self.category == cat_collab and not self.has_collaborator_acceptance)

# info from Person
missing_nickname = self.person.nickname == ""
# picture is complicated, bool() is used to check if the Image field has an associated
# filename, and False itself is used as the "dont want a picture!" flag
missing_picture = not self.person.picture and self.person.picture is not False

# info from Member itself
missing_payment = self.first_payment_month is None and self.category.fee > 0
missing_signed_letter = not self.has_subscription_letter

missing_info = {
'missing_signed_letter': missing_signed_letter,
'missing_student_certif': missing_student_certif,
'missing_payment': missing_payment,
'missing_nickname': missing_nickname,
'missing_picture': missing_picture,
'missing_collab_accept': missing_collab_accept,
}
missing_info['annual_fee'] = self.category.fee * 12
missing_info['member'] = self
missing_info['on_purpose_missing_var'] = "ERROR"
return missing_info


def picture_upload_path(instance, filename):
"""Customize the picture's upload path to MEDIA_ROOT/pictures/lastname_document.ext."""
Expand Down
119 changes: 119 additions & 0 deletions website/members/templates/members/signup_person_thankyou.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
{% extends "members/signup_initial.html" %}
{% load crispy_forms_tags %}
{% block inner-content %}
<div class="categories">
<h4 class="alert alert-success"> Su solicitud fue enviada con éxito</h4>
<h3>Próximos pasos</h3>
{% if missing_signed_letter %}
<p>
Tenés que mandar una carta en papel, firmada, expresando tu intención de querer asociarte (es un paso
necesario desde el punto de vista legal).

Nosotros te la generamos automáticamente (<a target="_blank" href="{{ object.application_letter.url }}">descargar</a>),
revisá los datos, imprimila y a mano poné lugar y fecha, firmá, aclará y poné tu DNI.
</p>
<p>
Para acelerar el trámite, sacale una foto y mandánosla, pero también la vas a tener que mandar por correo postal
o llevarla en mano a la sede de la Asociación Civil <strong>**</strong> (o traerla a algún evento de PyAr y
dársela a cualquiera de la Comisión Directiva).
</p>
{% endif %}

{% if missing_student_certif %}
<p>
Como sos socia/o "Estudiante", necesitamos un Certificado de Alumna/o Regular.

Cuando lo consigas, para acelerar el trámite, sacale una foto y mandánosla, pero también la
vas a tener que mandar por correo postal o llevarla en mano a la sede de la Asociación Civil <strong>**</strong> (o
traerla a algún evento de PyAr y dársela a cualquiera de la Comisión Directiva).
</p>
{% endif %}

{% if missing_payment %}
<p>
Tenés que pagar la cuota social. En tu caso, para Socia/o tipo {{ object.category }},
son ${{ object.category.fee }} por mes, y lo podés abonar de distintas maneras:</p>
<p>
Débito mensual, usando una tarjeta de crédito:
{% if object.category == object.category.ACTIVE %}
<a href="http://mpago.la/1WDPgB">http://mpago.la/1WDPgB</a>
{% elif object.category == object.category.SUPPORTER %}
<a href="http://mpago.la/3c4foF">http://mpago.la/3c4foF</a>
{% else %}
{{ on_purpose_missing_var }}
{% endif %}
</p>
{% endif %}

<p>
También podés pagar el año entero (un total de ${{ annual_fee }}) directamente por transferencia o depósito a...
<br>
<blockquote>
Asociación Civil Python Argentina<br>
Banco Credicoop<br>
Cuenta Corriente en pesos<br>
Nro. 191-153-009748/3<br>
CBU 19101530-55015300974832<br>
Alias python
</blockquote>

... o con tarjetas de crédito, débito, pagofácil, rapipago, etc:

{% if object.category == object.category.ACTIVE %}
<a href="https://forms.todopago.com.ar/formulario/commands?command=formulario&fr=1&m=4dee293be8f02f0a40d94e9d580c306b">Pagar con TodoPago</a>

{% elif object.category == object.category.SUPPORTER %}
<a href="https://forms.todopago.com.ar/formulario/commands?command=formulario&fr=1&m=7bc16ade2a98bf5953aca03084d433b6">Pagar con Todo</a>

{% else %}
{{ on_purpose_missing_var }}
{% endif %}
</p>
{% if missing_nickname %}
<p>
Pasanos un nick o sobrenombre, para el carnet de asociada/o, totalmente opcional (pero si no
querés avisanos así dejamos de pedirte).
</p>
{% endif %}

{% if missing_picture %}
<p>
Pasanos una foto cuadrada o cualquier imagen cuadrada, para el carnet de asociada/o, totalmente opcional
(pero si no querés avisanos así dejamos de pedirte).
</p>
{% endif %}

{% if missing_collab_accept %}
<p>
Como sos socia/o "Colaborador/a", tenés que anotarte para colaborar.<br>

La dinámica es la siguiente: tenemos un grupo de Telegram donde distintos responsables de la
Asociación Civil podemos pedir cosas y vos u otro/a socio/a lo pueden agarrar para hacer. Ejemplo de
un pedido posible: "hay que arreglar un bug en el sistema de gestión de la Asoc Civil (hecho en Django)
que no muestra tal cosa en tal lugar".<br>

Obvio, cada uno agarrará lo que pueda resolver, pero la idea es que colaboren Participar en ese canal y
realmente colaborar con lo que la Asociación Civil necesite es condición necesaria para que al año se
renueve la posibilidad de ser socio/a Colaborador/a.<br>

Entonces, pasame por favor tu handle de Telegram así te invito al grupo.
</p>
{% endif %}


{% if missing_signed_letter or missing_student_certif %}
<p>
<strong>**</strong> La dirección de la sede:
<blockquote>
Asociación Civil Python Argentina<br>
Chile 1155, piso 1<br>
CABA (C1098AAW)<br>
Buenos Aires, Argentina<br>
</blockquote>
</p>
{% endif %}
<p>
<a class="btn btn-primary" href="https://ac.python.org.ar">Ir a la página de la asociación</a>
</p>
</div>
{% endblock %}
19 changes: 10 additions & 9 deletions website/members/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from django.utils.timezone import now, make_aware
from django.urls import reverse

from members import logic, views
from members import logic, utils
from members.models import (
Member, Patron, Category, PaymentStrategy, Quota, Person,
Organization)
Expand Down Expand Up @@ -99,13 +99,14 @@ def test_signup_submit_success(self):
response = self.client.get(reverse('signup_person'))
response = self.client.post(reverse('signup_person'), data=data)
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, reverse('signup_thankyou'))
person = Person.objects.get(nickname='pepepin')
self.assertEqual(response.url, reverse('signup_person_thankyou', args=[person.membership_id]))
self.assertEqual(person.first_name, 'Pepe')
self.assertEqual(person.email, '[email protected]')
self.assertEqual(person.birth_date, datetime.date(1999, 12, 11))
self.assertEqual(person.membership.category.pk, cat.pk)
self.assertEqual(person.membership.patron.email, person.email)
self.assertIsNotNone(person.membership.application_letter)

def test_signup_submit_success_without_optionals(self):
# crear categoria
Expand All @@ -130,8 +131,8 @@ def test_signup_submit_success_without_optionals(self):
response = self.client.get(reverse('signup_person'))
response = self.client.post(reverse('signup_person'), data=data)
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, reverse('signup_thankyou'))
person = Person.objects.get(document_number='124354656')
self.assertEqual(response.url, reverse('signup_person_thankyou', args=[person.membership_id]))
self.assertEqual(person.first_name, 'Pepe')
self.assertEqual(person.email, '[email protected]')
self.assertEqual(person.birth_date, datetime.date(1999, 12, 11))
Expand Down Expand Up @@ -175,7 +176,7 @@ def test_signup_org_submit_success(self):
response = self.client.get(reverse('signup_organization'))
response = self.client.post(reverse('signup_organization'), data=data)
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, reverse('signup_thankyou'))
self.assertEqual(response.url, reverse('signup_organization_thankyou'))
orga = Organization.objects.get(name='Orga')
self.assertEqual(orga.contact_info, random_text)

Expand Down Expand Up @@ -576,21 +577,21 @@ class BuildDebtStringTestCase(TestCase):
"""Tests for the string debt building utility."""

def test_empty(self):
result = views._build_debt_string([])
result = utils.build_debt_string([])
self.assertEqual(result, "-")

def test_1(self):
result = views._build_debt_string([(2018, 8)])
result = utils.build_debt_string([(2018, 8)])
self.assertEqual(result, "1 (2018-08)")

def test_2(self):
result = views._build_debt_string([(2018, 8), (2018, 9)])
result = utils.build_debt_string([(2018, 8), (2018, 9)])
self.assertEqual(result, "2 (2018-08, 2018-09)")

def test_3(self):
result = views._build_debt_string([(2018, 8), (2018, 9), (2018, 10)])
result = utils.build_debt_string([(2018, 8), (2018, 9), (2018, 10)])
self.assertEqual(result, "3 (2018-08, 2018-09, 2018-10)")

def test_exceeding(self):
result = views._build_debt_string([(2018, 8), (2018, 9), (2018, 10), (2018, 11)])
result = utils.build_debt_string([(2018, 8), (2018, 9), (2018, 10), (2018, 11)])
self.assertEqual(result, "4 (2018-08, 2018-09, 2018-10, ...)")
5 changes: 4 additions & 1 deletion website/members/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
urlpatterns = [
path('solicitud-alta/', views.signup_initial, name='signup'),
path('solicitud-alta/persona/', views.signup_form_person, name='signup_person'),
path('solicitud-alta/persona/<pk>/gracias',
views.signup_thankyou, name='signup_person_thankyou'),
path('solicitud-alta/organizacion',
views.signup_form_organization, name='signup_organization'),
path('solicitud-alta/gracias', views.signup_thankyou, name='signup_thankyou'),
path('solicitud-alta/organizacion/gracias',
views.signup_organization_thankyou, name='signup_organization_thankyou'),

path('reportes/', views.reports_main, name='reports_main'),
path('reportes/deudas', views.report_debts, name='report_debts'),
Expand Down
Loading

0 comments on commit d4f2922

Please sign in to comment.