package models

import (
	"encoding/hex"
	"fmt"
	"math"
	"mtp2_if/db"
	"mtp2_if/pb"
	"mtp2_if/utils"
	"strconv"
	"strings"
	"time"

	"google.golang.org/protobuf/proto"
)

// Hsbygoodsex 商品扩展表
type Hsbygoodsex struct {
	Goodsid        int32     `json:"goodsid"  xorm:"'GOODSID'" binding:"required"` // 商 品ID
	Hotindex       int32     `json:"hotindex"  xorm:"'HOTINDEX'"`                  // 景点热度
	Descprovinceid int64     `json:"descprovinceid"  xorm:"'DESCPROVINCEID'"`      // 目的地(省)
	Desccityid     int64     `json:"desccityid"  xorm:"'DESCCITYID'"`              // 目的地(市)
	Vendorid       int32     `json:"vendorid"  xorm:"'VENDORID'"`                  // 供应商ID
	Goodsdesc      string    `json:"goodsdesc"  xorm:"'GOODSDESC'"`                // 商品详情
	Createtime     time.Time `json:"createtime"  xorm:"'CREATETIME'"`              // 创建时间
	Creatorid      int64     `json:"creatorid"  xorm:"'CREATORID'"`                // 创建人
	Modifierid     int64     `json:"modifierid"  xorm:"'MODIFIERID'"`              // 修改人
	Modifytime     time.Time `json:"modifytime"  xorm:"'MODIFYTIME'"`              // 修改时间
	Memberratio    float64   `json:"memberratio"  xorm:"'MEMBERRATIO'"`            // 会员货款比例 [71]
	Videourls      string    `json:"videourls"  xorm:"'VIDEOURLS'"`                // 介绍视频[多张用逗号分隔]
	Picurls        string    `json:"picurls"  xorm:"'PICURLS'"`                    // 介绍图片[多张用逗号分隔]
	Goodsprice     float64   `json:"goodsprice"  xorm:"'GOODSPRICE'"`              // 商品价格
	Categoryid     int32     `json:"categoryid"  xorm:"'CATEGORYID'"`              // 类别ID(WRCATEGORY)
}

// TableName is HSBY_GOODSEX
func (Hsbygoodsex) TableName() string {
	return "HSBY_GOODSEX"
}

// Hsbysupplierinfo 供应商表
type Hsbysupplierinfo struct {
	Vendorid    int32     `json:"vendorid"  xorm:"'VENDORID'" binding:"required"` // 供应商ID(SEQ_HSBY_SUPPLIERINFO)
	Vendorname  string    `json:"vendorname"  xorm:"'VENDORNAME'"`                // 名称描述客服电话名称
	Vendordesc  string    `json:"vendordesc"  xorm:"'VENDORDESC'"`                // 描述
	Vendorphone string    `json:"vendorphone"  xorm:"'VENDORPHONE'"`              // 客服电话
	Vendorattr  string    `json:"vendorattr"  xorm:"'VENDORATTR'"`                // 附件(多张，逗号分隔)
	Createtime  time.Time `json:"createtime"  xorm:"'CREATETIME'"`                // 创建时间
	Creatorid   int64     `json:"creatorid"  xorm:"'CREATORID'"`                  // 创建人
	Modifierid  int64     `json:"modifierid"  xorm:"'MODIFIERID'"`                // 修改人
	Modifytime  time.Time `json:"modifytime"  xorm:"'MODIFYTIME'"`                // 修改时间
}

// TableName is HSBY_SUPPLIERINFO
func (Hsbysupplierinfo) TableName() string {
	return "HSBY_SUPPLIERINFO"
}

// Tradepayorder 交易待付款表
type Tradepayorder struct {
	Tradeid        int64     `json:"tradeid"  xorm:"'TRADEID'" binding:"required"` // 成交单号(101+Unix秒时间戳(10位)+2位(MarketServiceID)+xxxx)
	Tradedate      string    `json:"tradedate"  xorm:"'TRADEDATE'"`                // 交易日(yyyyMMdd)
	Marketid       int32     `json:"marketid"  xorm:"'MARKETID'"`                  // 市场ID
	Goodsid        int32     `json:"goodsid"  xorm:"'GOODSID'"`                    // 商品ID
	Buyorderid     int64     `json:"buyorderid"  xorm:"'BUYORDERID'"`              // 买方委托单号
	Buyaccountid   int64     `json:"buyaccountid"  xorm:"'BUYACCOUNTID'"`          // 买方账号ID[报价币种]
	Sellorderid    int64     `json:"sellorderid"  xorm:"'SELLORDERID'"`            // 卖方委托单号
	Sellaccountid  int64     `json:"sellaccountid"  xorm:"'SELLACCOUNTID'"`        // 卖方账号ID[报价币种]
	Tradeamount    float64   `json:"tradeamount"  xorm:"'TRADEAMOUNT'"`            // 成交金额
	Tradecharge    float64   `json:"tradecharge"  xorm:"'TRADECHARGE'"`            // 成交手续费(买方)
	Payflag        int32     `json:"payflag"  xorm:"'PAYFLAG'"`                    // 付款标识 - 1:未支付 2:已支付 3:已过期 4:已撤销 5:结算过期 6:预售终止
	Createtime     time.Time `json:"createtime"  xorm:"'CREATETIME'"`              // 创建时间
	Paytime        time.Time `json:"paytime"  xorm:"'PAYTIME'"`                    // 付款时间
	Paylimitedtime time.Time `json:"paylimitedtime"  xorm:"'PAYLIMITEDTIME'"`      // 支付期限
	Offamount      float64   `json:"offamount"  xorm:"'OFFAMOUNT'"`                // 优惠金额
	Tradeprice     float64   `json:"tradeprice"  xorm:"'TRADEPRICE'"`              // 成交价格
	Tradeqty       int64     `json:"tradeqty"  xorm:"'TRADEQTY'"`                  // 成交数量
	Payamount      float64   `json:"payamount"  xorm:"'PAYAMOUNT'"`                // 支付金额 = TradeAmount + TradeCharge - OffAmount
}

// TableName is TRADE_PAYORDER
func (Tradepayorder) TableName() string {
	return "TRADE_PAYORDER"
}

// Coupontype 优惠券类型表
type Coupontype struct {
	Coupontypeid    int32     `json:"coupontypeid"  xorm:"'COUPONTYPEID'" binding:"required"` // 优惠券类型ID - SEQ_COUPONTYPE
	Areauserid      int64     `json:"areauserid"  xorm:"'AREAUSERID'"`                        // 所属机构
	Couponname      string    `json:"couponname"  xorm:"'COUPONNAME'"`                        // 优惠券名称
	Couponcategroy  int32     `json:"couponcategroy"  xorm:"'COUPONCATEGROY'"`                // 种类 - 1:现金券 2:折扣券 3:折扣券(单张)
	Conditionvalue  float64   `json:"conditionvalue"  xorm:"'CONDITIONVALUE'"`                // 条件阈值(可为0)
	Couponvalue     float64   `json:"couponvalue"  xorm:"'COUPONVALUE'"`                      // 面值[1:现金券 - 抵扣值 2:折扣券-折扣值]
	Limitedflag     int32     `json:"limitedflag"  xorm:"'LIMITEDFLAG'"`                      // 是否指定商品 - 0:不限 1:限制
	Limitedgoodsids string    `json:"limitedgoodsids"  xorm:"'LIMITEDGOODSIDS'"`              // 指定商品IDs[逗号分隔,前后加逗号]
	Isgeneral       int32     `json:"isgeneral"  xorm:"'ISGENERAL'"`                          // 是否通用券 - 0:否 1:是
	Userscope       string    `json:"userscope"  xorm:"'USERSCOPE'"`                          // 卖家范围(用户ID，逗号分隔,前后加逗号) [IsGeneral =0时使用]
	Qty             int64     `json:"qty"  xorm:"'QTY'"`                                      // 数量
	Curqty          int64     `json:"curqty"  xorm:"'CURQTY'"`                                // 剩余数量
	Createtime      time.Time `json:"createtime"  xorm:"'CREATETIME'"`                        // 创建时间
	Creatorid       int64     `json:"creatorid"  xorm:"'CREATORID'"`                          // 创建人
	Modifierid      int64     `json:"modifierid"  xorm:"'MODIFIERID'"`                        // 修改人
	Modifytime      time.Time `json:"modifytime"  xorm:"'MODIFYTIME'"`                        // 修改时间
	Usedqty         int64     `json:"usedqty"  xorm:"'USEDQTY'"`                              // 使用量
	Isvalid         int32     `json:"isvalid"  xorm:"'ISVALID'"`                              // 是否有效 - 0:无效 1:有效
	Expiredqty      int64     `json:"expiredqty"  xorm:"'EXPIREDQTY'"`                        // 失效量
}

// TableName is COUPONTYPE
func (Coupontype) TableName() string {
	return "COUPONTYPE"
}

// Couponposition 优惠券头寸表 - 导历史(期末为0的清除)
type Couponposition struct {
	Accountid     int64 `json:"accountid"  xorm:"'ACCOUNTID'" binding:"required"`       // 资金账户ID
	Coupontypeid  int32 `json:"coupontypeid"  xorm:"'COUPONTYPEID'" binding:"required"` // 优惠券类型ID
	Userid        int64 `json:"userid"  xorm:"'USERID'"`                                // 用户ID
	Oriqty        int64 `json:"oriqty"  xorm:"'ORIQTY'"`                                // 期初数量
	Orifreezeqty  int64 `json:"orifreezeqty"  xorm:"'ORIFREEZEQTY'"`                    // 期初冻结数量
	Curqty        int64 `json:"curqty"  xorm:"'CURQTY'"`                                // 期末数量
	Curfreezeqty  int64 `json:"curfreezeqty"  xorm:"'CURFREEZEQTY'"`                    // 期末冻结数量
	Todayincrease int64 `json:"todayincrease"  xorm:"'TODAYINCREASE'"`                  // 今日增加
	Todaydecrease int64 `json:"todaydecrease"  xorm:"'TODAYDECREASE'"`                  // 今日减少
}

// TableName is COUPONPOSITION
func (Couponposition) TableName() string {
	return "COUPONPOSITION"
}

// Couponhold 优惠券持仓表 - 导历史(不清当前表) - 每一个数量一条记录
type Couponhold struct {
	Couponholdid    int64     `json:"couponholdid"  xorm:"'COUPONHOLDID'" binding:"required"` // 优惠券持仓ID(229+Unix秒时间戳(10位)+xxxxxx)
	Giveapplyid     int64     `json:"giveapplyid"  xorm:"'GIVEAPPLYID'"`                      // 发放申请ID(SEQ_COUPONGIVEAPPLY)
	Accountid       int64     `json:"accountid"  xorm:"'ACCOUNTID'"`                          // 资金账户ID
	Coupontypeid    int32     `json:"coupontypeid"  xorm:"'COUPONTYPEID'"`                    // 优惠券类型ID - SEQ_COUPONTYPE
	Couponcategroy  int32     `json:"couponcategroy"  xorm:"'COUPONCATEGROY'"`                // 种类 - 1:现金券 2:折扣券 3:折扣券(单个商品)
	Conditionvalue  float64   `json:"conditionvalue"  xorm:"'CONDITIONVALUE'"`                // 条件阈值(可为0)
	Couponvalue     float64   `json:"couponvalue"  xorm:"'COUPONVALUE'"`                      // 面值[1:现金券 - 抵扣值 2:折扣券-折扣值]
	Limitedflag     int32     `json:"limitedflag"  xorm:"'LIMITEDFLAG'"`                      // 是否指定商品 - 0:不限 1:限制
	Limitedgoodsids string    `json:"limitedgoodsids"  xorm:"'LIMITEDGOODSIDS'"`              // 指定商品IDs[逗号分隔]
	Isgeneral       int32     `json:"isgeneral"  xorm:"'ISGENERAL'"`                          // 是否通用券 - 0:否 1:是
	Userscope       string    `json:"userscope"  xorm:"'USERSCOPE'"`                          // 卖家范围(用户ID，逗号分隔) [IsGeneral =0时使用]
	Userid          int64     `json:"userid"  xorm:"'USERID'"`                                // 用户ID
	Qty             int64     `json:"qty"  xorm:"'QTY'"`                                      // 数量(按1平铺)
	Startdate       time.Time `json:"startdate"  xorm:"'STARTDATE'"`                          // 开始日期
	Holdstatus      int32     `json:"holdstatus"  xorm:"'HOLDSTATUS'"`                        // 持仓状态 - 1:未生效 2:已生效 3:已使用 4:已过期
	Enddate         time.Time `json:"enddate"  xorm:"'ENDDATE'"`                              // 结束日期
	Createtime      time.Time `json:"createtime"  xorm:"'CREATETIME'"`                        // 创建时间
}

// TableName is COUPONHOLD
func (Couponhold) TableName() string {
	return "COUPONHOLD"
}

// Tradeordercoupon 交易委托优惠券表
type Tradeordercoupon struct {
	Orderid        string    `json:"orderid"  xorm:"'ORDERIDSTR'" binding:"required"`           // 委托单号(100+Unix秒时间戳(10位)+2位(MarketServiceID)+xxxx)
	Coupontypeid   string    `json:"coupontypeid"  xorm:"'COUPONTYPEIDSTR'" binding:"required"` // 优惠券类型ID(买方)
	Accountid      int64     `json:"accountid"  xorm:"'ACCOUNTID'"`                             // 资金账户ID(买方)
	Usedqty        int64     `json:"usedqty"  xorm:"'USEDQTY'"`                                 // 使用数量
	Couponcategroy int32     `json:"couponcategroy"  xorm:"'COUPONCATEGROY'"`                   // 种类 - 1:现金券 2:折扣券
	Conditionvalue float64   `json:"conditionvalue"  xorm:"'CONDITIONVALUE'"`                   // 条件阈值(可为0)
	Couponvalue    float64   `json:"couponvalue"  xorm:"'COUPONVALUE'"`                         // 面值[1:现金券 - 抵扣值 2:折扣券-折扣值(0-100)]
	Sellaccountid  int64     `json:"sellaccountid"  xorm:"'SELLACCOUNTID'"`                     // 资金账户ID(卖方)
	Marketid       int32     `json:"marketid"  xorm:"'MARKETID'"`                               // 市场ID
	Goodsid        int32     `json:"goodsid"  xorm:"'GOODSID'"`                                 // 商品ID
	Tradeid        string    `json:"tradeid"  xorm:"'TRADEIDSTR'"`                              // 成交单号(101+Unix秒时间戳(10位)+2位(MarketServiceID)+xxxx)
	Tradeamount    float64   `json:"tradeamount"  xorm:"'TRADEAMOUNT'"`                         // 成交金额
	Offamount      float64   `json:"offamount"  xorm:"'OFFAMOUNT'"`                             // 优惠金额
	Handlestatus   int32     `json:"handlestatus"  xorm:"'HANDLESTATUS'"`                       // 处理状态
	Createtime     time.Time `json:"createtime"  xorm:"'CREATETIME'"`                           // 创建时间
}

// TableName is TRADE_ORDERCOUPON
func (Tradeordercoupon) TableName() string {
	return "TRADE_ORDERCOUPON"
}

// Hiscouponhold 优惠卷持仓历史表
type Hiscouponhold struct {
	Couponholdid    int64     `json:"couponholdid"  xorm:"'COUPONHOLDID'" binding:"required"` //
	Giveapplyid     int64     `json:"giveapplyid"  xorm:"'GIVEAPPLYID'"`                      //
	Accountid       int64     `json:"accountid"  xorm:"'ACCOUNTID'"`                          //
	Coupontypeid    int32     `json:"coupontypeid"  xorm:"'COUPONTYPEID'"`                    //
	Couponcategroy  int32     `json:"couponcategroy"  xorm:"'COUPONCATEGROY'"`                //
	Conditionvalue  float64   `json:"conditionvalue"  xorm:"'CONDITIONVALUE'"`                //
	Couponvalue     float64   `json:"couponvalue"  xorm:"'COUPONVALUE'"`                      //
	Limitedflag     int32     `json:"limitedflag"  xorm:"'LIMITEDFLAG'"`                      //
	Limitedgoodsids string    `json:"limitedgoodsids"  xorm:"'LIMITEDGOODSIDS'"`              //
	Isgeneral       int32     `json:"isgeneral"  xorm:"'ISGENERAL'"`                          //
	Userscope       string    `json:"userscope"  xorm:"'USERSCOPE'"`                          //
	Userid          int64     `json:"userid"  xorm:"'USERID'"`                                //
	Qty             int64     `json:"qty"  xorm:"'QTY'"`                                      //
	Startdate       time.Time `json:"startdate"  xorm:"'STARTDATE'"`                          //
	Holdstatus      int32     `json:"holdstatus"  xorm:"'HOLDSTATUS'"`                        //
	Enddate         time.Time `json:"enddate"  xorm:"'ENDDATE'"`                              //
	Createtime      time.Time `json:"createtime"  xorm:"'CREATETIME'"`                        //
	Histradedate    string    `json:"histradedate"  xorm:"'HISTRADEDATE'" binding:"required"` //
	Isvaliddata     int32     `json:"isvaliddata"  xorm:"'ISVALIDDATA'"`                      //
	Oriqty          int64     `json:"oriqty"  xorm:"'ORIQTY'"`                                //
}

// TableName is HIS_COUPONHOLD
func (Hiscouponhold) TableName() string {
	return "HIS_COUPONHOLD"
}

// Clientfixedadconfig 终端固定广告配置 - 通用功能
type Clientfixedadconfig struct {
	Adtype     int32     `json:"adtype"  xorm:"'ADTYPE'" binding:"required"` // 广告位类型 - 1:新品抢购(HSBY)
	Adsort     int32     `json:"adsort"  xorm:"'ADSORT'" binding:"required"` // 排序
	Imagepath  string    `json:"imagepath"  xorm:"'IMAGEPATH'"`              // 图片
	Recsize    string    `json:"recsize"  xorm:"'RECSIZE'"`                  // 推荐尺寸
	Title      string    `json:"title"  xorm:"'TITLE'"`                      // 标题
	Urltype    int32     `json:"urltype"  xorm:"'URLTYPE'"`                  // 链接类型 - 1:直接地址 2:商品ID
	Urlcontent string    `json:"urlcontent"  xorm:"'URLCONTENT'"`            // 链接(地址或商品ID)
	Isshow     int32     `json:"isshow"  xorm:"'ISSHOW'"`                    // 是否展示 - 0:不展示 1:展示
	Createdate time.Time `json:"createdate"  xorm:"'CREATEDATE'"`            // 创建时间
	Creatorid  int64     `json:"creatorid"  xorm:"'CREATORID'"`              // 创建人
	Updatedate time.Time `json:"updatedate"  xorm:"'UPDATEDATE'"`            // 更新时间
	Modifierid int64     `json:"modifierid"  xorm:"'MODIFIERID'"`            // 操作人
	Areauserid int64     `json:"areauserid"  xorm:"'AREAUSERID'"`            // 所属机构ID
}

