invoicing: set error status on invoice line (#73740) #21

Merged
lguerin merged 1 commits from wip/73740-error-status into main 2023-02-04 15:35:55 +01:00
8 changed files with 387 additions and 50 deletions

View File

@ -76,13 +76,9 @@ class AbstractLineFilterSet(django_filters.FilterSet):
)
status = django_filters.ChoiceFilter(
label=_('Status'),
choices=[
('success', _('Success')),
('warning', _('Warning')),
('error', _('Error')),
],
widget=forms.RadioSelect,
empty_label=_('all'),
method='filter_status',
)
def __init__(self, *args, **kwargs):
@ -94,6 +90,30 @@ class AbstractLineFilterSet(django_filters.FilterSet):
else:
del self.filters['invoice_id']
status_choices = [
('success', _('Success')),
('warning', _('Warning')),
('error', _('Error')),
]
if not self.pool.draft:
status_choices += [
('error_todo', _('Error (To treat)')),
('error_ignored', _('Error (Ignored)')),
('error_fixed', _('Error (Fixed)')),
]
self.filters['status'].field.choices = status_choices
def filter_status(self, queryset, name, value):
if not value:
return queryset
if value == 'error_todo':
return queryset.filter(status='error', error_status='')
if value == 'error_ignored':
return queryset.filter(status='error', error_status='ignored')
if value == 'error_fixed':
return queryset.filter(status='error', error_status='fixed')
return queryset.filter(status=value)
class DraftInvoiceLineFilterSet(AbstractLineFilterSet):
class Meta:

View File

@ -0,0 +1,18 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('invoicing', '0013_formatted_number'),
]
operations = [
migrations.AddField(
model_name='invoiceline',
name='error_status',
field=models.CharField(
blank=True, choices=[('ignored', 'Ignored'), ('fixed', 'Fixed')], max_length=10
),
),
]

View File

@ -258,12 +258,14 @@ class Pool(models.Model):
final_line.pk = None
final_line.invoice = final_invoice
final_line.pool = self
final_line.error_status = ''
final_line.save()
for line in draft_pool.draftinvoiceline_set.filter(invoice__isnull=True).order_by('pk'):
final_line = copy.deepcopy(line)
final_line.__class__ = InvoiceLine
final_line.pk = None
final_line.error_status = ''
final_line.pool = self
final_line.save()
@ -427,3 +429,12 @@ class DraftInvoiceLine(AbstractInvoiceLine):
class InvoiceLine(AbstractInvoiceLine):
invoice = models.ForeignKey(Invoice, on_delete=models.PROTECT, null=True, related_name='lines')
from_injected_line = models.ForeignKey(InjectedLine, on_delete=models.PROTECT, null=True)
error_status = models.CharField(
max_length=10,
choices=[
('ignored', _('Ignored')),
('fixed', _('Fixed')),
],
blank=True,
)

View File

@ -0,0 +1,43 @@
{% load i18n %}
<td class="line_id">{{ line.pk }}</td>
<td>
{% if pool.draft and line.invoice %}
TMP-{{ line.invoice_id }}
{% elif line.invoice %}
{{ line.invoice.formatted_number }}
{% endif %}
</td>
<td>
{{ line.event_date|date:"d/m/Y" }} - {{ line.label }}
<br />
({{ line.slug }})
</td>
<td>{{ line.quantity }}</td>
<td>{{ line.unit_amount }}</td>
<td>{{ line.total_amount }}</td>
<td>{{ line.user_name }} ({{ line.user_external_id }})</td>
<td>{{ line.payer_external_id }}</td>
<td class="status">
<span class="tag tag-{{ line.status }}">{% spaceless %}
{% if line.status == 'error' and line.error_status %}
{{ line.get_error_status_display }}
{% else %}
{{ line.get_status_display }}
{% endif %}
{% endspaceless %}</span>
{% if line.status != 'success' %}
({{ line.get_error_display }})
{% if line.status == 'error' %}
<br />
{% if line.error_status %}
<a class="error-status" href="{% url 'lingo-manager-invoicing-line-set-error-status' pk=object.pk pool_pk=pool.pk line_pk=line.pk status='reset' %}">{% trans "reset" %}</a>
{% else %}
<a class="error-status" href="{% url 'lingo-manager-invoicing-line-set-error-status' pk=object.pk pool_pk=pool.pk line_pk=line.pk status='ignore' %}">{% trans "ignore" %}</a>
-
<a class="error-status" href="{% url 'lingo-manager-invoicing-line-set-error-status' pk=object.pk pool_pk=pool.pk line_pk=line.pk status='fix' %}">{% trans "mark as fixed" %}</a>
{% endif %}
{% endif %}
{% endif %}
{% if line.from_injected_line_id %}({% trans "Injected" %}){% endif %}
</td>
<td><a class="details-toggle" href="#">{% trans "see details" %}</a></td>

