From 41f194a3b9a8cbc63f81e60e8f33cfef005890c0 Mon Sep 17 00:00:00 2001 From: John McNamara Date: Sun, 8 Oct 2023 18:43:22 +0100 Subject: [PATCH] table: fix issue where column formulas were overwritten by table data --- lib/Excel/Writer/XLSX/Worksheet.pm | 26 ++++++-- t/regression/table34.t | 94 +++++++++++++++++++++++++++ t/regression/xlsx_files/table34.xlsx | Bin 0 -> 8767 bytes 3 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 t/regression/table34.t create mode 100644 t/regression/xlsx_files/table34.xlsx diff --git a/lib/Excel/Writer/XLSX/Worksheet.pm b/lib/Excel/Writer/XLSX/Worksheet.pm index 6731cc81..0bb0d088 100644 --- a/lib/Excel/Writer/XLSX/Worksheet.pm +++ b/lib/Excel/Writer/XLSX/Worksheet.pm @@ -5059,11 +5059,7 @@ sub add_table { $formula =~ s/@/[#This Row],/g; $col_data->{_formula} = $formula; - - for my $row ( $first_data_row .. $last_data_row ) { - $self->write_formula( $row, $col_num, $formula, - $user_data->{format} ); - } + # We write the formulas below after the table data. } # Handle the function for the total row. @@ -5165,6 +5161,26 @@ sub add_table { } + # Write any columns formulas after the user supplied table data to + # overwrite it if required. + $col_id = 0; + for my $col_num ( $col1 .. $col2 ) { + + my $column_data = $table{_columns}->[$col_id]; + + if ( $column_data && $column_data->{_formula} ) { + my $formula_format = $col_formats[$col_id]; + my $formula = $column_data->{_formula}; + + for my $row ( $first_data_row .. $last_data_row ) { + $self->write_formula( $row, $col_num, $formula, + $formula_format ); + } + } + $col_id++; + } + + # Store the filter cell positions for use in the autofit calculation. if ( $param->{autofilter} ) { for my $col ( $col1 .. $col2 ) { diff --git a/t/regression/table34.t b/t/regression/table34.t new file mode 100644 index 00000000..8cdb91fb --- /dev/null +++ b/t/regression/table34.t @@ -0,0 +1,94 @@ +############################################################################### +# +# Tests the output of Excel::Writer::XLSX against Excel generated files. +# +# Copyright 2000-2023, John McNamara, jmcnamara@cpan.org +# +# SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later +# + +use lib 't/lib'; +use TestFunctions qw(_compare_xlsx_files _is_deep_diff); +use strict; +use warnings; + +use Test::More tests => 1; + +############################################################################### +# +# Tests setup. +# +my $filename = 'table34.xlsx'; +my $dir = 't/regression/'; +my $got_filename = $dir . "ewx_$filename"; +my $exp_filename = $dir . 'xlsx_files/' . $filename; + + +my $ignore_members = [ 'xl/calcChain.xml', '\[Content_Types\].xml', 'xl/_rels/workbook.xml.rels' ]; +my $ignore_elements = { 'xl/workbook.xml' => ['new( $got_filename ); +my $worksheet = $workbook->add_worksheet(); + +my $format1 = $workbook->add_format( num_format => "0.0000" ); + +my $data = [ + [ 'Foo', 1234, 0, 4321 ], + [ 'Bar', 1256, 0, 4320 ], + [ 'Baz', 2234, 0, 4332 ], + [ 'Bop', 1324, 0, 4333 ], +]; + + +# Set the column width to match the target worksheet. +$worksheet->set_column('C:F', 10.288); + +# Add the table. +$worksheet->add_table( + 'C2:F6', + { + data => $data, + columns => [ + {}, + {}, + {}, + { formula => 'Table1[[#This Row],[Column3]]', format => $format1 } + ], + } +); + +$workbook->close(); + + +############################################################################### +# +# Compare the generated and existing Excel files. +# + +my ( $got, $expected, $caption ) = _compare_xlsx_files( + + $got_filename, + $exp_filename, + $ignore_members, + $ignore_elements, +); + +_is_deep_diff( $got, $expected, $caption ); + + +############################################################################### +# +# Cleanup. +# +unlink $got_filename; + +__END__ + + + diff --git a/t/regression/xlsx_files/table34.xlsx b/t/regression/xlsx_files/table34.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..9fd73fadcb7bfd949727f2a96d5c2f8bf81b0233 GIT binary patch literal 8767 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%0D8wGNpw!xZC%h95I55gofp273w@=}@IUIsjo z#1$1!HX?I;2QB_iaYoB?fn^GNAXegHSfNPR-mK4t`0CQ+dzi<92`I44`FWk!BJc^= zAYqlhz4zAc2hgsnNJF4gy<5Mqc&gLmuT7Cg{9oEz4fa2VQuryJdOKnDFEsKL8QJlV zHU?G(Apb{(1tPdRPw)%i;N4dzQ@xA5{k8+wYL4URJ9j4_jc1nUn15z5APP4!WBq=z z{pW7|dHv0tTV3hz3jRKk`&01yH4^C(f0@r+75w{n8q91 zFKH5FcY>7uN1b(5!`~}{U-AF|lnMa&M}2Tr{O=+Cuj1Ef{v!TIfLB*SN5b`cD~%7( MKq7vU?)%;U02?FS