// TableName is CLIENT_FIXEDADCONFIG
func (Clientfixedadconfig) TableName() string {
	return "CLIENT_FIXEDADCONFIG"
}

// HsbyTopGoods 热卖商品（二级市场挂牌点选）
type HsbyTopGoods struct {
	Goodsid      int64   `json:"goodsid"  xorm:"'GOODSID'" binding:"required"`     // 商品ID(自增ID SEQ_GOODS)
	Goodscode    string  `json:"goodscode"  xorm:"'GOODSCODE'" binding:"required"` // 商品代码(内部)
	Goodsname    string  `json:"goodsname"  xorm:"'GOODSNAME'" binding:"required"` // 商品名称
	Decimalplace int64   `json:"decimalplace"  xorm:"'DECIMALPLACE'"`              // 报价小数位
	Marketid     int64   `json:"marketid"  xorm:"'MARKETID'" binding:"required"`   // 所属市场ID
	Quoteminunit int64   `json:"quoteminunit"  xorm:"'QUOTEMINUNIT'"`              // 行情最小变动单位 [整数，报价小数位一起使用]
	Agreeunit    float64 `json:"agreeunit"  xorm:"'AGREEUNIT'"`                    // 合约单位

	Hotindex       int32  `json:"hotindex"  xorm:"'HOTINDEX'"`             // 景点热度
	Videourls      string `json:"videourls"  xorm:"'VIDEOURLS'"`           // 介绍视频[多张用逗号分隔]
	Picurls        string `json:"picurls"  xorm:"'PICURLS'"`               // 介绍图片[多张用逗号分隔]
	Descprovinceid int64  `json:"descprovinceid"  xorm:"'DESCPROVINCEID'"` // 目的地(省)
	Desccityid     int64  `json:"desccityid"  xorm:"'DESCCITYID'"`         // 目的地(市)

	Currency     string `json:"currency" xorm:"'CURRENCY'"`         // 货币
	Currencysign string `json:"currencysign" xorm:"'CURRENCYSIGN'"` // 货币符号

	Trademode int32 `json:"trademode"  xorm:"'TRADEMODE'" binding:"required"` // 交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价

	Last float64 `json:"last" xorm:"-"` // 现价
}

// GetHsbyTopGoodses 获取热门商品列表
// 参数 marketIDs string 所属市场ID列表, 格式 1,2,3
// 参数 descProvinceID int 目标省ID
// 参数 descCityID int 目标城市ID
// 返回 []TopGoods 热门商品列表
// 返回 error error
func GetHsbyTopGoodses(marketIDs string, descProvinceID, descCityID int) ([]HsbyTopGoods, error) {
	// 热门商品为二级市场（挂牌点选）下的商品信息

	engine := db.GetEngine()

	topGoodses := make([]HsbyTopGoods, 0)
	// 获取挂牌商品信息，以及扩展表信息
	// 与商城不一样的是，挂牌点选以商品表作为主表，同一商品可有多个委托单
	session := engine.Table("GOODS").
		Select(`GOODS.*, 
				HSBY_GOODSEX.HOTINDEX, HSBY_GOODSEX.VIDEOURLS, HSBY_GOODSEX.PICURLS, HSBY_GOODSEX.DESCPROVINCEID, HSBY_GOODSEX.DESCCITYID, 
				ENUMDICITEM.ENUMDICNAME CURRENCY, ENUMDICITEM.PARAM2 CURRENCYSIGN, 
				MARKET.TRADEMODE`).
		Join("LEFT", "HSBY_GOODSEX", "HSBY_GOODSEX.GOODSID = GOODS.GOODSID").
		Join("LEFT", "ENUMDICITEM", "ENUMDICITEM.ENUMITEMNAME = GOODS.CURRENCYID and ENUMDICITEM.ENUMDICCODE = 'currency'").
		Join("LEFT", "MARKET", "MARKET.MARKETID = GOODS.MARKETID").
		Where(fmt.Sprintf("GOODS.GOODSSTATUS = 3 and GOODS.MARKETID in (%s)", marketIDs)) // 二级市场只获取 3:上市 状态的商品
	if descProvinceID > 0 {
		session = session.And("HSBY_GOODSEX.DESCPROVINCEID = ?", descProvinceID)
	}
	if descCityID > 0 {
		session = session.And("HSBY_GOODSEX.DESCCITYID = ?", descCityID)
	}
	if err := session.Find(&topGoodses); err != nil {
		return nil, err
	}
	if len(topGoodses) == 0 {
		// 无数据
		return topGoodses, nil
	}
	// 获取商品ID列表
	goodsCodes := ""
	for _, v := range topGoodses {
		if len(goodsCodes) == 0 {
			goodsCodes = "'" + v.Goodscode + "'"
		} else {
			goodsCodes += ",'" + v.Goodscode + "'"
		}
	}

	// 获取商品现价
	quoteDays, err := GetQuoteDays(goodsCodes)
	if err != nil {
		return nil, err
	}
	for i, g := range topGoodses {
		topGoods := &topGoodses[i]
		// FIXME: - 这里应该使用 Duck Typing，后期再处理
		// 计算最小变动单位
		// lotSize := float64(topGoods.Quoteminunit) * math.Pow(0.1, float64(topGoods.Decimalplace))
		// topGoods.LotSize, _ = strconv.ParseFloat(utils.FormatFloat(lotSize, int(topGoods.Decimalplace)), 64)

		for _, q := range quoteDays {
			if g.Goodscode == q.Goodscode {
				if q.Last != 0 {
					topGoods.Last = utils.IntToFloat64(int(q.Last), int(g.Decimalplace))
				}
				// 没有现价则尝试用昨结
				if topGoods.Last == 0 && q.Presettle != 0 {
					topGoods.Last = utils.IntToFloat64(int(q.Presettle), int(g.Decimalplace))
				}

				continue
			}
		}
	}

	return topGoodses, nil
}

// HsbyListingGoodsDetail 二级市场（挂牌点选）商品信息详情
type HsbyListingGoodsDetail struct {
	Goodsid      int64   `json:"goodsid"  xorm:"'GOODSID'" binding:"required"`     // 商品ID(自增ID SEQ_GOODS)
	Goodscode    string  `json:"goodscode"  xorm:"'GOODSCODE'" binding:"required"` // 商品代码(内部)
	Goodsname    string  `json:"goodsname"  xorm:"'GOODSNAME'" binding:"required"` // 商品名称
	Decimalplace int64   `json:"decimalplace"  xorm:"'DECIMALPLACE'"`              // 报价小数位
	Marketid     int64   `json:"marketid"  xorm:"'MARKETID'" binding:"required"`   // 所属市场ID
	Quoteminunit int64   `json:"quoteminunit"  xorm:"'QUOTEMINUNIT'"`              // 行情最小变动单位 [整数，报价小数位一起使用]
	Agreeunit    float64 `json:"agreeunit"  xorm:"'AGREEUNIT'"`                    // 合约单位

	Hotindex       int32   `json:"hotindex"  xorm:"'HOTINDEX'"`             // 景点热度
	Videourls      string  `json:"videourls"  xorm:"'VIDEOURLS'"`           // 介绍视频[多张用逗号分隔]
	Picurls        string  `json:"picurls"  xorm:"'PICURLS'"`               // 介绍图片[多张用逗号分隔]
	Descprovinceid int64   `json:"descprovinceid"  xorm:"'DESCPROVINCEID'"` // 目的地(省)ID
	Desccityid     int64   `json:"desccityid"  xorm:"'DESCCITYID'"`         // 目的地(市)ID
	Goodsdesc      string  `json:"goodsdesc"  xorm:"'GOODSDESC'"`           // 商品详情
	Goodsprice     float64 `json:"goodsprice"  xorm:"'GOODSPRICE'"`         // 商品价格

	Currency     string `json:"currency" xorm:"'CURRENCY'"`         // 货币
	Currencysign string `json:"currencysign" xorm:"'CURRENCYSIGN'"` // 货币符号

	Vendorname  string `json:"vendorname"  xorm:"'VENDORNAME'"`   // 供应商名称
	Vendorphone string `json:"vendorphone"  xorm:"'VENDORPHONE'"` // 供应商客服电话
	Vendorattr  string `json:"vendorattr"  xorm:"'VENDORATTR'"`   // 供应商附件(多张，逗号分隔)

	Trademode int32 `json:"trademode"  xorm:"'TRADEMODE'" binding:"required"` // 交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价

	Last      float64 `json:"last" xorm:"-"`         // 现价
	Limitup   float64 `json:"limitup" xorm:"-"`      // 涨停价
	Limitdown float64 `json:"limitdown" xorm:"-"`    // 跌停价
	StepValue float64 `json:"stepvalue" xorm:"-"`    // 价格最小变动单位
	LotSize   int     `json:"lotsize" xorm:"-"`      // 手数最小变动单位
	Buymaxqty int     `json:"buymaxqty"  xorm:"'-'"` // 购买上限 [71] - 0为不限
}

// GetHsbyListingGoodsDetail 获取二级市场（挂牌点选）商品信息详情
// 参数 goodsID int 目标商品ID
// 返回 *HsbyListingGoodsDetail 二级市场（挂牌点选）商品信息详情，查询无结果返回nil
// 返回 error error
func GetHsbyListingGoodsDetail(goodsID, accountID int) (*HsbyListingGoodsDetail, error) {
	engine := db.GetEngine()

	details := make([]HsbyListingGoodsDetail, 0)
	// 获取挂牌商品信息，以及扩展表信息
	// FIXME: - 这里使用Get方法，会造成SQL语句的嵌套出错，后期再研究
	session := engine.Table("GOODS").
		Select(`GOODS.GOODSID, GOODS.GOODSCODE, GOODS.GOODSNAME, GOODS.DECIMALPLACE, GOODS.MARKETID, GOODS.QUOTEMINUNIT, GOODS.AGREEUNIT, 
				HSBY_GOODSEX.HOTINDEX, HSBY_GOODSEX.VIDEOURLS, HSBY_GOODSEX.PICURLS, HSBY_GOODSEX.DESCPROVINCEID, HSBY_GOODSEX.Desccityid, HSBY_GOODSEX.Goodsdesc, HSBY_GOODSEX.GOODSPRICE, 
				ENUMDICITEM.ENUMDICNAME CURRENCY, ENUMDICITEM.PARAM2 CURRENCYSIGN, 
				HSBY_SUPPLIERINFO.VENDORNAME, HSBY_SUPPLIERINFO.VENDORPHONE, HSBY_SUPPLIERINFO.VENDORATTR, 
				MARKET.TRADEMODE`).
		Join("LEFT", "HSBY_GOODSEX", "HSBY_GOODSEX.GOODSID = GOODS.GOODSID").
		Join("LEFT", "ENUMDICITEM", "ENUMDICITEM.ENUMITEMNAME = GOODS.CURRENCYID and ENUMDICITEM.ENUMDICCODE = 'currency'").
		Join("LEFT", "HSBY_SUPPLIERINFO", "HSBY_SUPPLIERINFO.VENDORID = HSBY_GOODSEX.VENDORID").
		Join("LEFT", "MARKET", "MARKET.MARKETID = GOODS.MARKETID").
		Where("GOODS.GOODSID = ?", goodsID)
	if err := session.Find(&details); err != nil {
		return nil, err
	}
	// 无目标商品
	if len(details) == 0 {
		return nil, nil
	}
	hsbyListingGoodsDetail := details[0]

	// 获取商品现价和涨跌停价
	quoteDays, err := GetQuoteDays("'" + hsbyListingGoodsDetail.Goodscode + "'")
	if err != nil {
		return nil, err
	}
	if len(quoteDays) > 0 {
		if quoteDays[0].Last != 0 {
			hsbyListingGoodsDetail.Last = utils.IntToFloat64(int(quoteDays[0].Last), int(hsbyListingGoodsDetail.Decimalplace))
		}
		// 没有现价则尝试用昨结
		if hsbyListingGoodsDetail.Last == 0 && quoteDays[0].Presettle != 0 {
			hsbyListingGoodsDetail.Last = utils.IntToFloat64(int(quoteDays[0].Presettle), int(hsbyListingGoodsDetail.Decimalplace))
		}
		if quoteDays[0].Limitup != 0 {
			hsbyListingGoodsDetail.Limitup = utils.IntToFloat64(int(quoteDays[0].Limitup), int(hsbyListingGoodsDetail.Decimalplace))
		}
		if quoteDays[0].Limitdown != 0 {
			hsbyListingGoodsDetail.Limitdown = utils.IntToFloat64(int(quoteDays[0].Limitdown), int(hsbyListingGoodsDetail.Decimalplace))
		}
	}

	// 计算价格最小变动单位
	stepValue := float64(hsbyListingGoodsDetail.Quoteminunit) * math.Pow(0.1, float64(hsbyListingGoodsDetail.Decimalplace))
	hsbyListingGoodsDetail.StepValue, _ = strconv.ParseFloat(utils.FormatFloat(stepValue, int(hsbyListingGoodsDetail.Decimalplace)), 64)

	// 计算手数最小变动单位，改在上层进行设置，这里暂时设置成1
	hsbyListingGoodsDetail.LotSize = 1

	return &hsbyListingGoodsDetail, nil
}

// HsbyGoodsOrderDetail 二级市场挂牌商品当前可摘委托单信息
type HsbyGoodsOrderDetail struct {
	Orderid    string    `json:"orderid"  xorm:"'ORDERID'" binding:"required"`     // 委托单号(100+Unix秒时间戳(10位)+2位(MarketServiceID)+xxxx)
	Buyorsell  int32     `json:"buyorsell"  xorm:"'BUYORSELL'" binding:"required"` // 买卖 - 0:买 1:卖
	Ordertime  time.Time `json:"ordertime"  xorm:"'ORDERTIME'" binding:"required"` // 委托时间
	Orderprice float64   `json:"orderprice"  xorm:"'ORDERPRICE'"`                  // 委托价格
	Enableqty  int64     `json:"enableqty" xorm:"ENABLEQTY"`                       // 可用数量

	Customername string `json:"customername"  xorm:"'CUSTOMERNAME'"` // 客户名称(企业名称)，已脱敏

	Currencysign string `json:"currencysign" xorm:"-"` // 货币符号
	Goodunit     string `json:"goodunit"  xorm:"-"`    // 报价单位
}

// GetHsbyGoodsOrderDetails 获取二级市场（挂牌点选）商品对应的挂牌委托单信息
// 输入 goodsID int 商品ID
// 输入 buyOrSell int 挂牌委托单方向（对手单方向），0：买 1：卖
// 输入 price float64 参考价格。买方向委托单则价格小于等于（站在摘牌人的角度）；卖方向委托单则价格大于等于
// 输出 []HsbyGoodsOrderDetail 商品对应的挂牌委托单信息
// 输出 error error
func GetHsbyGoodsOrderDetails(goodsID, buyOrSell int, price float64, accountIDs string) ([]HsbyGoodsOrderDetail, error) {
	engine := db.GetEngine()

	// 获取与目标商品相关的挂牌委托单信息（ListingSelectType = 1 or 3; OrderStatus =3 or 7）
	hsbyGoodsOrderDetails := make([]HsbyGoodsOrderDetail, 0)
	session := engine.Table("TRADE_ORDERDETAIL").
		Select(`to_char(TRADE_ORDERDETAIL.ORDERID) ORDERID, TRADE_ORDERDETAIL.BUYORSELL, TRADE_ORDERDETAIL.ORDERTIME, TRADE_ORDERDETAIL.ORDERPRICE, (TRADE_ORDERDETAIL.ORDERQTY - TRADE_ORDERDETAIL.TRADEQTY - TRADE_ORDERDETAIL.CANCELQTY) ENABLEQTY,
				substr(USERINFO.CUSTOMERNAME,0,1)||'****' as CUSTOMERNAME`).
		Join("LEFT", "TAACCOUNT", "TAACCOUNT.ACCOUNTID = TRADE_ORDERDETAIL.ACCOUNTID").
		Join("LEFT", "USERINFO", "USERINFO.USERID = TAACCOUNT.RELATEDUSERID").
		Where("(TRADE_ORDERDETAIL.LISTINGSELECTTYPE = 1 or TRADE_ORDERDETAIL.LISTINGSELECTTYPE = 3) and (TRADE_ORDERDETAIL.ORDERSTATUS = 3 or TRADE_ORDERDETAIL.ORDERSTATUS = 7)").
		And("TRADE_ORDERDETAIL.GOODSID = ?", goodsID).
		And("TRADE_ORDERDETAIL.BUYORSELL = ?", buyOrSell)
	if len(accountIDs) > 0 {
		session = session.And(fmt.Sprintf("TRADE_ORDERDETAIL.ACCOUNTID not in (%s)", accountIDs))
	}
	if price > 0 {
		if buyOrSell == 0 {
			// 对手单买方向委托单则价格大于等于（站在摘牌人的角度，摘牌方面是卖，我的闲置下单）
			session = session.And("TRADE_ORDERDETAIL.ORDERPRICE >= ?", price)
		} else {
			// 对手单卖方向委托单则价格小于等于（站在摘牌人的角度，摘牌方面是买，热门商品下单）
			session = session.And("TRADE_ORDERDETAIL.ORDERPRICE <= ?", price)
		}
	}
	if err := session.Find(&hsbyGoodsOrderDetails); err != nil {
		return nil, err
	}

	// 获取商品货币符号和报价单位
	goods, err := GetGoods(goodsID)
	if err != nil {
		return nil, err
	}
	currencyEnums, err := GetEnumDicItem("currency", int(goods.Currencyid))
	if err != nil {
		return nil, err
	}
	currencysign := ""
	if len(currencyEnums) > 0 {
		currencysign = currencyEnums[0].Param2
	}
	goodsUnitEnums, err := GetEnumDicItem("goodsunit", int(goods.Goodunitid))
	if err != nil {
		return nil, err
	}
	goodsUnit := ""
	if len(goodsUnitEnums) > 0 {
		goodsUnit = goodsUnitEnums[0].Enumdicname
	}

	for i := range hsbyGoodsOrderDetails {
		orderDetail := &hsbyGoodsOrderDetails[i]

		// 设置货币符号和报价单位
		orderDetail.Currencysign = currencysign
		orderDetail.Goodunit = goodsUnit
	}

	return hsbyGoodsOrderDetails, nil
}

