spotContract.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. package erms3
  2. import (
  3. "encoding/hex"
  4. "encoding/json"
  5. "math"
  6. "mtp2_if/db"
  7. "mtp2_if/global/app"
  8. "mtp2_if/global/e"
  9. "mtp2_if/logger"
  10. "mtp2_if/models"
  11. "mtp2_if/utils"
  12. "net/http"
  13. "time"
  14. "github.com/gin-gonic/gin"
  15. )
  16. // spotContract.go 现货合同
  17. // RecordUtcCount UTC计数(毫秒)
  18. var RecordUtcCount int = 0
  19. // SecondCount 秒计数
  20. var SecondCount int = 0
  21. // SpotPriceOrder 定价明细
  22. type SpotPriceOrder struct {
  23. Price float64 `json:"price" binding:"required"` // 价格
  24. Qty float64 `json:"qty" binding:"required"` // 数量
  25. Amount float64 `json:"amount" binding:"required"` // 金额
  26. }
  27. // SpotPointOrder 点价明细
  28. type SpotPointOrder struct {
  29. GoodsID int32 `json:"goodsid" binding:"required"` // 商品ID
  30. GoodsName string `json:"goodsname"` // 商品名称
  31. Qty float64 `json:"qty" binding:"required"` // 数量
  32. Basic float64 `json:"basic" binding:"required"` // 基差
  33. StartDate string `json:"startdate" binding:"required"` // 点价开始日期
  34. EndDate string `json:"enddate" binding:"required"` // 点价结束日期
  35. }
  36. // SoptContractDetail 合同明细信息
  37. type SoptContractDetail struct {
  38. WrStandardID int64 `json:"wrstandardid" binding:"required"` // 交易标的ID
  39. WrStandardName string `json:"wrstandardname" binding:"required"` // 交易标的名称
  40. ProductType int32 `json:"producttype" binding:"required"` // 产品类型 1:标准仓单 2:等标 3:非标
  41. ProductTypeName string `json:"producttypename"` // 产品类型名称
  42. DeliveryGoodsID int32 `json:"deliverygoodsid" binding:"required"` // 现货品种ID
  43. DeliveryGoodsName string `json:"deliverygoodsname"` // 现货品种名称
  44. DeliveryGoodsDesc string `json:"deliverygoodsdesc"` // 现货品种说明
  45. WarehouseID int32 `json:"warehouseid" binding:"required"` // 仓库ID
  46. WarehouseName int32 `json:"warehousename"` // 仓库名称
  47. UnitName string `json:"unitname" binding:"required"` // 单位名称
  48. PointDesc string `json:"pointdesc"` // 点价描述
  49. SpotPriceOrderList []SpotPriceOrder `json:"spotPriceOrderList"` // 定价列表
  50. SpotPointOrderVoList []SpotPointOrder `json:"spotPointOrderVoList"` // 点价列表
  51. }
  52. // SoptContractDetailSum 合同明细信息汇总(组织JSON使用)
  53. type SoptContractDetailSum struct {
  54. WrStandardID int64 `json:"wrstandardid" binding:"required"` // 交易标的ID
  55. WrStandardName string `json:"wrstandardname" binding:"required"` // 交易标的名称
  56. ProductType int32 `json:"producttype" binding:"required"` // 产品类型 1:标准仓单 2:等标 3:非标
  57. ProductTypeName string `json:"producttypename"` // 产品类型名称
  58. DeliveryGoodsID int32 `json:"deliverygoodsid" binding:"required"` // 现货品种ID
  59. DeliveryGoodsName string `json:"deliverygoodsname"` // 现货品种名称
  60. DeliveryGoodsDesc string `json:"deliverygoodsdesc"` // 现货品种说明
  61. WarehouseID int32 `json:"warehouseid" binding:"required"` // 仓库ID
  62. WarehouseName int32 `json:"warehousename"` // 仓库名称
  63. UnitName string `json:"unitname" binding:"required"` // 单位名称
  64. PointDesc string `json:"pointdesc"` // 点价描述
  65. SpotPriceOrderList []SpotPriceOrder `json:"spotPriceOrderList"` // 定价列表
  66. SpotPointOrderVoList []SpotPointOrder `json:"spotPointOrderVoList"` // 点价列表
  67. TotalPriceOrderQty float64 `json:"totalPriceOrderQty"` // 定价总数量
  68. TotalPriceOrderPrice float64 `json:"totalPriceOrderPrice"` // 定价总价格
  69. TotalPriceOrderAmount float64 `json:"totalPriceOrderAmount"` // 定价总金额
  70. TotalPointOrderQty float64 `json:"totalPointOrderQty"` // 点价总数量
  71. TotalQty float64 `json:"totalQty"` // 总数量
  72. }
  73. // AddSpotContractApplyReq 新增现货合同申请请求
  74. type AddSpotContractApplyReq struct {
  75. ContractNo string `json:"contractno" binding:"required"` // 现货合同编号
  76. ContractType int32 `json:"contracttype" binding:"required"` // 现货合同类型 - 1:采购 -1:销售
  77. AreaUserID int32 `json:"areauserid" binding:"required"` // 所属机构
  78. AccountID int64 `json:"accountid" binding:"required"` // 资金账户ID
  79. CustomerUserID int32 `json:"customeruserid" binding:"required"` // 客户ID
  80. CustomerAccountID int64 `json:"customeraccountid" binding:"required"` // 客户资金账户ID
  81. SignDate time.Time `json:"signdate" binding:"required"` // 签订日期
  82. LastDate time.Time `json:"lastdate" binding:"required"` // 交货时间
  83. ContractAttachment string `json:"contractattachment"` // 合同附件
  84. OriMarginPayer int32 `json:"orimarginpayer" binding:"required"` // 初始保证金支付方 -1:买方 2:卖方
  85. OriMargin float64 `json:"orimargin" binding:"required"` // 初始保证金
  86. Remark string `json:"remark"` // 备注
  87. MarketID int32 `json:"marketid" binding:"required"` // 市场ID
  88. CreatorID int32 `json:"creatorid"` // 申请人
  89. Details []SoptContractDetail `json:"details" binding:"required"` // 明细
  90. }
  91. // AddSpotContractApplyRsp 新增现货合同申请响应
  92. type AddSpotContractApplyRsp struct {
  93. SpotContractID int64 `json:"spotcontractid" binging:"required"` // 现货合同ID(345+Unix秒时间戳(10位)+xxxxxx)
  94. ContractNo string `json:"contractno" binding:"required""` // 现货合同编号
  95. }
  96. // AddSpotContractApply 新增现货合同申请
  97. // @Summary 新增现货合同申请
  98. // @Produce json
  99. // @Security ApiKeyAuth
  100. // @Param contractno query string true "现货合同编号"
  101. // @Param contracttype query int true "现货合同类型, 1:采购 -1:销售"
  102. // @Param areauserid query int true "所属机构"
  103. // @Param accountid query int true "资金账户ID"
  104. // @Param customeruserid query int true "客户ID"
  105. // @Param customeraccountid query int true "客户资金账户ID"
  106. // @Param signdate query string true "签订日期, 格式:yyyy-MM-dd HH:mm:ss"
  107. // @Param lastdate query string true "交货时间, 格式:yyyy-MM-dd HH:mm:ss"
  108. // @Param contractattachment query string true "合同附件"
  109. // @Param orimarginpayer query int true "初始保证金支付方, 1:买方 2:卖方"
  110. // @Param orimargin query number true "初始保证金"
  111. // @Param remark query string true "备注"
  112. // @Param marketid query int true "市场ID"
  113. // @Param creatorid query int true "申请人"
  114. // @Param details query int true "明细"
  115. // @Success 200 {object} AddSpotContractApplyRsp
  116. // @Failure 500 {object} app.Response
  117. // @Router /Erms3/AddSpotContractApply [post]
  118. // @Tags 风险管理v3
  119. func AddSpotContractApply(c *gin.Context) {
  120. appG := app.Gin{C: c}
  121. // 获取请求参数
  122. var req AddSpotContractApplyReq
  123. err := appG.C.ShouldBindQuery(&req)
  124. if err != nil {
  125. logger.GetLogger().Errorf("AddSpotContractApply failed: %s", err.Error())
  126. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  127. return
  128. }
  129. // 生成申请ID
  130. spotcontractid := GenSpotContractID()
  131. // 获取当前交易日
  132. tradedate, err := GetMarketTradeDate(int(req.MarketID))
  133. if err != nil {
  134. // 返回失败
  135. logger.GetLogger().Errorf("AddSpotContractApply get market trade date failed: %s", err.Error())
  136. appG.Response(http.StatusBadRequest, e.ERROR_OPERATION_FAILED, nil)
  137. return
  138. }
  139. // 根据明细,生成JSON信息
  140. detailjson, err := BuildDetailJSON(req.Details)
  141. if err != nil {
  142. // 返回失败
  143. logger.GetLogger().Errorf("AddSpotContractApply build detail json failed: %s", err.Error())
  144. appG.Response(http.StatusBadRequest, e.ERROR_OPERATION_FAILED, nil)
  145. return
  146. }
  147. // 组织sql,插入现货合同申请信息
  148. sql := `INSERT INTO ERMS3_SPOTCONTRACTAPPLY(SPOTCONTRACTID,
  149. TRADEDATE,
  150. CONTRACTNO,
  151. CONTRACTTYPE,
  152. AREAUSERID,
  153. ACCOUNTID,
  154. CUSTOMERUSERID,
  155. CUSTOMERACCOUNTID,
  156. SIGNDATE,
  157. LASTDATE,
  158. CONTRACTATTACHMENT,
  159. ORIMARGINPAYER,
  160. ORIMARGIN,
  161. REMARK,
  162. DETAILJSON,
  163. APPLYSTATUS,
  164. APPLYSRC,
  165. MARKETID,
  166. CREATORID,
  167. CREATETIME)
  168. VALUES(
  169. ?,
  170. ?,
  171. ?,
  172. ?,
  173. ?,
  174. ?,
  175. ?,
  176. ?,
  177. to_date(?, 'YYYY-MM-DD HH24:MI:SS'),
  178. to_date(?, 'YYYY-MM-DD HH24:MI:SS'),
  179. ?,
  180. ?,
  181. ?,
  182. ?,
  183. ?,
  184. 0,
  185. 2,
  186. ?,
  187. ?,
  188. sysdate)`
  189. engine := db.GetEngine()
  190. if _, err := engine.Exec(sql,
  191. spotcontractid,
  192. tradedate,
  193. req.ContractNo,
  194. req.ContractType,
  195. req.AreaUserID,
  196. req.AccountID,
  197. req.CustomerUserID,
  198. req.CustomerAccountID,
  199. req.SignDate,
  200. req.LastDate,
  201. req.ContractAttachment,
  202. req.OriMarginPayer,
  203. req.OriMargin,
  204. req.Remark,
  205. detailjson,
  206. req.MarketID,
  207. req.CreatorID); err != nil {
  208. // 插入失败
  209. logger.GetLogger().Errorf("AddSpotContractApply failed: %s", err.Error())
  210. appG.Response(http.StatusBadRequest, e.ERROR_OPERATION_FAILED, nil)
  211. return
  212. }
  213. rsp := AddSpotContractApplyRsp{
  214. SpotContractID: spotcontractid,
  215. ContractNo: req.ContractNo,
  216. }
  217. // 查询成功
  218. logger.GetLogger().Debugln("AddSpotContractApply successed: %v", rsp)
  219. appG.Response(http.StatusOK, e.SUCCESS, rsp)
  220. }
  221. // GenSpotContractID 生成现货合同ID
  222. func GenSpotContractID() int64 {
  223. // 获取当前时间
  224. cur := time.Now()
  225. // UnitNano获取的是纳秒,除以1000000获取毫秒级的时间戳
  226. timestamp := cur.UnixNano() / 1000000
  227. // 除以1000获取秒级的时间戳
  228. var curutc int = int(timestamp / 1000)
  229. if RecordUtcCount == curutc {
  230. SecondCount = SecondCount + 1
  231. } else {
  232. RecordUtcCount = curutc
  233. SecondCount = 1
  234. }
  235. var id int64 = int64(345)*int64(math.Pow(10, 16)) + int64(RecordUtcCount)*int64(math.Pow(10, 6)) + int64(SecondCount)
  236. return id
  237. }
  238. // GetMarketTradeDate 获取市场交易日
  239. func GetMarketTradeDate(marketid int) (string, error) {
  240. marketrun, err := models.GetMarketRun(marketid)
  241. if err != nil {
  242. return "", err
  243. }
  244. return marketrun.Tradedate, nil
  245. }
  246. // BuildDetailJSON 组件合同明细JSON
  247. func BuildDetailJSON(details []SoptContractDetail) (string, error) {
  248. detailsums := make([]SoptContractDetailSum, 0)
  249. for _, detail := range details {
  250. var totalpriceorderqty float64 = 0
  251. var totalpriceorderprice float64 = 0
  252. var totalpriceorderamount float64 = 0
  253. var totalpointorderqty float64 = 0
  254. var totalqty float64 = 0
  255. for _, spotpriceorder := range detail.SpotPriceOrderList {
  256. totalpriceorderqty = totalpriceorderqty + spotpriceorder.Qty
  257. totalpriceorderprice = totalpriceorderprice + spotpriceorder.Price
  258. totalpriceorderamount = totalpriceorderamount + spotpriceorder.Amount
  259. }
  260. for _, spotpointorder := range detail.SpotPointOrderVoList {
  261. totalpointorderqty = totalpointorderqty + spotpointorder.Qty
  262. }
  263. totalqty = totalpriceorderqty + totalpointorderqty
  264. var detailsum SoptContractDetailSum
  265. detailsum = SoptContractDetailSum{
  266. WrStandardID: detail.WrStandardID,
  267. WrStandardName: detail.WrStandardName,
  268. ProductType: detail.ProductType,
  269. ProductTypeName: detail.ProductTypeName,
  270. DeliveryGoodsID: detail.DeliveryGoodsID,
  271. DeliveryGoodsName: detail.DeliveryGoodsName,
  272. DeliveryGoodsDesc: detail.DeliveryGoodsDesc,
  273. WarehouseID: detail.WarehouseID,
  274. WarehouseName: detail.WarehouseName,
  275. UnitName: detail.UnitName,
  276. PointDesc: detail.PointDesc,
  277. SpotPriceOrderList: detail.SpotPriceOrderList,
  278. SpotPointOrderVoList: detail.SpotPointOrderVoList,
  279. TotalPriceOrderQty: totalpriceorderqty,
  280. TotalPriceOrderPrice: totalpriceorderprice,
  281. TotalPriceOrderAmount: totalpriceorderamount,
  282. TotalPointOrderQty: totalpointorderqty,
  283. TotalQty: totalqty,
  284. }
  285. detailsums = append(detailsums, detailsum)
  286. }
  287. jsoninfo, err := json.Marshal(detailsums)
  288. if err != nil {
  289. return "", err
  290. }
  291. return string(jsoninfo), nil
  292. }
  293. // QuerySpotContractAppleFormReq 查询合同申请表单数据请求参数
  294. type QuerySpotContractAppleFormReq struct {
  295. UserID int `form:"userID" binding:"required"`
  296. }
  297. // CustomerInfo 申请单账号信息
  298. type CustomerInfo struct {
  299. Userid int64 `json:"userid" binding:"required"` // 用户ID
  300. Customername string `json:"customername"` // 名称(企业名称)
  301. Mobile string `json:"mobile"` // 手机号码
  302. AccountIDs []int `json:"accountids"` // 资金账户ID列表
  303. }
  304. // QuerySpotContractAppleFormRsp 查询合同申请表单数据返回模型
  305. type QuerySpotContractAppleFormRsp struct {
  306. OurUser CustomerInfo `json:"ouruser"` // 我方账号
  307. OppositeUsers []CustomerInfo `json:"oppositeusers"` // 对方账号列表
  308. WrStandards []models.Wrstandard `json:"wrstandards"` // 仓单标准列表
  309. WareHouseInfos []models.Warehouseinfo `json:"warehouseinfos"` // 仓库信息列表
  310. }
  311. // QuerySpotContractAppleForm 查询合同申请表单数据
  312. // @Summary 查询合同申请表单数据
  313. // @Produce json
  314. // @Security ApiKeyAuth
  315. // @Param userID query int true "用户ID"
  316. // @Success 200 {object} QuerySpotContractAppleFormRsp
  317. // @Failure 500 {object} app.Response
  318. // @Router /Erms3/QuerySpotContractAppleForm [get]
  319. // @Tags 风险管理v3
  320. func QuerySpotContractAppleForm(c *gin.Context) {
  321. appG := app.Gin{C: c}
  322. // 获取请求参数
  323. var req QuerySpotContractAppleFormReq
  324. err := appG.C.ShouldBindQuery(&req)
  325. if err != nil {
  326. logger.GetLogger().Errorf("QuerySpotContractAppleForm failed: %s", err.Error())
  327. appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
  328. return
  329. }
  330. rsp := QuerySpotContractAppleFormRsp{}
  331. // 获取我方用户信息
  332. ourUser, err := models.GetUserInfo(req.UserID)
  333. if err != nil {
  334. // 查询失败
  335. logger.GetLogger().Errorf("QuerySpotContractAppleForm failed: %s", err.Error())
  336. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  337. return
  338. }
  339. rsp.OurUser.Userid = ourUser.Userid
  340. rsp.OurUser.Customername = ourUser.Customername
  341. key, _ := hex.DecodeString(utils.AESSecretKey) // 手机号码解密
  342. if phonenum, err := hex.DecodeString(ourUser.Mobile); err == nil { // hex -> []byte
  343. if mobile, err := utils.AESDecrypt(phonenum, key); err == nil {
  344. rsp.OurUser.Mobile = string(mobile)
  345. }
  346. }
  347. taAccounts, err := models.GetTaAccountsByType(req.UserID, 3) // 获取内部资金账户,现货都使用内部资金账户
  348. if err != nil {
  349. // 查询失败
  350. logger.GetLogger().Errorf("QuerySpotContractAppleForm failed: %s", err.Error())
  351. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  352. return
  353. }
  354. rsp.OurUser.AccountIDs = make([]int, 0)
  355. for _, v := range taAccounts {
  356. rsp.OurUser.AccountIDs = append(rsp.OurUser.AccountIDs, int(v.Accountid))
  357. }
  358. // 获取客户信息
  359. oppositeUsers, err := models.GetUsersByUserType(6)
  360. if err != nil {
  361. // 查询失败
  362. logger.GetLogger().Errorf("QuerySpotContractAppleForm failed: %s", err.Error())
  363. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  364. return
  365. }
  366. rsp.OppositeUsers = make([]CustomerInfo, 0)
  367. for _, v := range oppositeUsers {
  368. // 把自己过滤掉
  369. if int(v.Userid) == req.UserID {
  370. continue
  371. }
  372. userInfo := CustomerInfo{}
  373. userInfo.Userid = v.Userid
  374. userInfo.Customername = v.Customername
  375. // 获取客户的资金账户列表
  376. opposTaAccounts, err := models.GetTaAccountsByType(int(v.Userid), 3) // 获取内部资金账户,现货都使用内部资金账户
  377. if err != nil {
  378. // 查询失败
  379. logger.GetLogger().Errorf("QuerySpotContractAppleForm failed: %s", err.Error())
  380. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  381. return
  382. }
  383. userInfo.AccountIDs = make([]int, 0)
  384. for _, v := range opposTaAccounts {
  385. userInfo.AccountIDs = append(userInfo.AccountIDs, int(v.Accountid))
  386. }
  387. rsp.OppositeUsers = append(rsp.OppositeUsers, userInfo)
  388. }
  389. // 获取交易标的(仓单标准)
  390. rsp.WrStandards = make([]models.Wrstandard, 0)
  391. wrStandards, err := models.GetWrstandards()
  392. if err != nil {
  393. // 查询失败
  394. logger.GetLogger().Errorf("QuerySpotContractAppleForm failed: %s", err.Error())
  395. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  396. return
  397. }
  398. rsp.WrStandards = wrStandards
  399. // 获取仓库信息
  400. rsp.WareHouseInfos = make([]models.Warehouseinfo, 0)
  401. wareHouseInfos, err := models.GetWareHouseinfos()
  402. if err != nil {
  403. // 查询失败
  404. logger.GetLogger().Errorf("QuerySpotContractAppleForm failed: %s", err.Error())
  405. appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
  406. return
  407. }
  408. rsp.WareHouseInfos = wareHouseInfos
  409. // 查询成功
  410. logger.GetLogger().Debugln("QuerySpotContractAppleForm successed: %v", rsp)
  411. appG.Response(http.StatusOK, e.SUCCESS, rsp)
  412. }