Release 2.0.2 (#3856)

* allow to overwrite global spreadsheet styles
* bump version
* fix deprecations in vcard download
* bump composer packages
* added help page for all registered locales
* fix menu id's, cleanup times route, fix configurable homepage redirect
* format duration without leading zero in hours (unify javascript with php behavior)
* fix active records in all screen sizes
* improved responsiveness in XS
* fixed invoice number for customer null fields
* fix javascript respects multiple recent-activity dropdowns
* show recent activities on small screens
* fix user-profile layout column in XS
* fix search is always marked as active
This commit is contained in:
Kevin Papst
2023-02-21 19:21:49 +01:00
committed by GitHub
parent e474087257
commit 25469113fd
61 changed files with 821 additions and 580 deletions

View File

@@ -23,6 +23,7 @@ use App\Repository\Query\TimesheetQuery;
use App\Twig\LocaleFormatExtensions;
use App\Utils\StringHelper;
use DateTime;
use PhpOffice\PhpSpreadsheet\Cell\CellAddress;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
@@ -37,7 +38,7 @@ use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @internal
* @internal means no BC promise whatsoever!
*/
abstract class AbstractSpreadsheetRenderer
{
@@ -50,12 +51,17 @@ abstract class AbstractSpreadsheetRenderer
// Part 1 = positive; Part 2 = negative; Part 3 = zero; Part 4 = Text
public const RATE_FORMAT_DEFAULT = '#.##0,00 [$%1$s];-#.##0,00 [$%1$s]';
public const RATE_FORMAT_LEFT = '_("%1$s"* #,##0.00_);_("%1$s"* -#,##0.00;_("%1$s"* "-"??_);_(@_)';
public const RATE_FORMAT = self::RATE_FORMAT_LEFT;
public const RATE_FORMAT_RIGHT = '_(* "%1$s" #,##0.00_);_(* "%1$s" -#,##0.00;_(* "%1$s" "-"??_);_(@_)';
/**
* @internal used in html to excel exporter
*/
public const RATE_FORMAT_NO_CURRENCY = '#,##0.00;-#,##0.00';
/**
* @see self:RATE_FORMAT_*
*/
protected string $rateFormat = self::RATE_FORMAT_LEFT;
protected string $durationFormat = self::DURATION_FORMAT;
protected int $durationBase = 86400;
/**
@@ -117,10 +123,10 @@ abstract class AbstractSpreadsheetRenderer
return $this->voter->isGranted('view_rate_other_timesheet');
}
protected function setFormattedDateTime(Worksheet $sheet, $column, $row, ?DateTime $date): void
protected function setFormattedDateTime(Worksheet $sheet, int $column, int $row, ?DateTime $date): void
{
if (null === $date) {
$sheet->setCellValueByColumnAndRow($column, $row, '');
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), '');
return;
}
@@ -128,20 +134,20 @@ abstract class AbstractSpreadsheetRenderer
$excelDate = Date::PHPToExcel($date);
if ($excelDate === false) {
$sheet->setCellValueByColumnAndRow($column, $row, $date);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $date);
return;
}
$sheet->setCellValueByColumnAndRow($column, $row, $excelDate);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $excelDate);
// TODO why is that format hardcoded and does not depend on the users locale?
$sheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(self::DATETIME_FORMAT);
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode(self::DATETIME_FORMAT);
}
protected function setFormattedTime(Worksheet $sheet, $column, $row, ?DateTime $date): void
protected function setFormattedTime(Worksheet $sheet, int $column, int $row, ?DateTime $date): void
{
if (null === $date) {
$sheet->setCellValueByColumnAndRow($column, $row, '');
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), '');
return;
}
@@ -149,19 +155,19 @@ abstract class AbstractSpreadsheetRenderer
$excelDate = Date::PHPToExcel($date);
if ($excelDate === false) {
$sheet->setCellValueByColumnAndRow($column, $row, $date);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $date);
return;
}
$sheet->setCellValueByColumnAndRow($column, $row, $excelDate);
$sheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(self::TIME_FORMAT);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $excelDate);
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode(self::TIME_FORMAT);
}
protected function setFormattedDate(Worksheet $sheet, $column, $row, ?DateTime $date): void
protected function setFormattedDate(Worksheet $sheet, int $column, int $row, ?DateTime $date): void
{
if (null === $date) {
$sheet->setCellValueByColumnAndRow($column, $row, '');
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), '');
return;
}
@@ -169,48 +175,48 @@ abstract class AbstractSpreadsheetRenderer
$excelDate = Date::PHPToExcel($date);
if ($excelDate === false) {
$sheet->setCellValueByColumnAndRow($column, $row, $date);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $date);
return;
}
$sheet->setCellValueByColumnAndRow($column, $row, $excelDate);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $excelDate);
// TODO why is that format hardcoded and does not depend on the users locale?
$sheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_YYYYMMDD2);
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_YYYYMMDD2);
}
protected function setDurationTotal(Worksheet $sheet, $column, $row, $startCoordinate, $endCoordinate): void
protected function setDurationTotal(Worksheet $sheet, int $column, int $row, string $startCoordinate, string $endCoordinate): void
{
$sheet->setCellValueByColumnAndRow($column, $row, sprintf('=SUBTOTAL(9,%s:%s)', $startCoordinate, $endCoordinate));
$style = $sheet->getStyleByColumnAndRow($column, $row);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), sprintf('=SUBTOTAL(9,%s:%s)', $startCoordinate, $endCoordinate));
$style = $sheet->getStyle(CellAddress::fromColumnAndRow($column, $row));
$style->getNumberFormat()->setFormatCode($this->durationFormat);
}
protected function setDuration(Worksheet $sheet, $column, $row, $duration): void
protected function setDuration(Worksheet $sheet, int $column, int $row, ?int $duration): void
{
if (null === $duration) {
$duration = 0;
}
$sheet->setCellValueByColumnAndRow($column, $row, sprintf('=%s/%s', $duration, $this->durationBase));
$sheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode($this->durationFormat);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), sprintf('=%s/%s', $duration, $this->durationBase));
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode($this->durationFormat);
}
protected function setRateTotal(Worksheet $sheet, $column, $row, $startCoordinate, $endCoordinate): void
protected function setRateTotal(Worksheet $sheet, int $column, int $row, string $startCoordinate, string $endCoordinate): void
{
$sheet->setCellValueByColumnAndRow($column, $row, sprintf('=SUBTOTAL(9,%s:%s)', $startCoordinate, $endCoordinate));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), sprintf('=SUBTOTAL(9,%s:%s)', $startCoordinate, $endCoordinate));
}
protected function setRateStyle(Worksheet $sheet, $column, $row, $rate, $currency): void
protected function setRateStyle(Worksheet $sheet, int $column, int $row, ?string $currency): void
{
$sheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(
sprintf(self::RATE_FORMAT_LEFT, $currency)
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode(
sprintf($this->rateFormat, $currency ?? '')
);
}
protected function setRate(Worksheet $sheet, $column, $row, $rate, $currency): void
protected function setRate(Worksheet $sheet, int $column, int $row, ?float $rate, ?string $currency): void
{
$sheet->setCellValueByColumnAndRow($column, $row, $rate);
$this->setRateStyle($sheet, $column, $row, $rate, $currency);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $rate ?? 0);
$this->setRateStyle($sheet, $column, $row, $currency);
}
/**
@@ -227,8 +233,8 @@ abstract class AbstractSpreadsheetRenderer
/**
* @param ExportableItem[] $exportItems
* @param TimesheetQuery $query
* @param array $columns
* @return array
* @param array<string, array<string, callable|int|float|false|null>> $columns
* @return array<string, array<string, callable|int|float|false|null>>
*/
protected function getColumns(array $exportItems, TimesheetQuery $query, array $columns): array
{
@@ -289,7 +295,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getUser()) {
$user = $entity->getUser()->getDisplayName();
}
$sheet->setCellValueByColumnAndRow($column, $row, $user);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $user);
};
}
@@ -300,12 +306,12 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getUser()) {
$username = $entity->getUser()->getUserIdentifier();
}
$sheet->setCellValueByColumnAndRow($column, $row, $username);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $username);
};
}
if (!isset($columns['username']['header'])) {
$columns['username']['header'] = function (Worksheet $sheet, $row, $column): int {
$sheet->setCellValueByColumnAndRow($column, $row, $this->translator->trans('name'));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $this->translator->trans('name'));
return 1;
};
@@ -318,7 +324,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getProject()) {
$customer = $entity->getProject()->getCustomer()->getName();
}
$sheet->setCellValueByColumnAndRow($column, $row, $customer);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $customer);
};
}
@@ -328,7 +334,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getProject()) {
$project = $entity->getProject()->getName();
}
$sheet->setCellValueByColumnAndRow($column, $row, $project);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $project);
};
}
@@ -338,7 +344,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getActivity()) {
$activity = $entity->getActivity()->getName();
}
$sheet->setCellValueByColumnAndRow($column, $row, $activity);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $activity);
};
}
@@ -352,7 +358,7 @@ abstract class AbstractSpreadsheetRenderer
$isColumnFormatted = false;
$columns['description']['render'] = function (Worksheet $sheet, int $row, int $column, ExportableItem $entity) use (&$isColumnFormatted, $maxWidth, $wrapText, $sanitizeText) {
$cell = $sheet->getCellByColumnAndRow($column, $row);
$cell = $sheet->getCell(CellAddress::fromColumnAndRow($column, $row));
$desc = $entity->getDescription();
if ($sanitizeText && null !== $desc) {
@@ -379,20 +385,20 @@ abstract class AbstractSpreadsheetRenderer
if (isset($columns['exported']) && !isset($columns['exported']['render'])) {
$columns['exported']['render'] = function (Worksheet $sheet, int $row, int $column, ExportableItem $entity) {
$exported = $entity->isExported() ? 'yes' : 'no';
$sheet->setCellValueByColumnAndRow($column, $row, $this->translator->trans($exported));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $this->translator->trans($exported));
};
}
if (isset($columns['billable']) && !isset($columns['billable']['render'])) {
$columns['billable']['render'] = function (Worksheet $sheet, int $row, int $column, ExportableItem $entity) {
$exported = $entity->isBillable() ? 'yes' : 'no';
$sheet->setCellValueByColumnAndRow($column, $row, $this->translator->trans($exported));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $this->translator->trans($exported));
};
}
if (isset($columns['tags']) && !isset($columns['tags']['render'])) {
$columns['tags']['render'] = function (Worksheet $sheet, int $row, int $column, ExportableItem $entity) {
$sheet->setCellValueByColumnAndRow($column, $row, implode(',', $entity->getTagsAsArray()));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), implode(',', $entity->getTagsAsArray()));
};
}
@@ -422,7 +428,7 @@ abstract class AbstractSpreadsheetRenderer
$columns['timesheet-meta'] = [
'header' => function (Worksheet $sheet, $row, $column) use ($timesheetMetaFields): int {
foreach ($timesheetMetaFields as $metaField) {
$sheet->setCellValueByColumnAndRow($column++, $row, $this->translator->trans($metaField->getLabel()));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $this->translator->trans($metaField->getLabel()));
}
return \count($timesheetMetaFields);
@@ -434,7 +440,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $metaField) {
$metaFieldValue = $metaField->getValue();
}
$sheet->setCellValueByColumnAndRow($column++, $row, $metaFieldValue);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $metaFieldValue);
}
return \count($timesheetMetaFields);
@@ -450,7 +456,7 @@ abstract class AbstractSpreadsheetRenderer
$columns['customer-meta'] = [
'header' => function (Worksheet $sheet, $row, $column) use ($customerMetaFields): int {
foreach ($customerMetaFields as $metaField) {
$sheet->setCellValueByColumnAndRow($column++, $row, $this->translator->trans($metaField->getLabel()));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $this->translator->trans($metaField->getLabel()));
}
return \count($customerMetaFields);
@@ -464,7 +470,7 @@ abstract class AbstractSpreadsheetRenderer
$metaFieldValue = $metaField->getValue();
}
}
$sheet->setCellValueByColumnAndRow($column++, $row, $metaFieldValue);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $metaFieldValue);
}
return \count($customerMetaFields);
@@ -477,7 +483,7 @@ abstract class AbstractSpreadsheetRenderer
$columns['project-meta'] = [
'header' => function (Worksheet $sheet, $row, $column) use ($projectMetaFields): int {
foreach ($projectMetaFields as $metaField) {
$sheet->setCellValueByColumnAndRow($column++, $row, $this->translator->trans($metaField->getLabel()));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $this->translator->trans($metaField->getLabel()));
}
return \count($projectMetaFields);
@@ -491,7 +497,7 @@ abstract class AbstractSpreadsheetRenderer
$metaFieldValue = $metaField->getValue();
}
}
$sheet->setCellValueByColumnAndRow($column++, $row, $metaFieldValue);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $metaFieldValue);
}
return \count($projectMetaFields);
@@ -504,7 +510,7 @@ abstract class AbstractSpreadsheetRenderer
$columns['activity-meta'] = [
'header' => function (Worksheet $sheet, $row, $column) use ($activityMetaFields): int {
foreach ($activityMetaFields as $metaField) {
$sheet->setCellValueByColumnAndRow($column++, $row, $this->translator->trans($metaField->getLabel()));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $this->translator->trans($metaField->getLabel()));
}
return \count($activityMetaFields);
@@ -518,7 +524,7 @@ abstract class AbstractSpreadsheetRenderer
$metaFieldValue = $metaField->getValue();
}
}
$sheet->setCellValueByColumnAndRow($column++, $row, $metaFieldValue);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $metaFieldValue);
}
return \count($activityMetaFields);
@@ -533,7 +539,7 @@ abstract class AbstractSpreadsheetRenderer
$columns['user-meta'] = [
'header' => function (Worksheet $sheet, $row, $column) use ($userPreferences): int {
foreach ($userPreferences as $metaField) {
$sheet->setCellValueByColumnAndRow($column++, $row, $this->translator->trans($metaField->getLabel()));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $this->translator->trans($metaField->getLabel()));
}
return \count($userPreferences);
@@ -547,7 +553,7 @@ abstract class AbstractSpreadsheetRenderer
$metaFieldValue = $metaField->getValue();
}
}
$sheet->setCellValueByColumnAndRow($column++, $row, $metaFieldValue);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $metaFieldValue);
}
return \count($userPreferences);
@@ -557,20 +563,20 @@ abstract class AbstractSpreadsheetRenderer
if (isset($columns['type']) && !isset($columns['type']['render'])) {
$columns['type']['render'] = function (Worksheet $sheet, int $row, int $column, ExportableItem $entity) {
$sheet->setCellValueByColumnAndRow($column, $row, $entity->getType());
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $entity->getType());
};
}
if (isset($columns['category']) && !isset($columns['category']['render'])) {
$columns['category']['render'] = function (Worksheet $sheet, int $row, int $column, ExportableItem $entity) {
$sheet->setCellValueByColumnAndRow($column, $row, $entity->getCategory());
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $entity->getCategory());
};
}
if (isset($columns['customer_number'])) {
if (!isset($columns['customer_number']['header'])) {
$columns['customer_number']['header'] = function (Worksheet $sheet, $row, $column): int {
$sheet->setCellValueByColumnAndRow($column, $row, $this->translator->trans('number'));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $this->translator->trans('number'));
return 1;
};
@@ -582,7 +588,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getProject()) {
$customerId = $entity->getProject()->getCustomer()->getNumber();
}
$sheet->setCellValueByColumnAndRow($column, $row, $customerId);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $customerId);
};
}
}
@@ -590,7 +596,7 @@ abstract class AbstractSpreadsheetRenderer
if (isset($columns['customer_vat']) && !isset($columns['customer_vat']['render'])) {
if (!isset($columns['customer_vat']['header'])) {
$columns['customer_vat']['header'] = function (Worksheet $sheet, $row, $column): int {
$sheet->setCellValueByColumnAndRow($column, $row, $this->translator->trans('vat_id'));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $this->translator->trans('vat_id'));
return 1;
};
@@ -602,7 +608,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getProject()) {
$customerVat = $entity->getProject()->getCustomer()->getVatId();
}
$sheet->setCellValueByColumnAndRow($column, $row, $customerVat);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $customerVat);
};
}
}
@@ -610,7 +616,7 @@ abstract class AbstractSpreadsheetRenderer
if (isset($columns['order_number']) && !isset($columns['order_number']['render'])) {
if (!isset($columns['order_number']['header'])) {
$columns['order_number']['header'] = function (Worksheet $sheet, $row, $column): int {
$sheet->setCellValueByColumnAndRow($column, $row, $this->translator->trans('orderNumber'));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $this->translator->trans('orderNumber'));
return 1;
};
@@ -622,7 +628,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getProject()) {
$orderNumber = $entity->getProject()->getOrderNumber();
}
$sheet->setCellValueByColumnAndRow($column, $row, $orderNumber);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $orderNumber);
};
}
}
@@ -663,10 +669,13 @@ abstract class AbstractSpreadsheetRenderer
foreach ($columns as $label => $settings) {
if (isset($settings['header'])) {
if (!\is_callable($settings['header'])) {
throw new \RuntimeException('Invalid header renderer given for: ' . $label);
}
$amount = $settings['header']($sheet, $recordsHeaderRow, $recordsHeaderColumn);
$recordsHeaderColumn += $amount;
} else {
$sheet->setCellValueByColumnAndRow($recordsHeaderColumn++, $recordsHeaderRow, $this->translator->trans($label));
$sheet->setCellValue(CellAddress::fromColumnAndRow($recordsHeaderColumn++, $recordsHeaderRow), $this->translator->trans($label));
}
}
@@ -689,11 +698,11 @@ abstract class AbstractSpreadsheetRenderer
}
if (!\array_key_exists('render', $settings) || !\is_callable($settings['render'])) {
throw new \RuntimeException(sprintf('Missing renderer for export column %s', $label));
throw new \RuntimeException(sprintf('Missing or invalid renderer for export column %s', $label));
}
$amount = $settings['render']($sheet, $entryHeaderRow, $entryHeaderColumn, $exportItem);
$entryHeaderColumn += (null === $amount) ? 1 : $amount;
$entryHeaderColumn += (null === $amount) ? 1 : (int) $amount;
}
$entryHeaderRow++;
@@ -701,28 +710,28 @@ abstract class AbstractSpreadsheetRenderer
if ($this->isTotalRowSupported()) {
if (null !== $durationColumn) {
$startCoordinate = $sheet->getCellByColumnAndRow($durationColumn, 2)->getCoordinate();
$endCoordinate = $sheet->getCellByColumnAndRow($durationColumn, $entryHeaderRow - 1)->getCoordinate();
$startCoordinate = $sheet->getCell(CellAddress::fromColumnAndRow($durationColumn, 2))->getCoordinate();
$endCoordinate = $sheet->getCell(CellAddress::fromColumnAndRow($durationColumn, $entryHeaderRow - 1))->getCoordinate();
$this->setDurationTotal($sheet, $durationColumn, $entryHeaderRow, $startCoordinate, $endCoordinate);
$style = $sheet->getStyleByColumnAndRow($durationColumn, $entryHeaderRow);
$style = $sheet->getStyle(CellAddress::fromColumnAndRow($durationColumn, $entryHeaderRow));
$style->getBorders()->getTop()->setBorderStyle(Border::BORDER_THIN);
$style->getFont()->setBold(true);
}
if (null !== $rateColumn) {
$startCoordinate = $sheet->getCellByColumnAndRow($rateColumn, 2)->getCoordinate();
$endCoordinate = $sheet->getCellByColumnAndRow($rateColumn, $entryHeaderRow - 1)->getCoordinate();
$startCoordinate = $sheet->getCell(CellAddress::fromColumnAndRow($rateColumn, 2))->getCoordinate();
$endCoordinate = $sheet->getCell(CellAddress::fromColumnAndRow($rateColumn, $entryHeaderRow - 1))->getCoordinate();
$this->setRateTotal($sheet, $rateColumn, $entryHeaderRow, $startCoordinate, $endCoordinate);
$style = $sheet->getStyleByColumnAndRow($rateColumn, $entryHeaderRow);
$style = $sheet->getStyle(CellAddress::fromColumnAndRow($rateColumn, $entryHeaderRow));
$style->getBorders()->getTop()->setBorderStyle(Border::BORDER_THIN);
$style->getFont()->setBold(true);
}
if (null !== $internalRateColumn) {
$startCoordinate = $sheet->getCellByColumnAndRow($internalRateColumn, 2)->getCoordinate();
$endCoordinate = $sheet->getCellByColumnAndRow($internalRateColumn, $entryHeaderRow - 1)->getCoordinate();
$startCoordinate = $sheet->getCell(CellAddress::fromColumnAndRow($internalRateColumn, 2))->getCoordinate();
$endCoordinate = $sheet->getCell(CellAddress::fromColumnAndRow($internalRateColumn, $entryHeaderRow - 1))->getCoordinate();
$this->setRateTotal($sheet, $internalRateColumn, $entryHeaderRow, $startCoordinate, $endCoordinate);
$style = $sheet->getStyleByColumnAndRow($internalRateColumn, $entryHeaderRow);
$style = $sheet->getStyle(CellAddress::fromColumnAndRow($internalRateColumn, $entryHeaderRow));
$style->getBorders()->getTop()->setBorderStyle(Border::BORDER_THIN);
$style->getFont()->setBold(true);
}