// HybsMyBuyOrderDetail 我的订单（一二级市场的买方向委托单）
type HybsMyBuyOrderDetail struct {
	Orderid           string    `json:"orderid"  xorm:"'ORDERID'" binding:"required"`     // 委托单号(100+Unix秒时间戳(10位)+2位(MarketServiceID)+xxxx)
	Marketid          int32     `json:"marketid"  xorm:"'MARKETID'" binding:"required"`   // 市场ID
	Goodsid           int32     `json:"goodsid"  xorm:"'GOODSID'" binding:"required"`     // 商品ID
	Accountid         int64     `json:"accountid"  xorm:"'ACCOUNTID'" binding:"required"` // 账户ID[报价币种]
	Buyorsell         int32     `json:"buyorsell"  xorm:"'BUYORSELL'" binding:"required"` // 买卖 - 0:买 1:卖
	Orderprice        float64   `json:"orderprice"  xorm:"'ORDERPRICE'"`                  // 委托价格
	Orderqty          int64     `json:"orderqty"  xorm:"'ORDERQTY'" binding:"required"`   // 委托数量
	Tradeqty          int64     `json:"tradeqty"  xorm:"'TRADEQTY'"`                      // 成交数量
	Cancelqty         int64     `json:"cancelqty"  xorm:"'CANCELQTY'"`                    // 撤单数量
	Ordertime         time.Time `json:"ordertime"  xorm:"'ORDERTIME'" binding:"required"` // 委托时间
	Listingselecttype int32     `json:"listingselecttype"  xorm:"'LISTINGSELECTTYPE'"`    // 挂牌点选类型 - 1:挂牌 2:摘牌 3:先摘后挂
	Orderstatus       int32     `json:"orderstatus"  xorm:"'ORDERSTATUS'"`                // 委托状态 - 1： 委托请求 2：待冻结 3：委托成功 4： 委托失败 5：配对成功 6： 已撤销 7：部分成交 8：已成交 9：部成部撤 10：成交失败 11：已拒绝 12:经过摘牌(先摘后挂专用-先摘后挂已摘过) 13:冻结成功(通道交易专用) 14:通道已撤 15:通道部成部撤 16:成交失败违约(荷兰式竞拍专用)

	Goodscode    string  `json:"goodscode"  xorm:"'GOODSCODE'" binding:"required"` // 商品代码(内部)
	Goodsname    string  `json:"goodsname"  xorm:"'GOODSNAME'" binding:"required"` // 商品名称
	Decimalplace int64   `json:"decimalplace"  xorm:"'DECIMALPLACE'"`              // 报价小数位
	Agreeunit    float64 `json:"agreeunit"  xorm:"'AGREEUNIT'"`                    // 合约单位

	Picurls1 string `json:"picurls1"  xorm:"'PICURLS1'"` // 预售商品介绍图片[多张用逗号分隔]
	Picurls2 string `json:"picurls2"  xorm:"'PICURLS2'"` // 挂牌商品介绍图片[多张用逗号分隔]

	Trademode uint32 `json:"trademode"  xorm:"'TRADEMODE'" binding:"required"` // 交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价

	Currencysign string `json:"currencysign" xorm:"'CURRENCYSIGN'"` // 货币符号

	Vendorname1 string `json:"vendorname1"  xorm:"'VENDORNAME1'"` // 预售商品供应商名称
	Vendorname2 string `json:"vendorname2"  xorm:"'VENDORNAME2'"` // 挂牌商品供应商名称

	MyBuyStatus int     `json:"mybuystatus" xorm:"-"` // "我的订单"显示状态- 1：抢购中 2：求购中 3：已完成 4：已撤消 5：委托失败
	Orderamount float64 `json:"orderamount" xorm:"-"` // 委托金额
}

// GetHsbyBuyMyOrderDetails 获取“我的订单”数据（包括一二级市场）
// 输入 accountIDs string 资金账户列表
// 输入 myBuyStatus int "我的订单"状态, 1：抢购中 2：求购中 3：已完成
// 输出 []HybsMyBuyOrderDetail “我的订单”数据
// 输出 error error
func GetHsbyBuyMyOrderDetails(accountIDs string, myBuyStatus int) ([]HybsMyBuyOrderDetail, error) {
	// 获取市场信息
	markets, err := GetMarkets()
	if err != nil {
		return nil, err
	}

	engine := db.GetEngine()
	// 委托状态
	orderStatus := "0" // 单据状态，为0的时候查询全部
	marketIDs := ""    // 我的订单包括一二级市场的单据
	// FIXME: myBuyStatus 目前终端不传
	// switch myBuyStatus {
	// case 1: // 抢购中 (一级市场)
	// 	// 获取市场ID
	// 	for _, v := range markets {
	// 		if v.Trademode == 71 { // 预售挂牌
	// 			if len(marketIDs) == 0 {
	// 				marketIDs = strconv.Itoa(int(v.Marketid))
	// 			} else {
	// 				marketIDs += "," + strconv.Itoa(int(v.Marketid))
	// 			}
	// 		}
	// 	}
	// 	orderStatus = "3,7"
	// case 2: // 求购中（二级市场）
	// 	// 获取市场ID
	// 	for _, v := range markets {
	// 		if v.Trademode == 16 { // 挂牌点选
	// 			if len(marketIDs) == 0 {
	// 				marketIDs = strconv.Itoa(int(v.Marketid))
	// 			} else {
	// 				marketIDs += "," + strconv.Itoa(int(v.Marketid))
	// 			}
	// 		}
	// 	}
	// 	orderStatus = "3,7"
	// case 3: // 已完成
	// 	orderStatus = "8,9"
	// }
	// 默认取 TradeMode = 16 or 71 的市场
	if len(marketIDs) == 0 {
		for _, v := range markets {
			if v.Trademode == 16 || v.Trademode == 71 || v.Trademode == 70 {
				if len(marketIDs) == 0 {
					marketIDs = strconv.Itoa(int(v.Marketid))
				} else {
					marketIDs += "," + strconv.Itoa(int(v.Marketid))
				}
			}
		}
	}

	hybsMyBuyOrderDetails := make([]HybsMyBuyOrderDetail, 0)
	// "我的订单"都是买委托
	session := engine.Table("TRADE_ORDERDETAIL").
		Select(`to_char(TRADE_ORDERDETAIL.ORDERID) ORDERID, TRADE_ORDERDETAIL.*, 
				GOODS.GOODSCODE, GOODS.GOODSNAME, GOODS.DECIMALPLACE, GOODS.AGREEUNIT, 
				HG1.PICURLS PICURLS1, 
				HG2.PICURLS PICURLS2, 
				MARKET.TRADEMODE, 
				ENUMDICITEM.PARAM2 CURRENCYSIGN,
				HS1.VENDORNAME VENDORNAME1, 
				HS2.VENDORNAME VENDORNAME2`).
		Join("LEFT", "GOODS", "GOODS.GOODSID = TRADE_ORDERDETAIL.GOODSID").
		Join("LEFT", "CPTRADE_PRESALEGOODSEX", "CPTRADE_PRESALEGOODSEX.GOODSID = TRADE_ORDERDETAIL.GOODSID").
		Join("LEFT", "HSBY_GOODSEX HG1", "HG1.GOODSID = CPTRADE_PRESALEGOODSEX.RELATEDGOODSID").
		Join("LEFT", "HSBY_GOODSEX HG2", "HG2.GOODSID = GOODS.GOODSID").
		Join("LEFT", "ENUMDICITEM", "GOODS.CURRENCYID = ENUMDICITEM.ENUMITEMNAME and ENUMDICITEM.ENUMDICCODE = 'currency'").
		Join("LEFT", "MARKET", "MARKET.MARKETID = TRADE_ORDERDETAIL.MARKETID").
		Join("LEFT", "HSBY_SUPPLIERINFO HS1", "HS1.VENDORID = HG1.VENDORID").
		Join("LEFT", "HSBY_SUPPLIERINFO HS2", "HS2.VENDORID = HG2.VENDORID").
		Where(fmt.Sprintf("TRADE_ORDERDETAIL.BUYORSELL = 0 and TRADE_ORDERDETAIL.ACCOUNTID in (%s)", accountIDs)).
		And(fmt.Sprintf("TRADE_ORDERDETAIL.MARKETID in (%s)", marketIDs))
	// 是否过滤状态（抢购中、求购中、已完成）
	if orderStatus != "0" {
		session = session.And(fmt.Sprintf("TRADE_ORDERDETAIL.ORDERSTATUS in (%s)", orderStatus))
	}
	if err := session.Find(&hybsMyBuyOrderDetails); err != nil {
		return nil, err
	}

	// 设置“我的订单”显示状态
	for i := range hybsMyBuyOrderDetails {
		detail := &hybsMyBuyOrderDetails[i]

		// 委托金额 = 委托价格 * 委托数量 * 合约单位
		detail.Orderamount = detail.Orderprice * float64(detail.Orderqty) * float64(detail.Agreeunit)

		if detail.Trademode == 71 && (detail.Orderstatus == 3 || detail.Orderstatus == 7) {
			// 抢购中 -> 待成交
			detail.MyBuyStatus = 1
		} else if detail.Trademode == 16 && (detail.Orderstatus == 3 || detail.Orderstatus == 7) {
			// 求购中 -> 待成交
			detail.MyBuyStatus = 2
		} else if detail.Trademode == 70 && (detail.Orderstatus == 3 || detail.Orderstatus == 7) {
			// 待成交
			detail.MyBuyStatus = 1
		} else if detail.Orderstatus == 8 || detail.Orderstatus == 9 {
			// 已提交
			detail.MyBuyStatus = 3
		} else if detail.Orderstatus == 6 || detail.Orderstatus == 22 {
			// 已撤销
			detail.MyBuyStatus = 4
		} else if detail.Orderstatus == 4 {
			// 委托失败
			detail.MyBuyStatus = 5
		}
	}

	return hybsMyBuyOrderDetails, nil
}

// HsbyMyGoods 我的商品（买方向持仓）
type HsbyMyGoods struct {
	Accountid          int64   `json:"accountid"  xorm:"'ACCOUNTID'" binding:"required"` // 账号Id
	Goodsid            int32   `json:"goodsid"  xorm:"'GOODSID'" binding:"required"`     // 商品Id
	Buycurpositionqty  int64   `json:"buycurpositionqty"  xorm:"'BUYCURPOSITIONQTY'"`    // 买当前持仓总数量
	Buycurholderamount float64 `json:"buycurholderamount"  xorm:"'BUYCURHOLDERAMOUNT'"`  // 买当前持仓总金额[商品币种]
	EnableQty          int64   `json:"enableqty" xorm:"'ENABLEQTY'"`                     // 可用数量

	Goodscode    string  `json:"goodscode"  xorm:"'GOODSCODE'" binding:"required"` // 商品代码(内部)
	Goodsname    string  `json:"goodsname"  xorm:"'GOODSNAME'" binding:"required"` // 商品名称
	Decimalplace int64   `json:"decimalplace"  xorm:"'DECIMALPLACE'"`              // 报价小数位
	Agreeunit    float64 `json:"agreeunit"  xorm:"'AGREEUNIT'"`                    // 合约单位
	Goodsstatus  int64   `json:"goodsstatus"  xorm:"'GOODSSTATUS'"`                // 商品状态- 1:待审核 2:未上市 3:上市 4:已注销 5:审核拒绝 6:退市 7:待退市
	Marketid     int64   `json:"marketid"  xorm:"'MARKETID'" binding:"required"`   // 所属市场ID
	Quoteminunit int64   `json:"quoteminunit"  xorm:"'QUOTEMINUNIT'"`              // 行情最小变动单位 [整数，报价小数位一起使用]

	Picurls    string  `json:"picurls"  xorm:"'PICURLS'"`       // 介绍图片[多张用逗号分隔]
	Goodsprice float64 `json:"goodsprice"  xorm:"'GOODSPRICE'"` // 商品价格

	Currencysign string `json:"currencysign" xorm:"'CURRENCYSIGN'"` // 货币符号

	Trademode int32 `json:"trademode"  xorm:"'TRADEMODE'" binding:"required"` // 交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价

	Buyaverageprice float64 `json:"buyaverageprice" xorm:"-"` // 持仓均价

	Last      float64 `json:"last" xorm:"-"`         // 现价（仅使用于挂牌点选）
	Limitup   float64 `json:"limitup" xorm:"-"`      // 涨停价（仅使用于挂牌点选）
	Limitdown float64 `json:"limitdown" xorm:"-"`    // 跌停价（仅使用于挂牌点选）
	StepValue float64 `json:"stepvalue" xorm:"-"`    // 价格最小变动单位
	LotSize   int     `json:"lotsize" xorm:"-"`      // 手数最小变动单位
	Buymaxqty int     `json:"buymaxqty"  xorm:"'-'"` // 购买上限 [71] - 0为不限
}

// GetHsbyMyGoods 获取“我的商品”信息
// 输入 accountIDs string 资金账户列表，格式 1,2,3
// 输出 []HsbyMyGoods “我的商品”信息
// 输入 error error
func GetHsbyMyGoods(accountIDs string) ([]HsbyMyGoods, error) {
	engine := db.GetEngine()

	hsbyMyGoodses := make([]HsbyMyGoods, 0)
	// 此定制版本，只查询出当前手数（期末）大于0的数据 （TRADEPOSITION.BUYCURPOSITIONQTY > 0）
	if err := engine.Table("TRADEPOSITION TP").
		Select(`TP.*, (TP.BUYCURPOSITIONQTY - TP.BUYFROZENQTY - TP.BUYOTHERFROZENQTY) ENABLEQTY, 
				G.GOODSCODE, G.GOODSNAME, G.DECIMALPLACE, G.AGREEUNIT, G.GOODSSTATUS, G.MARKETID, G.QUOTEMINUNIT, 
				GX.PICURLS, GX.GOODSPRICE,  
				E.PARAM2 CURRENCYSIGN, 
				M.TRADEMODE`).
		Join("LEFT", "GOODS G", "G.GOODSID = TP.GOODSID").
		Join("INNER", "HSBY_GOODSEX GX", "GX.GOODSID = G.GOODSID").
		Join("LEFT", "ENUMDICITEM E", "G.CURRENCYID = E.ENUMITEMNAME and E.ENUMDICCODE = 'currency'").
		Join("LEFT", "MARKET M", "M.MARKETID = G.MARKETID").
		Where(fmt.Sprintf("G.GOODSSTATUS = 3 and TP.BUYCURPOSITIONQTY > 0 and TP.ACCOUNTID in (%s)", accountIDs)).Find(&hsbyMyGoodses); err != nil {
		return nil, err
	}

	for i := range hsbyMyGoodses {
		myGoods := &hsbyMyGoodses[i]

		// 持仓均价
		averagePrice := myGoods.Buycurholderamount / float64(myGoods.Buycurpositionqty) / myGoods.Agreeunit
		myGoods.Buyaverageprice, _ = strconv.ParseFloat(utils.FormatFloat(averagePrice, int(myGoods.Decimalplace)), 64)

		// 获取商品现价和涨跌停价（挂牌点选）
		if myGoods.Trademode == 16 {
			quoteDays, err := GetQuoteDays("'" + myGoods.Goodscode + "'")
			if err != nil {
				return nil, err
			}
			if len(quoteDays) > 0 {
				if quoteDays[0].Last != 0 {
					myGoods.Last = utils.IntToFloat64(int(quoteDays[0].Last), int(myGoods.Decimalplace))
				}
				// 没有现价则尝试用昨结
				if myGoods.Last == 0 && quoteDays[0].Presettle != 0 {
					myGoods.Last = utils.IntToFloat64(int(quoteDays[0].Presettle), int(myGoods.Decimalplace))
				}
				if quoteDays[0].Limitup != 0 {
					myGoods.Limitup = utils.IntToFloat64(int(quoteDays[0].Limitup), int(myGoods.Decimalplace))
				}
				if quoteDays[0].Limitdown != 0 {
					myGoods.Limitdown = utils.IntToFloat64(int(quoteDays[0].Limitdown), int(myGoods.Decimalplace))
				}
			}
		}

		// 计算价格最小变动单位
		stepValue := float64(myGoods.Quoteminunit) * math.Pow(0.1, float64(myGoods.Decimalplace))
		myGoods.StepValue, _ = strconv.ParseFloat(utils.FormatFloat(stepValue, int(myGoods.Decimalplace)), 64)

		// 获取交易规则
		accountID, err := strconv.Atoi(accountIDs)
		if err != nil {
			return nil, err
		}
		rule, err := GetTodayAccountTradeRule(accountID, int(myGoods.Goodsid))
		if err != nil {
			// 查询失败
			return nil, err
		}
		if rule != nil {
			tradeRuleInfoStruct := &pb.TradeRuleInfoStruct{}
			if err := proto.Unmarshal([]byte(rule.Infocontent), tradeRuleInfoStruct); err != nil {
				// 查询失败
				return nil, err
			}
			// INSERT INTO TRADERULEDESCRIPTION (RULEID, RULENAME, REGEXPRESS, DEFAULTVALUE, REMARK) VALUES (103, '单笔最小交易量', '^[1-9]\d*$', 1, '请输入正整数!');
			for _, v := range tradeRuleInfoStruct.TradeRules {
				if int(*v.RuleID) == 103 {
					myGoods.LotSize = int(*v.ParamValue)
				}
				// 挂牌点选的最大建仓手数与预售的不一样，直接从规则里取
				if int(*v.RuleID) == 104 {
					myGoods.Buymaxqty = int(*v.ParamValue)
				}
			}
		}
	}

	return hsbyMyGoodses, nil
}

