package dadi import ( "encoding/json" "errors" "film/base/httputil" "film/model" "film/worker/common" "fmt" log "github.com/sirupsen/logrus" "github.com/smbrave/goutil" "github.com/spf13/cast" "strings" ) type ProcessorConfig struct { Token string } type Processor struct { token string citys map[string]*City } func NewProcessor(cfg *ProcessorConfig) (common.Processor, error) { processor := &Processor{ token: cfg.Token, } if err := processor.init(); err != nil { return nil, err } return processor, nil } func (d *Processor) init() error { cityUrl := "https://appapi.dadicinema.com/app-web/v1/web/cinema/cbticket/cbase/cityAndCinemaList" params := d.getBaseParam(&Cinema{ Name: "大地影院(北京十里河铭泽店)", Id: 118, UnifiedCode: 11050621, }) body, err := httputil.HttpGet(cityUrl, params, d.getBaseHeader()) if err != nil { log.Errorf(" httputil.HttpGet url : %s error: %s", cityUrl, err.Error()) return err } result, err := d.checkError(body) if err != nil { return err } citys := make(map[string]*City) datas := cast.ToSlice(result) for _, d := range datas { data := cast.ToStringMap(d) cinemas := make([]*Cinema, 0) for _, c := range cast.ToSlice(data["cinemas"]) { cin := cast.ToStringMap(c) cinema := new(Cinema) cinema.Name = cast.ToString(cin["name"]) cinema.Address = cast.ToString(cin["address"]) cinema.Latitude = cast.ToString(cin["latitude"]) cinema.Longitude = cast.ToString(cin["longitude"]) cinema.CityId = cast.ToInt64(cin["cityId"]) cinema.UnifiedCode = cast.ToInt64(cin["unifiedCode"]) cinemas = append(cinemas, cinema) } cityInfo := cast.ToStringMap(data["cityInfo"]) city := new(City) city.Name = cast.ToString(cityInfo["chName"]) city.ShortName = cast.ToString(cityInfo["shortName"]) city.CityId = cast.ToInt64(data["cityId"]) city.CityCode = cast.ToInt64(data["cityCode"]) city.Cinemas = cinemas citys[city.ShortName] = city } d.citys = citys log.Infof("load dadi procoessor citys : %d", len(d.citys)) return nil } func (d *Processor) checkError(body []byte) (interface{}, error) { result := make(map[string]interface{}) if err := json.Unmarshal(body, &result); err != nil { log.Errorf("json.unmarshal [%s] error : %s", string(body), err.Error()) return nil, err } if cast.ToInt(result["code"]) != 200 { log.Errorf("code[%d] message[%s]", cast.ToInt(result["code"]), cast.ToString(result["msg"])) return nil, fmt.Errorf("code[%d] message[%s]", cast.ToInt(result["code"]), cast.ToString(result["msg"])) } return result["data"], nil } func (p *Processor) getBaseHeader() map[string]interface{} { return map[string]interface{}{ "User-Agent": "DaDiCinemaApp/8.7.3 (iPhone; iOS 15.2.1; Scale/3.00)", "c-User-Token": p.token, "c-tenantId": strings.Split(p.token, ":")[0], } } func (p *Processor) getBaseParam(cinema *Cinema) map[string]interface{} { tenantId := strings.Split(p.token, ":")[0] params := map[string]interface{}{ "channelCode": "SYH-DDZY-DD", "channelName": "大地自营-大地", "channelNo": "SYH-DDZY-DD", "channelUid": "SYH-DDZY-DD", "cinema": cast.ToString(cinema.UnifiedCode), "cinemaCode": cast.ToString(cinema.UnifiedCode), "cinemaUid": cast.ToString(cinema.Id), "d": "iPhone14,3", "i": "00000000-0000-0000-0000-000000000000", "k": p.token, "r": "1", "s": "iOS15.2.1", "t": "1", "tenantId": tenantId, "unifiedCinemaId": cast.ToString(cinema.Id), "unifiedCinemaName": cinema.Name, "unifiedCode": cast.ToString(cinema.UnifiedCode), "v": "8.7.3", } return params } func (p *Processor) getCinema(cityName, cinemaName string) (*Cinema, error) { if _, ok := p.citys[cityName]; !ok { log.Errorf("city[%s] not exist dadi cinema", cityName) return nil, fmt.Errorf("city[%s] not exist dadi cinema", cityName) } city := p.citys[cityName] for _, cinema := range city.Cinemas { if cinema.Name != cinemaName { continue } return cinema, nil } return nil, fmt.Errorf("city[%s] not[%s]", cityName, cinemaName) } func (d *Processor) getCinemaFilmShowHall(cinema *Cinema, filmName, startTime string) (*FilmShowHall, error) { baseReq := d.getBaseParam(cinema) reqUrl := "https://appapi.dadicinema.com/app-web/v1/web/film/getHitFilmAndFilmSession" body, err := httputil.HttpGet(reqUrl, baseReq, d.getBaseHeader()) if err != nil { log.Errorf("httpGet[%s] error : %s", reqUrl, err.Error()) return nil, err } result, err := d.checkError(body) if err != nil { return nil, err } var hall *FilmShowHall = nil for _, f := range cast.ToSlice(cast.ToStringMap(result)["filmList"]) { ff := cast.ToStringMap(f) moveName := cast.ToString(ff["name"]) if moveName != filmName { continue } for _, s := range cast.ToSlice(ff["showList"]) { ss := cast.ToStringMap(s) day := cast.ToString(ss["dayStr"]) for _, p := range cast.ToSlice(ss["plist"]) { pp := cast.ToStringMap(p) sTime := cast.ToString(pp["startTime"]) if startTime != sTime { continue } hall = new(FilmShowHall) hall.FilmName = filmName hall.ShowDay = day hall.HallName = cast.ToString(pp["hallName"]) hall.SessionId = cast.ToString(pp["sessionId"]) hall.StartTime = cast.ToString(pp["startTime"]) hall.EndTime = cast.ToString(pp["endTime"]) return hall, nil } } } log.Errorf("film[%s] startTime[%s] no exist", filmName, startTime) return nil, fmt.Errorf("film[%s] startTime[%s] no exist", filmName, startTime) } func (p *Processor) getSeatGoods(cinema *Cinema, sessionId, seats string) ([]*SeatGoods, error) { baseReq := p.getBaseParam(cinema) baseReq["sessionId"] = sessionId reqUrl := "https://appapi.dadicinema.com/app-web/v1/web/cinema/cbticket/cticket/getSessionSeat" body, err := httputil.HttpGet(reqUrl, baseReq, p.getBaseHeader()) if err != nil { log.Errorf("http get url: %s, error: %s", reqUrl, err.Error()) return nil, err } data, err := p.checkError(body) if err != nil { return nil, err } existMap := make(map[string]bool) for _, s := range strings.Split(seats, "|") { existMap[s] = true } allSeatGoods := make([]*SeatGoods, 0) for _, s := range cast.ToSlice(cast.ToStringMap(data)["seats"]) { seat := cast.ToStringMap(s) key := fmt.Sprintf("%d:%d", cast.ToInt(seat["phyRowId"]), cast.ToInt(seat["phyColId"])) if _, ok := existMap[key]; !ok { continue } areanInfo := cast.ToStringMap(seat["areaInfo"]) ticketPriceInfo := cast.ToStringMap(areanInfo["ticketPriceInfo"]) seatGoods := new(SeatGoods) seatGoods.SeatCode = cast.ToString(seat["seatCode"]) seatGoods.PlanCode = sessionId seatGoods.LevelCode = "" seatGoods.StandPrice = cast.ToString(ticketPriceInfo["standPrice"]) seatGoods.AddPrice = fmt.Sprintf("%.2f", cast.ToFloat64(ticketPriceInfo["addPrice"])) seatGoods.ServiceFee = fmt.Sprintf("%.2f", cast.ToFloat64(ticketPriceInfo["servicePrice"])) seatGoods.PlatServiceFee = fmt.Sprintf("%.2f", cast.ToFloat64(ticketPriceInfo["platServicePrice"])) allSeatGoods = append(allSeatGoods, seatGoods) } return allSeatGoods, nil } func (p *Processor) prevOrderInfo(cinema *Cinema, seatGoods []*SeatGoods) (*PreviewOrder, error) { // 座位下单 reqUrl := "https://appapi.dadicinema.com/app-web/v1/web/order/trade/order/ticket" baseReq := p.getBaseParam(cinema) baseReq["seatGoodsAddList"] = seatGoods baseReq["existsAreasPrice"] = false baseReq["phoneNo"] = "17610351227" reqBody := goutil.EncodeJSON(baseReq) baseHeader := p.getBaseHeader() baseHeader["Cookie"] = "HWWAFSESID=d527bdc7a4a18b8e40; HWWAFSESTIME=1680956218712" body, err := httputil.HttpPostJson(reqUrl, nil, baseHeader, []byte(reqBody)) if err != nil { log.Errorf("httpPost url[%s] error : %s", reqUrl, err.Error()) return nil, err } data, err := p.checkError(body) if err != nil { return nil, err } billCode := cast.ToString(data) // 计算价格 reqUrl = "https://appapi.dadicinema.com/app-web/v1/web/order/newPriceCalculate" baseReq = p.getBaseParam(cinema) baseReq["billCode"] = billCode baseReq["firstPriceCalculateFlag"] = 1 reqBody = goutil.EncodeJSON(baseReq) body, err = httputil.HttpPostJson(reqUrl, nil, p.getBaseHeader(), []byte(reqBody)) if err != nil { log.Errorf("httpPost url[%s] error : %s", reqUrl, err.Error()) return nil, err } data, err = p.checkError(body) if err != nil { return nil, err } log.Debugf("[newPriceCalculate] response : %s", goutil.EncodeJSON(data)) realData := cast.ToStringMap(data) previewOrder := new(PreviewOrder) previewOrder.TotalOriginPrice = int64(cast.ToFloat64(realData["ticketOriginPrice"]) * 100) previewOrder.TotalRealPrice = int64(cast.ToFloat64(realData["ticketRealPrice"]) * 100) previewOrder.CouponPrice = int64(cast.ToFloat64(realData["ticketCouponPrice"]) * 100) previewOrder.BillCode = billCode return previewOrder, nil } func (p *Processor) getUserPrice(cinema *Cinema, filmName, showTime string) (*FilmPrice, error) { reqUrl := "https://appapi.dadicinema.com/app-web/v1/web/film/getHitFilmAndFilmSession" baseReq := p.getBaseParam(cinema) body, err := httputil.HttpGet(reqUrl, baseReq, p.getBaseHeader()) if err != nil { log.Errorf("httpPost url[%s] error : %s", reqUrl, err.Error()) return nil, err } data, err := p.checkError(body) if err != nil { return nil, err } for _, f := range cast.ToSlice(cast.ToStringMap(data)["filmList"]) { film := cast.ToStringMap(f) name := cast.ToString(film["name"]) if name != filmName { continue } for _, ds := range cast.ToSlice(film["showList"]) { dayShow := cast.ToStringMap(ds) for _, ts := range cast.ToSlice(dayShow["plist"]) { timeShow := cast.ToStringMap(ts) startTime := cast.ToString(timeShow["startTime"]) if startTime != showTime { continue } prices := cast.ToSlice(timeShow["sceneTypePriceVOList"]) if len(prices) < 2 { log.Errorf("cinema[%s] timeShow[%s]", cinema.Name, goutil.EncodeJSON(timeShow)) return nil, err } result := new(FilmPrice) result.OriginPrice = int64(100 * cast.ToFloat64(cast.ToStringMap(prices[0])["scenePrice"])) result.VipPrice = int64(100 * cast.ToFloat64(cast.ToStringMap(prices[1])["scenePrice"])) result.SessionId = cast.ToString(timeShow["sessionId"]) return result, nil } } } log.Errorf("[%s][%s][%s][%s] not exist", cinema.Name, cinema.Address, filmName, showTime) return nil, fmt.Errorf("[%s][%s][%s][%s] not exist", cinema.Name, cinema.Address, filmName, showTime) } func (p *Processor) getUserCard(cinema *Cinema) ([]*UserCard, *UserCard, error) { reqUrl := "https://appapi.dadicinema.com/app-web/v1/user/cards" body, err := httputil.HttpPostForm(reqUrl, p.getBaseHeader(), p.getBaseParam(cinema)) if err != nil { log.Errorf("httpPost url[%s] error : %s", reqUrl, err.Error()) return nil, nil, err } data, err := p.checkError(body) if err != nil { return nil, nil, err } allCards := make([]*UserCard, 0) maxBlance := int64(-1000000) var defCard *UserCard = nil for _, c := range cast.ToSlice(data) { card := cast.ToStringMap(c) uCard := new(UserCard) uCard.CardNo = cast.ToString(card["cardNo"]) uCard.CardName = cast.ToString(card["cardName"]) uCard.Balance = int64(cast.ToFloat64(card["amount"]) * 100) uCard.Expire = cast.ToInt64(card["cardName"]) / 1000 allCards = append(allCards, uCard) if uCard.Balance > maxBlance { defCard = uCard maxBlance = uCard.Balance } } return allCards, defCard, nil } func (p *Processor) payOrder(cinema *Cinema, billCode, cardNo string, amount int64) error { baseReq := p.getBaseParam(cinema) baseReq["businessSystemCode"] = "c_app" baseReq["ip"] = "127.0.0.1" baseReq["amount"] = fmt.Sprintf("%.2f", float64(amount)/100) baseReq["orderRemark"] = "{\"saleBillUid\":\"\"}" baseReq["businessSystemName"] = "C_APP" baseReq["goodBody"] = "APP" baseReq["orderType"] = "0" baseReq["payChannelName"] = "大地自营-大地" baseReq["payChannel"] = "DDZY-DD" baseReq["payTerminal"] = "APP" baseReq["businessSystemMainOrderNumber"] = billCode baseReq["businessSystemFlowNumber"] = cast.ToString(goutil.GetBigID(0, 0)) baseReq["cardNumber"] = cardNo baseReq["payWay"] = "MEMBER_CARD_PAY" reqBody, _ := json.Marshal(baseReq) reqUrl := "https://appapi.dadicinema.com/app-web/v1/web/order/confirmPay" body, err := httputil.HttpPostJson(reqUrl, nil, p.getBaseHeader(), reqBody) if err != nil { log.Errorf("httpPost url[%s] error : %s", reqUrl, err.Error()) return err } _, err = p.checkError(body) if err != nil { log.Errorf("request : %s", goutil.EncodeJSON(baseReq)) return err } return nil } func (p *Processor) CheckOrder(order *model.Order) (*common.CheckInfo, error) { cinema, err := p.getCinema(order.CityName, order.CinemaName) if err != nil { return nil, err } /* 下单看实际价格 showHall, err := p.getCinemaFilmShowHall(cinema, order.MovieName, goutil.TimeToDateTime(order.ShowTime)) if err != nil { return nil, err } seatGoods, err := p.getSeatGoods(cinema, showHall.SessionId, order.Seats) if err != nil { return nil, err } previewOrder, err := p.prevOrderInfo(cinema, seatGoods) if err != nil { return nil, err } */ filmPrice, err := p.getUserPrice(cinema, order.MovieName, goutil.TimeToDateTime(order.ShowTime)) if err != nil { return nil, err } result := new(common.CheckInfo) result.TotalRealPrice = filmPrice.VipPrice * int64(order.SeatNum) result.TotalOriginPrice = filmPrice.OriginPrice * int64(order.SeatNum) result.CouponPrice = (filmPrice.OriginPrice - filmPrice.VipPrice) * int64(order.SeatNum) result.SessionCode = filmPrice.SessionId result.SessionType = "view" log.Infof("check order[%s][%s] previewOrder[%s] [%s][%s][%s] success", order.OrderNo, result.SessionCode, goutil.EncodeJSON(filmPrice), order.CityName, order.CinemaName, order.MovieName) return result, nil } func (p *Processor) CreateOrder(order *model.Order) (*common.OrderInfo, error) { cinema, err := p.getCinema(order.CityName, order.CinemaName) if err != nil { return nil, err } price, err := p.getUserPrice(cinema, order.MovieName, goutil.TimeToDateTime(order.ShowTime)) if err != nil { return nil, err } seatGoods, err := p.getSeatGoods(cinema, price.SessionId, order.Seats) if err != nil { return nil, err } previewOrder, err := p.prevOrderInfo(cinema, seatGoods) if err != nil { return nil, err } _, defautCard, err := p.getUserCard(cinema) if err != nil { return nil, err } if defautCard == nil { return nil, errors.New("No UserCard") } if err := p.payOrder(cinema, previewOrder.BillCode, defautCard.CardNo, previewOrder.TotalRealPrice); err != nil { return nil, err } orderInfo := new(common.OrderInfo) return orderInfo, nil } func (p *Processor) getOrderDetail(cinema *Cinema, orderNo string) { return } func (p *Processor) refundOrder(cinema *Cinema, orderNo string) error { //baseReq := p.getBaseParam(cinema) //baseReq["orderNo"] = orderNo return nil } func (p *Processor) CancelOrder(order *model.Order, checkInfo *common.CheckInfo) error { cinema, err := p.getCinema(order.CityName, order.CinemaName) if err != nil { return err } reqUrl := "https://appapi.dadicinema.com/app-web/v1/web/order/cancel" baseReq := p.getBaseParam(cinema) baseReq["billCode"] = checkInfo.SessionCode body, err := httputil.HttpPostJson(reqUrl, nil, p.getBaseHeader(), []byte(goutil.EncodeJSON(baseReq))) if err != nil { log.Errorf("http request url[%s] error[%s]", reqUrl, err.Error()) return err } _, err = p.checkError(body) if err != nil { return err } log.Infof("cancel order[%s][%s] [%s][%s][%s] success", order.OrderNo, checkInfo.SessionCode, order.CityName, order.CinemaName, order.MovieName) return nil }