diff --git a/lingo/api/serializers.py b/lingo/api/serializers.py
index 7ff4cc0..7518f18 100644
--- a/lingo/api/serializers.py
+++ b/lingo/api/serializers.py
@@ -22,6 +22,7 @@ from rest_framework.exceptions import ValidationError
from lingo.agendas.chrono import ChronoError, get_events
from lingo.agendas.models import Agenda
+from lingo.invoicing.models import InjectedLine, Regie
from lingo.pricing.models import AgendaPricing, AgendaPricingNotFound, PricingError
@@ -234,3 +235,21 @@ class PricingComputeSerializer(serializers.Serializer):
result['error'] = type(e).__name__
result['error_details'] = e.details
return result
+
+
+class InjectedLineSerializer(serializers.ModelSerializer):
+ regie = serializers.SlugRelatedField(queryset=Regie.objects, slug_field='slug')
+
+ class Meta:
+ model = InjectedLine
+ fields = [
+ 'event_date',
+ 'slug',
+ 'label',
+ 'quantity',
+ 'unit_amount',
+ 'total_amount',
+ 'user_external_id',
+ 'payer_external_id',
+ 'regie',
+ ]
diff --git a/lingo/api/urls.py b/lingo/api/urls.py
index 63c8695..68150b0 100644
--- a/lingo/api/urls.py
+++ b/lingo/api/urls.py
@@ -34,4 +34,9 @@ urlpatterns = [
views.invoicing_regies,
name='api-invoicing-regies',
),
+ path(
+ 'invoicing/injected-lines/',
+ views.injected_lines,
+ name='api-invoicing-injected-lines',
+ ),
]
diff --git a/lingo/api/views.py b/lingo/api/views.py
index 1e4848e..7921f45 100644
--- a/lingo/api/views.py
+++ b/lingo/api/views.py
@@ -22,7 +22,7 @@ from rest_framework.views import APIView
from lingo.agendas.models import Agenda
from lingo.api import serializers
from lingo.api.utils import APIErrorBadRequest, Response
-from lingo.invoicing.models import Regie
+from lingo.invoicing.models import InjectedLine, Regie
class AgendaCheckTypeList(APIView):
@@ -73,3 +73,19 @@ class InvoicingRegies(APIView):
invoicing_regies = InvoicingRegies.as_view()
+
+
+class InjectedLines(APIView):
+ permission_classes = (permissions.IsAuthenticated,)
+ serializer_class = serializers.InjectedLineSerializer
+
+ def post(self, request):
+ serializer = self.serializer_class(data=request.data)
+ if not serializer.is_valid():
+ raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors)
+
+ instance = InjectedLine.objects.create(**serializer.validated_data)
+ return Response({'err': 0, 'id': instance.pk})
+
+
+injected_lines = InjectedLines.as_view()
diff --git a/lingo/invoicing/migrations/0008_injected_line.py b/lingo/invoicing/migrations/0008_injected_line.py
new file mode 100644
index 0000000..d12a2df
--- /dev/null
+++ b/lingo/invoicing/migrations/0008_injected_line.py
@@ -0,0 +1,47 @@
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('invoicing', '0007_pool_exception'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='InjectedLine',
+ fields=[
+ (
+ 'id',
+ models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
+ ),
+ ('event_date', models.DateField()),
+ ('slug', models.SlugField(max_length=250)),
+ ('label', models.CharField(max_length=260)),
+ ('quantity', models.FloatField()),
+ ('unit_amount', models.DecimalField(decimal_places=2, max_digits=9)),
+ ('total_amount', models.DecimalField(decimal_places=2, max_digits=9)),
+ ('user_external_id', models.CharField(max_length=250)),
+ ('payer_external_id', models.CharField(max_length=250)),
+ (
+ 'regie',
+ models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='invoicing.Regie'),
+ ),
+ ],
+ ),
+ migrations.AddField(
+ model_name='draftinvoiceline',
+ name='from_injected_line',
+ field=models.ForeignKey(
+ null=True, on_delete=django.db.models.deletion.PROTECT, to='invoicing.InjectedLine'
+ ),
+ ),
+ migrations.AddField(
+ model_name='invoiceline',
+ name='from_injected_line',
+ field=models.ForeignKey(
+ null=True, on_delete=django.db.models.deletion.PROTECT, to='invoicing.InjectedLine'
+ ),
+ ),
+ ]
diff --git a/lingo/invoicing/models.py b/lingo/invoicing/models.py
index 89b955e..04b131f 100644
--- a/lingo/invoicing/models.py
+++ b/lingo/invoicing/models.py
@@ -194,6 +194,19 @@ class Invoice(AbstractInvoice):
pass
+class InjectedLine(models.Model):
+ event_date = models.DateField()
+ slug = models.SlugField(max_length=250)
+ label = models.CharField(max_length=260)
+ quantity = models.FloatField()
+ unit_amount = models.DecimalField(max_digits=9, decimal_places=2)
+ total_amount = models.DecimalField(max_digits=9, decimal_places=2)
+
+ user_external_id = models.CharField(max_length=250)
+ payer_external_id = models.CharField(max_length=250)
+ regie = models.ForeignKey(Regie, on_delete=models.PROTECT)
+
+
class AbstractInvoiceLine(models.Model):
slug = models.SlugField(max_length=250)
label = models.CharField(max_length=260)
@@ -274,7 +287,9 @@ class AbstractInvoiceLine(models.Model):
class DraftInvoiceLine(AbstractInvoiceLine):
invoice = models.ForeignKey(DraftInvoice, on_delete=models.PROTECT, null=True, related_name='lines')
+ from_injected_line = models.ForeignKey(InjectedLine, on_delete=models.PROTECT, null=True)
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)
diff --git a/lingo/invoicing/templates/lingo/invoicing/manager_pool_detail.html b/lingo/invoicing/templates/lingo/invoicing/manager_pool_detail.html
index d84e050..e7077be 100644
--- a/lingo/invoicing/templates/lingo/invoicing/manager_pool_detail.html
+++ b/lingo/invoicing/templates/lingo/invoicing/manager_pool_detail.html
@@ -33,7 +33,7 @@
{% trans "PK" %} |
{% trans "Invoice PK" %} |
{% trans "Label" %} |
- {% trans "Event" %} |
+ {% trans "Slug" %} |
{% trans "Quantity" %} |
{% trans "Unit amount" %} |
{% trans "Total amount" %} |
@@ -49,7 +49,7 @@
{{ line.pk }} |
{{ line.invoice_id|default:'' }} |
{{ line.label }} |
- {{ line.event.slug }} |
+ {{ line.slug }} |
{{ line.quantity }} |
{{ line.unit_amount }} |
{{ line.total_amount }} |
@@ -58,6 +58,7 @@
{{ line.get_status_display }}
{% if line.status != 'success' %}({{ line.get_error_display }}){% endif %}
+ {% if line.from_injected_line_id %}({% trans "Injected" %}){% endif %}
|
{% trans "see details" %} |
diff --git a/lingo/invoicing/utils.py b/lingo/invoicing/utils.py
index fd843b0..f8ee024 100644
--- a/lingo/invoicing/utils.py
+++ b/lingo/invoicing/utils.py
@@ -22,7 +22,7 @@ from django.utils.translation import ugettext_lazy as _
from lingo.agendas.chrono import get_check_status, get_subscriptions
from lingo.agendas.models import Agenda
-from lingo.invoicing.models import DraftInvoice, DraftInvoiceLine, RegieNotConfigured
+from lingo.invoicing.models import DraftInvoice, DraftInvoiceLine, InjectedLine, RegieNotConfigured
from lingo.pricing.models import AgendaPricing, AgendaPricingNotFound, PricingError
@@ -134,7 +134,44 @@ def get_invoice_lines_for_user(agendas, agendas_pricings, user_external_id, pool
pool=pool,
)
)
+
+ # fetch injected lines
+ injected_lines = (
+ InjectedLine.objects.filter(
+ event_date__gte=pool.campaign.date_start,
+ event_date__lt=pool.campaign.date_end,
+ user_external_id=user_external_id,
+ )
+ .exclude(
+ # exclude already invoiced lines
+ invoiceline__isnull=False
+ )
+ .exclude(
+ # exclude lines used in another campaign
+ pk__in=DraftInvoiceLine.objects.filter(from_injected_line__isnull=False)
+ .exclude(pool__campaign=pool.campaign)
+ .values('from_injected_line')
+ )
+ )
+
+ for injected_line in injected_lines:
+ lines.append(
+ DraftInvoiceLine(
+ slug=injected_line.slug,
+ label=injected_line.label,
+ quantity=injected_line.quantity,
+ unit_amount=injected_line.unit_amount,
+ total_amount=injected_line.total_amount,
+ user_external_id=injected_line.user_external_id,
+ payer_external_id=injected_line.user_external_id,
+ status='success',
+ pool=pool,
+ from_injected_line=injected_line,
+ )
+ )
+
DraftInvoiceLine.objects.bulk_create(lines)
+
return lines
@@ -169,13 +206,16 @@ def generate_invoices_from_lines(agendas, all_lines, pool):
if line.status != 'success':
# ignore lines in error
continue
- agenda_slug = line.event['agenda']
- if agenda_slug not in agendas_by_slug:
- # should not happen
- continue
- regie = agendas_by_slug[agenda_slug].regie
- if not regie:
- raise RegieNotConfigured(_('Regie not configured on %s') % agenda_slug)
+ if line.from_injected_line:
+ regie = line.from_injected_line.regie
+ else:
+ agenda_slug = line.event['agenda']
+ if agenda_slug not in agendas_by_slug:
+ # should not happen
+ continue
+ regie = agendas_by_slug[agenda_slug].regie
+ if not regie:
+ raise RegieNotConfigured(_('Regie not configured on %s') % agenda_slug)
if regie.pk not in lines_by_regie:
lines_by_regie[regie.pk] = {}
regie_subs = lines_by_regie[regie.pk]
diff --git a/tests/api/test_invoicing.py b/tests/api/test_invoicing.py
index 5538a0b..6d5fef9 100644
--- a/tests/api/test_invoicing.py
+++ b/tests/api/test_invoicing.py
@@ -1,6 +1,8 @@
+import datetime
+
import pytest
-from lingo.invoicing.models import Regie
+from lingo.invoicing.models import InjectedLine, Regie
pytestmark = pytest.mark.django_db
@@ -22,3 +24,51 @@ def test_regies(app, user):
{'id': 'bar', 'text': 'Bar', 'slug': 'bar'},
{'id': 'foo', 'text': 'Foo', 'slug': 'foo'},
]
+
+
+def test_add_injected_line(app, user):
+ app.post('/api/invoicing/injected-lines/', status=403)
+ app.authorization = ('Basic', ('john.doe', 'password'))
+
+ resp = app.post('/api/invoicing/injected-lines/', status=400)
+ assert resp.json['err']
+ assert resp.json['errors'] == {
+ 'event_date': ['This field is required.'],
+ 'slug': ['This field is required.'],
+ 'label': ['This field is required.'],
+ 'quantity': ['This field is required.'],
+ 'unit_amount': ['This field is required.'],
+ 'total_amount': ['This field is required.'],
+ 'user_external_id': ['This field is required.'],
+ 'payer_external_id': ['This field is required.'],
+ 'regie': ['This field is required.'],
+ }
+
+ params = {
+ 'event_date': '2023-01-17',
+ 'slug': 'foobar',
+ 'label': 'Foo Bar',
+ 'quantity': 42,
+ 'unit_amount': 2,
+ 'total_amount': 64,
+ 'user_external_id': 'user:1',
+ 'payer_external_id': 'payer:1',
+ 'regie': 'foo',
+ }
+ resp = app.post('/api/invoicing/injected-lines/', params=params, status=400)
+ assert resp.json['err']
+ assert resp.json['errors'] == {'regie': ['Object with slug=foo does not exist.']}
+
+ regie = Regie.objects.create(slug='foo')
+ resp = app.post('/api/invoicing/injected-lines/', params=params)
+ assert resp.json['err'] == 0
+ injected_line = InjectedLine.objects.get(pk=resp.json['id'])
+ assert injected_line.event_date == datetime.date(2023, 1, 17)
+ assert injected_line.slug == 'foobar'
+ assert injected_line.label == 'Foo Bar'
+ assert injected_line.quantity == 42
+ assert injected_line.unit_amount == 2
+ assert injected_line.total_amount == 64
+ assert injected_line.user_external_id == 'user:1'
+ assert injected_line.payer_external_id == 'payer:1'
+ assert injected_line.regie == regie
diff --git a/tests/invoicing/test_invoice_generation.py b/tests/invoicing/test_invoice_generation.py
index 825c13d..4426b8f 100644
--- a/tests/invoicing/test_invoice_generation.py
+++ b/tests/invoicing/test_invoice_generation.py
@@ -10,7 +10,16 @@ from django.test.utils import CaptureQueriesContext
from lingo.agendas.chrono import ChronoError
from lingo.agendas.models import Agenda
from lingo.invoicing import utils
-from lingo.invoicing.models import Campaign, DraftInvoice, DraftInvoiceLine, Pool, Regie, RegieNotConfigured
+from lingo.invoicing.models import (
+ Campaign,
+ DraftInvoice,
+ DraftInvoiceLine,
+ InjectedLine,
+ InvoiceLine,
+ Pool,
+ Regie,
+ RegieNotConfigured,
+)
from lingo.pricing.models import AgendaPricing, Criteria, CriteriaCategory, Pricing, PricingError
pytestmark = pytest.mark.django_db
@@ -200,6 +209,7 @@ def test_get_invoice_lines_for_user_check_status_error(mock_status):
@mock.patch('lingo.invoicing.utils.get_check_status')
@mock.patch('lingo.pricing.models.AgendaPricing.get_pricing_data_for_event')
def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_status):
+ regie = Regie.objects.create(label='Regie')
agenda1 = Agenda.objects.create(label='Agenda 1')
agenda2 = Agenda.objects.create(label='Agenda 2')
pricing = Pricing.objects.create(label='Foo bar 1')
@@ -214,10 +224,126 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
date_end=datetime.date(2022, 10, 1),
date_issue=datetime.date(2022, 10, 31),
)
+ old_pool = Pool.objects.create(
+ campaign=campaign,
+ draft=True,
+ )
pool = Pool.objects.create(
campaign=campaign,
draft=True,
)
+ other_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),
+ )
+ other_pool = Pool.objects.create(
+ campaign=other_campaign,
+ draft=True,
+ )
+
+ # create some injected lines
+ InjectedLine.objects.create(
+ event_date=datetime.date(2022, 8, 31), # too soon
+ slug='event-2022-08-31',
+ label='Event 2022-08-31',
+ quantity=2,
+ unit_amount=1.5,
+ total_amount=3,
+ user_external_id='user:1',
+ payer_external_id='payer:1',
+ regie=regie,
+ )
+ injected_line2 = InjectedLine.objects.create(
+ event_date=datetime.date(2022, 9, 1),
+ slug='event-2022-09-01',
+ label='Event 2022-09-01',
+ quantity=2,
+ unit_amount=1.5,
+ total_amount=3,
+ user_external_id='user:1',
+ payer_external_id='payer:1',
+ regie=regie,
+ )
+ # ok, same campaign
+ DraftInvoiceLine.objects.create(
+ quantity=0,
+ unit_amount=0,
+ total_amount=0,
+ pool=old_pool,
+ from_injected_line=injected_line2,
+ )
+ InjectedLine.objects.create(
+ event_date=datetime.date(2022, 9, 2),
+ slug='event-2022-09-02',
+ label='Event 2022-09-02',
+ quantity=2,
+ unit_amount=1.5,
+ total_amount=3,
+ user_external_id='user:2', # wrong user
+ payer_external_id='payer:1',
+ regie=regie,
+ )
+ injected_line4 = InjectedLine.objects.create(
+ event_date=datetime.date(2022, 9, 30),
+ slug='event-2022-09-30',
+ label='Event 2022-09-30',
+ quantity=3,
+ unit_amount=1.5,
+ total_amount=4.5,
+ user_external_id='user:1',
+ payer_external_id='payer:1',
+ regie=regie,
+ )
+ InjectedLine.objects.create(
+ event_date=datetime.date(2022, 10, 1), # too late
+ slug='event-2022-10-01',
+ label='Event 2022-10-01',
+ quantity=2,
+ unit_amount=1.5,
+ total_amount=3,
+ user_external_id='user:1',
+ payer_external_id='payer:1',
+ regie=regie,
+ )
+ injected_line6 = InjectedLine.objects.create(
+ event_date=datetime.date(2022, 9, 15),
+ slug='event-2022-09-15',
+ label='Event 2022-09-15',
+ quantity=3,
+ unit_amount=1.5,
+ total_amount=4.5,
+ user_external_id='user:1',
+ payer_external_id='payer:1',
+ regie=regie,
+ )
+ # nok, already invoiced
+ InvoiceLine.objects.create(
+ quantity=0,
+ unit_amount=0,
+ total_amount=0,
+ pool=old_pool,
+ from_injected_line=injected_line6,
+ )
+ injected_line7 = InjectedLine.objects.create(
+ event_date=datetime.date(2022, 9, 16),
+ slug='event-2022-09-15',
+ label='Event 2022-09-15',
+ quantity=3,
+ unit_amount=1.5,
+ total_amount=4.5,
+ user_external_id='user:1',
+ payer_external_id='payer:1',
+ regie=regie,
+ )
+ # nok, other campaign
+ DraftInvoiceLine.objects.create(
+ quantity=0,
+ unit_amount=0,
+ total_amount=0,
+ pool=other_pool,
+ from_injected_line=injected_line7,
+ )
# no agendas
assert (
@@ -234,15 +360,13 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
# no status
mock_status.return_value = []
- assert (
- utils.get_invoice_lines_for_user(
- agendas=[agenda1, agenda2],
- agendas_pricings=[agenda_pricing],
- user_external_id='user:1',
- pool=pool,
- )
- == []
+ lines = utils.get_invoice_lines_for_user(
+ agendas=[agenda1, agenda2],
+ agendas_pricings=[agenda_pricing],
+ user_external_id='user:1',
+ pool=pool,
)
+ assert len(lines) == 2 # injected lines
assert mock_status.call_args_list == [
mock.call(
agenda_slugs=['agenda-1', 'agenda-2'],
@@ -365,8 +489,8 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
adult_external_id='user:1',
),
]
- assert len(lines) == 4
- line1, line2, line3, line4 = lines
+ assert len(lines) == 6
+ line1, line2, line3, line4, line5, line6 = lines
assert isinstance(line1, DraftInvoiceLine)
assert line1.invoice is None
assert line1.slug == 'agenda-1@event-1'
@@ -385,6 +509,7 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
assert line1.pricing_data == {'foo1': 'bar1', 'pricing': 1}
assert line1.status == 'success'
assert line1.pool == pool
+ assert line1.from_injected_line is None
assert isinstance(line2, DraftInvoiceLine)
assert line2.invoice is None
assert line2.slug == 'agenda-1@event-2'
@@ -403,6 +528,7 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
assert line2.pricing_data == {'foo2': 'bar2', 'pricing': 2}
assert line2.status == 'success'
assert line2.pool == pool
+ assert line2.from_injected_line is None
assert isinstance(line3, DraftInvoiceLine)
assert line3.invoice is None
assert line3.slug == 'agenda-2@eveeent-1'
@@ -421,6 +547,7 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
assert line3.pricing_data == {'foo3': 'bar3', 'pricing': 3}
assert line3.status == 'success'
assert line3.pool == pool
+ assert line3.from_injected_line is None
assert isinstance(line4, DraftInvoiceLine)
assert line4.invoice is None
assert line4.slug == 'agenda-2@eveeent-2'
@@ -439,6 +566,35 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
assert line4.pricing_data == {'foo4': 'bar4', 'pricing': 4}
assert line4.status == 'success'
assert line4.pool == pool
+ assert line4.from_injected_line is None
+ assert isinstance(line5, DraftInvoiceLine)
+ assert line5.invoice is None
+ assert line5.slug == 'event-2022-09-01'
+ assert line5.label == 'Event 2022-09-01'
+ assert line5.quantity == 2
+ assert line5.unit_amount == 1.5
+ assert line5.total_amount == 3
+ assert line5.user_external_id == 'user:1'
+ assert line5.payer_external_id == 'user:1'
+ assert line5.event == {}
+ assert line5.pricing_data == {}
+ assert line5.status == 'success'
+ assert line5.pool == pool
+ assert line5.from_injected_line == injected_line2
+ assert isinstance(line6, DraftInvoiceLine)
+ assert line6.invoice is None
+ assert line6.slug == 'event-2022-09-30'
+ assert line6.label == 'Event 2022-09-30'
+ assert line6.quantity == 3
+ assert line6.unit_amount == 1.5
+ assert line6.total_amount == 4.5
+ assert line6.user_external_id == 'user:1'
+ assert line6.payer_external_id == 'user:1'
+ assert line6.event == {}
+ assert line6.pricing_data == {}
+ assert line6.status == 'success'
+ assert line6.pool == pool
+ assert line6.from_injected_line == injected_line4
@mock.patch('lingo.invoicing.utils.get_check_status')
@@ -866,7 +1022,7 @@ def test_get_all_invoice_lines_queryset(mock_status):
pool=pool,
)
assert lines
- assert len(ctx.captured_queries) == 7
+ assert len(ctx.captured_queries) == 9
def test_generate_invoices_from_lines():
@@ -967,6 +1123,27 @@ def test_generate_invoices_from_lines():
status='success',
pool=pool,
)
+ injected_line = InjectedLine.objects.create(
+ event_date=datetime.date(2022, 9, 1),
+ slug='event-2022-09-01',
+ label='Event 2022-09-01',
+ quantity=1,
+ unit_amount=7,
+ total_amount=7,
+ user_external_id='user:1',
+ payer_external_id='user:1',
+ regie=regie1,
+ )
+ line7 = DraftInvoiceLine.objects.create(
+ quantity=1,
+ unit_amount=7,
+ total_amount=7,
+ user_external_id='user:1',
+ payer_external_id='user:1',
+ status='success',
+ pool=pool,
+ from_injected_line=injected_line,
+ )
invoices = utils.generate_invoices_from_lines(
agendas=[],
@@ -987,7 +1164,7 @@ def test_generate_invoices_from_lines():
line6.delete()
invoices = utils.generate_invoices_from_lines(
agendas=[agenda1, agenda2, agenda3, agenda4],
- all_lines=[line_error, line1, line2, line3, line4, line5],
+ all_lines=[line_error, line1, line2, line3, line4, line5, line7],
pool=pool,
)
assert len(invoices) == 3
@@ -998,12 +1175,12 @@ def test_generate_invoices_from_lines():
invoice3.refresh_from_db()
assert isinstance(invoice1, DraftInvoice)
assert invoice1.label == 'Invoice from 2022-09-01 to 2022-09-30'
- assert invoice1.total_amount == 8
+ assert invoice1.total_amount == 15
assert invoice1.date_issue == datetime.date(2022, 10, 31)
assert invoice1.regie == regie1
assert invoice1.payer == 'user:1'
assert invoice1.pool == pool
- assert list(invoice1.lines.order_by('pk')) == [line1, line2, line5]
+ assert list(invoice1.lines.order_by('pk')) == [line1, line2, line5, line7]
assert isinstance(invoice2, DraftInvoice)
assert invoice2.label == 'Invoice from 2022-09-01 to 2022-09-30'
assert invoice2.total_amount == 3
diff --git a/tests/invoicing/test_models.py b/tests/invoicing/test_models.py
index 4df6d4c..7790a31 100644
--- a/tests/invoicing/test_models.py
+++ b/tests/invoicing/test_models.py
@@ -70,6 +70,7 @@ def test_invoice_total_amount(draft):
assert invoice2.total_amount == 0
# update total_amount
+ line.status = 'success'
line.total_amount = 12
line.save()
invoice.refresh_from_db()