misc: add a stub invoices connector (#10346)

This commit is contained in:
Frédéric Péters 2016-03-19 17:07:10 +01:00
parent b71ec791e2
commit ad45cbcf62
9 changed files with 402 additions and 0 deletions

View File

@ -0,0 +1,27 @@
# passerelle - uniform access to multiple data sources and services
# Copyright (C) 2016 Entr'ouvert
#
# 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 django.apps
class AppConfig(django.apps.AppConfig):
name = 'passerelle.contrib.stub_invoices'
label = 'stub_invoices'
def get_after_urls(self):
from . import urls
return urls.urlpatterns
default_app_config = 'passerelle.contrib.stub_invoices.AppConfig'

View File

@ -0,0 +1,30 @@
# passerelle - uniform access to multiple data sources and services
# Copyright (C) 2016 Entr'ouvert
#
# 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/>.
from django.utils.text import slugify
from django import forms
from .models import StubInvoicesConnector
class StubInvoicesConnectorForm(forms.ModelForm):
class Meta:
model = StubInvoicesConnector
exclude = ('slug', 'users')
def save(self, commit=True):
if not self.instance.slug:
self.instance.slug = slugify(self.instance.title)
return super(StubInvoicesConnectorForm, self).save(commit=commit)

View File

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('base', '0002_auto_20151009_0326'),
]
operations = [
migrations.CreateModel(
name='StubInvoicesConnector',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', models.CharField(max_length=50)),
('slug', models.SlugField()),
('description', models.TextField()),
('users', models.ManyToManyField(to='base.ApiUser', blank=True)),
],
options={
'verbose_name': 'Invoices',
},
),
]

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('stub_invoices', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='stubinvoicesconnector',
name='log_level',
field=models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL'), (b'FATAL', b'FATAL')]),
),
]

View File

@ -0,0 +1,79 @@
# passerelle - uniform access to multiple data sources and services
# Copyright (C) 2016 Entr'ouvert
#
# 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 datetime
from decimal import Decimal
import random
from django.core.urlresolvers import reverse
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from passerelle.base.models import BaseResource
class StubInvoicesConnector(BaseResource):
category = _('Stub Connectors')
class Meta:
verbose_name = _('Invoices')
@classmethod
def get_icon_class(cls):
return 'ressources'
@classmethod
def get_verbose_name(cls):
return cls._meta.verbose_name
def get_absolute_url(self):
return reverse('stub-invoices-view', kwargs={'slug': self.slug})
@classmethod
def get_add_url(cls):
return reverse('stub-invoices-add')
# generate a serie of stub invoices
invoices = {}
for i in range(15):
now = timezone.now()
id_ = '%d%04d' % (now.year, i+1)
invoices[id_] = {
'id': id_,
'display_id': id_,
'total_amount': Decimal(random.randint(100, 10000)) / 100,
'has_pdf': bool(i%3),
'created': now - datetime.timedelta(days=20) + datetime.timedelta(days=i),
'label': 'Label %s' % id_,
'pay_limit_date': now + datetime.timedelta(days=2+random.randint(0, 10)),
'online_payment': bool(i%2),
'paid': False,
}
if i < 5:
invoices[id_]['payment_date'] = invoices[id_]['created'] + datetime.timedelta(days=1+random.randint(0, 3))
invoices[id_]['online_payment'] = False
invoices[id_]['paid'] = True
elif invoices[id_]['online_payment'] is False:
invoices[id_]['no_online_payment_reason'] = random.choice(['autobilling', 'litigation'])
invoices[id_]['amount'] = invoices[id_]['total_amount']
def get_invoices(self):
return self.invoices.values()
def get_invoice(self, invoice_id):
return self.invoices.get(invoice_id)

View File

@ -0,0 +1,61 @@
{% extends "passerelle/manage.html" %}
{% load i18n passerelle %}
{% block more-user-links %}
{{ block.super }}
{% if object.id %}
<a href="{% url 'stub-invoices-view' slug=object.slug %}">{{ object.title }}</a>
{% endif %}
{% endblock %}
{% block appbar %}
<h2>Stub Invoices - {{ object.title }}</h2>
{% if perms.teamnet_axel.change_teamnet_axel %}
<a rel="popup" class="button" href="{% url 'stub-invoices-edit' slug=object.slug %}">{% trans 'edit' %}</a>
{% endif %}
{% if perms.teamnet_axel.delete_teamnet_axel %}
<a rel="popup" class="button" href="{% url 'stub-invoices-delete' slug=object.slug %}">{% trans 'delete' %}</a>
{% endif %}
{% endblock %}
{% block content %}
<ul>
<li>{% trans 'Get invoice history list:' %}
{% url 'stub-invoices-invoices-history' slug=object.slug as invoices_history_url %}
<a href="{{ invoices_history_url }}">{{ site_base_uri }}{{ invoices_history_url }}?NameID=...</a>
</li>
<li>{% trans 'Get invoice list:' %}
{% url 'stub-invoices-invoices' slug=object.slug as invoices_url %}
<a href="{{ invoices_url }}">{{ site_base_uri }}{{ invoices_url }}?NameID=...</a>
</li>
<li>{% trans 'Show invoice details:' %}
{% url 'stub-invoices-invoice' slug=object.slug invoice_id='20150916' as invoice_details_url %}
<a href="{{ invoice_details_url }}">{{ site_base_uri }}{{ invoice_details_url }}</a>
<em>20150916</em> {% trans 'is invoice identifier' %}
</li>
<li>{% trans 'Get invoice pdf:' %}
{% url 'stub-invoices-invoice-pdf' slug=object.slug invoice_id='20150916' as invoice_download_url %}
<a href="{{ invoice_download_url }}">{{ site_base_uri }}{{ invoice_download_url }}</a>
</li>
<li>{% trans 'Pay invoice:' %}
{% url 'stub-invoices-invoice-payment' slug=object.slug invoice_id='20150808' as payment_url %}
<a href="{{ payment_url }}">{{ site_base_uri }}{{ payment_url }}?NameID=...</a>
</li>
</ul>
</div>
{% if perms.base.view_accessright %}
<div>
<h3>{% trans "Security" %}</h3>
<p>
{% trans 'Access is limited to the following API users:' %}
</p>
{% access_rights_table resource=object permission='can_access' %}
{% endif %}
</div>
{% endblock %}

