promotion d'un pool draft en pool définitif (#73608) #18
|
@ -44,11 +44,3 @@ class CampaignForm(forms.ModelForm):
|
|||
self.add_error(None, _('Another campaign overlapping this period already exists.'))
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class PoolForm(forms.Form):
|
||||
draft = forms.BooleanField(label=_('Run a simulation'), initial=True, required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.campaign = kwargs.pop('campaign')
|
||||
super().__init__(*args, **kwargs)
|
||||
|
|
|
@ -28,7 +28,6 @@ class Command(BaseCommand):
|
|||
parser.add_argument('date_start')
|
||||
parser.add_argument('date_end')
|
||||
parser.add_argument('--date-issue')
|
||||
parser.add_argument('--draft', action='store_true')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
try:
|
||||
|
@ -58,7 +57,7 @@ class Command(BaseCommand):
|
|||
campaign = Campaign.objects.create(
|
||||
date_start=date_start, date_end=date_end, date_issue=date_issue
|
||||
)
|
||||
campaign.generate(spool=False, draft=options['draft'])
|
||||
campaign.generate(spool=False)
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS('Invoicing generation OK (start: %s, end: %s)' % (date_start, date_end))
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('invoicing', '0010_event_date'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='draftinvoice',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='invoice',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='invoice',
|
||||
name='number',
|
||||
field=models.PositiveIntegerField(default=0),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Counter',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||
),
|
||||
('name', models.CharField(max_length=128)),
|
||||
('value', models.PositiveIntegerField(default=0)),
|
||||
(
|
||||
'regie',
|
||||
models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='invoicing.Regie'),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'unique_together': {('regie', 'name')},
|
||||
},
|
||||
),
|
||||
]
|
|
@ -40,6 +40,11 @@ class RegieNotConfigured(Exception):
|
|||
self.msg = msg
|
||||
|
||||
|
||||
class PoolPromotionError(Exception):
|
||||
def __init__(self, msg):
|
||||
self.msg = msg
|
||||
|
||||
|
||||
class Regie(models.Model):
|
||||
label = models.CharField(_('Label'), max_length=150)
|
||||
slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
|
||||
|
@ -109,8 +114,8 @@ class Campaign(models.Model):
|
|||
'end': date_format(self.date_end, 'd/m/Y'),
|
||||
}
|
||||
|
||||
def generate(self, spool=True, draft=True):
|
||||
pool = self.pool_set.create(draft=draft)
|
||||
def generate(self, spool=True):
|
||||
pool = self.pool_set.create(draft=True)
|
||||
|
||||
if spool and 'uwsgi' in sys.modules:
|
||||
from lingo.invoicing.spooler import generate_invoices
|
||||
|
@ -143,6 +148,10 @@ class Pool(models.Model):
|
|||
)
|
||||
exception = models.TextField()
|
||||
|
||||
@property
|
||||
def is_last(self):
|
||||
return not self.campaign.pool_set.filter(created_at__gt=self.created_at).exists()
|
||||
|
||||
def generate_invoices(self):
|
||||
from lingo.invoicing import utils
|
||||
|
||||
|
@ -170,6 +179,79 @@ class Pool(models.Model):
|
|||
self.completed_at = now()
|
||||
self.save()
|
||||
|
||||
def promote(self):
|
||||
if not self.is_last:
|
||||
# not the last
|
||||
raise PoolPromotionError('Pool too old')
|
||||
if not self.draft:
|
||||
# not a draft
|
||||
raise PoolPromotionError('Pool is final')
|
||||
if self.status != 'completed':
|
||||
# not completed
|
||||
raise PoolPromotionError('Pool is not completed')
|
||||
|
||||
final_pool = copy.deepcopy(self)
|
||||
final_pool.pk = None
|
||||
final_pool.draft = False
|
||||
final_pool.status = 'registered'
|
||||
final_pool.completed_at = None
|
||||
final_pool.save()
|
||||
|
||||
if 'uwsgi' in sys.modules:
|
||||
from lingo.invoicing.spooler import populate_from_draft
|
||||
|
||||
tenant = getattr(connection, 'tenant', None)
|
||||
transaction.on_commit(
|
||||
lambda: populate_from_draft.spool(
|
||||
draft_pool_id=str(self.pk),
|
||||
final_pool_id=str(final_pool.pk),
|
||||
domain=getattr(tenant, 'domain_url', None),
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
final_pool.populate_from_draft(self)
|
||||
|
||||
def populate_from_draft(self, draft_pool):
|
||||
try:
|
||||
self.status = 'running'
|
||||
self.save()
|
||||
|
||||
for invoice in draft_pool.draftinvoice_set.all().order_by('pk'):
|
||||
final_invoice = copy.deepcopy(invoice)
|
||||
final_invoice.__class__ = Invoice
|
||||
final_invoice.pk = None
|
||||
final_invoice.pool = self
|
||||
final_invoice.number = Counter.get_count(
|
||||
regie=final_invoice.regie, name=final_invoice.created_at.strftime('%y-%m')
|
||||
)
|
||||
final_invoice.save()
|
||||
|
||||
for line in invoice.lines.all().order_by('pk'):
|
||||
final_line = copy.deepcopy(line)
|
||||
final_line.__class__ = InvoiceLine
|
||||
final_line.pk = None
|
||||
final_line.invoice = final_invoice
|
||||
final_line.pool = self
|
||||
final_line.save()
|
||||
|
||||
for line in draft_pool.draftinvoiceline_set.filter(invoice__isnull=True).order_by('pk'):
|
||||
final_line = copy.deepcopy(line)
|
||||
final_line.__class__ = InvoiceLine
|
||||
final_line.pk = None
|
||||
final_line.pool = self
|
||||
final_line.save()
|
||||
|
||||
except Exception:
|
||||
self.status = 'failed'
|
||||
self.exception = traceback.format_exc()
|
||||
raise
|
||||
finally:
|
||||
if self.status == 'running':
|
||||
self.status = 'completed'
|
||||
self.completed_at = now()
|
||||
self.save()
|
||||
|
||||
|
||||
class AbstractInvoice(models.Model):
|
||||
label = models.CharField(_('Label'), max_length=300)
|
||||
|
@ -177,6 +259,7 @@ class AbstractInvoice(models.Model):
|
|||
date_issue = models.DateField(_('Issue date'))
|
||||
regie = models.ForeignKey(Regie, on_delete=models.PROTECT)
|
||||
payer = models.CharField(_('Payer'), max_length=300)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
pool = models.ForeignKey(Pool, on_delete=models.PROTECT)
|
||||
|
||||
|
@ -188,8 +271,33 @@ class DraftInvoice(AbstractInvoice):
|
|||
pass
|
||||
|
||||
|
||||
class Counter(models.Model):
|
||||
regie = models.ForeignKey(Regie, on_delete=models.PROTECT)
|
||||
name = models.CharField(max_length=128)
|
||||
value = models.PositiveIntegerField(default=0)
|
||||
|
||||
class Meta:
|
||||
unique_together = (('regie', 'name'),)
|
||||
|
||||
@classmethod
|
||||
def get_count(cls, regie, name):
|
||||
queryset = cls.objects.select_for_update()
|
||||
with transaction.atomic():
|
||||
counter, dummy = queryset.get_or_create(regie=regie, name=name)
|
||||
counter.value += 1
|
||||
counter.save()
|
||||
return counter.value
|
||||
|
||||
|
||||
class Invoice(AbstractInvoice):
|
||||
pass
|
||||
number = models.PositiveIntegerField(default=0)
|
||||
|
||||
def format_number(self):
|
||||
return 'F-%s-%s-%06d' % (
|
||||
self.regie.slug.upper(),
|
||||
self.created_at.strftime('%y-%m'),
|
||||
int(self.number),
|
||||
)
|
||||
|
||||
|
||||
class InjectedLine(models.Model):
|
||||
|
|
|
@ -34,8 +34,32 @@ def generate_invoices(args):
|
|||
set_connection(args['domain'])
|
||||
|
||||
try:
|
||||
pool = Pool.objects.get(campaign__pk=args['campaign_id'], pk=args['pool_id'], status='registered')
|
||||
pool = Pool.objects.get(
|
||||
campaign__pk=args['campaign_id'], pk=args['pool_id'], status='registered', draft=True
|
||||
)
|
||||
except Pool.DoesNotExist:
|
||||
return
|
||||
|
||||
pool.generate_invoices()
|
||||
|
||||
|
||||
@spool
|
||||
def populate_from_draft(args):
|
||||
if args.get('domain'):
|
||||
# multitenant installation
|
||||
set_connection(args['domain'])
|
||||
|
||||
try:
|
||||
draft_pool = Pool.objects.get(pk=args['draft_pool_id'], status='completed', draft=True)
|
||||
except Pool.DoesNotExist:
|
||||
return
|
||||
|
||||
if draft_pool.campaign.pool_set.filter(created_at__gt=draft_pool.created_at, draft=True).exists():
|
||||
return
|
||||
|
||||
try:
|
||||
final_pool = Pool.objects.get(pk=args['final_pool_id'], status='registered', draft=False)
|
||||
except Pool.DoesNotExist:
|
||||
return
|
||||
|
||||
final_pool.populate_from_draft(draft_pool)
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
{% block content %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<p>{% trans "Are you sure you want to start a new pool?" %}</p>
|
||||
lguerin marked this conversation as resolved
Outdated
|
||||
<div class="buttons">
|
||||
<button class="submit-button">{% trans "Run" %}</button>
|
||||
<a class="cancel" href="{% url 'lingo-manager-invoicing-campaign-detail' object.pk %}">{% trans 'Cancel' %}</a>
|
|
@ -18,6 +18,9 @@
|
|||
{% if pool.draft and pool.status != 'registered' and pool.status != 'running' %}
|
||||
<a href="{% url 'lingo-manager-invoicing-pool-delete' pk=object.pk pool_pk=pool.pk %}" rel="popup">{% trans "Delete" %}</a>
|
||||
{% endif %}
|
||||
{% if pool.draft and pool.status == 'completed' and pool.is_last %}
|
||||
<a href="{% url 'lingo-manager-invoicing-pool-promote' pk=object.pk pool_pk=pool.pk %}" rel="popup">{% trans "Promote" %}</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -27,7 +30,11 @@
|
|||
{% ifchanged line.invoice_id %}
|
||||
{% if not forloop.first %}</ul>{% endif %}
|
||||
<h3 data-invoice-id="{{ line.invoice_id }}">
|
||||
{% blocktrans with number=line.invoice_id payer=line.invoice.payer amount=line.invoice.total_amount %}Invoice #{{ number }} addressed to {{ payer }}, amount {{ amount }}€{% endblocktrans %}
|
||||
{% if pool.draft %}
|
||||
{% blocktrans with number=line.invoice_id payer=line.invoice.payer amount=line.invoice.total_amount %}Invoice TMP-{{ number }} addressed to {{ payer }}, amount {{ amount }}€{% endblocktrans %}
|
||||
{% else %}
|
||||
{% blocktrans with number=line.invoice.format_number payer=line.invoice.payer amount=line.invoice.total_amount %}Invoice {{ number }} addressed to {{ payer }}, amount {{ amount }}€{% endblocktrans %}
|
||||
{% endif %}
|
||||
</h3>
|
||||
<ul class="objects-list" data-invoice-id="{{ line.invoice_id }}">
|
||||
{% endifchanged %}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
{% extends "lingo/invoicing/manager_pool_detail.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'lingo-manager-invoicing-pool-promote' pk=object.pk pool_pk=pool.pk %}">{% trans "Promote" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans "Promote" %}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<p>{% trans "Are you sure you want to promote this pool ? This action is irreversible." %}</p>
|
||||
<div class="buttons">
|
||||
<button class="submit-button">{% trans "Promote" %}</button>
|
||||
<a class="cancel" href="{% url 'lingo-manager-invoicing-pool-detail' pk=object.pk pool_pk=pool.pk %}">{% trans 'Cancel' %}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -79,6 +79,11 @@ urlpatterns = [
|
|||
views.pool_journal,
|
||||
name='lingo-manager-invoicing-pool-journal',
|
||||
),
|
||||
path(
|
||||
'campaign/<int:pk>/pool/<int:pool_pk>/promote/',
|
||||
views.pool_promote,
|
||||
name='lingo-manager-invoicing-pool-promote',
|
||||
),
|
||||
path(
|
||||
'campaign/<int:pk>/pool/<int:pool_pk>/delete/',
|
||||
views.pool_delete,
|
||||
|
|
|
@ -22,8 +22,8 @@ from django.contrib import messages
|
|||
from django.db import transaction
|
||||
from django.db.models import Count, IntegerField, OuterRef, Subquery, Value
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.http import Http404, HttpResponse
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import ungettext
|
||||
|
@ -38,7 +38,7 @@ from django.views.generic import (
|
|||
)
|
||||
|
||||
from lingo.agendas.models import Agenda
|
||||
from lingo.invoicing.forms import CampaignForm, PoolForm
|
||||
from lingo.invoicing.forms import CampaignForm
|
||||
from lingo.invoicing.models import (
|
||||
Campaign,
|
||||
DraftInvoice,
|
||||
|
@ -354,8 +354,7 @@ pool_journal = PoolJournalView.as_view()
|
|||
|
||||
|
||||
class PoolAddView(FormView):
|
||||
template_name = 'lingo/invoicing/manager_pool_form.html'
|
||||
form_class = PoolForm
|
||||
template_name = 'lingo/invoicing/manager_pool_add.html'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.object = get_object_or_404(
|
||||
|
@ -364,26 +363,53 @@ class PoolAddView(FormView):
|
|||
)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs['campaign'] = self.object
|
||||
return kwargs
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs['form'] = None
|
||||
kwargs['object'] = self.object
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def form_valid(self, form):
|
||||
self.object.generate(draft=form.cleaned_data['draft'])
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return '%s#open:pools' % reverse('lingo-manager-invoicing-campaign-detail', args=[self.object.pk])
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object.generate()
|
||||
return redirect(
|
||||
'%s#open:pools' % reverse('lingo-manager-invoicing-campaign-detail', args=[self.object.pk])
|
||||
)
|
||||
|
||||
|
||||
pool_add = PoolAddView.as_view()
|
||||
|
||||
|
||||
class PoolPromoteView(FormView):
|
||||
template_name = 'lingo/invoicing/manager_pool_promote.html'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.object = get_object_or_404(
|
||||
Pool,
|
||||
campaign__id=kwargs['pk'],
|
||||
pk=kwargs['pool_pk'],
|
||||
draft=True,
|
||||
status='completed',
|
||||
)
|
||||
if not self.object.is_last:
|
||||
raise Http404
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs['form'] = None
|
||||
kwargs['object'] = self.object.campaign
|
||||
kwargs['pool'] = self.object
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object.promote()
|
||||
return redirect(
|
||||
'%s#open:pools'
|
||||
% reverse('lingo-manager-invoicing-campaign-detail', args=[self.object.campaign.pk])
|
||||
)
|
||||
|
||||
|
||||
pool_promote = PoolPromoteView.as_view()
|
||||
|
||||
|
||||
class PoolDeleteView(DeleteView):
|
||||
template_name = 'lingo/manager_confirm_delete.html'
|
||||
model = Pool
|
||||
|
|
|
@ -3,7 +3,7 @@ from unittest import mock
|
|||
|
||||
import pytest
|
||||
|
||||
from lingo.invoicing.models import Campaign, DraftInvoice, DraftInvoiceLine, InvoiceLine, Pool, Regie
|
||||
from lingo.invoicing.models import Campaign, DraftInvoice, DraftInvoiceLine, Invoice, InvoiceLine, Pool, Regie
|
||||
from tests.utils import login
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
@ -306,23 +306,17 @@ def test_add_pool(app, admin_user):
|
|||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/invoicing/campaign/%s/pool/add/' % campaign.pk)
|
||||
assert resp.form['draft'].value == 'on'
|
||||
with mock.patch.object(Campaign, 'generate', autospec=True) as mock_generate:
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/invoicing/campaign/%s/#open:pools' % campaign.pk)
|
||||
assert mock_generate.call_args_list == [mock.call(campaign, draft=True)]
|
||||
assert mock_generate.call_args_list == [mock.call(campaign)]
|
||||
|
||||
pool = Pool.objects.create(
|
||||
campaign=campaign,
|
||||
draft=True,
|
||||
status='failed',
|
||||
)
|
||||
resp = app.get('/manage/invoicing/campaign/%s/pool/add/' % campaign.pk)
|
||||
resp.form['draft'] = False
|
||||
with mock.patch.object(Campaign, 'generate', autospec=True) as mock_generate:
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/invoicing/campaign/%s/#open:pools' % campaign.pk)
|
||||
assert mock_generate.call_args_list == [mock.call(campaign, draft=False)]
|
||||
app.get('/manage/invoicing/campaign/%s/pool/add/' % campaign.pk)
|
||||
|
||||
pool.status = 'completed'
|
||||
pool.save()
|
||||
|
@ -342,6 +336,53 @@ def test_add_pool(app, admin_user):
|
|||
app.get('/manage/invoicing/campaign/%s/pool/add/' % campaign.pk, status=404)
|
||||
|
||||
|
||||
def test_promote_pool(app, admin_user):
|
||||
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,
|
||||
status='completed',
|
||||
)
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/promote/' % (campaign.pk, pool.pk))
|
||||
with mock.patch.object(Pool, 'promote', autospec=True) as mock_promote:
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/invoicing/campaign/%s/#open:pools' % campaign.pk)
|
||||
assert mock_promote.call_args_list == [mock.call(pool)]
|
||||
|
||||
pool.status = 'registered'
|
||||
pool.save()
|
||||
app.get('/manage/invoicing/campaign/%s/pool/%s/promote/' % (campaign.pk, pool.pk), status=404)
|
||||
|
||||
pool.status = 'running'
|
||||
pool.save()
|
||||
app.get('/manage/invoicing/campaign/%s/pool/%s/promote/' % (campaign.pk, pool.pk), status=404)
|
||||
|
||||
pool.status = 'failed'
|
||||
pool.save()
|
||||
app.get('/manage/invoicing/campaign/%s/pool/%s/promote/' % (campaign.pk, pool.pk), status=404)
|
||||
|
||||
pool.status = 'completed'
|
||||
pool.draft = False
|
||||
pool.save()
|
||||
app.get('/manage/invoicing/campaign/%s/pool/%s/promote/' % (campaign.pk, pool.pk), status=404)
|
||||
|
||||
pool.draft = True
|
||||
pool.save()
|
||||
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/promote/' % (campaign.pk, pool.pk))
|
||||
resp.form.submit()
|
||||
|
||||
assert Pool.objects.filter(draft=False).exists()
|
||||
|
||||
# not the last
|
||||
app.get('/manage/invoicing/campaign/%s/pool/%s/promote/' % (campaign.pk, pool.pk), status=404)
|
||||
|
||||
|
||||
def test_detail_pool(app, admin_user):
|
||||
campaign = Campaign.objects.create(
|
||||
date_start=datetime.date(2022, 9, 1),
|
||||
|
@ -362,6 +403,7 @@ def test_detail_pool(app, admin_user):
|
|||
app = login(app)
|
||||
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/' % (campaign.pk, pool.pk))
|
||||
assert '/manage/invoicing/campaign/%s/pool/%s/delete/' % (campaign.pk, pool.pk) in resp
|
||||
assert '/manage/invoicing/campaign/%s/pool/%s/promote/' % (campaign.pk, pool.pk) in resp
|
||||
|
||||
app.get('/manage/invoicing/campaign/%s/pool/%s/' % (0, pool.pk), status=404)
|
||||
app.get('/manage/invoicing/campaign/%s/pool/%s/' % (campaign2.pk, pool.pk), status=404)
|
||||
|
@ -371,22 +413,37 @@ def test_detail_pool(app, admin_user):
|
|||
pool.save()
|
||||
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/' % (campaign.pk, pool.pk))
|
||||
assert '/manage/invoicing/campaign/%s/pool/%s/delete/' % (campaign.pk, pool.pk) not in resp
|
||||
assert '/manage/invoicing/campaign/%s/pool/%s/promote/' % (campaign.pk, pool.pk) not in resp
|
||||
|
||||
pool.draft = True
|
||||
pool.status = 'registered'
|
||||
pool.save()
|
||||
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/' % (campaign.pk, pool.pk))
|
||||
assert '/manage/invoicing/campaign/%s/pool/%s/delete/' % (campaign.pk, pool.pk) not in resp
|
||||
assert '/manage/invoicing/campaign/%s/pool/%s/promote/' % (campaign.pk, pool.pk) not in resp
|
||||
|
||||
pool.status = 'running'
|
||||
pool.save()
|
||||
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/' % (campaign.pk, pool.pk))
|
||||
assert '/manage/invoicing/campaign/%s/pool/%s/delete/' % (campaign.pk, pool.pk) not in resp
|
||||
assert '/manage/invoicing/campaign/%s/pool/%s/promote/' % (campaign.pk, pool.pk) not in resp
|
||||
|
||||
pool.status = 'failed'
|
||||
pool.save()
|
||||
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/' % (campaign.pk, pool.pk))
|
||||
assert '/manage/invoicing/campaign/%s/pool/%s/delete/' % (campaign.pk, pool.pk) in resp
|
||||
assert '/manage/invoicing/campaign/%s/pool/%s/promote/' % (campaign.pk, pool.pk) not in resp
|
||||
|
||||
pool.status = 'completed'
|
||||
pool.save()
|
||||
Pool.objects.create(
|
||||
campaign=pool.campaign,
|
||||
)
|
||||
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/' % (campaign.pk, pool.pk))
|
||||
assert '/manage/invoicing/campaign/%s/pool/%s/delete/' % (campaign.pk, pool.pk) in resp
|
||||
assert (
|
||||
'/manage/invoicing/campaign/%s/pool/%s/promote/' % (campaign.pk, pool.pk) not in resp
|
||||
) # not the last
|
||||
|
||||
line = DraftInvoiceLine.objects.create(
|
||||
event_date=datetime.date(2022, 9, 1),
|
||||
|
@ -446,7 +503,11 @@ def test_detail_pool(app, admin_user):
|
|||
assert 'tag-error' not in resp
|
||||
|
||||
|
||||
def test_detail_pool_invoices(app, admin_user):
|
||||
@pytest.mark.parametrize('draft', [True, False])
|
||||
def test_detail_pool_invoices(app, admin_user, draft):
|
||||
invoice_model = DraftInvoice if draft else Invoice
|
||||
line_model = DraftInvoiceLine if draft else InvoiceLine
|
||||
|
||||
campaign = Campaign.objects.create(
|
||||
date_start=datetime.date(2022, 9, 1),
|
||||
date_end=datetime.date(2022, 10, 1),
|
||||
|
@ -454,18 +515,23 @@ def test_detail_pool_invoices(app, admin_user):
|
|||
)
|
||||
pool = Pool.objects.create(
|
||||
campaign=campaign,
|
||||
draft=True,
|
||||
draft=draft,
|
||||
status='completed',
|
||||
)
|
||||
regie = Regie.objects.create(label='Foo')
|
||||
invoice1 = DraftInvoice.objects.create(
|
||||
invoice1 = invoice_model.objects.create(
|
||||
date_issue=datetime.date.today(), regie=regie, pool=pool, payer='payer:1'
|
||||
)
|
||||
invoice2 = DraftInvoice.objects.create(
|
||||
invoice2 = invoice_model.objects.create(
|
||||
date_issue=datetime.date.today(), regie=regie, pool=pool, payer='payer:2'
|
||||
)
|
||||
if not draft:
|
||||
invoice1.number = 42
|
||||
invoice1.save()
|
||||
invoice2.number = 43
|
||||
invoice2.save()
|
||||
|
||||
line11 = DraftInvoiceLine.objects.create(
|
||||
line11 = line_model.objects.create(
|
||||
event_date=datetime.date(2022, 9, 1),
|
||||
invoice=invoice1,
|
||||
quantity=1,
|
||||
|
@ -477,7 +543,7 @@ def test_detail_pool_invoices(app, admin_user):
|
|||
user_external_id='user:1',
|
||||
user_name='User1 Name1',
|
||||
)
|
||||
line12 = DraftInvoiceLine.objects.create(
|
||||
line12 = line_model.objects.create(
|
||||
event_date=datetime.date(2022, 9, 2),
|
||||
invoice=invoice1,
|
||||
quantity=1,
|
||||
|
@ -489,7 +555,7 @@ def test_detail_pool_invoices(app, admin_user):
|
|||
user_external_id='user:2',
|
||||
user_name='User2 Name2',
|
||||
)
|
||||
line13 = DraftInvoiceLine.objects.create(
|
||||
line13 = line_model.objects.create(
|
||||
event_date=datetime.date(2022, 9, 3),
|
||||
invoice=invoice1,
|
||||
quantity=1,
|
||||
|
@ -502,7 +568,7 @@ def test_detail_pool_invoices(app, admin_user):
|
|||
user_name='User1 Name1',
|
||||
)
|
||||
|
||||
orphan_line = DraftInvoiceLine.objects.create(
|
||||
orphan_line = line_model.objects.create(
|
||||
event_date=datetime.date(2022, 9, 1),
|
||||
quantity=1,
|
||||
unit_amount=42,
|
||||
|
@ -514,7 +580,7 @@ def test_detail_pool_invoices(app, admin_user):
|
|||
user_name='User1 Name1',
|
||||
)
|
||||
|
||||
line21 = DraftInvoiceLine.objects.create(
|
||||
line21 = line_model.objects.create(
|
||||
event_date=datetime.date(2022, 9, 1),
|
||||
invoice=invoice2,
|
||||
quantity=1,
|
||||
|
@ -530,10 +596,17 @@ def test_detail_pool_invoices(app, admin_user):
|
|||
app = login(app)
|
||||
resp = app.get('/manage/invoicing/campaign/%s/pool/%s/' % (campaign.pk, pool.pk))
|
||||
assert '#%s' % orphan_line.pk not in resp
|
||||
assert (
|
||||
resp.pyquery('h3[data-invoice-id="%s"]' % invoice1.pk).text()
|
||||
== 'Invoice #%s addressed to payer:1, amount 6.00€' % invoice1.pk
|
||||
)
|
||||
if draft:
|
||||
assert (
|
||||
resp.pyquery('h3[data-invoice-id="%s"]' % invoice1.pk).text()
|
||||
== 'Invoice TMP-%s addressed to payer:1, amount 6.00€' % invoice1.pk
|
||||
)
|
||||
else:
|
||||
assert resp.pyquery(
|
||||
'h3[data-invoice-id="%s"]' % invoice1.pk
|
||||
).text() == 'Invoice F-FOO-%s-000042 addressed to payer:1, amount 6.00€' % invoice1.created_at.strftime(
|
||||
'%y-%m'
|
||||
)
|
||||
assert len(resp.pyquery('ul[data-invoice-id="%s"] li' % invoice1.pk)) == 3
|
||||
assert (
|
||||
resp.pyquery('ul[data-invoice-id="%s"] li:nth-child(1)' % invoice1.pk).text()
|
||||
|
@ -547,10 +620,17 @@ def test_detail_pool_invoices(app, admin_user):
|
|||
resp.pyquery('ul[data-invoice-id="%s"] li:nth-child(3)' % invoice1.pk).text()
|
||||
== '#%s User2 Name2 - 02/09/2022 - Label 12 (2.00)' % line12.pk
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('h3[data-invoice-id="%s"]' % invoice2.pk).text()
|
||||
== 'Invoice #%s addressed to payer:2, amount 1.00€' % invoice2.pk
|
||||
)
|
||||
if draft:
|
||||
assert (
|
||||
resp.pyquery('h3[data-invoice-id="%s"]' % invoice2.pk).text()
|
||||
== 'Invoice TMP-%s addressed to payer:2, amount 1.00€' % invoice2.pk
|
||||
)
|
||||
else:
|
||||
assert resp.pyquery(
|
||||
'h3[data-invoice-id="%s"]' % invoice2.pk
|
||||
).text() == 'Invoice F-FOO-%s-000043 addressed to payer:2, amount 1.00€' % invoice2.created_at.strftime(
|
||||
'%y-%m'
|
||||
)
|
||||
assert len(resp.pyquery('ul[data-invoice-id="%s"] li' % invoice2.pk)) == 1
|
||||
assert (
|
||||
resp.pyquery('ul[data-invoice-id="%s"] li:nth-child(1)' % invoice2.pk).text()
|
||||
|
|
|
@ -6,17 +6,21 @@ 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,
|
||||
)
|
||||
|
@ -1273,7 +1277,7 @@ def test_generate_invoices(mock_generate, mock_lines, mock_users, mock_agendas):
|
|||
mock_lines.return_value = ['foo', 'baz']
|
||||
|
||||
# check only calls between functions
|
||||
campaign.generate(draft=True)
|
||||
campaign.generate()
|
||||
pool = Pool.objects.latest('pk')
|
||||
assert pool.campaign == campaign
|
||||
assert pool.draft is True
|
||||
|
@ -1316,7 +1320,7 @@ def test_generate_invoices_errors(mock_generate, mock_lines, mock_users, mock_ag
|
|||
|
||||
mock_agendas.return_value = [agenda1, agenda2]
|
||||
mock_users.side_effect = ChronoError('foo bar')
|
||||
campaign.generate(draft=True)
|
||||
campaign.generate()
|
||||
pool = Pool.objects.latest('pk')
|
||||
assert pool.status == 'failed'
|
||||
assert pool.exception == 'foo bar'
|
||||
|
@ -1324,7 +1328,7 @@ def test_generate_invoices_errors(mock_generate, mock_lines, mock_users, mock_ag
|
|||
mock_users.side_effect = None
|
||||
mock_users.return_value = ['foo', 'bar']
|
||||
mock_lines.side_effect = RegieNotConfigured('foo baz')
|
||||
campaign.generate(draft=True)
|
||||
campaign.generate()
|
||||
pool = Pool.objects.latest('pk')
|
||||
assert pool.status == 'failed'
|
||||
assert pool.exception == 'foo baz'
|
||||
|
@ -1359,17 +1363,13 @@ def test_generate_invoices_cmd():
|
|||
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, draft=False, spool=False)]
|
||||
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, draft=False, spool=False)]
|
||||
mock_generate.reset_mock()
|
||||
call_command('generate_invoices', '2022-09-01', '2022-10-01', '--draft')
|
||||
assert Campaign.objects.count() == 1
|
||||
assert mock_generate.call_args_list == [mock.call(campaign, draft=True, spool=False)]
|
||||
assert mock_generate.call_args_list == [mock.call(campaign, spool=False)]
|
||||
mock_generate.reset_mock()
|
||||
|
||||
# with overlapping
|
||||
|
@ -1386,7 +1386,7 @@ def test_generate_invoices_cmd():
|
|||
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, draft=False, spool=False)]
|
||||
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)
|
||||
|
@ -1394,7 +1394,424 @@ def test_generate_invoices_cmd():
|
|||
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, draft=False, spool=False)]
|
||||
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-%m')).value == 2
|
||||
assert Counter.objects.get(regie=regie2, name=today.strftime('%y-%m')).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.format_number() == 'F-REGIE1-%s-000001' % 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.format_number() == 'F-REGIE1-%s-000002' % 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.format_number() == 'F-REGIE2-%s-000001' % 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()
|
||||
|
|
|
@ -2,7 +2,16 @@ import datetime
|
|||
|
||||
import pytest
|
||||
|
||||
from lingo.invoicing.models import Campaign, DraftInvoice, DraftInvoiceLine, Invoice, InvoiceLine, Pool, Regie
|
||||
from lingo.invoicing.models import (
|
||||
Campaign,
|
||||
Counter,
|
||||
DraftInvoice,
|
||||
DraftInvoiceLine,
|
||||
Invoice,
|
||||
InvoiceLine,
|
||||
Pool,
|
||||
Regie,
|
||||
)
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
@ -151,3 +160,37 @@ def test_invoice_total_amount(draft):
|
|||
assert invoice.total_amount == 12
|
||||
invoice2.refresh_from_db()
|
||||
assert invoice2.total_amount == 0
|
||||
|
||||
|
||||
def test_counter():
|
||||
regie1 = Regie.objects.create()
|
||||
regie2 = Regie.objects.create()
|
||||
|
||||
assert Counter.get_count(regie=regie1, name='foo') == 1
|
||||
assert Counter.objects.count() == 1
|
||||
counter1 = Counter.objects.get(regie=regie1, name='foo')
|
||||
assert counter1.value == 1
|
||||
|
||||
assert Counter.get_count(regie=regie1, name='foo') == 2
|
||||
counter1.refresh_from_db()
|
||||
assert counter1.value == 2
|
||||
|
||||
assert Counter.get_count(regie=regie1, name='foo') == 3
|
||||
counter1.refresh_from_db()
|
||||
assert counter1.value == 3
|
||||
|
||||
assert Counter.get_count(regie=regie2, name='foo') == 1
|
||||
assert Counter.objects.count() == 2
|
||||
counter1.refresh_from_db()
|
||||
assert counter1.value == 3
|
||||
counter2 = Counter.objects.get(regie=regie2, name='foo')
|
||||
assert counter2.value == 1
|
||||
|
||||
assert Counter.get_count(regie=regie2, name='bar') == 1
|
||||
assert Counter.objects.count() == 3
|
||||
counter1.refresh_from_db()
|
||||
assert counter1.value == 3
|
||||
counter2.refresh_from_db()
|
||||
assert counter2.value == 1
|
||||
counter3 = Counter.objects.get(regie=regie2, name='bar')
|
||||
assert counter3.value == 1
|
||||
|
|
Loading…
Reference in New Issue
Pour faire mon intello, il n'y a pas d'espace avant le ? en typo anglaise.