// HsbyPreGoods 新品上市商品（一级市场产能预售）
type HsbyPreGoods struct {
	Goodsid       int64     `json:"goodsid"  xorm:"'GOODSID'" binding:"required"`     // 商品ID(自增ID SEQ_GOODS)
	Goodscode     string    `json:"goodscode"  xorm:"'GOODSCODE'" binding:"required"` // 商品代码(内部)
	Goodsname     string    `json:"goodsname"  xorm:"'GOODSNAME'" binding:"required"` // 商品名称
	Decimalplace  int64     `json:"decimalplace"  xorm:"'DECIMALPLACE'"`              // 报价小数位
	Marketid      int64     `json:"marketid"  xorm:"'MARKETID'" binding:"required"`   // 所属市场ID
	Goodsstatus   int64     `json:"goodsstatus"  xorm:"'GOODSSTATUS'"`                // 商品状态- 2:未上市 3:上市
	Quoteminunit  int64     `json:"quoteminunit"  xorm:"'QUOTEMINUNIT'"`              // 行情最小变动单位 [整数，报价小数位一起使用]
	Agreeunit     float64   `json:"agreeunit"  xorm:"'AGREEUNIT'"`                    // 合约单位
	Listingdate   time.Time `json:"listingdate"  xorm:"'LISTINGDATE'"`                // 交易开始日期
	Lasttradedate time.Time `json:"lasttradedate"  xorm:"'LASTTRADEDATE'"`            // 最后交易日期(状态：待退市)

	Relatedgoodsid int64   `json:"relatedgoodsid"  xorm:"'RELATEDGOODSID'"` // 关联交易合约ID
	Presaleqty     int64   `json:"presaleqty"  xorm:"'PRESALEQTY'"`         // 预售数量
	Refprice       float64 `json:"refprice"  xorm:"'REFPRICE'"`             // 参考价格[一口价]
	Presaledqty    int64   `json:"presaledqty"  xorm:"'PRESALEDQTY'"`       // 已预售量(预售结束时更新)
	EnableQty      int64   `json:"enableqty" xorm:"ENABLEQTY"`              // 剩余数量

	Currency     string `json:"currency" xorm:"'CURRENCY'"`         // 货币
	Currencysign string `json:"currencysign" xorm:"'CURRENCYSIGN'"` // 货币符号

	Videourls      string `json:"videourls"  xorm:"'VIDEOURLS'"`           // 介绍视频[多张用逗号分隔]
	Picurls        string `json:"picurls"  xorm:"'PICURLS'"`               // 介绍图片[多张用逗号分隔]
	Descprovinceid int64  `json:"descprovinceid"  xorm:"'DESCPROVINCEID'"` // 目的地(省)
	Desccityid     int64  `json:"desccityid"  xorm:"'DESCCITYID'"`         // 目的地(市)

	Trademode int32 `json:"trademode"  xorm:"'TRADEMODE'" binding:"required"` // 交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价
}

// GetHsbyPreGoodses 获取“新品上市”商品列表（一级市场产能预售）
// 输入 marketIDs string 市场ID列表，格式 1,2,3
// 输入 descProvinceID int 省ID
// 输入 descCityID int 市ID
// 输出 []HsbyPreGoods “新品上市”商品列表
// 输出 error error
func GetHsbyPreGoodses(marketIDs string, descProvinceID, descCityID int) ([]HsbyPreGoods, error) {
	engine := db.GetEngine()

	// 注意：一级产能预售市场使用的商品实际上是和二级市场有关系的，所以要使用 CPTRADE_PRESALEGOODSEX.RELATEDGOODSID 进行关联
	// 注意：CPTRADE_PRESALEGOODSEX 表的开始与结束时间是给大宗用的
	preGoodses := make([]HsbyPreGoods, 0)
	session := engine.Table("GOODS").
		Select(`GOODS.*, 
				CPTRADE_PRESALEGOODSEX.RELATEDGOODSID, CPTRADE_PRESALEGOODSEX.PRESALEQTY, CPTRADE_PRESALEGOODSEX.REFPRICE, 
				CPTRADE_PRESALEGOODSEX.PRESALEDQTY, (CPTRADE_PRESALEGOODSEX.PRESALEQTY - CPTRADE_PRESALEGOODSEX.PRESALEDQTY) ENABLEQTY, 
				ENUMDICITEM.ENUMDICNAME CURRENCY, ENUMDICITEM.PARAM2 CURRENCYSIGN, 
				HSBY_GOODSEX.VIDEOURLS, HSBY_GOODSEX.PICURLS, HSBY_GOODSEX.DESCPROVINCEID, HSBY_GOODSEX.DESCCITYID, 
				MARKET.TRADEMODE`).
		Join("INNER", "CPTRADE_PRESALEGOODSEX", "CPTRADE_PRESALEGOODSEX.GOODSID = GOODS.GOODSID").
		Join("LEFT", "ENUMDICITEM", "ENUMDICITEM.ENUMITEMNAME = GOODS.CURRENCYID and ENUMDICITEM.ENUMDICCODE = 'currency'").
		Join("LEFT", "HSBY_GOODSEX", "HSBY_GOODSEX.GOODSID = CPTRADE_PRESALEGOODSEX.RELATEDGOODSID").
		Join("LEFT", "MARKET", "MARKET.MARKETID = GOODS.MARKETID").
		Where(fmt.Sprintf("GOODS.GOODSSTATUS in (2,3) and GOODS.MARKETID in (%s)", marketIDs)) // 一级市场获取 2:未上市 3:上市 状态的商品
	if descProvinceID > 0 {
		session = session.And("HSBY_GOODSEX.DESCPROVINCEID = ?", descProvinceID)
	}
	if descCityID > 0 {
		session = session.And("HSBY_GOODSEX.DESCCITYID = ?", descCityID)
	}
	if err := session.Find(&preGoodses); err != nil {
		return nil, err
	}

	// for i := range preGoodses {
	// 	preGoods := &preGoodses[i]

	// 	// FIXME: - 这里应该使用 Duck Typing，后期再处理
	// 	// 计算最小变动单位
	// 	lotSize := float64(preGoods.Quoteminunit) * math.Pow(0.1, float64(preGoods.Decimalplace))
	// 	preGoods.LotSize, _ = strconv.ParseFloat(utils.FormatFloat(lotSize, int(preGoods.Decimalplace)), 64)
	// }

	return preGoodses, nil
}

// HsbyPreGoodsDetail 一级市场（产能预售）商品信息详情
type HsbyPreGoodsDetail struct {
	Goodsid       int64     `json:"goodsid"  xorm:"'GOODSID'" binding:"required"`     // 商品ID(自增ID SEQ_GOODS)
	Goodscode     string    `json:"goodscode"  xorm:"'GOODSCODE'" binding:"required"` // 商品代码(内部)
	Goodsname     string    `json:"goodsname"  xorm:"'GOODSNAME'" binding:"required"` // 商品名称
	Decimalplace  int64     `json:"decimalplace"  xorm:"'DECIMALPLACE'"`              // 报价小数位
	Marketid      int64     `json:"marketid"  xorm:"'MARKETID'" binding:"required"`   // 所属市场ID
	Goodsstatus   int64     `json:"goodsstatus"  xorm:"'GOODSSTATUS'"`                // 商品状态- 2:未上市 3:上市
	Quoteminunit  int64     `json:"quoteminunit"  xorm:"'QUOTEMINUNIT'"`              // 行情最小变动单位 [整数，报价小数位一起使用]
	Agreeunit     float64   `json:"agreeunit"  xorm:"'AGREEUNIT'"`                    // 合约单位
	Listingdate   time.Time `json:"listingdate"  xorm:"'LISTINGDATE'"`                // 交易开始日期
	Lasttradedate time.Time `json:"lasttradedate"  xorm:"'LASTTRADEDATE'"`            // 最后交易日期(状态：待退市)

	Relatedgoodsid int64   `json:"relatedgoodsid"  xorm:"'RELATEDGOODSID'"` // 关联交易合约ID
	Presaleqty     int64   `json:"presaleqty"  xorm:"'PRESALEQTY'"`         // 预售数量
	Refprice       float64 `json:"refprice"  xorm:"'REFPRICE'"`             // 参考价格[一口价]
	Presaledqty    int64   `json:"presaledqty"  xorm:"'PRESALEDQTY'"`       // 已预售量(预售结束时更新)
	EnableQty      int64   `json:"enableqty" xorm:"ENABLEQTY"`              // 剩余数量
	Buymaxqty      int     `json:"buymaxqty"  xorm:"'BUYMAXQTY'"`           // 购买上限 [71] - 0为不限

	Videourls      string `json:"videourls"  xorm:"'VIDEOURLS'"`           // 介绍视频[多张用逗号分隔]
	Picurls        string `json:"picurls"  xorm:"'PICURLS'"`               // 介绍图片[多张用逗号分隔]
	Descprovinceid int64  `json:"descprovinceid"  xorm:"'DESCPROVINCEID'"` // 目的地(省)ID
	Desccityid     int64  `json:"desccityid"  xorm:"'DESCCITYID'"`         // 目的地(市)ID
	Goodsdesc      string `json:"goodsdesc"  xorm:"'GOODSDESC'"`           // 商品详情

	Currency     string `json:"currency" xorm:"'CURRENCY'"`         // 货币
	Currencysign string `json:"currencysign" xorm:"'CURRENCYSIGN'"` // 货币符号
	Goodunit     string `json:"goodunit"  xorm:"GOODUNIT"`          // 报价单位

	Vendorname  string `json:"vendorname"  xorm:"'VENDORNAME'"`   // 供应商名称
	Vendorphone string `json:"vendorphone"  xorm:"'VENDORPHONE'"` // 供应商客服电话
	Vendorattr  string `json:"vendorattr"  xorm:"'VENDORATTR'"`   // 供应商附件(多张，逗号分隔)

	Trademode int32 `json:"trademode"  xorm:"'TRADEMODE'" binding:"required"` // 交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价

	Customername string `json:"customername" xorm:"'CUSTOMERNAME'"` // 发行单位

	StepValue float64 `json:"stepvalue" xorm:"-"` // 价格最小变动单位
	LotSize   int     `json:"lotsize" xorm:"-"`   // 手数最小变动单位
}

// GetHsbyPreGoodsDetail 获取一级市场（产能预售）商品信息详情
// 参数 goodsID int 目标商品ID
// 返回 *HsbyListingGoodsDetail 二级市场（挂牌点选）商品信息详情，查询无结果返回nil
// 返回 error error
func GetHsbyPreGoodsDetail(goodsID, accountID int) (*HsbyPreGoodsDetail, error) {
	engine := db.GetEngine()

	details := make([]HsbyPreGoodsDetail, 0)
	// 获取挂牌商品信息，以及扩展表信息
	// FIXME: - 这里使用Get方法，会造成SQL语句的嵌套出错，后期再研究
	session := engine.Table("GOODS").
		Select(`GOODS.*, 
				CPTRADE_PRESALEGOODSEX.RELATEDGOODSID, CPTRADE_PRESALEGOODSEX.PRESALEQTY, CPTRADE_PRESALEGOODSEX.REFPRICE, 
				CPTRADE_PRESALEGOODSEX.PRESALEDQTY, (CPTRADE_PRESALEGOODSEX.PRESALEQTY - CPTRADE_PRESALEGOODSEX.PRESALEDQTY) ENABLEQTY, CPTRADE_PRESALEGOODSEX.BUYMAXQTY, 
				HSBY_GOODSEX.VIDEOURLS, HSBY_GOODSEX.PICURLS, HSBY_GOODSEX.DESCPROVINCEID, HSBY_GOODSEX.Desccityid, HSBY_GOODSEX.Goodsdesc,
				ENUMDICITEM.ENUMDICNAME CURRENCY, ENUMDICITEM.PARAM2 CURRENCYSIGN, 
				E1.ENUMDICNAME GOODUNIT, 
				HSBY_SUPPLIERINFO.VENDORNAME, HSBY_SUPPLIERINFO.VENDORPHONE, HSBY_SUPPLIERINFO.VENDORATTR, 
				MARKET.TRADEMODE, 
				USERINFO.CUSTOMERNAME`).
		Join("INNER", "CPTRADE_PRESALEGOODSEX", "CPTRADE_PRESALEGOODSEX.GOODSID = GOODS.GOODSID").
		Join("LEFT", "HSBY_GOODSEX", "HSBY_GOODSEX.GOODSID = CPTRADE_PRESALEGOODSEX.RELATEDGOODSID").
		Join("LEFT", "ENUMDICITEM", "ENUMDICITEM.ENUMITEMNAME = GOODS.CURRENCYID and ENUMDICITEM.ENUMDICCODE = 'currency'").
		Join("LEFT", "ENUMDICITEM E1", "E1.ENUMITEMNAME = GOODS.GOODUNITID and E1.ENUMDICCODE = 'goodsunit'").
		Join("LEFT", "HSBY_SUPPLIERINFO", "HSBY_SUPPLIERINFO.VENDORID = HSBY_GOODSEX.VENDORID").
		Join("LEFT", "MARKET", "MARKET.MARKETID = GOODS.MARKETID").
		Join("LEFT", "USERINFO", "USERINFO.USERID = CPTRADE_PRESALEGOODSEX.USERID").
		Where("GOODS.GOODSID = ?", goodsID)
	if err := session.Find(&details); err != nil {
		return nil, err
	}
	// 无目标商品
	if len(details) == 0 {
		return nil, nil
	}
	preGoodsDetail := details[0]

	// FIXME: - 这里应该使用 Duck Typing，后期再处理
	// 计算价格最小变动单位
	stepValue := float64(preGoodsDetail.Quoteminunit) * math.Pow(0.1, float64(preGoodsDetail.Decimalplace))
	preGoodsDetail.StepValue, _ = strconv.ParseFloat(utils.FormatFloat(stepValue, int(preGoodsDetail.Decimalplace)), 64)

	// 计算手数最小变动单位，一级市场固定为1
	preGoodsDetail.LotSize = 1

	// 获取购买上限
	if accountID != 0 {
		buyMaxQty, err := GetCPTradeBuyLimit(goodsID, accountID)
		if err != nil {
			return nil, err
		}
		preGoodsDetail.Buymaxqty = buyMaxQty
	}

	return &preGoodsDetail, nil
}

// HsbySellMyDetail "我的闲置"单据信息（发布中 - 二级市场卖挂，3：委托成功、7：部分成交; 已完成 - 二级市场成交单，包括历史数据）
type HsbySellMyDetail struct {
	Orderid   string    `json:"orderid"  xorm:"'ORDERID'" binding:"required"`     // 单号（发布中 - 委托单号；已完成 - 成交单号）
	Marketid  int32     `json:"marketid"  xorm:"'MARKETID'" binding:"required"`   // 市场ID
	Goodsid   int32     `json:"goodsid"  xorm:"'GOODSID'" binding:"required"`     // 商品ID
	Accountid int64     `json:"accountid"  xorm:"'ACCOUNTID'" binding:"required"` // 账户ID[报价币种]
	Buyorsell int32     `json:"buyorsell"  xorm:"'BUYORSELL'" binding:"required"` // 买卖 - 0:买 1:卖
	Price     float64   `json:"price"  xorm:"'PRICE'"`                            // 价格
	Time      time.Time `json:"time"  xorm:"'TIME'" binding:"required"`           // 时间
	Qty       int64     `json:"qty"  xorm:"'QTY'"`                                // 数量

	Goodscode    string  `json:"goodscode"  xorm:"'GOODSCODE'" binding:"required"` // 商品代码(内部)
	Goodsname    string  `json:"goodsname"  xorm:"'GOODSNAME'" binding:"required"` // 商品名称
	Decimalplace int64   `json:"decimalplace"  xorm:"'DECIMALPLACE'"`              // 报价小数位
	Agreeunit    float64 `json:"agreeunit"  xorm:"'AGREEUNIT'"`                    // 合约单位

	Picurls string `json:"picurls"  xorm:"'PICURLS'"` // 介绍图片[多张用逗号分隔]

	Trademode uint32 `json:"trademode"  xorm:"'TRADEMODE'" binding:"required"` // 交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价

	Currencysign string `json:"currencysign" xorm:"'CURRENCYSIGN'"` // 货币符号

	Vendorname string `json:"vendorname"  xorm:"'VENDORNAME'"` // 供应商名称

	OrderType int32 `json:"ordertype" xorm:"'ORDERTYPE'"` // 单据类型：0 - 发布中, 1 - 已完成
}

// GetHsbySellMyOrderDetails 获取"我的闲置 - 发布中"单据信息
// 输入 accountIDs string 资金账户列表
// 输出 []HsbySellMyDetail "我的闲置 - 发布中"单据信息
// 输出 error error
func GetHsbySellMyOrderDetails(accountIDs string) ([]HsbySellMyDetail, error) {
	// 获取市场信息
	markets, err := GetMarkets()
	if err != nil {
		return nil, err
	}

	engine := db.GetEngine()
	marketIDs := "" // 我的闲置-发布中： 二级市场卖挂牌、三级商城
	for _, v := range markets {
		if v.Trademode == 16 || v.Trademode == 70 {
			if len(marketIDs) == 0 {
				marketIDs = strconv.Itoa(int(v.Marketid))
			} else {
				marketIDs += "," + strconv.Itoa(int(v.Marketid))
			}
		}
	}

	orderDetails := make([]HsbySellMyDetail, 0)
	// “我的闲置 - 发布中”都是卖挂委托
	session := engine.Table("TRADE_ORDERDETAIL").
		Select(`to_char(TRADE_ORDERDETAIL.ORDERID) ORDERID, 
				TRADE_ORDERDETAIL.MARKETID, TRADE_ORDERDETAIL.GOODSID, TRADE_ORDERDETAIL.ACCOUNTID, TRADE_ORDERDETAIL.BUYORSELL,
				TRADE_ORDERDETAIL.ORDERPRICE PRICE, TRADE_ORDERDETAIL.ORDERTIME TIME, 
				(TRADE_ORDERDETAIL.ORDERQTY - TRADE_ORDERDETAIL.TRADEQTY - TRADE_ORDERDETAIL.CANCELQTY) QTY,
				GOODS.GOODSCODE, GOODS.GOODSNAME, GOODS.DECIMALPLACE, GOODS.AGREEUNIT, 
				HSBY_GOODSEX.PICURLS, 
				MARKET.TRADEMODE, 
				ENUMDICITEM.PARAM2 CURRENCYSIGN, 
				HSBY_SUPPLIERINFO.VENDORNAME, 
				0 ORDERTYPE`).
		Join("LEFT", "GOODS", "GOODS.GOODSID = TRADE_ORDERDETAIL.GOODSID").
		Join("LEFT", "HSBY_GOODSEX", "HSBY_GOODSEX.GOODSID = GOODS.GOODSID").
		Join("LEFT", "ENUMDICITEM", "GOODS.CURRENCYID = ENUMDICITEM.ENUMITEMNAME and ENUMDICITEM.ENUMDICCODE = 'currency'").
		Join("LEFT", "MARKET", "MARKET.MARKETID = TRADE_ORDERDETAIL.MARKETID").
		Join("LEFT", "HSBY_SUPPLIERINFO", "HSBY_SUPPLIERINFO.VENDORID = HSBY_GOODSEX.VENDORID").
		Where(fmt.Sprintf(`TRADE_ORDERDETAIL.BUYORSELL = 1 and TRADE_ORDERDETAIL.LISTINGSELECTTYPE = 1 and (TRADE_ORDERDETAIL.ORDERSTATUS = 3 or TRADE_ORDERDETAIL.ORDERSTATUS = 7) 
						   and TRADE_ORDERDETAIL.ACCOUNTID in (%s)`, accountIDs)).
		And(fmt.Sprintf("TRADE_ORDERDETAIL.MARKETID in (%s)", marketIDs))
	if err := session.Find(&orderDetails); err != nil {
		return nil, err
	}

	return orderDetails, nil
}

