From a7441f7c07217626733e58d8dfca9a0dc3ddaa24 Mon Sep 17 00:00:00 2001 From: Étienne Loks Date: Thu, 5 Aug 2021 19:22:26 +0200 Subject: Preventive file: cost propertues - display cost in sheet files --- archaeological_files/models.py | 87 ++- .../templates/ishtar/sheet_file.html | 593 ++++++++++++++------- .../migrations/0216_auto_20210805_1703.py | 25 + ishtar_common/models.py | 2 + 4 files changed, 507 insertions(+), 200 deletions(-) create mode 100644 ishtar_common/migrations/0216_auto_20210805_1703.py diff --git a/archaeological_files/models.py b/archaeological_files/models.py index 79dabc84d..0eac73119 100644 --- a/archaeological_files/models.py +++ b/archaeological_files/models.py @@ -235,6 +235,12 @@ class EquipmentServiceCost(models.Model): def history_compress(self): return self.slug + @property + def unit_label(self): + if self.unit and self.unit in DCT_ES_UNITS: + return DCT_ES_UNITS[self.unit] + return "" + class FileType(GeneralType): class Meta: @@ -1033,6 +1039,47 @@ class File( self.general_contractor.save() return True + @property + def job_cost_planned(self): + return sum(job.cost_planned for job in self.jobs.all()) + + @property + def ground_job_cost_planned(self): + return sum(job.cost_planned for job in self.ground_jobs.all()) + + @property + def job_cost_worked(self): + return sum(job.cost_worked for job in self.jobs.all()) + + @property + def ground_job_cost_worked(self): + return sum(job.cost_worked for job in self.ground_jobs.all()) + + @property + def job_cost_diff_planned_worked(self): + return self.job_cost_planned - self.job_cost_worked + + @property + def ground_job_cost_diff_planned_worked(self): + return self.ground_job_cost_planned - self.ground_job_cost_worked + + @property + def used_equipments(self): + equipments = [] + service_types = list(GenericEquipmentServiceType.objects.all()) + for service_type in service_types: + q = self.equipment_costs.filter( + equipment_service_cost__equipment_service_type__generic_equipment_type=service_type) + if not q.count(): + continue + equipments.append([service_type.label, 0, 0, 0, []]) + for cost in q.all(): + equipments[-1][-4] += cost.cost_planned + equipments[-1][-3] += cost.cost_worked + equipments[-1][-1].append(cost) + equipments[-1][-2] = equipments[-1][-4] - equipments[-1][-3] + return equipments + def get_extra_actions(self, request): # url, base_text, icon, extra_text, extra css class, is a quick action actions = super(File, self).get_extra_actions(request) @@ -1318,6 +1365,14 @@ class PreventiveFileGroundJob(ManDays): class Meta: ordering = ("job",) + @property + def cost_planned(self): + return (self.job.ground_daily_cost or 0) * self.quantity_planned + + @property + def cost_worked(self): + return (self.job.ground_daily_cost or 0) * self.quantity_worked + class PreventiveFileJob(ManDays): file = models.ForeignKey(File, related_name="jobs") @@ -1326,8 +1381,18 @@ class PreventiveFileJob(ManDays): class Meta: ordering = ("job",) + @property + def cost_planned(self): + return (self.job.daily_cost or 0) * self.quantity_planned + + @property + def cost_worked(self): + return (self.job.daily_cost or 0) * self.quantity_worked + -class TechDays(models.Model): +class PreventiveFileEquipmentServiceCost(models.Model): + file = models.ForeignKey(File, related_name="equipment_costs") + equipment_service_cost = models.ForeignKey(EquipmentServiceCost) quantity_by_day_planned = models.FloatField( _("Quantity by day - planned"), null=True, blank=True ) @@ -1338,24 +1403,28 @@ class TechDays(models.Model): days_worked = models.FloatField(_("Days - worked"), null=True, blank=True) class Meta: - abstract = True + ordering = ("equipment_service_cost",) @property def quantity_planned(self): + if self.equipment_service_cost.flat_rate: + return self.quantity_by_day_planned or 0 if not self.days_planned or not self.quantity_by_day_planned: return 0 return self.days_planned * self.quantity_by_day_planned @property def quantity_worked(self): - if not self.days_worked or not self.quantity_by_day_worked: + if self.equipment_service_cost.flat_rate: + return self.quantity_by_day_worked or 0 + if not self.quantity_by_day_worked or not self.days_worked: return 0 return self.days_worked * self.quantity_by_day_worked + @property + def cost_planned(self): + return (self.equipment_service_cost.unitary_cost or 0) * self.quantity_planned -class PreventiveFileEquipmentServiceCost(TechDays): - file = models.ForeignKey(File, related_name="equipment_costs") - equipment_service_cost = models.ForeignKey(EquipmentServiceCost) - - class Meta: - ordering = ("equipment_service_cost",) + @property + def cost_worked(self): + return (self.equipment_service_cost.unitary_cost or 0) * self.quantity_worked diff --git a/archaeological_files/templates/ishtar/sheet_file.html b/archaeological_files/templates/ishtar/sheet_file.html index 7d3279988..d54d29e7e 100644 --- a/archaeological_files/templates/ishtar/sheet_file.html +++ b/archaeological_files/templates/ishtar/sheet_file.html @@ -11,211 +11,422 @@ {% with can_view_documents=permission_view_own_document|or_:permission_view_document %} {% with has_documents=item.documents.count %} {% with display_documents=can_view_documents|and_:has_documents %} +{% with has_costs=item.equipment_costs.count|or_:item.ground_jobs.count|or_:item.jobs.count %} + +{% if output != "ODT" and output != "PDF"%} + +{% endif %} -
-
-
- {% include "ishtar/blocks/window_image.html" %} -
-
- {% if item.complete_identifier %}

- {{ item.complete_identifier }}

{% endif %} -

{{item.full_internal_ref|default:''}}

-

{{item.internal_reference|default:''}}

-

{{item.name|default:''}}

- {% include "ishtar/blocks/sheet_external_id.html" %} +
+
+ +
+
+
+ {% include "ishtar/blocks/window_image.html" %} +
+
+ {% if item.complete_identifier %}

+ {{ item.complete_identifier }}

{% endif %} +

{{item.full_internal_ref|default:''}}

+

{{item.internal_reference|default:''}}

+

{{item.name|default:''}}

+ {% include "ishtar/blocks/sheet_external_id.html" %} +
+
+
+
-
-
-
-
- - -

{% trans "General"%}

-
- {% field_flex "Reception date" item.reception_date|date:"DATE_FORMAT" %} - {% include "ishtar/blocks/sheet_creation_section.html" %} +

{% trans "General"%}

+ +
+ {% field_flex "Reception date" item.reception_date|date:"DATE_FORMAT" %} + {% include "ishtar/blocks/sheet_creation_section.html" %} + + {% comment %} + {% if item.deadline_date and not item.acts %} +

{% item.deadline_date %}

+ {% endif %} + {% endcomment %} + + {% field_flex_detail "In charge" item.in_charge %} +
+
{%trans "State"%}
+
+ {% if item.is_active %}{%trans "Active file"%}{% else %}{%trans "Closed file"%}{% endif %} +
+
+ {% if item.closing %} +
+
{%trans "Closing date"%}
+
+ {{ item.closing.date }} {%trans "by" %} {{ item.closing.user.full_label }} +
+
+ {% endif %} + {% field_flex "Type" item.file_type %} + {% field_flex_detail "Related file" item.related_file %} + {% field_flex_full "Comment" item.comment "
" "
" %} +
-{% comment %} -{% if item.deadline_date and not item.acts %} -

{% item.deadline_date %}

-{% endif %} -{% endcomment %} - - {% field_flex_detail "In charge" item.in_charge %} -
-
{%trans "State"%}
-
- {% if item.is_active %}{%trans "Active file"%}{% else %}{%trans "Closed file"%}{% endif %} -
-
- {% if item.closing %} -
-
{%trans "Closing date"%}
-
- {{ item.closing.date }} {%trans "by" %} {{ item.closing.user.full_label }} -
-
- {% endif %} - {% field_flex "Type" item.file_type %} - {% field_flex_detail "Related file" item.related_file %} - {% field_flex_full "Comment" item.comment "
" "
" %} -
+ {% include "ishtar/blocks/sheet_json.html" %} + +

{% trans "Localisation"%}

+
+ {% field_flex_multiple_obj "Towns" item 'towns' %} + {% field_flex_multiple_obj "Departments" item 'departments' %} + {% field_flex "Main address" item.address %} + {% field_flex "Complement" item.address_complement %} + {% field_flex "Postal code" item.postal_code %} + {% if item.total_surface %} +
+
{%trans "Surface"%}
+
+ {{ item.total_surface }} m2 ({{ item.total_surface_ha }} ha) +
+
+ {% endif %} +
-{% include "ishtar/blocks/sheet_json.html" %} - -

{% trans "Localisation"%}

-
- {% field_flex_multiple_obj "Towns" item 'towns' %} - {% field_flex_multiple_obj "Departments" item 'departments' %} - {% field_flex "Main address" item.address %} - {% field_flex "Complement" item.address_complement %} - {% field_flex "Postal code" item.postal_code %} - {% if item.total_surface %} -
-
{%trans "Surface"%}
-
- {{ item.total_surface }} m2 ({{ item.total_surface_ha }} ha) -
-
- {% endif %} -
+ {% if item.is_preventive %} + +

{% trans "Preventive archaeological file"%}

+
+ + {% if item.total_developed_surface %} +
+
{%trans "Developed surface"%}
+
+ {{ item.total_developed_surface }} m2 ({{ item.total_developed_surface_ha }} ha) +
+
+ {% endif %} + + {% field_flex "Saisine type" item.saisine_type %} + + {% field_flex_detail "Responsible for planning service" item.responsible_town_planning_service %} + {% field_flex "Responsible for planning service address" item.responsible_town_planning_service.full_address %} + {% if item.town_planning_service %} + {% field_flex "Planning service organization" item.town_planning_service.full_address %} + {% else %} + {% field_flex "Planning service organization" item.responsible_town_planning_service.attached_to.full_address %} + {% endif %} + + {% field_flex "Permit type" item.permit_type %} + {% field_flex "Permit reference" item.permit_reference %} + {% field_flex "Date of planning service file" item.planning_service_date|date:"DATE_FORMAT" %} + + {% field_flex "General contractor" item.general_contractor.full_address %} + {% if item.corporation_general_contractor %} + {% field_flex "General contractor organization" item.corporation_general_contractor.full_address %} + {% else%} + {% field_flex "General contractor organization" item.general_contractor.attached_to.full_address %} + {% endif %} -{% if item.is_preventive %} - -

{% trans "Preventive archaeological file"%}

-
- - {% if item.total_developed_surface %} -
-
{%trans "Developed surface"%}
-
- {{ item.total_developed_surface }} m2 ({{ item.total_developed_surface_ha }} ha) -
-
- {% endif %} - - {% field_flex "Saisine type" item.saisine_type %} - - {% field_flex_detail "Responsible for planning service" item.responsible_town_planning_service %} - {% field_flex "Responsible for planning service address" item.responsible_town_planning_service.full_address %} - {% if item.town_planning_service %} - {% field_flex "Planning service organization" item.town_planning_service.full_address %} - {% else %} - {% field_flex "Planning service organization" item.responsible_town_planning_service.attached_to.full_address %} - {% endif %} - - {% field_flex "Permit type" item.permit_type %} - {% field_flex "Permit reference" item.permit_reference %} - {% field_flex "Date of planning service file" item.planning_service_date|date:"DATE_FORMAT" %} - - {% field_flex "General contractor" item.general_contractor.full_address %} - {% if item.corporation_general_contractor %} - {% field_flex "General contractor organization" item.corporation_general_contractor.full_address %} - {% else%} - {% field_flex "General contractor organization" item.general_contractor.attached_to.full_address %} - {% endif %} +
+ {% else %} -
-{% else %} +

{% trans "Research archaeology"%}

+
+ {% field_flex_detail "Head scientist" item.scientist %} + {% field_flex "Requested operation type" item.requested_operation_type %} + {% field_flex_detail "Organization" item.organization %} -

{% trans "Research archaeology"%}

-
- {% field_flex_detail "Head scientist" item.scientist %} - {% field_flex "Requested operation type" item.requested_operation_type %} - {% field_flex_detail "Organization" item.organization %} + {% if item.cira_advised != None %} + {% field_flex "Passage en CIRA" item.cira_advised|yesno %} + {% endif %} - {% if item.cira_advised != None %} - {% field_flex "Passage en CIRA" item.cira_advised|yesno %} - {% endif %} + {% if item.mh_register != None %} + {% field_flex "Sur Monument Historique classé" item.mh_register|yesno %} + {% endif %} - {% if item.mh_register != None %} - {% field_flex "Sur Monument Historique classé" item.mh_register|yesno %} - {% endif %} + {% if item.mh_listing != None %} + {% field_flex "Sur Monument Historique inscrit" item.mh_listing|yesno %} + {% endif %} - {% if item.mh_listing != None %} - {% field_flex "Sur Monument Historique inscrit" item.mh_listing|yesno %} - {% endif %} + {% if item.classified_area != None %} + {% field_flex "Classified area" item.classified_area|yesno %} + {% endif %} - {% if item.classified_area != None %} - {% field_flex "Classified area" item.classified_area|yesno %} - {% endif %} + {% if item.protected_area != None %} + {% field_flex "Protected area" item.protected_area|yesno %} + {% endif %} - {% if item.protected_area != None %} - {% field_flex "Protected area" item.protected_area|yesno %} - {% endif %} + {% field_flex_full "Comment" item.research_comment "
" "
" %} +
- {% field_flex_full "Comment" item.research_comment "
" "
" %} + {% endif %} + + {% if not next %} + + {% trans "Associated parcels" as parcels_label %} + {% include "ishtar/blocks/window_tables/parcels.html" %} + + {% trans "Administrative acts" as administrativeacts_label %} + {% table_administrativact administrativeacts_label item.administrative_act.all %} + +

{%trans "Associated operations"%}

+ + + + + + + + + + + {% for operation in item.operations.all %} + + + + + + + + + + {% empty %} + + {% endfor %} +
{% trans "Ref." %}Code Patriarche{% trans "Type" %}{% trans "In charge" %}{% trans "Start date" %}{% trans "Excavation end date" %} 
{{operation.year_index}}{{operation.full_code_patriarche|default:""}}{{operation.operation_type}}{{operation.in_charge|default:""}}{{operation.start_date|default:""}}{{operation.excavation_end_date|default:""}}
{% trans "No operation associated to this archaeological file" %}
+ +

{%trans "Admninistrative acts linked to associated operations"%}

+ + + + + + + + {% for act in item.operation_acts %} + + + + + + + {% empty %} + + {% endfor %} +
{% trans "Year" %}{% trans "Ref." %}{% trans "Type" %}{% trans "Date" %}
{{act.signature_date.year}}{{act.ref_sra}}{{act.act_type}}{{act.signature_date}}
{% trans "No administrative act linked to operations" %}
+ + {% endif %} + + {% trans "Document for this archaeological file" as fle_docs %} + {% if permission_view_own_document or permission_view_document %} + {% if item.documents.count %} + {% dynamic_table_document fle_docs 'documents' 'files' item.pk '' output %} + {% endif %} + {% endif %} + +
{% if has_costs %} +
+
+ {% field_flex "Start date" item.start_date|date:"DATE_FORMAT" %} + {% field_flex "End date" item.end_date|date:"DATE_FORMAT" %} + {% field_flex "Ground start date" item.ground_start_date|date:"DATE_FORMAT" %} + {% field_flex "Ground end date" item.ground_end_date|date:"DATE_FORMAT" %} + {% field_flex "Study period" item.study_period %} + {% field_flex "Execution report date" item.execution_report_date|date:"DATE_FORMAT" %} +
+
+ {% if item.total_developed_surface %} +
+
{%trans "Total developed surface"%}
+
+ {{ item.total_developed_surface }} m2 ({{ item.total_developed_surface_ha }} ha) +
+
+ {% endif %} + {% if item.total_surface %} +
+
{% trans "Surface" %}
+
+ {{ item.total_surface }} m2 ({{ item.total_surface_ha }} ha) +
+
+ {% endif %} +
+

{% trans "Human and technical requirements" %}

+ {% if item.ground_jobs.count %} +
+

{% trans "Ground jobs" %}

+ + + + + + + + + + + + + + + + + + {% for job in item.ground_jobs.all %} + + + + + + + + + + {% endfor %} + + + + + + + + + + + + +
{% trans "Job" %}{% trans "Planned" %}{% trans "Effective" %}
 {% trans "Man by day" %}{% trans "Days" %}{% trans "Cost" %}{% trans "Man by day" %}{% trans "Days" %}{% trans "Cost" %}
{{job.job}}{{job.man_by_day_planned|default:"-"}}{{job.days_planned|default:"-"}}{{job.cost_planned|default:"-"|floatformat:2}}{{job.man_by_day_worked|default:"-"}}{{job.days_worked|default:"-"}}{{job.cost_worked|default:"-"|floatformat:2}}
{% trans "Total" %}  + {{item.ground_job_cost_planned|default:"-"|floatformat:2}} +   + {{item.ground_job_cost_worked|default:"-"|floatformat:2}} +
{% trans "Difference" %}  + {{item.ground_job_cost_diff_planned_worked|default:"-"|floatformat:2}} +
+
+ {% endif %} + {% if item.jobs.count %} +
+

{% trans "Post-excavation jobs" %}

+ + + + + + + + + + + + + + + + + + {% for job in item.jobs.all %} + + + + + + + + + + {% endfor %} + + + + + + + + + + + + +
{% trans "Job" %}{% trans "Planned" %}{% trans "Effective" %}
 {% trans "Man by day" %}{% trans "Days" %}{% trans "Cost" %}{% trans "Man by day" %}{% trans "Days" %}{% trans "Cost" %}
{{job.job}}{{job.man_by_day_planned|default:"-"}}{{job.days_planned|default:"-"}}{{job.cost_planned|default:"-"|floatformat:2}}{{job.man_by_day_worked|default:"-"}}{{job.days_worked|default:"-"}}{{job.cost_worked|default:"-"|floatformat:2}}
{% trans "Total" %}  + {{item.job_cost_planned|default:"-"|floatformat:2}} +   + {{item.job_cost_worked|default:"-"|floatformat:2}} +
{% trans "Difference" %}  + {{item.job_cost_diff_planned_worked|default:"-"|floatformat:2}} +
+
+ {% endif %} + {% for service_type, cost_planned, cost_worked, diff, equipments in item.used_equipments %} +
+

{{service_type}}

+ + + + + + + + + + + + + + + + + + {% for equipment in equipments %} + {% if equipment.cost_planned or equipment.cost_worked %} + + + + + + + + + + + + {% endif %} + {% endfor %} + + + + + + + + + + + + +
{% trans "Equipment / service" %}{% trans "Planned" %}{% trans "Effective" %}
 {% trans "Quantity" %} {% trans "Cost" %}{% trans "Quantity" %} {% trans "Cost" %}
{{equipment.equipment_service_cost.equipment_service_type.label}}{{equipment.quantity_by_day_planned|default:"-"}}{{equipment.days_planned|default:"-"}}{{equipment.equipment_service_cost.unit_label}}{{equipment.cost_planned|default:"-"|floatformat:2}}{{equipment.quantity_by_day_worked|default:"-"}}{{equipment.days_worked|default:"-"}}{{equipment.equipment_service_cost.unit_label}}{{equipment.cost_worked|default:"-"|floatformat:2}}
{% trans "Total" %} {{cost_planned|default:"-"|floatformat:2}} {{cost_worked|default:"-"|floatformat:2}}
{% trans "Difference" %}  + {{diff|default:"-"|floatformat:2}} +
+
+ {% endfor %} +
{% endif %}
-{% endif %} - -{% if not next %} - -{% trans "Associated parcels" as parcels_label %} -{% include "ishtar/blocks/window_tables/parcels.html" %} - -{% trans "Administrative acts" as administrativeacts_label %} -{% table_administrativact administrativeacts_label item.administrative_act.all %} - -

{%trans "Associated operations"%}

- - - - - - - - - - - {% for operation in item.operations.all %} - - - - - - - - - - {% empty %} - - {% endfor %} -
{% trans "Ref." %}Code Patriarche{% trans "Type" %}{% trans "In charge" %}{% trans "Start date" %}{% trans "Excavation end date" %} 
{{operation.year_index}}{{operation.full_code_patriarche|default:""}}{{operation.operation_type}}{{operation.in_charge|default:""}}{{operation.start_date|default:""}}{{operation.excavation_end_date|default:""}}
{% trans "No operation associated to this archaeological file" %}
- -

{%trans "Admninistrative acts linked to associated operations"%}

- - - - - - - - {% for act in item.operation_acts %} - - - - - - - {% empty %} - - {% endfor %} -
{% trans "Year" %}{% trans "Ref." %}{% trans "Type" %}{% trans "Date" %}
{{act.signature_date.year}}{{act.ref_sra}}{{act.act_type}}{{act.signature_date}}
{% trans "No administrative act linked to operations" %}
- -{% endif %} - -{% trans "Document for this archaeological file" as fle_docs %} -{% if permission_view_own_document or permission_view_document %} -{% if item.documents.count %} -{% dynamic_table_document fle_docs 'documents' 'files' item.pk '' output %} -{% endif %} -{% endif %} - - -{% endwith %} {% endwith %} {% endwith %} +{% endwith %} {% endwith %} {% endwith %}{% endwith %} {% endblock %} diff --git a/ishtar_common/migrations/0216_auto_20210805_1703.py b/ishtar_common/migrations/0216_auto_20210805_1703.py new file mode 100644 index 000000000..40e0dd0f2 --- /dev/null +++ b/ishtar_common/migrations/0216_auto_20210805_1703.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.28 on 2021-08-05 17:03 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ishtar_common', '0215_ishtarsiteprofile_parent_relations_engine'), + ] + + operations = [ + migrations.AddField( + model_name='ishtarsiteprofile', + name='preventive_operator', + field=models.BooleanField(default=False, verbose_name='Preventive operator module'), + ), + migrations.AlterField( + model_name='formatertype', + name='formater_type', + field=models.CharField(choices=[('IntegerFormater', 'Integer'), ('FloatFormater', 'Float'), ('UnicodeFormater', 'String'), ('DateFormater', 'Date'), ('TypeFormater', 'Type'), ('YearFormater', 'Year'), ('InseeFormater', 'INSEE code'), ('UpperFormater', 'Upper case'), ('LowerFormater', 'Lower case'), ('StrToBoolean', 'String to boolean'), ('FileFormater', 'File'), ('UnknowType', 'Unknow type')], max_length=20, verbose_name='Formater type'), + ), + ] diff --git a/ishtar_common/models.py b/ishtar_common/models.py index e0b22a4f0..6007cadef 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -1093,6 +1093,8 @@ class IshtarSiteProfile(models.Model, Cached): _("Use town to locate when coordinates are missing"), default=True ) relation_graph = models.BooleanField(_("Generate relation graph"), default=False) + preventive_operator = models.BooleanField(_("Preventive operator module"), + default=False) underwater = models.BooleanField(_("Underwater module"), default=False) parcel_mandatory = models.BooleanField( _("Parcel are mandatory for context records"), default=True -- cgit v1.2.3