diff --git a/lingo/pricing/templates/lingo/pricing/manager_agenda_pricing_detail.html b/lingo/pricing/templates/lingo/pricing/manager_agenda_pricing_detail.html index 908d499..a24a340 100644 --- a/lingo/pricing/templates/lingo/pricing/manager_agenda_pricing_detail.html +++ b/lingo/pricing/templates/lingo/pricing/manager_agenda_pricing_detail.html @@ -15,6 +15,7 @@ diff --git a/lingo/pricing/urls.py b/lingo/pricing/urls.py index 473e808..ded8c7c 100644 --- a/lingo/pricing/urls.py +++ b/lingo/pricing/urls.py @@ -178,6 +178,11 @@ urlpatterns = [ views.agenda_pricing_delete, name='lingo-manager-agenda-pricing-delete', ), + url( + r'^agenda-pricing/(?P\d+)/export/$', + views.agenda_pricing_export, + name='lingo-manager-agenda-pricing-export', + ), url( r'^agenda-pricing/(?P\d+)/matrix/edit/$', views.agenda_pricing_matrix_edit, diff --git a/lingo/pricing/views.py b/lingo/pricing/views.py index e120dd9..fb62e35 100644 --- a/lingo/pricing/views.py +++ b/lingo/pricing/views.py @@ -192,15 +192,19 @@ class ConfigImportView(FormView): else: message2 = import_messages[obj_name]['update'](count) % {'count': count} - obj_results['messages'] = "%s %s" % (message1, message2) + if message1: + obj_results['messages'] = "%s %s" % (message1, message2) + else: + obj_results['messages'] = message2 - a_count, ct_count, pc_count, pm_count = ( + a_count, ct_count, pc_count, pm_count, p_count = ( len(results['agendas']['all']), len(results['check_type_groups']['all']), len(results['pricing_categories']['all']), len(results['pricing_models']['all']), + len(results['pricings']['all']), ) - if (a_count, ct_count, pc_count, pm_count) == (1, 0, 0, 0): + if (a_count, ct_count, pc_count, pm_count, p_count) == (1, 0, 0, 0, 0): # only one agenda imported, redirect to agenda page return HttpResponseRedirect( reverse( @@ -208,13 +212,13 @@ class ConfigImportView(FormView): kwargs={'pk': results['agendas']['all'][0].pk}, ) ) - if (a_count, ct_count, pc_count, pm_count) == (0, 1, 0, 0): + if (a_count, ct_count, pc_count, pm_count, p_count) == (0, 1, 0, 0, 0): # only one check type group imported, redirect to check type page return HttpResponseRedirect(reverse('lingo-manager-check-type-list')) - if (a_count, ct_count, pc_count, pm_count) == (0, 0, 1, 0): + if (a_count, ct_count, pc_count, pm_count, p_count) == (0, 0, 1, 0, 0): # 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): + if (a_count, ct_count, pc_count, pm_count, p_count) == (0, 0, 0, 1, 0): # only one pricing model imported, redirect to pricing model page return HttpResponseRedirect( reverse( @@ -222,6 +226,14 @@ class ConfigImportView(FormView): kwargs={'pk': results['pricing_models']['all'][0].pk}, ) ) + if (a_count, ct_count, pc_count, pm_count, p_count) == (0, 0, 0, 0, 1): + # only one pricing imported, redirect to pricing model page + return HttpResponseRedirect( + reverse( + 'lingo-manager-agenda-pricing-detail', + kwargs={'pk': results['pricings']['all'][0].pk}, + ) + ) if global_noop: messages.info(self.request, _('No data found.')) @@ -343,7 +355,7 @@ class PricingExport(DetailView): def get(self, request, *args, **kwargs): response = HttpResponse(content_type='application/json') today = datetime.date.today() - attachment = 'attachment; filename="export_pricing_{}_{}.json"'.format( + attachment = 'attachment; filename="export_pricing_model_{}_{}.json"'.format( self.get_object().slug, today.strftime('%Y%m%d') ) response['Content-Disposition'] = attachment @@ -786,6 +798,23 @@ class AgendaPricingDeleteView(DeleteView): agenda_pricing_delete = AgendaPricingDeleteView.as_view() +class AgendaPricingExport(DetailView): + model = AgendaPricing + + def get(self, request, *args, **kwargs): + response = HttpResponse(content_type='application/json') + today = datetime.date.today() + attachment = 'attachment; filename="export_pricing_{}_{}.json"'.format( + self.get_object().pricing.slug, today.strftime('%Y%m%d') + ) + response['Content-Disposition'] = attachment + json.dump({'pricings': [self.get_object().export_json()]}, response, indent=2) + return response + + +agenda_pricing_export = AgendaPricingExport.as_view() + + class AgendaPricingMatrixEdit(FormView): template_name = 'lingo/pricing/manager_agenda_pricing_matrix_form.html' diff --git a/tests/pricing/manager/test_import_export.py b/tests/pricing/manager/test_import_export.py index 869254a..57c78de 100644 --- a/tests/pricing/manager/test_import_export.py +++ b/tests/pricing/manager/test_import_export.py @@ -1,11 +1,12 @@ import copy +import datetime import json import pytest from webtest import Upload from lingo.agendas.models import Agenda, CheckType, CheckTypeGroup -from lingo.pricing.models import Criteria, CriteriaCategory, Pricing +from lingo.pricing.models import AgendaPricing, Criteria, CriteriaCategory, Pricing from tests.utils import login pytestmark = pytest.mark.django_db @@ -55,12 +56,14 @@ def test_export_site(freezer, app, admin_user): @pytest.mark.freeze_time('2021-07-08') def test_import_pricing(app, admin_user): - pricing = Pricing.objects.create(label='Model') + pricing = Pricing.objects.create(label='Foo') app = login(app) resp = app.get('/manage/pricing/model/%s/export/' % pricing.pk) assert resp.headers['content-type'] == 'application/json' - assert resp.headers['content-disposition'] == 'attachment; filename="export_pricing_model_20210708.json"' + assert ( + resp.headers['content-disposition'] == 'attachment; filename="export_pricing_model_foo_20210708.json"' + ) pricing_export = resp.text # existing pricing @@ -306,3 +309,75 @@ def test_import_check_type_group(app, admin_user): assert '3 check type groups have been created. No check type group updated.' in resp.text assert CheckTypeGroup.objects.count() == 3 assert CheckType.objects.count() == 6 + + +@pytest.mark.freeze_time('2021-07-08') +def test_import_agenda_pricing(app, admin_user): + pricing = Pricing.objects.create(label='Foo') + agenda_pricing = AgendaPricing.objects.create( + pricing=pricing, + date_start=datetime.date(year=2021, month=9, day=1), + date_end=datetime.date(year=2022, month=9, day=1), + ) + + app = login(app) + resp = app.get('/manage/pricing/agenda-pricing/%s/export/' % agenda_pricing.pk) + assert resp.headers['content-type'] == 'application/json' + assert resp.headers['content-disposition'] == 'attachment; filename="export_pricing_foo_20210708.json"' + agenda_pricing_export = resp.text + + # existing agenda_pricing + resp = app.get('/manage/pricing/', status=200) + resp = resp.click('Import') + resp.form['config_json'] = Upload( + 'export.json', agenda_pricing_export.encode('utf-8'), 'application/json' + ) + resp = resp.form.submit() + assert resp.location.endswith('/manage/pricing/agenda-pricing/%s/' % agenda_pricing.pk) + resp = resp.follow() + assert 'No pricing created. A pricing has been updated.' not in resp.text + assert AgendaPricing.objects.count() == 1 + + # new agenda_pricing + AgendaPricing.objects.all().delete() + resp = app.get('/manage/pricing/', status=200) + resp = resp.click('Import') + resp.form['config_json'] = Upload( + 'export.json', agenda_pricing_export.encode('utf-8'), 'application/json' + ) + resp = resp.form.submit() + agenda_pricing = AgendaPricing.objects.latest('pk') + assert resp.location.endswith('/manage/pricing/agenda-pricing/%s/' % agenda_pricing.pk) + resp = resp.follow() + assert 'A pricing has been created. No pricing updated.' not in resp.text + assert AgendaPricing.objects.count() == 1 + + # multiple agenda_pricing + agenda_pricings = json.loads(agenda_pricing_export) + agenda_pricings['pricings'].append(copy.copy(agenda_pricings['pricings'][0])) + agenda_pricings['pricings'].append(copy.copy(agenda_pricings['pricings'][0])) + agenda_pricings['pricings'][1]['label'] = 'Foo bar 2' + agenda_pricings['pricings'][1]['slug'] = 'foo-bar-2' + agenda_pricings['pricings'][2]['label'] = 'Foo bar 3' + agenda_pricings['pricings'][2]['slug'] = 'foo-bar-3' + + resp = app.get('/manage/pricing/', status=200) + resp = resp.click('Import') + resp.form['config_json'] = Upload( + 'export.json', json.dumps(agenda_pricings).encode('utf-8'), 'application/json' + ) + resp = resp.form.submit() + assert resp.location.endswith('/manage/pricing/') + resp = resp.follow() + assert '2 pricings have been created. A pricing has been updated.' in resp.text + assert AgendaPricing.objects.count() == 3 + + AgendaPricing.objects.all().delete() + resp = app.get('/manage/pricing/', status=200) + resp = resp.click('Import') + resp.form['config_json'] = Upload( + 'export.json', json.dumps(agenda_pricings).encode('utf-8'), 'application/json' + ) + resp = resp.form.submit().follow() + assert '3 pricings have been created. No pricing updated.' in resp.text + assert AgendaPricing.objects.count() == 3