View File

@ -0,0 +1,57 @@
# passerelle - uniform access to multiple data sources and services
# Copyright (C) 2016 Entr'ouvert
#
# 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/>.
from django.conf.urls import patterns, include, url
from passerelle.urls_utils import decorated_includes, required, app_enabled
from django.contrib.auth.decorators import login_required
from .views import *
public_urlpatterns = patterns('',
url(r'^(?P<slug>[\w,-]+)/$', StubInvoicesConnectorDetailView.as_view(),
name='stub-invoices-view'),
url(r'^(?P<slug>[\w,-]+)/invoices/history/$', HistoryInvoicesView.as_view(),
name='stub-invoices-invoices-history'),
url(r'^(?P<slug>[\w,-]+)/invoices/$', InvoicesView.as_view(),
name='stub-invoices-invoices'),
url(r'^(?P<slug>[\w,-]+)/invoice/(?P<invoice_id>[\w,-]+)/$', InvoiceView.as_view(),
name='stub-invoices-invoice'),
url(r'^(?P<slug>[\w,-]+)/invoice/(?P<invoice_id>[\w,-]+)/pdf/$', InvoicePDFView.as_view(),
name='stub-invoices-invoice-pdf'),
url(r'^(?P<slug>[\w,-]+)/invoice/(?P<invoice_id>[\w,-]+)/pay/$',
InvoicePayView.as_view(),
name='stub-invoices-invoice-payment'),
)
management_urlpatterns = patterns('',
url(r'^add$', StubInvoicesConnectorCreateView.as_view(),
name='stub-invoices-add'),
url(r'^(?P<slug>[\w,-]+)/edit$', StubInvoicesConnectorUpdateView.as_view(),
name='stub-invoices-edit'),
url(r'^(?P<slug>[\w,-]+)/delete$', StubInvoicesConnectorDeleteView.as_view(),
name='stub-invoices-delete'),
)
urlpatterns = required(
app_enabled('stub_invoices'),
patterns('',
url(r'^stub-invoices/', include(public_urlpatterns)),
url(r'^manage/stub-invoices/',
decorated_includes(login_required, include(management_urlpatterns))),
)
)

View File

@ -0,0 +1,102 @@
# passerelle - uniform access to multiple data sources and services
# Copyright (C) 2016 Entr'ouvert
#
# 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 json
from django.core.urlresolvers import reverse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.http import HttpResponse, Http404
from passerelle import utils
from .models import StubInvoicesConnector
from .forms import StubInvoicesConnectorForm
class StubInvoicesConnectorDetailView(DetailView):
model = StubInvoicesConnector
template_name = 'passerelle/stub-invoices/detail.html'
class StubInvoicesConnectorCreateView(CreateView):
model = StubInvoicesConnector
form_class = StubInvoicesConnectorForm
template_name = 'passerelle/manage/service_form.html'
class StubInvoicesConnectorUpdateView(UpdateView):
model = StubInvoicesConnector
form_class = StubInvoicesConnectorForm
template_name = 'passerelle/manage/service_form.html'
class StubInvoicesConnectorDeleteView(DeleteView):
model = StubInvoicesConnector
template_name = 'passerelle/manage/service_confirm_delete.html'
def get_success_url(self):
return reverse('manage-home')
class InvoicesView(DetailView):
model = StubInvoicesConnector
@utils.to_json('api')
def get(self, request, *args, **kwargs):
return [x for x in self.get_object().get_invoices() if not x.get('payment_date')]
class HistoryInvoicesView(DetailView):
model = StubInvoicesConnector
@utils.to_json('api')
def get(self, request, *args, **kwargs):
return [x for x in self.get_object().get_invoices() if x.get('payment_date')]
class InvoiceView(DetailView):
model = StubInvoicesConnector
@utils.to_json('api')
def get(self, request, *args, **kwargs):
return self.get_object().get_invoice(kwargs.get('invoice_id'))
class InvoicePDFView(DetailView):
model = StubInvoicesConnector
def get(self, request, *args, **kwargs):
invoice_id = kwargs['invoice_id']
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="%s.pdf"' % invoice_id
response.write('')
return response
class InvoicePayView(DetailView):
model = StubInvoicesConnector
@method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):
return super(InvoicePayView, self).dispatch(*args, **kwargs)
@utils.to_json('api')
@utils.protected_api('can_access')
def post(self, request, *args, **kwargs):
return utils.response_for_json(request, {'data': None})