>,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>,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>,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> $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> $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]); } }