From c15e67c83394c1734eb4e9802d8f343c6076efc1 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 13 五月 2026 16:16:45 +0800
Subject: [PATCH] Merge branch 'dev_New_pro' into dev_宁夏_英泽防锈

---
 src/main/java/com/ruoyi/account/service/AccountPurchaseService.java                            |   27 
 src/main/java/com/ruoyi/procurementrecord/bean/dto/InventoryInformationDto.java                |    2 
 src/main/java/com/ruoyi/procurementrecord/mapper/ProcurementRecordOutMapper.java               |    2 
 src/main/java/com/ruoyi/account/bean/dto/financial/FinLedgerQueryDto.java                      |   25 
 src/main/java/com/ruoyi/sales/service/ShippingInfoService.java                                 |    4 
 src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java                         |   10 
 src/main/java/com/ruoyi/procurementrecord/controller/ProcurementExceptionRecordController.java |   11 
 src/main/java/com/ruoyi/account/mapper/financial/FinFixedAssetMapper.java                      |   12 
 src/main/java/com/ruoyi/procurementrecord/bean/vo/ShippingInfoVo.java                          |   17 
 src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherStatusDto.java                    |   15 
 src/main/java/com/ruoyi/account/service/impl/financial/FinLedgerServiceImpl.java               |  206 ++
 src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java                                |   77 
 src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java                       |    6 
 src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java                            |    2 
 src/main/java/com/ruoyi/technology/bean/vo/TechnologyBomStructureVo.java                       |    3 
 src/main/resources/mapper/sales/SalesLedgerProductMapper.xml                                   |   39 
 doc/20260512_AccountSubject树形改造前端修改文档.md                                                       |  185 +
 src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementPageDtoCopy.java                 |    2 
 src/main/resources/application-dev.yml                                                         |    4 
 src/main/java/com/ruoyi/common/enums/StockOutQualifiedRecordTypeEnum.java                      |    1 
 src/main/java/com/ruoyi/procurementrecord/service/ReturnManagementService.java                 |    6 
 src/main/resources/mapper/procurementrecord/ReturnManagementMapper.xml                         |    8 
 src/main/java/com/ruoyi/account/bean/vo/SalesOutboundVo.java                                   |    6 
 src/main/java/com/ruoyi/account/bean/vo/financial/FinLedgerEntryRecordVo.java                  |   43 
 src/main/java/com/ruoyi/production/pojo/ProductionProductOutput.java                           |    3 
 src/main/resources/mapper/purchase/PurchaseReturnOrderProductsMapper.xml                       |    4 
 src/main/java/com/ruoyi/sales/dto/ShippingInfoDto.java                                         |    6 
 src/main/java/com/ruoyi/account/pojo/financial/FinVoucherEntry.java                            |   85 
 src/main/java/com/ruoyi/purchase/pojo/PurchaseReturnOrderProducts.java                         |   20 
 src/main/java/com/ruoyi/account/bean/dto/PurchaseReturnDto.java                                |   29 
 src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java        |   42 
 src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java                |   54 
 src/main/java/com/ruoyi/account/mapper/financial/FinVoucherEntryMapper.java                    |   28 
 src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementPageDto.java                     |    2 
 src/main/java/com/ruoyi/purchase/dto/SimpleReturnOrderGroupDto.java                            |    2 
 src/main/java/com/ruoyi/account/bean/vo/financial/FinLedgerRowVo.java                          |   53 
 src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementUpdateDto.java                   |    2 
 src/main/java/com/ruoyi/purchase/dto/PurchaseReturnOrderProductsDto.java                       |    2 
 src/main/java/com/ruoyi/account/bean/dto/financial/FinIntangibleAssetDto.java                  |   13 
 src/main/resources/mapper/procurementrecord/ProcurementRecordMapper.xml                        |   24 
 src/main/java/com/ruoyi/account/bean/vo/financial/FinVoucherDetailVo.java                      |   21 
 src/main/java/com/ruoyi/account/controller/AccountSubjectController.java                       |    8 
 src/main/java/com/ruoyi/account/service/impl/AccountSalesServiceImpl.java                      |   16 
 src/main/java/com/ruoyi/purchase/service/impl/PurchaseReturnOrdersServiceImpl.java             |   42 
 src/main/java/com/ruoyi/procurementrecord/bean/dto/ReturnSaleProductDto.java                   |   38 
 src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordController.java          |    3 
 src/main/java/com/ruoyi/account/bean/dto/PurchaseInboundDto.java                               |   29 
 src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementDto.java                         |    2 
 src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordOutService.java             |    6 
 src/main/java/com/ruoyi/projectManagement/service/impl/PlanServiceImpl.java                    |    5 
 src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java                     |    6 
 src/main/java/com/ruoyi/account/bean/dto/SalesOutboundDto.java                                 |    3 
 src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java                           |    2 
 src/main/resources/mapper/procurementrecord/ReturnSaleProductMapper.xml                        |   39 
 src/main/java/com/ruoyi/account/service/financial/FinVoucherService.java                       |   27 
 src/main/java/com/ruoyi/common/enums/StockInQualifiedRecordTypeEnum.java                       |   10 
 src/main/java/com/ruoyi/purchase/vo/PurchaseReturnDetailsVo.java                               |   13 
 src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java          |   51 
 src/main/java/com/ruoyi/warehouse/mapper/DocumentationMapper.java                              |    1 
 src/main/java/com/ruoyi/purchase/vo/PurchaseStockInProductVo.java                              |   50 
 src/main/java/com/ruoyi/procurementrecord/mapper/ReturnSaleProductMapper.java                  |    2 
 src/main/java/com/ruoyi/account/service/impl/AccountPurchaseServiceImpl.java                   |   59 
 src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementRecordOutPageDto.java            |    2 
 src/main/java/com/ruoyi/account/service/financial/FinFixedAssetService.java                    |   26 
 src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java       |    2 
 src/main/resources/mapper/sales/ShippingInfoMapper.xml                                         |   71 
 src/main/java/com/ruoyi/technology/service/impl/TechnologyBomServiceImpl.java                  |  125 
 src/main/java/com/ruoyi/account/mapper/AccountSubjectMapper.java                               |    5 
 src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java         |  181 +
 src/main/java/com/ruoyi/procurementrecord/pojo/ReturnManagement.java                           |    3 
 doc/20260511_设备保养定时任务设备项目字段前端联调说明.md                                                           |  111 +
 src/main/java/com/ruoyi/basic/utils/FileUtil.java                                              |   11 
 src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherDto.java                          |   20 
 src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementManagementUpdateDto.java         |    2 
 src/main/java/com/ruoyi/procurementrecord/controller/ReturnManagementController.java           |   17 
 src/main/java/com/ruoyi/account/pojo/financial/FinVoucher.java                                 |   83 
 src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java                                        |    4 
 src/main/resources/mapper/account/financial/FinVoucherEntryMapper.xml                          |   74 
 src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java                    |   49 
 src/main/java/com/ruoyi/stock/controller/StockUninventoryController.java                       |   12 
 src/main/java/com/ruoyi/account/mapper/financial/FinVoucherMapper.java                         |   12 
 src/main/java/com/ruoyi/production/pojo/ProductionProductInput.java                            |    3 
 src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java                                 |    3 
 src/main/java/com/ruoyi/purchase/mapper/PurchaseReturnOrdersMapper.java                        |   17 
 src/main/java/com/ruoyi/account/pojo/financial/FinFixedAsset.java                              |  101 +
 src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java                                         |    2 
 src/main/java/com/ruoyi/account/controller/financial/FinFixedAssetController.java              |   63 
 src/main/java/com/ruoyi/procurementrecord/pojo/ReturnSaleProduct.java                          |   15 
 src/main/java/com/ruoyi/account/service/impl/financial/FinVoucherServiceImpl.java              |  299 +++
 src/main/java/com/ruoyi/basic/dto/StorageBlobVO.java                                           |    4 
 src/main/java/com/ruoyi/account/mapper/financial/FinIntangibleAssetMapper.java                 |   12 
 src/main/java/com/ruoyi/procurementrecord/bean/dto/Details.java                                |    2 
 src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java                        |   30 
 src/main/java/com/ruoyi/account/service/impl/financial/FinIntangibleAssetServiceImpl.java      |  250 ++
 src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java                            |   13 
 src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java                |   75 
 src/main/java/com/ruoyi/account/controller/financial/FinLedgerController.java                  |   39 
 src/main/java/com/ruoyi/basic/pojo/ProductModel.java                                           |    1 
 src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java                      |    3 
 src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordOutController.java       |    6 
 src/main/resources/mapper/stock/StockOutRecordMapper.xml                                       |   29 
 src/main/java/com/ruoyi/account/controller/AccountSalesController.java                         |   12 
 src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java                                   |    2 
 src/main/java/com/ruoyi/purchase/service/PurchaseReturnOrdersService.java                      |    6 
 src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java                      |   14 
 src/main/java/com/ruoyi/procurementrecord/mapper/ReturnManagementMapper.java                   |    4 
 src/main/resources/mapper/account/SalesRefundAmountOrderMapper.xml                             |    8 
 src/main/java/com/ruoyi/production/pojo/ProductionAccount.java                                 |    6 
 src/main/java/com/ruoyi/account/service/impl/AccountSubjectServiceImpl.java                    |  362 +++
 src/main/resources/mapper/stock/StockInRecordMapper.xml                                        |   34 
 src/main/java/com/ruoyi/account/service/financial/FinIntangibleAssetService.java               |   26 
 src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java                                       |    3 
 src/main/java/com/ruoyi/technology/controller/TechnologyBomController.java                     |    2 
 src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java                       |   18 
 src/main/java/com/ruoyi/account/pojo/AccountSubject.java                                       |    6 
 src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementRecordOutAdd.java                |    2 
 src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherPageDto.java                      |   37 
 src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoStageHandleService.java      |    9 
 src/main/java/com/ruoyi/sales/mapper/ShippingInfoMapper.java                                   |    8 
 src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordService.java                |    2 
 src/main/java/com/ruoyi/procurementrecord/service/ReturnSaleProductService.java                |    2 
 src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordOutServiceImpl.java    |    6 
 src/main/java/com/ruoyi/account/controller/financial/FinIntangibleAssetController.java         |   63 
 src/main/java/com/ruoyi/account/service/impl/financial/FinFixedAssetServiceImpl.java           |  231 ++
 src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnSaleProductServiceImpl.java       |    2 
 src/main/java/com/ruoyi/account/bean/dto/financial/FinDetailLedgerQueryDto.java                |   22 
 src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementAddDto.java                      |    2 
 src/main/resources/mapper/technology/TechnologyBomStructureMapper.xml                          |    3 
 doc/20260512_财务管理模块前端联调文档.md                                                                   |  288 +++
 src/main/java/com/ruoyi/account/service/AccountSalesService.java                               |    4 
 src/main/java/com/ruoyi/account/bean/vo/PurchaseInboundVo.java                                 |   48 
 src/main/resources/mapper/account/AccountSubjectMapper.xml                                     |   10 
 doc/20260512_add_parent_id_to_account_subject.sql                                              |    5 
 src/main/java/com/ruoyi/account/controller/AccounPurchaseController.java                       |   68 
 src/main/java/com/ruoyi/purchase/controller/PurchaseReturnOrdersController.java                |   11 
 src/main/resources/mapper/purchase/PurchaseReturnOrdersMapper.xml                              |   92 
 src/main/java/com/ruoyi/account/service/AccountSubjectService.java                             |    8 
 src/main/resources/mapper/procurementrecord/ProcurementRecordOutMapper.xml                     |   16 
 src/main/java/com/ruoyi/account/bean/dto/financial/FinFixedAssetDto.java                       |   13 
 src/main/java/com/ruoyi/stock/mapper/StockInRecordMapper.java                                  |    4 
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java                         |  164 -
 src/main/java/com/ruoyi/account/service/financial/FinLedgerService.java                        |   17 
 src/main/java/com/ruoyi/purchase/vo/PurchaseReturnOrderProductsDetailVo.java                   |   62 
 src/main/java/com/ruoyi/technology/service/TechnologyBomService.java                           |    2 
 src/main/java/com/ruoyi/account/bean/vo/AccountSubjectVo.java                                  |   13 
 src/main/resources/mapper/stock/StockInventoryMapper.xml                                       |   26 
 doc/20260512_create_financial_management_tables.sql                                            |  104 +
 src/main/java/com/ruoyi/account/bean/vo/PurchaseReturnVo.java                                  |   48 
 src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherEntryDto.java                     |   13 
 /dev/null                                                                                      |   34 
 src/main/java/com/ruoyi/account/pojo/financial/FinIntangibleAsset.java                         |   98 +
 src/main/java/com/ruoyi/account/bean/dto/SalesReturnDto.java                                   |    3 
 src/main/java/com/ruoyi/account/bean/dto/financial/FinIdBatchDto.java                          |   17 
 src/main/java/com/ruoyi/procurementrecord/bean/vo/ShippingProductVo.java                       |   43 
 src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java                    |   97 
 src/main/java/com/ruoyi/procurementrecord/mapper/ProcurementRecordMapper.java                  |    6 
 src/main/java/com/ruoyi/basic/controller/CustomerController.java                               |    4 
 src/main/java/com/ruoyi/account/controller/financial/FinVoucherController.java                 |   69 
 src/main/java/com/ruoyi/procurementrecord/bean/dto/ReturnManagementDto.java                    |   10 
 159 files changed, 4,916 insertions(+), 665 deletions(-)

diff --git "a/doc/20260511_\350\256\276\345\244\207\344\277\235\345\205\273\345\256\232\346\227\266\344\273\273\345\212\241\350\256\276\345\244\207\351\241\271\347\233\256\345\255\227\346\256\265\345\211\215\347\253\257\350\201\224\350\260\203\350\257\264\346\230\216.md" "b/doc/20260511_\350\256\276\345\244\207\344\277\235\345\205\273\345\256\232\346\227\266\344\273\273\345\212\241\350\256\276\345\244\207\351\241\271\347\233\256\345\255\227\346\256\265\345\211\215\347\253\257\350\201\224\350\260\203\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..e35f0f9
--- /dev/null
+++ "b/doc/20260511_\350\256\276\345\244\207\344\277\235\345\205\273\345\256\232\346\227\266\344\273\273\345\212\241\350\256\276\345\244\207\351\241\271\347\233\256\345\255\227\346\256\265\345\211\215\347\253\257\350\201\224\350\260\203\350\257\264\346\230\216.md"
@@ -0,0 +1,111 @@
+# 璁惧淇濆吇瀹氭椂浠诲姟璁惧椤圭洰瀛楁鍓嶇鑱旇皟璇存槑
+
+> 鏇存柊鏃堕棿锛�2026-05-11  
+> 閫傜敤鑼冨洿锛氳澶囦繚鍏诲畾鏃朵换鍔★紙`maintenance_task`锛変笌璁惧淇濆吇璁板綍锛坄device_maintenance`锛�
+
+## 1. 鍙樻洿姒傝堪
+
+鏈鍚庣鍙樻洿锛�
+
+1. `MaintenanceTask` 鏂板瀛楁 `machineryCategory`锛堣澶囬」鐩級銆�
+2. 瀹氭椂浠诲姟鎵ц鐢熸垚璁惧淇濆吇璁板綍鏃讹紝浼氭妸 `MaintenanceTask.machineryCategory` 鍚屾鍐欏叆 `DeviceMaintenance.machineryCategory`銆�
+
+瀵瑰簲浠g爜浣嶇疆锛�
+
+- `src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java`
+- `src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java`
+
+## 2. 鏁版嵁搴撳彉鏇�
+
+闇�瑕佸厛鎵ц鏁版嵁搴撳彉鏇达紙鍚﹀垯鏂板/鏌ヨ璇ュ瓧娈典細寮傚父锛夛細
+
+```sql
+ALTER TABLE `maintenance_task`
+  ADD COLUMN `machinery_category` VARCHAR(100) NULL COMMENT '璁惧椤圭洰' AFTER `device_model`;
+```
+
+## 3. 瀛楁绾﹀畾
+
+| 瀛楁 | 鍚箟 | 绫诲瀷 | 寤鸿 |
+| --- | --- | --- | --- |
+| machineryCategory | 璁惧椤圭洰 | string | 鍓嶇鏂板/缂栬緫瀹氭椂浠诲姟鏃朵紶鍊� |
+
+璇存槑锛�
+
+- 鍚庣褰撳墠鏈璇ュ瓧娈靛仛寮哄埗闈炵┖鏍¢獙锛屼絾涓氬姟涓婂缓璁墠绔綔涓哄繀濉鐞嗐��
+- 鍘嗗彶 `maintenance_task` 鏃ф暟鎹嫢璇ュ瓧娈典负绌猴紝鍒欏熀浜庢棫浠诲姟鐢熸垚鐨勪繚鍏昏褰曚篃浼氫负绌恒��
+
+## 4. 鎺ュ彛鑱旇皟
+
+### 4.1 鏂板瀹氭椂浠诲姟
+
+```http
+POST /deviceMaintenanceTask/add
+Content-Type: application/json
+```
+
+璇锋眰绀轰緥锛�
+
+```json
+{
+  "taskName": "绌哄帇鏈篈-鍛ㄤ繚鍏�",
+  "taskId": 1001,
+  "deviceModel": "GA75",
+  "machineryCategory": "鍔ㄥ姏璁惧",
+  "frequencyType": "WEEKLY",
+  "frequencyDetail": "MON,09:00",
+  "registrantId": 1,
+  "registrationDate": "2026-05-11",
+  "remarks": "鑱旇皟鏍蜂緥"
+}
+```
+
+### 4.2 淇敼瀹氭椂浠诲姟
+
+```http
+POST /deviceMaintenanceTask/update
+Content-Type: application/json
+```
+
+璇锋眰绀轰緥锛堝惈 `id`锛夛細
+
+```json
+{
+  "id": 12,
+  "machineryCategory": "鍔ㄥ姏璁惧"
+}
+```
+
+### 4.3 瀹氭椂浠诲姟鍒楄〃
+
+```http
+GET /deviceMaintenanceTask/listPage?pageNum=1&pageSize=10
+```
+
+杩斿洖璁板綍涓細鍖呭惈 `machineryCategory` 瀛楁銆�
+
+### 4.4 璁惧淇濆吇璁板綍鍒楄〃/璇︽儏
+
+```http
+GET /device/maintenance/page?pageNum=1&pageSize=10
+GET /device/maintenance/{id}
+```
+
+杩斿洖涓� `machineryCategory` 鏉ユ簮浜� `device_maintenance.machinery_category`銆�  
+瀵逛簬鈥滅敱瀹氭椂浠诲姟鑷姩鐢熸垚鈥濈殑璁板綍锛岃鍊间細缁ф壙鐢熸垚鏃跺搴斾换鍔$殑 `machineryCategory`銆�
+
+## 5. 鍓嶇鏀归�犵偣
+
+1. 瀹氭椂浠诲姟鏂板/缂栬緫琛ㄥ崟澧炲姞鈥滆澶囬」鐩紙machineryCategory锛夆�濊緭鍏ラ」銆�
+2. 鎻愪氦 `/deviceMaintenanceTask/add`銆乣/deviceMaintenanceTask/update` 鏃舵惡甯� `machineryCategory`銆�
+3. 瀹氭椂浠诲姟鍒楄〃澧炲姞鈥滆澶囬」鐩�濆垪锛堝椤甸潰鏈夎鍒楄〃锛夈��
+4. 璁惧淇濆吇璁板綍鍒楄〃/璇︽儏澧炲姞鈥滆澶囬」鐩�濆睍绀猴紝绌哄�兼樉绀� `--`銆�
+
+## 6. 鑱旇皟楠屾敹娓呭崟
+
+1. 鏂板涓�涓甫 `machineryCategory` 鐨勫畾鏃朵换鍔★紝淇濆瓨鎴愬姛銆�
+2. 鏌ヨ `/deviceMaintenanceTask/listPage`锛岀‘璁よ浠诲姟杩斿洖 `machineryCategory`銆�
+3. 绛夊緟涓�娆″畾鏃惰Е鍙戯紙鎴栧皢棰戠巼璋冨埌涓磋繎鏃堕棿锛夛紝鐢熸垚淇濆吇璁板綍銆�
+4. 鏌ヨ `/device/maintenance/page` 鎴栬鎯呮帴鍙o紝纭鏂拌褰曠殑 `machineryCategory` 涓庝换鍔′竴鑷淬��
+5. 淇敼浠诲姟 `machineryCategory` 鍚庡啀娆¤Е鍙戯紝纭鈥滄柊鐢熸垚璁板綍鈥濅娇鐢ㄦ柊鍊硷紙鍘嗗彶璁板綍涓嶅洖鍐欙級銆�
+
diff --git "a/doc/20260512_AccountSubject\346\240\221\345\275\242\346\224\271\351\200\240\345\211\215\347\253\257\344\277\256\346\224\271\346\226\207\346\241\243.md" "b/doc/20260512_AccountSubject\346\240\221\345\275\242\346\224\271\351\200\240\345\211\215\347\253\257\344\277\256\346\224\271\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..c798c40
--- /dev/null
+++ "b/doc/20260512_AccountSubject\346\240\221\345\275\242\346\224\271\351\200\240\345\211\215\347\253\257\344\277\256\346\224\271\346\226\207\346\241\243.md"
@@ -0,0 +1,185 @@
+# AccountSubject 鏍戝舰鏀归�犲墠绔慨鏀规枃妗�
+
+鏇存柊鏃堕棿锛�2026-05-12
+
+## 1. 鍙樻洿鑳屾櫙
+
+`AccountSubjectController` 宸叉敼涓虹埗瀛愬眰绾ч�掑綊妯″紡锛宍/accountSubject/list` 鐜板湪杩斿洖鏍戝舰缁撴瀯锛坄children` 閫掑綊锛夛紝涓嶅啀鏄崟绾殑骞抽摵鍒楄〃銆�
+
+---
+
+## 2. 鍚庣鎺ュ彛鍙樺寲
+
+### 2.1 鏌ヨ鎺ュ彛锛堝凡鍙樻洿涓烘爲锛�
+
+- URL锛歚GET /accountSubject/list`
+- 鍏ュ弬锛氫繚鎸佷笉鍙橈紙`current,size,subjectCode,subjectName,subjectType,status`锛�
+- 鍑哄弬锛氫粛鏄垎椤靛3锛坄records,total`锛夛紝浣� `records` 鍙樹负鏍戣妭鐐规暟缁勶紙鏍硅妭鐐瑰垎椤碉紝瀛愯妭鐐归�掑綊鍐呭祵锛�
+
+绀轰緥锛�
+
+```json
+{
+  "code": 200,
+  "msg": "鎿嶄綔鎴愬姛",
+  "data": {
+    "records": [
+      {
+        "id": 1,
+        "parentId": null,
+        "subjectCode": "1002",
+        "subjectName": "閾惰瀛樻",
+        "subjectType": "璧勪骇绫�",
+        "balanceDirection": "鍊熸柟",
+        "status": 0,
+        "leaf": false,
+        "children": [
+          {
+            "id": 2,
+            "parentId": 1,
+            "subjectCode": "100201",
+            "subjectName": "宸ヨ瀛樻",
+            "subjectType": "璧勪骇绫�",
+            "balanceDirection": "鍊熸柟",
+            "status": 0,
+            "leaf": true,
+            "children": []
+          }
+        ]
+      }
+    ],
+    "total": 1
+  }
+}
+```
+
+### 2.2 鏂板/缂栬緫鎺ュ彛瀛楁鍙樺寲
+
+- `POST /accountSubject/add`
+- `PUT /accountSubject/edit`
+
+鏂板鏀寔瀛楁锛�
+
+- `parentId`锛氱埗鑺傜偣ID锛堜负绌鸿〃绀烘牴鑺傜偣锛�
+
+绀轰緥锛�
+
+```json
+{
+  "id": 2,
+  "parentId": 1,
+  "subjectCode": "100201",
+  "subjectName": "宸ヨ瀛樻",
+  "subjectType": "璧勪骇绫�",
+  "balanceDirection": "鍊熸柟",
+  "status": 0,
+  "remark": ""
+}
+```
+
+### 2.3 鍒犻櫎鎺ュ彛琛屼负鍙樺寲
+
+- `DELETE /accountSubject/remove/{ids}`
+
+琛屼负锛�
+
+1. 鍒犻櫎鐖惰妭鐐规椂浼氶�掑綊鍒犻櫎鎵�鏈夊瓙瀛欒妭鐐广��  
+2. 鑻ヤ换鎰忓緟鍒犻櫎鑺傜偣锛堝惈瀛愬瓩锛夊凡琚� `fin_voucher_entry.subject_code` 寮曠敤锛屽垯鏁翠綋鍒犻櫎澶辫触銆�
+
+---
+
+## 3. 鍓嶇鏀归�犳竻鍗�
+
+## 3.1 鎬昏处绉戠洰绠$悊椤�
+
+鏂囦欢锛歚src/views/financialManagement/generalLedger/index.vue`
+
+### 蹇呮敼椤�
+
+1. 鏂板鈥滅埗绉戠洰鈥濋�夋嫨鎺т欢锛坄el-cascader` 鎴� `el-tree-select`锛夛紝淇濆瓨鏃跺甫 `parentId`銆�  
+2. 鍒楄〃鏀逛负鏍戣〃灞曠ず锛堟帹鑽� `el-table` + `row-key` + `tree-props`锛夈��  
+3. 鎼滅储閫昏緫淇濇寔涓嶅彉锛屼絾瑕佸吋瀹� `records` 涓烘爲缁撴瀯銆�
+
+---
+
+## 3.2 鍑瘉椤电鐩笅鎷�
+
+鏂囦欢锛歚src/views/financialManagement/voucher/index.vue`
+
+褰撳墠鍑瘉鍒嗗綍浣跨敤 `el-select`锛堝钩閾猴級銆�  
+鍚庣宸茶繑鍥炴爲锛岄渶瑕佸墠绔墎骞冲寲鍚庡啀缁戝畾涓嬫媺銆�
+
+绀轰緥锛堝彲澶嶇敤锛夛細
+
+```js
+const flattenSubjectTree = (nodes, result = []) => {
+  (nodes || []).forEach(node => {
+    result.push({
+      code: node.subjectCode,
+      name: node.subjectName,
+      id: node.id,
+      parentId: node.parentId
+    });
+    if (node.children?.length) {
+      flattenSubjectTree(node.children, result);
+    }
+  });
+  return result;
+};
+
+// list 鎺ュ彛杩斿洖鍚庯細
+const treeRecords = response.data?.records || [];
+subjectList.value = flattenSubjectTree(treeRecords);
+```
+
+---
+
+## 3.3 绉戠洰鎬昏处/鏄庣粏璐﹂〉绾ц仈
+
+鏂囦欢锛�
+
+- `src/views/financialManagement/voucher/generalLedger.vue`
+- `src/views/financialManagement/voucher/detailLedger.vue`
+
+褰撳墠閫昏緫鏄妸 `records` 寮哄埗鏄犲皠鎴� `children: []`锛岄渶瑕佸垹闄よ繖娈碘�滃钩閾烘敼閫犫�濓紝鐩存帴浣跨敤鍚庣鏍戙��
+
+绀轰緥锛堝彲澶嶇敤锛夛細
+
+```js
+const toCascaderTree = (nodes = []) =>
+  nodes
+    .filter(item => item.subjectCode && item.subjectName)
+    .map(item => ({
+      code: item.subjectCode,
+      name: item.subjectName,
+      children: toCascaderTree(item.children || [])
+    }));
+
+subjectOptions.value = toCascaderTree(response.data?.records || []);
+```
+
+---
+
+## 4. 寤鸿鐨勫墠绔瓧娈电害瀹�
+
+寤鸿鍦ㄥ墠绔� `form` 澧炲姞锛�
+
+- `parentId: null`
+
+骞跺湪缂栬緫鍥炲~鏃朵繚鎸� `parentId`銆�
+
+---
+
+## 5. 鑱旇皟娉ㄦ剰浜嬮」
+
+1. `/accountSubject/list` 鐨� `total` 鏄牴鑺傜偣鏁伴噺锛屼笉鏄叏閲忚妭鐐规暟銆�  
+2. 鑻ラ〉闈粛鎸夊钩閾� `records.map(...)` 澶勭悊锛屼細涓㈠け瀛愯妭鐐广��  
+3. 鍒犻櫎绉戠洰澶辫触鏃讹紝浼樺厛妫�鏌ユ槸鍚﹁鍑瘉鍒嗗綍寮曠敤銆�  
+4. 淇濆瓨澶辫触鍑虹幇鈥滅埗绉戠洰涓嶈兘鏄綋鍓嶇鐩垨鍏跺瓙绉戠洰鈥濇椂锛岄渶瑕佸墠绔檺鍒剁埗鑺傜偣鍙�夎寖鍥淬��
+
+---
+
+## 6. 鏁版嵁搴撳瓧娈佃姹�
+
+`account_subject` 闇�瑕佸寘鍚� `parent_id` 瀛楁锛坄bigint`锛屽彲绌猴級銆�  
+鑻ョ嚎涓婂簱灏氭湭娣诲姞锛岃鍏堟墽琛� DDL 鍐嶈仈璋冦��
diff --git a/doc/20260512_add_parent_id_to_account_subject.sql b/doc/20260512_add_parent_id_to_account_subject.sql
new file mode 100644
index 0000000..cf33a33
--- /dev/null
+++ b/doc/20260512_add_parent_id_to_account_subject.sql
@@ -0,0 +1,5 @@
+-- account_subject 澧炲姞鐖剁骇绉戠洰瀛楁锛堟爲褰㈢粨鏋勶級
+ALTER TABLE `account_subject`
+ADD COLUMN `parent_id` bigint NULL COMMENT '鐖剁鐩甀D锛堜负绌鸿〃绀烘牴鑺傜偣锛�' AFTER `id`;
+
+CREATE INDEX `idx_account_subject_parent_id` ON `account_subject` (`parent_id`);
diff --git a/doc/20260512_create_financial_management_tables.sql b/doc/20260512_create_financial_management_tables.sql
new file mode 100644
index 0000000..db3caad
--- /dev/null
+++ b/doc/20260512_create_financial_management_tables.sql
@@ -0,0 +1,104 @@
+-- 璐㈠姟绠$悊妯″潡寤鸿〃鑴氭湰锛堝浐瀹氳祫浜�/鏃犲舰璧勪骇/鍑瘉/绉戠洰璐︼級
+-- 璇存槑锛�
+-- 1) 鎬昏处绉戠洰缁х画澶嶇敤宸叉湁琛� account_subject锛屼笉閲嶅鍒涘缓 fin_account_subject銆�
+-- 2) 閲戦瀛楁缁熶竴 decimal(18,2)銆�
+
+CREATE TABLE IF NOT EXISTS `fin_fixed_asset` (
+  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
+  `asset_code` varchar(64) NOT NULL COMMENT '璧勪骇缂栧彿',
+  `asset_name` varchar(128) NOT NULL COMMENT '璧勪骇鍚嶇О',
+  `category` varchar(64) NOT NULL COMMENT '璧勪骇绫诲埆',
+  `specification` varchar(255) DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
+  `purchase_date` date NOT NULL COMMENT '璐疆鏃ユ湡',
+  `original_value` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '璧勪骇鍘熷��',
+  `useful_life` int NOT NULL DEFAULT '1' COMMENT '浣跨敤骞撮檺(骞�)',
+  `residual_rate` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '娈嬪�肩巼(%)',
+  `accumulated_depreciation` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '绱鎶樻棫',
+  `net_value` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '鍑�鍊�',
+  `location` varchar(255) DEFAULT NULL COMMENT '瀛樻斁鍦扮偣',
+  `department` varchar(128) DEFAULT NULL COMMENT '浣跨敤閮ㄩ棬',
+  `keeper` varchar(64) DEFAULT NULL COMMENT '淇濈浜�',
+  `status` varchar(32) NOT NULL DEFAULT 'in_use' COMMENT '鐘舵��: in_use/idle/repair/scrapped',
+  `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
+  `create_user` varchar(64) DEFAULT NULL COMMENT '鍒涘缓浜�',
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+  `update_user` varchar(64) DEFAULT NULL COMMENT '淇敼浜�',
+  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+  `dept_id` bigint DEFAULT NULL COMMENT '閮ㄩ棬ID',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `uk_fin_fixed_asset_code` (`asset_code`),
+  KEY `idx_fin_fixed_asset_status` (`status`),
+  KEY `idx_fin_fixed_asset_category` (`category`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='鍥哄畾璧勪骇';
+
+CREATE TABLE IF NOT EXISTS `fin_intangible_asset` (
+  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
+  `asset_code` varchar(64) NOT NULL COMMENT '璧勪骇缂栧彿',
+  `asset_name` varchar(128) NOT NULL COMMENT '璧勪骇鍚嶇О',
+  `category` varchar(64) NOT NULL COMMENT '璧勪骇绫诲埆',
+  `certificate_no` varchar(128) DEFAULT NULL COMMENT '璇佷功缂栧彿',
+  `acquisition_date` date NOT NULL COMMENT '鍙栧緱鏃ユ湡',
+  `original_value` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '璧勪骇鍘熷��',
+  `amortization_period` int NOT NULL DEFAULT '1' COMMENT '鎽婇攢骞撮檺(骞�)',
+  `residual_rate` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '娈嬪�肩巼(%)',
+  `accumulated_amortization` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '绱鎽婇攢',
+  `net_value` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '鍑�鍊�',
+  `validity_date` date DEFAULT NULL COMMENT '鏈夋晥鏈熻嚦',
+  `status` varchar(32) NOT NULL DEFAULT 'in_use' COMMENT '鐘舵��: in_use/expired/amortized',
+  `description` varchar(1000) DEFAULT NULL COMMENT '璧勪骇鎻忚堪',
+  `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
+  `create_user` varchar(64) DEFAULT NULL COMMENT '鍒涘缓浜�',
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+  `update_user` varchar(64) DEFAULT NULL COMMENT '淇敼浜�',
+  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+  `dept_id` bigint DEFAULT NULL COMMENT '閮ㄩ棬ID',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `uk_fin_intangible_asset_code` (`asset_code`),
+  KEY `idx_fin_intangible_asset_status` (`status`),
+  KEY `idx_fin_intangible_asset_category` (`category`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='鏃犲舰璧勪骇';
+
+CREATE TABLE IF NOT EXISTS `fin_voucher` (
+  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
+  `voucher_no` varchar(64) NOT NULL COMMENT '鍑瘉瀛楀彿',
+  `voucher_date` date NOT NULL COMMENT '鍑瘉鏃ユ湡',
+  `summary` varchar(500) DEFAULT NULL COMMENT '鎽樿',
+  `debit` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '鍊熸柟鍚堣',
+  `credit` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '璐锋柟鍚堣',
+  `creator` varchar(64) DEFAULT NULL COMMENT '鍒跺崟浜�',
+  `status` varchar(32) NOT NULL DEFAULT 'unposted' COMMENT '鐘舵��: unposted/posted/cancelled',
+  `attachment_count` int NOT NULL DEFAULT '0' COMMENT '闄勪欢寮犳暟',
+  `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
+  `create_user` varchar(64) DEFAULT NULL COMMENT '鍒涘缓浜�',
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+  `update_user` varchar(64) DEFAULT NULL COMMENT '淇敼浜�',
+  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+  `dept_id` bigint DEFAULT NULL COMMENT '閮ㄩ棬ID',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `uk_fin_voucher_no` (`voucher_no`),
+  KEY `idx_fin_voucher_date` (`voucher_date`),
+  KEY `idx_fin_voucher_status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='鍑瘉涓昏〃';
+
+CREATE TABLE IF NOT EXISTS `fin_voucher_entry` (
+  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
+  `voucher_id` bigint NOT NULL COMMENT '鍑瘉ID',
+  `row_no` int NOT NULL DEFAULT '1' COMMENT '琛屽彿',
+  `subject_code` varchar(64) NOT NULL COMMENT '绉戠洰缂栫爜',
+  `subject_name` varchar(128) DEFAULT NULL COMMENT '绉戠洰鍚嶇О',
+  `summary` varchar(500) DEFAULT NULL COMMENT '鎽樿',
+  `debit` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '鍊熸柟閲戦',
+  `credit` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '璐锋柟閲戦',
+  `auxiliary_type` varchar(32) DEFAULT NULL COMMENT '杈呭姪鏍哥畻绫诲瀷',
+  `auxiliary_id` varchar(64) DEFAULT NULL COMMENT '杈呭姪鏍哥畻瀵硅薄ID',
+  `auxiliary_name` varchar(128) DEFAULT NULL COMMENT '杈呭姪鏍哥畻瀵硅薄鍚嶇О',
+  `create_user` varchar(64) DEFAULT NULL COMMENT '鍒涘缓浜�',
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+  `update_user` varchar(64) DEFAULT NULL COMMENT '淇敼浜�',
+  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+  `dept_id` bigint DEFAULT NULL COMMENT '閮ㄩ棬ID',
+  PRIMARY KEY (`id`),
+  KEY `idx_fin_voucher_entry_voucher` (`voucher_id`),
+  KEY `idx_fin_voucher_entry_subject` (`subject_code`),
+  KEY `idx_fin_voucher_entry_aux` (`auxiliary_type`, `auxiliary_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='鍑瘉鍒嗗綍';
diff --git "a/doc/20260512_\350\264\242\345\212\241\347\256\241\347\220\206\346\250\241\345\235\227\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md" "b/doc/20260512_\350\264\242\345\212\241\347\256\241\347\220\206\346\250\241\345\235\227\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..1804d82
--- /dev/null
+++ "b/doc/20260512_\350\264\242\345\212\241\347\256\241\347\220\206\346\250\241\345\235\227\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
@@ -0,0 +1,288 @@
+# 璐㈠姟绠$悊妯″潡鍓嶇鑱旇皟鏂囨。锛坅ccount 妯″潡锛�
+
+鏇存柊鏃堕棿锛�2026-05-12
+
+## 1. 閫氱敤璇存槑
+
+### 1.1 鍝嶅簲缁撴瀯
+鎴愬姛鍝嶅簲锛�
+
+```json
+{
+  "code": 200,
+  "msg": "鎿嶄綔鎴愬姛",
+  "data": {}
+}
+```
+
+涓氬姟鏍¢獙澶辫触锛堜緥濡傚�熻捶涓嶅钩琛°�佸繀濉己澶憋級鐢卞叏灞�寮傚父杩斿洖锛�
+
+```json
+{
+  "code": 500,
+  "msg": "閿欒淇℃伅",
+  "data": null
+}
+```
+
+### 1.2 鍒嗛〉缁撴瀯
+鍒嗛〉鎺ュ彛缁熶竴浣跨敤 MyBatis-Plus `Page`锛�
+- 璇锋眰鍙傛暟锛歚current`銆乣size`
+- 杩斿洖锛歚data.records`銆乣data.total`
+
+---
+
+## 2. 鎬昏处绉戠洰锛堝凡鍦ㄥ師鎺ュ彛涓婂寮烘牎楠岋級
+
+鎺ュ彛淇濇寔涓嶅彉锛�
+- `GET /accountSubject/list`
+- `POST /accountSubject/add`
+- `PUT /accountSubject/edit`
+- `DELETE /accountSubject/remove/{ids}`
+- `POST /accountSubject/export`
+
+鏂板瑙勫垯锛�
+1. `subjectCode`銆乣subjectName`銆乣subjectType` 蹇呭~銆�
+2. `subjectCode` 鍞竴鏍¢獙銆�
+3. 鍒犻櫎鍓嶅仛寮曠敤鏍¢獙锛氳嫢琚嚟璇佸垎褰�(`fin_voucher_entry.subject_code`)寮曠敤锛岀姝㈠垹闄ゃ��
+
+---
+
+## 3. 鍥哄畾璧勪骇
+
+Base URL锛歚/financial/fixedAsset`
+
+### 3.1 鍒嗛〉鏌ヨ
+- `GET /page`
+- Query锛歚current,size,assetCode,assetName,category,status`
+
+### 3.2 鏂板
+- `POST /add`
+- Body锛圝SON锛夛細
+
+```json
+{
+  "assetCode": "GD20260512001",
+  "assetName": "鍔炲叕鐢佃剳",
+  "category": "electronic",
+  "specification": "ThinkPad X1",
+  "purchaseDate": "2026-05-01",
+  "originalValue": 8000.00,
+  "usefulLife": 5,
+  "residualRate": 5.00,
+  "location": "璐㈠姟閮�",
+  "department": "璐㈠姟閮�",
+  "keeper": "寮犱笁",
+  "status": "in_use",
+  "remark": "绀轰緥"
+}
+```
+
+### 3.3 淇敼
+- `PUT /update`
+- Body锛氬悓鏂板锛岄渶鍖呭惈 `id`
+
+### 3.4 鍒犻櫎
+- `DELETE /delete?ids=1&ids=2`
+
+### 3.5 鎶樻棫璁℃彁锛堟寜鏈堬級
+- `POST /depreciate`
+- Body 鍙�夛細
+  - 鍏ㄩ儴鍦ㄧ敤璧勪骇锛歚{}`
+  - 鎸囧畾璧勪骇锛歚{"ids":[1,2,3]}`
+
+鏍稿績鍏紡锛�
+- `monthlyDepreciation = originalValue * (1 - residualRate/100) / (usefulLife*12)`
+- `accumulatedDepreciation += monthlyDepreciation`
+- `netValue = originalValue - accumulatedDepreciation`
+
+鐘舵�佸缓璁�硷細
+- `in_use`銆乣idle`銆乣repair`銆乣scrapped`
+
+---
+
+## 4. 鏃犲舰璧勪骇
+
+Base URL锛歚/financial/intangibleAsset`
+
+### 4.1 鍒嗛〉鏌ヨ
+- `GET /page`
+- Query锛歚current,size,assetCode,assetName,category,status`
+
+### 4.2 鏂板
+- `POST /add`
+
+```json
+{
+  "assetCode": "WX20260512001",
+  "assetName": "ERP杞欢璁稿彲",
+  "category": "software",
+  "certificateNo": "SW-001",
+  "acquisitionDate": "2026-05-01",
+  "originalValue": 50000.00,
+  "amortizationPeriod": 10,
+  "residualRate": 0.00,
+  "validityDate": "2036-05-01",
+  "status": "in_use",
+  "description": "绀轰緥",
+  "remark": ""
+}
+```
+
+### 4.3 淇敼
+- `PUT /update`
+- Body锛氬悓鏂板锛岄渶鍖呭惈 `id`
+
+### 4.4 鍒犻櫎
+- `DELETE /delete?ids=1&ids=2`
+
+### 4.5 鎽婇攢璁℃彁锛堟寜鏈堬級
+- `POST /amortize`
+- Body 鍙�夛細
+  - 鍏ㄩ儴鍦ㄧ敤璧勪骇锛歚{}`
+  - 鎸囧畾璧勪骇锛歚{"ids":[1,2,3]}`
+
+鏍稿績鍏紡锛�
+- `monthlyAmortization = originalValue * (1 - residualRate/100) / (amortizationPeriod*12)`
+- `accumulatedAmortization += monthlyAmortization`
+- `netValue = originalValue - accumulatedAmortization`
+- 褰� `netValue <= 0` 鏃讹細`netValue=0` 涓� `status=amortized`
+
+鐘舵�佸缓璁�硷細
+- `in_use`銆乣expired`銆乣amortized`
+
+---
+
+## 5. 鍑瘉
+
+Base URL锛歚/financial/voucher`
+
+### 5.1 鍒嗛〉鏌ヨ
+- `GET /page`
+- Query锛歚current,size,voucherNo,creator,status,startDate,endDate`
+
+### 5.2 鏂板
+- `POST /add`
+
+```json
+{
+  "voucherNo": "璁�-0001",
+  "voucherDate": "2026-05-12",
+  "summary": "閿�鍞敹鍏�",
+  "creator": "寮犱笁",
+  "attachmentCount": 0,
+  "remark": "",
+  "entries": [
+    {
+      "subjectCode": "1002",
+      "subjectName": "閾惰瀛樻",
+      "summary": "鏀跺埌璐ф",
+      "debit": 1000.00,
+      "credit": 0
+    },
+    {
+      "subjectCode": "6001",
+      "subjectName": "涓昏惀涓氬姟鏀跺叆",
+      "summary": "纭鏀跺叆",
+      "debit": 0,
+      "credit": 1000.00
+    }
+  ]
+}
+```
+
+### 5.3 淇敼
+- `PUT /update`
+- Body锛氬悓鏂板锛岄渶鍖呭惈 `id`
+- 浠� `unposted` 鐘舵�佸厑璁镐慨鏀�
+
+### 5.4 杩囪处
+- `POST /post`
+
+```json
+{
+  "id": 1
+}
+```
+
+### 5.5 浣滃簾
+- `POST /cancel`
+
+```json
+{
+  "id": 1
+}
+```
+
+### 5.6 璇︽儏
+- `GET /detail/{id}`
+
+鍏抽敭鏍¢獙锛�
+1. 鍒嗗綍鑷冲皯涓�鏉℃湁鏁堣锛堢鐩笉绌猴紝涓斿�熸柟鎴栬捶鏂� > 0锛夈��
+2. 姣忔潯鏈夋晥鍒嗗綍涓嶈兘鍊熻捶鍚屾椂澶т簬 0銆�
+3. 鍊熻捶骞宠 锛歚sum(debit) == sum(credit)` 涓旈兘 > 0銆�
+4. `subjectCode` 蹇呴』瀛樺湪浜� `account_subject`銆�
+
+鐘舵�佹祦杞細
+- `unposted -> posted`
+- `unposted -> cancelled`
+
+---
+
+## 6. 绉戠洰鎬昏处
+
+### 6.1 鏌ヨ鎺ュ彛
+- `GET /financial/ledger/general`
+
+### 6.2 Query 鍙傛暟
+- `subjectCode`锛堝繀濉級
+- `startMonth`锛圷YYY-MM锛�
+- `endMonth`锛圷YYY-MM锛�
+
+### 6.3 杩斿洖瀛楁
+- `rowType`锛歚opening` / `entry` / `monthly_total` / `yearly_total`
+- `date`
+- `voucherNo`
+- `summary`
+- `debit`
+- `credit`
+- `direction`锛堝��/璐凤級
+- `balance`锛堝�熸璐疯礋锛�
+
+璇存槑锛�
+- 绉戠洰鏀寔鈥滄寚瀹氱鐩強鍏朵笅绾э紙鍓嶇紑鍖归厤锛夆�濇煡璇€��
+- 鑷姩杈撳嚭鈥滄湡鍒濅綑棰� / 鏈湀鍚堣 / 鏈勾绱鈥濄��
+
+---
+
+## 7. 绉戠洰鏄庣粏璐�
+
+### 7.1 鏌ヨ鎺ュ彛
+- `GET /financial/ledger/detail`
+
+### 7.2 Query 鍙傛暟
+- `subjectCode`锛堝繀濉級
+- `auxiliaryType`锛堝彲閫夛細`customer/supplier/department/employee/project`锛�
+- `auxiliaryId`锛堝彲閫夛級
+- `startMonth`锛圷YYY-MM锛�
+- `endMonth`锛圷YYY-MM锛�
+
+### 7.3 杩斿洖瀛楁
+鍚岀鐩�昏处锛�
+- `rowType,date,voucherNo,summary,debit,credit,direction,balance`
+
+---
+
+## 8. 鏁版嵁搴撹剼鏈�
+
+宸叉彁渚涜剼鏈細
+
+- `doc/20260512_create_financial_management_tables.sql`
+
+鍖呭惈锛�
+- `fin_fixed_asset`
+- `fin_intangible_asset`
+- `fin_voucher`
+- `fin_voucher_entry`
+
+鎬昏处绉戠洰澶嶇敤鐜版湁 `account_subject`銆�
diff --git a/src/main/java/com/ruoyi/account/bean/dto/PurchaseInboundDto.java b/src/main/java/com/ruoyi/account/bean/dto/PurchaseInboundDto.java
new file mode 100644
index 0000000..757e6b4
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/PurchaseInboundDto.java
@@ -0,0 +1,29 @@
+package com.ruoyi.account.bean.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+@Data
+@Schema(name = "PurchaseInboundDto", description = "璐㈠姟绠$悊--閲囪喘鍏ュ簱鍙拌处(浼犲弬)")
+public class PurchaseInboundDto {
+
+    @Schema(description = "鍏ュ簱鍗曞彿")
+    private String inboundBatches;
+
+    @Schema(description = "渚涘簲鍟�")
+    private String supplierName;
+
+    @Schema(description = "寮�濮嬫棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private Date startDate;
+
+    @Schema(description = "缁撴潫鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private Date endDate;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/PurchaseReturnDto.java b/src/main/java/com/ruoyi/account/bean/dto/PurchaseReturnDto.java
new file mode 100644
index 0000000..c238990
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/PurchaseReturnDto.java
@@ -0,0 +1,29 @@
+package com.ruoyi.account.bean.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+@Data
+@Schema(name = "PurchaseReturnDto", description = "璐㈠姟绠$悊--閲囪喘閫�璐у彴璐�(浼犲弬)")
+public class PurchaseReturnDto {
+
+    @Schema(description = "閫�璐у崟鍙�")
+    private String returnNo;
+
+    @Schema(description = "渚涘簲鍟�")
+    private String supplierName;
+
+    @Schema(description = "寮�濮嬫棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private Date startDate;
+
+    @Schema(description = "缁撴潫鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private Date endDate;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/SalesOutboundDto.java b/src/main/java/com/ruoyi/account/bean/dto/SalesOutboundDto.java
index a30e035..33bc1b9 100644
--- a/src/main/java/com/ruoyi/account/bean/dto/SalesOutboundDto.java
+++ b/src/main/java/com/ruoyi/account/bean/dto/SalesOutboundDto.java
@@ -3,6 +3,7 @@
 import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
 
 import java.util.Date;
 
@@ -18,9 +19,11 @@
 
     @Schema(description = "寮�濮嬫棩鏈�")
     @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
     private Date startDate;
 
     @Schema(description = "缁撴潫鏃ユ湡")
     @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
     private Date endDate;
 }
diff --git a/src/main/java/com/ruoyi/account/bean/dto/SalesReturnDto.java b/src/main/java/com/ruoyi/account/bean/dto/SalesReturnDto.java
index d635408..b7ebae2 100644
--- a/src/main/java/com/ruoyi/account/bean/dto/SalesReturnDto.java
+++ b/src/main/java/com/ruoyi/account/bean/dto/SalesReturnDto.java
@@ -3,6 +3,7 @@
 import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
 
 import java.util.Date;
 
@@ -18,9 +19,11 @@
 
     @Schema(description = "寮�濮嬫棩鏈�")
     @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
     private Date startDate;
 
     @Schema(description = "缁撴潫鏃ユ湡")
     @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
     private Date endDate;
 }
diff --git a/src/main/java/com/ruoyi/account/bean/dto/financial/FinDetailLedgerQueryDto.java b/src/main/java/com/ruoyi/account/bean/dto/financial/FinDetailLedgerQueryDto.java
new file mode 100644
index 0000000..84a3676
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/financial/FinDetailLedgerQueryDto.java
@@ -0,0 +1,22 @@
+package com.ruoyi.account.bean.dto.financial;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 绉戠洰鏄庣粏璐︽煡璇㈠弬鏁帮紙鍚緟鍔╂牳绠楁潯浠讹級銆�
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FinDetailLedgerQueryDto extends FinLedgerQueryDto {
+
+    /**
+     * 杈呭姪鏍哥畻绫诲瀷锛歝ustomer/supplier/department/employee/project銆�
+     */
+    private String auxiliaryType;
+
+    /**
+     * 杈呭姪鏍哥畻瀵硅薄ID銆�
+     */
+    private String auxiliaryId;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/financial/FinFixedAssetDto.java b/src/main/java/com/ruoyi/account/bean/dto/financial/FinFixedAssetDto.java
new file mode 100644
index 0000000..c6baeca
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/financial/FinFixedAssetDto.java
@@ -0,0 +1,13 @@
+package com.ruoyi.account.bean.dto.financial;
+
+import com.ruoyi.account.pojo.financial.FinFixedAsset;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 鍥哄畾璧勪骇鏌ヨ涓庝繚瀛� DTO銆�
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FinFixedAssetDto extends FinFixedAsset {
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/financial/FinIdBatchDto.java b/src/main/java/com/ruoyi/account/bean/dto/financial/FinIdBatchDto.java
new file mode 100644
index 0000000..e3023ed
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/financial/FinIdBatchDto.java
@@ -0,0 +1,17 @@
+package com.ruoyi.account.bean.dto.financial;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 鎵归噺ID璇锋眰鍙傛暟銆�
+ */
+@Data
+public class FinIdBatchDto {
+
+    /**
+     * ID闆嗗悎銆�
+     */
+    private List<Long> ids;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/financial/FinIntangibleAssetDto.java b/src/main/java/com/ruoyi/account/bean/dto/financial/FinIntangibleAssetDto.java
new file mode 100644
index 0000000..60dd50e
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/financial/FinIntangibleAssetDto.java
@@ -0,0 +1,13 @@
+package com.ruoyi.account.bean.dto.financial;
+
+import com.ruoyi.account.pojo.financial.FinIntangibleAsset;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 鏃犲舰璧勪骇鏌ヨ涓庝繚瀛� DTO銆�
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FinIntangibleAssetDto extends FinIntangibleAsset {
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/financial/FinLedgerQueryDto.java b/src/main/java/com/ruoyi/account/bean/dto/financial/FinLedgerQueryDto.java
new file mode 100644
index 0000000..cfc0553
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/financial/FinLedgerQueryDto.java
@@ -0,0 +1,25 @@
+package com.ruoyi.account.bean.dto.financial;
+
+import lombok.Data;
+
+/**
+ * 绉戠洰璐︽煡璇㈠弬鏁般��
+ */
+@Data
+public class FinLedgerQueryDto {
+
+    /**
+     * 绉戠洰缂栫爜锛堟敮鎸佹湯绾ф垨鎸囧畾绉戠洰锛夈��
+     */
+    private String subjectCode;
+
+    /**
+     * 寮�濮嬫湀浠斤紝鏍煎紡锛歒YYY-MM銆�
+     */
+    private String startMonth;
+
+    /**
+     * 缁撴潫鏈堜唤锛屾牸寮忥細YYYY-MM銆�
+     */
+    private String endMonth;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherDto.java b/src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherDto.java
new file mode 100644
index 0000000..c7c6258
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherDto.java
@@ -0,0 +1,20 @@
+package com.ruoyi.account.bean.dto.financial;
+
+import com.ruoyi.account.pojo.financial.FinVoucher;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+/**
+ * 鍑瘉淇濆瓨 DTO锛堜富琛� + 鍒嗗綍锛夈��
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FinVoucherDto extends FinVoucher {
+
+    /**
+     * 鍑瘉鏄庣粏鍒嗗綍銆�
+     */
+    private List<FinVoucherEntryDto> entries;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherEntryDto.java b/src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherEntryDto.java
new file mode 100644
index 0000000..f722d79
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherEntryDto.java
@@ -0,0 +1,13 @@
+package com.ruoyi.account.bean.dto.financial;
+
+import com.ruoyi.account.pojo.financial.FinVoucherEntry;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 鍑瘉鍒嗗綍 DTO銆�
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FinVoucherEntryDto extends FinVoucherEntry {
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherPageDto.java b/src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherPageDto.java
new file mode 100644
index 0000000..9955bcc
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherPageDto.java
@@ -0,0 +1,37 @@
+package com.ruoyi.account.bean.dto.financial;
+
+import lombok.Data;
+
+import java.time.LocalDate;
+
+/**
+ * 鍑瘉鍒嗛〉鏌ヨ鍙傛暟銆�
+ */
+@Data
+public class FinVoucherPageDto {
+
+    /**
+     * 鍑瘉瀛楀彿锛堟ā绯婂尮閰嶏級銆�
+     */
+    private String voucherNo;
+
+    /**
+     * 鍒跺崟浜恒��
+     */
+    private String creator;
+
+    /**
+     * 鍑瘉鐘舵�併��
+     */
+    private String status;
+
+    /**
+     * 寮�濮嬫棩鏈燂紙鍚級銆�
+     */
+    private LocalDate startDate;
+
+    /**
+     * 缁撴潫鏃ユ湡锛堝惈锛夈��
+     */
+    private LocalDate endDate;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherStatusDto.java b/src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherStatusDto.java
new file mode 100644
index 0000000..47c0900
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/dto/financial/FinVoucherStatusDto.java
@@ -0,0 +1,15 @@
+package com.ruoyi.account.bean.dto.financial;
+
+import lombok.Data;
+
+/**
+ * 鍑瘉鐘舵�佸彉鏇村弬鏁般��
+ */
+@Data
+public class FinVoucherStatusDto {
+
+    /**
+     * 鍑瘉ID銆�
+     */
+    private Long id;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/vo/AccountSubjectVo.java b/src/main/java/com/ruoyi/account/bean/vo/AccountSubjectVo.java
index 3154d1c..c6bb078 100644
--- a/src/main/java/com/ruoyi/account/bean/vo/AccountSubjectVo.java
+++ b/src/main/java/com/ruoyi/account/bean/vo/AccountSubjectVo.java
@@ -3,6 +3,19 @@
 import com.ruoyi.account.pojo.AccountSubject;
 import lombok.Data;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @Data
 public class AccountSubjectVo extends AccountSubject {
+
+    /**
+     * 瀛愮鐩垪琛紙閫掑綊缁撴瀯锛夈��
+     */
+    private List<AccountSubjectVo> children = new ArrayList<>();
+
+    /**
+     * 鏄惁鍙跺瓙鑺傜偣銆�
+     */
+    private Boolean leaf;
 }
diff --git a/src/main/java/com/ruoyi/account/bean/vo/PurchaseInboundVo.java b/src/main/java/com/ruoyi/account/bean/vo/PurchaseInboundVo.java
new file mode 100644
index 0000000..934502a
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/vo/PurchaseInboundVo.java
@@ -0,0 +1,48 @@
+package com.ruoyi.account.bean.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@Schema(name = "PurchaseInboundVo", description = "璐㈠姟绠$悊--閲囪喘鍏ュ簱鍙拌处(杩斿洖)")
+@ExcelIgnoreUnannotated
+public class PurchaseInboundVo {
+
+    @Schema(description = "鍏ュ簱鍗昳d")
+    private Long id;
+
+    @Schema(description = "鍏ュ簱鍗曞彿")
+    @Excel(name = "鍏ュ簱鍗曞彿")
+    private String inboundBatches;
+
+    @Schema(description = "渚涘簲鍟�")
+    @Excel(name = "渚涘簲鍟�")
+    private String supplierName;
+
+    @Schema(description = "鍏ュ簱鏃ユ湡")
+    @Excel(name = "鍏ュ簱鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date InboundDate;
+
+    @Schema(description = "浜у搧鍚嶇О")
+    @Excel(name = "浜у搧鍚嶇О")
+    private String productName;
+
+    @Schema(description = "浜у搧瑙勬牸")
+    @Excel(name = "浜у搧瑙勬牸")
+    private String  specificationModel;
+
+    @Schema(description = "閲戦")
+    @Excel(name = "閲戦")
+    private BigDecimal InboundAmount;
+
+    @Schema(description = "閲囪喘璁㈠崟鍙�")
+    @Excel(name = "閲囪喘璁㈠崟鍙�")
+    private String purchaseContractNumber;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/vo/PurchaseReturnVo.java b/src/main/java/com/ruoyi/account/bean/vo/PurchaseReturnVo.java
new file mode 100644
index 0000000..e912993
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/vo/PurchaseReturnVo.java
@@ -0,0 +1,48 @@
+package com.ruoyi.account.bean.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Data
+@Schema(name = "PurchaseReturnVo", description = "璐㈠姟绠$悊--閲囪喘閫�璐у彴璐�(杩斿洖)")
+@ExcelIgnoreUnannotated
+public class PurchaseReturnVo {
+
+    @Schema(description = "閫�璐у崟id")
+    private Long id;
+
+    @Excel(name = "閫�璐у崟鍙�")
+    @Schema(description = "閫�璐у崟鍙�")
+    private String returnNo;
+
+    @Schema(description = "渚涘簲鍟�")
+    @Excel(name = "渚涘簲鍟�")
+    private String supplierName;
+
+    @Schema(description = "鍏宠仈鍏ュ簱鍗曞彿")
+    @Excel(name = "鍏宠仈鍏ュ簱鍗曞彿")
+    private String inboundBatches;
+
+    @Schema(description = "閫�璐ф棩鏈�")
+    @Excel(name = "閫�璐ф棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime preparedAt;
+
+    @Schema(description = "閫�娆炬�婚")
+    @Excel(name = "閫�娆炬�婚")
+    private BigDecimal totalAmount;
+
+    @Schema(description = "閫�璐ф柟寮�")
+    @Excel(name = "閫�璐ф柟寮�")
+    private String returnType;
+
+    @Schema(description = "閲囪喘璁㈠崟鍙�")
+    @Excel(name = "閲囪喘璁㈠崟鍙�")
+    private String purchaseContractNumber;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/vo/SalesOutboundVo.java b/src/main/java/com/ruoyi/account/bean/vo/SalesOutboundVo.java
index cfc0a68..5ccdb5b 100644
--- a/src/main/java/com/ruoyi/account/bean/vo/SalesOutboundVo.java
+++ b/src/main/java/com/ruoyi/account/bean/vo/SalesOutboundVo.java
@@ -38,9 +38,9 @@
     @Excel(name = "浜у搧瑙勬牸")
     private String  specificationModel;
 
-    @Schema(description = "鍑哄簱鏁伴噺")
-    @Excel(name = "鍑哄簱鏁伴噺")
-    private BigDecimal stockOutNum;
+    @Schema(description = "閲戦")
+    @Excel(name = "閲戦")
+    private BigDecimal outboundAmount;
 
     @Schema(description = "鍙戣揣缂栧彿")
     @Excel(name = "鍙戣揣缂栧彿")
diff --git a/src/main/java/com/ruoyi/account/bean/vo/financial/FinLedgerEntryRecordVo.java b/src/main/java/com/ruoyi/account/bean/vo/financial/FinLedgerEntryRecordVo.java
new file mode 100644
index 0000000..846b350
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/vo/financial/FinLedgerEntryRecordVo.java
@@ -0,0 +1,43 @@
+package com.ruoyi.account.bean.vo.financial;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+/**
+ * 绉戠洰璐﹀熀纭�鍒嗗綍鏌ヨ瀵硅薄锛圫QL鏄犲皠浣跨敤锛夈��
+ */
+@Data
+public class FinLedgerEntryRecordVo {
+
+    /**
+     * 鍑瘉鏃ユ湡銆�
+     */
+    private LocalDate voucherDate;
+
+    /**
+     * 鍑瘉瀛楀彿銆�
+     */
+    private String voucherNo;
+
+    /**
+     * 鎽樿銆�
+     */
+    private String summary;
+
+    /**
+     * 鍊熸柟閲戦銆�
+     */
+    private BigDecimal debit;
+
+    /**
+     * 璐锋柟閲戦銆�
+     */
+    private BigDecimal credit;
+
+    /**
+     * 琛屽彿锛堟帓搴忓瓧娈碉級銆�
+     */
+    private Integer rowNo;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/vo/financial/FinLedgerRowVo.java b/src/main/java/com/ruoyi/account/bean/vo/financial/FinLedgerRowVo.java
new file mode 100644
index 0000000..d01baf5
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/vo/financial/FinLedgerRowVo.java
@@ -0,0 +1,53 @@
+package com.ruoyi.account.bean.vo.financial;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+/**
+ * 绉戠洰璐﹁鏁版嵁杩斿洖瀵硅薄銆�
+ */
+@Data
+public class FinLedgerRowVo {
+
+    /**
+     * 琛岀被鍨嬶細opening/entry/monthly_total/yearly_total銆�
+     */
+    private String rowType;
+
+    /**
+     * 鏃ユ湡銆�
+     */
+    private LocalDate date;
+
+    /**
+     * 鍑瘉瀛楀彿銆�
+     */
+    private String voucherNo;
+
+    /**
+     * 鎽樿銆�
+     */
+    private String summary;
+
+    /**
+     * 鍊熸柟閲戦銆�
+     */
+    private BigDecimal debit;
+
+    /**
+     * 璐锋柟閲戦銆�
+     */
+    private BigDecimal credit;
+
+    /**
+     * 浣欓鏂瑰悜锛氬��/璐枫��
+     */
+    private String direction;
+
+    /**
+     * 浣欓锛堝�熸璐疯礋锛夈��
+     */
+    private BigDecimal balance;
+}
diff --git a/src/main/java/com/ruoyi/account/bean/vo/financial/FinVoucherDetailVo.java b/src/main/java/com/ruoyi/account/bean/vo/financial/FinVoucherDetailVo.java
new file mode 100644
index 0000000..d1eab48
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/vo/financial/FinVoucherDetailVo.java
@@ -0,0 +1,21 @@
+package com.ruoyi.account.bean.vo.financial;
+
+import com.ruoyi.account.pojo.financial.FinVoucher;
+import com.ruoyi.account.pojo.financial.FinVoucherEntry;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+/**
+ * 鍑瘉璇︽儏杩斿洖瀵硅薄銆�
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FinVoucherDetailVo extends FinVoucher {
+
+    /**
+     * 鍑瘉鍒嗗綍鍒楄〃銆�
+     */
+    private List<FinVoucherEntry> entries;
+}
diff --git a/src/main/java/com/ruoyi/account/controller/AccounPurchaseController.java b/src/main/java/com/ruoyi/account/controller/AccounPurchaseController.java
new file mode 100644
index 0000000..d1993ea
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/controller/AccounPurchaseController.java
@@ -0,0 +1,68 @@
+package com.ruoyi.account.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.PurchaseInboundDto;
+import com.ruoyi.account.bean.dto.PurchaseReturnDto;
+import com.ruoyi.account.bean.vo.PurchaseInboundVo;
+import com.ruoyi.account.bean.vo.PurchaseReturnVo;
+import com.ruoyi.account.service.AccountPurchaseService;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.domain.R;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊鐨勯噰璐儴鍒� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-07 04:45:30
+ */
+@RestController
+@RequestMapping("/accountPurchase")
+@RequiredArgsConstructor
+@Tag(name = "璐㈠姟绠$悊鐨勯噰璐儴鍒�")
+public class AccounPurchaseController {
+
+    private final AccountPurchaseService accountPurchaseService;
+
+    @GetMapping("/listPageAccountPurchase")
+    @Log(title = "閲囪喘鍏ュ簱鍙拌处", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟绠$悊--閲囪喘鍏ュ簱鍙拌处")
+    public R<IPage<PurchaseInboundVo>> listPageAccountPurchase(Page page, PurchaseInboundDto purchaseInboundDto) {
+        IPage<PurchaseInboundVo> listPage = accountPurchaseService.listPageAccountPurchase(page,purchaseInboundDto);
+        return R.ok(listPage);
+    }
+
+    @PostMapping("/exportAccountPurchaseInbound")
+    @Operation(summary = "瀵煎嚭閲囪喘鍏ュ簱鏂囦欢")
+    @Log(title = "瀵煎嚭閲囪喘鍏ュ簱鏂囦欢", businessType = BusinessType.EXPORT)
+    public void exportAccountPurchaseInbound(HttpServletResponse response, PurchaseInboundDto purchaseInboundDto) {
+        accountPurchaseService.exportAccountPurchaseInbound(response,purchaseInboundDto);
+    }
+
+    @GetMapping("/listPageAccountPurchaseReturn")
+    @Log(title = "閲囪喘閫�璐у彴璐�", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟绠$悊--閲囪喘閫�璐у彴璐�")
+    public R<IPage<PurchaseReturnVo>> listPageAccountPurchaseReturn(Page page, PurchaseReturnDto purchaseReturnDto) {
+        IPage<PurchaseReturnVo> listPage = accountPurchaseService.listPageAccountPurchaseReturn(page,purchaseReturnDto);
+        return R.ok(listPage);
+    }
+
+    @PostMapping("/exportAccountPurchaseReturn")
+    @Operation(summary = "瀵煎嚭閲囪喘閫�璐ф枃浠�")
+    @Log(title = "瀵煎嚭閲囪喘閫�璐ф枃浠�", businessType = BusinessType.EXPORT)
+    public void exportAccountPurchaseReturn(HttpServletResponse response,PurchaseReturnDto purchaseReturnDto) {
+        accountPurchaseService.exportAccountPurchaseReturn(response,purchaseReturnDto);
+    }
+
+}
diff --git a/src/main/java/com/ruoyi/account/controller/AccountSalesController.java b/src/main/java/com/ruoyi/account/controller/AccountSalesController.java
index 5fb5e4f..bca90db 100644
--- a/src/main/java/com/ruoyi/account/controller/AccountSalesController.java
+++ b/src/main/java/com/ruoyi/account/controller/AccountSalesController.java
@@ -35,11 +35,11 @@
 
     private final AccountSalesService accountSalesService;
 
-    @GetMapping("/listPageByOutbound")
+    @GetMapping("/listPageAccountSales")
     @Log(title = "閿�鍞嚭搴撳彴璐�", businessType = BusinessType.OTHER)
     @Operation(summary = "璐㈠姟绠$悊--閿�鍞嚭搴撳彴璐�")
-    public R<IPage<SalesOutboundVo>> listPageByOutbound(Page page, SalesOutboundDto salesOutboundDto) {
-        IPage<SalesOutboundVo> listPage = accountSalesService.listPageByOutbound(page,salesOutboundDto);
+    public R<IPage<SalesOutboundVo>> listPageAccountSales(Page page, SalesOutboundDto salesOutboundDto) {
+        IPage<SalesOutboundVo> listPage = accountSalesService.listPageAccountSales(page,salesOutboundDto);
         return R.ok(listPage);
     }
 
@@ -50,11 +50,11 @@
         accountSalesService.exportAccountSalesOutbound(response,salesOutboundDto);
     }
 
-    @GetMapping("/listPageByReturn")
+    @GetMapping("/listPageAccountSalesReturn")
     @Log(title = "閿�鍞��璐у彴璐�", businessType = BusinessType.OTHER)
     @Operation(summary = "璐㈠姟绠$悊--閿�鍞��璐у彴璐�")
-    public R<IPage<SalesReturnVo>> listPageBySalesReturn(Page page, SalesReturnDto salesReturnDto) {
-        IPage<SalesReturnVo> listPage = accountSalesService.listPageBySalesReturn(page,salesReturnDto);
+    public R<IPage<SalesReturnVo>> listPageAccountSalesReturn(Page page, SalesReturnDto salesReturnDto) {
+        IPage<SalesReturnVo> listPage = accountSalesService.listPageAccountSalesReturn(page,salesReturnDto);
         return R.ok(listPage);
     }
 
diff --git a/src/main/java/com/ruoyi/account/controller/AccountSubjectController.java b/src/main/java/com/ruoyi/account/controller/AccountSubjectController.java
index 8282883..38dd0ce 100644
--- a/src/main/java/com/ruoyi/account/controller/AccountSubjectController.java
+++ b/src/main/java/com/ruoyi/account/controller/AccountSubjectController.java
@@ -33,7 +33,7 @@
 
     @GetMapping("/list")
     @Log(title = "鎬昏处绉戠洰鏁版嵁闆嗗悎", businessType = BusinessType.OTHER)
-    @Operation(summary = "鎬昏处绉戠洰鍒嗛〉鏌ヨ")
+    @Operation(summary = "鎬昏处绉戠洰鏍戝舰鏌ヨ锛堥�掑綊锛�")
     public R<IPage<AccountSubjectVo>> AccountSubjectDtoList(Page<AccountSubjectDto> page, AccountSubjectDto accountSubjectDto) {
         IPage<AccountSubjectVo> paramList = accountSubjectService.baseList(page, accountSubjectDto);
         return R.ok(paramList);
@@ -43,21 +43,21 @@
     @Log(title = "鏂板鎬昏处绉戠洰", businessType = BusinessType.INSERT)
     @Operation(summary = "鏂板鎬昏处绉戠洰")
     public R AccountSubjectDtoAdd(@RequestBody AccountSubjectDto accountSubjectDto) {
-        return R.ok(accountSubjectService.save(accountSubjectDto));
+        return R.ok(accountSubjectService.saveAccountSubject(accountSubjectDto));
     }
 
     @PutMapping("/edit")
     @Log(title = "淇敼鎬昏处绉戠洰", businessType = BusinessType.UPDATE)
     @Operation(summary = "淇敼鎬昏处绉戠洰")
     public R AccountSubjectDtoEdit(@RequestBody AccountSubjectDto accountSubjectDto) {
-        return R.ok(accountSubjectService.updateById(accountSubjectDto));
+        return R.ok(accountSubjectService.updateAccountSubject(accountSubjectDto));
     }
 
     @DeleteMapping("/remove/{ids}")
     @Log(title = "鍒犻櫎鎬昏处绉戠洰", businessType = BusinessType.DELETE)
     @Operation(summary = "鍒犻櫎鎬昏处绉戠洰")
     public R AccountSubjectDtooRemove(@PathVariable Long[] ids) {
-        return R.ok(accountSubjectService.removeBatchByIds(Arrays.asList(ids)));
+        return R.ok(accountSubjectService.removeAccountSubjectByIds(Arrays.asList(ids)));
     }
 
     @PostMapping("/export")
diff --git a/src/main/java/com/ruoyi/account/controller/financial/FinFixedAssetController.java b/src/main/java/com/ruoyi/account/controller/financial/FinFixedAssetController.java
new file mode 100644
index 0000000..a18c9da
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/controller/financial/FinFixedAssetController.java
@@ -0,0 +1,63 @@
+package com.ruoyi.account.controller.financial;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.financial.FinFixedAssetDto;
+import com.ruoyi.account.bean.dto.financial.FinIdBatchDto;
+import com.ruoyi.account.pojo.financial.FinFixedAsset;
+import com.ruoyi.account.service.financial.FinFixedAssetService;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.domain.R;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+
+/**
+ * 鍥哄畾璧勪骇鎺у埗鍣ㄣ��
+ */
+@RestController
+@RequestMapping("/financial/fixedAsset")
+@RequiredArgsConstructor
+@Tag(name = "璐㈠姟绠$悊-鍥哄畾璧勪骇")
+public class FinFixedAssetController {
+
+    private final FinFixedAssetService finFixedAssetService;
+
+    @GetMapping("/page")
+    @Operation(summary = "鍥哄畾璧勪骇鍒嗛〉鏌ヨ")
+    public R<IPage<FinFixedAsset>> page(Page<FinFixedAsset> page, FinFixedAssetDto queryDto) {
+        return R.ok(finFixedAssetService.pageList(page, queryDto));
+    }
+
+    @PostMapping("/add")
+    @Log(title = "鍥哄畾璧勪骇", businessType = BusinessType.INSERT)
+    @Operation(summary = "鏂板鍥哄畾璧勪骇")
+    public R<Boolean> add(@RequestBody FinFixedAssetDto dto) {
+        return R.ok(finFixedAssetService.add(dto));
+    }
+
+    @PutMapping("/update")
+    @Log(title = "鍥哄畾璧勪骇", businessType = BusinessType.UPDATE)
+    @Operation(summary = "淇敼鍥哄畾璧勪骇")
+    public R<Boolean> update(@RequestBody FinFixedAssetDto dto) {
+        return R.ok(finFixedAssetService.update(dto));
+    }
+
+    @DeleteMapping("/delete")
+    @Log(title = "鍥哄畾璧勪骇", businessType = BusinessType.DELETE)
+    @Operation(summary = "鍒犻櫎鍥哄畾璧勪骇")
+    public R<Boolean> delete(@RequestParam("ids") Long[] ids) {
+        return R.ok(finFixedAssetService.deleteByIds(Arrays.asList(ids)));
+    }
+
+    @PostMapping("/depreciate")
+    @Log(title = "鍥哄畾璧勪骇鎶樻棫璁℃彁", businessType = BusinessType.UPDATE)
+    @Operation(summary = "鍥哄畾璧勪骇鎸夋湀璁℃彁鎶樻棫")
+    public R depreciate(@RequestBody(required = false) FinIdBatchDto dto) {
+        return R.ok(finFixedAssetService.depreciate(dto == null ? null : dto.getIds()));
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/controller/financial/FinIntangibleAssetController.java b/src/main/java/com/ruoyi/account/controller/financial/FinIntangibleAssetController.java
new file mode 100644
index 0000000..cb12f8c
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/controller/financial/FinIntangibleAssetController.java
@@ -0,0 +1,63 @@
+package com.ruoyi.account.controller.financial;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.financial.FinIdBatchDto;
+import com.ruoyi.account.bean.dto.financial.FinIntangibleAssetDto;
+import com.ruoyi.account.pojo.financial.FinIntangibleAsset;
+import com.ruoyi.account.service.financial.FinIntangibleAssetService;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.domain.R;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+
+/**
+ * 鏃犲舰璧勪骇鎺у埗鍣ㄣ��
+ */
+@RestController
+@RequestMapping("/financial/intangibleAsset")
+@RequiredArgsConstructor
+@Tag(name = "璐㈠姟绠$悊-鏃犲舰璧勪骇")
+public class FinIntangibleAssetController {
+
+    private final FinIntangibleAssetService finIntangibleAssetService;
+
+    @GetMapping("/page")
+    @Operation(summary = "鏃犲舰璧勪骇鍒嗛〉鏌ヨ")
+    public R<IPage<FinIntangibleAsset>> page(Page<FinIntangibleAsset> page, FinIntangibleAssetDto queryDto) {
+        return R.ok(finIntangibleAssetService.pageList(page, queryDto));
+    }
+
+    @PostMapping("/add")
+    @Log(title = "鏃犲舰璧勪骇", businessType = BusinessType.INSERT)
+    @Operation(summary = "鏂板鏃犲舰璧勪骇")
+    public R<Boolean> add(@RequestBody FinIntangibleAssetDto dto) {
+        return R.ok(finIntangibleAssetService.add(dto));
+    }
+
+    @PutMapping("/update")
+    @Log(title = "鏃犲舰璧勪骇", businessType = BusinessType.UPDATE)
+    @Operation(summary = "淇敼鏃犲舰璧勪骇")
+    public R<Boolean> update(@RequestBody FinIntangibleAssetDto dto) {
+        return R.ok(finIntangibleAssetService.update(dto));
+    }
+
+    @DeleteMapping("/delete")
+    @Log(title = "鏃犲舰璧勪骇", businessType = BusinessType.DELETE)
+    @Operation(summary = "鍒犻櫎鏃犲舰璧勪骇")
+    public R<Boolean> delete(@RequestParam("ids") Long[] ids) {
+        return R.ok(finIntangibleAssetService.deleteByIds(Arrays.asList(ids)));
+    }
+
+    @PostMapping("/amortize")
+    @Log(title = "鏃犲舰璧勪骇鎽婇攢璁℃彁", businessType = BusinessType.UPDATE)
+    @Operation(summary = "鏃犲舰璧勪骇鎸夋湀璁℃彁鎽婇攢")
+    public R amortize(@RequestBody(required = false) FinIdBatchDto dto) {
+        return R.ok(finIntangibleAssetService.amortize(dto == null ? null : dto.getIds()));
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/controller/financial/FinLedgerController.java b/src/main/java/com/ruoyi/account/controller/financial/FinLedgerController.java
new file mode 100644
index 0000000..423030a
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/controller/financial/FinLedgerController.java
@@ -0,0 +1,39 @@
+package com.ruoyi.account.controller.financial;
+
+import com.ruoyi.account.bean.dto.financial.FinDetailLedgerQueryDto;
+import com.ruoyi.account.bean.dto.financial.FinLedgerQueryDto;
+import com.ruoyi.account.bean.vo.financial.FinLedgerRowVo;
+import com.ruoyi.account.service.financial.FinLedgerService;
+import com.ruoyi.framework.web.domain.R;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 绉戠洰鎬昏处/鏄庣粏璐︽帶鍒跺櫒銆�
+ */
+@RestController
+@RequestMapping("/financial/ledger")
+@RequiredArgsConstructor
+@Tag(name = "璐㈠姟绠$悊-绉戠洰璐�")
+public class FinLedgerController {
+
+    private final FinLedgerService finLedgerService;
+
+    @GetMapping("/general")
+    @Operation(summary = "绉戠洰鎬昏处鏌ヨ")
+    public R<List<FinLedgerRowVo>> general(FinLedgerQueryDto queryDto) {
+        return R.ok(finLedgerService.queryGeneralLedger(queryDto));
+    }
+
+    @GetMapping("/detail")
+    @Operation(summary = "绉戠洰鏄庣粏璐︽煡璇�")
+    public R<List<FinLedgerRowVo>> detail(FinDetailLedgerQueryDto queryDto) {
+        return R.ok(finLedgerService.queryDetailLedger(queryDto));
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/controller/financial/FinVoucherController.java b/src/main/java/com/ruoyi/account/controller/financial/FinVoucherController.java
new file mode 100644
index 0000000..beeaafa
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/controller/financial/FinVoucherController.java
@@ -0,0 +1,69 @@
+package com.ruoyi.account.controller.financial;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.financial.FinVoucherDto;
+import com.ruoyi.account.bean.dto.financial.FinVoucherPageDto;
+import com.ruoyi.account.bean.dto.financial.FinVoucherStatusDto;
+import com.ruoyi.account.bean.vo.financial.FinVoucherDetailVo;
+import com.ruoyi.account.pojo.financial.FinVoucher;
+import com.ruoyi.account.service.financial.FinVoucherService;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.domain.R;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 鍑瘉鎺у埗鍣ㄣ��
+ */
+@RestController
+@RequestMapping("/financial/voucher")
+@RequiredArgsConstructor
+@Tag(name = "璐㈠姟绠$悊-鍑瘉")
+public class FinVoucherController {
+
+    private final FinVoucherService finVoucherService;
+
+    @GetMapping("/page")
+    @Operation(summary = "鍑瘉鍒嗛〉鏌ヨ")
+    public R<IPage<FinVoucher>> page(Page<FinVoucher> page, FinVoucherPageDto queryDto) {
+        return R.ok(finVoucherService.pageList(page, queryDto));
+    }
+
+    @PostMapping("/add")
+    @Log(title = "鍑瘉", businessType = BusinessType.INSERT)
+    @Operation(summary = "鏂板鍑瘉")
+    public R<Boolean> add(@RequestBody FinVoucherDto dto) {
+        return R.ok(finVoucherService.addVoucher(dto));
+    }
+
+    @PutMapping("/update")
+    @Log(title = "鍑瘉", businessType = BusinessType.UPDATE)
+    @Operation(summary = "淇敼鍑瘉")
+    public R<Boolean> update(@RequestBody FinVoucherDto dto) {
+        return R.ok(finVoucherService.updateVoucher(dto));
+    }
+
+    @PostMapping("/post")
+    @Log(title = "鍑瘉杩囪处", businessType = BusinessType.UPDATE)
+    @Operation(summary = "鍑瘉杩囪处")
+    public R<Boolean> post(@RequestBody FinVoucherStatusDto dto) {
+        return R.ok(finVoucherService.postVoucher(dto.getId()));
+    }
+
+    @PostMapping("/cancel")
+    @Log(title = "鍑瘉浣滃簾", businessType = BusinessType.UPDATE)
+    @Operation(summary = "鍑瘉浣滃簾")
+    public R<Boolean> cancel(@RequestBody FinVoucherStatusDto dto) {
+        return R.ok(finVoucherService.cancelVoucher(dto.getId()));
+    }
+
+    @GetMapping("/detail/{id}")
+    @Operation(summary = "鍑瘉璇︽儏")
+    public R<FinVoucherDetailVo> detail(@PathVariable("id") Long id) {
+        return R.ok(finVoucherService.detail(id));
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/mapper/AccountSubjectMapper.java b/src/main/java/com/ruoyi/account/mapper/AccountSubjectMapper.java
index 1fface5..46a4968 100644
--- a/src/main/java/com/ruoyi/account/mapper/AccountSubjectMapper.java
+++ b/src/main/java/com/ruoyi/account/mapper/AccountSubjectMapper.java
@@ -3,6 +3,9 @@
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.ruoyi.account.pojo.AccountSubject;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
  * <p>
@@ -15,4 +18,6 @@
 @Mapper
 public interface AccountSubjectMapper extends BaseMapper<AccountSubject> {
 
+    Long countReferencedBySubjectCodes(@Param("subjectCodes") List<String> subjectCodes);
+
 }
diff --git a/src/main/java/com/ruoyi/account/mapper/financial/FinFixedAssetMapper.java b/src/main/java/com/ruoyi/account/mapper/financial/FinFixedAssetMapper.java
new file mode 100644
index 0000000..da2ae49
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/mapper/financial/FinFixedAssetMapper.java
@@ -0,0 +1,12 @@
+package com.ruoyi.account.mapper.financial;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.account.pojo.financial.FinFixedAsset;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 鍥哄畾璧勪骇 Mapper銆�
+ */
+@Mapper
+public interface FinFixedAssetMapper extends BaseMapper<FinFixedAsset> {
+}
diff --git a/src/main/java/com/ruoyi/account/mapper/financial/FinIntangibleAssetMapper.java b/src/main/java/com/ruoyi/account/mapper/financial/FinIntangibleAssetMapper.java
new file mode 100644
index 0000000..8a7bbb2
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/mapper/financial/FinIntangibleAssetMapper.java
@@ -0,0 +1,12 @@
+package com.ruoyi.account.mapper.financial;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.account.pojo.financial.FinIntangibleAsset;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 鏃犲舰璧勪骇 Mapper銆�
+ */
+@Mapper
+public interface FinIntangibleAssetMapper extends BaseMapper<FinIntangibleAsset> {
+}
diff --git a/src/main/java/com/ruoyi/account/mapper/financial/FinVoucherEntryMapper.java b/src/main/java/com/ruoyi/account/mapper/financial/FinVoucherEntryMapper.java
new file mode 100644
index 0000000..2fa2b73
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/mapper/financial/FinVoucherEntryMapper.java
@@ -0,0 +1,28 @@
+package com.ruoyi.account.mapper.financial;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.account.bean.vo.financial.FinLedgerEntryRecordVo;
+import com.ruoyi.account.pojo.financial.FinVoucherEntry;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ * 鍑瘉鍒嗗綍 Mapper銆�
+ */
+@Mapper
+public interface FinVoucherEntryMapper extends BaseMapper<FinVoucherEntry> {
+
+    List<FinLedgerEntryRecordVo> listPostedEntries(@Param("subjectCode") String subjectCode,
+                                                   @Param("startDate") LocalDate startDate,
+                                                   @Param("endDate") LocalDate endDate,
+                                                   @Param("auxiliaryType") String auxiliaryType,
+                                                   @Param("auxiliaryId") String auxiliaryId);
+
+    List<FinLedgerEntryRecordVo> listPostedEntriesBefore(@Param("subjectCode") String subjectCode,
+                                                         @Param("beforeDate") LocalDate beforeDate,
+                                                         @Param("auxiliaryType") String auxiliaryType,
+                                                         @Param("auxiliaryId") String auxiliaryId);
+}
diff --git a/src/main/java/com/ruoyi/account/mapper/financial/FinVoucherMapper.java b/src/main/java/com/ruoyi/account/mapper/financial/FinVoucherMapper.java
new file mode 100644
index 0000000..b528b7c
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/mapper/financial/FinVoucherMapper.java
@@ -0,0 +1,12 @@
+package com.ruoyi.account.mapper.financial;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.account.pojo.financial.FinVoucher;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 鍑瘉涓昏〃 Mapper銆�
+ */
+@Mapper
+public interface FinVoucherMapper extends BaseMapper<FinVoucher> {
+}
diff --git a/src/main/java/com/ruoyi/account/pojo/AccountSubject.java b/src/main/java/com/ruoyi/account/pojo/AccountSubject.java
index 49ba3da..9616324 100644
--- a/src/main/java/com/ruoyi/account/pojo/AccountSubject.java
+++ b/src/main/java/com/ruoyi/account/pojo/AccountSubject.java
@@ -39,6 +39,12 @@
     private Long id;
 
     /**
+     * 鐖剁鐩甀D锛堜负绌鸿〃绀烘牴鑺傜偣锛�
+     */
+    @ApiModelProperty("鐖剁鐩甀D锛堜负绌鸿〃绀烘牴鑺傜偣锛�")
+    private Long parentId;
+
+    /**
      * 绉戠洰缂栫爜(鍞竴鏍囪瘑)
      */
     @ApiModelProperty("绉戠洰缂栫爜(鍞竴鏍囪瘑)")
diff --git a/src/main/java/com/ruoyi/account/pojo/financial/FinFixedAsset.java b/src/main/java/com/ruoyi/account/pojo/financial/FinFixedAsset.java
new file mode 100644
index 0000000..f11f700
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/pojo/financial/FinFixedAsset.java
@@ -0,0 +1,101 @@
+package com.ruoyi.account.pojo.financial;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * 鍥哄畾璧勪骇瀹炰綋銆�
+ */
+@Getter
+@Setter
+@ToString
+@TableName("fin_fixed_asset")
+@ApiModel(value = "FinFixedAsset瀵硅薄", description = "鍥哄畾璧勪骇")
+public class FinFixedAsset implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("涓婚敭ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty("璧勪骇缂栧彿")
+    private String assetCode;
+
+    @ApiModelProperty("璧勪骇鍚嶇О")
+    private String assetName;
+
+    @ApiModelProperty("璧勪骇绫诲埆")
+    private String category;
+
+    @ApiModelProperty("瑙勬牸鍨嬪彿")
+    private String specification;
+
+    @ApiModelProperty("璐疆鏃ユ湡")
+    private LocalDate purchaseDate;
+
+    @ApiModelProperty("璧勪骇鍘熷��")
+    private BigDecimal originalValue;
+
+    @ApiModelProperty("浣跨敤骞撮檺(骞�)")
+    private Integer usefulLife;
+
+    @ApiModelProperty("娈嬪�肩巼(%)")
+    private BigDecimal residualRate;
+
+    @ApiModelProperty("绱鎶樻棫")
+    private BigDecimal accumulatedDepreciation;
+
+    @ApiModelProperty("鍑�鍊�")
+    private BigDecimal netValue;
+
+    @ApiModelProperty("瀛樻斁鍦扮偣")
+    private String location;
+
+    @ApiModelProperty("浣跨敤閮ㄩ棬")
+    private String department;
+
+    @ApiModelProperty("淇濈浜�")
+    private String keeper;
+
+    @ApiModelProperty("鐘舵��")
+    private String status;
+
+    @ApiModelProperty("澶囨敞")
+    private String remark;
+
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private String createUser;
+
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private String updateUser;
+
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty("閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+}
diff --git a/src/main/java/com/ruoyi/account/pojo/financial/FinIntangibleAsset.java b/src/main/java/com/ruoyi/account/pojo/financial/FinIntangibleAsset.java
new file mode 100644
index 0000000..e8ab4d3
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/pojo/financial/FinIntangibleAsset.java
@@ -0,0 +1,98 @@
+package com.ruoyi.account.pojo.financial;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * 鏃犲舰璧勪骇瀹炰綋銆�
+ */
+@Getter
+@Setter
+@ToString
+@TableName("fin_intangible_asset")
+@ApiModel(value = "FinIntangibleAsset瀵硅薄", description = "鏃犲舰璧勪骇")
+public class FinIntangibleAsset implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("涓婚敭ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty("璧勪骇缂栧彿")
+    private String assetCode;
+
+    @ApiModelProperty("璧勪骇鍚嶇О")
+    private String assetName;
+
+    @ApiModelProperty("璧勪骇绫诲埆")
+    private String category;
+
+    @ApiModelProperty("璇佷功缂栧彿")
+    private String certificateNo;
+
+    @ApiModelProperty("鍙栧緱鏃ユ湡")
+    private LocalDate acquisitionDate;
+
+    @ApiModelProperty("璧勪骇鍘熷��")
+    private BigDecimal originalValue;
+
+    @ApiModelProperty("鎽婇攢骞撮檺(骞�)")
+    private Integer amortizationPeriod;
+
+    @ApiModelProperty("娈嬪�肩巼(%)")
+    private BigDecimal residualRate;
+
+    @ApiModelProperty("绱鎽婇攢")
+    private BigDecimal accumulatedAmortization;
+
+    @ApiModelProperty("鍑�鍊�")
+    private BigDecimal netValue;
+
+    @ApiModelProperty("鏈夋晥鏈熻嚦")
+    private LocalDate validityDate;
+
+    @ApiModelProperty("鐘舵��")
+    private String status;
+
+    @ApiModelProperty("璧勪骇鎻忚堪")
+    private String description;
+
+    @ApiModelProperty("澶囨敞")
+    private String remark;
+
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private String createUser;
+
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private String updateUser;
+
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty("閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+}
diff --git a/src/main/java/com/ruoyi/account/pojo/financial/FinVoucher.java b/src/main/java/com/ruoyi/account/pojo/financial/FinVoucher.java
new file mode 100644
index 0000000..0a2918c
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/pojo/financial/FinVoucher.java
@@ -0,0 +1,83 @@
+package com.ruoyi.account.pojo.financial;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * 鍑瘉涓昏〃瀹炰綋銆�
+ */
+@Getter
+@Setter
+@ToString
+@TableName("fin_voucher")
+@ApiModel(value = "FinVoucher瀵硅薄", description = "鍑瘉涓昏〃")
+public class FinVoucher implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("涓婚敭ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty("鍑瘉瀛楀彿")
+    private String voucherNo;
+
+    @ApiModelProperty("鍑瘉鏃ユ湡")
+    private LocalDate voucherDate;
+
+    @ApiModelProperty("鎽樿")
+    private String summary;
+
+    @ApiModelProperty("鍊熸柟鍚堣")
+    private BigDecimal debit;
+
+    @ApiModelProperty("璐锋柟鍚堣")
+    private BigDecimal credit;
+
+    @ApiModelProperty("鍒跺崟浜�")
+    private String creator;
+
+    @ApiModelProperty("鐘舵��: unposted/posted/cancelled")
+    private String status;
+
+    @ApiModelProperty("闄勪欢鏁伴噺")
+    private Integer attachmentCount;
+
+    @ApiModelProperty("澶囨敞")
+    private String remark;
+
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private String createUser;
+
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private String updateUser;
+
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty("閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+}
diff --git a/src/main/java/com/ruoyi/account/pojo/financial/FinVoucherEntry.java b/src/main/java/com/ruoyi/account/pojo/financial/FinVoucherEntry.java
new file mode 100644
index 0000000..44ac56e
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/pojo/financial/FinVoucherEntry.java
@@ -0,0 +1,85 @@
+package com.ruoyi.account.pojo.financial;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 鍑瘉鍒嗗綍瀹炰綋銆�
+ */
+@Getter
+@Setter
+@ToString
+@TableName("fin_voucher_entry")
+@ApiModel(value = "FinVoucherEntry瀵硅薄", description = "鍑瘉鍒嗗綍")
+public class FinVoucherEntry implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("涓婚敭ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty("鍑瘉ID")
+    private Long voucherId;
+
+    @ApiModelProperty("琛屽彿")
+    private Integer rowNo;
+
+    @ApiModelProperty("绉戠洰缂栫爜")
+    private String subjectCode;
+
+    @ApiModelProperty("绉戠洰鍚嶇О")
+    private String subjectName;
+
+    @ApiModelProperty("鎽樿")
+    private String summary;
+
+    @ApiModelProperty("鍊熸柟閲戦")
+    private BigDecimal debit;
+
+    @ApiModelProperty("璐锋柟閲戦")
+    private BigDecimal credit;
+
+    @ApiModelProperty("杈呭姪鏍哥畻绫诲瀷")
+    private String auxiliaryType;
+
+    @ApiModelProperty("杈呭姪鏍哥畻瀵硅薄ID")
+    private String auxiliaryId;
+
+    @ApiModelProperty("杈呭姪鏍哥畻瀵硅薄鍚嶇О")
+    private String auxiliaryName;
+
+    @ApiModelProperty("鍒涘缓浜�")
+    @TableField(fill = FieldFill.INSERT)
+    private String createUser;
+
+    @ApiModelProperty("鍒涘缓鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    @ApiModelProperty("淇敼浜�")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private String updateUser;
+
+    @ApiModelProperty("淇敼鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty("閮ㄩ棬ID")
+    @TableField(fill = FieldFill.INSERT)
+    private Long deptId;
+}
diff --git a/src/main/java/com/ruoyi/account/service/AccountPurchaseService.java b/src/main/java/com/ruoyi/account/service/AccountPurchaseService.java
new file mode 100644
index 0000000..386f921
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/AccountPurchaseService.java
@@ -0,0 +1,27 @@
+package com.ruoyi.account.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.PurchaseInboundDto;
+import com.ruoyi.account.bean.dto.PurchaseReturnDto;
+import com.ruoyi.account.bean.vo.PurchaseInboundVo;
+import com.ruoyi.account.bean.vo.PurchaseReturnVo;
+import jakarta.servlet.http.HttpServletResponse;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊鐨勯攢鍞儴鍒� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-07 04:45:30
+ */
+public interface AccountPurchaseService {
+    IPage<PurchaseInboundVo> listPageAccountPurchase(Page page, PurchaseInboundDto purchaseInboundDto);
+
+    void exportAccountPurchaseInbound(HttpServletResponse response, PurchaseInboundDto purchaseInboundDto);
+
+    IPage<PurchaseReturnVo> listPageAccountPurchaseReturn(Page page, PurchaseReturnDto purchaseReturnDto);
+
+    void exportAccountPurchaseReturn(HttpServletResponse response, PurchaseReturnDto purchaseReturnDto);
+}
diff --git a/src/main/java/com/ruoyi/account/service/AccountSalesService.java b/src/main/java/com/ruoyi/account/service/AccountSalesService.java
index 930c5dd..7db5416 100644
--- a/src/main/java/com/ruoyi/account/service/AccountSalesService.java
+++ b/src/main/java/com/ruoyi/account/service/AccountSalesService.java
@@ -18,11 +18,11 @@
  */
 public interface AccountSalesService  {
 
-    IPage<SalesOutboundVo> listPageByOutbound(Page page, SalesOutboundDto salesOutboundDto);
+    IPage<SalesOutboundVo> listPageAccountSales(Page page, SalesOutboundDto salesOutboundDto);
 
     void exportAccountSalesOutbound(HttpServletResponse response, SalesOutboundDto salesOutboundDto);
 
-    IPage<SalesReturnVo> listPageBySalesReturn(Page page, SalesReturnDto salesReturnDto);
+    IPage<SalesReturnVo> listPageAccountSalesReturn(Page page, SalesReturnDto salesReturnDto);
 
     void exportAccountSalesReturn(HttpServletResponse response, SalesReturnDto salesReturnDto);
 }
diff --git a/src/main/java/com/ruoyi/account/service/AccountSubjectService.java b/src/main/java/com/ruoyi/account/service/AccountSubjectService.java
index a7dd670..bcbc57c 100644
--- a/src/main/java/com/ruoyi/account/service/AccountSubjectService.java
+++ b/src/main/java/com/ruoyi/account/service/AccountSubjectService.java
@@ -8,6 +8,8 @@
 import com.baomidou.mybatisplus.extension.service.IService;
 import jakarta.servlet.http.HttpServletResponse;
 
+import java.util.List;
+
 /**
  * <p>
  * 鎬昏处绉戠洰琛� 鏈嶅姟绫�
@@ -20,5 +22,11 @@
 
     IPage<AccountSubjectVo> baseList(Page<AccountSubjectDto> page, AccountSubjectDto accountSubjectDto);
 
+    Boolean saveAccountSubject(AccountSubjectDto accountSubjectDto);
+
+    Boolean updateAccountSubject(AccountSubjectDto accountSubjectDto);
+
+    Boolean removeAccountSubjectByIds(List<Long> ids);
+
     void exportAccountSubject(HttpServletResponse response);
 }
diff --git a/src/main/java/com/ruoyi/account/service/financial/FinFixedAssetService.java b/src/main/java/com/ruoyi/account/service/financial/FinFixedAssetService.java
new file mode 100644
index 0000000..0b2c1cc
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/financial/FinFixedAssetService.java
@@ -0,0 +1,26 @@
+package com.ruoyi.account.service.financial;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.account.bean.dto.financial.FinFixedAssetDto;
+import com.ruoyi.account.pojo.financial.FinFixedAsset;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鍥哄畾璧勪骇鏈嶅姟銆�
+ */
+public interface FinFixedAssetService extends IService<FinFixedAsset> {
+
+    IPage<FinFixedAsset> pageList(Page<FinFixedAsset> page, FinFixedAssetDto queryDto);
+
+    Boolean add(FinFixedAssetDto dto);
+
+    Boolean update(FinFixedAssetDto dto);
+
+    Boolean deleteByIds(List<Long> ids);
+
+    Map<String, Object> depreciate(List<Long> ids);
+}
diff --git a/src/main/java/com/ruoyi/account/service/financial/FinIntangibleAssetService.java b/src/main/java/com/ruoyi/account/service/financial/FinIntangibleAssetService.java
new file mode 100644
index 0000000..46d946a
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/financial/FinIntangibleAssetService.java
@@ -0,0 +1,26 @@
+package com.ruoyi.account.service.financial;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.account.bean.dto.financial.FinIntangibleAssetDto;
+import com.ruoyi.account.pojo.financial.FinIntangibleAsset;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鏃犲舰璧勪骇鏈嶅姟銆�
+ */
+public interface FinIntangibleAssetService extends IService<FinIntangibleAsset> {
+
+    IPage<FinIntangibleAsset> pageList(Page<FinIntangibleAsset> page, FinIntangibleAssetDto queryDto);
+
+    Boolean add(FinIntangibleAssetDto dto);
+
+    Boolean update(FinIntangibleAssetDto dto);
+
+    Boolean deleteByIds(List<Long> ids);
+
+    Map<String, Object> amortize(List<Long> ids);
+}
diff --git a/src/main/java/com/ruoyi/account/service/financial/FinLedgerService.java b/src/main/java/com/ruoyi/account/service/financial/FinLedgerService.java
new file mode 100644
index 0000000..c4e9fa4
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/financial/FinLedgerService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.account.service.financial;
+
+import com.ruoyi.account.bean.dto.financial.FinDetailLedgerQueryDto;
+import com.ruoyi.account.bean.dto.financial.FinLedgerQueryDto;
+import com.ruoyi.account.bean.vo.financial.FinLedgerRowVo;
+
+import java.util.List;
+
+/**
+ * 绉戠洰璐︽湇鍔°��
+ */
+public interface FinLedgerService {
+
+    List<FinLedgerRowVo> queryGeneralLedger(FinLedgerQueryDto queryDto);
+
+    List<FinLedgerRowVo> queryDetailLedger(FinDetailLedgerQueryDto queryDto);
+}
diff --git a/src/main/java/com/ruoyi/account/service/financial/FinVoucherService.java b/src/main/java/com/ruoyi/account/service/financial/FinVoucherService.java
new file mode 100644
index 0000000..078bac4
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/financial/FinVoucherService.java
@@ -0,0 +1,27 @@
+package com.ruoyi.account.service.financial;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.account.bean.dto.financial.FinVoucherDto;
+import com.ruoyi.account.bean.dto.financial.FinVoucherPageDto;
+import com.ruoyi.account.bean.vo.financial.FinVoucherDetailVo;
+import com.ruoyi.account.pojo.financial.FinVoucher;
+
+/**
+ * 鍑瘉鏈嶅姟銆�
+ */
+public interface FinVoucherService extends IService<FinVoucher> {
+
+    IPage<FinVoucher> pageList(Page<FinVoucher> page, FinVoucherPageDto queryDto);
+
+    Boolean addVoucher(FinVoucherDto dto);
+
+    Boolean updateVoucher(FinVoucherDto dto);
+
+    Boolean postVoucher(Long id);
+
+    Boolean cancelVoucher(Long id);
+
+    FinVoucherDetailVo detail(Long id);
+}
diff --git a/src/main/java/com/ruoyi/account/service/impl/AccountPurchaseServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/AccountPurchaseServiceImpl.java
new file mode 100644
index 0000000..747f6cf
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/AccountPurchaseServiceImpl.java
@@ -0,0 +1,59 @@
+package com.ruoyi.account.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.PurchaseInboundDto;
+import com.ruoyi.account.bean.dto.PurchaseReturnDto;
+import com.ruoyi.account.bean.vo.PurchaseInboundVo;
+import com.ruoyi.account.bean.vo.PurchaseReturnVo;
+import com.ruoyi.account.service.AccountPurchaseService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper;
+import com.ruoyi.stock.mapper.StockInRecordMapper;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璐㈠姟绠$悊鐨勯攢鍞儴鍒� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-05-07 04:45:30
+ */
+@Service
+@RequiredArgsConstructor
+public class AccountPurchaseServiceImpl implements AccountPurchaseService {
+
+    private final StockInRecordMapper stockInRecordMapper;
+
+    private final PurchaseReturnOrdersMapper purchaseReturnOrdersMapper;
+
+
+    @Override
+    public IPage<PurchaseInboundVo> listPageAccountPurchase(Page page, PurchaseInboundDto purchaseInboundDto) {
+        return stockInRecordMapper.listPageAccountPurchase(page,purchaseInboundDto);
+    }
+
+    @Override
+    public void exportAccountPurchaseInbound(HttpServletResponse response, PurchaseInboundDto purchaseInboundDto) {
+        List<PurchaseInboundVo> list = stockInRecordMapper.listPageAccountPurchase(new Page(1,-1),purchaseInboundDto).getRecords();
+        ExcelUtil<PurchaseInboundVo> util = new ExcelUtil<>(PurchaseInboundVo.class);
+        util.exportExcel(response, list , "閲囪喘鍏ュ簱");
+    }
+
+    @Override
+    public IPage<PurchaseReturnVo> listPageAccountPurchaseReturn(Page page, PurchaseReturnDto purchaseReturnDto) {
+        return purchaseReturnOrdersMapper.listPageAccountPurchaseReturn(page,purchaseReturnDto);
+    }
+
+    @Override
+    public void exportAccountPurchaseReturn(HttpServletResponse response, PurchaseReturnDto purchaseReturnDto) {
+        List<PurchaseReturnVo> list = purchaseReturnOrdersMapper.listPageAccountPurchaseReturn(new Page(1,-1),purchaseReturnDto).getRecords();
+        ExcelUtil<PurchaseReturnVo> util = new ExcelUtil<>(PurchaseReturnVo.class);
+        util.exportExcel(response, list , "閲囪喘閫�璐�");
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/service/impl/AccountSalesServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/AccountSalesServiceImpl.java
index 8ad55fe..ddf4a57 100644
--- a/src/main/java/com/ruoyi/account/service/impl/AccountSalesServiceImpl.java
+++ b/src/main/java/com/ruoyi/account/service/impl/AccountSalesServiceImpl.java
@@ -9,7 +9,7 @@
 import com.ruoyi.account.service.AccountSalesService;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.procurementrecord.mapper.ReturnManagementMapper;
-import com.ruoyi.sales.mapper.ShippingInfoMapper;
+import com.ruoyi.stock.mapper.StockOutRecordMapper;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
@@ -28,30 +28,30 @@
 @RequiredArgsConstructor
 public class AccountSalesServiceImpl  implements AccountSalesService {
 
-    private final ShippingInfoMapper shippingInfoMapper;
+    private final StockOutRecordMapper stockOutRecordMapper;
 
     private final ReturnManagementMapper returnManagementMapper;
 
     @Override
-    public IPage<SalesOutboundVo> listPageByOutbound(Page page, SalesOutboundDto salesOutboundDto) {
-        return shippingInfoMapper.listPageByOutbound(page,salesOutboundDto);
+    public IPage<SalesOutboundVo> listPageAccountSales(Page page, SalesOutboundDto salesOutboundDto) {
+        return stockOutRecordMapper.listPageAccountSales(page,salesOutboundDto);
     }
 
     @Override
     public void exportAccountSalesOutbound(HttpServletResponse response, SalesOutboundDto salesOutboundDto) {
-        List<SalesOutboundVo> list = shippingInfoMapper.listPageByOutbound(new Page(1,-1),salesOutboundDto).getRecords();
+        List<SalesOutboundVo> list = stockOutRecordMapper.listPageAccountSales(new Page(1,-1),salesOutboundDto).getRecords();
         ExcelUtil<SalesOutboundVo> util = new ExcelUtil<>(SalesOutboundVo.class);
         util.exportExcel(response, list , "閿�鍞嚭搴�");
     }
 
     @Override
-    public IPage<SalesReturnVo> listPageBySalesReturn(Page page, SalesReturnDto salesReturnDto) {
-        return returnManagementMapper.listPageBySalesReturn(page,salesReturnDto);
+    public IPage<SalesReturnVo> listPageAccountSalesReturn(Page page, SalesReturnDto salesReturnDto) {
+        return returnManagementMapper.listPageAccountSalesReturn(page,salesReturnDto);
     }
 
     @Override
     public void exportAccountSalesReturn(HttpServletResponse response, SalesReturnDto salesReturnDto) {
-        List<SalesReturnVo> list = returnManagementMapper.listPageBySalesReturn(new Page(1,-1),salesReturnDto).getRecords();
+        List<SalesReturnVo> list = returnManagementMapper.listPageAccountSalesReturn(new Page(1,-1),salesReturnDto).getRecords();
         ExcelUtil<SalesReturnVo> util = new ExcelUtil<>(SalesReturnVo.class);
         util.exportExcel(response, list , "閿�鍞��璐�");
     }
diff --git a/src/main/java/com/ruoyi/account/service/impl/AccountSubjectServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/AccountSubjectServiceImpl.java
index 152966a..37bf64b 100644
--- a/src/main/java/com/ruoyi/account/service/impl/AccountSubjectServiceImpl.java
+++ b/src/main/java/com/ruoyi/account/service/impl/AccountSubjectServiceImpl.java
@@ -10,6 +10,7 @@
 import com.ruoyi.account.mapper.AccountSubjectMapper;
 import com.ruoyi.account.pojo.AccountSubject;
 import com.ruoyi.account.service.AccountSubjectService;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import jakarta.servlet.http.HttpServletResponse;
@@ -18,7 +19,16 @@
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -37,30 +47,78 @@
 
     @Override
     public IPage<AccountSubjectVo> baseList(Page<AccountSubjectDto> page, AccountSubjectDto accountSubjectDto) {
-        LambdaQueryWrapper<AccountSubject> queryWrapper = new LambdaQueryWrapper<>();
-        if (accountSubjectDto != null && StringUtils.isNotEmpty(accountSubjectDto.getSubjectCode())) {
-            queryWrapper.like(AccountSubject::getSubjectCode, accountSubjectDto.getSubjectCode());
-        }
-        if (accountSubjectDto != null && StringUtils.isNotEmpty(accountSubjectDto.getSubjectName())) {
-            queryWrapper.like(AccountSubject::getSubjectName, accountSubjectDto.getSubjectName());
-        }
-        if (accountSubjectDto != null && StringUtils.isNotEmpty(accountSubjectDto.getSubjectType())) {
-            queryWrapper.eq(AccountSubject::getSubjectType, accountSubjectDto.getSubjectType());
-        }
-        queryWrapper.orderByDesc(AccountSubject::getId);
+        Page<AccountSubjectDto> requestPage = page == null ? new Page<>(1, 10) : page;
+        List<AccountSubject> allSubjects = list(loadBaseQueryWrapper(accountSubjectDto));
+        List<AccountSubject> filteredSubjects = applyTreeFilter(allSubjects, accountSubjectDto);
+        List<AccountSubjectVo> fullTree = buildTree(filteredSubjects);
 
-        Page<AccountSubject> entityPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
-        Page<AccountSubject> paramPage = page(entityPage, queryWrapper);
+        long current = requestPage.getCurrent() <= 0 ? 1 : requestPage.getCurrent();
+        long size = requestPage.getSize() <= 0 ? 10 : requestPage.getSize();
+        int fromIndex = (int) Math.min((current - 1) * size, fullTree.size());
+        int toIndex = (int) Math.min(fromIndex + size, fullTree.size());
+        List<AccountSubjectVo> pagedRoots = fromIndex >= toIndex
+                ? Collections.emptyList()
+                : fullTree.subList(fromIndex, toIndex);
 
-        Page<AccountSubjectVo> resultPage = new Page<>(paramPage.getCurrent(), paramPage.getSize(), paramPage.getTotal());
-        List<AccountSubjectVo> records = new ArrayList<>(paramPage.getRecords().size());
-        for (AccountSubject item : paramPage.getRecords()) {
-            AccountSubjectVo vo = new AccountSubjectVo();
-            BeanUtils.copyProperties(item, vo);
-            records.add(vo);
-        }
-        resultPage.setRecords(records);
+        Page<AccountSubjectVo> resultPage = new Page<>(current, size, fullTree.size());
+        resultPage.setRecords(pagedRoots);
         return resultPage;
+    }
+
+    @Override
+    public Boolean saveAccountSubject(AccountSubjectDto accountSubjectDto) {
+        validateSubjectRequiredFields(accountSubjectDto);
+        validateSubjectCodeUnique(accountSubjectDto, false);
+        validateParent(accountSubjectDto.getParentId(), null);
+        if (accountSubjectDto.getStatus() == null) {
+            accountSubjectDto.setStatus(0);
+        }
+        return save(accountSubjectDto);
+    }
+
+    @Override
+    public Boolean updateAccountSubject(AccountSubjectDto accountSubjectDto) {
+        if (accountSubjectDto == null || accountSubjectDto.getId() == null) {
+            throw new ServiceException("淇敼澶辫触锛岀鐩甀D涓嶈兘涓虹┖");
+        }
+        if (getById(accountSubjectDto.getId()) == null) {
+            throw new ServiceException("淇敼澶辫触锛屾湭鎵惧埌瀵瑰簲绉戠洰");
+        }
+        validateParent(accountSubjectDto.getParentId(), accountSubjectDto.getId());
+        validateSubjectRequiredFields(accountSubjectDto);
+        validateSubjectCodeUnique(accountSubjectDto, true);
+        return updateById(accountSubjectDto);
+    }
+
+    @Override
+    public Boolean removeAccountSubjectByIds(List<Long> ids) {
+        if (ids == null || ids.isEmpty()) {
+            return true;
+        }
+        List<AccountSubject> allSubjects = list();
+        if (allSubjects == null || allSubjects.isEmpty()) {
+            return true;
+        }
+        Map<Long, List<Long>> childrenIdMap = buildChildrenIdMap(allSubjects);
+        Set<Long> removeIds = new LinkedHashSet<>();
+        for (Long id : ids) {
+            collectDescendantIds(id, childrenIdMap, removeIds);
+        }
+        if (removeIds.isEmpty()) {
+            return true;
+        }
+        List<String> subjectCodes = allSubjects.stream()
+                .filter(subject -> removeIds.contains(subject.getId()))
+                .map(AccountSubject::getSubjectCode)
+                .filter(StringUtils::isNotEmpty)
+                .collect(Collectors.toList());
+        if (!subjectCodes.isEmpty()) {
+            Long referencedCount = accountSubjectMapper.countReferencedBySubjectCodes(subjectCodes);
+            if (referencedCount != null && referencedCount > 0) {
+                throw new ServiceException("鍒犻櫎澶辫触锛岀鐩凡琚嚟璇佸垎褰曞紩鐢�");
+            }
+        }
+        return removeByIds(removeIds);
     }
 
     @Override
@@ -74,4 +132,266 @@
         ExcelUtil<AccountSubjectImportDto> util = new ExcelUtil<>(AccountSubjectImportDto.class);
         util.exportExcel(response, importDtos , "鎬昏处绉戠洰");
     }
+
+    /**
+     * 鏍¢獙绉戠洰蹇呭~瀛楁锛岄伩鍏嶈剰鏁版嵁鍐欏叆銆�
+     */
+    private void validateSubjectRequiredFields(AccountSubjectDto accountSubjectDto) {
+        if (accountSubjectDto == null) {
+            throw new ServiceException("鎬昏处绉戠洰鏁版嵁涓嶈兘涓虹┖");
+        }
+        if (StringUtils.isEmpty(accountSubjectDto.getSubjectCode())) {
+            throw new ServiceException("绉戠洰缂栫爜涓嶈兘涓虹┖");
+        }
+        if (StringUtils.isEmpty(accountSubjectDto.getSubjectName())) {
+            throw new ServiceException("绉戠洰鍚嶇О涓嶈兘涓虹┖");
+        }
+        if (StringUtils.isEmpty(accountSubjectDto.getSubjectType())) {
+            throw new ServiceException("绉戠洰绫诲瀷涓嶈兘涓虹┖");
+        }
+    }
+
+    /**
+     * 鏍¢獙绉戠洰缂栫爜鍞竴锛屾柊澧炲拰淇敼閮借鎵ц銆�
+     */
+    private void validateSubjectCodeUnique(AccountSubjectDto accountSubjectDto, boolean isUpdate) {
+        LambdaQueryWrapper<AccountSubject> codeQueryWrapper = new LambdaQueryWrapper<>();
+        codeQueryWrapper.eq(AccountSubject::getSubjectCode, accountSubjectDto.getSubjectCode());
+        if (isUpdate) {
+            codeQueryWrapper.ne(AccountSubject::getId, accountSubjectDto.getId());
+        }
+        AccountSubject exists = getOne(codeQueryWrapper, false);
+        if (Objects.nonNull(exists)) {
+            throw new ServiceException("绉戠洰缂栫爜宸插瓨鍦紝璇峰嬁閲嶅鎻愪氦");
+        }
+    }
+
+    /**
+     * 浠呮寜閫氱敤杩囨护鏉′欢鏌ヨ鍩虹鏁版嵁锛堟爲褰㈣繃婊ゅ悗缁啀鍋氾級銆�
+     */
+    private LambdaQueryWrapper<AccountSubject> loadBaseQueryWrapper(AccountSubjectDto accountSubjectDto) {
+        LambdaQueryWrapper<AccountSubject> queryWrapper = new LambdaQueryWrapper<>();
+        if (accountSubjectDto != null && accountSubjectDto.getStatus() != null) {
+            queryWrapper.eq(AccountSubject::getStatus, accountSubjectDto.getStatus());
+        }
+        queryWrapper.orderByAsc(AccountSubject::getSubjectCode).orderByAsc(AccountSubject::getId);
+        return queryWrapper;
+    }
+
+    /**
+     * 鏍戝舰杩囨护锛氬懡涓妭鐐瑰悗淇濈暀鍏剁埗閾句笌瀛愭爲锛屼繚璇侀�掑綊缁撴瀯瀹屾暣銆�
+     */
+    private List<AccountSubject> applyTreeFilter(List<AccountSubject> allSubjects, AccountSubjectDto queryDto) {
+        if (allSubjects == null || allSubjects.isEmpty()) {
+            return Collections.emptyList();
+        }
+        boolean hasFilter = queryDto != null && (
+                StringUtils.isNotEmpty(queryDto.getSubjectCode())
+                        || StringUtils.isNotEmpty(queryDto.getSubjectName())
+                        || StringUtils.isNotEmpty(queryDto.getSubjectType())
+        );
+        if (!hasFilter) {
+            return allSubjects;
+        }
+
+        Map<Long, AccountSubject> subjectMap = allSubjects.stream()
+                .filter(item -> item.getId() != null)
+                .collect(Collectors.toMap(AccountSubject::getId, item -> item, (a, b) -> a, LinkedHashMap::new));
+        Map<Long, List<AccountSubject>> childrenMap = buildChildrenMap(allSubjects);
+
+        Set<Long> matchedIds = new LinkedHashSet<>();
+        for (AccountSubject subject : allSubjects) {
+            if (subject.getId() == null) {
+                continue;
+            }
+            if (matchesFilter(subject, queryDto)) {
+                matchedIds.add(subject.getId());
+            }
+        }
+        if (matchedIds.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        Set<Long> resultIds = new LinkedHashSet<>(matchedIds);
+        for (Long matchedId : matchedIds) {
+            addAncestors(matchedId, subjectMap, resultIds);
+            addDescendants(matchedId, childrenMap, resultIds);
+        }
+
+        return allSubjects.stream()
+                .filter(item -> item.getId() != null && resultIds.contains(item.getId()))
+                .collect(Collectors.toList());
+    }
+
+    private boolean matchesFilter(AccountSubject subject, AccountSubjectDto queryDto) {
+        if (queryDto == null) {
+            return true;
+        }
+        if (StringUtils.isNotEmpty(queryDto.getSubjectCode())
+                && (subject.getSubjectCode() == null || !subject.getSubjectCode().contains(queryDto.getSubjectCode()))) {
+            return false;
+        }
+        if (StringUtils.isNotEmpty(queryDto.getSubjectName())
+                && (subject.getSubjectName() == null || !subject.getSubjectName().contains(queryDto.getSubjectName()))) {
+            return false;
+        }
+        if (StringUtils.isNotEmpty(queryDto.getSubjectType())
+                && !queryDto.getSubjectType().equals(subject.getSubjectType())) {
+            return false;
+        }
+        return true;
+    }
+
+    private void addAncestors(Long subjectId, Map<Long, AccountSubject> subjectMap, Set<Long> resultIds) {
+        AccountSubject current = subjectMap.get(subjectId);
+        if (current == null) {
+            return;
+        }
+        Long parentId = current.getParentId();
+        while (parentId != null && parentId > 0) {
+            AccountSubject parent = subjectMap.get(parentId);
+            if (parent == null) {
+                break;
+            }
+            if (!resultIds.add(parent.getId())) {
+                break;
+            }
+            parentId = parent.getParentId();
+        }
+    }
+
+    private void addDescendants(Long subjectId, Map<Long, List<AccountSubject>> childrenMap, Set<Long> resultIds) {
+        List<AccountSubject> children = childrenMap.getOrDefault(subjectId, Collections.emptyList());
+        for (AccountSubject child : children) {
+            if (child.getId() == null) {
+                continue;
+            }
+            if (resultIds.add(child.getId())) {
+                addDescendants(child.getId(), childrenMap, resultIds);
+            }
+        }
+    }
+
+    private Map<Long, List<AccountSubject>> buildChildrenMap(List<AccountSubject> subjects) {
+        Map<Long, List<AccountSubject>> childrenMap = new HashMap<>();
+        for (AccountSubject subject : subjects) {
+            if (subject.getId() == null) {
+                continue;
+            }
+            Long parentId = subject.getParentId();
+            if (parentId == null || parentId <= 0) {
+                continue;
+            }
+            childrenMap.computeIfAbsent(parentId, key -> new ArrayList<>()).add(subject);
+        }
+        return childrenMap;
+    }
+
+    /**
+     * 鍩轰簬 parentId 閫掑綊鏋勫缓绉戠洰鏍戙��
+     */
+    private List<AccountSubjectVo> buildTree(List<AccountSubject> subjects) {
+        if (subjects == null || subjects.isEmpty()) {
+            return Collections.emptyList();
+        }
+        List<AccountSubject> sortedSubjects = new ArrayList<>(subjects);
+        sortedSubjects.sort(Comparator
+                .comparing(AccountSubject::getSubjectCode, Comparator.nullsLast(String::compareTo))
+                .thenComparing(AccountSubject::getId, Comparator.nullsLast(Long::compareTo)));
+
+        Map<Long, AccountSubjectVo> subjectVoMap = new LinkedHashMap<>();
+        for (AccountSubject subject : sortedSubjects) {
+            if (subject.getId() == null) {
+                continue;
+            }
+            AccountSubjectVo vo = new AccountSubjectVo();
+            BeanUtils.copyProperties(subject, vo);
+            subjectVoMap.put(subject.getId(), vo);
+        }
+
+        List<AccountSubjectVo> roots = new ArrayList<>();
+        for (AccountSubject subject : sortedSubjects) {
+            if (subject.getId() == null) {
+                continue;
+            }
+            AccountSubjectVo current = subjectVoMap.get(subject.getId());
+            Long parentId = subject.getParentId();
+            if (parentId != null && parentId > 0 && subjectVoMap.containsKey(parentId)) {
+                subjectVoMap.get(parentId).getChildren().add(current);
+            } else {
+                roots.add(current);
+            }
+        }
+
+        markLeafRecursively(roots);
+        return roots;
+    }
+
+    private void markLeafRecursively(List<AccountSubjectVo> nodes) {
+        for (AccountSubjectVo node : nodes) {
+            List<AccountSubjectVo> children = node.getChildren();
+            node.setLeaf(children == null || children.isEmpty());
+            if (children != null && !children.isEmpty()) {
+                markLeafRecursively(children);
+            }
+        }
+    }
+
+    /**
+     * 鏍¢獙鐖跺瓙鍏崇郴锛氱埗鑺傜偣蹇呴』瀛樺湪锛屼笖涓嶈兘褰㈡垚寰幆寮曠敤銆�
+     */
+    private void validateParent(Long parentId, Long currentId) {
+        if (parentId == null || parentId <= 0) {
+            return;
+        }
+        if (currentId != null && parentId.equals(currentId)) {
+            throw new ServiceException("鐖剁鐩笉鑳介�夋嫨鑷韩");
+        }
+        AccountSubject parent = getById(parentId);
+        if (parent == null) {
+            throw new ServiceException("鐖剁鐩笉瀛樺湪锛岃閲嶆柊閫夋嫨");
+        }
+        // 闃叉褰㈡垚鐜細鏇存柊鏃讹紝鐖惰妭鐐逛笉鑳芥槸褰撳墠鑺傜偣鐨勪换鎰忓瓙瀛欒妭鐐广��
+        if (currentId != null) {
+            Set<Long> visited = new HashSet<>();
+            Long traceParentId = parentId;
+            while (traceParentId != null && traceParentId > 0) {
+                if (!visited.add(traceParentId)) {
+                    throw new ServiceException("绉戠洰灞傜骇瀛樺湪寰幆寮曠敤锛岃妫�鏌ョ埗绉戠洰璁剧疆");
+                }
+                if (traceParentId.equals(currentId)) {
+                    throw new ServiceException("鐖剁鐩笉鑳芥槸褰撳墠绉戠洰鎴栧叾瀛愮鐩�");
+                }
+                AccountSubject traceNode = getById(traceParentId);
+                if (traceNode == null) {
+                    break;
+                }
+                traceParentId = traceNode.getParentId();
+            }
+        }
+    }
+
+    private Map<Long, List<Long>> buildChildrenIdMap(List<AccountSubject> subjects) {
+        Map<Long, List<Long>> map = new HashMap<>();
+        for (AccountSubject subject : subjects) {
+            if (subject.getId() == null || subject.getParentId() == null || subject.getParentId() <= 0) {
+                continue;
+            }
+            map.computeIfAbsent(subject.getParentId(), key -> new ArrayList<>()).add(subject.getId());
+        }
+        return map;
+    }
+
+    /**
+     * 鏀堕泦寰呭垹闄よ妭鐐瑰強鍏舵墍鏈夊瓙瀛欒妭鐐广��
+     */
+    private void collectDescendantIds(Long id, Map<Long, List<Long>> childrenIdMap, Set<Long> result) {
+        if (id == null || !result.add(id)) {
+            return;
+        }
+        List<Long> children = childrenIdMap.getOrDefault(id, Collections.emptyList());
+        for (Long childId : children) {
+            collectDescendantIds(childId, childrenIdMap, result);
+        }
+    }
 }
diff --git a/src/main/java/com/ruoyi/account/service/impl/financial/FinFixedAssetServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/financial/FinFixedAssetServiceImpl.java
new file mode 100644
index 0000000..cb7a476
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/financial/FinFixedAssetServiceImpl.java
@@ -0,0 +1,231 @@
+package com.ruoyi.account.service.impl.financial;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.account.bean.dto.financial.FinFixedAssetDto;
+import com.ruoyi.account.mapper.financial.FinFixedAssetMapper;
+import com.ruoyi.account.pojo.financial.FinFixedAsset;
+import com.ruoyi.account.service.financial.FinFixedAssetService;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+
+/**
+ * 鍥哄畾璧勪骇鏈嶅姟瀹炵幇銆�
+ */
+@Service
+@RequiredArgsConstructor
+public class FinFixedAssetServiceImpl extends ServiceImpl<FinFixedAssetMapper, FinFixedAsset> implements FinFixedAssetService {
+
+    private static final BigDecimal ONE_HUNDRED = new BigDecimal("100");
+    private static final BigDecimal ZERO = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
+    private static final DateTimeFormatter CODE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
+
+    @Override
+    public IPage<FinFixedAsset> pageList(Page<FinFixedAsset> page, FinFixedAssetDto queryDto) {
+        LambdaQueryWrapper<FinFixedAsset> wrapper = new LambdaQueryWrapper<>();
+        if (queryDto != null && StringUtils.isNotEmpty(queryDto.getAssetCode())) {
+            wrapper.like(FinFixedAsset::getAssetCode, queryDto.getAssetCode());
+        }
+        if (queryDto != null && StringUtils.isNotEmpty(queryDto.getAssetName())) {
+            wrapper.like(FinFixedAsset::getAssetName, queryDto.getAssetName());
+        }
+        if (queryDto != null && StringUtils.isNotEmpty(queryDto.getCategory())) {
+            wrapper.eq(FinFixedAsset::getCategory, queryDto.getCategory());
+        }
+        if (queryDto != null && StringUtils.isNotEmpty(queryDto.getStatus())) {
+            wrapper.eq(FinFixedAsset::getStatus, queryDto.getStatus());
+        }
+        wrapper.orderByDesc(FinFixedAsset::getId);
+        return page(page, wrapper);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean add(FinFixedAssetDto dto) {
+        validateForSave(dto, false);
+        if (StringUtils.isEmpty(dto.getAssetCode())) {
+            dto.setAssetCode(generateAssetCode());
+        }
+        BigDecimal residualRate = normalizeResidualRate(dto.getResidualRate());
+        dto.setResidualRate(residualRate);
+        BigDecimal accumulatedDepreciation = defaultMoney(dto.getAccumulatedDepreciation());
+        dto.setAccumulatedDepreciation(accumulatedDepreciation);
+        dto.setNetValue(calculateNetValue(dto.getOriginalValue(), accumulatedDepreciation));
+        if (StringUtils.isEmpty(dto.getStatus())) {
+            dto.setStatus("in_use");
+        }
+        return save(dto);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean update(FinFixedAssetDto dto) {
+        if (dto == null || dto.getId() == null) {
+            throw new ServiceException("淇敼澶辫触锛岃祫浜D涓嶈兘涓虹┖");
+        }
+        FinFixedAsset existed = getById(dto.getId());
+        if (existed == null) {
+            throw new ServiceException("淇敼澶辫触锛屽浐瀹氳祫浜т笉瀛樺湪");
+        }
+        if (StringUtils.isEmpty(dto.getAssetCode())) {
+            dto.setAssetCode(existed.getAssetCode());
+        }
+        if (StringUtils.isEmpty(dto.getStatus())) {
+            dto.setStatus(existed.getStatus());
+        }
+        validateForSave(dto, true);
+        BigDecimal residualRate = normalizeResidualRate(dto.getResidualRate());
+        dto.setResidualRate(residualRate);
+        if (dto.getAccumulatedDepreciation() == null) {
+            dto.setAccumulatedDepreciation(defaultMoney(existed.getAccumulatedDepreciation()));
+        }
+        dto.setNetValue(calculateNetValue(dto.getOriginalValue(), dto.getAccumulatedDepreciation()));
+        return updateById(dto);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean deleteByIds(List<Long> ids) {
+        if (ids == null || ids.isEmpty()) {
+            throw new ServiceException("鍒犻櫎澶辫触锛岃閫夋嫨瑕佸垹闄ょ殑鏁版嵁");
+        }
+        return removeByIds(ids);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Map<String, Object> depreciate(List<Long> ids) {
+        LambdaQueryWrapper<FinFixedAsset> wrapper = new LambdaQueryWrapper<>();
+        if (ids != null && !ids.isEmpty()) {
+            wrapper.in(FinFixedAsset::getId, ids);
+        } else {
+            wrapper.eq(FinFixedAsset::getStatus, "in_use");
+        }
+        List<FinFixedAsset> assets = list(wrapper);
+        BigDecimal totalMonthlyDepreciation = ZERO;
+        int processedCount = 0;
+        for (FinFixedAsset asset : assets) {
+            if (!"in_use".equals(asset.getStatus())) {
+                continue;
+            }
+            BigDecimal monthlyDepreciation = calculateMonthlyDepreciation(
+                    asset.getOriginalValue(),
+                    asset.getResidualRate(),
+                    asset.getUsefulLife()
+            );
+            BigDecimal accumulatedDepreciation = defaultMoney(asset.getAccumulatedDepreciation()).add(monthlyDepreciation);
+            if (accumulatedDepreciation.compareTo(defaultMoney(asset.getOriginalValue())) > 0) {
+                accumulatedDepreciation = defaultMoney(asset.getOriginalValue());
+            }
+            asset.setAccumulatedDepreciation(roundMoney(accumulatedDepreciation));
+            asset.setNetValue(calculateNetValue(asset.getOriginalValue(), asset.getAccumulatedDepreciation()));
+            updateById(asset);
+            processedCount++;
+            totalMonthlyDepreciation = totalMonthlyDepreciation.add(monthlyDepreciation);
+        }
+        Map<String, Object> result = new HashMap<>(4);
+        result.put("processedCount", processedCount);
+        result.put("totalMonthlyDepreciation", roundMoney(totalMonthlyDepreciation));
+        result.put("executionTime", LocalDateTime.now());
+        return result;
+    }
+
+    /**
+     * 鎸夋枃妗h鍒欐牎楠屽浐瀹氳祫浜ф暟鎹��
+     */
+    private void validateForSave(FinFixedAssetDto dto, boolean isUpdate) {
+        if (dto == null) {
+            throw new ServiceException("鍥哄畾璧勪骇鏁版嵁涓嶈兘涓虹┖");
+        }
+        if (isUpdate && dto.getId() == null) {
+            throw new ServiceException("淇敼澶辫触锛岃祫浜D涓嶈兘涓虹┖");
+        }
+        if (StringUtils.isEmpty(dto.getAssetName())) {
+            throw new ServiceException("璧勪骇鍚嶇О涓嶈兘涓虹┖");
+        }
+        if (StringUtils.isEmpty(dto.getCategory())) {
+            throw new ServiceException("璧勪骇绫诲埆涓嶈兘涓虹┖");
+        }
+        if (dto.getPurchaseDate() == null) {
+            throw new ServiceException("璐疆鏃ユ湡涓嶈兘涓虹┖");
+        }
+        if (dto.getOriginalValue() == null || dto.getOriginalValue().compareTo(BigDecimal.ZERO) < 0) {
+            throw new ServiceException("璧勪骇鍘熷�间笉鑳戒负绌轰笖涓嶈兘灏忎簬0");
+        }
+        if (dto.getUsefulLife() == null || dto.getUsefulLife() <= 0) {
+            throw new ServiceException("浣跨敤骞撮檺蹇呴』澶т簬0");
+        }
+        if (dto.getResidualRate() != null && dto.getResidualRate().compareTo(BigDecimal.ZERO) < 0) {
+            throw new ServiceException("娈嬪�肩巼涓嶈兘灏忎簬0");
+        }
+        if (dto.getResidualRate() != null && dto.getResidualRate().compareTo(ONE_HUNDRED) > 0) {
+            throw new ServiceException("娈嬪�肩巼涓嶈兘澶т簬100%");
+        }
+        if (StringUtils.isNotEmpty(dto.getAssetCode())) {
+            LambdaQueryWrapper<FinFixedAsset> wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(FinFixedAsset::getAssetCode, dto.getAssetCode());
+            if (isUpdate) {
+                wrapper.ne(FinFixedAsset::getId, dto.getId());
+            }
+            if (count(wrapper) > 0) {
+                throw new ServiceException("璧勪骇缂栧彿宸插瓨鍦紝璇峰嬁閲嶅鎻愪氦");
+            }
+        }
+    }
+
+    /**
+     * 鍥哄畾璧勪骇鎶樻棫鍏紡锛�
+     * monthlyDepreciation = originalValue * (1 - residualRate/100) / (usefulLife*12)
+     */
+    private BigDecimal calculateMonthlyDepreciation(BigDecimal originalValue, BigDecimal residualRate, Integer usefulLife) {
+        BigDecimal normalizedOriginalValue = defaultMoney(originalValue);
+        BigDecimal normalizedResidualRate = normalizeResidualRate(residualRate);
+        BigDecimal depreciableRatio = BigDecimal.ONE.subtract(normalizedResidualRate.divide(ONE_HUNDRED, 8, RoundingMode.HALF_UP));
+        BigDecimal months = BigDecimal.valueOf((long) usefulLife * 12L);
+        if (months.compareTo(BigDecimal.ZERO) <= 0) {
+            throw new ServiceException("浣跨敤骞撮檺鏃犳晥锛屾棤娉曡鎻愭姌鏃�");
+        }
+        return roundMoney(normalizedOriginalValue.multiply(depreciableRatio).divide(months, 8, RoundingMode.HALF_UP));
+    }
+
+    /**
+     * 鍑�鍊� = 鍘熷�� - 绱鎶樻棫銆�
+     */
+    private BigDecimal calculateNetValue(BigDecimal originalValue, BigDecimal accumulatedDepreciation) {
+        BigDecimal value = defaultMoney(originalValue).subtract(defaultMoney(accumulatedDepreciation));
+        if (value.compareTo(BigDecimal.ZERO) < 0) {
+            value = BigDecimal.ZERO;
+        }
+        return roundMoney(value);
+    }
+
+    private BigDecimal normalizeResidualRate(BigDecimal residualRate) {
+        return residualRate == null ? BigDecimal.ZERO : residualRate;
+    }
+
+    private BigDecimal defaultMoney(BigDecimal value) {
+        return value == null ? ZERO : roundMoney(value);
+    }
+
+    private BigDecimal roundMoney(BigDecimal value) {
+        if (value == null) {
+            return ZERO;
+        }
+        return value.setScale(2, RoundingMode.HALF_UP);
+    }
+
+    private String generateAssetCode() {
+        return "GD" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10);
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/service/impl/financial/FinIntangibleAssetServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/financial/FinIntangibleAssetServiceImpl.java
new file mode 100644
index 0000000..72e5f06
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/financial/FinIntangibleAssetServiceImpl.java
@@ -0,0 +1,250 @@
+package com.ruoyi.account.service.impl.financial;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.account.bean.dto.financial.FinIntangibleAssetDto;
+import com.ruoyi.account.mapper.financial.FinIntangibleAssetMapper;
+import com.ruoyi.account.pojo.financial.FinIntangibleAsset;
+import com.ruoyi.account.service.financial.FinIntangibleAssetService;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+
+/**
+ * 鏃犲舰璧勪骇鏈嶅姟瀹炵幇銆�
+ */
+@Service
+@RequiredArgsConstructor
+public class FinIntangibleAssetServiceImpl extends ServiceImpl<FinIntangibleAssetMapper, FinIntangibleAsset> implements FinIntangibleAssetService {
+
+    private static final BigDecimal ONE_HUNDRED = new BigDecimal("100");
+    private static final BigDecimal ZERO = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
+    private static final DateTimeFormatter CODE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
+
+    @Override
+    public IPage<FinIntangibleAsset> pageList(Page<FinIntangibleAsset> page, FinIntangibleAssetDto queryDto) {
+        LambdaQueryWrapper<FinIntangibleAsset> wrapper = new LambdaQueryWrapper<>();
+        if (queryDto != null && StringUtils.isNotEmpty(queryDto.getAssetCode())) {
+            wrapper.like(FinIntangibleAsset::getAssetCode, queryDto.getAssetCode());
+        }
+        if (queryDto != null && StringUtils.isNotEmpty(queryDto.getAssetName())) {
+            wrapper.like(FinIntangibleAsset::getAssetName, queryDto.getAssetName());
+        }
+        if (queryDto != null && StringUtils.isNotEmpty(queryDto.getCategory())) {
+            wrapper.eq(FinIntangibleAsset::getCategory, queryDto.getCategory());
+        }
+        if (queryDto != null && StringUtils.isNotEmpty(queryDto.getStatus())) {
+            wrapper.eq(FinIntangibleAsset::getStatus, queryDto.getStatus());
+        }
+        wrapper.orderByDesc(FinIntangibleAsset::getId);
+        return page(page, wrapper);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean add(FinIntangibleAssetDto dto) {
+        validateForSave(dto, false);
+        if (StringUtils.isEmpty(dto.getAssetCode())) {
+            dto.setAssetCode(generateAssetCode());
+        }
+        BigDecimal residualRate = normalizeResidualRate(dto.getResidualRate());
+        dto.setResidualRate(residualRate);
+        BigDecimal accumulatedAmortization = defaultMoney(dto.getAccumulatedAmortization());
+        dto.setAccumulatedAmortization(accumulatedAmortization);
+        dto.setNetValue(calculateNetValue(dto.getOriginalValue(), accumulatedAmortization));
+        if (StringUtils.isEmpty(dto.getStatus())) {
+            dto.setStatus("in_use");
+        }
+        return save(dto);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean update(FinIntangibleAssetDto dto) {
+        if (dto == null || dto.getId() == null) {
+            throw new ServiceException("淇敼澶辫触锛岃祫浜D涓嶈兘涓虹┖");
+        }
+        FinIntangibleAsset existed = getById(dto.getId());
+        if (existed == null) {
+            throw new ServiceException("淇敼澶辫触锛屾棤褰㈣祫浜т笉瀛樺湪");
+        }
+        if (StringUtils.isEmpty(dto.getAssetCode())) {
+            dto.setAssetCode(existed.getAssetCode());
+        }
+        if (StringUtils.isEmpty(dto.getStatus())) {
+            dto.setStatus(existed.getStatus());
+        }
+        validateForSave(dto, true);
+        BigDecimal residualRate = normalizeResidualRate(dto.getResidualRate());
+        dto.setResidualRate(residualRate);
+        if (dto.getAccumulatedAmortization() == null) {
+            dto.setAccumulatedAmortization(defaultMoney(existed.getAccumulatedAmortization()));
+        }
+        dto.setNetValue(calculateNetValue(dto.getOriginalValue(), dto.getAccumulatedAmortization()));
+        if (dto.getNetValue().compareTo(BigDecimal.ZERO) <= 0) {
+            dto.setStatus("amortized");
+        } else if ("amortized".equals(dto.getStatus())) {
+            dto.setStatus("in_use");
+        }
+        if (dto.getValidityDate() != null
+                && dto.getValidityDate().isBefore(LocalDate.now())
+                && !"amortized".equals(dto.getStatus())) {
+            dto.setStatus("expired");
+        }
+        return updateById(dto);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean deleteByIds(List<Long> ids) {
+        if (ids == null || ids.isEmpty()) {
+            throw new ServiceException("鍒犻櫎澶辫触锛岃閫夋嫨瑕佸垹闄ょ殑鏁版嵁");
+        }
+        return removeByIds(ids);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Map<String, Object> amortize(List<Long> ids) {
+        LambdaQueryWrapper<FinIntangibleAsset> wrapper = new LambdaQueryWrapper<>();
+        if (ids != null && !ids.isEmpty()) {
+            wrapper.in(FinIntangibleAsset::getId, ids);
+        } else {
+            wrapper.eq(FinIntangibleAsset::getStatus, "in_use");
+        }
+        List<FinIntangibleAsset> assets = list(wrapper);
+        BigDecimal totalMonthlyAmortization = ZERO;
+        int processedCount = 0;
+        for (FinIntangibleAsset asset : assets) {
+            if (!"in_use".equals(asset.getStatus())) {
+                continue;
+            }
+            BigDecimal monthlyAmortization = calculateMonthlyAmortization(
+                    asset.getOriginalValue(),
+                    asset.getResidualRate(),
+                    asset.getAmortizationPeriod()
+            );
+            BigDecimal accumulatedAmortization = defaultMoney(asset.getAccumulatedAmortization()).add(monthlyAmortization);
+            if (accumulatedAmortization.compareTo(defaultMoney(asset.getOriginalValue())) > 0) {
+                accumulatedAmortization = defaultMoney(asset.getOriginalValue());
+            }
+            asset.setAccumulatedAmortization(roundMoney(accumulatedAmortization));
+            asset.setNetValue(calculateNetValue(asset.getOriginalValue(), asset.getAccumulatedAmortization()));
+
+            // 瑙勫垯锛氬綋鍑�鍊� <= 0 鏃讹紝鍑�鍊煎綊闆跺苟鏍囪涓哄凡鎽婇攢瀹屻��
+            if (asset.getNetValue().compareTo(BigDecimal.ZERO) <= 0) {
+                asset.setNetValue(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP));
+                asset.setStatus("amortized");
+            } else if (asset.getValidityDate() != null && asset.getValidityDate().isBefore(LocalDate.now())) {
+                asset.setStatus("expired");
+            }
+            updateById(asset);
+            processedCount++;
+            totalMonthlyAmortization = totalMonthlyAmortization.add(monthlyAmortization);
+        }
+        Map<String, Object> result = new HashMap<>(4);
+        result.put("processedCount", processedCount);
+        result.put("totalMonthlyAmortization", roundMoney(totalMonthlyAmortization));
+        result.put("executionTime", LocalDateTime.now());
+        return result;
+    }
+
+    /**
+     * 鎸夋枃妗h鍒欐牎楠屾棤褰㈣祫浜ф暟鎹��
+     */
+    private void validateForSave(FinIntangibleAssetDto dto, boolean isUpdate) {
+        if (dto == null) {
+            throw new ServiceException("鏃犲舰璧勪骇鏁版嵁涓嶈兘涓虹┖");
+        }
+        if (isUpdate && dto.getId() == null) {
+            throw new ServiceException("淇敼澶辫触锛岃祫浜D涓嶈兘涓虹┖");
+        }
+        if (StringUtils.isEmpty(dto.getAssetName())) {
+            throw new ServiceException("璧勪骇鍚嶇О涓嶈兘涓虹┖");
+        }
+        if (StringUtils.isEmpty(dto.getCategory())) {
+            throw new ServiceException("璧勪骇绫诲埆涓嶈兘涓虹┖");
+        }
+        if (dto.getAcquisitionDate() == null) {
+            throw new ServiceException("鍙栧緱鏃ユ湡涓嶈兘涓虹┖");
+        }
+        if (dto.getOriginalValue() == null || dto.getOriginalValue().compareTo(BigDecimal.ZERO) < 0) {
+            throw new ServiceException("璧勪骇鍘熷�间笉鑳戒负绌轰笖涓嶈兘灏忎簬0");
+        }
+        if (dto.getAmortizationPeriod() == null || dto.getAmortizationPeriod() <= 0) {
+            throw new ServiceException("鎽婇攢骞撮檺蹇呴』澶т簬0");
+        }
+        if (dto.getResidualRate() != null && dto.getResidualRate().compareTo(BigDecimal.ZERO) < 0) {
+            throw new ServiceException("娈嬪�肩巼涓嶈兘灏忎簬0");
+        }
+        if (dto.getResidualRate() != null && dto.getResidualRate().compareTo(ONE_HUNDRED) > 0) {
+            throw new ServiceException("娈嬪�肩巼涓嶈兘澶т簬100%");
+        }
+        if (StringUtils.isNotEmpty(dto.getAssetCode())) {
+            LambdaQueryWrapper<FinIntangibleAsset> wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(FinIntangibleAsset::getAssetCode, dto.getAssetCode());
+            if (isUpdate) {
+                wrapper.ne(FinIntangibleAsset::getId, dto.getId());
+            }
+            if (count(wrapper) > 0) {
+                throw new ServiceException("璧勪骇缂栧彿宸插瓨鍦紝璇峰嬁閲嶅鎻愪氦");
+            }
+        }
+    }
+
+    /**
+     * 鏃犲舰璧勪骇鎽婇攢鍏紡锛�
+     * monthlyAmortization = originalValue * (1 - residualRate/100) / (amortizationPeriod*12)
+     */
+    private BigDecimal calculateMonthlyAmortization(BigDecimal originalValue, BigDecimal residualRate, Integer amortizationPeriod) {
+        BigDecimal normalizedOriginalValue = defaultMoney(originalValue);
+        BigDecimal normalizedResidualRate = normalizeResidualRate(residualRate);
+        BigDecimal amortizableRatio = BigDecimal.ONE.subtract(normalizedResidualRate.divide(ONE_HUNDRED, 8, RoundingMode.HALF_UP));
+        BigDecimal months = BigDecimal.valueOf((long) amortizationPeriod * 12L);
+        if (months.compareTo(BigDecimal.ZERO) <= 0) {
+            throw new ServiceException("鎽婇攢骞撮檺鏃犳晥锛屾棤娉曡鎻愭憡閿�");
+        }
+        return roundMoney(normalizedOriginalValue.multiply(amortizableRatio).divide(months, 8, RoundingMode.HALF_UP));
+    }
+
+    /**
+     * 鍑�鍊� = 鍘熷�� - 绱鎽婇攢銆�
+     */
+    private BigDecimal calculateNetValue(BigDecimal originalValue, BigDecimal accumulatedAmortization) {
+        BigDecimal value = defaultMoney(originalValue).subtract(defaultMoney(accumulatedAmortization));
+        if (value.compareTo(BigDecimal.ZERO) < 0) {
+            value = BigDecimal.ZERO;
+        }
+        return roundMoney(value);
+    }
+
+    private BigDecimal normalizeResidualRate(BigDecimal residualRate) {
+        return residualRate == null ? BigDecimal.ZERO : residualRate;
+    }
+
+    private BigDecimal defaultMoney(BigDecimal value) {
+        return value == null ? ZERO : roundMoney(value);
+    }
+
+    private BigDecimal roundMoney(BigDecimal value) {
+        if (value == null) {
+            return ZERO;
+        }
+        return value.setScale(2, RoundingMode.HALF_UP);
+    }
+
+    private String generateAssetCode() {
+        return "WX" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10);
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/service/impl/financial/FinLedgerServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/financial/FinLedgerServiceImpl.java
new file mode 100644
index 0000000..a489c67
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/financial/FinLedgerServiceImpl.java
@@ -0,0 +1,206 @@
+package com.ruoyi.account.service.impl.financial;
+
+import com.ruoyi.account.bean.dto.financial.FinDetailLedgerQueryDto;
+import com.ruoyi.account.bean.dto.financial.FinLedgerQueryDto;
+import com.ruoyi.account.bean.vo.financial.FinLedgerEntryRecordVo;
+import com.ruoyi.account.bean.vo.financial.FinLedgerRowVo;
+import com.ruoyi.account.mapper.financial.FinVoucherEntryMapper;
+import com.ruoyi.account.service.financial.FinLedgerService;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.time.YearMonth;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.*;
+
+/**
+ * 绉戠洰鎬昏处/鏄庣粏璐︽湇鍔″疄鐜般��
+ */
+@Service
+@RequiredArgsConstructor
+public class FinLedgerServiceImpl implements FinLedgerService {
+
+    private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM");
+    private static final BigDecimal ZERO = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
+
+    private final FinVoucherEntryMapper finVoucherEntryMapper;
+
+    @Override
+    public List<FinLedgerRowVo> queryGeneralLedger(FinLedgerQueryDto queryDto) {
+        if (queryDto == null || StringUtils.isEmpty(queryDto.getSubjectCode())) {
+            return Collections.emptyList();
+        }
+        YearMonth startMonth = parseMonth(queryDto.getStartMonth(), "寮�濮嬫湀浠�");
+        YearMonth endMonth = parseMonth(queryDto.getEndMonth(), "缁撴潫鏈堜唤");
+        if (startMonth.isAfter(endMonth)) {
+            throw new ServiceException("寮�濮嬫湀浠戒笉鑳藉ぇ浜庣粨鏉熸湀浠�");
+        }
+        return buildLedgerRows(queryDto.getSubjectCode(), startMonth, endMonth, null, null);
+    }
+
+    @Override
+    public List<FinLedgerRowVo> queryDetailLedger(FinDetailLedgerQueryDto queryDto) {
+        if (queryDto == null || StringUtils.isEmpty(queryDto.getSubjectCode())) {
+            return Collections.emptyList();
+        }
+        YearMonth startMonth = parseMonth(queryDto.getStartMonth(), "寮�濮嬫湀浠�");
+        YearMonth endMonth = parseMonth(queryDto.getEndMonth(), "缁撴潫鏈堜唤");
+        if (startMonth.isAfter(endMonth)) {
+            throw new ServiceException("寮�濮嬫湀浠戒笉鑳藉ぇ浜庣粨鏉熸湀浠�");
+        }
+        return buildLedgerRows(queryDto.getSubjectCode(), startMonth, endMonth, queryDto.getAuxiliaryType(), queryDto.getAuxiliaryId());
+    }
+
+    /**
+     * 鏋勫缓璐︾翱琛屾暟鎹紝杈撳嚭鏈熷垵銆佸垎褰曘�佹湰鏈堝悎璁°�佹湰骞寸疮璁°��
+     */
+    private List<FinLedgerRowVo> buildLedgerRows(String subjectCode,
+                                                 YearMonth startMonth,
+                                                 YearMonth endMonth,
+                                                 String auxiliaryType,
+                                                 String auxiliaryId) {
+        LocalDate startDate = startMonth.atDay(1);
+        LocalDate endDate = endMonth.atEndOfMonth();
+
+        List<FinLedgerEntryRecordVo> openingEntries = finVoucherEntryMapper.listPostedEntriesBefore(
+                subjectCode, startDate, auxiliaryType, auxiliaryId
+        );
+        BigDecimal openingBalance = calculateBalance(openingEntries);
+
+        List<FinLedgerEntryRecordVo> currentPeriodEntries = finVoucherEntryMapper.listPostedEntries(
+                subjectCode, startDate, endDate, auxiliaryType, auxiliaryId
+        );
+        Map<YearMonth, List<FinLedgerEntryRecordVo>> monthEntriesMap = groupEntriesByMonth(currentPeriodEntries);
+
+        List<FinLedgerRowVo> rows = new ArrayList<>();
+        BigDecimal runningBalance = openingBalance;
+        BigDecimal yearDebit = ZERO;
+        BigDecimal yearCredit = ZERO;
+
+        for (YearMonth month = startMonth; !month.isAfter(endMonth); month = month.plusMonths(1)) {
+            rows.add(buildOpeningRow(month.atDay(1), runningBalance));
+
+            List<FinLedgerEntryRecordVo> monthEntries = monthEntriesMap.getOrDefault(month, Collections.emptyList());
+            BigDecimal monthDebit = ZERO;
+            BigDecimal monthCredit = ZERO;
+            for (FinLedgerEntryRecordVo entry : monthEntries) {
+                BigDecimal debit = money(entry.getDebit());
+                BigDecimal credit = money(entry.getCredit());
+                runningBalance = runningBalance.add(debit).subtract(credit);
+                monthDebit = monthDebit.add(debit);
+                monthCredit = monthCredit.add(credit);
+
+                FinLedgerRowVo row = new FinLedgerRowVo();
+                row.setRowType("entry");
+                row.setDate(entry.getVoucherDate());
+                row.setVoucherNo(entry.getVoucherNo());
+                row.setSummary(StringUtils.isNotEmpty(entry.getSummary()) ? entry.getSummary() : "");
+                row.setDebit(debit);
+                row.setCredit(credit);
+                row.setBalance(money(runningBalance));
+                row.setDirection(resolveDirection(runningBalance));
+                rows.add(row);
+            }
+
+            rows.add(buildMonthlyTotalRow(month.atEndOfMonth(), monthDebit, monthCredit, runningBalance));
+            yearDebit = yearDebit.add(monthDebit);
+            yearCredit = yearCredit.add(monthCredit);
+        }
+
+        rows.add(buildYearlyTotalRow(endMonth.atEndOfMonth(), yearDebit, yearCredit, runningBalance));
+        return rows;
+    }
+
+    private Map<YearMonth, List<FinLedgerEntryRecordVo>> groupEntriesByMonth(List<FinLedgerEntryRecordVo> entries) {
+        Map<YearMonth, List<FinLedgerEntryRecordVo>> map = new LinkedHashMap<>();
+        for (FinLedgerEntryRecordVo entry : entries) {
+            if (entry.getVoucherDate() == null) {
+                continue;
+            }
+            YearMonth month = YearMonth.from(entry.getVoucherDate());
+            map.computeIfAbsent(month, key -> new ArrayList<>()).add(entry);
+        }
+        return map;
+    }
+
+    private FinLedgerRowVo buildOpeningRow(LocalDate date, BigDecimal openingBalance) {
+        FinLedgerRowVo row = new FinLedgerRowVo();
+        row.setRowType("opening");
+        row.setDate(date);
+        row.setVoucherNo("-");
+        row.setSummary("鏈熷垵浣欓");
+        row.setDebit(ZERO);
+        row.setCredit(ZERO);
+        row.setBalance(money(openingBalance));
+        row.setDirection(resolveDirection(openingBalance));
+        return row;
+    }
+
+    private FinLedgerRowVo buildMonthlyTotalRow(LocalDate date,
+                                                BigDecimal monthDebit,
+                                                BigDecimal monthCredit,
+                                                BigDecimal monthBalance) {
+        FinLedgerRowVo row = new FinLedgerRowVo();
+        row.setRowType("monthly_total");
+        row.setDate(date);
+        row.setVoucherNo("-");
+        row.setSummary("鏈湀鍚堣");
+        row.setDebit(money(monthDebit));
+        row.setCredit(money(monthCredit));
+        row.setBalance(money(monthBalance));
+        row.setDirection(resolveDirection(monthBalance));
+        return row;
+    }
+
+    private FinLedgerRowVo buildYearlyTotalRow(LocalDate date,
+                                               BigDecimal yearDebit,
+                                               BigDecimal yearCredit,
+                                               BigDecimal yearBalance) {
+        FinLedgerRowVo row = new FinLedgerRowVo();
+        row.setRowType("yearly_total");
+        row.setDate(date);
+        row.setVoucherNo("-");
+        row.setSummary("鍚堣");
+        row.setDebit(money(yearDebit));
+        row.setCredit(money(yearCredit));
+        row.setBalance(money(yearBalance));
+        row.setDirection(resolveDirection(yearBalance));
+        return row;
+    }
+
+    private BigDecimal calculateBalance(List<FinLedgerEntryRecordVo> entries) {
+        BigDecimal balance = ZERO;
+        for (FinLedgerEntryRecordVo entry : entries) {
+            balance = balance.add(money(entry.getDebit())).subtract(money(entry.getCredit()));
+        }
+        return money(balance);
+    }
+
+    private String resolveDirection(BigDecimal balance) {
+        return money(balance).compareTo(BigDecimal.ZERO) >= 0 ? "鍊�" : "璐�";
+    }
+
+    private YearMonth parseMonth(String value, String fieldLabel) {
+        if (StringUtils.isEmpty(value)) {
+            throw new ServiceException(fieldLabel + "涓嶈兘涓虹┖锛屾牸寮忓簲涓篩YYY-MM");
+        }
+        try {
+            return YearMonth.parse(value, MONTH_FORMATTER);
+        } catch (DateTimeParseException ex) {
+            throw new ServiceException(fieldLabel + "鏍煎紡閿欒锛屾牸寮忓簲涓篩YYY-MM");
+        }
+    }
+
+    private BigDecimal money(BigDecimal value) {
+        if (value == null) {
+            return ZERO;
+        }
+        return value.setScale(2, RoundingMode.HALF_UP);
+    }
+}
diff --git a/src/main/java/com/ruoyi/account/service/impl/financial/FinVoucherServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/financial/FinVoucherServiceImpl.java
new file mode 100644
index 0000000..9e09020
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/financial/FinVoucherServiceImpl.java
@@ -0,0 +1,299 @@
+package com.ruoyi.account.service.impl.financial;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.account.bean.dto.financial.FinVoucherDto;
+import com.ruoyi.account.bean.dto.financial.FinVoucherEntryDto;
+import com.ruoyi.account.bean.dto.financial.FinVoucherPageDto;
+import com.ruoyi.account.bean.vo.financial.FinVoucherDetailVo;
+import com.ruoyi.account.mapper.AccountSubjectMapper;
+import com.ruoyi.account.mapper.financial.FinVoucherEntryMapper;
+import com.ruoyi.account.mapper.financial.FinVoucherMapper;
+import com.ruoyi.account.pojo.AccountSubject;
+import com.ruoyi.account.pojo.financial.FinVoucher;
+import com.ruoyi.account.pojo.financial.FinVoucherEntry;
+import com.ruoyi.account.service.financial.FinVoucherService;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 鍑瘉鏈嶅姟瀹炵幇銆�
+ */
+@Service
+@RequiredArgsConstructor
+public class FinVoucherServiceImpl extends ServiceImpl<FinVoucherMapper, FinVoucher> implements FinVoucherService {
+
+    private static final BigDecimal ZERO = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
+
+    private final FinVoucherEntryMapper finVoucherEntryMapper;
+    private final AccountSubjectMapper accountSubjectMapper;
+
+    @Override
+    public IPage<FinVoucher> pageList(Page<FinVoucher> page, FinVoucherPageDto queryDto) {
+        LambdaQueryWrapper<FinVoucher> wrapper = new LambdaQueryWrapper<>();
+        if (queryDto != null && StringUtils.isNotEmpty(queryDto.getVoucherNo())) {
+            wrapper.like(FinVoucher::getVoucherNo, queryDto.getVoucherNo());
+        }
+        if (queryDto != null && StringUtils.isNotEmpty(queryDto.getCreator())) {
+            wrapper.eq(FinVoucher::getCreator, queryDto.getCreator());
+        }
+        if (queryDto != null && StringUtils.isNotEmpty(queryDto.getStatus())) {
+            wrapper.eq(FinVoucher::getStatus, queryDto.getStatus());
+        }
+        if (queryDto != null && queryDto.getStartDate() != null) {
+            wrapper.ge(FinVoucher::getVoucherDate, queryDto.getStartDate());
+        }
+        if (queryDto != null && queryDto.getEndDate() != null) {
+            wrapper.le(FinVoucher::getVoucherDate, queryDto.getEndDate());
+        }
+        wrapper.orderByDesc(FinVoucher::getVoucherDate).orderByDesc(FinVoucher::getId);
+        return page(page, wrapper);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean addVoucher(FinVoucherDto dto) {
+        validateVoucherBasicInfo(dto, false);
+        List<FinVoucherEntry> validEntries = buildAndValidateEntries(dto);
+
+        FinVoucher voucher = new FinVoucher();
+        BeanUtils.copyProperties(dto, voucher);
+        voucher.setStatus("unposted");
+        voucher.setAttachmentCount(voucher.getAttachmentCount() == null ? 0 : voucher.getAttachmentCount());
+        BigDecimal totalDebit = calculateTotalDebit(validEntries);
+        BigDecimal totalCredit = calculateTotalCredit(validEntries);
+        voucher.setDebit(totalDebit);
+        voucher.setCredit(totalCredit);
+        if (StringUtils.isEmpty(voucher.getSummary())) {
+            voucher.setSummary(findDefaultSummary(validEntries));
+        }
+        save(voucher);
+        saveEntries(voucher.getId(), validEntries);
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean updateVoucher(FinVoucherDto dto) {
+        validateVoucherBasicInfo(dto, true);
+        FinVoucher existed = getById(dto.getId());
+        if (existed == null) {
+            throw new ServiceException("淇敼澶辫触锛屽嚟璇佷笉瀛樺湪");
+        }
+        if (!"unposted".equals(existed.getStatus())) {
+            throw new ServiceException("浠呮湭杩囪处鍑瘉鍏佽淇敼");
+        }
+        List<FinVoucherEntry> validEntries = buildAndValidateEntries(dto);
+
+        FinVoucher voucher = new FinVoucher();
+        BeanUtils.copyProperties(dto, voucher);
+        voucher.setStatus(existed.getStatus());
+        voucher.setAttachmentCount(voucher.getAttachmentCount() == null ? 0 : voucher.getAttachmentCount());
+        BigDecimal totalDebit = calculateTotalDebit(validEntries);
+        BigDecimal totalCredit = calculateTotalCredit(validEntries);
+        voucher.setDebit(totalDebit);
+        voucher.setCredit(totalCredit);
+        if (StringUtils.isEmpty(voucher.getSummary())) {
+            voucher.setSummary(findDefaultSummary(validEntries));
+        }
+        updateById(voucher);
+
+        LambdaQueryWrapper<FinVoucherEntry> deleteWrapper = new LambdaQueryWrapper<>();
+        deleteWrapper.eq(FinVoucherEntry::getVoucherId, voucher.getId());
+        finVoucherEntryMapper.delete(deleteWrapper);
+        saveEntries(voucher.getId(), validEntries);
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean postVoucher(Long id) {
+        FinVoucher voucher = getById(id);
+        if (voucher == null) {
+            throw new ServiceException("杩囪处澶辫触锛屽嚟璇佷笉瀛樺湪");
+        }
+        if (!"unposted".equals(voucher.getStatus())) {
+            throw new ServiceException("浠呮湭杩囪处鍑瘉鍏佽杩囪处");
+        }
+        voucher.setStatus("posted");
+        return updateById(voucher);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean cancelVoucher(Long id) {
+        FinVoucher voucher = getById(id);
+        if (voucher == null) {
+            throw new ServiceException("浣滃簾澶辫触锛屽嚟璇佷笉瀛樺湪");
+        }
+        if (!"unposted".equals(voucher.getStatus())) {
+            throw new ServiceException("浠呮湭杩囪处鍑瘉鍏佽浣滃簾");
+        }
+        voucher.setStatus("cancelled");
+        return updateById(voucher);
+    }
+
+    @Override
+    public FinVoucherDetailVo detail(Long id) {
+        FinVoucher voucher = getById(id);
+        if (voucher == null) {
+            throw new ServiceException("鏌ヨ澶辫触锛屽嚟璇佷笉瀛樺湪");
+        }
+        LambdaQueryWrapper<FinVoucherEntry> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(FinVoucherEntry::getVoucherId, id)
+                .orderByAsc(FinVoucherEntry::getRowNo)
+                .orderByAsc(FinVoucherEntry::getId);
+        List<FinVoucherEntry> entries = finVoucherEntryMapper.selectList(wrapper);
+
+        FinVoucherDetailVo vo = new FinVoucherDetailVo();
+        BeanUtils.copyProperties(voucher, vo);
+        vo.setEntries(entries);
+        return vo;
+    }
+
+    /**
+     * 鏍¢獙鍑瘉涓昏〃瀛楁銆佺姸鎬佸瓧娈典笌鍞竴鎬с��
+     */
+    private void validateVoucherBasicInfo(FinVoucherDto dto, boolean isUpdate) {
+        if (dto == null) {
+            throw new ServiceException("鍑瘉鏁版嵁涓嶈兘涓虹┖");
+        }
+        if (isUpdate && dto.getId() == null) {
+            throw new ServiceException("淇敼澶辫触锛屽嚟璇両D涓嶈兘涓虹┖");
+        }
+        if (StringUtils.isEmpty(dto.getVoucherNo())) {
+            throw new ServiceException("鍑瘉瀛楀彿涓嶈兘涓虹┖");
+        }
+        if (dto.getVoucherDate() == null) {
+            throw new ServiceException("鍑瘉鏃ユ湡涓嶈兘涓虹┖");
+        }
+        LambdaQueryWrapper<FinVoucher> uniqueWrapper = new LambdaQueryWrapper<>();
+        uniqueWrapper.eq(FinVoucher::getVoucherNo, dto.getVoucherNo());
+        if (isUpdate) {
+            uniqueWrapper.ne(FinVoucher::getId, dto.getId());
+        }
+        if (count(uniqueWrapper) > 0) {
+            throw new ServiceException("鍑瘉瀛楀彿宸插瓨鍦紝璇峰嬁閲嶅鎻愪氦");
+        }
+    }
+
+    /**
+     * 杩囨护鏈夋晥鍒嗗綍骞舵墽琛屽�熻捶骞宠 鏍¢獙銆�
+     */
+    private List<FinVoucherEntry> buildAndValidateEntries(FinVoucherDto dto) {
+        List<FinVoucherEntryDto> rawEntries = dto.getEntries();
+        if (rawEntries == null || rawEntries.isEmpty()) {
+            throw new ServiceException("鍒嗗綍涓嶈兘涓虹┖锛岃嚦灏戦渶瑕佷竴鏉℃湁鏁堝垎褰�");
+        }
+        List<FinVoucherEntry> validEntries = new ArrayList<>();
+        int rowNo = 1;
+        for (FinVoucherEntryDto entryDto : rawEntries) {
+            if (entryDto == null || StringUtils.isEmpty(entryDto.getSubjectCode())) {
+                continue;
+            }
+            BigDecimal debit = defaultMoney(entryDto.getDebit());
+            BigDecimal credit = defaultMoney(entryDto.getCredit());
+            if (debit.compareTo(BigDecimal.ZERO) <= 0 && credit.compareTo(BigDecimal.ZERO) <= 0) {
+                continue;
+            }
+            if (debit.compareTo(BigDecimal.ZERO) > 0 && credit.compareTo(BigDecimal.ZERO) > 0) {
+                throw new ServiceException("鍒嗗綍鍊熸柟鍜岃捶鏂逛笉鑳藉悓鏃跺ぇ浜�0");
+            }
+            FinVoucherEntry entry = new FinVoucherEntry();
+            BeanUtils.copyProperties(entryDto, entry);
+            entry.setDebit(debit);
+            entry.setCredit(credit);
+            entry.setRowNo(rowNo++);
+            validEntries.add(entry);
+        }
+        if (validEntries.isEmpty()) {
+            throw new ServiceException("鍒嗗綍鑷冲皯闇�瑕佷竴鏉℃湁鏁堣锛堢鐩笉绌猴紝涓斿�熸柟鎴栬捶鏂瑰ぇ浜�0锛�");
+        }
+
+        // 鍒嗗綍绉戠洰蹇呴』瀛樺湪锛岄伩鍏嶈剰绉戠洰缂栫爜鍏ヨ处銆�
+        Set<String> subjectCodes = validEntries.stream()
+                .map(FinVoucherEntry::getSubjectCode)
+                .filter(StringUtils::isNotEmpty)
+                .collect(Collectors.toSet());
+        if (subjectCodes.isEmpty()) {
+            throw new ServiceException("鍒嗗綍绉戠洰涓嶈兘涓虹┖");
+        }
+        LambdaQueryWrapper<AccountSubject> subjectWrapper = new LambdaQueryWrapper<>();
+        subjectWrapper.in(AccountSubject::getSubjectCode, subjectCodes);
+        List<AccountSubject> subjects = accountSubjectMapper.selectList(subjectWrapper);
+        Map<String, AccountSubject> subjectMap = subjects.stream()
+                .collect(Collectors.toMap(AccountSubject::getSubjectCode, it -> it, (a, b) -> a));
+        for (FinVoucherEntry entry : validEntries) {
+            AccountSubject accountSubject = subjectMap.get(entry.getSubjectCode());
+            if (accountSubject == null) {
+                throw new ServiceException("绉戠洰缂栫爜涓嶅瓨鍦細" + entry.getSubjectCode());
+            }
+            if (StringUtils.isEmpty(entry.getSubjectName())) {
+                entry.setSubjectName(accountSubject.getSubjectName());
+            }
+        }
+
+        BigDecimal totalDebit = calculateTotalDebit(validEntries);
+        BigDecimal totalCredit = calculateTotalCredit(validEntries);
+        if (totalDebit.compareTo(BigDecimal.ZERO) <= 0 || totalCredit.compareTo(BigDecimal.ZERO) <= 0) {
+            throw new ServiceException("鍊熻捶閲戦蹇呴』澶т簬0");
+        }
+        if (totalDebit.compareTo(totalCredit) != 0) {
+            throw new ServiceException("鍊熻捶涓嶅钩琛★紝绂佹淇濆瓨");
+        }
+        return validEntries;
+    }
+
+    private void saveEntries(Long voucherId, List<FinVoucherEntry> entries) {
+        if (voucherId == null) {
+            throw new ServiceException("鍑瘉ID涓嶈兘涓虹┖");
+        }
+        for (FinVoucherEntry entry : entries) {
+            entry.setVoucherId(voucherId);
+            finVoucherEntryMapper.insert(entry);
+        }
+    }
+
+    private String findDefaultSummary(List<FinVoucherEntry> entries) {
+        for (FinVoucherEntry entry : entries) {
+            if (StringUtils.isNotEmpty(entry.getSummary())) {
+                return entry.getSummary();
+            }
+        }
+        return "";
+    }
+
+    private BigDecimal calculateTotalDebit(List<FinVoucherEntry> entries) {
+        BigDecimal total = BigDecimal.ZERO;
+        for (FinVoucherEntry entry : entries) {
+            total = total.add(defaultMoney(entry.getDebit()));
+        }
+        return total.setScale(2, RoundingMode.HALF_UP);
+    }
+
+    private BigDecimal calculateTotalCredit(List<FinVoucherEntry> entries) {
+        BigDecimal total = BigDecimal.ZERO;
+        for (FinVoucherEntry entry : entries) {
+            total = total.add(defaultMoney(entry.getCredit()));
+        }
+        return total.setScale(2, RoundingMode.HALF_UP);
+    }
+
+    private BigDecimal defaultMoney(BigDecimal value) {
+        if (value == null) {
+            return ZERO;
+        }
+        return value.setScale(2, RoundingMode.HALF_UP);
+    }
+}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
index 2c5fda3..b0046d7 100644
--- a/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
@@ -15,6 +15,7 @@
 import com.ruoyi.basic.utils.FileUtil;
 import com.ruoyi.common.enums.FileNameType;
 import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
+import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.device.mapper.DeviceRepairMapper;
 import com.ruoyi.procurementrecord.utils.StockUtils;
@@ -31,14 +32,8 @@
 import com.ruoyi.quality.pojo.QualityInspectParam;
 import com.ruoyi.quality.pojo.QualityTestStandard;
 import com.ruoyi.quality.pojo.QualityTestStandardParam;
-import com.ruoyi.sales.mapper.CommonFileMapper;
-import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
-import com.ruoyi.sales.mapper.SalesQuotationMapper;
-import com.ruoyi.sales.mapper.ShippingInfoMapper;
-import com.ruoyi.sales.pojo.CommonFile;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
-import com.ruoyi.sales.pojo.SalesQuotation;
-import com.ruoyi.sales.pojo.ShippingInfo;
+import com.ruoyi.sales.mapper.*;
+import com.ruoyi.sales.pojo.*;
 import com.ruoyi.sales.service.impl.CommonFileServiceImpl;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
@@ -64,6 +59,7 @@
     private final PurchaseLedgerMapper purchaseLedgerMapper;
     private final SalesQuotationMapper salesQuotationMapper;
     private final ShippingInfoMapper shippingInfoMapper;
+    private final ShippingProductDetailMapper shippingProductDetailMapper;
     private final CommonFileServiceImpl commonFileService;
     private final StockUtils stockUtils;
     private final SalesLedgerProductMapper salesLedgerProductMapper;
@@ -183,7 +179,7 @@
                             addQualityInspect(purchaseLedger, salesLedgerProduct);
                         } else {
                             //鐩存帴鍏ュ簱
-                            stockUtils.addStockWithBatchNo(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(), purchaseLedger.getId(),purchaseLedger.getPurchaseContractNumber()+"-"+salesLedgerProduct.getId());
+                            stockUtils.addStockWithBatchNo(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(), purchaseLedger.getId(), purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId());
                         }
                     }
                 } else if (status.equals(3)) {
@@ -220,6 +216,9 @@
             if (shippingInfo != null) {
                 if (status.equals(2)) {
                     shippingInfo.setStatus("瀹℃牳閫氳繃");
+                    shippingInfo.setShippingDate(new Date());
+                    //鏇存敼鍑哄簱瀹℃牳鐘舵�侊紙寰呯‘璁ゆ敼鎴愬緟瀹℃牳锛�
+                    stockUtils.shipmentStatus(StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), shippingInfo.getId());
                 } else if (status.equals(3)) {
                     shippingInfo.setStatus("瀹℃牳鎷掔粷");
                 } else if (status.equals(1)) {
@@ -227,7 +226,6 @@
                 }
                 shippingInfoMapper.updateById(shippingInfo);
             }
-            //搴撳瓨鎵e噺
 
         }
         fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVE_NODE, approveNode.getId(), approveNode.getStorageBlobDTOS());
diff --git a/src/main/java/com/ruoyi/basic/controller/CustomerController.java b/src/main/java/com/ruoyi/basic/controller/CustomerController.java
index 9090d34..2130007 100644
--- a/src/main/java/com/ruoyi/basic/controller/CustomerController.java
+++ b/src/main/java/com/ruoyi/basic/controller/CustomerController.java
@@ -148,8 +148,8 @@
      * 绉佹捣瀹㈡埛娴佸洖鍏捣
      */
     @Log(title = "瀹㈡埛妗f", businessType = BusinessType.OTHER)
-    @PostMapping("/back")
-    public R back(Long id) {
+    @PostMapping("/back/{id}")
+    public R back(@PathVariable("id") Long id) {
         return R.ok(customerService.back(id));
     }
 }
diff --git a/src/main/java/com/ruoyi/basic/dto/StorageBlobVO.java b/src/main/java/com/ruoyi/basic/dto/StorageBlobVO.java
index 75eed4f..c9be475 100644
--- a/src/main/java/com/ruoyi/basic/dto/StorageBlobVO.java
+++ b/src/main/java/com/ruoyi/basic/dto/StorageBlobVO.java
@@ -10,6 +10,10 @@
      */
     private String previewURL;
 
+
+    private String url;
+    private String name;
+
     /**
      * 涓嬭浇鍦板潃
      */
diff --git a/src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java b/src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java
index d7d0649..9c63efb 100644
--- a/src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java
+++ b/src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java
@@ -132,10 +132,6 @@
     INBOUND_MANAGEMENT("inbound_management"),
     // Office Supplies
     OFFICE_SUPPLIES("office_supplies"),
-    // OA
-    OA_PROJECT_PHASE_TASK("oa_project_phase_task"),
-    OA_PROJECT("oa_project"),
-    OA_PROJECT_PHASE("oa_project_phase"),
     // Measuring Instrument Ledger
     SPARE_PARTS("spare_parts"),
     MEASURING_INSTRUMENT_LEDGER_RECORD("measuring_instrument_ledger_record"),
diff --git a/src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java b/src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java
index 36876d0..b245741 100644
--- a/src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java
+++ b/src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java
@@ -5,7 +5,7 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.basic.vo.ProductModelVo;
-import com.ruoyi.procurementrecord.dto.ProcurementPageDto;
+import com.ruoyi.procurementrecord.bean.dto.ProcurementPageDto;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
diff --git a/src/main/java/com/ruoyi/basic/pojo/ProductModel.java b/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
index f0e9470..8c0dc07 100644
--- a/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
+++ b/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
@@ -38,7 +38,6 @@
     private String model;
 
     @Excel(name = "浜у搧缂栫爜")
-    @TableField("product_code")
     private String productCode;
 
     /**
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 52d01ec..09c2a46 100644
--- a/src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
+++ b/src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
@@ -375,7 +375,7 @@
         //灏嗗鎴风殑type鏀逛负1 涓旂洿鎺ュ垎閰嶇粰褰撳墠鐢ㄦ埛
         Customer customer = customerMapper.selectById(id);
         customer.setType(1);
-        customer.setIsAssigned(1);
+        customer.setIsAssigned(0);
         return this.updateById(customer);
     }
 
diff --git a/src/main/java/com/ruoyi/basic/utils/FileUtil.java b/src/main/java/com/ruoyi/basic/utils/FileUtil.java
index c57468a..6ad5d77 100644
--- a/src/main/java/com/ruoyi/basic/utils/FileUtil.java
+++ b/src/main/java/com/ruoyi/basic/utils/FileUtil.java
@@ -98,8 +98,11 @@
         }
 
         // 鍒犻櫎鏃ч檮浠朵俊鎭�
-        if (application == null) {
+        if (application == null || application.trim().isEmpty()) {
             for (StorageBlobDTO storageBlobDTO : storageBlobDTOS) {
+                if (storageBlobDTO.getApplication() == null || storageBlobDTO.getApplication().trim().isEmpty()) {
+                    throw new RuntimeException("鏂囦欢鐢ㄩ�斾笉鑳戒负绌�");
+                }
                 deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum.getByType(storageBlobDTO.getApplication()), recordType, recordId);
             }
         } else {
@@ -344,6 +347,8 @@
             StorageBlobVO storageBlobVO = new StorageBlobVO();
             BeanUtils.copyProperties(storageBlob, storageBlobVO);
             storageBlobVO.setPreviewURL(buildSignedPreviewUrl(storageBlobVO));
+            storageBlobVO.setUrl(buildSignedPreviewUrl(storageBlobVO));
+            storageBlobVO.setName(storageBlob.getOriginalFilename());
             storageBlobVO.setDownloadURL(buildSignedDownloadUrl(storageBlobVO));
             storageBlobVO.setStorageAttachmentId(blobIdToAttachmentIdMap.get(storageBlob.getId()));
             storageBlobDTOS.add(storageBlobVO);
@@ -392,6 +397,8 @@
             StorageBlobVO storageBlobVO = new StorageBlobVO();
             BeanUtils.copyProperties(storageBlob, storageBlobVO);
             storageBlobVO.setPreviewURL(buildSignedPreviewUrl(storageBlobVO));
+            storageBlobVO.setUrl(buildSignedPreviewUrl(storageBlobVO));
+            storageBlobVO.setName(storageBlob.getOriginalFilename());
             storageBlobVO.setDownloadURL(buildSignedDownloadUrl(storageBlobVO));
             storageBlobVO.setStorageAttachmentId(blobIdToAttachmentIdMap.get(storageBlob.getId()));
             storageBlobDTOS.add(storageBlobVO);
@@ -417,6 +424,8 @@
             StorageBlobVO storageBlobVO = new StorageBlobVO();
             BeanUtils.copyProperties(storageBlob, storageBlobVO);
             storageBlobVO.setPreviewURL(buildSignedPreviewUrl(storageBlobVO));
+            storageBlobVO.setUrl(buildSignedPreviewUrl(storageBlobVO));
+            storageBlobVO.setName(storageBlob.getOriginalFilename());
             storageBlobVO.setDownloadURL(buildSignedDownloadUrl(storageBlobVO));
             storageBlobDTOS.add(storageBlobVO);
         }
diff --git a/src/main/java/com/ruoyi/common/enums/StockInQualifiedRecordTypeEnum.java b/src/main/java/com/ruoyi/common/enums/StockInQualifiedRecordTypeEnum.java
index 01c4d7e..7c149bc 100644
--- a/src/main/java/com/ruoyi/common/enums/StockInQualifiedRecordTypeEnum.java
+++ b/src/main/java/com/ruoyi/common/enums/StockInQualifiedRecordTypeEnum.java
@@ -2,29 +2,23 @@
 
 import lombok.Getter;
 
-
+//鍏ュ簱鏋氫妇
 @Getter
 public enum StockInQualifiedRecordTypeEnum implements BaseEnum<String> {
 
 
     CUSTOMIZATION_STOCK_IN("0", "鍚堟牸鑷畾涔夊叆搴�"),
-    CUSTOMIZATION_STOCK_OUT("1", "鍚堟牸鑷畾涔夊嚭搴�"),
     PRODUCTION_REPORT_STOCK_IN("2", "鐢熶骇鎶ュ伐-鍏ュ簱"),
-    PRODUCTION_REPORT_STOCK_OUT("3", "鐢熶骇鎶ュ伐-鍑哄簱"),
     DEFECTIVE_SCRAP("4", "涓嶅悎鏍煎鐞�-鎶ュ簾"),
     PRODUCTION_SCRAP("5", "鐢熶骇鎶ュ伐-鎶ュ簾"),
     QUALITYINSPECT_STOCK_IN("6", "璐ㄦ-鍚堟牸鍏ュ簱"),
     PURCHASE_STOCK_IN("7", "閲囪喘-鍏ュ簱"),
-    SALE_STOCK_OUT("8", "閿�鍞�-鍑哄簱"),
     CUSTOMIZATION_UNSTOCK_IN("9", "涓嶅悎鏍艰嚜瀹氫箟鍏ュ簱"),
-    CUSTOMIZATION_UNSTOCK_OUT("10", "涓嶅悎鏍艰嚜瀹氫箟鍑哄簱"),
+    CUSTOMIZATION_UNSTOCK_OUT("10", "閲囪喘-璐ㄦ-鍚堟牸鍏ュ簱"),
     DEFECTIVE_PASS("11", "涓嶅悎鏍�-璁╂鏀捐"),
-    QUALITYINSPECT_UNSTOCK_IN("12", "璐ㄦ-涓嶅悎鏍煎叆搴�"),
-    SALE_SHIP_STOCK_OUT("13", "閿�鍞�-鍙戣揣鍑哄簱"),
     RETURN_HE_IN("14", "閿�鍞��璐�-鍚堟牸鍏ュ簱"),
     RETURN_UNSTOCK_IN("15", "閿�鍞��璐�-涓嶅悎鏍煎叆搴�"),
     PICK_RETURN_IN("20", "棰嗘枡閫�鏂�-鍚堟牸鍏ュ簱"),
-    PURCHASE_RETURN_STOCK_OUT("21", "閲囪喘閫�璐�"),
     FEED_RETURN_IN("22", "鐢熶骇閫�鏂�-鍚堟牸鍏ュ簱");
 
 
diff --git a/src/main/java/com/ruoyi/common/enums/StockInUnQualifiedRecordTypeEnum.java b/src/main/java/com/ruoyi/common/enums/StockInUnQualifiedRecordTypeEnum.java
deleted file mode 100644
index a03e6bd..0000000
--- a/src/main/java/com/ruoyi/common/enums/StockInUnQualifiedRecordTypeEnum.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.ruoyi.common.enums;
-
-import lombok.Getter;
-
-
-@Getter
-public enum StockInUnQualifiedRecordTypeEnum implements BaseEnum<String> {
-
-
-    DEFECTIVE_SCRAP("4", "涓嶅悎鏍煎鐞�-鎶ュ簾"),
-    PRODUCTION_SCRAP("5", "鐢熶骇鎶ュ伐-鎶ュ簾"),
-    CUSTOMIZATION_UNSTOCK_IN("9", "涓嶅悎鏍艰嚜瀹氫箟鍏ュ簱"),
-    QUALITYINSPECT_UNSTOCK_IN("12", "璐ㄦ-涓嶅悎鏍煎叆搴�"),
-    RETURN_UNSTOCK_IN("15", "閿�鍞��璐�-涓嶅悎鏍煎叆搴�");
-
-
-    private final String code;
-    private final String value;
-
-    StockInUnQualifiedRecordTypeEnum(String code, String value) {
-        this.code = code;
-        this.value = value;
-    }
-
-}
diff --git a/src/main/java/com/ruoyi/common/enums/StockOutQualifiedRecordTypeEnum.java b/src/main/java/com/ruoyi/common/enums/StockOutQualifiedRecordTypeEnum.java
index 4fe1f6e..ccc6d78 100644
--- a/src/main/java/com/ruoyi/common/enums/StockOutQualifiedRecordTypeEnum.java
+++ b/src/main/java/com/ruoyi/common/enums/StockOutQualifiedRecordTypeEnum.java
@@ -9,6 +9,7 @@
     PRODUCTION_REPORT_STOCK_OUT("3", "鐢熶骇鎶ュ伐-鍑哄簱"),
     SALE_STOCK_OUT("8", "閿�鍞�-鍑哄簱"),
     PURCHASE_RETURN_STOCK_OUT("9", "閲囪喘閫�璐�"),
+    CUSTOMIZATION_UNSTOCK_OUT("10", "涓嶅悎鏍艰嚜瀹氫箟鍑哄簱"),
     SALE_SHIP_STOCK_OUT("13", "閿�鍞�-鍙戣揣鍑哄簱"),
     PICK_STOCK_OUT("14", "鐢熶骇棰嗘枡鍑哄簱"),
     FEED_STOCK_OUT("15", "鐢熶骇琛ユ枡鍑哄簱");
diff --git a/src/main/java/com/ruoyi/common/enums/StockOutUnQualifiedRecordTypeEnum.java b/src/main/java/com/ruoyi/common/enums/StockOutUnQualifiedRecordTypeEnum.java
deleted file mode 100644
index 2ee40bd..0000000
--- a/src/main/java/com/ruoyi/common/enums/StockOutUnQualifiedRecordTypeEnum.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.ruoyi.common.enums;
-
-import lombok.Getter;
-
-
-@Getter
-public enum StockOutUnQualifiedRecordTypeEnum implements BaseEnum<String> {
-
-
-    CUSTOMIZATION_UNSTOCK_OUT("10", "涓嶅悎鏍艰嚜瀹氫箟鍑哄簱");
-
-
-    private final String code;
-    private final String value;
-
-    StockOutUnQualifiedRecordTypeEnum(String code, String value) {
-        this.code = code;
-        this.value = value;
-    }
-
-}
diff --git a/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java b/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java
index 0edfc7b..2e35584 100644
--- a/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java
+++ b/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java
@@ -28,6 +28,9 @@
     @Schema(description = "瑙勬牸鍨嬪彿")
     private String deviceModel;
 
+    @Schema(description = "璁惧椤圭洰")
+    private String machineryCategory;
+
     /**
      * 涓婚敭ID
      */
diff --git a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java
index b9deb2d..09d5d77 100644
--- a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java
+++ b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java
@@ -4,6 +4,7 @@
 import com.ruoyi.device.pojo.MaintenanceTask;
 import lombok.RequiredArgsConstructor;
 import org.quartz.*;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Component;
@@ -18,14 +19,15 @@
 import java.util.Set;
 
 @Component
-@DisallowConcurrentExecution // 绂佹骞跺彂鎵ц鍚屼竴涓狫ob
-@RequiredArgsConstructor
+@DisallowConcurrentExecution
 public class MaintenanceTaskJob implements Job, Serializable {
-    private static final long serialVersionUID = 1L; // 蹇呴』瀹氫箟搴忓垪鍖朓D
+    private static final long serialVersionUID = 1L;
 
-    private final DeviceMaintenanceServiceImpl deviceMaintenanceService;
+    @Autowired
+    private DeviceMaintenanceServiceImpl deviceMaintenanceService;
 
-    private final JdbcTemplate jdbcTemplate;
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
 
     @Override
     public void execute(JobExecutionContext context) throws JobExecutionException {
@@ -96,6 +98,7 @@
         inspectionTask.setTenantId(timingTask.getTenantId());
         inspectionTask.setStatus(0);
         inspectionTask.setDeviceModel(timingTask.getDeviceModel());
+        inspectionTask.setMachineryCategory(timingTask.getMachineryCategory());
         inspectionTask.setCreateUser(Integer.parseInt(timingTask.getRegistrantId().toString()));
         inspectionTask.setUpdateTime(LocalDateTime.now());
         inspectionTask.setCreateTime(LocalDateTime.now());
diff --git a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java
index 389eda9..d9c5f69 100644
--- a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java
+++ b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java
@@ -5,6 +5,7 @@
 import com.ruoyi.inspectiontask.pojo.TimingTask;
 import lombok.RequiredArgsConstructor;
 import org.quartz.*;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Component;
@@ -20,12 +21,13 @@
 
 @Component
 @DisallowConcurrentExecution // 绂佹骞跺彂鎵ц鍚屼竴涓狫ob
-@RequiredArgsConstructor
 public class TimingTaskJob implements Job, Serializable {
     private static final long serialVersionUID = 1L; // 蹇呴』瀹氫箟搴忓垪鍖朓D
 
-    private final InspectionTaskMapper inspectionTaskMapper;
-    private final JdbcTemplate jdbcTemplate;
+    @Autowired
+    private InspectionTaskMapper inspectionTaskMapper;
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
 
     @Override
     public void execute(JobExecutionContext context) throws JobExecutionException {
@@ -46,7 +48,7 @@
             if (timingTask == null) {
                 throw new JobExecutionException("鎵句笉鍒板畾鏃朵换鍔�: " + taskId);
             }
-            
+
 //            if (!timingTask.isActive()) {
 //                throw new JobExecutionException("瀹氭椂浠诲姟宸茬鐢�: " + taskId);
 //            }
diff --git a/src/main/java/com/ruoyi/oA/controller/OaProjectController.java b/src/main/java/com/ruoyi/oA/controller/OaProjectController.java
deleted file mode 100644
index b7ecc7a..0000000
--- a/src/main/java/com/ruoyi/oA/controller/OaProjectController.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.ruoyi.oA.controller;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.oA.dto.OaProjectDto;
-import com.ruoyi.oA.pojo.OaProject;
-import com.ruoyi.oA.service.OaProjectService;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.Operation;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-import org.apache.commons.collections4.CollectionUtils;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.HashMap;
-import java.util.List;
-
-@Tag(name = "oA椤圭洰绠$悊")
-@RestController
-@AllArgsConstructor
-@RequestMapping("/oA/project")
-public class OaProjectController {
-    private final OaProjectService oaProjectService;
-
-    @Operation(summary = "鑾峰彇椤圭洰鍒楄〃")
-    @GetMapping("/listPage")
-    public AjaxResult listPage(Page page, OaProjectDto oaProjectDto) {
-        IPage<OaProjectDto> listPage = oaProjectService.listPage(page, oaProjectDto);
-        return AjaxResult.success(listPage);
-    }
-    @Operation(summary = "鑾峰彇椤圭洰鍒楄〃璇︽儏")
-    @GetMapping("/getList")
-    public AjaxResult getList(Page page, OaProjectDto oaProjectDto) {
-        IPage<OaProjectDto> listPage = oaProjectService.listPage(page, oaProjectDto);
-        HashMap<Object, Object> Map = new HashMap<>();
-        listPage.getRecords().forEach(item -> {
-            Map.put(item.getProjectId(), item);
-        });
-        return AjaxResult.success(Map);
-    }
-    @Operation(summary = "澧炴坊椤圭洰")
-    @PostMapping("/add")
-    public AjaxResult add(@RequestBody OaProject oaProject) {
-        boolean save = oaProjectService.save(oaProject);
-        return AjaxResult.success(save);
-    }
-    @Operation(summary = "鍒犻櫎椤圭洰")
-    @DeleteMapping("/delete/{id}")
-    public AjaxResult delete(@PathVariable Long id) {
-        boolean remove = oaProjectService.deleteById(id);
-        return AjaxResult.success(remove);
-    }
-    @Operation(summary = "鏇存柊椤圭洰")
-    @PostMapping("/update")
-    public AjaxResult update(@RequestBody OaProject oaProject) {
-        boolean update = oaProjectService.updateById(oaProject);
-        return AjaxResult.success(update);
-    }
-//    @Operation(summary = "鏍规嵁ID鑾峰彇椤圭洰璇︽儏")
-//    @GetMapping("/getById")
-//    public AjaxResult getById(Long id) {
-//        OaProject oaProject = oaProjectService.getById(id);
-//        return AjaxResult.success(oaProject);
-//    }
-    @Operation(summary = "瀵煎嚭鎵�閫夐」鐩�")
-    @PostMapping("/export/{ids}")
-    public void export(HttpServletResponse response, @PathVariable("ids") List<Long> ids) {
-        if (CollectionUtils.isEmpty(ids)) {
-            throw new IllegalArgumentException("瀵煎嚭椤圭洰鍒楄〃涓嶈兘涓虹┖");
-        }
-        oaProjectService.export(response, ids);
-    }
-
-}
diff --git a/src/main/java/com/ruoyi/oA/controller/OaProjectPhaseController.java b/src/main/java/com/ruoyi/oA/controller/OaProjectPhaseController.java
deleted file mode 100644
index a4a05bb..0000000
--- a/src/main/java/com/ruoyi/oA/controller/OaProjectPhaseController.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.ruoyi.oA.controller;
-
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.oA.pojo.OaProjectPhase;
-import com.ruoyi.oA.service.OaProjectPhaseService;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.Operation;
-import lombok.AllArgsConstructor;
-import org.springframework.web.bind.annotation.*;
-
-@Tag(name = "oA椤圭洰闃舵绠$悊")
-@RestController
-@RequestMapping("/oA/projectPhase")
-@AllArgsConstructor
-public class OaProjectPhaseController {
-    private final OaProjectPhaseService oaProjectPhaseService;
-
-    @Operation(summary = "鏂板椤圭洰闃舵")
-    @PostMapping("/add")
-    public AjaxResult add(@RequestBody OaProjectPhase oaProjectPhase) {
-        return AjaxResult.success(oaProjectPhaseService.save(oaProjectPhase));
-    }
-
-    @Operation(summary = "鍒犻櫎椤圭洰闃舵")
-    @DeleteMapping("/delete/{phaseId}")
-    public AjaxResult delete(@PathVariable Integer phaseId) {
-        return AjaxResult.success(oaProjectPhaseService.deleteById(phaseId));
-    }
-
-    @Operation(summary = "鏇存柊椤圭洰闃舵")
-    @PostMapping("/update")
-    public AjaxResult update(@RequestBody OaProjectPhase oaProjectPhase) {
-        return AjaxResult.success(oaProjectPhaseService.updateById(oaProjectPhase));
-    }
-
-    @Operation(summary = "鏍规嵁椤圭洰id鏌ヨ椤圭洰闃舵鍒楄〃")
-    @GetMapping("/listByProjectId/{projectId}")
-    public AjaxResult listByProjectId(@PathVariable Integer projectId) {
-        return AjaxResult.success(oaProjectPhaseService.listByProjectId(projectId));
-    }
-}
diff --git a/src/main/java/com/ruoyi/oA/controller/OaProjectPhaseTaskController.java b/src/main/java/com/ruoyi/oA/controller/OaProjectPhaseTaskController.java
deleted file mode 100644
index 91a846e..0000000
--- a/src/main/java/com/ruoyi/oA/controller/OaProjectPhaseTaskController.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.ruoyi.oA.controller;
-
-import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.oA.pojo.OaProjectPhaseTask;
-import com.ruoyi.oA.service.OaProjectPhaseTaskService;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.Operation;
-import lombok.AllArgsConstructor;
-import org.springframework.web.bind.annotation.*;
-
-@Tag(name = "oA椤圭洰闃舵浠诲姟绠$悊")
-@RestController
-@RequestMapping("/oA/projectPhaseTask")
-@AllArgsConstructor
-public class OaProjectPhaseTaskController {
-    private final OaProjectPhaseTaskService oaProjectPhaseTaskService;
-
-    @Operation(summary = "鏂板椤圭洰闃舵浠诲姟")
-    @PostMapping("/add")
-    public AjaxResult add(@RequestBody OaProjectPhaseTask oaProjectPhaseTask) {
-        return AjaxResult.success(oaProjectPhaseTaskService.save(oaProjectPhaseTask));
-    }
-
-    @Operation(summary = "鏍规嵁椤圭洰闃舵id鏌ヨ椤圭洰闃舵浠诲姟鍒楄〃")
-    @GetMapping("/listByPhaseId/{phaseId}")
-    public AjaxResult listByPhaseId(@PathVariable Integer phaseId) {
-        return AjaxResult.success(oaProjectPhaseTaskService.listByPhaseId(phaseId));
-    }
-
-    @Operation(summary = "鍒犻櫎椤圭洰闃舵浠诲姟")
-    @DeleteMapping("/delete/{taskId}")
-    public AjaxResult delete(@PathVariable Integer taskId) {
-        return AjaxResult.success(oaProjectPhaseTaskService.removeById(taskId));
-    }
-
-    @Operation(summary = "鏇存柊椤圭洰闃舵浠诲姟")
-    @PostMapping("/update")
-    public AjaxResult update(@RequestBody OaProjectPhaseTask oaProjectPhaseTask) {
-        return AjaxResult.success(oaProjectPhaseTaskService.updateById(oaProjectPhaseTask));
-    }
-}
diff --git a/src/main/java/com/ruoyi/oA/dto/OaProjectDto.java b/src/main/java/com/ruoyi/oA/dto/OaProjectDto.java
deleted file mode 100644
index 0f90faf..0000000
--- a/src/main/java/com/ruoyi/oA/dto/OaProjectDto.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.ruoyi.oA.dto;
-
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import com.ruoyi.oA.pojo.OaProject;
-import com.ruoyi.oA.pojo.OaProjectPhase;
-import com.ruoyi.oA.pojo.OaProjectPhaseTask;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class OaProjectDto extends OaProject {
-    /**
-     * 璐熻矗浜哄悕绉�
-     */
-    @Excel(name = "璐熻矗浜哄悕绉�")
-    private String managerName;
-    /**
-     * 椤圭洰闃舵鍒楄〃
-     */
-    private List<OaProjectPhaseDto> oaProjectPhasesDto;
-//    /**
-//     * 椤圭洰闃舵浠诲姟鍒楄〃
-//     */
-//    private List<OaProjectPhaseTask> oaProjectPhaseTasks;
-}
diff --git a/src/main/java/com/ruoyi/oA/dto/OaProjectPhaseDto.java b/src/main/java/com/ruoyi/oA/dto/OaProjectPhaseDto.java
deleted file mode 100644
index 4ef163e..0000000
--- a/src/main/java/com/ruoyi/oA/dto/OaProjectPhaseDto.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.ruoyi.oA.dto;
-
-import com.ruoyi.oA.pojo.OaProjectPhase;
-import com.ruoyi.oA.pojo.OaProjectPhaseTask;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class OaProjectPhaseDto extends OaProjectPhase {
-    private List<OaProjectPhaseTask> oaProjectPhaseTasks;
-}
diff --git a/src/main/java/com/ruoyi/oA/mapper/OaProjectMapper.java b/src/main/java/com/ruoyi/oA/mapper/OaProjectMapper.java
deleted file mode 100644
index 2114cef..0000000
--- a/src/main/java/com/ruoyi/oA/mapper/OaProjectMapper.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.ruoyi.oA.mapper;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.oA.dto.OaProjectDto;
-import com.ruoyi.oA.pojo.OaProject;
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
-* @author ywx
-* @description 閽堝琛ㄣ�恛a_project(OA绯荤粺-椤圭洰浠诲姟鍗忓悓-椤圭洰琛�)銆戠殑鏁版嵁搴撴搷浣淢apper
-* @createDate 2025-09-24 09:18:46
-* @Entity com.ruoyi.oA.pojo.OaProject
-*/
-public interface OaProjectMapper extends BaseMapper<OaProject> {
-
-    IPage<OaProjectDto> listPage(Page page,@Param("req") OaProjectDto oaProjectDto);
-
-    List<OaProjectDto> selectByIds(List<Long> ids);
-}
-
-
-
-
diff --git a/src/main/java/com/ruoyi/oA/mapper/OaProjectPhaseMapper.java b/src/main/java/com/ruoyi/oA/mapper/OaProjectPhaseMapper.java
deleted file mode 100644
index 41f6ab0..0000000
--- a/src/main/java/com/ruoyi/oA/mapper/OaProjectPhaseMapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.oA.mapper;
-
-import com.ruoyi.oA.pojo.OaProjectPhase;
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-
-/**
-* @author ywx
-* @description 閽堝琛ㄣ�恛a_project_phase(OA绯荤粺-椤圭洰闃舵琛�)銆戠殑鏁版嵁搴撴搷浣淢apper
-* @createDate 2025-09-24 09:18:46
-* @Entity com.ruoyi.oA.pojo.OaProjectPhase
-*/
-public interface OaProjectPhaseMapper extends BaseMapper<OaProjectPhase> {
-
-}
-
-
-
-
diff --git a/src/main/java/com/ruoyi/oA/mapper/OaProjectPhaseTaskMapper.java b/src/main/java/com/ruoyi/oA/mapper/OaProjectPhaseTaskMapper.java
deleted file mode 100644
index b357c76..0000000
--- a/src/main/java/com/ruoyi/oA/mapper/OaProjectPhaseTaskMapper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.oA.mapper;
-
-import com.ruoyi.oA.pojo.OaProjectPhaseTask;
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-
-/**
-* @author ywx
-* @description 閽堝琛ㄣ�恛a_project_phase_task(OA绯荤粺-椤圭洰闃舵-浠诲姟琛�)銆戠殑鏁版嵁搴撴搷浣淢apper
-* @createDate 2025-09-24 09:18:46
-* @Entity com.ruoyi.oA.pojo.OaProjectPhaseTask
-*/
-public interface OaProjectPhaseTaskMapper extends BaseMapper<OaProjectPhaseTask> {
-
-}
-
-
-
-
diff --git a/src/main/java/com/ruoyi/oA/pojo/OaProject.java b/src/main/java/com/ruoyi/oA/pojo/OaProject.java
deleted file mode 100644
index 4a5af5b..0000000
--- a/src/main/java/com/ruoyi/oA/pojo/OaProject.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package com.ruoyi.oA.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-
-import java.io.Serializable;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.Date;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-/**
- * OA绯荤粺-椤圭洰浠诲姟鍗忓悓-椤圭洰琛�
- * @TableName oa_project
- */
-@TableName(value ="oa_project")
-@Data
-public class OaProject implements Serializable {
-    /**
-     * 
-     */
-    @TableId(type = IdType.AUTO)
-    private Integer projectId;
-
-    /**
-     * 椤圭洰鍚嶇О
-     */
-    @Excel(name = "椤圭洰鍚嶇О")
-    private String projectName;
-
-    /**
-     * 椤圭洰鎻忚堪
-     */
-    @Excel(name = "椤圭洰鎻忚堪")
-    private String description;
-
-    /**
-     * 寮�濮嬫椂闂�
-     */
-    @Excel(name = "寮�濮嬫椂闂�")
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private LocalDate startDate;
-
-    /**
-     * 缁撴潫鏃堕棿
-     */
-    @Excel(name = "缁撴潫鏃堕棿")
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private LocalDate endDate;
-
-    /**
-     * 鐘舵��
-     */
-    @Excel(name = "鐘舵��")
-    private String status;
-
-    /**
-     * 瀹屾垚搴�
-     */
-    @Excel(name = "瀹屾垚搴�")
-    private Integer completionRate;
-
-    /**
-     * 璐熻矗浜篿d
-     */
-    private Long managerId;
-
-    /**
-     * 鍒涘缓鐢ㄦ埛
-     */
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime createTime;
-
-    /**
-     * 淇敼鐢ㄦ埛
-     */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Integer updateUser;
-
-    /**
-     * 淇敼鏃堕棿
-     */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime updateTime;
-
-    /**
-     * 绉熸埛ID
-     */
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/oA/pojo/OaProjectPhase.java b/src/main/java/com/ruoyi/oA/pojo/OaProjectPhase.java
deleted file mode 100644
index b26bb9d..0000000
--- a/src/main/java/com/ruoyi/oA/pojo/OaProjectPhase.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.ruoyi.oA.pojo;
-
-
-import com.baomidou.mybatisplus.annotation.*;
-
-import java.io.Serializable;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.Date;
-
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-/**
- * OA绯荤粺-椤圭洰闃舵琛�
- * @TableName oa_project_phase
- */
-@TableName(value ="oa_project_phase")
-@Data
-public class OaProjectPhase implements Serializable {
-    /**
-     * 
-     */
-    @TableId(type = IdType.AUTO)
-    private Integer phaseId;
-
-    /**
-     * 椤圭洰闃舵鍚嶇О
-     */
-    private String phaseName;
-
-    /**
-     * oa_project琛╥d
-     */
-    private Integer oaProjectId;
-
-    /**
-     * 寮�濮嬫椂闂�
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private LocalDate startDate;
-
-    /**
-     * 缁撴潫鏃堕棿
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private LocalDate endDate;
-
-    /**
-     * 鐘舵��
-     */
-    private String status;
-
-    /**
-     * 鍒涘缓鐢ㄦ埛
-     */
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime createTime;
-
-    /**
-     * 淇敼鐢ㄦ埛
-     */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Integer updateUser;
-
-    /**
-     * 淇敼鏃堕棿
-     */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime updateTime;
-
-    /**
-     * 绉熸埛ID
-     */
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/oA/pojo/OaProjectPhaseTask.java b/src/main/java/com/ruoyi/oA/pojo/OaProjectPhaseTask.java
deleted file mode 100644
index 1b81069..0000000
--- a/src/main/java/com/ruoyi/oA/pojo/OaProjectPhaseTask.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.ruoyi.oA.pojo;
-
-import com.baomidou.mybatisplus.annotation.*;
-
-import java.io.Serializable;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.Date;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-/**
- * OA绯荤粺-椤圭洰闃舵-浠诲姟琛�
- * @TableName oa_project_phase_task
- */
-@TableName(value ="oa_project_phase_task")
-@Data
-public class OaProjectPhaseTask implements Serializable {
-    /**
-     * 
-     */
-    @TableId(type = IdType.AUTO)
-    private Integer taskId;
-
-    /**
-     * 椤圭洰闃舵浠诲姟鍚嶇О
-     */
-    private String taskName;
-
-    /**
-     * oa_project_phase琛╥d
-     */
-    private Integer phaseId;
-
-    /**
-     * 寮�濮嬫椂闂�
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private LocalDate startDate;
-
-    /**
-     * 缁撴潫鏃堕棿
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private LocalDate endDate;
-
-    /**
-     * 鐩爣浠诲姟瀹屾垚鏃ユ湡
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
-    private LocalDate targetDate;
-
-    /**
-     * 鐩爣鍊�
-     */
-    private Integer targetValue;
-
-    /**
-     * 褰撳墠鍊�
-     */
-    private Integer currentValue;
-
-    /**
-     * 鍗曚綅
-     */
-    private String unit;
-
-    /**
-     * 鐘舵��
-     */
-    private String status;
-
-    /**
-     * 瀹屾垚搴�
-     */
-    private Integer completionRate;
-
-    /**
-     * 鍒涘缓鐢ㄦ埛
-     */
-    @TableField(fill = FieldFill.INSERT)
-    private Integer createUser;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime createTime;
-
-    /**
-     * 淇敼鐢ㄦ埛
-     */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private Integer updateUser;
-
-    /**
-     * 淇敼鏃堕棿
-     */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime updateTime;
-
-    /**
-     * 绉熸埛ID
-     */
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-
-    @TableField(fill = FieldFill.INSERT)
-    private Long deptId;
-}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/oA/service/OaProjectPhaseService.java b/src/main/java/com/ruoyi/oA/service/OaProjectPhaseService.java
deleted file mode 100644
index 7914080..0000000
--- a/src/main/java/com/ruoyi/oA/service/OaProjectPhaseService.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.ruoyi.oA.service;
-
-import com.ruoyi.oA.dto.OaProjectPhaseDto;
-import com.ruoyi.oA.pojo.OaProjectPhase;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-
-import java.util.List;
-
-/**
-* @author ywx
-* @description 閽堝琛ㄣ�恛a_project_phase(OA绯荤粺-椤圭洰闃舵琛�)銆戠殑鏁版嵁搴撴搷浣淪ervice
-* @createDate 2025-09-24 09:18:46
-*/
-public interface OaProjectPhaseService extends IService<OaProjectPhase> {
-
-    List<OaProjectPhaseDto> listByProjectId(Integer oaProjectId);
-
-    boolean deleteById(Integer phaseId);
-}
diff --git a/src/main/java/com/ruoyi/oA/service/OaProjectPhaseTaskService.java b/src/main/java/com/ruoyi/oA/service/OaProjectPhaseTaskService.java
deleted file mode 100644
index 225d12e..0000000
--- a/src/main/java/com/ruoyi/oA/service/OaProjectPhaseTaskService.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.ruoyi.oA.service;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.oA.pojo.OaProjectPhaseTask;
-import com.baomidou.mybatisplus.extension.service.IService;
-
-import java.util.List;
-
-/**
-* @author ywx
-* @description 閽堝琛ㄣ�恛a_project_phase_task(OA绯荤粺-椤圭洰闃舵-浠诲姟琛�)銆戠殑鏁版嵁搴撴搷浣淪ervice
-* @createDate 2025-09-24 09:18:46
-*/
-public interface OaProjectPhaseTaskService extends IService<OaProjectPhaseTask> {
-
-    List<OaProjectPhaseTask> listByPhaseId(Integer phaseId);
-}
diff --git a/src/main/java/com/ruoyi/oA/service/OaProjectService.java b/src/main/java/com/ruoyi/oA/service/OaProjectService.java
deleted file mode 100644
index 9f8e474..0000000
--- a/src/main/java/com/ruoyi/oA/service/OaProjectService.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.oA.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.oA.dto.OaProjectDto;
-import com.ruoyi.oA.pojo.OaProject;
-import jakarta.servlet.http.HttpServletResponse;
-
-import java.util.List;
-
-/**
-* @author ywx
-* @description 閽堝琛ㄣ�恛a_project(OA绯荤粺-椤圭洰浠诲姟鍗忓悓-椤圭洰琛�)銆戠殑鏁版嵁搴撴搷浣淪ervice
-* @createDate 2025-09-24 09:18:46
-*/
-public interface OaProjectService extends IService<OaProject> {
-
-    IPage<OaProjectDto> listPage(Page page, OaProjectDto oaProjectDto);
-
-    void export(HttpServletResponse response, List<Long> ids);
-
-    boolean deleteById(Long id);
-}
diff --git a/src/main/java/com/ruoyi/oA/service/impl/OaProjectPhaseServiceImpl.java b/src/main/java/com/ruoyi/oA/service/impl/OaProjectPhaseServiceImpl.java
deleted file mode 100644
index 640ec42..0000000
--- a/src/main/java/com/ruoyi/oA/service/impl/OaProjectPhaseServiceImpl.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.ruoyi.oA.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.common.utils.bean.BeanUtils;
-import com.ruoyi.oA.dto.OaProjectPhaseDto;
-import com.ruoyi.oA.mapper.OaProjectPhaseMapper;
-import com.ruoyi.oA.pojo.OaProjectPhase;
-import com.ruoyi.oA.pojo.OaProjectPhaseTask;
-import com.ruoyi.oA.service.OaProjectPhaseService;
-import com.ruoyi.oA.service.OaProjectPhaseTaskService;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
-* @author ywx
-* @description 閽堝琛ㄣ�恛a_project_phase(OA绯荤粺-椤圭洰闃舵琛�)銆戠殑鏁版嵁搴撴搷浣淪ervice瀹炵幇
-* @createDate 2025-09-24 09:18:46
-*/
-@Service
-@RequiredArgsConstructor
-@Transactional(rollbackFor = Exception.class)
-public class OaProjectPhaseServiceImpl extends ServiceImpl<OaProjectPhaseMapper, OaProjectPhase>
-    implements OaProjectPhaseService{
-    private final OaProjectPhaseMapper oaProjectPhaseMapper;
-    private final OaProjectPhaseTaskService oaProjectPhaseTaskService;
-
-    @Override
-    public List<OaProjectPhaseDto> listByProjectId(Integer oaProjectId) {
-        List<OaProjectPhase> oaProjectPhases = oaProjectPhaseMapper.selectList(new LambdaQueryWrapper<OaProjectPhase>()
-                .eq(OaProjectPhase::getOaProjectId, oaProjectId));
-        List<OaProjectPhaseDto> collect = oaProjectPhases.stream().map(oaProjectPhase -> {
-            OaProjectPhaseDto oaProjectPhaseDto = new OaProjectPhaseDto();
-            BeanUtils.copyProperties(oaProjectPhase, oaProjectPhaseDto);
-//            List<OaProjectPhaseTask> oaProjectPhaseTasks = oaProjectPhaseTaskService.listByPhaseId(oaProjectPhaseDto.getPhaseId());
-            oaProjectPhaseDto.setOaProjectPhaseTasks(oaProjectPhaseTaskService.listByPhaseId(oaProjectPhaseDto.getPhaseId()));
-            return oaProjectPhaseDto;
-        }).collect(Collectors.toList());
-        return collect;
-    }
-
-    @Override
-    public boolean deleteById(Integer phaseId) {
-        // 鍏堝垹闄ら」鐩樁娈典笅鐨勪换鍔�
-        oaProjectPhaseTaskService.remove(new LambdaQueryWrapper<OaProjectPhaseTask>()
-                .eq(OaProjectPhaseTask::getPhaseId, phaseId));
-        return oaProjectPhaseMapper.deleteById(phaseId) > 0;
-    }
-}
-
-
-
-
diff --git a/src/main/java/com/ruoyi/oA/service/impl/OaProjectPhaseTaskServiceImpl.java b/src/main/java/com/ruoyi/oA/service/impl/OaProjectPhaseTaskServiceImpl.java
deleted file mode 100644
index 625e8d8..0000000
--- a/src/main/java/com/ruoyi/oA/service/impl/OaProjectPhaseTaskServiceImpl.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.ruoyi.oA.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.oA.pojo.OaProjectPhaseTask;
-import com.ruoyi.oA.service.OaProjectPhaseTaskService;
-import com.ruoyi.oA.mapper.OaProjectPhaseTaskMapper;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-
-/**
-* @author ywx
-* @description 閽堝琛ㄣ�恛a_project_phase_task(OA绯荤粺-椤圭洰闃舵-浠诲姟琛�)銆戠殑鏁版嵁搴撴搷浣淪ervice瀹炵幇
-* @createDate 2025-09-24 09:18:46
-*/
-@Service
-public class OaProjectPhaseTaskServiceImpl extends ServiceImpl<OaProjectPhaseTaskMapper, OaProjectPhaseTask>
-    implements OaProjectPhaseTaskService{
-
-
-    @Override
-    public List<OaProjectPhaseTask> listByPhaseId(Integer phaseId) {
-        return baseMapper.selectList(new LambdaQueryWrapper<OaProjectPhaseTask>()
-                .eq(OaProjectPhaseTask::getPhaseId, phaseId));
-    }
-}
-
-
-
-
diff --git a/src/main/java/com/ruoyi/oA/service/impl/OaProjectServiceImpl.java b/src/main/java/com/ruoyi/oA/service/impl/OaProjectServiceImpl.java
deleted file mode 100644
index afe125a..0000000
--- a/src/main/java/com/ruoyi/oA/service/impl/OaProjectServiceImpl.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.ruoyi.oA.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.oA.dto.OaProjectDto;
-import com.ruoyi.oA.mapper.OaProjectMapper;
-import com.ruoyi.oA.pojo.OaProject;
-import com.ruoyi.oA.pojo.OaProjectPhase;
-import com.ruoyi.oA.service.OaProjectPhaseService;
-import com.ruoyi.oA.service.OaProjectService;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-
-/**
-* @author ywx
-* @description 閽堝琛ㄣ�恛a_project(OA绯荤粺-椤圭洰浠诲姟鍗忓悓-椤圭洰琛�)銆戠殑鏁版嵁搴撴搷浣淪ervice瀹炵幇
-* @createDate 2025-09-24 09:18:45
-*/
-@Service
-@Transactional(rollbackFor = Exception.class)
-@RequiredArgsConstructor
-public class OaProjectServiceImpl extends ServiceImpl<OaProjectMapper, OaProject>
-    implements OaProjectService{
-    private final OaProjectMapper oaProjectMapper;
-    private final OaProjectPhaseService oaProjectPhaseService;
-
-    @Override
-    public IPage<OaProjectDto> listPage(Page page, OaProjectDto oaProjectDto) {
-        IPage<OaProjectDto> iPage = oaProjectMapper.listPage(page, oaProjectDto);
-        // 椤圭洰闃舵鍒楄〃
-        for (OaProjectDto projectDto : iPage.getRecords()) {
-            projectDto.setOaProjectPhasesDto(oaProjectPhaseService.listByProjectId(projectDto.getProjectId()));
-        }
-        return iPage;
-    }
-
-    @Override
-    public void export(HttpServletResponse response, List<Long> ids) {
-        List<OaProjectDto> list = oaProjectMapper.selectByIds(ids);
-        ExcelUtil<OaProjectDto> util = new ExcelUtil<OaProjectDto>(OaProjectDto.class);
-        util.exportExcel(response, list , "椤圭洰鏁版嵁");
-    }
-
-    @Override
-    public boolean deleteById(Long id) {
-        // 鍏堝垹闄ら」鐩笅鐨勯樁娈�
-        List<OaProjectPhase> oaProjectPhases = oaProjectPhaseService.list(new LambdaQueryWrapper<OaProjectPhase>()
-                .eq(OaProjectPhase::getOaProjectId, id));
-        if (!oaProjectPhases.isEmpty()) {
-            oaProjectPhases.forEach(oaProjectPhase -> {
-                oaProjectPhaseService.deleteById(oaProjectPhase.getPhaseId());
-            });
-        }
-        return oaProjectMapper.deleteById(id) > 0;
-    }
-}
-
-
-
-
diff --git a/src/main/java/com/ruoyi/procurementrecord/dto/Details.java b/src/main/java/com/ruoyi/procurementrecord/bean/dto/Details.java
similarity index 90%
rename from src/main/java/com/ruoyi/procurementrecord/dto/Details.java
rename to src/main/java/com/ruoyi/procurementrecord/bean/dto/Details.java
index 08dd6af..ba226d1 100644
--- a/src/main/java/com/ruoyi/procurementrecord/dto/Details.java
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/dto/Details.java
@@ -1,4 +1,4 @@
-package com.ruoyi.procurementrecord.dto;
+package com.ruoyi.procurementrecord.bean.dto;
 
 import lombok.Data;
 
diff --git a/src/main/java/com/ruoyi/procurementrecord/dto/InventoryInformationDto.java b/src/main/java/com/ruoyi/procurementrecord/bean/dto/InventoryInformationDto.java
similarity index 91%
rename from src/main/java/com/ruoyi/procurementrecord/dto/InventoryInformationDto.java
rename to src/main/java/com/ruoyi/procurementrecord/bean/dto/InventoryInformationDto.java
index 2396b29..b45b5b9 100644
--- a/src/main/java/com/ruoyi/procurementrecord/dto/InventoryInformationDto.java
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/dto/InventoryInformationDto.java
@@ -1,4 +1,4 @@
-package com.ruoyi.procurementrecord.dto;
+package com.ruoyi.procurementrecord.bean.dto;
 
 import lombok.Data;
 
diff --git a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementAddDto.java b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementAddDto.java
similarity index 89%
rename from src/main/java/com/ruoyi/procurementrecord/dto/ProcurementAddDto.java
rename to src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementAddDto.java
index 6bb4e47..e231348 100644
--- a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementAddDto.java
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementAddDto.java
@@ -1,4 +1,4 @@
-package com.ruoyi.procurementrecord.dto;
+package com.ruoyi.procurementrecord.bean.dto;
 
 import lombok.Data;
 
diff --git a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementDto.java b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementDto.java
similarity index 97%
rename from src/main/java/com/ruoyi/procurementrecord/dto/ProcurementDto.java
rename to src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementDto.java
index d8004b4..aa88d45 100644
--- a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementDto.java
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementDto.java
@@ -1,4 +1,4 @@
-package com.ruoyi.procurementrecord.dto;
+package com.ruoyi.procurementrecord.bean.dto;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.ruoyi.framework.aspectj.lang.annotation.Excel;
diff --git a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementManagementUpdateDto.java b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementManagementUpdateDto.java
similarity index 94%
rename from src/main/java/com/ruoyi/procurementrecord/dto/ProcurementManagementUpdateDto.java
rename to src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementManagementUpdateDto.java
index ac896a2..f9fc9ff 100644
--- a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementManagementUpdateDto.java
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementManagementUpdateDto.java
@@ -1,4 +1,4 @@
-package com.ruoyi.procurementrecord.dto;
+package com.ruoyi.procurementrecord.bean.dto;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.ruoyi.framework.aspectj.lang.annotation.Excel;
diff --git a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementPageDto.java b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementPageDto.java
similarity index 98%
rename from src/main/java/com/ruoyi/procurementrecord/dto/ProcurementPageDto.java
rename to src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementPageDto.java
index 57c2dbb..fa3e337 100644
--- a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementPageDto.java
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementPageDto.java
@@ -1,4 +1,4 @@
-package com.ruoyi.procurementrecord.dto;
+package com.ruoyi.procurementrecord.bean.dto;
 
 
 import com.fasterxml.jackson.annotation.JsonFormat;
diff --git a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementPageDtoCopy.java b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementPageDtoCopy.java
similarity index 98%
rename from src/main/java/com/ruoyi/procurementrecord/dto/ProcurementPageDtoCopy.java
rename to src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementPageDtoCopy.java
index 9173ce3..8e89c2f 100644
--- a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementPageDtoCopy.java
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementPageDtoCopy.java
@@ -1,4 +1,4 @@
-package com.ruoyi.procurementrecord.dto;
+package com.ruoyi.procurementrecord.bean.dto;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.ruoyi.framework.aspectj.lang.annotation.Excel;
diff --git a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementRecordOutAdd.java b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementRecordOutAdd.java
similarity index 90%
rename from src/main/java/com/ruoyi/procurementrecord/dto/ProcurementRecordOutAdd.java
rename to src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementRecordOutAdd.java
index 58fba64..09272c4 100644
--- a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementRecordOutAdd.java
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementRecordOutAdd.java
@@ -1,4 +1,4 @@
-package com.ruoyi.procurementrecord.dto;
+package com.ruoyi.procurementrecord.bean.dto;
 
 import lombok.Data;
 
diff --git a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementRecordOutPageDto.java b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementRecordOutPageDto.java
similarity index 97%
rename from src/main/java/com/ruoyi/procurementrecord/dto/ProcurementRecordOutPageDto.java
rename to src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementRecordOutPageDto.java
index 6b57f2a..a5dd8d6 100644
--- a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementRecordOutPageDto.java
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementRecordOutPageDto.java
@@ -1,4 +1,4 @@
-package com.ruoyi.procurementrecord.dto;
+package com.ruoyi.procurementrecord.bean.dto;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.ruoyi.framework.aspectj.lang.annotation.Excel;
diff --git a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementUpdateDto.java b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementUpdateDto.java
similarity index 90%
rename from src/main/java/com/ruoyi/procurementrecord/dto/ProcurementUpdateDto.java
rename to src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementUpdateDto.java
index 1a51301..cf9320d 100644
--- a/src/main/java/com/ruoyi/procurementrecord/dto/ProcurementUpdateDto.java
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ProcurementUpdateDto.java
@@ -1,4 +1,4 @@
-package com.ruoyi.procurementrecord.dto;
+package com.ruoyi.procurementrecord.bean.dto;
 
 import lombok.Data;
 
diff --git a/src/main/java/com/ruoyi/procurementrecord/dto/ReturnManagementDto.java b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ReturnManagementDto.java
similarity index 65%
rename from src/main/java/com/ruoyi/procurementrecord/dto/ReturnManagementDto.java
rename to src/main/java/com/ruoyi/procurementrecord/bean/dto/ReturnManagementDto.java
index b69f241..539f3c7 100644
--- a/src/main/java/com/ruoyi/procurementrecord/dto/ReturnManagementDto.java
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ReturnManagementDto.java
@@ -1,17 +1,9 @@
-package com.ruoyi.procurementrecord.dto;
+package com.ruoyi.procurementrecord.bean.dto;
 
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.fasterxml.jackson.annotation.JsonFormat;
 import com.ruoyi.procurementrecord.pojo.ReturnManagement;
-import com.ruoyi.procurementrecord.pojo.ReturnSaleProduct;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
 
-import java.time.LocalDateTime;
 import java.util.List;
 
 /**
diff --git a/src/main/java/com/ruoyi/procurementrecord/bean/dto/ReturnSaleProductDto.java b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ReturnSaleProductDto.java
new file mode 100644
index 0000000..6cfae1b
--- /dev/null
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ReturnSaleProductDto.java
@@ -0,0 +1,38 @@
+package com.ruoyi.procurementrecord.bean.dto;
+
+import com.ruoyi.procurementrecord.pojo.ReturnSaleProduct;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class ReturnSaleProductDto extends ReturnSaleProduct {
+
+    private String productName;
+
+    private String model;
+
+    private String unit;
+
+    //鏈��璐ф暟閲�
+    private BigDecimal unQuantity;
+
+    //鎬婚��璐ф暟閲�
+    private BigDecimal totalReturnNum;
+
+    // 閫�璐ф�讳环
+    private BigDecimal price;
+
+    // 閫�璐ф�讳环
+    private BigDecimal taxInclusiveUnitPrice;
+
+    @Schema(description = "鍑哄簱鍗曞彿")
+    private String outboundBatches;
+
+    @Schema(description = "鎵规鍙�")
+    private String batchNo;
+
+    @Schema(description = "鍙戣揣鍑哄簱鏁伴噺")
+    private BigDecimal stockOutNum;
+}
diff --git a/src/main/java/com/ruoyi/procurementrecord/bean/vo/ShippingInfoVo.java b/src/main/java/com/ruoyi/procurementrecord/bean/vo/ShippingInfoVo.java
new file mode 100644
index 0000000..d442c63
--- /dev/null
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/vo/ShippingInfoVo.java
@@ -0,0 +1,17 @@
+package com.ruoyi.procurementrecord.bean.vo;
+
+import com.ruoyi.sales.pojo.ShippingInfo;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Schema(name = "ShippingInfoVo", description = "钀ラ攢绠$悊--鍙戣揣淇℃伅")
+public class ShippingInfoVo {
+
+    private ShippingInfo shippingInfo;
+
+    @Schema(description = "鍙戣揣浜у搧鍒楄〃")
+    private List<ShippingProductVo> shippingProductVoList;
+}
diff --git a/src/main/java/com/ruoyi/procurementrecord/bean/vo/ShippingProductVo.java b/src/main/java/com/ruoyi/procurementrecord/bean/vo/ShippingProductVo.java
new file mode 100644
index 0000000..9f87aef
--- /dev/null
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/vo/ShippingProductVo.java
@@ -0,0 +1,43 @@
+package com.ruoyi.procurementrecord.bean.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(name = "ShippingProductVo", description = "钀ラ攢绠$悊--鍙戣揣鍑哄簱浜у搧鍒楄〃")
+public class ShippingProductVo {
+    @Schema(description = "鍑哄簱鍗昳d")
+    private Long id;
+
+    @Schema(description = "浜у搧瑙勬牸id")
+    private Long productModelId;
+
+    @Schema(description = "浜у搧澶х被")
+    private String productCategory;
+
+    @Schema(description = "瑙勬牸鍨嬪彿")
+    private String specificationModel;
+
+    @Schema(description = "鍗曚綅")
+    private String unit;
+
+    @Schema(description = "鍑哄簱鍗曞彿")
+    private String outboundBatches;
+
+    @Schema(description = "鍙戣揣鍑哄簱鏁伴噺")
+    private BigDecimal stockOutNum;
+
+    @Schema(description = "鎵规鍙�")
+    private String batchNo;
+
+    @Schema(description = "鏈��璐ф暟")
+    private BigDecimal unQuantity;
+
+    @Schema(description = "閫�璐ф�绘暟")
+    private BigDecimal totalReturnNum;
+
+    @Schema(description = "鍚◣鍗曚环")
+    private BigDecimal taxInclusiveUnitPrice;
+}
diff --git a/src/main/java/com/ruoyi/procurementrecord/controller/ProcurementExceptionRecordController.java b/src/main/java/com/ruoyi/procurementrecord/controller/ProcurementExceptionRecordController.java
index c594994..bb14493 100644
--- a/src/main/java/com/ruoyi/procurementrecord/controller/ProcurementExceptionRecordController.java
+++ b/src/main/java/com/ruoyi/procurementrecord/controller/ProcurementExceptionRecordController.java
@@ -1,24 +1,13 @@
 package com.ruoyi.procurementrecord.controller;
 
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.framework.aspectj.lang.annotation.Log;
-import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
 import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.procurementrecord.dto.*;
 import com.ruoyi.procurementrecord.mapper.ProcurementExceptionRecordMapper;
 import com.ruoyi.procurementrecord.pojo.ProcurementExceptionRecord;
-import com.ruoyi.procurementrecord.service.ProcurementRecordService;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.Operation;
 import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
-
-import jakarta.servlet.http.HttpServletResponse;
-import java.util.List;
 
 /**
  * @author :yys
diff --git a/src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordController.java b/src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordController.java
index e567eea..7e49990 100644
--- a/src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordController.java
+++ b/src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordController.java
@@ -8,7 +8,7 @@
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
 import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.procurementrecord.dto.*;
+import com.ruoyi.procurementrecord.bean.dto.*;
 import com.ruoyi.procurementrecord.mapper.CustomStorageMapper;
 import com.ruoyi.procurementrecord.pojo.CustomStorage;
 import com.ruoyi.procurementrecord.service.ProcurementRecordService;
@@ -16,7 +16,6 @@
 import io.swagger.v3.oas.annotations.Operation;
 import lombok.AllArgsConstructor;
 import org.apache.ibatis.annotations.Delete;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
diff --git a/src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordOutController.java b/src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordOutController.java
index f024bfe..c86d3e6 100644
--- a/src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordOutController.java
+++ b/src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordOutController.java
@@ -7,9 +7,9 @@
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
 import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.procurementrecord.dto.ProcurementRecordOutAdd;
-import com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto;
-import com.ruoyi.procurementrecord.dto.ProcurementUpdateDto;
+import com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutAdd;
+import com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutPageDto;
+import com.ruoyi.procurementrecord.bean.dto.ProcurementUpdateDto;
 import com.ruoyi.procurementrecord.mapper.ProcurementRecordOutMapper;
 import com.ruoyi.procurementrecord.service.ProcurementRecordOutService;
 import io.swagger.v3.oas.annotations.tags.Tag;
diff --git a/src/main/java/com/ruoyi/procurementrecord/controller/ReturnManagementController.java b/src/main/java/com/ruoyi/procurementrecord/controller/ReturnManagementController.java
index 22882f4..b3f31b9 100644
--- a/src/main/java/com/ruoyi/procurementrecord/controller/ReturnManagementController.java
+++ b/src/main/java/com/ruoyi/procurementrecord/controller/ReturnManagementController.java
@@ -4,21 +4,16 @@
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.common.utils.OrderUtils;
 import com.ruoyi.framework.web.controller.BaseController;
 import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.procurementrecord.dto.ReturnManagementDto;
-import com.ruoyi.procurementrecord.mapper.ReturnManagementMapper;
-import com.ruoyi.procurementrecord.pojo.ReturnManagement;
+import com.ruoyi.procurementrecord.bean.dto.ReturnManagementDto;
+import com.ruoyi.procurementrecord.bean.vo.ShippingInfoVo;
 import com.ruoyi.procurementrecord.pojo.ReturnSaleProduct;
 import com.ruoyi.procurementrecord.service.ReturnManagementService;
 import com.ruoyi.procurementrecord.service.ReturnSaleProductService;
-import com.ruoyi.procurementrecord.service.impl.ReturnSaleProductServiceImpl;
-import com.ruoyi.sales.dto.SalesLedgerDto;
-import io.swagger.v3.oas.annotations.tags.Tag;
 import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
@@ -87,10 +82,10 @@
     }
 
     @GetMapping("/getByShippingId")
-    @Operation(summary = "閿�鍞��璐�-鏍规嵁鍑哄簱鍗曟煡璇㈤攢鍞鍗曚互鍙婁骇鍝佷俊鎭�")
+    @Operation(summary = "閿�鍞��璐�-鏍规嵁鍙戣揣鍗曟煡璇㈤攢鍞鍗曚互鍙婂嚭搴撶殑浜у搧淇℃伅")
     public AjaxResult getByShippingId(Long shippingId) {
-        SalesLedgerDto salesLedgerDto = returnManagementService.getReturnManagementDtoByShippingIdId(shippingId);
-        return success(salesLedgerDto);
+        ShippingInfoVo shippingInfoVo = returnManagementService.getReturnManagementDtoByShippingIdId(shippingId);
+        return success(shippingInfoVo);
     }
 
 }
diff --git a/src/main/java/com/ruoyi/procurementrecord/dto/ReturnSaleProductDto.java b/src/main/java/com/ruoyi/procurementrecord/dto/ReturnSaleProductDto.java
deleted file mode 100644
index 51cb040..0000000
--- a/src/main/java/com/ruoyi/procurementrecord/dto/ReturnSaleProductDto.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.ruoyi.procurementrecord.dto;
-
-import com.ruoyi.procurementrecord.pojo.ReturnSaleProduct;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-@Data
-public class ReturnSaleProductDto extends ReturnSaleProduct {
-
-    private String productName;
-
-    private String model;
-
-    private String unit;
-
-    //鏈��璐ф暟閲�
-    private BigDecimal unQuantity;
-
-    private BigDecimal totalReturnNum;
-
-    // 閫�璐ф�讳环
-    private BigDecimal price;
-
-    // 閫�璐ф�讳环
-    private BigDecimal taxInclusiveUnitPrice;
-}
diff --git a/src/main/java/com/ruoyi/procurementrecord/mapper/ProcurementRecordMapper.java b/src/main/java/com/ruoyi/procurementrecord/mapper/ProcurementRecordMapper.java
index b41cf62..f37f6d8 100644
--- a/src/main/java/com/ruoyi/procurementrecord/mapper/ProcurementRecordMapper.java
+++ b/src/main/java/com/ruoyi/procurementrecord/mapper/ProcurementRecordMapper.java
@@ -3,9 +3,9 @@
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.procurementrecord.dto.ProcurementDto;
-import com.ruoyi.procurementrecord.dto.ProcurementPageDto;
-import com.ruoyi.procurementrecord.dto.ProcurementPageDtoCopy;
+import com.ruoyi.procurementrecord.bean.dto.ProcurementDto;
+import com.ruoyi.procurementrecord.bean.dto.ProcurementPageDto;
+import com.ruoyi.procurementrecord.bean.dto.ProcurementPageDtoCopy;
 import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
 import org.apache.ibatis.annotations.Param;
 
diff --git a/src/main/java/com/ruoyi/procurementrecord/mapper/ProcurementRecordOutMapper.java b/src/main/java/com/ruoyi/procurementrecord/mapper/ProcurementRecordOutMapper.java
index eebd7cc..a1e003e 100644
--- a/src/main/java/com/ruoyi/procurementrecord/mapper/ProcurementRecordOutMapper.java
+++ b/src/main/java/com/ruoyi/procurementrecord/mapper/ProcurementRecordOutMapper.java
@@ -3,7 +3,7 @@
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto;
+import com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutPageDto;
 import com.ruoyi.procurementrecord.pojo.ProcurementRecordOut;
 import org.apache.ibatis.annotations.Param;
 
diff --git a/src/main/java/com/ruoyi/procurementrecord/mapper/ReturnManagementMapper.java b/src/main/java/com/ruoyi/procurementrecord/mapper/ReturnManagementMapper.java
index ec1693e..815559c 100644
--- a/src/main/java/com/ruoyi/procurementrecord/mapper/ReturnManagementMapper.java
+++ b/src/main/java/com/ruoyi/procurementrecord/mapper/ReturnManagementMapper.java
@@ -5,7 +5,7 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.account.bean.dto.SalesReturnDto;
 import com.ruoyi.account.bean.vo.SalesReturnVo;
-import com.ruoyi.procurementrecord.dto.ReturnManagementDto;
+import com.ruoyi.procurementrecord.bean.dto.ReturnManagementDto;
 import com.ruoyi.procurementrecord.pojo.ReturnManagement;
 import org.apache.ibatis.annotations.Param;
 
@@ -25,5 +25,5 @@
 
     ReturnManagementDto getReturnManagementDtoById(Long id);
 
-    IPage<SalesReturnVo> listPageBySalesReturn(Page page, @Param("req") SalesReturnDto salesReturnDto);
+    IPage<SalesReturnVo> listPageAccountSalesReturn(Page page, @Param("req") SalesReturnDto salesReturnDto);
 }
diff --git a/src/main/java/com/ruoyi/procurementrecord/mapper/ReturnSaleProductMapper.java b/src/main/java/com/ruoyi/procurementrecord/mapper/ReturnSaleProductMapper.java
index 879a074..d185189 100644
--- a/src/main/java/com/ruoyi/procurementrecord/mapper/ReturnSaleProductMapper.java
+++ b/src/main/java/com/ruoyi/procurementrecord/mapper/ReturnSaleProductMapper.java
@@ -1,6 +1,6 @@
 package com.ruoyi.procurementrecord.mapper;
 
-import com.ruoyi.procurementrecord.dto.ReturnSaleProductDto;
+import com.ruoyi.procurementrecord.bean.dto.ReturnSaleProductDto;
 import com.ruoyi.procurementrecord.pojo.ReturnSaleProduct;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Mapper;
diff --git a/src/main/java/com/ruoyi/procurementrecord/pojo/ReturnManagement.java b/src/main/java/com/ruoyi/procurementrecord/pojo/ReturnManagement.java
index f5d8c79..4e8e3fb 100644
--- a/src/main/java/com/ruoyi/procurementrecord/pojo/ReturnManagement.java
+++ b/src/main/java/com/ruoyi/procurementrecord/pojo/ReturnManagement.java
@@ -8,7 +8,6 @@
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
-import java.util.Date;
 
 /**
  * @author :yys
@@ -64,10 +63,12 @@
     @Schema(description = "鍒涘缓鏃堕棿")
     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @TableField(fill = FieldFill.INSERT)
     private LocalDateTime createTime;
     @Schema(description = "鏇存柊鏃堕棿")
     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
     private LocalDateTime updateTime;
 
     @Schema(description = "鍒涘缓鐢ㄦ埛")
diff --git a/src/main/java/com/ruoyi/procurementrecord/pojo/ReturnSaleProduct.java b/src/main/java/com/ruoyi/procurementrecord/pojo/ReturnSaleProduct.java
index b7b0efa..2afeaa4 100644
--- a/src/main/java/com/ruoyi/procurementrecord/pojo/ReturnSaleProduct.java
+++ b/src/main/java/com/ruoyi/procurementrecord/pojo/ReturnSaleProduct.java
@@ -1,15 +1,12 @@
 package com.ruoyi.procurementrecord.pojo;
 
-import com.baomidou.mybatisplus.annotation.FieldFill;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import java.io.Serializable;
-import java.math.BigDecimal;
+import com.baomidou.mybatisplus.annotation.*;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Getter;
 import lombok.Setter;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
 
 /**
  * <p>
@@ -37,8 +34,8 @@
     @Schema(description = "閫�璐у崟id")
     private Long returnManagementId;
 
-    @Schema(description = "閫�璐т骇鍝乮d")
-    private Long returnsalesLedgerProductId;
+    @Schema(description = "鍏宠仈鍑哄簱鍗昳d")
+    private Long stockOutRecordId;
 
     @Schema(description = "閫�璐т骇鍝佹暟閲�")
     private BigDecimal num;
diff --git a/src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordOutService.java b/src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordOutService.java
index 202ce88..803c03f 100644
--- a/src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordOutService.java
+++ b/src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordOutService.java
@@ -3,9 +3,9 @@
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.procurementrecord.dto.ProcurementRecordOutAdd;
-import com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto;
-import com.ruoyi.procurementrecord.dto.ProcurementUpdateDto;
+import com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutAdd;
+import com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutPageDto;
+import com.ruoyi.procurementrecord.bean.dto.ProcurementUpdateDto;
 import com.ruoyi.procurementrecord.pojo.ProcurementRecordOut;
 
 import jakarta.servlet.http.HttpServletResponse;
diff --git a/src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordService.java b/src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordService.java
index da23205..a209cf9 100644
--- a/src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordService.java
+++ b/src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordService.java
@@ -5,7 +5,7 @@
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.procurementrecord.dto.*;
+import com.ruoyi.procurementrecord.bean.dto.*;
 import com.ruoyi.procurementrecord.pojo.CustomStorage;
 import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
 
diff --git a/src/main/java/com/ruoyi/procurementrecord/service/ReturnManagementService.java b/src/main/java/com/ruoyi/procurementrecord/service/ReturnManagementService.java
index 1a2de96..4e7555a 100644
--- a/src/main/java/com/ruoyi/procurementrecord/service/ReturnManagementService.java
+++ b/src/main/java/com/ruoyi/procurementrecord/service/ReturnManagementService.java
@@ -3,9 +3,9 @@
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.procurementrecord.dto.ReturnManagementDto;
+import com.ruoyi.procurementrecord.bean.dto.ReturnManagementDto;
+import com.ruoyi.procurementrecord.bean.vo.ShippingInfoVo;
 import com.ruoyi.procurementrecord.pojo.ReturnManagement;
-import com.ruoyi.sales.dto.SalesLedgerDto;
 
 /**
  * @author :yys
@@ -26,7 +26,7 @@
 
     boolean updateReturnManagementDto(ReturnManagementDto returnManagementDto);
 
-    SalesLedgerDto getReturnManagementDtoByShippingIdId(Long shippingId);
+    ShippingInfoVo getReturnManagementDtoByShippingIdId(Long shippingId);
 
     boolean handle(Long returnManagementId);
 
diff --git a/src/main/java/com/ruoyi/procurementrecord/service/ReturnSaleProductService.java b/src/main/java/com/ruoyi/procurementrecord/service/ReturnSaleProductService.java
index 07c080f..d16b527 100644
--- a/src/main/java/com/ruoyi/procurementrecord/service/ReturnSaleProductService.java
+++ b/src/main/java/com/ruoyi/procurementrecord/service/ReturnSaleProductService.java
@@ -1,6 +1,6 @@
 package com.ruoyi.procurementrecord.service;
 
-import com.ruoyi.procurementrecord.dto.ReturnSaleProductDto;
+import com.ruoyi.procurementrecord.bean.dto.ReturnSaleProductDto;
 import com.ruoyi.procurementrecord.pojo.ReturnSaleProduct;
 import com.baomidou.mybatisplus.extension.service.IService;
 
diff --git a/src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordOutServiceImpl.java b/src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordOutServiceImpl.java
index 8b6b33d..8b73f4a 100644
--- a/src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordOutServiceImpl.java
+++ b/src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordOutServiceImpl.java
@@ -5,9 +5,9 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.procurementrecord.dto.ProcurementRecordOutAdd;
-import com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto;
-import com.ruoyi.procurementrecord.dto.ProcurementUpdateDto;
+import com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutAdd;
+import com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutPageDto;
+import com.ruoyi.procurementrecord.bean.dto.ProcurementUpdateDto;
 import com.ruoyi.procurementrecord.mapper.ProcurementRecordOutMapper;
 import com.ruoyi.procurementrecord.pojo.ProcurementRecordOut;
 import com.ruoyi.procurementrecord.service.ProcurementRecordOutService;
diff --git a/src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java b/src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java
index 8a3c4ba..1d99dec 100644
--- a/src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java
+++ b/src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java
@@ -12,7 +12,7 @@
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.security.LoginUser;
 import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.procurementrecord.dto.*;
+import com.ruoyi.procurementrecord.bean.dto.*;
 import com.ruoyi.procurementrecord.mapper.CustomStorageMapper;
 import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper;
 import com.ruoyi.procurementrecord.mapper.ProcurementRecordOutMapper;
diff --git a/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java b/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java
index b22d63d..b4701f6 100644
--- a/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java
+++ b/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java
@@ -8,21 +8,19 @@
 import com.ruoyi.account.pojo.AccountExpense;
 import com.ruoyi.account.service.SalesRefundAmountOrderService;
 import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
-import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
 import com.ruoyi.common.utils.OrderUtils;
 import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.procurementrecord.dto.ReturnManagementDto;
-import com.ruoyi.procurementrecord.dto.ReturnSaleProductDto;
+import com.ruoyi.procurementrecord.bean.dto.ReturnManagementDto;
+import com.ruoyi.procurementrecord.bean.dto.ReturnSaleProductDto;
+import com.ruoyi.procurementrecord.bean.vo.ShippingInfoVo;
+import com.ruoyi.procurementrecord.bean.vo.ShippingProductVo;
 import com.ruoyi.procurementrecord.mapper.ReturnManagementMapper;
 import com.ruoyi.procurementrecord.pojo.ReturnManagement;
 import com.ruoyi.procurementrecord.pojo.ReturnSaleProduct;
 import com.ruoyi.procurementrecord.service.ReturnManagementService;
 import com.ruoyi.procurementrecord.service.ReturnSaleProductService;
 import com.ruoyi.procurementrecord.utils.StockUtils;
-import com.ruoyi.sales.dto.SalesLedgerDto;
-import com.ruoyi.sales.dto.SalesLedgerProductDto;
 import com.ruoyi.sales.mapper.SalesLedgerMapper;
-import com.ruoyi.sales.pojo.SalesLedger;
 import com.ruoyi.sales.pojo.ShippingInfo;
 import com.ruoyi.sales.service.ShippingInfoService;
 import lombok.RequiredArgsConstructor;
@@ -33,7 +31,6 @@
 import org.springframework.util.ObjectUtils;
 
 import java.math.BigDecimal;
-import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
@@ -77,28 +74,28 @@
 
     @Override
     public boolean updateReturnManagementDto(ReturnManagementDto returnManagementDto) {
-        List<ReturnSaleProduct> returnSaleProducts = new ArrayList<>();
         if (!CollectionUtils.isEmpty(returnManagementDto.getReturnSaleProducts())) {
             returnManagementDto.getReturnSaleProducts().stream().forEach(returnSaleProductDto -> {
                 ReturnSaleProduct returnSaleProduct = new ReturnSaleProduct();
                 BeanUtils.copyProperties(returnSaleProductDto, returnSaleProduct);
-                returnSaleProducts.add(returnSaleProduct);
+                if (returnSaleProductDto.getId() == null){
+                    returnSaleProduct.setReturnManagementId(returnManagementDto.getId());
+                    returnSaleProduct.setStatus(0);
+                    returnSaleProductService.save(returnSaleProduct);
+                }else returnSaleProductService.updateById(returnSaleProduct);
             });
         }
-        returnSaleProductService.updateBatchById(returnSaleProducts);
         return updateById(returnManagementDto);
     }
 
     @Override
-    public SalesLedgerDto getReturnManagementDtoByShippingIdId(Long shippingId) {
+    public ShippingInfoVo getReturnManagementDtoByShippingIdId(Long shippingId) {
         ShippingInfo byId = shippingInfoService.getById(shippingId);
-        SalesLedger salesLedger = salesLedgerMapper.selectById(byId.getSalesLedgerId());
-        SalesLedgerDto salesLedgerDto = new SalesLedgerDto();
-        BeanUtils.copyProperties(salesLedger, salesLedgerDto);
-
-        List<SalesLedgerProductDto> salesLedgerProductDtos = shippingInfoService.getReturnManagementDtoById(byId.getId());
-        salesLedgerDto.setProductDtoData(salesLedgerProductDtos);
-         return salesLedgerDto;
+        ShippingInfoVo shippingInfoVo = new ShippingInfoVo();
+        shippingInfoVo.setShippingInfo(byId);
+        List<ShippingProductVo> shippingProductVos = shippingInfoService.getReturnManagementDtoById(byId.getId());
+        shippingInfoVo.setShippingProductVoList(shippingProductVos);
+         return shippingInfoVo;
     }
 
     @Override
@@ -106,6 +103,7 @@
         ReturnManagement byId = this.getById(returnManagementId);
         List<ReturnSaleProductDto> list = returnSaleProductService.listReturnSaleProduct(returnManagementId);
         byId.setStatus(1);
+        byId.setSettler(SecurityUtils.getLoginUser().getNickName());
         updateById(byId);
         SalesRefundAmountOrderDto salesRefundAmountOrder = new SalesRefundAmountOrderDto();
         salesRefundAmountOrder.setReturnManagementId(returnManagementId);
@@ -118,11 +116,11 @@
             salesRefundAmountOrder.setRefundedAmount(new BigDecimal(0));
             // 鏄惁鏈夎川閲忛棶棰�
             if (returnSaleProduct.getIsQuality() == 1) {
-                // 鏈夎川閲忛棶棰橈紝鍏ヤ笉鍚堟牸搴�
-                stockUtils.addUnStock(returnSaleProduct.getProductModelId(),returnSaleProduct.getNum(), StockInUnQualifiedRecordTypeEnum.RETURN_UNSTOCK_IN.getCode(),returnSaleProduct.getId());
+                // 鏈夎川閲忛棶棰橈紝鍏ヤ笉鍚堟牸搴�(甯︽壒娆�)
+                stockUtils.addUnStockWithBatchNo(returnSaleProduct.getProductModelId(),returnSaleProduct.getNum(), StockInQualifiedRecordTypeEnum.RETURN_UNSTOCK_IN.getCode(),returnSaleProduct.getId(),returnSaleProduct.getBatchNo());
             }else{
-                // 鏃犺川閲忛棶棰橈紝鍏ュ悎鏍煎簱
-                stockUtils.addStock(returnSaleProduct.getProductModelId(),returnSaleProduct.getNum(), StockInQualifiedRecordTypeEnum.RETURN_HE_IN.getCode(),returnSaleProduct.getId());
+                // 鏃犺川閲忛棶棰橈紝鍏ュ悎鏍煎簱(甯︽壒娆�)
+                stockUtils.addStockWithBatchNo(returnSaleProduct.getProductModelId(),returnSaleProduct.getNum(), StockInQualifiedRecordTypeEnum.RETURN_HE_IN.getCode(),returnSaleProduct.getId(),returnSaleProduct.getBatchNo());
             }
         }
         salesRefundAmountOrder.setRefundAmount(bigDecimal);
diff --git a/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnSaleProductServiceImpl.java b/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnSaleProductServiceImpl.java
index 4809674..29a9ee7 100644
--- a/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnSaleProductServiceImpl.java
+++ b/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnSaleProductServiceImpl.java
@@ -1,7 +1,7 @@
 package com.ruoyi.procurementrecord.service.impl;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.procurementrecord.dto.ReturnSaleProductDto;
+import com.ruoyi.procurementrecord.bean.dto.ReturnSaleProductDto;
 import com.ruoyi.procurementrecord.mapper.ReturnSaleProductMapper;
 import com.ruoyi.procurementrecord.pojo.ReturnSaleProduct;
 import com.ruoyi.procurementrecord.service.ReturnSaleProductService;
diff --git a/src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java b/src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
index 5356500..8e004e4 100644
--- a/src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
+++ b/src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
@@ -1,12 +1,13 @@
 package com.ruoyi.procurementrecord.utils;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.ruoyi.common.enums.ReviewStatusEnum;
 import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper;
 import com.ruoyi.procurementrecord.mapper.ProcurementRecordOutMapper;
 import com.ruoyi.stock.dto.StockInventoryDto;
 import com.ruoyi.stock.dto.StockUninventoryDto;
-import com.ruoyi.stock.mapper.StockInventoryMapper;
 import com.ruoyi.stock.pojo.StockInRecord;
 import com.ruoyi.stock.pojo.StockOutRecord;
 import com.ruoyi.stock.service.StockInRecordService;
@@ -28,7 +29,6 @@
     private final StockInventoryService stockInventoryService;
     private final StockInRecordService stockInRecordService;
     private final StockOutRecordService stockOutRecordService;
-    private final StockInventoryMapper stockInventoryMapper;
 
     /**
      * 涓嶅悎鏍煎叆搴�
@@ -44,6 +44,24 @@
         stockUninventoryDto.setRecordType(String.valueOf(recordType));
         stockUninventoryDto.setQualitity(quantity);
         stockUninventoryDto.setProductModelId(productModelId);
+        stockUninventoryService.addStockInRecordOnly(stockUninventoryDto);
+    }
+
+    /**
+     * 涓嶅悎鏍煎叆搴撳甫鎵规鍙�
+     *
+     * @param productModelId
+     * @param quantity
+     * @param recordType
+     * @param recordId
+     */
+    public void addUnStockWithBatchNo(Long productModelId, BigDecimal quantity, String recordType, Long recordId, String batchNo) {
+        StockUninventoryDto stockUninventoryDto = new StockUninventoryDto();
+        stockUninventoryDto.setRecordId(recordId);
+        stockUninventoryDto.setRecordType(String.valueOf(recordType));
+        stockUninventoryDto.setQualitity(quantity);
+        stockUninventoryDto.setProductModelId(productModelId);
+        stockUninventoryDto.setBatchNo(batchNo);
         stockUninventoryService.addStockInRecordOnly(stockUninventoryDto);
     }
 
@@ -66,8 +84,6 @@
 
     /**
      * 鍚堟牸鍏ュ簱
-     * @param productModelId
-     * @param quantity
      * @param recordType
      * @param recordId
      */
@@ -105,15 +121,6 @@
      * @param recordType
      * @param recordId
      */
-    public void substractStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId) {
-        StockInventoryDto stockInventoryDto = new StockInventoryDto();
-        stockInventoryDto.setRecordId(recordId);
-        stockInventoryDto.setRecordType(String.valueOf(recordType));
-        stockInventoryDto.setQualitity(quantity);
-        stockInventoryDto.setProductModelId(productModelId);
-        stockInventoryService.subtractStockInventory(stockInventoryDto);
-    }
-
     public void substractStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId, String batchNo) {
         StockInventoryDto stockInventoryDto = new StockInventoryDto();
         stockInventoryDto.setRecordId(recordId);
@@ -121,22 +128,34 @@
         stockInventoryDto.setQualitity(quantity);
         stockInventoryDto.setProductModelId(productModelId);
         stockInventoryDto.setBatchNo(batchNo);
-        stockInventoryService.subtractStockInventory(stockInventoryDto);
+        stockInventoryService.addStockOutRecordOnly(stockInventoryDto);
+    }
+
+    /**
+     * 鍙戣揣瀹℃壒鐘舵�佹洿鏀�
+     * @param recordType
+     * @param recordId
+     */
+    public void shipmentStatus(String recordType, Long recordId) {
+        LambdaQueryWrapper<StockOutRecord> queryWrapper = new LambdaQueryWrapper<StockOutRecord>().eq(StockOutRecord::getRecordType, recordType)
+                .eq(StockOutRecord::getRecordId, recordId);
+        stockOutRecordService.list(queryWrapper).stream().forEach(stockOutRecord -> {
+            stockOutRecord.setApprovalStatus(0);
+            stockOutRecordService.updateById(stockOutRecord);
+        });
     }
 
     //涓嶅悎鏍煎簱瀛樺垹闄�
     public void deleteStockInRecord(Long recordId, String recordType) {
         StockInRecord one = stockInRecordService.getOne(new QueryWrapper<StockInRecord>()
                 .lambda().eq(StockInRecord::getRecordId, recordId)
-                .eq(StockInRecord::getRecordType, recordType));
+                .eq(StockInRecord::getRecordType, recordType), false);
         if (ObjectUtils.isNotEmpty(one)) {
-            stockInRecordService.batchDelete(Collections.singletonList(one.getId()));
-            //灏嗗簱瀛樺噺鍥炴潵
-            StockInventoryDto stockInventoryDto = new StockInventoryDto();
-            stockInventoryDto.setRecordId(recordId);
-            stockInventoryDto.setRecordType(recordType);
-            stockInventoryDto.setQualitity(one.getStockInNum());
-            stockInventoryMapper.updateSubtractStockInventory((stockInventoryDto));
+            if (ReviewStatusEnum.APPROVED.getCode().equals(one.getApprovalStatus())) {
+                stockInRecordService.batchDelete(Collections.singletonList(one.getId()));
+            } else {
+                stockInRecordService.removeById(one.getId());
+            }
         }
 
     }
@@ -144,15 +163,13 @@
     public void deleteStockOutRecord(Long recordId, String recordType) {
         StockOutRecord one = stockOutRecordService.getOne(new QueryWrapper<StockOutRecord>()
                 .lambda().eq(StockOutRecord::getRecordId, recordId)
-                .eq(StockOutRecord::getRecordType, recordType));
+                .eq(StockOutRecord::getRecordType, recordType), false);
         if (ObjectUtils.isNotEmpty(one)) {
-            stockOutRecordService.batchDelete(Collections.singletonList(one.getId()));
-            //灏嗗簱瀛樺姞鍥炴潵
-            StockInventoryDto stockInventoryDto = new StockInventoryDto();
-            stockInventoryDto.setRecordId(recordId);
-            stockInventoryDto.setRecordType(recordType);
-            stockInventoryDto.setQualitity(one.getStockOutNum());
-            stockInventoryMapper.updateAddStockInventory((stockInventoryDto));
+            if (ReviewStatusEnum.APPROVED.getCode().equals(one.getApprovalStatus())) {
+                stockOutRecordService.batchDelete(Collections.singletonList(one.getId()));
+            } else {
+                stockOutRecordService.removeById(one.getId());
+            }
         }
 
     }
diff --git a/src/main/java/com/ruoyi/production/pojo/ProductionAccount.java b/src/main/java/com/ruoyi/production/pojo/ProductionAccount.java
index e205db2..c53f138 100644
--- a/src/main/java/com/ruoyi/production/pojo/ProductionAccount.java
+++ b/src/main/java/com/ruoyi/production/pojo/ProductionAccount.java
@@ -27,12 +27,6 @@
     @TableId(value = "id", type = IdType.AUTO)
     private Long id;
 
-    @Schema(description = "閿�鍞彴璐d")
-    private Long salesLedgerId;
-
-    @Schema(description = "閿�鍞骇鍝佽鏍糹d")
-    private Long salesLedgerProductId;
-
     @Schema(description = "鎶ュ伐琛╥d")
     private Long productionProductMainId;
 
diff --git a/src/main/java/com/ruoyi/production/pojo/ProductionProductInput.java b/src/main/java/com/ruoyi/production/pojo/ProductionProductInput.java
index 9c6e9d1..5171aa7 100644
--- a/src/main/java/com/ruoyi/production/pojo/ProductionProductInput.java
+++ b/src/main/java/com/ruoyi/production/pojo/ProductionProductInput.java
@@ -14,9 +14,6 @@
     @TableId(type = IdType.AUTO)
     private Long id;
 
-    @Schema(description = "鎶ュ伐id")
-    private Long productMainId;
-
     @Schema(description = "鐢熶骇鎶ュ伐涓昏〃id")
     private Long productionProductMainId;
 
diff --git a/src/main/java/com/ruoyi/production/pojo/ProductionProductOutput.java b/src/main/java/com/ruoyi/production/pojo/ProductionProductOutput.java
index 5e1daef..40f9a41 100644
--- a/src/main/java/com/ruoyi/production/pojo/ProductionProductOutput.java
+++ b/src/main/java/com/ruoyi/production/pojo/ProductionProductOutput.java
@@ -14,9 +14,6 @@
     @TableId(type = IdType.AUTO)
     private Long id;
 
-    @Schema(description = "鎶ュ伐id")
-    private Long productMainId;
-
     @Schema(description = "鐢熶骇鎶ュ伐涓昏〃id")
     private Long productionProductMainId;
 
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
index 35cdb27..d0dab50 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
@@ -1,18 +1,29 @@
 package com.ruoyi.production.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.production.bean.dto.ProductionBomStructureDto;
 import com.ruoyi.production.bean.vo.ProductionBomStructureVo;
 import com.ruoyi.production.mapper.ProductionBomStructureMapper;
+import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
+import com.ruoyi.production.mapper.ProductionOrderBomMapper;
+import com.ruoyi.production.mapper.ProductionOrderMapper;
+import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper;
 import com.ruoyi.production.pojo.ProductionBomStructure;
+import com.ruoyi.production.pojo.ProductionOperationTask;
+import com.ruoyi.production.pojo.ProductionOrder;
+import com.ruoyi.production.pojo.ProductionOrderBom;
+import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
 import com.ruoyi.production.service.ProductionBomStructureService;
 import lombok.RequiredArgsConstructor;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -26,7 +37,11 @@
 @RequiredArgsConstructor()
 public class ProductionBomStructureServiceImpl extends ServiceImpl<ProductionBomStructureMapper, ProductionBomStructure> implements ProductionBomStructureService {
 
-    private  final ProductionBomStructureMapper productionBomStructureMapper;
+    private final ProductionBomStructureMapper productionBomStructureMapper;
+    private final ProductionOrderBomMapper productionOrderBomMapper;
+    private final ProductionOrderMapper productionOrderMapper;
+    private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
+    private final ProductionOperationTaskMapper productionOperationTaskMapper;
 
     /**
      * 鏍规嵁BOM鏌ヨ骞剁粍瑁呯粨鏋勬爲銆�
@@ -136,9 +151,173 @@
         if (!updateList.isEmpty()) {
             this.updateBatchById(updateList);
         }
+        syncDemandedQuantityAndTaskPlanQuantity(orderBomId, dto.getProductionOrderId());
         return true;
     }
 
+    private void syncDemandedQuantityAndTaskPlanQuantity(Long orderBomId, Long productionOrderId) {
+        if (orderBomId == null) {
+            return;
+        }
+        ProductionOrderBom orderBom = productionOrderBomMapper.selectById(orderBomId);
+        if (orderBom == null) {
+            return;
+        }
+        Long currentProductionOrderId = productionOrderId != null ? productionOrderId : orderBom.getProductionOrderId();
+        if (currentProductionOrderId == null) {
+            return;
+        }
+        ProductionOrder productionOrder = productionOrderMapper.selectById(currentProductionOrderId);
+        if (productionOrder == null) {
+            return;
+        }
+
+        BigDecimal orderQuantity = defaultDecimal(productionOrder.getQuantity());
+        List<ProductionBomStructure> structureList = this.list(
+                Wrappers.<ProductionBomStructure>lambdaQuery()
+                        .eq(ProductionBomStructure::getProductionOrderBomId, orderBomId)
+                        .orderByAsc(ProductionBomStructure::getId));
+        syncStructureDemandedQuantity(structureList, orderQuantity);
+        syncTaskPlanQuantity(
+                currentProductionOrderId,
+                structureList,
+                orderQuantity,
+                orderBom.getProductModelId() != null ? orderBom.getProductModelId() : productionOrder.getProductModelId());
+    }
+
+    private void syncStructureDemandedQuantity(List<ProductionBomStructure> structureList, BigDecimal orderQuantity) {
+        if (structureList == null || structureList.isEmpty()) {
+            return;
+        }
+        List<ProductionBomStructure> updateList = new ArrayList<>();
+        for (ProductionBomStructure structure : structureList) {
+            if (structure == null || structure.getId() == null) {
+                continue;
+            }
+            BigDecimal demandedQuantity = defaultDecimal(structure.getUnitQuantity()).multiply(orderQuantity);
+            if (compareDecimal(structure.getDemandedQuantity(), demandedQuantity) == 0) {
+                continue;
+            }
+            ProductionBomStructure update = new ProductionBomStructure();
+            update.setId(structure.getId());
+            update.setDemandedQuantity(demandedQuantity);
+            updateList.add(update);
+            structure.setDemandedQuantity(demandedQuantity);
+        }
+        if (!updateList.isEmpty()) {
+            this.updateBatchById(updateList);
+        }
+    }
+
+    private void syncTaskPlanQuantity(Long productionOrderId,
+                                      List<ProductionBomStructure> structureList,
+                                      BigDecimal orderQuantity,
+                                      Long rootProductModelId) {
+        List<ProductionOperationTask> taskList = productionOperationTaskMapper.selectList(
+                Wrappers.<ProductionOperationTask>lambdaQuery()
+                        .eq(ProductionOperationTask::getProductionOrderId, productionOrderId)
+                        .orderByAsc(ProductionOperationTask::getId));
+        if (taskList == null || taskList.isEmpty()) {
+            return;
+        }
+
+        Set<Long> routingOperationIds = taskList.stream()
+                .map(ProductionOperationTask::getProductionOrderRoutingOperationId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+        if (routingOperationIds.isEmpty()) {
+            return;
+        }
+
+        Map<Long, ProductionOrderRoutingOperation> routingOperationMap = productionOrderRoutingOperationMapper
+                .selectBatchIds(routingOperationIds)
+                .stream()
+                .filter(item -> item != null && item.getId() != null)
+                .collect(Collectors.toMap(ProductionOrderRoutingOperation::getId, item -> item, (left, right) -> left));
+        Map<String, BigDecimal> demandedQuantityMap = buildOperationDemandedQuantityMap(structureList, rootProductModelId, orderQuantity);
+
+        for (ProductionOperationTask task : taskList) {
+            if (task == null || task.getId() == null || task.getProductionOrderRoutingOperationId() == null) {
+                continue;
+            }
+            ProductionOrderRoutingOperation routingOperation = routingOperationMap.get(task.getProductionOrderRoutingOperationId());
+            if (routingOperation == null || routingOperation.getTechnologyRoutingOperationId() == null) {
+                continue;
+            }
+            BigDecimal planQuantity = resolveTaskPlanQuantity(routingOperation, demandedQuantityMap, orderQuantity);
+            if (compareDecimal(task.getPlanQuantity(), planQuantity) == 0) {
+                continue;
+            }
+            ProductionOperationTask update = new ProductionOperationTask();
+            update.setId(task.getId());
+            update.setPlanQuantity(planQuantity);
+            productionOperationTaskMapper.updateById(update);
+        }
+    }
+
+    private Map<String, BigDecimal> buildOperationDemandedQuantityMap(List<ProductionBomStructure> structureList,
+                                                                      Long rootProductModelId,
+                                                                      BigDecimal orderQuantity) {
+        if (structureList == null || structureList.isEmpty()) {
+            return Collections.emptyMap();
+        }
+        Map<Long, ProductionBomStructure> structureById = structureList.stream()
+                .filter(item -> item != null && item.getId() != null)
+                .collect(Collectors.toMap(ProductionBomStructure::getId, item -> item, (left, right) -> left));
+        Map<String, BigDecimal> demandedQuantityMap = new HashMap<>();
+        for (ProductionBomStructure bomStructure : structureList) {
+            if (bomStructure == null || bomStructure.getTechnologyOperationId() == null || bomStructure.getUnitQuantity() == null) {
+                continue;
+            }
+            Long outputProductModelId = resolveOutputProductModelId(bomStructure, structureById, rootProductModelId);
+            String key = buildOperationDemandedQuantityKey(bomStructure.getTechnologyOperationId(), outputProductModelId);
+            demandedQuantityMap.merge(key, bomStructure.getUnitQuantity().multiply(orderQuantity), BigDecimal::add);
+        }
+        return demandedQuantityMap;
+    }
+
+    private BigDecimal resolveTaskPlanQuantity(ProductionOrderRoutingOperation routingOperation,
+                                               Map<String, BigDecimal> demandedQuantityMap,
+                                               BigDecimal orderQuantity) {
+        if (routingOperation == null || demandedQuantityMap == null || demandedQuantityMap.isEmpty()) {
+            return orderQuantity;
+        }
+        String key = buildOperationDemandedQuantityKey(
+                routingOperation.getTechnologyOperationId(),
+                routingOperation.getProductModelId());
+        BigDecimal planQuantity = demandedQuantityMap.get(key);
+        return planQuantity != null ? planQuantity : orderQuantity;
+    }
+
+    private String buildOperationDemandedQuantityKey(Long operationId, Long outputProductModelId) {
+        return String.valueOf(operationId) + "#" + String.valueOf(outputProductModelId);
+    }
+
+    private Long resolveOutputProductModelId(ProductionBomStructure bomStructure,
+                                             Map<Long, ProductionBomStructure> structureById,
+                                             Long rootProductModelId) {
+        if (bomStructure == null) {
+            return rootProductModelId;
+        }
+        Long parentId = bomStructure.getParentId();
+        if (parentId == null) {
+            return rootProductModelId != null ? rootProductModelId : bomStructure.getProductModelId();
+        }
+        ProductionBomStructure parent = structureById.get(parentId);
+        if (parent != null && parent.getProductModelId() != null) {
+            return parent.getProductModelId();
+        }
+        return rootProductModelId != null ? rootProductModelId : bomStructure.getProductModelId();
+    }
+
+    private BigDecimal defaultDecimal(BigDecimal value) {
+        return value == null ? BigDecimal.ZERO : value;
+    }
+
+    private int compareDecimal(BigDecimal left, BigDecimal right) {
+        return defaultDecimal(left).compareTo(defaultDecimal(right));
+    }
+
     /**
      * 灏嗘爲褰㈢粨鏋勬媿骞虫垚鍒楄〃锛屼究浜庣粺涓�淇濆瓨銆�
      */
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
index 344800c..5a8ea9c 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -245,6 +245,7 @@
                         .eq(TechnologyRoutingOperation::getTechnologyRoutingId, technologyRouting.getId())
                         .orderByDesc(TechnologyRoutingOperation::getDragSort)
                         .orderByDesc(TechnologyRoutingOperation::getId));
+        Map<String, BigDecimal> operationDemandedQuantityMap = buildOperationDemandedQuantityMap(technologyRouting, productionOrder);
         Map<Long, String> operationNameMap = technologyOperationMapper.selectBatchIds(
         // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
                         routingOperations.stream()
@@ -278,7 +279,7 @@
                 ProductionOperationTask task = new ProductionOperationTask();
                 task.setProductionOrderRoutingOperationId(targetOperation.getId());
                 task.setProductionOrderId(productionOrder.getId());
-                task.setPlanQuantity(defaultDecimal(productionOrder.getQuantity()));
+                task.setPlanQuantity(resolveTaskPlanQuantity(sourceOperation, operationDemandedQuantityMap, productionOrder));
                 task.setCompleteQuantity(BigDecimal.ZERO);
                 task.setWorkOrderNo(generateNextTaskNo());
                 task.setStatus(2);
@@ -311,6 +312,72 @@
             }
         }
         return syncedParamCount;
+    }
+
+    private Map<String, BigDecimal> buildOperationDemandedQuantityMap(TechnologyRouting technologyRouting,
+                                                                      ProductionOrder productionOrder) {
+        if (technologyRouting == null || technologyRouting.getBomId() == null) {
+            return Collections.emptyMap();
+        }
+        BigDecimal orderQuantity = defaultDecimal(productionOrder == null ? null : productionOrder.getQuantity());
+        List<TechnologyBomStructure> bomStructures = technologyBomStructureMapper.selectList(
+                Wrappers.<TechnologyBomStructure>lambdaQuery()
+                        .eq(TechnologyBomStructure::getBomId, technologyRouting.getBomId())
+                        .isNotNull(TechnologyBomStructure::getOperationId)
+                        .orderByAsc(TechnologyBomStructure::getId));
+        if (bomStructures.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        Map<Long, TechnologyBomStructure> structureById = bomStructures.stream()
+                .filter(item -> item != null && item.getId() != null)
+                .collect(Collectors.toMap(TechnologyBomStructure::getId, item -> item, (left, right) -> left));
+        Map<String, BigDecimal> demandedQuantityMap = new HashMap<>();
+        for (TechnologyBomStructure bomStructure : bomStructures) {
+            if (bomStructure == null || bomStructure.getOperationId() == null) {
+                continue;
+            }
+            BigDecimal unitQuantity = bomStructure.getUnitQuantity();
+            if (unitQuantity == null) {
+                continue;
+            }
+            Long outputProductModelId = resolveOutputProductModelId(bomStructure, structureById, technologyRouting.getProductModelId());
+            String key = buildOperationDemandedQuantityKey(bomStructure.getOperationId(), outputProductModelId);
+            demandedQuantityMap.merge(key, unitQuantity.multiply(orderQuantity), BigDecimal::add);
+        }
+        return demandedQuantityMap;
+    }
+
+    private BigDecimal resolveTaskPlanQuantity(TechnologyRoutingOperation sourceOperation,
+                                               Map<String, BigDecimal> operationDemandedQuantityMap,
+                                               ProductionOrder productionOrder) {
+        if (sourceOperation == null || operationDemandedQuantityMap == null || operationDemandedQuantityMap.isEmpty()) {
+            return defaultDecimal(productionOrder == null ? null : productionOrder.getQuantity());
+        }
+        String key = buildOperationDemandedQuantityKey(sourceOperation.getTechnologyOperationId(), sourceOperation.getProductModelId());
+        BigDecimal planQuantity = operationDemandedQuantityMap.get(key);
+        return planQuantity != null ? planQuantity : defaultDecimal(productionOrder == null ? null : productionOrder.getQuantity());
+    }
+
+    private String buildOperationDemandedQuantityKey(Long operationId, Long outputProductModelId) {
+        return String.valueOf(operationId) + "#" + String.valueOf(outputProductModelId);
+    }
+
+    private Long resolveOutputProductModelId(TechnologyBomStructure bomStructure,
+                                             Map<Long, TechnologyBomStructure> structureById,
+                                             Long routingProductModelId) {
+        if (bomStructure == null) {
+            return routingProductModelId;
+        }
+        Long parentId = bomStructure.getParentId();
+        if (parentId == null) {
+            return routingProductModelId != null ? routingProductModelId : bomStructure.getProductModelId();
+        }
+        TechnologyBomStructure parent = structureById.get(parentId);
+        if (parent != null && parent.getProductModelId() != null) {
+            return parent.getProductModelId();
+        }
+        return routingProductModelId != null ? routingProductModelId : bomStructure.getProductModelId();
     }
 
     private ProductionOrderBom syncProductionOrderBomSnapshot(ProductionOrder productionOrder, TechnologyRouting technologyRouting) {
@@ -788,12 +855,10 @@
                 if (reportOutput == null) {
                     continue;
                 }
-                Long reportMainId = reportOutput.getProductionProductMainId() != null
-                        ? reportOutput.getProductionProductMainId()
-                        : reportOutput.getProductMainId();
-                if (reportMainId == null) {
+                if (reportOutput.getProductionProductMainId() == null) {
                     continue;
                 }
+                Long reportMainId = reportOutput.getProductionProductMainId();
                 reportOutputMap.computeIfAbsent(reportMainId, k -> new ArrayList<>()).add(reportOutput);
             }
 
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
index 808e75d..2e1e578 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -12,7 +12,6 @@
 import com.ruoyi.basic.pojo.Product;
 import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
-import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
 import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.bean.BeanUtils;
@@ -27,6 +26,8 @@
 import com.ruoyi.project.system.mapper.SysUserMapper;
 import com.ruoyi.quality.mapper.*;
 import com.ruoyi.quality.pojo.*;
+import com.ruoyi.stock.pojo.StockInRecord;
+import com.ruoyi.stock.service.StockInRecordService;
 import com.ruoyi.stock.dto.StockInventoryDto;
 import com.ruoyi.stock.service.StockInventoryService;
 import com.ruoyi.technology.mapper.TechnologyOperationMapper;
@@ -78,6 +79,7 @@
     private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
     private final TechnologyOperationMapper technologyOperationMapper;
     private final StockUtils stockUtils;
+    private final StockInRecordService stockInRecordService;
     private final StockInventoryService stockInventoryService;
 
     @Override
@@ -292,7 +294,6 @@
             // 褰撳墠瀹炵幇鎸夊伐搴忔垚鍝佺洿鎺ヤ綔涓烘姇鍏ワ紝鍚庣画鑻ユ帴鍏ラ鏂欒褰曞彲鍦ㄨ繖閲屾浛鎹㈡潵婧愩��
             ProductionProductInput productionProductInput = new ProductionProductInput();
             productionProductInput.setProductionProductMainId(productionProductMain.getId());
-            productionProductInput.setProductMainId(productionProductMain.getId());
             productionProductInput.setProductModelId(item.getProductModelId());
             productionProductInput.setInputQuantity(item.getUnitQuantity().multiply(defaultDecimal(dto.getQuantity())));
             productionProductInput.setQuantity(productionProductInput.getInputQuantity());
@@ -301,13 +302,14 @@
 
         ProductionProductOutput productionProductOutput = new ProductionProductOutput();
         productionProductOutput.setProductionProductMainId(productionProductMain.getId());
-        productionProductOutput.setProductMainId(productionProductMain.getId());
         productionProductOutput.setProductModelId(productModel.getId());
         productionProductOutput.setQuantity(defaultDecimal(dto.getQuantity()));
         productionProductOutput.setScrapQty(defaultDecimal(dto.getScrapQty()));
         productionProductOutputMapper.insert(productionProductOutput);
         BigDecimal reportQty = defaultDecimal(productionProductOutput.getQuantity());
+        BigDecimal scrapQty = defaultDecimal(productionProductOutput.getScrapQty());
         BigDecimal productQty = reportQty;
+        String qualifiedBatchNo = null;
 
         List<ProductionOrderRoutingOperation> routingOperationList = productionOrderRoutingOperationMapper.selectList(
                 Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
@@ -353,6 +355,11 @@
                 stockInventoryDto.setQualitity(productQty);
                 stockInventoryDto.setProductModelId(productModel.getId());
                 stockInventoryService.addStockInRecordOnly(stockInventoryDto);
+                qualifiedBatchNo = resolveLatestStockInBatchNo(
+                        productionProductMain.getId(),
+                        StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(),
+                        productModel.getId(),
+                        "0");
             }
 
             productionOperationTask.setCompleteQuantity(defaultDecimal(productionOperationTask.getCompleteQuantity()).add(productQty));
@@ -391,8 +398,6 @@
             }
             ProductionAccount productionAccount = new ProductionAccount();
             productionAccount.setProductionProductMainId(productionProductMain.getId());
-//            productionAccount.setSalesLedgerId(productionOrder.getSalesLedgerId());
-//            productionAccount.setSalesLedgerProductId(productionOrder.getSalesLedgerProductId() == null ? null : productionOrder.getSalesLedgerProductId().longValue());
             productionAccount.setSchedulingUserId(user == null ? null : user.getUserId());
             productionAccount.setSchedulingUserName(user == null ? dto.getUserName() : user.getNickName());
             productionAccount.setFinishedNum(productQty);
@@ -401,11 +406,37 @@
             productionAccount.setSchedulingDate(LocalDateTime.now());
             productionAccountMapper.insert(productionAccount);
         }
-//        if (defaultDecimal(dto.getScrapQty()).compareTo(BigDecimal.ZERO) > 0) {
-//            stockUtils.addUnStock(productModel.getId(), dto.getScrapQty(),
-//                    StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode(), productionProductMain.getId());
-//        }
+        if (scrapQty.compareTo(BigDecimal.ZERO) > 0) {
+            stockUtils.addUnStockWithBatchNo(
+                    productModel.getId(),
+                    scrapQty,
+                    StockInQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode(),
+                    productionProductMain.getId(),
+                    qualifiedBatchNo);
+        }
         return true;
+    }
+
+    private String resolveLatestStockInBatchNo(Long recordId,
+                                               String recordType,
+                                               Long productModelId,
+                                               String stockType) {
+        if (recordId == null || productModelId == null) {
+            return null;
+        }
+        StockInRecord stockInRecord = stockInRecordService.getOne(
+                Wrappers.<StockInRecord>lambdaQuery()
+                        .eq(StockInRecord::getRecordId, recordId)
+                        .eq(StockInRecord::getRecordType, recordType)
+                        .eq(StockInRecord::getProductModelId, productModelId)
+                        .eq(StockInRecord::getType, stockType)
+                        .orderByDesc(StockInRecord::getId)
+                        .last("limit 1"),
+                false);
+        if (stockInRecord == null) {
+            throw new ServiceException("鏈壘鍒板搴旂殑鍏ュ簱鐢宠璁板綍");
+        }
+        return stockInRecord.getBatchNo();
     }
 
     private void syncOperationParamInputValue(ProductionProductMainDto dto,
@@ -605,7 +636,7 @@
         productionOrderRoutingOperationParamMapper.delete(
                 Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
                         .eq(ProductionOrderRoutingOperationParam::getProductionProductMainId, productionProductMain.getId()));
-        stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
+        stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
         stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode());
         stockUtils.deleteStockOutRecord(productionProductMain.getId(), StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());
         productionProductMainMapper.deleteById(productionProductMain.getId());
diff --git a/src/main/java/com/ruoyi/projectManagement/service/impl/PlanServiceImpl.java b/src/main/java/com/ruoyi/projectManagement/service/impl/PlanServiceImpl.java
index e05ce2e..d999843 100644
--- a/src/main/java/com/ruoyi/projectManagement/service/impl/PlanServiceImpl.java
+++ b/src/main/java/com/ruoyi/projectManagement/service/impl/PlanServiceImpl.java
@@ -7,6 +7,7 @@
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.ruoyi.basic.dto.StorageBlobVO;
+import com.ruoyi.basic.enums.ApplicationTypeEnum;
 import com.ruoyi.basic.enums.RecordTypeEnum;
 import com.ruoyi.basic.service.CustomerFollowUpFileService;
 import com.ruoyi.basic.utils.FileUtil;
@@ -53,13 +54,13 @@
     @Transactional(rollbackFor = Exception.class)
     public void savePlan(SavePlanVo savePlanVo) {
         Plan plan = BeanUtil.copyProperties(savePlanVo, Plan.class);
-        // 闄勪欢澶勭悊
-        fileUtil.saveStorageAttachmentByRecordTypeAndRecordId("", RecordTypeEnum.PLAN, savePlanVo.getId(), savePlanVo.getStorageBlobDTOs());
         if (savePlanVo.getId() == null) {
             planMapper.insert(plan);
         } else {
             planMapper.updateById(plan);
         }
+        // 闄勪欢澶勭悊
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.PLAN, plan.getId(), savePlanVo.getStorageBlobDTOs());
         planService.savePlanNode(plan.getId(), savePlanVo.getSavePlanNodeList());
     }
 
diff --git a/src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoStageHandleService.java b/src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoStageHandleService.java
index 2025777..76c7617 100644
--- a/src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoStageHandleService.java
+++ b/src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoStageHandleService.java
@@ -5,6 +5,7 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.ruoyi.basic.dto.StorageBlobVO;
+import com.ruoyi.basic.enums.ApplicationTypeEnum;
 import com.ruoyi.basic.enums.RecordTypeEnum;
 import com.ruoyi.basic.service.CustomerFollowUpFileService;
 import com.ruoyi.basic.utils.FileUtil;
@@ -48,18 +49,12 @@
     @Transactional
     public void save(@NotNull SaveInfoStageVo saveInfoStageVo) {
         InfoStage infoStage = BeanUtil.copyProperties(saveInfoStageVo, InfoStage.class);
-        // 闄勪欢澶勭悊
-        String attachmentIds = StrUtil.join(",", Optional.ofNullable(saveInfoStageVo.getAttachmentIds()).orElse(Collections.emptyList()));
-        infoStage.setAttachment(attachmentIds);
-
-        fileUtil.saveStorageAttachmentByRecordTypeAndRecordId("", RecordTypeEnum.INFO_STAGE, infoStage.getProjectManagementInfoId(), saveInfoStageVo.getStorageBlobDTOs());
-
         if (infoStage.getId() == null) {
             infoStageMapper.insert(infoStage);
         } else {
             infoStageMapper.updateById(infoStage);
         }
-
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.INFO_STAGE, infoStage.getId(), saveInfoStageVo.getStorageBlobDTOs());
         infoStageHandleService.syncInfoStage(infoStage.getProjectManagementInfoId());
     }
 
diff --git a/src/main/java/com/ruoyi/purchase/controller/PurchaseReturnOrdersController.java b/src/main/java/com/ruoyi/purchase/controller/PurchaseReturnOrdersController.java
index 16449e8..bb669b6 100644
--- a/src/main/java/com/ruoyi/purchase/controller/PurchaseReturnOrdersController.java
+++ b/src/main/java/com/ruoyi/purchase/controller/PurchaseReturnOrdersController.java
@@ -8,9 +8,13 @@
 import com.ruoyi.purchase.dto.PurchaseReturnOrderDto;
 import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper;
 import com.ruoyi.purchase.service.PurchaseReturnOrdersService;
+import com.ruoyi.purchase.vo.PurchaseStockInProductVo;
+import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.AllArgsConstructor;
 import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * <p>
@@ -56,5 +60,12 @@
         return AjaxResult.success();
     }
 
+    @GetMapping("/getByPurchaseLedgerId")
+    @Operation(summary = "閲囪喘閫�璐�-鏍规嵁閲囪喘璁㈠崟id鏌ヨ閲囪喘璁㈠崟瀵瑰簲鐨勫叆搴撲骇鍝佷俊鎭�")
+    public AjaxResult getByPurchaseLedgerId(Long purchaseLedgerId) {
+        List<PurchaseStockInProductVo> purchaseStockInProductVos = purchaseReturnOrdersService.getByPurchaseLedgerId(purchaseLedgerId);
+        return AjaxResult.success(purchaseStockInProductVos);
+    }
+
 
 }
diff --git a/src/main/java/com/ruoyi/purchase/dto/PurchaseReturnOrderProductsDto.java b/src/main/java/com/ruoyi/purchase/dto/PurchaseReturnOrderProductsDto.java
index c89c151..928d8bf 100644
--- a/src/main/java/com/ruoyi/purchase/dto/PurchaseReturnOrderProductsDto.java
+++ b/src/main/java/com/ruoyi/purchase/dto/PurchaseReturnOrderProductsDto.java
@@ -9,5 +9,7 @@
     private String productName;
     private String model;
     private String unit;
+    //鎵规鍙�
+    private String batchNo;
 
 }
diff --git a/src/main/java/com/ruoyi/purchase/dto/SimpleReturnOrderGroupDto.java b/src/main/java/com/ruoyi/purchase/dto/SimpleReturnOrderGroupDto.java
index dc9220a..e66382e 100644
--- a/src/main/java/com/ruoyi/purchase/dto/SimpleReturnOrderGroupDto.java
+++ b/src/main/java/com/ruoyi/purchase/dto/SimpleReturnOrderGroupDto.java
@@ -16,6 +16,6 @@
 @AllArgsConstructor
 @NoArgsConstructor
 public class SimpleReturnOrderGroupDto implements Serializable {
-    private Long salesLedgerProductId;
+    private Long productModelId;
     private BigDecimal sumReturnQuantity;
 }
diff --git a/src/main/java/com/ruoyi/purchase/mapper/PurchaseReturnOrdersMapper.java b/src/main/java/com/ruoyi/purchase/mapper/PurchaseReturnOrdersMapper.java
index c6f55b7..9d28354 100644
--- a/src/main/java/com/ruoyi/purchase/mapper/PurchaseReturnOrdersMapper.java
+++ b/src/main/java/com/ruoyi/purchase/mapper/PurchaseReturnOrdersMapper.java
@@ -1,14 +1,20 @@
 package com.ruoyi.purchase.mapper;
 
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.PurchaseReturnDto;
+import com.ruoyi.account.bean.vo.PurchaseReturnVo;
 import com.ruoyi.purchase.dto.PurchaseReturnOrderDto;
-import com.ruoyi.purchase.pojo.PurchaseReturnOrders;
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.ruoyi.purchase.dto.PurchaseReturnOrderHasAllInfoDto;
+import com.ruoyi.purchase.pojo.PurchaseReturnOrders;
+import com.ruoyi.purchase.vo.PurchaseReturnOrderProductsDetailVo;
+import com.ruoyi.purchase.vo.PurchaseStockInProductVo;
 import jakarta.validation.constraints.NotNull;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
  * <p>
@@ -23,4 +29,11 @@
     IPage<PurchaseReturnOrderHasAllInfoDto> listPage(Page page, @Param("params") PurchaseReturnOrderDto purchaseReturnOrder);
 
     PurchaseReturnOrderHasAllInfoDto getPurchaseReturnOrderHasAllInfoById(@Param("id") @NotNull Long id);
+
+    IPage<PurchaseReturnVo> listPageAccountPurchaseReturn(Page page, @Param("req") PurchaseReturnDto purchaseReturnDto);
+
+    //鏍规嵁閲囪喘璁㈠崟id鏌ヨ閲囪喘璁㈠崟瀵瑰簲鐨勫叆搴撲骇鍝佷俊鎭�
+    List<PurchaseStockInProductVo> getByPurchaseLedgerId(@Param("purchaseLedgerId") Long purchaseLedgerId);
+
+    List<PurchaseReturnOrderProductsDetailVo> getPurchaseReturnOrderProductsDetailById(@Param("id") Long id);
 }
diff --git a/src/main/java/com/ruoyi/purchase/pojo/PurchaseReturnOrderProducts.java b/src/main/java/com/ruoyi/purchase/pojo/PurchaseReturnOrderProducts.java
index 2a1b172..7738a34 100644
--- a/src/main/java/com/ruoyi/purchase/pojo/PurchaseReturnOrderProducts.java
+++ b/src/main/java/com/ruoyi/purchase/pojo/PurchaseReturnOrderProducts.java
@@ -1,20 +1,17 @@
 package com.ruoyi.purchase.pojo;
 
-import com.baomidou.mybatisplus.annotation.FieldFill;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Getter;
 import lombok.Setter;
 
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
 /**
  * <p>
- * 
+ *
  * </p>
  *
  * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
@@ -34,7 +31,7 @@
     @Schema(description = "閫�璐у崟id")
     private Long purchaseReturnOrderId;
 
-    @Schema(description = "閲囪喘浜у搧id")
+    @Schema(description = "閿�鍞彴璐︿骇鍝乮d")
     private Long salesLedgerProductId;
 
     @Schema(description = "閫�璐ф暟閲�")
@@ -54,4 +51,7 @@
     @TableField(fill = FieldFill.INSERT)
     private Long deptId;
 
+    @Schema(description = "鍏宠仈鍏ュ簱鍗昳d")
+    private Long stockInRecordId;
+
 }
diff --git a/src/main/java/com/ruoyi/purchase/service/PurchaseReturnOrdersService.java b/src/main/java/com/ruoyi/purchase/service/PurchaseReturnOrdersService.java
index 2038e09..14e040e 100644
--- a/src/main/java/com/ruoyi/purchase/service/PurchaseReturnOrdersService.java
+++ b/src/main/java/com/ruoyi/purchase/service/PurchaseReturnOrdersService.java
@@ -8,7 +8,10 @@
 import com.ruoyi.purchase.vo.PurchaseReturnDetailsVo;
 import com.ruoyi.purchase.dto.PurchaseReturnOrderHasAllInfoDto;
 
+import com.ruoyi.purchase.vo.PurchaseStockInProductVo;
 import jakarta.validation.constraints.NotNull;
+
+import java.util.List;
 
 /**
  * <p>
@@ -27,4 +30,7 @@
     PurchaseReturnDetailsVo getPurchaseReturnOrderDtoById(@NotNull Long id);
 
     void deleteById(@NotNull Long id);
+
+    List<PurchaseStockInProductVo> getByPurchaseLedgerId(Long purchaseLedgerId);
+
 }
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseReturnOrdersServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseReturnOrdersServiceImpl.java
index b5003ae..24e3405 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseReturnOrdersServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseReturnOrdersServiceImpl.java
@@ -1,7 +1,6 @@
 package com.ruoyi.purchase.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -9,24 +8,24 @@
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.account.pojo.AccountIncome;
 import com.ruoyi.account.service.AccountIncomeService;
-import com.ruoyi.common.enums.SaleEnum;
 import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
 import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.framework.security.LoginUser;
 import com.ruoyi.procurementrecord.utils.StockUtils;
 import com.ruoyi.purchase.dto.PurchaseReturnOrderDto;
+import com.ruoyi.purchase.dto.PurchaseReturnOrderHasAllInfoDto;
 import com.ruoyi.purchase.dto.PurchaseReturnOrderProductsDto;
 import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
 import com.ruoyi.purchase.mapper.PurchaseReturnOrderProductsMapper;
 import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper;
-import com.ruoyi.purchase.pojo.PurchaseLedger;
 import com.ruoyi.purchase.pojo.PurchaseReturnOrderProducts;
 import com.ruoyi.purchase.pojo.PurchaseReturnOrders;
 import com.ruoyi.purchase.service.PurchaseReturnOrdersService;
 import com.ruoyi.purchase.vo.PurchaseReturnDetailsVo;
+import com.ruoyi.purchase.vo.PurchaseReturnOrderProductsDetailVo;
+import com.ruoyi.purchase.vo.PurchaseStockInProductVo;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
-import com.ruoyi.purchase.dto.PurchaseReturnOrderHasAllInfoDto;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.sales.service.ISalesLedgerService;
 import com.ruoyi.stock.mapper.StockOutRecordMapper;
@@ -36,8 +35,6 @@
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
-import java.util.Map;
-import java.util.Objects;
 import java.util.stream.Collectors;
 
 /**
@@ -76,13 +73,13 @@
                 purchaseReturnOrderProductsDto.setSalesLedgerProductId(purchaseReturnOrderProductsDto.getSalesLedgerProductId());
                 purchaseReturnOrderProductsDto.setPurchaseReturnOrderId(purchaseReturnOrderDto.getId());
                 purchaseReturnOrderProductsDto.setReturnQuantity(purchaseReturnOrderProductsDto.getReturnQuantity());
+                purchaseReturnOrderProductsDto.setStockInRecordId(purchaseReturnOrderProductsDto.getStockInRecordId());
                 // 杩欓噷涓烘柊澧炲洜姝d涓簄ull
                 purchaseReturnOrderProductsDto.setId(null);
                 purchaseReturnOrderProductsMapper.insert(purchaseReturnOrderProductsDto);
-                //搴撳瓨闇�瑕佸嚭搴�(閲囪喘閫�璐�)
-                PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(purchaseReturnOrderDto.getPurchaseLedgerId());
+                //搴撳瓨闇�瑕佸嚭搴�(閲囪喘閫�璐�,甯︽壒娆″彿)
                 SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(purchaseReturnOrderProductsDto.getSalesLedgerProductId());
-                stockUtils.substractStock(salesLedgerProduct.getProductModelId(), purchaseReturnOrderProductsDto.getReturnQuantity(), StockOutQualifiedRecordTypeEnum.PURCHASE_RETURN_STOCK_OUT.getCode(), purchaseReturnOrderDto.getId(), purchaseLedger.getPurchaseContractNumber()+"-"+salesLedgerProduct.getId());
+                stockUtils.substractStock(salesLedgerProduct.getProductModelId(), purchaseReturnOrderProductsDto.getReturnQuantity(), StockOutQualifiedRecordTypeEnum.PURCHASE_RETURN_STOCK_OUT.getCode(), purchaseReturnOrderProductsDto.getId(), purchaseReturnOrderProductsDto.getBatchNo());
             }
         }else {
             throw new RuntimeException("璇烽�夋嫨閫�璐у晢鍝�");
@@ -107,25 +104,12 @@
 
     @Override
     public PurchaseReturnDetailsVo getPurchaseReturnOrderDtoById(Long id) {
+        //鏌ヤ富浣�
         PurchaseReturnOrderHasAllInfoDto purchaseReturnOrders = purchaseReturnOrdersMapper.getPurchaseReturnOrderHasAllInfoById(id);
         PurchaseReturnDetailsVo purchaseReturnOrderDto = BeanUtil.copyProperties(purchaseReturnOrders, PurchaseReturnDetailsVo.class);
-        // 鏌ヨ鍑轰粬鍏蜂綋瀵瑰簲鐨勯��璐�
-        LambdaQueryWrapper<PurchaseReturnOrderProducts> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(PurchaseReturnOrderProducts::getPurchaseReturnOrderId, purchaseReturnOrders.getId());
-
-        List<PurchaseReturnOrderProducts> purchaseReturnOrderProducts = purchaseReturnOrderProductsMapper.selectList(queryWrapper);
-        List<PurchaseReturnDetailsVo.PurchaseReturnOrderProductsDetailVo> purchaseReturnOrderProductsDetailVos = BeanUtil.copyToList(purchaseReturnOrderProducts, PurchaseReturnDetailsVo.PurchaseReturnOrderProductsDetailVo.class);
-        // 鏌ヨ鍑哄搴旂殑鍟嗗搧淇℃伅
-        List<Long> productIds = purchaseReturnOrderProductsDetailVos.stream().map(PurchaseReturnDetailsVo.PurchaseReturnOrderProductsDetailVo::getSalesLedgerProductId).distinct().filter(Objects::nonNull).collect(Collectors.toList());
-        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerService.getSalesLedgerProductListByIds(productIds, SaleEnum.PURCHASE);
-        Map<Long, SalesLedgerProduct> productmap = salesLedgerProducts.stream().collect(Collectors.toMap(SalesLedgerProduct::getId, product -> product));
-        purchaseReturnOrderProductsDetailVos.forEach(purchaseReturnOrderProductsDetailVo -> {
-            purchaseReturnOrderProductsDetailVo.setSalesLedgerProduct(productmap.get(purchaseReturnOrderProductsDetailVo.getSalesLedgerProductId()));
-        });
-
+        //鏌ユ槑缁�
+        List<PurchaseReturnOrderProductsDetailVo> purchaseReturnOrderProductsDetailVos = purchaseReturnOrdersMapper.getPurchaseReturnOrderProductsDetailById(id);
         purchaseReturnOrderDto.setPurchaseReturnOrderProductsDetailVoList(purchaseReturnOrderProductsDetailVos);
-
-
         return purchaseReturnOrderDto;
     }
 
@@ -133,13 +117,14 @@
     @Transactional
     public void deleteById(Long id) {
         purchaseReturnOrdersMapper.deleteById(id);
+        List<PurchaseReturnOrderProducts> purchaseReturnOrderProducts = purchaseReturnOrderProductsMapper.selectList(Wrappers.<PurchaseReturnOrderProducts>lambdaQuery().eq(PurchaseReturnOrderProducts::getPurchaseReturnOrderId, id));
         LambdaUpdateWrapper<PurchaseReturnOrderProducts> updateWrapper = new LambdaUpdateWrapper<>();
         updateWrapper.eq(PurchaseReturnOrderProducts::getPurchaseReturnOrderId, id);
         purchaseReturnOrderProductsMapper.delete(updateWrapper);
         //(閲囪喘閫�璐х殑鏁版嵁闇�瑕佸垹鎺�)
         stockOutRecordMapper.delete(Wrappers.<StockOutRecord>lambdaQuery()
                 .eq(StockOutRecord::getRecordType,StockOutQualifiedRecordTypeEnum.PURCHASE_RETURN_STOCK_OUT.getCode())
-                .eq(StockOutRecord::getRecordId, id));
+                .in(StockOutRecord::getRecordId, purchaseReturnOrderProducts.stream().map(PurchaseReturnOrderProducts::getId).collect(Collectors.toList())));
         // 璐㈠姟
         LambdaUpdateWrapper<AccountIncome> updateWrapperAccountIncome = new LambdaUpdateWrapper<>();
         updateWrapperAccountIncome.eq(AccountIncome::getBusinessId, id);
@@ -147,4 +132,9 @@
         updateWrapperAccountIncome.eq(AccountIncome::getIncomeType, 4);
         accountIncomeService.remove(updateWrapperAccountIncome);
     }
+
+    @Override
+    public List<PurchaseStockInProductVo> getByPurchaseLedgerId(Long purchaseLedgerId) {
+        return purchaseReturnOrdersMapper.getByPurchaseLedgerId(purchaseLedgerId);
+    }
 }
diff --git a/src/main/java/com/ruoyi/purchase/vo/PurchaseReturnDetailsVo.java b/src/main/java/com/ruoyi/purchase/vo/PurchaseReturnDetailsVo.java
index 975cd5c..6496b4a 100644
--- a/src/main/java/com/ruoyi/purchase/vo/PurchaseReturnDetailsVo.java
+++ b/src/main/java/com/ruoyi/purchase/vo/PurchaseReturnDetailsVo.java
@@ -1,14 +1,12 @@
 package com.ruoyi.purchase.vo;
 
 import com.ruoyi.purchase.dto.PurchaseReturnOrderHasAllInfoDto;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
-import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -24,15 +22,4 @@
 
     private List<PurchaseReturnOrderProductsDetailVo> purchaseReturnOrderProductsDetailVoList;
 
-    @Data
-    @AllArgsConstructor
-    @NoArgsConstructor
-    public static class PurchaseReturnOrderProductsDetailVo implements Serializable {
-        private Long id;
-        private BigDecimal returnQuantity;
-        private Long salesLedgerProductId;
-        private Long purchaseReturnOrderId;
-
-        private SalesLedgerProduct salesLedgerProduct;
-    }
 }
diff --git a/src/main/java/com/ruoyi/purchase/vo/PurchaseReturnOrderProductsDetailVo.java b/src/main/java/com/ruoyi/purchase/vo/PurchaseReturnOrderProductsDetailVo.java
new file mode 100644
index 0000000..dcd58b5
--- /dev/null
+++ b/src/main/java/com/ruoyi/purchase/vo/PurchaseReturnOrderProductsDetailVo.java
@@ -0,0 +1,62 @@
+package com.ruoyi.purchase.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+
+
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class PurchaseReturnOrderProductsDetailVo  {
+
+    @Schema(description = "閫�璐ф槑缁唅d")
+    private Long id;
+
+    @Schema(description = "閿�鍞彴璐︾殑浜у搧id")
+    private Long salesLedgerProductId;
+
+    @Schema(description = "浜у搧瑙勬牸id")
+    private Long productModelId;
+
+    @Schema(description = "浜у搧澶х被")
+    private String productCategory;
+
+    @Schema(description = "瑙勬牸鍨嬪彿")
+    private String specificationModel;
+
+    @Schema(description = "鍗曚綅")
+    private String unit;
+
+    @Schema(description = "鍏ュ簱鍗曞彿")
+    private String inboundBatches;
+
+    @Schema(description = "鍏ュ簱鏁伴噺")
+    private BigDecimal stockInNum;
+
+    @Schema(description = "鎵规鍙�")
+    private String batchNo;
+
+    @Schema(description = "鏈��璐ф暟")
+    private BigDecimal unQuantity;
+
+    @Schema(description = "宸查��璐ф暟閲�")
+    private BigDecimal totalReturnNum;
+
+    @Schema(description = "鍚◣鍗曚环")
+    private BigDecimal taxInclusiveUnitPrice;
+
+    @Schema(description = "閫�璐ф暟閲�")
+    private BigDecimal returnQuantity;
+
+    @Schema(description = "閫�璐у崟id")
+    private Long purchaseReturnOrderId;
+
+    @Schema(description = "鏄惁璐ㄦ")
+    private Boolean isChecked;
+
+}
diff --git a/src/main/java/com/ruoyi/purchase/vo/PurchaseStockInProductVo.java b/src/main/java/com/ruoyi/purchase/vo/PurchaseStockInProductVo.java
new file mode 100644
index 0000000..3f8e0ec
--- /dev/null
+++ b/src/main/java/com/ruoyi/purchase/vo/PurchaseStockInProductVo.java
@@ -0,0 +1,50 @@
+package com.ruoyi.purchase.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(name = "PurchaseStockInProductVo", description = "閲囪喘绠$悊--閲囪喘璁㈠崟涓嬪叆搴撲骇鍝佸垪琛�")
+public class PurchaseStockInProductVo {
+
+    @Schema(description = "鍏ュ簱鍗昳d")
+    private Long id;
+
+    @Schema(description = "閿�鍞彴璐︾殑浜у搧id")
+    private Long salesLedgerProductId;
+
+    @Schema(description = "浜у搧瑙勬牸id")
+    private Long productModelId;
+
+    @Schema(description = "浜у搧澶х被")
+    private String productCategory;
+
+    @Schema(description = "瑙勬牸鍨嬪彿")
+    private String specificationModel;
+
+    @Schema(description = "鍗曚綅")
+    private String unit;
+
+    @Schema(description = "鍏ュ簱鍗曞彿")
+    private String inboundBatches;
+
+    @Schema(description = "鍏ュ簱鏁伴噺")
+    private BigDecimal stockInNum;
+
+    @Schema(description = "鎵规鍙�")
+    private String batchNo;
+
+    @Schema(description = "鍙��璐ф暟")
+    private BigDecimal unQuantity;
+
+    @Schema(description = "閫�璐ф�绘暟")
+    private BigDecimal totalReturnNum;
+
+    @Schema(description = "鍚◣鍗曚环")
+    private BigDecimal taxInclusiveUnitPrice;
+
+    @Schema(description = "鏄惁璐ㄦ")
+    private Boolean isChecked;
+}
diff --git a/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java b/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
index 8c53500..b23bb67 100644
--- a/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
+++ b/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -20,6 +20,8 @@
 import com.ruoyi.quality.pojo.QualityInspect;
 import com.ruoyi.quality.pojo.QualityInspectParam;
 import com.ruoyi.quality.pojo.QualityUnqualified;
+import com.ruoyi.stock.pojo.StockInRecord;
+import com.ruoyi.stock.service.StockInRecordService;
 import com.ruoyi.quality.service.IQualityInspectParamService;
 import com.ruoyi.quality.service.IQualityInspectService;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
@@ -34,6 +36,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URLEncoder;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -45,6 +48,7 @@
 
     private final StockUtils stockUtils;
     private final StockInventoryService stockInventoryService;
+    private final StockInRecordService stockInRecordService;
     private QualityInspectMapper qualityInspectMapper;
 
     private IQualityInspectParamService qualityInspectParamService;
@@ -103,16 +107,61 @@
             // stockUtils.addStock(qualityInspect.getProductModelId(), qualityInspect.getQuantity(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode(), qualityInspect.getId());
             //浠呮坊鍔犲叆搴撹褰�
             StockInventoryDto stockInventoryDto = new StockInventoryDto();
+            //濡傛灉鏄噰璐川妫�鍚堟牸鍏ュ簱閫夌敤CUSTOMIZATION_UNSTOCK_OUT,鍏朵綑鍚堟牸鍏ュ簱閫夌敤QUALITYINSPECT_STOCK_IN
             stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode()));
+            if (ObjectUtils.isNotEmpty(qualityInspect.getPurchaseLedgerId())){
+                stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode()));
+            }
             stockInventoryDto.setRecordId(qualityInspect.getId());
             stockInventoryDto.setProductModelId(qualityInspect.getProductModelId());
             stockInventoryDto.setQualitity(qualityInspect.getQuantity());
+            stockInventoryDto.setBatchNo(resolveProductionBatchNo(
+                    qualityInspect.getProductMainId(),
+                    qualityInspect.getId(),
+                    qualityInspect.getProductModelId()));
             stockInventoryService.addStockInRecordOnly(stockInventoryDto);
         }
         qualityInspect.setInspectState(1);//宸叉彁浜�
         return qualityInspectMapper.updateById(qualityInspect);
     }
 
+    private String resolveProductionBatchNo(Long productionProductMainId,
+                                            Long qualityInspectId,
+                                            Long productModelId) {
+        if (productModelId == null) {
+            return null;
+        }
+        if (productionProductMainId != null) {
+            StockInRecord productionRecord = stockInRecordService.getOne(
+                    Wrappers.<StockInRecord>lambdaQuery()
+                            .eq(StockInRecord::getRecordId, productionProductMainId)
+                            .eq(StockInRecord::getProductModelId, productModelId)
+                            .in(StockInRecord::getRecordType, Arrays.asList(
+                                    StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(),
+                                    StockInQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode()))
+                            .isNotNull(StockInRecord::getBatchNo)
+                            .orderByDesc(StockInRecord::getId)
+                            .last("limit 1"),
+                    false);
+            if (productionRecord != null) {
+                return productionRecord.getBatchNo();
+            }
+        }
+        if (qualityInspectId == null) {
+            return null;
+        }
+        StockInRecord inspectRecord = stockInRecordService.getOne(
+                Wrappers.<StockInRecord>lambdaQuery()
+                        .eq(StockInRecord::getRecordId, qualityInspectId)
+                        .eq(StockInRecord::getProductModelId, productModelId)
+                        .eq(StockInRecord::getRecordType, StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode())
+                        .isNotNull(StockInRecord::getBatchNo)
+                        .orderByDesc(StockInRecord::getId)
+                        .last("limit 1"),
+                false);
+        return inspectRecord == null ? null : inspectRecord.getBatchNo();
+    }
+
     /*鐢熸垚妫�楠屾姤鍛�*/
     @Override
     public void down(HttpServletResponse response, QualityInspect qualityInspect) {
diff --git a/src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java b/src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
index 0296ef4..b3d93b8 100644
--- a/src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
+++ b/src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
@@ -6,7 +6,6 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
-import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.bean.BeanUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -24,6 +23,8 @@
 import com.ruoyi.quality.mapper.QualityUnqualifiedMapper;
 import com.ruoyi.quality.pojo.QualityInspect;
 import com.ruoyi.quality.pojo.QualityUnqualified;
+import com.ruoyi.stock.pojo.StockInRecord;
+import com.ruoyi.stock.service.StockInRecordService;
 import com.ruoyi.quality.service.IQualityInspectService;
 import com.ruoyi.quality.service.IQualityUnqualifiedService;
 import com.ruoyi.stock.service.StockUninventoryService;
@@ -34,6 +35,7 @@
 import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -51,6 +53,7 @@
     private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
     private final ProductionOperationTaskMapper productionOperationTaskMapper;
     private final StockUninventoryService stockUninventoryService;
+    private final StockInRecordService stockInRecordService;
 
     @Override
     public IPage<QualityUnqualified> qualityUnqualifiedListPage(Page page, QualityUnqualified qualityUnqualified) {
@@ -68,6 +71,8 @@
     public int deal(QualityUnqualified qualityUnqualified) {
         QualityUnqualified unqualified = qualityUnqualifiedMapper.selectById(qualityUnqualified.getId());
         QualityInspect qualityInspect = qualityInspectService.getById(unqualified.getInspectId());
+        String batchNo = qualityInspect == null ? null
+                : resolveProductionBatchNo(qualityInspect.getProductMainId(), qualityInspect.getId(), qualityInspect.getProductModelId());
         if (ObjectUtils.isNotNull(qualityInspect) && qualityInspect.getInspectType() != 0) {
             switch (qualityUnqualified.getDealResult()) {
                 case "杩斾慨":
@@ -81,12 +86,12 @@
                     }
                     break;
                 case "鎶ュ簾":
-                    stockUtils.addUnStock(qualityInspect.getProductModelId(), unqualified.getQuantity(),
-                            StockInUnQualifiedRecordTypeEnum.DEFECTIVE_SCRAP.getCode(), unqualified.getId());
+                    stockUtils.addUnStockWithBatchNo(qualityInspect.getProductModelId(), unqualified.getQuantity(),
+                            StockInQualifiedRecordTypeEnum.DEFECTIVE_SCRAP.getCode(), unqualified.getId(), batchNo);
                     break;
                 case "璁╂鏀捐":
-                    stockUtils.addStock(qualityInspect.getProductModelId(), unqualified.getQuantity(),
-                            StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId());
+                    stockUtils.addStockWithBatchNo(qualityInspect.getProductModelId(), unqualified.getQuantity(),
+                            StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId(), batchNo);
                     break;
                 default:
                     break;
@@ -96,7 +101,7 @@
             switch (qualityUnqualified.getDealResult()) {
                 case "鎶ュ簾":
                     stockUtils.addUnStock(modelId, unqualified.getQuantity(),
-                            StockInUnQualifiedRecordTypeEnum.DEFECTIVE_SCRAP.getCode(), unqualified.getId());
+                            StockInQualifiedRecordTypeEnum.DEFECTIVE_SCRAP.getCode(), unqualified.getId());
                     break;
                 case "璁╂鏀捐":
                     stockUtils.addStock(modelId, unqualified.getQuantity(),
@@ -220,4 +225,41 @@
     private BigDecimal defaultDecimal(BigDecimal value) {
         return value == null ? BigDecimal.ZERO : value;
     }
+
+    private String resolveProductionBatchNo(Long productionProductMainId,
+                                            Long qualityInspectId,
+                                            Long productModelId) {
+        if (productModelId == null) {
+            return null;
+        }
+        if (productionProductMainId != null) {
+            StockInRecord productionRecord = stockInRecordService.getOne(
+                    Wrappers.<StockInRecord>lambdaQuery()
+                            .eq(StockInRecord::getRecordId, productionProductMainId)
+                            .eq(StockInRecord::getProductModelId, productModelId)
+                            .in(StockInRecord::getRecordType, Arrays.asList(
+                                    StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(),
+                                    StockInQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode()))
+                            .isNotNull(StockInRecord::getBatchNo)
+                            .orderByDesc(StockInRecord::getId)
+                            .last("limit 1"),
+                    false);
+            if (productionRecord != null) {
+                return productionRecord.getBatchNo();
+            }
+        }
+        if (qualityInspectId == null) {
+            return null;
+        }
+        StockInRecord inspectRecord = stockInRecordService.getOne(
+                Wrappers.<StockInRecord>lambdaQuery()
+                        .eq(StockInRecord::getRecordId, qualityInspectId)
+                        .eq(StockInRecord::getProductModelId, productModelId)
+                        .eq(StockInRecord::getRecordType, StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode())
+                        .isNotNull(StockInRecord::getBatchNo)
+                        .orderByDesc(StockInRecord::getId)
+                        .last("limit 1"),
+                false);
+        return inspectRecord == null ? null : inspectRecord.getBatchNo();
+    }
 }
diff --git a/src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java b/src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java
index a4c1106..9485919 100644
--- a/src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java
+++ b/src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java
@@ -71,9 +71,9 @@
         if (CollUtil.isEmpty(list)) {
             return AjaxResult.success(list);
         }
-        List<Long> productIds = list.stream().map(SalesLedgerProduct::getId).collect(Collectors.toList());
+        List<Long> productIds = list.stream().map(SalesLedgerProduct::getProductModelId).collect(Collectors.toList());
         List<SimpleReturnOrderGroupDto> groupListByProductIds = purchaseReturnOrderProductsMapper.getReturnOrderGroupListByProductIds(productIds);
-        Map<Long, BigDecimal> returnOrderGroupDtoMap = groupListByProductIds.stream().collect(Collectors.toMap(SimpleReturnOrderGroupDto::getSalesLedgerProductId, item -> item.getSumReturnQuantity()));
+        Map<Long, BigDecimal> returnOrderGroupDtoMap = groupListByProductIds.stream().collect(Collectors.toMap(SimpleReturnOrderGroupDto::getProductModelId, item -> item.getSumReturnQuantity()));
 
         list.forEach(item -> {
             if (item.getFutureTickets().compareTo(BigDecimal.ZERO) == 0) {
@@ -90,7 +90,7 @@
                 }
             }
             // 缁熻閫�璐ф暟閲�
-            BigDecimal returnQuality = returnOrderGroupDtoMap.getOrDefault(item.getId(), BigDecimal.ZERO);
+            BigDecimal returnQuality = returnOrderGroupDtoMap.getOrDefault(item.getProductModelId(), BigDecimal.ZERO);
             item.setReturnQuality(returnQuality);
             item.setAvailableQuality(item.getQuantity().subtract(returnQuality));
         });
diff --git a/src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java b/src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java
index 0257f2a..f707b5b 100644
--- a/src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java
+++ b/src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java
@@ -116,7 +116,7 @@
 
 
     @GetMapping("/getByCustomerName")
-    @Operation(summary = "閫氳繃瀹㈡埛鍚嶇О鏌ヨ")
+    @Operation(summary = "閫氳繃瀹㈡埛鍚嶇О鏌ヨ鍏宠仈鐨勫彂璐у崟鍙�")
     public AjaxResult getByCustomerName(String customerName) {
         return AjaxResult.success(shippingInfoService.getShippingInfoByCustomerName(customerName));
     }
diff --git a/src/main/java/com/ruoyi/sales/dto/ShippingInfoDto.java b/src/main/java/com/ruoyi/sales/dto/ShippingInfoDto.java
index e12149f..43409bc 100644
--- a/src/main/java/com/ruoyi/sales/dto/ShippingInfoDto.java
+++ b/src/main/java/com/ruoyi/sales/dto/ShippingInfoDto.java
@@ -8,6 +8,7 @@
 import com.ruoyi.sales.pojo.ShippingProductDetail;
 import lombok.Data;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -40,6 +41,11 @@
     private List<Long> batchNo;
     private List<ShippingProductDetail> batchNoDetailList;
 
+    //鍏宠仈鐨勫嚭搴撳崟鍙�
+    private String outboundBatches;
+
+    //鍙戣揣鏁伴噺
+    private BigDecimal totalQuantity;
 
 
 }
diff --git a/src/main/java/com/ruoyi/sales/mapper/ShippingInfoMapper.java b/src/main/java/com/ruoyi/sales/mapper/ShippingInfoMapper.java
index 57b142d..07bddbb 100644
--- a/src/main/java/com/ruoyi/sales/mapper/ShippingInfoMapper.java
+++ b/src/main/java/com/ruoyi/sales/mapper/ShippingInfoMapper.java
@@ -3,9 +3,7 @@
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.bean.dto.SalesOutboundDto;
-import com.ruoyi.account.bean.vo.SalesOutboundVo;
-import com.ruoyi.sales.dto.SalesLedgerProductDto;
+import com.ruoyi.procurementrecord.bean.vo.ShippingProductVo;
 import com.ruoyi.sales.dto.ShippingInfoDto;
 import com.ruoyi.sales.pojo.ShippingInfo;
 import org.apache.ibatis.annotations.Param;
@@ -21,9 +19,7 @@
 
     List<ShippingInfo> listAll();
 
-    List<SalesLedgerProductDto> getReturnManagementDtoById(@Param("shippingId")Long shippingId);
+    List<ShippingProductVo> getReturnManagementDtoById(@Param("shippingId")Long shippingId);
 
     List<ShippingInfo> getShippingInfoByCustomerName(String customerName);
-
-    IPage<SalesOutboundVo> listPageByOutbound(Page page, @Param("req") SalesOutboundDto salesOutboundDto);
 }
diff --git a/src/main/java/com/ruoyi/sales/service/ShippingInfoService.java b/src/main/java/com/ruoyi/sales/service/ShippingInfoService.java
index 69e8245..aa7bad5 100644
--- a/src/main/java/com/ruoyi/sales/service/ShippingInfoService.java
+++ b/src/main/java/com/ruoyi/sales/service/ShippingInfoService.java
@@ -3,7 +3,7 @@
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.ruoyi.sales.dto.SalesLedgerProductDto;
+import com.ruoyi.procurementrecord.bean.vo.ShippingProductVo;
 import com.ruoyi.sales.dto.ShippingApproveDto;
 import com.ruoyi.sales.dto.ShippingInfoDto;
 import com.ruoyi.sales.dto.ShippingProductDetailDto;
@@ -22,7 +22,7 @@
 
     boolean delete(List<Long> ids);
 
-    List<SalesLedgerProductDto> getReturnManagementDtoById( Long shippingId);
+    List<ShippingProductVo> getReturnManagementDtoById(Long shippingId);
 
     List<ShippingInfo> getShippingInfoByCustomerName(String customerName);
 
diff --git a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
index 9803611..a2f918b 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -9,10 +9,13 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.account.service.AccountIncomeService;
+import com.ruoyi.basic.enums.ApplicationTypeEnum;
+import com.ruoyi.basic.enums.RecordTypeEnum;
 import com.ruoyi.basic.mapper.CustomerMapper;
 import com.ruoyi.basic.mapper.ProductMapper;
 import com.ruoyi.basic.mapper.ProductModelMapper;
 import com.ruoyi.basic.pojo.Customer;
+import com.ruoyi.basic.utils.FileUtil;
 import com.ruoyi.common.enums.FileNameType;
 import com.ruoyi.common.enums.SaleEnum;
 import com.ruoyi.common.exception.base.BaseException;
@@ -102,6 +105,8 @@
     private final ProductionProductInputMapper productionProductInputMapper;
     private final QualityInspectMapper qualityInspectMapper;
     private final RedisTemplate<String, String> redisTemplate;
+    private final FileUtil fileUtil;
+
     @Autowired
     private SysDeptMapper sysDeptMapper;
     @Value("${file.upload-dir}")
@@ -142,14 +147,14 @@
         List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(productWrapper);
         if (type.equals(SaleEnum.PURCHASE)) {
             // 鏌ヨ閫�璐т俊鎭�
-            List<Long> productIds = salesLedgerProducts.stream().map(SalesLedgerProduct::getId).collect(Collectors.toList());
+            List<Long> productIds = salesLedgerProducts.stream().map(SalesLedgerProduct::getProductModelId).collect(Collectors.toList());
             List<SimpleReturnOrderGroupDto> groupListByProductIds = new ArrayList<>();
             if(CollectionUtils.isNotEmpty(productIds)){
                 groupListByProductIds = purchaseReturnOrderProductsMapper.getReturnOrderGroupListByProductIds(productIds);
             }
-            Map<Long, BigDecimal> returnOrderGroupDtoMap = groupListByProductIds.stream().collect(Collectors.toMap(SimpleReturnOrderGroupDto::getSalesLedgerProductId, SimpleReturnOrderGroupDto::getSumReturnQuantity));
+            Map<Long, BigDecimal> returnOrderGroupDtoMap = groupListByProductIds.stream().collect(Collectors.toMap(SimpleReturnOrderGroupDto::getProductModelId, SimpleReturnOrderGroupDto::getSumReturnQuantity));
             salesLedgerProducts.forEach(item -> {
-                BigDecimal returnQuality = returnOrderGroupDtoMap.getOrDefault(item.getId(), BigDecimal.ZERO);
+                BigDecimal returnQuality = returnOrderGroupDtoMap.getOrDefault(item.getProductModelId(), BigDecimal.ZERO);
                 item.setReturnQuality(returnQuality);
                 item.setAvailableQuality(item.getQuantity().subtract(returnQuality));
             });
@@ -582,125 +587,44 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int addOrUpdateSalesLedger(SalesLedgerDto salesLedgerDto) {
-        try {
-            // 1. 鏍¢獙瀹㈡埛淇℃伅
-            Customer customer = customerMapper.selectById(salesLedgerDto.getCustomerId());
-            if (customer == null) {
-                throw new BaseException("瀹㈡埛涓嶅瓨鍦�");
-            }
-
-            // 2. DTO杞珽ntity
-            SalesLedger salesLedger = convertToEntity(salesLedgerDto);
-            salesLedger.setCustomerName(customer.getCustomerName());
-            salesLedger.setTenantId(customer.getTenantId());
-            // 3. 鏂板鎴栨洿鏂颁富琛�
-            if (salesLedger.getId() == null) {
-                String contractNo = generateSalesContractNo();
-                salesLedger.setSalesContractNo(contractNo);
-                salesLedgerMapper.insert(salesLedger);
-            } else {
-                salesLedgerMapper.updateById(salesLedger);
-            }
-
-            // 4. 澶勭悊瀛愯〃鏁版嵁
-            List<SalesLedgerProduct> productList = salesLedgerDto.getProductData();
-            if (productList != null && !productList.isEmpty()) {
-                handleSalesLedgerProducts(salesLedger.getId(), productList, EnumUtil.fromCode(SaleEnum.class, salesLedgerDto.getType()));
-                updateMainContractAmount(
-                        salesLedger.getId(),
-                        productList,
-                        SalesLedgerProduct::getTaxInclusiveTotalPrice,
-                        salesLedgerMapper,
-                        SalesLedger.class
-                );
-            }
-
-            // 5. 杩佺Щ涓存椂鏂囦欢鍒版寮忕洰褰�
-            if (salesLedgerDto.getTempFileIds() != null && !salesLedgerDto.getTempFileIds().isEmpty()) {
-                migrateTempFilesToFormal(salesLedger.getId(), salesLedgerDto.getTempFileIds());
-            }
-            return 1;
-        } catch (IOException e) {
-            throw new BaseException("鏂囦欢杩佺Щ澶辫触: " + e.getMessage());
+        // 1. 鏍¢獙瀹㈡埛淇℃伅
+        Customer customer = customerMapper.selectById(salesLedgerDto.getCustomerId());
+        if (customer == null) {
+            throw new BaseException("瀹㈡埛涓嶅瓨鍦�");
         }
+
+        // 2. DTO杞珽ntity
+        SalesLedger salesLedger = convertToEntity(salesLedgerDto);
+        salesLedger.setCustomerName(customer.getCustomerName());
+        salesLedger.setTenantId(customer.getTenantId());
+        // 3. 鏂板鎴栨洿鏂颁富琛�
+        if (salesLedger.getId() == null) {
+            String contractNo = generateSalesContractNo();
+            salesLedger.setSalesContractNo(contractNo);
+            salesLedgerMapper.insert(salesLedger);
+        } else {
+            salesLedgerMapper.updateById(salesLedger);
+        }
+
+
+        // 4. 澶勭悊瀛愯〃鏁版嵁
+        List<SalesLedgerProduct> productList = salesLedgerDto.getProductData();
+        if (productList != null && !productList.isEmpty()) {
+            handleSalesLedgerProducts(salesLedger.getId(), productList, EnumUtil.fromCode(SaleEnum.class, salesLedgerDto.getType()));
+            updateMainContractAmount(
+                    salesLedger.getId(),
+                    productList,
+                    SalesLedgerProduct::getTaxInclusiveTotalPrice,
+                    salesLedgerMapper,
+                    SalesLedger.class
+            );
+        }
+
+        // 5. 淇濆瓨閿�鍞彴璐﹂檮浠�
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.SALES_LEDGER, salesLedger.getId(), salesLedgerDto.getStorageBlobDTOs());
+
+        return 1;
     }
-
-    /**
-     * 灏嗕复鏃舵枃浠惰縼绉诲埌姝e紡鐩綍
-     *
-     * @param businessId  涓氬姟ID锛堥攢鍞彴璐D锛�
-     * @param tempFileIds 涓存椂鏂囦欢ID鍒楄〃
-     * @throws IOException 鏂囦欢鎿嶄綔寮傚父
-     */
-    private void migrateTempFilesToFormal(Long businessId, List<String> tempFileIds) throws IOException {
-        if (CollectionUtils.isEmpty(tempFileIds)) {
-            return;
-        }
-
-        // 鏋勫缓姝e紡鐩綍璺緞锛堟寜涓氬姟绫诲瀷鍜屾棩鏈熷垎缁勶級
-        String formalDir = uploadDir + LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE);
-
-        Path formalDirPath = Paths.get(formalDir);
-
-        // 纭繚姝e紡鐩綍瀛樺湪锛堥�掑綊鍒涘缓锛�
-        if (!Files.exists(formalDirPath)) {
-            Files.createDirectories(formalDirPath);
-        }
-
-        for (String tempFileId : tempFileIds) {
-            // 鏌ヨ涓存椂鏂囦欢璁板綍
-            TempFile tempFile = tempFileMapper.selectById(tempFileId);
-            if (tempFile == null) {
-                log.warn("涓存椂鏂囦欢涓嶅瓨鍦紝璺宠繃澶勭悊: {}", tempFileId);
-                continue;
-            }
-
-            // 鏋勫缓姝e紡鏂囦欢鍚嶏紙鍖呭惈涓氬姟ID鍜屾椂闂存埑锛岄伩鍏嶅啿绐侊級
-            String originalFilename = tempFile.getOriginalName();
-            String fileExtension = FilenameUtils.getExtension(originalFilename);
-            String formalFilename = businessId + "_" +
-                    System.currentTimeMillis() + "_" +
-                    UUID.randomUUID().toString().substring(0, 8) +
-                    (StringUtils.hasText(fileExtension) ? "." + fileExtension : "");
-
-            Path formalFilePath = formalDirPath.resolve(formalFilename);
-
-            try {
-                // 鎵ц鏂囦欢杩佺Щ锛堜娇鐢ㄥ師瀛愭搷浣滅‘淇濆畨鍏ㄦ�э級
-//                Files.move(
-//                        Paths.get(tempFile.getTempPath()),
-//                        formalFilePath,
-//                        StandardCopyOption.REPLACE_EXISTING,
-//                        StandardCopyOption.ATOMIC_MOVE
-//                );
-                // 鍘熷瓙绉诲姩澶辫触锛屼娇鐢ㄥ鍒�+鍒犻櫎
-                Files.copy(Paths.get(tempFile.getTempPath()), formalFilePath, StandardCopyOption.REPLACE_EXISTING);
-                Files.deleteIfExists(Paths.get(tempFile.getTempPath()));
-                log.info("鏂囦欢杩佺Щ鎴愬姛: {} -> {}", tempFile.getTempPath(), formalFilePath);
-
-                // 鏇存柊鏂囦欢璁板綍锛堝叧鑱斿埌涓氬姟ID锛�
-                CommonFile fileRecord = new CommonFile();
-                fileRecord.setCommonId(businessId);
-                fileRecord.setName(originalFilename);
-                fileRecord.setUrl(formalFilePath.toString());
-                fileRecord.setCreateTime(LocalDateTime.now());
-                //閿�鍞�
-                fileRecord.setType(FileNameType.SALE.getValue());
-                commonFileMapper.insert(fileRecord);
-
-                // 鍒犻櫎涓存椂鏂囦欢璁板綍
-                tempFileMapper.deleteById(tempFile);
-
-                log.info("鏂囦欢杩佺Щ鎴愬姛: {} -> {}", tempFile.getTempPath(), formalFilePath);
-            } catch (IOException e) {
-                log.error("鏂囦欢杩佺Щ澶辫触: {}", tempFile.getTempPath(), e);
-                // 鍙�夋嫨鍥炴粴浜嬪姟鎴栬褰曞け璐ユ枃浠�
-                throw new IOException("鏂囦欢杩佺Щ寮傚父", e);
-            }
-        }
-    }
-
-    // 鏂囦欢杩佺Щ鏂规硶
 
     @Override
     public void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, SaleEnum type) {
diff --git a/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
index ba17fe9..b112549 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
@@ -11,6 +11,7 @@
 import com.ruoyi.basic.utils.FileUtil;
 import com.ruoyi.common.enums.FileNameType;
 import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
+import com.ruoyi.procurementrecord.bean.vo.ShippingProductVo;
 import com.ruoyi.procurementrecord.utils.StockUtils;
 import com.ruoyi.sales.dto.SalesLedgerProductDto;
 import com.ruoyi.sales.dto.ShippingApproveDto;
@@ -55,7 +56,7 @@
     @Override
     public IPage<ShippingInfoDto> listPage(Page page, ShippingInfo req) {
         IPage<ShippingInfoDto> listPage = shippingInfoMapper.listPage(page, req);
-        listPage.getRecords().forEach(item ->{
+        listPage.getRecords().forEach(item -> {
             item.setStorageBlobVOs(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum.IMAGE, RecordTypeEnum.SHIPPING_INFO, item.getId()));
         });
         return listPage;
@@ -68,7 +69,7 @@
             throw new RuntimeException("鍙戣揣淇℃伅涓嶅瓨鍦�");
         }
         //鎵e噺搴撳瓨
-        if(!"宸插彂璐�".equals(byId.getStatus())){
+        if (!"宸插彂璐�".equals(byId.getStatus())) {
             List<ShippingProductDetail> shippingProductDetails = shippingProductDetailMapper.selectList(new LambdaQueryWrapper<ShippingProductDetail>().eq(ShippingProductDetail::getShippingInfoId, req.getId()));
             if (CollectionUtils.isEmpty(shippingProductDetails)) {
                 throw new RuntimeException("鍙戣揣淇℃伅涓嶅瓨鍦�");
@@ -85,28 +86,28 @@
         boolean update = this.updateById(byId);
         // 淇濆瓨鏂囦欢
         fileUtil.saveStorageAttachment(ApplicationTypeEnum.IMAGE, RecordTypeEnum.SHIPPING_INFO, req.getId(), req.getStorageBlobDTOs());
-        return update ;
+        return update;
     }
 
     @Override
     public boolean delete(List<Long> ids) {
         List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>()
                 .in(ShippingInfo::getId, ids));
-        if(CollectionUtils.isEmpty(shippingInfos)) return false;
+        if (CollectionUtils.isEmpty(shippingInfos)) return false;
         // 鍒犻櫎闄勪欢
         commonFileService.deleteByBusinessIds(ids, FileNameType.SHIP.getValue());
         // 鎵e凡鍙戣揣搴撳瓨
         for (ShippingInfo shippingInfo : shippingInfos) {
-            if("宸插彂璐�".equals(shippingInfo.getStatus())) {
+            if ("宸插彂璐�".equals(shippingInfo.getStatus())) {
                 stockUtils.deleteStockOutRecord(shippingInfo.getId(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode());
             }
         }
         // 鍒犻櫎鍙戣揣瀹℃壒
-        if(CollectionUtils.isNotEmpty(shippingInfos)){
-            for (ShippingInfo shippingInfo : shippingInfos){
+        if (CollectionUtils.isNotEmpty(shippingInfos)) {
+            for (ShippingInfo shippingInfo : shippingInfos) {
                 List<ApproveProcess> one = approveProcessService.list(new LambdaQueryWrapper<ApproveProcess>()
                         .like(ApproveProcess::getApproveReason, shippingInfo.getShippingNo()));
-                if(one != null){
+                if (one != null) {
                     List<Long> list = one.stream().map(ApproveProcess::getId).toList();
                     approveProcessService.delByIds(list);
                 }
@@ -119,8 +120,8 @@
     }
 
     @Override
-    public List<SalesLedgerProductDto> getReturnManagementDtoById(Long shippingId) {
-        return shippingInfoMapper.getReturnManagementDtoById(shippingId );
+    public List<ShippingProductVo> getReturnManagementDtoById(Long shippingId) {
+        return shippingInfoMapper.getReturnManagementDtoById(shippingId);
 
     }
 
@@ -131,9 +132,14 @@
 
     @Override
     public boolean add(ShippingInfoDto req) {
-        this.save( req);
+        this.save(req);
         req.getBatchNoDetailList().forEach(item -> item.setShippingInfoId(req.getId()));
         shippingProductDetailMapper.insert(req.getBatchNoDetailList());
+        for (ShippingProductDetail shippingProductDetail : req.getBatchNoDetailList()) {
+            stockUtils.substractStock(shippingProductDetail.getProductModelId(), shippingProductDetail.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId(), shippingProductDetail.getBatchNo());
+        }
+        // 淇濆瓨鏂囦欢
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.IMAGE, RecordTypeEnum.SHIPPING_INFO, req.getId(), req.getStorageBlobDTOs());
         return true;
     }
 
@@ -147,7 +153,7 @@
         ShippingApproveDto shippingApproveDto = new ShippingApproveDto();
         ShippingInfo shippingInfo = new ShippingInfo();
         shippingInfo.setShippingNo(shippingNo);
-        shippingApproveDto.setShippingInfo(shippingInfoMapper.listPage(new Page(1, -1),shippingInfo).getRecords().get(0));
+        shippingApproveDto.setShippingInfo(shippingInfoMapper.listPage(new Page(1, -1), shippingInfo).getRecords().get(0));
         List<ShippingProductDetailDto> dateilByShippingNo = shippingProductDetailMapper.getDateilByShippingNo(shippingNo);
         shippingApproveDto.setShippingProductDetailDtoList(dateilByShippingNo);
         return shippingApproveDto;
diff --git a/src/main/java/com/ruoyi/stock/controller/StockUninventoryController.java b/src/main/java/com/ruoyi/stock/controller/StockUninventoryController.java
index 477a68d..3a002e0 100644
--- a/src/main/java/com/ruoyi/stock/controller/StockUninventoryController.java
+++ b/src/main/java/com/ruoyi/stock/controller/StockUninventoryController.java
@@ -2,8 +2,8 @@
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
-import com.ruoyi.common.enums.StockOutUnQualifiedRecordTypeEnum;
+import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
+import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
 import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.stock.dto.StockInventoryDto;
 import com.ruoyi.stock.dto.StockUninventoryDto;
@@ -37,7 +37,7 @@
     @PostMapping("/addstockUninventory")
     @Operation(summary = "鏂板搴撳瓨")
     public R addstockUninventory(@RequestBody StockUninventoryDto stockUninventoryDto) {
-        stockUninventoryDto.setRecordType(String.valueOf(StockInUnQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_IN.getCode()));
+        stockUninventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_IN.getCode()));
         stockUninventoryDto.setRecordId(0L);
         return R.ok(stockUninventoryService.addStockUninventory(stockUninventoryDto));
     }
@@ -46,7 +46,7 @@
     @PostMapping("/subtractstockUninventory")
     @Operation(summary = "鎵e噺搴撳瓨")
     public R subtractstockUninventory(@RequestBody StockUninventoryDto stockUninventoryDto) {
-        stockUninventoryDto.setRecordType(String.valueOf(StockOutUnQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode()));
+        stockUninventoryDto.setRecordType(String.valueOf(StockOutQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode()));
         stockUninventoryDto.setRecordId(0L);
         return R.ok(stockUninventoryService.subtractStockUninventory(stockUninventoryDto));
     }
@@ -54,7 +54,7 @@
     @PostMapping("/addStockInRecordOnly")
     @Operation(summary = "鏂板鍏ュ簱璁板綍锛堜粎鍒涘缓璁板綍锛屼笉璋冩暣搴撳瓨锛�")
     public R addStockInRecordOnly(@RequestBody StockUninventoryDto stockUninventoryDto) {
-        stockUninventoryDto.setRecordType(String.valueOf(StockInUnQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_IN.getCode()));
+        stockUninventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_IN.getCode()));
         stockUninventoryDto.setRecordId(0L);
         return R.ok(stockUninventoryService.addStockInRecordOnly(stockUninventoryDto));
     }
@@ -62,7 +62,7 @@
     @PostMapping("/addStockOutRecordOnly")
     @Operation(summary = "鏂板鍑哄簱璁板綍锛堜粎鍒涘缓璁板綍锛屼笉璋冩暣搴撳瓨锛�")
     public R addStockOutRecordOnly(@RequestBody StockUninventoryDto stockUninventoryDto) {
-        stockUninventoryDto.setRecordType(String.valueOf(StockOutUnQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode()));
+        stockUninventoryDto.setRecordType(String.valueOf(StockOutQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode()));
         stockUninventoryDto.setRecordId(0L);
         return R.ok(stockUninventoryService.addStockOutRecordOnly(stockUninventoryDto));
     }
diff --git a/src/main/java/com/ruoyi/stock/mapper/StockInRecordMapper.java b/src/main/java/com/ruoyi/stock/mapper/StockInRecordMapper.java
index afc30ae..4dd64c7 100644
--- a/src/main/java/com/ruoyi/stock/mapper/StockInRecordMapper.java
+++ b/src/main/java/com/ruoyi/stock/mapper/StockInRecordMapper.java
@@ -3,6 +3,8 @@
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.PurchaseInboundDto;
+import com.ruoyi.account.bean.vo.PurchaseInboundVo;
 import com.ruoyi.stock.dto.StockInRecordDto;
 import com.ruoyi.stock.execl.StockInRecordExportData;
 import com.ruoyi.stock.pojo.StockInRecord;
@@ -14,4 +16,6 @@
     IPage<StockInRecordDto> listPage(Page page, @Param("params") StockInRecordDto stockInRecordDto);
 
     List<StockInRecordExportData> listStockInRecordExportData(@Param("params") StockInRecordDto stockInRecordDto);
+
+    IPage<PurchaseInboundVo> listPageAccountPurchase(Page page, @Param("req") PurchaseInboundDto purchaseInboundDto);
 }
diff --git a/src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java b/src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java
index d180ef9..eb05e8c 100644
--- a/src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java
+++ b/src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java
@@ -3,6 +3,8 @@
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.SalesOutboundDto;
+import com.ruoyi.account.bean.vo.SalesOutboundVo;
 import com.ruoyi.stock.dto.StockOutRecordDto;
 import com.ruoyi.stock.execl.StockOutRecordExportData;
 import com.ruoyi.stock.pojo.StockOutRecord;
@@ -25,4 +27,5 @@
 
     List<StockOutRecordExportData> listStockOutRecordExportData(@Param("params") StockOutRecordDto stockOutRecordDto);
 
+    IPage<SalesOutboundVo> listPageAccountSales(Page page, @Param("req") SalesOutboundDto salesOutboundDto);
 }
diff --git a/src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java b/src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java
index 20ea4a2..1fd2893 100644
--- a/src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java
+++ b/src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java
@@ -75,7 +75,7 @@
     @Schema(description = "绫诲瀷  0鍚堟牸鍏ュ簱 1涓嶅悎鏍煎叆搴�")
     private String type;
 
-    @Schema(description = "瀹℃壒鐘舵��  0-寰呭鎵� 1-閫氳繃 2-椹冲洖", implementation = ReviewStatusEnum.class)
+    @Schema(description = "瀹℃壒鐘舵��  0-寰呭鎵� 1-閫氳繃 2-椹冲洖 3-閿�鍞嚭搴撳緟纭", implementation = ReviewStatusEnum.class)
     private Integer approvalStatus;
 
     @TableField(fill = FieldFill.INSERT)
diff --git a/src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java b/src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java
index f84a9d8..ab34aa8 100644
--- a/src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java
+++ b/src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java
@@ -5,8 +5,8 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.common.enums.ReviewStatusEnum;
+import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
 import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
-import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
 import com.ruoyi.common.exception.base.BaseException;
 import com.ruoyi.common.utils.EnumUtil;
 import com.ruoyi.common.utils.OrderUtils;
@@ -24,12 +24,12 @@
 import com.ruoyi.stock.pojo.StockInventory;
 import com.ruoyi.stock.pojo.StockUninventory;
 import com.ruoyi.stock.service.StockInRecordService;
+import jakarta.servlet.http.HttpServletResponse;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 
-import jakarta.servlet.http.HttpServletResponse;
 import java.util.List;
 
 @Service
@@ -123,7 +123,7 @@
             if (stockInRecordExportData.getType().equals("0")) {
                 stockInRecordExportData.setRecordType(EnumUtil.fromCode(StockOutQualifiedRecordTypeEnum.class, Integer.parseInt(stockInRecordExportData.getRecordType())).getValue());
             }else {
-                stockInRecordExportData.setRecordType(EnumUtil.fromCode(StockInUnQualifiedRecordTypeEnum.class, Integer.parseInt(stockInRecordExportData.getRecordType())).getValue());
+                stockInRecordExportData.setRecordType(EnumUtil.fromCode(StockInQualifiedRecordTypeEnum.class, Integer.parseInt(stockInRecordExportData.getRecordType())).getValue());
             }
         }
         ExcelUtil<StockInRecordExportData> util = new ExcelUtil<>(StockInRecordExportData.class);
diff --git a/src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java b/src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
index d712518..3808916 100644
--- a/src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
+++ b/src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
@@ -10,7 +10,6 @@
 import com.ruoyi.basic.mapper.ProductModelMapper;
 import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
-import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -345,7 +344,7 @@
                     if (dto.getUnQualifiedQuantity() != null && dto.getUnQualifiedQuantity().compareTo(BigDecimal.ZERO) > 0) {
                         StockUninventoryDto stockUninventoryDto = new StockUninventoryDto();
                         stockUninventoryDto.setRecordId(0L);
-                        stockUninventoryDto.setRecordType(StockInUnQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_IN.getCode());
+                        stockUninventoryDto.setRecordType(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_IN.getCode());
                         stockUninventoryDto.setQualitity(dto.getUnQualifiedQuantity());
                         stockUninventoryDto.setRemark(dto.getRemark());
 
diff --git a/src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java b/src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java
index cead7fc..9a6bd9b 100644
--- a/src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java
+++ b/src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java
@@ -5,8 +5,8 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.common.enums.ReviewStatusEnum;
+import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
 import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
-import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
 import com.ruoyi.common.exception.base.BaseException;
 import com.ruoyi.common.utils.EnumUtil;
 import com.ruoyi.common.utils.OrderUtils;
@@ -20,19 +20,16 @@
 import com.ruoyi.stock.mapper.StockInventoryMapper;
 import com.ruoyi.stock.mapper.StockOutRecordMapper;
 import com.ruoyi.stock.mapper.StockUninventoryMapper;
-import com.ruoyi.stock.pojo.StockInRecord;
 import com.ruoyi.stock.pojo.StockInventory;
 import com.ruoyi.stock.pojo.StockOutRecord;
 import com.ruoyi.stock.pojo.StockUninventory;
 import com.ruoyi.stock.service.StockOutRecordService;
-import lombok.AllArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
 import lombok.RequiredArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 
-import jakarta.servlet.http.HttpServletResponse;
 import java.util.List;
 
 /**
@@ -59,8 +56,9 @@
     public int add(StockOutRecordDto stockOutRecordDto) {
         String no = OrderUtils.countTodayByCreateTime(stockOutRecordMapper, "CK","outbound_batches");
         stockOutRecordDto.setOutboundBatches(no);
-        StockInRecord stockInRecord = new StockInRecord();
-        BeanUtils.copyProperties(stockOutRecordDto, stockInRecord);
+        if (StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode().equals(stockOutRecordDto.getRecordType())){
+            stockOutRecordDto.setApprovalStatus(3);
+        }
         return stockOutRecordMapper.insert(stockOutRecordDto);
     }
 
@@ -129,7 +127,7 @@
             if (stockInRecordExportData.getType().equals("0")) {
                 stockInRecordExportData.setRecordType(EnumUtil.fromCode(StockOutQualifiedRecordTypeEnum.class, Integer.parseInt(stockInRecordExportData.getRecordType())).getValue());
             }else {
-                stockInRecordExportData.setRecordType(EnumUtil.fromCode(StockInUnQualifiedRecordTypeEnum.class, Integer.parseInt(stockInRecordExportData.getRecordType())).getValue());
+                stockInRecordExportData.setRecordType(EnumUtil.fromCode(StockInQualifiedRecordTypeEnum.class, Integer.parseInt(stockInRecordExportData.getRecordType())).getValue());
             }
         }
         ExcelUtil<StockOutRecordExportData> util = new ExcelUtil<>(StockOutRecordExportData.class);
diff --git a/src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java b/src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java
index 4835b09..4c7d157 100644
--- a/src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java
+++ b/src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java
@@ -4,8 +4,12 @@
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.basic.mapper.ProductModelMapper;
+import com.ruoyi.basic.pojo.ProductModel;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.exception.base.BaseException;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -14,21 +18,22 @@
 import com.ruoyi.stock.dto.StockOutRecordDto;
 import com.ruoyi.stock.dto.StockUninventoryDto;
 import com.ruoyi.stock.execl.StockUnInventoryExportData;
+import com.ruoyi.stock.mapper.StockInventoryMapper;
 import com.ruoyi.stock.mapper.StockUninventoryMapper;
+import com.ruoyi.stock.pojo.StockInRecord;
 import com.ruoyi.stock.pojo.StockInventory;
 import com.ruoyi.stock.pojo.StockUninventory;
 import com.ruoyi.stock.service.StockInRecordService;
 import com.ruoyi.stock.service.StockOutRecordService;
 import com.ruoyi.stock.service.StockUninventoryService;
-import lombok.AllArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
 import lombok.RequiredArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import jakarta.servlet.http.HttpServletResponse;
-
 import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
 import java.util.List;
 
 /**
@@ -47,6 +52,8 @@
     private final StockUninventoryMapper stockUninventoryMapper;
     private final StockOutRecordService stockOutRecordService;
     private final StockInRecordService stockInRecordService;
+    private final ProductModelMapper productModelMapper;
+    private final StockInventoryMapper stockInventoryMapper;
 
     @Override
     public IPage<StockUninventoryDto> pageStockUninventory(Page page, StockUninventoryDto stockUninventoryDto) {
@@ -120,7 +127,11 @@
         stockInRecordDto.setRecordId(stockUninventoryDto.getRecordId());
         stockInRecordDto.setRecordType(stockUninventoryDto.getRecordType());
         stockInRecordDto.setStockInNum(stockUninventoryDto.getQualitity());
-        stockInRecordDto.setBatchNo(stockUninventoryDto.getBatchNo());
+        String batchNo = StringUtils.trim(stockUninventoryDto.getBatchNo());
+        if (StringUtils.isEmpty(batchNo)) {
+            batchNo = generateAutoBatchNo(stockUninventoryDto.getProductModelId());
+        }
+        stockInRecordDto.setBatchNo(batchNo);
         stockInRecordDto.setProductModelId(stockUninventoryDto.getProductModelId());
         stockInRecordDto.setType("1");
         stockInRecordDto.setRemark(stockUninventoryDto.getRemark());
@@ -200,4 +211,80 @@
         stockUninventory.setLockedQuantity(stockUninventory.getLockedQuantity().subtract(stockInventoryDto.getLockedQuantity()));
         return this.updateById(stockUninventory);
     }
+
+    //瑙勫垯鐢熸垚锛�20260424-浜у搧缂栧彿-001
+    private String generateAutoBatchNo(Long productModelId) {
+        if (productModelId == null) {
+            throw new ServiceException("浜у搧瑙勬牸ID涓嶈兘涓虹┖");
+        }
+        ProductModel productModel = productModelMapper.selectById(productModelId);
+        if (productModel == null) {
+            throw new ServiceException("浜у搧瑙勬牸涓嶅瓨鍦紝ID=" + productModelId);
+        }
+        String productCode = StringUtils.trim(productModel.getProductCode());
+        if (StringUtils.isEmpty(productCode)) {
+            throw new ServiceException("浜у搧瑙勬牸鏈淮鎶や骇鍝佺紪鐮侊紝ID=" + productModelId);
+        }
+
+        String dateText = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
+        String prefix = dateText + "-" + productCode + "-";
+        int maxSequence = resolveMaxSequence(prefix);
+        int sequence = maxSequence + 1;
+        while (sequence < 1_000_000) {
+            String batchNo = prefix + String.format("%03d", sequence);
+            if (!isBatchNoExists(batchNo)) {
+                return batchNo;
+            }
+            sequence++;
+        }
+        throw new ServiceException("鎵瑰彿搴忓彿瓒呭嚭鑼冨洿锛岃妫�鏌ユ壒鍙锋暟鎹�");
+    }
+
+    private int resolveMaxSequence(String prefix) {
+        int maxSequence = 0;
+        List<StockInventory> stockInventoryList = stockInventoryMapper.selectList(
+                Wrappers.<StockInventory>lambdaQuery()
+                        .select(StockInventory::getBatchNo)
+                        .likeRight(StockInventory::getBatchNo, prefix));
+        for (StockInventory stockInventory : stockInventoryList) {
+            maxSequence = Math.max(maxSequence, parseSequence(stockInventory.getBatchNo(), prefix));
+        }
+
+        List<StockInRecord> stockInRecordList = stockInRecordService.list(
+                Wrappers.<StockInRecord>lambdaQuery()
+                        .select(StockInRecord::getBatchNo)
+                        .likeRight(StockInRecord::getBatchNo, prefix));
+        for (StockInRecord stockInRecord : stockInRecordList) {
+            maxSequence = Math.max(maxSequence, parseSequence(stockInRecord.getBatchNo(), prefix));
+        }
+        return maxSequence;
+    }
+
+    private int parseSequence(String batchNo, String prefix) {
+        if (StringUtils.isEmpty(batchNo) || StringUtils.isEmpty(prefix) || !batchNo.startsWith(prefix)) {
+            return 0;
+        }
+        String sequenceText = batchNo.substring(prefix.length());
+        if (StringUtils.isEmpty(sequenceText) || !sequenceText.matches("\\d+")) {
+            return 0;
+        }
+        try {
+            return Integer.parseInt(sequenceText);
+        } catch (NumberFormatException ignored) {
+            return 0;
+        }
+    }
+
+    private boolean isBatchNoExists(String batchNo) {
+        if (StringUtils.isEmpty(batchNo)) {
+            return false;
+        }
+        Long inventoryCount = stockInventoryMapper.selectCount(
+                Wrappers.<StockInventory>lambdaQuery().eq(StockInventory::getBatchNo, batchNo));
+        if (inventoryCount != null && inventoryCount > 0) {
+            return true;
+        }
+        return stockInRecordService.count(
+                Wrappers.<StockInRecord>lambdaQuery().eq(StockInRecord::getBatchNo, batchNo)) > 0;
+    }
 }
diff --git a/src/main/java/com/ruoyi/technology/bean/vo/TechnologyBomStructureVo.java b/src/main/java/com/ruoyi/technology/bean/vo/TechnologyBomStructureVo.java
index e41540d..d3719d6 100644
--- a/src/main/java/com/ruoyi/technology/bean/vo/TechnologyBomStructureVo.java
+++ b/src/main/java/com/ruoyi/technology/bean/vo/TechnologyBomStructureVo.java
@@ -23,5 +23,8 @@
     @Schema(description = "瑙勬牸鍨嬪彿")
     private String model;
 
+    @Schema(description = "浜у搧缂栫爜")
+    private String productCode;
+
     private List<TechnologyBomStructureVo> children;
 }
diff --git a/src/main/java/com/ruoyi/technology/controller/TechnologyBomController.java b/src/main/java/com/ruoyi/technology/controller/TechnologyBomController.java
index 226973f..9e35143 100644
--- a/src/main/java/com/ruoyi/technology/controller/TechnologyBomController.java
+++ b/src/main/java/com/ruoyi/technology/controller/TechnologyBomController.java
@@ -76,7 +76,7 @@
     @PreAuthorize("@ss.hasPermi('product:bom:export')")
     @Operation(summary = "瀵煎嚭BOM鏂囦欢")
     @Log(title = "瀵煎嚭BOM鏂囦欢", businessType = BusinessType.EXPORT)
-    public void exportBom(HttpServletResponse response, @RequestParam Integer bomId) {
+    public void exportBom(HttpServletResponse response, @RequestParam Long bomId) {
         technologyBomService.exportBom(response, bomId);
     }
 
diff --git a/src/main/java/com/ruoyi/technology/service/TechnologyBomService.java b/src/main/java/com/ruoyi/technology/service/TechnologyBomService.java
index 31fd335..d4aa3d3 100644
--- a/src/main/java/com/ruoyi/technology/service/TechnologyBomService.java
+++ b/src/main/java/com/ruoyi/technology/service/TechnologyBomService.java
@@ -26,7 +26,7 @@
 
     R uploadBom(MultipartFile file);
 
-    void exportBom(HttpServletResponse response, Integer bomId);
+    void exportBom(HttpServletResponse response, Long bomId);
 
     R copy(TechnologyBom technologyBom);
 }
diff --git a/src/main/java/com/ruoyi/technology/service/impl/TechnologyBomServiceImpl.java b/src/main/java/com/ruoyi/technology/service/impl/TechnologyBomServiceImpl.java
index bac4f37..8894288 100644
--- a/src/main/java/com/ruoyi/technology/service/impl/TechnologyBomServiceImpl.java
+++ b/src/main/java/com/ruoyi/technology/service/impl/TechnologyBomServiceImpl.java
@@ -15,8 +15,7 @@
 import com.ruoyi.common.utils.bean.BeanUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.web.domain.R;
-import com.ruoyi.production.bean.dto.BomImportDto;
-import com.ruoyi.production.bean.dto.ProductStructureDto;
+import com.ruoyi.technology.bean.dto.BomImportDto;
 import com.ruoyi.technology.bean.dto.TechnologyBomDto;
 import com.ruoyi.technology.bean.dto.TechnologyBomStructureDto;
 import com.ruoyi.technology.bean.vo.TechnologyBomStructureVo;
@@ -263,70 +262,72 @@
 
 
     @Override
-    public void exportBom(HttpServletResponse response, Integer bomId) {
+    public void exportBom(HttpServletResponse response, Long bomId) {
         if (bomId == null) {
+            throw new ServiceException("BOM ID涓嶈兘涓虹┖");
+        }
+
+        List<TechnologyBomStructureVo> treeData = technologyBomStructureService.listByBomId(bomId);
+        if (treeData == null || treeData.isEmpty()) {
             return;
         }
 
-//        List<ProductStructureDto> treeData = productStructureService.listBybomId(bomId);
-//        if (treeData == null || treeData.isEmpty()) {
-//            return;
-//        }
-//
-//        //  灏嗘爲褰㈢粨鏋勬墎骞冲寲 浣跨敤 BFS绠楁硶 瀵煎嚭,鎸夊眰绾ч『搴�
-//        List<BomImportDto> exportList = new ArrayList<>();
-//
-//        // Map<ID, Node> idMap 鐢ㄤ簬鏌ユ壘鐖惰妭鐐�
-//        Map<Long, ProductStructureDto> idMap = new HashMap<>();
-//        populateMap(treeData, idMap);
-//
-//        //  treeData 鐨勭涓�涓槸鏍硅妭鐐�
-//        for (ProductStructureDto root : treeData) {
-//            //  娣诲姞鏍硅妭鐐�
-//            BomImportDto rootRow = new BomImportDto();
-//            rootRow.setParentName(root.getProductName());
-//            rootRow.setParentSpec(root.getModel());
-//            rootRow.setUnitQty(root.getUnitQuantity());
-//            rootRow.setRemark("");
-//            exportList.add(rootRow);
-//
-//            //  BFS 閬嶅巻-闃熷垪
-//            Queue<ProductStructureDto> queue = new LinkedList<>();
-//            if (root.getChildren() != null) {
-//                queue.addAll(root.getChildren());
-//            }
-//
-//            while (!queue.isEmpty()) {
-//                ProductStructureDto child = queue.poll();
-//
-//                // 鏌ユ壘鐖惰妭鐐�
-//                ProductStructureDto parent = idMap.get(child.getParentId());
-//                if (parent == null) {
-//                    // 闄や簡鏈�澶栧眰鑺傜偣,鍏朵粬鑺傜偣鐨勭埗绫昏偗瀹氭槸涓嶄細涓虹┖鐨�
-//                    continue;
-//                }
-//
-//                BomImportDto row = new BomImportDto();
-//                // 鐖剁被淇℃伅
-//                row.setParentName(parent.getProductName());
-//                row.setParentSpec(parent.getModel());
-//                // 瀛愮被淇℃伅
-//                row.setChildName(child.getProductName());
-//                row.setChildSpec(child.getModel());
-//                row.setUnitQty(child.getUnitQuantity());
-//                row.setProcess(child.getProcessName());
-//
-//                exportList.add(row);
-//
-//                //  灏嗗瓙鑺傜偣鐨勫瓙鑺傜偣鍔犲叆闃熷垪-涓嬩竴灞�
-//                if (child.getChildren() != null && !child.getChildren().isEmpty()) {
-//                    queue.addAll(child.getChildren());
-//                }
-//            }
-//        }
+        //  灏嗘爲褰㈢粨鏋勬墎骞冲寲 浣跨敤 BFS绠楁硶 瀵煎嚭,鎸夊眰绾ч『搴�
+        List<BomImportDto> exportList = new ArrayList<>();
+
+        // Map<ID, Node> idMap 鐢ㄤ簬鏌ユ壘鐖惰妭鐐�
+        Map<Long, TechnologyBomStructureVo> idMap = new HashMap<>();
+        populateMap(treeData, idMap);
+
+        //  treeData 鐨勭涓�涓槸鏍硅妭鐐�
+        for (TechnologyBomStructureVo root : treeData) {
+            //  娣诲姞鏍硅妭鐐�
+            BomImportDto rootRow = new BomImportDto();
+            rootRow.setParentName(root.getProductName());
+            rootRow.setParentSpec(root.getModel());
+            rootRow.setUnitQty(root.getUnitQuantity());
+            rootRow.setParentCode(root.getProductCode());
+            rootRow.setRemark("");
+            exportList.add(rootRow);
+
+            //  BFS 閬嶅巻-闃熷垪
+            Queue<TechnologyBomStructureVo> queue = new LinkedList<>();
+            if (root.getChildren() != null) {
+                queue.addAll(root.getChildren());
+            }
+
+            while (!queue.isEmpty()) {
+                TechnologyBomStructureVo child = queue.poll();
+
+                // 鏌ユ壘鐖惰妭鐐�
+                TechnologyBomStructureVo parent = idMap.get(child.getParentId());
+                if (parent == null) {
+                    // 闄や簡鏈�澶栧眰鑺傜偣,鍏朵粬鑺傜偣鐨勭埗绫昏偗瀹氭槸涓嶄細涓虹┖鐨�
+                    continue;
+                }
+
+                BomImportDto row = new BomImportDto();
+                // 鐖剁被淇℃伅
+                row.setParentName(parent.getProductName());
+                row.setParentSpec(parent.getModel());
+                // 瀛愮被淇℃伅
+                row.setChildName(child.getProductName());
+                row.setChildSpec(child.getModel());
+                row.setUnitQty(child.getUnitQuantity());
+                row.setProcess(child.getOperationName());
+                row.setChildCode(child.getProductCode());
+
+                exportList.add(row);
+
+                //  灏嗗瓙鑺傜偣鐨勫瓙鑺傜偣鍔犲叆闃熷垪-涓嬩竴灞�
+                if (child.getChildren() != null && !child.getChildren().isEmpty()) {
+                    queue.addAll(child.getChildren());
+                }
+            }
+        }
 
         ExcelUtil<BomImportDto> util = new ExcelUtil<>(BomImportDto.class);
-//        util.exportExcel(response, exportList, "BOM缁撴瀯瀵煎嚭");
+        util.exportExcel(response, exportList, "BOM缁撴瀯瀵煎嚭");
     }
 
     @Override
@@ -408,11 +409,11 @@
         return s.replaceAll("[\\u00A0\\u3000]", "").trim();
     }
 
-    private void populateMap(List<ProductStructureDto> nodes, Map<Long, ProductStructureDto> map) {
+    private void populateMap(List<TechnologyBomStructureVo> nodes, Map<Long, TechnologyBomStructureVo> map) {
         if (nodes == null || nodes.isEmpty()) {
             return;
         }
-        for (ProductStructureDto node : nodes) {
+        for (TechnologyBomStructureVo node : nodes) {
             map.put(node.getId(), node);
             populateMap(node.getChildren(), map);
         }
diff --git a/src/main/java/com/ruoyi/warehouse/mapper/DocumentationMapper.java b/src/main/java/com/ruoyi/warehouse/mapper/DocumentationMapper.java
index 33278bf..85cceec 100644
--- a/src/main/java/com/ruoyi/warehouse/mapper/DocumentationMapper.java
+++ b/src/main/java/com/ruoyi/warehouse/mapper/DocumentationMapper.java
@@ -2,7 +2,6 @@
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto;
 import com.ruoyi.warehouse.dto.DocumentationDto;
 import com.ruoyi.warehouse.pojo.Documentation;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index 9f2ffcc..b1869c3 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -74,9 +74,9 @@
     druid:
       # 涓诲簱鏁版嵁婧�
       master:
-        url: jdbc:mysql://localhost:3300/product-inventory-management-new-pro?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        url: jdbc:mysql://localhost:3306/product-inventory-management-new-pro?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
         username: root
-        password: root
+        password: 123456
       # 浠庡簱鏁版嵁婧�
       slave:
         # 浠庢暟鎹簮寮�鍏�/榛樿鍏抽棴
diff --git a/src/main/resources/mapper/account/AccountSubjectMapper.xml b/src/main/resources/mapper/account/AccountSubjectMapper.xml
index 179d858..95f450f 100644
--- a/src/main/resources/mapper/account/AccountSubjectMapper.xml
+++ b/src/main/resources/mapper/account/AccountSubjectMapper.xml
@@ -5,6 +5,7 @@
     <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
     <resultMap id="BaseResultMap" type="com.ruoyi.account.pojo.AccountSubject">
         <id column="id" property="id" />
+        <result column="parent_id" property="parentId" />
         <result column="subject_code" property="subjectCode" />
         <result column="subject_name" property="subjectName" />
         <result column="subject_type" property="subjectType" />
@@ -18,4 +19,13 @@
         <result column="dept_id" property="deptId" />
     </resultMap>
 
+    <select id="countReferencedBySubjectCodes" resultType="java.lang.Long">
+        SELECT COUNT(1)
+        FROM fin_voucher_entry
+        WHERE subject_code IN
+        <foreach collection="subjectCodes" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+    </select>
+
 </mapper>
diff --git a/src/main/resources/mapper/account/SalesRefundAmountOrderMapper.xml b/src/main/resources/mapper/account/SalesRefundAmountOrderMapper.xml
index 05617b1..a41c8c1 100644
--- a/src/main/resources/mapper/account/SalesRefundAmountOrderMapper.xml
+++ b/src/main/resources/mapper/account/SalesRefundAmountOrderMapper.xml
@@ -18,9 +18,9 @@
     <select id="pageSalesRefundAmountOrderDto" resultType="com.ruoyi.account.bean.dto.SalesRefundAmountOrderDto">
         select sl.sales_contract_no,
         sl.customer_contract_no,
-        slp.specification_model,
-        slp.product_category as product_name,
-        slp.unit,
+        pm.model as specification_model,
+        p.product_name ,
+        pm.unit,
         sl.customer_name,
         rm.return_no as return_management_no,
         srao.*
@@ -28,6 +28,8 @@
         left join return_management rm on srao.return_management_id = rm.id
         left join return_sale_product rs on rm.id = rs.return_management_id
         left join sales_ledger_product slp on rs.return_sales_ledger_product_id = slp.id
+        left join product_model pm on slp.product_model_id = pm.id
+            left join product p on pm.product_id = p.id
         left join sales_ledger sl on slp.sales_ledger_id = sl.id
         <where>
             <if test="ew.salesContractNo != null and ew.salesContractNo !=''">
diff --git a/src/main/resources/mapper/account/financial/FinVoucherEntryMapper.xml b/src/main/resources/mapper/account/financial/FinVoucherEntryMapper.xml
new file mode 100644
index 0000000..56633ba
--- /dev/null
+++ b/src/main/resources/mapper/account/financial/FinVoucherEntryMapper.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.account.mapper.financial.FinVoucherEntryMapper">
+
+    <resultMap id="BaseResultMap" type="com.ruoyi.account.pojo.financial.FinVoucherEntry">
+        <id column="id" property="id"/>
+        <result column="voucher_id" property="voucherId"/>
+        <result column="row_no" property="rowNo"/>
+        <result column="subject_code" property="subjectCode"/>
+        <result column="subject_name" property="subjectName"/>
+        <result column="summary" property="summary"/>
+        <result column="debit" property="debit"/>
+        <result column="credit" property="credit"/>
+        <result column="auxiliary_type" property="auxiliaryType"/>
+        <result column="auxiliary_id" property="auxiliaryId"/>
+        <result column="auxiliary_name" property="auxiliaryName"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="dept_id" property="deptId"/>
+    </resultMap>
+
+    <select id="listPostedEntries" resultType="com.ruoyi.account.bean.vo.financial.FinLedgerEntryRecordVo">
+        SELECT
+            v.voucher_date AS voucherDate,
+            v.voucher_no AS voucherNo,
+            CASE
+                WHEN e.summary IS NOT NULL AND e.summary != '' THEN e.summary
+                ELSE v.summary
+            END AS summary,
+            e.debit AS debit,
+            e.credit AS credit,
+            e.row_no AS rowNo
+        FROM fin_voucher_entry e
+        INNER JOIN fin_voucher v ON e.voucher_id = v.id
+        WHERE v.status = 'posted'
+          AND (e.subject_code = #{subjectCode} OR e.subject_code LIKE CONCAT(#{subjectCode}, '%'))
+          AND v.voucher_date <![CDATA[>=]]> #{startDate}
+          AND v.voucher_date <![CDATA[<=]]> #{endDate}
+        <if test="auxiliaryType != null and auxiliaryType != ''">
+          AND e.auxiliary_type = #{auxiliaryType}
+        </if>
+        <if test="auxiliaryId != null and auxiliaryId != ''">
+          AND e.auxiliary_id = #{auxiliaryId}
+        </if>
+        ORDER BY v.voucher_date ASC, v.id ASC, e.row_no ASC, e.id ASC
+    </select>
+
+    <select id="listPostedEntriesBefore" resultType="com.ruoyi.account.bean.vo.financial.FinLedgerEntryRecordVo">
+        SELECT
+            v.voucher_date AS voucherDate,
+            v.voucher_no AS voucherNo,
+            CASE
+                WHEN e.summary IS NOT NULL AND e.summary != '' THEN e.summary
+                ELSE v.summary
+            END AS summary,
+            e.debit AS debit,
+            e.credit AS credit,
+            e.row_no AS rowNo
+        FROM fin_voucher_entry e
+        INNER JOIN fin_voucher v ON e.voucher_id = v.id
+        WHERE v.status = 'posted'
+          AND (e.subject_code = #{subjectCode} OR e.subject_code LIKE CONCAT(#{subjectCode}, '%'))
+          AND v.voucher_date <![CDATA[<]]> #{beforeDate}
+        <if test="auxiliaryType != null and auxiliaryType != ''">
+          AND e.auxiliary_type = #{auxiliaryType}
+        </if>
+        <if test="auxiliaryId != null and auxiliaryId != ''">
+          AND e.auxiliary_id = #{auxiliaryId}
+        </if>
+    </select>
+
+</mapper>
diff --git a/src/main/resources/mapper/oA/OaProjectMapper.xml b/src/main/resources/mapper/oA/OaProjectMapper.xml
deleted file mode 100644
index c245a39..0000000
--- a/src/main/resources/mapper/oA/OaProjectMapper.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper
-        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.oA.mapper.OaProjectMapper">
-
-
-    <select id="listPage" resultType="com.ruoyi.oA.dto.OaProjectDto">
-        select op.*,su.nick_name as managerName from oa_project op
-        LEFT JOIN sys_user su ON op.manager_id=su.user_id
-        <where>
-        1=1
-            <if test="req.projectName != null and req.projectName != ''">
-                and op.project_name like concat('%',#{req.projectName},'%')
-            </if>
-            <if test="req.managerName != null and req.managerName != ''">
-                and su.nick_name like concat('%',#{req.managerName},'%')
-            </if>
-            <if test="req.status != null and req.status != ''">
-                and op.status = #{req.status}
-            </if>
-        </where>
-    </select>
-    <select id="selectByIds" resultType="com.ruoyi.oA.dto.OaProjectDto">
-        select op.*,su.nick_name as managerName from oa_project op
-        LEFT JOIN sys_user su ON op.manager_id=su.user_id
-        where op.project_id in
-        <foreach collection="ids" item="id" open="(" close=")" separator=",">
-            #{id}
-        </foreach>
-    </select>
-</mapper>
diff --git a/src/main/resources/mapper/oA/OaProjectPhaseMapper.xml b/src/main/resources/mapper/oA/OaProjectPhaseMapper.xml
deleted file mode 100644
index 2f52fe9..0000000
--- a/src/main/resources/mapper/oA/OaProjectPhaseMapper.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper
-        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.oA.mapper.OaProjectPhaseMapper">
-
-    <resultMap id="BaseResultMap" type="com.ruoyi.oA.pojo.OaProjectPhase">
-            <id property="phaseId" column="phase_id" jdbcType="INTEGER"/>
-            <result property="phaseName" column="phase_name" jdbcType="VARCHAR"/>
-            <result property="oaProjectId" column="oa_project_id" jdbcType="INTEGER"/>
-            <result property="startDate" column="start_date" jdbcType="TIMESTAMP"/>
-            <result property="endDate" column="end_date" jdbcType="TIMESTAMP"/>
-            <result property="status" column="status" jdbcType="VARCHAR"/>
-            <result property="createUser" column="create_user" jdbcType="BIGINT"/>
-            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
-            <result property="updateUser" column="update_user" jdbcType="BIGINT"/>
-            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
-            <result property="tenantId" column="tenant_id" jdbcType="BIGINT"/>
-    </resultMap>
-
-    <sql id="Base_Column_List">
-        phase_id,phase_name,oa_project_id,
-        start_date,end_date,status,
-        create_user,create_time,update_user,
-        update_time,tenant_id
-    </sql>
-</mapper>
diff --git a/src/main/resources/mapper/oA/OaProjectPhaseTaskMapper.xml b/src/main/resources/mapper/oA/OaProjectPhaseTaskMapper.xml
deleted file mode 100644
index cc029d9..0000000
--- a/src/main/resources/mapper/oA/OaProjectPhaseTaskMapper.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper
-        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ruoyi.oA.mapper.OaProjectPhaseTaskMapper">
-
-    <resultMap id="BaseResultMap" type="com.ruoyi.oA.pojo.OaProjectPhaseTask">
-            <id property="taskId" column="task_id" jdbcType="INTEGER"/>
-            <result property="taskName" column="task_name" jdbcType="VARCHAR"/>
-            <result property="phaseId" column="phase_id" jdbcType="INTEGER"/>
-            <result property="startDate" column="start_date" jdbcType="TIMESTAMP"/>
-            <result property="endDate" column="end_date" jdbcType="TIMESTAMP"/>
-            <result property="targetDate" column="target_date" jdbcType="TIMESTAMP"/>
-            <result property="targetValue" column="target_value" jdbcType="INTEGER"/>
-            <result property="currentValue" column="current_value" jdbcType="INTEGER"/>
-            <result property="unit" column="unit" jdbcType="VARCHAR"/>
-            <result property="status" column="status" jdbcType="VARCHAR"/>
-            <result property="completionRate" column="completion_rate" jdbcType="INTEGER"/>
-            <result property="createUser" column="create_user" jdbcType="BIGINT"/>
-            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
-            <result property="updateUser" column="update_user" jdbcType="BIGINT"/>
-            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
-            <result property="tenantId" column="tenant_id" jdbcType="BIGINT"/>
-    </resultMap>
-
-    <sql id="Base_Column_List">
-        task_id,task_name,phase_id,
-        start_date,end_date,target_date,
-        target_value,current_value,unit,
-        status,completion_rate,create_user,
-        create_time,update_user,update_time,
-        tenant_id
-    </sql>
-</mapper>
diff --git a/src/main/resources/mapper/procurementrecord/ProcurementRecordMapper.xml b/src/main/resources/mapper/procurementrecord/ProcurementRecordMapper.xml
index b0166ca..f1a87ca 100644
--- a/src/main/resources/mapper/procurementrecord/ProcurementRecordMapper.xml
+++ b/src/main/resources/mapper/procurementrecord/ProcurementRecordMapper.xml
@@ -2,7 +2,7 @@
         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper">
 
-    <select id="listProcurementBySalesLedgerId" resultType="com.ruoyi.procurementrecord.dto.ProcurementDto">
+    <select id="listProcurementBySalesLedgerId" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementDto">
         select
             t1.supplier_name,
             t2.product_category,
@@ -28,7 +28,7 @@
         </if>
         group by t2.id
     </select>
-    <select id="listPage" resultType="com.ruoyi.procurementrecord.dto.ProcurementPageDto">
+    <select id="listPage" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementPageDto">
         select
         t3.supplier_name,
         t3.purchase_contract_number,
@@ -68,7 +68,7 @@
         </where>
         order by t1.create_time desc
     </select>
-    <select id="list" resultType="com.ruoyi.procurementrecord.dto.ProcurementPageDto">
+    <select id="list" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementPageDto">
         select
             t3.supplier_name,
             t3.purchase_contract_number,
@@ -92,7 +92,7 @@
                   left join purchase_ledger t3 on t3.id = t2.sales_ledger_id
                 where t1.type = 1
     </select>
-    <select id="listOne" resultType="com.ruoyi.procurementrecord.dto.ProcurementPageDto">
+    <select id="listOne" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementPageDto">
         select
             t3.customer_contract_no,
             t3.sales_contract_no,
@@ -117,7 +117,7 @@
             left join sales_ledger t3 on t3.id = t2.sales_ledger_id
         where t1.type = 2
     </select>
-    <select id="listPageCopy" resultType="com.ruoyi.procurementrecord.dto.ProcurementPageDtoCopy">
+    <select id="listPageCopy" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementPageDtoCopy">
         select
         t3.supplier_name,
         t3.purchase_contract_number,
@@ -175,7 +175,7 @@
         group by t3.supplier_name,t2.product_category,t2.specification_model,t1.unit_price
         order by t1.create_time desc
     </select>
-    <select id="listCopy" resultType="com.ruoyi.procurementrecord.dto.ProcurementPageDtoCopy">
+    <select id="listCopy" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementPageDtoCopy">
         select
             t3.supplier_name,
             t3.purchase_contract_number,
@@ -203,7 +203,7 @@
         where t1.type = 1
         group by t3.supplier_name,t2.product_category,t2.specification_model
     </select>
-    <select id="listCopyOne" resultType="com.ruoyi.procurementrecord.dto.ProcurementPageDtoCopy">
+    <select id="listCopyOne" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementPageDtoCopy">
         select
             t3.customer_contract_no,
             t3.sales_contract_no,
@@ -232,7 +232,7 @@
         where t1.type = 2
         group by t3.customer_name,t2.product_category,t2.specification_model
     </select>
-    <select id="listPageByProduction" resultType="com.ruoyi.procurementrecord.dto.ProcurementPageDto">
+    <select id="listPageByProduction" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementPageDto">
         select
         t3.customer_contract_no,
         t3.sales_contract_no,
@@ -274,7 +274,7 @@
         </where>
         order by t1.create_time desc
     </select>
-    <select id="listPageCopyByProduction" resultType="com.ruoyi.procurementrecord.dto.ProcurementPageDtoCopy">
+    <select id="listPageCopyByProduction" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementPageDtoCopy">
         select
         t3.customer_contract_no,
         t3.sales_contract_no,
@@ -336,7 +336,7 @@
         group by t2.product_category,t2.specification_model,t1.unit_price
         order by t1.create_time desc
     </select>
-    <select id="listPagePRS" resultType="com.ruoyi.procurementrecord.dto.ProcurementPageDtoCopy">
+    <select id="listPagePRS" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementPageDtoCopy">
         select *
         from  procurement_record_storage t1
         left join sales_ledger_product t2 on t2.id = t1.sales_ledger_product_id
@@ -358,7 +358,7 @@
         from procurement_record_storage
         where product_model_id = #{productModelId}
     </select>
-    <select id="listPageByProductProduction" resultType="com.ruoyi.procurementrecord.dto.ProcurementPageDto">
+    <select id="listPageByProductProduction" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementPageDto">
         select
         t1.*,
         t1.inbound_num as inboundNum0,
@@ -380,4 +380,4 @@
         </where>
         order by t1.create_time desc
     </select>
-</mapper>
\ No newline at end of file
+</mapper>
diff --git a/src/main/resources/mapper/procurementrecord/ProcurementRecordOutMapper.xml b/src/main/resources/mapper/procurementrecord/ProcurementRecordOutMapper.xml
index adc64dd..46925aa 100644
--- a/src/main/resources/mapper/procurementrecord/ProcurementRecordOutMapper.xml
+++ b/src/main/resources/mapper/procurementrecord/ProcurementRecordOutMapper.xml
@@ -2,7 +2,7 @@
         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.ruoyi.procurementrecord.mapper.ProcurementRecordOutMapper">
 
-    <select id="listPage" resultType="com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto">
+    <select id="listPage" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutPageDto">
         select
         t3.supplier_name,
         t2.product_category,
@@ -38,7 +38,7 @@
         </where>
         order by t1.create_time desc
     </select>
-    <select id="list" resultType="com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto">
+    <select id="list" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutPageDto">
         select t3.supplier_name,
                t2.product_category,
                t1.id,
@@ -58,7 +58,7 @@
         where t1.type = 1
     </select>
 
-    <select id="listOne" resultType="com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto">
+    <select id="listOne" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutPageDto">
         select t3.customer_contract_no,
                t3.sales_contract_no,
                t3.customer_name,
@@ -80,7 +80,7 @@
         where t1.type = 2
     </select>
 
-    <select id="listTwo" resultType="com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto">
+    <select id="listTwo" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutPageDto">
         select t1.supplier_name,
                t1.product_category,
                t1.id,
@@ -97,7 +97,7 @@
         from procurement_record_out t1
         where t1.type = 3
     </select>
-    <select id="listPageByProduct" resultType="com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto">
+    <select id="listPageByProduct" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutPageDto">
         select
         t3.customer_contract_no,
         t3.sales_contract_no,
@@ -134,7 +134,7 @@
         </where>
         order by t1.create_time desc
     </select>
-    <select id="listPageByCustom" resultType="com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto">
+    <select id="listPageByCustom" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutPageDto">
         select
         t2.supplier_name,
         t2.product_category,
@@ -180,7 +180,7 @@
         order by id desc
         limit 1
     </select>
-    <select id="listPageBySemiProduct" resultType="com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto">
+    <select id="listPageBySemiProduct" resultType="com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutPageDto">
         select
         t1.id,
         t1.code,
@@ -206,4 +206,4 @@
         order by t1.create_time desc
     </select>
 
-</mapper>
\ No newline at end of file
+</mapper>
diff --git a/src/main/resources/mapper/procurementrecord/ReturnManagementMapper.xml b/src/main/resources/mapper/procurementrecord/ReturnManagementMapper.xml
index a06b4f0..d348a6b 100644
--- a/src/main/resources/mapper/procurementrecord/ReturnManagementMapper.xml
+++ b/src/main/resources/mapper/procurementrecord/ReturnManagementMapper.xml
@@ -2,7 +2,7 @@
         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.ruoyi.procurementrecord.mapper.ReturnManagementMapper">
 
-    <select id="listPage" resultType="com.ruoyi.procurementrecord.dto.ReturnManagementDto">
+    <select id="listPage" resultType="com.ruoyi.procurementrecord.bean.dto.ReturnManagementDto">
         select rm.*,
                c.customer_name,
                si.shipping_no,
@@ -40,7 +40,7 @@
             </if>
         </where>
     </select>
-    <select id="getReturnManagementDtoById" resultType="com.ruoyi.procurementrecord.dto.ReturnManagementDto">
+    <select id="getReturnManagementDtoById" resultType="com.ruoyi.procurementrecord.bean.dto.ReturnManagementDto">
      select rm.*,
                c.customer_name,
                si.shipping_no,
@@ -53,7 +53,7 @@
                  left join sales_ledger sl on si.sales_ledger_id = sl.id
         where rm.id = #{id}
     </select>
-    <select id="listPageBySalesReturn" resultType="com.ruoyi.account.bean.vo.SalesReturnVo">
+    <select id="listPageAccountSalesReturn" resultType="com.ruoyi.account.bean.vo.SalesReturnVo">
          select rm.id,
                 rm.return_no,
                 c.customer_name,
@@ -75,7 +75,7 @@
                 and c.customer_name like concat('%',#{req.customerName},'%')
             </if>
             <if test="req.startDate != null and req.endDate != null">
-                AND DATE_FORMAT(rm.make_time, '%Y-%m-%d') BETWEEN #{startDate} AND #{endDate}
+                AND DATE_FORMAT(rm.make_time, '%Y-%m-%d') BETWEEN #{req.startDate} AND #{req.endDate}
             </if>
          order by rm.id DESC
     </select>
diff --git a/src/main/resources/mapper/procurementrecord/ReturnSaleProductMapper.xml b/src/main/resources/mapper/procurementrecord/ReturnSaleProductMapper.xml
index 55cba43..93bd879 100644
--- a/src/main/resources/mapper/procurementrecord/ReturnSaleProductMapper.xml
+++ b/src/main/resources/mapper/procurementrecord/ReturnSaleProductMapper.xml
@@ -6,33 +6,46 @@
     <resultMap id="BaseResultMap" type="com.ruoyi.procurementrecord.pojo.ReturnSaleProduct">
         <id column="id" property="id" />
         <result column="return_management_id" property="returnManagementId" />
-        <result column="return_sales_ledger_product_id" property="returnsalesLedgerProductId" />
+        <result column="stock_out_record_id" property="stockOutRecordId" />
         <result column="num" property="num" />
         <result column="status" property="status" />
     </resultMap>
-    <select id="listReturnSaleProductDto" resultType="com.ruoyi.procurementrecord.dto.ReturnSaleProductDto">
-        SELECT slp.product_category                                         as product_name,
-               slp.specification_model                                      as model,
-               slp.unit                                      as unit,
+    <select id="listReturnSaleProductDto" resultType="com.ruoyi.procurementrecord.bean.dto.ReturnSaleProductDto">
+        SELECT distinct
+            p.product_name                                         as product_name,
+               pm.model                                     as model,
+               pm.unit                                      as unit,
                rsp.*,
-               GREATEST(slp.quantity - COALESCE(rs.total_return_num, 0), 0) AS un_quantity,
+            sor.outbound_batches,
+            sor.stock_out_num,
+            sor.batch_no,
+               GREATEST(sor.stock_out_num - COALESCE(rsp.num, 0), 0) AS un_quantity,
                COALESCE(rs.total_return_num, 0)                             AS total_return_num
         FROM return_sale_product rsp
                  LEFT JOIN return_management rm ON rm.id = rsp.return_management_id
                  LEFT JOIN shipping_info si ON si.id = rm.shipping_id
+                 LEFT JOIN shipping_product_detail spd ON spd.shipping_info_id = si.id
+                 LEFT JOIN stock_out_record sor ON rsp.stock_out_record_id = sor.id and sor.record_type = '13'
                  LEFT JOIN sales_ledger_product slp ON si.sales_ledger_product_id = slp.id and slp.type = 1
-                 LEFT JOIN (SELECT return_sales_ledger_product_id,
-
+                left join product_model pm on slp.product_model_id = pm.id
+                  LEFT JOIN product p on pm.product_id = p.id
+                 LEFT JOIN (SELECT stock_out_record_id,
                                    SUM(num) AS total_return_num
                             FROM return_sale_product
-                            WHERE 1 = 1 and return_management_id != #{returnManagementId}
-                            GROUP BY return_sales_ledger_product_id) rs ON rs.return_sales_ledger_product_id = slp.id
+                            WHERE 1 = 1 and return_management_id = #{returnManagementId}
+                            GROUP BY stock_out_record_id) rs ON rs.stock_out_record_id = sor.id
         where rm.id =#{returnManagementId}
     </select>
-    <select id="listReturnSaleProduct" resultType="com.ruoyi.procurementrecord.dto.ReturnSaleProductDto">
-        select rsp.*,slp.tax_inclusive_unit_price ,slp.tax_inclusive_total_price*rsp.num as price
+    <select id="listReturnSaleProduct" resultType="com.ruoyi.procurementrecord.bean.dto.ReturnSaleProductDto">
+        select rsp.*,
+               sor.batch_no,
+               slp.tax_inclusive_unit_price ,
+               slp.tax_inclusive_total_price*rsp.num as price
         from return_sale_product rsp
-                 left join sales_ledger_product slp on slp.id = rsp.return_sales_ledger_product_id
+                 LEFT JOIN return_management rm ON rm.id = rsp.return_management_id
+                 LEFT JOIN shipping_info si ON si.id = rm.shipping_id
+                 LEFT JOIN sales_ledger_product slp ON si.sales_ledger_product_id = slp.id and slp.type = 1
+                 LEFT JOIN stock_out_record sor ON rsp.stock_out_record_id = sor.id
         where rsp.return_management_id = #{returnManagementId}
     </select>
 
diff --git a/src/main/resources/mapper/purchase/PurchaseReturnOrderProductsMapper.xml b/src/main/resources/mapper/purchase/PurchaseReturnOrderProductsMapper.xml
index cd13f3c..ec1efe1 100644
--- a/src/main/resources/mapper/purchase/PurchaseReturnOrderProductsMapper.xml
+++ b/src/main/resources/mapper/purchase/PurchaseReturnOrderProductsMapper.xml
@@ -13,7 +13,9 @@
     </resultMap>
     <select id="getReturnOrderGroupListByProductIds" resultType="com.ruoyi.purchase.dto.SimpleReturnOrderGroupDto"
             parameterType="java.util.List">
-        select t1.sales_ledger_product_id,sum(t1.return_quantity) as sum_return_quantity from purchase_return_order_products as t1
+        select t1.sales_ledger_product_id,
+               sum(t1.return_quantity) as sum_return_quantity
+        from purchase_return_order_products as t1
         inner join purchase_return_orders as t2 on t1.purchase_return_order_id = t2.id
         WHERE t1.sales_ledger_product_id IN
         <foreach item="id" collection="productIds" separator="," open="(" close=")">
diff --git a/src/main/resources/mapper/purchase/PurchaseReturnOrdersMapper.xml b/src/main/resources/mapper/purchase/PurchaseReturnOrdersMapper.xml
index 77435ad..a001e9a 100644
--- a/src/main/resources/mapper/purchase/PurchaseReturnOrdersMapper.xml
+++ b/src/main/resources/mapper/purchase/PurchaseReturnOrdersMapper.xml
@@ -53,4 +53,96 @@
         <include refid="getPurchaseReturnOrderHasAllInfoFormAndColumn"/>
         where pro.id = #{id}
     </select>
+    <select id="listPageAccountPurchaseReturn"
+            resultType="com.ruoyi.account.bean.vo.PurchaseReturnVo">
+         select pro.id,
+                pro.no returnNo,
+                t.inboundBatches,
+                sm.supplier_name,
+                pro.prepared_at,
+                pro.total_amount,
+                CASE pro.return_type WHEN 0 THEN '閫�璐ч��娆�' WHEN 1 THEN '鎷掓敹' END AS returnType,
+                pl.purchase_contract_number
+        from purchase_return_orders pro
+        left join
+            (select prop.purchase_return_order_id,
+                    GROUP_CONCAT(sir.inbound_batches SEPARATOR ',') AS inboundBatches
+            from purchase_return_order_products prop
+            left join stock_in_record sir on prop.stock_in_record_id = sir.id
+            GROUP BY prop.purchase_return_order_id) t on t.purchase_return_order_id = pro.id
+        left join supplier_manage sm on pro.supplier_id = sm.id
+        left join purchase_ledger pl on pro.purchase_ledger_id = pl.id
+        where 1=1
+            <if test="req.returnNo != null and req.returnNo != ''">
+                and pro.no like concat('%',#{req.returnNo},'%')
+            </if>
+            <if test="req.supplierName != null and req.supplierName != ''">
+                and sm.supplier_name like concat('%',#{req.supplierName},'%')
+            </if>
+            <if test="req.startDate != null and req.endDate != null">
+                AND DATE_FORMAT(pro.prepared_at, '%Y-%m-%d') BETWEEN #{req.startDate} AND #{req.endDate}
+            </if>
+         order by pro.id DESC
+    </select>
+    <select id="getByPurchaseLedgerId" resultType="com.ruoyi.purchase.vo.PurchaseStockInProductVo">
+         SELECT
+            sir.id,
+            sir.product_model_id,
+            slp.id salesLedgerProductId,
+            slp.product_category,
+            slp.specification_model,
+            slp.unit,
+            slp.is_checked,
+            sir.inbound_batches,
+            sir.stock_in_num,
+            sir.batch_no,
+            slp.tax_inclusive_unit_price,
+            GREATEST(sir.stock_in_num - COALESCE(rs.total_return_num, 0), 0) AS un_quantity,
+            COALESCE(rs.total_return_num, 0) AS total_return_num
+            FROM stock_in_record sir
+            LEFT JOIN quality_inspect qi ON sir.record_type = 10 AND sir.record_id = qi.id
+            LEFT JOIN purchase_ledger pl
+            ON pl.id = IF(sir.record_type = 7, sir.record_id, qi.purchase_ledger_id)
+            LEFT JOIN sales_ledger_product slp ON pl.id = slp.sales_ledger_id
+            LEFT JOIN (
+                SELECT
+                    stock_in_record_id,
+                    SUM(return_quantity) AS total_return_num
+                FROM purchase_return_order_products prop
+                         left join purchase_return_orders pro on pro.id = prop.purchase_return_order_id
+                WHERE 1=1
+                GROUP BY stock_in_record_id
+            ) rs ON rs.stock_in_record_id = sir.id
+        WHERE sir.approval_status = 1 AND slp.type = 2
+        AND sir.record_type IN ('7','10')
+         and pl.id = #{purchaseLedgerId}
+    </select>
+    <select id="getPurchaseReturnOrderProductsDetailById"
+            resultType="com.ruoyi.purchase.vo.PurchaseReturnOrderProductsDetailVo">
+    select prop.id,
+           prop.sales_ledger_product_id,
+           slp.product_model_id,
+           slp.product_category,
+           slp.specification_model,
+           slp.is_checked,
+           slp.unit,
+           sir.inbound_batches,
+           sir.stock_in_num,
+           sir.batch_no,
+           slp.tax_inclusive_unit_price,
+           prop.return_quantity,
+           prop.purchase_return_order_id,
+           GREATEST(sir.stock_in_num - COALESCE(prop.return_quantity, 0), 0) AS un_quantity,
+           COALESCE(rs.total_return_num, 0)                             AS total_return_num
+    from purchase_return_order_products prop
+    left join purchase_return_orders pro on prop.purchase_return_order_id = pro.id
+    LEFT JOIN stock_in_record sir ON prop.stock_in_record_id = sir.id and sir.record_type in ('7','10')
+    LEFT JOIN sales_ledger_product slp ON prop.sales_ledger_product_id = slp.id  and slp.type = 2
+    LEFT JOIN (SELECT stock_in_record_id,
+                      SUM(return_quantity) AS total_return_num
+               FROM purchase_return_order_products
+               WHERE 1 = 1 and purchase_return_order_id = #{id}
+               GROUP BY stock_in_record_id) rs ON rs.stock_in_record_id = sir.id
+    where pro.id = #{id}
+    </select>
 </mapper>
diff --git a/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml b/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
index 49689a1..f3fa32d 100644
--- a/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
+++ b/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -6,7 +6,42 @@
 
     <select id="selectSalesLedgerProductList" resultType="com.ruoyi.sales.pojo.SalesLedgerProduct">
         SELECT
-        T1.*,
+        T1.id,
+        T1.sales_ledger_id,
+        T1.warn_num,
+        T1.speculative_trading_name,
+        T1.quantity,
+        T1.min_stock,
+        T1.tax_rate,
+        T1.tax_inclusive_unit_price,
+        T1.tax_inclusive_total_price,
+        T1.tax_exclusive_total_price,
+        T1.invoice_type,
+        T1.type,
+        T1.tickets_num,
+        T1.tickets_amount,
+        T1.future_tickets,
+        T1.future_tickets_amount,
+        T1.invoice_num,
+        T1.no_invoice_num,
+        T1.invoice_amount,
+        T1.no_invoice_amount,
+        T1.product_id,
+        T1.product_model_id,
+        T1.register,
+        T1.register_date,
+        T1.approve_status,
+        T1.pending_invoice_total,
+        T1.invoice_total,
+        T1.pending_tickets_total,
+        T1.tickets_total,
+        T1.is_checked,
+        T1.is_production,
+        T1.create_user,
+        T1.dept_id,
+        p.product_name as product_category,
+        pm.model as specification_model,
+        pm.unit as unit,
         CASE
         WHEN (IFNULL(t2.qualitity, 0) - IFNULL(t2.locked_quantity, 0)) >0 THEN 1
         ELSE 0
@@ -29,6 +64,8 @@
         LEFT JOIN shipping_product_detail spd ON si.id = spd.shipping_info_id
         GROUP BY sales_ledger_product_id
         ) t3 ON t3.sales_ledger_product_id = T1.id
+        left join product_model pm ON T1.product_model_id = pm.id
+        left join product p ON pm.product_id = p.id
         <where>
             <if test="salesLedgerProduct.salesLedgerId != null">
                 AND T1.sales_ledger_id = #{salesLedgerProduct.salesLedgerId}
diff --git a/src/main/resources/mapper/sales/ShippingInfoMapper.xml b/src/main/resources/mapper/sales/ShippingInfoMapper.xml
index cd7dc3e..762c2d4 100644
--- a/src/main/resources/mapper/sales/ShippingInfoMapper.xml
+++ b/src/main/resources/mapper/sales/ShippingInfoMapper.xml
@@ -19,14 +19,22 @@
         s.update_user,
         s.tenant_id,
         sl.sales_contract_no,
-        slp.specification_model,
+        pm.model as specification_model,
+        pm.unit,
         p.product_name,
-        sl.customer_name
+        sl.customer_name,
+        spd.totalQuantity,
+        sor.outboundBatches
         FROM shipping_info s
+        LEFT JOIN (select shipping_info_id,sum(quantity) totalQuantity from shipping_product_detail GROUP BY shipping_info_id) spd ON spd.shipping_info_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 and slp.type = 1
         left join product_model pm on slp.product_model_id = pm.id
         left join product p on pm.product_id = p.id
+        left join (select record_id,GROUP_CONCAT(outbound_batches SEPARATOR ',') AS outboundBatches
+                   from stock_out_record
+                   where record_type='13'and approval_status=1
+                   group by record_id)sor on sor.record_id= s.id
         WHERE 1=1
         <if test="req.salesContractNo != null and req.salesContractNo != ''">
             AND sl.sales_contract_no LIKE CONCAT('%',#{req.salesContractNo},'%')
@@ -58,62 +66,43 @@
         FROM shipping_info s
                  LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id
     </select>
-    <select id="getReturnManagementDtoById" resultType="com.ruoyi.sales.dto.SalesLedgerProductDto">
-        SELECT
-        slp.*,
-        si.shipping_no,
-        GREATEST(slp.quantity - COALESCE(rs.total_return_num, 0), 0) AS un_quantity,
-        COALESCE(rs.total_return_num, 0) AS total_return_num
+    <select id="getReturnManagementDtoById" resultType="com.ruoyi.procurementrecord.bean.vo.ShippingProductVo">
+        SELECT distinct
+            sor.id,
+            slp.product_category,
+            slp.specification_model,
+            slp.unit,
+            slp.product_model_id,
+            sor.outbound_batches,
+            sor.stock_out_num,
+            sor.batch_no,
+            slp.tax_inclusive_unit_price,
+            GREATEST(sor.stock_out_num - COALESCE(rs.total_return_num, 0), 0) AS un_quantity,
+            COALESCE(rs.total_return_num, 0) AS total_return_num
         FROM shipping_info si
+        LEFT JOIN shipping_product_detail spd ON spd.shipping_info_id = si.id
+        LEFT JOIN stock_out_record sor ON sor.record_id = si.id and sor.record_type = '13'
         LEFT JOIN sales_ledger_product slp ON si.sales_ledger_product_id = slp.id and slp.type = 1
         LEFT JOIN (
         SELECT
-        return_sales_ledger_product_id,
+        stock_out_record_id,
         SUM(num) AS total_return_num
         FROM return_sale_product rsp
         left join return_management rm on rm.id = rsp.return_management_id
         left join shipping_info si on si.id = rm.shipping_id
         WHERE 1=1
-        GROUP BY return_sales_ledger_product_id
-        ) rs ON rs.return_sales_ledger_product_id = slp.id
+        GROUP BY stock_out_record_id
+        ) rs ON rs.stock_out_record_id = sor.id
         <where>
             <if test="shippingId != null">
                 si.id = #{shippingId}
             </if>
         </where>
+        order by sor.id
     </select>
     <select id="getShippingInfoByCustomerName" resultType="com.ruoyi.sales.pojo.ShippingInfo">
         select * from shipping_info si
         left join sales_ledger sl on si.sales_ledger_id = sl.id
-        where si.status = '宸插彂璐�' and sl.customer_name = #{customerName}
-    </select>
-    <select id="listPageByOutbound" resultType="com.ruoyi.account.bean.vo.SalesOutboundVo">
-         SELECT
-        sor.id,
-        sor.outbound_batches,
-        sl.customer_name,
-        s.shipping_date,
-        p.product_name,
-        slp.specification_model,
-        slp.stock_out_num,
-        s.shipping_no,
-        sl.sales_contract_no
-        FROM shipping_info s
-        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 and slp.type = 1
-        left join product_model pm on slp.product_model_id = pm.id
-        left join product p on pm.product_id = p.id
-        left join stock_out_record sor on sor.record_id = s.id and sor.record_type='13'
-        WHERE s.status='宸插彂璐�'
-        <if test="req.outboundBatches != null and req.outboundBatches != ''">
-            AND sor.outbound_batches LIKE CONCAT('%',#{req.outboundBatches},'%')
-        </if>
-        <if test="req.customerName != null and req.customerName != ''">
-            AND sl.customer_name LIKE CONCAT('%',#{req.customerName},'%')
-        </if>
-        <if test="req.startDate != null and req.endDate != null">
-            AND s.shipping_date BETWEEN #{startDate} AND #{endDate}
-        </if>
-        order by sor.id DESC
+        where  sl.customer_name = #{customerName}
     </select>
 </mapper>
diff --git a/src/main/resources/mapper/stock/StockInRecordMapper.xml b/src/main/resources/mapper/stock/StockInRecordMapper.xml
index 62f1d19..579a464 100644
--- a/src/main/resources/mapper/stock/StockInRecordMapper.xml
+++ b/src/main/resources/mapper/stock/StockInRecordMapper.xml
@@ -70,4 +70,38 @@
         </where>
         order by sir.id desc
     </select>
+    <select id="listPageAccountPurchase" resultType="com.ruoyi.account.bean.vo.PurchaseInboundVo">
+        SELECT
+            sir.id,
+            sir.inbound_batches,
+            pl.supplier_name,
+            DATE(sir.create_time) AS inboundDate,
+            p.product_name,
+            pm.model as specification_model,
+            sir.stock_in_num * slp.tax_inclusive_unit_price AS InboundAmount,
+            pl.purchase_contract_number
+            FROM stock_in_record sir
+            -- 10 绫诲瀷鎵嶅叧鑱旇川妫�琛�
+            LEFT JOIN quality_inspect qi ON sir.record_type = 10 AND sir.record_id = qi.id
+            -- 鍔ㄦ�佸叧鑱旈噰璐紙鑷姩閫傞厤 7 鍜� 10锛�
+            LEFT JOIN purchase_ledger pl
+            ON pl.id = IF(sir.record_type = 7, sir.record_id, qi.purchase_ledger_id)
+            -- 浜у搧鍏宠仈涓嶅姩
+            LEFT JOIN sales_ledger_product slp ON pl.id = slp.product_id
+            LEFT JOIN product_model pm ON sir.product_model_id = pm.id
+            LEFT JOIN product p ON pm.product_id = p.id
+            -- 鏉′欢
+        WHERE sir.approval_status = 1 AND slp.type = 2
+        AND sir.record_type IN ('7','10')
+        <if test="req.inboundBatches != null and req.inboundBatches != ''">
+            AND sir.inbound_batches LIKE CONCAT('%',#{req.inboundBatches},'%')
+        </if>
+        <if test="req.supplierName != null and req.supplierName != ''">
+            AND pl.supplier_name LIKE CONCAT('%',#{req.supplierName},'%')
+        </if>
+        <if test="req.startDate != null and req.endDate != null">
+            AND DATE(sir.create_time) BETWEEN #{req.startDate} AND #{req.endDate}
+        </if>
+        order by sir.id DESC
+    </select>
 </mapper>
diff --git a/src/main/resources/mapper/stock/StockInventoryMapper.xml b/src/main/resources/mapper/stock/StockInventoryMapper.xml
index 60fc90e..9612933 100644
--- a/src/main/resources/mapper/stock/StockInventoryMapper.xml
+++ b/src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -436,7 +436,7 @@
         WHERE sor.product_model_id = #{productModelId}
           AND (sor.batch_no = #{batchNo} OR (#{batchNo} IS NULL AND sor.batch_no IS NULL))
           AND sor.type = #{type}
-          AND sor.approval_status = 0
+          AND sor.approval_status IN (0, 3)
     </select>
 
     <select id="listSelectableBatchNoByProductModelIds" resultType="com.ruoyi.stock.pojo.StockInventory">
@@ -453,12 +453,24 @@
         order by si.product_model_id, si.batch_no
     </select>
     <select id="getByModelId" resultType="com.ruoyi.stock.pojo.StockInventory">
-        select spd.id, spd.batch_no, spd.locked_quantity, (spd.qualitity - IFNULL(sd.qualitity, 0)) as qualitity
-        from stock_inventory spd
-                 left join (select stock_inventory_id, sum(quantity) as qualitity
-                            from shipping_product_detail
-                            group by stock_inventory_id) as sd on sd.stock_inventory_id = spd.id
-        where product_model_id = #{productModelId}
+        select si.id, si.batch_no, si.locked_quantity, (si.qualitity - IFNULL(sd.qualitity, 0)) as qualitity
+        from stock_inventory si
+                 left join (
+                    select spd.stock_inventory_id, sum(spd.quantity) as qualitity
+                    from shipping_product_detail spd
+                    where exists (
+                        select 1
+                        from stock_out_record sor
+                        where sor.record_id = spd.shipping_info_id
+                          and sor.record_type = '13'
+                          and sor.type = '0'
+                          and sor.approval_status in (0, 3)
+                          and sor.product_model_id = spd.product_model_id
+                          and (sor.batch_no = spd.batch_no or (sor.batch_no is null and spd.batch_no is null))
+                    )
+                    group by spd.stock_inventory_id
+                 ) as sd on sd.stock_inventory_id = si.id
+        where si.product_model_id = #{productModelId}
     </select>
 
 </mapper>
diff --git a/src/main/resources/mapper/stock/StockOutRecordMapper.xml b/src/main/resources/mapper/stock/StockOutRecordMapper.xml
index 8615294..35421c9 100644
--- a/src/main/resources/mapper/stock/StockOutRecordMapper.xml
+++ b/src/main/resources/mapper/stock/StockOutRecordMapper.xml
@@ -86,4 +86,33 @@
         order by sor.id desc
     </select>
 
+    <select id="listPageAccountSales" resultType="com.ruoyi.account.bean.vo.SalesOutboundVo">
+    SELECT
+        sor.id,
+        sor.outbound_batches,
+        sl.customer_name,
+        sor.create_time as shippingDate,
+        p.product_name,
+        pm.model as specification_model,
+        sor.stock_out_num * slp.tax_inclusive_unit_price as outboundAmount,
+        s.shipping_no,
+        sl.sales_contract_no
+        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 and slp.type = 1
+        left join product_model pm on slp.product_model_id = pm.id
+        left join product p on pm.product_id = p.id
+        WHERE sor.record_type='13' and sor.approval_status=1
+        <if test="req.outboundBatches != null and req.outboundBatches != ''">
+            AND sor.outbound_batches LIKE CONCAT('%',#{req.outboundBatches},'%')
+        </if>
+        <if test="req.customerName != null and req.customerName != ''">
+            AND sl.customer_name LIKE CONCAT('%',#{req.customerName},'%')
+        </if>
+        <if test="req.startDate != null and req.endDate != null">
+            AND s.shipping_date BETWEEN #{req.startDate} AND #{req.endDate}
+        </if>
+        order by sor.id DESC
+    </select>
 </mapper>
diff --git a/src/main/resources/mapper/technology/TechnologyBomStructureMapper.xml b/src/main/resources/mapper/technology/TechnologyBomStructureMapper.xml
index 2030715..536cdba 100644
--- a/src/main/resources/mapper/technology/TechnologyBomStructureMapper.xml
+++ b/src/main/resources/mapper/technology/TechnologyBomStructureMapper.xml
@@ -21,7 +21,8 @@
                p.product_name as productName,
                pm.product_id as productId,
                pm.model,
-               top1.name as operationName
+               top1.name as operationName,
+               pm.product_code as productCode
         from technology_bom_structure tbs
         left join product_model pm on tbs.product_model_id = pm.id
         left join product p on pm.product_id = p.id

--
Gitblit v1.9.3