增加印章同步功能

This commit is contained in:
2025-08-13 20:09:14 +08:00
parent f066ff218d
commit c74acbf6aa
10 changed files with 643 additions and 102 deletions

View File

@@ -1,7 +1,6 @@
package com.seeyon.apps.esign.constants;
public class EsignApiUrl {
public static final String QUERY_SEAL_URL = "/v3/seals/org-own-seal-list";
public static final String SEAL_GRANT_URL = "/v3/seals/org-seals/internal-auth";
public static final String SIGN_START_URL = "/v3/sign-flow/{signFlowId}/start";
public static final String SIGN_BY_FILE_URL = "/v3/sign-flow/create-by-file";
@@ -14,4 +13,5 @@ public class EsignApiUrl {
public static final String QUERY_ORGINFO = "/v3/organizations/identity-info";
public static final String CONTRACT_COMPARE_GETURL = "/v3/contract-compare-url";
public static final String TOKEN_GET_URL = "/v1/oauth2/access_token";
public static final String SEAL_QUERY_URL = "/v3/seals/org-own-seal-list";
}

View File

@@ -14,6 +14,10 @@ public enum EsignConfigConstants {
nodeTokenUrl("/seeyon/rest/flow/notification/","超级节点回调URL"),
restName("",""),
restPwd("",""),
signAutoDate("","是否自动加盖签署日期"),
eSignOrgId("61f735dd368c45a191f43a6711c3c88a","e签宝平台方组织id"),
formLoginName("2019","表单数据录入登录名"),
sealInfoFormCode("","印章档案编码"),
;
private String defaultValue;

View File

@@ -83,7 +83,36 @@ public class FormDataOperator {
}
}
public FormColumn queryOneRowFormData(String formNo, List<String> queryColumnVos, List<FormWhereCondition> conditionVos) throws BusinessException {
public void deleteByCondition(String formNo, List<FormWhereCondition> conditionVos) throws Exception {
FormApi4Cap4 formApi4Cap4 = (FormApi4Cap4) AppContext.getBean("formApi4Cap4");
FormBean cap4FormBean = formApi4Cap4.getFormByFormCode(formNo);
List<String> queryColumns = new ArrayList<>();
FormTableBean masterTableBean = cap4FormBean.getMasterTableBean();
String tableName = masterTableBean.getTableName();
Map<String, FormFieldBean> fieldMap4Name = masterTableBean.getFieldMap4Name();
for (FormWhereCondition conditionVo : conditionVos) {
FormFieldBean fieldBeanByDisplay = masterTableBean.getFieldBeanByDisplay(conditionVo.getDisplay());
if (fieldBeanByDisplay == null) {
if (conditionVo.getDisplay().equals("ID") || conditionVo.getDisplay().equals("id")) {
conditionVo.setFieldName(conditionVo.getDisplay());
}
continue;
}
conditionVo.setFieldName(fieldBeanByDisplay.getColumnName());
}
Map<String, Object> generateSql = generateDelSql(conditionVos, tableName);
String sql = (String) generateSql.get("sql");
List<Object> params = (List<Object>) generateSql.get("params");
JDBCAgent jdbcAgent = new JDBCAgent();
try {
jdbcAgent.execute(sql, params);
} finally {
jdbcAgent.close();
}
}
public FormColumn queryOneRowFormData(String formNo, List<String> queryColumnVos, List<FormWhereCondition> conditionVos) throws Exception {
FormApi4Cap4 formApi4Cap4 = (FormApi4Cap4) AppContext.getBean("formApi4Cap4");
FormBean cap4FormBean = formApi4Cap4.getFormByFormCode(formNo);
List<String> queryColumns = new ArrayList<>();
@@ -138,13 +167,10 @@ public class FormDataOperator {
}
columns.add(column);
}
return columns.get(0);
} catch (Exception e) {
System.out.println(e.getMessage());
return columns.size() > 0 ? columns.get(0) : null;
} finally {
jdbcAgent.close();
}
return null;
}
public List<FormColumn> queryFormDataCondition(String formNo, List<String> queryColumnVos, List<FormWhereCondition> conditionVos) throws BusinessException {
@@ -256,6 +282,20 @@ public class FormDataOperator {
return result;
}
private Map<String, Object> generateDelSql(List<FormWhereCondition> conditions, String tableName) {
if (tableName == null) {
throw new IllegalArgumentException("tableName cannot be null or empty");
}
StringBuilder sqlBuilder = new StringBuilder("DELETE ");
sqlBuilder.append(" from " + tableName);
List<Object> params = new ArrayList<>();
sqlBuilder.append(buildWhereClause(conditions,params));
Map<String, Object> result = new HashMap<>();
result.put("sql", sqlBuilder.toString());
result.put("params", params);
return result;
}
private Map<String, Object> generateSql(List<FormUpdateField> fieldValues, String tableName,List<FormWhereCondition> conditions) {
if (fieldValues == null || fieldValues.isEmpty()) {
throw new IllegalArgumentException("Field values cannot be null or empty");

View File

@@ -0,0 +1,74 @@
package com.seeyon.apps.esign.job;
import com.seeyon.aicloud.common.JsonUtils;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignApiUrl;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.EsignApiHeader;
import com.seeyon.apps.esign.po.EsignBaseResp;
import com.seeyon.apps.esign.po.SealInfoVo;
import com.seeyon.apps.esign.service.SealService;
import com.seeyon.apps.esign.service.TokenCacheManager;
import com.seeyon.apps.esign.utils.HttpClient;
import com.seeyon.apps.ext.quartz.AbstractQuartzTask;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Component
public class SealDocSyncJob extends AbstractQuartzTask {
private static final Log log = LogFactory.getLog(SealDocSyncJob.class);
@Autowired
private EsignConfigProvider configProvider;
@Autowired
private TokenCacheManager tokenCacheManager;
@Autowired
private SealService sealService;
@Override
public String taskRun(String s) throws Exception {
log.info("开始执行印章同步任务");
syncSeals();
log.info("印章同步任务完成");
return "";
}
private void syncSeals() {
String orgId = configProvider.getBizConfigByKey(EsignConfigConstants.eSignOrgId);
String host = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST);
Integer pageNum = 1;
Integer pageSize = 20;
EsignApiHeader esignApiHeader = EsignApiHeader.build().appId(configProvider.getBizConfigByKey(EsignConfigConstants.APP_ID));
esignApiHeader.token(tokenCacheManager.getToken());
EsignBaseResp esignBaseResp = null;
Map<String,Object> dataMap = null;
do {
String url = host + EsignApiUrl.SEAL_QUERY_URL + "?" + "orgId=" + orgId + "&pageNum=" + (pageNum++) + "&pageSize=" + pageSize;
String respStr = HttpClient.httpGet(url, esignApiHeader.convert2Headers(),"UTF-8");
esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class);
if(esignBaseResp.getCode() != 0) {
break;
}
dataMap = (Map<String,Object>)esignBaseResp.getData();
Object[] sealArray = (Object[]) dataMap.get("seals");
if(sealArray == null || sealArray.length == 0) {
break;
}
for (Object o : sealArray) {
SealInfoVo sealInfoVo = JsonUtils.parseObject(JsonUtils.toJSONString(o), SealInfoVo.class);
sealService.upsertOaSealDoc(sealInfoVo);
}
}while (true);
}
@Override
public String getName() {
return "E签宝印章信息同步任务";
}
}

View File

@@ -6,7 +6,10 @@ import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.form.FormDataOperator;
import com.seeyon.apps.esign.form.FormUpdateField;
import com.seeyon.apps.esign.form.FormWhereCondition;
import com.seeyon.apps.esign.po.*;
import com.seeyon.apps.esign.po.NormalSignFieldConfig;
import com.seeyon.apps.esign.po.SignField;
import com.seeyon.apps.esign.po.SignFieldPosition;
import com.seeyon.apps.esign.po.Signer;
import com.seeyon.apps.esign.service.EsignByTemplateService;
import com.seeyon.apps.esign.service.EsignByUploadFileService;
import com.seeyon.apps.ext.workflow.vo.FormDataVo;
@@ -21,12 +24,15 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class EsignNode extends ACommonSuperNode {
public class EsignMultipleSignerNode extends ACommonSuperNode {
private static final Log log = LogFactory.getLog(EsignNode.class);
private static final Log log = LogFactory.getLog(EsignMultipleSignerNode.class);
private static final String CONTRACT_NAME_FIELD = "合同名称";
private static final String CONTRACT_ATTACHMENT_FIELD = "合同审批附件";
@@ -53,14 +59,14 @@ public class EsignNode extends ACommonSuperNode {
public SuperNodeContext proceed(String s, FormDataVo formDataVo, FormDataMasterBean formDataMasterBean) {
SuperNodeContext context = new SuperNodeContext();
context.setNeedSave(true);
log.info("进入 E签宝签署集成超级节点");
log.info("进入 E签宝多方签署集成超级节点");
try {
Map<String, Object> signParams = buildSignParams(formDataVo, formDataMasterBean, true);
if (signParams == null) throw new RuntimeException("签署参数构建失败");
String esignFlowId = templateService.createBySignTemplate(signParams);
log.info("E签宝签署流程ID: " + esignFlowId + " , OA超级节点ID" + formDataVo.getToken());
log.info("E签宝合同已发送: " + esignFlowId);
log.info("E签宝多方签署合同已发送: " + esignFlowId);
return context.wait("等待签署结束");
} catch (Exception e) {
log.error("E签宝签署失败", e);
@@ -87,8 +93,8 @@ public class EsignNode extends ACommonSuperNode {
private List<Signer> buildSigners(FormDataVo formDataVo, String fileId,boolean qifengSign) throws Exception {
List<Object> positions = uploadFileService.getSignPosition(fileId);
SignFieldPosition bPosition = extractPosition(positions, "乙方盖章/签字");
SignFieldPosition aPosition = extractPosition(positions, "甲方盖章/签字");
List<SignFieldPosition> bPositions = extractPosition(positions, "乙方盖章/签字");
List<SignFieldPosition> aPositions = extractPosition(positions, "甲方盖章/签字");
String bSignerType = formDataVo.getFieldData("乙方签署类型").getStringValue();
SignFieldPosition aQiFengposition = new SignFieldPosition();
@@ -98,27 +104,23 @@ public class EsignNode extends ACommonSuperNode {
bQiFengposition.setAcrossPageMode("ALL");
bQiFengposition.setPositionY(720f);
List<SignFieldPosition> aPos = new ArrayList<>();
aPos.add(aPosition);
aPos.add(aQiFengposition);
List<SignFieldPosition> bPos = new ArrayList<>();
bPos.add(bPosition);
bPos.add(bQiFengposition);
Signer bSigner = !"组织".equals(bSignerType) ? createPsnSigner(fileId,formDataVo.getFieldData("乙方姓名").getStringValue(),bPos,1,formDataVo.getFieldData("乙方电话").getStringValue(),false) : createOrgSigner(
aPositions.add(aQiFengposition);
bPositions.add(bQiFengposition);
String sealId = formDataVo.getFieldData("甲方印章ID").getStringValue();
Signer bSigner = !"组织".equals(bSignerType) ? createPsnSigner(fileId,formDataVo.getFieldData("乙方姓名").getStringValue(),bPositions,1,formDataVo.getFieldData("乙方电话").getStringValue(),false) : createOrgSigner(
fileId,
getStringField(formDataVo, B_UNIT_NAME_FIELD),
bPos, 1, formDataVo.getFieldData("乙方法人姓名").getStringValue(),
bPositions, 1, formDataVo.getFieldData("乙方法人姓名").getStringValue(),
formDataVo.getFieldData("乙方法人身份证号").getStringValue(),
formDataVo.getFieldData("乙方企业社会信用代码").getStringValue(),
formDataVo.getFieldData("乙方经办人手机号").getStringValue(),
formDataVo.getFieldData("乙方经办人姓名").getStringValue(),
formDataVo.getFieldData("乙方经办人身份证号").getStringValue(),false
);
,null);
Signer aSigner = createOrgSigner(
fileId,null, aPos, 2, null, null, null, null, null, null,true
);
fileId,null, aPositions, 2, null, null, null, null, null, null,true
,sealId);
List<Signer> signers = new ArrayList<>();
signers.add(bSigner);
signers.add(aSigner);
@@ -139,7 +141,6 @@ public class EsignNode extends ACommonSuperNode {
docs.add(docMap);
Map<String, Object> signFlowConfig = buildSignFlowConfig(formDataVo, formDataMasterBean);
List<Signer> signers = buildSigners(formDataVo, fileId,true);
Map<String, Object> signParams = new HashMap<>();
signParams.put("signFlowConfig", signFlowConfig);
signParams.put("signers", signers);
@@ -188,32 +189,37 @@ public class EsignNode extends ACommonSuperNode {
signer.setPsnSignerInfo(psnInfo);
}
List<SignField> signFields = new ArrayList<>();
for (SignFieldPosition po : pos) {
NormalSignFieldConfig fieldConfig = new NormalSignFieldConfig();
fieldConfig.setSignFieldPosition(pos.get(0));
if("ALL".equals(po.getAcrossPageMode())){
fieldConfig.setSignFieldPosition(po);
fieldConfig.setAutoSign(autoSign);
fieldConfig.setSignFieldStyle(2);
SignField qiFengfield = new SignField();
qiFengfield.setSignFieldType(0);
qiFengfield.setNormalSignFieldConfig(fieldConfig);
qiFengfield.setFileId(fileId);
signFields.add(qiFengfield);
}else {
fieldConfig.setSignFieldPosition(po);
fieldConfig.setAutoSign(autoSign);
fieldConfig.setSignFieldStyle(1);
SignField field = new SignField();
field.setSignFieldType(0);
field.setNormalSignFieldConfig(fieldConfig);
field.setSignDateConfig(new SignDateConfig());
field.setFileId(fileId);
signFields.add(field);
}
}
NormalSignFieldConfig qiFengfieldConfig = new NormalSignFieldConfig();
qiFengfieldConfig.setSignFieldPosition(pos.get(1));
qiFengfieldConfig.setAutoSign(autoSign);
qiFengfieldConfig.setSignFieldStyle(2);
SignField qiFengfield = new SignField();
qiFengfield.setSignFieldType(0);
qiFengfield.setNormalSignFieldConfig(qiFengfieldConfig);
qiFengfield.setFileId(fileId);
signer.setSignFields(Arrays.asList(field,qiFengfield));
signer.setSignFields(signFields);
return signer;
}
private Signer createOrgSigner(String fileId ,String orgName, List<SignFieldPosition> pos, int order,
String legalName, String legalId, String orgCode,
String transPhone, String psnName, String psnId,Boolean autoSign) {
String transPhone, String psnName, String psnId,Boolean autoSign,String sealId) {
Signer signer = new Signer();
signer.setSignerType(1);
signer.setSignConfig(mapOf("signOrder", order));
@@ -238,41 +244,54 @@ public class EsignNode extends ACommonSuperNode {
signer.setOrgSignerInfo(orgInfo);
}
List<SignField> signFields = new ArrayList<>();
for (SignFieldPosition po : pos) {
NormalSignFieldConfig fieldConfig = new NormalSignFieldConfig();
fieldConfig.setSignFieldPosition(pos.get(0));
fieldConfig.setAssignedSealId(sealId);
if("ALL".equals(po.getAcrossPageMode())){
fieldConfig.setSignFieldPosition(po);
fieldConfig.setAutoSign(autoSign);
fieldConfig.setSignFieldStyle(2);
SignField qiFengfield = new SignField();
qiFengfield.setSignFieldType(0);
qiFengfield.setNormalSignFieldConfig(fieldConfig);
qiFengfield.setFileId(fileId);
signFields.add(qiFengfield);
}else {
fieldConfig.setSignFieldPosition(po);
fieldConfig.setAutoSign(autoSign);
fieldConfig.setSignFieldStyle(1);
SignField field = new SignField();
field.setSignFieldType(0);
field.setNormalSignFieldConfig(fieldConfig);
field.setSignDateConfig(new SignDateConfig());
field.setFileId(fileId);
signFields.add(field);
}
}
NormalSignFieldConfig qiFengfieldConfig = new NormalSignFieldConfig();
qiFengfieldConfig.setSignFieldPosition(pos.get(1));
qiFengfieldConfig.setAutoSign(autoSign);
qiFengfieldConfig.setSignFieldStyle(2);
SignField qiFengfield = new SignField();
qiFengfield.setSignFieldType(0);
qiFengfield.setNormalSignFieldConfig(qiFengfieldConfig);
qiFengfield.setFileId(fileId);
signer.setSignFields(Arrays.asList(field,qiFengfield));
signer.setSignFields(signFields);
return signer;
}
private SignFieldPosition extractPosition(List<Object> positions, String keyword) {
private List<SignFieldPosition> extractPosition(List<Object> positions, String keyword) {
List<SignFieldPosition> posList = new ArrayList<>();
for (Object obj : positions) {
Map<String, Object> position = (Map<String, Object>) obj;
if (Boolean.TRUE.equals(position.get("searchResult")) && keyword.equals(position.get("keyword"))) {
Object[] posArray = (Object[]) position.get("positions");
Map<String, Object> posMap = (Map<String, Object>) posArray[0];
Map<String, Object> coord = (Map<String, Object>) ((Object[])posMap.get("coordinates"))[0];
for (Object o : posArray) {
Map<String, Object> posMap = (Map<String, Object>)o;
Object[] coords = (Object[]) posMap.get("coordinates");
for (Object coord : coords) {
Map<String,Object> tempMap = (Map<String, Object>) coord;
SignFieldPosition sfp = new SignFieldPosition();
sfp.setPositionPage(posMap.get("pageNum") + "");
sfp.setPositionX(toFloat(coord.get("positionX")) + 150f);
sfp.setPositionY(toFloat(coord.get("positionY")));
return sfp;
sfp.setPositionX(toFloat(tempMap.get("positionX")) + 150f);
sfp.setPositionY(toFloat(tempMap.get("positionY")));
posList.add(sfp);
}
}
return posList;
}
}
throw new RuntimeException("未找到关键字位置: " + keyword);
@@ -288,11 +307,11 @@ public class EsignNode extends ACommonSuperNode {
@Override
public String getNodeId() {
return "nd_20250702";
return "nd_20250703";
}
@Override
public String getNodeName() {
return "E签宝签署节点";
return "E签宝甲乙双方签署节点";
}
}

View File

@@ -0,0 +1,292 @@
package com.seeyon.apps.esign.node;
import com.seeyon.apps.common.workflow.node.ACommonSuperNode;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.form.FormDataOperator;
import com.seeyon.apps.esign.form.FormUpdateField;
import com.seeyon.apps.esign.form.FormWhereCondition;
import com.seeyon.apps.esign.po.*;
import com.seeyon.apps.esign.service.EsignByTemplateService;
import com.seeyon.apps.esign.service.EsignByUploadFileService;
import com.seeyon.apps.ext.workflow.vo.FormDataVo;
import com.seeyon.apps.ext.workflow.vo.SuperNodeContext;
import com.seeyon.cap4.form.bean.FormDataMasterBean;
import com.seeyon.cap4.form.bean.FormFieldBean;
import com.seeyon.cap4.form.service.CAP4FormManager;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.common.exceptions.BusinessException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class EsignOneSignerNode extends ACommonSuperNode {
private static final Log log = LogFactory.getLog(EsignOneSignerNode.class);
private static final String CONTRACT_NAME_FIELD = "合同名称";
private static final String CONTRACT_ATTACHMENT_FIELD = "合同审批附件";
private static final String B_UNIT_NAME_FIELD = "乙方单位名称";
private static CAP4FormManager cap4FormManager = (CAP4FormManager) AppContext.getBean("cap4FormManager");
@Autowired
private EsignConfigProvider configProvider;
@Autowired
private EsignByUploadFileService uploadFileService;
@Autowired
private EsignByTemplateService templateService;
@Override
public String getPluginId() {
return EsignConfigConstants.getPluginId();
}
@Override
public String getFormParse() {
return "";
}
@Override
public SuperNodeContext proceed(String s, FormDataVo formDataVo, FormDataMasterBean formDataMasterBean) {
SuperNodeContext context = new SuperNodeContext();
context.setNeedSave(true);
log.info("进入 E签宝单方签署集成超级节点");
try {
Map<String, Object> signParams = buildSignParams(formDataVo, formDataMasterBean, true);
if (signParams == null) throw new RuntimeException("签署参数构建失败");
String esignFlowId = templateService.createBySignTemplate(signParams);
log.info("E签宝签署流程ID: " + esignFlowId + " , OA超级节点ID" + formDataVo.getToken());
log.info("E签宝单方签署合同已发送: " + esignFlowId);
return context.wait("等待签署结束");
} catch (Exception e) {
log.error("E签宝签署失败", e);
context.setErrMsg("E签宝签署失败: " + e.getMessage());
return context.back("E签宝签署失败: " + e.getMessage());
}
}
private Map<String, Object> buildSignFlowConfig(FormDataVo formDataVo,FormDataMasterBean masterBean) throws Exception {
String contractName = getStringField(formDataVo, CONTRACT_NAME_FIELD);
if (contractName == null) throw new RuntimeException("合同名称不能为空");
String formId = formDataVo.getToken() +"_" + formDataVo.getId();
Long enumId = masterBean.getFormTable().getFieldBeanByDisplay("E签宝签署状态").getEnumId();
String signCallBackUrl = configProvider.getBizConfigByKey(EsignConfigConstants.OA_HOST) + "/seeyon/esigncallback.do?method=callback&formId=" + formId + "&tablename=" + masterBean.getFormTable().getTableName() + "&updatefield=" + masterBean.getFormTable().getFieldBeanByDisplay("盖章后合同附件").getColumnName() + "&statusfield=" + masterBean.getFormTable().getFieldBeanByDisplay("E签宝签署状态").getColumnName() + "_" + enumId;
Map<String, Object> config = new HashMap<>();
config.put("signFlowTitle", contractName);
config.put("autoFinish", true);
config.put("notifyUrl", signCallBackUrl);
Map<String, Object> noticeConfig = new HashMap<>();
noticeConfig.put("noticeTypes", "1");
config.put("noticeConfig", noticeConfig);
return config;
}
private List<Signer> buildOnlyASigner(FormDataVo formDataVo, String fileId) throws Exception {
List<Object> positions = uploadFileService.getSignPosition(fileId);
List<SignFieldPosition> aPositions = extractPosition(positions, "甲方盖章/签字");
SignFieldPosition aQiFengposition = new SignFieldPosition();
aQiFengposition.setAcrossPageMode("ALL");
aQiFengposition.setPositionY(520f);
String sealId = formDataVo.getFieldData("甲方印章ID").getStringValue();
aPositions.add(aQiFengposition);
Signer aSigner = createOrgSigner(
fileId,null, aPositions, 1, null, null, null, null, null, null,true
,sealId);
List<Signer> signers = new ArrayList<>();
signers.add(aSigner);
return signers;
}
private Map<String, Object> buildSignParams(FormDataVo formDataVo, FormDataMasterBean formDataMasterBean, boolean byFile) throws Exception {
String fileId = null;
if (byFile) {
String attachmentId = getStringField(formDataVo, CONTRACT_ATTACHMENT_FIELD);
if (attachmentId == null) throw new RuntimeException("合同附件不能为空");
fileId = uploadFileService.uploadFileToEsign(attachmentId);
}
Map<String, Object> docMap = new HashMap<>();
docMap.put("fileId", fileId);
List<Object> docs = new ArrayList<>();
docs.add(docMap);
Map<String, Object> signFlowConfig = buildSignFlowConfig(formDataVo, formDataMasterBean);
List<Signer> signers = buildOnlyASigner(formDataVo, fileId);
Map<String, Object> signParams = new HashMap<>();
signParams.put("signFlowConfig", signFlowConfig);
signParams.put("signers", signers);
signParams.put("docs", docs);
return signParams;
}
private void fillFileId(String fileId,FormDataVo formDataVo,FormDataMasterBean formDataMasterBean) throws NoSuchFieldException, BusinessException {
String tableName = formDataVo.getTableName();
FormFieldBean fieldBeanByDisplay = formDataMasterBean.getFormTable().getFieldBeanByDisplay("合同文件ID");
FormDataOperator formDataOperator = new FormDataOperator();
List<FormUpdateField> updateFields = new ArrayList<>();
updateFields.add(FormUpdateField.build().fieldName(fieldBeanByDisplay.getColumnName()).value(fileId));
List<FormWhereCondition> whereConditions = new ArrayList<>();
FormWhereCondition condition = FormWhereCondition.build().value(formDataVo.getId());
condition.setFieldName("ID");
whereConditions.add(condition);
formDataOperator.updateMasterForm(updateFields,tableName,whereConditions);
}
private Map<String, Object> mapOf(Object... keyValues) {
if (keyValues.length % 2 != 0) {
throw new IllegalArgumentException("参数个数必须为偶数key 和 value 必须成对出现");
}
Map<String, Object> map = new HashMap<>();
for (int i = 0; i < keyValues.length; i += 2) {
Object key = keyValues[i];
Object value = keyValues[i + 1];
if (!(key instanceof String)) {
throw new IllegalArgumentException("key 必须是 String 类型,当前为:" + key.getClass());
}
map.put((String) key, value);
}
return map;
}
private Signer createPsnSigner( String fileId, String psnName,List<SignFieldPosition> pos, int order, String phone,Boolean autoSign) {
Signer signer = new Signer();
signer.setSignerType(0);
signer.setSignConfig(mapOf("signOrder", order));
if(Boolean.FALSE.equals(autoSign)){
signer.setNoticeConfig(mapOf("noticeTypes", "1"));
Map<String, Object> psnInfo = mapOf("psnAccount", phone, "psnInfo", mapOf("psnName", psnName));
signer.setPsnSignerInfo(psnInfo);
}
List<SignField> signFields = new ArrayList<>();
for (SignFieldPosition po : pos) {
NormalSignFieldConfig fieldConfig = new NormalSignFieldConfig();
if("ALL".equals(po.getAcrossPageMode())){
fieldConfig.setSignFieldPosition(po);
fieldConfig.setAutoSign(autoSign);
fieldConfig.setSignFieldStyle(2);
SignField qiFengfield = new SignField();
qiFengfield.setSignFieldType(0);
qiFengfield.setNormalSignFieldConfig(fieldConfig);
qiFengfield.setFileId(fileId);
signFields.add(qiFengfield);
}else {
fieldConfig.setSignFieldPosition(po);
fieldConfig.setAutoSign(autoSign);
fieldConfig.setSignFieldStyle(1);
SignField field = new SignField();
field.setSignFieldType(0);
field.setNormalSignFieldConfig(fieldConfig);
field.setFileId(fileId);
signFields.add(field);
}
}
signer.setSignFields(signFields);
return signer;
}
private Signer createOrgSigner(String fileId ,String orgName, List<SignFieldPosition> pos, int order,
String legalName, String legalId, String orgCode,
String transPhone, String psnName, String psnId,Boolean autoSign,String sealId) {
Signer signer = new Signer();
signer.setSignerType(1);
signer.setSignConfig(mapOf("signOrder", order));
if(Boolean.FALSE.equals(autoSign)){
signer.setNoticeConfig(mapOf("noticeTypes", "1"));
Map<String, Object> orgInfo = mapOf("orgName", orgName, "orgInfo", mapOf(
"legalRepName", legalName,
"legalRepIDCardNum", legalId,
"orgIDCardNum", orgCode,
"orgIDCardType", "CRED_ORG_USCC"
),
"transactorInfo", mapOf(
"psnAccount", transPhone,
"psnInfo", mapOf(
"psnName", psnName,
"psnIDCardNum", psnId
)
)
);
signer.setOrgSignerInfo(orgInfo);
}
List<SignField> signFields = new ArrayList<>();
for (SignFieldPosition po : pos) {
NormalSignFieldConfig fieldConfig = new NormalSignFieldConfig();
fieldConfig.setAssignedSealId(sealId);
if("ALL".equals(po.getAcrossPageMode())){
fieldConfig.setSignFieldPosition(po);
fieldConfig.setAutoSign(autoSign);
fieldConfig.setSignFieldStyle(2);
SignField qiFengfield = new SignField();
qiFengfield.setSignFieldType(0);
qiFengfield.setNormalSignFieldConfig(fieldConfig);
qiFengfield.setFileId(fileId);
signFields.add(qiFengfield);
}else {
fieldConfig.setSignFieldPosition(po);
fieldConfig.setAutoSign(autoSign);
fieldConfig.setSignFieldStyle(1);
SignField field = new SignField();
field.setSignFieldType(0);
field.setNormalSignFieldConfig(fieldConfig);
field.setFileId(fileId);
signFields.add(field);
}
}
signer.setSignFields(signFields);
return signer;
}
private List<SignFieldPosition> extractPosition(List<Object> positions, String keyword) {
List<SignFieldPosition> posList = new ArrayList<>();
for (Object obj : positions) {
Map<String, Object> position = (Map<String, Object>) obj;
if (Boolean.TRUE.equals(position.get("searchResult")) && keyword.equals(position.get("keyword"))) {
Object[] posArray = (Object[]) position.get("positions");
for (Object o : posArray) {
Map<String, Object> posMap = (Map<String, Object>)o;
Object[] coords = (Object[]) posMap.get("coordinates");
for (Object coord : coords) {
Map<String,Object> tempMap = (Map<String, Object>) coord;
SignFieldPosition sfp = new SignFieldPosition();
sfp.setPositionPage(posMap.get("pageNum") + "");
sfp.setPositionX(toFloat(tempMap.get("positionX")) + 150f);
sfp.setPositionY(toFloat(tempMap.get("positionY")));
posList.add(sfp);
}
}
return posList;
}
}
throw new RuntimeException("未找到关键字位置: " + keyword);
}
private String getStringField(FormDataVo vo, String field) throws NoSuchFieldException {
return vo.getFieldData(field) != null ? vo.getFieldData(field).getStringValue() : null;
}
private Float toFloat(Object val) {
return val instanceof Number ? ((Number) val).floatValue() : Float.parseFloat(val.toString());
}
@Override
public String getNodeId() {
return "nd_20250702";
}
@Override
public String getNodeName() {
return "E签宝甲方单方签署节点";
}
}

View File

@@ -4,6 +4,7 @@ public class NormalSignFieldConfig {
private Boolean autoSign;
private Integer signFieldStyle;
private SignFieldPosition signFieldPosition;
private String assignedSealId; //指定签章id
public Boolean getAutoSign() {
return autoSign;
@@ -28,4 +29,12 @@ public class NormalSignFieldConfig {
public void setSignFieldPosition(SignFieldPosition signFieldPosition) {
this.signFieldPosition = signFieldPosition;
}
public String getAssignedSealId() {
return assignedSealId;
}
public void setAssignedSealId(String assignedSealId) {
this.assignedSealId = assignedSealId;
}
}

View File

@@ -0,0 +1,50 @@
package com.seeyon.apps.esign.po;
public class SealInfoVo {
private String sealId; //印章ID
private String sealName; //印章名称
private String sealBizTypeDescription; //印章描述
private String statusDescription; //印章状态描述
private String sealImageDownloadUrl; //印章图片下载地址
public String getSealId() {
return sealId;
}
public void setSealId(String sealId) {
this.sealId = sealId;
}
public String getSealName() {
return sealName;
}
public void setSealName(String sealName) {
this.sealName = sealName;
}
public String getSealBizTypeDescription() {
return sealBizTypeDescription;
}
public void setSealBizTypeDescription(String sealBizTypeDescription) {
this.sealBizTypeDescription = sealBizTypeDescription;
}
public String getStatusDescription() {
return statusDescription;
}
public void setStatusDescription(String statusDescription) {
this.statusDescription = statusDescription;
}
public String getSealImageDownloadUrl() {
return sealImageDownloadUrl;
}
public void setSealImageDownloadUrl(String sealImageDownloadUrl) {
this.sealImageDownloadUrl = sealImageDownloadUrl;
}
}

View File

@@ -6,7 +6,6 @@ public class SignField {
private Integer signFieldType;
private NormalSignFieldConfig normalSignFieldConfig;
private RemarkSignFieldConfig remarkSignFieldConfig;
private SignDateConfig signDateConfig;
public String getFileId() {
return fileId;
@@ -40,11 +39,4 @@ public class SignField {
this.remarkSignFieldConfig = remarkSignFieldConfig;
}
public SignDateConfig getSignDateConfig() {
return signDateConfig;
}
public void setSignDateConfig(SignDateConfig signDateConfig) {
this.signDateConfig = signDateConfig;
}
}

View File

@@ -6,22 +6,41 @@ import com.seeyon.aicloud.common.JsonUtils;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignApiUrl;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.form.FormColumn;
import com.seeyon.apps.esign.form.FormDataOperator;
import com.seeyon.apps.esign.form.FormExportUtil;
import com.seeyon.apps.esign.form.FormWhereCondition;
import com.seeyon.apps.esign.po.EsignApiHeader;
import com.seeyon.apps.esign.po.EsignBaseResp;
import com.seeyon.apps.esign.po.SealInfoVo;
import com.seeyon.apps.esign.utils.HttpClient;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.common.exceptions.BusinessException;
import com.seeyon.ctp.services.ServiceException;
import com.seeyon.v3x.services.form.FormFactory;
import com.seeyon.v3x.services.form.bean.FormExport;
import com.seeyon.v3x.services.form.bean.ValueExport;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.*;
@Component
public class SealService {
private static final Log log = LogFactory.getLog(SealService.class);
@Autowired
private EsignConfigProvider configProvider;
private FormFactory formFactory;
public FormFactory getFormFactory() {
if (formFactory == null) {
formFactory = (FormFactory) AppContext.getBean("formFactory");
}
return formFactory;
}
public void grantSeal(Map<String, Object> params) throws Exception {
JsonObject reqParams = new JsonObject();
@@ -56,10 +75,10 @@ public class SealService {
esignApiHeader.appId(configProvider.getBizConfigByKey(EsignConfigConstants.APP_ID))
.httpMethod("GET")
.heads("")
.pathAndParameters(EsignApiUrl.QUERY_SEAL_URL + "?" + HttpClient.sortQueryString("orgId=" + orgId + "&pageNo=" + pageNo + "&pageSize=" + pageSize))
.pathAndParameters(EsignApiUrl.SEAL_QUERY_URL + "?" + HttpClient.sortQueryString("orgId=" + orgId + "&pageNo=" + pageNo + "&pageSize=" + pageSize))
.contentMD5("")
.signature(configProvider.getBizConfigByKey(EsignConfigConstants.APP_SECRET));
String url = host + EsignApiUrl.QUERY_SEAL_URL + "?orgId=" + orgId + "&pageNo=" + pageNo + "&pageSize=" + pageSize;
String url = host + EsignApiUrl.SEAL_QUERY_URL + "?orgId=" + orgId + "&pageNo=" + pageNo + "&pageSize=" + pageSize;
String respStr = HttpClient.httpGet(url, esignApiHeader.convert2Headers(), "UTF-8");
EsignBaseResp esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class);
Map<String, Object> data = (Map<String, Object>) esignBaseResp.getData();
@@ -72,4 +91,46 @@ public class SealService {
}
return null;
}
public void upsertOaSealDoc(SealInfoVo vo) {
FormDataOperator formDataOperator = new FormDataOperator();
String formNo = configProvider.getBizConfigByKey(EsignConfigConstants.sealInfoFormCode);
List<FormWhereCondition> conditions = new ArrayList<>();
conditions.add(FormWhereCondition.build().display("印章ID").value(vo.getSealId()));
FormColumn formColumn = null;
try {
formColumn = formDataOperator.queryOneRowFormData(formNo, null, conditions);
} catch (Exception e) {
log.error("查询印章信息失败: " + e.getMessage(), e);
}
if (formColumn == null) {
if ("已启用".equals(vo.getStatusDescription())) {
Map<String, String> params = new HashMap<>();
params.put("印章ID", vo.getSealId());
params.put("印章名称", vo.getSealName());
params.put("印章类型", vo.getSealBizTypeDescription());
params.put("印章状态", vo.getStatusDescription());
// params.put("印章图片地址",vo.getSealImageDownloadUrl());
FormExport formExport = new FormExport();
FormExportUtil formExportUtil = new FormExportUtil();
List<ValueExport> valueExport = formExportUtil.setFormValue(params);
formExport.setValues(valueExport);
try {
getFormFactory().importBusinessFormData(configProvider.getBizConfigByKey(EsignConfigConstants.formLoginName), configProvider.getBizConfigByKey(EsignConfigConstants.sealInfoFormCode),
formExport, new String[]{});
} catch (ServiceException e) {
log.error(vo.getSealName() + "信息写入OA档案失败," + e.getMessage(), e);
}
}
} else {
if (!"已启用".equals(vo.getSealBizTypeDescription())) {
try {
formDataOperator.deleteByCondition(formNo, conditions);
} catch (Exception e) {
log.error("删除停用印章失败" + e.getMessage(), e);
}
}
}
}
}