0001-invoicing-link-between-Regie-and-Agenda-71074.patch
lingo/agendas/migrations/0004_regie.py | ||
---|---|---|
1 |
import django.db.models.deletion |
|
2 |
from django.db import migrations, models |
|
3 | ||
4 | ||
5 |
class Migration(migrations.Migration): |
|
6 | ||
7 |
dependencies = [ |
|
8 |
('invoicing', '0001_initial'), |
|
9 |
('agendas', '0003_check_type_group'), |
|
10 |
] |
|
11 | ||
12 |
operations = [ |
|
13 |
migrations.AddField( |
|
14 |
model_name='agenda', |
|
15 |
name='regie', |
|
16 |
field=models.ForeignKey( |
|
17 |
blank=True, |
|
18 |
null=True, |
|
19 |
on_delete=django.db.models.deletion.SET_NULL, |
|
20 |
to='invoicing.Regie', |
|
21 |
verbose_name='Regie', |
|
22 |
), |
|
23 |
), |
|
24 |
] |
lingo/agendas/models.py | ||
---|---|---|
36 | 36 |
null=True, |
37 | 37 |
on_delete=models.SET_NULL, |
38 | 38 |
) |
39 |
regie = models.ForeignKey( |
|
40 |
'invoicing.Regie', |
|
41 |
verbose_name=_('Regie'), |
|
42 |
blank=True, |
|
43 |
null=True, |
|
44 |
on_delete=models.SET_NULL, |
|
45 |
) |
|
39 | 46 | |
40 | 47 |
def __str__(self): |
41 | 48 |
return self.label |
lingo/invoicing/templates/lingo/invoicing/manager_regie_detail.html | ||
---|---|---|
15 | 15 |
{% endblock %} |
16 | 16 | |
17 | 17 |
{% block content %} |
18 |
{% if regie.description %} |
|
19 |
<div class="bo-block">{{regie.description}}</div> |
|
20 |
{% endif %} |
|
21 |
<div class="bo-block"> |
|
22 |
<h3>{% trans "Parameters" %}</h3> |
|
23 |
<ul> |
|
24 |
<li>{% trans "slug" %} : {{regie.slug}}</li> |
|
25 |
<li>{% trans "cashier role" %} : {{regie.cashier_role}}</li> |
|
26 |
</ul> |
|
18 |
<div class="section"> |
|
19 |
<div class="pk-tabs"> |
|
20 |
<div class="pk-tabs--tab-list" role="tablist"> |
|
21 |
<button aria-controls="panel-settings" aria-selected="true" id="tab-settings" role="tab" tabindex="0">{% trans "Settings" %}</button> |
|
22 |
<button aria-controls="panel-usage" aria-selected="false" id="tab-usage" role="tab" tabindex="-1">{% trans "Used in agendas" %}</button> |
|
23 |
</div> |
|
24 |
<div class="pk-tabs--container"> |
|
25 | ||
26 |
<div aria-labelledby="tab-settings" id="panel-settings" role="tabpanel" tabindex="0"> |
|
27 |
{% if regie.description %} |
|
28 |
<h3>{% trans "Description" %}</h3> |
|
29 |
<p>{{ regie.description|linebreaksbr }}</p> |
|
30 |
{% endif %} |
|
31 |
<h3>{% trans "Parameters" %}</h3> |
|
32 |
<ul> |
|
33 |
<li>{% trans "Identifier:" %} {{ regie.slug }}</li> |
|
34 |
<li>{% trans "Cashier role:" %} {{ regie.cashier_role }}</li> |
|
35 |
</ul> |
|
36 |
</div> |
|
37 | ||
38 |
<div aria-labelledby="tab-usage" hidden="" id="panel-usage" role="tabpanel" tabindex="0"> |
|
39 |
{% if agendas %} |
|
40 |
<ul class="objects-list single-links"> |
|
41 |
{% for agenda in agendas %} |
|
42 |
<li> |
|
43 |
<a href="{% url 'lingo-manager-agenda-detail' pk=agenda.pk %}"> |
|
44 |
{{ agenda.label }} |
|
45 |
</a> |
|
46 |
</li> |
|
47 |
{% endfor %} |
|
48 |
</ul> |
|
49 |
{% else %} |
|
50 |
<div class="big-msg-info"> |
|
51 |
{% blocktrans trimmed %} |
|
52 |
This Regie is not used yet. |
|
53 |
{% endblocktrans %} |
|
54 |
</div> |
|
55 |
{% endif %} |
|
56 |
</div> |
|
57 | ||
58 |
</div> |
|
59 |
</div> |
|
27 | 60 |
</div> |
28 | 61 |
{% endblock %} |
lingo/invoicing/views.py | ||
---|---|---|
34 | 34 |
UpdateView, |
35 | 35 |
) |
36 | 36 | |
37 |
from lingo.agendas.models import Agenda |
|
37 | 38 |
from lingo.invoicing.models import Regie, RegieImportError |
38 | 39 |
from lingo.pricing.forms import ImportForm |
39 | 40 | |
... | ... | |
83 | 84 |
model = Regie |
84 | 85 | |
85 | 86 |
def get_context_data(self, **kwargs): |
86 |
context = super().get_context_data(**kwargs)
|
|
87 |
context['regie'] = self.object
|
|
88 |
return context
|
|
87 |
kwargs['regie'] = self.object
|
|
88 |
kwargs['agendas'] = Agenda.objects.filter(regie=self.object)
|
|
89 |
return super().get_context_data(**kwargs)
|
|
89 | 90 | |
90 | 91 | |
91 | 92 |
regie_detail = RegieDetailView.as_view() |
lingo/pricing/templates/lingo/pricing/manager_agenda_detail.html | ||
---|---|---|
22 | 22 |
<div class="pk-tabs--tab-list" role="tablist"> |
23 | 23 |
<button aria-controls="panel-pricings" aria-selected="true" id="tab-pricings" role="tab" tabindex="0">{% trans "Pricings" context 'agenda pricing' %}</button> |
24 | 24 |
<button aria-controls="panel-check" aria-selected="false" id="tab-check" role="tab" tabindex="-1">{% trans "Booking check options" %}</button> |
25 |
<button aria-controls="panel-invoicing" aria-selected="false" id="tab-invoicing" role="tab" tabindex="-1">{% trans "Invoicing options" %}</button> |
|
25 | 26 |
</div> |
26 | 27 |
<div class="pk-tabs--container"> |
27 | 28 | |
... | ... | |
96 | 97 |
</div> |
97 | 98 |
</div> |
98 | 99 | |
100 |
<div aria-labelledby="tab-invoicing" hidden="" id="panel-invoicing" role="tabpanel" tabindex="0"> |
|
101 |
<ul> |
|
102 |
<li>{% trans "Regie:" %} {{ object.regie|default:"" }}</li> |
|
103 |
</ul> |
|
104 |
<div class="panel--buttons"> |
|
105 |
<a rel="popup" class="button" href="{% url 'lingo-manager-agenda-invoicing-settings' pk=object.pk %}">{% trans 'Configure' %}</a> |
|
106 |
</div> |
|
107 |
</div> |
|
108 | ||
99 | 109 |
</div> |
100 | 110 |
</div> |
101 | 111 |
</div> |
lingo/pricing/urls.py | ||
---|---|---|
153 | 153 |
views.agenda_booking_check_settings, |
154 | 154 |
name='lingo-manager-agenda-booking-check-settings', |
155 | 155 |
), |
156 |
path( |
|
157 |
'agenda/<int:pk>/invoicing-options/', |
|
158 |
views.agenda_invoicing_settings, |
|
159 |
name='lingo-manager-agenda-invoicing-settings', |
|
160 |
), |
|
156 | 161 |
path( |
157 | 162 |
'agenda-pricings/', |
158 | 163 |
views.agenda_pricing_list, |
lingo/pricing/views.py | ||
---|---|---|
747 | 747 |
agenda_booking_check_settings = AgendaBookingCheckSettingsView.as_view() |
748 | 748 | |
749 | 749 | |
750 |
class AgendaInvoicingSettingsView(AgendaMixin, UpdateView): |
|
751 |
template_name = 'lingo/pricing/manager_agenda_form.html' |
|
752 |
model = Agenda |
|
753 |
fields = ['regie'] |
|
754 |
tab_anchor = 'invoicing' |
|
755 | ||
756 |
def get_context_data(self, **kwargs): |
|
757 |
context = super().get_context_data(**kwargs) |
|
758 |
context['form_url'] = reverse('lingo-manager-agenda-invoicing-settings', args=[self.agenda.pk]) |
|
759 |
context['title'] = _("Configure invoicing options") |
|
760 |
return context |
|
761 | ||
762 | ||
763 |
agenda_invoicing_settings = AgendaInvoicingSettingsView.as_view() |
|
764 | ||
765 | ||
750 | 766 |
class AgendaPricingListView(ListView): |
751 | 767 |
template_name = 'lingo/pricing/manager_agenda_pricing_list.html' |
752 | 768 |
model = AgendaPricing |
tests/invoicing/test_manager.py | ||
---|---|---|
6 | 6 |
from django.urls import reverse |
7 | 7 |
from webtest import Upload |
8 | 8 | |
9 |
from lingo.agendas.models import Agenda |
|
9 | 10 |
from lingo.invoicing.models import Regie |
10 | 11 |
from tests.utils import login |
11 | 12 | |
... | ... | |
95 | 96 |
resp = app.get(reverse('lingo-manager-invoicing-regie-detail', kwargs={'pk': regie.pk})) |
96 | 97 |
h2 = resp.pyquery('div#appbar h2') |
97 | 98 |
assert h2.text() == 'Regie - Foo' |
98 |
descr = resp.pyquery('div#content div.bo-block')[0]
|
|
99 |
descr = resp.pyquery('div#panel-settings p')[0]
|
|
99 | 100 |
assert descr.text == 'foo description' |
100 |
slug = resp.pyquery('div#content div.bo-block ul li')[0] |
|
101 |
assert slug.text == 'slug\xa0: foo' |
|
102 |
cashier_role = resp.pyquery('div#content div.bo-block ul li')[1] |
|
103 |
assert cashier_role.text == 'cashier role\xa0: role-foo' |
|
101 |
slug = resp.pyquery('div#panel-settings ul li')[0] |
|
102 |
assert slug.text == 'Identifier: foo' |
|
103 |
cashier_role = resp.pyquery('div#panel-settings ul li')[1] |
|
104 |
assert cashier_role.text == 'Cashier role: role-foo' |
|
105 |
usage = resp.pyquery('div#panel-usage div')[0] |
|
106 |
assert 'This Regie is not used yet.' in usage.text |
|
104 | 107 |
edit_button = resp.pyquery( |
105 | 108 |
'span.actions a[href="%s"]' % reverse('lingo-manager-invoicing-regie-edit', kwargs={'pk': regie.pk}) |
106 | 109 |
) |
... | ... | |
110 | 113 |
) |
111 | 114 |
assert delete_button.text() == 'Delete' |
112 | 115 | |
116 |
agenda1 = Agenda.objects.create(label='Foo Bar', regie=regie) |
|
117 |
agenda2 = Agenda.objects.create(label='Foo Bar 2', regie=regie) |
|
118 |
agenda3 = Agenda.objects.create(label='Foo Bar 3') |
|
119 |
resp = app.get(reverse('lingo-manager-invoicing-regie-detail', kwargs={'pk': regie.pk})) |
|
120 |
assert '/manage/pricing/agenda/%s/' % agenda1.pk in resp |
|
121 |
assert '/manage/pricing/agenda/%s/' % agenda2.pk in resp |
|
122 |
assert '/manage/pricing/agenda/%s/' % agenda3.pk not in resp |
|
123 | ||
113 | 124 | |
114 | 125 |
def test_manager_invoicing_regie_edit(app, admin_user): |
115 | 126 |
app = login(app) |
... | ... | |
151 | 162 |
app = login(app) |
152 | 163 |
group = Group.objects.create(name='role-foo') |
153 | 164 |
regie1 = Regie.objects.create(label='Foo', description='foo description', cashier_role=group) |
154 |
regie2 = Regie.objects.create(label='Bar', description='bar description', cashier_role=group)
|
|
165 |
Regie.objects.create(label='Bar', description='bar description', cashier_role=group) |
|
155 | 166 |
response = app.get(reverse('lingo-manager-invoicing-regie-export')) |
156 | 167 |
assert response.headers['content-type'] == 'application/json' |
157 | 168 |
assert response.headers['content-disposition'] == 'attachment; filename="export_regies_20200615.json"' |
tests/pricing/manager/test_agenda.py | ||
---|---|---|
3 | 3 |
import pytest |
4 | 4 | |
5 | 5 |
from lingo.agendas.models import Agenda, CheckTypeGroup |
6 |
from lingo.invoicing.models import Regie |
|
6 | 7 |
from tests.utils import login |
7 | 8 | |
8 | 9 |
pytestmark = pytest.mark.django_db |
... | ... | |
59 | 60 |
agenda.refresh_from_db() |
60 | 61 |
assert agenda.check_type_group == group |
61 | 62 |
assert 'Check type group: Foo bar' in resp |
63 | ||
64 | ||
65 |
def test_edit_agenda_invoicing_settings(app, admin_user): |
|
66 |
agenda = Agenda.objects.create(label='Foo bar') |
|
67 |
regie = Regie.objects.create(label='Foo bar') |
|
68 | ||
69 |
app = login(app) |
|
70 |
resp = app.get('/manage/pricing/agenda/%s/' % agenda.pk) |
|
71 |
resp = resp.click(href='/manage/pricing/agenda/%s/invoicing-options' % agenda.pk) |
|
72 |
resp.form['regie'] = regie.pk |
|
73 |
resp = resp.form.submit().follow() |
|
74 |
agenda.refresh_from_db() |
|
75 |
assert agenda.regie == regie |
|
76 |
assert 'Regie: Foo bar' in resp |
|
62 |
- |