144 lines
7.0 KiB
PHP
144 lines
7.0 KiB
PHP
<?php
|
|
|
|
namespace Modules\EcommerceFinance\Repositories;
|
|
|
|
use Modules\EcommerceFinance\Services\UpstreamReadOnlyQuery;
|
|
use Modules\EcommerceFinance\Services\UpstreamReadOnlyQueryFactory;
|
|
|
|
/**
|
|
* 原材料库存管理只读数据仓库。
|
|
*/
|
|
class InventoryRepository
|
|
{
|
|
private const SOURCE = 'jiansun';
|
|
|
|
private const SUMMARY_KEYS = [
|
|
'opening_balance',
|
|
'stock_in',
|
|
'lamination_out',
|
|
'inventory',
|
|
'remaining_value',
|
|
'stock_in_amount',
|
|
'closing_remaining_value',
|
|
'previous_remaining_value',
|
|
'stock_out_amount',
|
|
];
|
|
|
|
private ?UpstreamReadOnlyQuery $query = null;
|
|
|
|
public function __construct(private readonly UpstreamReadOnlyQueryFactory $queries)
|
|
{
|
|
}
|
|
|
|
/** @return array{data:array<int,array<string,mixed>>,total:int,totals:array<string,float>} */
|
|
public function boardInventoryDetails(array $filters, int $page, int $limit): array
|
|
{
|
|
$where = [
|
|
's.stockType = ?',
|
|
's.[month] = (SELECT MAX(latest.[month]) FROM [dbo].[pm_boardInventoryDetail_snapshot] latest WHERE latest.stockType = ?)',
|
|
];
|
|
$bindings = ['素板', '素板'];
|
|
|
|
if (($filters['manufacturer'] ?? '') !== '') {
|
|
$where[] = 's.supplier LIKE ? ESCAPE \'\\\'';
|
|
$bindings[] = $this->contains($filters['manufacturer']);
|
|
}
|
|
if (($filters['specification'] ?? '') !== '') {
|
|
$where[] = 's.name LIKE ? ESCAPE \'\\\'';
|
|
$bindings[] = $this->contains($filters['specification']);
|
|
}
|
|
if (($filters['matching_value'] ?? '') !== '') {
|
|
$where[] = 's.number LIKE ? ESCAPE \'\\\'';
|
|
$bindings[] = $this->contains($filters['matching_value']);
|
|
}
|
|
if (($filters['date_from'] ?? '') !== '') {
|
|
$where[] = 'CONVERT(date, COALESCE(s.[date], s.[month])) >= ?';
|
|
$bindings[] = $filters['date_from'];
|
|
}
|
|
if (($filters['date_to'] ?? '') !== '') {
|
|
$where[] = 'CONVERT(date, COALESCE(s.[date], s.[month])) <= ?';
|
|
$bindings[] = $filters['date_to'];
|
|
}
|
|
|
|
$page = max($page, 1);
|
|
$limit = min(max($limit, 1), 100);
|
|
$offset = ($page - 1) * $limit;
|
|
$whereSql = implode(' AND ', $where);
|
|
|
|
$sql = "WITH source_rows AS (
|
|
SELECT
|
|
ISNULL(s.supplier, '') AS manufacturer,
|
|
CONVERT(varchar(10), COALESCE(s.[date], s.[month]), 120) AS [date],
|
|
ISNULL(s.name, '') AS specification,
|
|
ISNULL(s.number, '') AS matching_value,
|
|
CAST(ISNULL(s.lastBalance, 0) AS decimal(18,2)) AS opening_balance,
|
|
CAST(ISNULL(s.averagePrice, 0) AS decimal(18,2)) AS weighted_average_price,
|
|
CAST(ISNULL(s.inCount, 0) AS decimal(18,2)) AS stock_in,
|
|
CAST(ISNULL(s.deliveryCount, 0) AS decimal(18,2)) AS lamination_out,
|
|
CAST(ISNULL(s.balance, 0) AS decimal(18,2)) AS inventory,
|
|
CAST(ISNULL(s.surplusPrice, 0) AS decimal(18,2)) AS remaining_value,
|
|
CAST(ISNULL(s.inCount, 0) * ISNULL(s.averagePrice, 0) AS decimal(18,2)) AS stock_in_amount,
|
|
CAST(ISNULL(s.balance, 0) * ISNULL(s.averagePrice, 0) AS decimal(18,2)) AS closing_remaining_value,
|
|
CAST(ISNULL(s.lastBalance, 0) * ISNULL(s.averagePrice, 0) AS decimal(18,2)) AS previous_remaining_value,
|
|
CAST(ISNULL(s.deliveryCount, 0) * ISNULL(s.averagePrice, 0) AS decimal(18,2)) AS stock_out_amount,
|
|
CAST(SUM(CAST(ISNULL(s.lastBalance, 0) AS decimal(38,2))) OVER () AS decimal(18,2)) AS summary_opening_balance,
|
|
CAST(SUM(CAST(ISNULL(s.inCount, 0) AS decimal(38,2))) OVER () AS decimal(18,2)) AS summary_stock_in,
|
|
CAST(SUM(CAST(ISNULL(s.deliveryCount, 0) AS decimal(38,2))) OVER () AS decimal(18,2)) AS summary_lamination_out,
|
|
CAST(SUM(CAST(ISNULL(s.balance, 0) AS decimal(38,2))) OVER () AS decimal(18,2)) AS summary_inventory,
|
|
CAST(SUM(CAST(ISNULL(s.surplusPrice, 0) AS decimal(38,2))) OVER () AS decimal(18,2)) AS summary_remaining_value,
|
|
CAST(SUM(CAST(ISNULL(s.inCount, 0) * ISNULL(s.averagePrice, 0) AS decimal(38,2))) OVER () AS decimal(18,2)) AS summary_stock_in_amount,
|
|
CAST(SUM(CAST(ISNULL(s.balance, 0) * ISNULL(s.averagePrice, 0) AS decimal(38,2))) OVER () AS decimal(18,2)) AS summary_closing_remaining_value,
|
|
CAST(SUM(CAST(ISNULL(s.lastBalance, 0) * ISNULL(s.averagePrice, 0) AS decimal(38,2))) OVER () AS decimal(18,2)) AS summary_previous_remaining_value,
|
|
CAST(SUM(CAST(ISNULL(s.deliveryCount, 0) * ISNULL(s.averagePrice, 0) AS decimal(38,2))) OVER () AS decimal(18,2)) AS summary_stock_out_amount,
|
|
ROW_NUMBER() OVER (
|
|
ORDER BY COALESCE(s.[date], s.[month]) DESC, s.supplier, s.name, s.number, s.id DESC
|
|
) AS row_no,
|
|
COUNT(*) OVER () AS total_count
|
|
FROM [dbo].[pm_boardInventoryDetail_snapshot] s
|
|
WHERE {$whereSql}
|
|
)
|
|
SELECT manufacturer, [date], specification, matching_value,
|
|
opening_balance, weighted_average_price, stock_in, lamination_out,
|
|
inventory, remaining_value, stock_in_amount, closing_remaining_value,
|
|
previous_remaining_value, stock_out_amount,
|
|
summary_opening_balance, summary_stock_in, summary_lamination_out,
|
|
summary_inventory, summary_remaining_value, summary_stock_in_amount,
|
|
summary_closing_remaining_value, summary_previous_remaining_value,
|
|
summary_stock_out_amount, total_count
|
|
FROM source_rows
|
|
WHERE row_no BETWEEN ? AND ?
|
|
ORDER BY row_no";
|
|
|
|
$rows = $this->query()->select($sql, array_merge($bindings, [$offset + 1, $offset + $limit]));
|
|
$totals = array_fill_keys(self::SUMMARY_KEYS, 0.0);
|
|
|
|
if ($rows !== []) {
|
|
foreach (self::SUMMARY_KEYS as $key) {
|
|
$totals[$key] = (float) ($rows[0]['summary_' . $key] ?? 0);
|
|
}
|
|
}
|
|
|
|
$total = (int) ($rows[0]['total_count'] ?? 0);
|
|
|
|
foreach ($rows as &$row) {
|
|
unset($row['total_count']);
|
|
|
|
foreach (self::SUMMARY_KEYS as $key) {
|
|
unset($row['summary_' . $key]);
|
|
}
|
|
}
|
|
|
|
return ['data' => $rows, 'total' => $total, 'totals' => $totals];
|
|
}
|
|
|
|
private function query(): UpstreamReadOnlyQuery
|
|
{
|
|
return $this->query ??= $this->queries->forSource(self::SOURCE);
|
|
}
|
|
|
|
private function contains(string $value): string
|
|
{
|
|
return '%' . str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], trim($value)) . '%';
|
|
}
|
|
}
|