904 lines
34 KiB
PHP
904 lines
34 KiB
PHP
<?php
|
||
|
||
namespace Modules\EcommerceFinance\Repositories;
|
||
|
||
use Modules\EcommerceFinance\Services\JianSunConnection;
|
||
use Modules\EcommerceFinance\Services\UpstreamReadOnlyQuery;
|
||
use Modules\EcommerceFinance\Services\UpstreamReadOnlyQueryFactory;
|
||
use PDO;
|
||
|
||
/**
|
||
* 供应商应付 - 子功能页面数据仓库
|
||
*
|
||
* 封装 5 个子页面的数据访问逻辑:
|
||
* - returnReconciliations() 退货对账
|
||
* - invoiceDeductions() 发票扣款
|
||
* - compensationDetails() 赔偿明细
|
||
* - advanceDetails() 借支明细
|
||
* - sampleDeductions() 样品扣款
|
||
*
|
||
* 所有方法返回统一结构: ['data' => array<int,array>, 'total' => int]
|
||
*/
|
||
class SupplierPayableRepository
|
||
{
|
||
private ?PDO $db = null;
|
||
|
||
private readonly UpstreamReadOnlyQuery $query;
|
||
|
||
public function __construct(UpstreamReadOnlyQueryFactory $queries)
|
||
{
|
||
$this->query = $queries->forSource('jiansun');
|
||
}
|
||
|
||
private function db(): PDO
|
||
{
|
||
return $this->db ??= JianSunConnection::get();
|
||
}
|
||
|
||
/**
|
||
* 通用工具:带筛选 + 分页的查询
|
||
*/
|
||
private function runQuery(
|
||
string $sql,
|
||
array $params,
|
||
int $page,
|
||
int $pageSize,
|
||
string $orderBy = '(SELECT 0)',
|
||
int $countThreshold = 5000
|
||
): array
|
||
{
|
||
$offset = ($page - 1) * $pageSize;
|
||
|
||
// 1. 总数(先查总数,超阈值再用近似)
|
||
$countSql = 'SELECT COUNT(*) AS cnt FROM (' . $sql . ') AS sub';
|
||
$total = 0;
|
||
try {
|
||
$stmt = $this->db()->prepare($countSql);
|
||
$stmt->execute($params);
|
||
$total = (int) $stmt->fetchColumn();
|
||
} catch (\Throwable $e) {
|
||
// 极端情况:表太大查不到总数时退回到 -1
|
||
$total = -1;
|
||
}
|
||
|
||
// 2. 分页数据:排序字段只允许由仓库内部固定传入,不接受请求参数。
|
||
// ROW_NUMBER 位于无 ORDER BY 的派生表外层,兼容旧版 SQL Server。
|
||
$pagedSql = 'SELECT * FROM (SELECT src.*, ROW_NUMBER() OVER (ORDER BY ' . $orderBy . ') AS rn FROM (' . $sql . ') AS src) AS t WHERE rn BETWEEN ? AND ? ORDER BY rn';
|
||
$paramsWithRange = array_merge($params, [$offset + 1, $offset + $pageSize]);
|
||
|
||
$stmt = $this->db()->prepare($pagedSql);
|
||
$stmt->execute($paramsWithRange);
|
||
|
||
return [
|
||
'data' => $stmt->fetchAll(),
|
||
'total' => $total,
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 计算分页的 SELECT TOP N(无 COUNT),加速大表查询
|
||
*/
|
||
private function runQueryFast(
|
||
string $sql,
|
||
array $params,
|
||
int $page,
|
||
int $pageSize,
|
||
int $total = -1,
|
||
string $orderBy = '(SELECT 0)'
|
||
): array
|
||
{
|
||
$offset = ($page - 1) * $pageSize;
|
||
$pagedSql = 'SELECT * FROM (SELECT src.*, ROW_NUMBER() OVER (ORDER BY ' . $orderBy . ') AS rn FROM (' . $sql . ') AS src) AS t WHERE rn BETWEEN ? AND ? ORDER BY rn';
|
||
$paramsWithRange = array_merge($params, [$offset + 1, $offset + $pageSize]);
|
||
$stmt = $this->db()->prepare($pagedSql);
|
||
$stmt->execute($paramsWithRange);
|
||
|
||
return [
|
||
'data' => $stmt->fetchAll(),
|
||
'total' => $total,
|
||
];
|
||
}
|
||
|
||
// ============================================================
|
||
// 1. 退货对账 — finance_purchaseReturn (36791行)
|
||
// ============================================================
|
||
public function returnReconciliations(array $filters, int $page, int $pageSize): array
|
||
{
|
||
$where = [];
|
||
$params = [];
|
||
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'supplierName LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
if (!empty($filters['warehouse'])) {
|
||
$where[] = 'warehouseName LIKE ?';
|
||
$params[] = '%' . $filters['warehouse'] . '%';
|
||
}
|
||
if (!empty($filters['sku_id'])) {
|
||
$where[] = 'sku_id LIKE ?';
|
||
$params[] = '%' . $filters['sku_id'] . '%';
|
||
}
|
||
if (!empty($filters['express_no'])) {
|
||
$where[] = 'expressNo LIKE ?';
|
||
$params[] = '%' . $filters['express_no'] . '%';
|
||
}
|
||
if (!empty($filters['date_from'])) {
|
||
$where[] = 'date >= ?';
|
||
$params[] = $filters['date_from'];
|
||
}
|
||
if (!empty($filters['date_to'])) {
|
||
$where[] = 'date <= ?';
|
||
$params[] = $filters['date_to'];
|
||
}
|
||
|
||
$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||
|
||
$sql = "SELECT
|
||
id AS id,
|
||
CONVERT(varchar(10), date, 120) AS send_time,
|
||
supplierName AS supplier,
|
||
sku_id AS barcode,
|
||
name AS sku_name,
|
||
CAST(qty AS decimal(18,2)) AS qty,
|
||
CAST(price AS decimal(18,2)) AS unit_price,
|
||
CAST(price * qty AS decimal(18,2)) AS amount,
|
||
CAST(priceB AS decimal(18,2)) AS guess_unit_price,
|
||
CAST(priceB * qty AS decimal(18,2)) AS guess_amount,
|
||
remark,
|
||
io_id AS wms_pick_no,
|
||
warehouseName AS warehouse,
|
||
expressNo AS express_no,
|
||
expressName AS express_name,
|
||
CONVERT(varchar(10), io_date, 120) AS io_date,
|
||
labels,
|
||
creator_name AS creator,
|
||
'' AS title,
|
||
'' AS supplier_barcode,
|
||
'' AS original_barcode,
|
||
'' AS reconciler
|
||
FROM finance_purchaseReturn
|
||
$whereSql";
|
||
|
||
$result = $this->runQuery($sql, $params, $page, $pageSize, 'send_time DESC, wms_pick_no DESC');
|
||
|
||
return [
|
||
'data' => $result['data'],
|
||
'total' => $result['total'],
|
||
];
|
||
}
|
||
|
||
public function returnReconciliationSummary(array $filters): array
|
||
{
|
||
$where = [];
|
||
$params = [];
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'supplierName LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
if (!empty($filters['date_from'])) {
|
||
$where[] = 'date >= ?';
|
||
$params[] = $filters['date_from'];
|
||
}
|
||
if (!empty($filters['date_to'])) {
|
||
$where[] = 'date <= ?';
|
||
$params[] = $filters['date_to'];
|
||
}
|
||
$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||
|
||
$sql = "SELECT
|
||
ISNULL(SUM(price * qty), 0) AS total_amount,
|
||
ISNULL(SUM(priceB * qty), 0) AS total_guess_amount,
|
||
COUNT(*) AS total_count
|
||
FROM finance_purchaseReturn $whereSql";
|
||
$stmt = $this->db()->prepare($sql);
|
||
$stmt->execute($params);
|
||
$row = $stmt->fetch();
|
||
|
||
return [
|
||
'totalAmount' => (float) $row['total_amount'],
|
||
'totalGuessAmount' => (float) $row['total_guess_amount'],
|
||
'totalCount' => (int) $row['total_count'],
|
||
];
|
||
}
|
||
|
||
// ============================================================
|
||
// 2. 发票扣款 — finance_invoiceDeduction (195行)
|
||
// ============================================================
|
||
public function invoiceDeductions(array $filters, int $page, int $pageSize): array
|
||
{
|
||
$where = [];
|
||
$params = [];
|
||
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'supplier LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
if (!empty($filters['month_from'])) {
|
||
$where[] = 'month >= ?';
|
||
$params[] = $filters['month_from'];
|
||
}
|
||
if (!empty($filters['month_to'])) {
|
||
$where[] = 'month <= ?';
|
||
$params[] = $filters['month_to'];
|
||
}
|
||
|
||
$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||
|
||
$sql = "SELECT
|
||
id AS id,
|
||
CONVERT(varchar(7), month, 120) AS month_str,
|
||
'' AS category,
|
||
supplier AS payee,
|
||
supplier AS receiver,
|
||
'' AS board_factory,
|
||
CAST(0 AS decimal(18,2)) AS subsidy_fee,
|
||
remark,
|
||
CAST(price AS decimal(18,2)) AS price,
|
||
remark AS detail,
|
||
'' AS note,
|
||
personCharge AS person_charge,
|
||
CONVERT(varchar(19), createTime, 120) AS create_time,
|
||
creator
|
||
FROM finance_invoiceDeduction
|
||
$whereSql";
|
||
|
||
return $this->runQuery($sql, $params, $page, $pageSize, 'month_str DESC, create_time DESC');
|
||
}
|
||
|
||
public function invoiceDeductionSummary(array $filters): array
|
||
{
|
||
$where = [];
|
||
$params = [];
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'supplier LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||
|
||
$sql = "SELECT ISNULL(SUM(price), 0) AS total_price, COUNT(*) AS total_count FROM finance_invoiceDeduction $whereSql";
|
||
$stmt = $this->db()->prepare($sql);
|
||
$stmt->execute($params);
|
||
$row = $stmt->fetch();
|
||
|
||
return [
|
||
'totalPrice' => (float) $row['total_price'],
|
||
'totalCount' => (int) $row['total_count'],
|
||
];
|
||
}
|
||
|
||
// ============================================================
|
||
// 3. 赔偿明细 — fys_supplierPaymentSummary
|
||
// ============================================================
|
||
public function compensationDetails(array $filters, int $page, int $pageSize): array
|
||
{
|
||
[$whereSql, $bindings] = $this->compensationWhere($filters);
|
||
$page = max($page, 1);
|
||
$pageSize = min(max($pageSize, 1), 100);
|
||
$offset = ($page - 1) * $pageSize;
|
||
$total = (int) ($this->query->scalar(
|
||
"SELECT COUNT(*) FROM [dbo].[fys_supplierPaymentSummary] WHERE $whereSql",
|
||
$bindings,
|
||
) ?? 0);
|
||
|
||
$rows = $this->query->select(
|
||
"SELECT
|
||
[id] AS id,
|
||
[Month] AS month,
|
||
[supplier] AS supplier,
|
||
CAST([Totalindemnity] AS decimal(18,2)) AS amount,
|
||
[reason] AS reason,
|
||
[remarks] AS remark
|
||
FROM [dbo].[fys_supplierPaymentSummary]
|
||
WHERE $whereSql
|
||
ORDER BY [Month] DESC, [id] DESC
|
||
OFFSET $offset ROWS FETCH NEXT $pageSize ROWS ONLY",
|
||
$bindings,
|
||
);
|
||
|
||
foreach ($rows as &$row) {
|
||
$row['amount'] = (float) ($row['amount'] ?? 0);
|
||
}
|
||
unset($row);
|
||
|
||
return ['data' => $rows, 'total' => $total];
|
||
}
|
||
|
||
public function compensationDetailSummary(array $filters): array
|
||
{
|
||
[$whereSql, $bindings] = $this->compensationWhere($filters);
|
||
$row = $this->query->first(
|
||
"SELECT
|
||
ISNULL(SUM([Totalindemnity]), 0) AS total_amount,
|
||
COUNT(*) AS total_count
|
||
FROM [dbo].[fys_supplierPaymentSummary]
|
||
WHERE $whereSql",
|
||
$bindings,
|
||
) ?? [];
|
||
|
||
return [
|
||
'totalAmount' => (float) ($row['total_amount'] ?? 0),
|
||
'totalCount' => (int) ($row['total_count'] ?? 0),
|
||
];
|
||
}
|
||
|
||
/** @return array{0:string,1:array<int,string>} */
|
||
private function compensationWhere(array $filters): array
|
||
{
|
||
$where = ['[Totalindemnity] IS NOT NULL', '[Totalindemnity] <> 0'];
|
||
$bindings = [];
|
||
|
||
if (! empty($filters['supplier'])) {
|
||
$where[] = "[supplier] LIKE ? ESCAPE '\\'";
|
||
$bindings[] = '%' . str_replace(
|
||
['\\', '%', '_'],
|
||
['\\\\', '\\%', '\\_'],
|
||
trim((string) $filters['supplier']),
|
||
) . '%';
|
||
}
|
||
if (! empty($filters['month_from'])) {
|
||
$where[] = '[Month] >= ?';
|
||
$bindings[] = (string) $filters['month_from'];
|
||
}
|
||
if (! empty($filters['month_to'])) {
|
||
$where[] = '[Month] <= ?';
|
||
$bindings[] = (string) $filters['month_to'];
|
||
}
|
||
|
||
return [implode(' AND ', $where), $bindings];
|
||
}
|
||
|
||
// ============================================================
|
||
// 4. 借支明细 — finance_advanceLoans (4行, 字段不足,部分列显示-)
|
||
// ============================================================
|
||
public function advanceDetails(array $filters, int $page, int $pageSize): array
|
||
{
|
||
$where = [];
|
||
$params = [];
|
||
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'supplier LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
if (!empty($filters['month_from'])) {
|
||
$where[] = 'month >= ?';
|
||
$params[] = $filters['month_from'];
|
||
}
|
||
if (!empty($filters['month_to'])) {
|
||
$where[] = 'month <= ?';
|
||
$params[] = $filters['month_to'];
|
||
}
|
||
|
||
$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||
|
||
$sql = "SELECT
|
||
id AS id,
|
||
supplier,
|
||
'' AS contract_name,
|
||
CAST(price AS decimal(18,2)) AS advance_amount,
|
||
CAST(0 AS decimal(18,2)) AS actual_pay,
|
||
CAST(0 AS decimal(18,2)) AS month_deduct,
|
||
CAST(0 AS decimal(18,2)) AS should_deduct,
|
||
'' AS deduct_start_month,
|
||
'' AS deduct_end_month,
|
||
0 AS remain_periods,
|
||
CONVERT(varchar(7), month, 120) AS month_str,
|
||
'' AS loan_term,
|
||
remark,
|
||
'' AS is_paid,
|
||
CONVERT(varchar(7), month, 120) AS pay_month,
|
||
'' AS serial_no,
|
||
'' AS loan_agreement,
|
||
personCharge AS person_charge,
|
||
'' AS receipt_0,
|
||
'' AS receipt_1,
|
||
'' AS receipt_2,
|
||
CONVERT(varchar(19), createTime, 120) AS create_time,
|
||
creator
|
||
FROM finance_advanceLoans
|
||
$whereSql";
|
||
|
||
return $this->runQuery($sql, $params, $page, $pageSize, 'month_str DESC, create_time DESC');
|
||
}
|
||
|
||
public function advanceDetailSummary(array $filters): array
|
||
{
|
||
$where = [];
|
||
$params = [];
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'supplier LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||
|
||
$sql = "SELECT ISNULL(SUM(price), 0) AS total_amount, COUNT(*) AS total_count FROM finance_advanceLoans $whereSql";
|
||
$stmt = $this->db()->prepare($sql);
|
||
$stmt->execute($params);
|
||
$row = $stmt->fetch();
|
||
|
||
return [
|
||
'totalAmount' => (float) $row['total_amount'],
|
||
'totalCount' => (int) $row['total_count'],
|
||
];
|
||
}
|
||
|
||
// ============================================================
|
||
// 5. 样品扣款 — finance_sampleDeduction (12行)
|
||
// ============================================================
|
||
public function sampleDeductions(array $filters, int $page, int $pageSize): array
|
||
{
|
||
$where = [];
|
||
$params = [];
|
||
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'supplier LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
if (!empty($filters['department'])) {
|
||
$where[] = 'department LIKE ?';
|
||
$params[] = '%' . $filters['department'] . '%';
|
||
}
|
||
if (!empty($filters['creator'])) {
|
||
$where[] = 'creator LIKE ?';
|
||
$params[] = '%' . $filters['creator'] . '%';
|
||
}
|
||
if (!empty($filters['sku_id'])) {
|
||
$where[] = 'sku_id LIKE ?';
|
||
$params[] = '%' . $filters['sku_id'] . '%';
|
||
}
|
||
if (!empty($filters['date_from'])) {
|
||
$where[] = 'finishTime >= ?';
|
||
$params[] = $filters['date_from'];
|
||
}
|
||
if (!empty($filters['date_to'])) {
|
||
$where[] = 'finishTime <= ?';
|
||
$params[] = $filters['date_to'];
|
||
}
|
||
|
||
$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||
|
||
$sql = "SELECT
|
||
id AS id,
|
||
CONVERT(varchar(10), finishTime, 120) AS finish_time,
|
||
department,
|
||
creator,
|
||
sku_id,
|
||
skuName,
|
||
CAST(num AS decimal(18,2)) AS num,
|
||
supplier,
|
||
purchase,
|
||
productCode,
|
||
CAST(shippingFee AS decimal(18,2)) AS shipping_fee,
|
||
CAST(costPrice AS decimal(18,2)) AS cost_price,
|
||
CAST(totalAmount AS decimal(18,2)) AS total_amount,
|
||
CAST(estimatedPrice AS decimal(18,2)) AS estimated_price,
|
||
CAST(estimatedPriceAll AS decimal(18,2)) AS estimated_price_all,
|
||
'' AS remark,
|
||
businessId,
|
||
CONVERT(varchar(19), updateAt, 120) AS update_time
|
||
FROM finance_sampleDeduction
|
||
$whereSql";
|
||
|
||
return $this->runQuery($sql, $params, $page, $pageSize, 'finish_time DESC');
|
||
}
|
||
|
||
public function sampleDeductionSummary(array $filters): array
|
||
{
|
||
$where = [];
|
||
$params = [];
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'supplier LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||
|
||
$sql = "SELECT
|
||
ISNULL(SUM(totalAmount), 0) AS total_amount,
|
||
ISNULL(SUM(estimatedPriceAll), 0) AS total_estimate,
|
||
COUNT(*) AS total_count
|
||
FROM finance_sampleDeduction $whereSql";
|
||
$stmt = $this->db()->prepare($sql);
|
||
$stmt->execute($params);
|
||
$row = $stmt->fetch();
|
||
|
||
return [
|
||
'totalAmount' => (float) $row['total_amount'],
|
||
'totalEstimate' => (float) $row['total_estimate'],
|
||
'totalCount' => (int) $row['total_count'],
|
||
];
|
||
}
|
||
|
||
// ============================================================
|
||
// 6. 送货未定价 — pm_unOrderDetails (265452行)
|
||
// ============================================================
|
||
public function deliveryUnpriced(array $filters, int $page, int $pageSize): array
|
||
{
|
||
$where = [];
|
||
$params = [];
|
||
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'supplier LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
if (!empty($filters['warehouse'])) {
|
||
$where[] = 'warehouse LIKE ?';
|
||
$params[] = '%' . $filters['warehouse'] . '%';
|
||
}
|
||
if (!empty($filters['purchase'])) {
|
||
$where[] = 'purchase LIKE ?';
|
||
$params[] = '%' . $filters['purchase'] . '%';
|
||
}
|
||
if (!empty($filters['barcode'])) {
|
||
$where[] = 'barCode LIKE ?';
|
||
$params[] = '%' . $filters['barcode'] . '%';
|
||
}
|
||
if (!empty($filters['express_no'])) {
|
||
$where[] = 'expressNo LIKE ?';
|
||
$params[] = '%' . $filters['express_no'] . '%';
|
||
}
|
||
if (!empty($filters['date_from'])) {
|
||
$where[] = 'date >= ?';
|
||
$params[] = $filters['date_from'];
|
||
}
|
||
if (!empty($filters['date_to'])) {
|
||
$where[] = 'date <= ?';
|
||
$params[] = $filters['date_to'];
|
||
}
|
||
|
||
$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||
|
||
$sql = "SELECT
|
||
Id AS id,
|
||
CONVERT(varchar(10), date, 120) AS date,
|
||
purchase,
|
||
warehouse,
|
||
supplier,
|
||
transactionNo,
|
||
distributionNo,
|
||
expressNo,
|
||
sku,
|
||
barCode,
|
||
skuName,
|
||
CONVERT(varchar(19), distributionDate, 120) AS distribution_date,
|
||
CONVERT(varchar(10), shipDate, 120) AS ship_date,
|
||
expressName
|
||
FROM pm_unOrderDetails
|
||
$whereSql";
|
||
|
||
return $this->runQuery($sql, $params, $page, $pageSize, 'date DESC, id DESC');
|
||
}
|
||
|
||
public function deliveryUnpricedSummary(array $filters): array
|
||
{
|
||
$where = [];
|
||
$params = [];
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'supplier LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||
|
||
$sql = "SELECT COUNT(*) AS total_count FROM pm_unOrderDetails $whereSql";
|
||
$stmt = $this->db()->prepare($sql);
|
||
$stmt->execute($params);
|
||
$row = $stmt->fetch();
|
||
|
||
return [
|
||
'totalCount' => (int) $row['total_count'],
|
||
];
|
||
}
|
||
|
||
// ============================================================
|
||
// 7. 退货未定价 — finance_purchaseReturn WHERE priceB = 0 (35928行)
|
||
// ============================================================
|
||
public function returnUnpriced(array $filters, int $page, int $pageSize): array
|
||
{
|
||
$where = ['(priceB = 0 OR priceB IS NULL)'];
|
||
$params = [];
|
||
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'supplierName LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
if (!empty($filters['warehouse'])) {
|
||
$where[] = 'warehouseName LIKE ?';
|
||
$params[] = '%' . $filters['warehouse'] . '%';
|
||
}
|
||
if (!empty($filters['sku_id'])) {
|
||
$where[] = 'sku_id LIKE ?';
|
||
$params[] = '%' . $filters['sku_id'] . '%';
|
||
}
|
||
if (!empty($filters['express_no'])) {
|
||
$where[] = 'expressNo LIKE ?';
|
||
$params[] = '%' . $filters['express_no'] . '%';
|
||
}
|
||
if (!empty($filters['date_from'])) {
|
||
$where[] = 'date >= ?';
|
||
$params[] = $filters['date_from'];
|
||
}
|
||
if (!empty($filters['date_to'])) {
|
||
$where[] = 'date <= ?';
|
||
$params[] = $filters['date_to'];
|
||
}
|
||
|
||
$whereSql = 'WHERE ' . implode(' AND ', $where);
|
||
|
||
$sql = "SELECT
|
||
id AS id,
|
||
CONVERT(varchar(10), date, 120) AS send_time,
|
||
supplierName AS supplier,
|
||
sku_id AS barcode,
|
||
name AS sku_name,
|
||
CAST(qty AS decimal(18,2)) AS qty,
|
||
CAST(price AS decimal(18,2)) AS unit_price,
|
||
CAST(price * qty AS decimal(18,2)) AS amount,
|
||
CAST(ISNULL(priceB, 0) AS decimal(18,2)) AS guess_unit_price,
|
||
CAST(ISNULL(priceB, 0) * qty AS decimal(18,2)) AS guess_amount,
|
||
remark,
|
||
io_id AS wms_pick_no,
|
||
warehouseName AS warehouse,
|
||
expressNo AS express_no,
|
||
expressName AS express_name,
|
||
CONVERT(varchar(10), io_date, 120) AS io_date,
|
||
labels,
|
||
creator_name AS creator
|
||
FROM finance_purchaseReturn
|
||
$whereSql";
|
||
|
||
return $this->runQuery($sql, $params, $page, $pageSize, 'send_time DESC');
|
||
}
|
||
|
||
public function returnUnpricedSummary(array $filters): array
|
||
{
|
||
$where = ['(priceB = 0 OR priceB IS NULL)'];
|
||
$params = [];
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'supplierName LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
$whereSql = 'WHERE ' . implode(' AND ', $where);
|
||
|
||
$sql = "SELECT
|
||
ISNULL(SUM(price * qty), 0) AS total_amount,
|
||
COUNT(*) AS total_count
|
||
FROM finance_purchaseReturn $whereSql";
|
||
$stmt = $this->db()->prepare($sql);
|
||
$stmt->execute($params);
|
||
$row = $stmt->fetch();
|
||
|
||
return [
|
||
'totalAmount' => (float) $row['total_amount'],
|
||
'totalCount' => (int) $row['total_count'],
|
||
];
|
||
}
|
||
|
||
// ============================================================
|
||
// 筛选器选项
|
||
// ============================================================
|
||
public function filterOptionsForReturn(): array
|
||
{
|
||
$suppliers = $this->fetchDistinct('SELECT DISTINCT supplierName FROM finance_purchaseReturn WHERE supplierName IS NOT NULL ORDER BY supplierName');
|
||
$warehouses = $this->fetchDistinct('SELECT DISTINCT warehouseName FROM finance_purchaseReturn WHERE warehouseName IS NOT NULL ORDER BY warehouseName');
|
||
|
||
return compact('suppliers', 'warehouses');
|
||
}
|
||
|
||
public function filterOptionsForInvoice(): array
|
||
{
|
||
$suppliers = $this->fetchDistinct('SELECT DISTINCT supplier FROM finance_invoiceDeduction WHERE supplier IS NOT NULL ORDER BY supplier');
|
||
|
||
return ['suppliers' => $suppliers];
|
||
}
|
||
|
||
public function filterOptionsForCompensation(): array
|
||
{
|
||
$suppliers = array_column($this->query->select(
|
||
'SELECT DISTINCT TOP 200 [supplier] AS value '
|
||
. 'FROM [dbo].[fys_supplierPaymentSummary] '
|
||
. 'WHERE [Totalindemnity] IS NOT NULL AND [Totalindemnity] <> 0 AND [supplier] IS NOT NULL '
|
||
. 'ORDER BY [supplier]',
|
||
), 'value');
|
||
|
||
return ['suppliers' => $suppliers];
|
||
}
|
||
|
||
public function filterOptionsForAdvance(): array
|
||
{
|
||
$suppliers = $this->fetchDistinct('SELECT DISTINCT supplier FROM finance_advanceLoans WHERE supplier IS NOT NULL ORDER BY supplier');
|
||
|
||
return ['suppliers' => $suppliers];
|
||
}
|
||
|
||
public function filterOptionsForDeliveryUnpriced(): array
|
||
{
|
||
$suppliers = $this->fetchDistinct('SELECT DISTINCT supplier FROM pm_unOrderDetails WHERE supplier IS NOT NULL ORDER BY supplier');
|
||
$warehouses = $this->fetchDistinct('SELECT DISTINCT warehouse FROM pm_unOrderDetails WHERE warehouse IS NOT NULL ORDER BY warehouse');
|
||
$purchases = $this->fetchDistinct('SELECT DISTINCT purchase FROM pm_unOrderDetails WHERE purchase IS NOT NULL ORDER BY purchase');
|
||
|
||
return compact('suppliers', 'warehouses', 'purchases');
|
||
}
|
||
|
||
public function filterOptionsForReturnUnpriced(): array
|
||
{
|
||
$suppliers = $this->fetchDistinct("SELECT DISTINCT supplierName FROM finance_purchaseReturn WHERE (priceB = 0 OR priceB IS NULL) AND supplierName IS NOT NULL ORDER BY supplierName");
|
||
$warehouses = $this->fetchDistinct("SELECT DISTINCT warehouseName FROM finance_purchaseReturn WHERE (priceB = 0 OR priceB IS NULL) AND warehouseName IS NOT NULL ORDER BY warehouseName");
|
||
|
||
return compact('suppliers', 'warehouses');
|
||
}
|
||
|
||
public function filterOptionsForSample(): array
|
||
{
|
||
$suppliers = $this->fetchDistinct('SELECT DISTINCT supplier FROM finance_sampleDeduction WHERE supplier IS NOT NULL ORDER BY supplier');
|
||
$departments = $this->fetchDistinct('SELECT DISTINCT department FROM finance_sampleDeduction WHERE department IS NOT NULL ORDER BY department');
|
||
$creators = $this->fetchDistinct('SELECT DISTINCT creator FROM finance_sampleDeduction WHERE creator IS NOT NULL ORDER BY creator');
|
||
|
||
return compact('suppliers', 'departments', 'creators');
|
||
}
|
||
|
||
private function fetchDistinct(string $sql): array
|
||
{
|
||
$rows = $this->db()->query($sql)->fetchAll(PDO::FETCH_COLUMN);
|
||
return array_values(array_filter($rows, fn ($v) => $v !== null && $v !== ''));
|
||
}
|
||
|
||
// ============================================================
|
||
// 8. 其他扣款补款 — fys_supplierPaymentSummary WHERE other != 0 (460行)
|
||
// ============================================================
|
||
public function otherAdjustments(array $filters, int $page, int $pageSize): array
|
||
{
|
||
$where = ['(other IS NOT NULL AND other != 0)'];
|
||
$params = [];
|
||
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'supplier LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
if (!empty($filters['month_from'])) {
|
||
$where[] = 'Month >= ?';
|
||
$params[] = $filters['month_from'];
|
||
}
|
||
if (!empty($filters['month_to'])) {
|
||
$where[] = 'Month <= ?';
|
||
$params[] = $filters['month_to'];
|
||
}
|
||
|
||
$whereSql = 'WHERE ' . implode(' AND ', $where);
|
||
|
||
$sql = "SELECT
|
||
id AS id,
|
||
Month AS month_str,
|
||
supplier,
|
||
CAST(other AS decimal(18,2)) AS supplement_amount,
|
||
reason AS supplement_reason,
|
||
remarks AS remark,
|
||
mark AS remark2,
|
||
checker AS person_charge
|
||
FROM fys_supplierPaymentSummary
|
||
$whereSql";
|
||
|
||
$result = $this->runQuery($sql, $params, $page, $pageSize, 'month_str DESC, supplier');
|
||
foreach ($result['data'] as &$row) {
|
||
$row['project'] = '其他扣款补款';
|
||
}
|
||
unset($row);
|
||
|
||
return $result;
|
||
}
|
||
|
||
public function otherAdjustmentsSummary(array $filters): array
|
||
{
|
||
$where = ['(other IS NOT NULL AND other != 0)'];
|
||
$params = [];
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'supplier LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
$whereSql = 'WHERE ' . implode(' AND ', $where);
|
||
|
||
$sql = "SELECT
|
||
ISNULL(SUM(other), 0) AS total_amount,
|
||
COUNT(*) AS total_count
|
||
FROM fys_supplierPaymentSummary $whereSql";
|
||
$stmt = $this->db()->prepare($sql);
|
||
$stmt->execute($params);
|
||
$row = $stmt->fetch();
|
||
|
||
return [
|
||
'totalAmount' => (float) $row['total_amount'],
|
||
'totalCount' => (int) $row['total_count'],
|
||
];
|
||
}
|
||
|
||
// ============================================================
|
||
// 9. 代发快递 — fys_express_courier_settlement (940行)
|
||
// ============================================================
|
||
public function dropshippingExpress(array $filters, int $page, int $pageSize): array
|
||
{
|
||
$where = ['(is_delete = 0 OR is_delete IS NULL)'];
|
||
$params = [];
|
||
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'courier_company_name LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
if (!empty($filters['express_name'])) {
|
||
$where[] = 'expressname LIKE ?';
|
||
$params[] = '%' . $filters['express_name'] . '%';
|
||
}
|
||
if (!empty($filters['month_from'])) {
|
||
$where[] = 'month >= ?';
|
||
$params[] = $filters['month_from'];
|
||
}
|
||
if (!empty($filters['month_to'])) {
|
||
$where[] = 'month <= ?';
|
||
$params[] = $filters['month_to'];
|
||
}
|
||
|
||
$whereSql = 'WHERE ' . implode(' AND ', $where);
|
||
|
||
$sql = "SELECT
|
||
id AS id,
|
||
reconciliation_person,
|
||
month AS month_str,
|
||
courier_company_name AS supplier,
|
||
CAST(ISNULL(waybill, 0) AS decimal(18,2)) AS express_freight,
|
||
CAST(ISNULL(courier_provided_amount, 0) AS decimal(18,2)) AS express_account,
|
||
CAST(ISNULL(replenish_courier, 0) AS decimal(18,2)) AS replenish_freight,
|
||
CAST(ISNULL(confirmed_amount, 0) AS decimal(18,2)) AS replenish_account,
|
||
CAST(ISNULL(reconciliation_difference, 0) AS decimal(18,2)) AS return_fee,
|
||
CAST(ISNULL(compensation_amount, 0) AS decimal(18,2)) AS intercept_fee,
|
||
CAST(ISNULL(other_replenishment, 0) AS decimal(18,2)) AS change_address_fee,
|
||
CAST(ISNULL(corporate_payment_amount, 0) AS decimal(18,2)) AS turnover_fee,
|
||
CAST(ISNULL(personal_payment_amount, 0) AS decimal(18,2)) AS overlong_fee,
|
||
CAST(ISNULL(payable_amount, 0) AS decimal(18,2)) AS total_freight,
|
||
status AS remark,
|
||
expressname AS express_name,
|
||
file_status AS remark2,
|
||
creator,
|
||
CONVERT(varchar(19), create_time, 120) AS create_time
|
||
FROM fys_express_courier_settlement
|
||
$whereSql";
|
||
|
||
return $this->runQuery($sql, $params, $page, $pageSize, 'month_str DESC, express_name');
|
||
}
|
||
|
||
public function dropshippingExpressSummary(array $filters): array
|
||
{
|
||
$where = ['(is_delete = 0 OR is_delete IS NULL)'];
|
||
$params = [];
|
||
if (!empty($filters['supplier'])) {
|
||
$where[] = 'courier_company_name LIKE ?';
|
||
$params[] = '%' . $filters['supplier'] . '%';
|
||
}
|
||
$whereSql = 'WHERE ' . implode(' AND ', $where);
|
||
|
||
$sql = "SELECT
|
||
ISNULL(SUM(payable_amount), 0) AS total_amount,
|
||
COUNT(*) AS total_count
|
||
FROM fys_express_courier_settlement $whereSql";
|
||
$stmt = $this->db()->prepare($sql);
|
||
$stmt->execute($params);
|
||
$row = $stmt->fetch();
|
||
|
||
return [
|
||
'totalAmount' => (float) $row['total_amount'],
|
||
'totalCount' => (int) $row['total_count'],
|
||
];
|
||
}
|
||
|
||
public function filterOptionsForOtherAdjustments(): array
|
||
{
|
||
$suppliers = $this->fetchDistinct("SELECT DISTINCT supplier FROM fys_supplierPaymentSummary WHERE (other IS NOT NULL AND other != 0) AND supplier IS NOT NULL ORDER BY supplier");
|
||
|
||
return ['suppliers' => $suppliers];
|
||
}
|
||
|
||
public function filterOptionsForDropshippingExpress(): array
|
||
{
|
||
$suppliers = $this->fetchDistinct("SELECT DISTINCT courier_company_name FROM fys_express_courier_settlement WHERE (is_delete = 0 OR is_delete IS NULL) AND courier_company_name IS NOT NULL ORDER BY courier_company_name");
|
||
$expressNames = $this->fetchDistinct("SELECT DISTINCT expressname FROM fys_express_courier_settlement WHERE (is_delete = 0 OR is_delete IS NULL) AND expressname IS NOT NULL ORDER BY expressname");
|
||
|
||
return compact('suppliers', 'expressNames');
|
||
}
|
||
}
|