invoicing: add user_name on lines (#73514)

This commit is contained in:
Lauréline Guérin 2023-01-19 11:58:46 +01:00
parent f49b9b8d03
commit 9f85afd377
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
5 changed files with 80 additions and 19 deletions

View File

@ -0,0 +1,23 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('invoicing', '0008_injected_line'),
]
operations = [
migrations.AddField(
model_name='draftinvoiceline',
name='user_name',
field=models.CharField(default='', max_length=250),
preserve_default=False,
),
migrations.AddField(
model_name='invoiceline',
name='user_name',
field=models.CharField(default='', max_length=250),
preserve_default=False,
),
]

View File

@ -152,11 +152,9 @@ class Pool(models.Model):
# get agendas with pricing corresponding to the period
agendas = utils.get_agendas(pool=self)
# get subscribed users for each agenda, for the period
user_external_ids = utils.get_users_from_subscriptions(agendas=agendas, pool=self)
users = utils.get_users_from_subscriptions(agendas=agendas, pool=self)
# get invoice lines for all subscribed users, for each agenda in the corresponding period
lines = utils.get_all_invoice_lines(
agendas=agendas, user_external_ids=user_external_ids, pool=self
)
lines = utils.get_all_invoice_lines(agendas=agendas, users=users, pool=self)
# and generate invoices
utils.generate_invoices_from_lines(agendas=agendas, all_lines=lines, pool=self)
except (RegieNotConfigured, ChronoError) as e:
@ -215,6 +213,7 @@ class AbstractInvoiceLine(models.Model):
total_amount = models.DecimalField(max_digits=9, decimal_places=2)
user_external_id = models.CharField(max_length=250)
user_name = models.CharField(max_length=250)
payer_external_id = models.CharField(max_length=250)
event = JSONField(default=dict)
pricing_data = JSONField(default=dict, encoder=DjangoJSONEncoder)

View File

@ -53,7 +53,7 @@
<td>{{ line.quantity }}</td>
<td>{{ line.unit_amount }}</td>
<td>{{ line.total_amount }}</td>
<td>{{ line.user_external_id }}</td>
<td>{{ line.user_name }} ({{ line.user_external_id }})</td>
<td>{{ line.payer_external_id }}</td>
<td class="status">
<span class="tag tag-{{ line.status }}">{{ line.get_status_display }}</span>

View File

