CaiWuXiTong/modules/EcommerceFinance/Repositories/EdgeBandingRepository.php

294 lines
13 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;
/**
* 原材料-封边条只读数据仓库。
*
* 数据源只暴露固定的 SELECT,页面请求通过 JianSunQueryCache 做快照、限流
* 和熔断。源表中不存在的展示字段使用空值,不从演示数据倒灌真实业务数据。
*/
class EdgeBandingRepository
{
private const SOURCE = 'jiansun';
private ?UpstreamReadOnlyQuery $query = null;
public function __construct(private readonly UpstreamReadOnlyQueryFactory $queries)
{
}
/** @return array{data:array<int,array<string,mixed>>,total:int} */
public function prices(array $filters, int $page, int $limit): array
{
$where = ["p.number LIKE 'FBT%'"];
$bindings = [];
if (($filters['raw_name'] ?? '') !== '') {
$where[] = 'p.name LIKE ? ESCAPE \'\\\'';
$bindings[] = $this->contains($filters['raw_name']);
}
if (($filters['raw_code'] ?? '') !== '') {
$where[] = 'p.number LIKE ? ESCAPE \'\\\'';
$bindings[] = $this->contains($filters['raw_code']);
}
if (($filters['production_code'] ?? '') !== '') {
$where[] = "CONCAT(p.number, 'F01') LIKE ? ESCAPE '\\'";
$bindings[] = $this->contains($filters['production_code']);
}
if (($filters['supplier'] ?? '') !== '') {
$where[] = 'p.supplier LIKE ? ESCAPE \'\\\'';
$bindings[] = $this->contains($filters['supplier']);
}
$whereSql = implode(' AND ', $where);
$page = max($page, 1);
$limit = min(max($limit, 1), 100);
$offset = ($page - 1) * $limit;
$sql = "WITH source_rows AS (
SELECT
p.name AS raw_name,
p.number AS raw_code,
CONCAT(p.number, 'F01') AS production_code,
CAST(p.price AS decimal(18,2)) AS latest_price,
p.supplier AS target_supplier,
ROW_NUMBER() OVER (ORDER BY p.number, p.supplier) AS row_no,
COUNT(*) OVER () AS total_count
FROM [dbo].[pm_averageUnitPrice] p
WHERE {$whereSql}
)
SELECT raw_name, raw_code, production_code,
latest_price, target_supplier, 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]));
foreach ($rows as &$row) {
$row['price_type'] = '采购价';
$row['factory_type'] = '封边条厂';
}
return $this->pageResult($rows);
}
/** @return array{data:array<int,array<string,mixed>>,total:int} */
public function details(array $filters, int $page, int $limit): array
{
$where = ["s.procode LIKE 'FBT%'"];
$bindings = [];
if (($filters['date'] ?? '') !== '') {
$where[] = 'CONVERT(date, s.sendTime) = ?';
$bindings[] = $filters['date'];
}
if (($filters['production_code'] ?? '') !== '') {
$where[] = 's.procode LIKE ? ESCAPE \'\\\'';
$bindings[] = $this->contains($filters['production_code']);
}
if (($filters['raw_name'] ?? '') !== '') {
$where[] = 's.skuname LIKE ? ESCAPE \'\\\'';
$bindings[] = $this->contains($filters['raw_name']);
}
if (($filters['return_flag'] ?? '') === 'return') {
$where[] = 'ISNULL(s.settlementStock, 0) < 0';
} elseif (($filters['return_flag'] ?? '') === 'normal') {
$where[] = 'ISNULL(s.settlementStock, 0) >= 0';
}
if (($filters['outbound_supplier'] ?? '') !== '') {
$where[] = 's.supplier LIKE ? ESCAPE \'\\\'';
$bindings[] = $this->contains($filters['outbound_supplier']);
}
if (($filters['arrival_supplier'] ?? '') !== '') {
$where[] = 's.whName LIKE ? ESCAPE \'\\\'';
$bindings[] = $this->contains($filters['arrival_supplier']);
}
if (($filters['outbound_no'] ?? '') !== '') {
// 现有结算表没有单独的出库单号,快递/送货号作为可检索的外部单号。
$where[] = 'ISNULL(s.expressNo, \'\') LIKE ? ESCAPE \'\\\'';
$bindings[] = $this->contains($filters['outbound_no']);
}
$whereSql = implode(' AND ', $where);
$page = max($page, 1);
$limit = min(max($limit, 1), 100);
$offset = ($page - 1) * $limit;
$sql = "WITH source_rows AS (
SELECT
CONVERT(varchar(19), s.sendTime, 120) AS inbound_date,
s.procode AS production_code,
s.skuname AS raw_name,
CAST(ISNULL(s.settlementStock, 0) AS decimal(18,2)) AS outbound_quantity,
s.supplier AS outbound_supplier,
ISNULL(s.whName, '') AS arrival_supplier,
CONVERT(varchar(10), s.sendTime, 120) AS batch_date,
'' AS outbound_no,
ISNULL(s.remark, '') AS outbound_remark,
'' AS requisition_no,
ISNULL(s.expressNo, '') AS delivery_no,
CAST(ISNULL(s.settlementStock, 0) AS decimal(18,2)) AS received_quantity,
CAST(ISNULL(s.settlementPrice, 0) AS decimal(18,2)) AS reconciliation_amount,
CAST(0 AS decimal(18,2)) AS freight,
CAST(ISNULL(a.price, 0) AS decimal(18,2)) AS edge_band_unit_price,
CAST(ISNULL(s.settlementStock, 0) * ISNULL(a.price, 0) AS decimal(18,2)) AS payable_amount,
CAST(ISNULL(s.singlePrice, 0) AS decimal(18,2)) AS furniture_unit_price,
CAST(ISNULL(s.settlementPrice, 0) AS decimal(18,2)) AS furniture_amount,
CAST(ISNULL(s.singlePrice, 0) - ISNULL(a.price, 0) AS decimal(18,2)) AS price_difference,
CAST(ISNULL(s.settlementPrice, 0) - (ISNULL(s.settlementStock, 0) * ISNULL(a.price, 0)) AS decimal(18,2)) AS profit,
ROW_NUMBER() OVER (ORDER BY s.sendTime DESC, s.Id DESC) AS row_no,
COUNT(*) OVER () AS total_count
FROM [dbo].[fys_supplierGoods_sttlement_sale] s
LEFT JOIN [dbo].[pm_averageUnitPrice] a
ON a.number = s.procode AND a.supplier = s.supplier
WHERE {$whereSql}
)
SELECT inbound_date, production_code, raw_name, outbound_quantity,
outbound_supplier, arrival_supplier, batch_date,
outbound_no, outbound_remark, requisition_no, delivery_no,
received_quantity, reconciliation_amount, freight, edge_band_unit_price,
payable_amount, furniture_unit_price, furniture_amount, price_difference,
profit, 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]));
foreach ($rows as &$row) {
$row['unit'] = '米';
$row['return_flag'] = (float) ($row['outbound_quantity'] ?? 0) < 0 ? '退货' : '正常出库';
$row['number_type'] = '申领';
}
return $this->pageResult($rows);
}
/** @return array{data:array<int,array<string,mixed>>,total:int} */
public function payables(array $filters, int $page, int $limit): array
{
$where = [
"EXISTS (
SELECT 1
FROM [dbo].[pm_averageUnitPrice] edge_price
WHERE edge_price.number LIKE 'FBT%'
AND edge_price.supplier = p.supplier
)",
];
$bindings = [];
if (($filters['period'] ?? '') !== '') {
$where[] = 'p.Month = ?';
$bindings[] = $filters['period'];
}
if (($filters['supplier'] ?? '') !== '') {
$where[] = 'p.supplier LIKE ? ESCAPE \'\\\'';
$bindings[] = $this->contains($filters['supplier']);
}
$whereSql = implode(' AND ', $where);
$page = max($page, 1);
$limit = min(max($limit, 1), 100);
$offset = ($page - 1) * $limit;
$sql = "WITH source_rows AS (
SELECT
p.supplier,
CAST(SUM(ISNULL(p.bginMonthPay, 0)) AS decimal(18,2)) AS month_start_unpaid,
CAST(SUM(ISNULL(p.loan, 0)) AS decimal(18,2)) AS goods_amount,
CAST(SUM(ISNULL(p.ExpFieght, 0)) AS decimal(18,2)) AS prepaid_freight,
CAST(SUM(ISNULL(p.Totalindemnity, 0)) AS decimal(18,2)) AS compensation,
CAST(SUM(ISNULL(p.supplySup, 0)) AS decimal(18,2)) AS supplier_refund,
CAST(SUM(ISNULL(p.ShouldPay, 0)) AS decimal(18,2)) AS payable_amount,
CAST(SUM(ISNULL(p.factPay, 0)) AS decimal(18,2)) AS paid_amount,
CAST(SUM(ISNULL(p.cashierbypaid, 0)) AS decimal(18,2)) AS actual_payment,
CAST(SUM(ISNULL(p.toPrivate, 0)) AS decimal(18,2)) AS private_payment,
CAST(SUM(ISNULL(p.toCorporate, 0)) AS decimal(18,2)) AS corporate_payment,
MAX(ISNULL(p.remarks, '')) AS remark,
CAST(SUM(SUM(ISNULL(p.bginMonthPay, 0))) OVER () AS decimal(18,2)) AS summary_month_start_unpaid,
CAST(SUM(SUM(ISNULL(p.loan, 0))) OVER () AS decimal(18,2)) AS summary_goods_amount,
CAST(SUM(SUM(ISNULL(p.ExpFieght, 0))) OVER () AS decimal(18,2)) AS summary_prepaid_freight,
CAST(SUM(SUM(ISNULL(p.Totalindemnity, 0))) OVER () AS decimal(18,2)) AS summary_compensation,
CAST(SUM(SUM(ISNULL(p.supplySup, 0))) OVER () AS decimal(18,2)) AS summary_supplier_refund,
CAST(SUM(SUM(ISNULL(p.ShouldPay, 0))) OVER () AS decimal(18,2)) AS summary_payable_amount,
CAST(SUM(SUM(ISNULL(p.factPay, 0))) OVER () AS decimal(18,2)) AS summary_paid_amount,
CAST(SUM(SUM(ISNULL(p.cashierbypaid, 0))) OVER () AS decimal(18,2)) AS summary_actual_payment,
CAST(SUM(SUM(ISNULL(p.toPrivate, 0))) OVER () AS decimal(18,2)) AS summary_private_payment,
CAST(SUM(SUM(ISNULL(p.toCorporate, 0))) OVER () AS decimal(18,2)) AS summary_corporate_payment,
ROW_NUMBER() OVER (ORDER BY p.supplier) AS row_no,
COUNT(*) OVER () AS total_count
FROM [dbo].[fys_supplierPaymentSummary] p
WHERE {$whereSql}
GROUP BY p.supplier
)
SELECT supplier, month_start_unpaid, goods_amount, prepaid_freight,
compensation, supplier_refund, payable_amount, paid_amount,
actual_payment, private_payment, corporate_payment, remark,
summary_month_start_unpaid, summary_goods_amount,
summary_prepaid_freight, summary_compensation,
summary_supplier_refund, summary_payable_amount,
summary_paid_amount, summary_actual_payment,
summary_private_payment, summary_corporate_payment,
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]));
return $this->payablesPageResult($rows);
}
private function query(): UpstreamReadOnlyQuery
{
return $this->query ??= $this->queries->forSource(self::SOURCE);
}
private function contains(string $value): string
{
return '%' . str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], trim($value)) . '%';
}
/** @param array<int,array<string,mixed>> $rows */
private function pageResult(array $rows): array
{
$total = (int) ($rows[0]['total_count'] ?? 0);
foreach ($rows as &$row) {
unset($row['total_count']);
}
return ['data' => $rows, 'total' => $total];
}
/** @param array<int,array<string,mixed>> $rows */
private function payablesPageResult(array $rows): array
{
$summaryKeys = [
'month_start_unpaid', 'goods_amount', 'prepaid_freight', 'compensation',
'supplier_refund', 'payable_amount', 'paid_amount', 'actual_payment',
'private_payment', 'corporate_payment',
];
$totals = array_fill_keys($summaryKeys, 0.0);
if ($rows !== []) {
foreach ($summaryKeys as $key) {
$totals[$key] = (float) ($rows[0]['summary_' . $key] ?? 0);
}
}
foreach ($rows as &$row) {
foreach ($summaryKeys as $key) {
unset($row['summary_' . $key]);
}
}
return array_merge($this->pageResult($rows), ['totals' => $totals]);
}
}