View File

@ -57,30 +57,7 @@
<tbody>
{% for line in lines %}
<tr data-line-id="{{ line.pk }}">
<td class="line_id">{{ line.pk }}</td>
<td>
{% if pool.draft and line.invoice %}
TMP-{{ line.invoice_id }}
{% elif line.invoice %}
{{ line.invoice.formatted_number }}
{% endif %}
</td>
<td>
{{ line.event_date|date:"d/m/Y" }} - {{ line.label }}
<br />
({{ line.slug }})
</td>
<td>{{ line.quantity }}</td>
<td>{{ line.unit_amount }}</td>
<td>{{ line.total_amount }}</td>
<td>{{ line.user_name }} ({{ line.user_external_id }})</td>
<td>{{ line.payer_external_id }}</td>
<td class="status">
<span class="tag tag-{{ line.status }}">{{ line.get_status_display }}</span>
{% if line.status != 'success' %}({{ line.get_error_display }}){% endif %}
{% if line.from_injected_line_id %}({% trans "Injected" %}){% endif %}
</td>
<td><a class="details-toggle">{% trans "see details" %}</a></td>
{% include 'lingo/invoicing/manager_line_detail_fragment.html' %}
</tr>
<tr data-details-for-line-id="{{ line.pk }}" style="display: none">
<td colspan="10">
@ -96,7 +73,8 @@
</div>
<script>
$(function() {
$('a.details-toggle').on('click', function() {
$(document).on('click', 'a.details-toggle', function(event) {
event.preventDefault();
var line_id = $(this).parents('tr').data('line-id');
var $details = $('tr[data-details-for-line-id=' + line_id + ']');
if ($details.is(':visible')) {
@ -107,6 +85,18 @@
$details.show();
}
});
$(document).on('click', 'a.error-status', function(event) {
lguerin marked this conversation as resolved Outdated

Mini-effort pour faire en sorte de ne pas recharger la page lorsqu'on change une error status.
Les compteurs (en haut de page) ne sont pas refresh, et en fonction des filtres sélectionnés ça peut ne plus être consistant, mais je pense que c'est acceptable.

Mini-effort pour faire en sorte de ne pas recharger la page lorsqu'on change une error status. Les compteurs (en haut de page) ne sont pas refresh, et en fonction des filtres sélectionnés ça peut ne plus être consistant, mais je pense que c'est acceptable.
Outdated
Review

Je trouve que ce commentaire pourrait trouver sa place dans le code, à cet endroit précis. Juste un « avoid reloading the whole page. There is no refresh of counters, it is not so important. »

Je trouve que ce commentaire pourrait trouver sa place dans le code, à cet endroit précis. Juste un « avoid reloading the whole page. There is no refresh of counters, it is not so important. »
// avoid reloading the whole page. There is no refresh of counters, it is not so important.
event.preventDefault();
var $a = $(this);
$.ajax({
url: $a.attr('href')
}).done(function(html) {
$a.parents('tr').html(html);
}).fail(function() {
location.reload();
});
});
});
</script>
{% endblock %}

View File

@ -89,4 +89,9 @@ urlpatterns = [
views.pool_delete,
name='lingo-manager-invoicing-pool-delete',
),
path(
'ajax/campaign/<int:pk>/pool/<int:pool_pk>/line/<int:line_pk>/<slug:status>/',
views.line_set_error_status,
name='lingo-manager-invoicing-line-set-error-status',
),
]

View File

@ -51,6 +51,10 @@ from lingo.invoicing.models import (
from lingo.pricing.forms import ImportForm
def is_ajax(request):
return request.headers.get('x-requested-with') == 'XMLHttpRequest'
def import_regies(data):
results = collections.defaultdict(list)
with transaction.atomic():
@ -223,7 +227,9 @@ class CampaignDetailView(DetailView):
draft_lines.filter(status='success').annotate(count=Count('pool')).values('count')
)
lines = InvoiceLine.objects.filter(pool=OuterRef('pk')).order_by().values('pool')
count_error = lines.filter(status='error').annotate(count=Count('pool')).values('count')
count_error = (
lines.filter(status='error', error_status='').annotate(count=Count('pool')).values('count')
)
count_warning = lines.filter(status='warning').annotate(count=Count('pool')).values('count')
count_success = lines.filter(status='success').annotate(count=Count('pool')).values('count')
kwargs['pools'] = self.object.pool_set.annotate(
@ -311,7 +317,9 @@ class PoolDetailView(DetailView):
if self.object.draft:
line_model = DraftInvoiceLine
all_lines = line_model.objects.filter(pool=self.object)
self.object.error_count = len([line for line in all_lines if line.status == 'error'])
self.object.error_count = len(
[line for line in all_lines if line.status == 'error' and not getattr(line, 'error_status', '')]
)
self.object.warning_count = len([line for line in all_lines if line.status == 'warning'])
self.object.success_count = len([line for line in all_lines if line.status == 'success'])
kwargs['lines'] = (
@ -346,7 +354,9 @@ class PoolJournalView(DetailView):
line_model = DraftInvoiceLine
filter_model = DraftInvoiceLineFilterSet
all_lines = line_model.objects.filter(pool=self.object).order_by('pk').select_related('invoice')
self.object.error_count = len([line for line in all_lines if line.status == 'error'])
self.object.error_count = len(
[line for line in all_lines if line.status == 'error' and not getattr(line, 'error_status', '')]
)
self.object.warning_count = len([line for line in all_lines if line.status == 'warning'])
self.object.success_count = len([line for line in all_lines if line.status == 'success'])
data = self.request.GET or None
@ -442,3 +452,46 @@ class PoolDeleteView(DeleteView):
pool_delete = PoolDeleteView.as_view()
class LineSetErrorStatusView(DetailView):
model = InvoiceLine
pk_url_kwarg = 'line_pk'
template_name = 'lingo/invoicing/manager_line_detail_fragment.html'
def get_queryset(self):
return (
super()
.get_queryset()
.filter(status='error', pool=self.kwargs['pool_pk'], pool__campaign=self.kwargs['pk'])
)
def get_context_data(self, **kwargs):
kwargs['object'] = self.object.pool.campaign
kwargs['pool'] = self.object.pool
kwargs['line'] = self.object
return super().get_context_data(**kwargs)
def get(self, request, *args, **kwargs):
self.object = self.get_object()
error_status = kwargs['status']
if error_status == 'reset':
self.object.error_status = ''
elif error_status == 'ignore':
self.object.error_status = 'ignored'
elif error_status == 'fix':
self.object.error_status = 'fixed'
else:
raise Http404
self.object.save()
if is_ajax(self.request):
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
return redirect(
reverse('lingo-manager-invoicing-pool-journal', args=[kwargs['pk'], kwargs['pool_pk']])
)
line_set_error_status = LineSetErrorStatusView.as_view()

View File

@ -173,6 +173,19 @@ def test_detail_campaign(app, admin_user):
assert 'tag-success' not in resp
assert '<span class="tag tag-warning">1</span>' in resp
assert 'tag-error' not in resp
line.status = 'error'
line.error_status = 'ignored'
line.save()
resp = app.get('/manage/invoicing/campaign/%s/' % campaign.pk)
assert 'tag-success' not in resp
assert 'tag-warning' not in resp
assert '<span class="tag tag-error">1</span>' not in resp
line.error_status = 'fixed'
line.save()
resp = app.get('/manage/invoicing/campaign/%s/' % campaign.pk)
assert 'tag-success' not in resp
assert 'tag-warning' not in resp
assert '<span class="tag tag-error">1</span>' not in resp
def test_edit_campaign(app, admin_user):
@ -742,6 +755,19 @@ def test_journal_pool(app, admin_user):
assert 'tag-success' not in resp
assert '<span class="tag tag-warning">1</span>' in resp
assert 'tag-error' not in resp
line.status = 'error'
line.error_status = 'ignored'
line.save()
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/journal/' % (campaign.pk, pool.pk))
assert 'tag-success' not in resp
assert 'tag-warning' not in resp
assert '<span class="tag tag-error">1</span>' not in resp
line.error_status = 'fixed'
line.save()
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/journal/' % (campaign.pk, pool.pk))
assert 'tag-success' not in resp
assert 'tag-warning' not in resp
assert '<span class="tag tag-error">1</span>' not in resp
@pytest.mark.parametrize('draft', [True, False])
@ -830,6 +856,11 @@ def test_journal_pool_lines(app, admin_user, draft):
payer_external_id='payer:2',
)
)
if not draft:
lines[-1].error_status = 'ignored'
lines[-1].save()
lines[-2].error_status = 'fixed'
lines[-2].save()
lines.append(
line_model.objects.create(
@ -867,7 +898,7 @@ def test_journal_pool_lines(app, admin_user, draft):
)
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[2].pk).text())
== 'Error (No matching criteria for category: cat-foo)'
== 'Error (No matching criteria for category: cat-foo) ignore - mark as fixed'
)
assert (
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[2].pk).text().strip()
@ -875,7 +906,7 @@ def test_journal_pool_lines(app, admin_user, draft):
)
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[3].pk).text())
== 'Error (Multiple default criteria found for category: cat-foo)'
== 'Error (Multiple default criteria found for category: cat-foo) ignore - mark as fixed'
)
assert (
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[3].pk).text().strip()
@ -883,7 +914,7 @@ def test_journal_pool_lines(app, admin_user, draft):
)
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[4].pk).text())
== 'Error (Impossible to determine a pricing for criterias: qf-1 (category: qf), bar (category: foo))'
== 'Error (Impossible to determine a pricing for criterias: qf-1 (category: qf), bar (category: foo)) ignore - mark as fixed'
)
assert (
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[4].pk).text().strip()
@ -891,7 +922,7 @@ def test_journal_pool_lines(app, admin_user, draft):
)
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[5].pk).text())
== 'Error (Pricing is not a decimal: foobar)'
== 'Error (Pricing is not a decimal: foobar) ignore - mark as fixed'
)
assert (
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[5].pk).text().strip()
@ -899,7 +930,7 @@ def test_journal_pool_lines(app, admin_user, draft):
)
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[6].pk).text())
== 'Error (Unknown check status: unknown)'
== 'Error (Unknown check status: unknown) ignore - mark as fixed'
)
assert (
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[6].pk).text().strip()
@ -907,7 +938,7 @@ def test_journal_pool_lines(app, admin_user, draft):
)
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[7].pk).text())
== 'Error (Event is not checked)'
== 'Error (Event is not checked) ignore - mark as fixed'
)
assert (
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[7].pk).text().strip()
@ -915,7 +946,7 @@ def test_journal_pool_lines(app, admin_user, draft):
)
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[8].pk).text())
== 'Error (Booking is not checked)'
== 'Error (Booking is not checked) ignore - mark as fixed'
)
assert (
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[8].pk).text().strip()
@ -923,7 +954,7 @@ def test_journal_pool_lines(app, admin_user, draft):
)
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[9].pk).text())
== 'Error (Multiple booking found)'
== 'Error (Multiple booking found) ignore - mark as fixed'
)
assert (
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[9].pk).text().strip()
@ -931,24 +962,36 @@ def test_journal_pool_lines(app, admin_user, draft):
)
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[10].pk).text())
== 'Error (Check type error: not found)'
== 'Error (Check type error: not found) ignore - mark as fixed'
)
assert (
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[10].pk).text().strip()
== "{'error': 'PricingBookingCheckTypeError', 'error_details': {'reason': 'not-found'}} {'event': 'foobar'}"
)
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[11].pk).text())
== 'Error (Check type error: pricing not configured (group: foo-bar, check type: foo-reason))'
)
if draft:
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[11].pk).text())
== 'Error (Check type error: pricing not configured (group: foo-bar, check type: foo-reason)) ignore - mark as fixed'
)
else:
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[11].pk).text())
== 'Fixed (Check type error: pricing not configured (group: foo-bar, check type: foo-reason)) reset'
)
assert resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[11].pk).text().strip() == (
"{'error': 'PricingBookingCheckTypeError', 'error_details': {'check_type': 'foo-reason', "
"'check_type_group': 'foo-bar', 'reason': 'not-configured'}} {'event': 'foobar'}"
)
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[12].pk).text())
== 'Error (Check type error: wrong kind (group: foo-bar, check type: foo-reason))'
)
if draft:
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[12].pk).text())
== 'Error (Check type error: wrong kind (group: foo-bar, check type: foo-reason)) ignore - mark as fixed'
)
else:
assert (
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[12].pk).text())
== 'Ignored (Check type error: wrong kind (group: foo-bar, check type: foo-reason)) reset'
)
assert resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[12].pk).text().strip() == (
"{'error': 'PricingBookingCheckTypeError', 'error_details': {'check_type': 'foo-reason', "
"'check_type_group': 'foo-bar', 'reason': 'wrong-kind'}} {'event': 'foobar'}"
@ -1022,6 +1065,22 @@ def test_journal_pool_lines(app, admin_user, draft):
params={'status': 'error'},
)
assert len(resp.pyquery('tr td.status')) == 11
if not draft:
resp = app.get(
'/manage/invoicing/campaign/%s/pool/%s/journal/' % (campaign.pk, pool.pk),
params={'status': 'error_todo'},
)
assert len(resp.pyquery('tr td.status')) == 9
resp = app.get(
'/manage/invoicing/campaign/%s/pool/%s/journal/' % (campaign.pk, pool.pk),
params={'status': 'error_ignored'},
)
assert len(resp.pyquery('tr td.status')) == 1
resp = app.get(
'/manage/invoicing/campaign/%s/pool/%s/journal/' % (campaign.pk, pool.pk),
params={'status': 'error_fixed'},
)
assert len(resp.pyquery('tr td.status')) == 1
def test_delete_pool(app, admin_user):
@ -1080,3 +1139,141 @@ def test_delete_pool(app, admin_user):
pool.draft = True
pool.save()
app.get('/manage/invoicing/campaign/%s/pool/%s/delete/' % (campaign.pk, pool.pk))
def test_set_error_status_line(app, admin_user):
campaign = Campaign.objects.create(
date_start=datetime.date(2022, 9, 1),
date_end=datetime.date(2022, 10, 1),
date_issue=datetime.date(2022, 10, 31),
)
pool = Pool.objects.create(
campaign=campaign,
draft=False,
status='completed',
)
line = InvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
quantity=1,
unit_amount=1,
total_amount=1,
status='success',
pool=pool,
)
app = login(app)
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/journal/' % (campaign.pk, pool.pk))
assert (
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/reset/' % (campaign.pk, pool.pk, line.pk)
not in resp
)
assert (
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/ignore/' % (campaign.pk, pool.pk, line.pk)
not in resp
)
assert (
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/fix/' % (campaign.pk, pool.pk, line.pk)
not in resp
)
app.get(
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/reset/' % (campaign.pk, pool.pk, line.pk),
status=404,
)
app.get(
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/ignore/' % (campaign.pk, pool.pk, line.pk),
status=404,
)
app.get(
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/fix/' % (campaign.pk, pool.pk, line.pk),
status=404,
)
line.status = 'warning'
line.save()
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/journal/' % (campaign.pk, pool.pk))
assert (
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/reset/' % (campaign.pk, pool.pk, line.pk)
not in resp
)
assert (
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/ignore/' % (campaign.pk, pool.pk, line.pk)
not in resp
)
assert (
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/fix/' % (campaign.pk, pool.pk, line.pk)
not in resp
)
app.get(
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/reset/' % (campaign.pk, pool.pk, line.pk),
status=404,
)
app.get(
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/ignore/' % (campaign.pk, pool.pk, line.pk),
status=404,
)
app.get(
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/fix/' % (campaign.pk, pool.pk, line.pk),
status=404,
)
line.status = 'error'
line.save()
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/journal/' % (campaign.pk, pool.pk))
assert (
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/reset/' % (campaign.pk, pool.pk, line.pk)
not in resp
)
assert (
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/ignore/' % (campaign.pk, pool.pk, line.pk) in resp
)
assert '/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/fix/' % (campaign.pk, pool.pk, line.pk) in resp
line.error_status = 'ignored'
line.save()
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/journal/' % (campaign.pk, pool.pk))
assert (
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/reset/' % (campaign.pk, pool.pk, line.pk) in resp
)
assert (
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/ignore/' % (campaign.pk, pool.pk, line.pk)
not in resp
)
assert (
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/fix/' % (campaign.pk, pool.pk, line.pk)
not in resp
)
line.error_status = 'fixed'
line.save()
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/journal/' % (campaign.pk, pool.pk))
assert (
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/reset/' % (campaign.pk, pool.pk, line.pk) in resp
)
assert (
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/ignore/' % (campaign.pk, pool.pk, line.pk)
not in resp
)
assert (
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/fix/' % (campaign.pk, pool.pk, line.pk)
not in resp
)
app.get('/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/reset/' % (campaign.pk, pool.pk, line.pk))
line.refresh_from_db()
assert line.error_status == ''
app.get('/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/ignore/' % (campaign.pk, pool.pk, line.pk))
line.refresh_from_db()
assert line.error_status == 'ignored'
app.get('/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/fix/' % (campaign.pk, pool.pk, line.pk))
line.refresh_from_db()
assert line.error_status == 'fixed'
app.get('/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/reset/' % (0, pool.pk, line.pk), status=404)
app.get(
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/reset/' % (campaign.pk, 0, line.pk), status=404
)
app.get(
'/manage/invoicing/ajax/campaign/%s/pool/%s/line/%s/reset/' % (campaign.pk, pool.pk, 0), status=404
)