diff --git a/app/Service/LocalizationService.php b/app/Service/LocalizationService.php index b2269812..a03d1b7d 100644 --- a/app/Service/LocalizationService.php +++ b/app/Service/LocalizationService.php @@ -96,6 +96,30 @@ class LocalizationService } } + /** + * Format a duration for reporting contexts (PDF reports, places that display duration + * directly next to cost). Promotes the verbose `Hh Mm` format to the compact `HH:MM:SS` + * so totals stay narrow and reconcile with cost, which is always computed to the second. + */ + public function formatIntervalForReporting(CarbonInterval $interval): string + { + $promoted = [ + IntervalFormat::HoursMinutes, + IntervalFormat::HoursMinutesColonSeparated, + ]; + if (! in_array($this->intervalFormat, $promoted, true)) { + return $this->formatInterval($interval); + } + + $previous = $this->intervalFormat; + $this->intervalFormat = IntervalFormat::HoursMinutesSecondsColonSeparated; + try { + return $this->formatInterval($interval); + } finally { + $this->intervalFormat = $previous; + } + } + public function formatCurrency(Money $money): string { $currencyService = app(CurrencyService::class); diff --git a/resources/js/Components/Common/Reporting/ReportingChart.vue b/resources/js/Components/Common/Reporting/ReportingChart.vue index 8db1567d..e1ff6d66 100644 --- a/resources/js/Components/Common/Reporting/ReportingChart.vue +++ b/resources/js/Components/Common/Reporting/ReportingChart.vue @@ -2,7 +2,7 @@ import VChart, { THEME_KEY } from 'vue-echarts'; import { computed, provide, inject, shallowRef, type ComputedRef } from 'vue'; import LinearGradient from 'zrender/lib/graphic/LinearGradient'; -import { formatDate, formatHumanReadableDuration, formatWeek } from '@/packages/ui/src/utils/time'; +import { formatDate, formatReportingDuration, formatWeek } from '@/packages/ui/src/utils/time'; import { use } from 'echarts/core'; import { CanvasRenderer } from 'echarts/renderers'; import { BarChart } from 'echarts/charts'; @@ -137,7 +137,7 @@ const option = computed(() => ({ type: 'bar', tooltip: { valueFormatter: (value: number) => { - return formatHumanReadableDuration( + return formatReportingDuration( value, organization?.value?.interval_format, organization?.value?.number_format diff --git a/resources/js/Components/Common/Reporting/ReportingOverview.vue b/resources/js/Components/Common/Reporting/ReportingOverview.vue index a561621b..3ec124bf 100644 --- a/resources/js/Components/Common/Reporting/ReportingOverview.vue +++ b/resources/js/Components/Common/Reporting/ReportingOverview.vue @@ -8,7 +8,7 @@ import { import { SaveIcon } from 'lucide-vue-next'; import { getOrganizationCurrencyString } from '@/utils/money'; import { - formatHumanReadableDuration, + formatReportingDuration, getDayJsInstance, getLocalizedDayJs, } from '@/packages/ui/src/utils/time'; @@ -426,7 +426,7 @@ const tableData = computed(() => { class="justify-end flex items-center font-medium" :class="!showBillableRate ? 'pr-6' : ''"> {{ - formatHumanReadableDuration( + formatReportingDuration( aggregatedTableTimeEntries.seconds, organization?.interval_format, organization?.number_format diff --git a/resources/js/Components/Common/Reporting/ReportingPieChart.vue b/resources/js/Components/Common/Reporting/ReportingPieChart.vue index 8cb78028..7e09238f 100644 --- a/resources/js/Components/Common/Reporting/ReportingPieChart.vue +++ b/resources/js/Components/Common/Reporting/ReportingPieChart.vue @@ -10,7 +10,7 @@ import { TitleComponent, TooltipComponent, } from 'echarts/components'; -import { formatHumanReadableDuration } from '@/packages/ui/src/utils/time'; +import { formatReportingDuration } from '@/packages/ui/src/utils/time'; import { useCssVariable } from '@/packages/ui/src'; import type { Organization } from '@/packages/api/src'; @@ -67,7 +67,7 @@ const option = computed(() => ({ }, tooltip: { valueFormatter: (value: number) => { - return formatHumanReadableDuration( + return formatReportingDuration( value, organization?.value?.interval_format, organization?.value?.number_format diff --git a/resources/js/Components/Common/Reporting/ReportingRow.vue b/resources/js/Components/Common/Reporting/ReportingRow.vue index 26b24b1c..cb339fe0 100644 --- a/resources/js/Components/Common/Reporting/ReportingRow.vue +++ b/resources/js/Components/Common/Reporting/ReportingRow.vue @@ -1,5 +1,5 @@