CaiWuXiTong/modules/EcommerceFinance/Repositories/InternalFlowReportRepository.php
WuYongJie 8419d4097c feat: 内部流转报表导入工作簿数据并支持查询导出
- 新增共享镜像表 business_internal_flow_records 与整份替换导入命令 internal-flow:import
- 按 Excel 表头展示抬头、标签、预计9月销量、开票、所需进项成本、收票、剩余缺口与开票比例
- 复用公司基础信息的字段查询、表头排序、筛选字段与导出 Excel 交互
- 新增导入与页面测试,覆盖合计行跳过、重导入替换、筛选排序与未导入空状态
2026-10-06 22:08:08 +08:00

90 lines
2.6 KiB
PHP

<?php
namespace Modules\EcommerceFinance\Repositories;
use Illuminate\Database\ConnectionInterface;
use Modules\EcommerceFinance\Services\InternalFlowWorkbookImporter;
/**
* 内部流转报表读取共享业务镜像中的导入结果。
*
* 页面只读;数据由 InternalFlowWorkbookImporter 按整份工作簿替换导入。
*/
class InternalFlowReportRepository
{
public const TABLE = InternalFlowWorkbookImporter::TABLE;
/** 允许排序的列,防止把用户输入拼进 SQL。 */
public const SORTABLE = [
'company_name',
'tag',
'projected_sales',
'invoiced_to_buyer',
'internal_invoiced',
'required_input_cost',
'receipt_from_supplier',
'receipt_from_suofeiya',
'receipt_from_gujia',
'internal_transfer_1',
'internal_transfer_2',
'internal_transfer_3',
'receipt_total',
'remaining_gap',
'invoicing_ratio',
];
private readonly ConnectionInterface $connection;
public function __construct(GenericBusinessMirrorRepository $mirror)
{
$this->connection = $mirror->connection();
}
public function ready(): bool
{
return $this->connection->getSchemaBuilder()->hasTable(self::TABLE);
}
/**
* @param array{company_name?:string,tag?:string} $filters
* @return array{data: list<array<string,mixed>>, total: int}
*/
public function paginate(int $page, int $perPage, array $filters = [], ?string $sort = null, string $direction = 'asc'): array
{
if (! $this->ready()) {
return ['data' => [], 'total' => 0];
}
$query = $this->connection->table(self::TABLE);
$companyName = trim((string) ($filters['company_name'] ?? ''));
if ($companyName !== '') {
$query->where('company_name', 'like', '%' . addcslashes($companyName, '%_\\') . '%');
}
$tag = trim((string) ($filters['tag'] ?? ''));
if ($tag !== '') {
$query->where('tag', '=', $tag);
}
$total = (clone $query)->count();
$column = in_array($sort, self::SORTABLE, true) ? $sort : null;
$direction = strtolower($direction) === 'desc' ? 'desc' : 'asc';
if ($column !== null) {
$query->orderBy($column, $direction)->orderBy('sort_order');
} else {
$query->orderBy('sort_order')->orderBy('id');
}
$rows = $query
->forPage(max($page, 1), min(max($perPage, 1), 100))
->get()
->map(static fn (object $row): array => (array) $row)
->all();
return ['data' => $rows, 'total' => $total];
}
}