{% extends 'reporting/layout.html.twig' %} {% import "macros/charts.html.twig" as charts %} {% import "macros/widgets.html.twig" as widgets %} {% set tableName = tableName|default('project_details_reporting') %} {% set tableId = 'project-details-form' %} {% set showMoneyBudget = project_details is not null and is_granted('budget', project_details.project) %} {% set showTimeBudget = project_details is not null and is_granted('time', project_details.project) %} {% set view_revenue = project_details is not null and is_granted('view_rate_other_timesheet') %} {% set see_users = is_granted('view_other_timesheet') or is_granted('view_other_reporting') %} {% block stylesheets %} {{ parent() }} {{ encore_entry_link_tags('chart') }} {% endblock %} {% block head %} {{ parent() }} {{ encore_entry_script_tags('chart') }} {% endblock %} {% block javascripts %} {{ parent() }} {% set options = {'label': 'duration', 'title': 'name', 'legend': {'display': false}} %} {% if view_revenue %} {% set options = options|merge({'footer': 'rate'}) %} {% endif %} {{ charts.doughnut_javascript(options) }} {{ charts.bar_javascript({'legend': {'display': false}}) }} {% endblock %} {% block report_form_layout %} {{ form_widget(form.project, {'label': false, 'placeholder': 'please_choose'}) }} {% endblock %} {% block report %} {% set hasData = project is not null and project_view is not null %} {% if not hasData %} {{ widgets.nothing_found() }} {% else %} {{ _self.project_details(project, project_view, project_details, showMoneyBudget, showTimeBudget, view_revenue, see_users) }} {% set currency = project.customer.currency %} {%- for yearStat in project_details.years|reverse %} {% set year = yearStat.year %} {{ _self.duration_stat(year, year, year, month_names(), yearStat, project_details.getYearActivities(year), project_details.userYears(year), currency, view_revenue, see_users) }} {% endfor %} {% endif %} {% endblock %} {% macro duration_stat(id, title, year, labels, yearStat, activities, users, currency, view_revenue, see_users) %} {% set rates = [] %} {% set durations = [] %} {% set chartPrefix = 'chart' ~ id %} {% for monthNumber in 1..12 %} {% set rate = 0 %} {% set duration = 0 %} {% set month = yearStat.month(monthNumber) %} {% if month is not null %} {% set rate = month.totalRate %} {% set duration = month.totalDuration %} {% endif %} {% set durations = durations|merge([{'label': duration|duration, 'value': duration|chart_duration}]) %} {% set rates = rates|merge([{'label': rate|money(currency), 'value': rate}]) %} {% endfor -%}

{{ title }}

