wip/73742-invoicing-configure-injected-lines-in-campaign (#73742) #23
|
@ -25,7 +25,7 @@ from lingo.invoicing.models import Campaign, DraftInvoiceLine, InvoiceLine, Regi
|
|||
class CampaignForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Campaign
|
||||
fields = ['date_start', 'date_end', 'date_issue']
|
||||
fields = ['date_start', 'date_end', 'date_issue', 'injected_lines']
|
||||
widgets = {
|
||||
'date_start': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
|
||||
'date_end': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
|
||||
|
@ -92,6 +92,7 @@ class AbstractLineFilterSet(django_filters.FilterSet):
|
|||
|
||||
status_choices = [
|
||||
('success', _('Success')),
|
||||
('success_injected', '%s (%s)' % (_('Success'), _('Injected'))),
|
||||
('warning', _('Warning')),
|
||||
('error', _('Error')),
|
||||
]
|
||||
|
@ -106,6 +107,8 @@ class AbstractLineFilterSet(django_filters.FilterSet):
|
|||
def filter_status(self, queryset, name, value):
|
||||
if not value:
|
||||
return queryset
|
||||
if value == 'success_injected':
|
||||
return queryset.filter(status='success', from_injected_line__isnull=False)
|
||||
if value == 'error_todo':
|
||||
return queryset.filter(status='error', error_status='')
|
||||
if value == 'error_ignored':
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('invoicing', '0014_error_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='campaign',
|
||||
name='injected_lines',
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
('no', 'No'),
|
||||
('period', 'Yes, only for the period'),
|
||||
('all', 'Yes, all injected lines before the end of the period'),
|
||||
],
|
||||
default='no',
|
||||
max_length=10,
|
||||
verbose_name='Integrate injected lines',
|
||||
),
|
||||
),
|
||||
]
|
|
@ -134,6 +134,16 @@ class Campaign(models.Model):
|
|||
date_start = models.DateField(_('Start date'))
|
||||
date_end = models.DateField(_('End date'))
|
||||
date_issue = models.DateField(_('Issue date'))
|
||||
injected_lines = models.CharField(
|
||||
_('Integrate injected lines'),
|
||||
choices=[
|
||||
('no', _('No')),
|
||||
('period', _('Yes, only for the period')),
|
||||
('all', _('Yes, all injected lines before the end of the period')),
|
||||
],
|
||||
default='no',
|
||||
|
||||
max_length=10,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return _('From %(start)s to %(end)s') % {
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
<li>{% trans "Start date:" %} {{ object.date_start|date:'d/m/Y' }}</li>
|
||||
<li>{% trans "End date:" %} {{ object.date_end|date:'d/m/Y' }}</li>
|
||||
<li>{% trans "Issue date:" %} {{ object.date_issue|date:'d/m/Y' }}</li>
|
||||
<li>{% trans "Integrate injected lines:" %} {{ object.get_injected_lines_display }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -143,42 +143,47 @@ def get_invoice_lines_for_user(agendas, agendas_pricings, user_external_id, user
|
|||
)
|
||||
)
|
||||
|
||||
# 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(
|
||||
event_date=injected_line.event_date,
|
||||
slug=injected_line.slug,
|
||||
label=injected_line.label,
|
||||
quantity=injected_line.quantity,
|
||||
unit_amount=injected_line.unit_amount,
|
||||
total_amount=injected_line.total_amount,
|
||||
if pool.campaign.injected_lines != 'no':
|
||||
# fetch injected lines
|
||||
injected_lines = (
|
||||
InjectedLine.objects.filter(
|
||||
event_date__lt=pool.campaign.date_end,
|
||||
user_external_id=user_external_id,
|
||||
user_name=user_name,
|
||||
payer_external_id=injected_line.user_external_id,
|
||||
status='success',
|
||||
pool=pool,
|
||||
from_injected_line=injected_line,
|
||||
)
|
||||
.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')
|
||||
)
|
||||
.order_by('event_date')
|
||||
)
|
||||
if pool.campaign.injected_lines == 'period':
|
||||
injected_lines = injected_lines.filter(
|
||||
event_date__gte=pool.campaign.date_start,
|
||||
)
|
||||
|
||||
for injected_line in injected_lines:
|
||||
lines.append(
|
||||
DraftInvoiceLine(
|
||||
event_date=injected_line.event_date,
|
||||
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=user_external_id,
|
||||
user_name=user_name,
|
||||
payer_external_id=injected_line.user_external_id,
|
||||
status='success',
|
||||
pool=pool,
|
||||
from_injected_line=injected_line,
|
||||
)
|
||||
)
|
||||
|
||||
DraftInvoiceLine.objects.bulk_create(lines)
|
||||
|
||||
|
|
|
@ -198,6 +198,7 @@ regies_import = RegiesImportView.as_view()
|
|||
class CampaignListView(ListView):
|
||||
template_name = 'lingo/invoicing/manager_campaign_list.html'
|
||||
model = Campaign
|
||||
ordering = '-date_start'
|
||||
|
||||
|
||||
campaign_list = CampaignListView.as_view()
|
||||
|
|
|
@ -784,6 +784,7 @@ def test_journal_pool_lines(app, admin_user, draft):
|
|||
invoice_model = DraftInvoice if draft else Invoice
|
||||
line_model = DraftInvoiceLine if draft else InvoiceLine
|
||||
|
||||
regie = Regie.objects.create(label='Foo')
|
||||
campaign = Campaign.objects.create(
|
||||
date_start=datetime.date(2022, 9, 1),
|
||||
date_end=datetime.date(2022, 10, 1),
|
||||
|
@ -871,6 +872,15 @@ def test_journal_pool_lines(app, admin_user, draft):
|
|||
lines[-2].error_status = 'fixed'
|
||||
lines[-2].save()
|
||||
|
||||
injected_line = InjectedLine.objects.create(
|
||||
event_date=datetime.date(2022, 9, 1),
|
||||
quantity=1,
|
||||
unit_amount=1,
|
||||
total_amount=1,
|
||||
user_external_id='user:2',
|
||||
payer_external_id='payer:2',
|
||||
regie=regie,
|
||||
)
|
||||
lines.append(
|
||||
line_model.objects.create(
|
||||
event_date=datetime.date(2022, 9, 1),
|
||||
|
@ -884,6 +894,7 @@ def test_journal_pool_lines(app, admin_user, draft):
|
|||
event={'event': 'foobar2'},
|
||||
user_external_id='user:2',
|
||||
payer_external_id='payer:2',
|
||||
from_injected_line=injected_line,
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -1005,7 +1016,10 @@ def test_journal_pool_lines(app, admin_user, draft):
|
|||
"{'error': 'PricingBookingCheckTypeError', 'error_details': {'check_type': 'foo-reason', "
|
||||
"'check_type_group': 'foo-bar', 'reason': 'wrong-kind'}} {'event': 'foobar'}"
|
||||
)
|
||||
assert format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[13].pk).text()) == 'Success'
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[13].pk).text())
|
||||
== 'Success (Injected)'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[13].pk).text().strip()
|
||||
== "{'foo': 'bar'} {'event': 'foobar2'}"
|
||||
|
@ -1064,6 +1078,11 @@ def test_journal_pool_lines(app, admin_user, draft):
|
|||
params={'status': 'success'},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 2
|
||||
resp = app.get(
|
||||
'/manage/invoicing/campaign/%s/pool/%s/journal/' % (campaign.pk, pool.pk),
|
||||
params={'status': 'success_injected'},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 1
|
||||
resp = app.get(
|
||||
'/manage/invoicing/campaign/%s/pool/%s/journal/' % (campaign.pk, pool.pk),
|
||||
params={'status': 'warning'},
|
||||
|
|
|
@ -222,9 +222,10 @@ def test_get_invoice_lines_for_user_check_status_error(mock_status):
|
|||
)
|
||||
|
||||
|
||||
@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):
|
||||
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')
|
||||
|
@ -239,6 +240,7 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
|
|||
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,
|
||||
|
@ -259,8 +261,8 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
|
|||
)
|
||||
|
||||
# create some injected lines
|
||||
InjectedLine.objects.create(
|
||||
event_date=datetime.date(2022, 8, 31), # too soon
|
||||
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,
|
||||
|
@ -387,7 +389,12 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
|
|||
user_name='User1 Name1',
|
||||
pool=pool,
|
||||
)
|
||||
assert len(lines) == 2 # injected lines
|
||||
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'],
|
||||
|
@ -511,8 +518,15 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
|
|||
adult_external_id='user:1',
|
||||
),
|
||||
]
|
||||
assert len(lines) == 6
|
||||
line1, line2, line3, line4, line5, line6 = lines
|
||||
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)
|
||||
|
@ -597,38 +611,56 @@ def test_get_invoice_lines_for_user_check_status(mock_pricing_data_event, mock_s
|
|||
assert line4.status == 'success'
|
||||
assert line4.pool == pool
|
||||
assert line4.from_injected_line is None
|
||||
assert isinstance(line5, DraftInvoiceLine)
|
||||
assert line5.invoice is None
|
||||
assert line5.event_date == injected_line2.event_date
|
||||
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.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_line2
|
||||
assert isinstance(line6, DraftInvoiceLine)
|
||||
assert line6.invoice is None
|
||||
assert line6.event_date == injected_line4.event_date
|
||||
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.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_line4
|
||||
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')
|
||||
|
@ -1016,6 +1048,7 @@ def test_get_all_invoice_lines_queryset(mock_status):
|
|||
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,
|
||||
|
|
Loading…
Reference in New Issue
J'aurais bien mis "all" par défaut, mais on ne va pas chipoter, et je ne sais pas bien l'usage qui sera fait en vrai... on verra bien à ce moment là.