// GetHsbySellMyTradeDetails 获取"我的闲置 - 已完成"单据信息
// 输入 accountIDs string 资金账户列表
// 输出 []HsbySellMyDetail "我的闲置 - 已完成"单据信息
// 输出 error error
func GetHsbySellMyTradeDetails(accountIDs string) ([]HsbySellMyDetail, error) {
	// 获取市场信息
	markets, err := GetMarkets()
	if err != nil {
		return nil, err
	}

	engine := db.GetEngine()
	marketIDs := "" // 我的闲置-发布中： 二级市场卖方向成交单（包括历史成交单）
	// 默认取 TradeMode = 16
	for _, v := range markets {
		if v.Trademode == 16 || v.Trademode == 70 {
			if len(marketIDs) == 0 {
				marketIDs = strconv.Itoa(int(v.Marketid))
			} else {
				marketIDs += "," + strconv.Itoa(int(v.Marketid))
			}
		}
	}

	orders := make([]HsbySellMyDetail, 0)

	// 当前成交单
	curOrders := make([]HsbySellMyDetail, 0)
	if err := engine.Table("TRADE_TRADEDETAIL").
		Select(`to_char(TRADE_TRADEDETAIL.TRADEID) ORDERID, 
				TRADE_TRADEDETAIL.MARKETID, TRADE_TRADEDETAIL.GOODSID, TRADE_TRADEDETAIL.ACCOUNTID, TRADE_TRADEDETAIL.BUYORSELL,
				TRADE_TRADEDETAIL.TRADEPRICE PRICE, TRADE_TRADEDETAIL.TRADEQTY QTY, TRADE_TRADEDETAIL.TRADETIME TIME, TRADE_TRADEDETAIL.TRADEAMOUNT AMOUNT, 
				GOODS.GOODSCODE, GOODS.GOODSNAME, GOODS.DECIMALPLACE, GOODS.AGREEUNIT, 
				HSBY_GOODSEX.PICURLS, 
				MARKET.TRADEMODE, 
				ENUMDICITEM.PARAM2 CURRENCYSIGN, 
				HSBY_SUPPLIERINFO.VENDORNAME, 
				1 ORDERTYPE`).
		Join("LEFT", "GOODS", "GOODS.GOODSID = TRADE_TRADEDETAIL.GOODSID").
		Join("LEFT", "HSBY_GOODSEX", "HSBY_GOODSEX.GOODSID = GOODS.GOODSID").
		Join("LEFT", "ENUMDICITEM", "GOODS.CURRENCYID = ENUMDICITEM.ENUMITEMNAME and ENUMDICITEM.ENUMDICCODE = 'currency'").
		Join("LEFT", "MARKET", "MARKET.MARKETID = TRADE_TRADEDETAIL.MARKETID").
		Join("LEFT", "HSBY_SUPPLIERINFO", "HSBY_SUPPLIERINFO.VENDORID = HSBY_GOODSEX.VENDORID").
		Where(fmt.Sprintf(`TRADE_TRADEDETAIL.BUYORSELL = 1 and TRADE_TRADEDETAIL.TRADETYPE in (1,24) 
						   and TRADE_TRADEDETAIL.ACCOUNTID in (%s)`, accountIDs)).
		And(fmt.Sprintf("TRADE_TRADEDETAIL.MARKETID in (%s)", marketIDs)).Find(&curOrders); err != nil {
		return nil, err
	}
	if len(curOrders) > 0 {
		orders = append(orders, curOrders...)
	}

	// 历史成交单
	hisOrders := make([]HsbySellMyDetail, 0)
	if err := engine.Table("HIS_TRADE_TRADEDETAIL").
		Select(`to_char(HIS_TRADE_TRADEDETAIL.TRADEID) ORDERID, 
				HIS_TRADE_TRADEDETAIL.MARKETID, HIS_TRADE_TRADEDETAIL.GOODSID, HIS_TRADE_TRADEDETAIL.ACCOUNTID, HIS_TRADE_TRADEDETAIL.BUYORSELL,
				HIS_TRADE_TRADEDETAIL.TRADEPRICE PRICE, HIS_TRADE_TRADEDETAIL.TRADEQTY QTY, HIS_TRADE_TRADEDETAIL.TRADETIME TIME, HIS_TRADE_TRADEDETAIL.TRADEAMOUNT AMOUNT, 
				GOODS.GOODSCODE, GOODS.GOODSNAME, GOODS.DECIMALPLACE, GOODS.AGREEUNIT, 
				HSBY_GOODSEX.PICURLS, 
				MARKET.TRADEMODE, 
				ENUMDICITEM.PARAM2 CURRENCYSIGN, 
				HSBY_SUPPLIERINFO.VENDORNAME, 
				1 ORDERTYPE`).
		Join("LEFT", "GOODS", "GOODS.GOODSID = HIS_TRADE_TRADEDETAIL.GOODSID").
		Join("LEFT", "HSBY_GOODSEX", "HSBY_GOODSEX.GOODSID = GOODS.GOODSID").
		Join("LEFT", "ENUMDICITEM", "GOODS.CURRENCYID = ENUMDICITEM.ENUMITEMNAME and ENUMDICITEM.ENUMDICCODE = 'currency'").
		Join("LEFT", "MARKET", "MARKET.MARKETID = HIS_TRADE_TRADEDETAIL.MARKETID").
		Join("LEFT", "HSBY_SUPPLIERINFO", "HSBY_SUPPLIERINFO.VENDORID = HSBY_GOODSEX.VENDORID").
		Where(fmt.Sprintf(`HIS_TRADE_TRADEDETAIL.BUYORSELL = 1 and HIS_TRADE_TRADEDETAIL.TRADETYPE in (1,24) and HIS_TRADE_TRADEDETAIL.ISVALIDDATA = 1 
						   and HIS_TRADE_TRADEDETAIL.ACCOUNTID in (%s)`, accountIDs)).
		And(fmt.Sprintf("HIS_TRADE_TRADEDETAIL.MARKETID in (%s)", marketIDs)).Find(&hisOrders); err != nil {
		return nil, err
	}
	if len(hisOrders) > 0 {
		orders = append(orders, hisOrders...)
	}

	return orders, nil
}

// HsbyMyPackage 我的包裹信息
type HsbyMyPackage struct {
	Takeorderid     string    `json:"takeorderid"  xorm:"'TAKEORDERID'" binding:"required"` // 提货单号(905+Unix秒时间戳(10位)+xxxxxx)
	Accountid       int64     `json:"accountid"  xorm:"'ACCOUNTID'"`                        // 账户ID
	Goodsid         int64     `json:"goodsid"  xorm:"'GOODSID'"`                            // 商品ID
	Userid          int64     `json:"userid"  xorm:"'USERID'"`                              // 用户ID
	Qty             float64   `json:"qty"  xorm:"'QTY'"`                                    // 提货数量
	Reqtime         time.Time `json:"reqtime"  xorm:"'REQTIME'"`                            // 更新时间
	Recivername     string    `json:"recivername"  xorm:"'RECIVERNAME'"`                    // 提货人姓名
	Cardtypeid      int32     `json:"cardtypeid"  xorm:"'CARDTYPEID'"`                      // 提货人证件类型
	Cardnum         string    `json:"cardnum"  xorm:"'CARDNUM'"`                            // 提货人证件号码
	Phonenum        string    `json:"phonenum"  xorm:"'PHONENUM'"`                          // 提货人联系方式
	Takemode        int32     `json:"takemode"  xorm:"'TAKEMODE'"`                          // 提货方式 - 2:自提 3:配送
	Address         string    `json:"address"  xorm:"'ADDRESS'"`                            // 提货人详细地址
	Takeremark      string    `json:"takeremark"  xorm:"'TAKEREMARK'"`                      // 提货备注
	Takeorderstatus int32     `json:"takeorderstatus"  xorm:"'TAKEORDERSTATUS'"`            // 提货状态 - 1:待发货 2:已发货 3:已收货
	Auditer         int32     `json:"auditer"  xorm:"'AUDITER'"`                            // 审核人
	Audittime       time.Time `json:"audittime"  xorm:"'AUDITTIME'"`                        // 审核时间
	Checkremark     string    `json:"checkremark"  xorm:"'CHECKREMARK'"`                    // 审核备注
	Tradedate       string    `json:"tradedate"  xorm:"'TRADEDATE'"`                        // 交易日(yyyyMMdd)
	Marketid        int32     `json:"marketid"  xorm:"'MARKETID'"`                          // 市场ID
	Handlestatus    int32     `json:"handlestatus"  xorm:"'HANDLESTATUS'"`                  // 处理状态
	Amount          float64   `json:"amount"  xorm:"'AMOUNT'"`                              // 提货金额
	Averageprice    float64   `json:"averageprice" xorm:"'AVERAGEPRICE'"`                   // 均价

	Goodscode    string  `json:"goodscode"  xorm:"'GOODSCODE'" binding:"required"` // 商品代码(内部)
	Goodsname    string  `json:"goodsname"  xorm:"'GOODSNAME'" binding:"required"` // 商品名称
	Decimalplace int64   `json:"decimalplace"  xorm:"'DECIMALPLACE'"`              // 报价小数位
	Agreeunit    float64 `json:"agreeunit"  xorm:"'AGREEUNIT'"`                    // 合约单位

	Picurls string `json:"picurls"  xorm:"'PICURLS'"` // 介绍图片[多张用逗号分隔]

	Currencysign string `json:"currencysign" xorm:"'CURRENCYSIGN'"` // 货币符号

	Vendorname string `json:"vendorname"  xorm:"'VENDORNAME'"` // 供应商名称

	Trademode uint32 `json:"trademode"  xorm:"'TRADEMODE'" binding:"required"` // 交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价
}

// GetHsbyMyPackages 获取我的包裹信息
// 输入 accountIDs string 资金账户列表
// 输入 takeOrderStatus int 提货状态 - 1:待发货 2:已发货 3:已收货
// 输出 []HsbyMyPackage 我的包裹信息
// 输出 error error
func GetHsbyMyPackages(accountIDs string, takeOrderStatus int) ([]HsbyMyPackage, error) {
	engine := db.GetEngine()

	myPackages := make([]HsbyMyPackage, 0)
	session := engine.Table("TRADE_GOODSPICKUP").
		Select(`to_char(TRADE_GOODSPICKUP.TAKEORDERID) TAKEORDERID, (DIVISION.PATHNAME || TRADE_GOODSPICKUP.ADDRESS) ADDRESS, TRADE_GOODSPICKUP.*, 
				(TRADE_GOODSPICKUP.AMOUNT/TRADE_GOODSPICKUP.QTY/GOODS.AGREEUNIT) AVERAGEPRICE, 
				GOODS.GOODSCODE, GOODS.GOODSNAME, GOODS.DECIMALPLACE, GOODS.AGREEUNIT, 
				HSBY_GOODSEX.PICURLS, 
				ENUMDICITEM.PARAM2 CURRENCYSIGN, 
				HSBY_SUPPLIERINFO.VENDORNAME, 
				M.TRADEMODE`).
		Join("LEFT", "GOODS", "GOODS.GOODSID = TRADE_GOODSPICKUP.GOODSID").
		Join("LEFT", "HSBY_GOODSEX", "HSBY_GOODSEX.GOODSID = GOODS.GOODSID").
		Join("LEFT", "ENUMDICITEM", "GOODS.CURRENCYID = ENUMDICITEM.ENUMITEMNAME and ENUMDICITEM.ENUMDICCODE = 'currency'").
		Join("LEFT", "HSBY_SUPPLIERINFO", "HSBY_SUPPLIERINFO.VENDORID = HSBY_GOODSEX.VENDORID").
		Join("LEFT", "DIVISION", "DIVISION.AUTOID = TRADE_GOODSPICKUP.DISTRICTID").
		Join("LEFT", "MARKET M", "M.MARKETID = GOODS.MARKETID").
		Where(fmt.Sprintf("TRADE_GOODSPICKUP.ACCOUNTID in (%s)", accountIDs))
	if takeOrderStatus > 0 {
		session = session.And("TAKEORDERSTATUS = ?", takeOrderStatus)
	}
	if err := session.Find(&myPackages); err != nil {
		return nil, err
	}

	// FIXME：- 目前暂时在服务端对手机号码进行解密
	key, _ := hex.DecodeString(utils.AESSecretKey)
	for i := range myPackages {
		myPackage := &myPackages[i]

		if len(myPackage.Phonenum) > 0 {
			// 解密手机号码
			if phonenum, err := hex.DecodeString(myPackage.Phonenum); err == nil { // hex -> []byte
				if mobile, err := utils.AESDecrypt(phonenum, key); err == nil {
					myPackage.Phonenum = string(mobile)
				}
			}
		}
	}

	return myPackages, nil
}

// SetHsbyMyPackagesStatus 设置我的包裹提货状态
func SetHsbyMyPackagesStatus(takeOrderID string, accountID, status int) error {
	engine := db.GetEngine()

	sql := fmt.Sprintf("update TRADE_GOODSPICKUP set TAKEORDERSTATUS = %d where TAKEORDERID = %s and ACCOUNTID = %d", status, takeOrderID, accountID)
	_, err := engine.Exec(sql)

	return err
}

// GetHsbyProvincesAndCities 获取省市信息数组
// 参数 provinceID int 省ID，选填
// 返回 []Division 枚举信息数组
// 返回 error error
func GetHsbyProvincesAndCities(provinceID int) ([]Division, error) {
	engine := db.GetEngine()

	divisions := make([]Division, 0)
	session := engine.Where("DIVISIONLEVEL = 'province' or DIVISIONLEVEL = 'city'").
		And(`AUTOID in (
				(select DESCPROVINCEID AUTOID from HSBY_GOODSEX inner join GOODS on GOODS.GOODSID = HSBY_GOODSEX.GOODSID and GOODS.GOODSSTATUS in (2,3))
				union all
				(select DESCCITYID AUTOID from HSBY_GOODSEX inner join GOODS on GOODS.GOODSID = HSBY_GOODSEX.GOODSID and GOODS.GOODSSTATUS in (2,3))
						)`)
	if provinceID > 0 {
		session = session.And("AUTOID = ?", provinceID)
	}
	if err := session.Find(&divisions); err != nil {
		return nil, err
	}

	return divisions, nil
}

// HsbyBuyMyTradeDetail "我的订单 - 已完成"单据信息（一二级市场成交单，包括历史数据）
type HsbyBuyMyTradeDetail struct {
	Orderid   string    `json:"orderid"  xorm:"'ORDERID'" binding:"required"`     // 单号（成交单号）
	Marketid  int32     `json:"marketid"  xorm:"'MARKETID'" binding:"required"`   // 市场ID
	Goodsid   int32     `json:"goodsid"  xorm:"'GOODSID'" binding:"required"`     // 商品ID
	Accountid int64     `json:"accountid"  xorm:"'ACCOUNTID'" binding:"required"` // 账户ID[报价币种]
	Buyorsell int32     `json:"buyorsell"  xorm:"'BUYORSELL'" binding:"required"` // 买卖 - 0:买 1:卖
	Price     float64   `json:"price"  xorm:"'PRICE'"`                            // 价格
	Qty       int64     `json:"qty"  xorm:"'QTY'" binding:"required"`             // 数量
	Time      time.Time `json:"time"  xorm:"'TIME'" binding:"required"`           // 时间
	Amount    float64   `json:"amount" xorm:"'AMOUNT'"`                           // 金额 = 价格 * 数量 * 合约单位

	Goodscode    string  `json:"goodscode"  xorm:"'GOODSCODE'" binding:"required"` // 商品代码(内部)
	Goodsname    string  `json:"goodsname"  xorm:"'GOODSNAME'" binding:"required"` // 商品名称
	Decimalplace int64   `json:"decimalplace"  xorm:"'DECIMALPLACE'"`              // 报价小数位
	Agreeunit    float64 `json:"agreeunit"  xorm:"'AGREEUNIT'"`                    // 合约单位

	Picurls1 string `json:"picurls1"  xorm:"'PICURLS1'"` // 预售商品介绍图片[多张用逗号分隔]
	Picurls2 string `json:"picurls2"  xorm:"'PICURLS2'"` // 挂牌商品介绍图片[多张用逗号分隔]

	Trademode uint32 `json:"trademode"  xorm:"'TRADEMODE'" binding:"required"` // 交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价

	Currencysign string `json:"currencysign" xorm:"'CURRENCYSIGN'"` // 货币符号

	Vendorname1 string `json:"vendorname1"  xorm:"'VENDORNAME1'"` // 预售商品供应商名称
	Vendorname2 string `json:"vendorname2"  xorm:"'VENDORNAME2'"` // 挂牌商品供应商名称

	Orderamount float64 `json:"orderamount" xorm:"ORDERAMOUNT"` // 委托金额
}

