CaiWuXiTong/modules/EcommerceFinance/Repositories/SupplierPayableReportRepository.php
苏木 a1498e6134 feat: 负数预警增加最晚出账单时间 (#1123)
Co-authored-by: 苏木 <594326199@qq.com>
Co-committed-by: 苏木 <594326199@qq.com>
2026-11-11 20:39:09 +08:00

247 lines
9.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Modules\EcommerceFinance\Repositories;
use Modules\EcommerceFinance\Services\UpstreamReadOnlyQuery;
use Modules\EcommerceFinance\Services\UpstreamReadOnlyQueryFactory;
class SupplierPayableReportRepository
{
private const SOURCE = 'jiansun';
private readonly UpstreamReadOnlyQuery $query;
public function __construct(UpstreamReadOnlyQueryFactory $queries)
{
$this->query = $queries->forSource(self::SOURCE);
}
/** @return array{rows:array<int,array<string,mixed>>} */
public function boardDeductions(array $filters, int $page, int $limit): array
{
[$whereSql, $bindings] = $this->boardWhere($filters);
[$offset, $fetch] = $this->pageWindow($page, $limit);
$sql = 'SELECT '
. '[id] AS id, '
. 'CONVERT(varchar(10), [inDate], 23) AS stock_in_date, '
. 'CONVERT(varchar(10), [deliveryDate], 23) AS stock_out_date, '
. '[giveSupplier] AS furniture_factory, '
. '[arrSupplier] AS lamination_factory, '
. '[name] AS deduction_type, '
. '[number] AS specification, '
. '[plainName] AS material_name, '
. '[inCount] AS received_quantity, '
. '[priceA] AS unit_price, '
. '[moneyA] AS amount, '
. 'CAST(NULL AS varchar(10)) AS unit, '
. 'CONVERT(varchar(10), [date], 23) AS batch_date, '
. '[deliveryNo] AS stock_out_number, '
. '[deliveryRemarks] AS stock_out_remark, '
. '[applyNo] AS claim_number, '
. '[numberType] AS number_type, '
. '[sendNo] AS delivery_number '
. 'FROM [dbo].[finance_boardDeduction]'
. $whereSql
. ' ORDER BY [inDate] DESC, [id] DESC'
. " OFFSET {$offset} ROWS FETCH NEXT {$fetch} ROWS ONLY";
return ['rows' => array_map([$this, 'normalizeBoardRow'], $this->query->select($sql, $bindings))];
}
/** @return array{rows:array<int,array<string,mixed>>} */
public function supplierPayables(array $filters, int $page, int $limit): array
{
[$whereSql, $bindings] = $this->payablesWhere($filters);
[$offset, $fetch] = $this->pageWindow($page, $limit);
$sql = 'SELECT '
. '[id] AS id, '
. '[company] AS company, '
. '[supplier] AS supplier, '
. '[checker] AS checker, '
. '[settleway] AS settlement_method, '
. '[ExpFieght] AS express_freight, '
. '[bginMonthPay] AS beginning_payable, '
. '[unpriced] AS unpriced, '
. '[advloan] AS advance_loan, '
. '[loan] AS loan, '
. '[refund] AS refund, '
. '[procurement] AS procurement, '
. '[invoiceDct] AS invoice_deduction, '
. '[boardDct] AS board_deduction, '
. '[specimenDct] AS sample_deduction, '
. '[Totalindemnity] AS total_compensation, '
. '[other] AS other_adjustment, '
. '[supplySup] AS supplier_supplement, '
. '[billRemaining] AS supplier_balance, '
. '[ShouldPay] AS should_pay, '
. '[guessPrice] AS estimated_price, '
. '[toCorporate] AS to_corporate, '
. '[toPrivate] AS to_private, '
. '[factPay] AS actual_pay, '
. '[remarks] AS remarks, '
. '[reason] AS private_reason, '
. '[mark] AS negative_reason, '
. '[Month] AS month, '
. '[depositMoney] AS deposit, '
. '[cashierbypaid] AS cashier_paid, '
. '[isPayment] AS is_payment, '
. 'CONVERT(varchar(19), [createTime], 120) AS created_at, '
. 'CONVERT(varchar(19), [modifiedTime], 120) AS modified_at '
. 'FROM [dbo].[fys_supplierPaymentSummary]'
. $whereSql
. ' ORDER BY [id] DESC'
. " OFFSET {$offset} ROWS FETCH NEXT {$fetch} ROWS ONLY";
return ['rows' => array_map([$this, 'normalizePayableRow'], $this->query->select($sql, $bindings))];
}
/**
* 按月份读取供应商应付表最晚出账时间(上游 modifiedTime)。
*
* @param list<string> $months
* @return list<array{month:string,supplier:string,checker:string,settlement_method:string,modified_at:string}>
*/
public function latestModifiedTimes(array $months): array
{
$months = array_values(array_unique(array_filter(
array_map(static fn (mixed $month): string => trim((string) $month), $months),
static fn (string $month): bool => preg_match('/^\d{4}-\d{2}$/', $month) === 1,
)));
if ($months === []) {
return [];
}
$placeholders = implode(',', array_fill(0, count($months), '?'));
$sql = 'SELECT '
. '[Month] AS month, '
. '[supplier] AS supplier, '
. '[checker] AS checker, '
. '[settleway] AS settlement_method, '
. 'CONVERT(varchar(19), MAX([modifiedTime]), 120) AS modified_at '
. 'FROM [dbo].[fys_supplierPaymentSummary] '
. "WHERE [Month] IN ({$placeholders}) "
. 'GROUP BY [Month], [supplier], [checker], [settleway]';
return array_map(
static fn (array $row): array => [
'month' => trim((string) ($row['month'] ?? '')),
'supplier' => trim((string) ($row['supplier'] ?? '')),
'checker' => trim((string) ($row['checker'] ?? '')),
'settlement_method' => trim((string) ($row['settlement_method'] ?? '')),
'modified_at' => trim((string) ($row['modified_at'] ?? '')),
],
$this->query->select($sql, $months),
);
}
/** @return array{0:string,1:array<int,string>} */
private function boardWhere(array $filters): array
{
$where = [];
$bindings = [];
foreach ([
'stock_in_date' => 'inDate',
'stock_out_date' => 'deliveryDate',
] as $filter => $column) {
if (($filters[$filter] ?? '') === '') {
continue;
}
$where[] = "CAST([{$column}] AS date) = ?";
$bindings[] = (string) $filters[$filter];
}
foreach ([
'furniture_factory' => 'giveSupplier',
'lamination_factory' => 'arrSupplier',
'deduction_type' => 'name',
'material_name' => 'plainName',
'claim_number' => 'applyNo',
] as $filter => $column) {
if (($filters[$filter] ?? '') === '') {
continue;
}
$where[] = "[{$column}] LIKE ? ESCAPE '\\'";
$bindings[] = $this->contains((string) $filters[$filter]);
}
return [$where === [] ? '' : ' WHERE ' . implode(' AND ', $where), $bindings];
}
/** @return array{0:string,1:array<int,string>} */
private function payablesWhere(array $filters): array
{
$where = [];
$bindings = [];
if (($filters['month'] ?? '') !== '') {
$where[] = '[Month] = ?';
$bindings[] = (string) $filters['month'];
}
foreach ([
'supplier' => 'supplier',
'checker' => 'checker',
'settlement_method' => 'settleway',
] as $filter => $column) {
if (($filters[$filter] ?? '') === '') {
continue;
}
$where[] = "[{$column}] LIKE ? ESCAPE '\\'";
$bindings[] = $this->contains((string) $filters[$filter]);
}
return [$where === [] ? '' : ' WHERE ' . implode(' AND ', $where), $bindings];
}
/** @return array{0:int,1:int} */
private function pageWindow(int $page, int $limit): array
{
$page = max($page, 1);
$limit = min(max($limit, 1), 100);
return [($page - 1) * $limit, $limit + 1];
}
private function contains(string $value): string
{
return '%' . str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], trim($value)) . '%';
}
/** @param array<string,mixed> $row */
private function normalizeBoardRow(array $row): array
{
foreach (['received_quantity', 'unit_price', 'amount'] as $field) {
$row[$field] = $this->number($row[$field] ?? null);
}
return $row;
}
/** @param array<string,mixed> $row */
private function normalizePayableRow(array $row): array
{
foreach ([
'express_freight', 'beginning_payable', 'unpriced', 'advance_loan', 'loan',
'refund', 'procurement', 'invoice_deduction', 'board_deduction',
'sample_deduction', 'total_compensation', 'other_adjustment',
'supplier_supplement', 'supplier_balance', 'should_pay', 'estimated_price',
'to_corporate', 'to_private', 'actual_pay', 'deposit', 'cashier_paid',
] as $field) {
$row[$field] = $this->number($row[$field] ?? null);
}
$row['is_payment'] = (bool) ($row['is_payment'] ?? false);
return $row;
}
private function number(mixed $value): ?float
{
return $value === null || $value === '' ? null : (float) $value;
}
}