package erms3 import ( "encoding/hex" "encoding/json" "math" "mtp2_if/db" "mtp2_if/global/app" "mtp2_if/global/e" "mtp2_if/logger" "mtp2_if/models" "mtp2_if/utils" "net/http" "time" "github.com/gin-gonic/gin" ) // spotContract.go 现货合同 // RecordUtcCount UTC计数(毫秒) var RecordUtcCount int = 0 // SecondCount 秒计数 var SecondCount int = 0 // SpotPriceOrder 定价明细 type SpotPriceOrder struct { Price float64 `json:"price" binding:"required"` // 价格 Qty float64 `json:"qty" binding:"required"` // 数量 Amount float64 `json:"amount" binding:"required"` // 金额 } // SpotPointOrder 点价明细 type SpotPointOrder struct { GoodsID int32 `json:"goodsid" binding:"required"` // 商品ID GoodsName string `json:"goodsname"` // 商品名称 Qty float64 `json:"qty" binding:"required"` // 数量 Basic float64 `json:"basic" binding:"required"` // 基差 StartDate string `json:"startdate" binding:"required"` // 点价开始日期 EndDate string `json:"enddate" binding:"required"` // 点价结束日期 } // SoptContractDetail 合同明细信息 type SoptContractDetail struct { WrStandardID int64 `json:"wrstandardid" binding:"required"` // 交易标的ID WrStandardName string `json:"wrstandardname" binding:"required"` // 交易标的名称 ProductType int32 `json:"producttype" binding:"required"` // 产品类型 1:标准仓单 2:等标 3:非标 ProductTypeName string `json:"producttypename"` // 产品类型名称 DeliveryGoodsID int32 `json:"deliverygoodsid" binding:"required"` // 现货品种ID DeliveryGoodsName string `json:"deliverygoodsname"` // 现货品种名称 DeliveryGoodsDesc string `json:"deliverygoodsdesc"` // 现货品种说明 WarehouseID int32 `json:"warehouseid" binding:"required"` // 仓库ID WarehouseName int32 `json:"warehousename"` // 仓库名称 UnitName string `json:"unitname" binding:"required"` // 单位名称 PointDesc string `json:"pointdesc"` // 点价描述 SpotPriceOrderList []SpotPriceOrder `json:"spotPriceOrderList"` // 定价列表 SpotPointOrderVoList []SpotPointOrder `json:"spotPointOrderVoList"` // 点价列表 } // SoptContractDetailSum 合同明细信息汇总(组织JSON使用) type SoptContractDetailSum struct { WrStandardID int64 `json:"wrstandardid" binding:"required"` // 交易标的ID WrStandardName string `json:"wrstandardname" binding:"required"` // 交易标的名称 ProductType int32 `json:"producttype" binding:"required"` // 产品类型 1:标准仓单 2:等标 3:非标 ProductTypeName string `json:"producttypename"` // 产品类型名称 DeliveryGoodsID int32 `json:"deliverygoodsid" binding:"required"` // 现货品种ID DeliveryGoodsName string `json:"deliverygoodsname"` // 现货品种名称 DeliveryGoodsDesc string `json:"deliverygoodsdesc"` // 现货品种说明 WarehouseID int32 `json:"warehouseid" binding:"required"` // 仓库ID WarehouseName int32 `json:"warehousename"` // 仓库名称 UnitName string `json:"unitname" binding:"required"` // 单位名称 PointDesc string `json:"pointdesc"` // 点价描述 SpotPriceOrderList []SpotPriceOrder `json:"spotPriceOrderList"` // 定价列表 SpotPointOrderVoList []SpotPointOrder `json:"spotPointOrderVoList"` // 点价列表 TotalPriceOrderQty float64 `json:"totalPriceOrderQty"` // 定价总数量 TotalPriceOrderPrice float64 `json:"totalPriceOrderPrice"` // 定价总价格 TotalPriceOrderAmount float64 `json:"totalPriceOrderAmount"` // 定价总金额 TotalPointOrderQty float64 `json:"totalPointOrderQty"` // 点价总数量 TotalQty float64 `json:"totalQty"` // 总数量 } // AddSpotContractApplyReq 新增现货合同申请请求 type AddSpotContractApplyReq struct { ContractNo string `json:"contractno" binding:"required"` // 现货合同编号 ContractType int32 `json:"contracttype" binding:"required"` // 现货合同类型 - 1:采购 -1:销售 AreaUserID int32 `json:"areauserid" binding:"required"` // 所属机构 AccountID int64 `json:"accountid" binding:"required"` // 资金账户ID CustomerUserID int32 `json:"customeruserid" binding:"required"` // 客户ID CustomerAccountID int64 `json:"customeraccountid" binding:"required"` // 客户资金账户ID SignDate time.Time `json:"signdate" binding:"required"` // 签订日期 LastDate time.Time `json:"lastdate" binding:"required"` // 交货时间 ContractAttachment string `json:"contractattachment"` // 合同附件 OriMarginPayer int32 `json:"orimarginpayer" binding:"required"` // 初始保证金支付方 -1:买方 2:卖方 OriMargin float64 `json:"orimargin" binding:"required"` // 初始保证金 Remark string `json:"remark"` // 备注 MarketID int32 `json:"marketid" binding:"required"` // 市场ID CreatorID int32 `json:"creatorid"` // 申请人 Details []SoptContractDetail `json:"details" binding:"required"` // 明细 } // AddSpotContractApplyRsp 新增现货合同申请响应 type AddSpotContractApplyRsp struct { SpotContractID int64 `json:"spotcontractid" binging:"required"` // 现货合同ID(345+Unix秒时间戳(10位)+xxxxxx) ContractNo string `json:"contractno" binding:"required""` // 现货合同编号 } // AddSpotContractApply 新增现货合同申请 // @Summary 新增现货合同申请 // @Produce json // @Security ApiKeyAuth // @Param contractno query string true "现货合同编号" // @Param contracttype query int true "现货合同类型, 1:采购 -1:销售" // @Param areauserid query int true "所属机构" // @Param accountid query int true "资金账户ID" // @Param customeruserid query int true "客户ID" // @Param customeraccountid query int true "客户资金账户ID" // @Param signdate query string true "签订日期, 格式:yyyy-MM-dd HH:mm:ss" // @Param lastdate query string true "交货时间, 格式:yyyy-MM-dd HH:mm:ss" // @Param contractattachment query string true "合同附件" // @Param orimarginpayer query int true "初始保证金支付方, 1:买方 2:卖方" // @Param orimargin query number true "初始保证金" // @Param remark query string true "备注" // @Param marketid query int true "市场ID" // @Param creatorid query int true "申请人" // @Param details query int true "明细" // @Success 200 {object} AddSpotContractApplyRsp // @Failure 500 {object} app.Response // @Router /Erms3/AddSpotContractApply [post] // @Tags 风险管理v3 func AddSpotContractApply(c *gin.Context) { appG := app.Gin{C: c} // 获取请求参数 var req AddSpotContractApplyReq err := appG.C.ShouldBindQuery(&req) if err != nil { logger.GetLogger().Errorf("AddSpotContractApply failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil) return } // 生成申请ID spotcontractid := GenSpotContractID() // 获取当前交易日 tradedate, err := GetMarketTradeDate(int(req.MarketID)) if err != nil { // 返回失败 logger.GetLogger().Errorf("AddSpotContractApply get market trade date failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.ERROR_OPERATION_FAILED, nil) return } // 根据明细,生成JSON信息 detailjson, err := BuildDetailJSON(req.Details) if err != nil { // 返回失败 logger.GetLogger().Errorf("AddSpotContractApply build detail json failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.ERROR_OPERATION_FAILED, nil) return } // 组织sql,插入现货合同申请信息 sql := `INSERT INTO ERMS3_SPOTCONTRACTAPPLY(SPOTCONTRACTID, TRADEDATE, CONTRACTNO, CONTRACTTYPE, AREAUSERID, ACCOUNTID, CUSTOMERUSERID, CUSTOMERACCOUNTID, SIGNDATE, LASTDATE, CONTRACTATTACHMENT, ORIMARGINPAYER, ORIMARGIN, REMARK, DETAILJSON, APPLYSTATUS, APPLYSRC, MARKETID, CREATORID, CREATETIME) VALUES( ?, ?, ?, ?, ?, ?, ?, ?, to_date(?, 'YYYY-MM-DD HH24:MI:SS'), to_date(?, 'YYYY-MM-DD HH24:MI:SS'), ?, ?, ?, ?, ?, 0, 2, ?, ?, sysdate)` engine := db.GetEngine() if _, err := engine.Exec(sql, spotcontractid, tradedate, req.ContractNo, req.ContractType, req.AreaUserID, req.AccountID, req.CustomerUserID, req.CustomerAccountID, req.SignDate, req.LastDate, req.ContractAttachment, req.OriMarginPayer, req.OriMargin, req.Remark, detailjson, req.MarketID, req.CreatorID); err != nil { // 插入失败 logger.GetLogger().Errorf("AddSpotContractApply failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.ERROR_OPERATION_FAILED, nil) return } rsp := AddSpotContractApplyRsp{ SpotContractID: spotcontractid, ContractNo: req.ContractNo, } // 查询成功 logger.GetLogger().Debugln("AddSpotContractApply successed: %v", rsp) appG.Response(http.StatusOK, e.SUCCESS, rsp) } // GenSpotContractID 生成现货合同ID func GenSpotContractID() int64 { // 获取当前时间 cur := time.Now() // UnitNano获取的是纳秒,除以1000000获取毫秒级的时间戳 timestamp := cur.UnixNano() / 1000000 // 除以1000获取秒级的时间戳 var curutc int = int(timestamp / 1000) if RecordUtcCount == curutc { SecondCount = SecondCount + 1 } else { RecordUtcCount = curutc SecondCount = 1 } var id int64 = int64(345)*int64(math.Pow(10, 16)) + int64(RecordUtcCount)*int64(math.Pow(10, 6)) + int64(SecondCount) return id } // GetMarketTradeDate 获取市场交易日 func GetMarketTradeDate(marketid int) (string, error) { marketrun, err := models.GetMarketRun(marketid) if err != nil { return "", err } return marketrun.Tradedate, nil } // BuildDetailJSON 组件合同明细JSON func BuildDetailJSON(details []SoptContractDetail) (string, error) { detailsums := make([]SoptContractDetailSum, 0) for _, detail := range details { var totalpriceorderqty float64 = 0 var totalpriceorderprice float64 = 0 var totalpriceorderamount float64 = 0 var totalpointorderqty float64 = 0 var totalqty float64 = 0 for _, spotpriceorder := range detail.SpotPriceOrderList { totalpriceorderqty = totalpriceorderqty + spotpriceorder.Qty totalpriceorderprice = totalpriceorderprice + spotpriceorder.Price totalpriceorderamount = totalpriceorderamount + spotpriceorder.Amount } for _, spotpointorder := range detail.SpotPointOrderVoList { totalpointorderqty = totalpointorderqty + spotpointorder.Qty } totalqty = totalpriceorderqty + totalpointorderqty var detailsum SoptContractDetailSum detailsum = SoptContractDetailSum{ WrStandardID: detail.WrStandardID, WrStandardName: detail.WrStandardName, ProductType: detail.ProductType, ProductTypeName: detail.ProductTypeName, DeliveryGoodsID: detail.DeliveryGoodsID, DeliveryGoodsName: detail.DeliveryGoodsName, DeliveryGoodsDesc: detail.DeliveryGoodsDesc, WarehouseID: detail.WarehouseID, WarehouseName: detail.WarehouseName, UnitName: detail.UnitName, PointDesc: detail.PointDesc, SpotPriceOrderList: detail.SpotPriceOrderList, SpotPointOrderVoList: detail.SpotPointOrderVoList, TotalPriceOrderQty: totalpriceorderqty, TotalPriceOrderPrice: totalpriceorderprice, TotalPriceOrderAmount: totalpriceorderamount, TotalPointOrderQty: totalpointorderqty, TotalQty: totalqty, } detailsums = append(detailsums, detailsum) } jsoninfo, err := json.Marshal(detailsums) if err != nil { return "", err } return string(jsoninfo), nil } // QuerySpotContractAppleFormReq 查询合同申请表单数据请求参数 type QuerySpotContractAppleFormReq struct { UserID int `form:"userID" binding:"required"` } // CustomerInfo 申请单账号信息 type CustomerInfo struct { Userid int64 `json:"userid" binding:"required"` // 用户ID Customername string `json:"customername"` // 名称(企业名称) Mobile string `json:"mobile"` // 手机号码 AccountIDs []int `json:"accountids"` // 资金账户ID列表 } // QuerySpotContractAppleFormRsp 查询合同申请表单数据返回模型 type QuerySpotContractAppleFormRsp struct { OurUser CustomerInfo `json:"ouruser"` // 我方账号 OppositeUsers []CustomerInfo `json:"oppositeusers"` // 对方账号列表 WrStandards []models.Wrstandard `json:"wrstandards"` // 仓单标准列表 WareHouseInfos []models.Warehouseinfo `json:"warehouseinfos"` // 仓库信息列表 } // QuerySpotContractAppleForm 查询合同申请表单数据 // @Summary 查询合同申请表单数据 // @Produce json // @Security ApiKeyAuth // @Param userID query int true "用户ID" // @Success 200 {object} QuerySpotContractAppleFormRsp // @Failure 500 {object} app.Response // @Router /Erms3/QuerySpotContractAppleForm [get] // @Tags 风险管理v3 func QuerySpotContractAppleForm(c *gin.Context) { appG := app.Gin{C: c} // 获取请求参数 var req QuerySpotContractAppleFormReq err := appG.C.ShouldBindQuery(&req) if err != nil { logger.GetLogger().Errorf("QuerySpotContractAppleForm failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil) return } rsp := QuerySpotContractAppleFormRsp{} // 获取我方用户信息 ourUser, err := models.GetUserInfo(req.UserID) if err != nil { // 查询失败 logger.GetLogger().Errorf("QuerySpotContractAppleForm failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil) return } rsp.OurUser.Userid = ourUser.Userid rsp.OurUser.Customername = ourUser.Customername key, _ := hex.DecodeString(utils.AESSecretKey) // 手机号码解密 if phonenum, err := hex.DecodeString(ourUser.Mobile); err == nil { // hex -> []byte if mobile, err := utils.AESDecrypt(phonenum, key); err == nil { rsp.OurUser.Mobile = string(mobile) } } taAccounts, err := models.GetTaAccountsByType(req.UserID, 3) // 获取内部资金账户,现货都使用内部资金账户 if err != nil { // 查询失败 logger.GetLogger().Errorf("QuerySpotContractAppleForm failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil) return } rsp.OurUser.AccountIDs = make([]int, 0) for _, v := range taAccounts { rsp.OurUser.AccountIDs = append(rsp.OurUser.AccountIDs, int(v.Accountid)) } // 获取客户信息 oppositeUsers, err := models.GetUsersByUserType(6) if err != nil { // 查询失败 logger.GetLogger().Errorf("QuerySpotContractAppleForm failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil) return } rsp.OppositeUsers = make([]CustomerInfo, 0) for _, v := range oppositeUsers { // 把自己过滤掉 if int(v.Userid) == req.UserID { continue } userInfo := CustomerInfo{} userInfo.Userid = v.Userid userInfo.Customername = v.Customername // 获取客户的资金账户列表 opposTaAccounts, err := models.GetTaAccountsByType(int(v.Userid), 3) // 获取内部资金账户,现货都使用内部资金账户 if err != nil { // 查询失败 logger.GetLogger().Errorf("QuerySpotContractAppleForm failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil) return } userInfo.AccountIDs = make([]int, 0) for _, v := range opposTaAccounts { userInfo.AccountIDs = append(userInfo.AccountIDs, int(v.Accountid)) } rsp.OppositeUsers = append(rsp.OppositeUsers, userInfo) } // 获取交易标的(仓单标准) rsp.WrStandards = make([]models.Wrstandard, 0) wrStandards, err := models.GetWrstandards() if err != nil { // 查询失败 logger.GetLogger().Errorf("QuerySpotContractAppleForm failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil) return } rsp.WrStandards = wrStandards // 获取仓库信息 rsp.WareHouseInfos = make([]models.Warehouseinfo, 0) wareHouseInfos, err := models.GetWareHouseinfos() if err != nil { // 查询失败 logger.GetLogger().Errorf("QuerySpotContractAppleForm failed: %s", err.Error()) appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil) return } rsp.WareHouseInfos = wareHouseInfos // 查询成功 logger.GetLogger().Debugln("QuerySpotContractAppleForm successed: %v", rsp) appG.Response(http.StatusOK, e.SUCCESS, rsp) }