Quellcode durchsuchen

增加生成现货采购合同功能

zhou.xiaoning vor 3 Jahren
Ursprung
Commit
17d8547bf9

+ 1 - 1
config.yaml

@@ -29,4 +29,4 @@ rabbitmq:
 # system configuration
 system:
   env: 'develop'  # "develop" & "public", Change to "develop" to skip authentication for development mode
-  store-path: '/home/pub/image/uploadFile' # JAVA文件上传目录
+  store-path: '/home/pub/image/uploadFile' # JAVA文件上传目录 <- 已作废

+ 1 - 0
global/funcode.go

@@ -3,4 +3,5 @@ package global
 var (
 	THJPurchaseTradeNtf = 1441865 // 铁合金成交通知
 	PurchaseTransferNtf = 1441846 // 铁合金协议转让通知
+	WRTradeDealedNtf    = 131110  // 仓单贸易成交通知
 )

+ 5 - 0
model/common.go

@@ -14,3 +14,8 @@ func (t *Division) GetTotalAddressByDistrictID(address string) (totalAddress str
 
 	return
 }
+
+// Get 获取CONFIGID获取信息
+func (t *Wskhopenaccountconfig) Get() (has bool, err error) {
+	return global.M2A_DB.Where("CONFIGID = ?", t.CONFIGID).Get(t)
+}

+ 48 - 0
model/database.go

