Merge remote-tracking branch 'origin/dev_New_pro' into dev_New_pro
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # AccountSubject æ å½¢æ¹é åç«¯ä¿®æ¹ææ¡£ |
| | | |
| | | æ´æ°æ¶é´ï¼2026-05-12 |
| | | |
| | | ## 1. åæ´èæ¯ |
| | | |
| | | `AccountSubjectController` å·²æ¹ä¸ºç¶åå±çº§é彿¨¡å¼ï¼`/accountSubject/list` ç°å¨è¿åæ å½¢ç»æï¼`children` éå½ï¼ï¼ä¸åæ¯å纯çå¹³éºå表ã |
| | | |
| | | --- |
| | | |
| | | ## 2. å端æ¥å£åå |
| | | |
| | | ### 2.1 æ¥è¯¢æ¥å£ï¼å·²åæ´ä¸ºæ ï¼ |
| | | |
| | | - URLï¼`GET /accountSubject/list` |
| | | - å
¥åï¼ä¿æä¸åï¼`current,size,subjectCode,subjectName,subjectType,status`ï¼ |
| | | - åºåï¼ä»æ¯å页壳ï¼`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 åèè°ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- account_subject å¢å ç¶çº§ç§ç®åæ®µï¼æ å½¢ç»æï¼ |
| | | ALTER TABLE `account_subject` |
| | | ADD COLUMN `parent_id` bigint NULL COMMENT 'ç¶ç§ç®IDï¼ä¸ºç©ºè¡¨ç¤ºæ ¹èç¹ï¼' AFTER `id`; |
| | | |
| | | CREATE INDEX `idx_account_subject_parent_id` ON `account_subject` (`parent_id`); |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- è´¢å¡ç®¡ç模åå»ºè¡¨èæ¬ï¼åºå®èµäº§/æ å½¢èµäº§/åè¯/ç§ç®è´¦ï¼ |
| | | -- 说æï¼ |
| | | -- 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='åè¯åå½'; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # è´¢å¡ç®¡ç模åå端èè°ææ¡£ï¼account 模åï¼ |
| | | |
| | | æ´æ°æ¶é´ï¼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ï¼JSONï¼ï¼ |
| | | |
| | | ```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`ï¼YYYY-MMï¼ |
| | | - `endMonth`ï¼YYYY-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`ï¼YYYY-MMï¼ |
| | | - `endMonth`ï¼YYYY-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`ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.account.bean.dto.financial; |
| | | |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | /** |
| | | * ç§ç®æç»è´¦æ¥è¯¢åæ°ï¼å«è¾
婿 ¸ç®æ¡ä»¶ï¼ã |
| | | */ |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @Data |
| | | public class FinDetailLedgerQueryDto extends FinLedgerQueryDto { |
| | | |
| | | /** |
| | | * è¾
婿 ¸ç®ç±»åï¼customer/supplier/department/employee/projectã |
| | | */ |
| | | private String auxiliaryType; |
| | | |
| | | /** |
| | | * è¾
婿 ¸ç®å¯¹è±¡IDã |
| | | */ |
| | | private String auxiliaryId; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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 { |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.account.bean.dto.financial; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æ¹éID请æ±åæ°ã |
| | | */ |
| | | @Data |
| | | public class FinIdBatchDto { |
| | | |
| | | /** |
| | | * IDéåã |
| | | */ |
| | | private List<Long> ids; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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 { |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.account.bean.dto.financial; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * ç§ç®è´¦æ¥è¯¢åæ°ã |
| | | */ |
| | | @Data |
| | | public class FinLedgerQueryDto { |
| | | |
| | | /** |
| | | * ç§ç®ç¼ç ï¼æ¯ææ«çº§ææå®ç§ç®ï¼ã |
| | | */ |
| | | private String subjectCode; |
| | | |
| | | /** |
| | | * å¼å§æä»½ï¼æ ¼å¼ï¼YYYY-MMã |
| | | */ |
| | | private String startMonth; |
| | | |
| | | /** |
| | | * ç»ææä»½ï¼æ ¼å¼ï¼YYYY-MMã |
| | | */ |
| | | private String endMonth; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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 { |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.account.bean.dto.financial; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * åè¯ç¶æåæ´åæ°ã |
| | | */ |
| | | @Data |
| | | public class FinVoucherStatusDto { |
| | | |
| | | /** |
| | | * åè¯IDã |
| | | */ |
| | | private Long id; |
| | | } |
| | |
| | | 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; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.account.bean.vo.financial; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | |
| | | /** |
| | | * ç§ç®è´¦åºç¡å彿¥è¯¢å¯¹è±¡ï¼SQLæ å°ä½¿ç¨ï¼ã |
| | | */ |
| | | @Data |
| | | public class FinLedgerEntryRecordVo { |
| | | |
| | | /** |
| | | * åè¯æ¥æã |
| | | */ |
| | | private LocalDate voucherDate; |
| | | |
| | | /** |
| | | * åè¯åå·ã |
| | | */ |
| | | private String voucherNo; |
| | | |
| | | /** |
| | | * æè¦ã |
| | | */ |
| | | private String summary; |
| | | |
| | | /** |
| | | * åæ¹éé¢ã |
| | | */ |
| | | private BigDecimal debit; |
| | | |
| | | /** |
| | | * è´·æ¹éé¢ã |
| | | */ |
| | | private BigDecimal credit; |
| | | |
| | | /** |
| | | * è¡å·ï¼æåºå段ï¼ã |
| | | */ |
| | | private Integer rowNo; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | |
| | | |
| | | @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); |
| | |
| | | @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") |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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())); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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())); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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)); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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)); |
| | | } |
| | | } |
| | |
| | | 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> |
| | |
| | | @Mapper |
| | | public interface AccountSubjectMapper extends BaseMapper<AccountSubject> { |
| | | |
| | | Long countReferencedBySubjectCodes(@Param("subjectCodes") List<String> subjectCodes); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | } |
| | |
| | | private Long id; |
| | | |
| | | /** |
| | | * ç¶ç§ç®IDï¼ä¸ºç©ºè¡¨ç¤ºæ ¹èç¹ï¼ |
| | | */ |
| | | @ApiModelProperty("ç¶ç§ç®IDï¼ä¸ºç©ºè¡¨ç¤ºæ ¹èç¹ï¼") |
| | | private Long parentId; |
| | | |
| | | /** |
| | | * ç§ç®ç¼ç (å¯ä¸æ è¯) |
| | | */ |
| | | @ApiModelProperty("ç§ç®ç¼ç (å¯ä¸æ è¯)") |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * <p> |
| | | * æ»è´¦ç§ç®è¡¨ æå¡ç±» |
| | |
| | | |
| | | 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); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| | |
| | | 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; |
| | |
| | | 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; |
| | | |
| | | /** |
| | |
| | | |
| | | @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("ä¿®æ¹å¤±è´¥ï¼ç§ç®IDä¸è½ä¸ºç©º"); |
| | | } |
| | | 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 |
| | |
| | | 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); |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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("ä¿®æ¹å¤±è´¥ï¼èµäº§IDä¸è½ä¸ºç©º"); |
| | | } |
| | | 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; |
| | | } |
| | | |
| | | /** |
| | | * æææ¡£è§åæ ¡éªåºå®èµäº§æ°æ®ã |
| | | */ |
| | | private void validateForSave(FinFixedAssetDto dto, boolean isUpdate) { |
| | | if (dto == null) { |
| | | throw new ServiceException("åºå®èµäº§æ°æ®ä¸è½ä¸ºç©º"); |
| | | } |
| | | if (isUpdate && dto.getId() == null) { |
| | | throw new ServiceException("ä¿®æ¹å¤±è´¥ï¼èµäº§IDä¸è½ä¸ºç©º"); |
| | | } |
| | | 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); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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("ä¿®æ¹å¤±è´¥ï¼èµäº§IDä¸è½ä¸ºç©º"); |
| | | } |
| | | 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; |
| | | } |
| | | |
| | | /** |
| | | * æææ¡£è§åæ ¡éªæ å½¢èµäº§æ°æ®ã |
| | | */ |
| | | private void validateForSave(FinIntangibleAssetDto dto, boolean isUpdate) { |
| | | if (dto == null) { |
| | | throw new ServiceException("æ å½¢èµäº§æ°æ®ä¸è½ä¸ºç©º"); |
| | | } |
| | | if (isUpdate && dto.getId() == null) { |
| | | throw new ServiceException("ä¿®æ¹å¤±è´¥ï¼èµäº§IDä¸è½ä¸ºç©º"); |
| | | } |
| | | 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); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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 + "ä¸è½ä¸ºç©ºï¼æ ¼å¼åºä¸ºYYYY-MM"); |
| | | } |
| | | try { |
| | | return YearMonth.parse(value, MONTH_FORMATTER); |
| | | } catch (DateTimeParseException ex) { |
| | | throw new ServiceException(fieldLabel + "æ ¼å¼éè¯¯ï¼æ ¼å¼åºä¸ºYYYY-MM"); |
| | | } |
| | | } |
| | | |
| | | private BigDecimal money(BigDecimal value) { |
| | | if (value == null) { |
| | | return ZERO; |
| | | } |
| | | return value.setScale(2, RoundingMode.HALF_UP); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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("ä¿®æ¹å¤±è´¥ï¼åè¯IDä¸è½ä¸ºç©º"); |
| | | } |
| | | 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); |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | # å¼åç¯å¢é
ç½® |
| | | server: |
| | | # æå¡å¨çHTTP端å£ï¼é»è®¤ä¸º8080 |
| | | port: 7005 |
| | | port: 7006 |
| | | servlet: |
| | | # åºç¨ç访é®è·¯å¾ |
| | | context-path: / |
| | |
| | | <!-- éç¨æ¥è¯¢æ å°ç»æ --> |
| | | <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" /> |
| | |
| | | <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> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <?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> |