123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- package dao
- import (
- "context"
- "encoding/json"
- "go-common/app/service/openplatform/ticket-item/model"
- "go-common/library/cache/redis"
- "go-common/library/ecode"
- "go-common/library/log"
- "time"
- "github.com/jinzhu/gorm"
- )
- const (
- // TypeWithoutSeat 场次类型 站票
- TypeWithoutSeat = 2
- // TicketTypeElec 场次票类型 电子票
- TicketTypeElec = 2
- // scTypeNormal 普通场次
- scTypeNormal = 1
- // scTypePass 通票场次
- scTypePass = 2
- // scTypeAllPass 联票场次
- scTypeAllPass = 3
- )
- var scTypeName = map[int32]string{
- scTypeNormal: "普通场次",
- scTypePass: "通票",
- scTypeAllPass: "联票",
- }
- // RawScListByItem 批量取项目场次
- func (d *Dao) RawScListByItem(c context.Context, ids []int64) (info map[int64][]*model.Screen, err error) {
- info = make(map[int64][]*model.Screen)
- rows, err := d.db.Model(&model.Screen{}).Where("project_id in (?)", ids).Rows()
- if err != nil {
- log.Error("RawScListByItem(%v) error(%v)", ids, err)
- return
- }
- defer rows.Close()
- for rows.Next() {
- var sc model.Screen
- err = d.db.ScanRows(rows, &sc)
- if err != nil {
- log.Error("RawScListByItem(%v) scan error(%v)", ids, err)
- return
- }
- info[sc.ProjectID] = append(info[sc.ProjectID], &sc)
- }
- return
- }
- // CacheScListByItem 缓存取项目票价
- func (d *Dao) CacheScListByItem(c context.Context, ids []int64) (info map[int64][]*model.Screen, err error) {
- var keys []interface{}
- keyPidMap := make(map[string]int64, len(ids))
- for _, id := range ids {
- key := keyItemScreen(id)
- if _, ok := keyPidMap[key]; !ok {
- // duplicate mid
- keyPidMap[key] = id
- keys = append(keys, key)
- }
- }
- conn := d.redis.Get(c)
- defer conn.Close()
- var data [][]byte
- log.Info("MGET %v", model.JSONEncode(keys))
- if data, err = redis.ByteSlices(conn.Do("mget", keys...)); err != nil {
- log.Error("ItemScList MGET %v ERR: %v", model.JSONEncode(keys), err)
- return
- }
- info = make(map[int64][]*model.Screen)
- for _, d := range data {
- if d != nil {
- var scs []*model.Screen
- json.Unmarshal(d, &scs)
- info[scs[0].ProjectID] = scs
- }
- }
- return
- }
- // AddCacheScListByItem 为项目场次添加缓存
- func (d *Dao) AddCacheScListByItem(c context.Context, info map[int64][]*model.Screen) (err error) {
- conn := d.redis.Get(c)
- defer func() {
- conn.Flush()
- conn.Close()
- }()
- var data []interface{}
- var keys []string
- for k, v := range info {
- b, _ := json.Marshal(v)
- key := keyItemScreen(k)
- keys = append(keys, key)
- data = append(data, key, b)
- }
- log.Info("MSET %v", keys)
- if err = conn.Send("MSET", data...); err != nil {
- return
- }
- for i := 0; i < len(data); i += 2 {
- conn.Send("EXPIRE", data[i], CacheTimeout)
- }
- return
- }
- // RawScList 批量取场次
- func (d *Dao) RawScList(c context.Context, ids []int64) (info map[int64]*model.Screen, err error) {
- info = make(map[int64]*model.Screen)
- rows, err := d.db.Model(&model.Screen{}).Where("id in (?)", ids).Rows()
- if err != nil {
- log.Error("RawScList(%v) error(%v)", ids, err)
- return
- }
- defer rows.Close()
- for rows.Next() {
- var sc model.Screen
- err = d.db.ScanRows(rows, &sc)
- if err != nil {
- log.Error("RawScList(%v) scan error(%v)", ids, err)
- return
- }
- info[sc.ID] = &sc
- }
- return
- }
- // CacheScList 缓存批量取场次
- func (d *Dao) CacheScList(c context.Context, ids []int64) (info map[int64]*model.Screen, err error) {
- var keys []interface{}
- keyPidMap := make(map[string]int64, len(ids))
- for _, id := range ids {
- key := keyScreen(id)
- if _, ok := keyPidMap[key]; !ok {
- // duplicate id
- keyPidMap[key] = id
- keys = append(keys, key)
- }
- }
- conn := d.redis.Get(c)
- defer conn.Close()
- var data [][]byte
- log.Info("MGET %v", model.JSONEncode(keys))
- if data, err = redis.ByteSlices(conn.Do("mget", keys...)); err != nil {
- log.Error("ScList MGET %v ERR: %v", model.JSONEncode(keys), err)
- return
- }
- info = make(map[int64]*model.Screen)
- for _, d := range data {
- if d != nil {
- var sc model.Screen
- json.Unmarshal(d, &sc)
- info[sc.ID] = &sc
- }
- }
- return
- }
- // AddCacheScList 为场次添加缓存
- func (d *Dao) AddCacheScList(c context.Context, info map[int64]*model.Screen) (err error) {
- conn := d.redis.Get(c)
- defer func() {
- conn.Flush()
- conn.Close()
- }()
- var data []interface{}
- var keys []string
- for k, v := range info {
- b, _ := json.Marshal(v)
- key := keyScreen(k)
- keys = append(keys, key)
- data = append(data, key, b)
- }
- log.Info("MSET %v", keys)
- if err = conn.Send("MSET", data...); err != nil {
- return
- }
- for i := 0; i < len(data); i += 2 {
- conn.Send("EXPIRE", data[i], CacheTimeout)
- }
- return
- }
- // CreateOrUpdateScreen 创建或更新场次
- func (d *Dao) CreateOrUpdateScreen(c context.Context, tx *gorm.DB, screenInfo model.Screen) (model.Screen, error) {
- if screenInfo.ID == 0 {
- // create
- if err := tx.Create(&screenInfo).Error; err != nil {
- log.Error("创建场次失败:%s", err)
- tx.Rollback()
- return model.Screen{}, err
- }
- } else {
- // update
- if err := tx.Model(&model.Screen{}).Where("id = ?", screenInfo.ID).Updates(map[string]interface{}{
- "name": screenInfo.Name,
- "status": screenInfo.Status,
- "type": screenInfo.Type,
- "ticket_type": screenInfo.TicketType,
- "screen_type": screenInfo.ScreenType,
- "delivery_type": screenInfo.DeliveryType,
- "pick_seat": screenInfo.PickSeat,
- "start_time": screenInfo.StartTime,
- "end_time": screenInfo.EndTime,
- "project_id": screenInfo.ProjectID,
- }).Error; err != nil {
- log.Error("更新场次失败:%s", err)
- tx.Rollback()
- return model.Screen{}, err
- }
- }
- return screenInfo, nil
- }
- // GetOrUpdatePassSc 更新或新建通联票场次 返回id
- func (d *Dao) GetOrUpdatePassSc(c context.Context, tx *gorm.DB, pid int64, tksPass []TicketPass, scStartTimes map[int32]int32,
- scEndTimes map[int32]int32, scType int32, opType int32) (int64, error) {
- var passScID int64
- scTime, err := d.CalPassScTime(scStartTimes, scEndTimes, tksPass)
- if err != nil {
- tx.Rollback()
- return 0, err
- }
- var screen model.Screen
- if d.db.Where("project_id = ? and screen_type = ? and deleted_at = 0", pid, scType).First(&screen).RecordNotFound() {
- // 不存在场次并且有票种存在则新建一个
- if len(tksPass) > 0 {
- passScreen := model.Screen{
- ProjectID: pid,
- Name: scTypeName[scType],
- StartTime: scTime[0],
- EndTime: scTime[1],
- Type: TypeWithoutSeat, // 站票
- TicketType: TicketTypeElec, // 电子票
- DeliveryType: 1, // 默认不配送
- ScreenType: scType,
- Status: opType,
- }
- if err := tx.Create(&passScreen).Error; err != nil {
- log.Error("创建通票或联票场次失败:%s", err)
- tx.Rollback()
- return 0, err
- }
- passScID = passScreen.ID
- }
- } else {
- if len(tksPass) > 0 {
- // update
- if err := tx.Model(&model.Screen{}).Where("id = ?", screen.ID).Updates(map[string]interface{}{
- "status": opType,
- "start_time": scTime[0],
- "end_time": scTime[1],
- }).Error; err != nil {
- log.Error("更新通票联票场次失败:%s", err)
- tx.Rollback()
- return 0, err
- }
- passScID = screen.ID
- } else {
- // 如果没有通票/联票 删除通票/联票场次
- if err := d.DelScreen(c, tx, []int64{screen.ID}, nil, pid); err != nil {
- return 0, err
- }
- passScID = screen.ID
- }
- }
- return passScID, nil
- }
- // DelScreen 删除场次
- func (d *Dao) DelScreen(c context.Context, tx *gorm.DB, oldIDs []int64, newIDs []int64, pid int64) error {
- delIDs, _ := model.ClassifyIDs(oldIDs, newIDs)
- for _, delID := range delIDs {
- if !d.CanDelScreen(delID) {
- tx.Rollback()
- return ecode.TicketCannotDelSc
- }
- // 删除场次前把改场次下的票价一起删除
- priceIDs, err := d.GetPriceIDs(delID, 1)
- if err != nil {
- return err
- }
- if err := d.DelTicket(c, tx, priceIDs, nil, pid, true); err != nil {
- return err
- }
- // 删除场次
- if err := tx.Exec("UPDATE screen SET deleted_at=? WHERE id = ? AND project_id = ?", time.Now().Format("2006-01-02 15:04:05"), delID, pid).Error; err != nil {
- log.Error("删除场次失败:%s", err)
- tx.Rollback()
- return err
- }
- }
- return nil
- }
- // CalPassScTime 获取通联场次的开始结束时间, 取关联场次时间的极值。返回[0]=starttime [1]=endtime
- func (d *Dao) CalPassScTime(scStartTimes map[int32]int32, scEndTimes map[int32]int32, tksPass []TicketPass) ([]int32, error) {
- var startTimes, endTimes, currStartTimes, currEndTimes []int32
- for _, v := range tksPass {
- currStartTimes = []int32{}
- currEndTimes = []int32{}
- for _, v2 := range v.LinkScreens {
- if _, ok := scStartTimes[v2]; !ok {
- log.Error("关联的场次开始时间不存在")
- return []int32{}, ecode.TicketLkScTimeNotFound
- }
- if _, ok := scEndTimes[v2]; !ok {
- log.Error("关联的场次结束时间不存在")
- return []int32{}, ecode.TicketLkScTimeNotFound
- }
- currStartTimes = append(currStartTimes, scStartTimes[v2])
- currEndTimes = append(currEndTimes, scEndTimes[v2])
- }
- startTimes = append(startTimes, model.Min(currStartTimes))
- endTimes = append(endTimes, model.Max(currEndTimes))
- }
- return []int32{model.Min(startTimes), model.Max(endTimes)}, nil
- }
- // CanDelScreen 检查是否可以删除场次
- func (d *Dao) CanDelScreen(id int64) bool {
- var priceIDs []int64
- // 获取场次下 所有票价id
- var prices []model.TicketPrice
- if err := d.db.Select("id").Where("screen_id = ? and deleted_at = 0", id).Find(&prices).Error; err != nil {
- log.Error("获取场次下所有票价id失败:%s", err)
- return false
- }
- for _, v := range prices {
- priceIDs = append(priceIDs, v.ID)
- }
- if d.HasPromotion(priceIDs, 2) || d.StockChanged(priceIDs) {
- log.Error("场次的票价下存在拼团或者库存有变动")
- return false
- }
- return true
- }
|