film/worker/dadi/dadi_processor.go

498 lines
16 KiB
Go

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
}