ResearchExpenseSummarySheetExport.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <?php
  2. namespace App\Exports;
  3. use Maatwebsite\Excel\Concerns\WithEvents;
  4. use Maatwebsite\Excel\Concerns\WithTitle;
  5. use Maatwebsite\Excel\Events\AfterSheet;
  6. use PhpOffice\PhpSpreadsheet\Style\Alignment;
  7. use PhpOffice\PhpSpreadsheet\Style\Border;
  8. class ResearchExpenseSummarySheetExport implements WithEvents, WithTitle
  9. {
  10. protected $year;
  11. protected $items;
  12. protected $taxId;
  13. protected $companyName;
  14. public function __construct($year, array $payload)
  15. {
  16. $this->year = $year;
  17. $this->items = $payload['items'] ?? [];
  18. $this->taxId = $payload['tax_id'] ?? '';
  19. $this->companyName = $payload['company_name'] ?? '';
  20. }
  21. public function title(): string { return $this->year . '年汇总表'; }
  22. public function registerEvents(): array
  23. {
  24. return [
  25. AfterSheet::class => function (AfterSheet $event) {
  26. $sheet = $event->sheet->getDelegate();
  27. // 1. 设置列宽 (A-Q)
  28. $widths = ['A'=>12, 'B'=>40, 'C'=>10, 'D'=>12, 'E'=>18, 'F'=>12, 'G'=>12, 'H'=>12, 'I'=>12, 'J'=>12, 'K'=>15, 'L'=>12, 'M'=>12, 'N'=>12, 'O'=>12, 'P'=>12, 'Q'=>12];
  29. foreach ($widths as $col => $w) { $sheet->getColumnDimension($col)->setWidth($w); }
  30. // 2. 绘制表头 (去大标题样式)
  31. $this->drawCorrectHeader($sheet);
  32. // 3. 填充数据
  33. $currentRow = 8;
  34. $capRows = []; // 仅存 资本化且已完成(status=3) 的行
  35. $expRows = []; // 存 费用化 的行
  36. foreach ($this->items as $item) {
  37. $sheet->setCellValue("A{$currentRow}", $item['no']);
  38. $sheet->setCellValue("B{$currentRow}", $item['name']);
  39. $sheet->setCellValue("C{$currentRow}", $item['status'] == 3 ? '已完成' : '进行中');
  40. $sheet->setCellValue("D{$currentRow}", $item['type']);
  41. // 原始数据
  42. $sheet->setCellValue("F{$currentRow}", $item['val1']); // 1.人工
  43. $sheet->setCellValue("G{$currentRow}", $item['val2']); // 2.投入
  44. $sheet->setCellValue("H{$currentRow}", $item['val3']); // 3.折旧
  45. $sheet->setCellValue("I{$currentRow}", $item['val4']); // 4.摊销
  46. $sheet->setCellValue("J{$currentRow}", $item['val5']); // 5.新产品
  47. $sheet->setCellValue("L{$currentRow}", $item['val7_1']); // 7.1
  48. $sheet->setCellValue("N{$currentRow}", $item['val8_1']); // 8.1
  49. $sheet->setCellValue("P{$currentRow}", $item['val8_3'] ?? 0); // 8.3
  50. // 【逻辑修正】明细行公式
  51. $sheet->setCellValue("K{$currentRow}", "=SUM(F{$currentRow}:J{$currentRow})"); // 6列
  52. $sheet->setCellValue("O{$currentRow}", "=N{$currentRow}*0.8"); // 8.2 = 8.1 * 80%
  53. // 明细行不限制 7.2 和 8.4,通常直接取 7.1 和 8.3
  54. $sheet->setCellValue("M{$currentRow}", "=L{$currentRow}"); // 7.2
  55. $sheet->setCellValue("Q{$currentRow}", "=P{$currentRow}"); // 8.4
  56. // E列 = 6 + 7.2 + 8.2 + 8.4
  57. $sheet->setCellValue("E{$currentRow}", "=K{$currentRow}+M{$currentRow}+O{$currentRow}+Q{$currentRow}");
  58. if ($item['type'] == '资本化支出' && $item['status'] == 3) {
  59. $capRows[] = $currentRow;
  60. } elseif ($item['type'] == '费用化支出') {
  61. $expRows[] = $currentRow;
  62. }
  63. $currentRow++;
  64. }
  65. // 4. 合计行勾稽计算
  66. $this->applySummaryLogic($sheet, $currentRow, $capRows, $expRows);
  67. // 5. 样式设置
  68. $lastDataRow = $currentRow + 3;
  69. $sheet->getStyle("A5:Q{$lastDataRow}")->applyFromArray(['borders' => ['allBorders' => ['borderStyle' => Border::BORDER_THIN]]]);
  70. $sheet->getStyle("E8:Q{$lastDataRow}")->getNumberFormat()->setFormatCode('#,##0.00');
  71. $sheet->getStyle("A5:Q7")->getAlignment()->setWrapText(true)->setHorizontal('center')->setVertical('center');
  72. // 签字行
  73. $sheet->setCellValue("A" . ($lastDataRow + 1), "法定代表人(签章):");
  74. },
  75. ];
  76. }
  77. private function drawCorrectHeader($sheet)
  78. {
  79. $sheet->mergeCells('A2:Q2');
  80. $sheet->setCellValue('A2', '研发支出辅助账汇总表');
  81. $sheet->getStyle('A2')->getAlignment()->setHorizontal('center');
  82. $sheet->getStyle('A2')->getFont()->setSize(16)->setBold(true);
  83. $sheet->setCellValue('A3', '纳税人识别号:' . $this->taxId);
  84. $sheet->setCellValue('J3', '纳税人名称:' . $this->companyName);
  85. $sheet->setCellValue('O3', "属期:{$this->year}年");
  86. $sheet->setCellValue('Q3', '单位:元');
  87. $vHeaders = ['A'=>'项目编号', 'B'=>'项目名称', 'C'=>'完成情况', 'D'=>'支出类型', 'E'=>"允许加计\n扣除金额合计"];
  88. foreach ($vHeaders as $col => $text) {
  89. $sheet->mergeCells("{$col}5:{$col}7");
  90. $sheet->setCellValue("{$col}5", $text);
  91. }
  92. $subHeaders = ['F'=>'人员人工费用', 'G'=>'直接投入费用', 'H'=>'折旧费用', 'I'=>'无形资产摊销', 'J'=>'新产品设计费等', 'K'=>'前五项 小计'];
  93. foreach ($subHeaders as $col => $text) {
  94. $sheet->mergeCells("{$col}5:{$col}6");
  95. $sheet->setCellValue("{$col}5", $text);
  96. }
  97. $sheet->mergeCells('L5:M5'); $sheet->setCellValue('L5', '其他相关费用及限额');
  98. $sheet->setCellValue('L6', '其他相关费用合计'); $sheet->setCellValue('M6', "经限额调整后的\n其他相关费用");
  99. $sheet->mergeCells('N5:Q5'); $sheet->setCellValue('N5', '委托研发费用及限额');
  100. $sheet->setCellValue('N6', "委托境内机构或\n个人研发费用"); $sheet->setCellValue('O6', "允许加计扣除的\n委托境内研发费");
  101. $sheet->setCellValue('P6', "委托境外机构\n进行研发活动费"); $sheet->setCellValue('Q6', "经限额调整后的\n委托境外研发费");
  102. $nums = ['F'=>'1','G'=>'2','H'=>'3','I'=>'4','J'=>'5','K'=>'6','L'=>'7.1','M'=>'7.2','N'=>'8.1','O'=>'8.2','P'=>'8.3','Q'=>'8.4'];
  103. foreach ($nums as $col => $n) { $sheet->setCellValue("{$col}7", $n); }
  104. }
  105. private function applySummaryLogic($sheet, $r, $capRows, $expRows)
  106. {
  107. $r_cap = $r; $r_exp = $r + 1; $r_oth = $r + 2; $r_all = $r + 3;
  108. $labels = ['资本化金额小计', '费用化金额小计', '其中:其他事项', '全额合计'];
  109. foreach ($labels as $i => $label) {
  110. $sheet->mergeCells("A" . ($r+$i) . ":D" . ($r+$i));
  111. $sheet->setCellValue("A" . ($r+$i), $label);
  112. }
  113. // 基础汇总列 (F,G,H,I,J,L,N,P)
  114. $cols = ['F', 'G', 'H', 'I', 'J', 'L', 'N', 'P'];
  115. foreach ($cols as $col) {
  116. $f_cap = !empty($capRows) ? "=SUM(".implode(',', array_map(fn($row)=>"{$col}{$row}", $capRows)).")" : "0";
  117. $f_exp = !empty($expRows) ? "=SUM(".implode(',', array_map(fn($row)=>"{$col}{$row}", $expRows)).") + {$col}{$r_oth}" : "{$col}{$r_oth}";
  118. $sheet->setCellValue("{$col}{$r_cap}", $f_cap);
  119. $sheet->setCellValue("{$col}{$r_exp}", $f_exp);
  120. $sheet->setCellValue("{$col}{$r_all}", "={$col}{$r_cap}+{$col}{$r_exp}");
  121. }
  122. // --- 核心勾稽逻辑修正 ---
  123. foreach ([$r_cap, $r_exp, $r_all] as $row) {
  124. $sheet->setCellValue("K{$row}", "=SUM(F{$row}:J{$row})"); // 6列
  125. $sheet->setCellValue("O{$row}", "=N{$row}*0.8"); // 8.2列
  126. // 修正:7.2列 (规则六)
  127. if ($row == $r_all) {
  128. $sheet->setCellValue("M{$row}", "=MIN(L{$row}, K{$row}*0.1/0.9)");
  129. } else {
  130. $sheet->setCellValue("M{$row}", "=IF(L{$r_all}>0, (M{$r_all}/L{$r_all})*L{$row}, 0)");
  131. }
  132. // 修正:8.4列 (规则八:金额合计行计算公式)
  133. if ($row == $r_all) {
  134. // 1. 金额合计 = MIN((6列+7.2列+8.2列)*2/3, 8.3列*80%)
  135. $sheet->setCellValue("Q{$row}", "=MIN((K{$row}+M{$row}+O{$row})*2/3, P{$row}*0.8)");
  136. } else {
  137. // 分摊逻辑
  138. $sheet->setCellValue("Q{$row}", "=IF(P{$r_all}>0, (Q{$r_all}/P{$r_all})*P{$row}, 0)");
  139. }
  140. // 修正:E列 (规则四:E = 6+7.2+8.2+8.4)
  141. $sheet->setCellValue("E{$row}", "=K{$row}+M{$row}+O{$row}+Q{$row}");
  142. }
  143. }
  144. }