@@ -367,3 +367,51 @@ type Thjpurchasetransfer struct {
 func (r *Thjpurchasetransfer) TableName() string {
 	return "THJ_PURCHASETRANSFER"
 }
+
+// Wrtradetradequote 仓单贸易成交行情表
+type Wrtradetradequote struct {
+	WRTRADEDETAILID   int64     `json:"wrtradedetailid" xorm:"WRTRADEDETAILID"`     // 仓单贸易成交单ID(321+Unix秒时间戳(10位)+xxxxxx)
+	TRADEDATE         string    `json:"tradedate" xorm:"TRADEDATE"`                 // 交易日(yyyyMMdd)
+	MARKETID          int32     `json:"marketid" xorm:"MARKETID"`                   // 市场ID
+	WRFACTORTYPEID    int64     `json:"wrfactortypeid" xorm:"WRFACTORTYPEID"`       // 仓单要素类型ID
+	DELIVERYGOODSID   int32     `json:"deliverygoodsid" xorm:"DELIVERYGOODSID"`     // 现货品种ID
+	WRSTANDARDID      int32     `json:"wrstandardid" xorm:"WRSTANDARDID"`           // 现货商品ID
+	BUYUSERID         int64     `json:"buyuserid" xorm:"BUYUSERID"`                 // 买方用户ID
+	BUYACCOUNTID      int64     `json:"buyaccountid" xorm:"BUYACCOUNTID"`           // 买方账号ID
+	SELLUSERID        int64     `json:"selluserid" xorm:"SELLUSERID"`               // 卖方用户ID
+	SELLACCOUNTID     int64     `json:"sellaccountid" xorm:"SELLACCOUNTID"`         // 卖方账号ID
+	TRADETIME         time.Time `json:"tradetime" xorm:"TRADETIME"`                 // 成交时间
+	TRADEPRICE        float64   `json:"tradeprice" xorm:"TRADEPRICE"`               // 成交价格
+	TRADEQTY          int64     `json:"tradeqty" xorm:"TRADEQTY"`                   // 成交数量
+	TRADEAMOUNT       float64   `json:"tradeamount" xorm:"TRADEAMOUNT"`             // 成交金额
+	PERFORMANCEPLANID int64     `json:"performanceplanid" xorm:"PERFORMANCEPLANID"` // 履约计划ID/合同ID
+	EXCHANGERATE      float64   `json:"exchangerate" xorm:"EXCHANGERATE"`           // 汇率
+	BUYCHARGEVALUE    float64   `json:"buychargevalue" xorm:"BUYCHARGEVALUE"`       // 买方手续费
+	SELLCHARGEVALUE   float64   `json:"sellchargevalue" xorm:"SELLCHARGEVALUE"`     // 卖方手续费
+	ORITRADEAMOUNT    float64   `json:"oritradeamount" xorm:"ORITRADEAMOUNT"`       // 成交金额[商品币种]
+	VATRATE           float64   `json:"vatrate" xorm:"VATRATE"`                     // 增值税率
+	VATRATEAMOUNT     float64   `json:"vatrateamount" xorm:"VATRATEAMOUNT"`         // 增值税率金额
+	CONTRACTADDRBUY   string    `json:"contractaddrbuy" xorm:"CONTRACTADDRBUY"`     // 贸易合同地址(买家)
+	CONTRACTADDRSELL  string    `json:"contractaddrsell" xorm:"CONTRACTADDRSELL"`   // 贸易合同地址(卖家)
+}
+
+// TableName is WRTRADE_TRADEQUOTE
+func (r *Wrtradetradequote) TableName() string {
+	return "WRTRADE_TRADEQUOTE"
+}
+
+// Wskhopenaccountconfig 网上开户配置表
+type Wskhopenaccountconfig struct {
+	CONFIGID     int32     `json:"configid" xorm:"CONFIGID"`         // 配置ID
+	CONFIGTYPE   int32     `json:"configtype" xorm:"CONFIGTYPE"`     // 配置类型
+	CONFIGVALUE  string    `json:"configvalue" xorm:"CONFIGVALUE"`   // 配置值
+	REMARK       string    `json:"remark" xorm:"REMARK"`             // 备注
+	CREATETIME   time.Time `json:"createtime" xorm:"CREATETIME"`     // 创建时间
+	MODIFIEDTIME time.Time `json:"modifiedtime" xorm:"MODIFIEDTIME"` // 修改时间
+	MODIFIEDBY   int64     `json:"modifiedby" xorm:"MODIFIEDBY"`     // 修改人帐号
+}
+
+// TableName is WSKH_OPENACCOUNTCONFIG
+func (r *Wskhopenaccountconfig) TableName() string {
+	return "WSKH_OPENACCOUNTCONFIG"
+}

+ 15 - 0
model/thj.go

@@ -28,3 +28,18 @@ func (t *Thjpurchasetransfer) UpdateContractAddr() (err error) {
 	_, err = global.M2A_DB.Where("TRANSFERID = ?", t.TRANSFERID).Cols("CONTRACTADDR").Update(t)
 	return
 }
+
+// Get 通过仓单贸易成交单ID获取信息
+func (t *Wrtradetradequote) Get() (has bool, err error) {
+	return global.M2A_DB.Where("WRTRADEDETAILID = ?", t.WRTRADEDETAILID).Get(t)
+}
+
+// UpdateContractAddr 更新合同地址
+func (t *Wrtradetradequote) UpdateContractAddr(buyOrSell int) (err error) {
+	field := "CONTRACTADDRBUY"
+	if buyOrSell == 1 {
+		field = "CONTRACTADDRSELL"
+	}
+	_, err = global.M2A_DB.Where("WRTRADEDETAILID = ?", t.WRTRADEDETAILID).Cols(field).Update(t)
+	return
+}

+ 399 - 30
res/pb/mtp2.pb.go

@@ -153,6 +153,86 @@ func (x *MessageHead) GetAccountID2() uint64 {
 	return 0
 }
 
+// 公共通知消息头
+type NotifyHead struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	NtfMode        *int32   `protobuf:"varint,1,opt,name=NtfMode" json:"NtfMode,omitempty"`               // 消息通知模式(单播、组播、广播)
+	ExcludeAcctIDs []uint32 `protobuf:"varint,2,rep,name=ExcludeAcctIDs" json:"ExcludeAcctIDs,omitempty"` // 排除账号集合(首先过滤此集合帐号)
+	ExchIDs        []uint32 `protobuf:"varint,3,rep,name=ExchIDs" json:"ExchIDs,omitempty"`               // 目标交易所集合(若匹配所属交易所,推送)
+	MemberIDs      []uint32 `protobuf:"varint,4,rep,name=MemberIDs" json:"MemberIDs,omitempty"`           // 目标会员集合(若匹配所属会员,推送)
+	AccountIDs     []uint64 `protobuf:"varint,5,rep,name=AccountIDs" json:"AccountIDs,omitempty"`         // 目标账号集合(以上均不匹配时,最后检查此集合)
+}
+
+func (x *NotifyHead) Reset() {
+	*x = NotifyHead{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_mtp2_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *NotifyHead) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*NotifyHead) ProtoMessage() {}
+
+func (x *NotifyHead) ProtoReflect() protoreflect.Message {
+	mi := &file_mtp2_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use NotifyHead.ProtoReflect.Descriptor instead.
+func (*NotifyHead) Descriptor() ([]byte, []int) {
+	return file_mtp2_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *NotifyHead) GetNtfMode() int32 {
+	if x != nil && x.NtfMode != nil {
+		return *x.NtfMode
+	}
+	return 0
+}
+
+func (x *NotifyHead) GetExcludeAcctIDs() []uint32 {
+	if x != nil {
+		return x.ExcludeAcctIDs
+	}
+	return nil
+}
+
+func (x *NotifyHead) GetExchIDs() []uint32 {
+	if x != nil {
+		return x.ExchIDs
+	}
+	return nil
+}
+
+func (x *NotifyHead) GetMemberIDs() []uint32 {
+	if x != nil {
+		return x.MemberIDs
+	}
+	return nil
+}
+
+func (x *NotifyHead) GetAccountIDs() []uint64 {
+	if x != nil {
+		return x.AccountIDs
+	}
+	return nil
+}
+
 // 铁合金成交通知
 type THJPurchaseTradeNtf struct {
 	state         protoimpl.MessageState
@@ -166,7 +246,7 @@ type THJPurchaseTradeNtf struct {
 func (x *THJPurchaseTradeNtf) Reset() {
 	*x = THJPurchaseTradeNtf{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_mtp2_proto_msgTypes[1]
+		mi := &file_mtp2_proto_msgTypes[2]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -179,7 +259,7 @@ func (x *THJPurchaseTradeNtf) String() string {
 func (*THJPurchaseTradeNtf) ProtoMessage() {}
 
 func (x *THJPurchaseTradeNtf) ProtoReflect() protoreflect.Message {
-	mi := &file_mtp2_proto_msgTypes[1]
+	mi := &file_mtp2_proto_msgTypes[2]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -192,7 +272,7 @@ func (x *THJPurchaseTradeNtf) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use THJPurchaseTradeNtf.ProtoReflect.Descriptor instead.
 func (*THJPurchaseTradeNtf) Descriptor() ([]byte, []int) {
-	return file_mtp2_proto_rawDescGZIP(), []int{1}
+	return file_mtp2_proto_rawDescGZIP(), []int{2}
 }
 
 func (x *THJPurchaseTradeNtf) GetHeader() *MessageHead {
@@ -222,7 +302,7 @@ type PurchaseTransferNtf struct {
 func (x *PurchaseTransferNtf) Reset() {
 	*x = PurchaseTransferNtf{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_mtp2_proto_msgTypes[2]
+		mi := &file_mtp2_proto_msgTypes[3]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -235,7 +315,7 @@ func (x *PurchaseTransferNtf) String() string {
 func (*PurchaseTransferNtf) ProtoMessage() {}
 
 func (x *PurchaseTransferNtf) ProtoReflect() protoreflect.Message {
-	mi := &file_mtp2_proto_msgTypes[2]
+	mi := &file_mtp2_proto_msgTypes[3]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -248,7 +328,7 @@ func (x *PurchaseTransferNtf) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use PurchaseTransferNtf.ProtoReflect.Descriptor instead.
 func (*PurchaseTransferNtf) Descriptor() ([]byte, []int) {
-	return file_mtp2_proto_rawDescGZIP(), []int{2}
+	return file_mtp2_proto_rawDescGZIP(), []int{3}
 }
 
 func (x *PurchaseTransferNtf) GetHeader() *MessageHead {
@@ -265,6 +345,206 @@ func (x *PurchaseTransferNtf) GetTransferID() uint64 {
 	return 0
 }
 
+// 仓单贸易成交通知
+type WRTradeDealedNtf struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Header                *MessageHead `protobuf:"bytes,1,opt,name=Header" json:"Header,omitempty"`                                 // 消息头
+	NtfHeader             *NotifyHead  `protobuf:"bytes,2,opt,name=NtfHeader" json:"NtfHeader,omitempty"`                           // NotifyHead 公共消息头
+	ListingOrderID        *uint64      `protobuf:"varint,3,opt,name=ListingOrderID" json:"ListingOrderID,omitempty"`                // uint64 挂牌委托单号
+	DelistingOrderID      *uint64      `protobuf:"varint,4,opt,name=DelistingOrderID" json:"DelistingOrderID,omitempty"`            // uint64 摘牌委托单号
+	TradeQty              *uint64      `protobuf:"varint,5,opt,name=TradeQty" json:"TradeQty,omitempty"`                            // uint64 挂牌成交数量
+	ActiveQty             *uint64      `protobuf:"varint,6,opt,name=ActiveQty" json:"ActiveQty,omitempty"`                          // uint64 挂牌剩余数量
+	RealTradeQty          *uint64      `protobuf:"varint,7,opt,name=RealTradeQty" json:"RealTradeQty,omitempty"`                    // uint64 摘牌实际成交数量
+	TradeID               *uint64      `protobuf:"varint,8,opt,name=TradeID" json:"TradeID,omitempty"`                              // uint64 成交单ID
+	BuyAccountID          *uint64      `protobuf:"varint,9,opt,name=BuyAccountID" json:"BuyAccountID,omitempty"`                    // uint64 买资金账号
+	SellAccountID         *uint64      `protobuf:"varint,10,opt,name=SellAccountID" json:"SellAccountID,omitempty"`                 // uint64 卖资金账号
+	TradePrice            *float64     `protobuf:"fixed64,11,opt,name=TradePrice" json:"TradePrice,omitempty"`                      // double 成交价
+	TradeTime             *string      `protobuf:"bytes,12,opt,name=TradeTime" json:"TradeTime,omitempty"`                          // string 成交时间
+	WRFactorTypeID        *uint64      `protobuf:"varint,13,opt,name=WRFactorTypeID" json:"WRFactorTypeID,omitempty"`               // uint64 仓单要素ID
+	WRTransferUserID      *uint32      `protobuf:"varint,14,opt,name=WRTransferUserID" json:"WRTransferUserID,omitempty"`           // uint32 仓单受让账户
+	FreezeFirstAmount     *float64     `protobuf:"fixed64,15,opt,name=FreezeFirstAmount" json:"FreezeFirstAmount,omitempty"`        // double 冻结首付金额
+	UnFreezeFirstAmount   *float64     `protobuf:"fixed64,16,opt,name=UnFreezeFirstAmount" json:"UnFreezeFirstAmount,omitempty"`    // double 解冻首付金额
+	RealTradeAmount       *float64     `protobuf:"fixed64,17,opt,name=RealTradeAmount" json:"RealTradeAmount,omitempty"`            // double 实际成交金额
+	PerformanceAmount     *float64     `protobuf:"fixed64,18,opt,name=PerformanceAmount" json:"PerformanceAmount,omitempty"`        // double 履约金额
+	PerformancePlanID     *uint64      `protobuf:"varint,19,opt,name=PerformancePlanID" json:"PerformancePlanID,omitempty"`         // uint64 履约计划ID
+	PerformanceTemplateID *int64       `protobuf:"varint,20,opt,name=PerformanceTemplateID" json:"PerformanceTemplateID,omitempty"` // int64 履约计划模板ID
+}
+
+func (x *WRTradeDealedNtf) Reset() {
+	*x = WRTradeDealedNtf{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_mtp2_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *WRTradeDealedNtf) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WRTradeDealedNtf) ProtoMessage() {}
+
+func (x *WRTradeDealedNtf) ProtoReflect() protoreflect.Message {
+	mi := &file_mtp2_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use WRTradeDealedNtf.ProtoReflect.Descriptor instead.
+func (*WRTradeDealedNtf) Descriptor() ([]byte, []int) {
+	return file_mtp2_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *WRTradeDealedNtf) GetHeader() *MessageHead {
+	if x != nil {
+		return x.Header
+	}
+	return nil
+}
+
+func (x *WRTradeDealedNtf) GetNtfHeader() *NotifyHead {
+	if x != nil {
+		return x.NtfHeader
+	}
+	return nil
+}
+
+func (x *WRTradeDealedNtf) GetListingOrderID() uint64 {
+	if x != nil && x.ListingOrderID != nil {
+		return *x.ListingOrderID
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetDelistingOrderID() uint64 {
+	if x != nil && x.DelistingOrderID != nil {
+		return *x.DelistingOrderID
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetTradeQty() uint64 {
+	if x != nil && x.TradeQty != nil {
+		return *x.TradeQty
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetActiveQty() uint64 {
+	if x != nil && x.ActiveQty != nil {
+		return *x.ActiveQty
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetRealTradeQty() uint64 {
+	if x != nil && x.RealTradeQty != nil {
+		return *x.RealTradeQty
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetTradeID() uint64 {
+	if x != nil && x.TradeID != nil {
+		return *x.TradeID
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetBuyAccountID() uint64 {
+	if x != nil && x.BuyAccountID != nil {
+		return *x.BuyAccountID
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetSellAccountID() uint64 {
+	if x != nil && x.SellAccountID != nil {
+		return *x.SellAccountID
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetTradePrice() float64 {
+	if x != nil && x.TradePrice != nil {
+		return *x.TradePrice
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetTradeTime() string {
+	if x != nil && x.TradeTime != nil {
+		return *x.TradeTime
+	}
+	return ""
+}
+
+func (x *WRTradeDealedNtf) GetWRFactorTypeID() uint64 {
+	if x != nil && x.WRFactorTypeID != nil {
+		return *x.WRFactorTypeID
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetWRTransferUserID() uint32 {
+	if x != nil && x.WRTransferUserID != nil {
+		return *x.WRTransferUserID
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetFreezeFirstAmount() float64 {
+	if x != nil && x.FreezeFirstAmount != nil {
+		return *x.FreezeFirstAmount
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetUnFreezeFirstAmount() float64 {
+	if x != nil && x.UnFreezeFirstAmount != nil {
+		return *x.UnFreezeFirstAmount
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetRealTradeAmount() float64 {
+	if x != nil && x.RealTradeAmount != nil {
+		return *x.RealTradeAmount
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetPerformanceAmount() float64 {
+	if x != nil && x.PerformanceAmount != nil {
+		return *x.PerformanceAmount
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetPerformancePlanID() uint64 {
+	if x != nil && x.PerformancePlanID != nil {
+		return *x.PerformancePlanID
+	}
+	return 0
+}
+
+func (x *WRTradeDealedNtf) GetPerformanceTemplateID() int64 {
+	if x != nil && x.PerformanceTemplateID != nil {
+		return *x.PerformanceTemplateID
+	}
+	return 0
+}
+
 var File_mtp2_proto protoreflect.FileDescriptor
 
 var file_mtp2_proto_rawDesc = []byte{
@@ -289,20 +569,81 @@ var file_mtp2_proto_rawDesc = []byte{
 	0x54, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x52, 0x65, 0x73,
 	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x1e, 0x0a, 0x0a, 0x41, 0x63,
 	0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x32, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a,
-	0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x32, 0x22, 0x68, 0x0a, 0x13, 0x54, 0x48,
-	0x4a, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x54, 0x72, 0x61, 0x64, 0x65, 0x4e, 0x74,
-	0x66, 0x12, 0x27, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65,
-	0x61, 0x64, 0x52, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x0f, 0x57, 0x52,
-	0x54, 0x72, 0x61, 0x64, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x49, 0x44, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x04, 0x52, 0x0f, 0x57, 0x52, 0x54, 0x72, 0x61, 0x64, 0x65, 0x44, 0x65, 0x74, 0x61,
-	0x69, 0x6c, 0x49, 0x44, 0x22, 0x5e, 0x0a, 0x13, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65,
-	0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x4e, 0x74, 0x66, 0x12, 0x27, 0x0a, 0x06, 0x48,
-	0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62,
-	0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x52, 0x06, 0x48, 0x65,
-	0x61, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72,
-	0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66,
-	0x65, 0x72, 0x49, 0x44,
+	0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x32, 0x22, 0xa6, 0x01, 0x0a, 0x0a, 0x4e,
+	0x6f, 0x74, 0x69, 0x66, 0x79, 0x48, 0x65, 0x61, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x4e, 0x74, 0x66,
+	0x4d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x4e, 0x74, 0x66, 0x4d,
+	0x6f, 0x64, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x63,
+	0x63, 0x74, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0e, 0x45, 0x78, 0x63,
+	0x6c, 0x75, 0x64, 0x65, 0x41, 0x63, 0x63, 0x74, 0x49, 0x44, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x45,
+	0x78, 0x63, 0x68, 0x49, 0x44, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x07, 0x45, 0x78,
+	0x63, 0x68, 0x49, 0x44, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49,
+	0x44, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x09, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72,
+	0x49, 0x44, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44,
+	0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0a, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
+	0x49, 0x44, 0x73, 0x22, 0x68, 0x0a, 0x13, 0x54, 0x48, 0x4a, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61,
+	0x73, 0x65, 0x54, 0x72, 0x61, 0x64, 0x65, 0x4e, 0x74, 0x66, 0x12, 0x27, 0x0a, 0x06, 0x48, 0x65,
+	0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e,
+	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x52, 0x06, 0x48, 0x65, 0x61,
+	0x64, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x0f, 0x57, 0x52, 0x54, 0x72, 0x61, 0x64, 0x65, 0x44, 0x65,
+	0x74, 0x61, 0x69, 0x6c, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x57, 0x52,
+	0x54, 0x72, 0x61, 0x64, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x49, 0x44, 0x22, 0x5e, 0x0a,
+	0x13, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65,
+	0x72, 0x4e, 0x74, 0x66, 0x12, 0x27, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
+	0x65, 0x48, 0x65, 0x61, 0x64, 0x52, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a,
+	0x0a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x04, 0x52, 0x0a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x49, 0x44, 0x22, 0xad, 0x06,
+	0x0a, 0x10, 0x57, 0x52, 0x54, 0x72, 0x61, 0x64, 0x65, 0x44, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x4e,
+	0x74, 0x66, 0x12, 0x27, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48,
+	0x65, 0x61, 0x64, 0x52, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x09, 0x4e,
+	0x74, 0x66, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e,
+	0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x48, 0x65, 0x61, 0x64, 0x52, 0x09,
+	0x4e, 0x74, 0x66, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x4c, 0x69, 0x73,
+	0x74, 0x69, 0x6e, 0x67, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x04, 0x52, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49,
+	0x44, 0x12, 0x2a, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4f, 0x72,
+	0x64, 0x65, 0x72, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x44, 0x65, 0x6c,
+	0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a,
+	0x08, 0x54, 0x72, 0x61, 0x64, 0x65, 0x51, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x08, 0x54, 0x72, 0x61, 0x64, 0x65, 0x51, 0x74, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x41, 0x63, 0x74,
+	0x69, 0x76, 0x65, 0x51, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x41, 0x63,
+	0x74, 0x69, 0x76, 0x65, 0x51, 0x74, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x6c, 0x54,
+	0x72, 0x61, 0x64, 0x65, 0x51, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x52,
+	0x65, 0x61, 0x6c, 0x54, 0x72, 0x61, 0x64, 0x65, 0x51, 0x74, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x54,
+	0x72, 0x61, 0x64, 0x65, 0x49, 0x44, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x54, 0x72,
+	0x61, 0x64, 0x65, 0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x42, 0x75, 0x79, 0x41, 0x63, 0x63, 0x6f,
+	0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x42, 0x75, 0x79,
+	0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x24, 0x0a, 0x0d, 0x53, 0x65, 0x6c,
+	0x6c, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x0d, 0x53, 0x65, 0x6c, 0x6c, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x12,
+	0x1e, 0x0a, 0x0a, 0x54, 0x72, 0x61, 0x64, 0x65, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x0b, 0x20,
+	0x01, 0x28, 0x01, 0x52, 0x0a, 0x54, 0x72, 0x61, 0x64, 0x65, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12,
+	0x1c, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x64, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x09, 0x54, 0x72, 0x61, 0x64, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x26, 0x0a,
+	0x0e, 0x57, 0x52, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x49, 0x44, 0x18,
+	0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x57, 0x52, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x54,
+	0x79, 0x70, 0x65, 0x49, 0x44, 0x12, 0x2a, 0x0a, 0x10, 0x57, 0x52, 0x54, 0x72, 0x61, 0x6e, 0x73,
+	0x66, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52,
+	0x10, 0x57, 0x52, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49,
+	0x44, 0x12, 0x2c, 0x0a, 0x11, 0x46, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x46, 0x69, 0x72, 0x73, 0x74,
+	0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x01, 0x52, 0x11, 0x46, 0x72,
+	0x65, 0x65, 0x7a, 0x65, 0x46, 0x69, 0x72, 0x73, 0x74, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12,
+	0x30, 0x0a, 0x13, 0x55, 0x6e, 0x46, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x46, 0x69, 0x72, 0x73, 0x74,
+	0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x01, 0x52, 0x13, 0x55, 0x6e,
+	0x46, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x46, 0x69, 0x72, 0x73, 0x74, 0x41, 0x6d, 0x6f, 0x75, 0x6e,
+	0x74, 0x12, 0x28, 0x0a, 0x0f, 0x52, 0x65, 0x61, 0x6c, 0x54, 0x72, 0x61, 0x64, 0x65, 0x41, 0x6d,
+	0x6f, 0x75, 0x6e, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0f, 0x52, 0x65, 0x61, 0x6c,
+	0x54, 0x72, 0x61, 0x64, 0x65, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x11, 0x50,
+	0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
+	0x18, 0x12, 0x20, 0x01, 0x28, 0x01, 0x52, 0x11, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61,
+	0x6e, 0x63, 0x65, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x11, 0x50, 0x65, 0x72,
+	0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6c, 0x61, 0x6e, 0x49, 0x44, 0x18, 0x13,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63,
+	0x65, 0x50, 0x6c, 0x61, 0x6e, 0x49, 0x44, 0x12, 0x34, 0x0a, 0x15, 0x50, 0x65, 0x72, 0x66, 0x6f,
+	0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x44,
+	0x18, 0x14, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61,
+	0x6e, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x44,
 }
 
 var (
@@ -317,20 +658,24 @@ func file_mtp2_proto_rawDescGZIP() []byte {
 	return file_mtp2_proto_rawDescData
 }
 
-var file_mtp2_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
+var file_mtp2_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
 var file_mtp2_proto_goTypes = []interface{}{
 	(*MessageHead)(nil),         // 0: pb.MessageHead
-	(*THJPurchaseTradeNtf)(nil), // 1: pb.THJPurchaseTradeNtf
-	(*PurchaseTransferNtf)(nil), // 2: pb.PurchaseTransferNtf
+	(*NotifyHead)(nil),          // 1: pb.NotifyHead
+	(*THJPurchaseTradeNtf)(nil), // 2: pb.THJPurchaseTradeNtf
+	(*PurchaseTransferNtf)(nil), // 3: pb.PurchaseTransferNtf
+	(*WRTradeDealedNtf)(nil),    // 4: pb.WRTradeDealedNtf
 }
 var file_mtp2_proto_depIdxs = []int32{
 	0, // 0: pb.THJPurchaseTradeNtf.Header:type_name -> pb.MessageHead
 	0, // 1: pb.PurchaseTransferNtf.Header:type_name -> pb.MessageHead
-	2, // [2:2] is the sub-list for method output_type
-	2, // [2:2] is the sub-list for method input_type
-	2, // [2:2] is the sub-list for extension type_name
-	2, // [2:2] is the sub-list for extension extendee
-	0, // [0:2] is the sub-list for field type_name
+	0, // 2: pb.WRTradeDealedNtf.Header:type_name -> pb.MessageHead
+	1, // 3: pb.WRTradeDealedNtf.NtfHeader:type_name -> pb.NotifyHead
+	4, // [4:4] is the sub-list for method output_type
+	4, // [4:4] is the sub-list for method input_type
+	4, // [4:4] is the sub-list for extension type_name
+	4, // [4:4] is the sub-list for extension extendee
+	0, // [0:4] is the sub-list for field type_name
 }
 
 func init() { file_mtp2_proto_init() }
@@ -352,7 +697,7 @@ func file_mtp2_proto_init() {
 			}
 		}
 		file_mtp2_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*THJPurchaseTradeNtf); i {
+			switch v := v.(*NotifyHead); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -364,6 +709,18 @@ func file_mtp2_proto_init() {
 			}
 		}
 		file_mtp2_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*THJPurchaseTradeNtf); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_mtp2_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*PurchaseTransferNtf); i {
 			case 0:
 				return &v.state
@@ -375,6 +732,18 @@ func file_mtp2_proto_init() {
 				return nil
 			}
 		}
+		file_mtp2_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*WRTradeDealedNtf); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
 	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
@@ -382,7 +751,7 @@ func file_mtp2_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_mtp2_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   3,
+			NumMessages:   5,
 			NumExtensions: 0,
 			NumServices:   0,
 		},

+ 33 - 0
res/pb/mtp2.proto

@@ -17,6 +17,15 @@ message MessageHead {
 	optional uint64 AccountID2 = 11; // 账号ID-币币交易使用
 }
 
+// 公共通知消息头
+message NotifyHead {
+		optional int32 NtfMode = 1; // 消息通知模式(单播、组播、广播)
+		repeated uint32 ExcludeAcctIDs = 2; // 排除账号集合(首先过滤此集合帐号)
+		repeated uint32 ExchIDs = 3; // 目标交易所集合(若匹配所属交易所,推送)
+		repeated uint32 MemberIDs = 4; // 目标会员集合(若匹配所属会员,推送)
+		repeated uint64 AccountIDs = 5; // 目标账号集合(以上均不匹配时,最后检查此集合)
+}
+
 // 铁合金成交通知
 message THJPurchaseTradeNtf {
 	optional MessageHead Header = 1; // 消息头
@@ -27,4 +36,28 @@ message THJPurchaseTradeNtf {
 message PurchaseTransferNtf {
 	optional MessageHead Header = 1; // 消息头
 		optional uint64 TransferID = 2; // uint64 协议转让ID
+}
+
+// 仓单贸易成交通知
+message WRTradeDealedNtf {
+	optional MessageHead Header = 1; // 消息头
+		optional NotifyHead NtfHeader = 2; // NotifyHead 公共消息头
+		optional uint64 ListingOrderID = 3; // uint64 挂牌委托单号
+		optional uint64 DelistingOrderID = 4; // uint64 摘牌委托单号
+		optional uint64 TradeQty = 5; // uint64 挂牌成交数量
+		optional uint64 ActiveQty = 6; // uint64 挂牌剩余数量
+		optional uint64 RealTradeQty = 7; // uint64 摘牌实际成交数量
+		optional uint64 TradeID = 8; // uint64 成交单ID
+		optional uint64 BuyAccountID = 9; // uint64 买资金账号
+		optional uint64 SellAccountID = 10; // uint64 卖资金账号
+		optional double TradePrice = 11; // double 成交价
+		optional string TradeTime = 12; // string 成交时间
+		optional uint64 WRFactorTypeID = 13; // uint64 仓单要素ID
+		optional uint32 WRTransferUserID = 14; // uint32 仓单受让账户
+		optional double FreezeFirstAmount = 15; // double 冻结首付金额
+		optional double UnFreezeFirstAmount = 16; // double 解冻首付金额
+		optional double RealTradeAmount = 17; // double 实际成交金额
+		optional double PerformanceAmount = 18; // double 履约金额
+		optional uint64 PerformancePlanID = 19; // uint64 履约计划ID
+		optional int64 PerformanceTemplateID = 20; // int64 履约计划模板ID
 }

+ 209 - 7
service/thjNtf.go

@@ -36,6 +36,9 @@ func (t *THJNtf) Process(msg *[]byte) {
 	case uint32(global.PurchaseTransferNtf):
 		<-time.After(2 * time.Second)
 		onTHJPurchaseTransferNtf(&bytes)
+	case uint32(global.WRTradeDealedNtf):
+		<-time.After(2 * time.Second)
+		onWRTradeDealedNtf(&bytes)
 	}
 }
 
@@ -44,13 +47,20 @@ func onTHJPurchaseTradeNtf(bytes *[]byte) {
 	// Read from docx file
 	r, err := docx.ReadDocxFile("./static/产能预售合同.docx")
 	if err != nil {
-		global.M2A_LOG.Error("读取合同文件失败", zap.Error(err))
+		global.M2A_LOG.Error("[铁合金成交通知] 读取合同文件失败", zap.Error(err))
+		return
+	}
+
+	// 获取网上开户地址(用于客户端下载文件)
+	openconfig := model.Wskhopenaccountconfig{CONFIGID: 6}
+	if has, err := openconfig.Get(); err != nil || !has {
+		global.M2A_LOG.Error("[铁合金成交通知] 获取网上开户地址失败", zap.Error(err))
 		return
 	}
 
 	var p pb.THJPurchaseTradeNtf
 	if err := proto.Unmarshal(*bytes, &p); err != nil {
-		global.M2A_LOG.Error("总线回复数据反序列化失败", zap.Error(err))
+		global.M2A_LOG.Error("[铁合金成交通知] 总线回复数据反序列化失败", zap.Error(err))
 		return
 	}
 
@@ -181,7 +191,7 @@ func onTHJPurchaseTradeNtf(bytes *[]byte) {
 
 	// 导出pdf到目标目录
 	folderPath := "Purchase_Contract/" + time.Now().Format("20060102")
-	savePath := global.M2A_CONFIG.System.StorePath + "/" + folderPath
+	savePath := openconfig.CONFIGVALUE + "/" + folderPath
 	if exist, _ := utils.PathExists(savePath); !exist {
 		os.MkdirAll(savePath, os.ModePerm)
 	}
@@ -207,20 +217,27 @@ func onTHJPurchaseTransferNtf(bytes *[]byte) {
 	// Read from docx file
 	r, err := docx.ReadDocxFile("./static/协议转让合同.docx")
 	if err != nil {
-		global.M2A_LOG.Error("读取合同文件失败", zap.Error(err))
+		global.M2A_LOG.Error("[铁合金协议转让通知] 读取合同文件失败", zap.Error(err))
+		return
+	}
+
+	// 获取网上开户地址(用于客户端下载文件)
+	openconfig := model.Wskhopenaccountconfig{CONFIGID: 6}
+	if has, err := openconfig.Get(); err != nil || !has {
+		global.M2A_LOG.Error("[铁合金协议转让通知] 获取网上开户地址失败", zap.Error(err))
 		return
 	}
 
 	var p pb.PurchaseTransferNtf
 	if err := proto.Unmarshal(*bytes, &p); err != nil {
-		global.M2A_LOG.Error("总线回复数据反序列化失败", zap.Error(err))
+		global.M2A_LOG.Error("[铁合金协议转让通知] 总线回复数据反序列化失败", zap.Error(err))
 		return
 	}
 
 	// 铁合金采购协议表
 	thjpurchasetransfer := model.Thjpurchasetransfer{TRANSFERID: int64(p.GetTransferID())}
 	if has, err := thjpurchasetransfer.Get(); err != nil || !has {
-		global.M2A_LOG.Error("[铁合金协议转让通知] 获取铁合金采购成交扩展信息失败", zap.Error(err))
+		global.M2A_LOG.Error("[铁合金协议转让通知] 获取铁合金采购协议表信息失败", zap.Error(err))
 		return
 	}
 
@@ -393,7 +410,7 @@ func onTHJPurchaseTransferNtf(bytes *[]byte) {
 
 	// 导出pdf到目标目录
 	folderPath := "Agreement_Assignment/" + time.Now().Format("20060102")
-	savePath := global.M2A_CONFIG.System.StorePath + "/" + folderPath
+	savePath := openconfig.CONFIGVALUE + "/" + folderPath
 	if exist, _ := utils.PathExists(savePath); !exist {
 		os.MkdirAll(savePath, os.ModePerm)
 	}
@@ -412,3 +429,188 @@ func onTHJPurchaseTransferNtf(bytes *[]byte) {
 	}
 	global.M2A_LOG.Info("[铁合金协议转让通知] 合同生成成功", zap.Any("file", savePath+pdfFilename))
 }
+
+// onWRTradeDealedNtf 仓单贸易成交通知
+func onWRTradeDealedNtf(bytes *[]byte) {
+	var p pb.WRTradeDealedNtf
+	if err := proto.Unmarshal(*bytes, &p); err != nil {
+		global.M2A_LOG.Error("[仓单贸易成交通知] 总线回复数据反序列化失败", zap.Error(err))
+		return
+	}
+	if p.GetHeader().GetMarketID() != 65201 {
+		return
+	}
+
+	// 铁合金采购协议表
+	wrtradetradequote := model.Wrtradetradequote{WRTRADEDETAILID: int64(p.GetTradeID())}
+	if has, err := wrtradetradequote.Get(); err != nil || !has {
+		global.M2A_LOG.Error("[仓单贸易成交通知] 获取仓单贸易成交行情表信息失败", zap.Error(err))
+		return
+	}
+
+	buildWRTradeDealedContract(wrtradetradequote, 0)
+	buildWRTradeDealedContract(wrtradetradequote, 1)
+}
+
+/*
+buildWRTradeDealedContract 生成现货采购合同
+
+buyOrSell 0-买方合同 1-卖方合同
+*/
+func buildWRTradeDealedContract(wrtradetradequote model.Wrtradetradequote, buyOrSell int) {
+	tempDocx := "./static/现货贸易合同(买家模板).docx"
+	if buyOrSell == 1 {
+		tempDocx = "./static/现货贸易合同(卖家模板).docx"
+	}
+	r, err := docx.ReadDocxFile(tempDocx)
+	if err != nil {
+		global.M2A_LOG.Error("[仓单贸易成交通知] 读取合同文件失败", zap.Error(err))
+		return
+	}
+
+	// 获取网上开户地址(用于客户端下载文件)
+	openconfig := model.Wskhopenaccountconfig{CONFIGID: 6}
+	if has, err := openconfig.Get(); err != nil || !has {
+		global.M2A_LOG.Error("[仓单贸易成交通知] 获取网上开户地址失败", zap.Error(err))
+		return
+	}
+
+	// 现货商品信息
+	wrstandard := model.Wrstandard{WRSTANDARDID: int64(wrtradetradequote.WRSTANDARDID)}
+	if has, err := wrstandard.Get(); err != nil || !has {
+		global.M2A_LOG.Error("[仓单贸易成交通知] 获取现货商品信息失败", zap.Error(err))
+		return
+	}
+
+	// 甲方或乙方信息
+	userId := wrtradetradequote.BUYUSERID
+	if buyOrSell == 1 {
+		userId = wrtradetradequote.SELLUSERID
+	}
+	userinfo := model.Userinfo{USERID: userId}
+	if has, err := userinfo.Get(); err != nil || !has {
+		global.M2A_LOG.Error("[仓单贸易成交通知] 获取用户信息失败", zap.Error(err))
+		return
+	}
+	division := model.Division{AUTOID: int64(userinfo.DISTRICTID)}
+	totalAddress, err := division.GetTotalAddressByDistrictID(userinfo.ADDRESS)
+	if err != nil {
+		global.M2A_LOG.Error("[仓单贸易成交通知] 获取用户地址信息失败", zap.Error(err))
+		return
+	}
+	// 证件号码解密
+	key, _ := hex.DecodeString(utils.AESSecretKey)
+	if len(userinfo.CARDNUM) > 0 {
+		if cardnum, err := hex.DecodeString(userinfo.CARDNUM); err == nil { // hex -> []byte
+			if c, err := utils.AESDecrypt(cardnum, key); err == nil {
+				userinfo.CARDNUM = string(c)
+			}
+		}
+	}
+	// 手机号码解密
+	if len(userinfo.MOBILE) > 0 {
+		if phonenum, err := hex.DecodeString(userinfo.MOBILE); err == nil { // hex -> []byte
+			if mobile, err := utils.AESDecrypt(phonenum, key); err == nil {
+				userinfo.MOBILE = string(mobile)
+			}
+		}
+	}
+
+	// 签约信息
+	bankaccountsign := model.Bankaccountsign{}
+	if has, err := bankaccountsign.GetByUserID(uint64(userId)); err != nil || !has {
+		global.M2A_LOG.Error("[仓单贸易成交通知] 获取用户签约信息失败", zap.Error(err))
+		return
+	}
+	// 账号解密
+	if len(bankaccountsign.BANKACCOUNTNO) > 0 {
+		if tt, err := hex.DecodeString(bankaccountsign.BANKACCOUNTNO); err == nil { // hex -> []byte
+			if dd, err := utils.AESDecrypt(tt, key); err == nil {
+				bankaccountsign.BANKACCOUNTNO = string(dd)
+			}
+		}
+	}
+
+	// 银行信息
+	bankinfo := model.Bankbankinfo{BANKID: bankaccountsign.BANKID}
+	if has, err := bankinfo.Get(); err != nil || !has {
+		global.M2A_LOG.Error("[仓单贸易成交通知] 获取银行信息失败", zap.Error(err))
+		return
+	}
+
+	// 电子仓单号
+	type temp struct {
+		LADINGBILLID string `xorm:"LADINGBILLID"`
+	}
+	_temp := temp{}
+	sql := fmt.Sprintf(`
+	select 
+		to_char(wrd.LADINGBILLID) LADINGBILLID
+	from wrtrade_tradedetail td
+	left join WRChangeDetail wrd on td.wrid = wrd.wrid and wrd.changetype = 1
+	where td.WRTRADEDETAILID = %v and td.wrtradetype = 2
+  	`, wrtradetradequote.WRTRADEDETAILID)
+	global.M2A_DB.SQL(sql).Get(&_temp)
+
+	docx1 := r.Editable()
+	docx1.Replace("${WRTRADEDETAILID}", strconv.Itoa(int(wrtradetradequote.WRTRADEDETAILID)), -1)
+	if transfertradedate, e := time.Parse("20060102", wrtradetradequote.TRADEDATE); e != nil {
+		docx1.Replace("TRADEDATE", transfertradedate.Format("2006年01月02日"), -1)
+	}
+	// 判断是公司还是个人
+	if userinfo.USERINFOTYPE == 1 {
+		// 个人
+		docx1.Replace("COMPANY", "", -1)
+		docx1.Replace("LEGALPERSONNAME", userinfo.CUSTOMERNAME, -1)
+	} else {
+		// 公司
+		docx1.Replace("COMPANY", userinfo.CUSTOMERNAME, -1)
+		docx1.Replace("LEGALPERSONNAME", userinfo.LEGALPERSONNAME, -1)
+	}
+	docx1.Replace("DESADDRESS", totalAddress, -1)
+	docx1.Replace("CARDNUM", userinfo.CARDNUM, -1)
+	docx1.Replace("MOBILE", userinfo.MOBILE, -1)
+	docx1.Replace("BANK", bankinfo.BANKNAME, -1)
+	docx1.Replace("BANKACCOUNTNO", bankaccountsign.BANKACCOUNTNO, -1)
+	docx1.Replace("WRSTANDARDNAME", wrstandard.WRSTANDARDNAME, -1)
+	docx1.Replace("TRADEQTY", strconv.Itoa(int(wrtradetradequote.TRADEQTY)), -1)
+	docx1.Replace("TRADEPRICE", strconv.FormatFloat(wrtradetradequote.TRADEPRICE, 'f', -1, 64), -1)
+	docx1.Replace("TRADEAMOUNT", strconv.FormatFloat(wrtradetradequote.TRADEAMOUNT, 'f', -1, 64), -1)
+	docx1.Replace("STORAGEFEE", strconv.FormatFloat(wrstandard.STORAGEFEE, 'f', -1, 64), -1)
+	docx1.Replace("LADINGBILLID", _temp.LADINGBILLID, -1)
+
+	// 暂存docx文件
+	if exist, _ := utils.PathExists("./.tmp"); !exist {
+		os.Mkdir("./.tmp", os.ModePerm)
+	}
+	uid, _ := uuid.NewV4()
+	docxFilename := fmt.Sprintf("%v_%v_%v.docx", buyOrSell, strconv.Itoa(int(wrtradetradequote.WRTRADEDETAILID)), uid.String())
+	pdfFilename := strings.Replace(docxFilename, "docx", "pdf", -1)
+	docx1.WriteToFile("./.tmp/" + docxFilename)
+	r.Close()
+
+	// 导出pdf到目标目录
+	folderPath := "Spot_Contract/" + time.Now().Format("20060102")
+	savePath := openconfig.CONFIGVALUE + "/" + folderPath
+	if exist, _ := utils.PathExists(savePath); !exist {
+		os.MkdirAll(savePath, os.ModePerm)
+	}
+	success := utils.ConvertToPDF("./.tmp/"+docxFilename, savePath)
+	if !success {
+		// 转换失败
+		global.M2A_LOG.Error("[仓单贸易成交通知] docx转换pdf失败", zap.Error(err))
+		return
+	}
+
+	// 更新数据库
+	if buyOrSell == 0 {
+		wrtradetradequote.CONTRACTADDRBUY = fmt.Sprintf("./uploadFile/%v/%v", folderPath, pdfFilename)
+	} else {
+		wrtradetradequote.CONTRACTADDRSELL = fmt.Sprintf("./uploadFile/%v/%v", folderPath, pdfFilename)
+	}
+	if err = wrtradetradequote.UpdateContractAddr(buyOrSell); err != nil {
+		global.M2A_LOG.Error("[仓单贸易成交通知] 更新数据库失败", zap.Error(err))
+		return
+	}
+	global.M2A_LOG.Info("[仓单贸易成交通知] 合同生成成功", zap.Any("file", savePath+pdfFilename))
+}

+ 0 - 36
static/main.go

@@ -1,36 +0,0 @@
-package main
-
-import (
-	"github.com/nguyenthenguyen/docx"
-)
-
-func main() {
-	// Read from docx file
-	r, err := docx.ReadDocxFile("./现货预售合同.docx")
-	if err != nil {
-		return
-	}
-
-	docx1 := r.Editable()
-	docx1.Replace("${WRTRADEDETAILID}", "WRTRADEDETAILID", -1)
-	docx1.Replace("${TRADETIME}", "TRADETIME", -1)
-	docx1.Replace("${DESADDRESS}", "DESADDRESS", -1)
-	docx1.Replace("${CUSTOMERNAME}", "CUSTOMERNAME", -1)
-	docx1.Replace("${CARDNUM}", "CARDNUM", -1)
-	docx1.Replace("${MOBILE}", "MOBILE", -1)
-	docx1.Replace("${BANK}", "BANK", -1)
-	docx1.Replace("${BANKACCOUNTNO}", "BANKACCOUNTNO", -1)
-	docx1.Replace("${WRSTANDARDNAME}", "WRSTANDARDNAME", -1)
-	docx1.Replace("${SELLUSER}", "SELLUSER", -1)
-	docx1.Replace("${LASTAMOUNT}", "LASTAMOUNT", -1)
-	docx1.Replace("${DEPOSITRATE}", "DEPOSITRATE", -1)
-	docx1.Replace("${TRADEQTY}", "TRADEQTY", -1)
-	docx1.Replace("${TRADEPRICE}", "TRADEPRICE", -1)
-	docx1.Replace("${ENDDATEMONTH}", "ENDDATEMONTH", -1)
-	docx1.Replace("${THJDELIVERYMODE}", "THJDELIVERYMODE", -1)
-	docx1.Replace("${ENDDATE}", "ENDDATE", -1)
-	docx1.Replace("${STORAGEFEE}", "STORAGEFEE", -1)
-
-	docx1.WriteToFile("./new_result_1.doc")
-	r.Close()
-}

BIN
static/现货贸易合同(买家模板).docx


BIN
static/现货贸易合同(卖家模板).docx