@ -35,7 +35,7 @@ def get_agendas(pool):
def get_users_from_subscriptions(agendas, pool):
user_external_ids = set()
users = {}
for agenda in agendas:
subscriptions = get_subscriptions(
agenda_slug=agenda.slug,
@ -43,11 +43,15 @@ def get_users_from_subscriptions(agendas, pool):
date_end=pool.campaign.date_end,
)
for subscription in subscriptions:
user_external_ids.add(subscription['user_external_id'])
return user_external_ids
user_external_id = subscription['user_external_id']
if user_external_id in users:
continue
user_name = '%s %s' % (subscription['user_first_name'], subscription['user_last_name'])
users[user_external_id] = user_name.strip()[:250] or user_external_id
return [(user_id, user_name) for user_id, user_name in users.items()]
def get_invoice_lines_for_user(agendas, agendas_pricings, user_external_id, pool):
def get_invoice_lines_for_user(agendas, agendas_pricings, user_external_id, user_name, pool):
def get_agenda_pricing(agendas_pricings_for_agenda, date_event):
# same logic as AgendaPricing.get_agenda_pricing
for agenda_pricing in agendas_pricings_for_agenda:
@ -110,6 +114,7 @@ def get_invoice_lines_for_user(agendas, agendas_pricings, user_external_id, pool
unit_amount=0,
total_amount=0,
user_external_id=user_external_id,
user_name=user_name,
payer_external_id=user_external_id, # XXX
event=serialized_event,
pricing_data=pricing_error,
@ -127,6 +132,7 @@ def get_invoice_lines_for_user(agendas, agendas_pricings, user_external_id, pool
unit_amount=pricing_data['pricing'],
total_amount=pricing_data['pricing'],
user_external_id=user_external_id,
user_name=user_name,
payer_external_id=user_external_id, # XXX
event=serialized_event,
pricing_data=pricing_data,
@ -162,7 +168,8 @@ def get_invoice_lines_for_user(agendas, agendas_pricings, user_external_id, pool
quantity=injected_line.quantity,
unit_amount=injected_line.unit_amount,
total_amount=injected_line.total_amount,
user_external_id=injected_line.user_external_id,
user_external_id=user_external_id,
user_name=user_name,
payer_external_id=injected_line.user_external_id,
status='success',
pool=pool,
@ -175,7 +182,7 @@ def get_invoice_lines_for_user(agendas, agendas_pricings, user_external_id, pool
return lines
def get_all_invoice_lines(agendas, user_external_ids, pool):
def get_all_invoice_lines(agendas, users, pool):
agendas_pricings = (
AgendaPricing.objects.filter(flat_fee_schedule=False)
.extra(
@ -186,12 +193,13 @@ def get_all_invoice_lines(agendas, user_external_ids, pool):
)
lines = []
for user_external_id in user_external_ids:
for user_external_id, user_name in users:
# generate lines for each user
lines += get_invoice_lines_for_user(
agendas=agendas,
agendas_pricings=agendas_pricings,
user_external_id=user_external_id,
user_name=user_name,
pool=pool,
)
return lines

View File

@ -130,12 +130,12 @@ def test_get_users_from_subscriptions(mock_subscriptions):
)
# no agendas
assert utils.get_users_from_subscriptions(agendas=[], pool=pool) == set()
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) == set()
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)
@ -151,16 +151,22 @@ def test_get_users_from_subscriptions(mock_subscriptions):
[
{
'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',
},
@ -168,12 +174,17 @@ def test_get_users_from_subscriptions(mock_subscriptions):
[
{
'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', 'user:2'}
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)
@ -202,6 +213,7 @@ def test_get_invoice_lines_for_user_check_status_error(mock_status):
agendas=[agenda],
agendas_pricings=[],
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
@ -351,6 +363,7 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
agendas=[],
agendas_pricings=[agenda_pricing],
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
== []
@ -364,6 +377,7 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
agendas=[agenda1, agenda2],
agendas_pricings=[agenda_pricing],
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
assert len(lines) == 2 # injected lines
@ -433,6 +447,7 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
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 == [
@ -499,6 +514,7 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
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',
@ -518,6 +534,7 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
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',
@ -537,6 +554,7 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
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',
@ -556,6 +574,7 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
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',
@ -575,6 +594,7 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
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 == {}
@ -589,6 +609,7 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
assert line6.unit_amount == 1.5
assert line6.total_amount == 4.5
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 == {}
@ -652,6 +673,7 @@ def test_get_invoice_lines_for_user_check_status_agenda_pricing_dates(mock_statu
agendas=[agenda],
agendas_pricings=AgendaPricing.objects.all(),
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
assert len(lines) == 1
@ -677,6 +699,7 @@ def test_get_invoice_lines_for_user_check_status_agenda_pricing_dates(mock_statu
agendas=[agenda],
agendas_pricings=AgendaPricing.objects.all(),
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
assert len(lines) == 1
@ -701,6 +724,7 @@ def test_get_invoice_lines_for_user_check_status_agenda_pricing_dates(mock_statu
agendas=[agenda],
agendas_pricings=AgendaPricing.objects.all(),
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
assert len(lines) == 1
@ -713,6 +737,7 @@ def test_get_invoice_lines_for_user_check_status_agenda_pricing_dates(mock_statu
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',
@ -788,6 +813,7 @@ def test_get_invoice_lines_for_user_check_status_pricing_error(mock_pricing_data
agendas=[agenda],
agendas_pricings=[agenda_pricing],
user_external_id='user:1',
user_name='User1 Name1',
pool=pool,
)
assert len(lines) == 3
@ -800,6 +826,7 @@ def test_get_invoice_lines_for_user_check_status_pricing_error(mock_pricing_data
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',
@ -818,6 +845,7 @@ def test_get_invoice_lines_for_user_check_status_pricing_error(mock_pricing_data
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',
@ -836,6 +864,7 @@ def test_get_invoice_lines_for_user_check_status_pricing_error(mock_pricing_data
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',
@ -888,7 +917,7 @@ def test_get_all_invoice_lines(mock_user_lines):
assert (
utils.get_all_invoice_lines(
agendas=[agenda1, agenda2],
user_external_ids=[],
users=[],
pool=pool,
)
== []
@ -898,7 +927,7 @@ def test_get_all_invoice_lines(mock_user_lines):
# with subscribed users
assert utils.get_all_invoice_lines(
agendas=[agenda1, agenda2],
user_external_ids=['user:1', 'user:2'],
users=[('user:1', 'User1 Name1'), ('user:2', 'User2 Name2')],
pool=pool,
) == [line1, line2, line3]
assert mock_user_lines.call_args_list == [
@ -906,12 +935,14 @@ def test_get_all_invoice_lines(mock_user_lines):
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,
),
]
@ -1018,7 +1049,7 @@ def test_get_all_invoice_lines_queryset(mock_status):
with CaptureQueriesContext(connection) as ctx:
lines = utils.get_all_invoice_lines(
agendas=[agenda1, agenda2],
user_external_ids=['user:1', 'user:2'],
users=[('user:1', 'User1 Name1'), ('user:2', 'User2 Name2')],
pool=pool,
)
assert lines
@ -1232,7 +1263,7 @@ def test_generate_invoices(mock_generate, mock_lines, mock_users, mock_agendas):
assert mock_lines.call_args_list == [
mock.call(
agendas=[agenda1, agenda2],
user_external_ids=['foo', 'bar'],
users=['foo', 'bar'],
pool=pool,
)
]