lingo/tests/invoicing/test_invoice_generation.py

1851 lines
65 KiB
Python

import datetime
import decimal
from unittest import mock
import pytest
from django.core.management import CommandError, call_command
from django.db import connection
from django.test.utils import CaptureQueriesContext
from django.utils.timezone import now
from lingo.agendas.chrono import ChronoError
from lingo.agendas.models import Agenda
from lingo.invoicing import utils
from lingo.invoicing.models import (
Campaign,
Counter,
DraftInvoice,
DraftInvoiceLine,
InjectedLine,
Invoice,
InvoiceLine,
Pool,
PoolPromotionError,
Regie,
RegieNotConfigured,
)
from lingo.pricing.models import AgendaPricing, Criteria, CriteriaCategory, Pricing, PricingError
pytestmark = pytest.mark.django_db
def test_get_agendas():
agenda1 = Agenda.objects.create(label='Agenda 1')
agenda2 = Agenda.objects.create(label='Agenda 2')
agenda3 = Agenda.objects.create(label='Agenda 3')
Agenda.objects.create(label='Agenda 4')
pricing = Pricing.objects.create(label='Foo bar 1')
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=True,
)
# no agenda pricing defined
assert list(utils.get_agendas(pool=pool)) == []
# agenda pricing, but for flat_fee_schedule
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2022, month=9, day=1),
date_end=datetime.date(year=2022, month=10, day=1),
flat_fee_schedule=True, # wrong config
)
agenda_pricing.agendas.add(agenda1)
assert list(utils.get_agendas(pool=pool)) == []
# create some agenda pricing
agenda_pricing1 = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
)
agenda_pricing2 = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2022, month=9, day=1),
date_end=datetime.date(year=2022, month=10, day=1),
)
assert list(utils.get_agendas(pool=pool)) == []
# link agendas to agenda pricing
agenda_pricing1.agendas.add(agenda1, agenda2)
agenda_pricing2.agendas.add(agenda3)
assert list(utils.get_agendas(pool=pool)) == [agenda3]
campaign.date_start = datetime.date(2021, 9, 1)
campaign.date_end = datetime.date(2021, 10, 1)
campaign.save()
assert list(utils.get_agendas(pool=pool)) == [agenda1, agenda2]
campaign.date_start = datetime.date(2022, 8, 31)
campaign.date_end = datetime.date(2022, 9, 1)
campaign.save()
assert list(utils.get_agendas(pool=pool)) == []
campaign.date_start = datetime.date(2022, 9, 1)
campaign.date_end = datetime.date(2022, 9, 2)
campaign.save()
assert list(utils.get_agendas(pool=pool)) == [agenda3]
campaign.date_start = datetime.date(2022, 9, 30)
campaign.date_end = datetime.date(2022, 10, 1)
campaign.save()
assert list(utils.get_agendas(pool=pool)) == [agenda3]
campaign.date_start = datetime.date(2022, 10, 1)
campaign.date_end = datetime.date(2022, 10, 2)
campaign.save()
assert list(utils.get_agendas(pool=pool)) == []
campaign.date_start = datetime.date(2021, 9, 15)
campaign.date_end = datetime.date(2022, 9, 15)
campaign.save()
assert list(utils.get_agendas(pool=pool)) == [agenda1, agenda2, agenda3]
@mock.patch('lingo.invoicing.utils.get_subscriptions')
def test_get_users_from_subscriptions_error(mock_subscriptions):
agenda = Agenda.objects.create(label='Agenda')
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=True,
)
mock_subscriptions.side_effect = ChronoError('foo baz')
with pytest.raises(ChronoError):
utils.get_users_from_subscriptions(agendas=[agenda], pool=pool)
@mock.patch('lingo.invoicing.utils.get_subscriptions')
def test_get_users_from_subscriptions(mock_subscriptions):
agenda1 = Agenda.objects.create(label='Agenda 1')
agenda2 = Agenda.objects.create(label='Agenda 2')
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=True,
)
# no agendas
assert utils.get_users_from_subscriptions(agendas=[], pool=pool) == []
assert mock_subscriptions.call_args_list == []
# no subscriptions
mock_subscriptions.return_value = []
assert utils.get_users_from_subscriptions(agendas=[agenda1, agenda2], pool=pool) == []
assert mock_subscriptions.call_args_list == [
mock.call(
agenda_slug='agenda-1', date_start=datetime.date(2022, 9, 1), date_end=datetime.date(2022, 10, 1)
),
mock.call(
agenda_slug='agenda-2', date_start=datetime.date(2022, 9, 1), date_end=datetime.date(2022, 10, 1)
),
]
mock_subscriptions.reset_mock()
# with subscriptions
mock_subscriptions.side_effect = [
[
{
'user_external_id': 'user:1',
'user_first_name': 'User1',
'user_last_name': 'Name1',
'date_start': '2022-08-01',
'date_end': '2022-09-02',
},
{
'user_external_id': 'user:1',
'user_first_name': 'Foo Bar',
'user_last_name': '',
'date_start': '2022-09-02',
'date_end': '2022-09-03',
},
{
'user_external_id': 'user:2',
'user_first_name': '',
'user_last_name': '',
'date_start': '2022-09-02',
'date_end': '2022-09-03',
},
],
[
{
'user_external_id': 'user:1',
'user_first_name': 'User1 Name1',
'user_last_name': '',
'date_start': '2022-08-01',
'date_end': '2022-10-01',
},
],
]
assert utils.get_users_from_subscriptions(agendas=[agenda1, agenda2], pool=pool) == [
('user:1', 'User1 Name1'),
('user:2', 'user:2'),
]
assert mock_subscriptions.call_args_list == [
mock.call(
agenda_slug='agenda-1', date_start=datetime.date(2022, 9, 1), date_end=datetime.date(2022, 10, 1)
),
mock.call(
agenda_slug='agenda-2', date_start=datetime.date(2022, 9, 1), date_end=datetime.date(2022, 10, 1)
),
]
@mock.patch('lingo.invoicing.utils.get_check_status')
def test_get_invoice_lines_for_user_check_status_error(mock_status):
agenda = Agenda.objects.create(label='Agenda')
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=True,
)
mock_status.side_effect = ChronoError('foo baz')
with pytest.raises(ChronoError):
utils.get_invoice_lines_for_user(
agendas=[agenda],
agendas_pricings=[],
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
@pytest.mark.parametrize('injected_lines', ['no', 'period', 'all'])
@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, injected_lines):
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')
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2022, month=9, day=1),
date_end=datetime.date(year=2022, month=10, day=1),
)
agenda_pricing.agendas.add(agenda1, agenda2)
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),
injected_lines=injected_lines,
)
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
injected_line1 = InjectedLine.objects.create(
event_date=datetime.date(2022, 8, 31), # before the period
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(
event_date=datetime.date(2022, 9, 1),
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(
event_date=datetime.date(2022, 9, 15),
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(
event_date=datetime.date(2022, 9, 16),
quantity=0,
unit_amount=0,
total_amount=0,
pool=other_pool,
from_injected_line=injected_line7,
)
# no agendas
assert (
utils.get_invoice_lines_for_user(
agendas=[],
agendas_pricings=[agenda_pricing],
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
== []
)
assert mock_status.call_args_list == []
assert mock_pricing_data_event.call_args_list == []
# no status
mock_status.return_value = []
lines = utils.get_invoice_lines_for_user(
agendas=[agenda1, agenda2],
agendas_pricings=[agenda_pricing],
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
if injected_lines == 'no':
assert len(lines) == 0
elif injected_lines == 'period':
assert len(lines) == 2 # injected lines
else:
assert len(lines) == 3 # injected lines
assert mock_status.call_args_list == [
mock.call(
agenda_slugs=['agenda-1', 'agenda-2'],
user_external_id='user:1',
date_start=datetime.date(2022, 9, 1),
date_end=datetime.date(2022, 10, 1),
)
]
mock_status.reset_mock()
assert mock_pricing_data_event.call_args_list == []
# correct data
mock_pricing_data_event.side_effect = [
{'foo1': 'bar1', 'pricing': 1},
{'foo2': 'bar2', 'pricing': 2},
{'foo3': 'bar3', 'pricing': 3},
{'foo4': 'bar4', 'pricing': 4},
]
mock_status.return_value = [
# many events for agenda-1
{
'event': {
'agenda': 'agenda-1',
'start_datetime': '2022-09-01T12:00:00+02:00',
'slug': 'event-1',
'label': 'Event 1',
},
'check_status': {'foo': 'bar1'},
'booking': {'foo': 'baz1'},
},
{
'event': {
'agenda': 'agenda-1',
'start_datetime': '2022-09-02T12:00:00+02:00',
'slug': 'event-2',
'label': 'Event 2',
},
'check_status': {'foo': 'bar2'},
'booking': {'foo': 'baz2'},
},
# and for agenda-2
{
'event': {
'agenda': 'agenda-2',
'start_datetime': '2022-09-01T13:00:00+02:00',
'slug': 'eveeent-1',
'label': 'Eveeent 1',
},
'check_status': {'foo': 'barrr1'},
'booking': {'foo': 'bazzz1'},
},
{
'event': {
'agenda': 'agenda-2',
'start_datetime': '2022-09-02T13:00:00+02:00',
'slug': 'eveeent-2',
'label': 'Eveeent 2',
},
'check_status': {'foo': 'barrr2'},
'booking': {'foo': 'bazzz2'},
},
]
lines = utils.get_invoice_lines_for_user(
agendas=[agenda1, agenda2],
agendas_pricings=[agenda_pricing],
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
assert mock_pricing_data_event.call_args_list == [
mock.call(
request=mock.ANY,
agenda=agenda1,
event={
'agenda': 'agenda-1',
'start_datetime': '2022-09-01T12:00:00+02:00',
'slug': 'event-1',
'label': 'Event 1',
},
check_status={'foo': 'bar1'},
user_external_id='user:1',
adult_external_id='user:1',
),
mock.call(
request=mock.ANY,
agenda=agenda1,
event={
'agenda': 'agenda-1',
'start_datetime': '2022-09-02T12:00:00+02:00',
'slug': 'event-2',
'label': 'Event 2',
},
check_status={'foo': 'bar2'},
user_external_id='user:1',
adult_external_id='user:1',
),
mock.call(
request=mock.ANY,
agenda=agenda2,
event={
'agenda': 'agenda-2',
'start_datetime': '2022-09-01T13:00:00+02:00',
'slug': 'eveeent-1',
'label': 'Eveeent 1',
},
check_status={'foo': 'barrr1'},
user_external_id='user:1',
adult_external_id='user:1',
),
mock.call(
request=mock.ANY,
agenda=agenda2,
event={
'agenda': 'agenda-2',
'start_datetime': '2022-09-02T13:00:00+02:00',
'slug': 'eveeent-2',
'label': 'Eveeent 2',
},
check_status={'foo': 'barrr2'},
user_external_id='user:1',
adult_external_id='user:1',
),
]
if injected_lines == 'no':
assert len(lines) == 4
line1, line2, line3, line4 = lines
elif injected_lines == 'period':
assert len(lines) == 6
line1, line2, line3, line4, line6, line7 = lines
else:
assert len(lines) == 7
line1, line2, line3, line4, line5, line6, line7 = lines
assert isinstance(line1, DraftInvoiceLine)
assert line1.invoice is None
assert line1.event_date == datetime.date(2022, 9, 1)
assert line1.slug == 'agenda-1@event-1'
assert line1.label == 'Event 1'
assert line1.quantity == 1
assert line1.unit_amount == 1
assert line1.total_amount == 1
assert line1.user_external_id == 'user:1'
assert line1.user_name == 'User1 Name1'
assert line1.payer_external_id == 'user:1'
assert line1.event == {
'agenda': 'agenda-1',
'start_datetime': '2022-09-01T12:00:00+02:00',
'slug': 'event-1',
'label': 'Event 1',
}
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.event_date == datetime.date(2022, 9, 2)
assert line2.slug == 'agenda-1@event-2'
assert line2.label == 'Event 2'
assert line2.quantity == 1
assert line2.unit_amount == 2
assert line2.total_amount == 2
assert line2.user_external_id == 'user:1'
assert line2.user_name == 'User1 Name1'
assert line2.payer_external_id == 'user:1'
assert line2.event == {
'agenda': 'agenda-1',
'start_datetime': '2022-09-02T12:00:00+02:00',
'slug': 'event-2',
'label': 'Event 2',
}
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.event_date == datetime.date(2022, 9, 1)
assert line3.slug == 'agenda-2@eveeent-1'
assert line3.label == 'Eveeent 1'
assert line3.quantity == 1
assert line3.unit_amount == 3
assert line3.total_amount == 3
assert line3.user_external_id == 'user:1'
assert line3.user_name == 'User1 Name1'
assert line3.payer_external_id == 'user:1'
assert line3.event == {
'agenda': 'agenda-2',
'start_datetime': '2022-09-01T13:00:00+02:00',
'slug': 'eveeent-1',
'label': 'Eveeent 1',
}
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.event_date == datetime.date(2022, 9, 2)
assert line4.slug == 'agenda-2@eveeent-2'
assert line4.label == 'Eveeent 2'
assert line4.quantity == 1
assert line4.unit_amount == 4
assert line4.total_amount == 4
assert line4.user_external_id == 'user:1'
assert line4.user_name == 'User1 Name1'
assert line4.payer_external_id == 'user:1'
assert line4.event == {
'agenda': 'agenda-2',
'start_datetime': '2022-09-02T13:00:00+02:00',
'slug': 'eveeent-2',
'label': 'Eveeent 2',
}
assert line4.pricing_data == {'foo4': 'bar4', 'pricing': 4}
assert line4.status == 'success'
assert line4.pool == pool
assert line4.from_injected_line is None
if injected_lines != 'no':
if injected_lines == 'all':
assert isinstance(line5, DraftInvoiceLine)
assert line5.invoice is None
assert line5.event_date == injected_line1.event_date
assert line5.slug == 'event-2022-08-31'
assert line5.label == 'Event 2022-08-31'
assert line5.quantity == 2
assert line5.unit_amount == 1.5
assert line5.total_amount == 3
assert line5.user_external_id == 'user:1'
assert line5.user_name == 'User1 Name1'
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_line1
assert isinstance(line6, DraftInvoiceLine)
assert line6.invoice is None
assert line6.event_date == injected_line2.event_date
assert line6.slug == 'event-2022-09-01'
assert line6.label == 'Event 2022-09-01'
assert line6.quantity == 2
assert line6.unit_amount == 1.5
assert line6.total_amount == 3
assert line6.user_external_id == 'user:1'
assert line6.user_name == 'User1 Name1'
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_line2
assert isinstance(line7, DraftInvoiceLine)
assert line7.invoice is None
assert line7.event_date == injected_line4.event_date
assert line7.slug == 'event-2022-09-30'
assert line7.label == 'Event 2022-09-30'
assert line7.quantity == 3
assert line7.unit_amount == 1.5
assert line7.total_amount == 4.5
assert line7.user_external_id == 'user:1'
assert line7.user_name == 'User1 Name1'
assert line7.payer_external_id == 'user:1'
assert line7.event == {}
assert line7.pricing_data == {}
assert line7.status == 'success'
assert line7.pool == pool
assert line7.from_injected_line == injected_line4
@mock.patch('lingo.invoicing.utils.get_check_status')
def test_get_invoice_lines_for_user_check_status_agenda_pricing_dates(mock_status):
agenda = Agenda.objects.create(label='Agenda')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing1 = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2022, month=9, day=1),
date_end=datetime.date(year=2022, month=10, day=1),
)
agenda_pricing1.agendas.add(agenda)
agenda_pricing2 = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2022, month=10, day=1),
date_end=datetime.date(year=2022, month=11, day=1),
flat_fee_schedule=True,
)
agenda_pricing2.agendas.add(agenda)
agenda_pricing3 = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2022, month=10, day=1),
date_end=datetime.date(year=2022, month=11, day=1),
)
agenda_pricing3.agendas.add(agenda)
campaign = Campaign.objects.create(
date_start=datetime.date(2022, 1, 1),
date_end=datetime.date(2023, 1, 1),
date_issue=datetime.date(2023, 1, 31),
)
pool = Pool.objects.create(
campaign=campaign,
draft=True,
)
pricing_data_event_patch = mock.patch.object(AgendaPricing, 'get_pricing_data_for_event', autospec=True)
# check agenda pricing of september is used
for event_date in ['2022-09-01T12:00:00+02:00', '2022-09-30T12:00:00+02:00']:
mock_status.return_value = [
{
'event': {
'agenda': 'agenda',
'start_datetime': event_date,
'slug': 'event',
'label': 'Event',
},
'check_status': {'foo': 'bar'},
'booking': {'foo': 'baz'},
},
]
with pricing_data_event_patch as mock_pricing_data_event:
mock_pricing_data_event.return_value = {'foo': 'bar', 'pricing': 42}
lines = utils.get_invoice_lines_for_user(
agendas=[agenda],
agendas_pricings=AgendaPricing.objects.all(),
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
assert len(lines) == 1
assert mock_pricing_data_event.call_args_list[0][0][0] == agenda_pricing1
# check agenda pricing of october is used
for event_date in ['2022-10-01T12:00:00+02:00', '2022-10-31T12:00:00+02:00']:
mock_status.return_value = [
{
'event': {
'agenda': 'agenda',
'start_datetime': event_date,
'slug': 'event',
'label': 'Event',
},
'check_status': {'foo': 'bar'},
'booking': {'foo': 'baz'},
},
]
with pricing_data_event_patch as mock_pricing_data_event:
mock_pricing_data_event.return_value = {'foo': 'bar', 'pricing': 42}
lines = utils.get_invoice_lines_for_user(
agendas=[agenda],
agendas_pricings=AgendaPricing.objects.all(),
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
assert len(lines) == 1
assert mock_pricing_data_event.call_args_list[0][0][0] == agenda_pricing3
# no matching agenda pricing
for event_date in ['2022-08-31T12:00:00+02:00', '2022-11-01T12:00:00+02:00']:
mock_status.return_value = [
{
'event': {
'agenda': 'agenda',
'start_datetime': event_date,
'slug': 'event',
'label': 'Event',
},
'check_status': {'foo': 'bar'},
'booking': {'foo': 'baz'},
},
]
with pricing_data_event_patch as mock_pricing_data_event:
lines = utils.get_invoice_lines_for_user(
agendas=[agenda],
agendas_pricings=AgendaPricing.objects.all(),
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
assert len(lines) == 1
line = lines[0]
assert isinstance(line, DraftInvoiceLine)
assert line.invoice is None
assert line.slug == 'agenda@event'
assert line.label == 'Event'
assert line.quantity == 0
assert line.unit_amount == 0
assert line.total_amount == 0
assert line.user_external_id == 'user:1'
assert line.user_name == 'User1 Name1'
assert line.payer_external_id == 'user:1'
assert line.event == {
'agenda': 'agenda',
'start_datetime': event_date,
'slug': 'event',
'label': 'Event',
}
assert line.pricing_data == {'error': 'AgendaPricingNotFound', 'error_details': {}}
assert line.status == 'warning'
assert line.pool == pool
assert mock_pricing_data_event.call_args_list == []
@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_pricing_error(mock_pricing_data_event, mock_status):
agenda = Agenda.objects.create(label='Agenda')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2022, month=9, day=1),
date_end=datetime.date(year=2022, month=10, day=1),
)
agenda_pricing.agendas.add(agenda)
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=True,
)
mock_pricing_data_event.side_effect = [
{'foo1': 'bar1', 'pricing': decimal.Decimal(1)},
PricingError(details={'foo': 'bar'}),
{'foo3': 'bar3', 'pricing': decimal.Decimal(3)},
]
mock_status.return_value = [
{
'event': {
'agenda': 'agenda',
'start_datetime': '2022-09-01T12:00:00+02:00',
'slug': 'event-1',
'label': 'Event 1',
},
'check_status': {'foo': 'bar'},
'booking': {'foo': 'baz'},
},
{
'event': {
'agenda': 'agenda',
'start_datetime': '2022-09-02T12:00:00+02:00',
'slug': 'event-2',
'label': 'Event 2',
},
'check_status': {'foo': 'bar'},
'booking': {'foo': 'baz'},
},
{
'event': {
'agenda': 'agenda',
'start_datetime': '2022-09-03T12:00:00+02:00',
'slug': 'event-3',
'label': 'Event 3',
},
'check_status': {'foo': 'bar'},
'booking': {'foo': 'baz'},
},
]
lines = utils.get_invoice_lines_for_user(
agendas=[agenda],
agendas_pricings=[agenda_pricing],
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
assert len(lines) == 3
line1, line2, line3 = lines
assert isinstance(line1, DraftInvoiceLine)
assert line1.invoice is None
assert line1.event_date == datetime.date(2022, 9, 1)
assert line1.slug == 'agenda@event-1'
assert line1.label == 'Event 1'
assert line1.quantity == 1
assert line1.unit_amount == 1
assert line1.total_amount == 1
assert line1.user_external_id == 'user:1'
assert line1.user_name == 'User1 Name1'
assert line1.payer_external_id == 'user:1'
assert line1.event == {
'agenda': 'agenda',
'start_datetime': '2022-09-01T12:00:00+02:00',
'slug': 'event-1',
'label': 'Event 1',
}
assert line1.pricing_data == {'foo1': 'bar1', 'pricing': 1}
assert line1.status == 'success'
assert line1.pool == pool
assert isinstance(line2, DraftInvoiceLine)
assert line2.invoice is None
assert line2.event_date == datetime.date(2022, 9, 2)
assert line2.slug == 'agenda@event-2'
assert line2.label == 'Event 2'
assert line2.quantity == 0
assert line2.unit_amount == 0
assert line2.total_amount == 0
assert line2.user_external_id == 'user:1'
assert line2.user_name == 'User1 Name1'
assert line2.payer_external_id == 'user:1'
assert line2.event == {
'agenda': 'agenda',
'start_datetime': '2022-09-02T12:00:00+02:00',
'slug': 'event-2',
'label': 'Event 2',
}
assert line2.pricing_data == {'error': 'PricingError', 'error_details': {'foo': 'bar'}}
assert line2.status == 'error'
assert line2.pool == pool
assert isinstance(line3, DraftInvoiceLine)
assert line3.invoice is None
assert line3.event_date == datetime.date(2022, 9, 3)
assert line3.slug == 'agenda@event-3'
assert line3.label == 'Event 3'
assert line3.quantity == 1
assert line3.unit_amount == 3
assert line3.total_amount == 3
assert line3.user_external_id == 'user:1'
assert line3.user_name == 'User1 Name1'
assert line3.payer_external_id == 'user:1'
assert line3.event == {
'agenda': 'agenda',
'start_datetime': '2022-09-03T12:00:00+02:00',
'slug': 'event-3',
'label': 'Event 3',
}
assert line3.pricing_data == {'foo3': 'bar3', 'pricing': 3}
assert line3.status == 'success'
assert line3.pool == pool
@mock.patch('lingo.invoicing.utils.get_invoice_lines_for_user')
def test_get_all_invoice_lines(mock_user_lines):
agenda1 = Agenda.objects.create(label='Agenda 1')
agenda2 = Agenda.objects.create(label='Agenda 2')
Agenda.objects.create(label='Agenda 3')
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=True,
)
line1 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
quantity=0,
unit_amount=0,
total_amount=0,
pool=pool,
)
line2 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
quantity=0,
unit_amount=0,
total_amount=0,
pool=pool,
)
line3 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
quantity=0,
unit_amount=0,
total_amount=0,
pool=pool,
)
mock_user_lines.side_effect = [[line1, line2], [line3]]
# no subscribed users
assert (
utils.get_all_invoice_lines(
agendas=[agenda1, agenda2],
users=[],
pool=pool,
)
== []
)
assert mock_user_lines.call_args_list == []
# with subscribed users
assert utils.get_all_invoice_lines(
agendas=[agenda1, agenda2],
users=[('user:1', 'User1 Name1'), ('user:2', 'User2 Name2')],
pool=pool,
) == [line1, line2, line3]
assert mock_user_lines.call_args_list == [
mock.call(
agendas=[agenda1, agenda2],
agendas_pricings=mock.ANY,
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
),
mock.call(
agendas=[agenda1, agenda2],
agendas_pricings=mock.ANY,
user_external_id='user:2',
user_name='User2 Name2',
pool=pool,
),
]
@mock.patch('lingo.invoicing.utils.get_check_status')
def test_get_all_invoice_lines_queryset(mock_status):
# don't mock get_pricing_data_for_event to check all querysets
category1 = CriteriaCategory.objects.create(label='Foo1', slug='foo1')
criteria1 = Criteria.objects.create(label='Bar1', slug='bar1', condition='True', category=category1)
category2 = CriteriaCategory.objects.create(label='Foo2', slug='foo2')
criteria2 = Criteria.objects.create(label='Bar2', slug='bar2', condition='True', category=category2)
pricing1 = Pricing.objects.create(label='Foo bar 1')
pricing1.criterias.add(criteria1, criteria2)
pricing1.categories.add(category1, through_defaults={'order': 1})
pricing1.categories.add(category2, through_defaults={'order': 2})
pricing2 = Pricing.objects.create(label='Foo bar 2')
pricing2.criterias.add(criteria1, criteria2)
pricing2.categories.add(category1, through_defaults={'order': 1})
pricing2.categories.add(category2, through_defaults={'order': 2})
agenda1 = Agenda.objects.create(label='Agenda 1')
agenda_pricing11 = AgendaPricing.objects.create(
pricing=pricing1,
date_start=datetime.date(year=2022, month=9, day=1),
date_end=datetime.date(year=2022, month=10, day=1),
)
agenda_pricing11.agendas.add(agenda1)
agenda_pricing12 = AgendaPricing.objects.create(
pricing=pricing1,
date_start=datetime.date(year=2022, month=10, day=1),
date_end=datetime.date(year=2022, month=11, day=1),
)
agenda_pricing12.agendas.add(agenda1)
agenda2 = Agenda.objects.create(label='Agenda 2')
agenda_pricing21 = AgendaPricing.objects.create(
pricing=pricing2,
date_start=datetime.date(year=2022, month=9, day=1),
date_end=datetime.date(year=2022, month=10, day=1),
)
agenda_pricing21.agendas.add(agenda2)
agenda_pricing22 = AgendaPricing.objects.create(
pricing=pricing2,
date_start=datetime.date(year=2022, month=10, day=1),
date_end=datetime.date(year=2022, month=11, day=1),
)
agenda_pricing22.agendas.add(agenda2)
campaign = Campaign.objects.create(
date_start=datetime.date(2022, 9, 1),
date_end=datetime.date(2022, 11, 1),
date_issue=datetime.date(2022, 11, 30),
injected_lines='all',
)
pool = Pool.objects.create(
campaign=campaign,
draft=True,
)
mock_status.return_value = [
{
'event': {
'agenda': 'agenda-1',
'start_datetime': '2022-09-01T12:00:00+02:00',
'slug': 'event',
'label': 'Event',
},
'check_status': {'foo': 'bar'},
'booking': {'foo': 'baz'},
},
{
'event': {
'agenda': 'agenda-1',
'start_datetime': '2022-10-01T12:00:00+02:00',
'slug': 'event',
'label': 'Event',
},
'check_status': {'foo': 'bar'},
'booking': {'foo': 'baz'},
},
{
'event': {
'agenda': 'agenda-2',
'start_datetime': '2022-09-01T12:00:00+02:00',
'slug': 'event',
'label': 'Event',
},
'check_status': {'foo': 'bar'},
'booking': {'foo': 'baz'},
},
{
'event': {
'agenda': 'agenda-2',
'start_datetime': '2022-10-01T12:00:00+02:00',
'slug': 'event',
'label': 'Event',
},
'check_status': {'foo': 'bar'},
'booking': {'foo': 'baz'},
},
]
with CaptureQueriesContext(connection) as ctx:
lines = utils.get_all_invoice_lines(
agendas=[agenda1, agenda2],
users=[('user:1', 'User1 Name1'), ('user:2', 'User2 Name2')],
pool=pool,
)
assert lines
assert len(ctx.captured_queries) == 9
def test_generate_invoices_from_lines():
regie1 = Regie.objects.create(label='Regie 1')
regie2 = Regie.objects.create(label='Regie 2')
agenda1 = Agenda.objects.create(label='Agenda 1', regie=regie1)
agenda2 = Agenda.objects.create(label='Agenda 2', regie=regie2)
agenda3 = Agenda.objects.create(label='Agenda 3', regie=regie1)
agenda4 = Agenda.objects.create(label='Agenda 4') # regie not configured
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=True,
)
line_error = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
event={'agenda': 'agenda-1'},
quantity=0,
unit_amount=0,
total_amount=0,
user_external_id='user:1',
payer_external_id='user:1',
status='error',
pool=pool,
)
line1 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
event={'agenda': 'agenda-1'},
quantity=1,
unit_amount=1,
total_amount=1,
user_external_id='user:1',
payer_external_id='user:1',
status='success',
pool=pool,
)
line2 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
event={'agenda': 'agenda-1'},
quantity=1,
unit_amount=2,
total_amount=2,
user_external_id='user:1',
payer_external_id='user:1',
status='success',
pool=pool,
)
line3 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
event={'agenda': 'agenda-2'},
quantity=1,
unit_amount=3,
total_amount=3,
user_external_id='user:1',
payer_external_id='user:1',
status='success',
pool=pool,
)
line4 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
event={'agenda': 'agenda-2'},
quantity=1,
unit_amount=4,
total_amount=4,
user_external_id='user:1',
payer_external_id='user:2',
status='success',
pool=pool,
)
line5 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
event={'agenda': 'agenda-3'},
quantity=1,
unit_amount=5,
total_amount=5,
user_external_id='user:2',
payer_external_id='user:1',
status='success',
pool=pool,
)
DraftInvoiceLine.objects.create( # not used for generation
event_date=datetime.date(2022, 9, 1),
event={'agenda': 'agenda-3'},
quantity=1,
unit_amount=5,
total_amount=5,
user_external_id='user:2',
payer_external_id='user:1',
status='success',
pool=pool,
)
line6 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
event={'agenda': 'agenda-4'}, # regie not configured
quantity=1,
unit_amount=6,
total_amount=6,
user_external_id='user:1',
payer_external_id='user:1',
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(
event_date=datetime.date(2022, 9, 1),
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=[],
all_lines=[line_error, line1, line2, line3, line4, line5, line6],
pool=pool,
)
assert len(invoices) == 0
with pytest.raises(RegieNotConfigured) as excinfo:
invoices = utils.generate_invoices_from_lines(
agendas=[agenda1, agenda2, agenda3, agenda4],
all_lines=[line_error, line1, line2, line3, line4, line5, line6],
pool=pool,
)
assert '%s' % excinfo.value == 'Regie not configured on agenda-4'
assert len(invoices) == 0
line6.delete()
invoices = utils.generate_invoices_from_lines(
agendas=[agenda1, agenda2, agenda3, agenda4],
all_lines=[line_error, line1, line2, line3, line4, line5, line7],
pool=pool,
)
assert len(invoices) == 3
invoice1, invoice2, invoice3 = invoices
# refresh total_amount field (triggered)
invoice1.refresh_from_db()
invoice2.refresh_from_db()
invoice3.refresh_from_db()
assert isinstance(invoice1, DraftInvoice)
assert invoice1.label == 'Invoice from 2022-09-01 to 2022-09-30'
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, line7]
assert isinstance(invoice2, DraftInvoice)
assert invoice2.label == 'Invoice from 2022-09-01 to 2022-09-30'
assert invoice2.total_amount == 3
assert invoice2.date_issue == datetime.date(2022, 10, 31)
assert invoice2.regie == regie2
assert invoice2.payer == 'user:1'
assert invoice2.pool == pool
assert list(invoice2.lines.order_by('pk')) == [line3]
assert isinstance(invoice3, DraftInvoice)
assert invoice3.label == 'Invoice from 2022-09-01 to 2022-09-30'
assert invoice3.total_amount == 4
assert invoice3.date_issue == datetime.date(2022, 10, 31)
assert invoice3.regie == regie2
assert invoice3.payer == 'user:2'
assert invoice3.pool == pool
assert list(invoice3.lines.order_by('pk')) == [line4]
@mock.patch('lingo.invoicing.utils.get_agendas')
@mock.patch('lingo.invoicing.utils.get_users_from_subscriptions')
@mock.patch('lingo.invoicing.utils.get_all_invoice_lines')
@mock.patch('lingo.invoicing.utils.generate_invoices_from_lines')
def test_generate_invoices(mock_generate, mock_lines, mock_users, mock_agendas):
agenda1 = Agenda.objects.create(label='Agenda 1')
agenda2 = Agenda.objects.create(label='Agenda 2')
Agenda.objects.create(label='Agenda 3')
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),
)
mock_agendas.return_value = [agenda1, agenda2]
mock_users.return_value = ['foo', 'bar']
mock_lines.return_value = ['foo', 'baz']
# check only calls between functions
campaign.generate()
pool = Pool.objects.latest('pk')
assert pool.campaign == campaign
assert pool.draft is True
assert mock_agendas.call_args_list == [mock.call(pool=pool)]
assert mock_users.call_args_list == [
mock.call(
agendas=[agenda1, agenda2],
pool=pool,
)
]
assert mock_lines.call_args_list == [
mock.call(
agendas=[agenda1, agenda2],
users=['foo', 'bar'],
pool=pool,
)
]
assert mock_generate.call_args_list == [
mock.call(
agendas=[agenda1, agenda2],
all_lines=['foo', 'baz'],
pool=pool,
)
]
@mock.patch('lingo.invoicing.utils.get_agendas')
@mock.patch('lingo.invoicing.utils.get_users_from_subscriptions')
@mock.patch('lingo.invoicing.utils.get_all_invoice_lines')
@mock.patch('lingo.invoicing.utils.generate_invoices_from_lines')
def test_generate_invoices_errors(mock_generate, mock_lines, mock_users, mock_agendas):
agenda1 = Agenda.objects.create(label='Agenda 1')
agenda2 = Agenda.objects.create(label='Agenda 2')
Agenda.objects.create(label='Agenda 3')
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),
)
mock_agendas.return_value = [agenda1, agenda2]
mock_users.side_effect = ChronoError('foo bar')
campaign.generate()
pool = Pool.objects.latest('pk')
assert pool.status == 'failed'
assert pool.exception == 'foo bar'
mock_users.side_effect = None
mock_users.return_value = ['foo', 'bar']
mock_lines.side_effect = RegieNotConfigured('foo baz')
campaign.generate()
pool = Pool.objects.latest('pk')
assert pool.status == 'failed'
assert pool.exception == 'foo baz'
def test_generate_invoices_cmd():
with mock.patch.object(Campaign, 'generate', autospec=True) as mock_generate:
with pytest.raises(CommandError) as excinfo:
call_command('generate_invoices')
assert '%s' % excinfo.value == 'Error: the following arguments are required: date_start, date_end'
assert mock_generate.call_args_list == []
with pytest.raises(CommandError) as excinfo:
call_command('generate_invoices', 'bad-value', '2022-10-01')
assert '%s' % excinfo.value == 'Bad value "bad-value" for date_start'
assert mock_generate.call_args_list == []
with pytest.raises(CommandError) as excinfo:
call_command('generate_invoices', '2022-09-01', 'bad-value')
assert '%s' % excinfo.value == 'Bad value "bad-value" for date_end'
assert mock_generate.call_args_list == []
with pytest.raises(CommandError) as excinfo:
call_command('generate_invoices', '2022-09-01', '2022-10-01', '--date-issue=bad-value')
assert '%s' % excinfo.value == 'Bad value "bad-value" for date_issue'
assert mock_generate.call_args_list == []
assert Campaign.objects.count() == 0
call_command('generate_invoices', '2022-09-01', '2022-10-01')
assert Campaign.objects.count() == 1
campaign = Campaign.objects.latest('pk')
assert campaign.date_start == datetime.date(2022, 9, 1)
assert campaign.date_end == datetime.date(2022, 10, 1)
assert campaign.date_issue == campaign.date_end
assert mock_generate.call_args_list == [mock.call(campaign, spool=False)]
mock_generate.reset_mock()
# again
call_command('generate_invoices', '2022-09-01', '2022-10-01')
assert Campaign.objects.count() == 1
assert mock_generate.call_args_list == [mock.call(campaign, spool=False)]
mock_generate.reset_mock()
# with overlapping
with pytest.raises(CommandError) as excinfo:
call_command('generate_invoices', '2022-08-31', '2022-09-02')
assert '%s' % excinfo.value == 'Overlapping campaigns already exist'
assert mock_generate.call_args_list == []
with pytest.raises(CommandError) as excinfo:
call_command('generate_invoices', '2022-09-30', '2022-10-02')
assert '%s' % excinfo.value == 'Overlapping campaigns already exist'
assert mock_generate.call_args_list == []
# no overlapping
call_command('generate_invoices', '2022-08-01', '2022-09-01', '--date-issue=2022-10-31')
assert Campaign.objects.count() == 2
campaign = Campaign.objects.latest('pk')
assert mock_generate.call_args_list == [mock.call(campaign, spool=False)]
assert campaign.date_start == datetime.date(2022, 8, 1)
assert campaign.date_end == datetime.date(2022, 9, 1)
assert campaign.date_issue == datetime.date(2022, 10, 31)
mock_generate.reset_mock()
call_command('generate_invoices', '2022-10-01', '2022-11-01')
assert Campaign.objects.count() == 3
campaign = Campaign.objects.latest('pk')
assert mock_generate.call_args_list == [mock.call(campaign, spool=False)]
assert campaign.date_start == datetime.date(2022, 10, 1)
assert campaign.date_end == datetime.date(2022, 11, 1)
assert campaign.date_issue == campaign.date_end
def test_promote_pool():
today = datetime.date.today()
regie1 = Regie.objects.create(label='Regie1')
regie2 = Regie.objects.create(label='Regie2')
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),
)
old_pool = Pool.objects.create(
campaign=campaign,
draft=True,
)
pool = Pool.objects.create(
campaign=campaign,
draft=True,
completed_at=now(),
status='completed',
)
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,
)
invoice1 = DraftInvoice.objects.create(
date_issue=datetime.date.today(), regie=regie1, pool=pool, payer='payer:1'
)
line11 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
slug='label-11',
label='Label 11',
quantity=1,
unit_amount=1,
total_amount=1,
user_external_id='user:1',
user_name='User1 Name1',
payer_external_id='payer:1',
status='success',
event={'foo': 'bar'},
pricing_data={'foo': 'baz'},
invoice=invoice1,
pool=pool,
)
injected_line12 = InjectedLine.objects.create(
event_date=datetime.date(2022, 9, 1),
slug='label-12',
label='Label 12',
quantity=1,
unit_amount=2,
total_amount=2,
user_external_id='user:2',
payer_external_id='payer:1',
regie=regie1,
)
line12 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
slug='label-12',
label='Label 12',
quantity=1,
unit_amount=2,
total_amount=2,
user_external_id='user:2',
user_name='User2 Name2',
payer_external_id='payer:1',
status='success',
from_injected_line=injected_line12,
invoice=invoice1,
pool=pool,
)
invoice2 = DraftInvoice.objects.create(
date_issue=datetime.date.today(), regie=regie1, pool=pool, payer='payer:2'
)
injected_line21 = InjectedLine.objects.create(
event_date=datetime.date(2022, 9, 1),
slug='label-21',
label='Label 21',
quantity=1,
unit_amount=1,
total_amount=1,
user_external_id='user:2',
payer_external_id='payer:2',
regie=regie1,
)
line21 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
slug='label-21',
label='Label 21',
quantity=1,
unit_amount=1,
total_amount=1,
user_external_id='user:1',
user_name='User1 Name1',
payer_external_id='payer:2',
status='success',
invoice=invoice2,
pool=pool,
from_injected_line=injected_line21,
)
line22 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
slug='label-22',
label='Label 22',
quantity=1,
unit_amount=2,
total_amount=2,
user_external_id='user:2',
user_name='User2 Name2',
payer_external_id='payer:2',
status='success',
invoice=invoice2,
pool=pool,
)
orphan_line1 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
slug='orphan-1',
label='Orphan 1',
quantity=0,
unit_amount=0,
total_amount=0,
user_external_id='user:1',
user_name='User1 Name1',
payer_external_id='payer:1',
status='error',
pool=pool,
)
orphan_line2 = DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
slug='orphan-2',
label='Orphan 2',
quantity=0,
unit_amount=0,
total_amount=0,
user_external_id='user:1',
user_name='User1 Name1',
payer_external_id='payer:1',
status='warning',
pool=pool,
)
invoice3 = DraftInvoice.objects.create(
date_issue=datetime.date.today(), regie=regie2, pool=pool, payer='payer:1'
)
old_invoice = DraftInvoice.objects.create(
date_issue=datetime.date.today(), regie=regie1, pool=old_pool, payer='payer:1'
)
DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
slug='old-1',
label='Old 1',
quantity=1,
unit_amount=1,
total_amount=1,
user_external_id='user:1',
user_name='User1 Name1',
payer_external_id='payer:1',
status='success',
invoice=old_invoice,
pool=old_pool,
)
old_injected_line2 = InjectedLine.objects.create(
event_date=datetime.date(2022, 9, 1),
slug='old-2',
label='Old 2',
quantity=1,
unit_amount=2,
total_amount=2,
user_external_id='user:2',
payer_external_id='payer:1',
regie=regie1,
)
DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
slug='old-2',
label='Old 2',
quantity=1,
unit_amount=2,
total_amount=2,
user_external_id='user:2',
user_name='User2 Name2',
payer_external_id='payer:1',
status='success',
from_injected_line=old_injected_line2,
invoice=old_invoice,
pool=old_pool,
)
other_invoice = DraftInvoice.objects.create(
date_issue=datetime.date.today(), regie=regie1, pool=other_pool, payer='payer:1'
)
DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
slug='other-1',
label='Other 1',
quantity=1,
unit_amount=1,
total_amount=1,
user_external_id='user:1',
user_name='User1 Name1',
payer_external_id='payer:1',
status='success',
invoice=other_invoice,
pool=other_pool,
)
other_injected_line2 = InjectedLine.objects.create(
event_date=datetime.date(2022, 9, 1),
slug='other-2',
label='Other 2',
quantity=1,
unit_amount=2,
total_amount=2,
user_external_id='user:2',
payer_external_id='payer:1',
regie=regie1,
)
DraftInvoiceLine.objects.create(
event_date=datetime.date(2022, 9, 1),
slug='other-2',
label='Other 2',
quantity=1,
unit_amount=2,
total_amount=2,
user_external_id='user:2',
user_name='User2 Name2',
payer_external_id='payer:1',
status='success',
from_injected_line=other_injected_line2,
invoice=other_invoice,
pool=other_pool,
)
# refresh amounts
invoice1.refresh_from_db()
invoice2.refresh_from_db()
assert Campaign.objects.count() == 2
assert Pool.objects.count() == 3
assert Pool.objects.filter(draft=False).count() == 0
assert DraftInvoice.objects.count() == 5
assert DraftInvoiceLine.objects.count() == 10
assert Invoice.objects.count() == 0
assert InvoiceLine.objects.count() == 0
assert InjectedLine.objects.count() == 4
pool.promote()
def test_counts():
assert Campaign.objects.count() == 2
assert Pool.objects.count() == 4
assert Pool.objects.filter(draft=False).count() == 1
assert DraftInvoice.objects.count() == 5
assert DraftInvoiceLine.objects.count() == 10
assert Invoice.objects.count() == 3
assert InvoiceLine.objects.count() == 6
assert InjectedLine.objects.count() == 4
assert Counter.objects.get(regie=regie1, name=today.strftime('%y')).value == 2
assert Counter.objects.get(regie=regie2, name=today.strftime('%y')).value == 1
test_counts()
final_pool = Pool.objects.filter(draft=False).get()
assert final_pool.campaign == campaign
assert final_pool.created_at > pool.created_at
assert final_pool.completed_at > pool.completed_at
assert final_pool.status == 'completed'
assert final_pool.exception == ''
final_invoice1 = Invoice.objects.order_by('pk')[0]
assert final_invoice1.date_issue == invoice1.date_issue
assert final_invoice1.regie == regie1
assert final_invoice1.pool == final_pool
assert final_invoice1.payer == invoice1.payer
assert final_invoice1.total_amount == invoice1.total_amount == 3
assert final_invoice1.number == 1
assert final_invoice1.formatted_number == 'F%02d-%s-0000001' % (regie1.pk, today.strftime('%y-%m'))
final_line11 = InvoiceLine.objects.order_by('pk')[0]
assert final_line11.event_date == line11.event_date
assert final_line11.slug == line11.slug
assert final_line11.label == line11.label
assert final_line11.quantity == line11.quantity
assert final_line11.unit_amount == line11.unit_amount
assert final_line11.total_amount == line11.total_amount
assert final_line11.user_external_id == line11.user_external_id
assert final_line11.user_name == line11.user_name
assert final_line11.payer_external_id == line11.payer_external_id
assert final_line11.event == line11.event
assert final_line11.pricing_data == line11.pricing_data
assert final_line11.status == line11.status
assert final_line11.pool == final_pool
assert final_line11.invoice == final_invoice1
assert final_line11.from_injected_line is None
final_line12 = InvoiceLine.objects.order_by('pk')[1]
assert final_line12.event_date == line12.event_date
assert final_line12.slug == line12.slug
assert final_line12.label == line12.label
assert final_line12.quantity == line12.quantity
assert final_line12.unit_amount == line12.unit_amount
assert final_line12.total_amount == line12.total_amount
assert final_line12.user_external_id == line12.user_external_id
assert final_line12.user_name == line12.user_name
assert final_line12.payer_external_id == line12.payer_external_id
assert final_line12.event == line12.event
assert final_line12.pricing_data == line12.pricing_data
assert final_line12.status == line12.status
assert final_line12.pool == final_pool
assert final_line12.invoice == final_invoice1
assert final_line12.from_injected_line == injected_line12
final_invoice2 = Invoice.objects.order_by('pk')[1]
assert final_invoice2.date_issue == invoice2.date_issue
assert final_invoice2.regie == regie1
assert final_invoice2.pool == final_pool
assert final_invoice2.payer == invoice2.payer
assert final_invoice2.total_amount == invoice2.total_amount == 3
assert final_invoice2.number == 2
assert final_invoice2.formatted_number == 'F%02d-%s-0000002' % (regie1.pk, today.strftime('%y-%m'))
final_line21 = InvoiceLine.objects.order_by('pk')[2]
assert final_line21.event_date == line21.event_date
assert final_line21.slug == line21.slug
assert final_line21.label == line21.label
assert final_line21.quantity == line21.quantity
assert final_line21.unit_amount == line21.unit_amount
assert final_line21.total_amount == line21.total_amount
assert final_line21.user_external_id == line21.user_external_id
assert final_line21.user_name == line21.user_name
assert final_line21.payer_external_id == line21.payer_external_id
assert final_line21.event == line21.event
assert final_line21.pricing_data == line21.pricing_data
assert final_line21.status == line21.status
assert final_line21.pool == final_pool
assert final_line21.invoice == final_invoice2
assert final_line21.from_injected_line == injected_line21
final_line22 = InvoiceLine.objects.order_by('pk')[3]
assert final_line22.event_date == line22.event_date
assert final_line22.slug == line22.slug
assert final_line22.label == line22.label
assert final_line22.quantity == line22.quantity
assert final_line22.unit_amount == line22.unit_amount
assert final_line22.total_amount == line22.total_amount
assert final_line22.user_external_id == line22.user_external_id
assert final_line22.user_name == line22.user_name
assert final_line22.payer_external_id == line22.payer_external_id
assert final_line22.event == line22.event
assert final_line22.pricing_data == line22.pricing_data
assert final_line22.status == line22.status
assert final_line22.pool == final_pool
assert final_line22.invoice == final_invoice2
assert final_line22.from_injected_line is None
final_orphan_line1 = InvoiceLine.objects.order_by('pk')[4]
assert final_orphan_line1.event_date == orphan_line1.event_date
assert final_orphan_line1.slug == orphan_line1.slug
assert final_orphan_line1.label == orphan_line1.label
assert final_orphan_line1.quantity == orphan_line1.quantity
assert final_orphan_line1.unit_amount == orphan_line1.unit_amount
assert final_orphan_line1.total_amount == orphan_line1.total_amount
assert final_orphan_line1.user_external_id == orphan_line1.user_external_id
assert final_orphan_line1.user_name == orphan_line1.user_name
assert final_orphan_line1.payer_external_id == orphan_line1.payer_external_id
assert final_orphan_line1.event == orphan_line1.event
assert final_orphan_line1.pricing_data == orphan_line1.pricing_data
assert final_orphan_line1.status == orphan_line1.status
assert final_orphan_line1.pool == final_pool
assert final_orphan_line1.from_injected_line is None
final_orphan_line2 = InvoiceLine.objects.order_by('pk')[5]
assert final_orphan_line2.event_date == orphan_line2.event_date
assert final_orphan_line2.slug == orphan_line2.slug
assert final_orphan_line2.label == orphan_line2.label
assert final_orphan_line2.quantity == orphan_line2.quantity
assert final_orphan_line2.unit_amount == orphan_line2.unit_amount
assert final_orphan_line2.total_amount == orphan_line2.total_amount
assert final_orphan_line2.user_external_id == orphan_line2.user_external_id
assert final_orphan_line2.user_name == orphan_line2.user_name
assert final_orphan_line2.payer_external_id == orphan_line2.payer_external_id
assert final_orphan_line2.event == orphan_line2.event
assert final_orphan_line2.pricing_data == orphan_line2.pricing_data
assert final_orphan_line2.status == orphan_line2.status
assert final_orphan_line2.pool == final_pool
assert final_orphan_line2.from_injected_line is None
final_invoice3 = Invoice.objects.order_by('pk')[2]
assert final_invoice3.date_issue == invoice3.date_issue
assert final_invoice3.regie == regie2
assert final_invoice3.pool == final_pool
assert final_invoice3.payer == invoice3.payer
assert final_invoice3.total_amount == invoice3.total_amount == 0
assert final_invoice3.number == 1
assert final_invoice3.formatted_number == 'F%02d-%s-0000001' % (regie2.pk, today.strftime('%y-%m'))
with pytest.raises(PoolPromotionError) as excinfo:
old_pool.promote()
assert '%s' % excinfo.value == 'Pool too old'
test_counts()
with pytest.raises(PoolPromotionError) as excinfo:
final_pool.promote()
assert '%s' % excinfo.value == 'Pool is final'
test_counts()
for status in ['registered', 'running', 'failed']:
other_pool.status = status
other_pool.save()
with pytest.raises(PoolPromotionError) as excinfo:
other_pool.promote()
assert '%s' % excinfo.value == 'Pool is not completed'
test_counts()