From fb3a5d1f1c77848dfe5fd47d0cb4132ad25c1564 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 24 六月 2026 13:09:12 +0800
Subject: [PATCH] 客户往来,供应商往来优化
---
src/main/resources/mapper/basic/CustomerMapper.xml | 162 +++++++
src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java | 20
src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java | 5
src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml | 10
src/main/java/com/ruoyi/basic/service/ICustomerService.java | 28 +
src/main/resources/mapper/sales/ShippingInfoMapper.xml | 3
docs/20260618_customer_transactions_optimization.md | 839 ++++++++++++++++++++++++++++++++++++++
src/main/java/com/ruoyi/sales/pojo/ShippingInfo.java | 4
src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java | 18
src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java | 21
src/main/java/com/ruoyi/sales/vo/CustomerTransactionsDetailsVo.java | 3
src/main/java/com/ruoyi/sales/vo/CustomerTransactionsShipmentVo.java | 56 ++
src/main/java/com/ruoyi/sales/vo/CustomerTransactionsSummaryVo.java | 53 ++
src/main/java/com/ruoyi/sales/vo/CustomerTransactionsProductVo.java | 53 ++
14 files changed, 1,271 insertions(+), 4 deletions(-)
diff --git a/docs/20260618_customer_transactions_optimization.md b/docs/20260618_customer_transactions_optimization.md
new file mode 100644
index 0000000..ebb7fa2
--- /dev/null
+++ b/docs/20260618_customer_transactions_optimization.md
@@ -0,0 +1,839 @@
+# 瀹㈡埛寰�鏉ュ缁村害鏄庣粏鍔熻兘鍓嶇鑱旇皟鏂囨。
+
+> 浼樺寲瀹㈡埛寰�鏉ュ姛鑳斤紝鏂板澶氱淮搴︽槑缁嗘煡璇㈡帴鍙o紝鏀寔浜у搧鏄庣粏鍜屽彂璐ф槑缁嗙淮搴�
+
+## 娑夊強椤甸潰
+
+- 钀ラ攢绠$悊 / 瀹㈡埛寰�鏉� - 瀹㈡埛寰�鏉ュ垪琛ㄩ〉
+- 钀ラ攢绠$悊 / 瀹㈡埛寰�鏉� - 瀹㈡埛寰�鏉ヨ鎯呴〉锛堟柊澧烇級
+- 钀ラ攢绠$悊 / 瀹㈡埛寰�鏉� - 浜у搧鏄庣粏Tab锛堟柊澧烇級
+- 钀ラ攢绠$悊 / 瀹㈡埛寰�鏉� - 鍙戣揣鏄庣粏Tab锛堟柊澧烇級
+
+## API
+
+### 1. 瀹㈡埛寰�鏉ュ垪琛紙鍘熸湁鎺ュ彛锛屾湭鍙樻洿锛�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | /metricStatistics/customewTransactions | 瀹㈡埛寰�鏉ュ垪琛� |
+
+**璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| pageNum | Long | 鍚� | 椤电爜锛岄粯璁�1 |
+| pageSize | Long | 鍚� | 姣忛〉鏉℃暟锛岄粯璁�10 |
+| customerName | String | 鍚� | 瀹㈡埛鍚嶇О锛堟ā绯婃悳绱級 |
+
+**鍝嶅簲瀛楁锛�**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| customerId | Long | 瀹㈡埛ID |
+| customerName | String | 瀹㈡埛鍚嶇О |
+| contractAmounts | BigDecimal | 鍚堝悓鎬婚噾棰� |
+| receiptPaymentAmount | BigDecimal | 鏀舵閲戦 |
+| receiptableAmount | BigDecimal | 搴旀敹閲戦 |
+
+---
+
+### 1.5 瀹㈡埛寰�鏉ユ槑缁嗭紙鍘熸湁鎺ュ彛锛屾柊澧炲瓧娈碉級
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | /metricStatistics/customewTransactionsDetails | 瀹㈡埛寰�鏉ユ槑缁嗭紙鍚堝悓缁村害锛� |
+
+**璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| customerId | Long | 鏄� | 瀹㈡埛ID |
+| pageNum | Long | 鍚� | 椤电爜锛岄粯璁�1 |
+| pageSize | Long | 鍚� | 姣忛〉鏉℃暟锛岄粯璁�10 |
+
+**鍝嶅簲瀛楁锛�**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| salesLedgerId | Long | 閿�鍞彴璐D |
+| salesContractNo | String | 閿�鍞悎鍚屽彿 |
+| executionDate | LocalDate | 鍚堝悓绛捐鏃ユ湡 |
+| contractAmount | BigDecimal | 鍚堝悓閲戦 |
+| **productNames** | String | **浜у搧鍚嶇О鍒楄〃锛堥�楀彿鍒嗛殧锛夈�愭柊澧炪��** |
+| receiptPaymentAmount | BigDecimal | 鏀舵閲戦 |
+| receiptableAmount | BigDecimal | 搴旀敹閲戦 |
+
+**鍝嶅簲绀轰緥锛�**
+
+```json
+{
+ "code": 200,
+ "msg": "鎿嶄綔鎴愬姛",
+ "data": {
+ "records": [
+ {
+ "salesLedgerId": 1,
+ "salesContractNo": "HT-2026-001",
+ "executionDate": "2026-06-01",
+ "contractAmount": 50000.00,
+ "productNames": "浜у搧A,浜у搧B,浜у搧C",
+ "receiptPaymentAmount": 30000.00,
+ "receiptableAmount": 20000.00
+ }
+ ],
+ "total": 10
+ }
+}
+```
+
+---
+
+### 2. 瀹㈡埛寰�鏉ョ粺璁℃眹鎬伙紙鏂板锛�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | /metricStatistics/customerTransactionsSummary | 瀹㈡埛寰�鏉ョ粺璁℃眹鎬� |
+
+**璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| customerId | Long | 鏄� | 瀹㈡埛ID |
+
+**鍝嶅簲瀛楁锛�**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| customerId | Long | 瀹㈡埛ID |
+| customerName | String | 瀹㈡埛鍚嶇О |
+| contractAmounts | BigDecimal | 鍚堝悓鎬婚噾棰� |
+| contractCount | Integer | 鍚堝悓鏁伴噺 |
+| productCount | Integer | 浜у搧绉嶇被鏁� |
+| shippedAmounts | BigDecimal | 鍙戣揣鎬婚噾棰� |
+| shippedQuantity | BigDecimal | 鍙戣揣鎬绘暟閲� |
+| receivedAmounts | BigDecimal | 鏀舵閲戦 |
+| receivableAmounts | BigDecimal | 搴旀敹閲戦 |
+| returnAmounts | BigDecimal | 閫�璐ч噾棰� |
+| unshippedAmounts | BigDecimal | 鏈彂璐ч噾棰� |
+| receivedRate | BigDecimal | 鏀舵鐜�(%) |
+| shippedRate | BigDecimal | 鍙戣揣鐜�(%) |
+
+**鍝嶅簲绀轰緥锛�**
+
+```json
+{
+ "code": 200,
+ "msg": "鎿嶄綔鎴愬姛",
+ "data": {
+ "customerId": 1,
+ "customerName": "瀹㈡埛A",
+ "contractAmounts": 100000.00,
+ "contractCount": 5,
+ "productCount": 12,
+ "shippedAmounts": 80000.00,
+ "shippedQuantity": 500,
+ "receivedAmounts": 60000.00,
+ "receivableAmounts": 20000.00,
+ "returnAmounts": 5000.00,
+ "unshippedAmounts": 20000.00,
+ "receivedRate": 75.00,
+ "shippedRate": 80.00
+ }
+}
+```
+
+---
+
+### 3. 瀹㈡埛寰�鏉ヤ骇鍝佹槑缁嗭紙鏂板锛�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | /metricStatistics/customerTransactionsProducts | 瀹㈡埛寰�鏉ヤ骇鍝佹槑缁� |
+
+**璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| customerId | Long | 鏄� | 瀹㈡埛ID |
+| salesLedgerId | Long | 鍚� | 閿�鍞彴璐D锛堝彲閫夛紝鐢ㄤ簬绛涢�夋煇鍚堝悓锛� |
+| pageNum | Long | 鍚� | 椤电爜锛岄粯璁�1 |
+| pageSize | Long | 鍚� | 姣忛〉鏉℃暟锛岄粯璁�10 |
+
+**鍝嶅簲瀛楁锛�**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| salesLedgerId | Long | 閿�鍞彴璐D |
+| salesContractNo | String | 閿�鍞悎鍚屽彿 |
+| productId | Long | 浜у搧ID |
+| productName | String | 浜у搧鍚嶇О |
+| model | String | 瑙勬牸鍨嬪彿 |
+| unit | String | 鍗曚綅 |
+| contractQuantity | BigDecimal | 鍚堝悓鏁伴噺 |
+| taxInclusiveUnitPrice | BigDecimal | 鍚堝悓鍗曚环(鍚◣) |
+| contractAmount | BigDecimal | 鍚堝悓閲戦 |
+| shippedQuantity | BigDecimal | 宸插彂璐ф暟閲� |
+| shippedAmount | BigDecimal | 宸插彂璐ч噾棰� |
+| receivedAmount | BigDecimal | 宸叉敹娆鹃噾棰� |
+| receivableAmount | BigDecimal | 搴旀敹閲戦 |
+
+**鍝嶅簲绀轰緥锛�**
+
+```json
+{
+ "code": 200,
+ "msg": "鎿嶄綔鎴愬姛",
+ "data": {
+ "records": [
+ {
+ "salesLedgerId": 1,
+ "salesContractNo": "HT-2026-001",
+ "productId": 10,
+ "productName": "浜у搧A",
+ "model": "瑙勬牸1",
+ "unit": "浠�",
+ "contractQuantity": 100,
+ "taxInclusiveUnitPrice": 50.00,
+ "contractAmount": 5000.00,
+ "shippedQuantity": 80,
+ "shippedAmount": 4000.00,
+ "receivedAmount": 3000.00,
+ "receivableAmount": 1000.00
+ }
+ ],
+ "total": 25,
+ "pageNum": 1,
+ "pageSize": 10
+ }
+}
+```
+
+---
+
+### 4. 瀹㈡埛寰�鏉ュ彂璐ф槑缁嗭紙鏂板锛�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | /metricStatistics/customerTransactionsShipments | 瀹㈡埛寰�鏉ュ彂璐ф槑缁� |
+
+**璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| customerId | Long | 鏄� | 瀹㈡埛ID |
+| salesLedgerId | Long | 鍚� | 閿�鍞彴璐D锛堝彲閫夛紝鐢ㄤ簬绛涢�夋煇鍚堝悓锛� |
+| pageNum | Long | 鍚� | 椤电爜锛岄粯璁�1 |
+| pageSize | Long | 鍚� | 姣忛〉鏉℃暟锛岄粯璁�10 |
+
+**鍝嶅簲瀛楁锛�**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| salesLedgerId | Long | 閿�鍞彴璐D |
+| salesContractNo | String | 閿�鍞悎鍚屽彿 |
+| shippingId | Long | 鍙戣揣鍗旾D |
+| shippingNo | String | 鍙戣揣鍗曞彿 |
+| productName | String | 浜у搧鍚嶇О |
+| model | String | 瑙勬牸鍨嬪彿 |
+| shippingQuantity | BigDecimal | 鍙戣揣鏁伴噺 |
+| shippingAmount | BigDecimal | 鍙戣揣閲戦(鍚◣) |
+| batchNo | String | 鍑哄簱鎵瑰彿 |
+| shippingDate | LocalDate | 鍙戣揣鏃ユ湡 |
+| approvalStatus | Integer | 瀹℃壒鐘舵��(0寰呭/1宸插) |
+| receivedAmount | BigDecimal | 宸叉敹娆鹃噾棰� |
+| receivableAmount | BigDecimal | 搴旀敹閲戦 |
+
+**鍝嶅簲绀轰緥锛�**
+
+```json
+{
+ "code": 200,
+ "msg": "鎿嶄綔鎴愬姛",
+ "data": {
+ "records": [
+ {
+ "salesLedgerId": 1,
+ "salesContractNo": "HT-2026-001",
+ "shippingId": 100,
+ "shippingNo": "FH-2026-001",
+ "productName": "浜у搧A",
+ "model": "瑙勬牸1",
+ "shippingQuantity": 50,
+ "shippingAmount": 2500.00,
+ "batchNo": "20260618001",
+ "shippingDate": "2026-06-18",
+ "approvalStatus": 1,
+ "receivedAmount": 2000.00,
+ "receivableAmount": 500.00
+ }
+ ],
+ "total": 30,
+ "pageNum": 1,
+ "pageSize": 10
+ }
+}
+```
+
+---
+
+## 鍓嶇椤甸潰璁捐
+
+### 1. 瀹㈡埛寰�鏉ュ垪琛ㄩ〉锛堜紭鍖栵級
+
+```html
+<template>
+ <div class="app-container">
+ <!-- 鎼滅储鏍� -->
+ <el-form :model="queryParams" ref="queryForm" :inline="true">
+ <el-form-item label="瀹㈡埛鍚嶇О" prop="customerName">
+ <el-input v-model="queryParams.customerName" placeholder="璇疯緭鍏ュ鎴峰悕绉�" clearable />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getList">鎼滅储</el-button>
+ <el-button @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+
+ <!-- 鏁版嵁琛ㄦ牸 -->
+ <el-table :data="list" v-loading="loading">
+ <el-table-column label="瀹㈡埛鍚嶇О" prop="customerName" />
+ <el-table-column label="鍚堝悓鎬婚噾棰�" prop="contractAmounts" align="right">
+ <template #default="{ row }">
+ {{ formatMoney(row.contractAmounts) }}
+ </template>
+ </el-table-column>
+ <el-table-column label="鏀舵閲戦" prop="receiptPaymentAmount" align="right">
+ <template #default="{ row }">
+ {{ formatMoney(row.receiptPaymentAmount) }}
+ </template>
+ </el-table-column>
+ <el-table-column label="搴旀敹閲戦" prop="receiptableAmount" align="right">
+ <template #default="{ row }">
+ <span :class="{ 'text-danger': row.receiptableAmount > 0 }">
+ {{ formatMoney(row.receiptableAmount) }}
+ </span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" width="150" align="center">
+ <template #default="{ row }">
+ <el-button type="text" @click="viewDetail(row)">鏌ョ湅鏄庣粏</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <!-- 鍒嗛〉 -->
+ <el-pagination
+ v-show="total > 0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+ </div>
+</template>
+
+<script>
+export default {
+ name: 'CustomerTransactions',
+ data() {
+ return {
+ loading: false,
+ list: [],
+ total: 0,
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ customerName: ''
+ }
+ }
+ },
+ created() {
+ this.getList()
+ },
+ methods: {
+ getList() {
+ this.loading = true
+ this.$axios.get('/metricStatistics/customewTransactions', { params: this.queryParams })
+ .then(res => {
+ this.list = res.data.records
+ this.total = res.data.total
+ })
+ .finally(() => {
+ this.loading = false
+ })
+ },
+ resetQuery() {
+ this.queryParams.customerName = ''
+ this.getList()
+ },
+ formatMoney(value) {
+ if (!value) return '0.00'
+ return Number(value).toFixed(2)
+ },
+ viewDetail(row) {
+ this.$router.push({ path: '/sales/customerTransactions/detail', query: { customerId: row.customerId } })
+ }
+ }
+}
+</script>
+```
+
+---
+
+### 2. 瀹㈡埛寰�鏉ヨ鎯呴〉锛堟柊澧烇級
+
+```html
+<template>
+ <div class="app-container">
+ <!-- 椤堕儴缁熻鍗$墖 -->
+ <el-card class="summary-card">
+ <div slot="header">
+ <span>{{ summary.customerName }} - 寰�鏉ョ粺璁�</span>
+ </div>
+ <el-row :gutter="20">
+ <el-col :span="4">
+ <div class="stat-item">
+ <div class="stat-label">鍚堝悓鎬婚噾棰�</div>
+ <div class="stat-value">{{ formatMoney(summary.contractAmounts) }}</div>
+ </div>
+ </el-col>
+ <el-col :span="4">
+ <div class="stat-item">
+ <div class="stat-label">鍚堝悓鏁伴噺</div>
+ <div class="stat-value">{{ summary.contractCount }}浠�</div>
+ </div>
+ </el-col>
+ <el-col :span="4">
+ <div class="stat-item">
+ <div class="stat-label">浜у搧绉嶇被</div>
+ <div class="stat-value">{{ summary.productCount }}绉�</div>
+ </div>
+ </el-col>
+ <el-col :span="4">
+ <div class="stat-item">
+ <div class="stat-label">鍙戣揣閲戦</div>
+ <div class="stat-value">{{ formatMoney(summary.shippedAmounts) }}</div>
+ </div>
+ </el-col>
+ <el-col :span="4">
+ <div class="stat-item">
+ <div class="stat-label">鏀舵閲戦</div>
+ <div class="stat-value text-success">{{ formatMoney(summary.receivedAmounts) }}</div>
+ </div>
+ </el-col>
+ <el-col :span="4">
+ <div class="stat-item">
+ <div class="stat-label">搴旀敹閲戦</div>
+ <div class="stat-value text-danger">{{ formatMoney(summary.receivableAmounts) }}</div>
+ </div>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20" style="margin-top: 15px;">
+ <el-col :span="4">
+ <div class="stat-item">
+ <div class="stat-label">閫�璐ч噾棰�</div>
+ <div class="stat-value">{{ formatMoney(summary.returnAmounts) }}</div>
+ </div>
+ </el-col>
+ <el-col :span="4">
+ <div class="stat-item">
+ <div class="stat-label">鏈彂璐ч噾棰�</div>
+ <div class="stat-value text-warning">{{ formatMoney(summary.unshippedAmounts) }}</div>
+ </div>
+ </el-col>
+ <el-col :span="4">
+ <div class="stat-item">
+ <div class="stat-label">鏀舵鐜�</div>
+ <div class="stat-value">
+ <el-progress :percentage="summary.receivedRate || 0" :stroke-width="18" />
+ </div>
+ </div>
+ </el-col>
+ <el-col :span="4">
+ <div class="stat-item">
+ <div class="stat-label">鍙戣揣鐜�</div>
+ <div class="stat-value">
+ <el-progress :percentage="summary.shippedRate || 0" :stroke-width="18" color="#67c23a" />
+ </div>
+ </div>
+ </el-col>
+ </el-row>
+ </el-card>
+
+ <!-- Tab 鍒囨崲 -->
+ <el-tabs v-model="activeTab" @tab-click="handleTabChange">
+ <el-tab-pane label="浜у搧鏄庣粏" name="products">
+ <product-table :customerId="customerId" />
+ </el-tab-pane>
+ <el-tab-pane label="鍙戣揣鏄庣粏" name="shipments">
+ <shipment-table :customerId="customerId" />
+ </el-tab-pane>
+ <el-tab-pane label="鍚堝悓鏄庣粏" name="contracts">
+ <contract-table :customerId="customerId" />
+ </el-tab-pane>
+ </el-tabs>
+ </div>
+</template>
+
+<script>
+import ProductTable from './components/ProductTable.vue'
+import ShipmentTable from './components/ShipmentTable.vue'
+import ContractTable from './components/ContractTable.vue'
+
+export default {
+ name: 'CustomerTransactionsDetail',
+ components: { ProductTable, ShipmentTable, ContractTable },
+ data() {
+ return {
+ customerId: null,
+ summary: {},
+ activeTab: 'products'
+ }
+ },
+ created() {
+ this.customerId = this.$route.query.customerId
+ if (this.customerId) {
+ this.getSummary()
+ }
+ },
+ methods: {
+ getSummary() {
+ this.$axios.get('/metricStatistics/customerTransactionsSummary', {
+ params: { customerId: this.customerId }
+ }).then(res => {
+ this.summary = res.data
+ })
+ },
+ formatMoney(value) {
+ if (!value) return '0.00'
+ return Number(value).toFixed(2)
+ },
+ handleTabChange(tab) {
+ // Tab 鍒囨崲鏃跺埛鏂板瓙缁勪欢鏁版嵁
+ }
+ }
+}
+</script>
+
+<style scoped>
+.summary-card {
+ margin-bottom: 20px;
+}
+.stat-item {
+ text-align: center;
+}
+.stat-label {
+ font-size: 14px;
+ color: #909399;
+}
+.stat-value {
+ font-size: 18px;
+ font-weight: bold;
+ margin-top: 5px;
+}
+.text-success {
+ color: #67c23a;
+}
+.text-danger {
+ color: #f56c6c;
+}
+.text-warning {
+ color: #e6a23c;
+}
+</style>
+```
+
+---
+
+### 3. 浜у搧鏄庣粏缁勪欢 (ProductTable.vue)
+
+```html
+<template>
+ <div>
+ <!-- 绛涢�� -->
+ <el-form :inline="true" size="small">
+ <el-form-item label="鍚堝悓鍙�">
+ <el-select v-model="filterData.salesLedgerId" clearable placeholder="鍏ㄩ儴鍚堝悓" @change="getList">
+ <el-option v-for="item in contractList" :key="item.id" :label="item.salesContractNo" :value="item.id" />
+ </el-select>
+ </el-form-item>
+ </el-form>
+
+ <!-- 琛ㄦ牸 -->
+ <el-table :data="list" v-loading="loading" size="small">
+ <el-table-column label="鍚堝悓鍙�" prop="salesContractNo" width="150" />
+ <el-table-column label="浜у搧鍚嶇О" prop="productName" />
+ <el-table-column label="瑙勬牸鍨嬪彿" prop="model" width="120" />
+ <el-table-column label="鍗曚綅" prop="unit" width="80" />
+ <el-table-column label="鍚堝悓鏁伴噺" prop="contractQuantity" align="right" width="100" />
+ <el-table-column label="鍚堝悓鍗曚环" prop="taxInclusiveUnitPrice" align="right" width="100">
+ <template #default="{ row }">
+ {{ formatMoney(row.taxInclusiveUnitPrice) }}
+ </template>
+ </el-table-column>
+ <el-table-column label="鍚堝悓閲戦" prop="contractAmount" align="right" width="120">
+ <template #default="{ row }">
+ {{ formatMoney(row.contractAmount) }}
+ </template>
+ </el-table-column>
+ <el-table-column label="宸插彂璐ф暟閲�" prop="shippedQuantity" align="right" width="100" />
+ <el-table-column label="宸插彂璐ч噾棰�" prop="shippedAmount" align="right" width="120">
+ <template #default="{ row }">
+ {{ formatMoney(row.shippedAmount) }}
+ </template>
+ </el-table-column>
+ <el-table-column label="宸叉敹娆鹃噾棰�" prop="receivedAmount" align="right" width="120">
+ <template #default="{ row }">
+ <span class="text-success">{{ formatMoney(row.receivedAmount) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="搴旀敹閲戦" prop="receivableAmount" align="right" width="120">
+ <template #default="{ row }">
+ <span :class="{ 'text-danger': row.receivableAmount > 0 }">
+ {{ formatMoney(row.receivableAmount) }}
+ </span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍙戣揣杩涘害" width="150">
+ <template #default="{ row }">
+ <el-progress
+ :percentage="calcPercent(row.shippedQuantity, row.contractQuantity)"
+ :stroke-width="10"
+ />
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <!-- 鍒嗛〉 -->
+ <el-pagination
+ v-show="total > 0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ layout="total, prev, pager, next"
+ @pagination="getList"
+ />
+ </div>
+</template>
+
+<script>
+export default {
+ name: 'ProductTable',
+ props: {
+ customerId: {
+ type: Number,
+ required: true
+ }
+ },
+ data() {
+ return {
+ loading: false,
+ list: [],
+ total: 0,
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ customerId: null,
+ salesLedgerId: null
+ },
+ filterData: {
+ salesLedgerId: null
+ },
+ contractList: []
+ }
+ },
+ watch: {
+ customerId(val) {
+ if (val) {
+ this.queryParams.customerId = val
+ this.getList()
+ this.getContractList()
+ }
+ }
+ },
+ methods: {
+ getList() {
+ this.loading = true
+ this.queryParams.salesLedgerId = this.filterData.salesLedgerId
+ this.$axios.get('/metricStatistics/customerTransactionsProducts', { params: this.queryParams })
+ .then(res => {
+ this.list = res.data.records
+ this.total = res.data.total
+ })
+ .finally(() => {
+ this.loading = false
+ })
+ },
+ getContractList() {
+ // 鑾峰彇璇ュ鎴风殑鍚堝悓鍒楄〃鐢ㄤ簬绛涢��
+ this.$axios.get('/metricStatistics/customewTransactionsDetails', {
+ params: { customerId: this.customerId, pageNum: 1, pageSize: 100 }
+ }).then(res => {
+ this.contractList = res.data.records
+ })
+ },
+ formatMoney(value) {
+ if (!value) return '0.00'
+ return Number(value).toFixed(2)
+ },
+ calcPercent(shipped, total) {
+ if (!total || total === 0) return 0
+ return Math.round((shipped / total) * 100)
+ }
+ }
+}
+</script>
+```
+
+---
+
+### 4. 鍙戣揣鏄庣粏缁勪欢 (ShipmentTable.vue)
+
+```html
+<template>
+ <div>
+ <!-- 绛涢�� -->
+ <el-form :inline="true" size="small">
+ <el-form-item label="鍚堝悓鍙�">
+ <el-select v-model="filterData.salesLedgerId" clearable placeholder="鍏ㄩ儴鍚堝悓" @change="getList">
+ <el-option v-for="item in contractList" :key="item.id" :label="item.salesContractNo" :value="item.id" />
+ </el-select>
+ </el-form-item>
+ </el-form>
+
+ <!-- 琛ㄦ牸 -->
+ <el-table :data="list" v-loading="loading" size="small">
+ <el-table-column label="鍚堝悓鍙�" prop="salesContractNo" width="150" />
+ <el-table-column label="鍙戣揣鍗曞彿" prop="shippingNo" width="150" />
+ <el-table-column label="浜у搧鍚嶇О" prop="productName" />
+ <el-table-column label="瑙勬牸鍨嬪彿" prop="model" width="120" />
+ <el-table-column label="鍙戣揣鏁伴噺" prop="shippingQuantity" align="right" width="100" />
+ <el-table-column label="鍙戣揣閲戦" prop="shippingAmount" align="right" width="120">
+ <template #default="{ row }">
+ {{ formatMoney(row.shippingAmount) }}
+ </template>
+ </el-table-column>
+ <el-table-column label="鍑哄簱鎵瑰彿" prop="batchNo" width="150" />
+ <el-table-column label="鍙戣揣鏃ユ湡" prop="shippingDate" width="120" />
+ <el-table-column label="瀹℃壒鐘舵��" prop="approvalStatus" width="100">
+ <template #default="{ row }">
+ <el-tag :type="row.approvalStatus === 1 ? 'success' : 'warning'" size="mini">
+ {{ row.approvalStatus === 1 ? '宸插' : '寰呭' }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="宸叉敹娆鹃噾棰�" prop="receivedAmount" align="right" width="120">
+ <template #default="{ row }">
+ <span class="text-success">{{ formatMoney(row.receivedAmount) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="搴旀敹閲戦" prop="receivableAmount" align="right" width="120">
+ <template #default="{ row }">
+ <span :class="{ 'text-danger': row.receivableAmount > 0 }">
+ {{ formatMoney(row.receivableAmount) }}
+ </span>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <!-- 鍒嗛〉 -->
+ <el-pagination
+ v-show="total > 0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ layout="total, prev, pager, next"
+ @pagination="getList"
+ />
+ </div>
+</template>
+
+<script>
+export default {
+ name: 'ShipmentTable',
+ props: {
+ customerId: {
+ type: Number,
+ required: true
+ }
+ },
+ data() {
+ return {
+ loading: false,
+ list: [],
+ total: 0,
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ customerId: null,
+ salesLedgerId: null
+ },
+ filterData: {
+ salesLedgerId: null
+ },
+ contractList: []
+ }
+ },
+ watch: {
+ customerId(val) {
+ if (val) {
+ this.queryParams.customerId = val
+ this.getList()
+ this.getContractList()
+ }
+ }
+ },
+ methods: {
+ getList() {
+ this.loading = true
+ this.queryParams.salesLedgerId = this.filterData.salesLedgerId
+ this.$axios.get('/metricStatistics/customerTransactionsShipments', { params: this.queryParams })
+ .then(res => {
+ this.list = res.data.records
+ this.total = res.data.total
+ })
+ .finally(() => {
+ this.loading = false
+ })
+ },
+ getContractList() {
+ this.$axios.get('/metricStatistics/customewTransactionsDetails', {
+ params: { customerId: this.customerId, pageNum: 1, pageSize: 100 }
+ }).then(res => {
+ this.contractList = res.data.records
+ })
+ },
+ formatMoney(value) {
+ if (!value) return '0.00'
+ return Number(value).toFixed(2)
+ }
+ }
+}
+</script>
+```
+
+---
+
+## 娉ㄦ剰浜嬮」
+
+1. **璺敱閰嶇疆**锛氶渶鍦ㄨ矾鐢变腑鏂板瀹㈡埛寰�鏉ヨ鎯呴〉璺敱 `/sales/customerTransactions/detail`
+2. **缁勪欢鎷嗗垎**锛氫骇鍝佹槑缁嗗拰鍙戣揣鏄庣粏寤鸿鎷嗗垎涓虹嫭绔嬬粍浠讹紝渚夸簬澶嶇敤鍜岀淮鎶�
+3. **绛涢�夎仈鍔�**锛氫骇鍝佹槑缁嗗拰鍙戣揣鏄庣粏鏀寔鎸夊悎鍚岀瓫閫夛紝鍚堝悓鍒楄〃浠庡師鏈夋帴鍙h幏鍙�
+4. **鏁版嵁鏍煎紡**锛氶噾棰濆瓧娈甸渶缁熶竴浣跨敤 `formatMoney` 鏂规硶鏍煎紡鍖栨樉绀�
+5. **杩涘害鏉℃樉绀�**锛氫骇鍝佹槑缁嗕腑鐨勫彂璐ц繘搴︿娇鐢� `el-progress` 缁勪欢鐩磋灞曠ず
+6. **鐘舵�佹爣璇�**锛氬簲鏀堕噾棰濆ぇ浜�0鏃朵娇鐢ㄧ孩鑹叉爣璇嗭紝宸叉敹娆句娇鐢ㄧ豢鑹叉爣璇�
+7. **瀹℃壒鐘舵��**锛氬彂璐ф槑缁嗕腑鐨勫鎵圭姸鎬佷娇鐢� `el-tag` 灞曠ず锛屽凡瀹′负缁胯壊锛屽緟瀹′负榛勮壊
+
+---
+
+## 鏁版嵁瀵规瘮
+
+### 浼樺寲鍓� vs 浼樺寲鍚�
+
+| 缁村害 | 浼樺寲鍓� | 浼樺寲鍚� |
+|------|--------|--------|
+| 瀹㈡埛寰�鏉� | 鍙湁鍚堝悓閲戦銆佹敹娆俱�佸簲鏀� | 鏂板鍚堝悓鏁般�佷骇鍝佹暟銆佸彂璐х巼銆佹敹娆剧巼绛�12椤规寚鏍� |
+| 鏄庣粏缁村害 | 浠呭悎鍚屾槑缁� | 鏂板浜у搧鏄庣粏銆佸彂璐ф槑缁� |
+| 绛涢�夎兘鍔� | 浠呮寜瀹㈡埛鍚嶇瓫閫� | 鏀寔鎸夊悎鍚岀瓫閫変骇鍝�/鍙戣揣鏄庣粏 |
+| 鏁版嵁杩芥函 | 鏃犳硶杩芥函鍏蜂綋鍙戣揣 | 鍙拷婧瘡鏉″彂璐ц褰曠殑鏀舵鎯呭喌 |
+| 杩涘害灞曠ず | 鏃� | 鍙戣揣杩涘害鏉$洿瑙傚睍绀� |
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java b/src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java
index f871b91..1bc9f0f 100644
--- a/src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java
+++ b/src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java
@@ -8,6 +8,9 @@
import com.ruoyi.basic.vo.CustomerVo;
import com.ruoyi.sales.vo.CustomerTransactionsDetailsVo;
import com.ruoyi.sales.vo.CustomerTransactionsVo;
+import com.ruoyi.sales.vo.CustomerTransactionsProductVo;
+import com.ruoyi.sales.vo.CustomerTransactionsShipmentVo;
+import com.ruoyi.sales.vo.CustomerTransactionsSummaryVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@@ -77,4 +80,21 @@
IPage<CustomerTransactionsVo> customewTransactions(Page page, @Param("customerName") String customerName);
IPage<CustomerTransactionsDetailsVo> customewTransactionsDetails(Page page, @Param("customerId") Long customerId);
+
+ /**
+ * 鏌ヨ瀹㈡埛寰�鏉ョ粺璁℃眹鎬�
+ */
+ CustomerTransactionsSummaryVo getCustomerTransactionsSummary(@Param("customerId") Long customerId);
+
+ /**
+ * 鏌ヨ瀹㈡埛寰�鏉ヤ骇鍝佹槑缁�
+ */
+ IPage<CustomerTransactionsProductVo> getCustomerTransactionsProducts(Page page,
+ @Param("customerId") Long customerId, @Param("salesLedgerId") Long salesLedgerId);
+
+ /**
+ * 鏌ヨ瀹㈡埛寰�鏉ュ彂璐ф槑缁�
+ */
+ IPage<CustomerTransactionsShipmentVo> getCustomerTransactionsShipments(Page page,
+ @Param("customerId") Long customerId, @Param("salesLedgerId") Long salesLedgerId);
}
diff --git a/src/main/java/com/ruoyi/basic/service/ICustomerService.java b/src/main/java/com/ruoyi/basic/service/ICustomerService.java
index 27e4739..53ab6d6 100644
--- a/src/main/java/com/ruoyi/basic/service/ICustomerService.java
+++ b/src/main/java/com/ruoyi/basic/service/ICustomerService.java
@@ -9,6 +9,9 @@
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.sales.vo.CustomerTransactionsDetailsVo;
import com.ruoyi.sales.vo.CustomerTransactionsVo;
+import com.ruoyi.sales.vo.CustomerTransactionsProductVo;
+import com.ruoyi.sales.vo.CustomerTransactionsShipmentVo;
+import com.ruoyi.sales.vo.CustomerTransactionsSummaryVo;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@@ -111,4 +114,29 @@
* @return
*/
IPage<CustomerTransactionsDetailsVo> customewTransactionsDetails(Page page, Long customerId);
+
+ /**
+ * 鏌ヨ瀹㈡埛寰�鏉ョ粺璁℃眹鎬伙紙浼樺寲鐗堬級
+ * @param customerId 瀹㈡埛ID
+ * @return 缁熻姹囨�绘暟鎹�
+ */
+ CustomerTransactionsSummaryVo getCustomerTransactionsSummary(Long customerId);
+
+ /**
+ * 鏌ヨ瀹㈡埛寰�鏉ヤ骇鍝佹槑缁�
+ * @param page 鍒嗛〉鍙傛暟
+ * @param customerId 瀹㈡埛ID
+ * @param salesLedgerId 閿�鍞彴璐D锛堝彲閫夛級
+ * @return 浜у搧鏄庣粏鍒嗛〉鏁版嵁
+ */
+ IPage<CustomerTransactionsProductVo> getCustomerTransactionsProducts(Page page, Long customerId, Long salesLedgerId);
+
+ /**
+ * 鏌ヨ瀹㈡埛寰�鏉ュ彂璐ф槑缁�
+ * @param page 鍒嗛〉鍙傛暟
+ * @param customerId 瀹㈡埛ID
+ * @param salesLedgerId 閿�鍞彴璐D锛堝彲閫夛級
+ * @return 鍙戣揣鏄庣粏鍒嗛〉鏁版嵁
+ */
+ IPage<CustomerTransactionsShipmentVo> getCustomerTransactionsShipments(Page page, Long customerId, Long salesLedgerId);
}
diff --git a/src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java b/src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
index eef85aa..edf927c 100644
--- a/src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
+++ b/src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
@@ -25,6 +25,9 @@
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.vo.CustomerTransactionsDetailsVo;
import com.ruoyi.sales.vo.CustomerTransactionsVo;
+import com.ruoyi.sales.vo.CustomerTransactionsProductVo;
+import com.ruoyi.sales.vo.CustomerTransactionsShipmentVo;
+import com.ruoyi.sales.vo.CustomerTransactionsSummaryVo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
@@ -391,6 +394,21 @@
return customerMapper.customewTransactionsDetails(page, customerId);
}
+ @Override
+ public CustomerTransactionsSummaryVo getCustomerTransactionsSummary(Long customerId) {
+ return customerMapper.getCustomerTransactionsSummary(customerId);
+ }
+
+ @Override
+ public IPage<CustomerTransactionsProductVo> getCustomerTransactionsProducts(Page page, Long customerId, Long salesLedgerId) {
+ return customerMapper.getCustomerTransactionsProducts(page, customerId, salesLedgerId);
+ }
+
+ @Override
+ public IPage<CustomerTransactionsShipmentVo> getCustomerTransactionsShipments(Page page, Long customerId, Long salesLedgerId) {
+ return customerMapper.getCustomerTransactionsShipments(page, customerId, salesLedgerId);
+ }
+
/**
* 涓嬪垝绾垮懡鍚嶈浆椹煎嘲鍛藉悕
*/
diff --git a/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java b/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
index 322eabf..c578b78 100644
--- a/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
+++ b/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
@@ -38,8 +38,6 @@
@Excel(name = "閲囪喘鍚堝悓鍙�")
private String purchaseContractNumber;
-
-
/**
* 渚涘簲鍟嗗悕绉癷d
*/
@@ -143,6 +141,9 @@
private List<SalesLedgerProduct> productData;
+ @Schema(description = "鎵归噺澶勭悊閲囪喘鍙拌处ID鍒楄〃")
+ private List<Long> ids;
+
private List<String> tempFileIds;
private List<CommonFile> SalesLedgerFiles;
diff --git a/src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java b/src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java
index 577508a..f6fe494 100644
--- a/src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java
+++ b/src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java
@@ -55,4 +55,25 @@
return R.ok(customerService.customewTransactionsDetails(page,customerId));
}
+ @GetMapping("/customerTransactionsSummary")
+ @Log(title = "瀹㈡埛寰�鏉ョ粺璁℃眹鎬�", businessType = BusinessType.OTHER)
+ @Operation(summary = "瀹㈡埛寰�鏉ョ粺璁℃眹鎬�")
+ public R customerTransactionsSummary(Long customerId) {
+ return R.ok(customerService.getCustomerTransactionsSummary(customerId));
+ }
+
+ @GetMapping("/customerTransactionsProducts")
+ @Log(title = "瀹㈡埛寰�鏉ヤ骇鍝佹槑缁�", businessType = BusinessType.OTHER)
+ @Operation(summary = "瀹㈡埛寰�鏉ヤ骇鍝佹槑缁�")
+ public R customerTransactionsProducts(Page page, Long customerId, Long salesLedgerId) {
+ return R.ok(customerService.getCustomerTransactionsProducts(page, customerId, salesLedgerId));
+ }
+
+ @GetMapping("/customerTransactionsShipments")
+ @Log(title = "瀹㈡埛寰�鏉ュ彂璐ф槑缁�", businessType = BusinessType.OTHER)
+ @Operation(summary = "瀹㈡埛寰�鏉ュ彂璐ф槑缁�")
+ public R customerTransactionsShipments(Page page, Long customerId, Long salesLedgerId) {
+ return R.ok(customerService.getCustomerTransactionsShipments(page, customerId, salesLedgerId));
+ }
+
}
diff --git a/src/main/java/com/ruoyi/sales/pojo/ShippingInfo.java b/src/main/java/com/ruoyi/sales/pojo/ShippingInfo.java
index ed9a268..e564770 100644
--- a/src/main/java/com/ruoyi/sales/pojo/ShippingInfo.java
+++ b/src/main/java/com/ruoyi/sales/pojo/ShippingInfo.java
@@ -28,6 +28,10 @@
@Excel(name = "瀹㈡埛鍚嶇О")
private String customerName;
+ @TableField(exist = false)
+ @Schema(description = "瀹㈡埛ID")
+ private Long customerId;
+
@TableId(value = "id", type = IdType.AUTO)
private Long id;
diff --git a/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsDetailsVo.java b/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsDetailsVo.java
index 992860e..3771647 100644
--- a/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsDetailsVo.java
+++ b/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsDetailsVo.java
@@ -24,6 +24,9 @@
@Schema(description = "鍚堝悓閲戦")
private BigDecimal contractAmount;
+ @Schema(description = "浜у搧鍚嶇О鍒楄〃锛堥�楀彿鍒嗛殧锛�")
+ private String productNames;
+
@Schema(description = "鏀舵閲戦")
private BigDecimal receiptPaymentAmount;
diff --git a/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsProductVo.java b/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsProductVo.java
new file mode 100644
index 0000000..9b0452b
--- /dev/null
+++ b/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsProductVo.java
@@ -0,0 +1,53 @@
+package com.ruoyi.sales.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 瀹㈡埛寰�鏉ヤ骇鍝佹槑缁哣O
+ */
+@Data
+@Schema(name = "CustomerTransactionsProductVo", description = "瀹㈡埛寰�鏉ヤ骇鍝佹槑缁�")
+public class CustomerTransactionsProductVo {
+
+ @Schema(description = "閿�鍞彴璐D")
+ private Long salesLedgerId;
+
+ @Schema(description = "閿�鍞悎鍚屽彿")
+ private String salesContractNo;
+
+ @Schema(description = "浜у搧ID")
+ private Long productId;
+
+ @Schema(description = "浜у搧鍚嶇О")
+ private String productName;
+
+ @Schema(description = "瑙勬牸鍨嬪彿")
+ private String model;
+
+ @Schema(description = "鍗曚綅")
+ private String unit;
+
+ @Schema(description = "鍚堝悓鏁伴噺")
+ private BigDecimal contractQuantity;
+
+ @Schema(description = "鍚堝悓鍗曚环(鍚◣)")
+ private BigDecimal taxInclusiveUnitPrice;
+
+ @Schema(description = "鍚堝悓閲戦")
+ private BigDecimal contractAmount;
+
+ @Schema(description = "宸插彂璐ф暟閲�")
+ private BigDecimal shippedQuantity;
+
+ @Schema(description = "宸插彂璐ч噾棰�")
+ private BigDecimal shippedAmount;
+
+ @Schema(description = "宸叉敹娆鹃噾棰�")
+ private BigDecimal receivedAmount;
+
+ @Schema(description = "搴旀敹閲戦")
+ private BigDecimal receivableAmount;
+}
diff --git a/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsShipmentVo.java b/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsShipmentVo.java
new file mode 100644
index 0000000..9ce8033
--- /dev/null
+++ b/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsShipmentVo.java
@@ -0,0 +1,56 @@
+package com.ruoyi.sales.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+/**
+ * 瀹㈡埛寰�鏉ュ彂璐ф槑缁哣O
+ */
+@Data
+@Schema(name = "CustomerTransactionsShipmentVo", description = "瀹㈡埛寰�鏉ュ彂璐ф槑缁�")
+public class CustomerTransactionsShipmentVo {
+
+ @Schema(description = "閿�鍞彴璐D")
+ private Long salesLedgerId;
+
+ @Schema(description = "閿�鍞悎鍚屽彿")
+ private String salesContractNo;
+
+ @Schema(description = "鍙戣揣鍗旾D")
+ private Long shippingId;
+
+ @Schema(description = "鍙戣揣鍗曞彿")
+ private String shippingNo;
+
+ @Schema(description = "浜у搧鍚嶇О")
+ private String productName;
+
+ @Schema(description = "瑙勬牸鍨嬪彿")
+ private String model;
+
+ @Schema(description = "鍙戣揣鏁伴噺")
+ private BigDecimal shippingQuantity;
+
+ @Schema(description = "鍙戣揣閲戦(鍚◣)")
+ private BigDecimal shippingAmount;
+
+ @Schema(description = "鍑哄簱鎵瑰彿")
+ private String batchNo;
+
+ @Schema(description = "鍙戣揣鏃ユ湡")
+ @JsonFormat(pattern = "yyyy-MM-dd")
+ private LocalDate shippingDate;
+
+ @Schema(description = "瀹℃壒鐘舵��(0寰呭/1宸插)")
+ private Integer approvalStatus;
+
+ @Schema(description = "宸叉敹娆鹃噾棰�")
+ private BigDecimal receivedAmount;
+
+ @Schema(description = "搴旀敹閲戦")
+ private BigDecimal receivableAmount;
+}
diff --git a/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsSummaryVo.java b/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsSummaryVo.java
new file mode 100644
index 0000000..f172f67
--- /dev/null
+++ b/src/main/java/com/ruoyi/sales/vo/CustomerTransactionsSummaryVo.java
@@ -0,0 +1,53 @@
+package com.ruoyi.sales.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 瀹㈡埛寰�鏉ョ粺璁℃眹鎬籚O锛堜紭鍖栫増锛�
+ */
+@Data
+@Schema(name = "CustomerTransactionsSummaryVo", description = "瀹㈡埛寰�鏉ョ粺璁℃眹鎬�")
+public class CustomerTransactionsSummaryVo {
+
+ @Schema(description = "瀹㈡埛ID")
+ private Long customerId;
+
+ @Schema(description = "瀹㈡埛鍚嶇О")
+ private String customerName;
+
+ @Schema(description = "鍚堝悓鎬婚噾棰�")
+ private BigDecimal contractAmounts;
+
+ @Schema(description = "鍚堝悓鏁伴噺")
+ private Integer contractCount;
+
+ @Schema(description = "浜у搧绉嶇被鏁�")
+ private Integer productCount;
+
+ @Schema(description = "鍙戣揣鎬婚噾棰�")
+ private BigDecimal shippedAmounts;
+
+ @Schema(description = "鍙戣揣鎬绘暟閲�")
+ private BigDecimal shippedQuantity;
+
+ @Schema(description = "鏀舵閲戦")
+ private BigDecimal receivedAmounts;
+
+ @Schema(description = "搴旀敹閲戦")
+ private BigDecimal receivableAmounts;
+
+ @Schema(description = "閫�璐ч噾棰�")
+ private BigDecimal returnAmounts;
+
+ @Schema(description = "鏈彂璐ч噾棰�")
+ private BigDecimal unshippedAmounts;
+
+ @Schema(description = "鏀舵鐜�(%)")
+ private BigDecimal receivedRate;
+
+ @Schema(description = "鍙戣揣鐜�(%)")
+ private BigDecimal shippedRate;
+}
diff --git a/src/main/resources/mapper/basic/CustomerMapper.xml b/src/main/resources/mapper/basic/CustomerMapper.xml
index 8117c66..fe3309b 100644
--- a/src/main/resources/mapper/basic/CustomerMapper.xml
+++ b/src/main/resources/mapper/basic/CustomerMapper.xml
@@ -151,6 +151,7 @@
sl.sales_contract_no,
sl.execution_date,
sl.contract_amount,
+ IFNULL(T4.productNames, '') AS productNames,
IFNULL(T1.receiptPaymentAmount, 0) AS receiptPaymentAmount,
IFNULL(T2.outboundAmount, 0) - IFNULL(T3.returnAmount, 0) AS receiptableAmount
from sales_ledger sl
@@ -188,6 +189,167 @@
where rm.status=1
group by sl.id
)T3 on T3.id = sl.id
+ left join (
+ select slp.sales_ledger_id, GROUP_CONCAT(p.product_name) as productNames
+ from sales_ledger_product slp
+ left join product p on slp.product_id = p.id
+ where slp.type = 1
+ group by slp.sales_ledger_id
+ ) T4 on T4.sales_ledger_id = sl.id
where sl.customer_id = #{customerId}
+ order by sl.id desc
+ </select>
+
+ <!-- 瀹㈡埛寰�鏉ョ粺璁℃眹鎬� -->
+ <select id="getCustomerTransactionsSummary" resultType="com.ruoyi.sales.vo.CustomerTransactionsSummaryVo">
+ SELECT
+ c.id AS customerId,
+ c.customer_name AS customerName,
+ IFNULL(T1.contractAmounts, 0) AS contractAmounts,
+ IFNULL(T1.contractCount, 0) AS contractCount,
+ IFNULL(T5.productCount, 0) AS productCount,
+ IFNULL(T2.shippedAmounts, 0) AS shippedAmounts,
+ IFNULL(T2.shippedQuantity, 0) AS shippedQuantity,
+ IFNULL(T3.receivedAmounts, 0) AS receivedAmounts,
+ IFNULL(T2.shippedAmounts, 0) - IFNULL(T3.receivedAmounts, 0) AS receivableAmounts,
+ IFNULL(T4.returnAmounts, 0) AS returnAmounts,
+ IFNULL(T1.contractAmounts, 0) - IFNULL(T2.shippedAmounts, 0) AS unshippedAmounts,
+ CASE WHEN IFNULL(T2.shippedAmounts, 0) > 0
+ THEN ROUND(IFNULL(T3.receivedAmounts, 0) / T2.shippedAmounts * 100, 2)
+ ELSE 0 END AS receivedRate,
+ CASE WHEN IFNULL(T1.contractAmounts, 0) > 0
+ THEN ROUND(IFNULL(T2.shippedAmounts, 0) / T1.contractAmounts * 100, 2)
+ ELSE 0 END AS shippedRate
+ FROM customer c
+ LEFT JOIN (
+ SELECT customer_id, SUM(contract_amount) AS contractAmounts, COUNT(*) AS contractCount
+ FROM sales_ledger WHERE customer_id = #{customerId}
+ GROUP BY customer_id
+ ) T1 ON T1.customer_id = c.id
+ LEFT JOIN (
+ SELECT
+ sl.customer_id,
+ SUM(sor.stock_out_num) AS shippedQuantity,
+ SUM(sor.stock_out_num * slp.tax_inclusive_unit_price) AS shippedAmounts
+ FROM stock_out_record sor
+ LEFT JOIN shipping_info s ON sor.record_id = s.id
+ LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id
+ LEFT JOIN sales_ledger_product slp ON s.sales_ledger_product_id = slp.id
+ WHERE sor.record_type = '13' AND sor.approval_status = 1 AND slp.type = 1
+ AND sl.customer_id = #{customerId}
+ GROUP BY sl.customer_id
+ ) T2 ON T2.customer_id = c.id
+ LEFT JOIN (
+ SELECT customer_id, SUM(collection_amount) AS receivedAmounts
+ FROM account_sales_collection WHERE customer_id = #{customerId}
+ GROUP BY customer_id
+ ) T3 ON T3.customer_id = c.id
+ LEFT JOIN (
+ SELECT
+ sl.customer_id,
+ SUM(rm.refund_amount) AS returnAmounts
+ FROM return_management rm
+ LEFT JOIN shipping_info si ON rm.shipping_id = si.id
+ LEFT JOIN sales_ledger sl ON si.sales_ledger_id = sl.id
+ WHERE rm.status = 1 AND sl.customer_id = #{customerId}
+ GROUP BY sl.customer_id
+ ) T4 ON T4.customer_id = c.id
+ LEFT JOIN (
+ SELECT sl.customer_id, COUNT(DISTINCT pm.product_id) AS productCount
+ FROM sales_ledger sl
+ LEFT JOIN sales_ledger_product slp ON sl.id = slp.sales_ledger_id
+ LEFT JOIN product_model pm ON slp.product_id = pm.id
+ WHERE sl.customer_id = #{customerId} AND slp.type = 1
+ GROUP BY sl.customer_id
+ ) T5 ON T5.customer_id = c.id
+ WHERE c.id = #{customerId}
+ </select>
+
+ <!-- 瀹㈡埛寰�鏉ヤ骇鍝佹槑缁� -->
+ <select id="getCustomerTransactionsProducts" resultType="com.ruoyi.sales.vo.CustomerTransactionsProductVo">
+ SELECT
+ sl.id AS salesLedgerId,
+ sl.sales_contract_no AS salesContractNo,
+ slp.product_id AS productId,
+ IFNULL(p.product_name, slp.product_category) AS productName,
+ IFNULL(pm.model, slp.specification_model) AS model,
+ IFNULL(pm.unit, slp.unit) AS unit,
+ slp.quantity AS contractQuantity,
+ slp.tax_inclusive_unit_price AS taxInclusiveUnitPrice,
+ slp.quantity * slp.tax_inclusive_unit_price AS contractAmount,
+ IFNULL(T1.shippedQuantity, 0) AS shippedQuantity,
+ IFNULL(T1.shippedAmount, 0) AS shippedAmount,
+ IFNULL(T2.receivedAmount, 0) AS receivedAmount,
+ IFNULL(T1.shippedAmount, 0) - IFNULL(T2.receivedAmount, 0) AS receivableAmount
+ FROM sales_ledger sl
+ LEFT JOIN sales_ledger_product slp ON sl.id = slp.sales_ledger_id
+ LEFT JOIN product_model pm ON slp.product_id = pm.id
+ LEFT JOIN product p ON pm.product_id = p.id
+ LEFT JOIN (
+ SELECT
+ s.sales_ledger_id,
+ s.sales_ledger_product_id,
+ SUM(sor.stock_out_num) AS shippedQuantity,
+ SUM(sor.stock_out_num * slp2.tax_inclusive_unit_price) AS shippedAmount
+ FROM stock_out_record sor
+ LEFT JOIN shipping_info s ON sor.record_id = s.id
+ LEFT JOIN sales_ledger_product slp2 ON s.sales_ledger_product_id = slp2.id
+ WHERE sor.record_type = '13' AND sor.approval_status = 1
+ GROUP BY s.sales_ledger_id, s.sales_ledger_product_id
+ ) T1 ON T1.sales_ledger_id = sl.id AND T1.sales_ledger_product_id = slp.id
+ LEFT JOIN (
+ SELECT
+ s.sales_ledger_id,
+ s.sales_ledger_product_id,
+ SUM(ascc.collection_amount) AS receivedAmount
+ FROM account_sales_collection ascc
+ LEFT JOIN stock_out_record sor ON FIND_IN_SET(sor.id, ascc.stock_out_record_ids) > 0
+ LEFT JOIN shipping_info s ON sor.record_id = s.id
+ WHERE sor.record_type = '13' AND sor.approval_status = 1
+ GROUP BY s.sales_ledger_id, s.sales_ledger_product_id
+ ) T2 ON T2.sales_ledger_id = sl.id AND T2.sales_ledger_product_id = slp.id
+ WHERE sl.customer_id = #{customerId} AND slp.type = 1
+ <if test="salesLedgerId != null">
+ AND sl.id = #{salesLedgerId}
+ </if>
+ ORDER BY sl.id DESC, slp.id DESC
+ </select>
+
+ <!-- 瀹㈡埛寰�鏉ュ彂璐ф槑缁� -->
+ <select id="getCustomerTransactionsShipments" resultType="com.ruoyi.sales.vo.CustomerTransactionsShipmentVo">
+ SELECT
+ sl.id AS salesLedgerId,
+ sl.sales_contract_no AS salesContractNo,
+ s.id AS shippingId,
+ s.shipping_no AS shippingNo,
+ IFNULL(p.product_name, slp.product_category) AS productName,
+ IFNULL(pm.model, slp.specification_model) AS model,
+ sor.stock_out_num AS shippingQuantity,
+ sor.stock_out_num * slp.tax_inclusive_unit_price AS shippingAmount,
+ sor.batch_no AS batchNo,
+ s.shipping_date AS shippingDate,
+ sor.approval_status AS approvalStatus,
+ IFNULL(T1.receivedAmount, 0) AS receivedAmount,
+ sor.stock_out_num * slp.tax_inclusive_unit_price - IFNULL(T1.receivedAmount, 0) AS receivableAmount
+ FROM stock_out_record sor
+ LEFT JOIN shipping_info s ON sor.record_id = s.id
+ LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id
+ LEFT JOIN sales_ledger_product slp ON s.sales_ledger_product_id = slp.id
+ LEFT JOIN product_model pm ON slp.product_id = pm.id
+ LEFT JOIN product p ON pm.product_id = p.id
+ LEFT JOIN (
+ SELECT
+ sor2.id AS stock_out_record_id,
+ SUM(ascc.collection_amount) AS receivedAmount
+ FROM account_sales_collection ascc
+ LEFT JOIN stock_out_record sor2 ON FIND_IN_SET(sor2.id, ascc.stock_out_record_ids) > 0
+ WHERE ascc.customer_id = #{customerId}
+ GROUP BY sor2.id
+ ) T1 ON T1.stock_out_record_id = sor.id
+ WHERE sor.record_type = '13' AND sl.customer_id = #{customerId}
+ <if test="salesLedgerId != null">
+ AND sl.id = #{salesLedgerId}
+ </if>
+ ORDER BY sor.id DESC
</select>
</mapper>
diff --git a/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml b/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
index a818160..bac1534 100644
--- a/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
+++ b/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
@@ -81,13 +81,13 @@
sir.stock_in_num
FROM stock_in_record sir
INNER JOIN quality_inspect qi
- ON TRIM(sir.record_type) = '10'
+ ON TRIM(sir.record_type) IN ('6', '10')
AND sir.record_id = qi.id
INNER JOIN sales_ledger_product slp
ON slp.type = 2
AND slp.sales_ledger_id = qi.purchase_ledger_id
AND slp.product_model_id = qi.product_model_id
- WHERE sir.approval_status = 1
+ WHERE qi.inspect_state = 1
) rel
GROUP BY rel.sales_ledger_product_id
) approved_qty ON approved_qty.sales_ledger_product_id = slp.id
@@ -120,6 +120,12 @@
<if test="c.supplierId != null">
AND pl.supplier_id = #{c.supplierId}
</if>
+ <if test="c.ids != null and c.ids.size() > 0">
+ AND pl.id IN
+ <foreach collection="c.ids" item="id" open="(" separator="," close=")">
+ #{id}
+ </foreach>
+ </if>
<if test="c.approvalStatus != null">
AND pl.approval_status = #{c.approvalStatus}
</if>
diff --git a/src/main/resources/mapper/sales/ShippingInfoMapper.xml b/src/main/resources/mapper/sales/ShippingInfoMapper.xml
index 762c2d4..9d387a5 100644
--- a/src/main/resources/mapper/sales/ShippingInfoMapper.xml
+++ b/src/main/resources/mapper/sales/ShippingInfoMapper.xml
@@ -48,6 +48,9 @@
<if test="req.expressNumber != null and req.expressNumber != ''">
AND s.express_number LIKE CONCAT('%',#{req.expressNumber},'%')
</if>
+ <if test="req.customerId != null">
+ AND sl.customer_id = #{req.customerId}
+ </if>
order by create_time DESC
</select>
<select id="listAll" resultType="com.ruoyi.sales.pojo.ShippingInfo">
--
Gitblit v1.9.3