// GetHsbyBuyMyTradeDetails 获取"我的订单 - 已完成"单据信息（一二级市场成交单，包括历史数据）
// 输入 accountIDs string 资金账户列表
// 输出 []HsbyBuyMyTradeDetail "我的订单 - 已完成"单据信息
// 输出 error error
func GetHsbyBuyMyTradeDetails(accountIDs string) ([]HsbyBuyMyTradeDetail, error) {
	// 获取市场信息
	markets, err := GetMarkets()
	if err != nil {
		return nil, err
	}

	engine := db.GetEngine()
	marketIDs := "" // 我的订单包括一二级市场卖方向成交单（包括历史成交单）
	// 默认取 TradeMode = 16
	for _, v := range markets {
		if v.Trademode == 16 || v.Trademode == 71 || v.Trademode == 70 {
			if len(marketIDs) == 0 {
				marketIDs = strconv.Itoa(int(v.Marketid))
			} else {
				marketIDs += "," + strconv.Itoa(int(v.Marketid))
			}
		}
	}

	orders := make([]HsbyBuyMyTradeDetail, 0)

	// 当前成交单
	curOrders := make([]HsbyBuyMyTradeDetail, 0)
	if err := engine.Table("TRADE_TRADEDETAIL").
		Select(`to_char(TRADE_TRADEDETAIL.TRADEID) ORDERID, 
				TRADE_TRADEDETAIL.MARKETID, TRADE_TRADEDETAIL.GOODSID, TRADE_TRADEDETAIL.ACCOUNTID, TRADE_TRADEDETAIL.BUYORSELL,
				TRADE_TRADEDETAIL.TRADEPRICE PRICE, TRADE_TRADEDETAIL.TRADEQTY QTY, TRADE_TRADEDETAIL.TRADETIME TIME, TRADE_TRADEDETAIL.TRADEAMOUNT AMOUNT, 
				GOODS.GOODSCODE, GOODS.GOODSNAME, GOODS.DECIMALPLACE, GOODS.AGREEUNIT, 
				HG1.PICURLS PICURLS1, HG2.PICURLS PICURLS2, 
				MARKET.TRADEMODE, 
				ENUMDICITEM.PARAM2 CURRENCYSIGN, 
				HS1.VENDORNAME VENDORNAME1, HS2.VENDORNAME VENDORNAME2, 
				(OD.ORDERPRICE * OD.ORDERQTY * GOODS.AGREEUNIT) ORDERAMOUNT`).
		Join("LEFT", "GOODS", "GOODS.GOODSID = TRADE_TRADEDETAIL.GOODSID").
		Join("LEFT", "CPTRADE_PRESALEGOODSEX", "CPTRADE_PRESALEGOODSEX.GOODSID = TRADE_TRADEDETAIL.GOODSID").
		Join("LEFT", "HSBY_GOODSEX HG1", "HG1.GOODSID = CPTRADE_PRESALEGOODSEX.RELATEDGOODSID").
		Join("LEFT", "HSBY_GOODSEX HG2", "HG2.GOODSID = GOODS.GOODSID").
		Join("LEFT", "ENUMDICITEM", "GOODS.CURRENCYID = ENUMDICITEM.ENUMITEMNAME and ENUMDICITEM.ENUMDICCODE = 'currency'").
		Join("LEFT", "MARKET", "MARKET.MARKETID = TRADE_TRADEDETAIL.MARKETID").
		Join("LEFT", "HSBY_SUPPLIERINFO HS1", "HS1.VENDORID = HG1.VENDORID").
		Join("LEFT", "HSBY_SUPPLIERINFO HS2", "HS2.VENDORID = HG2.VENDORID").
		Join("LEFT", "TRADE_ORDERDETAIL OD", "OD.ORDERID = TRADE_TRADEDETAIL.ORDERID").
		Where(fmt.Sprintf(`TRADE_TRADEDETAIL.BUYORSELL = 0 and TRADE_TRADEDETAIL.TRADETYPE in (1,24) 
						   and TRADE_TRADEDETAIL.ACCOUNTID in (%s)`, accountIDs)).
		And(fmt.Sprintf("TRADE_TRADEDETAIL.MARKETID in (%s)", marketIDs)).Find(&curOrders); err != nil {
		return nil, err
	}
	if len(curOrders) > 0 {
		orders = append(orders, curOrders...)
	}

	// 历史成交单
	hisOrders := make([]HsbyBuyMyTradeDetail, 0)
	if err := engine.Table("HIS_TRADE_TRADEDETAIL").
		Select(`to_char(HIS_TRADE_TRADEDETAIL.TRADEID) ORDERID, 
				HIS_TRADE_TRADEDETAIL.MARKETID, HIS_TRADE_TRADEDETAIL.GOODSID, HIS_TRADE_TRADEDETAIL.ACCOUNTID, HIS_TRADE_TRADEDETAIL.BUYORSELL,
				HIS_TRADE_TRADEDETAIL.TRADEPRICE PRICE, HIS_TRADE_TRADEDETAIL.TRADEQTY QTY, HIS_TRADE_TRADEDETAIL.TRADETIME TIME, HIS_TRADE_TRADEDETAIL.TRADEAMOUNT AMOUNT, 
				GOODS.GOODSCODE, GOODS.GOODSNAME, GOODS.DECIMALPLACE, GOODS.AGREEUNIT, 
				HG1.PICURLS PICURLS1, HG2.PICURLS PICURLS2, 
				MARKET.TRADEMODE, 
				ENUMDICITEM.PARAM2 CURRENCYSIGN, 
				HS1.VENDORNAME VENDORNAME1, HS2.VENDORNAME VENDORNAME2, 
				(OD.ORDERPRICE * OD.ORDERQTY * GOODS.AGREEUNIT) ORDERAMOUNT`).
		Join("LEFT", "GOODS", "GOODS.GOODSID = HIS_TRADE_TRADEDETAIL.GOODSID").
		Join("LEFT", "CPTRADE_PRESALEGOODSEX", "CPTRADE_PRESALEGOODSEX.GOODSID = HIS_TRADE_TRADEDETAIL.GOODSID").
		Join("LEFT", "HSBY_GOODSEX HG1", "HG1.GOODSID = CPTRADE_PRESALEGOODSEX.RELATEDGOODSID").
		Join("LEFT", "HSBY_GOODSEX HG2", "HG2.GOODSID = GOODS.GOODSID").
		Join("LEFT", "ENUMDICITEM", "GOODS.CURRENCYID = ENUMDICITEM.ENUMITEMNAME and ENUMDICITEM.ENUMDICCODE = 'currency'").
		Join("LEFT", "MARKET", "MARKET.MARKETID = HIS_TRADE_TRADEDETAIL.MARKETID").
		Join("LEFT", "HSBY_SUPPLIERINFO HS1", "HS1.VENDORID = HG1.VENDORID").
		Join("LEFT", "HSBY_SUPPLIERINFO HS2", "HS2.VENDORID = HG2.VENDORID").
		Join("LEFT", "HIS_TRADE_ORDERDETAIL OD", "OD.ORDERID = HIS_TRADE_TRADEDETAIL.ORDERID").
		Where(fmt.Sprintf(`HIS_TRADE_TRADEDETAIL.BUYORSELL = 0 and HIS_TRADE_TRADEDETAIL.TRADETYPE in (1,24) and HIS_TRADE_TRADEDETAIL.ISVALIDDATA = 1 
						   and HIS_TRADE_TRADEDETAIL.ACCOUNTID in (%s)`, accountIDs)).
		And(fmt.Sprintf("HIS_TRADE_TRADEDETAIL.MARKETID in (%s)", marketIDs)).Find(&hisOrders); err != nil {
		return nil, err
	}
	if len(hisOrders) > 0 {
		orders = append(orders, hisOrders...)
	}

	return orders, nil
}

// HsbyBuyMyPayOrder "我的订单 - 待付款"单据信息（一二级市场待付款信息）
type HsbyBuyMyPayOrder struct {
	Tradeid        string    `json:"tradeid"  xorm:"'TRADEIDSTR'" binding:"required"` // 成交单号(101+Unix秒时间戳(10位)+2位(MarketServiceID)+xxxx)
	Tradedate      string    `json:"tradedate"  xorm:"'TRADEDATE'"`                   // 交易日(yyyyMMdd)
	Marketid       int32     `json:"marketid"  xorm:"'MARKETID'"`                     // 市场ID
	Goodsid        int32     `json:"goodsid"  xorm:"'GOODSID'"`                       // 商品ID
	Buyorderid     string    `json:"buyorderid"  xorm:"'BUYORDERIDSTR'"`              // 买方委托单号
	Buyaccountid   int64     `json:"buyaccountid"  xorm:"'BUYACCOUNTID'"`             // 买方账号ID[报价币种]
	Sellorderid    string    `json:"sellorderid"  xorm:"'SELLORDERIDSTR'"`            // 卖方委托单号
	Sellaccountid  int64     `json:"sellaccountid"  xorm:"'SELLACCOUNTID'"`           // 卖方账号ID[报价币种]
	Tradeamount    float64   `json:"tradeamount"  xorm:"'TRADEAMOUNT'"`               // 成交金额
	Tradecharge    float64   `json:"tradecharge"  xorm:"'TRADECHARGE'"`               // 成交手续费(买方)
	Payflag        int32     `json:"payflag"  xorm:"'PAYFLAG'"`                       // 付款标识 - 1:未支付 2:已支付 3:已过期 4:已撤销 5:结算过期 6:预售终止
	Createtime     time.Time `json:"createtime"  xorm:"'CREATETIME'"`                 // 创建时间
	Paytime        time.Time `json:"paytime"  xorm:"'PAYTIME'"`                       // 付款时间
	Paylimitedtime time.Time `json:"paylimitedtime"  xorm:"'PAYLIMITEDTIME'"`         // 支付期限
	Offamount      float64   `json:"offamount"  xorm:"'OFFAMOUNT'"`                   // 优惠金额
	Tradeprice     float64   `json:"tradeprice"  xorm:"'TRADEPRICE'"`                 // 成交价格
	Tradeqty       int64     `json:"tradeqty"  xorm:"'TRADEQTY'"`                     // 成交数量
	Payamount      float64   `json:"payamount"  xorm:"'PAYAMOUNT'"`                   // 支付金额 = TradeAmount + TradeCharge

	OriginalAmount float64 `json:"originalamount" xorm:"ORIGINALAMOUNT"` // 原金额 = TradeAmount + TradeCharge + OffAmount

	Goodscode    string  `json:"goodscode"  xorm:"'GOODSCODE'" binding:"required"` // 商品代码(内部)
	Goodsname    string  `json:"goodsname"  xorm:"'GOODSNAME'" binding:"required"` // 商品名称
	Decimalplace int64   `json:"decimalplace"  xorm:"'DECIMALPLACE'"`              // 报价小数位
	Agreeunit    float64 `json:"agreeunit"  xorm:"'AGREEUNIT'"`                    // 合约单位

	Picurls1 string `json:"picurls1"  xorm:"'PICURLS1'"` // 预售商品介绍图片[多张用逗号分隔]
	Picurls2 string `json:"picurls2"  xorm:"'PICURLS2'"` // 挂牌商品介绍图片[多张用逗号分隔]

	Trademode uint32 `json:"trademode"  xorm:"'TRADEMODE'" binding:"required"` // 交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价

	Currencysign string `json:"currencysign" xorm:"'CURRENCYSIGN'"` // 货币符号

	Vendorname1 string `json:"vendorname1"  xorm:"'VENDORNAME1'"` // 预售商品供应商名称
	Vendorname2 string `json:"vendorname2"  xorm:"'VENDORNAME2'"` // 挂牌商品供应商名称
}

// GetHsbyBuyMyPayOrders 获取待付款信息
func GetHsbyBuyMyPayOrders(accountIDs string, buyOrderID, sellOrderID int) ([]HsbyBuyMyPayOrder, error) {
	// 获取市场信息
	markets, err := GetMarkets()
	if err != nil {
		return nil, err
	}

	engine := db.GetEngine()
	marketIDs := "" // 我的订单包括一二级市场卖方向成交单
	// 默认取 TradeMode = 16
	for _, v := range markets {
		if v.Trademode == 16 || v.Trademode == 71 || v.Trademode == 70 {
			if len(marketIDs) == 0 {
				marketIDs = strconv.Itoa(int(v.Marketid))
			} else {
				marketIDs += "," + strconv.Itoa(int(v.Marketid))
			}
		}
	}

	orders := make([]HsbyBuyMyPayOrder, 0)
	session := engine.Table("TRADE_PAYORDER TP").
		Select(`to_char(TP.TRADEID) TRADEIDSTR, to_char(TP.BUYORDERID) BUYORDERIDSTR, to_char(TP.SELLORDERID) SELLORDERIDSTR, TP.*, (TP.TRADEAMOUNT + NVL(TP.TRADECHARGE,0) + NVL(TP.OFFAMOUNT,0)) ORIGINALAMOUNT,
				GOODS.GOODSCODE, GOODS.GOODSNAME, GOODS.DECIMALPLACE, GOODS.AGREEUNIT, 
				HG1.PICURLS PICURLS1, HG2.PICURLS PICURLS2, 
				MARKET.TRADEMODE, 
				ENUMDICITEM.PARAM2 CURRENCYSIGN, 
				HS1.VENDORNAME VENDORNAME1, HS2.VENDORNAME VENDORNAME2`).
		Join("LEFT", "GOODS", "GOODS.GOODSID = TP.GOODSID").
		Join("LEFT", "CPTRADE_PRESALEGOODSEX CP", "CP.GOODSID = TP.GOODSID").
		Join("LEFT", "HSBY_GOODSEX HG1", "HG1.GOODSID = CP.RELATEDGOODSID").
		Join("LEFT", "HSBY_GOODSEX HG2", "HG2.GOODSID = GOODS.GOODSID").
		Join("LEFT", "ENUMDICITEM", "GOODS.CURRENCYID = ENUMDICITEM.ENUMITEMNAME and ENUMDICITEM.ENUMDICCODE = 'currency'").
		Join("LEFT", "MARKET", "MARKET.MARKETID = TP.MARKETID").
		Join("LEFT", "HSBY_SUPPLIERINFO HS1", "HS1.VENDORID = HG1.VENDORID").
		Join("LEFT", "HSBY_SUPPLIERINFO HS2", "HS2.VENDORID = HG2.VENDORID").
		Where(fmt.Sprintf(`TP.PAYFLAG = 1 and TP.BUYACCOUNTID in (%s)`, accountIDs)).
		And(fmt.Sprintf("TP.MARKETID in (%s)", marketIDs))
	if buyOrderID != 0 {
		session = session.And("TP.BUYORDERID = ?", buyOrderID)
	}
	if sellOrderID != 0 {
		session = session.And("TP.SELLORDERID = ?", sellOrderID)
	}
	if err := session.Find(&orders); err != nil {
		return nil, err
	}

	return orders, nil
}

// HsbyMarketInfo 海商报业相关市场信息
type HsbyMarketInfo struct {
	Marketid     int32  `json:"marketid"  xorm:"'MARKETID'" binding:"required"`         // 市场ID正常5位，前三位固定：两位表示交易模式， 一位表示交易属性(1:收益权，2：所有权) 其它特殊市场：0-系统 1-交割服务 2-账户服务3-履约服务 4-仓单服务 5-积分服务 6-银行服务
	Marketname   string `json:"marketname"  xorm:"'MARKETNAME'"`                        // 市场名称
	Trademode    int32  `json:"trademode"  xorm:"'TRADEMODE'" binding:"required"`       // 交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价
	Marketstatus int32  `json:"marketstatus"  xorm:"'MARKETSTATUS'" binding:"required"` // 生效状态(ValidStatus枚举): 1:待生效 2:正常 3:注销
}

// GetHsbyMarketInfos 获取海商报业相关市场信息
func GetHsbyMarketInfos() ([]HsbyMarketInfo, error) {
	engine := db.GetEngine()

	markets := make([]HsbyMarketInfo, 0)
	if err := engine.Table("MARKET").Where("TRADEMODE in (71,16,70)").Find(&markets); err != nil {
		return nil, err
	}

	return markets, nil
}

// HsbySellCollectionOrder 我的闲置中收款信息
type HsbySellCollectionOrder struct {
	Tradeid        string    `json:"tradeid"  xorm:"'TRADEIDSTR'" binding:"required"` // 成交单号(101+Unix秒时间戳(10位)+2位(MarketServiceID)+xxxx)
	Tradedate      string    `json:"tradedate"  xorm:"'TRADEDATE'"`                   // 交易日(yyyyMMdd)
	Marketid       int32     `json:"marketid"  xorm:"'MARKETID'"`                     // 市场ID
	Goodsid        int32     `json:"goodsid"  xorm:"'GOODSID'"`                       // 商品ID
	Buyorderid     string    `json:"buyorderid"  xorm:"'BUYORDERIDSTR'"`              // 买方委托单号
	Buyaccountid   int64     `json:"buyaccountid"  xorm:"'BUYACCOUNTID'"`             // 买方账号ID[报价币种]
	Sellorderid    string    `json:"sellorderid"  xorm:"'SELLORDERIDSTR'"`            // 卖方委托单号
	Sellaccountid  int64     `json:"sellaccountid"  xorm:"'SELLACCOUNTID'"`           // 卖方账号ID[报价币种]
	Tradeamount    float64   `json:"tradeamount"  xorm:"'TRADEAMOUNT'"`               // 成交金额
	Tradecharge    float64   `json:"tradecharge"  xorm:"'TRADECHARGE'"`               // 成交手续费(买方)
	Payflag        int32     `json:"payflag"  xorm:"'PAYFLAG'"`                       // 付款标识 - 1:未支付 2:已支付 3:已过期 4:已撤销 5:结算过期 6:预售终止
	Createtime     time.Time `json:"createtime"  xorm:"'CREATETIME'"`                 // 创建时间
	Paytime        time.Time `json:"paytime"  xorm:"'PAYTIME'"`                       // 付款时间
	Paylimitedtime time.Time `json:"paylimitedtime"  xorm:"'PAYLIMITEDTIME'"`         // 支付期限
	Offamount      float64   `json:"offamount"  xorm:"'OFFAMOUNT'"`                   // 优惠金额
	Tradeprice     float64   `json:"tradeprice"  xorm:"'TRADEPRICE'"`                 // 成交价格
	Tradeqty       int64     `json:"tradeqty"  xorm:"'TRADEQTY'"`                     // 成交数量
	Payamount      float64   `json:"payamount"  xorm:"'PAYAMOUNT'"`                   // 支付金额 = TradeAmount + TradeCharge - OffAmount

	Goodscode    string  `json:"goodscode"  xorm:"'GOODSCODE'" binding:"required"` // 商品代码(内部)
	Goodsname    string  `json:"goodsname"  xorm:"'GOODSNAME'" binding:"required"` // 商品名称
	Decimalplace int64   `json:"decimalplace"  xorm:"'DECIMALPLACE'"`              // 报价小数位
	Agreeunit    float64 `json:"agreeunit"  xorm:"'AGREEUNIT'"`                    // 合约单位

	Picurls string `json:"picurls"  xorm:"'PICURLS'"` // 商品介绍图片[多张用逗号分隔]

	Trademode uint32 `json:"trademode"  xorm:"'TRADEMODE'" binding:"required"` // 交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价

	Currencysign string `json:"currencysign" xorm:"'CURRENCYSIGN'"` // 货币符号
}

