pricing: import/export pricings (#67196)

This commit is contained in:
Lauréline Guérin 2022-07-18 16:27:03 +02:00
parent c694ee5e67
commit 369fbb8602
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
7 changed files with 79 additions and 50 deletions

View File

@ -52,25 +52,16 @@ class Agenda(models.Model):
def export_json(self):
return {
'slug': self.slug,
'pricings': [x.export_json() for x in self.old_agendapricings.all()],
'check_type_group': self.check_type_group.slug if self.check_type_group else None,
}
@classmethod
def import_json(cls, data, overwrite=False):
from lingo.pricing.models import AgendaPricing, Pricing
data = copy.deepcopy(data)
try:
agenda = Agenda.objects.get(slug=data['slug'])
except Agenda.DoesNotExist:
raise AgendaImportError(_('Missing "%s" agenda') % data['slug'])
pricings = data.pop('pricings', None) or []
for pricing_data in pricings:
try:
pricing_data['pricing'] = Pricing.objects.get(slug=pricing_data['pricing'])
except Pricing.DoesNotExist:
raise AgendaImportError(_('Missing "%s" pricing model') % pricing_data['pricing'])
if data.get('check_type_group'):
try:
data['check_type_group'] = CheckTypeGroup.objects.get(slug=data['check_type_group'])
@ -80,10 +71,6 @@ class Agenda(models.Model):
agenda.check_type_group = data.get('check_type_group')
agenda.save()
for pricing_data in pricings:
pricing_data['agenda'] = agenda
AgendaPricing.import_json(pricing_data)
return False, agenda
def get_chrono_url(self):

View File

@ -34,6 +34,7 @@ class ExportForm(forms.Form):
label=_('Pricing criteria categories'), required=False, initial=True
)
pricing_models = forms.BooleanField(label=_('Pricing models'), required=False, initial=True)
pricings = forms.BooleanField(label=_('Pricings'), required=False, initial=True)
class ImportForm(forms.Form):

View File

@ -343,25 +343,42 @@ class AgendaPricing(models.Model):
date_end = models.DateField()
pricing_data = JSONField(null=True)
@classmethod
def import_json(cls, data):
data = clean_import_data(cls, data)
cls.objects.update_or_create(
agenda=data['agenda'],
pricing=data['pricing'],
date_start=data['date_start'],
date_end=data['date_end'],
defaults=data,
)
def export_json(self):
return {
'pricing': self.pricing.slug,
'date_start': self.date_start.strftime('%Y-%m-%d'),
'date_end': self.date_end.strftime('%Y-%m-%d'),
'pricing_data': self.pricing_data,
'agendas': [a.slug for a in self.agendas.all()],
}
@classmethod
def import_json(cls, data, overwrite=False):
data = copy.deepcopy(data)
agenda_slugs = data.pop('agendas', None) or []
data = clean_import_data(cls, data)
agendas = []
for agenda_slug in agenda_slugs:
try:
agendas.append(Agenda.objects.get(slug=agenda_slug))
except Agenda.DoesNotExist:
raise AgendaImportError(_('Missing "%s" agenda') % agenda_slug)
try:
data['pricing'] = Pricing.objects.get(slug=data['pricing'])
except Pricing.DoesNotExist:
raise AgendaImportError(_('Missing "%s" pricing model') % data['pricing'])
agenda_pricing, created = cls.objects.update_or_create(
pricing=data['pricing'],
date_start=data['date_start'],
date_end=data['date_end'],
defaults=data,
)
if overwrite and not created:
agenda_pricing.agendas.clear()
agenda_pricing.agendas.add(*agendas)
return created, agenda_pricing
@staticmethod
def get_pricing_data(
request,

View File

@ -27,9 +27,12 @@ def export_site(
check_type_groups=True,
pricing_categories=True,
pricing_models=True,
pricings=True,
):
'''Dump site objects to JSON-dumpable dictionnary'''
data = collections.OrderedDict()
if pricings:
data['pricings'] = [x.export_json() for x in AgendaPricing.objects.all()]
if pricing_models:
data['pricing_models'] = [x.export_json() for x in Pricing.objects.all()]
if pricing_categories:
@ -63,6 +66,7 @@ def import_site(data, if_empty=False, clean=False, overwrite=False):
'check_type_groups',
'pricing_categories',
'pricing_models',
'pricings',
]
}
@ -72,6 +76,7 @@ def import_site(data, if_empty=False, clean=False, overwrite=False):
(Pricing, 'pricing_models'),
(CheckTypeGroup, 'check_type_groups'),
(Agenda, 'agendas'),
(AgendaPricing, 'pricings'),
):
objs = data.get(key, [])
for obj in objs:

View File

@ -151,6 +151,20 @@ class ConfigImportView(FormView):
x,
),
},
'pricings': {
'create_noop': _('No pricing created.'),
'create': lambda x: ungettext(
'A pricing has been created.',
'%(count)d pricings have been created.',
x,
),
'update_noop': _('No pricing updated.'),
'update': lambda x: ungettext(
'A pricing has been updated.',
'%(count)d pricings have been updated.',
x,
),
},
}
global_noop = True
@ -192,7 +206,7 @@ class ConfigImportView(FormView):
# only one criteria category imported, redirect to criteria page
return HttpResponseRedirect(reverse('lingo-manager-pricing-criteria-list'))
if (a_count, ct_count, pc_count, pm_count) == (0, 0, 0, 1):
# only one pricing imported, redirect to pricing page
# only one pricing model imported, redirect to pricing model page
return HttpResponseRedirect(
reverse(
'lingo-manager-pricing-detail',
@ -207,6 +221,7 @@ class ConfigImportView(FormView):
messages.info(self.request, results['check_type_groups']['messages'])
messages.info(self.request, results['pricing_categories']['messages'])
messages.info(self.request, results['pricing_models']['messages'])
messages.info(self.request, results['pricings']['messages'])
return super().form_valid(form)

View File

@ -27,6 +27,7 @@ def test_export_site(freezer, app, admin_user):
'check_type_groups': [],
'pricing_categories': [],
'pricing_models': [],
'pricings': [],
}
Agenda.objects.create(label='Foo Bar')
@ -41,6 +42,7 @@ def test_export_site(freezer, app, admin_user):
resp.form['check_type_groups'] = False
resp.form['pricing_categories'] = False
resp.form['pricing_models'] = False
resp.form['pricings'] = False
resp = resp.form.submit()
site_json = json.loads(resp.text)
@ -48,6 +50,7 @@ def test_export_site(freezer, app, admin_user):
assert 'check_type_groups' not in site_json
assert 'pricing_categories' not in site_json
assert 'pricing_models' not in site_json
assert 'pricings' not in site_json
@pytest.mark.freeze_time('2021-07-08')

View File

@ -28,10 +28,9 @@ def get_output_of_command(command, *args, **kwargs):
def test_import_export(app):
agenda = Agenda.objects.create(label='Foo Bar')
Agenda.objects.create(label='Foo Bar')
pricing = Pricing.objects.create(label='Foo')
AgendaPricing.objects.create(
agenda=agenda,
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
@ -40,12 +39,14 @@ def test_import_export(app):
output = get_output_of_command('export_pricing_config')
assert len(json.loads(output)['agendas']) == 1
assert len(json.loads(output)['pricings']) == 1
assert len(json.loads(output)['pricings'][0]['agendas']) == 0
assert len(json.loads(output)['pricing_models']) == 1
assert len(json.loads(output)['pricing_categories']) == 1
import_site(data={}, clean=True)
empty_output = get_output_of_command('export_pricing_config')
assert len(json.loads(empty_output)['agendas']) == 1
assert len(json.loads(empty_output)['agendas'][0]['pricings']) == 0
assert len(json.loads(empty_output)['pricings']) == 0
assert len(json.loads(empty_output)['pricing_models']) == 0
assert len(json.loads(empty_output)['pricing_categories']) == 0
@ -53,7 +54,6 @@ def test_import_export(app):
sys.stdin = StringIO(json.dumps({}))
pricing = Pricing.objects.create(label='Foo')
AgendaPricing.objects.create(
agenda=agenda,
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
@ -92,11 +92,10 @@ def test_import_export(app):
shutil.rmtree(tempdir)
def test_import_export_agenda_with_pricing(app):
def test_import_export_agenda_pricing(app):
pricing = Pricing.objects.create(label='Foo')
agenda = Agenda.objects.create(label='Foo Bar')
agenda_pricing = AgendaPricing.objects.create(
agenda=agenda,
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
@ -104,59 +103,61 @@ def test_import_export_agenda_with_pricing(app):
'foo': 'bar',
},
)
agenda_pricing.agendas.set([agenda])
output = get_output_of_command('export_pricing_config')
import_site(data={}, clean=True)
assert Pricing.objects.count() == 0
data = json.loads(output)
del data['pricing_models']
with pytest.raises(AgendaImportError) as excinfo:
import_site(data, overwrite=True)
assert str(excinfo.value) == 'Missing "foo" pricing model'
Pricing.objects.create(label='foobar')
with pytest.raises(AgendaImportError) as excinfo:
import_site(data, overwrite=True)
assert str(excinfo.value) == 'Missing "foo" pricing model'
Agenda.objects.all().delete()
pricing = Pricing.objects.create(label='Foo')
with pytest.raises(AgendaImportError) as excinfo:
import_site(data, overwrite=True)
assert str(excinfo.value) == 'Missing "foo-bar" agenda'
agenda2 = Agenda.objects.create(label='Baz')
with pytest.raises(AgendaImportError) as excinfo:
import_site(data, overwrite=True)
assert str(excinfo.value) == 'Missing "foo-bar" agenda'
del data['pricing_models']
Pricing.objects.all().delete()
agenda = Agenda.objects.create(label='Foo Bar')
with pytest.raises(AgendaImportError) as excinfo:
import_site(data, overwrite=True)
assert str(excinfo.value) == 'Missing "foo" pricing model'
pricing = Pricing.objects.create(label='Foo')
import_site(data, overwrite=True)
assert agenda.old_agendapricings.count() == 1
agenda_pricing = agenda.old_agendapricings.get()
assert agenda_pricing.agenda == agenda
agenda_pricing = AgendaPricing.objects.latest('pk')
assert list(agenda_pricing.agendas.all()) == [agenda]
assert agenda_pricing.pricing == pricing
assert agenda_pricing.date_start == datetime.date(year=2021, month=9, day=1)
assert agenda_pricing.date_end == datetime.date(year=2021, month=10, day=1)
assert agenda_pricing.pricing_data == {'foo': 'bar'}
# again
import_site(data)
assert agenda.old_agendapricings.count() == 1
agenda_pricing = AgendaPricing.objects.get(pk=agenda_pricing.pk)
assert agenda_pricing.agenda == agenda
assert list(agenda_pricing.agendas.all()) == [agenda]
assert agenda_pricing.pricing == pricing
data['agendas'][0]['pricings'].append(
data['pricings'].append(
{
'pricing': 'foo',
'agendas': ['foo-bar', 'baz'],
'date_start': '2022-09-01',
'date_end': '2022-10-01',
'pricing_data': {'foo': 'bar'},
}
)
import_site(data)
assert agenda.old_agendapricings.count() == 2
agenda_pricing = AgendaPricing.objects.latest('pk')
assert agenda_pricing.agenda == agenda
assert list(agenda_pricing.agendas.all().order_by('slug')) == [agenda2, agenda]
assert agenda_pricing.pricing == pricing
assert agenda_pricing.date_start == datetime.date(year=2022, month=9, day=1)
assert agenda_pricing.date_end == datetime.date(year=2022, month=10, day=1)
assert agenda_pricing.pricing_data == {'foo': 'bar'}
def test_import_export_agenda_with_check_types(app):