invoicing: inject line model (#73456) #16

Merged
lguerin merged 2 commits from wip/73456-invoicing-injected-line into main 2023-01-20 16:47:56 +01:00
10 changed files with 398 additions and 27 deletions

View File

@ -22,6 +22,7 @@ from rest_framework.exceptions import ValidationError
from lingo.agendas.chrono import ChronoError, get_events from lingo.agendas.chrono import ChronoError, get_events
from lingo.agendas.models import Agenda from lingo.agendas.models import Agenda
from lingo.invoicing.models import InjectedLine, Regie
from lingo.pricing.models import AgendaPricing, AgendaPricingNotFound, PricingError from lingo.pricing.models import AgendaPricing, AgendaPricingNotFound, PricingError
@ -234,3 +235,21 @@ class PricingComputeSerializer(serializers.Serializer):
result['error'] = type(e).__name__ result['error'] = type(e).__name__
result['error_details'] = e.details result['error_details'] = e.details
return result 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',
]

View File

@ -34,4 +34,9 @@ urlpatterns = [
views.invoicing_regies, views.invoicing_regies,
name='api-invoicing-regies', name='api-invoicing-regies',
), ),
path(
'invoicing/injected-lines/',
views.injected_lines,
name='api-invoicing-injected-lines',
),
] ]

View File

@ -22,7 +22,7 @@ from rest_framework.views import APIView
from lingo.agendas.models import Agenda from lingo.agendas.models import Agenda
from lingo.api import serializers from lingo.api import serializers
from lingo.api.utils import APIErrorBadRequest, Response from lingo.api.utils import APIErrorBadRequest, Response
from lingo.invoicing.models import Regie from lingo.invoicing.models import InjectedLine, Regie
class AgendaCheckTypeList(APIView): class AgendaCheckTypeList(APIView):
@ -73,3 +73,19 @@ class InvoicingRegies(APIView):
invoicing_regies = InvoicingRegies.as_view() 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():
lguerin marked this conversation as resolved Outdated
Outdated
Review

oups ?

oups ?
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()

View File

@ -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'
),
),
]

View File

@ -194,6 +194,19 @@ class Invoice(AbstractInvoice):
pass 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): class AbstractInvoiceLine(models.Model):
slug = models.SlugField(max_length=250) slug = models.SlugField(max_length=250)
label = models.CharField(max_length=260) label = models.CharField(max_length=260)
@ -274,7 +287,9 @@ class AbstractInvoiceLine(models.Model):
class DraftInvoiceLine(AbstractInvoiceLine): class DraftInvoiceLine(AbstractInvoiceLine):
invoice = models.ForeignKey(DraftInvoice, on_delete=models.PROTECT, null=True, related_name='lines') 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): class InvoiceLine(AbstractInvoiceLine):
invoice = models.ForeignKey(Invoice, on_delete=models.PROTECT, null=True, related_name='lines') 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)

View File

@ -33,7 +33,7 @@
<th>{% trans "PK" %}</th> <th>{% trans "PK" %}</th>
<th>{% trans "Invoice PK" %}</th> <th>{% trans "Invoice PK" %}</th>
<th>{% trans "Label" %}</th> <th>{% trans "Label" %}</th>
<th>{% trans "Event" %}</th> <th>{% trans "Slug" %}</th>
Ghost marked this conversation as resolved
Review

ça fait partie du même travail, le remplacement cette colonne "Event" par une colonne "Slug" ? (j'ai l'impression de rater un truc évident, mais)

ça fait partie du même travail, le remplacement cette colonne "Event" par une colonne "Slug" ? (j'ai l'impression de rater un truc évident, mais)
Review

J'allais chercher le slug de l'event dans line.event.xxx, mais j'ai la même chose dans line.slug, et pour une ligne injectée je veux voir line.slug.

