diff --git a/contracts/migrations/0030_alter_signee_address_country_and_more.py b/contracts/migrations/0030_alter_signee_address_country_and_more.py new file mode 100644 index 0000000000000000000000000000000000000000..bd6463ee98131fafddba6a1f289d5c3811542dbe --- /dev/null +++ b/contracts/migrations/0030_alter_signee_address_country_and_more.py @@ -0,0 +1,43 @@ +# Generated by Django 4.1.4 on 2023-04-02 19:31 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('contracts', '0029_alter_contracteesignature_role_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='signee', + name='address_country', + field=models.CharField(blank=True, default='Česká Republika', max_length=256, null=True, verbose_name='Země'), + ), + migrations.AlterField( + model_name='signee', + name='address_district', + field=models.CharField(blank=True, max_length=256, null=True, verbose_name='Obec'), + ), + migrations.AlterField( + model_name='signee', + name='address_street_with_number', + field=models.CharField(blank=True, help_text='Veřejné pouze, když typ není nastaven na fyzickou osobu.', max_length=256, null=True, verbose_name='Ulice, č.p.'), + ), + migrations.AlterField( + model_name='signee', + name='address_zip', + field=models.CharField(blank=True, help_text='Veřejné pouze, když typ není nastaven na fyzickou osobu.', max_length=16, null=True, verbose_name='PSČ'), + ), + migrations.AlterField( + model_name='signee', + name='date_of_birth', + field=models.DateField(blank=True, help_text='U fyzických osob musí být vyplněno.', null=True, verbose_name='Datum narození'), + ), + migrations.AlterField( + model_name='signee', + name='ico_number', + field=models.CharField(blank=True, help_text='U právnických a podnikajících fyzických osob musí být vyplněno. Vyplněním můžeš automaticky načíst data z ARES.', max_length=16, null=True, verbose_name='IČO'), + ), + ] diff --git a/contracts/migrations/0031_alter_contract_cost_unit_other_and_more.py b/contracts/migrations/0031_alter_contract_cost_unit_other_and_more.py new file mode 100644 index 0000000000000000000000000000000000000000..75b507bd57938dea626d2915401615db13f8e5ad --- /dev/null +++ b/contracts/migrations/0031_alter_contract_cost_unit_other_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 4.1.4 on 2023-04-02 19:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('contracts', '0030_alter_signee_address_country_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='contract', + name='cost_unit_other', + field=models.CharField(blank=True, help_text='Je nutno vyplnit v případě, že máš vybranou možnost "jiné" v jednotce nákladů.', max_length=128, null=True, verbose_name='Jednotka nákladů (jiné)'), + ), + migrations.AlterField( + model_name='contracteesignature', + name='role', + field=models.CharField(blank=True, help_text='Např. "nájemník"', max_length=256, null=True, verbose_name='Role'), + ), + migrations.AlterField( + model_name='signeesignature', + name='role', + field=models.CharField(blank=True, help_text='Např. "pronajímatel"', max_length=256, null=True, verbose_name='Role'), + ), + ] diff --git a/contracts/models.py b/contracts/models.py index 4fcc486fe7a928177203f5b7e6534391af910f95..8fa16d2950392aea239e8efebd343140e0e1e2d7 100644 --- a/contracts/models.py +++ b/contracts/models.py @@ -103,23 +103,31 @@ class Signee(CreatedByMixin, OwnPermissionsMixin, SignatureCountMixin, models.Mo address_street_with_number = models.CharField( max_length=256, + blank=True, + null=True, verbose_name="Ulice, č.p.", help_text="Veřejné pouze, když typ není nastaven na fyzickou osobu.", ) # WARNING: Legal entity status dependent! address_district = models.CharField( max_length=256, + blank=True, + null=True, verbose_name="Obec", ) address_zip = models.CharField( max_length=16, + blank=True, + null=True, verbose_name="PSČ", help_text="Veřejné pouze, když typ není nastaven na fyzickou osobu.", ) # WARNING: Legal entity status dependent! address_country = models.CharField( max_length=256, + blank=True, + null=True, verbose_name="Země", default=settings.DEFAULT_COUNTRY, ) @@ -129,13 +137,17 @@ class Signee(CreatedByMixin, OwnPermissionsMixin, SignatureCountMixin, models.Mo blank=True, null=True, verbose_name="IČO", - help_text="Vyplněním můžeš automaticky načíst data z ARES.", + help_text=( + "U právnických a podnikajících fyzických osob musí být vyplněno. " + "Vyplněním můžeš automaticky načíst data z ARES." + ), ) # WARNING: Legal entity status dependent! date_of_birth = models.DateField( blank=True, null=True, verbose_name="Datum narození", + help_text="U fyzických osob musí být vyplněno." ) # WARNING: Legal entity status dependent! department = models.CharField( @@ -156,6 +168,53 @@ class Signee(CreatedByMixin, OwnPermissionsMixin, SignatureCountMixin, models.Mo self.EntityTypes.OTHER, ) + @property + def has_any_address_information(self) -> bool: + for field in ( + "address_street_with_number", + "address_district", + "address_zip", + "address_country", + ): + if getattr(self, field): + return True + + return False + + def clean(self): + if ( + self.entity_type == self.EntityTypes.NATURAL_PERSON + and not self.date_of_birth + ): + raise ValidationError({ + "date_of_birth": "U fyzických osob musí být definováno." + }) + + if ( + self.entity_type in ( + self.EntityTypes.LEGAL_ENTITY, + self.EntityTypes.BUSINESS_NATURAL_PERSON + ) + and not self.ico_number + ): + raise ValidationError({ + "ico_number": "U právnických a podnikajících fyzických osob musí být definováno." + }) + + if (self.entity_type != self.EntityTypes.OTHER): + for field in ( + "address_street_with_number", + "address_district", + "address_zip", + "address_country", + ): + if not getattr(self, field): + raise ValidationError({ + field: "Pokud není vybrán typ \"Jiné\", musí být definováno." + }) + + return super().clean() + def __str__(self) -> str: result = self.name @@ -491,7 +550,7 @@ class Contract(NameStrMixin, models.Model): cost_unit_other = models.CharField( max_length=128, verbose_name="Jednotka nákladů (jiné)", - help_text="Je nutno vyplnit v případě, že máš vybranou možnost 'jiné' v jednotce nákladů.", + help_text="Je nutno vyplnit v případě, že máš vybranou možnost \"jiné\" v jednotce nákladů.", blank=True, null=True, ) @@ -610,13 +669,13 @@ class Contract(NameStrMixin, models.Model): if self.cost_unit == self.CostUnits.OTHER and not self.cost_unit_other: raise ValidationError( { - "cost_unit_other": "Musí být definováno, pokud je vybrána jednotka nákladů 'jiné'." + "cost_unit_other": "Musí být definováno, pokud je vybrána jednotka nákladů \"jiné\"." } ) elif self.cost_unit != self.CostUnits.OTHER and self.cost_unit_other: raise ValidationError( { - "cost_unit_other": "Nemůže být definováno, pokud není vybrána jednotka nákladů 'jiné'." + "cost_unit_other": "Nemůže být definováno, pokud není vybrána jednotka nákladů \"jiné\"." } ) @@ -631,6 +690,8 @@ class Contract(NameStrMixin, models.Model): } ) + return super().clean() + def save(self, *args, **kwargs): self.updated_on = get_current_utc_timestamp() @@ -712,7 +773,7 @@ class ContracteeSignature(models.Model): blank=True, null=True, verbose_name="Role", - help_text="Např. 'nájemník'", + help_text="Např. \"nájemník\"", ) def __str__(self) -> str: @@ -749,7 +810,7 @@ class SigneeSignature(models.Model): blank=True, null=True, verbose_name="Role", - help_text="Např. 'pronajímatel'", + help_text="Např. \"pronajímatel\"", ) def __str__(self) -> str: diff --git a/contracts/templates/contracts/view_contract.html b/contracts/templates/contracts/view_contract.html index 1c6d6317dc3bfa34ff51cd4816532d820b86e0fb..0cf4c06431606e045a457a71d86417011590a963 100644 --- a/contracts/templates/contracts/view_contract.html +++ b/contracts/templates/contracts/view_contract.html @@ -416,9 +416,11 @@ </a> </div> - <div class="mb-2"> - {{ signature.signee.get_entity_type_display }} - </div> + {% if signature.signee.entity_type != signature.signee.EntityTypes.OTHER %} + <div class="mb-2"> + {{ signature.signee.get_entity_type_display }} + </div> + {% endif %} {% if user.can_view_confidential and not signature.signee.entity_has_public_address %} <div class="border !bg-red-100 border-red-200 p-1.5 rounded-md mt-1.5 mb-2 inline-block"> @@ -437,11 +439,13 @@ </div> {% if user.can_view_confidential or signature.signee.entity_has_public_address %} - {{ signature.signee.address_street_with_number }}<br> - {{ signature.signee.address_zip }} {{ signature.signee.address_district }}<br> - {{ signature.signee.address_country }} + {% if signature.signee.address_street_with_number %}{{ signature.signee.address_street_with_number }}<br>{% endif %} + {% if signature.signee.address_zip %}{{ signature.signee.address_zip }}{% endif %} + {% if signature.signee.address_district %}{{ signature.signee.address_district }}<br>{% endif %} + {% if signature.signee.address_country %}{{ signature.signee.address_country }}{% endif %} {% else %} - {{ signature.signee.address_district }}, {{ signature.signee.address_country }} + {% if signature.signee.address_district %}{{ signature.signee.address_district }},{% endif %} + {% if signature.signee.address_country %}{{ signature.signee.address_country }}{% endif %} {% endif %} {% if signature.signee.ico_number %} diff --git a/contracts/templates/contracts/view_signee.html b/contracts/templates/contracts/view_signee.html index 9eaa8fbf1ed98234f1fe68462811e195dd3860d7..81dc6a0db7566c775efecc8daa1a5c02157bdfce 100644 --- a/contracts/templates/contracts/view_signee.html +++ b/contracts/templates/contracts/view_signee.html @@ -11,56 +11,62 @@ </div> </div> - <address class="mb-8"> - <div class="mb-2"> - <strong>{{ signee.name }}</strong> - {% if signee.department %} - - {{ signee.department }} - {% endif %} - </div> + {% if signee.has_any_address_information %} + <address class="mb-8"> + <div class="mb-2"> + <strong>{{ signee.name }}</strong> + {% if signee.department %} + - {{ signee.department }} + {% endif %} + </div> - <div class="mb-2"> - {{ signee.get_entity_type_display }} - </div> + {% if signee.entity_type != signee.EntityTypes.OTHER %} + <div class="mb-2"> + {{ signee.get_entity_type_display }} + </div> + {% endif %} - {% if user.can_view_confidential and not signee.entity_has_public_address %} - <div class="border !bg-red-100 border-red-200 p-1.5 rounded-md mt-1.5 mb-2 inline-block"> - {% endif %} + {% if user.can_view_confidential and not signee.entity_has_public_address %} + <div class="border !bg-red-100 border-red-200 p-1.5 rounded-md mt-1.5 mb-2 inline-block"> + {% endif %} - <div> - {% if not signee.entity_has_public_address %} - {% if user.can_view_confidential %} - <div class="flex items-center mb-3"> - {% include "contracts/includes/private_info_icon.html" %}<span class="text-red-600">Máš přístup k celé adrese.</span> - </div> - {% else %} - <span class="text-gray-500">(zobrazujeme pouze obec)</span> + <div> + {% if not signee.entity_has_public_address %} + {% if user.can_view_confidential %} + <div class="flex items-center mb-3"> + {% include "contracts/includes/private_info_icon.html" %}<span class="text-red-600">Máš přístup k celé adrese.</span> + </div> + {% else %} + <span class="text-gray-500">(zobrazujeme pouze obec)</span> + {% endif %} {% endif %} - {% endif %} - </div> + </div> - {% if user.can_view_confidential or signee.entity_has_public_address %} - {{ signee.address_street_with_number }}<br> - {{ signee.address_zip }} {{ signee.address_district }}<br> - {{ signee.address_country }} - {% else %} - {{ signee.address_district }}, {{ signee.address_country }} - {% endif %} + {% if user.can_view_confidential or signee.entity_has_public_address %} + {% if signee.address_street_with_number %}{{ signee.address_street_with_number }}<br>{% endif %} + {% if signee.address_zip %}{{ signee.address_zip }}{% endif %} + {% if signee.address_district %}{{ signee.address_district }}<br>{% endif %} + {% if signee.address_country %}{{ signee.address_country }}{% endif %} + {% else %} + {% if signee.address_district %}{{ signee.address_district }},{% endif %} + {% if signee.address_country %}{{ signee.address_country }}{% endif %} + {% endif %} - {% if signee.ico_number %} - <br><br> - <strong>IČO</strong>: {{ signee.ico_number }} - {% endif %} + {% if signee.ico_number %} + <br><br> + <strong>IČO</strong>: {{ signee.ico_number }} + {% endif %} - {% if user.can_view_confidential and signee.date_of_birth %} - <br><br> - <strong>Datum narození</strong>: {{ signee.date_of_birth }} - {% endif %} + {% if user.can_view_confidential and signee.date_of_birth %} + <br><br> + <strong>Datum narození</strong>: {{ signee.date_of_birth }} + {% endif %} - {% if user.can_view_confidential and not signee.entity_has_public_address %} - </div> - {% endif %} - </address> + {% if user.can_view_confidential and not signee.entity_has_public_address %} + </div> + {% endif %} + </address> + {% endif %} <h2 class="text-lg font-bold mb-10"> Smlouvy podepsané touto stranou diff --git a/contracts/views.py b/contracts/views.py index 987d43eb061b5f192ab6a92ef921c087f6216838..b3583881d190103c84898a7cd680d3fe7d4d5bc9 100644 --- a/contracts/views.py +++ b/contracts/views.py @@ -1,3 +1,5 @@ +from xml.etree import ElementTree + import requests from django.conf import settings from django.core.paginator import Paginator @@ -368,6 +370,13 @@ def get_ares_info(request, ico: int): f"https://wwwinfo.mfcr.cz/cgi-bin/ares/darv_std.cgi?ico={ico}" ) + tree = ElementTree.fromstring(ares_info.content) + + for result_count in tree.iter("are:Pocet_zaznamu"): + if result_count.text == "0": + raise HTTPExceptions.NOT_FOUND + + return HttpResponse( content=ares_info.content, status=ares_info.status_code, diff --git a/static_src/admin/signee_form.js b/static_src/admin/signee_form.js index ce8e74bd8a5e76226d68598b99adac112656609f..2dc4acc21698c4a076c9004d19eae4dc4511894a 100644 --- a/static_src/admin/signee_form.js +++ b/static_src/admin/signee_form.js @@ -10,14 +10,17 @@ const fieldDepartmentValues = new Set([ $(window).ready( () => { - let isNaturalPerson = ($("#id_entity_type").find(":selected").val() === "natural_person"); - let isEmpty = ($("#id_entity_type").find(":selected").val() === ""); + let selectedValue = $("#id_entity_type").find(":selected").val(); + + let isNaturalPerson = (selectedValue === "natural_person"); + let isOther = (selectedValue === "other"); + let isEmpty = (selectedValue === ""); $(".field-date_of_birth"). css( "display", ( - (isNaturalPerson) ? + (!isEmpty && (isNaturalPerson || isOther)) ? "block" : "none" ) ); @@ -35,26 +38,29 @@ $(window).ready( css( "display", ( - (!isEmpty && fieldDepartmentValues.has($("#id_entity_type").find(":selected").val())) ? + (!isEmpty && fieldDepartmentValues.has(selectedValue)) ? "block" : "none" ) ); - if (!isNaturalPerson && !isEmpty) $("#id_date_of_birth").val(""); + if (!isNaturalPerson && !isOther && !isEmpty) $("#id_date_of_birth").val(""); if (isNaturalPerson) $("#id_ico_number").val(""); - if (!fieldDepartmentValues.has($("#id_entity_type").find(":selected").val()) && !isEmpty) $("#id_department").val(""); + if (!fieldDepartmentValues.has(selectedValue) && !isEmpty) $("#id_department").val(""); $("#id_entity_type").on( "change", event => { - isEmpty = ($(event.target).val() === ""); - isNaturalPerson = ($(event.target).val() === "natural_person"); + selectedValue = $(event.target).val(); + + isEmpty = (selectedValue === ""); + isOther = (selectedValue === "other"); + isNaturalPerson = (selectedValue === "natural_person"); $(".field-date_of_birth"). css( "display", ( - (!isEmpty && isNaturalPerson) ? + (!isEmpty && (isNaturalPerson || isOther)) ? "block" : "none" ) ); @@ -76,7 +82,7 @@ $(window).ready( ) ); - if (!isNaturalPerson && !isEmpty) $("#id_date_of_birth").val(""); + if (!isNaturalPerson && !isOther && !isEmpty) $("#id_date_of_birth").val(""); if (isNaturalPerson) $("#id_ico_number").val(""); if (!fieldDepartmentValues.has($(event.target).val()) && !isEmpty) $("#id_department").val(""); }