forked from CGM_Public/pretix_original
Load address format information when selecting country
This commit is contained in:
@@ -54,6 +54,7 @@ from django.core.validators import (
|
||||
from django.db.models import QuerySet
|
||||
from django.forms import Select, widgets
|
||||
from django.forms.widgets import FILE_INPUT_CONTRADICTION
|
||||
from django.urls import reverse
|
||||
from django.utils.formats import date_format
|
||||
from django.utils.html import escape
|
||||
from django.utils.safestring import mark_safe
|
||||
@@ -712,6 +713,7 @@ class BaseQuestionsForm(forms.Form):
|
||||
initial=country,
|
||||
widget=forms.Select(attrs={
|
||||
'autocomplete': 'country',
|
||||
'data-country-information-url': reverse('js_helpers.states'),
|
||||
}),
|
||||
)
|
||||
c = [('', pgettext_lazy('address', 'Select state'))]
|
||||
@@ -1005,7 +1007,7 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
'street': forms.Textarea(attrs={
|
||||
'rows': 2,
|
||||
'placeholder': _('Street and Number'),
|
||||
'autocomplete': 'street-address'
|
||||
'autocomplete': 'street-address',
|
||||
}),
|
||||
'beneficiary': forms.Textarea(attrs={'rows': 3}),
|
||||
'country': forms.Select(attrs={
|
||||
@@ -1021,7 +1023,7 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
'data-display-dependency': '#id_is_business_1',
|
||||
'autocomplete': 'organization',
|
||||
}),
|
||||
'vat_id': forms.TextInput(attrs={'data-display-dependency': '#id_is_business_1', 'data-countries-with-vat-id': ','.join(VAT_ID_COUNTRIES)}),
|
||||
'vat_id': forms.TextInput(attrs={'data-display-dependency': '#id_is_business_1'}),
|
||||
'internal_reference': forms.TextInput,
|
||||
}
|
||||
labels = {
|
||||
@@ -1055,6 +1057,7 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
])
|
||||
|
||||
self.fields['country'].choices = CachedCountries()
|
||||
self.fields['country'].widget.attrs['data-country-information-url'] = reverse('js_helpers.states')
|
||||
|
||||
c = [('', pgettext_lazy('address', 'Select state'))]
|
||||
fprefix = self.prefix + '-' if self.prefix else ''
|
||||
@@ -1083,6 +1086,10 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
)
|
||||
self.fields['state'].widget.is_required = True
|
||||
|
||||
self.fields['street'].required = False
|
||||
self.fields['zipcode'].required = False
|
||||
self.fields['city'].required = False
|
||||
|
||||
# Without JavaScript the VAT ID field is not hidden, so we empty the field if a country outside the EU is selected.
|
||||
if cc and not ask_for_vat_id(cc) and fprefix + 'vat_id' in self.data:
|
||||
self.data = self.data.copy()
|
||||
|
||||
@@ -3204,9 +3204,9 @@ class InvoiceAddress(models.Model):
|
||||
company = models.CharField(max_length=255, blank=True, verbose_name=_('Company name'))
|
||||
name_cached = models.CharField(max_length=255, verbose_name=_('Full name'), blank=True)
|
||||
name_parts = models.JSONField(default=dict)
|
||||
street = models.TextField(verbose_name=_('Address'), blank=False)
|
||||
zipcode = models.CharField(max_length=30, verbose_name=_('ZIP code'), blank=False)
|
||||
city = models.CharField(max_length=255, verbose_name=_('City'), blank=False)
|
||||
street = models.TextField(verbose_name=_('Address'), blank=True)
|
||||
zipcode = models.CharField(max_length=30, verbose_name=_('ZIP code'), blank=True)
|
||||
city = models.CharField(max_length=255, verbose_name=_('City'), blank=True)
|
||||
country_old = models.CharField(max_length=255, verbose_name=_('Country'), blank=False)
|
||||
country = FastCountryField(verbose_name=_('Country'), blank=False, blank_label=_('Select country'),
|
||||
countries=CachedCountries)
|
||||
|
||||
@@ -22,16 +22,28 @@
|
||||
import pycountry
|
||||
from django.http import JsonResponse
|
||||
|
||||
from pretix.base.addressvalidation import COUNTRIES_WITH_STREET_ZIPCODE_AND_CITY_REQUIRED
|
||||
from pretix.base.models.tax import VAT_ID_COUNTRIES
|
||||
from pretix.base.settings import COUNTRIES_WITH_STATE_IN_ADDRESS
|
||||
|
||||
|
||||
def states(request):
|
||||
cc = request.GET.get("country", "DE")
|
||||
info = {
|
||||
'street': {'required': cc in COUNTRIES_WITH_STREET_ZIPCODE_AND_CITY_REQUIRED},
|
||||
'zipcode': {'required': cc in COUNTRIES_WITH_STREET_ZIPCODE_AND_CITY_REQUIRED},
|
||||
'city': {'required': cc in COUNTRIES_WITH_STREET_ZIPCODE_AND_CITY_REQUIRED},
|
||||
'state': {'visible': cc in COUNTRIES_WITH_STATE_IN_ADDRESS, 'required': cc in COUNTRIES_WITH_STATE_IN_ADDRESS},
|
||||
'vat_id': {'visible': cc in VAT_ID_COUNTRIES, 'required': False},
|
||||
}
|
||||
if cc not in COUNTRIES_WITH_STATE_IN_ADDRESS:
|
||||
return JsonResponse({'data': []})
|
||||
return JsonResponse({'data': [], **info,})
|
||||
types, form = COUNTRIES_WITH_STATE_IN_ADDRESS[cc]
|
||||
statelist = [s for s in pycountry.subdivisions.get(country_code=cc) if s.type in types]
|
||||
return JsonResponse({'data': [
|
||||
{'name': s.name, 'code': s.code[3:]}
|
||||
for s in sorted(statelist, key=lambda s: s.name)
|
||||
]})
|
||||
return JsonResponse({
|
||||
'data': [
|
||||
{'name': s.name, 'code': s.code[3:]}
|
||||
for s in sorted(statelist, key=lambda s: s.name)
|
||||
],
|
||||
**info,
|
||||
})
|
||||
|
||||
@@ -1,65 +1,61 @@
|
||||
$(function () {
|
||||
"use strict";
|
||||
|
||||
$("select[name$=state]:not([data-static])").each(function () {
|
||||
var dependent = $(this),
|
||||
counter = 0,
|
||||
dependency = $(this).closest(".panel-body, form").find('select[name$=country]'),
|
||||
depRequired = dependency.closest(".form-group").is(".required"),
|
||||
$("select[data-country-information-url]").each(function () {
|
||||
let counter = 0;
|
||||
const dependency = $(this),
|
||||
url = this.getAttribute('data-country-information-url'),
|
||||
form = $(this).closest(".panel-body, form"),
|
||||
isRequired = dependency.closest(".form-group").is(".required"),
|
||||
dependents = {
|
||||
'city': form.find("input[name$=city]"),
|
||||
'zipcode': form.find("input[name$=zipcode]"),
|
||||
'street': form.find("textarea[name$=street]"),
|
||||
'state': form.find("select[name$=state]"),
|
||||
'vat_id': form.find("input[name$=vat_id]"),
|
||||
},
|
||||
update = function (ev) {
|
||||
counter++;
|
||||
var curCounter = counter;
|
||||
dependent.prop("disabled", true);
|
||||
const curCounter = counter;
|
||||
for (var k in dependents) dependents[k].prop("disabled", true);
|
||||
dependency.closest(".form-group").find("label").prepend("<span class='fa fa-cog fa-spin'></span> ");
|
||||
$.getJSON('/js_helpers/states/?country=' + dependency.val(), function (data) {
|
||||
$.getJSON(url + '?country=' + dependency.val(), function (data) {
|
||||
if (counter > curCounter) {
|
||||
return; // Lost race
|
||||
}
|
||||
var selected_value = dependent.prop("data-selected-value");
|
||||
dependent.find("option").filter(function (t) {return !!$(this).attr("value")}).remove();
|
||||
var selected_value = dependents.state.prop("data-selected-value");
|
||||
dependents.state.find("option").filter(function (t) {return !!$(this).attr("value")}).remove();
|
||||
if (data.data.length > 0) {
|
||||
$.each(data.data, function (k, s) {
|
||||
var o = $("<option>").attr("value", s.code).text(s.name);
|
||||
if (s.code == selected_value || (selected_value && selected_value.indexOf && selected_value.indexOf(s.code) > -1)) {
|
||||
o.prop("selected", true);
|
||||
}
|
||||
dependent.append(o);
|
||||
dependents.state.append(o);
|
||||
});
|
||||
dependent.closest(".form-group").show().toggleClass('required', depRequired);
|
||||
dependent.prop('required', depRequired);
|
||||
} else {
|
||||
dependent.closest(".form-group").hide();
|
||||
dependent.prop("required", false);
|
||||
}
|
||||
dependent.prop("disabled", false);
|
||||
for(var k in dependents) {
|
||||
const options = data[k], dependent = dependents[k]; console.log(options, dependent)
|
||||
if ('visible' in options) {
|
||||
if (options.visible) {
|
||||
dependent.closest(".form-group").show().toggleClass('required', isRequired);
|
||||
dependent.prop('required', isRequired);
|
||||
} else {
|
||||
dependent.closest(".form-group").hide();
|
||||
dependent.prop("required", false);
|
||||
}
|
||||
}
|
||||
if ('required' in options) {
|
||||
dependent.closest(".form-group").toggleClass('required', options.required && isRequired);
|
||||
dependent.prop('required', options.required && isRequired);
|
||||
}
|
||||
}
|
||||
for (var k in dependents) dependents[k].prop("disabled", false);
|
||||
dependency.closest(".form-group").find("label .fa-spin").remove();
|
||||
});
|
||||
};
|
||||
if (dependent.find("option").length === 1) {
|
||||
dependent.closest(".form-group").hide();
|
||||
} else {
|
||||
dependent.closest(".form-group").toggleClass('required', depRequired);
|
||||
dependent.prop('required', depRequired);
|
||||
}
|
||||
update();
|
||||
dependency.on("change", update);
|
||||
});
|
||||
|
||||
$("input[name$=vat_id][data-countries-with-vat-id]").each(function () {
|
||||
var dependent = $(this),
|
||||
dependency_country = $(this).closest(".panel-body, form").find('select[name$=country]'),
|
||||
dependency_id_is_business_1 = $(this).closest(".panel-body, form").find('input[id$=id_is_business_1]'),
|
||||
update = function (ev) {
|
||||
if (dependency_id_is_business_1.length && !dependency_id_is_business_1.prop("checked")) {
|
||||
dependent.closest(".form-group").hide();
|
||||
} else if (dependent.attr('data-countries-with-vat-id').split(',').includes(dependency_country.val())) {
|
||||
dependent.closest(".form-group").show();
|
||||
} else {
|
||||
dependent.closest(".form-group").hide();
|
||||
}
|
||||
};
|
||||
update();
|
||||
dependency_country.on("change", update);
|
||||
dependency_id_is_business_1.on("change", update);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user