J'allais chercher le slug de l'event dans line.event.xxx, mais j'ai la même chose dans line.slug, et pour une ligne injectée je veux voir line.slug.
<th>{% trans "Quantity" %}</th> <th>{% trans "Quantity" %}</th>
<th>{% trans "Unit amount" %}</th> <th>{% trans "Unit amount" %}</th>
<th>{% trans "Total amount" %}</th> <th>{% trans "Total amount" %}</th>
@ -49,7 +49,7 @@
<td class="line_id">{{ line.pk }}</td> <td class="line_id">{{ line.pk }}</td>
<td>{{ line.invoice_id|default:'' }}</td> <td>{{ line.invoice_id|default:'' }}</td>
<td>{{ line.label }}</td> <td>{{ line.label }}</td>
<td>{{ line.event.slug }}</td> <td>{{ line.slug }}</td>
<td>{{ line.quantity }}</td> <td>{{ line.quantity }}</td>
<td>{{ line.unit_amount }}</td> <td>{{ line.unit_amount }}</td>
<td>{{ line.total_amount }}</td> <td>{{ line.total_amount }}</td>
@ -58,6 +58,7 @@
<td class="status"> <td class="status">
<span class="tag tag-{{ line.status }}">{{ line.get_status_display }}</span> <span class="tag tag-{{ line.status }}">{{ line.get_status_display }}</span>
{% if line.status != 'success' %}({{ line.get_error_display }}){% endif %} {% if line.status != 'success' %}({{ line.get_error_display }}){% endif %}
{% if line.from_injected_line_id %}({% trans "Injected" %}){% endif %}
</td> </td>
<td><a class="details-toggle">{% trans "see details" %}</a></td> <td><a class="details-toggle">{% trans "see details" %}</a></td>
</tr> </tr>

View File

@ -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.chrono import get_check_status, get_subscriptions
from lingo.agendas.models import Agenda 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 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, 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) DraftInvoiceLine.objects.bulk_create(lines)
return lines return lines
@ -169,13 +206,16 @@ def generate_invoices_from_lines(agendas, all_lines, pool):
if line.status != 'success': if line.status != 'success':
# ignore lines in error # ignore lines in error
continue continue
agenda_slug = line.event['agenda'] if line.from_injected_line:
if agenda_slug not in agendas_by_slug: regie = line.from_injected_line.regie
# should not happen else:
continue agenda_slug = line.event['agenda']
regie = agendas_by_slug[agenda_slug].regie if agenda_slug not in agendas_by_slug:
if not regie: # should not happen
raise RegieNotConfigured(_('Regie not configured on %s') % agenda_slug) 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: if regie.pk not in lines_by_regie:
lines_by_regie[regie.pk] = {} lines_by_regie[regie.pk] = {}
regie_subs = lines_by_regie[regie.pk] regie_subs = lines_by_regie[regie.pk]

View File

