Compare commits

..
10 Commits
Author SHA1 Message Date
ifly 752fba0582 迁移部分内联sql 2026-07-15 09:07:38 +08:00
ifly a8b2c05bd8 包迁移 2026-07-14 10:14:46 +08:00
ifly ab46eb7383 把内联sql改外层 2026-07-14 10:04:03 +08:00
ifly 3b6ae6123b sql文件整理 2026-07-13 14:53:02 +08:00
ifly 0cce9d3acc 签章位置固定功能 2026-07-10 17:03:39 +08:00
ifly f7b995ed3a 补足用户切换功能 2026-07-09 16:07:48 +08:00
ifly 000d5d3028 审批完成的合同,在合同签署界面进行在线签署。合同发起界面不能在线签署。 2026-07-09 15:12:25 +08:00
ifly 3dff283259 1. 变量占位符:{中文变量}
2. 变量占位符预设类型,可以是:输入框、下拉、富文本(允许插入表格作为合同正本的附件内容)
2026-07-09 14:08:26 +08:00
ifly f18a173d25 细节修改 2026-07-08 08:36:44 +08:00
ifly 4433646003 相对方确认签署 2026-07-01 13:00:06 +08:00
202 changed files with 4410 additions and 2961 deletions
@@ -1,27 +1,24 @@
-- =============================================
-- Oracle version for zgwl_end.sql
-- Execute with: sqlplus developer/dev123@localhost/XEPDB1 @zgwl_end_oracle.sql
-- BIZ_STUDENT 建表脚本 (Oracle)
-- 自动整理生成,已合并历史patch字段
-- 执行方式: sqlplus developer/dev123@localhost/XEPDB1 @BIZ_STUDENT.sql
-- =============================================
WHENEVER SQLERROR EXIT SQL.SQLCODE;
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE BIZ_STUDENT';
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_BIZ_STUDENT';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
IF SQLCODE != -2289 THEN RAISE; END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_BIZ_STUDENT';
EXECUTE IMMEDIATE 'DROP TABLE BIZ_STUDENT CASCADE CONSTRAINTS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2289 THEN
RAISE;
END IF;
IF SQLCODE != -942 THEN RAISE; END IF;
END;
/
@@ -54,6 +51,12 @@ COMMENT ON COLUMN BIZ_STUDENT.UPDATE_DT IS '更新时间';
COMMENT ON COLUMN BIZ_STUDENT.CREATE_BY IS '创建人';
COMMENT ON COLUMN BIZ_STUDENT.UPDATE_BY IS '更新人';
CREATE SEQUENCE SEQ_BIZ_STUDENT
START WITH 1925800000000000004
INCREMENT BY 1
NOCACHE
NOCYCLE;
INSERT INTO BIZ_STUDENT (ID, STUDENT_NO, STUDENT_NAME, GENDER, AGE, PHONE, ADDRESS, CREATE_DT, UPDATE_DT, CREATE_BY, UPDATE_BY) VALUES
(1925800000000000001, 'S2024001', '张三', '', 20, '13800001111', '宁波市鄞州区', SYSTIMESTAMP, SYSTIMESTAMP, 'system', 'system');
INSERT INTO BIZ_STUDENT (ID, STUDENT_NO, STUDENT_NAME, GENDER, AGE, PHONE, ADDRESS, CREATE_DT, UPDATE_DT, CREATE_BY, UPDATE_BY) VALUES
@@ -61,8 +64,4 @@ INSERT INTO BIZ_STUDENT (ID, STUDENT_NO, STUDENT_NAME, GENDER, AGE, PHONE, ADDRE
INSERT INTO BIZ_STUDENT (ID, STUDENT_NO, STUDENT_NAME, GENDER, AGE, PHONE, ADDRESS, CREATE_DT, UPDATE_DT, CREATE_BY, UPDATE_BY) VALUES
(1925800000000000003, 'S2024003', '王五', '', 22, '13800003333', '宁波市镇海区', SYSTIMESTAMP, SYSTIMESTAMP, 'system', 'system');
CREATE SEQUENCE SEQ_BIZ_STUDENT
START WITH 1925800000000000004
INCREMENT BY 1
NOCACHE
NOCYCLE;
COMMIT;
@@ -1,27 +1,24 @@
-- =============================================
-- Oracle version for zgwl_manifest_tables.sql
-- Execute with: sqlplus developer/dev123@localhost/XEPDB1 @zgwl_manifest_tables_oracle.sql
-- CONTRACT_TEMPLATE_MANAGE 建表脚本 (Oracle)
-- 自动整理生成,已合并历史patch字段
-- 执行方式: sqlplus developer/dev123@localhost/XEPDB1 @CONTRACT_TEMPLATE_MANAGE.sql
-- =============================================
WHENEVER SQLERROR EXIT SQL.SQLCODE;
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE CONTRACT_TEMPLATE_MANAGE';
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_CONTRACT_TEMPLATE_MANAGE';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
IF SQLCODE != -2289 THEN RAISE; END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_CONTRACT_TEMPLATE_MANAGE';
EXECUTE IMMEDIATE 'DROP TABLE CONTRACT_TEMPLATE_MANAGE CASCADE CONSTRAINTS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2289 THEN
RAISE;
END IF;
IF SQLCODE != -942 THEN RAISE; END IF;
END;
/
@@ -50,10 +47,6 @@ CREATE TABLE CONTRACT_TEMPLATE_MANAGE (
CONSTRAINT UK_TEMPLATE_CODE UNIQUE (TEMPLATE_CODE)
);
CREATE INDEX IDX_TEMPLATE_NAME ON CONTRACT_TEMPLATE_MANAGE (TEMPLATE_NAME);
CREATE INDEX IDX_CONTRACT_TYPE ON CONTRACT_TEMPLATE_MANAGE (CONTRACT_TYPE);
CREATE INDEX IDX_STATUS ON CONTRACT_TEMPLATE_MANAGE (STATUS);
COMMENT ON TABLE CONTRACT_TEMPLATE_MANAGE IS '合同模板管理表';
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.ID IS '主键ID';
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.TEMPLATE_CODE IS '范本编号,后端自动生成';
@@ -76,10 +69,14 @@ COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.UPDATED_BY IS '更新人';
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.UPDATED_TIME IS '更新时间';
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.DEL_FLAG IS '删除标记:0存在 2删除';
CREATE INDEX IDX_TEMPLATE_NAME ON CONTRACT_TEMPLATE_MANAGE (TEMPLATE_NAME);
CREATE INDEX IDX_CONTRACT_TYPE ON CONTRACT_TEMPLATE_MANAGE (CONTRACT_TYPE);
CREATE INDEX IDX_STATUS ON CONTRACT_TEMPLATE_MANAGE (STATUS);
CREATE SEQUENCE SEQ_CONTRACT_TEMPLATE_MANAGE
START WITH 1
INCREMENT BY 1
NOCACHE
NOCYCLE;
CREATE SEQUENCE SEQ_CONTRACT_TEMPLATE_MANAGE INCREMENT BY 1 MINVALUE 1 MAXVALUE 9999999999999999999999999999 NOCYCLE CACHE 20 NOORDER
COMMIT;
@@ -1,47 +1,24 @@
-- =============================================
-- Oracle version for zgwl_partner_tables.sql
-- Execute with: sqlplus developer/dev123@localhost/XEPDB1 @zgwl_partner_tables_oracle.sql
-- ILDM_FEE_CUSTOMER_INFO 建表脚本 (Oracle)
-- 自动整理生成,已合并历史patch字段
-- 执行方式: sqlplus developer/dev123@localhost/XEPDB1 @ILDM_FEE_CUSTOMER_INFO.sql
-- =============================================
WHENEVER SQLERROR EXIT SQL.SQLCODE;
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE SEAL_PARTNER_CONTACT';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE ILDM_FEE_CUSTOMER_INFO';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_SEAL_PARTNER_CONTACT';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2289 THEN
RAISE;
END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_ILDM_FEE_CUSTOMER_INFO';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2289 THEN
RAISE;
END IF;
IF SQLCODE != -2289 THEN RAISE; END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE ILDM_FEE_CUSTOMER_INFO CASCADE CONSTRAINTS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN RAISE; END IF;
END;
/
@@ -112,16 +89,11 @@ CREATE TABLE ILDM_FEE_CUSTOMER_INFO (
SYNC_STATUS VARCHAR2(20 CHAR) DEFAULT 'unsynced' NOT NULL,
SYNC_TIME DATE,
SYNC_MESSAGE VARCHAR2(500 CHAR),
CONSTRAINT PK_ILDM_FEE_CUSTOMER_INFO PRIMARY KEY (CUSTOMER_SYSID)
CONSTRAINT PK_ILDM_FEE_CUSTOMER_INFO PRIMARY KEY (CUSTOMER_SYSID),
LINKED_ORG_ID NUMBER(19),
LINKED_USER_ACCOUNT VARCHAR2(64)
);
CREATE INDEX IDX_CUSTOMER_NO ON ILDM_FEE_CUSTOMER_INFO (CUSTOMER_NO);
CREATE INDEX IDX_OPPOSITE_ID ON ILDM_FEE_CUSTOMER_INFO (OPPOSITE_ID);
CREATE INDEX IDX_CUSTOMER_TAXNO ON ILDM_FEE_CUSTOMER_INFO (CUSTOMER_TAXNO);
CREATE INDEX IDX_SYSTEM_TYPE ON ILDM_FEE_CUSTOMER_INFO (SYSTEM_TYPE);
CREATE INDEX IDX_CREATE_TIME ON ILDM_FEE_CUSTOMER_INFO (CREATE_TIME);
CREATE INDEX IDX_SYNC_STATUS ON ILDM_FEE_CUSTOMER_INFO (SYNC_STATUS);
COMMENT ON TABLE ILDM_FEE_CUSTOMER_INFO IS '客户/相对方信息表';
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.CUSTOMER_SYSID IS '客户系统ID';
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.CUSTOMER_NAME_C IS '公司全称';
@@ -149,37 +121,21 @@ COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.NATURE_OF_ENTERPRISE_ORG_LEV IS '组织
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.RELATIVE_TYPE IS '类型';
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.IS_DELETED IS '法务系统删除标记';
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.COMMENTS IS '备注【法务】';
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.LINKED_ORG_ID IS '关联内部组织ID(集团内货代公司对应组织树节点ID)';
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.LINKED_USER_ACCOUNT IS '关联用户账号/手机号(内部货代公司对应的业务端登录账号)';
CREATE INDEX IDX_CUSTOMER_NO ON ILDM_FEE_CUSTOMER_INFO (CUSTOMER_NO);
CREATE INDEX IDX_OPPOSITE_ID ON ILDM_FEE_CUSTOMER_INFO (OPPOSITE_ID);
CREATE INDEX IDX_CUSTOMER_TAXNO ON ILDM_FEE_CUSTOMER_INFO (CUSTOMER_TAXNO);
CREATE INDEX IDX_SYSTEM_TYPE ON ILDM_FEE_CUSTOMER_INFO (SYSTEM_TYPE);
CREATE INDEX IDX_CREATE_TIME ON ILDM_FEE_CUSTOMER_INFO (CREATE_TIME);
CREATE INDEX IDX_SYNC_STATUS ON ILDM_FEE_CUSTOMER_INFO (SYNC_STATUS);
CREATE TABLE SEAL_PARTNER_CONTACT (
ID NUMBER(19) NOT NULL,
PARTNER_RECORD_ID NUMBER(19) NOT NULL,
CONTACT_NAME VARCHAR2(50 CHAR) NOT NULL,
CONTACT_PHONE VARCHAR2(20 CHAR) NOT NULL,
POSTAL_ADDRESS VARCHAR2(100 CHAR) NOT NULL,
EMAIL VARCHAR2(50 CHAR) NOT NULL,
SORT_ORDER NUMBER(10) DEFAULT 1 NOT NULL,
DEL_FLAG CHAR(1 CHAR) DEFAULT '0' NOT NULL,
CREATE_BY VARCHAR2(64 CHAR),
CREATE_TIME DATE DEFAULT SYSDATE,
UPDATE_BY VARCHAR2(64 CHAR),
UPDATE_TIME DATE DEFAULT SYSDATE,
REMARK VARCHAR2(500 CHAR),
CONSTRAINT PK_SEAL_PARTNER_CONTACT PRIMARY KEY (ID)
);
CREATE INDEX IDX_PARTNER_RECORD_ID ON SEAL_PARTNER_CONTACT (PARTNER_RECORD_ID);
COMMENT ON TABLE SEAL_PARTNER_CONTACT IS '相对方联系人表';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.ID IS '主键ID';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.PARTNER_RECORD_ID IS '关联相对方主表 CUSTOMER_SYSID';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.CONTACT_NAME IS '联系人姓名';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.CONTACT_PHONE IS '联系电话';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.POSTAL_ADDRESS IS '通讯地址';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.EMAIL IS '电子邮箱';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.SORT_ORDER IS '排序号';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.DEL_FLAG IS '删除标记:0存在 2删除';
CREATE SEQUENCE SEQ_ILDM_FEE_CUSTOMER_INFO
START WITH 4
INCREMENT BY 1
NOCACHE
NOCYCLE;
INSERT INTO ILDM_FEE_CUSTOMER_INFO
(CUSTOMER_SYSID, CUSTOMER_NAME_C, CUSTOMER_TAXNO, CUSTOMER_REGADDR, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME,
@@ -195,7 +151,6 @@ VALUES
'李四', '5000万元', 'OPP-202605210001', 'EFFECTUAL', '0', '0',
'QY', 'GNQY', 'supplier', 'N',
'本地初始化测试数据', 'synced', TO_DATE('2026-05-20 09:15:10', 'YYYY-MM-DD HH24:MI:SS'), '已按数据采集接口规范同步到法务系统');
INSERT INTO ILDM_FEE_CUSTOMER_INFO
(CUSTOMER_SYSID, CUSTOMER_NAME_C, CUSTOMER_TAXNO, CUSTOMER_REGADDR, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME,
EMAIL_ADDRESS, OPPOSITE_ID, OPPOSITE_CHARACTER, GAT_FLAG, GROUP_FLAG, COUNTRY, COUNTRY_NAME,
@@ -210,7 +165,6 @@ VALUES
NULL, NULL, 'OPP-202605210002', 'EFFECTUAL', '0', '0',
'QT', NULL, 'client', 'N',
'个人类型测试数据', 'unsynced', NULL, '新增后尚未同步');
INSERT INTO ILDM_FEE_CUSTOMER_INFO
(CUSTOMER_SYSID, CUSTOMER_NAME_C, CUSTOMER_TAXNO, CUSTOMER_REGADDR, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME,
EMAIL_ADDRESS, OPPOSITE_ID, OPPOSITE_CHARACTER, GAT_FLAG, GROUP_FLAG, COUNTRY, COUNTRY_NAME,
@@ -226,38 +180,4 @@ VALUES
'QY', 'WZQY', 'Partner', 'N',
'境外组织测试数据', 'failed', TO_DATE('2026-05-18 11:10:40', 'YYYY-MM-DD HH24:MI:SS'), '法务系统返回:注册地址长度超限,请修正后重试');
INSERT INTO SEAL_PARTNER_CONTACT
(ID, PARTNER_RECORD_ID, CONTACT_NAME, CONTACT_PHONE, POSTAL_ADDRESS, EMAIL,
SORT_ORDER, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK)
VALUES
(1, 1, '周经理', '15757460062', '宁波市北仑区明州西路188号A座', 'zhoujingli@example.com',
1, '0', 'local_test', TO_DATE('2026-05-20 09:12:33', 'YYYY-MM-DD HH24:MI:SS'),
'local_test', TO_DATE('2026-05-20 09:12:33', 'YYYY-MM-DD HH24:MI:SS'), '主联系人');
INSERT INTO SEAL_PARTNER_CONTACT
(ID, PARTNER_RECORD_ID, CONTACT_NAME, CONTACT_PHONE, POSTAL_ADDRESS, EMAIL,
SORT_ORDER, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK)
VALUES
(2, 3, 'Alice Brown', '+44-20-8899-0001', '88 Harbour Street, London', 'alice.brown@ocean-energy.com',
1, '0', 'local_test', TO_DATE('2026-05-18 11:08:22', 'YYYY-MM-DD HH24:MI:SS'),
'local_test', TO_DATE('2026-05-18 11:08:22', 'YYYY-MM-DD HH24:MI:SS'), '海外主联系人');
INSERT INTO SEAL_PARTNER_CONTACT
(ID, PARTNER_RECORD_ID, CONTACT_NAME, CONTACT_PHONE, POSTAL_ADDRESS, EMAIL,
SORT_ORDER, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK)
VALUES
(3, 3, 'Tom Lee', '+44-20-8899-0002', '88 Harbour Street, London', 'tom.lee@ocean-energy.com',
2, '0', 'local_test', TO_DATE('2026-05-18 11:08:22', 'YYYY-MM-DD HH24:MI:SS'),
'local_test', TO_DATE('2026-05-18 11:08:22', 'YYYY-MM-DD HH24:MI:SS'), '备用联系人');
CREATE SEQUENCE SEQ_ILDM_FEE_CUSTOMER_INFO
START WITH 4
INCREMENT BY 1
NOCACHE
NOCYCLE;
CREATE SEQUENCE SEQ_SEAL_PARTNER_CONTACT
START WITH 4
INCREMENT BY 1
NOCACHE
NOCYCLE;
COMMIT;
+61
View File
@@ -0,0 +1,61 @@
-- =============================================
-- SEAL_CONTRACT_LAUNCH_AR_ELE 建表脚本 (Oracle)
-- 自动整理生成,已合并历史patch字段
-- 执行方式: sqlplus developer/dev123@localhost/XEPDB1 @SEAL_CONTRACT_LAUNCH_AR_ELE.sql
-- =============================================
WHENEVER SQLERROR EXIT SQL.SQLCODE;
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_SC_AR_ELE';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2289 THEN RAISE; END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE SEAL_CONTRACT_LAUNCH_AR_ELE CASCADE CONSTRAINTS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN RAISE; END IF;
END;
/
CREATE TABLE SEAL_CONTRACT_LAUNCH_AR_ELE (
ID NUMBER(19) NOT NULL,
CONTRACT_ID NUMBER(19) NOT NULL,
ARCHIVES_NAME VARCHAR2(255 CHAR) NOT NULL,
SORT_ORDER NUMBER(10) DEFAULT 1,
CREATE_BY VARCHAR2(64 CHAR),
CREATE_TIME DATE DEFAULT SYSDATE,
UPDATE_BY VARCHAR2(64 CHAR),
UPDATE_TIME DATE DEFAULT SYSDATE,
IS_DELETED VARCHAR2(2 CHAR) DEFAULT 'N',
REMARK VARCHAR2(1000 CHAR),
CONSTRAINT PK_SEAL_CONTRACT_LAUNCH_AR_ELE PRIMARY KEY (ID)
);
COMMENT ON TABLE SEAL_CONTRACT_LAUNCH_AR_ELE IS '合同归档电子档案材料表';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_ELE.ID IS '主键ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_ELE.CONTRACT_ID IS '合同主表ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_ELE.ARCHIVES_NAME IS '档案名称';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_ELE.SORT_ORDER IS '排序号';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_ELE.CREATE_BY IS '创建人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_ELE.CREATE_TIME IS '创建时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_ELE.UPDATE_BY IS '更新人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_ELE.UPDATE_TIME IS '更新时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_ELE.IS_DELETED IS '逻辑删除标记';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_ELE.REMARK IS '备注';
CREATE INDEX IDX_CONTRACT_LAUNCH_AR_ELE_CT ON SEAL_CONTRACT_LAUNCH_AR_ELE (CONTRACT_ID);
CREATE SEQUENCE SEQ_SC_AR_ELE
INCREMENT BY 1
MINVALUE 1
MAXVALUE 9999999999999999999999999999
NOCYCLE
CACHE 20
NOORDER;
COMMIT;
@@ -0,0 +1,65 @@
-- =============================================
-- SEAL_CONTRACT_LAUNCH_AR_PAPER 建表脚本 (Oracle)
-- 自动整理生成,已合并历史patch字段
-- 执行方式: sqlplus developer/dev123@localhost/XEPDB1 @SEAL_CONTRACT_LAUNCH_AR_PAPER.sql
-- =============================================
WHENEVER SQLERROR EXIT SQL.SQLCODE;
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_SC_AR_PAPER';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2289 THEN RAISE; END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE SEAL_CONTRACT_LAUNCH_AR_PAPER CASCADE CONSTRAINTS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN RAISE; END IF;
END;
/
CREATE TABLE SEAL_CONTRACT_LAUNCH_AR_PAPER (
ID NUMBER(19) NOT NULL,
CONTRACT_ID NUMBER(19) NOT NULL,
ARCHIVES_NAME VARCHAR2(255 CHAR) NOT NULL,
ARCHIVES_NUM VARCHAR2(50 CHAR) NOT NULL,
ARCHIVES_TIME DATE NOT NULL,
SORT_ORDER NUMBER(10) DEFAULT 1,
CREATE_BY VARCHAR2(64 CHAR),
CREATE_TIME DATE DEFAULT SYSDATE,
UPDATE_BY VARCHAR2(64 CHAR),
UPDATE_TIME DATE DEFAULT SYSDATE,
IS_DELETED VARCHAR2(2 CHAR) DEFAULT 'N',
REMARK VARCHAR2(1000 CHAR),
CONSTRAINT PK_SC_AR_PAPER PRIMARY KEY (ID)
);
COMMENT ON TABLE SEAL_CONTRACT_LAUNCH_AR_PAPER IS '合同归档纸质档案材料表';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_PAPER.ID IS '主键ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_PAPER.CONTRACT_ID IS '合同主表ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_PAPER.ARCHIVES_NAME IS '档案名称';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_PAPER.ARCHIVES_NUM IS '份数';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_PAPER.ARCHIVES_TIME IS '归档时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_PAPER.SORT_ORDER IS '排序号';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_PAPER.CREATE_BY IS '创建人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_PAPER.CREATE_TIME IS '创建时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_PAPER.UPDATE_BY IS '更新人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_PAPER.UPDATE_TIME IS '更新时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_PAPER.IS_DELETED IS '逻辑删除标记';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_AR_PAPER.REMARK IS '备注';
CREATE INDEX IDX_SC_AR_PAPER_CTID ON SEAL_CONTRACT_LAUNCH_AR_PAPER (CONTRACT_ID);
CREATE SEQUENCE SEQ_SC_AR_PAPER
INCREMENT BY 1
MINVALUE 1
MAXVALUE 9999999999999999999999999999
NOCYCLE
CACHE 20
NOORDER;
COMMIT;
+74
View File
@@ -0,0 +1,74 @@
-- =============================================
-- SEAL_CONTRACT_LAUNCH_FILE 建表脚本 (Oracle)
-- 自动整理生成,已合并历史patch字段
-- 执行方式: sqlplus developer/dev123@localhost/XEPDB1 @SEAL_CONTRACT_LAUNCH_FILE.sql
-- =============================================
WHENEVER SQLERROR EXIT SQL.SQLCODE;
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_SEAL_CONTRACT_LAUNCH_FILE';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2289 THEN RAISE; END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE SEAL_CONTRACT_LAUNCH_FILE CASCADE CONSTRAINTS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN RAISE; END IF;
END;
/
CREATE TABLE SEAL_CONTRACT_LAUNCH_FILE (
ID NUMBER(19) NOT NULL,
CONTRACT_ID NUMBER(19) NOT NULL,
FILE_CATEGORY VARCHAR2(30 CHAR) NOT NULL,
ARCHIVE_ELE_ID NUMBER(19),
FILE_NAME VARCHAR2(255 CHAR) NOT NULL,
FILE_PATH VARCHAR2(500 CHAR) NOT NULL,
LEGAL_FILE_URL VARCHAR2(1000 CHAR),
FILE_TYPE VARCHAR2(50 CHAR),
FILE_SIZE NUMBER(19),
SORT_ORDER NUMBER(10) DEFAULT 1,
CREATE_BY VARCHAR2(64 CHAR),
CREATE_TIME DATE DEFAULT SYSDATE,
UPDATE_BY VARCHAR2(64 CHAR),
UPDATE_TIME DATE DEFAULT SYSDATE,
IS_DELETED VARCHAR2(2 CHAR) DEFAULT 'N',
REMARK VARCHAR2(1000 CHAR),
CONSTRAINT PK_SEAL_CONTRACT_LAUNCH_FILE PRIMARY KEY (ID)
);
COMMENT ON TABLE SEAL_CONTRACT_LAUNCH_FILE IS '合同附件表';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.ID IS '主键ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.CONTRACT_ID IS '合同主表ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.FILE_CATEGORY IS '文件分类:body/other/gist/signed/archive';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.ARCHIVE_ELE_ID IS '关联合同电子档案材料ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.FILE_NAME IS '文件名称';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.FILE_PATH IS '文件路径';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.LEGAL_FILE_URL IS '法务系统附件路径缓存';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.FILE_TYPE IS '文件类型';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.FILE_SIZE IS '文件大小';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.SORT_ORDER IS '排序号';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.CREATE_BY IS '创建人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.CREATE_TIME IS '创建时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.UPDATE_BY IS '更新人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.UPDATE_TIME IS '更新时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.IS_DELETED IS '逻辑删除标记';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_FILE.REMARK IS '备注';
CREATE INDEX IDX_SC_FILE_CTID ON SEAL_CONTRACT_LAUNCH_FILE (CONTRACT_ID);
CREATE INDEX IDX_SC_FILE_ARELE ON SEAL_CONTRACT_LAUNCH_FILE (ARCHIVE_ELE_ID);
CREATE SEQUENCE SEQ_SEAL_CONTRACT_LAUNCH_FILE
INCREMENT BY 1
MINVALUE 1
MAXVALUE 9999999999999999999999999999
NOCYCLE
CACHE 20
NOORDER;
COMMIT;
+63
View File
@@ -0,0 +1,63 @@
-- =============================================
-- SEAL_CONTRACT_LAUNCH_LOG 建表脚本 (Oracle)
-- 自动整理生成,已合并历史patch字段
-- 执行方式: sqlplus developer/dev123@localhost/XEPDB1 @SEAL_CONTRACT_LAUNCH_LOG.sql
-- =============================================
WHENEVER SQLERROR EXIT SQL.SQLCODE;
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_SEAL_CONTRACT_LAUNCH_LOG';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2289 THEN RAISE; END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE SEAL_CONTRACT_LAUNCH_LOG CASCADE CONSTRAINTS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN RAISE; END IF;
END;
/
CREATE TABLE SEAL_CONTRACT_LAUNCH_LOG (
ID NUMBER(19) NOT NULL,
CONTRACT_ID NUMBER(19) NOT NULL,
ACTION_TYPE VARCHAR2(50 CHAR) NOT NULL,
ACTION_NAME VARCHAR2(100 CHAR) NOT NULL,
ACTION_STATUS VARCHAR2(20 CHAR) NOT NULL,
OPERATOR_NAME VARCHAR2(64 CHAR),
OPERATOR_PHONE VARCHAR2(32 CHAR),
ACTION_TIME DATE DEFAULT SYSDATE,
ACTION_CONTENT VARCHAR2(2000 CHAR),
CALLBACK_PAYLOAD CLOB,
REMARK VARCHAR2(1000 CHAR),
CONSTRAINT PK_SEAL_CONTRACT_LAUNCH_LOG PRIMARY KEY (ID)
);
COMMENT ON TABLE SEAL_CONTRACT_LAUNCH_LOG IS '合同操作日志表';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_LOG.ID IS '主键ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_LOG.CONTRACT_ID IS '合同主表ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_LOG.ACTION_TYPE IS '动作类型';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_LOG.ACTION_NAME IS '动作名称';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_LOG.ACTION_STATUS IS '动作状态';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_LOG.OPERATOR_NAME IS '操作人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_LOG.OPERATOR_PHONE IS '操作人手机号';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_LOG.ACTION_TIME IS '操作时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_LOG.ACTION_CONTENT IS '操作说明';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_LOG.CALLBACK_PAYLOAD IS '回调或接口报文';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_LOG.REMARK IS '备注';
CREATE INDEX IDX_SC_LOG_CTID ON SEAL_CONTRACT_LAUNCH_LOG (CONTRACT_ID);
CREATE SEQUENCE SEQ_SEAL_CONTRACT_LAUNCH_LOG
INCREMENT BY 1
MINVALUE 1
MAXVALUE 9999999999999999999999999999
NOCYCLE
CACHE 20
NOORDER;
COMMIT;
+247
View File
@@ -0,0 +1,247 @@
-- =============================================
-- SEAL_CONTRACT_LAUNCH_MAIN 建表脚本 (Oracle)
-- 自动整理生成,已合并历史patch字段
-- 执行方式: sqlplus developer/dev123@localhost/XEPDB1 @SEAL_CONTRACT_LAUNCH_MAIN.sql
-- =============================================
WHENEVER SQLERROR EXIT SQL.SQLCODE;
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_SEAL_CONTRACT_LAUNCH_MAIN';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2289 THEN RAISE; END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE SEAL_CONTRACT_LAUNCH_MAIN CASCADE CONSTRAINTS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN RAISE; END IF;
END;
/
CREATE TABLE SEAL_CONTRACT_LAUNCH_MAIN (
ID NUMBER(19) NOT NULL,
CONTRACT_SYS_ID VARCHAR2(64 CHAR) NOT NULL,
CONTRACT_CODE VARCHAR2(64 CHAR),
LAW_CONTRACT_CODE VARCHAR2(64 CHAR),
LAW_CONTRACT_ID VARCHAR2(64 CHAR),
CONTRACT_NAME VARCHAR2(200 CHAR) NOT NULL,
CONTRACT_TYPE VARCHAR2(64 CHAR) NOT NULL,
CONTRACT_TYPE_CODE VARCHAR2(64 CHAR) NOT NULL,
CONTRACT_SOURCE VARCHAR2(32 CHAR) DEFAULT 'ECP' NOT NULL,
CREATION_MODE VARCHAR2(20 CHAR) NOT NULL,
TEMPLATE_ID NUMBER(19),
TEMPLATE_CODE VARCHAR2(64 CHAR),
TEMPLATE_NAME VARCHAR2(200 CHAR),
STATUS VARCHAR2(30 CHAR) NOT NULL,
APPROVE_STATUS VARCHAR2(30 CHAR),
APPROVE_MESSAGE VARCHAR2(500 CHAR),
SEAL_CONTRACT_ID VARCHAR2(64 CHAR),
SEAL_CONTRACT_STATUS NUMBER(10),
CONTRACT_AMOUNT NUMBER(20, 2),
CURRENCY_NAME VARCHAR2(20 CHAR),
CONTRACT_PERIOD_TYPE VARCHAR2(10 CHAR),
PERIOD_EXPLAIN VARCHAR2(500 CHAR),
EFFECTIVE_START DATE,
EFFECTIVE_END DATE,
PAYMENT_METHOD VARCHAR2(500 CHAR),
PRIMARY_CONTENT VARCHAR2(2000 CHAR),
AMOUNT_EXPLAIN VARCHAR2(2000 CHAR),
VALUATION_MODE VARCHAR2(10 CHAR),
NEED_AMENDMENTS VARCHAR2(4 CHAR) DEFAULT '0',
ESTIMATED_AMOUNT NUMBER(20, 2),
SEAL_TYPE VARCHAR2(50 CHAR),
TEXT_SOURCE VARCHAR2(50 CHAR),
MANDATE_TYPE VARCHAR2(50 CHAR),
CARGO_TYPE VARCHAR2(50 CHAR),
ASSIST_DEPARTMENT_NAME VARCHAR2(200 CHAR),
EXECUTOR_ACCOUNT VARCHAR2(64 CHAR),
CREATOR_PHONE VARCHAR2(32 CHAR),
SELF_CODE VARCHAR2(64 CHAR),
MAIN_CONTRACT_CODE VARCHAR2(200 CHAR),
SIGNING_SUBJECT_CODE VARCHAR2(500 CHAR),
DATE_TYPE VARCHAR2(10 CHAR),
IS_ADDIT INTEGER DEFAULT 2,
IS_ELECTRON VARCHAR2(4 CHAR) DEFAULT '1',
PAYMENT_DIRECTION VARCHAR2(10 CHAR),
PUSH_URL VARCHAR2(500 CHAR),
IS_MAJOR_CONTRACT INTEGER DEFAULT 0,
IS_OPEN_BIDDING INTEGER DEFAULT 0,
IS_YEAR_BUDGET INTEGER DEFAULT 0,
IS_SHARE VARCHAR2(4 CHAR) DEFAULT '0',
CONTRACT_NATURE VARCHAR2(4 CHAR) DEFAULT '0',
IS_SGAT VARCHAR2(4 CHAR) DEFAULT '0',
IS_NORMAL VARCHAR2(4 CHAR) DEFAULT '1',
IS_TERMINATED VARCHAR2(4 CHAR) DEFAULT '0',
IS_SINGLE_AGREEMENT VARCHAR2(4 CHAR) DEFAULT '0',
BIDDING_NO VARCHAR2(100 CHAR),
OPEN_BIDDING_REMARK VARCHAR2(500 CHAR),
CONTRACT_GIST_REMARK VARCHAR2(1000 CHAR),
EW_AMOUNT_TYPE VARCHAR2(100 CHAR),
DJ_AMOUNT NUMBER(20, 2),
YJ_AMOUNT NUMBER(20, 2),
YFK_AMOUNT NUMBER(20, 2),
BZJ_AMOUNT NUMBER(20, 2),
BODY_SUMMARY VARCHAR2(2000 CHAR),
TEMPLATE_FIELD_VALUES_JSON CLOB,
CONTRACT_TEXT_FILE_NAME VARCHAR2(255 CHAR),
CONTRACT_TEXT_FILE_PATH VARCHAR2(500 CHAR),
CONTRACT_TEXT_FILE_TYPE VARCHAR2(50 CHAR),
CONTRACT_TEXT_FILE_SIZE NUMBER(19),
SIGNED_FILE_NAME VARCHAR2(255 CHAR),
SIGNED_FILE_PATH VARCHAR2(500 CHAR),
SIGNED_FILE_TYPE VARCHAR2(50 CHAR),
SIGNED_FILE_SIZE NUMBER(19),
SIGNED_FILE_URL VARCHAR2(1000 CHAR),
SIGNED_OFFLINE_REASON VARCHAR2(1000 CHAR),
SIGN_DATE DATE,
SEAL_DATE DATE,
SEAL_QUANTITY NUMBER(10) DEFAULT 1,
ACTIVE_DATE DATE,
ARCHIVE_DATE DATE,
ARCHIVE_RECEIVE_DEPT VARCHAR2(100 CHAR),
ARCHIVE_TRANSFEROR VARCHAR2(64 CHAR),
ARCHIVE_KEEPER VARCHAR2(64 CHAR),
ARCHIVE_KEEPER_UNIT VARCHAR2(200 CHAR),
ARCHIVE_KEEPER_UNIT_CODE VARCHAR2(100 CHAR),
INVOICE_DATE DATE,
RECEIVE_DATE DATE,
REMIND_DAYS NUMBER(10) DEFAULT 3,
INITIATOR VARCHAR2(64 CHAR),
INITIATOR_DEPT VARCHAR2(200 CHAR),
COMPANY_NAME VARCHAR2(200 CHAR),
ORG_ID VARCHAR2(64 CHAR),
QUERY_SCOPE VARCHAR2(20 CHAR),
CREATE_BY VARCHAR2(64 CHAR),
CREATE_TIME DATE DEFAULT SYSDATE,
UPDATE_BY VARCHAR2(64 CHAR),
UPDATE_TIME DATE DEFAULT SYSDATE,
IS_DELETED VARCHAR2(2 CHAR) DEFAULT 'N',
REMARK VARCHAR2(1000 CHAR),
CONSTRAINT PK_SEAL_CONTRACT_LAUNCH_MAIN PRIMARY KEY (ID),
CONSTRAINT UK_SEAL_CONTRACT_SYS_ID UNIQUE (CONTRACT_SYS_ID),
SEAL_IS_SEAL VARCHAR2(4 CHAR) DEFAULT '1',
SEAL_APPROVE_SAME VARCHAR2(4 CHAR) DEFAULT '1',
COUNTERPARTY_CONFIRM_JSON VARCHAR2(2000 CHAR)
);
COMMENT ON TABLE SEAL_CONTRACT_LAUNCH_MAIN IS '合同发起主表';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.ID IS '主键ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CONTRACT_SYS_ID IS '平台合同唯一编码';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CONTRACT_CODE IS '业务合同编码';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.LAW_CONTRACT_CODE IS '法务系统合同编号';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.LAW_CONTRACT_ID IS '法务系统合同ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CONTRACT_NAME IS '合同名称';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CONTRACT_TYPE IS '合同类型中文名称';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CONTRACT_TYPE_CODE IS '合同类型编码';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CONTRACT_SOURCE IS '合同来源';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CREATION_MODE IS '创建方式:template/manual';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.TEMPLATE_ID IS '模板ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.TEMPLATE_CODE IS '模板编号';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.TEMPLATE_NAME IS '模板名称';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.STATUS IS '合同当前状态';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.APPROVE_STATUS IS '审批状态';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.APPROVE_MESSAGE IS '审批说明';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SEAL_CONTRACT_ID IS '签章平台合同ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SEAL_CONTRACT_STATUS IS '签章平台合同状态';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CONTRACT_AMOUNT IS '合同金额';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CURRENCY_NAME IS '币种';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CONTRACT_PERIOD_TYPE IS '合同期限类型:0固定期限 1无固定期限';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.PERIOD_EXPLAIN IS '期限说明';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.EFFECTIVE_START IS '生效开始日期';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.EFFECTIVE_END IS '生效结束日期';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.PAYMENT_METHOD IS '付款方式';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.PRIMARY_CONTENT IS '合同主要内容';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.AMOUNT_EXPLAIN IS '金额说明';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.VALUATION_MODE IS '计价方式';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.NEED_AMENDMENTS IS '是否需修订条款:1是 0否';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.ESTIMATED_AMOUNT IS '预估金额';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SEAL_QUANTITY IS '用印数量';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SEAL_TYPE IS '签订方式';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.TEXT_SOURCE IS '文本来源';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.MANDATE_TYPE IS '委托类型';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CARGO_TYPE IS '货种';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.ASSIST_DEPARTMENT_NAME IS '协助部门';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.EXECUTOR_ACCOUNT IS '合同执行人账号';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CREATOR_PHONE IS '创建人手机号';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SELF_CODE IS '二级单位合同编码';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.MAIN_CONTRACT_CODE IS '主合同编码';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SIGNING_SUBJECT_CODE IS '签约主体编码,多个用逗号分隔';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.DATE_TYPE IS '固定期间日期类型:0年 1月 2日';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.IS_ADDIT IS '是否补录:1是 2否';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.IS_ELECTRON IS '签署方式:0纸质 1电子';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.PAYMENT_DIRECTION IS '收支方向';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.PUSH_URL IS '法务审批回调地址';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.IS_MAJOR_CONTRACT IS '是否重大合同';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.IS_OPEN_BIDDING IS '是否公开招标';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.IS_YEAR_BUDGET IS '是否列入当年预算';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.IS_SHARE IS '是否共享';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CONTRACT_NATURE IS '签约主体是否涉外';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.IS_SGAT IS '是否涉港澳台';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.IS_NORMAL IS '是否正常';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.IS_TERMINATED IS '是否终止';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.IS_SINGLE_AGREEMENT IS '是否单方协议';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.BIDDING_NO IS '招标编号';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.OPEN_BIDDING_REMARK IS '公开招标备注';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CONTRACT_GIST_REMARK IS '签订依据说明';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.EW_AMOUNT_TYPE IS '额外金额类型:DJ定金 YJ押金 YFK预付款 BZJ保证金';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.DJ_AMOUNT IS '定金金额';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.YJ_AMOUNT IS '押金金额';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.YFK_AMOUNT IS '预付款金额';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.BZJ_AMOUNT IS '保证金金额';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.BODY_SUMMARY IS '正文摘要';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.TEMPLATE_FIELD_VALUES_JSON IS '模板字段值JSON';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CONTRACT_TEXT_FILE_NAME IS '合同正文文件名';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CONTRACT_TEXT_FILE_PATH IS '合同正文文件路径';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CONTRACT_TEXT_FILE_TYPE IS '合同正文文件类型';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CONTRACT_TEXT_FILE_SIZE IS '合同正文文件大小';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SIGNED_FILE_NAME IS '已签署文件名';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SIGNED_FILE_PATH IS '已签署文件路径';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SIGNED_FILE_TYPE IS '已签署文件类型';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SIGNED_FILE_SIZE IS '已签署文件大小';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SIGNED_OFFLINE_REASON IS '线下签署原因';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SIGNED_FILE_URL IS '已签署文件URL';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SIGN_DATE IS '签署日期';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SEAL_DATE IS '用印时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.ACTIVE_DATE IS '合同生效日期';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.ARCHIVE_DATE IS '归档时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.ARCHIVE_RECEIVE_DEPT IS '合同归档接收部门编码';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.ARCHIVE_TRANSFEROR IS '移交人账号';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.ARCHIVE_KEEPER IS '档案保管人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.ARCHIVE_KEEPER_UNIT IS '档案保管单位';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.ARCHIVE_KEEPER_UNIT_CODE IS '档案保管单位编码';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.INVOICE_DATE IS '开票时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.RECEIVE_DATE IS '收款时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.REMIND_DAYS IS '提醒提前天数';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.INITIATOR IS '发起人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.INITIATOR_DEPT IS '发起部门';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.COMPANY_NAME IS '发起公司';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.ORG_ID IS '组织ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.QUERY_SCOPE IS '查询范围';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CREATE_BY IS '创建人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.CREATE_TIME IS '创建时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.UPDATE_BY IS '更新人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.UPDATE_TIME IS '更新时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.IS_DELETED IS '逻辑删除标记';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.REMARK IS '备注';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SEAL_IS_SEAL IS '是否用印:1是 0否';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.SEAL_APPROVE_SAME IS '审批是否一致:1是 0否';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_MAIN.COUNTERPARTY_CONFIRM_JSON IS '相对方签署确认状态JSON';
CREATE INDEX IDX_CONTRACT_LAUNCH_STATUS ON SEAL_CONTRACT_LAUNCH_MAIN (STATUS);
CREATE INDEX IDX_CONTRACT_LAUNCH_CODE ON SEAL_CONTRACT_LAUNCH_MAIN (CONTRACT_CODE);
CREATE INDEX IDX_CONTRACT_LAUNCH_NAME ON SEAL_CONTRACT_LAUNCH_MAIN (CONTRACT_NAME);
CREATE INDEX IDX_SC_MAIN_CRTIME ON SEAL_CONTRACT_LAUNCH_MAIN (CREATE_TIME);
CREATE SEQUENCE SEQ_SEAL_CONTRACT_LAUNCH_MAIN
INCREMENT BY 1
MINVALUE 1
MAXVALUE 9999999999999999999999999999
NOCYCLE
CACHE 20
NOORDER;
COMMIT;
+101
View File
@@ -0,0 +1,101 @@
-- =============================================
-- SEAL_CONTRACT_LAUNCH_PARTY 建表脚本 (Oracle)
-- 自动整理生成,已合并历史patch字段
-- 执行方式: sqlplus developer/dev123@localhost/XEPDB1 @SEAL_CONTRACT_LAUNCH_PARTY.sql
-- =============================================
WHENEVER SQLERROR EXIT SQL.SQLCODE;
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_SEAL_CONTRACT_LAUNCH_PARTY';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2289 THEN RAISE; END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE SEAL_CONTRACT_LAUNCH_PARTY CASCADE CONSTRAINTS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN RAISE; END IF;
END;
/
CREATE TABLE SEAL_CONTRACT_LAUNCH_PARTY (
ID NUMBER(19) NOT NULL,
CONTRACT_ID NUMBER(19) NOT NULL,
ROLE_CODE VARCHAR2(10 CHAR) NOT NULL,
ROLE_NAME VARCHAR2(20 CHAR) NOT NULL,
SORT_ORDER NUMBER(10) DEFAULT 1,
PARTNER_ID NUMBER(19),
OPPOSITE_ID VARCHAR2(64 CHAR),
COMPANY_NAME VARCHAR2(200 CHAR) NOT NULL,
COMPANY_TYPE VARCHAR2(50 CHAR),
OPPOSITE_CHARACTER VARCHAR2(20 CHAR),
CONTACT_NAME VARCHAR2(100 CHAR),
CONTACT_PHONE VARCHAR2(50 CHAR),
CONTACT_EMAIL VARCHAR2(100 CHAR),
CONTACT_ADDRESS VARCHAR2(500 CHAR),
REGISTERED_ADDRESS VARCHAR2(500 CHAR),
LEGAL_REPRESENTATIVE VARCHAR2(100 CHAR),
CREDIT_CODE VARCHAR2(100 CHAR),
BANK_NAME VARCHAR2(200 CHAR),
BANK_ACCOUNT VARCHAR2(100 CHAR),
NATURAL_PERSON_ID_TYPE VARCHAR2(20 CHAR),
NATURAL_PERSON_ID_NUMBER VARCHAR2(100 CHAR),
IS_GROUP_INTERNAL VARCHAR2(4 CHAR),
IS_HONG_KONG_MACAO_TAIWAN VARCHAR2(4 CHAR),
CREATE_BY VARCHAR2(64 CHAR),
CREATE_TIME DATE DEFAULT SYSDATE,
UPDATE_BY VARCHAR2(64 CHAR),
UPDATE_TIME DATE DEFAULT SYSDATE,
IS_DELETED VARCHAR2(2 CHAR) DEFAULT 'N',
REMARK VARCHAR2(1000 CHAR),
CONSTRAINT PK_SEAL_CONTRACT_LAUNCH_PARTY PRIMARY KEY (ID),
SUBJECT_CODE VARCHAR2(100 CHAR)
);
COMMENT ON TABLE SEAL_CONTRACT_LAUNCH_PARTY IS '合同方信息表';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.ID IS '主键ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.CONTRACT_ID IS '合同主表ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.ROLE_CODE IS '角色编码:A/B/C';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.ROLE_NAME IS '角色名称:甲方/乙方/丙方';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.SORT_ORDER IS '排序号';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.PARTNER_ID IS '相对方管理表主键';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.OPPOSITE_ID IS '法务相对方ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.COMPANY_NAME IS '公司名称';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.COMPANY_TYPE IS '公司类型';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.OPPOSITE_CHARACTER IS '公司性质';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.CONTACT_NAME IS '联系人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.CONTACT_PHONE IS '联系电话';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.CONTACT_EMAIL IS '联系邮箱';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.CONTACT_ADDRESS IS '通讯地址';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.REGISTERED_ADDRESS IS '注册地址';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.LEGAL_REPRESENTATIVE IS '法定代表人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.CREDIT_CODE IS '统一社会信用代码';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.BANK_NAME IS '开户行';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.BANK_ACCOUNT IS '银行账号';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.NATURAL_PERSON_ID_TYPE IS '自然人证件类型';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.NATURAL_PERSON_ID_NUMBER IS '自然人证件号码';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.IS_GROUP_INTERNAL IS '是否集团内';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.IS_HONG_KONG_MACAO_TAIWAN IS '是否涉港澳台';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.CREATE_BY IS '创建人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.CREATE_TIME IS '创建时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.UPDATE_BY IS '更新人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.UPDATE_TIME IS '更新时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.IS_DELETED IS '逻辑删除标记';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.REMARK IS '备注';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.SUBJECT_CODE IS '主体编码(我方主体组织ID,相对方通常为空)';
CREATE INDEX IDX_SC_PARTY_CTID ON SEAL_CONTRACT_LAUNCH_PARTY (CONTRACT_ID);
CREATE SEQUENCE SEQ_SEAL_CONTRACT_LAUNCH_PARTY
INCREMENT BY 1
MINVALUE 1
MAXVALUE 9999999999999999999999999999
NOCYCLE
CACHE 20
NOORDER;
COMMIT;
+77
View File
@@ -0,0 +1,77 @@
-- =============================================
-- SEAL_CONTRACT_LAUNCH_PLAN 建表脚本 (Oracle)
-- 自动整理生成,已合并历史patch字段
-- 执行方式: sqlplus developer/dev123@localhost/XEPDB1 @SEAL_CONTRACT_LAUNCH_PLAN.sql
-- =============================================
WHENEVER SQLERROR EXIT SQL.SQLCODE;
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_SEAL_CONTRACT_LAUNCH_PLAN';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2289 THEN RAISE; END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE SEAL_CONTRACT_LAUNCH_PLAN CASCADE CONSTRAINTS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN RAISE; END IF;
END;
/
CREATE TABLE SEAL_CONTRACT_LAUNCH_PLAN (
ID NUMBER(19) NOT NULL,
CONTRACT_ID NUMBER(19) NOT NULL,
PLAN_MATTER VARCHAR2(500 CHAR) NOT NULL,
PLAN_WHERE VARCHAR2(500 CHAR) NOT NULL,
PLAN_TIME DATE NOT NULL,
PLAN_DAY NUMBER(10) DEFAULT 3,
PLAN_MONEY NUMBER(20, 2),
PLAN_SUBJECT_CODE VARCHAR2(100 CHAR),
PLAN_SUBJECT_NAME VARCHAR2(200 CHAR),
EXECUTOR_UNIT_ID NUMBER(19),
PLAN_DETAIL VARCHAR2(1000 CHAR),
PLAN_STATUS VARCHAR2(20 CHAR) DEFAULT '0',
CREATE_BY VARCHAR2(64 CHAR),
CREATE_TIME DATE DEFAULT SYSDATE,
UPDATE_BY VARCHAR2(64 CHAR),
UPDATE_TIME DATE DEFAULT SYSDATE,
IS_DELETED VARCHAR2(2 CHAR) DEFAULT 'N',
REMARK VARCHAR2(1000 CHAR),
CONSTRAINT PK_SEAL_CONTRACT_LAUNCH_PLAN PRIMARY KEY (ID)
);
COMMENT ON TABLE SEAL_CONTRACT_LAUNCH_PLAN IS '合同履行计划表';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.ID IS '主键ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.CONTRACT_ID IS '合同主表ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.PLAN_MATTER IS '履行事项';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.PLAN_WHERE IS '履约条件';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.PLAN_TIME IS '节点日期';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.PLAN_DAY IS '提前提醒天数';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.PLAN_MONEY IS '款项金额';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.PLAN_SUBJECT_CODE IS '所属主体编码';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.PLAN_SUBJECT_NAME IS '所属主体名称';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.EXECUTOR_UNIT_ID IS '执行人公司ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.PLAN_DETAIL IS '备注';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.PLAN_STATUS IS '反馈状态';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.CREATE_BY IS '创建人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.CREATE_TIME IS '创建时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.UPDATE_BY IS '更新人';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.UPDATE_TIME IS '更新时间';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.IS_DELETED IS '逻辑删除标记';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PLAN.REMARK IS '备注';
CREATE INDEX IDX_SC_PLAN_CTID ON SEAL_CONTRACT_LAUNCH_PLAN (CONTRACT_ID);
CREATE SEQUENCE SEQ_SEAL_CONTRACT_LAUNCH_PLAN
INCREMENT BY 1
MINVALUE 1
MAXVALUE 9999999999999999999999999999
NOCYCLE
CACHE 20
NOORDER;
COMMIT;
@@ -0,0 +1,68 @@
-- =============================================
-- SEAL_CONTRACT_LAUNCH_SEAL_POS 建表脚本 (Oracle)
-- 自动整理生成,已合并历史patch字段
-- 执行方式: sqlplus developer/dev123@localhost/XEPDB1 @SEAL_CONTRACT_LAUNCH_SEAL_POS.sql
-- =============================================
WHENEVER SQLERROR EXIT SQL.SQLCODE;
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_SEAL_CONTRACT_LAUNCH_POS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2289 THEN RAISE; END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE SEQ_SEAL_CONTRACT_LAUNCH_POS CASCADE CONSTRAINTS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN RAISE; END IF;
END;
/
CREATE TABLE SEAL_CONTRACT_LAUNCH_SEAL_POS (
ID NUMBER(20) PRIMARY KEY,
CONTRACT_ID NUMBER(20) NOT NULL,
PARTY_ID NUMBER(20) NOT NULL,
LABEL VARCHAR2(100) NOT NULL,
REQUIRED CHAR(1) DEFAULT 'Y' NOT NULL,
PAGE_NUM NUMBER(10) NOT NULL,
X NUMBER(12,2) NOT NULL,
Y NUMBER(12,2) NOT NULL,
WIDTH NUMBER(12,2) NOT NULL,
HEIGHT NUMBER(12,2) NOT NULL,
SEAL_ID VARCHAR2(100),
SEAL_NAME VARCHAR2(200),
REQUEST_ID VARCHAR2(100),
SIGNED_STATUS NUMBER(2) DEFAULT 0 NOT NULL,
SIGNED_BY_NAME VARCHAR2(100),
SIGNED_BY_ID VARCHAR2(100),
SIGNED_TIME TIMESTAMP,
CREATE_BY VARCHAR2(100),
CREATE_TIME TIMESTAMP DEFAULT SYSTIMESTAMP,
UPDATE_BY VARCHAR2(100),
UPDATE_TIME TIMESTAMP DEFAULT SYSTIMESTAMP,
IS_DELETED CHAR(1) DEFAULT 'N' NOT NULL,
REMARK VARCHAR2(500)
);
COMMENT ON TABLE SEAL_CONTRACT_LAUNCH_SEAL_POS IS '合同签章位配置表';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_SEAL_POS.PARTY_ID IS '签署方子表ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_SEAL_POS.REQUIRED IS '是否必签(Y/N)';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_SEAL_POS.REQUEST_ID IS '最近一次预盖章二维码请求ID';
COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_SEAL_POS.SIGNED_STATUS IS '0空框 1已选章 2待回调 3已签 4失败';
CREATE INDEX IDX_SC_LAUNCH_SEAL_POS_CONTRACT ON SEAL_CONTRACT_LAUNCH_SEAL_POS (CONTRACT_ID, IS_DELETED);
CREATE INDEX IDX_SC_LAUNCH_SEAL_POS_REQUEST ON SEAL_CONTRACT_LAUNCH_SEAL_POS (REQUEST_ID, IS_DELETED);
CREATE SEQUENCE SEQ_SEAL_CONTRACT_LAUNCH_POS
INCREMENT BY 1
MINVALUE 1
MAXVALUE 9999999999999999999999999999
NOCYCLE
CACHE 20
NOORDER;
COMMIT;
+82
View File
@@ -0,0 +1,82 @@
-- =============================================
-- SEAL_PARTNER_CONTACT 建表脚本 (Oracle)
-- 自动整理生成,已合并历史patch字段
-- 执行方式: sqlplus developer/dev123@localhost/XEPDB1 @SEAL_PARTNER_CONTACT.sql
-- =============================================
WHENEVER SQLERROR EXIT SQL.SQLCODE;
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_SEAL_PARTNER_CONTACT';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2289 THEN RAISE; END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE SEAL_PARTNER_CONTACT CASCADE CONSTRAINTS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN RAISE; END IF;
END;
/
CREATE TABLE SEAL_PARTNER_CONTACT (
ID NUMBER(19) NOT NULL,
PARTNER_RECORD_ID NUMBER(19) NOT NULL,
CONTACT_NAME VARCHAR2(50 CHAR) NOT NULL,
CONTACT_PHONE VARCHAR2(20 CHAR) NOT NULL,
POSTAL_ADDRESS VARCHAR2(100 CHAR) NOT NULL,
EMAIL VARCHAR2(50 CHAR) NOT NULL,
SORT_ORDER NUMBER(10) DEFAULT 1 NOT NULL,
DEL_FLAG CHAR(1 CHAR) DEFAULT '0' NOT NULL,
CREATE_BY VARCHAR2(64 CHAR),
CREATE_TIME DATE DEFAULT SYSDATE,
UPDATE_BY VARCHAR2(64 CHAR),
UPDATE_TIME DATE DEFAULT SYSDATE,
REMARK VARCHAR2(500 CHAR),
CONSTRAINT PK_SEAL_PARTNER_CONTACT PRIMARY KEY (ID)
);
COMMENT ON TABLE SEAL_PARTNER_CONTACT IS '相对方联系人表';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.ID IS '主键ID';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.PARTNER_RECORD_ID IS '关联相对方主表 CUSTOMER_SYSID';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.CONTACT_NAME IS '联系人姓名';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.CONTACT_PHONE IS '联系电话';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.POSTAL_ADDRESS IS '通讯地址';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.EMAIL IS '电子邮箱';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.SORT_ORDER IS '排序号';
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.DEL_FLAG IS '删除标记:0存在 2删除';
CREATE INDEX IDX_PARTNER_RECORD_ID ON SEAL_PARTNER_CONTACT (PARTNER_RECORD_ID);
CREATE SEQUENCE SEQ_SEAL_PARTNER_CONTACT
START WITH 4
INCREMENT BY 1
NOCACHE
NOCYCLE;
INSERT INTO SEAL_PARTNER_CONTACT
(ID, PARTNER_RECORD_ID, CONTACT_NAME, CONTACT_PHONE, POSTAL_ADDRESS, EMAIL,
SORT_ORDER, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK)
VALUES
(1, 1, '周经理', '15757460062', '宁波市北仑区明州西路188号A座', 'zhoujingli@example.com',
1, '0', 'local_test', TO_DATE('2026-05-20 09:12:33', 'YYYY-MM-DD HH24:MI:SS'),
'local_test', TO_DATE('2026-05-20 09:12:33', 'YYYY-MM-DD HH24:MI:SS'), '主联系人');
INSERT INTO SEAL_PARTNER_CONTACT
(ID, PARTNER_RECORD_ID, CONTACT_NAME, CONTACT_PHONE, POSTAL_ADDRESS, EMAIL,
SORT_ORDER, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK)
VALUES
(2, 3, 'Alice Brown', '+44-20-8899-0001', '88 Harbour Street, London', 'alice.brown@ocean-energy.com',
1, '0', 'local_test', TO_DATE('2026-05-18 11:08:22', 'YYYY-MM-DD HH24:MI:SS'),
'local_test', TO_DATE('2026-05-18 11:08:22', 'YYYY-MM-DD HH24:MI:SS'), '海外主联系人');
INSERT INTO SEAL_PARTNER_CONTACT
(ID, PARTNER_RECORD_ID, CONTACT_NAME, CONTACT_PHONE, POSTAL_ADDRESS, EMAIL,
SORT_ORDER, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK)
VALUES
(3, 3, 'Tom Lee', '+44-20-8899-0002', '88 Harbour Street, London', 'tom.lee@ocean-energy.com',
2, '0', 'local_test', TO_DATE('2026-05-18 11:08:22', 'YYYY-MM-DD HH24:MI:SS'),
'local_test', TO_DATE('2026-05-18 11:08:22', 'YYYY-MM-DD HH24:MI:SS'), '备用联系人');
COMMIT;
-26
View File
@@ -1,26 +0,0 @@
-- =============================================
-- Partner module time-column update for Oracle
-- Execute with:
-- sqlplus developer/dev123@localhost/XEPDB1 @partner_alter_date_oracle.sql
-- =============================================
WHENEVER SQLERROR EXIT SQL.SQLCODE;
PROMPT Alter ILDM_FEE_CUSTOMER_INFO.CREATE_TIME / UPDATE_TIME to DATE...
ALTER TABLE ILDM_FEE_CUSTOMER_INFO MODIFY (
CREATE_TIME DATE,
UPDATE_TIME DATE
);
PROMPT Alter SEAL_PARTNER_CONTACT.CREATE_TIME / UPDATE_TIME to DATE...
ALTER TABLE SEAL_PARTNER_CONTACT MODIFY (
CREATE_TIME DATE,
UPDATE_TIME DATE
);
PROMPT Verify column types...
SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, DATA_LENGTH
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME IN ('ILDM_FEE_CUSTOMER_INFO', 'SEAL_PARTNER_CONTACT')
AND COLUMN_NAME IN ('CREATE_TIME', 'UPDATE_TIME')
ORDER BY TABLE_NAME, COLUMN_NAME;
+5
View File
@@ -29,6 +29,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
@@ -1,46 +0,0 @@
package com.nbport.zgwl.auth;
import org.springframework.stereotype.Component;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* 本地模拟 AuthManager。
*
* 目的不是还原正式权限中心,而是把调用方式先固定住:
* authManager.isUserCanAccessSys(userId, SysEnum.BUSINESS/MANAGE)
*
* 后续复制到正式环境时,保留方法签名,替换内部实现即可。
*/
@Component
public class AuthManager {
/**
* 写死几套本地用户可访问系统。
*
* 约定:
* 1L -> 超管,可同时访问 manage / business
* 2L -> manage 侧管理员
* 3L -> business 侧业务管理员
* 4L -> business 侧普通用户
*/
private static final Map<Long, Set<SysEnum>> USER_SYS_ACCESS = new HashMap<>();
static {
USER_SYS_ACCESS.put(1L, EnumSet.of(SysEnum.MANAGE, SysEnum.BUSINESS));
USER_SYS_ACCESS.put(2L, EnumSet.of(SysEnum.MANAGE));
USER_SYS_ACCESS.put(3L, EnumSet.of(SysEnum.BUSINESS));
USER_SYS_ACCESS.put(4L, EnumSet.of(SysEnum.BUSINESS));
}
public boolean isUserCanAccessSys(Long userId, SysEnum sysEnum) {
if (userId == null || sysEnum == null) {
return false;
}
Set<SysEnum> accessSet = USER_SYS_ACCESS.get(userId);
return accessSet != null && accessSet.contains(sysEnum);
}
}
@@ -1,404 +0,0 @@
package com.nbport.zgwl.contractlaunch.controller;
import com.nbport.zgwl.common.PageResult;
import com.nbport.zgwl.common.R;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchApproveDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchiveDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchCollectSaveDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackRequestDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackSampleDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchQueryDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchSealDto;
import com.nbport.zgwl.contractlaunch.service.ContractLaunchService;
import com.nbport.zgwl.contractlaunch.utils.ContractLaunchConstants;
import com.nbport.zgwl.entity.SysUserEntity;
import com.nbport.zgwl.utils.AdminSecurityManage;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* 合同发起 Controller
*
* 这里除了正常 CRUD,还额外提供了几类“测试按钮”接口:
* 1. 模拟法务审批通过 / 驳回
* 2. 模拟合同采集
* 3. 合同归档
* 4. 回写签章结果
*
* 这些测试接口在法务系统不可用期间便于你完整演示流程,
* 后续接入真实系统后,保留或删除都很方便。
*/
@RestController
@RequiredArgsConstructor
@RequestMapping(ContractLaunchConstants.REQUEST_PREFIX)
public class ContractLaunchController {
private final ContractLaunchService contractLaunchService;
private final AdminSecurityManage adminSecurityManage;
/**
* 分页查询合同列表。
*
* 支持按合同名称、合同编号、合同类型、状态、创建时间范围过滤。
* 返回结果附带合同方摘要、文件列表、履行计划(不含日志,列表页日志量大)。
*
* 对应前端功能:合同列表页
*
* 请求体 ContractLaunchQueryDto 字段:
* contractName - 合同名称(模糊)
* contractCode - 合同编号
* contractType - 合同类型
* status - 状态(draft/reviewing/rejected/pending_sign/signing/...
* dateStart - 创建时间范围-开始(yyyy-MM-dd
* dateEnd - 创建时间范围-结束(yyyy-MM-dd
*/
@PostMapping("/list")
public R<PageResult<ContractLaunchDto>> queryList(@RequestBody ContractLaunchQueryDto queryDto) {
return R.success(contractLaunchService.queryPage(queryDto));
}
/**
* 查询合同详情(含所有子表数据)。
*
* 返回合同基本信息 + 合同方列表 + 文件列表 + 履行计划 + 操作日志。
*
* 对应前端功能:合同详情页 / 编辑页面回显
*/
@GetMapping("/{id}")
public R<ContractLaunchDto> getDetail(@PathVariable("id") Long id) {
return R.success(contractLaunchService.getDetail(id));
}
/**
* 获取当前登录人的我方组织信息(当前先返回 mock 数据)。
*
* 用途:
* 1. 发起合同页面只读展示“我方”信息
* 2. 后续接入真实组织主数据时,前端不需要再改字段来源
*/
@GetMapping("/self-profile")
public R<Object> getSelfProfile() {
SysUserEntity currentUser = adminSecurityManage.getUser();
return R.success(currentUser == null ? null : currentUser.getSysOrgEntity());
}
/**
* 创建合同草稿。
*
* 流程:生成 contractSysIdCLS-xxx)和 contractCode → 保存主表 → 保存子表(合同方/文件/履行计划)→ 记录操作日志
* 状态变为:draft(草稿)
*
* 必填校验项:合同名称、合同类型、合同类型编码、计价方式、币种、签订方式、合同期限类型、至少一个甲方+乙方
*
* 对应前端功能:新建合同 → 保存草稿
*/
@PostMapping
public R<ContractLaunchDto> createDraft(@RequestBody ContractLaunchDto contract) {
return R.success(contractLaunchService.createDraft(contract));
}
/**
* 编辑合同草稿。
*
* 仅 draft(草稿)或 rejected(已驳回)状态允许编辑。
* 逻辑:先删子表旧数据,再以当前数据重新插入(替换式更新)。
* 保留原有的 contractSysId、contractCode、创建人/创建时间 不变。
*
* 对应前端功能:编辑草稿 → 保存
*/
@PutMapping
public R<ContractLaunchDto> updateDraft(@RequestBody ContractLaunchDto contract) {
return R.success(contractLaunchService.updateDraft(contract));
}
/**
* 复制合同并生成新草稿。
*
* 业务设计:
* 1. 允许从任意未删除合同复制出一份新的草稿,方便高频复用历史合同
* 2. 保留主信息、合同方、正文附件、履行计划等业务内容
* 3. 重置系统编号、合同编号、审批/签署/归档状态与相关痕迹,避免串流程数据
*
* 对应前端功能:列表页 → 复制合同
*/
@PostMapping("/{id}/copy")
public R<ContractLaunchDto> copyDraft(@PathVariable("id") Long id) {
return R.success(contractLaunchService.copyDraft(id));
}
/**
* 基于现有合同发起变更/附加合同草稿。
*
* 处理原则:
* 1. 复制现有业务内容
* 2. 自动关联主合同编码 mainContractCode
* 3. 生成新的草稿,供业务在此基础上做变更补充
*/
@PostMapping("/{id}/change")
public R<ContractLaunchDto> createChangeDraft(@PathVariable("id") Long id) {
return R.success(contractLaunchService.createChangeDraft(id));
}
/**
* 提交法务审批。
*
* 状态流转:draft/rejected → reviewing
* 调用结算平台 pushContract 接口将合同数据推送给法务系统开始审批流程。
* 目前法务接口不可用,仅做状态变更 + 记录日志(TODO:联调时打开 settlementPushService.pushContract 调用)。
*
* 推送法务的报文包含:合同基本字段 + contractOpposites(相对方) + contractKxPlans(履行计划) + 附件等
*
* 对应前端功能:提交审批按钮
*/
@PostMapping("/{id}/submit")
public R<ContractLaunchDto> submitToLaw(@PathVariable("id") Long id) {
return R.success(contractLaunchService.submitToLaw(id));
}
/**
* 【测试按钮】模拟法务审批通过。
*
* 状态流转:reviewing → pending_sign(待签署)
* 生成模拟的 lawContractCode 和 lawContractId 记录到合同上,以便后续流程使用。
* 可在请求体中传入 approveMessage(审批意见)、lawContractCode、lawContractId 覆盖自动生成的值。
*
* 真实场景下,此方法应由法务系统的回调接口替代(见 lawApproveCallback)。
*
* 对应前端功能:测试按钮 → 模拟审批通过
*/
@PostMapping("/{id}/mock-approve")
public R<ContractLaunchDto> mockApprove(@PathVariable("id") Long id,
@RequestBody(required = false) ContractLaunchApproveDto approveDto) {
return R.success(contractLaunchService.mockApprove(id, approveDto));
}
/**
* 【测试按钮】模拟法务审批驳回。
*
* 状态流转:reviewing → rejected(已驳回)
* 可在请求体中传入 approveMessage(驳回原因)。
* 驳回后合同可再次编辑和提交。
*
* 对应前端功能:测试按钮 → 模拟驳回
*/
@PostMapping("/{id}/mock-reject")
public R<ContractLaunchDto> mockReject(@PathVariable("id") Long id,
@RequestBody(required = false) ContractLaunchApproveDto approveDto) {
return R.success(contractLaunchService.mockReject(id, approveDto));
}
/**
* 获取法务审批回调样例。
*
* 用途:
* 1. 前端展示与法务协商的固定 data 结构
* 2. 本地联调时复制到 Postman,直接调用 callback 接口
*
* 说明:
* - 样例中的水印文件路径当前先复用本地合同正文路径
* - 后续法务真正实现文件传输后,只需要替换 watermarkFile.filePath 来源
*/
@GetMapping("/{id}/callback/law/approve/sample")
public R<ContractLaunchLawCallbackSampleDto> getLawApproveCallbackSample(@PathVariable("id") Long id) {
return R.success(contractLaunchService.buildLawApproveCallbackSample(id));
}
/**
* 法务审批结果回调入口(供法务系统调用)。
*
* submitToLaw 时推给法务的 pushUrl 默认指向此接口:POST /contract/launch/callback/law/approve
* 法务审批完成后,会往 pushUrl POST 审批结果。
*
* 当前约定请求体结构固定为:
* {
* "data": {
* "contractSysId": "...",
* "approveStatus": "approved|rejected",
* ...
* }
* }
*
* 这样前后端、法务、Postman 联调都统一只看 data 这一套结构,
* 不再做多字段兼容判断,便于后续正式协商定稿。
*
* 状态流转:reviewing → pending_sign(通过) / rejected(驳回)
*
* 对应前端功能:法务系统审批完成后自动回调(目前用法务系统暂未对接)
*/
@PostMapping("/callback/law/approve")
public R<ContractLaunchDto> lawApproveCallback(@RequestBody ContractLaunchLawCallbackRequestDto callbackRequest) {
return R.success(contractLaunchService.handleLawApproveCallback(callbackRequest == null ? null : callbackRequest.getData()));
}
/**
* 签署发起回调(浙江CA安全签调用)。
*
* 在浙江CA安全签平台创建签署合同后,回写 sealContractId 到本系统合同。
* 状态流转:pending_sign → signing(签署中)
*
* 请求体 ContractLaunchSealDto 字段:
* sealContractId - 签章平台生成的合同ID(必填)
* sealContractStatus - 签署状态(1:签署中)
*
* 对应前端功能:调起浙江CA签署后,回写签章合同ID
*/
@PostMapping("/{id}/seal/save")
public R<ContractLaunchDto> saveSealInfo(@PathVariable("id") Long id,
@RequestBody ContractLaunchSealDto sealDto) {
return R.success(contractLaunchService.saveSealInfo(id, sealDto));
}
/**
* 签署完成回调(浙江CA安全签/线下签署完成后调用)。
*
* 所有签署方完成签署后,将签署完成的合同文件信息回写。
* 状态流转:signing → pending_collect(待采集)
*
* 请求体 ContractLaunchSealDto 字段:
* sealContractStatus - 签署状态(2:签署完成)
* signedFileName - 签署完成后的文件名
* signedFilePath - 签署文件存储路径
* signedFileType - 文件类型
* signedFileSize - 文件大小
* signedOfflineReason - 线下签署原因(如果未在线签署)
*
* 签署文件会自动保存到 file 子表(fileCategory = "signed"),先删旧签署文件再插入新的。
*
* 对应前端功能:签署完成 → 回写签署结果
*/
@PostMapping("/{id}/seal/finish")
public R<ContractLaunchDto> finishSeal(@PathVariable("id") Long id,
@RequestBody ContractLaunchSealDto sealDto) {
return R.success(contractLaunchService.markSealCompleted(id, sealDto));
}
/**
* 【测试按钮】模拟合同采集。
*
* 合同签署完成后,调用数据采集 V3.0 的 collectContract 接口将合同信息推送到法务系统存档。
* 目前法务接口不可用,仅做状态变更 + 记录日志(TODO:联调时打开 dataCollectionPushService.collectContract 调用)。
*
* 状态流转:pending_collect → pending_archive(待归档)
*
* 推送数据采集的报文包含:合同基本字段 + 用印信息(c_seal)+ 签订信息(c_sign+ 附件等
*
* 对应前端功能:测试按钮 → 模拟采集
*/
@PostMapping("/{id}/mock-collect")
public R<ContractLaunchDto> mockCollect(@PathVariable("id") Long id) {
return R.success(contractLaunchService.mockCollect(id));
}
/**
* 保存采集信息(用印信息 + 签订信息)。
*
* 签署完成后,在「合同采集」阶段(pending_collect),
* 用户通过采集弹窗补充/修改用印信息和签订信息后保存到合同记录。
* 与 mock-collect 分开,允许用户在触发采集前先保存草稿。
*
* 请求体 ContractLaunchCollectSaveDto 字段:
* sealIsSeal - 是否用印
* sealApproveSame - 用印和审批文本是否一致
* sealQuantity - 用印数量
* sealDate - 用印时间
* signDate - 签订日期
* activeDate - 合同生效日期
* executorAccount - 合同履行执行人
* signedFileName - 签署文件名
* signedFilePath - 签署文件路径
* signedFileType - 签署文件类型
* signedFileSize - 签署文件大小
*/
@PostMapping("/{id}/collect/save")
public R<ContractLaunchDto> saveCollectInfo(@PathVariable("id") Long id,
@RequestBody ContractLaunchCollectSaveDto collectDto) {
return R.success(contractLaunchService.saveCollectInfo(id, collectDto));
}
/**
* 获取相对方签署确认状态。
*/
@GetMapping("/{id}/counterparty-confirm")
public R<Map<String, Object>> getCounterpartyConfirm(@PathVariable("id") Long id) {
return R.success(contractLaunchService.getCounterpartyConfirmFiltered(id));
}
/**
* 相对方确认已签署完成。
*
* 请求体:{"companyName": "四川德鑫矿业资源有限公司"}
* 后端自动获取当前登录用户信息写入确认记录。
*/
@PostMapping("/{id}/counterparty-confirm")
public R<Map<String, Object>> confirmCounterparty(@PathVariable("id") Long id,
@RequestBody Map<String, String> body) {
String companyName = body.get("companyName");
if (companyName == null || companyName.isBlank()) {
return R.error("companyName 不能为空");
}
return R.success(contractLaunchService.confirmCounterparty(id, companyName));
}
/**
* 合同归档。
*
* 合同全生命周期最后一步,状态变为 completed(已完成)。
* 同时将归档信息按数据采集 V3.0 的合同归档接口推送到法务系统存档
* TODO:联调时打开 dataCollectionPushService.collectContractArchive 调用)。
*
* 请求体 ContractLaunchArchiveDto 字段:
* archiveReceiveDept - 合同归档接收部门编码
* archiveTransferor - 移交人账号
* archivePapers - 纸质档案材料列表
* archiveEles - 电子档案材料列表(含 approvalAttachs
*
* 归档附件自动保存到 file 子表(fileCategory = "archive"),
* 纸质/电子档案明细分别保存到独立子表。
*
* 对应前端功能:归档按钮 → 合同完结
*/
@PostMapping("/{id}/archive")
public R<ContractLaunchDto> archive(@PathVariable("id") Long id,
@RequestBody(required = false) ContractLaunchArchiveDto archiveDto) {
return R.success(contractLaunchService.archive(id, archiveDto));
}
/**
* 合同终止。
*
* 允许除 completed 外的任意环节执行终止。
* 当前仅在本系统内变更状态并记录日志,法务系统终止需后续分别操作。
*/
@PostMapping("/{id}/terminate")
public R<ContractLaunchDto> terminate(@PathVariable("id") Long id,
@RequestBody(required = false) Map<String, Object> payload) {
Object reasonValue = payload == null ? null : payload.get("terminateReason");
String terminateReason = reasonValue == null ? null : String.valueOf(reasonValue).trim();
return R.success(contractLaunchService.terminate(id, terminateReason));
}
/**
* 删除合同草稿(逻辑删除)。
*
* 仅 draft(草稿)或 rejected(已驳回)状态允许删除。
* 逻辑:设置 isDeleted = 'Y',不物理删除数据。
*
* 对应前端功能:删除草稿按钮
*/
@DeleteMapping("/{id}")
public R<String> deleteDraft(@PathVariable("id") Long id) {
contractLaunchService.deleteDraft(id);
return R.success("删除成功");
}
}
@@ -1,79 +0,0 @@
package com.nbport.zgwl.contractlaunch.service;
import com.nbport.zgwl.common.PageResult;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchApproveDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchiveDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchCollectSaveDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackSampleDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchQueryDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchSealDto;
import java.util.Map;
public interface ContractLaunchService {
/** 分页查询合同列表 */
PageResult<ContractLaunchDto> queryPage(ContractLaunchQueryDto queryDto);
/** 查询合同详情(含合同方/文件/履行计划/日志) */
ContractLaunchDto getDetail(Long id);
/** 创建合同草稿 */
ContractLaunchDto createDraft(ContractLaunchDto contract);
/** 编辑合同草稿 */
ContractLaunchDto updateDraft(ContractLaunchDto contract);
/** 复制合同并生成新的草稿 */
ContractLaunchDto copyDraft(Long id);
/** 基于现有合同发起变更/附加合同草稿 */
ContractLaunchDto createChangeDraft(Long id);
/** 提交法务审批(调用结算平台 pushContract 接口) */
ContractLaunchDto submitToLaw(Long id);
/** 模拟审批通过(测试按钮,TODO:替换为真实法务回调) */
ContractLaunchDto mockApprove(Long id, ContractLaunchApproveDto approveDto);
/** 模拟审批驳回(测试按钮,TODO:替换为真实法务回调) */
ContractLaunchDto mockReject(Long id, ContractLaunchApproveDto approveDto);
/** 获取法务审批回调样例(用于本地联调和前端展示) */
ContractLaunchLawCallbackSampleDto buildLawApproveCallbackSample(Long id);
/** 接收法务审批回调(处理审批结果,更新合同状态) */
ContractLaunchDto handleLawApproveCallback(ContractLaunchLawCallbackDto callbackData);
/** 回写签章信息(签署发起时调用,记录 sealContractId */
ContractLaunchDto saveSealInfo(Long id, ContractLaunchSealDto sealDto);
/** 签署完成回调(回写签署文件路径,状态变更为待采集) */
ContractLaunchDto markSealCompleted(Long id, ContractLaunchSealDto sealDto);
/** 保存采集信息(用印+签订信息),用于采集弹窗保存草稿 */
ContractLaunchDto saveCollectInfo(Long id, ContractLaunchCollectSaveDto collectDto);
/** 获取相对方签署确认状态 Map */
Map<String, Object> getCounterpartyConfirmMap(Long id);
/** 获取相对方签署确认状态(按权限过滤:manage 全量,business 只看自己) */
Map<String, Object> getCounterpartyConfirmFiltered(Long id);
/** 相对方确认已签署完成 */
Map<String, Object> confirmCounterparty(Long id, String companyName);
/** 模拟合同采集(调用数据采集 collectContract 接口,TODO:替换为真实调用) */
ContractLaunchDto mockCollect(Long id);
/** 合同归档(状态变更为已完成,TODO:同时推送归档到法务) */
ContractLaunchDto archive(Long id, ContractLaunchArchiveDto archiveDto);
/** 合同终止 */
ContractLaunchDto terminate(Long id, String terminateReason);
/** 删除草稿(仅 draft/rejected 状态允许) */
void deleteDraft(Long id);
}
@@ -1,74 +0,0 @@
package com.nbport.zgwl.controller;
import com.nbport.zgwl.common.R;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/admin/dict")
public class AdminDictController {
private static final String TEMPLATE_FIELD_DICT_TYPE = "CONTRACT_TEMPLATE_FIELDS";
@PostMapping("/getDictDataByType")
public R<List<DictDataItem>> getDictDataByType(@RequestBody(required = false) Map<String, Object> body) {
String dictType = resolveDictType(body);
if (TEMPLATE_FIELD_DICT_TYPE.equals(dictType)) {
return R.success(buildTemplateFieldItems());
}
return R.success(List.of());
}
private String resolveDictType(Map<String, Object> body) {
if (body == null) {
return null;
}
Object params = body.get("params");
if (params instanceof Map<?, ?> paramMap) {
Object dictType = paramMap.get("dictType");
return dictType == null ? null : String.valueOf(dictType).trim();
}
Object dictType = body.get("dictType");
return dictType == null ? null : String.valueOf(dictType).trim();
}
private List<DictDataItem> buildTemplateFieldItems() {
return List.of(
new DictDataItem("合同名称", "contractName", "合同正文中的合同名称"),
new DictDataItem("合同编码", "contractCode", "合同正文中的合同编码"),
new DictDataItem("合同类型", "contractType", "合同正文中的合同类型"),
new DictDataItem("合同金额", "contractAmountDisplay", "用于展示金额文本"),
new DictDataItem("有效期起", "effectiveStart", "合同有效期起始日期"),
new DictDataItem("有效期止", "effectiveEnd", "合同有效期结束日期"),
new DictDataItem("有效期区间", "effectivePeriod", "合同有效期区间文本"),
new DictDataItem("付款方式", "paymentMethod", "合同中的付款方式说明"),
new DictDataItem("合同标的说明", "primaryContent", "合同主要内容或标的说明"),
new DictDataItem("业务备注", "amountExplain", "可用于维护金额说明或业务备注"),
new DictDataItem("甲方名称", "partyAName", "模板变量值,由用户自行维护"),
new DictDataItem("乙方名称", "partyBName", "模板变量值,由用户自行维护"),
new DictDataItem("丙方名称", "partyCName", "模板变量值,由用户自行维护"),
new DictDataItem("合同方摘要", "counterpartySummary", "模板变量值,由用户自行维护"),
new DictDataItem("附件情况", "attachmentSummary", "模板变量值,由用户自行维护"),
new DictDataItem("模板名称", "templateLabel", "模板变量值,由用户自行维护"),
new DictDataItem("签署日期", "signDate", "模板变量值,由用户自行维护"),
new DictDataItem("A的TAx", "partyATaxNo", "模板变量值,由用户自行维护"),
new DictDataItem("B的TAx", "partyBTaxNo", "模板变量值,由用户自行维护")
);
}
@Data
@AllArgsConstructor
private static class DictDataItem {
private String k;
private String v;
private String remark;
}
}
@@ -1,15 +1,15 @@
package com.nbport.zgwl;
package com.nbport.zgwl.fiance;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan({
"com.nbport.zgwl.mapper",
"com.nbport.zgwl.partner.mapper",
"com.nbport.zgwl.manifest.mapper",
"com.nbport.zgwl.contractlaunch.mapper",
"com.nbport.zgwl.contractlog.mapper"
"com.nbport.zgwl.fiance.mapper",
"com.nbport.zgwl.fiance.partner.mapper",
"com.nbport.zgwl.fiance.manifest.mapper",
"com.nbport.zgwl.fiance.contractlaunch.mapper",
"com.nbport.zgwl.fiance.contractlog.mapper"
})
@SpringBootApplication
public class ZgwlEndApplication {
@@ -0,0 +1,26 @@
package com.nbport.zgwl.fiance.auth;
import com.nbport.zgwl.fiance.utils.MockSecurityUserRegistry;
import org.springframework.stereotype.Component;
/**
* 本地模拟 AuthManager。
*
* 目的不是还原正式权限中心,而是把调用方式先固定住:
* authManager.isUserCanAccessSys(userId, SysEnum.BUSINESS/MANAGE)
*
* 后续复制到正式环境时,保留方法签名,替换内部实现即可。
*/
@Component
public class AuthManager {
private final MockSecurityUserRegistry mockSecurityUserRegistry;
public AuthManager(MockSecurityUserRegistry mockSecurityUserRegistry) {
this.mockSecurityUserRegistry = mockSecurityUserRegistry;
}
public boolean isUserCanAccessSys(Long userId, SysEnum sysEnum) {
return mockSecurityUserRegistry.canAccessSystem(userId, sysEnum);
}
}
@@ -1,11 +1,10 @@
package com.nbport.zgwl.auth;
package com.nbport.zgwl.fiance.auth;
import com.nbport.zgwl.entity.SysUserEntity;
import com.nbport.zgwl.utils.AdminSecurityManage;
import com.nbport.zgwl.fiance.entity.SysUserEntity;
import com.nbport.zgwl.fiance.utils.AdminSecurityManage;
import com.nbport.zgwl.fiance.utils.MockSecurityUserRegistry;
import org.springframework.stereotype.Component;
import java.util.Set;
/**
* 本地模拟 SecurityManager
*
@@ -15,18 +14,17 @@ import java.util.Set;
@Component
public class SecurityManager {
private static final Set<Long> SUPER_ADMIN_IDS = Set.of(1L);
private final AdminSecurityManage adminSecurityManage;
private final MockSecurityUserRegistry mockSecurityUserRegistry;
public SecurityManager(AdminSecurityManage adminSecurityManage) {
public SecurityManager(AdminSecurityManage adminSecurityManage,
MockSecurityUserRegistry mockSecurityUserRegistry) {
this.adminSecurityManage = adminSecurityManage;
this.mockSecurityUserRegistry = mockSecurityUserRegistry;
}
public boolean isSuperAdmin() {
SysUserEntity currentUser = adminSecurityManage.getUser();
return currentUser != null
&& currentUser.getId() != null
&& SUPER_ADMIN_IDS.contains(currentUser.getId());
return currentUser != null && mockSecurityUserRegistry.isSuperAdmin(currentUser.getId());
}
}
@@ -1,4 +1,4 @@
package com.nbport.zgwl.auth;
package com.nbport.zgwl.fiance.auth;
/**
* 本地模拟系统枚举
@@ -1,4 +1,4 @@
package com.nbport.zgwl.common;
package com.nbport.zgwl.fiance.common;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -1,6 +1,6 @@
package com.nbport.zgwl.common;
package com.nbport.zgwl.fiance.common;
import com.nbport.zgwl.exception.ServiceErrorCodeRange;
import com.nbport.zgwl.fiance.exception.ServiceErrorCodeRange;
public interface GlobalErrorCodeConstants {
@@ -1,4 +1,4 @@
package com.nbport.zgwl.common;
package com.nbport.zgwl.fiance.common;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -1,9 +1,9 @@
package com.nbport.zgwl.common;
package com.nbport.zgwl.fiance.common;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonView;
import com.nbport.zgwl.exception.ServiceErrorCodeRange;
import com.nbport.zgwl.exception.ServiceException;
import com.nbport.zgwl.fiance.exception.ServiceErrorCodeRange;
import com.nbport.zgwl.fiance.exception.ServiceException;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serial;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.common;
package com.nbport.zgwl.fiance.common;
public class Views {
@@ -0,0 +1,21 @@
package com.nbport.zgwl.fiance.config;
import io.minio.MinioClient;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@RequiredArgsConstructor
public class MinioConfiguration {
private final MinioProperties minioProperties;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(minioProperties.getEndpoint())
.credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
.build();
}
}
@@ -0,0 +1,25 @@
package com.nbport.zgwl.fiance.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "minio")
public class MinioProperties {
private String endpoint;
private String accessKey;
private String secretKey;
private String bucketName = "zgwl-contract";
private String basePath = "";
private boolean createBucketIfMissing = true;
private boolean publicReadWrite = true;
}
@@ -1,4 +1,4 @@
package com.nbport.zgwl.config;
package com.nbport.zgwl.fiance.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
@@ -0,0 +1,215 @@
package com.nbport.zgwl.fiance.contractlaunch.controller;
import com.nbport.zgwl.fiance.common.PageResult;
import com.nbport.zgwl.fiance.common.R;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchApproveDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchArchiveDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchCollectSaveDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchLawCallbackRequestDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchLawCallbackSampleDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchQueryDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionBatchStatusDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionCheckResultDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionPageDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionSaveDto;
import com.nbport.zgwl.fiance.contractlaunch.service.ContractLaunchService;
import com.nbport.zgwl.fiance.contractlaunch.utils.ContractLaunchConstants;
import com.nbport.zgwl.fiance.entity.SysUserEntity;
import com.nbport.zgwl.fiance.utils.AdminSecurityManage;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
/**
* 合同发起 Controller
*
* 这里除了正常 CRUD,还额外提供了几类“测试按钮”接口:
* 1. 模拟法务审批通过 / 驳回
* 2. 模拟合同采集
* 3. 合同归档
* 4. 回写签章结果
*/
@RestController
@RequiredArgsConstructor
@RequestMapping(ContractLaunchConstants.REQUEST_PREFIX)
public class ContractLaunchController {
private final ContractLaunchService contractLaunchService;
private final AdminSecurityManage adminSecurityManage;
@PostMapping("/list")
public R<PageResult<ContractLaunchDto>> queryList(@RequestBody ContractLaunchQueryDto queryDto) {
return R.success(contractLaunchService.queryPage(queryDto));
}
@GetMapping("/{id}")
public R<ContractLaunchDto> getDetail(@PathVariable("id") Long id) {
return R.success(contractLaunchService.getDetail(id));
}
@GetMapping("/self-profile")
public R<Object> getSelfProfile() {
SysUserEntity currentUser = adminSecurityManage.getUser();
return R.success(currentUser == null ? null : currentUser.getSysOrgEntity());
}
@PostMapping
public R<ContractLaunchDto> createDraft(@RequestBody ContractLaunchDto contract) {
return R.success(contractLaunchService.createDraft(contract));
}
@PutMapping
public R<ContractLaunchDto> updateDraft(@RequestBody ContractLaunchDto contract) {
return R.success(contractLaunchService.updateDraft(contract));
}
@PostMapping("/{id}/copy")
public R<ContractLaunchDto> copyDraft(@PathVariable("id") Long id) {
return R.success(contractLaunchService.copyDraft(id));
}
@PostMapping("/{id}/change")
public R<ContractLaunchDto> createChangeDraft(@PathVariable("id") Long id) {
return R.success(contractLaunchService.createChangeDraft(id));
}
@PostMapping("/{id}/submit")
public R<ContractLaunchDto> submitToLaw(@PathVariable("id") Long id) {
return R.success(contractLaunchService.submitToLaw(id));
}
@PostMapping("/{id}/mock-approve")
public R<ContractLaunchDto> mockApprove(@PathVariable("id") Long id,
@RequestBody(required = false) ContractLaunchApproveDto approveDto) {
return R.success(contractLaunchService.mockApprove(id, approveDto));
}
@PostMapping("/{id}/mock-reject")
public R<ContractLaunchDto> mockReject(@PathVariable("id") Long id,
@RequestBody(required = false) ContractLaunchApproveDto approveDto) {
return R.success(contractLaunchService.mockReject(id, approveDto));
}
@GetMapping("/{id}/callback/law/approve/sample")
public R<ContractLaunchLawCallbackSampleDto> getLawApproveCallbackSample(@PathVariable("id") Long id) {
return R.success(contractLaunchService.buildLawApproveCallbackSample(id));
}
@PostMapping("/callback/law/approve")
public R<ContractLaunchDto> lawApproveCallback(@RequestBody ContractLaunchLawCallbackRequestDto callbackRequest) {
return R.success(contractLaunchService.handleLawApproveCallback(callbackRequest == null ? null : callbackRequest.getData()));
}
@PostMapping("/{id}/seal/save")
public R<ContractLaunchDto> saveSealInfo(@PathVariable("id") Long id,
@RequestBody ContractLaunchSealDto sealDto) {
return R.success(contractLaunchService.saveSealInfo(id, sealDto));
}
@PostMapping("/{id}/seal/finish")
public R<ContractLaunchDto> finishSeal(@PathVariable("id") Long id,
@RequestBody ContractLaunchSealDto sealDto) {
return R.success(contractLaunchService.markSealCompleted(id, sealDto));
}
@PostMapping("/{id}/mock-collect")
public R<ContractLaunchDto> mockCollect(@PathVariable("id") Long id) {
return R.success(contractLaunchService.mockCollect(id));
}
@PostMapping("/{id}/collect/save")
public R<ContractLaunchDto> saveCollectInfo(@PathVariable("id") Long id,
@RequestBody ContractLaunchCollectSaveDto collectDto) {
return R.success(contractLaunchService.saveCollectInfo(id, collectDto));
}
@GetMapping("/{id}/counterparty-confirm")
public R<Map<String, Object>> getCounterpartyConfirm(@PathVariable("id") Long id) {
return R.success(contractLaunchService.getCounterpartyConfirmFiltered(id));
}
@PostMapping("/{id}/counterparty-confirm")
public R<Map<String, Object>> confirmCounterparty(@PathVariable("id") Long id,
@RequestBody Map<String, String> body) {
String partyIdValue = body.get("partyId");
if (partyIdValue == null || partyIdValue.isBlank()) {
return R.error("partyId 不能为空");
}
try {
return R.success(contractLaunchService.confirmCounterparty(id, Long.valueOf(partyIdValue)));
} catch (NumberFormatException ex) {
return R.error("partyId 格式不正确");
}
}
@PostMapping("/{id}/seal-position/init")
public R<ContractLaunchSealPositionPageDto> initSealPosition(@PathVariable("id") Long id) {
return R.success(contractLaunchService.initSealPosition(id));
}
@GetMapping("/{id}/seal-position/list")
public R<ContractLaunchSealPositionPageDto> getSealPositionPage(@PathVariable("id") Long id) {
return R.success(contractLaunchService.getSealPositionPage(id));
}
@PostMapping("/{id}/seal-position/save")
public R<ContractLaunchSealPositionPageDto> saveSealPositions(@PathVariable("id") Long id,
@RequestBody(required = false) ContractLaunchSealPositionSaveDto saveDto) {
return R.success(contractLaunchService.saveSealPositions(id, saveDto == null ? new ContractLaunchSealPositionSaveDto() : saveDto));
}
@PostMapping("/{id}/seal-position/batch-status")
public R<ContractLaunchSealPositionPageDto> batchUpdateSealPositionStatus(@PathVariable("id") Long id,
@RequestBody ContractLaunchSealPositionBatchStatusDto batchDto) {
return R.success(contractLaunchService.batchUpdateSealPositionStatus(id, batchDto));
}
@PostMapping("/{id}/seal-position/check")
public R<ContractLaunchSealPositionCheckResultDto> checkSealPositions(@PathVariable("id") Long id,
@RequestBody(required = false) Map<String, Object> body) {
Long partyId = null;
Object partyIdValue = body == null ? null : body.get("partyId");
if (partyIdValue != null && !String.valueOf(partyIdValue).isBlank()) {
partyId = Long.valueOf(String.valueOf(partyIdValue));
}
return R.success(contractLaunchService.checkSealPositions(id, partyId));
}
@PostMapping("/{id}/watermark/upload")
public R<ContractLaunchDto> uploadWatermarkFile(@PathVariable("id") Long id,
@RequestParam("file") MultipartFile file) {
return R.success(contractLaunchService.uploadWatermarkFile(id, file));
}
@PostMapping("/{id}/archive")
public R<ContractLaunchDto> archive(@PathVariable("id") Long id,
@RequestBody(required = false) ContractLaunchArchiveDto archiveDto) {
return R.success(contractLaunchService.archive(id, archiveDto));
}
@PostMapping("/{id}/terminate")
public R<ContractLaunchDto> terminate(@PathVariable("id") Long id,
@RequestBody(required = false) Map<String, Object> payload) {
Object reasonValue = payload == null ? null : payload.get("terminateReason");
String terminateReason = reasonValue == null ? null : String.valueOf(reasonValue).trim();
return R.success(contractLaunchService.terminate(id, terminateReason));
}
@DeleteMapping("/{id}")
public R<String> deleteDraft(@PathVariable("id") Long id) {
contractLaunchService.deleteDraft(id);
return R.success("删除成功");
}
}
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
@@ -84,6 +84,12 @@ public class ContractLaunchDto implements Serializable {
/** 签章平台合同ID(浙江CA安全签创建后返回) */
private String sealContractId;
/** 签章位是否已配置(Y/N)。 */
private String sealPosConfigured;
/** PDF 预览图片地址列表 JSON。 */
private String sealPdfImageList;
/** 签章状态(1:签署中, 2:签署完成, 3:签署失败, null:未发起) */
private Integer sealContractStatus;
@@ -185,13 +191,13 @@ public class ContractLaunchDto implements Serializable {
private String pushUrl;
/** 是否重大合同(1:是, 0:否) */
private Integer isMajorContract;
private String isMajorContract;
/** 是否公开招标(1:是, 0:否) */
private Integer isOpenBidding;
private String isOpenBidding;
/** 是否列入当年预算(1:是, 0:否) */
private Integer isYearBudget;
private String isYearBudget;
/** 是否共享(1:是, 0:否) */
private String isShare;
@@ -402,4 +408,7 @@ public class ContractLaunchDto implements Serializable {
/** 操作日志列表 */
private List<ContractLaunchLogDto> logList = new ArrayList<>();
/** 当前合同的签章位列表。 */
private List<ContractLaunchSealPositionDto> sealPositionList = new ArrayList<>();
}
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
@@ -1,11 +1,12 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import com.nbport.zgwl.dto.BasePageDto;
import com.nbport.zgwl.fiance.dto.BasePageDto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 合同发起列表查询参数
@@ -29,6 +30,9 @@ public class ContractLaunchQueryDto extends BasePageDto implements Serializable
/** 状态(draft/reviewing/rejected/pending_sign/signing/pending_collect/pending_archive/completed */
private String status;
/** 状态集合(用于多状态查询,如待签署+签署中) */
private List<String> statusList;
/** 创建时间范围-开始 yyyy-MM-dd */
private String dateStart;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.dto;
package com.nbport.zgwl.fiance.contractlaunch.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
@@ -0,0 +1,45 @@
package com.nbport.zgwl.fiance.contractlaunch.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 批量更新签章位状态入参。
*/
@Data
public class ContractLaunchSealPositionBatchStatusDto implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/** 当前操作代表哪一方签。 */
private Long partyId;
/** 目标状态:0空框 1已选章 2待回调 3已签 4失败。 */
private Integer signedStatus;
private String requestId;
private String signedByName;
private String signedById;
private List<Item> items = new ArrayList<>();
@Data
public static class Item implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long id;
private String sealId;
private String sealName;
}
}
@@ -0,0 +1,24 @@
package com.nbport.zgwl.fiance.contractlaunch.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 签章位校验结果。
*/
@Data
public class ContractLaunchSealPositionCheckResultDto implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private boolean passed;
private int missingCount;
private List<ContractLaunchSealPositionDto> missingPositions = new ArrayList<>();
}
@@ -0,0 +1,73 @@
package com.nbport.zgwl.fiance.contractlaunch.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 合同签章位 DTO。
*
* 一份合同可配置多个签章位,
* 每个签章位绑定到具体合同方(partyId)。
*/
@Data
public class ContractLaunchSealPositionDto implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long id;
private Long contractId;
private Long partyId;
private String label;
/** Y/N,是否必签。 */
private String required;
private Integer pageNum;
private Double x;
private Double y;
private Double width;
private Double height;
private String sealId;
private String sealName;
/** 最近一次二维码请求ID。 */
private String requestId;
/** 0空框 1已选章 2待回调 3已签 4失败。 */
private Integer signedStatus;
private String signedByName;
private String signedById;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime signedTime;
private String createBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime createTime;
private String updateBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime updateTime;
private String isDeleted;
private String remark;
}
@@ -0,0 +1,42 @@
package com.nbport.zgwl.fiance.contractlaunch.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 签章位页面返回对象。
*
* 同时返回:
* 1. 签章平台合同ID
* 2. PDF 预览信息
* 3. 当前合同的签章位列表
* 4. 当前用户可代表签署的 partyId 列表
*/
@Data
public class ContractLaunchSealPositionPageDto implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long contractId;
private String sealContractId;
private String sealPosConfigured;
private Integer imageWidth;
private Integer imageHeight;
private List<String> pdfToImageList = new ArrayList<>();
private List<ContractLaunchSealPositionDto> positions = new ArrayList<>();
private List<Long> availablePartyIds = new ArrayList<>();
private Long preferredPartyId;
}
@@ -0,0 +1,24 @@
package com.nbport.zgwl.fiance.contractlaunch.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 批量保存签章位入参。
*
* 第一版采用替换式保存:
* 前端传当前整份合同的全部签章位,
* 后端先删后插,避免逐条 diff。
*/
@Data
public class ContractLaunchSealPositionSaveDto implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private List<ContractLaunchSealPositionDto> positions = new ArrayList<>();
}
@@ -1,139 +1,121 @@
package com.nbport.zgwl.contractlaunch.mapper;
package com.nbport.zgwl.fiance.contractlaunch.mapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchiveEleDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchivePaperDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchFileDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLogDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchPartyDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchPlanDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchQueryDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchArchiveEleDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchArchivePaperDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchFileDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchLogDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchPartyDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchPlanDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchQueryDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionDto;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ContractLaunchMapper {
/** 获取主表序列(Oracle 主键生成) */
Long selectMainSeqNextVal();
/** 获取合同方表序列 */
Long selectPartySeqNextVal();
/** 获取文件表序列 */
Long selectFileSeqNextVal();
/** 获取履行计划表序列 */
Long selectPlanSeqNextVal();
/** 获取日志表序列 */
Long selectLogSeqNextVal();
/** 获取纸质归档表序列 */
Long selectArchivePaperSeqNextVal();
/** 获取电子归档表序列 */
Long selectArchiveEleSeqNextVal();
/** 分页查询合同列表 */
Long selectSealPositionSeqNextVal();
IPage<ContractLaunchDto> selectContractPage(Page<ContractLaunchDto> page, @Param("query") ContractLaunchQueryDto queryDto);
/** 根据主键查询合同 */
ContractLaunchDto selectContractById(@Param("id") Long id);
/** 根据主键并带权限条件查询合同 */
ContractLaunchDto selectContractByIdWithScope(@Param("id") Long id, @Param("query") ContractLaunchQueryDto queryDto);
/** 根据 contractSysId 查询合同(法务回调时用于定位) */
ContractLaunchDto selectContractByContractSysId(@Param("contractSysId") String contractSysId);
/** 根据 sealContractId 查询合同(签章平台回调时用于定位) */
ContractLaunchDto selectContractBySealContractId(@Param("sealContractId") String sealContractId);
/** 新增合同 */
int insertContract(ContractLaunchDto contract);
/** 修改合同 */
int updateContract(ContractLaunchDto contract);
/** 逻辑删除合同 */
int deleteContract(@Param("id") Long id, @Param("updateBy") String updateBy);
/** 批量插入合同方 */
int batchInsertParty(@Param("list") List<ContractLaunchPartyDto> list,
@Param("createBy") String createBy,
@Param("updateBy") String updateBy);
/** 批量插入文件 */
int batchInsertFile(@Param("list") List<ContractLaunchFileDto> list,
@Param("createBy") String createBy,
@Param("updateBy") String updateBy);
/** 批量插入履行计划 */
int batchInsertPlan(@Param("list") List<ContractLaunchPlanDto> list,
@Param("createBy") String createBy,
@Param("updateBy") String updateBy);
/** 批量插入纸质归档材料 */
int batchInsertArchivePaper(@Param("list") List<ContractLaunchArchivePaperDto> list,
@Param("createBy") String createBy,
@Param("updateBy") String updateBy);
/** 批量插入电子归档材料 */
int batchInsertArchiveEle(@Param("list") List<ContractLaunchArchiveEleDto> list,
@Param("createBy") String createBy,
@Param("updateBy") String updateBy);
/** 插入单条操作日志 */
int insertLog(ContractLaunchLogDto logDto);
/** 删除合同下的所有合同方(逻辑删除) */
int deletePartyByContractId(@Param("contractId") Long contractId,
@Param("updateBy") String updateBy);
/** 删除合同下的所有文件(逻辑删除) */
int deleteFileByContractId(@Param("contractId") Long contractId,
@Param("updateBy") String updateBy);
/** 按分类删除合同下的文件(如重新上传正文时只删正文,不删其他附件) */
int deleteFileByContractIdAndCategory(@Param("contractId") Long contractId,
@Param("fileCategory") String fileCategory,
@Param("updateBy") String updateBy);
/** 回写法务附件路径缓存 */
int updateFileLegalUrl(@Param("id") Long id,
@Param("legalFileUrl") String legalFileUrl,
@Param("updateBy") String updateBy);
/** 删除合同下的所有履行计划(逻辑删除) */
int deletePlanByContractId(@Param("contractId") Long contractId,
@Param("updateBy") String updateBy);
/** 删除合同下的纸质归档材料(逻辑删除) */
int deleteArchivePaperByContractId(@Param("contractId") Long contractId,
@Param("updateBy") String updateBy);
/** 删除合同下的电子归档材料(逻辑删除) */
int deleteArchiveEleByContractId(@Param("contractId") Long contractId,
@Param("updateBy") String updateBy);
/** 批量查询合同方(按 contractIds */
int deleteSealPositionByContractId(@Param("contractId") Long contractId,
@Param("updateBy") String updateBy);
int batchInsertSealPosition(@Param("list") List<ContractLaunchSealPositionDto> list,
@Param("createBy") String createBy,
@Param("updateBy") String updateBy);
List<ContractLaunchSealPositionDto> selectSealPositionByContractId(@Param("contractId") Long contractId);
List<ContractLaunchSealPositionDto> selectSealPositionByRequestId(@Param("requestId") String requestId);
int updateSealPosition(ContractLaunchSealPositionDto position);
List<ContractLaunchPartyDto> selectPartyByContractIds(@Param("contractIds") List<Long> contractIds);
/** 批量查询文件(按 contractIds */
List<ContractLaunchFileDto> selectFileByContractIds(@Param("contractIds") List<Long> contractIds);
/** 批量查询履行计划(按 contractIds */
List<ContractLaunchPlanDto> selectPlanByContractIds(@Param("contractIds") List<Long> contractIds);
/** 批量查询纸质归档材料(按 contractIds */
List<ContractLaunchArchivePaperDto> selectArchivePaperByContractIds(@Param("contractIds") List<Long> contractIds);
/** 批量查询电子归档材料(按 contractIds */
List<ContractLaunchArchiveEleDto> selectArchiveEleByContractIds(@Param("contractIds") List<Long> contractIds);
/** 批量查询操作日志(按 contractIds */
List<ContractLaunchLogDto> selectLogByContractIds(@Param("contractIds") List<Long> contractIds);
}
@@ -1,11 +1,11 @@
package com.nbport.zgwl.contractlaunch.service;
package com.nbport.zgwl.fiance.contractlaunch.service;
import cn.hutool.core.util.StrUtil;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchFileDto;
import com.nbport.zgwl.contractlaunch.mapper.ContractLaunchMapper;
import com.nbport.zgwl.contractpush.service.DataCollectionPushService;
import com.nbport.zgwl.exception.ServiceException;
import com.nbport.zgwl.service.LocalFileService;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchFileDto;
import com.nbport.zgwl.fiance.contractlaunch.mapper.ContractLaunchMapper;
import com.nbport.zgwl.fiance.contractpush.service.DataCollectionPushService;
import com.nbport.zgwl.fiance.exception.ServiceException;
import com.nbport.zgwl.fiance.service.LocalFileService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@@ -0,0 +1,571 @@
package com.nbport.zgwl.fiance.contractlaunch.service;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.nbport.zgwl.fiance.auth.AuthManager;
import com.nbport.zgwl.fiance.auth.SecurityManager;
import com.nbport.zgwl.fiance.auth.SysEnum;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchPartyDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionBatchStatusDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionPageDto;
import com.nbport.zgwl.fiance.contractlaunch.mapper.ContractLaunchMapper;
import com.nbport.zgwl.fiance.contractlaunch.utils.ContractLaunchConstants;
import com.nbport.zgwl.fiance.entity.SysUserEntity;
import com.nbport.zgwl.fiance.exception.ServiceException;
import com.nbport.zgwl.fiance.partner.dto.PartnerManageDto;
import com.nbport.zgwl.fiance.partner.service.PartnerManageService;
import com.nbport.zgwl.fiance.seal.config.SealConfig;
import com.nbport.zgwl.fiance.seal.service.SealTokenService;
import com.nbport.zgwl.fiance.seal.utils.SealHttpClient;
import com.nbport.zgwl.fiance.service.LocalFileService;
import com.nbport.zgwl.fiance.utils.AdminSecurityManage;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 签章位相关的辅助能力。
*
* 这部分逻辑后补到现有 Service 时,尽量不去拆散原来的大类,
* 因此单独抽一个父类承接:
* 1. 签章平台预览初始化
* 2. 签章位坐标校验与状态流转
* 3. 当前用户可代表的签署方识别
*/
abstract class ContractLaunchSealPositionSupport {
protected static final int DEFAULT_IMAGE_WIDTH = 793;
protected static final int DEFAULT_IMAGE_HEIGHT = 1122;
protected void assertSealPositionConfigAccess(ContractLaunchDto contract) {
if (contract == null || contract.getId() == null) {
throw new ServiceException("合同不存在");
}
if (!"1".equals(defaultIfBlank(contract.getIsElectron(), "1"))) {
throw new ServiceException("仅电子合同支持配置签章位");
}
SysUserEntity currentUser = adminSecurityManage().getUser();
if (currentUser == null) {
throw new ServiceException("当前用户未登录");
}
if (securityManager().isSuperAdmin()) {
return;
}
if (!authManager().isUserCanAccessSys(currentUser.getId(), SysEnum.MANAGE)) {
throw new ServiceException("仅管理端用户可配置签章位");
}
}
protected void assertSealPositionViewAccess(ContractLaunchDto contract) {
if (contract == null || contract.getId() == null) {
throw new ServiceException("合同不存在");
}
if (!"1".equals(defaultIfBlank(contract.getIsElectron(), "1"))) {
throw new ServiceException("仅电子合同支持在线签署");
}
SysUserEntity currentUser = adminSecurityManage().getUser();
if (currentUser == null) {
throw new ServiceException("当前用户未登录");
}
if (securityManager().isSuperAdmin()) {
return;
}
boolean canManage = authManager().isUserCanAccessSys(currentUser.getId(), SysEnum.MANAGE);
boolean canBusiness = authManager().isUserCanAccessSys(currentUser.getId(), SysEnum.BUSINESS);
if (!canManage && !canBusiness) {
throw new ServiceException("当前用户无权访问在线签署");
}
}
protected SealPreviewData startSealPreview(ContractLaunchDto contract) {
if (contract == null) {
throw new ServiceException("合同不存在");
}
String filePath = trim(contract.getContractTextFilePath());
if (isBlank(filePath)) {
throw new ServiceException("请先上传水印文件");
}
byte[] fileBytes = localFileService().readFileBytes(filePath);
String fileName = defaultIfBlank(trim(contract.getContractTextFileName()), defaultIfBlank(trim(contract.getContractName()), "合同正文") + ".pdf");
String contentType = resolveContentType(fileName, contract.getContractTextFileType());
MultipartFile multipartFile = new SimpleMultipartFile(fileBytes, fileName, contentType);
String token = sealTokenService().getAccessToken();
String apiUrl = sealConfig().getBaseUrl() + "/saas/api/contract/start";
String response = SealHttpClient.postMultipart(apiUrl, multipartFile, baseFileName(contract.getContractName(), fileName), "seal-position-init", token);
JSONObject result = JSON.parseObject(response);
if (result == null || !result.getBooleanValue("isSuccess")) {
throw new ServiceException(result == null ? "初始化签署文件失败" : defaultIfBlank(result.getString("msg"), "初始化签署文件失败"));
}
SealPreviewData previewData = parsePreviewData(result.get("data"));
if (isBlank(previewData.contractId())) {
throw new ServiceException("签章平台未返回合同ID");
}
return previewData;
}
protected SealPreviewData previewSealContract(String sealContractId, String cachedImageListJson) {
List<String> cachedImageList = parseCachedImageList(cachedImageListJson);
if (isBlank(sealContractId)) {
return new SealPreviewData(null, DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT, cachedImageList);
}
try {
JSONObject body = new JSONObject();
body.put("contractId", sealContractId);
String response = SealHttpClient.post(
sealConfig().getBaseUrl() + "/saas/api/contract/preview",
body.toJSONString(),
sealTokenService().getAccessToken(),
"application/json"
);
JSONObject result = JSON.parseObject(response);
if (result != null && result.getBooleanValue("isSuccess")) {
SealPreviewData previewData = parsePreviewData(result.get("data"));
if (!previewData.pdfToImageList().isEmpty()) {
return previewData;
}
}
} catch (Exception ex) {
if (cachedImageList.isEmpty()) {
throw new ServiceException("获取签章预览失败: " + ex.getMessage());
}
}
return new SealPreviewData(sealContractId, DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT, cachedImageList);
}
protected ContractLaunchSealPositionPageDto buildSealPositionPage(ContractLaunchDto contract, SealPreviewData previewData) {
ContractLaunchSealPositionPageDto pageDto = new ContractLaunchSealPositionPageDto();
pageDto.setContractId(contract.getId());
pageDto.setSealContractId(defaultIfBlank(contract.getSealContractId(), previewData == null ? null : previewData.contractId()));
pageDto.setSealPosConfigured(defaultIfBlank(contract.getSealPosConfigured(), ContractLaunchConstants.FLAG_NO));
pageDto.setImageWidth(previewData == null ? DEFAULT_IMAGE_WIDTH : previewData.imageWidth());
pageDto.setImageHeight(previewData == null ? DEFAULT_IMAGE_HEIGHT : previewData.imageHeight());
pageDto.setPdfToImageList(previewData == null ? new ArrayList<>() : new ArrayList<>(previewData.pdfToImageList()));
pageDto.setPositions(new ArrayList<>(contractLaunchMapper().selectSealPositionByContractId(contract.getId())));
List<Long> availablePartyIds = resolveAvailablePartyIds(contract, adminSecurityManage().getUser());
pageDto.setAvailablePartyIds(availablePartyIds);
pageDto.setPreferredPartyId(availablePartyIds.size() == 1 ? availablePartyIds.get(0) : null);
return pageDto;
}
protected void validateSealPositionForSave(ContractLaunchSealPositionDto item, Map<Long, ContractLaunchPartyDto> partyMap) {
if (item == null) {
throw new ServiceException("签章位数据不能为空");
}
if (item.getPartyId() == null) {
throw new ServiceException("签章位必须绑定签署方");
}
if (partyMap == null || !partyMap.containsKey(item.getPartyId())) {
throw new ServiceException("签章位绑定的签署方不存在");
}
if (isBlank(item.getLabel())) {
throw new ServiceException("签章位标签不能为空");
}
if (item.getPageNum() == null || item.getPageNum() <= 0) {
throw new ServiceException("签章位页码必须大于0");
}
if (item.getX() == null || item.getY() == null || item.getWidth() == null || item.getHeight() == null) {
throw new ServiceException("签章位坐标不能为空");
}
if (item.getWidth() <= 0 || item.getHeight() <= 0) {
throw new ServiceException("签章位宽高必须大于0");
}
}
protected String normalizeRequiredFlag(String required) {
String value = trim(required);
if (value == null) {
return ContractLaunchConstants.FLAG_YES;
}
String normalized = value.toUpperCase(Locale.ROOT);
if ("N".equals(normalized) || "0".equals(normalized) || "FALSE".equals(normalized)) {
return ContractLaunchConstants.FLAG_NO;
}
return ContractLaunchConstants.FLAG_YES;
}
protected Double roundCoordinate(Double value) {
if (value == null) {
return null;
}
return Math.round(value * 100D) / 100D;
}
protected List<Long> resolveAvailablePartyIds(ContractLaunchDto contract, SysUserEntity currentUser) {
if (contract == null || contract.getPartyList() == null || contract.getPartyList().isEmpty() || currentUser == null) {
return new ArrayList<>();
}
if (securityManager().isSuperAdmin()) {
return contract.getPartyList().stream()
.map(ContractLaunchPartyDto::getId)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
boolean canManage = authManager().isUserCanAccessSys(currentUser.getId(), SysEnum.MANAGE);
boolean canBusiness = authManager().isUserCanAccessSys(currentUser.getId(), SysEnum.BUSINESS);
String currentOrgId = trim(orgIdAsString(currentUser));
String currentAccount = trim(currentUser.getUsername());
String currentMobile = trim(currentUser.getMobilePhone());
Set<Long> partyIds = new LinkedHashSet<>();
for (ContractLaunchPartyDto party : contract.getPartyList()) {
if (party == null || party.getId() == null) {
continue;
}
if (canManage && isOurParty(party) && Objects.equals(currentOrgId, trim(party.getSubjectCode()))) {
partyIds.add(party.getId());
continue;
}
if (canBusiness && isOppositeParty(party) && isBusinessPartyMatch(party, currentOrgId, currentAccount, currentMobile)) {
partyIds.add(party.getId());
}
}
return new ArrayList<>(partyIds);
}
protected Long resolveTargetPartyId(Long partyId, List<Long> availablePartyIds) {
if (partyId != null) {
if (availablePartyIds != null && !availablePartyIds.isEmpty() && !availablePartyIds.contains(partyId)) {
throw new ServiceException("当前用户不可操作该签署方");
}
return partyId;
}
if (availablePartyIds == null || availablePartyIds.isEmpty()) {
throw new ServiceException("当前用户未匹配到可签署方,请选择后重试");
}
if (availablePartyIds.size() > 1) {
throw new ServiceException("当前用户匹配到多个签署方,请选择后重试");
}
return availablePartyIds.get(0);
}
protected void applySealPositionStatus(ContractLaunchSealPositionDto position,
ContractLaunchSealPositionBatchStatusDto batchDto,
ContractLaunchSealPositionBatchStatusDto.Item item,
SysUserEntity currentUser,
LocalDateTime now) {
Integer signedStatus = batchDto.getSignedStatus();
if (signedStatus == null) {
throw new ServiceException("签章位状态不能为空");
}
position.setUpdateBy(currentUser == null ? "system" : currentUser.getUsername());
position.setUpdateTime(now);
if (signedStatus == ContractLaunchConstants.SEAL_POS_STATUS_EMPTY) {
position.setSealId(null);
position.setSealName(null);
position.setRequestId(null);
position.setSignedByName(null);
position.setSignedById(null);
position.setSignedTime(null);
position.setSignedStatus(ContractLaunchConstants.SEAL_POS_STATUS_EMPTY);
return;
}
if (signedStatus == ContractLaunchConstants.SEAL_POS_STATUS_SELECTED) {
if (item == null || isBlank(item.getSealId())) {
throw new ServiceException("已选章状态必须传印章ID");
}
position.setSealId(item.getSealId());
position.setSealName(item.getSealName());
position.setRequestId(null);
position.setSignedByName(null);
position.setSignedById(null);
position.setSignedTime(null);
position.setSignedStatus(ContractLaunchConstants.SEAL_POS_STATUS_SELECTED);
return;
}
if (signedStatus == ContractLaunchConstants.SEAL_POS_STATUS_SIGNING) {
String sealId = item == null ? null : item.getSealId();
if (!isBlank(sealId)) {
position.setSealId(sealId);
}
if (item != null && !isBlank(item.getSealName())) {
position.setSealName(item.getSealName());
}
if (isBlank(position.getSealId())) {
throw new ServiceException("提交预盖章前请先选择印章");
}
if (isBlank(batchDto.getRequestId())) {
throw new ServiceException("二维码请求ID不能为空");
}
position.setRequestId(batchDto.getRequestId());
position.setSignedByName(null);
position.setSignedById(null);
position.setSignedTime(null);
position.setSignedStatus(ContractLaunchConstants.SEAL_POS_STATUS_SIGNING);
return;
}
if (signedStatus == ContractLaunchConstants.SEAL_POS_STATUS_SIGNED) {
if (item != null && !isBlank(item.getSealId())) {
position.setSealId(item.getSealId());
}
if (item != null && !isBlank(item.getSealName())) {
position.setSealName(item.getSealName());
}
if (!isBlank(batchDto.getRequestId())) {
position.setRequestId(batchDto.getRequestId());
}
position.setSignedByName(defaultIfBlank(batchDto.getSignedByName(), currentUser == null ? null : currentUser.getUsername()));
position.setSignedById(defaultIfBlank(batchDto.getSignedById(), currentUser == null ? null : String.valueOf(currentUser.getId())));
position.setSignedTime(now);
position.setSignedStatus(ContractLaunchConstants.SEAL_POS_STATUS_SIGNED);
return;
}
if (signedStatus == ContractLaunchConstants.SEAL_POS_STATUS_FAILED) {
position.setRequestId(null);
position.setSignedByName(null);
position.setSignedById(null);
position.setSignedTime(null);
position.setSignedStatus(ContractLaunchConstants.SEAL_POS_STATUS_FAILED);
return;
}
throw new ServiceException("不支持的签章位状态: " + signedStatus);
}
protected boolean isSealPresignFailed(Map<String, Object> callbackData) {
String contractStatus = stringValue(callbackData == null ? null : callbackData.get("contractStatus"));
if (!isBlank(contractStatus)) {
if ("20".equals(contractStatus) || "2000".equals(contractStatus)) {
return false;
}
if ("0".equals(contractStatus) || contractStatus.startsWith("-")) {
return true;
}
}
Object successValue = callbackData == null ? null : (callbackData.containsKey("isSuccess") ? callbackData.get("isSuccess") : callbackData.get("success"));
if (successValue != null) {
return !Boolean.parseBoolean(String.valueOf(successValue));
}
String statusText = (stringValue(callbackData == null ? null : callbackData.get("status")) + " "
+ stringValue(callbackData == null ? null : callbackData.get("msg"))).toLowerCase(Locale.ROOT);
return statusText.contains("fail") || statusText.contains("cancel") || statusText.contains("timeout") || statusText.contains("reject");
}
protected String stringValue(Object value) {
return value == null ? null : trim(String.valueOf(value));
}
protected boolean isBlank(String value) {
return value == null || value.isBlank();
}
protected String defaultIfBlank(String value, String defaultValue) {
return isBlank(value) ? defaultValue : value;
}
protected String orgIdAsString(SysUserEntity user) {
if (user == null || user.getSysOrgEntity() == null || user.getSysOrgEntity().getId() == null) {
return null;
}
return String.valueOf(user.getSysOrgEntity().getId());
}
protected String trim(String value) {
return value == null ? null : value.trim();
}
protected boolean isOurParty(ContractLaunchPartyDto party) {
return party != null && "OUR".equalsIgnoreCase(trim(party.getRoleCode()));
}
protected boolean isOppositeParty(ContractLaunchPartyDto party) {
return party != null && "OPPOSITE".equalsIgnoreCase(trim(party.getRoleCode()));
}
protected boolean isSingleAgreement(ContractLaunchDto contract) {
return contract != null && "1".equals(defaultIfBlank(contract.getIsSingleAgreement(), "0"));
}
private boolean isBusinessPartyMatch(ContractLaunchPartyDto party, String currentOrgId, String currentAccount, String currentMobile) {
if (Objects.equals(currentOrgId, trim(party.getSubjectCode()))) {
return true;
}
if (party.getPartnerId() == null) {
return false;
}
try {
PartnerManageDto partner = partnerManageService().selectPartnerById(party.getPartnerId());
if (partner == null) {
return false;
}
if (partner.getLinkedOrgId() != null && Objects.equals(currentOrgId, String.valueOf(partner.getLinkedOrgId()))) {
return true;
}
String linkedUserAccount = trim(partner.getLinkedUserAccount());
return !isBlank(linkedUserAccount) && (linkedUserAccount.equalsIgnoreCase(defaultIfBlank(currentAccount, ""))
|| linkedUserAccount.equalsIgnoreCase(defaultIfBlank(currentMobile, "")));
} catch (Exception ignored) {
return false;
}
}
private SealPreviewData parsePreviewData(Object dataObject) {
if (dataObject == null) {
return new SealPreviewData(null, DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT, new ArrayList<>());
}
JSONObject data = dataObject instanceof JSONObject
? (JSONObject) dataObject
: JSON.parseObject(JSON.toJSONString(dataObject));
if (data == null) {
return new SealPreviewData(null, DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT, new ArrayList<>());
}
List<String> imageList = new ArrayList<>();
Object imageObject = data.get("pdfToImageList");
if (imageObject instanceof JSONArray array) {
for (int i = 0; i < array.size(); i++) {
String item = stringValue(array.get(i));
if (!isBlank(item)) {
imageList.add(item);
}
}
} else if (imageObject instanceof List<?> list) {
for (Object item : list) {
String imageUrl = stringValue(item);
if (!isBlank(imageUrl)) {
imageList.add(imageUrl);
}
}
} else if (imageObject != null) {
imageList.addAll(parseCachedImageList(String.valueOf(imageObject)));
}
Integer imageWidth = data.getInteger("imageWidth");
Integer imageHeight = data.getInteger("imageHeight");
return new SealPreviewData(
stringValue(data.get("contractId")),
imageWidth == null || imageWidth <= 0 ? DEFAULT_IMAGE_WIDTH : imageWidth,
imageHeight == null || imageHeight <= 0 ? DEFAULT_IMAGE_HEIGHT : imageHeight,
imageList
);
}
private List<String> parseCachedImageList(String json) {
if (isBlank(json)) {
return new ArrayList<>();
}
try {
JSONArray array = JSON.parseArray(json);
List<String> imageList = new ArrayList<>();
for (int i = 0; i < array.size(); i++) {
String item = stringValue(array.get(i));
if (!isBlank(item)) {
imageList.add(item);
}
}
return imageList;
} catch (Exception ex) {
return new ArrayList<>();
}
}
private String baseFileName(String contractName, String fileName) {
String value = defaultIfBlank(trim(contractName), trim(fileName));
if (isBlank(value)) {
return "合同正文";
}
int index = value.lastIndexOf('.');
return index > 0 ? value.substring(0, index) : value;
}
private String resolveContentType(String fileName, String fileType) {
String suffix = trim(fileType);
if (isBlank(suffix) && !isBlank(fileName) && fileName.contains(".")) {
suffix = fileName.substring(fileName.lastIndexOf('.') + 1);
}
suffix = defaultIfBlank(suffix, "pdf").toLowerCase(Locale.ROOT);
return switch (suffix) {
case "doc" -> "application/msword";
case "docx" -> "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
case "pdf" -> "application/pdf";
default -> "application/octet-stream";
};
}
protected abstract ContractLaunchMapper contractLaunchMapper();
protected abstract AdminSecurityManage adminSecurityManage();
protected abstract AuthManager authManager();
protected abstract SecurityManager securityManager();
protected abstract LocalFileService localFileService();
protected abstract SealTokenService sealTokenService();
protected abstract SealConfig sealConfig();
protected abstract PartnerManageService partnerManageService();
protected record SealPreviewData(String contractId, Integer imageWidth, Integer imageHeight, List<String> pdfToImageList) {
}
private static class SimpleMultipartFile implements MultipartFile {
private final byte[] content;
private final String originalFilename;
private final String contentType;
private SimpleMultipartFile(byte[] content, String originalFilename, String contentType) {
this.content = content == null ? new byte[0] : content;
this.originalFilename = originalFilename;
this.contentType = contentType;
}
@Override
public String getName() {
return "file";
}
@Override
public String getOriginalFilename() {
return originalFilename;
}
@Override
public String getContentType() {
return contentType;
}
@Override
public boolean isEmpty() {
return content.length == 0;
}
@Override
public long getSize() {
return content.length;
}
@Override
public byte[] getBytes() {
return content;
}
@Override
public InputStream getInputStream() {
return new ByteArrayInputStream(content);
}
@Override
public void transferTo(File dest) throws IOException {
try (FileOutputStream outputStream = new FileOutputStream(dest)) {
outputStream.write(content);
}
}
}
}
@@ -0,0 +1,77 @@
package com.nbport.zgwl.fiance.contractlaunch.service;
import com.nbport.zgwl.fiance.common.PageResult;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchApproveDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchArchiveDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchCollectSaveDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchLawCallbackDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchLawCallbackSampleDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchQueryDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionBatchStatusDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionCheckResultDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionPageDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionSaveDto;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
public interface ContractLaunchService {
PageResult<ContractLaunchDto> queryPage(ContractLaunchQueryDto queryDto);
ContractLaunchDto getDetail(Long id);
ContractLaunchDto createDraft(ContractLaunchDto contract);
ContractLaunchDto updateDraft(ContractLaunchDto contract);
ContractLaunchDto copyDraft(Long id);
ContractLaunchDto createChangeDraft(Long id);
ContractLaunchDto submitToLaw(Long id);
ContractLaunchDto mockApprove(Long id, ContractLaunchApproveDto approveDto);
ContractLaunchDto mockReject(Long id, ContractLaunchApproveDto approveDto);
ContractLaunchLawCallbackSampleDto buildLawApproveCallbackSample(Long id);
ContractLaunchDto handleLawApproveCallback(ContractLaunchLawCallbackDto callbackData);
ContractLaunchDto saveSealInfo(Long id, ContractLaunchSealDto sealDto);
ContractLaunchDto markSealCompleted(Long id, ContractLaunchSealDto sealDto);
ContractLaunchDto saveCollectInfo(Long id, ContractLaunchCollectSaveDto collectDto);
Map<String, Object> getCounterpartyConfirmMap(Long id);
Map<String, Object> getCounterpartyConfirmFiltered(Long id);
Map<String, Object> confirmCounterparty(Long id, Long partyId);
ContractLaunchSealPositionPageDto initSealPosition(Long id);
ContractLaunchSealPositionPageDto getSealPositionPage(Long id);
ContractLaunchSealPositionPageDto saveSealPositions(Long id, ContractLaunchSealPositionSaveDto saveDto);
ContractLaunchSealPositionPageDto batchUpdateSealPositionStatus(Long id, ContractLaunchSealPositionBatchStatusDto batchDto);
ContractLaunchSealPositionCheckResultDto checkSealPositions(Long id, Long partyId);
void handleSealPresignCallback(Map<String, Object> callbackData);
ContractLaunchDto uploadWatermarkFile(Long id, MultipartFile file);
ContractLaunchDto mockCollect(Long id);
ContractLaunchDto archive(Long id, ContractLaunchArchiveDto archiveDto);
ContractLaunchDto terminate(Long id, String terminateReason);
void deleteDraft(Long id);
}
@@ -1,50 +1,64 @@
package com.nbport.zgwl.contractlaunch.service;
package com.nbport.zgwl.fiance.contractlaunch.service;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nbport.zgwl.auth.AuthManager;
import com.nbport.zgwl.auth.SecurityManager;
import com.nbport.zgwl.auth.SysEnum;
import com.nbport.zgwl.fiance.auth.AuthManager;
import com.nbport.zgwl.fiance.auth.SecurityManager;
import com.nbport.zgwl.fiance.auth.SysEnum;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nbport.zgwl.common.PageResult;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchApproveDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchiveDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchiveEleDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchArchivePaperDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchCollectSaveDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchFileDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackFileDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackSampleDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLogDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchPartyDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchPlanDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchQueryDto;
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchSealDto;
import com.nbport.zgwl.contractlaunch.service.ContractLaunchLegalFileBridgeService;
import com.nbport.zgwl.contractlaunch.mapper.ContractLaunchMapper;
import com.nbport.zgwl.contractlaunch.utils.ContractLaunchCodeUtils;
import com.nbport.zgwl.contractlaunch.utils.ContractLaunchConstants;
import com.nbport.zgwl.contractlaunch.utils.JsonUtils;
import com.nbport.zgwl.contractpush.dto.PushPayloadDTO;
import com.nbport.zgwl.contractpush.service.DataCollectionPushService;
import com.nbport.zgwl.contractpush.service.SettlementPushService;
import com.nbport.zgwl.partner.dto.PartnerManageDto;
import com.nbport.zgwl.partner.service.PartnerManageService;
import com.nbport.zgwl.seal.service.SealTokenService;
import com.nbport.zgwl.seal.config.SealConfig;
import com.nbport.zgwl.seal.utils.SealHttpClient;
import com.nbport.zgwl.fiance.common.PageResult;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchApproveDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchArchiveDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchArchiveEleDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchArchivePaperDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchCollectSaveDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchFileDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchLawCallbackDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchLawCallbackFileDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchLawCallbackSampleDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchLogDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchPartyDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchPlanDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchQueryDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionBatchStatusDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionCheckResultDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionPageDto;
import com.nbport.zgwl.fiance.contractlaunch.dto.ContractLaunchSealPositionSaveDto;
import com.nbport.zgwl.fiance.contractlaunch.service.ContractLaunchLegalFileBridgeService;
import com.nbport.zgwl.fiance.contractlaunch.mapper.ContractLaunchMapper;
import com.nbport.zgwl.fiance.contractlaunch.utils.ContractLaunchCodeUtils;
import com.nbport.zgwl.fiance.contractlaunch.utils.ContractLaunchConstants;
import com.nbport.zgwl.fiance.contractlaunch.utils.JsonUtils;
import com.nbport.zgwl.fiance.contractpush.dto.PushPayloadDTO;
import com.nbport.zgwl.fiance.contractpush.service.DataCollectionPushService;
import com.nbport.zgwl.fiance.contractpush.service.SettlementPushService;
import com.nbport.zgwl.fiance.partner.dto.PartnerManageDto;
import com.nbport.zgwl.fiance.partner.service.PartnerManageService;
import com.nbport.zgwl.fiance.seal.service.SealTokenService;
import com.nbport.zgwl.fiance.seal.config.SealConfig;
import com.nbport.zgwl.fiance.seal.utils.SealHttpClient;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.nbport.zgwl.service.LocalFileService;
import com.nbport.zgwl.entity.SysUserEntity;
import com.nbport.zgwl.exception.ServiceException;
import com.nbport.zgwl.utils.AdminSecurityManage;
import com.nbport.zgwl.fiance.service.LocalFileService;
import com.nbport.zgwl.fiance.entity.SysUserEntity;
import com.nbport.zgwl.fiance.exception.ServiceException;
import com.nbport.zgwl.fiance.utils.AdminSecurityManage;
import com.nbport.zgwl.fiance.utils.FileStorageUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@@ -68,7 +82,7 @@ import java.util.stream.Collectors;
@Slf4j
@Service
@RequiredArgsConstructor
public class ContractLaunchServiceImpl implements ContractLaunchService {
public class ContractLaunchServiceImpl extends ContractLaunchSealPositionSupport implements ContractLaunchService {
/** 法务接口要求的日期时间格式:yyyy-MM-dd HH:mm:ss */
private static final DateTimeFormatter LAW_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@@ -129,13 +143,17 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
if (securityManager.isSuperAdmin()) {
return "admin";
}
String scopeByPermission = resolveScopeByDataPermission(currentUser.getDataPermission());
if (scopeByPermission != null) {
return scopeByPermission;
}
if (authManager.isUserCanAccessSys(currentUser.getId(), SysEnum.MANAGE)) {
return "company";
}
if (authManager.isUserCanAccessSys(currentUser.getId(), SysEnum.BUSINESS)) {
return "company";
}
return "personal";
return isAdminUser(currentUser) ? "company" : "personal";
}
/** 查询详情,含日志 */
@@ -499,7 +517,8 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
contract.setSealContractId(sealDto.getSealContractId() == null || sealDto.getSealContractId().isBlank() ? contract.getSealContractId() : sealDto.getSealContractId());
contract.setSealContractStatus(sealDto.getSealContractStatus());
contract.setSignedFileName(sealDto.getSignedFileName());
contract.setSignedFilePath(resolveSignedFilePath(sealDto));
String signedFilePath = resolveSignedFilePath(sealDto);
contract.setSignedFilePath(signedFilePath);
contract.setSignedFileUrl(sealDto.getSignedFileUrl() != null && !sealDto.getSignedFileUrl().isBlank()
? sealDto.getSignedFileUrl()
: (isExternalUrl(sealDto.getSignedFilePath()) ? sealDto.getSignedFilePath() : null));
@@ -514,7 +533,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
contract.setUpdateBy(currentUser.getUsername());
contract.setUpdateTime(completedTime);
contractLaunchMapper.updateContract(contract);
saveSignedFile(id, sealDto, currentUser.getUsername());
saveSignedFile(id, signedFilePath, sealDto, currentUser.getUsername());
// 区分在线签署完成和线下签署上传两种场景记录日志
boolean isOfflineUpload = sealDto.getSignedOfflineReason() != null && !sealDto.getSignedOfflineReason().isBlank();
if (isOfflineUpload) {
@@ -556,6 +575,29 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
* dataCollectionPushService.collectContract(requestDTO);
*/
@Override
@Transactional(rollbackFor = Exception.class)
public ContractLaunchDto uploadWatermarkFile(Long id, MultipartFile file) {
ContractLaunchDto contract = getDetail(id);
if (!ContractLaunchConstants.STATUS_PENDING_SIGN.equals(contract.getStatus())) {
throw new ServiceException("仅待签署状态的合同可上传水印文件");
}
String relativePath = localFileService.upload(file);
contract.setContractTextFileName(file.getOriginalFilename());
contract.setContractTextFilePath(relativePath);
String suffix = FileStorageUtils.getFileSuffix(file.getOriginalFilename());
contract.setContractTextFileType(suffix.startsWith(".") ? suffix.substring(1) : suffix);
contract.setContractTextFileSize(file.getSize());
contract.setUpdateBy(adminSecurityManage.getUser().getUsername());
contract.setUpdateTime(LocalDateTime.now());
contractLaunchMapper.updateContract(contract);
insertLog(id, ContractLaunchConstants.ACTION_SEAL_UPLOAD,
"上传水印合同文件", ContractLaunchConstants.ACTION_STATUS_SUCCESS,
"手动上传带法务水印的合同文件: " + file.getOriginalFilename(), null,
adminSecurityManage.getUser());
return getDetail(id);
}
/**
* 保存采集信息用印+签订信息
*
@@ -612,58 +654,66 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
@Override
public Map<String, Object> getCounterpartyConfirmFiltered(Long id) {
Map<String, Object> all = getCounterpartyConfirmMap(id);
SysUserEntity currentUser = adminSecurityManage.getUser();
boolean canManageAll = authManager.isUserCanAccessSys(currentUser.getId(), SysEnum.MANAGE);
if (canManageAll) {
return all;
}
// business 用户只返回自己组织对应的相对方确认状态
ContractLaunchDto contract = getDetail(id);
Map<String, Object> all = getCounterpartyConfirmMap(id);
List<Map<String, Object>> items = new ArrayList<>();
String userOrgId = currentUser.getSysOrgEntity() == null ? "" : String.valueOf(currentUser.getSysOrgEntity().getId());
String userOrgName = currentUser.getSysOrgEntity() == null ? "" : currentUser.getSysOrgEntity().getOrgName();
Map<String, Object> filtered = new LinkedHashMap<>();
if (contract.getPartyList() != null) {
contract.getPartyList().stream()
.filter(this::isOppositeParty)
.filter(p -> userOrgId.equals(p.getOppositeId())
|| userOrgId.equals(p.getSubjectCode())
|| userOrgName.equals(p.getCompanyName()))
.forEach(p -> {
String name = p.getCompanyName();
filtered.put(name, all.getOrDefault(name, new LinkedHashMap<>()));
});
.filter(p -> canManageAll || userOrgId.equals(trim(p.getSubjectCode())))
.forEach(p -> items.add(buildCounterpartyConfirmViewItem(p, all)));
}
return filtered;
Map<String, Object> result = new LinkedHashMap<>();
result.put("items", items);
return result;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Map<String, Object> confirmCounterparty(Long id, String companyName) {
public Map<String, Object> confirmCounterparty(Long id, Long partyId) {
ContractLaunchDto contract = getDetail(id);
SysUserEntity currentUser = adminSecurityManage.getUser();
String orgName = currentUser.getSysOrgEntity() == null ? "" : currentUser.getSysOrgEntity().getOrgName();
String userOrgId = currentUser.getSysOrgEntity() == null ? "" : String.valueOf(currentUser.getSysOrgEntity().getId());
String username = currentUser.getUsername();
String mobile = currentUser.getMobilePhone();
if (partyId == null) {
throw new ServiceException("partyId 不能为空");
}
ContractLaunchPartyDto targetParty = contract.getPartyList() == null ? null : contract.getPartyList().stream()
.filter(this::isOppositeParty)
.filter(p -> Objects.equals(p.getId(), partyId))
.findFirst()
.orElse(null);
if (targetParty == null) {
throw new ServiceException("相对方不存在");
}
// 权限校验business 用户只能确认自己组织对应的相对方
boolean canManageAll = authManager.isUserCanAccessSys(currentUser.getId(), SysEnum.MANAGE);
if (!canManageAll) {
String userOrgId = currentUser.getSysOrgEntity() == null ? "" : String.valueOf(currentUser.getSysOrgEntity().getId());
boolean matched = (contract.getPartyList() != null) && contract.getPartyList().stream()
.filter(this::isOppositeParty)
.anyMatch(p -> companyName.equals(p.getCompanyName())
&& (userOrgId.equals(p.getOppositeId()) || userOrgId.equals(p.getSubjectCode())));
if (!matched) {
if (!userOrgId.equals(trim(targetParty.getSubjectCode()))) {
throw new ServiceException("只能确认本组织对应的相对方");
}
}
Map<String, Object> confirmMap = getCounterpartyConfirmMap(id);
ContractLaunchSealPositionCheckResultDto checkResult = checkSealPositions(id, targetParty.getId());
if (checkResult != null && !checkResult.isPassed()) {
throw new ServiceException("该相对方还有 " + checkResult.getMissingCount() + " 个必签位置未完成签署,请先完成签章后再确认");
}
Map<String, Object> confirmMap = getCounterpartyConfirmMap(id);
String confirmKey = buildCounterpartyConfirmKey(targetParty);
Map<String, Object> entry = new LinkedHashMap<>();
entry.put("confirmed", true);
boolean isSelf = companyName.equals(orgName);
entry.put("partyId", targetParty.getId());
entry.put("partnerId", targetParty.getPartnerId());
entry.put("companyName", targetParty.getCompanyName());
entry.put("subjectCode", targetParty.getSubjectCode());
boolean isSelf = userOrgId.equals(trim(targetParty.getSubjectCode()));
entry.put("method", isSelf ? "self" : "manual");
entry.put("confirmedBy", username);
entry.put("confirmedMobile", mobile);
@@ -671,13 +721,195 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
if (!isSelf) {
entry.put("remark", "非本组织相对方,由 " + username + " 代为确认");
}
confirmMap.put(companyName, entry);
confirmMap.put(confirmKey, entry);
contract.setCounterpartyConfirmJson(JsonUtils.toJson(confirmMap));
contract.setUpdateBy(username);
contract.setUpdateTime(LocalDateTime.now());
contractLaunchMapper.updateContract(contract);
return confirmMap;
return getCounterpartyConfirmFiltered(id);
}
@Override
@Transactional(rollbackFor = Exception.class)
public ContractLaunchSealPositionPageDto initSealPosition(Long id) {
ContractLaunchDto contract = getDetail(id);
assertSealPositionConfigAccess(contract);
SealPreviewData previewData;
SysUserEntity currentUser = adminSecurityManage.getUser();
if (isBlank(contract.getSealContractId())) {
previewData = startSealPreview(contract);
contract.setSealContractId(previewData.contractId());
contract.setSealPdfImageList(JsonUtils.toJson(previewData.pdfToImageList()));
contract.setSealPosConfigured(defaultIfBlank(contract.getSealPosConfigured(), ContractLaunchConstants.FLAG_NO));
contract.setUpdateBy(currentUser.getUsername());
contract.setUpdateTime(LocalDateTime.now());
contractLaunchMapper.updateContract(contract);
insertLog(id, ContractLaunchConstants.ACTION_SEAL_CREATE, "初始化签署文件", ContractLaunchConstants.ACTION_STATUS_SUCCESS, "已基于水印文件创建签章平台合同", previewData, currentUser);
} else {
previewData = previewSealContract(contract.getSealContractId(), contract.getSealPdfImageList());
if (!previewData.pdfToImageList().isEmpty()) {
contract.setSealPdfImageList(JsonUtils.toJson(previewData.pdfToImageList()));
contract.setUpdateBy(currentUser.getUsername());
contract.setUpdateTime(LocalDateTime.now());
contractLaunchMapper.updateContract(contract);
}
}
return buildSealPositionPage(getDetail(id), previewData);
}
@Override
public ContractLaunchSealPositionPageDto getSealPositionPage(Long id) {
ContractLaunchDto contract = getDetail(id);
assertSealPositionViewAccess(contract);
return buildSealPositionPage(contract, previewSealContract(contract.getSealContractId(), contract.getSealPdfImageList()));
}
@Override
@Transactional(rollbackFor = Exception.class)
public ContractLaunchSealPositionPageDto saveSealPositions(Long id, ContractLaunchSealPositionSaveDto saveDto) {
ContractLaunchDto contract = getDetail(id);
assertSealPositionConfigAccess(contract);
if (!ContractLaunchConstants.STATUS_PENDING_SIGN.equals(contract.getStatus())) {
throw new ServiceException("仅待签署状态允许配置签章位");
}
if (isBlank(contract.getSealContractId())) {
throw new ServiceException("请先初始化签署文件");
}
SysUserEntity currentUser = adminSecurityManage.getUser();
String operator = currentUser.getUsername();
Map<Long, ContractLaunchPartyDto> partyMap = contract.getPartyList() == null ? Map.of() : contract.getPartyList().stream()
.collect(Collectors.toMap(ContractLaunchPartyDto::getId, item -> item, (a, b) -> a, LinkedHashMap::new));
List<ContractLaunchSealPositionDto> newPositions = new ArrayList<>();
if (saveDto != null && saveDto.getPositions() != null) {
for (ContractLaunchSealPositionDto item : saveDto.getPositions()) {
validateSealPositionForSave(item, partyMap);
ContractLaunchSealPositionDto position = new ContractLaunchSealPositionDto();
position.setContractId(id);
position.setPartyId(item.getPartyId());
position.setLabel(trim(item.getLabel()));
position.setRequired(normalizeRequiredFlag(item.getRequired()));
position.setPageNum(item.getPageNum());
position.setX(roundCoordinate(item.getX()));
position.setY(roundCoordinate(item.getY()));
position.setWidth(roundCoordinate(item.getWidth()));
position.setHeight(roundCoordinate(item.getHeight()));
position.setSignedStatus(ContractLaunchConstants.SEAL_POS_STATUS_EMPTY);
position.setCreateBy(operator);
position.setUpdateBy(operator);
position.setIsDeleted(ContractLaunchConstants.IS_DELETED_NO);
newPositions.add(position);
}
}
contractLaunchMapper.deleteSealPositionByContractId(id, operator);
if (!newPositions.isEmpty()) {
// Oracle INSERT ALL 在一条语句里插多行时会让 NEXTVAL 行为异常这里改成逐条插入更稳
for (ContractLaunchSealPositionDto position : newPositions) {
contractLaunchMapper.batchInsertSealPosition(List.of(position), operator, operator);
}
}
contract.setSealPosConfigured(newPositions.isEmpty() ? ContractLaunchConstants.FLAG_NO : ContractLaunchConstants.FLAG_YES);
contract.setUpdateBy(operator);
contract.setUpdateTime(LocalDateTime.now());
contractLaunchMapper.updateContract(contract);
insertLog(id, ContractLaunchConstants.ACTION_SEAL_POSITION_CONFIG, "保存签章位", ContractLaunchConstants.ACTION_STATUS_SUCCESS, "已保存签章位配置,共 " + newPositions.size() + "", saveDto, currentUser);
return getSealPositionPage(id);
}
@Override
@Transactional(rollbackFor = Exception.class)
public ContractLaunchSealPositionPageDto batchUpdateSealPositionStatus(Long id, ContractLaunchSealPositionBatchStatusDto batchDto) {
ContractLaunchDto contract = getDetail(id);
assertSealPositionViewAccess(contract);
if (batchDto == null || batchDto.getItems() == null || batchDto.getItems().isEmpty()) {
throw new ServiceException("签章位状态更新数据不能为空");
}
SysUserEntity currentUser = adminSecurityManage.getUser();
List<Long> availablePartyIds = resolveAvailablePartyIds(contract, currentUser);
Long targetPartyId = resolveTargetPartyId(batchDto.getPartyId(), availablePartyIds);
Map<Long, ContractLaunchSealPositionDto> positionMap = contractLaunchMapper.selectSealPositionByContractId(id).stream()
.collect(Collectors.toMap(ContractLaunchSealPositionDto::getId, item -> item, (a, b) -> a, LinkedHashMap::new));
LocalDateTime now = LocalDateTime.now();
for (ContractLaunchSealPositionBatchStatusDto.Item item : batchDto.getItems()) {
ContractLaunchSealPositionDto position = positionMap.get(item.getId());
if (position == null) {
throw new ServiceException("签章位不存在: " + item.getId());
}
if (!Objects.equals(position.getPartyId(), targetPartyId)) {
throw new ServiceException("签章位不属于当前签署方");
}
applySealPositionStatus(position, batchDto, item, currentUser, now);
contractLaunchMapper.updateSealPosition(position);
}
if (Objects.equals(batchDto.getSignedStatus(), ContractLaunchConstants.SEAL_POS_STATUS_SIGNING)
&& ContractLaunchConstants.STATUS_PENDING_SIGN.equals(contract.getStatus())) {
contract.setStatus(ContractLaunchConstants.STATUS_SIGNING);
contract.setSealContractStatus(20);
contract.setUpdateBy(currentUser.getUsername());
contract.setUpdateTime(now);
contractLaunchMapper.updateContract(contract);
}
insertLog(id, ContractLaunchConstants.ACTION_SEAL_POSITION_STATUS, "更新签章位状态", ContractLaunchConstants.ACTION_STATUS_SUCCESS, "已批量更新签章位状态", batchDto, currentUser);
return getSealPositionPage(id);
}
@Override
public ContractLaunchSealPositionCheckResultDto checkSealPositions(Long id, Long partyId) {
ContractLaunchDto contract = getDetail(id);
assertSealPositionViewAccess(contract);
SysUserEntity currentUser = adminSecurityManage.getUser();
List<Long> availablePartyIds = resolveAvailablePartyIds(contract, currentUser);
if (partyId != null && !availablePartyIds.isEmpty() && !availablePartyIds.contains(partyId) && !securityManager.isSuperAdmin()) {
throw new ServiceException("当前用户不可校验该签署方");
}
List<ContractLaunchSealPositionDto> positions = contractLaunchMapper.selectSealPositionByContractId(id).stream()
.filter(item -> ContractLaunchConstants.FLAG_YES.equals(normalizeRequiredFlag(item.getRequired())))
.filter(item -> partyId == null || Objects.equals(item.getPartyId(), partyId))
.filter(item -> !Objects.equals(item.getSignedStatus(), ContractLaunchConstants.SEAL_POS_STATUS_SIGNED))
.collect(Collectors.toList());
ContractLaunchSealPositionCheckResultDto result = new ContractLaunchSealPositionCheckResultDto();
result.setPassed(positions.isEmpty());
result.setMissingCount(positions.size());
result.setMissingPositions(positions);
return result;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void handleSealPresignCallback(Map<String, Object> callbackData) {
String requestId = stringValue(callbackData.get("requestId"));
if (isBlank(requestId)) {
return;
}
List<ContractLaunchSealPositionDto> positions = contractLaunchMapper.selectSealPositionByRequestId(requestId);
if (positions == null || positions.isEmpty()) {
return;
}
boolean success = !isSealPresignFailed(callbackData);
LocalDateTime now = LocalDateTime.now();
String signer = stringValue(callbackData.get("signer"));
String signerId = stringValue(callbackData.get("signerId"));
String operator = isBlank(signer) ? "seal_callback" : signer;
Long contractId = positions.get(0).getContractId();
for (ContractLaunchSealPositionDto position : positions) {
if (success) {
position.setSignedStatus(ContractLaunchConstants.SEAL_POS_STATUS_SIGNED);
position.setSignedByName(signer);
position.setSignedById(signerId);
position.setSignedTime(now);
} else {
position.setSignedStatus(isBlank(position.getSealId()) ? ContractLaunchConstants.SEAL_POS_STATUS_EMPTY : ContractLaunchConstants.SEAL_POS_STATUS_SELECTED);
position.setRequestId(null);
position.setSignedByName(null);
position.setSignedById(null);
position.setSignedTime(null);
}
position.setUpdateBy(operator);
position.setUpdateTime(now);
contractLaunchMapper.updateSealPosition(position);
}
insertLog(contractId, ContractLaunchConstants.ACTION_SEAL_POSITION_STATUS, success ? "预盖章回调成功" : "预盖章回调失败", success ? ContractLaunchConstants.ACTION_STATUS_SUCCESS : ContractLaunchConstants.ACTION_STATUS_FAILED, success ? "签章位已根据回调更新为已签" : "签章位已根据回调回滚为可重试状态", callbackData, adminSecurityManage.getUser());
}
/**
@@ -748,7 +980,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
? archiveDto.getArchiveTransferor()
: currentUser.getMobilePhone());
contract.setArchiveKeeperUnit(currentUser.getSysOrgEntity() == null ? contract.getArchiveKeeperUnit() : currentUser.getSysOrgEntity().getOrgName());
contract.setArchiveKeeperUnitCode(currentUser.getSysOrgEntity() == null ? contract.getArchiveKeeperUnitCode() : currentUser.getSysOrgEntity().getId());
contract.setArchiveKeeperUnitCode(currentUser.getSysOrgEntity() == null ? contract.getArchiveKeeperUnitCode() : orgIdAsString(currentUser));
contract.setStatus(ContractLaunchConstants.STATUS_COMPLETED);
contract.setUpdateBy(currentUser.getUsername());
contract.setUpdateTime(now);
@@ -839,7 +1071,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
contract.setInitiator(currentUser.getUsername());
contract.setInitiatorDept(currentUser.getSysOrgEntity() == null ? "" : currentUser.getSysOrgEntity().getOrgName());
contract.setCompanyName(currentUser.getSysOrgEntity() == null ? "" : currentUser.getSysOrgEntity().getOrgName());
contract.setOrgId(currentUser.getSysOrgEntity() == null ? "" : currentUser.getSysOrgEntity().getId());
contract.setOrgId(defaultIfBlank(orgIdAsString(currentUser), ""));
contract.setCreatorPhone(currentUser.getMobilePhone());
contract.setCreateBy(currentUser.getUsername());
contract.setCreateTime(now);
@@ -1168,8 +1400,8 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
}
/** 保存签署文件到 file 子表(先删旧签署文件,再插入新的) */
private void saveSignedFile(Long contractId, ContractLaunchSealDto sealDto, String operator) {
if (sealDto.getSignedFilePath() == null || sealDto.getSignedFilePath().isBlank()) {
private void saveSignedFile(Long contractId, String signedFilePath, ContractLaunchSealDto sealDto, String operator) {
if (signedFilePath == null || signedFilePath.isBlank()) {
return;
}
contractLaunchMapper.deleteFileByContractIdAndCategory(contractId, ContractLaunchConstants.FILE_CATEGORY_SIGNED, operator);
@@ -1180,7 +1412,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
fileDto.setFileName(sealDto.getSignedFileName() == null || sealDto.getSignedFileName().isBlank()
? "已签署合同文件"
: sealDto.getSignedFileName());
fileDto.setFilePath(sealDto.getSignedFilePath());
fileDto.setFilePath(signedFilePath);
fileDto.setFileType(sealDto.getSignedFileType());
fileDto.setFileSize(sealDto.getSignedFileSize());
fileDto.setSortOrder(1);
@@ -1195,8 +1427,10 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
logDto.setActionType(actionType);
logDto.setActionName(actionName);
logDto.setActionStatus(actionStatus);
logDto.setOperatorName(currentUser.getUsername());
logDto.setOperatorPhone(currentUser.getMobilePhone());
String operatorName = currentUser == null || currentUser.getUsername() == null || currentUser.getUsername().isBlank()
? "system" : currentUser.getUsername();
logDto.setOperatorName(operatorName);
logDto.setOperatorPhone(currentUser == null ? null : currentUser.getMobilePhone());
logDto.setActionTime(LocalDateTime.now());
logDto.setActionContent(actionContent);
logDto.setCallbackPayload(payload == null ? null : JSON.toJSONString(payload));
@@ -1240,10 +1474,10 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
contract.setIsElectron("1");
}
if (contract.getIsOpenBidding() == null) {
contract.setIsOpenBidding(0);
contract.setIsOpenBidding("0");
}
if (contract.getIsYearBudget() == null) {
contract.setIsYearBudget(0);
contract.setIsYearBudget("0");
}
if (contract.getPaymentDirection() == null || contract.getPaymentDirection().isBlank()) {
contract.setPaymentDirection("0");
@@ -1324,15 +1558,18 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
contract.setPartyList(normalized);
}
private boolean isOurParty(ContractLaunchPartyDto party) {
@Override
protected boolean isOurParty(ContractLaunchPartyDto party) {
return party != null && "OUR".equalsIgnoreCase(trim(party.getRoleCode()));
}
private boolean isOppositeParty(ContractLaunchPartyDto party) {
@Override
protected boolean isOppositeParty(ContractLaunchPartyDto party) {
return party != null && "OPPOSITE".equalsIgnoreCase(trim(party.getRoleCode()));
}
private boolean isSingleAgreement(ContractLaunchDto contract) {
@Override
protected boolean isSingleAgreement(ContractLaunchDto contract) {
String value = contract == null ? null : trim(contract.getIsSingleAgreement());
return "1".equals(value) || "Y".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value);
}
@@ -1361,7 +1598,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
}
String currentOrgId = currentUser == null || currentUser.getSysOrgEntity() == null
? null
: trim(currentUser.getSysOrgEntity().getId());
: trim(orgIdAsString(currentUser));
return currentOrgId != null ? currentOrgId : trim(contract.getOrgId());
}
@@ -1371,7 +1608,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
}
String currentOrgId = currentUser == null || currentUser.getSysOrgEntity() == null
? null
: trim(currentUser.getSysOrgEntity().getId());
: trim(orgIdAsString(currentUser));
String currentOrgName = currentUser == null || currentUser.getSysOrgEntity() == null
? null
: trim(currentUser.getSysOrgEntity().getOrgName());
@@ -1461,7 +1698,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
}
String currentOrgId = trim(adminSecurityManage.getUser() == null || adminSecurityManage.getUser().getSysOrgEntity() == null
? null
: adminSecurityManage.getUser().getSysOrgEntity().getId());
: orgIdAsString(adminSecurityManage.getUser()));
if (currentOrgId != null && !currentOrgId.isBlank()) {
boolean containsCurrentOrg = contract.getPartyList().stream()
.filter(this::isOurParty)
@@ -1487,7 +1724,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
if (!isSingleAgreement(contract) && !hasCounterparty) {
throw new ServiceException("至少维护一个相对方");
}
if (Integer.valueOf(1).equals(contract.getIsOpenBidding())
if ("1".equals(contract.getIsOpenBidding())
&& (contract.getBiddingNo() == null || contract.getBiddingNo().isBlank())) {
throw new ServiceException("公开招标时必须填写关联招标号");
}
@@ -1558,8 +1795,8 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
payload.put("mainContractCode", contract.getMainContractCode());
payload.put("periodExplain", contract.getPeriodExplain());
payload.put("valuationMode", contract.getValuationMode());
payload.put("isMajorContract", contract.getIsMajorContract() == null ? 0 : contract.getIsMajorContract());
payload.put("sealType", contract.getSealType());
payload.put("isMajorContract", contract.getIsMajorContract() == null ? "0" : contract.getIsMajorContract());
payload.put("sealType", "YWZ".equals(contract.getSealType()) ? "QT" : contract.getSealType());
payload.put("creatorPhone", contract.getCreatorPhone());
// dateType 仅在固定期限时传递无固定期限不传
if ("0".equals(contract.getContractPeriodType())) {
@@ -1584,9 +1821,9 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
payload.put("contractPeriod", contract.getContractPeriodType());
payload.put("contractAmount", contract.getContractAmount());
payload.put("isSgat", contract.getIsSgat());
payload.put("isOpenBidding", contract.getIsOpenBidding() == null ? 0 : contract.getIsOpenBidding());
payload.put("isOpenBidding", contract.getIsOpenBidding() == null ? "0" : contract.getIsOpenBidding());
payload.put("pushUrl", contract.getPushUrl());
payload.put("isYearBudget", contract.getIsYearBudget() == null ? 0 : contract.getIsYearBudget());
payload.put("isYearBudget", contract.getIsYearBudget() == null ? "0" : contract.getIsYearBudget());
payload.put("isShare", contract.getIsShare());
payload.put("assistDepartmentName", contract.getAssistDepartmentName());
payload.put("contractNature", contract.getContractNature());
@@ -1676,18 +1913,18 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
payload.put("c_qyztGAT", contract.getIsSgat());
payload.put("c_qyztSW", contract.getContractNature());
payload.put("c_executor", contract.getExecutorAccount());
payload.put("c_openBidding", contract.getIsOpenBidding() == null ? "0" : String.valueOf(contract.getIsOpenBidding()));
payload.put("c_openBidding", contract.getIsOpenBidding() == null ? "0" : contract.getIsOpenBidding());
// 关联招标号公开招标选是时必填
if (Integer.valueOf(1).equals(contract.getIsOpenBidding()) && contract.getBiddingNo() != null) {
if ("1".equals(contract.getIsOpenBidding()) && contract.getBiddingNo() != null) {
payload.put("c_biddingNo", contract.getBiddingNo());
} else {
payload.put("c_biddingNo", null);
}
// c_currentBudget 仅在收支方向为付款1时传 V3.0 文档一致
if ("1".equals(contract.getPaymentDirection())) {
payload.put("c_currentBudget", contract.getIsYearBudget() == null ? "0" : String.valueOf(contract.getIsYearBudget()));
payload.put("c_currentBudget", contract.getIsYearBudget() == null ? "0" : contract.getIsYearBudget());
}
payload.put("c_major", contract.getIsMajorContract() == null ? "0" : String.valueOf(contract.getIsMajorContract()));
payload.put("c_major", contract.getIsMajorContract() == null ? "0" : contract.getIsMajorContract());
payload.put("c_signMethod", contract.getSealType());
// payload.put("c_authAttachs", buildCollectionFilePayloadList(contract, ContractLaunchConstants.FILE_CATEGORY_AUTH));
payload.put("c_creator", contract.getInitiator());
@@ -1784,6 +2021,10 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
*/
private void applyLawWatermarkFile(ContractLaunchDto contract, ContractLaunchLawCallbackFileDto watermarkFile) {
if (watermarkFile == null || watermarkFile.getFilePath() == null || watermarkFile.getFilePath().isBlank()) {
contract.setContractTextFileName(null);
contract.setContractTextFilePath(null);
contract.setContractTextFileType(null);
contract.setContractTextFileSize(null);
return;
}
contract.setContractTextFileName(trim(watermarkFile.getFileName()));
@@ -1908,7 +2149,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
log.info("签章文件为外部URL,先通过签章API获取新下载地址: {}", filePath);
String token = sealTokenService.getAccessToken();
// 通过签章API获取服务端可用的下载URL
String freshUrl = fetchSealDownloadUrl(sealDto.getSealContractId(), token, filePath);
String freshUrl = fetchSealDownloadUrl(sealDto.getSealContractId(), token);
log.info("获取到签章下载地址: {}", freshUrl);
String localPath = localFileService.downloadFromUrl(freshUrl, token);
log.info("签章文件已下载到本地: {}", localPath);
@@ -1920,8 +2161,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
/**
* 通过签章平台API获取下载URL服务端IP绑定的新URL
*/
private String fetchSealDownloadUrl(String sealContractId, String token, String fallbackUrl) {
try {
private String fetchSealDownloadUrl(String sealContractId, String token) {
String apiUrl = sealConfig.getBaseUrl() + "/saas/api/contract/download";
JSONObject body = new JSONObject();
body.put("contractId", sealContractId);
@@ -1937,13 +2177,8 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
} else if (dataObj instanceof String && !((String) dataObj).isBlank()) {
return (String) dataObj;
}
} else {
log.warn("签章平台下载API返回失败: {}", response);
}
} catch (Exception e) {
log.warn("通过签章API获取下载URL失败,使用原始URL: {}", e.getMessage());
}
return fallbackUrl;
throw new ServiceException("签章平台下载接口返回失败,无法获取签署文件下载地址");
}
private boolean isExternalUrl(String path) {
@@ -2172,10 +2407,34 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
return null;
}
private String trim(String value) {
@Override
protected String trim(String value) {
return value == null ? null : value.trim();
}
private String buildCounterpartyConfirmKey(ContractLaunchPartyDto party) {
if (party == null || party.getId() == null) {
return "";
}
return "party_" + party.getId();
}
private Map<String, Object> buildCounterpartyConfirmViewItem(ContractLaunchPartyDto party, Map<String, Object> allConfirmMap) {
Map<String, Object> item = new LinkedHashMap<>();
item.put("partyId", party.getId());
item.put("partnerId", party.getPartnerId());
item.put("companyName", party.getCompanyName());
item.put("subjectCode", party.getSubjectCode());
item.put("oppositeId", party.getOppositeId());
Object state = allConfirmMap.get(buildCounterpartyConfirmKey(party));
if (state instanceof Map<?, ?> stateMap) {
item.putAll((Map<? extends String, ?>) stateMap);
} else {
item.put("confirmed", false);
}
return item;
}
private void applyQueryScope(ContractLaunchQueryDto queryDto, SysUserEntity currentUser) {
ContractLaunchQueryDto scopeQuery = buildScopeQuery(currentUser);
queryDto.setQueryScope(scopeQuery.getQueryScope());
@@ -2190,7 +2449,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
queryDto.setCurrentUserId(currentUser == null ? null : currentUser.getUsername());
queryDto.setCurrentOrgId(currentUser == null || currentUser.getSysOrgEntity() == null
? null
: currentUser.getSysOrgEntity().getId());
: orgIdAsString(currentUser));
queryDto.setCurrentDeptName(currentUser == null
? null
: (currentUser.getDeptName() == null || currentUser.getDeptName().isBlank()
@@ -2223,4 +2482,44 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
}
return null;
}
@Override
protected ContractLaunchMapper contractLaunchMapper() {
return contractLaunchMapper;
}
@Override
protected AdminSecurityManage adminSecurityManage() {
return adminSecurityManage;
}
@Override
protected AuthManager authManager() {
return authManager;
}
@Override
protected SecurityManager securityManager() {
return securityManager;
}
@Override
protected LocalFileService localFileService() {
return localFileService;
}
@Override
protected SealTokenService sealTokenService() {
return sealTokenService;
}
@Override
protected SealConfig sealConfig() {
return sealConfig;
}
@Override
protected PartnerManageService partnerManageService() {
return partnerManageService;
}
}
@@ -0,0 +1,41 @@
package com.nbport.zgwl.fiance.contractlaunch.service;
import java.util.ArrayList;
import java.util.List;
/**
* 签章平台预览结果。
*
* 不用 record,保持和项目现有 Java 风格更一致,
* 同时保留 record 风格的 accessor 命名,方便 ServiceImpl 直接调用。
*/
public class SealPreviewData {
private final String contractId;
private final Integer imageWidth;
private final Integer imageHeight;
private final List<String> pdfToImageList;
public SealPreviewData(String contractId, Integer imageWidth, Integer imageHeight, List<String> pdfToImageList) {
this.contractId = contractId;
this.imageWidth = imageWidth;
this.imageHeight = imageHeight;
this.pdfToImageList = pdfToImageList == null ? new ArrayList<>() : new ArrayList<>(pdfToImageList);
}
public String contractId() {
return contractId;
}
public Integer imageWidth() {
return imageWidth;
}
public Integer imageHeight() {
return imageHeight;
}
public List<String> pdfToImageList() {
return new ArrayList<>(pdfToImageList);
}
}
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.utils;
package com.nbport.zgwl.fiance.contractlaunch.utils;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.utils;
package com.nbport.zgwl.fiance.contractlaunch.utils;
/**
* 合同发起模块常量
@@ -63,11 +63,24 @@ public final class ContractLaunchConstants {
public static final String ACTION_SEAL_CALLBACK = "seal_callback";
/** 线下签署文件上传 */
public static final String ACTION_SEAL_UPLOAD = "seal_upload";
/** 签章平台二维码生成(等待扫码确认) */
public static final String ACTION_SEAL_QRCODE = "seal_qrcode";
public static final String ACTION_SEAL_POSITION_CONFIG = "seal_position_config";
public static final String ACTION_SEAL_POSITION_STATUS = "seal_position_status";
public static final String ACTION_STATUS_SUCCESS = "success";
public static final String ACTION_STATUS_FAILED = "failed";
public static final String ACTION_STATUS_PENDING = "pending";
public static final String FLAG_YES = "Y";
public static final String FLAG_NO = "N";
public static final int SEAL_POS_STATUS_EMPTY = 0;
public static final int SEAL_POS_STATUS_SELECTED = 1;
public static final int SEAL_POS_STATUS_SIGNING = 2;
public static final int SEAL_POS_STATUS_SIGNED = 3;
public static final int SEAL_POS_STATUS_FAILED = 4;
public static final String IS_DELETED_NO = "N";
public static final String IS_DELETED_YES = "Y";
}
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlaunch.utils;
package com.nbport.zgwl.fiance.contractlaunch.utils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
@@ -1,10 +1,10 @@
package com.nbport.zgwl.contractlog.controller;
package com.nbport.zgwl.fiance.contractlog.controller;
import com.nbport.zgwl.common.PageResult;
import com.nbport.zgwl.common.R;
import com.nbport.zgwl.contractlog.dto.ContractLogDto;
import com.nbport.zgwl.contractlog.dto.ContractLogQueryDto;
import com.nbport.zgwl.contractlog.service.ContractLogService;
import com.nbport.zgwl.fiance.common.PageResult;
import com.nbport.zgwl.fiance.common.R;
import com.nbport.zgwl.fiance.contractlog.dto.ContractLogDto;
import com.nbport.zgwl.fiance.contractlog.dto.ContractLogQueryDto;
import com.nbport.zgwl.fiance.contractlog.service.ContractLogService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractlog.dto;
package com.nbport.zgwl.fiance.contractlog.dto;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
@@ -1,6 +1,6 @@
package com.nbport.zgwl.contractlog.dto;
package com.nbport.zgwl.fiance.contractlog.dto;
import com.nbport.zgwl.dto.BasePageDto;
import com.nbport.zgwl.fiance.dto.BasePageDto;
import lombok.Data;
import java.io.Serial;
@@ -1,9 +1,9 @@
package com.nbport.zgwl.contractlog.mapper;
package com.nbport.zgwl.fiance.contractlog.mapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nbport.zgwl.contractlog.dto.ContractLogDto;
import com.nbport.zgwl.contractlog.dto.ContractLogQueryDto;
import com.nbport.zgwl.fiance.contractlog.dto.ContractLogDto;
import com.nbport.zgwl.fiance.contractlog.dto.ContractLogQueryDto;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -1,8 +1,8 @@
package com.nbport.zgwl.contractlog.service;
package com.nbport.zgwl.fiance.contractlog.service;
import com.nbport.zgwl.common.PageResult;
import com.nbport.zgwl.contractlog.dto.ContractLogDto;
import com.nbport.zgwl.contractlog.dto.ContractLogQueryDto;
import com.nbport.zgwl.fiance.common.PageResult;
import com.nbport.zgwl.fiance.contractlog.dto.ContractLogDto;
import com.nbport.zgwl.fiance.contractlog.dto.ContractLogQueryDto;
import java.util.List;
@@ -1,13 +1,13 @@
package com.nbport.zgwl.contractlog.service;
package com.nbport.zgwl.fiance.contractlog.service;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nbport.zgwl.common.PageResult;
import com.nbport.zgwl.contractlaunch.utils.ContractLaunchConstants;
import com.nbport.zgwl.contractlog.dto.ContractLogDto;
import com.nbport.zgwl.contractlog.dto.ContractLogQueryDto;
import com.nbport.zgwl.contractlog.mapper.ContractLogMapper;
import com.nbport.zgwl.fiance.common.PageResult;
import com.nbport.zgwl.fiance.contractlaunch.utils.ContractLaunchConstants;
import com.nbport.zgwl.fiance.contractlog.dto.ContractLogDto;
import com.nbport.zgwl.fiance.contractlog.dto.ContractLogQueryDto;
import com.nbport.zgwl.fiance.contractlog.mapper.ContractLogMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractpush.config;
package com.nbport.zgwl.fiance.contractpush.config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractpush.config;
package com.nbport.zgwl.fiance.contractpush.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -1,11 +1,11 @@
package com.nbport.zgwl.contractpush.controller;
package com.nbport.zgwl.fiance.contractpush.controller;
import com.nbport.zgwl.common.R;
import com.nbport.zgwl.contractpush.dto.ApproveQueryRequestDTO;
import com.nbport.zgwl.contractpush.dto.ApproveViewUrlRequestDTO;
import com.nbport.zgwl.contractpush.dto.PushPayloadDTO;
import com.nbport.zgwl.contractpush.dto.PushTokenRequestDTO;
import com.nbport.zgwl.contractpush.service.DataCollectionPushService;
import com.nbport.zgwl.fiance.common.R;
import com.nbport.zgwl.fiance.contractpush.dto.ApproveQueryRequestDTO;
import com.nbport.zgwl.fiance.contractpush.dto.ApproveViewUrlRequestDTO;
import com.nbport.zgwl.fiance.contractpush.dto.PushPayloadDTO;
import com.nbport.zgwl.fiance.contractpush.dto.PushTokenRequestDTO;
import com.nbport.zgwl.fiance.contractpush.service.DataCollectionPushService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -1,11 +1,11 @@
package com.nbport.zgwl.contractpush.controller;
package com.nbport.zgwl.fiance.contractpush.controller;
import com.nbport.zgwl.common.R;
import com.nbport.zgwl.contractpush.dto.ApproveQueryRequestDTO;
import com.nbport.zgwl.contractpush.dto.ApproveViewUrlRequestDTO;
import com.nbport.zgwl.contractpush.dto.PushPayloadDTO;
import com.nbport.zgwl.contractpush.dto.PushTokenRequestDTO;
import com.nbport.zgwl.contractpush.service.SettlementPushService;
import com.nbport.zgwl.fiance.common.R;
import com.nbport.zgwl.fiance.contractpush.dto.ApproveQueryRequestDTO;
import com.nbport.zgwl.fiance.contractpush.dto.ApproveViewUrlRequestDTO;
import com.nbport.zgwl.fiance.contractpush.dto.PushPayloadDTO;
import com.nbport.zgwl.fiance.contractpush.dto.PushTokenRequestDTO;
import com.nbport.zgwl.fiance.contractpush.service.SettlementPushService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractpush.dto;
package com.nbport.zgwl.fiance.contractpush.dto;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractpush.dto;
package com.nbport.zgwl.fiance.contractpush.dto;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractpush.dto;
package com.nbport.zgwl.fiance.contractpush.dto;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.contractpush.dto;
package com.nbport.zgwl.fiance.contractpush.dto;
import lombok.Data;
@@ -1,7 +1,7 @@
package com.nbport.zgwl.contractpush.handler;
package com.nbport.zgwl.fiance.contractpush.handler;
import cn.hutool.core.util.StrUtil;
import com.nbport.zgwl.exception.ServiceException;
import com.nbport.zgwl.fiance.exception.ServiceException;
import org.springframework.stereotype.Component;
import java.util.LinkedHashMap;
@@ -1,15 +1,15 @@
package com.nbport.zgwl.contractpush.service;
package com.nbport.zgwl.fiance.contractpush.service;
import cn.hutool.core.util.StrUtil;
import com.nbport.zgwl.contractpush.config.ContractPushProperties;
import com.nbport.zgwl.contractpush.dto.ApproveQueryRequestDTO;
import com.nbport.zgwl.contractpush.dto.ApproveViewUrlRequestDTO;
import com.nbport.zgwl.contractpush.dto.PushPayloadDTO;
import com.nbport.zgwl.contractpush.dto.PushTokenRequestDTO;
import com.nbport.zgwl.contractpush.handler.ContractPushRequestHandler;
import com.nbport.zgwl.contractpush.utils.ContractPushHttpUtils;
import com.nbport.zgwl.contractpush.utils.ContractPushUrlUtils;
import com.nbport.zgwl.exception.ServiceException;
import com.nbport.zgwl.fiance.contractpush.config.ContractPushProperties;
import com.nbport.zgwl.fiance.contractpush.dto.ApproveQueryRequestDTO;
import com.nbport.zgwl.fiance.contractpush.dto.ApproveViewUrlRequestDTO;
import com.nbport.zgwl.fiance.contractpush.dto.PushPayloadDTO;
import com.nbport.zgwl.fiance.contractpush.dto.PushTokenRequestDTO;
import com.nbport.zgwl.fiance.contractpush.handler.ContractPushRequestHandler;
import com.nbport.zgwl.fiance.contractpush.utils.ContractPushHttpUtils;
import com.nbport.zgwl.fiance.contractpush.utils.ContractPushUrlUtils;
import com.nbport.zgwl.fiance.exception.ServiceException;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@@ -1,17 +1,19 @@
package com.nbport.zgwl.contractpush.service;
package com.nbport.zgwl.fiance.contractpush.service;
import cn.hutool.core.util.StrUtil;
import com.nbport.zgwl.contractpush.config.ContractPushProperties;
import com.nbport.zgwl.contractpush.dto.ApproveQueryRequestDTO;
import com.nbport.zgwl.contractpush.dto.ApproveViewUrlRequestDTO;
import com.nbport.zgwl.contractpush.dto.PushPayloadDTO;
import com.nbport.zgwl.contractpush.dto.PushTokenRequestDTO;
import com.nbport.zgwl.contractpush.handler.ContractPushRequestHandler;
import com.nbport.zgwl.contractpush.utils.ContractPushHttpUtils;
import com.nbport.zgwl.contractpush.utils.ContractPushUrlUtils;
import com.nbport.zgwl.exception.ServiceException;
import com.nbport.zgwl.fiance.contractpush.config.ContractPushProperties;
import com.nbport.zgwl.fiance.contractpush.dto.ApproveQueryRequestDTO;
import com.nbport.zgwl.fiance.contractpush.dto.ApproveViewUrlRequestDTO;
import com.nbport.zgwl.fiance.contractpush.dto.PushPayloadDTO;
import com.nbport.zgwl.fiance.contractpush.dto.PushTokenRequestDTO;
import com.nbport.zgwl.fiance.contractpush.handler.ContractPushRequestHandler;
import com.nbport.zgwl.fiance.contractpush.utils.ContractPushHttpUtils;
import com.nbport.zgwl.fiance.contractpush.utils.ContractPushUrlUtils;
import com.nbport.zgwl.fiance.exception.ServiceException;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -26,6 +28,9 @@ public class SettlementPushService {
private final ContractPushHttpUtils httpUtils;
private final ContractPushRequestHandler requestHandler;
private volatile String cachedToken;
private volatile long tokenExpireTime;
public SettlementPushService(ContractPushProperties properties,
ContractPushHttpUtils httpUtils,
ContractPushRequestHandler requestHandler) {
@@ -91,19 +96,48 @@ public class SettlementPushService {
return result;
}
/** 获取结算平台 token,优先用入参,没有则自动调用 getToken 接口获取 */
/** 获取结算平台 token,优先用入参,没有则使用缓存或自动调用 getToken 接口获取 */
private String resolveSettlementToken(String inputToken) {
if (StrUtil.isNotBlank(inputToken)) {
return inputToken;
}
if (cachedToken != null && System.currentTimeMillis() < tokenExpireTime) {
return cachedToken;
}
Map<String, Object> tokenResult = getToken(new PushTokenRequestDTO());
Object data = tokenResult.get("data");
if (data instanceof Map) {
Object accessToken = ((Map<?, ?>) data).get("access_token");
if (accessToken != null) {
return String.valueOf(accessToken);
String token = String.valueOf(accessToken);
cachedToken = token;
tokenExpireTime = parseJwtExp(token);
return token;
}
}
throw new ServiceException("获取结算平台 token 失败");
}
/** 从 JWT token 中解析 exp 作为过期时间,解析失败则兜底 50 分钟 */
private long parseJwtExp(String token) {
long defaultTtl = 50 * 60 * 1000L;
try {
String[] parts = token.split("\\.");
if (parts.length < 2) return System.currentTimeMillis() + defaultTtl;
byte[] decoded = Base64.getUrlDecoder().decode(parts[1]);
String json = new String(decoded, StandardCharsets.UTF_8);
int expIdx = json.indexOf("\"exp\"");
if (expIdx < 0) return System.currentTimeMillis() + defaultTtl;
int colonIdx = json.indexOf(':', expIdx);
int commaIdx = json.indexOf(',', colonIdx);
int braceIdx = json.indexOf('}', colonIdx);
int end = commaIdx > 0 && commaIdx < braceIdx ? commaIdx : braceIdx;
long exp = Long.parseLong(json.substring(colonIdx + 1, end).trim());
return exp * 1000 - 60_000;
} catch (Exception e) {
return System.currentTimeMillis() + defaultTtl;
}
}
}
@@ -1,8 +1,8 @@
package com.nbport.zgwl.contractpush.utils;
package com.nbport.zgwl.fiance.contractpush.utils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.nbport.zgwl.exception.ServiceException;
import com.nbport.zgwl.fiance.exception.ServiceException;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
@@ -1,7 +1,7 @@
package com.nbport.zgwl.contractpush.utils;
package com.nbport.zgwl.fiance.contractpush.utils;
import cn.hutool.core.util.StrUtil;
import com.nbport.zgwl.exception.ServiceException;
import com.nbport.zgwl.fiance.exception.ServiceException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
@@ -0,0 +1,126 @@
package com.nbport.zgwl.fiance.controller;
import com.nbport.zgwl.fiance.common.R;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/admin/dict")
public class AdminDictController {
private static final String TEMPLATE_FIELD_DICT_TYPE = "CONTRACT_TEMPLATE_FIELDS";
private static final String TEMPLATE_DICT_TYPES = "TEMPLATE_DICT_TYPES";
@PostMapping("/getDictDataByType")
public R<List<DictDataItem>> getDictDataByType(@RequestBody(required = false) Map<String, Object> body) {
String dictType = resolveDictType(body);
if (dictType == null || dictType.isBlank()) {
return R.success(List.<DictDataItem>of());
}
return R.success(switch (dictType) {
case TEMPLATE_FIELD_DICT_TYPE -> buildTemplateFieldItems();
case TEMPLATE_DICT_TYPES -> buildTemplateDictTypeItems();
case "orgBusType" -> buildOrgBusTypeItems();
case "contractPayMethod" -> buildContractPayMethodItems();
case "sealScopeType" -> buildSealScopeTypeItems();
case "partnerLevel" -> buildPartnerLevelItems();
default -> List.<DictDataItem>of();
});
}
private String resolveDictType(Map<String, Object> body) {
if (body == null) {
return null;
}
Object params = body.get("params");
if (params instanceof Map<?, ?> paramMap) {
Object dictType = paramMap.get("dictType");
return dictType == null ? null : String.valueOf(dictType).trim();
}
Object dictType = body.get("dictType");
return dictType == null ? null : String.valueOf(dictType).trim();
}
private List<DictDataItem> buildTemplateDictTypeItems() {
return List.of(
new DictDataItem("业务类型(orgBusType", "orgBusType", "模板下拉框可选的字典类型"),
new DictDataItem("付款方式(contractPayMethod", "contractPayMethod", "模板下拉框可选的字典类型"),
new DictDataItem("签章范围(sealScopeType", "sealScopeType", "模板下拉框可选的字典类型"),
new DictDataItem("相对方级别(partnerLevel", "partnerLevel", "模板下拉框可选的字典类型")
);
}
private List<DictDataItem> buildTemplateFieldItems() {
return List.of(
new DictDataItem("合同名称", "contractName", "合同正文中的合同名称"),
new DictDataItem("合同编码", "contractCode", "合同正文中的合同编码"),
new DictDataItem("合同类型", "contractType", "合同正文中的合同类型"),
new DictDataItem("合同金额", "contractAmountDisplay", "用于展示金额文本"),
new DictDataItem("有效期起", "effectiveStart", "合同有效期起始日期"),
new DictDataItem("有效期止", "effectiveEnd", "合同有效期结束日期"),
new DictDataItem("有效期区间", "effectivePeriod", "合同有效期区间文本"),
new DictDataItem("付款方式", "paymentMethod", "合同中的付款方式说明"),
new DictDataItem("合同标的说明", "primaryContent", "合同主要内容或标的说明"),
new DictDataItem("业务备注", "amountExplain", "可用于维护金额说明或业务备注"),
new DictDataItem("甲方名称", "partyAName", "模板变量值,由用户自行维护"),
new DictDataItem("乙方名称", "partyBName", "模板变量值,由用户自行维护"),
new DictDataItem("丙方名称", "partyCName", "模板变量值,由用户自行维护"),
new DictDataItem("合同方摘要", "counterpartySummary", "模板变量值,由用户自行维护"),
new DictDataItem("附件情况", "attachmentSummary", "模板变量值,由用户自行维护"),
new DictDataItem("模板名称", "templateLabel", "模板变量值,由用户自行维护"),
new DictDataItem("签署日期", "signDate", "模板变量值,由用户自行维护"),
new DictDataItem("甲方税号", "partyATaxNo", "模板变量值,由用户自行维护"),
new DictDataItem("乙方税号", "partyBTaxNo", "模板变量值,由用户自行维护"),
new DictDataItem("附件一内容", "attachmentContent1", "建议配成富文本,且占位符单独成段"),
new DictDataItem("附件二内容", "attachmentContent2", "建议配成富文本,且占位符单独成段"),
new DictDataItem("业务类型", "orgBusType", "建议配成下拉,字典类型可填 orgBusType")
);
}
private List<DictDataItem> buildOrgBusTypeItems() {
return List.of(
new DictDataItem("海铁联运", "SEA_RAIL", "测试字典:海铁联运"),
new DictDataItem("仓储服务", "WAREHOUSE", "测试字典:仓储服务"),
new DictDataItem("港内运输", "PORT_TRANSPORT", "测试字典:港内运输")
);
}
private List<DictDataItem> buildContractPayMethodItems() {
return List.of(
new DictDataItem("银行转账", "BANK_TRANSFER", "测试字典:付款方式"),
new DictDataItem("电汇", "WIRE_TRANSFER", "测试字典:付款方式"),
new DictDataItem("承兑汇票", "ACCEPTANCE_BILL", "测试字典:付款方式")
);
}
private List<DictDataItem> buildSealScopeTypeItems() {
return List.of(
new DictDataItem("仅我方盖章", "OUR_ONLY", "测试字典:签章范围"),
new DictDataItem("双方盖章", "BOTH_PARTIES", "测试字典:签章范围"),
new DictDataItem("多方盖章", "MULTI_PARTY", "测试字典:签章范围")
);
}
private List<DictDataItem> buildPartnerLevelItems() {
return List.of(
new DictDataItem("核心客户", "CORE", "测试字典:相对方级别"),
new DictDataItem("普通客户", "NORMAL", "测试字典:相对方级别"),
new DictDataItem("外部合作方", "OUTSIDE", "测试字典:相对方级别")
);
}
@Data
@AllArgsConstructor
private static class DictDataItem {
private String k;
private String v;
private String remark;
}
}
@@ -1,6 +1,6 @@
package com.nbport.zgwl.controller;
package com.nbport.zgwl.fiance.controller;
import com.nbport.zgwl.common.R;
import com.nbport.zgwl.fiance.common.R;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -1,8 +1,8 @@
package com.nbport.zgwl.controller;
package com.nbport.zgwl.fiance.controller;
import com.nbport.zgwl.common.R;
import com.nbport.zgwl.exception.ServiceException;
import com.nbport.zgwl.service.LocalFileService;
import com.nbport.zgwl.fiance.common.R;
import com.nbport.zgwl.fiance.exception.ServiceException;
import com.nbport.zgwl.fiance.service.LocalFileService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
@@ -0,0 +1,37 @@
package com.nbport.zgwl.fiance.controller;
import com.nbport.zgwl.fiance.common.R;
import com.nbport.zgwl.fiance.utils.AdminSecurityManage;
import com.nbport.zgwl.fiance.utils.MockSecurityUserRegistry;
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;
/**
* 本地测试用的 mock 用户切换辅助接口。
*
* 仅返回用户列表和当前用户摘要,
* 真正的切换仍由前端通过请求头 X-Mock-User 控制,
* 这样不会引入新的登录态或会话依赖。
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/mock/security")
public class MockUserSwitchController {
private final AdminSecurityManage adminSecurityManage;
private final MockSecurityUserRegistry mockSecurityUserRegistry;
@GetMapping("/users")
public R<List<MockSecurityUserRegistry.MockUserOptionDto>> listUsers() {
return R.success(mockSecurityUserRegistry.listUserOptions());
}
@GetMapping("/current")
public R<MockSecurityUserRegistry.MockCurrentUserDto> getCurrentUser() {
return R.success(mockSecurityUserRegistry.buildCurrentUserDto(adminSecurityManage.resolveMockUserKey()));
}
}
@@ -1,13 +1,13 @@
package com.nbport.zgwl.controller;
package com.nbport.zgwl.fiance.controller;
import com.nbport.zgwl.common.PageResult;
import com.nbport.zgwl.common.R;
import com.nbport.zgwl.dto.StudentQueryDto;
import com.nbport.zgwl.dto.StudentSaveDto;
import com.nbport.zgwl.entity.StudentEntity;
import com.nbport.zgwl.entity.SysUserEntity;
import com.nbport.zgwl.service.StudentService;
import com.nbport.zgwl.utils.MockSecurityManager;
import com.nbport.zgwl.fiance.common.PageResult;
import com.nbport.zgwl.fiance.common.R;
import com.nbport.zgwl.fiance.dto.StudentQueryDto;
import com.nbport.zgwl.fiance.dto.StudentSaveDto;
import com.nbport.zgwl.fiance.entity.StudentEntity;
import com.nbport.zgwl.fiance.entity.SysUserEntity;
import com.nbport.zgwl.fiance.service.StudentService;
import com.nbport.zgwl.fiance.utils.MockSecurityManager;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.dto;
package com.nbport.zgwl.fiance.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.dto;
package com.nbport.zgwl.fiance.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.dto;
package com.nbport.zgwl.fiance.dto;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.entity;
package com.nbport.zgwl.fiance.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.entity;
package com.nbport.zgwl.fiance.entity;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.entity;
package com.nbport.zgwl.fiance.entity;
import lombok.Data;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.entity;
package com.nbport.zgwl.fiance.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.exception;
package com.nbport.zgwl.fiance.exception;
public interface ServiceErrorCodeRange {
@@ -1,4 +1,4 @@
package com.nbport.zgwl.exception;
package com.nbport.zgwl.fiance.exception;
import lombok.Getter;
@@ -1,8 +1,8 @@
package com.nbport.zgwl.handler;
package com.nbport.zgwl.fiance.handler;
import com.nbport.zgwl.common.GlobalErrorCodeConstants;
import com.nbport.zgwl.common.R;
import com.nbport.zgwl.exception.ServiceException;
import com.nbport.zgwl.fiance.common.GlobalErrorCodeConstants;
import com.nbport.zgwl.fiance.common.R;
import com.nbport.zgwl.fiance.exception.ServiceException;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.handler;
package com.nbport.zgwl.fiance.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
@@ -1,13 +1,14 @@
package com.nbport.zgwl.manifest.controller;
package com.nbport.zgwl.fiance.manifest.controller;
import com.nbport.zgwl.common.PageResult;
import com.nbport.zgwl.common.R;
import com.nbport.zgwl.manifest.dto.ContractTemplateDto;
import com.nbport.zgwl.manifest.dto.ContractTemplateQueryDto;
import com.nbport.zgwl.manifest.dto.TemplateOrgOptionDto;
import com.nbport.zgwl.manifest.service.ContractTemplateService;
import com.nbport.zgwl.manifest.utils.ManifestManageConstants;
import com.nbport.zgwl.fiance.common.PageResult;
import com.nbport.zgwl.fiance.common.R;
import com.nbport.zgwl.fiance.manifest.dto.ContractTemplateDto;
import com.nbport.zgwl.fiance.manifest.dto.ContractTemplateQueryDto;
import com.nbport.zgwl.fiance.manifest.dto.TemplateOrgOptionDto;
import com.nbport.zgwl.fiance.manifest.service.ContractTemplateService;
import com.nbport.zgwl.fiance.manifest.utils.ManifestManageConstants;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@@ -71,4 +72,10 @@ public class ContractTemplateController {
public R<ContractTemplateDto> changeStatus(@PathVariable("id") Long id, @PathVariable("status") String status) {
return R.success(contractTemplateService.changeTemplateStatus(id, status));
}
@DeleteMapping("/{id}")
public R<Void> delete(@PathVariable("id") Long id) {
contractTemplateService.deleteTemplate(id);
return R.success();
}
}
@@ -1,4 +1,4 @@
package com.nbport.zgwl.manifest.domain;
package com.nbport.zgwl.fiance.manifest.domain;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -1,4 +1,4 @@
package com.nbport.zgwl.manifest.dto;
package com.nbport.zgwl.fiance.manifest.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
@@ -1,6 +1,6 @@
package com.nbport.zgwl.manifest.dto;
package com.nbport.zgwl.fiance.manifest.dto;
import com.nbport.zgwl.dto.BasePageDto;
import com.nbport.zgwl.fiance.dto.BasePageDto;
import lombok.Data;
import lombok.EqualsAndHashCode;

Some files were not shown because too many files have changed in this diff Show More