package pendant import ( "bytes" "context" "database/sql" "fmt" "time" "go-common/app/service/main/usersuit/model" xsql "go-common/library/database/sql" "go-common/library/log" "go-common/library/xstr" "github.com/pkg/errors" ) const ( _getGroupOnlineSQL = "SELECT id,name,rank,status,image,image_model,frequency_limit,time_limit FROM pendant_group WHERE status = 1 or id in (30,31) ORDER BY rank" _getGroupByIDSQL = "SELECT id,name,rank,status,image,image_model,frequency_limit,time_limit FROM pendant_group where id = ?" _selGIDRefPIDSQL = "SELECT gid,pid FROM pendant_group_ref" _getPendantInfoSQL = "SELECT id,name,image,image_model,status FROM pendant_info" _getPendantInfoByIDSQL = "SELECT id,name,image,image_model,status FROM pendant_info where id = ? limit 1" _getPendantInfosSQL = "SELECT id,name,image,image_model,status,rank FROM pendant_info ORDER BY rank" _getPendantPriceSQL = "SELECT pid,type,price FROM pendant_price where pid = ? " _getOrderHistorySQL = "SELECT mid,order_id,pay_id,appid,status,pid,time_length,cost,buy_time,is_callback,callback_time,pay_type FROM user_pendant_order WHERE %s" _getUserPackageSQL = "SELECT mid,pid,expires,type,status,is_vip FROM user_pendant_pkg WHERE mid = ? AND pid = ? " _getUserPackageByMidSQL = "SELECT mid,pid,expires,type,status,is_vip FROM user_pendant_pkg WHERE mid = ? AND expires >= ? AND status > 0 ORDER BY mtime DESC" _countOrderHistorySQL = "SELECT count(1) FROM user_pendant_order WHERE %s" _getPendantEquipByMidSQL = "SELECT mid,pid,expires FROM user_pendant_equip WHERE mid = ? and expires >= ?" _getPendantEquipByMidsSQL = "SELECT mid,pid,expires FROM user_pendant_equip WHERE mid IN (%s) and expires >= ?" _insertPendantPackageSQL = "INSERT INTO user_pendant_pkg(mid,pid,expires,type,status,is_vip) VALUES (?,?,?,?,?,?)" _insertOrderHistory = "INSERT INTO user_pendant_order(mid,order_id,pay_id,appid,status,pid,time_length,cost,buy_time,is_callback,callback_time,pay_type) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)" _insertOperationSQL = "INSERT INTO pendant_grant_history(mid,pid,source_type,operator_name,operator_action) VALUES (?,?,?,?,?)" _insertEquipSQL = "INSERT INTO user_pendant_equip(mid,pid,expires) VALUES (?,?,?) ON DUPLICATE KEY UPDATE pid=VALUES(pid),expires=VALUES(expires)" _updatePackageSQL = "UPDATE user_pendant_pkg %s WHERE mid=? AND pid=?" _updatePackageExpireSQL = "UPDATE user_pendant_pkg SET status=0 WHERE mid=? AND expires= ?") values = append(values, arg.StartTime) } if arg.EndTime != 0 { cond.WriteString(" AND buy_time <= ?") values = append(values, arg.EndTime) } if tp == "info" { cond.WriteString(" order by buy_time DESC LIMIT ?,20") values = append(values, (arg.Page-1)*20) sql = fmt.Sprintf(_getOrderHistorySQL, cond.String()) } else if tp == "count" { sql = fmt.Sprintf(_countOrderHistorySQL, cond.String()) } return } // OrderInfo return order info func (d *Dao) OrderInfo(c context.Context, arg *model.ArgOrderHistory) (res []*model.PendantOrderInfo, count int64, err error) { sqlstr, values := d.getOrderInfoSQL(c, arg, "info") var ( row *xsql.Rows r *xsql.Row ) res = make([]*model.PendantOrderInfo, 0) if row, err = d.db.Query(c, sqlstr, values...); err != nil { log.Error("PendantOrderInfo query error %v", err) return } defer row.Close() cstr, values2 := d.getOrderInfoSQL(c, arg, "count") r = d.db.QueryRow(c, cstr, values2...) for row.Next() { info := new(model.PendantOrderInfo) if err = row.Scan(&info.Mid, &info.OrderID, &info.PayID, &info.AppID, &info.Stauts, &info.Pid, &info.TimeLength, &info.Cost, &info.BuyTime, &info.IsCallback, &info.CallbackTime, &info.PayType); err != nil { log.Error("PendantOrderInfo scan error %v", err) return } if info.PayType == 3 { info.PayPrice = info.PayPrice / 100 } res = append(res, info) } err = r.Scan(&count) if err == xsql.ErrNoRows { res = nil err = nil return } return } // OrderInfoByID return order info by order id func (d *Dao) OrderInfoByID(c context.Context, orderID string) (res *model.PendantOrderInfo, err error) { row := d.db.QueryRow(c, fmt.Sprintf(_getOrderHistorySQL, "order_id=?"), orderID) res = new(model.PendantOrderInfo) if err = row.Scan(&res.Mid, &res.OrderID, &res.PayID, &res.AppID, &res.Stauts, &res.Pid, &res.TimeLength, &res.Cost, &res.BuyTime, &res.IsCallback, &res.CallbackTime, &res.PayType); err != nil { if err == xsql.ErrNoRows { res = nil err = nil return } log.Error("OrderInfoByID scan error %v", err) return } return } // AddOrderInfo add order log func (d *Dao) AddOrderInfo(c context.Context, arg *model.PendantOrderInfo) (id int64, err error) { var res sql.Result if res, err = d.db.Exec(c, _insertOrderHistory, arg.Mid, arg.OrderID, arg.PayID, arg.AppID, arg.Stauts, arg.Pid, arg.TimeLength, arg.Cost, arg.BuyTime, arg.IsCallback, arg.CallbackTime, arg.PayType); err != nil { log.Error("AddOrderInfo insert error %v", err) return } return res.LastInsertId() } // TxAddOrderInfo add order log func (d *Dao) TxAddOrderInfo(c context.Context, arg *model.PendantOrderInfo, tx *xsql.Tx) (id int64, err error) { var res sql.Result if res, err = tx.Exec(_insertOrderHistory, arg.Mid, arg.OrderID, arg.PayID, arg.AppID, arg.Stauts, arg.Pid, arg.TimeLength, arg.Cost, arg.BuyTime, arg.IsCallback, arg.CallbackTime, arg.PayType); err != nil { log.Error("TxAddOrderInfo insert error %v", err) return } return res.LastInsertId() } // UpdateOrderInfo update order info func (d *Dao) UpdateOrderInfo(c context.Context, arg *model.PendantOrderInfo) (id int64, err error) { var res sql.Result if res, err = d.db.Exec(c, _updateOrderInfoSQL, arg.Stauts, arg.PayID, arg.IsCallback, arg.CallbackTime, arg.OrderID); err != nil { log.Error("UpdateOrderInfo update error %v", err) return } return res.LastInsertId() } // TxUpdateOrderInfo update order info func (d *Dao) TxUpdateOrderInfo(c context.Context, arg *model.PendantOrderInfo, tx *xsql.Tx) (id int64, err error) { var res sql.Result if res, err = tx.Exec(_updateOrderInfoSQL, arg.Stauts, arg.PayID, arg.IsCallback, arg.CallbackTime, arg.OrderID); err != nil { log.Error("UpdateOrderInfo update error %v", err) return } return res.LastInsertId() } // PackageByMid get pendant in user's package func (d *Dao) PackageByMid(c context.Context, mid int64) (res []*model.PendantPackage, err error) { var ( row *xsql.Rows t = time.Now().Unix() ) res = make([]*model.PendantPackage, 0) if row, err = d.db.Query(c, _getUserPackageByMidSQL, mid, t); err != nil { log.Error("Package query error %v", err) return } defer row.Close() for row.Next() { info := new(model.PendantPackage) if err = row.Scan(&info.Mid, &info.Pid, &info.Expires, &info.Type, &info.Status, &info.IsVIP); err != nil { log.Error("Package scan error %v", err) return } res = append(res, info) } return } // PackageByID get pendant in user's package func (d *Dao) PackageByID(c context.Context, mid, pid int64) (res *model.PendantPackage, err error) { var row *xsql.Row res = new(model.PendantPackage) row = d.db.QueryRow(c, _getUserPackageSQL, mid, pid) if err = row.Scan(&res.Mid, &res.Pid, &res.Expires, &res.Type, &res.Status, &res.IsVIP); err != nil { if err == xsql.ErrNoRows { res = nil err = nil return } log.Error("Package scan error %v", err) return } return } // EquipByMid obtain pendant equiped func (d *Dao) EquipByMid(c context.Context, mid, t int64) (res *model.PendantEquip, noRow bool, err error) { var row *xsql.Row res = new(model.PendantEquip) row = d.db.QueryRow(c, _getPendantEquipByMidSQL, mid, t) if err = row.Scan(&res.Mid, &res.Pid, &res.Expires); err != nil { if err == xsql.ErrNoRows { noRow = true res = nil err = nil return } err = errors.WithStack(err) } return } // EquipByMids obtain equipss by mids . func (d *Dao) EquipByMids(c context.Context, mids []int64, t int64) (res map[int64]*model.PendantEquip, err error) { res = make(map[int64]*model.PendantEquip) rows, err := d.db.Query(c, fmt.Sprintf(_getPendantEquipByMidsSQL, xstr.JoinInts(mids)), t) if err != nil { err = errors.WithStack(err) return } defer rows.Close() for rows.Next() { pe := &model.PendantEquip{} if err = rows.Scan(&pe.Mid, &pe.Pid, &pe.Expires); err != nil { if err == xsql.ErrNoRows { err = nil return } err = errors.WithStack(err) } if _, ok := res[pe.Mid]; !ok { res[pe.Mid] = pe } } err = rows.Err() return } // AddEquip add equip func (d *Dao) AddEquip(c context.Context, arg *model.PendantEquip) (n int64, err error) { var res sql.Result if res, err = d.db.Exec(c, _insertEquipSQL, arg.Mid, arg.Pid, arg.Expires); err != nil { return 0, err } return res.RowsAffected() } // UpEquipMID uninstall user pid by mid. func (d *Dao) UpEquipMID(c context.Context, mid int64) (n int64, err error) { var res sql.Result if res, err = d.db.Exec(c, _updateEquipMIDSQL, mid); err != nil { return 0, err } return res.RowsAffected() } // TxUpdatePackageInfo update package info func (d *Dao) TxUpdatePackageInfo(c context.Context, arg *model.PendantPackage, tx *xsql.Tx) (n int64, err error) { var ( bf bytes.Buffer values = make([]interface{}, 0, 4) res sql.Result ) if arg.Status != 0 && arg.Expires != 0 { bf.WriteString("SET status=?,expires=?,type=?") values = append(values, arg.Status) values = append(values, arg.Expires) values = append(values, arg.Type) } else if arg.Status != 0 { bf.WriteString("SET status=?,type=?") values = append(values, arg.Status) values = append(values, arg.Type) } else if arg.Expires != 0 { bf.WriteString("SET expires=?,type=?") values = append(values, arg.Expires) values = append(values, arg.Type) } values = append(values, arg.Mid) values = append(values, arg.Pid) if res, err = tx.Exec(fmt.Sprintf(_updatePackageSQL, bf.String()), values...); err != nil { log.Error("TxUpdatePackageInfo update error %v", err) return } return res.RowsAffected() } // CheckPackageExpire check expire items and update func (d *Dao) CheckPackageExpire(c context.Context, mid, expires int64) (rows int64, err error) { var res sql.Result if res, err = d.db.Exec(c, _updatePackageExpireSQL, mid, expires); err != nil { log.Error("CheckPackageExpire error %v", err) return } return res.RowsAffected() } // BeginTran begin a tx. func (d *Dao) BeginTran(c context.Context) (res *xsql.Tx, err error) { if res, err = d.db.Begin(c); err != nil || res == nil { log.Error("BeginTran error %v", err) return } return } // TxAddPackage add a pendant in package func (d *Dao) TxAddPackage(c context.Context, arg *model.PendantPackage, tx *xsql.Tx) (id int64, err error) { var res sql.Result if res, err = tx.Exec(_insertPendantPackageSQL, arg.Mid, arg.Pid, arg.Expires, arg.Type, arg.Status, arg.IsVIP); err != nil { log.Error("TxAddPackage insert error %v", err) return } return res.LastInsertId() } // TxAddHistory add a history of operation func (d *Dao) TxAddHistory(c context.Context, arg *model.PendantHistory, tx *xsql.Tx) (id int64, err error) { var res sql.Result if res, err = tx.Exec(_insertOperationSQL, arg.Mid, arg.Pid, arg.SourceType, arg.OperatorName, arg.OperatorAction); err != nil { log.Error("TxAddHistory insert error %v", err) return } return res.LastInsertId() }