PHPOffice / PhpSpreadsheet

A pure PHP library for reading and writing spreadsheet files
https://phpspreadsheet.readthedocs.io
MIT License
13.36k stars 3.47k forks source link

Table total row causes Excel error on opening #3572

Closed wgstjf closed 3 weeks ago

wgstjf commented 1 year ago

This is:

- [ x] a bug report
- [ ] a feature request
- [ ] **not** a usage question (ask them on https://stackoverflow.com/questions/tagged/phpspreadsheet or https://gitter.im/PHPOffice/PhpSpreadsheet)

What is the expected behavior?

Using (initally) code from https://github.com/PHPOffice/PhpSpreadsheet/blob/master/samples/Table/02_Table_Total.php we have tried to add a totals row to our table that uses SUBTOTAL formula to calculate the total for each column

What is the current behavior?

Excel declares "We found a problem with some content...." and offers to recover the workbook. Agreeing to this results in the file opening and the table displayed correctly (including total row).

The repairs window states that it has repaired records from "Table from /xl/tables/table1.xml part (Table)". The log file contents are:

_<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

error106280_02.xmlErrors were detected in file 'C:\Users\will\Downloads\test-spreadsheet.xlsx'Excel completed file level validation and repair. Some parts of this workbook may have been repaired or discarded.Repaired Records: Table from /xl/tables/table1.xml part (Table)_ If we don't include the totals row, or include the row but don't use formulas, the error goes away. The issue seems to be very much connected to the use of a formula as we have tried the following: - setValue('=SUBTOTAL(109,TransactionData[Total])'); ERRORS - setValue('=SUBTOTAL(109,TransactionData[L2:L37])'); ERRORS - setCellValueExplicit(L37, '=SUM(L2:L36)', \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_FORMULA); ERRORS - setValue('Test'); NO ERROR ### What are the steps to reproduce? See above. We are outputting the file using ```php save('php://output'); die(); ``` If this is an issue with reading a specific spreadsheet file, then it may be appropriate to provide a sample file that demonstrates the problem; but please keep it as small as possible, and sanitize any confidential information before uploading. ### What features do you think are causing the issue - [ ] Reader - [x ] Writer - [ ] Styles - [ ] Data Validations - [x ] Formula Calculations - [ ] Charts - [ ] AutoFilter - [ ] Form Elements ### Does an issue affect all spreadsheet file formats? If not, which formats are affected? ### Which versions of PhpSpreadsheet and PHP are affected? 1.28 8.0.28 Thanks in advance, Will
oleibman commented 1 year ago

Can you share the code that you are using to create the table and add it to the worksheet? (Roughly this as you've modified it from the sample you started with):

$table = new Table();
// your code 
$spreadsheet->getActiveSheet()->addTable($table);
wgstjf commented 1 year ago

Hi, thanks for replying.

We are dynamically creating rows from a database query. Each row is added as follows:

$j = 2;
   foreach ($event_transactions as $transaction) {
   $transaction_formatted = format_transaction(transaction);
   // Vars
   $last_col_number = $j;
   $col_letter = 'A';
   foreach ($fields as $field) {
      $value = (isset($transaction_formatted[$field])) ? $transaction_formatted[$field] : '';
      $worksheet->setCellValue($col_letter.$j, $value);
      ++$col_letter; 
   }
   $j++;
}

And for the table:


#-----------------------------------------------------------------
# Create Table
#-----------------------------------------------------------------
$table = new Table();
$table->setName('TransactionData');
$table->setShowTotalsRow(true);
$table->setRange('A1:'.$last_col_letter.$j); // Using $j so that we get +1 for the totals row

$spreadsheet->getActiveSheet()->addTable($table);

#-----------------------------------------------------------------
# Add Totals
#-----------------------------------------------------------------

$add_totals_row = true; // If set to false then no errors generated when opening xslx

if ($add_totals_row) {
  $spreadsheet->getActiveSheet()->getCell('H'.$j)->setValue('TOTALS');
  $spreadsheet->getActiveSheet()->getCell('I'.$j)->setValue('=SUBTOTAL(109,TransactionData[Sub Total])');
  $spreadsheet->getActiveSheet()->getCell('J'.$j)->setValue('=SUBTOTAL(109,TransactionData[Booking Fee])');
  $spreadsheet->getActiveSheet()->getCell('K'.$j)->setValue('=SUBTOTAL(109,TransactionData[Discount])');
  $spreadsheet->getActiveSheet()->getCell('L'.$j)->setValue('=SUBTOTAL(109,TransactionData[Refund])');
  $spreadsheet->getActiveSheet()->getCell('M'.$j)->setValue('=SUBTOTAL(109,TransactionData[Total])');
}

This outputs:

     +-----------+------------------+-------------------+---------------------+-----------------------+------------+------------+----------+-------------------------------------------+---------------------------------------------+------------------------------------------+----------------------------------------+---------------------------------------+---------+
     | A         | B                | C                 | D                   | E                     | F          | G          | H        | I                                         | J                                           | K                                        | L                                      | M                                     | N       |
+----+-----------+------------------+-------------------+---------------------+-----------------------+------------+------------+----------+-------------------------------------------+---------------------------------------------+------------------------------------------+----------------------------------------+---------------------------------------+---------+
|  1 | User Name | Participant Name | Horse Name        | Added               | Class Title           | Type       | Spaces     | Order ID | Sub Total                                 | Booking Fee                                 | Discount                                 | Refund                                 | Total                                 | Changes |
|  2 | Test Name | Test Participant | Jim, Penny, Giles | 2023-05-15 12:09:00 | 80cm - COST PER TEAM  | Ammendment | WHAT HERE? | 92       | 40                                        | 2                                           | 0                                        | 0                                      | 42                                    | Test    |
|  3 | Test Name | Test Participant | Jim, Penny, Giles | 2023-05-15 12:03:47 | 90cm cost per team    | Entry      | WHAT HERE? | 91       | 320                                       | 24                                          | 0                                        | 0                                      | 344                                   | Test    |
|  4 | Test Name | Test Participant | Jim, Penny, Giles | 2023-05-15 11:57:26 | 80cm - COST PER TEAM  | Ammendment | WHAT HERE? | 90       | 40                                        | 2                                           | 0                                        | 0                                      | 42                                    | Test    |
|  5 | Test Name | Test Participant | Jim, Penny, Giles | 2023-05-15 11:08:04 | 90cm cost per team    | Entry      | WHAT HERE? | 89       | 320                                       | 24                                          | 0                                        | 0                                      | 344                                   | Test    |
|  6 | Test Name | Test Participant |                   | 2023-04-20 11:16:17 | Spectator Ticket      | Entry      | WHAT HERE? | 77       | 0                                         | 1                                           | 0                                        | 0                                      | 1                                     | Test    |
|  7 | Test Name | Test Participant | Penny, Joy, Giles | 2023-04-20 10:32:19 | 90cm cost per team    | Entry      | WHAT HERE? | 76       | 320                                       | 24                                          | 0                                        | 0                                      | 350                                   | Test    |
|  8 | Test Name | Test Participant | Penny, Jim, Joy   | 2023-04-20 10:17:59 | 90cm cost per team    | Entry      | WHAT HERE? | 75       | 320                                       | 24                                          | 0                                        | 20                                     | 330                                   | Test    |
|  9 | Test Name | Test Participant |                   | 2023-04-20 10:15:19 | 90cm cost per team    | Entry      | WHAT HERE? | 74       | 320                                       | 24                                          | 0                                        | 0                                      | 350                                   | Test    |
| 10 | Test Name | Test Participant |                   | 2023-04-20 10:09:48 | 90cm cost per team    | Entry      | WHAT HERE? | 73       | 320                                       | 24                                          | 0                                        | 0                                      | 350                                   | Test    |
| 11 | Test Name | Test Participant | Penny, Jim, Jeff  | 2023-04-20 09:46:29 | 90cm cost per team    | Entry      | WHAT HERE? | 72       | 320                                       | 8                                           | 0                                        | 0                                      | 330                                   | Test    |
| 12 | Test Name | Test Participant | Jim               | 2023-04-20 09:46:29 | 80cm - COST PER RIDER | Entry      | WHAT HERE? | 72       | 80                                        | 2                                           | 0                                        | 0                                      | 84                                    | Test    |
| 13 | Test Name | Test Participant | Joy               | 2023-04-20 09:46:29 | 80cm - COST PER RIDER | Entry      | WHAT HERE? | 72       | 80                                        | 2                                           | 0                                        | 0                                      | 84                                    | Test    |
| 14 | Test Name | Test Participant | Penny             | 2023-04-20 09:46:29 | 80cm - COST PER RIDER | Entry      | WHAT HERE? | 72       | 80                                        | 2                                           | 0                                        | 0                                      | 84                                    | Test    |
| 15 | Test Name | Test Participant |                   | 2023-03-22 11:22:55 | 80cm - COST PER RIDER | Entry      | WHAT HERE? | 40       | 80                                        | 2                                           | 0                                        | 0                                      | 84                                    | Test    |
| 16 | Test Name | Test Participant | Giles             | 2023-03-21 16:31:26 | 80cm - COST PER RIDER | Entry      | WHAT HERE? | 31       | 80                                        | 2                                           | 0                                        | 80                                     | 2                                     | Test    |
| 17 | Test Name | Test Participant |                   | 2023-03-21 16:31:26 | Spectator Ticket      | Entry      | WHAT HERE? | 31       | 0                                         | 1                                           | 0                                        | 0                                      | 1                                     | Test    |
| 18 | Test Name | Test Participant | Penny             | 2023-03-08 12:48:48 | 80cm - COST PER RIDER | Entry      | WHAT HERE? | 28       | 80                                        | 2                                           | 0                                        | 0                                      | 82                                    | Test    |
| 19 | Test Name | Test Participant | Jim               | 2022-09-28 14:51:12 | Test per rider        | Entry      | WHAT HERE? | 8        | 0                                         | 2                                           | 0                                        | 0                                      | 14.5                                  | Test    |
| 20 | Test Name | Test Participant | Penny             | 2022-09-28 14:51:12 | Test per rider        | Entry      | WHAT HERE? | 8        | 0                                         | 2                                           | 0                                        | 0                                      | 14.5                                  | Test    |
| 21 | Test Name | Test Participant | Penny, Jim, Jeff  | 2022-09-23 12:13:43 | Test per class        | Entry      | WHAT HERE? | 7        | 0                                         | 1.5                                         | 0                                        | 0                                      | 23.56                                 | Test    |
| 22 | Test Name | Test Participant | Jim               | 2022-09-23 12:13:43 | Test per rider        | Entry      | WHAT HERE? | 7        | 0                                         | 2                                           | 0                                        | 0                                      | 14.5                                  | Test    |
| 23 | Test Name | Test Participant | Penny             | 2022-09-23 12:13:43 | Test per rider        | Entry      | WHAT HERE? | 7        | 0                                         | 2                                           | 0                                        | 0                                      | 16.5                                  | Test    |
| 24 | Test Name | Test Participant | Penny, Jim, Giles | 2022-09-22 15:41:40 | Test per rider        | Entry      | WHAT HERE? | 6        | 37.5                                      | 6                                           | 0                                        | 0                                      | 37.5                                  | Test    |
| 25 | Test Name | Test Participant | Penny, Jim        | 2022-09-22 15:20:01 | Test                  | Entry      | WHAT HERE? | 5        | 20.06                                     | 1.5                                         | 0                                        | 0                                      | 24.06                                 | Test    |
| 26 | Test Name | Test Participant | Penny, Jim, Giles | 2022-09-22 15:20:01 | Test 2                | Entry      | WHAT HERE? | 5        | 37.5                                      | 6                                           | 0                                        | 0                                      | 37.5                                  | Test    |
| 27 | Test Name | Test Participant |                   | 2022-09-22 15:20:01 | Spectator Ticket      | Entry      | WHAT HERE? | 5        | 0                                         | 1.5                                         | 0                                        | 0                                      | 0                                     | Test    |
| 28 | Test Name | Test Participant |                   | 2022-09-21 09:34:36 | Spectator Ticket      | Entry      | WHAT HERE? | 4        | 5                                         | 1.5                                         | 0                                        | 5                                      | 5                                     | Test    |
| 29 | Test Name | Test Participant |                   | 2022-09-20 16:09:29 | Spectator Ticket      | Entry      | WHAT HERE? | 3        | 5                                         | 1.5                                         | 0                                        | 0                                      | 5                                     | Test    |
| 30 | Test Name | Test Participant | Penny, Jim, Giles | 2022-09-20 16:09:29 | Test                  | Entry      | WHAT HERE? | 3        | 20.06                                     | 1.5                                         | 0                                        | 0                                      | 22.06                                 | Test    |
| 31 | Test Name | Test Participant |                   | 2022-09-20 15:46:31 | Spectator Ticket      | Entry      | WHAT HERE? | 2        | 5                                         | 1.5                                         | 0                                        | 0                                      | 5                                     | Test    |
| 32 | Test Name | Test Participant | Penny, Jim, Giles | 2022-09-20 15:46:31 | Test 2                | Entry      | WHAT HERE? | 2        | 37.5                                      | 6                                           | 0                                        | 0                                      | 37.5                                  | Test    |
| 33 | Test Name | Test Participant | Penny, Jim        | 2022-09-20 15:46:31 | Test                  | Entry      | WHAT HERE? | 2        | 20.06                                     | 1.5                                         | 0                                        | 0                                      | 20.06                                 | Test    |
| 34 | Test Name | Test Participant | Penny, Jim, Giles | 2022-09-16 12:22:23 | Test                  | Entry      | WHAT HERE? | 1        | 0                                         | 1.5                                         | 0                                        | 0                                      | 0                                     | Test    |
| 35 | Test Name | Test Participant |                   | 2022-09-16 12:22:23 | Spectator Ticket      | Entry      | WHAT HERE? | 1        | 0                                         | 1.5                                         | 0                                        | 0                                      | 0                                     | Test    |
| 36 | Test Name | Test Participant | Penny, Jim, Jeff  | 2022-09-16 12:22:23 | Test 2                | Entry      | WHAT HERE? | 1        | 0                                         | 6                                           | 0                                        | 0                                      | 0                                     | Test    |
| 37 |           |                  |                   |                     |                       |            |            | TOTALS   | =SUBTOTAL(109,TransactionData[Sub Total]) | =SUBTOTAL(109,TransactionData[Booking Fee]) | =SUBTOTAL(109,TransactionData[Discount]) | =SUBTOTAL(109,TransactionData[Refund]) | =SUBTOTAL(109,TransactionData[Total]) |         |
+----+-----------+------------------+-------------------+---------------------+-----------------------+------------+------------+----------+-------------------------------------------+---------------------------------------------+------------------------------------------+----------------------------------------+---------------------------------------+---------+
MarkBaker commented 1 year ago

Before setting the formula for the totals row cells, make sure that the table recognises that the cell has a totals formula

$table->getColumn('I')->setTotalsRowFunction('sum');

for each column that needs a total.

wgstjf commented 1 year ago

Outstanding Mark! Thank you for solving that headache, much appreciated.

MarkBaker commented 1 year ago

Tables are a relatively new feature for PhpSpreadsheet, and are gradually being improved and extended. The most recent improvement was actual support for Structured References within the Calculation Engine; but there is still work to do... particularly with styles and support in other file formats. I'll add automatically updating the totals row function to that list

wgstjf commented 1 year ago

Mark, one more query if I may?

I want to reference the Totals row of the table in a cell on another sheet. If I do so the resulting spreadsheet is corrupted and won't open. If I disable pre calculation of formulas then it does work but the values all display as zero until you enable editing

// Booking Fees
$worksheet->setCellValue('A15', 'Online Booking fees');
$worksheet->setCellValue('C15', '=TransactionData[[#Totals],Total]');

Any thoughts? Cheers, Will

oleibman commented 1 year ago

PR #3659, which was merged last week, should address that problem. Can you confirm by testing against master?

Gawdl3y commented 1 year ago

I am experiencing this issue even when setting totals row functions for each of the columns before overwriting the cell values.

// Get the highest row/column (+1 to the row since we're going to add a totals row)
$worksheet = $event->sheet->getDelegate();
$highest = $worksheet->getCellCollection()->getHighestRowAndColumn();
$highest['row']++;

// Set up the table
$table = new Table;
$table->setName('DepartmentSummary');
$table->setShowTotalsRow(true);
$table->setRange("A1:{$highest['column']}{$highest['row']}");

// Set up the totals row and add the table to the sheet
$table->getColumn('A')->setTotalsRowLabel('Total');
$table->getColumn('B')->setTotalsRowFunction('sum');
$table->getColumn('C')->setTotalsRowFunction('sum');
$table->getColumn('D')->setTotalsRowFunction('sum');
$worksheet->addTable($table);

// Overwrite the totals row cells since PhpSpreadsheet doesn't yet fully implement the functionality
$worksheet->getCell("A{$highest['row']}")->setValue('Total');
$worksheet->getCell("B{$highest['row']}")->setValue('=SUBTOTAL(109, DepartmentSummary[Hours])');
$worksheet->getCell("C{$highest['row']}")->setValue('=SUBTOTAL(109, DepartmentSummary[Volunteers])');
$worksheet->getCell("D{$highest['row']}")->setValue('=SUBTOTAL(109, DepartmentSummary[Time entries])');

With this code, when opening the spreadsheet, Excel gives the exact error as in the original issue description.

oleibman commented 1 year ago

I add the following lines near the end of 02_Table_Totals.php, on which you have based your program:

$newSheet = $spreadsheet->createSheet();
$newSheet->getCell('A1')->setValue('=SalesData[[#Totals],Sales]');

I think this is close to what you're trying to accomplish - getting the total for a specific column of a table located on a different sheet. When I run this code, I am able to open the result, and A1 on the second sheet shows the correct formula (it doesn't have a value for the formula in the Xml, but Excel fills that in with 9930, as it should). The same is more or less true if I enter the formula as =SalesData[[#Totals],[Sales]]. So, if you are doing approximately the same thing and winding up with a corrupt spreadsheet, is it possible to upload your spreadsheet to see if I can figure out what might be wrong with it?

Gawdl3y commented 1 year ago

In my case, the table that I'm adding the totals row to is on the same sheet - I'm not attempting to cross sheets at all, as I don't even have more than one sheet.

oleibman commented 1 year ago

Again, 02_Tables_Total adds the totals row on the same sheet and does not have a problem. I need to see your spreadsheet in order to attempt to figure out what is going wrong.

vectorseKGS commented 8 months ago

Gawdl3y, Try removing the space in front of 'DepartmentSummary' in your SUBTOTAL formula. I had the same issue. Removing any whitespace between the comma and the table name resolved the issue.

seyfcom commented 2 months ago

Hi ! first, thanks for the great library. I use version 2.2.* I cannot succeed in not having a error in Excel with table, and totals. it says "Repaired Records: Table from /xl/tables/table1.xml part (Table)" First point : When I compare the XML inside Excel, I see after repair that the RANGE is not including the total row in the repaired file and if I don't include it, the row does not have the totals.

Secondly, whatever I do, except if I disable the table in the sheet, I have an error, and I don't see any reason why. Do you know how to get more info from Excel where the error is ?

I use this code.

` //set new table for Excel

        $table = new Table();
       // $maxColumn is actually a bad variable name, it is a string like "R98",
        $table->setName('Participation')->setRange('A'. $r .':' . $maxColumn);
        $style = new TableStyle();
        $style->setTheme(TableStyle::TABLE_STYLE_MEDIUM2)->setShowRowStripes(true);
        $table->setStyle($style);
        $table->setShowHeaderRow(true)->setAllowFilter(true)->setShowTotalsRow(true);
        // set column for SUM function
        for ($i = $columSumPresence; $i <= count($arrayData[0]); $i++) {
            $table->getColumn($this->getLetterCodeFromInt($i))->setTotalsRowFunction('sum');
        }
        $sheet->setCellValue('A' . $totalRow, 'Totals');
        $sheet->setCellValue($this->getLetterCodeFromInt($columSumPresence) . $totalRow, '=SUBTOTAL(109,Participation[' . $this->translator->trans('lbl_Sum_presence') . '])');
        $sheet->setCellValue($this->getLetterCodeFromInt($columSumReference) . $totalRow, '=SUBTOTAL(109,Participation[' . $this->translator->trans('lbl_Sum_reference') . '])');
        $sheet->setCellValue($this->getLetterCodeFromInt($columDifference) . $totalRow, '=SUBTOTAL(109,Participation[' . $this->translator->trans('lbl_Difference') . '])');
        foreach ($units as $key => $unit) {
            $sheet->setCellValue($this->getLetterCodeFromInt($key + $columDifference +1) . $totalRow, "=SUBTOTAL(109,Participation[" . $unit->getCodeUnit() . "])");
        }
        $sheet->addTable($table);

`

But as I said, even with just a new Table and addTable I get the error.

oleibman commented 2 months ago

@seyfcom Without the entire code, I can't be sure, but the following statement looks wrong to me:

 $table->setName('Participation')->setRange('A'. $r .':' . $maxColumn);

I think you need to specify an ending row for the range. Your code looks like it will give you a range of, say, A2:C, but your range needs to be something like A2:C5.

seyfcom commented 2 months ago

@oleibman $maxColumn is actually a bad variable name, it is a string like "R98", so it gives the full range. I tried entering manually then range to be sure. Nothing changes. But thanks anyway !!

oleibman commented 2 months ago

It is still difficult to figure out without all the missing code (arrayData, columnSumPresence, getLetterCodeFromInt, maybe others). However, I think the following code gives a good approximation of what you want to do:

        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();
        $table = new Table();
        $r = 1;
        $totalRow = 8;
        $sheet->fromArray([
            ['Column1', 'Presence', 'Reference', 'Difference'],
            [null, 1, null, null],
            [null, null, 2, null],
            [null, null, null, 3],
            [null, null, 4, null],
            [null, 5, null, null],
        ]);
        $maxColumn = "D$totalRow";
        $table->setName('Participation')
            ->setRange('A'. $r .':' . $maxColumn);
        $style = new TableStyle();
        $style->setTheme(TableStyle::TABLE_STYLE_MEDIUM2)
            ->setShowRowStripes(true);
        $table->setStyle($style);
        $table->setShowHeaderRow(true)
            ->setAllowFilter(true)
            ->setShowTotalsRow(true);
        // set column for SUM function
        foreach (['B', 'C', 'D'] as $col) {
            $table->getColumn($col)
                ->setTotalsRowFunction('sum');
        }
        $sheet->setCellValue('A' . $totalRow, 'Totals');
        foreach (['B', 'C', 'D'] as $col) {
            $sheet->setCellValue(
                "$col$totalRow",
                '=SUBTOTAL(109,Participation['
                . $sheet->getCell($col . $r)->getValue()
                . '])'
            );
        }

        $sheet->addTable($table);
        $writer = new XlsxWriter($spreadsheet);
        $outfile = 'issue.3572.xlsx';
        $writer->save($outfile);

My output spreadsheet from this code opens without issue, and appears to be correct. Can you compare this to your code and see where there might be differences?

seyfcom commented 1 month ago

Hi ! I finally found the error, it was on a merge cell, outside of the table, but it broke the table somehow... sorry and thanks a lot for your help !

seyfcom commented 1 week ago

Hi, I have again a problem with this Table function. With this code

// $this->getLetterCodeFromInt($i)  returns the Letter for Excel, from an Integer

            $maxRow = $myWorkSheet->getHighestRow();
            $totalRow = $maxRow +1; // add 1 for totals
            $table = new Table();
            $table->setName('UnitCostChild')->setRange('A' . $dataRow . ':' . $this->getLetterCodeFromInt(count($data[0])) . $totalRow);
            $style = new TableStyle();
            $style->setTheme(TableStyle::TABLE_STYLE_MEDIUM2)->setShowRowStripes(true);
            $table->setStyle($style);
            $table->setShowHeaderRow(true)->setAllowFilter(true)->setShowTotalsRow(true);
            for ($i = 4; $i <= count($data[0]) - 5; $i++) { // columns 1-3 and last 5 must not have totals
                $table->getColumn($this->getLetterCodeFromInt($i))->setTotalsRowFunction('Sum');
                $myWorkSheet->setCellValue($this->getLetterCodeFromInt($i) . $totalRow, '=SUBTOTAL(109, UnitCostChild[' . $myWorkSheet->getCell($this->getLetterCodeFromInt($i) . $dataRow)->getValue() . '])');
            }
            $myWorkSheet->setCellValue('A' . $totalRow, 'Total');
            $myWorkSheet->addTable($table);

I still get the message that the file has a problem if I want to recover. Then when I activate the edition mode, it says again that it has circular reference, but There is no other formula than the totals here. In the xml error there is no help.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<recoveryLog xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><logFileName>error289000_01.xml</logFileName>
<summary>Errors were detected in file 'C:\Users\Fabrice\Downloads\AES_Statistiques_AES_04.11.2024_17.12.06.xlsx'</summary>
<additionalInfo><info>Excel completed file level validation and repair. Some parts of this workbook may have been repaired or discarded.</info>
</additionalInfo><repairedRecords><repairedRecord>Repaired Records: Table from /xl/tables/table4.xml part (Table)</repairedRecord>
</repairedRecords></recoveryLog>

Can it be that there is a special caracter that breaks it ? If I take the same sheet and I do the totals in Excel manually it works fine and I get the same formulas. I'm really out of options to find a solution. Here the image of error message and a file for demo, those a dummies data.

error_msg_1 error_msg_2 error_msg_3 Démo AES Récapitulatif_presences_2023-06-22_2024-11-04.xlsx

oleibman commented 1 week ago

I'm beginning to become more than a little exasperated with Excel's "error" handling and its "diagnostic" messages. I believe you have 2 problems. The first is in the following statement (reformatted to make it a bit easier to read:

$myWorkSheet->setCellValue($this->getLetterCodeFromInt($i) . $totalRow,
    '=SUBTOTAL(109, UnitCostChild['
   . $myWorkSheet->getCell($this->getLetterCodeFromInt($i) . $dataRow)->getValue() . '])');

There is a space between 109 and UnitCostChild. I don't understand why it should matter, but you need to remove the space.

Bringing us to problem 2:

table->getColumn($this->getLetterCodeFromInt($i))
    ->setTotalsRowFunction('Sum');

Again, I don't understand why, but Sum (uppercase S) needs to be sum (lowercase s).

seyfcom commented 1 week ago

Well, I'm not sure if I still may ask anything about error then. I am also very tired of all the tests I have made, without results. I am sorry to tell you that the space doesn't change anything and that de Sum versus sum was already with lower case, i just copied the wrong code, as i tried to see if upper case would help.

I know it is the total row that cause problem, the rest is ok if I don't add the total row.

Last time I had errors, it was a completly out of table range cell merged that fired the error... with no reason. Maybe this time it is also something stupid like this, but I don't see what, as I did not merge any cell.

Your tool is great, I'm sure Excel is bulllshitting, but the problem is that the users are unhappy...

oleibman commented 1 week ago

I used the following code, modeled very closely on yours:

<?php

require __DIR__ . '/PhpSpreadsheet' . '/vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Table;
use PhpOffice\PhpSpreadsheet\Worksheet\Table\TableStyle;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;

class issue3572 {
    public static function issue() {
        $spreadsheet = new Spreadsheet();
        $myWorkSheet = $spreadsheet->getActiveSheet();

        $headerRow = 3;
        $data = [
            ['Name', 'Age', 'Contrats', 'Nbr Test', 'Data1', 'Data2', 'Data3', 'Blank1', 'Blank2', 'Blank3', 'Blank4', 'Blank5'],
            ['Name1', 'Age1', '', 1, 2, 3, 4, 'b1', 'b2', 'b3', 'b4', 'b5'], 
            ['Name2', 'Age2', '', 2, 3, 4, 5, 'b1', 'b2', 'b3', 'b4', 'b5'], 
            ['Name3', 'Age3', '', 3, 4, 5, 6, 'b1', 'b2', 'b3', 'b4', 'b5'],
        ];
        $lastCol = Coordinate::stringFromColumnIndex(count($data[0]));
        $myWorkSheet->fromArray($data, null, "A$headerRow", true);

        $maxRow = $myWorkSheet->getHighestRow();
        $totalRow = $maxRow + 1; // add 1 for totals
        $table = new Table();
        $table->setName('UnitCostChild');
        $table->setRange("A$headerRow:$lastCol$totalRow");
        $style = new TableStyle();
        $style->setTheme(TableStyle::TABLE_STYLE_MEDIUM2)
            ->setShowRowStripes(true);
        $table->setStyle($style);
        $table->setShowHeaderRow(true)
            ->setAllowFilter(true)
            ->setShowTotalsRow(true);
        //$table->getColumn('A')->setTotalsRowLabel('Total');

        for ($i = 4; $i <= count($data[0]) - 5; $i++){ // columns 1-3 and last 5 must not have totals
            $col = Coordinate::stringFromColumnIndex($i);
            $table->getColumn($col)->setTotalsRowFunction('sum');
            $myWorkSheet->setCellValue($col . $totalRow,
                '=SUBTOTAL(109,UnitCostChild['
                . $myWorkSheet->getCell($col . $headerRow)->getValue() . '])');
        }
        $myWorkSheet->setCellValue('A' . $totalRow, 'Total');
        $myWorkSheet->addTable($table);

        $writer = new XlsxWriter($spreadsheet);
        $outfile = 'issue.3572b9.xlsx';
        $writer->save($outfile);
        echo "saved $outfile\n";
    }
}

issue3572::issue();

It produced a file that Excel considered corrupt until I made the two changes I mentioned above. Can you try this and see what happens?

oleibman commented 1 week ago

BTW, I also tried Coût CHF test as the column D label, and that still worked, so I think we can rule out problems caused by the non-ASCII characters.

oleibman commented 1 week ago

Also BTW, LibreOffice opens the "corrupt" files without incident, reinforcing the idea that this is an Excel problem.

oleibman commented 1 week ago

I have taken another look at the spreadsheet you provided. You are partially correct - you are using lowercase sum whenever needed. However, all the SUBTOTAL(109, UnitCostChild absolutely contain a space between the comma and Unit, and those need to be fixed. When I edit the Xml in xl/worksheets/sheet1.xml and manually remove those spaces, Excel opens the file correctly.

seyfcom commented 1 week ago

I did not say the space problem was ok, I said that even when I remove it it didn't work.

I don't really get the difference between your code and mine, except for tiny things, but yours work.

Anyway thanks a lot !

seyfcom commented 1 week ago

Wouah, it seems my function $this->getLetterCodeFromInt($i) is supposed to be like the one from your tool Coordinate::stringFromColumnIndex($i) (take I missed obviously !) is the reason it doesn't work. Simply by replacing that it seems to be fine. I don't understand but sorry if I missed it.