| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529 |
- package sign
- import (
- "bytes"
- "encoding/base64"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "mtp20access/global"
- "mtp20access/model/account"
- "mtp20access/model/account/request"
- "mtp20access/model/account/response"
- "mtp20access/service/asign"
- "mtp20access/utils"
- "net/http"
- "os"
- "strconv"
- "time"
- "github.com/gofrs/uuid"
- "go.uber.org/zap"
- )
- // QueryUserESignRecord 查询用户电子签记录表
- func QueryUserESignRecord(userId int) (rsp []account.Useresignrecord, err error) {
- rsp = make([]account.Useresignrecord, 0)
- if err = global.M2A_DB.Where("USERID = ?", userId).OrderBy("ORDERINDEX").Find(&rsp); err != nil {
- return
- }
- for i := range rsp {
- data := &rsp[i]
- if data.TEMPLATETYPE == 2 && data.RECORDSTATUS == 2 {
- // 去爱签同步合同状态
- rspCTStatus, e := asign.ContractStatus(data.CONTRACTNO)
- if e != nil {
- err = e
- global.M2A_LOG.Error("【QueryUserESignRecord】 查询合同状态失败", zap.Error(err))
- return
- }
- // 下载合同并修改合同状态
- e = modifyContractStatus(data.CONTRACTNO, strconv.Itoa(rspCTStatus.Data.Status))
- if e != nil {
- // 从新获取记录
- recordId := data.RECORDID
- data = new(account.Useresignrecord)
- has, e := global.M2A_DB.Where("RECORDID = ?", recordId).Get(data)
- if e != nil || !has {
- err = e
- global.M2A_LOG.Error("【QueryUserESignRecord】 获取用户电子签记录失败", zap.Error(err))
- return
- }
- }
- }
- }
- return
- }
- // AddUser 添加用户
- func AddUser(req request.AddUserReq, userId int) (err error) {
- // 获取用户电子签记录
- useresignrecord := new(account.Useresignrecord)
- has, _ := global.M2A_DB.Where("USERID = ? AND TEMPLATETYPE = 1 AND RECORDSTATUS = 3", userId).Get(useresignrecord)
- if has {
- err = errors.New("用户已同步")
- return
- }
- // 调用爱签API-添加个人用户(https://{host}/user/addPersonalUser)
- rsp, err := asign.AddPersonalUserBy(
- strconv.Itoa(userId),
- req.Name,
- req.IdCard,
- req.Mobile,
- req.IdCardType,
- )
- if err != nil {
- return
- }
- if rsp.Code != 100000 {
- err = errors.New(strconv.Itoa(rsp.Code))
- global.M2A_LOG.Error("【AddUser】 接口调用失败", zap.Error(err))
- return
- }
- // 更新用户电子签记录-实名认证状态
- authinfo, err := json.Marshal(req)
- if err != nil {
- global.M2A_LOG.Error("【AddUser】 构建AUTHINFO失败", zap.Error(err))
- return
- }
- sql := fmt.Sprintf(`
- UPDATE useresignrecord
- SET RECORDSTATUS = 3,
- UPDATETIME = SYSDATE,
- AUTHINFO = '%v'
- WHERE USERID = %v AND TEMPLATETYPE = 1
- `, string(authinfo), userId)
- if _, err = global.M2A_DB.Exec(sql); err != nil {
- global.M2A_LOG.Error("【AddUser】 更新用户电子签记录失败", zap.Error(err))
- return
- }
- return
- }
- // CreateContractAndAddSigner 上传待签署文件和添加签署方
- func CreateContractAndAddSigner(req request.CreateContractAndAddSignerReq, userId int) (rsp response.CreateContractAndAddSignerRsp, err error) {
- // 获取用户电子签记录
- useresignrecord := new(account.Useresignrecord)
- has, err := global.M2A_DB.Where("USERID = ? AND TEMPLATENO = ?", userId, req.TemplateNo).Get(useresignrecord)
- if err != nil || !has {
- global.M2A_LOG.Error("【CreateContractAndAddSigner】 获取用户电子签记录失败", zap.Error(err))
- return
- }
- // 判断是否需要创建合同(上传待签署文件)
- if useresignrecord.CONTRACTNO == "" {
- // 生成合同编号
- // #{userid} || '_' || to_char(sysdate, 'yyyyMMddhh24miss') || '_' || seq_useresignrecord.currval,
- contractNo := fmt.Sprintf("%d_%s_%v", userId, time.Now().Format("20060102150405"), useresignrecord.RECORDID)
- // 调用爱签API-上传待签署文件(https://{host}/contract/createContract)
- r, e := asign.CreateContract(
- contractNo,
- useresignrecord.TEMPLATENAME,
- useresignrecord.TEMPLATENO,
- )
- if e != nil {
- err = e
- return
- }
- if r.Code != 100000 {
- err = errors.New(strconv.Itoa(r.Code))
- global.M2A_LOG.Error("【CreateContractAndAddSigner】 上传待签署文件接口调用失败", zap.Error(err))
- return
- }
- // 将返回的合同编号写入数据库
- useresignrecord.CONTRACTNO = contractNo
- sql := fmt.Sprintf(`
- UPDATE useresignrecord
- SET contractNo = '%v',
- UPDATETIME = SYSDATE
- WHERE RECORDID = %v
- `, useresignrecord.CONTRACTNO, useresignrecord.RECORDID)
- if _, err = global.M2A_DB.Exec(sql); err != nil {
- global.M2A_LOG.Error("【CreateContractAndAddSigner】 写入合同编号失败", zap.Error(err))
- return
- }
- }
- // 判断是否需要添加签署方(获取合同签约地址)
- if useresignrecord.SIGNURL != "" {
- err = errors.New("合同签署链接已存在")
- } else {
- // 调用爱签API-添加签署方(https://{host}/contract/addSigner)
- r, e := asign.AddSigner(
- useresignrecord.CONTRACTNO,
- strconv.Itoa(userId),
- )
- if e != nil {
- err = e
- return
- }
- if r.Code != 100000 {
- err = errors.New(strconv.Itoa(r.Code))
- global.M2A_LOG.Error("【CreateContractAndAddSigner】 添加签署方接口调用失败", zap.Error(err))
- return
- }
- if len(r.Data.SignUser) > 0 {
- useresignrecord.SIGNURL = r.Data.SignUser[0].SignUrl
- // 将返回的合同编号写入数据库
- sql := fmt.Sprintf(`
- UPDATE useresignrecord
- SET RECORDSTATUS = 2,
- SIGNURL = '%v',
- UPDATETIME = SYSDATE
- WHERE RECORDID = %v
- `, useresignrecord.SIGNURL, useresignrecord.RECORDID)
- if _, err = global.M2A_DB.Exec(sql); err != nil {
- global.M2A_LOG.Error("【CreateContractAndAddSigner】 写入合同签署链接失败", zap.Error(err))
- return
- }
- // 给客户端返回合同签署地址
- rsp.SignUrl = useresignrecord.SIGNURL
- }
- }
- return
- }
- // SignCompleted
- func SignCompleted(userId int) (err error) {
- // 获取用户电子签记录
- datas := make([]account.Useresignrecord, 0)
- err = global.M2A_DB.Where("USERID = ?", userId).Find(&datas)
- if err != nil {
- global.M2A_LOG.Error("[SignCompleted] 获取用户电子签记录失败", zap.Error(err))
- return
- }
- var record *account.Useresignrecord
- for i, item := range datas {
- if item.TEMPLATETYPE == 1 {
- record = &datas[i]
- }
- switch item.TEMPLATETYPE {
- case 1: // 实名认证
- if item.RECORDSTATUS != 3 {
- err = errors.New("未完成用户添加")
- return
- }
- case 2: // 合同签署
- // 如果是签署中状态,则查询一下合同状态
- if item.RECORDSTATUS == 2 {
- rspCTStatus, e := asign.ContractStatus(item.CONTRACTNO)
- if e != nil {
- err = e
- global.M2A_LOG.Error("[SignCompleted] 查询合同状态失败", zap.Error(err))
- return
- }
- // 下载合同并修改合同状态
- err = modifyContractStatus(rspCTStatus.Data.ContractNo, strconv.Itoa(rspCTStatus.Data.Status))
- return
- } else if (item.RECORDSTATUS != 3 && item.RECORDSTATUS != 2) && item.TEMPLATETYPE == 2 {
- err = errors.New("未完成所有合同签署")
- global.M2A_LOG.Error(err.Error())
- return
- }
- case 3: // 个人意愿
- if item.RECORDSTATUS != 3 {
- err = errors.New("未完成个人意愿核身认证")
- return
- }
- }
- }
- // 获取临时存储的用户信息
- if record == nil || record.AUTHINFO == "" {
- global.M2A_LOG.Error("[SignCompleted] 获取实名认证信息失败", zap.Error(err))
- return
- }
- // {"name":"甘肃碳交","idCard":"360428200007287603","idCardType":1,"idCardPhoto":"./uploadFile/20230812/202308121518494929.png","idCardPhotoBackURL":"./uploadFile/20230812/202308121518529223.png","mobile":"15914012151"}
- cacheMap := make(map[string]interface{})
- err = json.Unmarshal([]byte(record.AUTHINFO), &cacheMap)
- if err != nil {
- global.M2A_LOG.Error("[SignCompleted] 反序列化临时存储用户信息失败", zap.Error(err))
- return
- }
- // 调用JAVA实名认证接口
- reqParam := make(map[string]interface{})
- reqParam["userid"] = userId
- reqParam["cardnum"] = cacheMap["idCard"]
- reqParam["username"] = cacheMap["name"]
- reqParam["cardtype"] = 0 // 目前写死证件类型为身份证 - 0
- reqParam["cardfrontphotourl"] = cacheMap["idCardPhoto"]
- reqParam["cardbackphotourl"] = cacheMap["idCardPhotoBackURL"]
- reqParam["userinfotype"] = 1 // 目前写死为个人 - 1
- jsonParam, err := json.Marshal(&reqParam)
- if err != nil {
- global.M2A_LOG.Error("[SignCompleted] 反序列化JAVA实名认证入参失败", zap.Error(err))
- return
- }
- // 构建请求
- javaUrl := global.M2A_CONFIG.Asign.OpenApiUrl + "/onlineopen/userInfo/addAuth"
- req, err := http.NewRequest("POST", javaUrl, bytes.NewReader(jsonParam))
- // 设置请求头
- req.Header.Set("Content-Type", "application/json; charset=utf-8")
- client := &http.Client{}
- rsp, err := client.Do(req)
- if err != nil {
- global.M2A_LOG.Error("[SignCompleted] 请求失败", zap.Error(err))
- return
- }
- defer rsp.Body.Close()
- body, err := io.ReadAll(rsp.Body)
- if err != nil {
- global.M2A_LOG.Error("[SignCompleted] 获取body失败", zap.Error(err))
- return
- }
- // rspData: map[code:0 hasAuth:1 message:认证成功]
- rspData := make(map[string]interface{})
- if err = json.Unmarshal(body, &rspData); err != nil {
- global.M2A_LOG.Error("[SignCompleted] 反序列化java body失败", zap.Error(err))
- return
- }
- global.M2A_LOG.Info("[SignCompleted] 调用JAVA实名认证接口返回", zap.Any("rspData", rspData))
- code, ok := rspData["code"]
- if !ok {
- err = errors.New("实名认证失败,请稍后重试")
- return
- }
- if code != "0" {
- err = fmt.Errorf("实名认证失败,%v", rspData["message"])
- global.M2A_LOG.Error("[SignCompleted]", zap.Error(err))
- return
- }
- return
- }
- /*
- handleASignCompleted 处理爱签合同签署完成后回调通知
- req 异步推送参数
- */
- func HandleASignCompleted(contractNo, status string) (err error) {
- /*
- // 合同签署完成后回调通知示例
- String publickey = "MFwwDQcccccxxxxmEz/nw27Ln6AP90ZCMPi+iNF1m9mhNECAwEAAQ==";
- String remark = ""; // 若被拒签则会返回拒签原因,拒签原因不参与签名
- Map <String, String> map = new HashMap<>();
- map.put("action", "signCompleted");
- map.put("contractNo", "20221114142140345");
- map.put("status", "2");
- map.put("signTime", "2022-11-14 14:22:00");
- map.put("timestamp", "1668406920005");
- map.put("validityTime", "2022-11-24 23:59:59");
- String json = JSONObject.toJSONString(map, SerializerFeature.MapSortField);
- System.out.println("数据:" + json);
- // 计算签名
- try {
- String sign = "feFfcprGjdmDDqRmxK5qlWlMncX0mc6LJ5agebOGIx2QiAern+6ZRg/SBHOgvHp/+1ywVRdyKNUKxPneETwKPw==";
- System.out.println(RSAUtils.rsaSignCheck(sign, json, publickey));
- } catch (Exception e) {
- e.printStackTrace();
- }
- */
- // 获取合同编号
- if contractNo == "" {
- global.M2A_LOG.Error("【HandleASignCompleted】 获取合同编号失败")
- return
- }
- // 获取合同状态
- if status == "" {
- global.M2A_LOG.Error("【HandleASignCompleted】 获取获取合同状态失败")
- return
- }
- // 下载合同并修改合同状态
- err = modifyContractStatus(contractNo, status)
- return
- }
- // modifyContractStatus 爱签异步推送和查询合同状态后调用
- // 注意传入的status是爱签的合同状态
- // 合同状态:
- // 0:等待签约
- // 1:签约中
- // 2:已签约
- // 3:过期
- // 4:拒签
- // 6:作废
- // -2:状态异常
- func modifyContractStatus(contractNo, status string) (err error) {
- if status == "2" {
- // 获取用户电子签记录
- useresignrecord := new(account.Useresignrecord)
- has, e := global.M2A_DB.Where("CONTRACTNO = ?", contractNo).Get(useresignrecord)
- if e != nil || !has {
- err = e
- global.M2A_LOG.Error("【modifyContractStatus】 获取用户电子签记录失败", zap.Error(err))
- return
- }
- if useresignrecord.RECORDSTATUS == 3 {
- // 已完成签署,不需要再下载和修改数据库状态
- return
- }
- // 已签约
- // 下载合同
- r, e := asign.DownloadContract(contractNo)
- if e != nil {
- err = e
- return
- }
- if r.Code != 100000 {
- err = errors.New(strconv.Itoa(r.Code))
- global.M2A_LOG.Error("【modifyContractStatus】 下载合同接口调用失败", zap.Error(err))
- return
- }
- if r.Data.Data != "" {
- // 获取网上开户地址(用于客户端下载文件)
- openconfig := account.Wskhopenaccountconfig{CONFIGID: 6}
- has, e := openconfig.Get()
- if e != nil || !has {
- err = e
- global.M2A_LOG.Error("【modifyContractStatus】 获取网上开户地址失败", zap.Error(err))
- return
- }
- // 将Base64写入目标文件
- uid, _ := uuid.NewV4()
- fileName := fmt.Sprintf("%v.pdf", uid.String())
- // openconfig.CONFIGVALUE = "./" // FIXME: - 测试代码
- folderPath := "sign/" + time.Now().Format("20060102")
- savePath := openconfig.CONFIGVALUE + "/uploadFile/" + folderPath
- if exist, _ := utils.PathExists(savePath); !exist {
- os.MkdirAll(savePath, os.ModePerm)
- }
- fb, e := base64.StdEncoding.DecodeString(r.Data.Data)
- if e != nil {
- err = e
- global.M2A_LOG.Error("【modifyContractStatus】 解码pdf文件失败", zap.Error(err))
- return
- }
- if err = os.WriteFile(savePath+"/"+fileName, fb, 0666); err != nil {
- global.M2A_LOG.Error("【modifyContractStatus】 保存合同失败", zap.Error(err))
- return
- }
- // 更新数据库记录
- contractfileaddr := fmt.Sprintf("./uploadFile/%v/%v", folderPath, fileName)
- sql := fmt.Sprintf(`
- UPDATE useresignrecord
- SET RECORDSTATUS = 3,
- UPDATETIME = SYSDATE,
- CONTRACTFILEADDR = '%v'
- WHERE CONTRACTNO = '%v'
- `, contractfileaddr, contractNo)
- if _, err = global.M2A_DB.Exec(sql); err != nil {
- global.M2A_LOG.Error("【modifyContractStatus】 更新用户电子签记录失败", zap.Error(err))
- return
- }
- }
- } else if status == "0" || status == "1" {
- err = fmt.Errorf("合同签署状态不正确, status: %v", status)
- return
- } else {
- // 其它状态一律改为4(签署拒绝)
- // 更新数据库记录
- sql := fmt.Sprintf(`
- UPDATE useresignrecord
- SET RECORDSTATUS = 4,
- UPDATETIME = SYSDATE
- WHERE CONTRACTNO = '%v'
- `, contractNo)
- if _, err = global.M2A_DB.Exec(sql); err != nil {
- global.M2A_LOG.Error("【HandleASignCompleted】 更新用户电子签记录失败", zap.Error(err))
- return
- }
- err = fmt.Errorf("合同签署状态不正确, status: %v", status)
- }
- return
- }
- // WillFace 个人意愿核身认证
- func WillFace(req request.WillFaceReq, userId int) (wrsp response.WillFaceRsp, err error) {
- // 获取用户电子签记录
- useresignrecord := new(account.Useresignrecord)
- has, err := global.M2A_DB.Where("USERID = ? AND TEMPLATETYPE = 3", userId).Get(useresignrecord)
- if err != nil || !has {
- global.M2A_LOG.Error("【WillFace】 获取用户电子签记录失败", zap.Error(err))
- return
- }
- if useresignrecord.RECORDSTATUS == 3 {
- err = errors.New("不可重复进行个人意愿核身认证")
- return
- }
- // 调用爱签API-个人意愿核身认证(https://{host}/auth/person/willFace)
- rsp, err := asign.WillFace(
- req.RealName,
- req.IdCardNo,
- useresignrecord.TEMPLATENO,
- useresignrecord.TEMPLATENAME,
- strconv.Itoa(int(useresignrecord.RECORDID)))
- if err != nil {
- return
- }
- if rsp.Code != 100000 {
- err = errors.New(strconv.Itoa(rsp.Code))
- global.M2A_LOG.Error("【WillFace】 接口调用失败", zap.Error(err))
- return
- }
- wrsp.FaceUrl = rsp.Data.FaceUrl
- // 更新用户电子签记录
- sql := fmt.Sprintf(`
- UPDATE useresignrecord
- SET RECORDSTATUS = 2,
- UPDATETIME = SYSDATE,
- SIGNURL = '%v'
- WHERE RECORDID = %v
- `, rsp.Data.FaceUrl, useresignrecord.RECORDID)
- if _, err = global.M2A_DB.Exec(sql); err != nil {
- global.M2A_LOG.Error("【WillFace】 更新用户电子签记录失败", zap.Error(err))
- return
- }
- return
- }
- // 个人意愿核身认证爱签回调通知处理
- func HandleWillFace(sign, result, msg, recordId string) (err error) {
- // 获取用户电子签记录
- useresignrecord := new(account.Useresignrecord)
- has, e := global.M2A_DB.Where("RECORDID = ?", recordId).Get(useresignrecord)
- if e != nil || !has {
- err = e
- global.M2A_LOG.Error("【HandleWillFace】 获取用户电子签记录失败", zap.Error(err))
- return
- }
- // 人脸认证结果
- // 1:认证成功
- // 2:认证失败
- if result == "1" {
- // FIXME: - 这里应该校验签名(姓名和身份证号码)
- // 更新数据库记录
- sql := fmt.Sprintf(`
- UPDATE useresignrecord
- SET RECORDSTATUS = 3,
- UPDATETIME = SYSDATE
- WHERE RECORDID = %v
- `, recordId)
- if _, err = global.M2A_DB.Exec(sql); err != nil {
- global.M2A_LOG.Error("【HandleWillFace】 更新用户电子签记录失败", zap.Error(err))
- return
- }
- }
- return
- }
|