{{ widgets.badge_counter(yearStat.duration|duration) }} {% if view_revenue %} {{ widgets.badge_counter(yearStat.rate|money(currency)) }} {% endif %}
{{ charts.bar_chart(chartPrefix ~ 'Duration', labels, [durations], {'height': '300px'}) }}
{% if view_revenue %}
{{ charts.bar_chart(chartPrefix ~ 'Rate', labels, [rates], {'height': '300px', 'renderEvent': 'render.' ~ chartPrefix ~ 'Rate'}) }}
{% endif %}
{{ _self.activity_tab(activities, yearStat.duration, currency, chartPrefix, view_revenue) }}
{% if see_users %}
{{ _self.user_tab(year, users) }}
{% endif %}
{% endmacro %} {% macro user_tab(year, userYearStats) %}
{% for monthName in month_names() %} {% endfor %} {% set yearTotal = 0 %} {% for userYearStat in userYearStats|sort((a, b) => b.duration <=> a.duration) %} {% set user = userYearStat.user %} {% set userYear = userYearStat.year %} {% set userTotal = userYearStat.duration %} {% set yearTotal = yearTotal + userTotal %} {% for monthNumber in 1..12 %} {% set month = userYear.getMonth(monthNumber) %} {% endfor %} {% endfor %} {% for monthNumber in 1..12 %} {% set total = 0 %} {% for userYearStat in userYearStats %} {% set month = userYearStat.year.getMonth(monthNumber) %} {% if month is not null %} {% set total = total + month.duration %} {% endif %} {% endfor %} {% endfor %}
{{ 'username'|trans }} {{ monthName }}
{{ widgets.label_dot(user.displayName, user.color) }} {{ userTotal|duration }} {% if month is not null %} {{ month.totalDuration|duration }} {% endif %}
{{ yearTotal|duration }} {{ total|duration }}
{% endmacro %} {# activities = array totalDuration = int currency = string chartPrefix = string view_revenue = boolean #} {% macro activity_tab(activities, totalDuration, currency, chartPrefix, view_revenue) %} {% set dataset = [] %} {% set labels = [] %}
{% if view_revenue %} {% endif %} {% set totalRate = 0.0 %} {% set billable = 0 %} {% for stat in activities|sort((a, b) => b.duration <=> a.duration) %} {% set rate = stat.rate %} {% set totalRate = totalRate + rate %} {% set billable = billable + stat.rateBillable %} {% set dataset = dataset|merge([{'value': stat.duration, 'name': stat.name, 'color': stat.activity.color|colorize(stat.activity.name), 'duration': stat.duration|duration, 'rate': rate|money(currency)}]) %} {% set percentage = 0 %} {% if totalDuration > 0 and stat.duration > 0 %} {% set percentage = (100 / (totalDuration / stat.duration)) %} {% endif %} {% if view_revenue %} {% endif %} {% endfor %} {% if view_revenue %} {% endif %}
{{ 'duration'|trans }}{{ 'billable'|trans }} {{ 'stats.amountTotal'|trans }}
{{ widgets.label_activity(stat.activity, {'inherit': false, 'random': true}) }} {{ stat.duration|duration }}{{ stat.rateBillable|money(currency) }} {{ stat.rate|money(currency) }}{{ percentage|number_format(1) }} %
{{ totalDuration|duration }}{{ billable|money(currency) }} {{ totalRate|money(currency) }}
{% set chartOptions = {'height': (dataset|length > 12 ? '600px' : '300px'), 'renderEvent': 'render.' ~ chartPrefix ~ 'Activity'} %} {{ charts.doughnut_chart(chartPrefix ~ 'Activity', labels, dataset, chartOptions) }}
{% endmacro %} {# project = Project project_view = ProjectViewModel project_details = ProjectDetailsModel #} {% macro project_details(project, project_view, project_details, showMoneyBudget, showTimeBudget, view_revenue, see_users) %} {% set activities = project_details.activities %} {% set years = project_details.years %} {% import "macros/progressbar.html.twig" as progress %} {% import "macros/widgets.html.twig" as widgets %} {% import "macros/charts.html.twig" as charts %} {% set currency = project.customer.currency %} {% set chartPrefix = 'project' ~ project.id %} {%- set labels = [] %} {% set rates = [] %} {% set durations = [] %} {% for year in years %} {% set labels = labels|merge([year.year]) %} {% set rates = rates|merge([{'label': year.rate|money(currency), 'value': year.rate}]) %} {% set durations = durations|merge([{'label': year.duration|duration, 'value': year.duration|chart_duration}]) %} {% endfor -%} {% set showTotalDurationChart = project_view.durationTotal > 0 and years|length > 1 %} {% set showTotalRevenueChart = view_revenue and project_view.rateTotal > 0 and years|length > 1 %}

{{ widgets.label_project(project, {'inherit': false}) }}

{{ widgets.badge_counter(project_view.durationTotal|duration) }} {% if view_revenue %} {{ widgets.badge_counter(project_view.rateTotal|money(currency)) }} {% endif %}
{{ 'customer'|trans }}
{{ widgets.label_customer(project.customer) }}
{{ 'project'|trans }}
{{ widgets.label_project(project) }}
{{ 'stats.durationTotal'|trans }}
{{ project_view.durationTotal|duration }}
{% if view_revenue %}
{{ 'stats.amountTotal'|trans }}
{{ project_view.rateTotal|money(currency) }}
{{ 'billable'|trans }}
{{ project_view.billableRate|money(currency) }}
{% endif %}
{{ 'last_record'|trans }}
{% if project_view.lastRecord is not null %} {{ project_view.lastRecord|date_short }} {% else %} – {% endif %}
{% if is_granted('create_export') %} {% endif %} {% if is_granted('view_invoice') %} {% endif %}
{% if (showMoneyBudget and project.hasBudget()) or (showTimeBudget and project.hasTimeBudget()) %} {% from "project/charts.html.twig" import project_budget %} {{ project_budget(project, project_details, chartPrefix) }} {% endif %}
{% if (showMoneyBudget and project.hasBudget()) or (showTimeBudget and project.hasTimeBudget()) %} {% set budgetStats = project_details.budgetStatisticModel %}
{% if showTimeBudget and project.hasTimeBudget() %} {% endif %} {% if showMoneyBudget and project.hasBudget() %} {% endif %}
{{ 'timeBudget'|trans }} {% if budgetStats.isMonthlyBudget() %} ({{ 'budgetType_month'|trans }}) {% endif %} {{ progress.progressbar_timebudget(budgetStats) }}
{{ 'budget'|trans }} {% if budgetStats.isMonthlyBudget() %} ({{ 'budgetType_month'|trans }}) {% endif %} {{ progress.progressbar_budget(budgetStats, project.customer.currency) }}
{% endif %}
{% if showTotalDurationChart %}
{{ charts.bar_chart(chartPrefix ~ 'Duration', labels, [durations], {'height': '300px', 'renderEvent': 'render.' ~ chartPrefix ~ 'Duration'}) }}
{% if showTotalRevenueChart %}
{{ charts.bar_chart(chartPrefix ~ 'Rate', labels, [rates], {'height': '300px', 'renderEvent': 'render.' ~ chartPrefix ~ 'Rate'}) }}
{% endif %} {% endif %} {% if activities is not empty %}
{{ _self.activity_tab(activities, project_view.durationTotal, project.customer.currency, chartPrefix, view_revenue) }}
{% endif %} {% if see_users and project_details.userStats|length > 0 %}
{% if view_revenue %} {% endif %} {% set rateTotal = 0 %} {% set rateTotalBillable = 0 %} {% set totalDuration = 0 %} {% set datasets = [] %} {% set labels = [] %} {% for userStat in project_details.userStats|sort((a, b) => b.duration <=> a.duration) %} {% set user = userStat.user %} {% set color = user.color|colorize(user.displayName) %} {% set rateTotal = rateTotal + userStat.rate %} {% set rateTotalBillable = rateTotalBillable + userStat.rateBillable %} {% set totalDuration = totalDuration + userStat.duration %} {% set datasets = datasets|merge([{'name': user.displayName, 'duration': userStat.duration|duration, 'value': userStat.duration, 'color': color, 'rate': userStat.rate|money(currency)}]) %} {% set percentage = 0 %} {% if project_view.durationTotal > 0 and userStat.duration > 0 %} {% set percentage = (100 / (project_view.durationTotal / userStat.duration)) %} {% endif %} {% if view_revenue %} {% endif %} {% endfor %} {% if view_revenue %} {% endif %}
{{ 'duration'|trans }}{{ 'billable'|trans }} {{ 'stats.amountTotal'|trans }}
{{ widgets.label_dot(user.displayName, user.color) }} {{ userStat.duration|duration }} {{ userStat.rateBillable|money(currency) }} {{ userStat.rate|money(currency) }} {{ percentage|number_format(1) }} %
{{ totalDuration|duration }}{{ rateTotalBillable|money(currency) }} {{ rateTotal|money(currency) }}
{% set chartOptions = {'height': (datasets|length > 12 ? '600px' : '300px'), 'renderEvent': 'render.' ~ chartPrefix ~ 'User'} %} {{ charts.doughnut_chart(chartPrefix ~ 'User', labels, datasets, chartOptions) }}
{% endif %}
{% endmacro %}