View file File name : layout-listing.html.twig Content :{% extends 'base.html.twig' %} {% import "macros/widgets.html.twig" as widgets %} {% import "macros/datatables.html.twig" as tables %} {% import "macros/search.html.twig" as search %} {% if not showSummary is defined %} {% set showSummary = false %} {% endif %} {% if not showStartEndTime is defined %} {% set showStartEndTime = true %} {% endif %} {% set columns = { 'id': {'class': 'alwaysVisible multiCheckbox', 'orderBy': false, 'title': false, 'html_before': tables.datatable_multiupdate_all()}, 'date': {'class': 'alwaysVisible', 'orderBy': 'begin'}, } %} {% if showStartEndTime %} {% set columns = columns|merge({ 'starttime': {'class': 'hidden-xs text-center', 'orderBy': 'begin'}, 'endtime': {'class': 'hidden-xs text-center', 'orderBy': 'end'} }) %} {% endif %} {% set columns = columns|merge({'duration': {'class': 'text-right'}}) %} {% if canSeeRate %} {% set columns = columns|merge({'rate': {'class': 'text-right'}}) %} {% endif %} {% set columns = columns|merge({ 'customer': {'class': 'hidden-xs hidden-sm hidden-md'}, 'project': {'class': 'hidden-xs hidden-sm hidden-md'}, 'activity': {'class': 'hidden-xs hidden-sm'}, 'description': {'class': 'hidden-xs hidden-sm'}, 'tags': {'class': 'hidden-xs hidden-sm', 'orderBy': false}, }) %} {% for field in metaColumns %} {% set columns = columns|merge({ ('mf_' ~ field.name): {'title': field.label|trans, 'class': 'hidden-xs hidden-sm', 'orderBy': false} }) %} {% endfor %} {% if canSeeUsername %} {% set columns = columns|merge({ 'username': {'class': 'hidden-xs', 'orderBy': false}, }) %} {% endif %} {% set columns = columns|merge({ 'billable': {'class': 'text-center hidden w-min', 'orderBy': false}, 'exported': {'class': 'text-center hidden w-min', 'orderBy': false}, 'actions': {'class': 'actions alwaysVisible'}, }) %} {% block page_search %}{{ search.searchModal(toolbarForm) }}{% endblock %} {% block main_before %} {{ tables.data_table_column_modal(tableName, columns) }} {% endblock %} {% block main %} {% if entries.count == 0 %} {{ widgets.nothing_found('kimai.timesheetUpdate') }} {% else %} {{ tables.datatable_header(tableName, columns, query, {'reload': 'kimai.timesheetUpdate kimai.timesheetDelete'}) }} {% set checkOverlappingDesc = false %} {% set checkOverlappingAsc = false %} {% if query.orderBy == 'begin' or query.orderBy == 'end' %} {% set checkOverlappingDesc = (query.order == 'DESC') %} {% set checkOverlappingAsc = not checkOverlappingDesc %} {% endif %} {% set day = null %} {% set dayDuration = 0 %} {% set dayRate = {} %} {% set lastEntry = null %} {% for entry in entries %} {%- set customerCurrency = entry.project.customer.currency -%} {%- if day is same as(null) -%} {% set day = entry.begin|date_short %} {% endif %} {%- if showSummary and day is not same as(entry.begin|date_short) -%} {{ _self.summary(day, dayDuration, dayRate, columns, canSeeRate, canSeeUsername, showStartEndTime, tableName, metaColumns) }} {% set day = entry.begin|date_short %} {% set dayDuration = 0 %} {% set dayRate = {} %} {%- endif -%} {% set class = '' %} {% if checkOverlappingDesc or checkOverlappingAsc %} {% if lastEntry is not null and entry.end is not null and entry.user is same as (lastEntry.user) %} {% if checkOverlappingDesc and entry.end.timestamp > lastEntry.begin.timestamp %} {% set class = class ~ ' overlapping' %} {% elseif checkOverlappingAsc and entry.begin.timestamp < lastEntry.end.timestamp %} {% set class = class ~ ' overlapping' %} {% endif %} {% endif %} {% endif %} {% if not entry.end %} {% set class = class ~ ' recording' %} {% endif %} <tr{% if is_granted('edit', entry) %} class="modal-ajax-form open-edit{{ class }}" data-href="{{ path(editRoute, {'id': entry.id}) }}"{% endif %}> <td class="text-nowrap"> {% if is_granted('edit', entry) or is_granted('delete', entry) %} {{ tables.datatable_multiupdate_row(entry.id) }} {% endif %} </td> <td class="text-nowrap {{ tables.data_table_column_class(tableName, columns, 'date') }}">{{ entry.begin|date_short }}</td> {% if showStartEndTime %} <td class="text-nowrap {{ tables.data_table_column_class(tableName, columns, 'starttime') }}">{{ entry.begin|time }}</td> <td class="text-nowrap {{ tables.data_table_column_class(tableName, columns, 'endtime') }}"> {% if entry.end %} {{ entry.end|time }} {% else %} ‐ {% endif %} </td> {% endif %} {% if entry.end %} <td class="text-nowrap {{ tables.data_table_column_class(tableName, columns, 'duration') }}">{{ entry.duration|duration }}</td> {% else %} <td class="text-nowrap {{ tables.data_table_column_class(tableName, columns, 'duration') }}"> <i data-since="{{ entry.begin.format(constant('DATE_ISO8601')) }}">{{ entry|duration }}</i> </td> {% endif %} {% if canSeeRate %} <td class="text-nowrap {{ tables.data_table_column_class(tableName, columns, 'rate') }}"> {% if not entry.end or not is_granted('view_rate', entry) %} ‐ {% else %} {{ entry.rate|money(entry.project.customer.currency) }} {% endif %} </td> {% endif %} <td class="{{ tables.data_table_column_class(tableName, columns, 'customer') }}"> {{ widgets.label_customer(entry.project.customer) }} </td> <td class="{{ tables.data_table_column_class(tableName, columns, 'project') }}"> {{ widgets.label_project(entry.project) }} </td> <td class="{{ tables.data_table_column_class(tableName, columns, 'activity') }}"> {{ widgets.label_activity(entry.activity) }} </td> <td class="{{ tables.data_table_column_class(tableName, columns, 'description') }} timesheet-description"> {% if allowMarkdown %} {{ entry.description|desc2html }} {% else %} {{ entry.description|nl2br }} {% endif %} </td> <td class="{{ tables.data_table_column_class(tableName, columns, 'tags') }}">{{ widgets.tag_list(entry.tags) }}</td> {% for field in metaColumns %} <td class="text-nowrap {{ tables.data_table_column_class(tableName, columns, 'mf_' ~ field.name) }}"> {{ tables.datatable_meta_column(entry, field) }} </td> {% endfor %} {% if canSeeUsername %} <td class="{{ tables.data_table_column_class(tableName, columns, 'username') }}"> {{ widgets.label_user(entry.user) }} </td> {% endif %} <td class="{{ tables.data_table_column_class(tableName, columns, 'billable') }}"> {{ widgets.label_boolean(entry.billable) }} </td> <td class="{{ tables.data_table_column_class(tableName, columns, 'exported') }}"> {{ widgets.label_boolean(entry.exported) }} </td> <td class="actions"> {{ block('row_action') }} </td> </tr> {%- if entry.end -%} {% if dayRate[customerCurrency] is not defined %} {% set dayRate = dayRate|merge({(customerCurrency): 0}) %} {% endif %} {% set dayRate = dayRate|merge({(customerCurrency): dayRate[customerCurrency] + entry.rate}) %} {%- endif -%} {%- set dayDuration = dayDuration + entry.duration -%} {% set lastEntry = entry %} {% endfor %} {% if showSummary %} {{ _self.summary(day, dayDuration, dayRate, columns, canSeeRate, canSeeUsername, showStartEndTime, tableName, metaColumns) }} {% endif %} {{ tables.data_table_footer(entries, paginationRoute, multiUpdateForm) }} {% endif %} {% endblock %} {% macro summary(day, duration, dayRates, columns, canSeeRate, canSeeUsername, showStartEndTime, tableName, metaColumns) %} {% import "macros/datatables.html.twig" as tables %} <tr class="summary info"> <td></td> <td class="text-nowrap">{{ day }}</td> {% if showStartEndTime %} <td class="{{ tables.data_table_column_class(tableName, columns, 'starttime') }}"></td> <td class="{{ tables.data_table_column_class(tableName, columns, 'endtime') }}"></td> {% endif %} <td class="text-nowrap {{ tables.data_table_column_class(tableName, columns, 'duration') }}">{{ duration|duration }}</td> {% if canSeeRate %} <td class="text-nowrap {{ tables.data_table_column_class(tableName, columns, 'rate') }}"> {% for currency, rate in dayRates %} {{ rate|money(currency) }} {% if not loop.last %} <br> {% endif %} {% endfor %} </td> {% endif %} <td class="{{ tables.data_table_column_class(tableName, columns, 'customer') }}"></td> <td class="{{ tables.data_table_column_class(tableName, columns, 'project') }}"></td> <td class="{{ tables.data_table_column_class(tableName, columns, 'activity') }}"></td> <td class="{{ tables.data_table_column_class(tableName, columns, 'description') }}"></td> <td class="{{ tables.data_table_column_class(tableName, columns, 'tags') }}"></td> {% for field in metaColumns %} <td class="{{ tables.data_table_column_class(tableName, columns, 'mf_' ~ field.name) }}"></td> {% endfor %} {% if canSeeUsername %} <td class="{{ tables.data_table_column_class(tableName, columns, 'username') }}"></td> {% endif %} <td class="{{ tables.data_table_column_class(tableName, columns, 'billable') }}"></td> <td class="{{ tables.data_table_column_class(tableName, columns, 'exported') }}"></td> <td class="actions"></td> </tr> {% endmacro %}