@ -1,6 +1,8 @@
import datetime
import pytest import pytest
from lingo.invoicing.models import Regie from lingo.invoicing.models import InjectedLine, Regie
pytestmark = pytest.mark.django_db pytestmark = pytest.mark.django_db
@ -22,3 +24,51 @@ def test_regies(app, user):
{'id': 'bar', 'text': 'Bar', 'slug': 'bar'}, {'id': 'bar', 'text': 'Bar', 'slug': 'bar'},
{'id': 'foo', 'text': 'Foo', 'slug': 'foo'}, {'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

View File

@ -10,7 +10,16 @@ from django.test.utils import CaptureQueriesContext
from lingo.agendas.chrono import ChronoError from lingo.agendas.chrono import ChronoError
from lingo.agendas.models import Agenda from lingo.agendas.models import Agenda
from lingo.invoicing import utils 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 from lingo.pricing.models import AgendaPricing, Criteria, CriteriaCategory, Pricing, PricingError
pytestmark = pytest.mark.django_db 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.invoicing.utils.get_check_status')
@mock.patch('lingo.pricing.models.AgendaPricing.get_pricing_data_for_event') @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): 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') agenda1 = Agenda.objects.create(label='Agenda 1')
agenda2 = Agenda.objects.create(label='Agenda 2') agenda2 = Agenda.objects.create(label='Agenda 2')
pricing = Pricing.objects.create(label='Foo bar 1') 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_end=datetime.date(2022, 10, 1),
date_issue=datetime.date(2022, 10, 31), date_issue=datetime.date(2022, 10, 31),
) )
old_pool = Pool.objects.create(
campaign=campaign,
draft=True,
)
pool = Pool.objects.create( pool = Pool.objects.create(
campaign=campaign, campaign=campaign,
draft=True, 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 # no agendas
assert ( assert (
@ -234,15 +360,13 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
# no status # no status
mock_status.return_value = [] mock_status.return_value = []
assert ( lines = utils.get_invoice_lines_for_user(
utils.get_invoice_lines_for_user( agendas=[agenda1, agenda2],
agendas=[agenda1, agenda2], agendas_pricings=[agenda_pricing],
agendas_pricings=[agenda_pricing], user_external_id='user:1',
user_external_id='user:1', pool=pool,
pool=pool,
)
== []
) )
assert len(lines) == 2 # injected lines
assert mock_status.call_args_list == [ assert mock_status.call_args_list == [
mock.call( mock.call(
agenda_slugs=['agenda-1', 'agenda-2'], 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', adult_external_id='user:1',
), ),
] ]
assert len(lines) == 4 assert len(lines) == 6
line1, line2, line3, line4 = lines line1, line2, line3, line4, line5, line6 = lines
assert isinstance(line1, DraftInvoiceLine) assert isinstance(line1, DraftInvoiceLine)
assert line1.invoice is None assert line1.invoice is None
assert line1.slug == 'agenda-1@event-1' 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.pricing_data == {'foo1': 'bar1', 'pricing': 1}
assert line1.status == 'success' assert line1.status == 'success'
assert line1.pool == pool assert line1.pool == pool
assert line1.from_injected_line is None
assert isinstance(line2, DraftInvoiceLine) assert isinstance(line2, DraftInvoiceLine)
assert line2.invoice is None assert line2.invoice is None
assert line2.slug == 'agenda-1@event-2' 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.pricing_data == {'foo2': 'bar2', 'pricing': 2}
assert line2.status == 'success' assert line2.status == 'success'
assert line2.pool == pool assert line2.pool == pool
assert line2.from_injected_line is None
assert isinstance(line3, DraftInvoiceLine) assert isinstance(line3, DraftInvoiceLine)
assert line3.invoice is None assert line3.invoice is None
assert line3.slug == 'agenda-2@eveeent-1' 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.pricing_data == {'foo3': 'bar3', 'pricing': 3}
assert line3.status == 'success' assert line3.status == 'success'
assert line3.pool == pool assert line3.pool == pool
assert line3.from_injected_line is None
assert isinstance(line4, DraftInvoiceLine) assert isinstance(line4, DraftInvoiceLine)
assert line4.invoice is None assert line4.invoice is None
assert line4.slug == 'agenda-2@eveeent-2' 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.pricing_data == {'foo4': 'bar4', 'pricing': 4}
assert line4.status == 'success' assert line4.status == 'success'
assert line4.pool == pool 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') @mock.patch('lingo.invoicing.utils.get_check_status')
@ -866,7 +1022,7 @@ def test_get_all_invoice_lines_queryset(mock_status):
pool=pool, pool=pool,
) )
assert lines assert lines
assert len(ctx.captured_queries) == 7 assert len(ctx.captured_queries) == 9
def test_generate_invoices_from_lines(): def test_generate_invoices_from_lines():
@ -967,6 +1123,27 @@ def test_generate_invoices_from_lines():
status='success', status='success',
pool=pool, 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( invoices = utils.generate_invoices_from_lines(
agendas=[], agendas=[],
@ -987,7 +1164,7 @@ def test_generate_invoices_from_lines():
line6.delete() line6.delete()
invoices = utils.generate_invoices_from_lines( invoices = utils.generate_invoices_from_lines(
agendas=[agenda1, agenda2, agenda3, agenda4], 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, pool=pool,
) )
assert len(invoices) == 3 assert len(invoices) == 3
@ -998,12 +1175,12 @@ def test_generate_invoices_from_lines():
invoice3.refresh_from_db() invoice3.refresh_from_db()
assert isinstance(invoice1, DraftInvoice) assert isinstance(invoice1, DraftInvoice)
assert invoice1.label == 'Invoice from 2022-09-01 to 2022-09-30' 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.date_issue == datetime.date(2022, 10, 31)
assert invoice1.regie == regie1 assert invoice1.regie == regie1
assert invoice1.payer == 'user:1' assert invoice1.payer == 'user:1'
assert invoice1.pool == pool 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 isinstance(invoice2, DraftInvoice)
assert invoice2.label == 'Invoice from 2022-09-01 to 2022-09-30' assert invoice2.label == 'Invoice from 2022-09-01 to 2022-09-30'
assert invoice2.total_amount == 3 assert invoice2.total_amount == 3

View File

@ -70,6 +70,7 @@ def test_invoice_total_amount(draft):
assert invoice2.total_amount == 0 assert invoice2.total_amount == 0
# update total_amount # update total_amount
line.status = 'success'
line.total_amount = 12 line.total_amount = 12
line.save() line.save()
invoice.refresh_from_db() invoice.refresh_from_db()