CaiWuXiTong/modules/EcommerceFinance/Services/FinanceLedgerAccountTemplate.php

208 lines
8.4 KiB
PHP

<?php
namespace Modules\EcommerceFinance\Services;
use App\Utilities\FinanceLedgerAccountStatus;
use App\Utilities\FinanceLedgerAccountShouldKeep;
use App\Utilities\FinanceLedgerAccountType;
use Illuminate\Support\Facades\DB;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataValidation;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Symfony\Component\HttpFoundation\StreamedResponse;
/**
* 财务台账账户总表空白录入模板。
*/
class FinanceLedgerAccountTemplate
{
private const MAX_ROWS = 1000;
private const HEADERS = [
'公司名称',
'账户简称',
'账户类型',
'账户状态',
'地区',
'账号',
'开户行',
'开户城市/网点',
'公司规划',
'账户是否保留',
'后4位',
'单笔限额',
'日限额',
'月限额',
'年限额',
'可用金额',
'不可用金额',
'每日可出',
'预计出清天数',
'提额目标',
'提额状态',
'提额动作',
'已做动作',
'下一步',
'备注',
'责任人',
];
public function download(): StreamedResponse
{
$spreadsheet = $this->makeSpreadsheet();
return response()->streamDownload(function () use ($spreadsheet): void {
$writer = new Xlsx($spreadsheet);
$writer->setPreCalculateFormulas(false);
$writer->save('php://output');
$spreadsheet->disconnectWorksheets();
}, '财务台账-账户总表录入模板.xlsx', [
'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'Cache-Control' => 'no-store, no-cache, must-revalidate',
]);
}
private function makeSpreadsheet(): Spreadsheet
{
$spreadsheet = new Spreadsheet();
$spreadsheet->getProperties()
->setTitle('财务台账账户总表录入模板')
->setSubject('账户总表重新录入');
$sheet = $spreadsheet->getActiveSheet();
$sheet->setTitle('账户总表');
$lastColumn = Coordinate::stringFromColumnIndex(count(self::HEADERS));
$lastRow = self::MAX_ROWS + 1;
foreach (self::HEADERS as $index => $header) {
$column = Coordinate::stringFromColumnIndex($index + 1);
$sheet->setCellValue("{$column}1", $header);
$sheet->getColumnDimension($column)->setWidth($this->width($index));
}
$sheet->freezePane('A2');
$sheet->setAutoFilter("A1:{$lastColumn}1");
$sheet->getRowDimension(1)->setRowHeight(28);
$sheet->getStyle("A1:{$lastColumn}1")->getAlignment()
->setHorizontal(Alignment::HORIZONTAL_CENTER)
->setVertical(Alignment::VERTICAL_CENTER)
->setWrapText(true);
$sheet->getStyle("A1:{$lastColumn}1")->getFont()->setBold(true)->getColor()->setARGB('FFFFFFFF');
$sheet->getStyle("A1:{$lastColumn}1")->getFill()
->setFillType(Fill::FILL_SOLID)
->getStartColor()->setARGB('FF856632');
$sheet->getStyle("A1:{$lastColumn}{$lastRow}")->getBorders()->getAllBorders()
->setBorderStyle(Border::BORDER_THIN)->getColor()->setARGB('FFD8D2C7');
$sheet->getStyle("A2:O{$lastRow}")->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_TEXT);
$sheet->getStyle("P2:R{$lastRow}")->getNumberFormat()->setFormatCode('#,##0.00');
$sheet->getStyle("S2:S{$lastRow}")->getNumberFormat()->setFormatCode('0.00');
$sheet->getStyle("T2:Z{$lastRow}")->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_TEXT);
$options = $spreadsheet->createSheet();
$options->setTitle('选项');
$options->setCellValue('A1', '账户状态');
$options->setCellValue('B1', '账户类型');
$options->setCellValue('C1', '账户是否保留');
$statuses = array_values(FinanceLedgerAccountStatus::OPTIONS);
$types = $this->accountTypes();
$keepOptions = FinanceLedgerAccountShouldKeep::OPTIONS;
foreach ($statuses as $index => $status) {
$options->setCellValue('A' . ($index + 2), $status);
}
foreach ($types as $index => $type) {
$options->setCellValue('B' . ($index + 2), $type);
}
foreach ($keepOptions as $index => $option) {
$options->setCellValue('C' . ($index + 2), $option);
}
$options->setSheetState(Worksheet::SHEETSTATE_HIDDEN);
$this->applyListValidation($sheet, 'D', '\'选项\'!$A$2:$A$' . (count($statuses) + 1), '请选择账户状态');
if ($types !== []) {
$this->applyListValidation($sheet, 'C', '\'选项\'!$B$2:$B$' . (count($types) + 1), '请选择账户类型');
}
$this->applyListValidation($sheet, 'J', '\'选项\'!$C$2:$C$' . (count($keepOptions) + 1), '请选择账户是否保留');
$notes = $spreadsheet->createSheet();
$notes->setTitle('填写说明');
$notes->fromArray([
['项目', '说明'],
['用途', '账户总表重新录入模板,不包含当前账户数据。'],
['必填', '公司名称、账户简称。'],
['账户状态', implode(' / ', $statuses)],
['账户类型', $types !== [] ? implode(' / ', $types) : '留空或按实际填写'],
['账户是否保留', implode(' / ', $keepOptions)],
['金额', '可用金额、不可用金额、每日可出按数字填写;限额列保留原有组合写法。'],
['提交前', '请核对账户数、余额合计和期初合计,再导入系统。'],
], null, 'A1');
$notes->getColumnDimension('A')->setWidth(16);
$notes->getColumnDimension('B')->setWidth(70);
$notes->getStyle('A1:B1')->getFont()->setBold(true)->getColor()->setARGB('FFFFFFFF');
$notes->getStyle('A1:B1')->getFill()
->setFillType(Fill::FILL_SOLID)
->getStartColor()->setARGB('FF856632');
$notes->getStyle('A1:B8')->getAlignment()->setVertical(Alignment::VERTICAL_TOP)->setWrapText(true);
$notes->getStyle('A1:B8')->getBorders()->getAllBorders()
->setBorderStyle(Border::BORDER_THIN)->getColor()->setARGB('FFD8D2C7');
$notes->getRowDimension(1)->setRowHeight(26);
$spreadsheet->setActiveSheetIndex(0);
return $spreadsheet;
}
private function applyListValidation(
Worksheet $sheet,
string $column,
string $formula,
string $prompt,
): void {
$validation = $sheet->getCell("{$column}2")->getDataValidation();
$validation->setType(DataValidation::TYPE_LIST);
$validation->setErrorStyle(DataValidation::STYLE_STOP);
$validation->setAllowBlank(true);
$validation->setShowInputMessage(true);
$validation->setPromptTitle('选择' . $prompt);
$validation->setPrompt($prompt);
$validation->setShowErrorMessage(true);
$validation->setErrorTitle('选项无效');
$validation->setError($prompt);
$validation->setFormula1($formula);
$validation->setShowDropDown(true);
for ($row = 2; $row <= self::MAX_ROWS + 1; $row++) {
$sheet->getCell("{$column}{$row}")->setDataValidation(clone $validation);
}
}
private function accountTypes(): array
{
$connection = DB::connection((string) config('upstream_mirrors.connection', 'business_mirror'));
$base = $connection->table('fin_accounts')
->whereNotNull('account_type')->where('account_type', '<>', '')
->distinct()->pluck('account_type')->all();
$overrides = $connection->table('fin_account_type_overrides')
->whereNotNull('account_type')->where('account_type', '<>', '')
->distinct()->pluck('account_type')->all();
return FinanceLedgerAccountType::options($base, $overrides);
}
private function width(int $index): int
{
return match ($index) {
0, 6 => 30,
1, 5, 7, 24 => 22,
2, 3, 4, 8, 9, 18 => 13,
15, 16, 17 => 16,
default => 18,
};
}
}