middleware('auth'); $this->middleware('company.identify'); } public function export(Request $request): StreamedResponse { $requestedPeriod = trim((string) $request->query('month', '')); $period = preg_match('/^\d{4}-\d{2}$/', $requestedPeriod) === 1 ? $requestedPeriod : now()->subMonthNoOverflow()->format('Y-m'); $companyId = (int) (company_id() ?: 1); $deliveryRows = $this->periodRows( PayablesUnpricedCycleProcessor::DELIVERY_PRICED_DATASET, $period, $companyId, ); $returnRows = $this->periodRows( PayablesUnpricedCycleProcessor::RETURN_PRICED_DATASET, $period, $companyId, ); $deliverySummary = $this->summary($deliveryRows, 'guessAmount', 'amount'); $returnSummary = $this->summary($returnRows, 'guess_amount', 'amount'); $spreadsheet = new Spreadsheet(); $summarySheet = $spreadsheet->getActiveSheet(); $summarySheet->setTitle('账期汇总'); $summarySheet->fromArray([ ['类型', '记录数', '件数', '金额', '预估金额'], ['送货未定价', $deliverySummary['count'], $deliverySummary['quantity'], $deliverySummary['amount'], $deliverySummary['estimated_amount']], ['退货未定价', $returnSummary['count'], $returnSummary['quantity'], $returnSummary['amount'], $returnSummary['estimated_amount']], ], null, 'A1'); $this->styleSheet($summarySheet, 5, 3, [2 => 'number', 3 => 'number', 4 => 'number', 5 => 'number']); $summarySheet->getColumnDimension('A')->setWidth(18); foreach (['B', 'C', 'D', 'E'] as $column) { $summarySheet->getColumnDimension($column)->setWidth(18); } $deliverySheet = $spreadsheet->createSheet(); $this->writeDetailSheet( $deliverySheet, '送货未定价', $this->registry->fields(PayablesFinalRegistry::SECTION_SUPPLIER, 'delivery-unpriced'), $deliveryRows, ); $returnSheet = $spreadsheet->createSheet(); $this->writeDetailSheet( $returnSheet, '退货未定价', $this->registry->fields(PayablesFinalRegistry::SECTION_SUPPLIER, 'return-unpriced'), $returnRows, ); $spreadsheet->setActiveSheetIndex(0); $fileName = '之前月未定价-本月定价_' . $period . '_' . now()->format('Ymd_His') . '.xlsx'; return response()->streamDownload(function () use ($spreadsheet): void { (new Xlsx($spreadsheet))->save('php://output'); $spreadsheet->disconnectWorksheets(); }, $fileName, [ 'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'Cache-Control' => 'private, no-store', ]); } /** * @return list> */ private function periodRows(string $dataset, string $period, int $companyId): array { return array_values(array_filter( $this->store->listRows($dataset, $companyId), static fn (array $row): bool => (string) ($row['_accounting_period'] ?? '') === $period, )); } /** * @param list> $rows * @return array{count:int,quantity:float,amount:float,estimated_amount:float} */ private function summary(array $rows, string $estimatedAmountField, string $amountField): array { $quantity = 0.0; $amount = 0.0; $estimatedAmount = 0.0; foreach ($rows as $row) { if (is_numeric($row['qty'] ?? null)) { $quantity += (float) $row['qty']; } if (is_numeric($row[$amountField] ?? null)) { $amount += (float) $row[$amountField]; } if (is_numeric($row[$estimatedAmountField] ?? null)) { $estimatedAmount += (float) $row[$estimatedAmountField]; } } return [ 'count' => count($rows), 'quantity' => $quantity, 'amount' => $amount, 'estimated_amount' => $estimatedAmount, ]; } /** * @param array $fields * @param list> $rows */ private function writeDetailSheet( \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet, string $title, array $fields, array $rows, ): void { $sheet->setTitle($title); $headers = array_merge(['序号'], array_column($fields, 'label')); $sheet->fromArray($headers, null, 'A1'); $data = []; foreach ($rows as $index => $row) { $line = [$index + 1]; foreach ($fields as $field => $definition) { $value = $row[$field] ?? ''; $line[] = $definition['type'] === 'number' && is_numeric($value) ? (float) $value : (string) $value; } $data[] = $line; } if ($data !== []) { $sheet->fromArray($data, null, 'A2'); } $lastColumn = Coordinate::stringFromColumnIndex(count($headers)); $lastRow = max(1, count($data) + 1); $types = []; $columnIndex = 2; foreach ($fields as $definition) { if ($definition['type'] === 'number') { $types[$columnIndex] = 'number'; } $column = Coordinate::stringFromColumnIndex($columnIndex); $sheet->getColumnDimension($column)->setWidth(min(32, max(12, mb_strlen($definition['label']) * 2 + 5))); $columnIndex++; } $sheet->getColumnDimension('A')->setWidth(9); $this->styleSheet($sheet, count($headers), $lastRow, $types); $sheet->freezePane('A2'); $sheet->setAutoFilter('A1:' . $lastColumn . $lastRow); } /** * @param array $types */ private function styleSheet( \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet, int $columnCount, int $rowCount, array $types, ): void { $lastColumn = Coordinate::stringFromColumnIndex($columnCount); $headerRange = 'A1:' . $lastColumn . '1'; $sheet->getStyle($headerRange)->applyFromArray([ 'font' => ['bold' => true, 'color' => ['rgb' => 'FFFFFF']], 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => '856632']], 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER], 'borders' => ['allBorders' => ['borderStyle' => Border::BORDER_THIN, 'color' => ['rgb' => 'D8D2C7']]], ]); $sheet->getRowDimension(1)->setRowHeight(24); if ($rowCount > 1) { $sheet->getStyle('A2:' . $lastColumn . $rowCount) ->getBorders() ->getAllBorders() ->setBorderStyle(Border::BORDER_THIN) ->getColor() ->setRGB('E7E2D8'); } foreach ($types as $index => $type) { if ($type !== 'number') { continue; } $column = Coordinate::stringFromColumnIndex($index); $sheet->getStyle($column . '2:' . $column . max(2, $rowCount)) ->getNumberFormat() ->setFormatCode('#,##0.00'); } } }