// GetHsbySellCollectionOrders 获取我的闲置中待收款信息
func GetHsbySellCollectionOrders(accountIDs string) ([]HsbySellCollectionOrder, error) {
	// 获取市场信息
	markets, err := GetMarkets()
	if err != nil {
		return nil, err
	}

	engine := db.GetEngine()
	marketIDs := ""
	for _, v := range markets {
		if v.Trademode == 16 || v.Trademode == 70 {
			if len(marketIDs) == 0 {
				marketIDs = strconv.Itoa(int(v.Marketid))
			} else {
				marketIDs += "," + strconv.Itoa(int(v.Marketid))
			}
		}
	}

	orders := make([]HsbySellCollectionOrder, 0)
	session := engine.Table("TRADE_PAYORDER TP").
		Select(`to_char(TP.TRADEID) TRADEIDSTR, to_char(TP.BUYORDERID) BUYORDERIDSTR, to_char(TP.SELLORDERID) SELLORDERIDSTR, TP.*,
				G.GOODSCODE, G.GOODSNAME, G.DECIMALPLACE, G.AGREEUNIT, 
				HG.PICURLS, 
				M.TRADEMODE, 
				E.PARAM2 CURRENCYSIGN`).
		Join("LEFT", "GOODS G", "G.GOODSID = TP.GOODSID").
		Join("LEFT", "HSBY_GOODSEX HG", "HG.GOODSID = G.GOODSID").
		Join("LEFT", "ENUMDICITEM E", "G.CURRENCYID = E.ENUMITEMNAME and E.ENUMDICCODE = 'currency'").
		Join("LEFT", "MARKET M", "M.MARKETID = TP.MARKETID").
		Join("LEFT", "HSBY_SUPPLIERINFO HS", "HS.VENDORID = HG.VENDORID").
		Where(fmt.Sprintf(`TP.PAYFLAG = 1 and TP.SELLACCOUNTID in (%s)`, accountIDs)).
		And(fmt.Sprintf("TP.MARKETID in (%s)", marketIDs))
	if err := session.Find(&orders); err != nil {
		return nil, err
	}

	return orders, nil
}

// HsbyMarketGoods 特卖商城商品（三级市场商场）
type HsbyMarketGoods struct {
	Orderid     string  `json:"orderid"  xorm:"'ORDERIDSTR'" binding:"required"`  // 委托单号(100+Unix秒时间戳(10位)+2位(MarketServiceID)+xxxx)
	Marketid    int32   `json:"marketid"  xorm:"'MARKETID'" binding:"required"`   // 市场ID
	Goodsid     int32   `json:"goodsid"  xorm:"'GOODSID'" binding:"required"`     // 商品ID
	Accountid   int64   `json:"accountid"  xorm:"'ACCOUNTID'" binding:"required"` // 账户ID[报价币种]
	Buyorsell   int32   `json:"buyorsell"  xorm:"'BUYORSELL'" binding:"required"` // 买卖 - 0:买 1:卖
	Orderprice  float64 `json:"orderprice"  xorm:"'ORDERPRICE'"`                  // 委托价格
	Orderstatus int32   `json:"orderstatus"  xorm:"'ORDERSTATUS'"`                // 委托状态 - 1： 委托请求 2：待冻结 3：委托成功 4： 委托失败 5：配对成功 6： 已撤销 7：部分成交 8：已成交 9：部成部撤 10：成交失败 11：已拒绝 12:经过摘牌(先摘后挂专用-先摘后挂已摘过) 13:冻结成功(通道交易专用) 14:通道已撤 15:通道部成部撤 16:成交失败违约(荷兰式竞拍专用)

	Goodscode    string  `json:"goodscode"  xorm:"'GOODSCODE'" binding:"required"` // 商品代码(内部)
	Goodsname    string  `json:"goodsname"  xorm:"'GOODSNAME'" binding:"required"` // 商品名称
	Decimalplace int64   `json:"decimalplace"  xorm:"'DECIMALPLACE'"`              // 报价小数位
	Quoteminunit int64   `json:"quoteminunit"  xorm:"'QUOTEMINUNIT'"`              // 行情最小变动单位 [整数，报价小数位一起使用]
	Agreeunit    float64 `json:"agreeunit"  xorm:"'AGREEUNIT'"`                    // 合约单位

	Hotindex   int32   `json:"hotindex"  xorm:"'HOTINDEX'"`     // 景点热度
	Videourls  string  `json:"videourls"  xorm:"'VIDEOURLS'"`   // 介绍视频[多张用逗号分隔]
	Picurls    string  `json:"picurls"  xorm:"'PICURLS'"`       // 介绍图片[多张用逗号分隔]
	Categoryid int32   `json:"categoryid"  xorm:"'CATEGORYID'"` // 类别ID(WRCATEGORY)
	Goodsprice float64 `json:"goodsprice"  xorm:"'GOODSPRICE'"` // 商品价格

	Currency     string `json:"currency" xorm:"'CURRENCY'"`         // 货币
	Currencysign string `json:"currencysign" xorm:"'CURRENCYSIGN'"` // 货币符号

	Trademode int32 `json:"trademode"  xorm:"'TRADEMODE'" binding:"required"` // 交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价

	Customername string `json:"customername"  xorm:"'CUSTOMERNAME'"` // 卖家名称

	HasCoupon bool `json:"hascoupon" xorm:"-"` // 是否可用优惠卷

	SellUserID int `json:"sellUserID" xorm:"-"` // 卖方UserID
}

// GetHsbyMarketGoodsesByVisitor 游客获取商城商品列表（三级商城）
func GetHsbyMarketGoodsesByVisitor(marketIDs string, categoryID int, goodsIDs string) ([]HsbyMarketGoods, error) {
	engine := db.GetEngine()

	orders := make([]HsbyMarketGoods, 0)
	session := engine.Table("GOODS G").
		Select(`'1' ORDERIDSTR, 2 ACCOUNTID, 0 BUYORSELL, 
				G.GOODSID, G.MARKETID, G.GOODSCODE, G.GOODSNAME, G.DECIMALPLACE, G.QUOTEMINUNIT, G.AGREEUNIT, 
				GX.HOTINDEX, GX.PICURLS, GX.CATEGORYID, GX.GOODSDESC, GX.GOODSPRICE, 
				E.ENUMDICNAME CURRENCY, E.PARAM2 CURRENCYSIGN, 
				M.TRADEMODE`).
		Join("LEFT", "HSBY_GOODSEX GX", "GX.GOODSID = G.GOODSID").
		Join("LEFT", "ENUMDICITEM E", "E.ENUMITEMNAME = G.CURRENCYID and E.ENUMDICCODE = 'currency'").
		Join("LEFT", "MARKET M", "M.MARKETID = G.MARKETID").
		Where(fmt.Sprintf("G.GOODSSTATUS = 3 and G.MARKETID in (%s)", marketIDs))
	if categoryID != 0 {
		session = session.And("GX.CATEGORYID = ?", categoryID)
	}
	if len(goodsIDs) > 0 {
		session = session.And(fmt.Sprintf("G.GOODSID in (%s)", goodsIDs))
	}
	if err := session.Find(&orders); err != nil {
		return nil, err
	}

	return orders, nil
}

// GetHsbyMarketGoodses 获取商城商品列表（三级商城）
func GetHsbyMarketGoodses(marketIDs string, accountID, categoryID int, goodsIDs string, couponTypeID int) ([]HsbyMarketGoods, error) {
	engine := db.GetEngine()

	// 新需求：当账号登录后传入accountID时，只显示此账户所属会员下面的商城商品（注意会员账号的所属会员就是自己）
	// 获取accountID对应账户的所属会员UserID
	var memberUserIDs []string
	if err := engine.Table("USERACCOUNT U").
		Select("to_char(U.MEMBERUSERID) MEMBERUSERID").
		Join("INNER", "TAACCOUNT TA", "TA.RELATEDUSERID = U.USERID").
		Where("TA.ACCOUNTID = ?", accountID).
		Find(&memberUserIDs); err != nil {
		return nil, err
	}

	// 获取此会员下所有的资金账户
	var memberAccountIDs []string
	if err := engine.Table("TAACCOUNT").
		Select("to_char(ACCOUNTID) ACCOUNTID").
		Where(fmt.Sprintf("RELATEDUSERID in (%s)", strings.Join(memberUserIDs, ","))).
		Find(&memberAccountIDs); err != nil {
		fmt.Println(err.Error())
		return nil, err
	}

	// 获取优惠卷类型信息
	var couponType Coupontype
	if _, err := engine.Where("ISVALID = 1 and COUPONTYPEID = ?", couponTypeID).Get(&couponType); err != nil {
		return nil, err
	}

	orders := make([]HsbyMarketGoods, 0)
	// 与挂牌点选不一样的是商城是以委托单为主表；已经卖完的委托单不显示
	session := engine.Table("TRADE_ORDERDETAIL T").
		Select(`to_char(T.ORDERID) ORDERIDSTR, T.*, 
				G.GOODSCODE, G.GOODSNAME, G.DECIMALPLACE, G.QUOTEMINUNIT, G.AGREEUNIT, 
				GX.HOTINDEX, GX.PICURLS, GX.CATEGORYID, GX.GOODSDESC, GX.GOODSPRICE, 
				E.ENUMDICNAME CURRENCY, E.PARAM2 CURRENCYSIGN, 
				M.TRADEMODE, 
				U.CUSTOMERNAME`).
		Join("LEFT", "GOODS G", "G.GOODSID = T.GOODSID").
		Join("LEFT", "HSBY_GOODSEX GX", "GX.GOODSID = T.GOODSID").
		Join("LEFT", "ENUMDICITEM E", "E.ENUMITEMNAME = G.CURRENCYID and E.ENUMDICCODE = 'currency'").
		Join("LEFT", "MARKET M", "M.MARKETID = T.MARKETID").
		Join("LEFT", "TAACCOUNT TA", "TA.ACCOUNTID = T.ACCOUNTID").
		Join("LEFT", "USERINFO U", "U.USERID = TA.RELATEDUSERID").
		Where(fmt.Sprintf("T.MARKETID in (%s)", marketIDs)).
		And("T.ORDERSTATUS in (3,7) and T.BUYORSELL = 1 and (T.ORDERQTY - T.TRADEQTY - T.CANCELQTY) > 0").
		And(fmt.Sprintf("T.ACCOUNTID in (%s)", strings.Join(memberAccountIDs, ",")))
	if categoryID != 0 {
		session = session.And("GX.CATEGORYID = ?", categoryID)
	}
	if len(goodsIDs) > 0 {
		session = session.And(fmt.Sprintf("G.GOODSID in (%s)", goodsIDs))
	}
	if couponTypeID > 0 {
		if couponType.Coupontypeid == 0 {
			// 没有查询到对应的优惠卷，直接返回空数组
			return make([]HsbyMarketGoods, 0), nil
		}

		// 优惠卷特定商品
		if couponType.Limitedflag == 1 {
			// 去掉头尾逗号
			limitedGoodsIDs := couponType.Limitedgoodsids
			if strings.HasPrefix(limitedGoodsIDs, ",") && strings.HasSuffix(limitedGoodsIDs, ",") {
				limitedGoodsIDs = limitedGoodsIDs[1 : len(limitedGoodsIDs)-1]
			}
			session = session.And(fmt.Sprintf("T.GOODSID in (%s)", limitedGoodsIDs))
		}

		// 优惠卷特定卖家
		if couponType.Isgeneral == 0 {
			// 去掉头尾逗号
			userScope := couponType.Userscope
			if strings.HasPrefix(userScope, ",") && strings.HasSuffix(userScope, ",") {
				userScope = userScope[1 : len(userScope)-1]
			}
			// 查询对应的卖家资金账户信息
			taAccounts := make([]Taaccount, 0)
			if err := engine.Where(fmt.Sprintf("RELATEDUSERID in (%s)", userScope)).Find(&taAccounts); err != nil {
				return nil, err
			}
			sellAccountIDs := ""
			for _, v := range taAccounts {
				if len(sellAccountIDs) == 0 {
					sellAccountIDs = strconv.Itoa(int(v.Accountid))
				} else {
					sellAccountIDs += "," + strconv.Itoa(int(v.Accountid))
				}
			}
			session = session.And(fmt.Sprintf("T.ACCOUNTID in (%s)", sellAccountIDs))
		}
	}
	if err := session.Find(&orders); err != nil {
		return nil, err
	}

	// 获取当前账户的优惠卷
	type myCouponPosition struct {
		Accountid    int64 `json:"accountid"  xorm:"'ACCOUNTID'" binding:"required"`       // 资金账户ID
		Coupontypeid int32 `json:"coupontypeid"  xorm:"'COUPONTYPEID'" binding:"required"` // 优惠券类型ID
		Curqty       int64 `json:"curqty"  xorm:"'CURQTY'"`                                // 期末数量
		Curfreezeqty int64 `json:"curfreezeqty"  xorm:"'CURFREEZEQTY'"`                    // 期末冻结数量

		Limitedflag     int32  `json:"limitedflag"  xorm:"'LIMITEDFLAG'"`         // 是否指定商品 - 0:不限 1:限制
		Limitedgoodsids string `json:"limitedgoodsids"  xorm:"'LIMITEDGOODSIDS'"` // 指定商品IDs[逗号分隔,前后加逗号]
		Isgeneral       int32  `json:"isgeneral"  xorm:"'ISGENERAL'"`             // 是否通用券 - 0:否 1:是
		Userscope       string `json:"userscope"  xorm:"'USERSCOPE'"`             // 卖家范围(用户ID，逗号分隔,前后加逗号) [IsGeneral =0时使用]
	}
	myCouponPositions := make([]myCouponPosition, 0)
	if accountID != 0 {
		if err := engine.Table("COUPONPOSITION C").
			Select(`C.ACCOUNTID, C.COUPONTYPEID, C.CURQTY, C.CURFREEZEQTY,
				CT.LIMITEDFLAG, CT.LIMITEDGOODSIDS, CT.ISGENERAL, CT.USERSCOPE`).
			Join("INNER", "COUPONTYPE CT", "CT.COUPONTYPEID = C.COUPONTYPEID").
			Where("C.ACCOUNTID = ?", accountID).And("(C.CURQTY - C.CURFREEZEQTY) > 0").Find(&myCouponPositions); err != nil {
			return nil, err
		}
	}

	// 是否有优惠卷可用
	if len(orders) > 0 && len(myCouponPositions) > 0 {
		for _, coupon := range myCouponPositions {
			if coupon.Curqty <= 0 {
				continue
			}

			if coupon.Limitedflag == 0 && coupon.Isgeneral == 1 {
				// 有不指定商品的通用卷则所有委托单都可以用卷
				for i := range orders {
					order := &orders[i]
					order.HasCoupon = true
				}
				break
			} else {
				for i := range orders {
					order := &orders[i]

					// 获取卖家UserID
					userInfo, err := GetUserInfoByAccountID(int(order.Accountid))
					if err != nil {
						continue
					}
					order.SellUserID = int(userInfo.Userid)
					// order.Customername = userInfo.Customername

					tmpGoodsID := fmt.Sprintf(",%d,", order.Goodsid)
					tmpUserID := fmt.Sprintf(",%d,", userInfo.Userid)

					// 优惠卷是否可用于商品
					isRightGoods := false
					if coupon.Limitedflag == 0 {
						isRightGoods = true
					} else {
						if strings.Contains(coupon.Limitedgoodsids, tmpGoodsID) {
							isRightGoods = true
						}
					}
					// 优惠卷是否可用于卖家
					isRightAccount := false
					if coupon.Isgeneral == 1 {
						isRightAccount = true
					} else {
						if strings.Contains(coupon.Userscope, tmpUserID) {
							isRightAccount = true
						}
					}

					if isRightGoods && isRightAccount {
						order.HasCoupon = true
					}
				}
			}
		}
	}

	return orders, nil
}

// HsbyMarketGoodsDetail 特卖商城商品（三级市场商场）
type HsbyMarketGoodsDetail struct {
	Orderid     string  `json:"orderid"  xorm:"'ORDERIDSTR'" binding:"required"`  // 委托单号(100+Unix秒时间戳(10位)+2位(MarketServiceID)+xxxx)
	Marketid    int32   `json:"marketid"  xorm:"'MARKETID'" binding:"required"`   // 市场ID
	Goodsid     int32   `json:"goodsid"  xorm:"'GOODSID'" binding:"required"`     // 商品ID
	Accountid   int64   `json:"accountid"  xorm:"'ACCOUNTID'" binding:"required"` // 账户ID[报价币种]
	Buyorsell   int32   `json:"buyorsell"  xorm:"'BUYORSELL'" binding:"required"` // 买卖 - 0:买 1:卖
	Orderprice  float64 `json:"orderprice"  xorm:"'ORDERPRICE'"`                  // 委托价格
	Orderqty    int64   `json:"orderqty"  xorm:"'ORDERQTY'" binding:"required"`   // 委托数量
	Tradeqty    int64   `json:"tradeqty"  xorm:"'TRADEQTY'"`                      // 成交数量
	Cancelqty   int64   `json:"cancelqty"  xorm:"'CANCELQTY'"`                    // 撤单数量
	Orderstatus int32   `json:"orderstatus"  xorm:"'ORDERSTATUS'"`                // 委托状态 - 1： 委托请求 2：待冻结 3：委托成功 4： 委托失败 5：配对成功 6： 已撤销 7：部分成交 8：已成交 9：部成部撤 10：成交失败 11：已拒绝 12:经过摘牌(先摘后挂专用-先摘后挂已摘过) 13:冻结成功(通道交易专用) 14:通道已撤 15:通道部成部撤 16:成交失败违约(荷兰式竞拍专用)

	Goodscode    string  `json:"goodscode"  xorm:"'GOODSCODE'" binding:"required"` // 商品代码(内部)
	Goodsname    string  `json:"goodsname"  xorm:"'GOODSNAME'" binding:"required"` // 商品名称
	Decimalplace int64   `json:"decimalplace"  xorm:"'DECIMALPLACE'"`              // 报价小数位
	Quoteminunit int64   `json:"quoteminunit"  xorm:"'QUOTEMINUNIT'"`              // 行情最小变动单位 [整数，报价小数位一起使用]
	Agreeunit    float64 `json:"agreeunit"  xorm:"'AGREEUNIT'"`                    // 合约单位

	Hotindex   int32   `json:"hotindex"  xorm:"'HOTINDEX'"`     // 景点热度
	Videourls  string  `json:"videourls"  xorm:"'VIDEOURLS'"`   // 介绍视频[多张用逗号分隔]
	Picurls    string  `json:"picurls"  xorm:"'PICURLS'"`       // 介绍图片[多张用逗号分隔]
	Categoryid int32   `json:"categoryid"  xorm:"'CATEGORYID'"` // 类别ID(WRCATEGORY)
	Goodsdesc  string  `json:"goodsdesc"  xorm:"'GOODSDESC'"`   // 商品详情
	Goodsprice float64 `json:"goodsprice"  xorm:"'GOODSPRICE'"` // 商品价格

	Currency     string `json:"currency" xorm:"'CURRENCY'"`         // 货币
	Currencysign string `json:"currencysign" xorm:"'CURRENCYSIGN'"` // 货币符号

	Trademode int32 `json:"trademode"  xorm:"'TRADEMODE'" binding:"required"` // 交易模式 - 10:做市 13:竞价 15:通道交易 16:挂牌点选 17:仓单贸易 18:期权 19:竞拍-降价式 20:竞拍-竞价式 21:竞拍-大宗式 22:受托竞价

	Vendorname  string `json:"vendorname"  xorm:"'VENDORNAME'"`   // 供应商名称
	Vendorattr  string `json:"vendorattr"  xorm:"'VENDORATTR'"`   // 供应商附件(多张，逗号分隔)
	Vendorphone string `json:"vendorphone"  xorm:"'VENDORPHONE'"` // 供应商客服电话

	Customername string `json:"customername"  xorm:"'CUSTOMERNAME'"` // 卖家名称

	SellUserID int `json:"sellUserID" xorm:"SELLUSERID"` // 卖方UserID

	LotSize   int `json:"lotsize" xorm:"-"`      // 手数最小变动单位
	Buymaxqty int `json:"buymaxqty"  xorm:"'-'"` // 购买上限 [71] - 0为不限
}

