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} */ 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'); } }