Facturation: bouton et flag "finaliser la campagne" (#75560) #47

Merged
lguerin merged 3 commits from wip/75560-campaign-finalize into main 2023-04-24 09:18:16 +02:00
12 changed files with 423 additions and 21 deletions

View File

@ -206,3 +206,20 @@ def unlock_events_check(agenda_slugs, date_start, date_end):
raise ChronoError(_('Unable to unlock events check'))
if result.get('err'):
raise ChronoError(_('Unable to unlock events check (%s)') % result['err_desc'])
def mark_events_invoiced(agenda_slugs, date_start, date_end):
result = chrono_json(
'/api/agendas/events/invoiced/',
json_params={
'invoiced': True,
'agendas': ','.join(agenda_slugs),
'date_start': date_start.isoformat(),
'date_end': date_end.isoformat(),
},
method='post',
)
if not result:
raise ChronoError(_('Unable to mark events as invoiced'))
if result.get('err'):
raise ChronoError(_('Unable to mark events as invoiced (%s)') % result['err_desc'])

View File

@ -0,0 +1,15 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('invoicing', '0023_campaign_dates'),
]
operations = [
migrations.AddField(
model_name='campaign',
name='finalized',
field=models.BooleanField(default=False),
),
]

View File

@ -147,6 +147,7 @@ class Campaign(models.Model):
)
agendas = models.ManyToManyField(Agenda, related_name='campaigns')
invalid = models.BooleanField(default=False)
finalized = models.BooleanField(default=False)
def __str__(self):
return _('%(label)s (%(start)s - %(end)s)') % {
@ -164,6 +165,10 @@ class Campaign(models.Model):
if commit:
self.save()
def mark_as_finalized(self):
self.finalized = True
self.save()
def generate(self, spool=True):
pool = self.pool_set.create(draft=True)
try:

View File

@ -8,7 +8,7 @@
{% block appbar %}
<h2>{{ object }}</h2>
{% if not has_running_pool and not has_real_pool %}
{% if not object.finalized and not has_running_pool and not has_real_pool %}
<span class="actions">
<a href="{% url 'lingo-manager-invoicing-campaign-delete' regie_pk=regie.pk pk=object.pk %}" rel="popup">{% trans "Delete" %}</a>
<a href="{% url 'lingo-manager-invoicing-campaign-edit' regie_pk=regie.pk pk=object.pk %}">{% trans "Edit" %}</a>
@ -53,7 +53,7 @@
<li>{% trans "Issue date:" %} {{ object.date_issue|date:'d/m/Y' }}</li>
<li>{% trans "Debit date:" %} {{ object.date_debit|date:'d/m/Y' }}</li>
</ul>
{% if not has_running_pool %}
{% if not object.finalized and not has_running_pool %}
<div class="panel--buttons">
<a class="pk-button" rel="popup" href="{% url 'lingo-manager-invoicing-campaign-dates-edit' regie_pk=regie.pk pk=object.pk %}">{% trans 'Edit' %}</a>
</div>
@ -81,13 +81,19 @@
</li>
{% endfor %}
</ul>
{% if not has_running_pool and not has_real_pool %}
<div class="panel--buttons">
<a class="pk-button" rel="popup" href="{% url 'lingo-manager-invoicing-pool-add' regie_pk=regie.pk pk=object.pk %}">{% trans 'Start a pool' %}</a>
{% if not object.invalid %}
<a class="pk-button" rel="popup" href="{% url 'lingo-manager-invoicing-campaign-unlock-check' regie_pk=regie.pk pk=object.pk %}">{% trans 'Unlock check' %}</a>
{% endif %}
</div>
{% if not object.finalized and not has_running_pool %}
{% if not has_real_pool %}
<div class="panel--buttons">
<a class="pk-button" rel="popup" href="{% url 'lingo-manager-invoicing-pool-add' regie_pk=regie.pk pk=object.pk %}">{% trans 'Start a pool' %}</a>
{% if not object.invalid %}
<a class="pk-button" rel="popup" href="{% url 'lingo-manager-invoicing-campaign-unlock-check' regie_pk=regie.pk pk=object.pk %}">{% trans 'Unlock check' %}</a>
{% endif %}
</div>
{% elif has_real_completed_pool %}
<div class="panel--buttons">
<a class="pk-button" rel="popup" href="{% url 'lingo-manager-invoicing-campaign-finalize' regie_pk=regie.pk pk=object.pk %}">{% trans 'Finalize campaign' %}</a>
</div>
{% endif %}
{% endif %}
</div>

View File

@ -0,0 +1,22 @@
{% extends "lingo/invoicing/manager_campaign_detail.html" %}
{% load i18n %}
{% block breadcrumb %}
{{ block.super }}
<a href="{% url 'lingo-manager-invoicing-campaign-finalize' regie.pk object.pk %}">{% trans "Finalize campaign" %}</a>
{% endblock %}
{% block appbar %}
<h2>{% trans "Finalize campaign" %}</h2>
{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
<p>{% trans "Are you sure you want to finalize this campaign?" %}</p>
<div class="buttons">
<button class="submit-button">{% trans "Finalize campaign" %}</button>
<a class="cancel" href="{% url 'lingo-manager-invoicing-campaign-detail' regie.pk object.pk %}">{% trans 'Cancel' %}</a>
</div>
</form>
{% endblock %}

View File

@ -15,11 +15,13 @@
</h2>
<span class="actions">
<a href="{% url 'lingo-manager-invoicing-pool-journal' regie_pk=regie.pk pk=object.pk pool_pk=pool.pk %}">{% trans "Journal" %}</a>
{% if not has_running_pool %}
<a href="{% url 'lingo-manager-invoicing-pool-delete' regie_pk=regie.pk pk=object.pk pool_pk=pool.pk %}" rel="popup">{% trans "Delete" %}</a>
{% endif %}
{% if not object.invalid and pool.draft and pool.status == 'completed' and pool.is_last %}
<a href="{% url 'lingo-manager-invoicing-pool-promote' regie_pk=regie.pk pk=object.pk pool_pk=pool.pk %}" rel="popup">{% trans "Promote" %}</a>
{% if not object.finalized %}
{% if not has_running_pool %}
<a href="{% url 'lingo-manager-invoicing-pool-delete' regie_pk=regie.pk pk=object.pk pool_pk=pool.pk %}" rel="popup">{% trans "Delete" %}</a>
{% endif %}
{% if not object.invalid and pool.draft and pool.status == 'completed' and pool.is_last %}
<a href="{% url 'lingo-manager-invoicing-pool-promote' regie_pk=regie.pk pk=object.pk pool_pk=pool.pk %}" rel="popup">{% trans "Promote" %}</a>
{% endif %}
{% endif %}
</span>
{% endblock %}

View File

@ -69,6 +69,9 @@
<a href="{% url 'lingo-manager-invoicing-campaign-detail' regie_pk=regie.pk pk=campaign.pk %}">
{{ campaign }}
<span class="extra-info"> [{% trans "issue date:" %} {{ campaign.date_issue|date:'d/m/Y' }}]</span>
{% if campaign.finalized %}
<span class="badge">{% trans "finalized" %}</span>
{% endif %}
</a>
</li>
{% endfor %}

View File

@ -73,6 +73,11 @@ urlpatterns = [
views.campaign_unlock_check,
name='lingo-manager-invoicing-campaign-unlock-check',
),
path(
'regie/<int:regie_pk>/campaign/<int:pk>/finalize/',
views.campaign_finalize,
name='lingo-manager-invoicing-campaign-finalize',
),
path(
'regie/<int:regie_pk>/campaign/<int:pk>/pool/add/',
views.pool_add,

View File

@ -39,7 +39,7 @@ from django.views.generic import (
)
from weasyprint import HTML
from lingo.agendas.chrono import ChronoError, unlock_events_check
from lingo.agendas.chrono import ChronoError, mark_events_invoiced, unlock_events_check
from lingo.agendas.models import Agenda
from lingo.invoicing.forms import (
CampaignDatesForm,
@ -288,6 +288,9 @@ class CampaignDetailView(DetailView):
).order_by('-created_at')
kwargs['has_running_pool'] = any(p.status in ['registered', 'running'] for p in kwargs['pools'])
kwargs['has_real_pool'] = any(not p.draft for p in kwargs['pools'])
kwargs['has_real_completed_pool'] = any(
not p.draft and p.status == 'completed' for p in kwargs['pools']
)
if self.object.invalid:
messages.warning(self.request, _('The last pool is invalid, please start a new pool.'))
return super().get_context_data(**kwargs)
@ -309,7 +312,7 @@ class CampaignEditView(UpdateView):
return (
super()
.get_queryset()
.filter(regie=self.regie)
.filter(regie=self.regie, finalized=False)
.exclude(pool__draft=False)
.exclude(pool__status__in=['registered', 'running'])
)
@ -338,7 +341,7 @@ class CampaignDatesEditView(UpdateView):
return (
super()
.get_queryset()
.filter(regie=self.regie)
.filter(regie=self.regie, finalized=False)
.exclude(pool__status__in=['registered', 'running'])
)
@ -367,7 +370,7 @@ class CampaignDeleteView(DeleteView):
return (
super()
.get_queryset()
.filter(regie=self.regie)
.filter(regie=self.regie, finalized=False)
.exclude(pool__draft=False)
.exclude(pool__status__in=['registered', 'running'])
)
@ -392,7 +395,7 @@ class CampaignUnlockCheckView(FormView):
def dispatch(self, request, *args, **kwargs):
self.regie = get_object_or_404(Regie, pk=kwargs['regie_pk'])
self.object = get_object_or_404(
Campaign.objects.filter(regie=self.regie, invalid=False)
Campaign.objects.filter(regie=self.regie, invalid=False, finalized=False)
.exclude(pool__draft=False)
.exclude(pool__status__in=['registered', 'running']),
pk=kwargs['pk'],
@ -427,6 +430,52 @@ class CampaignUnlockCheckView(FormView):
campaign_unlock_check = CampaignUnlockCheckView.as_view()
class CampaignFinalizeView(FormView):
template_name = 'lingo/invoicing/manager_campaign_finalize.html'
def dispatch(self, request, *args, **kwargs):
self.regie = get_object_or_404(Regie, pk=kwargs['regie_pk'])
self.object = get_object_or_404(
Campaign.objects.filter(regie=self.regie, invalid=False, finalized=False).filter(
pk__in=Pool.objects.filter(draft=False, status='completed').values('campaign')
),
pk=kwargs['pk'],
)
return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
kwargs['form'] = None
kwargs['regie'] = self.regie
kwargs['object'] = self.object
return super().get_context_data(**kwargs)
def post(self, request, *args, **kwargs):
try:
agendas = [a.slug for a in self.object.agendas.all()]
if agendas:
try:
mark_events_invoiced(
agenda_slugs=agendas,
date_start=self.object.date_start,
date_end=self.object.date_end,
)
except ChronoError as e:
messages.error(self.request, _('Fail to mark events as invoiced: %s') % e)
raise
except ChronoError:
pass
else:
self.object.mark_as_finalized()
return redirect(
'%s#open:pools'
% reverse('lingo-manager-invoicing-campaign-detail', args=[self.regie.pk, self.object.pk])
)
campaign_finalize = CampaignFinalizeView.as_view()
class PoolDetailView(ListView):
template_name = 'lingo/invoicing/manager_pool_detail.html'
paginate_by = 100
@ -520,7 +569,7 @@ class PoolAddView(FormView):
def dispatch(self, request, *args, **kwargs):
self.regie = get_object_or_404(Regie, pk=kwargs['regie_pk'])
self.object = get_object_or_404(
Campaign.objects.filter(regie=self.regie)
Campaign.objects.filter(regie=self.regie, finalized=False)
.exclude(pool__draft=False)
.exclude(pool__status__in=['registered', 'running']),
pk=kwargs['pk'],
@ -555,6 +604,7 @@ class PoolPromoteView(FormView):
campaign__id=kwargs['pk'],
campaign__regie=self.regie,
campaign__invalid=False,
campaign__finalized=False,
pk=kwargs['pool_pk'],
draft=True,
status='completed',
@ -591,7 +641,9 @@ class PoolDeleteView(DeleteView):
def dispatch(self, request, *args, **kwargs):
self.regie = get_object_or_404(Regie, pk=kwargs['regie_pk'])
self.campaign = get_object_or_404(
Campaign.objects.filter(regie=self.regie).exclude(pool__status__in=['registered', 'running']),
Campaign.objects.filter(regie=self.regie, finalized=False).exclude(
pool__status__in=['registered', 'running']
),
pk=kwargs['pk'],
)
return super().dispatch(request, *args, **kwargs)

View File

@ -14,6 +14,7 @@ from lingo.agendas.chrono import (
get_events,
get_subscriptions,
lock_events_check,
mark_events_invoiced,
refresh_agendas,
unlock_events_check,
)
@ -604,3 +605,75 @@ def test_unlock_events_check_status():
'date_end': '2022-10-01',
}
assert requests_post.call_args_list[0][1]['remote_service']['url'] == 'http://chrono.example.org'
def test_mark_events_invoiced_no_service(settings):
settings.KNOWN_SERVICES = {}
with pytest.raises(ChronoError) as e:
mark_events_invoiced(
agenda_slugs=['foo'],
date_start=datetime.date(2022, 9, 1),
date_end=datetime.date(2022, 10, 1),
)
assert str(e.value) == 'Unable to mark events as invoiced'
settings.KNOWN_SERVICES = {'other': []}
with pytest.raises(ChronoError) as e:
mark_events_invoiced(
agenda_slugs=['foo'],
date_start=datetime.date(2022, 9, 1),
date_end=datetime.date(2022, 10, 1),
)
assert str(e.value) == 'Unable to mark events as invoiced'
def test_mark_events_invoiced_status():
with mock.patch('requests.Session.post') as requests_post:
requests_post.side_effect = ConnectionError()
with pytest.raises(ChronoError) as e:
mark_events_invoiced(
agenda_slugs=['foo', 'bar'],
date_start=datetime.date(2022, 9, 1),
date_end=datetime.date(2022, 10, 1),
)
assert str(e.value) == 'Unable to mark events as invoiced'
with mock.patch('requests.Session.post') as requests_post:
mock_resp = Response()
mock_resp.status_code = 500
requests_post.return_value = mock_resp
with pytest.raises(ChronoError) as e:
mark_events_invoiced(
agenda_slugs=['foo', 'bar'],
date_start=datetime.date(2022, 9, 1),
date_end=datetime.date(2022, 10, 1),
)
assert str(e.value) == 'Unable to mark events as invoiced'
with mock.patch('requests.Session.post') as requests_post:
mock_resp = Response()
mock_resp.status_code = 404
requests_post.return_value = mock_resp
with pytest.raises(ChronoError) as e:
mark_events_invoiced(
agenda_slugs=['foo', 'bar'],
date_start=datetime.date(2022, 9, 1),
date_end=datetime.date(2022, 10, 1),
)
assert str(e.value) == 'Unable to mark events as invoiced'
with mock.patch('requests.Session.post') as requests_post:
requests_post.return_value = MockedRequestResponse(content=json.dumps({'foo': 'bar'}))
mark_events_invoiced(
agenda_slugs=['foo', 'bar'],
date_start=datetime.date(2022, 9, 1),
date_end=datetime.date(2022, 10, 1),
)
assert requests_post.call_args_list[0][0] == ('/api/agendas/events/invoiced/',)
assert requests_post.call_args_list[0][1]['json'] == {
'invoiced': True,
'agendas': 'foo,bar',
'date_start': '2022-09-01',
'date_end': '2022-10-01',
}
assert requests_post.call_args_list[0][1]['remote_service']['url'] == 'http://chrono.example.org'

View File

@ -231,6 +231,7 @@ def test_detail_campaign(app, admin_user):
assert '/manage/invoicing/regie/%s/campaign/%s/pool/%s/' % (regie.pk, campaign.pk, pool2.pk) in resp
assert '/manage/invoicing/regie/%s/campaign/%s/pool/add/' % (regie.pk, campaign.pk) not in resp
assert '/manage/invoicing/regie/%s/campaign/%s/unlock-check/' % (regie.pk, campaign.pk) not in resp
assert '/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk) not in resp
pool2.status = 'running'
pool2.save()
@ -242,6 +243,7 @@ def test_detail_campaign(app, admin_user):
assert '/manage/invoicing/regie/%s/campaign/%s/pool/%s/' % (regie.pk, campaign.pk, pool2.pk) in resp
assert '/manage/invoicing/regie/%s/campaign/%s/pool/add/' % (regie.pk, campaign.pk) not in resp
assert '/manage/invoicing/regie/%s/campaign/%s/unlock-check/' % (regie.pk, campaign.pk) not in resp
assert '/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk) not in resp
pool2.status = 'failed'
pool2.save()
@ -253,6 +255,7 @@ def test_detail_campaign(app, admin_user):
assert '/manage/invoicing/regie/%s/campaign/%s/pool/%s/' % (regie.pk, campaign.pk, pool2.pk) in resp
assert '/manage/invoicing/regie/%s/campaign/%s/pool/add/' % (regie.pk, campaign.pk) in resp
assert '/manage/invoicing/regie/%s/campaign/%s/unlock-check/' % (regie.pk, campaign.pk) in resp
assert '/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk) not in resp
pool3 = Pool.objects.create(
campaign=campaign,
@ -268,8 +271,15 @@ def test_detail_campaign(app, admin_user):
assert '/manage/invoicing/regie/%s/campaign/%s/pool/%s/' % (regie.pk, campaign.pk, pool3.pk) in resp
assert '/manage/invoicing/regie/%s/campaign/%s/pool/add/' % (regie.pk, campaign.pk) not in resp
assert '/manage/invoicing/regie/%s/campaign/%s/unlock-check/' % (regie.pk, campaign.pk) not in resp
assert '/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk) in resp
assert 'The last pool is invalid, please start a new pool.' not in resp
for status in ['running', 'failed', 'registered']:
pool3.status = status
pool3.save()
resp = app.get('/manage/invoicing/regie/%s/campaign/%s/' % (regie.pk, campaign.pk))
assert '/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk) not in resp
pool3.status = 'completed'
pool3.draft = True
pool3.save()
campaign.invalid = True
@ -283,8 +293,23 @@ def test_detail_campaign(app, admin_user):
assert '/manage/invoicing/regie/%s/campaign/%s/pool/%s/' % (regie.pk, campaign.pk, pool3.pk) in resp
assert '/manage/invoicing/regie/%s/campaign/%s/pool/add/' % (regie.pk, campaign.pk) in resp
assert '/manage/invoicing/regie/%s/campaign/%s/unlock-check/' % (regie.pk, campaign.pk) not in resp
assert '/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk) not in resp
assert 'The last pool is invalid, please start a new pool.' in resp
campaign.invalid = False
campaign.finalized = True
campaign.save()
resp = app.get('/manage/invoicing/regie/%s/campaign/%s/' % (regie.pk, campaign.pk))
assert '/manage/invoicing/regie/%s/campaign/%s/edit/' % (regie.pk, campaign.pk) not in resp
assert '/manage/invoicing/regie/%s/campaign/%s/dates/edit/' % (regie.pk, campaign.pk) not in resp
assert '/manage/invoicing/regie/%s/campaign/%s/delete/' % (regie.pk, campaign.pk) not in resp
assert '/manage/invoicing/regie/%s/campaign/%s/pool/%s/' % (regie.pk, campaign.pk, pool1.pk) in resp
assert '/manage/invoicing/regie/%s/campaign/%s/pool/%s/' % (regie.pk, campaign.pk, pool2.pk) in resp
assert '/manage/invoicing/regie/%s/campaign/%s/pool/%s/' % (regie.pk, campaign.pk, pool3.pk) in resp
assert '/manage/invoicing/regie/%s/campaign/%s/pool/add/' % (regie.pk, campaign.pk) not in resp
assert '/manage/invoicing/regie/%s/campaign/%s/unlock-check/' % (regie.pk, campaign.pk) not in resp
assert '/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk) not in resp
line = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
quantity=1,
@ -413,6 +438,12 @@ def test_edit_campaign(app, admin_user):
pool.save()
app.get('/manage/invoicing/regie/%s/campaign/%s/edit/' % (regie.pk, campaign.pk), status=404)
pool.draft = True
pool.save()
campaign.finalized = True
campaign.save()
app.get('/manage/invoicing/regie/%s/campaign/%s/edit/' % (regie.pk, campaign.pk), status=404)
def test_edit_campaign_overlapping_date_start(app, admin_user):
regie = Regie.objects.create(label='Foo')
@ -637,6 +668,14 @@ def test_edit_campaign_dates(app, admin_user):
assert invoice2.date_issue == campaign.date_issue
assert invoice2.date_debit == campaign.date_debit
app.get('/manage/invoicing/regie/%s/campaign/%s/dates/edit/' % (regie.pk, campaign.pk))
app.get('/manage/invoicing/regie/%s/campaign/%s/dates/edit/' % (0, campaign.pk), status=404)
campaign.finalized = True
campaign.save()
app.get('/manage/invoicing/regie/%s/campaign/%s/dates/edit/' % (regie.pk, campaign.pk), status=404)
def test_delete_campaign(app, admin_user):
regie = Regie.objects.create(label='Foo')
@ -753,6 +792,12 @@ def test_add_pool(app, admin_user):
pool.save()
app.get('/manage/invoicing/regie/%s/campaign/%s/pool/add/' % (regie.pk, campaign.pk), status=404)
pool.draft = True
pool.save()
campaign.finalized = True
campaign.save()
app.get('/manage/invoicing/regie/%s/campaign/%s/pool/add/' % (regie.pk, campaign.pk), status=404)
@mock.patch('lingo.invoicing.views.unlock_events_check')
def test_unlock_check(mock_unlock, app, admin_user):
@ -843,6 +888,108 @@ def test_unlock_check(mock_unlock, app, admin_user):
campaign.save()
app.get('/manage/invoicing/regie/%s/campaign/%s/unlock-check/' % (regie.pk, campaign.pk), status=404)
campaign.invalid = False
campaign.finalized = True
campaign.save()
app.get('/manage/invoicing/regie/%s/campaign/%s/unlock-check/' % (regie.pk, campaign.pk), status=404)
@mock.patch('lingo.invoicing.views.mark_events_invoiced')
def test_finalize(mock_invoiced, app, admin_user):
regie = Regie.objects.create(label='Foo')
agenda = Agenda.objects.create(label='Foo bar', regie=regie)
agenda2 = Agenda.objects.create(label='Foo bar 2', regie=regie)
Agenda.objects.create(label='Foo bar 3', regie=regie)
campaign = Campaign.objects.create(
regie=regie,
date_start=datetime.date(2022, 9, 1),
date_end=datetime.date(2022, 10, 1),
date_publication=datetime.date(2022, 10, 1),
date_payment_deadline=datetime.date(2022, 10, 31),
date_issue=datetime.date(2022, 10, 31),
date_debit=datetime.date(2022, 11, 15),
)
pool = Pool.objects.create(
campaign=campaign,
draft=False,
status='completed',
)
app = login(app)
# no agendas
resp = app.get('/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk))
resp = resp.form.submit()
assert resp.location.endswith(
'/manage/invoicing/regie/%s/campaign/%s/#open:pools' % (regie.pk, campaign.pk)
)
assert mock_invoiced.call_args_list == []
campaign.refresh_from_db()
assert campaign.finalized is True
# with agendas
campaign.finalized = False
campaign.save()
campaign.agendas.add(agenda, agenda2)
resp = app.get('/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk))
resp = resp.form.submit()
assert resp.location.endswith(
'/manage/invoicing/regie/%s/campaign/%s/#open:pools' % (regie.pk, campaign.pk)
)
assert mock_invoiced.call_args_list == [
mock.call(
agenda_slugs=['foo-bar', 'foo-bar-2'],
date_start=datetime.date(2022, 9, 1),
date_end=datetime.date(2022, 10, 1),
)
]
campaign.refresh_from_db()
assert campaign.finalized is True
# ChronoError
campaign.finalized = False
campaign.save()
mock_invoiced.side_effect = ChronoError('foo baz')
resp = app.get('/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk))
resp = resp.form.submit().follow()
assert 'Fail to mark events as invoiced: foo baz' in resp
campaign.refresh_from_db()
assert campaign.finalized is False
pool.status = 'failed'
pool.save()
app.get('/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk), status=404)
pool.status = 'completed'
pool.save()
app.get('/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk))
app.get('/manage/invoicing/regie/%s/campaign/%s/finalize/' % (0, campaign.pk), status=404)
pool.status = 'registered'
pool.save()
app.get('/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk), status=404)
pool.status = 'running'
pool.save()
app.get('/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk), status=404)
pool.status = 'completed'
pool.draft = True
pool.save()
app.get('/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk), status=404)
pool.draft = False
pool.save()
campaign.invalid = True
campaign.save()
app.get('/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk), status=404)
campaign.invalid = False
campaign.finalized = True
campaign.save()
app.get('/manage/invoicing/regie/%s/campaign/%s/finalize/' % (regie.pk, campaign.pk), status=404)
def test_promote_pool(app, admin_user):
regie = Regie.objects.create(label='Foo')
@ -913,6 +1060,14 @@ def test_promote_pool(app, admin_user):
)
campaign.invalid = False
campaign.finalized = True
campaign.save()
app.get(
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/promote/' % (regie.pk, campaign.pk, pool.pk),
status=404,
)
campaign.finalized = False
campaign.save()
resp = app.get(
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/promote/' % (regie.pk, campaign.pk, pool.pk)
@ -1021,6 +1176,19 @@ def test_detail_pool(app, admin_user):
)
campaign.invalid = False
campaign.finalized = True
campaign.save()
resp = app.get('/manage/invoicing/regie/%s/campaign/%s/pool/%s/' % (regie.pk, campaign.pk, pool.pk))
assert (
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/delete/' % (regie.pk, campaign.pk, pool.pk)
not in resp
)
assert (
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/promote/' % (regie.pk, campaign.pk, pool.pk)
not in resp
)
campaign.finalized = False
campaign.save()
pool2 = Pool.objects.create(
campaign=pool.campaign,
@ -2360,6 +2528,15 @@ def test_delete_pool(app, admin_user):
status=404,
)
campaign.finalized = True
campaign.save()
app.get(
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/delete/' % (regie.pk, campaign.pk, pool.pk),
status=404,
)
campaign.finalized = False
campaign.save()
pool.draft = False
pool.status = 'error'
pool.save()

View File

@ -115,6 +115,31 @@ def test_manager_invoicing_regie_detail(app, admin_user):
assert '/manage/pricing/agenda/%s/' % agenda2.pk in resp
assert '/manage/pricing/agenda/%s/' % agenda3.pk not in resp
campaign = Campaign.objects.create(
regie=regie,
date_start=datetime.date(2022, 9, 1),
date_end=datetime.date(2022, 10, 1),
date_publication=datetime.date(2022, 10, 1),
date_payment_deadline=datetime.date(2022, 10, 31),
date_issue=datetime.date(2022, 10, 31),
date_debit=datetime.date(2022, 11, 15),
)
resp = app.get(reverse('lingo-manager-invoicing-regie-detail', kwargs={'pk': regie.pk}))
href = resp.pyquery(
'div#panel-campaigns ul li a[href="%s"]'
% reverse('lingo-manager-invoicing-campaign-detail', kwargs={'regie_pk': regie.pk, 'pk': campaign.pk})
)
assert href.text() == '(01/09/2022 - 01/10/2022) [issue date: 31/10/2022]'
campaign.finalized = True
campaign.save()
resp = app.get(reverse('lingo-manager-invoicing-regie-detail', kwargs={'pk': regie.pk}))
href = resp.pyquery(
'div#panel-campaigns ul li a[href="%s"]'
% reverse('lingo-manager-invoicing-campaign-detail', kwargs={'regie_pk': regie.pk, 'pk': campaign.pk})
)
assert href.text() == '(01/09/2022 - 01/10/2022) [issue date: 31/10/2022] finalized'
def test_manager_invoicing_regie_edit(app, admin_user):
app = login(app)