// GetHsbyMarketGoodsDetailByVisitor 游客获取商城商品详情（三级商城）
func GetHsbyMarketGoodsDetailByVisitor(goodsID int) (*HsbyMarketGoodsDetail, error) {
	engine := db.GetEngine()

	orders := make([]HsbyMarketGoodsDetail, 0)
	// 游客商城商品以商品表为主表
	session := engine.Table("GOODS G").
		Select(`'1' ORDERIDSTR, 1 ACCOUNTID, 1 BUYORSELL, 1 ORDERQTY, 
				G.GOODSCODE, G.GOODSNAME, G.DECIMALPLACE, G.QUOTEMINUNIT, G.AGREEUNIT, G.MARKETID, G.GOODSID, 
				GX.HOTINDEX, GX.VIDEOURLS, GX.PICURLS, GX.CATEGORYID, GX.GOODSDESC, GX.GOODSPRICE, 
				E.ENUMDICNAME CURRENCY, E.PARAM2 CURRENCYSIGN, 
				M.TRADEMODE, 
				H.VENDORNAME, H.VENDORATTR, H.VENDORPHONE`).
		Join("LEFT", "HSBY_GOODSEX GX", "GX.GOODSID = G.GOODSID").
		Join("LEFT", "ENUMDICITEM E", "E.ENUMITEMNAME = G.CURRENCYID and E.ENUMDICCODE = 'currency'").
		Join("LEFT", "MARKET M", "M.MARKETID = G.MARKETID").
		Join("LEFT", "HSBY_SUPPLIERINFO H", "H.VENDORID = GX.VENDORID").
		Where("G.GOODSID = ?", goodsID)
	if err := session.Find(&orders); err != nil {
		return nil, err
	}
	// 无目标商品
	if len(orders) == 0 {
		return nil, nil
	}
	hsbyMarketGoodsDetail := orders[0]
	// 最小交易手数在上层进行设置，这里暂设置为1
	hsbyMarketGoodsDetail.LotSize = 1

	return &hsbyMarketGoodsDetail, nil
}

// GetHsbyMarketGoodsDetail 获取商城商品详情（三级商城）
func GetHsbyMarketGoodsDetail(orderID, accountID int) (*HsbyMarketGoodsDetail, error) {
	engine := db.GetEngine()

	orders := make([]HsbyMarketGoodsDetail, 0)
	// 与挂牌点选不一样的是商城是以委托单为主表
	session := engine.Table("TRADE_ORDERDETAIL T").
		Select(`to_char(T.ORDERID) ORDERIDSTR, T.*, 
				G.GOODSCODE, G.GOODSNAME, G.DECIMALPLACE, G.QUOTEMINUNIT, G.AGREEUNIT, 
				GX.HOTINDEX, GX.VIDEOURLS, GX.PICURLS, GX.CATEGORYID, GX.GOODSDESC, GX.GOODSPRICE, 
				E.ENUMDICNAME CURRENCY, E.PARAM2 CURRENCYSIGN, 
				M.TRADEMODE, 
				H.VENDORNAME, H.VENDORATTR, H.VENDORPHONE, 
				U.USERID SELLUSERID, U.CUSTOMERNAME`).
		Join("LEFT", "GOODS G", "G.GOODSID = T.GOODSID").
		Join("LEFT", "HSBY_GOODSEX GX", "GX.GOODSID = T.GOODSID").
		Join("LEFT", "ENUMDICITEM E", "E.ENUMITEMNAME = G.CURRENCYID and E.ENUMDICCODE = 'currency'").
		Join("LEFT", "MARKET M", "M.MARKETID = T.MARKETID").
		Join("LEFT", "HSBY_SUPPLIERINFO H", "H.VENDORID = GX.VENDORID").
		Join("LEFT", "TAACCOUNT TA", "TA.ACCOUNTID = T.ACCOUNTID").
		Join("LEFT", "USERINFO U", "U.USERID = TA.RELATEDUSERID").
		Where("T.ORDERID = ?", orderID)
	if err := session.Find(&orders); err != nil {
		return nil, err
	}
	// 无目标商品
	if len(orders) == 0 {
		return nil, nil
	}
	hsbyMarketGoodsDetail := orders[0]
	// 最小交易手数在上层进行设置，这里暂设置为1
	hsbyMarketGoodsDetail.LotSize = 1

	return &hsbyMarketGoodsDetail, nil
}

// MyCoupon 我的优惠卷
type MyCoupon struct {
	Accountid     int64  `json:"accountid"  xorm:"'ACCOUNTID'" binding:"required"`          // 资金账户ID
	Coupontypeid  string `json:"coupontypeid"  xorm:"'COUPONTYPEIDSTR'" binding:"required"` // 优惠券类型ID
	Userid        int64  `json:"userid"  xorm:"'USERID'"`                                   // 用户ID
	Oriqty        int64  `json:"oriqty"  xorm:"'ORIQTY'"`                                   // 期初数量
	Orifreezeqty  int64  `json:"orifreezeqty"  xorm:"'ORIFREEZEQTY'"`                       // 期初冻结数量
	Curqty        int64  `json:"curqty"  xorm:"'CURQTY'"`                                   // 期末数量
	Curfreezeqty  int64  `json:"curfreezeqty"  xorm:"'CURFREEZEQTY'"`                       // 期末冻结数量
	Todayincrease int64  `json:"todayincrease"  xorm:"'TODAYINCREASE'"`                     // 今日增加
	Todaydecrease int64  `json:"todaydecrease"  xorm:"'TODAYDECREASE'"`                     // 今日减少

	Areauserid      int64   `json:"areauserid"  xorm:"'AREAUSERID'"`           // 所属机构
	Couponname      string  `json:"couponname"  xorm:"'COUPONNAME'"`           // 优惠券名称
	Couponcategroy  int32   `json:"couponcategroy"  xorm:"'COUPONCATEGROY'"`   // 种类 - 1:现金券 2:折扣券 3:折扣券(单张)
	Conditionvalue  float64 `json:"conditionvalue"  xorm:"'CONDITIONVALUE'"`   // 条件阈值(可为0)
	Couponvalue     float64 `json:"couponvalue"  xorm:"'COUPONVALUE'"`         // 面值[1:现金券 - 抵扣值 2:折扣券-折扣值]
	Limitedflag     int32   `json:"limitedflag"  xorm:"'LIMITEDFLAG'"`         // 是否指定商品 - 0:不限 1:限制
	Limitedgoodsids string  `json:"limitedgoodsids"  xorm:"'LIMITEDGOODSIDS'"` // 指定商品IDs[逗号分隔,前后加逗号]
	Isgeneral       int32   `json:"isgeneral"  xorm:"'ISGENERAL'"`             // 是否通用券 - 0:否 1:是
	Userscope       string  `json:"userscope"  xorm:"'USERSCOPE'"`             // 卖家范围(用户ID，逗号分隔,前后加逗号) [IsGeneral =0时使用]

	IsUnusable bool `json:"isunusable" xorm:"-"` // 是否不可用
	ReasonType int  `json:"reasontype"`          // 不可用原因 - 0:未确认 1:不可用于此商品 2:不可用于此卖家
}

// GetMyCoupons 获取我的优惠卷信息
func GetMyCoupons(accountIDs string, goodsID, sellUserID int) ([]MyCoupon, error) {
	engine := db.GetEngine()

	myCoupons := make([]MyCoupon, 0)
	session := engine.Table("COUPONPOSITION CP").
		Select("to_char(CP.COUPONTYPEID) COUPONTYPEIDSTR, CP.*").
		Join("INNER", "COUPONTYPE CT", "CT.COUPONTYPEID = CP.COUPONTYPEID").
		Where(fmt.Sprintf("CP.ACCOUNTID in (%s)", accountIDs))
	if err := session.Find(&myCoupons); err != nil {
		return nil, err
	}

	// 如果传入了商品ID和卖方UserID，则判断优惠卷是否可用
	if goodsID != 0 && sellUserID != 0 && len(myCoupons) > 0 {
		for i := range myCoupons {
			myCoupon := &myCoupons[i]

			// 优惠卷是否可用于商品
			isRightGoods := false
			if myCoupon.Limitedflag == 0 {
				isRightGoods = true
			} else {
				if strings.Contains(myCoupon.Limitedgoodsids, fmt.Sprintf(",%d,", goodsID)) {
					isRightGoods = true
				}
			}
			// 优惠卷是否可用于卖家
			isRightAccount := false
			if myCoupon.Isgeneral == 1 {
				isRightAccount = true
			} else {
				if strings.Contains(myCoupon.Userscope, fmt.Sprintf(",%d,", sellUserID)) {
					isRightAccount = true
				}
			}

			if !isRightGoods {
				myCoupon.IsUnusable = true
				myCoupon.ReasonType = 1
			}
			if !isRightAccount {
				myCoupon.IsUnusable = true
				myCoupon.ReasonType = 2
			}
		}
	}

	return myCoupons, nil
}

// MyCouponHold 我的优惠卷持仓
type MyCouponHold struct {
	Couponholdid    string    `json:"couponholdid"  xorm:"'COUPONHOLDIDSTR'" binding:"required"` // 优惠券持仓ID(229+Unix秒时间戳(10位)+xxxxxx)
	Giveapplyid     int64     `json:"giveapplyid"  xorm:"'GIVEAPPLYID'"`                         // 发放申请ID(SEQ_COUPONGIVEAPPLY)
	Accountid       int64     `json:"accountid"  xorm:"'ACCOUNTID'"`                             // 资金账户ID
	Coupontypeid    string    `json:"coupontypeid"  xorm:"'COUPONTYPEIDSTR'"`                    // 优惠券类型ID - SEQ_COUPONTYPE
	Couponcategroy  int32     `json:"couponcategroy"  xorm:"'COUPONCATEGROY'"`                   // 种类 - 1:现金券 2:折扣券 3:折扣券(单个商品)
	Conditionvalue  float64   `json:"conditionvalue"  xorm:"'CONDITIONVALUE'"`                   // 条件阈值(可为0)
	Couponvalue     float64   `json:"couponvalue"  xorm:"'COUPONVALUE'"`                         // 面值[1:现金券 - 抵扣值 2:折扣券-折扣值]
	Limitedflag     int32     `json:"limitedflag"  xorm:"'LIMITEDFLAG'"`                         // 是否指定商品 - 0:不限 1:限制
	Limitedgoodsids string    `json:"limitedgoodsids"  xorm:"'LIMITEDGOODSIDS'"`                 // 指定商品IDs[逗号分隔]
	Isgeneral       int32     `json:"isgeneral"  xorm:"'ISGENERAL'"`                             // 是否通用券 - 0:否 1:是
	Userscope       string    `json:"userscope"  xorm:"'USERSCOPE'"`                             // 卖家范围(用户ID，逗号分隔) [IsGeneral =0时使用]
	Userid          int64     `json:"userid"  xorm:"'USERID'"`                                   // 用户ID
	Qty             int64     `json:"qty"  xorm:"'QTY'"`                                         // 数量(按1平铺)
	Startdate       time.Time `json:"startdate"  xorm:"'STARTDATE'"`                             // 开始日期
	Holdstatus      int32     `json:"holdstatus"  xorm:"'HOLDSTATUS'"`                           // 持仓状态 - 1:未生效 2:已生效 3:已使用 4:已过期
	Enddate         time.Time `json:"enddate"  xorm:"'ENDDATE'"`                                 // 结束日期
	Createtime      time.Time `json:"createtime"  xorm:"'CREATETIME'"`                           // 创建时间

	Couponname string `json:"couponname"  xorm:"'COUPONNAME'"` // 优惠券名称
}

// GetMyCouponHolds 获取优惠卷明细
func GetMyCouponHolds(accountIDs string, holdStatus string) ([]MyCouponHold, error) {
	engine := db.GetEngine()

	myCouponHolds := make([]MyCouponHold, 0)
	session := engine.Table("COUPONHOLD CH").
		Select(`to_char(CH.COUPONHOLDID) COUPONHOLDIDSTR, to_char(CH.COUPONTYPEID) COUPONTYPEIDSTR, CH.*, CT.COUPONNAME`).
		Join("INNER", "COUPONTYPE CT", "CT.COUPONTYPEID = CH.COUPONTYPEID").
		Where(fmt.Sprintf("CH.ACCOUNTID in (%s)", accountIDs))
	if len(holdStatus) > 0 {
		session = session.And(fmt.Sprintf("CH.HOLDSTATUS in (%s)", holdStatus))
	}
	if err := session.Find(&myCouponHolds); err != nil {
		return nil, err
	}

	// 如果指定查询已过期的优惠卷，则还需要查询历史表
	if holdStatus == "4" {
		myHisCouponHolds := make([]MyCouponHold, 0)
		if err := engine.Table("HIS_COUPONHOLD CH").
			Select(`to_char(CH.COUPONHOLDID) COUPONHOLDIDSTR, to_char(CH.COUPONTYPEID) COUPONTYPEIDSTR, CH.*, CT.COUPONNAME`).
			Join("INNER", "COUPONTYPE CT", "CT.COUPONTYPEID = CH.COUPONTYPEID").
			Where(fmt.Sprintf("CH.ISVALIDDATA = 1 and CH.HOLDSTATUS = 4 and CH.ACCOUNTID in (%s)", accountIDs)).
			Find(&myHisCouponHolds); err != nil {
			return nil, err
		}
		myCouponHolds = append(myCouponHolds, myHisCouponHolds...)
	}

	return myCouponHolds, nil
}

// MyUsedCoupon 已使用优惠卷
type MyUsedCoupon struct {
	Orderid        string    `json:"orderid"  xorm:"'ORDERIDSTR'" binding:"required"`           // 委托单号(100+Unix秒时间戳(10位)+2位(MarketServiceID)+xxxx)
	Coupontypeid   string    `json:"coupontypeid"  xorm:"'COUPONTYPEIDSTR'" binding:"required"` // 优惠券类型ID(买方)
	Accountid      int64     `json:"accountid"  xorm:"'ACCOUNTID'"`                             // 资金账户ID(买方)
	Usedqty        int64     `json:"usedqty"  xorm:"'USEDQTY'"`                                 // 使用数量
	Couponcategroy int32     `json:"couponcategroy"  xorm:"'COUPONCATEGROY'"`                   // 种类 - 1:现金券 2:折扣券
	Conditionvalue float64   `json:"conditionvalue"  xorm:"'CONDITIONVALUE_TC'"`                // 条件阈值(可为0)
	Couponvalue    float64   `json:"couponvalue"  xorm:"'COUPONVALUE'"`                         // 面值[1:现金券 - 抵扣值 2:折扣券-折扣值(0-100)]
	Sellaccountid  int64     `json:"sellaccountid"  xorm:"'SELLACCOUNTID'"`                     // 资金账户ID(卖方)
	Marketid       int32     `json:"marketid"  xorm:"'MARKETID'"`                               // 市场ID
	Goodsid        int32     `json:"goodsid"  xorm:"'GOODSID'"`                                 // 商品ID
	Tradeid        string    `json:"tradeid"  xorm:"'TRADEIDSTR'"`                              // 成交单号(101+Unix秒时间戳(10位)+2位(MarketServiceID)+xxxx)
	Tradeamount    float64   `json:"tradeamount"  xorm:"'TRADEAMOUNT'"`                         // 成交金额
	Offamount      float64   `json:"offamount"  xorm:"'OFFAMOUNT'"`                             // 优惠金额
	Handlestatus   int32     `json:"handlestatus"  xorm:"'HANDLESTATUS'"`                       // 处理状态
	Createtime     time.Time `json:"createtime"  xorm:"'CREATETIME'"`                           // 创建时间

	Couponname string `json:"couponname"  xorm:"'COUPONNAME'"` // 优惠券名称
}

// GetMyUsedCoupon 获取已使用优惠卷
func GetMyUsedCoupon(accountIDs string) ([]MyUsedCoupon, error) {
	engine := db.GetEngine()

	myUsedCoupons := make([]MyUsedCoupon, 0)
	if err := engine.Table("TRADE_ORDERCOUPON T").
		Select(`to_char(T.ORDERID) ORDERIDSTR, to_char(T.COUPONTYPEID) COUPONTYPEIDSTR, to_char(T.TRADEID) TRADEIDSTR, T.*, 
				C.COUPONNAME, C.CONDITIONVALUE CONDITIONVALUE_TC`).
		Join("INNER", "COUPONTYPE C", "C.COUPONTYPEID = T.COUPONTYPEID").
		Where(fmt.Sprintf("T.ACCOUNTID in (%s)", accountIDs)).
		Desc("T.CREATETIME").
		Find(&myUsedCoupons); err != nil {
		return nil, err
	}

	return myUsedCoupons, nil
}

// GetClientFixedADConfigs 获取终端固定广告配置
func GetClientFixedADConfigs() ([]Clientfixedadconfig, error) {
	engine := db.GetEngine()

	clientFixedADConfigs := make([]Clientfixedadconfig, 0)
	if err := engine.Where("ISSHOW = 1").Find(&clientFixedADConfigs); err != nil {
		return nil, err
	}

	return clientFixedADConfigs, nil
}
