sign.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. package sign
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "mtp20access/global"
  9. "mtp20access/model/account"
  10. "mtp20access/model/account/request"
  11. "mtp20access/model/account/response"
  12. "mtp20access/service/asign"
  13. "mtp20access/utils"
  14. "net/http"
  15. "os"
  16. "strconv"
  17. "time"
  18. "github.com/gofrs/uuid"
  19. "go.uber.org/zap"
  20. )
  21. // QueryUserESignRecord 查询用户电子签记录表
  22. func QueryUserESignRecord(userId int) (rsp []account.Useresignrecord, err error) {
  23. rsp = make([]account.Useresignrecord, 0)
  24. err = global.M2A_DB.Where("USERID = ?", userId).Find(&rsp)
  25. return
  26. }
  27. // AddUser 添加用户
  28. func AddUser(req request.AddUserReq, userId int) (err error) {
  29. // 获取用户电子签记录
  30. useresignrecord := new(account.Useresignrecord)
  31. has, _ := global.M2A_DB.Where("USERID = ? AND TEMPLATETYPE = 1 AND RECORDSTATUS = 3", userId).Get(useresignrecord)
  32. if has {
  33. err = errors.New("用户已同步")
  34. return
  35. }
  36. // 调用爱签API-添加个人用户(https://{host}/user/addPersonalUser)
  37. rsp, err := asign.AddPersonalUserBy(
  38. strconv.Itoa(userId),
  39. req.Name,
  40. req.IdCard,
  41. req.Mobile,
  42. req.IdCardType,
  43. )
  44. if err != nil {
  45. return
  46. }
  47. if rsp.Code != 100000 {
  48. err = errors.New(strconv.Itoa(rsp.Code))
  49. global.M2A_LOG.Error("【AddUser】 接口调用失败", zap.Error(err))
  50. return
  51. }
  52. // 更新用户电子签记录-实名认证状态
  53. authinfo, err := json.Marshal(req)
  54. if err != nil {
  55. global.M2A_LOG.Error("【AddUser】 构建AUTHINFO失败", zap.Error(err))
  56. return
  57. }
  58. sql := fmt.Sprintf(`
  59. UPDATE useresignrecord
  60. SET RECORDSTATUS = 3,
  61. UPDATETIME = SYSDATE,
  62. AUTHINFO = '%v'
  63. WHERE USERID = %v AND TEMPLATETYPE = 1
  64. `, string(authinfo), userId)
  65. if _, err = global.M2A_DB.Exec(sql); err != nil {
  66. global.M2A_LOG.Error("【AddUser】 更新用户电子签记录失败", zap.Error(err))
  67. return
  68. }
  69. return
  70. }
  71. // CreateContractAndAddSigner 上传待签署文件和添加签署方
  72. func CreateContractAndAddSigner(req request.CreateContractAndAddSignerReq, userId int) (rsp response.CreateContractAndAddSignerRsp, err error) {
  73. // 获取用户电子签记录
  74. useresignrecord := new(account.Useresignrecord)
  75. has, err := global.M2A_DB.Where("USERID = ? AND TEMPLATENO = ?", userId, req.TemplateNo).Get(useresignrecord)
  76. if err != nil || !has {
  77. global.M2A_LOG.Error("【CreateContractAndAddSigner】 获取用户电子签记录失败", zap.Error(err))
  78. return
  79. }
  80. // 判断是否需要创建合同(上传待签署文件)
  81. if useresignrecord.CONTRACTNO == "" {
  82. // 生成合同编号
  83. // #{userid} || '_' || to_char(sysdate, 'yyyyMMddhh24miss') || '_' || seq_useresignrecord.currval,
  84. contractNo := fmt.Sprintf("%d_%s_%v", userId, time.Now().Format("20060102150405"), useresignrecord.RECORDID)
  85. // 调用爱签API-上传待签署文件(https://{host}/contract/createContract)
  86. r, e := asign.CreateContract(
  87. contractNo,
  88. useresignrecord.TEMPLATENAME,
  89. useresignrecord.TEMPLATENO,
  90. )
  91. if e != nil {
  92. err = e
  93. return
  94. }
  95. if r.Code != 100000 {
  96. err = errors.New(strconv.Itoa(r.Code))
  97. global.M2A_LOG.Error("【CreateContractAndAddSigner】 上传待签署文件接口调用失败", zap.Error(err))
  98. return
  99. }
  100. // 将返回的合同编号写入数据库
  101. useresignrecord.CONTRACTNO = contractNo
  102. sql := fmt.Sprintf(`
  103. UPDATE useresignrecord
  104. SET contractNo = '%v',
  105. UPDATETIME = SYSDATE
  106. WHERE RECORDID = %v
  107. `, useresignrecord.CONTRACTNO, useresignrecord.RECORDID)
  108. if _, err = global.M2A_DB.Exec(sql); err != nil {
  109. global.M2A_LOG.Error("【CreateContractAndAddSigner】 写入合同编号失败", zap.Error(err))
  110. return
  111. }
  112. }
  113. // 判断是否需要添加签署方(获取合同签约地址)
  114. if useresignrecord.SIGNURL != "" {
  115. err = errors.New("合同签署链接已存在")
  116. } else {
  117. // 调用爱签API-添加签署方(https://{host}/contract/addSigner)
  118. r, e := asign.AddSigner(
  119. useresignrecord.CONTRACTNO,
  120. strconv.Itoa(userId),
  121. )
  122. if e != nil {
  123. err = e
  124. return
  125. }
  126. if r.Code != 100000 {
  127. err = errors.New(strconv.Itoa(r.Code))
  128. global.M2A_LOG.Error("【CreateContractAndAddSigner】 添加签署方接口调用失败", zap.Error(err))
  129. return
  130. }
  131. if len(r.Data.SignUser) > 0 {
  132. useresignrecord.SIGNURL = r.Data.SignUser[0].SignUrl
  133. // 将返回的合同编号写入数据库
  134. sql := fmt.Sprintf(`
  135. UPDATE useresignrecord
  136. SET RECORDSTATUS = 2,
  137. SIGNURL = '%v',
  138. UPDATETIME = SYSDATE
  139. WHERE RECORDID = %v
  140. `, useresignrecord.SIGNURL, useresignrecord.RECORDID)
  141. if _, err = global.M2A_DB.Exec(sql); err != nil {
  142. global.M2A_LOG.Error("【CreateContractAndAddSigner】 写入合同签署链接失败", zap.Error(err))
  143. return
  144. }
  145. // 给客户端返回合同签署地址
  146. rsp.SignUrl = useresignrecord.SIGNURL
  147. }
  148. }
  149. return
  150. }
  151. // SignCompleted
  152. func SignCompleted(userId int) (err error) {
  153. // 获取用户电子签记录
  154. datas := make([]account.Useresignrecord, 0)
  155. err = global.M2A_DB.Where("USERID = ?", userId).Find(&datas)
  156. if err != nil {
  157. global.M2A_LOG.Error("SignCompleted 获取用户电子签记录失败", zap.Error(err))
  158. return
  159. }
  160. // mgk
  161. var record *account.Useresignrecord
  162. for i, item := range datas {
  163. if item.TEMPLATETYPE == 1 {
  164. record = &datas[i]
  165. }
  166. // 如果是签署中状态,则查询一下合同状态
  167. if item.RECORDSTATUS == 2 {
  168. rspCTStatus, e := asign.ContractStatus(item.CONTRACTNO)
  169. if e != nil {
  170. err = e
  171. global.M2A_LOG.Error("[SignCompleted] 查询合同状态失败", zap.Error(err))
  172. return
  173. }
  174. if rspCTStatus.Data.Status == 2 {
  175. // 已签约
  176. // 下载合同
  177. r, e := asign.DownloadContract(item.CONTRACTNO)
  178. if e != nil {
  179. err = e
  180. return
  181. }
  182. if r.Code != 100000 {
  183. err = errors.New(strconv.Itoa(r.Code))
  184. global.M2A_LOG.Error("[SignCompleted] 下载合同接口调用失败", zap.Error(err))
  185. return
  186. }
  187. if r.Data.Data != "" {
  188. // 获取网上开户地址(用于客户端下载文件)
  189. openconfig := account.Wskhopenaccountconfig{CONFIGID: 6}
  190. has, e := openconfig.Get()
  191. if e != nil || !has {
  192. err = e
  193. global.M2A_LOG.Error("[SignCompleted] 获取网上开户地址失败", zap.Error(err))
  194. return
  195. }
  196. // 将Base64写入目标文件
  197. uid, _ := uuid.NewV4()
  198. fileName := fmt.Sprintf("%v.pdf", uid.String())
  199. // openconfig.CONFIGVALUE = "./" // FIXME: - 测试代码
  200. folderPath := "sign/" + time.Now().Format("20060102")
  201. savePath := openconfig.CONFIGVALUE + "/uploadFile/" + folderPath
  202. if exist, _ := utils.PathExists(savePath); !exist {
  203. os.MkdirAll(savePath, os.ModePerm)
  204. }
  205. f, e := os.OpenFile(savePath+"/"+fileName, os.O_RDWR|os.O_CREATE, os.ModePerm)
  206. if e != nil {
  207. err = e
  208. global.M2A_LOG.Error("【HandleASignCompleted】 获取网上开户地址失败", zap.Error(err))
  209. return
  210. }
  211. defer f.Close()
  212. // 更新数据库记录
  213. contractfileaddr := fmt.Sprintf("./uploadFile/%v/%v", folderPath, fileName)
  214. sql := fmt.Sprintf(`
  215. UPDATE useresignrecord
  216. SET RECORDSTATUS = 3,
  217. UPDATETIME = SYSDATE,
  218. CONTRACTFILEADDR = '%v'
  219. WHERE CONTRACTNO = '%v'
  220. `, contractfileaddr, item.CONTRACTNO)
  221. if _, err = global.M2A_DB.Exec(sql); err != nil {
  222. global.M2A_LOG.Error("【HandleASignCompleted】 更新用户电子签记录失败", zap.Error(err))
  223. return
  224. }
  225. }
  226. }
  227. } else if item.RECORDSTATUS != 3 && item.RECORDSTATUS != 2 {
  228. err = errors.New("未完成所有合同签署")
  229. global.M2A_LOG.Error(err.Error())
  230. return
  231. }
  232. }
  233. // 获取临时存储的用户信息
  234. if record == nil || record.AUTHINFO == "" {
  235. global.M2A_LOG.Error("[SignCompleted] 获取实名认证信息失败", zap.Error(err))
  236. return
  237. }
  238. // {"name":"甘肃碳交","idCard":"360428200007287603","idCardType":1,"idCardPhoto":"./uploadFile/20230812/202308121518494929.png","idCardPhotoBackURL":"./uploadFile/20230812/202308121518529223.png","mobile":"15914012151"}
  239. cacheMap := make(map[string]interface{})
  240. err = json.Unmarshal([]byte(record.AUTHINFO), &cacheMap)
  241. if err != nil {
  242. global.M2A_LOG.Error("[SignCompleted] 反序列化临时存储用户信息失败", zap.Error(err))
  243. return
  244. }
  245. // 调用JAVA实名认证接口
  246. reqParam := make(map[string]interface{})
  247. reqParam["userid"] = userId
  248. reqParam["cardnum"] = cacheMap["idCard"]
  249. reqParam["username"] = cacheMap["name"]
  250. reqParam["cardtype"] = 0 // 目前写死证件类型为身份证 - 0
  251. reqParam["cardfrontphotourl"] = cacheMap["idCardPhoto"]
  252. reqParam["cardbackphotourl"] = cacheMap["idCardPhotoBackURL"]
  253. reqParam["userinfotype"] = 1 // 目前写死为个人 - 1
  254. jsonParam, err := json.Marshal(&reqParam)
  255. if err != nil {
  256. global.M2A_LOG.Error("[SignCompleted] 反序列化JAVA实名认证入参失败", zap.Error(err))
  257. return
  258. }
  259. // 构建请求
  260. javaUrl := global.M2A_CONFIG.Asign.OpenApiUrl + "/onlineopen/userInfo/addAuth"
  261. req, err := http.NewRequest("POST", javaUrl, bytes.NewReader(jsonParam))
  262. // 设置请求头
  263. req.Header.Set("Content-Type", "application/json; charset=utf-8")
  264. client := &http.Client{}
  265. rsp, err := client.Do(req)
  266. if err != nil {
  267. global.M2A_LOG.Error("[SignCompleted] 请求失败", zap.Error(err))
  268. return
  269. }
  270. defer rsp.Body.Close()
  271. body, err := io.ReadAll(rsp.Body)
  272. if err != nil {
  273. global.M2A_LOG.Error("[SignCompleted] 获取body失败", zap.Error(err))
  274. return
  275. }
  276. rspData := make(map[string]interface{})
  277. if err = json.Unmarshal(body, &rspData); err != nil {
  278. global.M2A_LOG.Error("[SignCompleted] 反序列化java body失败", zap.Error(err))
  279. return
  280. }
  281. fmt.Println("rspData:", rspData)
  282. return
  283. }
  284. /*
  285. handleASignCompleted 处理爱签合同签署完成后回调通知
  286. req 异步推送参数
  287. */
  288. func HandleASignCompleted(contractNo, status string) (err error) {
  289. /*
  290. // 合同签署完成后回调通知示例
  291. String publickey = "MFwwDQcccccxxxxmEz/nw27Ln6AP90ZCMPi+iNF1m9mhNECAwEAAQ==";
  292. String remark = ""; // 若被拒签则会返回拒签原因,拒签原因不参与签名
  293. Map <String, String> map = new HashMap<>();
  294. map.put("action", "signCompleted");
  295. map.put("contractNo", "20221114142140345");
  296. map.put("status", "2");
  297. map.put("signTime", "2022-11-14 14:22:00");
  298. map.put("timestamp", "1668406920005");
  299. map.put("validityTime", "2022-11-24 23:59:59");
  300. String json = JSONObject.toJSONString(map, SerializerFeature.MapSortField);
  301. System.out.println("数据:" + json);
  302. // 计算签名
  303. try {
  304. String sign = "feFfcprGjdmDDqRmxK5qlWlMncX0mc6LJ5agebOGIx2QiAern+6ZRg/SBHOgvHp/+1ywVRdyKNUKxPneETwKPw==";
  305. System.out.println(RSAUtils.rsaSignCheck(sign, json, publickey));
  306. } catch (Exception e) {
  307. e.printStackTrace();
  308. }
  309. */
  310. // 获取合同编号
  311. if contractNo == "" {
  312. global.M2A_LOG.Error("【HandleASignCompleted】 获取合同编号失败")
  313. return
  314. }
  315. // 获取合同状态
  316. if status == "" {
  317. global.M2A_LOG.Error("【HandleASignCompleted】 获取获取合同状态失败")
  318. return
  319. }
  320. if status == "2" {
  321. // 已签约
  322. // 下载合同
  323. r, e := asign.DownloadContract(contractNo)
  324. if e != nil {
  325. err = e
  326. return
  327. }
  328. if r.Code != 100000 {
  329. err = errors.New(strconv.Itoa(r.Code))
  330. global.M2A_LOG.Error("【HandleASignCompleted】 下载合同接口调用失败", zap.Error(err))
  331. return
  332. }
  333. if r.Data.Data != "" {
  334. // 获取网上开户地址(用于客户端下载文件)
  335. openconfig := account.Wskhopenaccountconfig{CONFIGID: 6}
  336. has, e := openconfig.Get()
  337. if e != nil || !has {
  338. err = e
  339. global.M2A_LOG.Error("【HandleASignCompleted】 获取网上开户地址失败", zap.Error(err))
  340. return
  341. }
  342. // 将Base64写入目标文件
  343. uid, _ := uuid.NewV4()
  344. fileName := fmt.Sprintf("%v.pdf", uid.String())
  345. // openconfig.CONFIGVALUE = "./" // FIXME: - 测试代码
  346. folderPath := "sign/" + time.Now().Format("20060102")
  347. savePath := openconfig.CONFIGVALUE + "/uploadFile/" + folderPath
  348. if exist, _ := utils.PathExists(savePath); !exist {
  349. os.MkdirAll(savePath, os.ModePerm)
  350. }
  351. f, e := os.OpenFile(savePath+"/"+fileName, os.O_RDWR|os.O_CREATE, os.ModePerm)
  352. if e != nil {
  353. err = e
  354. global.M2A_LOG.Error("【HandleASignCompleted】 获取网上开户地址失败", zap.Error(err))
  355. return
  356. }
  357. defer f.Close()
  358. // 更新数据库记录
  359. contractfileaddr := fmt.Sprintf("./uploadFile/%v/%v", folderPath, fileName)
  360. sql := fmt.Sprintf(`
  361. UPDATE useresignrecord
  362. SET RECORDSTATUS = 3,
  363. UPDATETIME = SYSDATE,
  364. CONTRACTFILEADDR = '%v'
  365. WHERE CONTRACTNO = '%v'
  366. `, contractfileaddr, contractNo)
  367. if _, err = global.M2A_DB.Exec(sql); err != nil {
  368. global.M2A_LOG.Error("【HandleASignCompleted】 更新用户电子签记录失败", zap.Error(err))
  369. return
  370. }
  371. }
  372. }
  373. return
  374. }