Files
jx-callback/business/partner/purchase/mtwm/store.go
邹宗楠 bcb0f3b24a 1
2023-12-11 18:24:02 +08:00

485 lines
19 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package mtwm
import (
"encoding/json"
"errors"
"fmt"
"math"
"regexp"
"strings"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/errlist"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"git.rosy.net.cn/jx-callback/business/jxstore/event"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
var (
opTimeErrReg = regexp.MustCompile(`当前配送营业时间为:([\d:~,]*)`)
storeVendorOrgCodeMap = map[string]map[string]string{
"589": map[string]string{
"firstTag": mtwmapi.MtwmC4Tag, //经营品类
"settlementID": "7030017", //结算ID
"poiCert": "1,2,5", //资质列表
},
"5873": map[string]string{
"firstTag": mtwmapi.MtwmSCTag,
"settlementID": "",
"poiCert": "1,2,5,6",
},
"4123": map[string]string{
"firstTag": mtwmapi.MtwmSGTag,
"settlementID": "6572945",
"poiCert": "1,5",
},
}
poiCertMap = map[string]string{
"1": "门脸图",
"2": "环境图",
"5": "营业执照",
"6": "食品经营许可证",
}
)
type tEbaiStoreInfo struct {
model.Store
VendorStoreID string `orm:"column(vendor_store_id)"`
RealLastOperator string
EbaiStoreStatus int
SyncStatus int
ProvinceID int `orm:"column(province_id)"`
CityID int `orm:"column(city_id)"`
DistrictID int `orm:"column(district_id)"`
}
func (p *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorStoreName string) (retVal *dao.StoreDetail, err error) {
result, err := getAPIWithoutToken(vendorOrgCode).PoiGet(vendorStoreID)
if err == nil {
retVal = &dao.StoreDetail{
Store: model.Store{
Address: result.Address,
Tel1: result.Phone,
},
}
retVal.OriginalName = result.Name
_, retVal.Name = jxutils.SplitStoreName(retVal.OriginalName, partner.StoreNameSeparator, globals.StoreNameMtwm)
retVal.SetOpTime(openTimeMtwm2JX(result.ShippingTime))
retVal.Status = bizStatusMtwm2JX(result.OpenLevel, result.IsOnline)
tel2 := result.StandbyTel
if tel2 != "" && tel2 != retVal.Tel1 {
retVal.Tel2 = tel2
}
retVal.Lng = int(result.Longitude)
retVal.Lat = int(result.Latitude)
lng := jxutils.IntCoordinate2Standard(retVal.Lng)
lat := jxutils.IntCoordinate2Standard(retVal.Lat)
db := dao.GetDB()
retVal.DistrictCode = api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat)
city, err := dao.GetPlaceByCode(db, result.CityID)
retVal.CityName = city.Name
retVal.CityCode = result.CityID
poiCode := result.AppPoiCode
retVal.VendorStoreID = vendorStoreID
retVal.ID = int(utils.Str2Int64WithDefault(poiCode, 0))
retVal.DeliveryRangeType = model.DeliveryRangeTypePolygon
var deliveryRangeInfo []map[string]interface{}
deliveryRangeInfo, err = getAPIWithoutToken(vendorOrgCode).ShippingFetch(poiCode)
if err != nil {
deliveryRangeInfo, err = getAPIWithoutToken(vendorOrgCode).ShippingList(poiCode)
}
if err == nil {
if len(deliveryRangeInfo) > 0 {
retVal.DeliveryRange = rangeMtwm2JX(deliveryRangeInfo[0]["area"].(string))
logisticsCode := utils.Interface2String(deliveryRangeInfo[0]["logistics_code"])
if logisticsCode == "" || logisticsCode == mtwmapi.PeiSongTypeSelf {
retVal.DeliveryType = scheduler.StoreDeliveryTypeByStore
} else {
retVal.DeliveryType = scheduler.StoreDeliveryTypeByPlatform
}
}
}
return retVal, nil
}
return nil, err
}
func (p *PurchaseHandler) CreateStore(db *dao.DaoDB, storeID int, userName string) (err error) {
return p.UpdateStore(db, storeID, userName)
}
func (p *PurchaseHandler) CreateStore2(db *dao.DaoDB, storeID int, userName string, params map[string]interface{}, storeDetail *dao.StoreDetail) (vendorStoreID string, err error) {
vendorOrgCode := params["vendorOrgCode"].(string)
if vendorOrgCode == "" {
return "", fmt.Errorf("平台账号必传!")
}
cityName := storeDetail.CityName
if strings.Contains(cityName, "市") {
cityName = strings.Replace(cityName, "市", "", strings.LastIndex(cityName, "市"))
}
shippingTime := ""
if storeDetail.OpenTime1 != 0 && storeDetail.CloseTime1 != 0 {
shippingTime += jxutils.JxOperationTime2StrTime(storeDetail.OpenTime1)
shippingTime += "-"
shippingTime += jxutils.JxOperationTime2StrTime(storeDetail.CloseTime1)
if storeDetail.OpenTime2 != 0 && storeDetail.CloseTime2 != 0 {
shippingTime += ","
shippingTime += jxutils.JxOperationTime2StrTime(storeDetail.OpenTime2)
shippingTime += "-"
shippingTime += jxutils.JxOperationTime2StrTime(storeDetail.CloseTime2)
}
}
vendorInfoMap := storeVendorOrgCodeMap[vendorOrgCode]
poiSettleSaveParam := &mtwmapi.PoiSettleSaveParam{
Type: 1, //创建
ApplyInfos: []*mtwmapi.ApplyInfo{
&mtwmapi.ApplyInfo{
AppPoiCode: utils.Int2Str(storeDetail.ID),
SettlementID: utils.Str2Int(vendorInfoMap["settlementID"]), //结算ID暂时还没得
MultiPoiBasicInfo: &mtwmapi.MultiPoiBasicInfo{
Name: params["vendorStoreName"].(string),
City: cityName,
Address: storeDetail.Address,
Longitude: utils.Float64ToStr(jxutils.IntCoordinate2Standard(storeDetail.Lng)),
Latitude: utils.Float64ToStr(jxutils.IntCoordinate2Standard(storeDetail.Lat)),
FirstTag: vendorInfoMap["firstTag"],
CallCenter: storeDetail.Tel1,
ContactPhone: storeDetail.Tel1,
ContactName: storeDetail.IDName,
EcommerceAccountPhone: "18048531223", //石总的手机
ShippingTime: shippingTime,
},
MultiPoiShippingInfo: &mtwmapi.MultiPoiShippingInfo{
ShippingType: 5, //1:商家自配 5:美团专送,101:美团快送
//美团专送不需要输下面这俩
// MinPrice: params["minPrice"].(float64),
// ShippingFee: params["shippingFee"].(float64),
},
//资质
},
},
}
switchCertType := func(certType string) (licensePic, licenseSocialCreditCode, licenseNumber, licenseLegalPerson, licenseAddress, licenseValidStartDate, licenseValidity string, isLongTime int) {
switch certType {
case "1":
licensePic = storeDetail.StoreFrontPic
case "2":
licensePic = storeDetail.StoreInPic
case "5":
licensePic = storeDetail.Licence
licenseSocialCreditCode = storeDetail.LicenceCode
licenseNumber = storeDetail.LicenceCode
licenseLegalPerson = storeDetail.LicenceOwnerName
licenseAddress = storeDetail.LicenceAddress
licenseValidStartDate = storeDetail.LicenceValid
if storeDetail.LicenceExpire == "" {
isLongTime = 1
} else {
licenseValidity = storeDetail.LicenceExpire
}
case "6":
licensePic = storeDetail.Licence2Image
licenseSocialCreditCode = storeDetail.Licence2Code
licenseNumber = storeDetail.Licence2Code
licenseLegalPerson = storeDetail.LicenceOwnerName
licenseAddress = storeDetail.LicenceAddress
licenseValidStartDate = storeDetail.Licence2Valid
if storeDetail.Licence2Expire == "" {
isLongTime = 1
} else {
licenseValidity = storeDetail.Licence2Expire
}
}
return licensePic, licenseSocialCreditCode, licenseNumber, licenseLegalPerson, licenseAddress, licenseValidStartDate, licenseValidity, isLongTime
}
var certs []*mtwmapi.MultiPoiCertInfo
for _, v := range strings.Split(vendorInfoMap["poiCert"], ",") {
cert := &mtwmapi.MultiPoiCertInfo{
Type: utils.Str2Int(v),
LicenseName: poiCertMap[v],
}
cert.LicensePic, cert.LicenseSocialCreditCode, cert.LicenseNumber, cert.LicenseLegalPerson, cert.LicenseAddress, cert.LicenseValidStartDate, cert.LicenseValidity, cert.IsLongTime = switchCertType(v)
certs = append(certs, cert)
}
poiSettleSaveParam.ApplyInfos[0].MultiPoiCertInfos = certs
mtapi := getAPIWithoutToken(vendorOrgCode)
if vendorStoreID, err = mtapi.PoiSettleSave(poiSettleSaveParam); err == nil {
err = mtapi.PoiSettleAuditSubmit([]string{vendorStoreID})
}
return vendorStoreID, err
}
func (p *PurchaseHandler) DeleteStore(db *dao.DaoDB, storeID int, userName string) (err error) {
return err
}
func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error) {
var name string
if db == nil {
db = dao.GetDB()
}
mtapi := getAPI(getStoreVendorOrgCode(storeID), storeID, "")
//获取本地store信息
storeDetail, err := dao.GetStoreDetail(db, storeID, model.VendorIDMTWM, "")
if err != nil {
return err
}
errList := errlist.New()
//获取平台store信息
remoteStoreInfo, err := mtapi.PoiGet(storeDetail.VendorStoreID)
if err != nil {
return err
}
mergedStoreStatus := jxutils.MergeStoreStatus(storeDetail.Status, storeDetail.VendorStatus)
name = remoteStoreInfo.Name
if storeDetail.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreName) != 0 {
if storeDetail.VendorStoreName != "" {
name = storeDetail.VendorStoreName
}
// else {
// name = jxutils.ComposeStoreName(storeDetail.Store.Name, model.VendorIDMTWM)
// }
}
store := fmt.Sprintf("门店id:%d,门店名称:%s,第三方门店状态:%d,本地修改前门店状态%d,本地门店修改后状态:%d,第三方平台Id(美团):%s", storeID, remoteStoreInfo.Name, remoteStoreInfo.IsOnline, storeDetail.Status, mergedStoreStatus, storeDetail.VendorOrgCode)
event.AddOperateEvent(jxcontext.AdminCtx, jxcontext.AdminCtx.GetTrackInfo(), store, "", "", 10, "UpdateStore")
//TODO 美团暂时不用那个电话
phone := storeDetail.Tel1
params := map[string]interface{}{
"name": name, //jxutils.ComposeStoreName(storeDetail.Store.Name, model.VendorIDMTWM),
"address": storeDetail.Address, // 美团好像地址也不能改的?
"longitude": jxutils.IntCoordinate2Standard(int(remoteStoreInfo.Longitude)),
"latitude": jxutils.IntCoordinate2Standard(int(remoteStoreInfo.Latitude)),
"phone": phone,
"shipping_fee": remoteStoreInfo.ShippingFee,
"shipping_time": remoteStoreInfo.ShippingTime,
"open_level": remoteStoreInfo.OpenLevel,
"is_online": remoteStoreInfo.IsOnline,
"third_tag_name": remoteStoreInfo.ThirdTagName,
"promotion_info": storeDetail.PromoteInfo,
}
if globals.EnableMtwmStoreWrite {
errList.AddErr(mtapi.PoiSave(storeDetail.VendorStoreID, params))
}
if storeDetail.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreStatus) != 0 {
errList.AddErr(p.UpdateStoreStatus(jxcontext.AdminCtx, storeDetail.VendorOrgCode, storeID, storeDetail.VendorStoreID, mergedStoreStatus))
}
errList.AddErr(p.UpdateStoreOpTime(jxcontext.AdminCtx, storeDetail.VendorOrgCode, storeID, storeDetail.VendorStoreID, storeDetail.GetOpTimeList()))
// errList.AddErr(p.UpdateStoreBoxFee(jxcontext.AdminCtx, storeDetail.VendorOrgCode, storeID, storeDetail.VendorStoreID))
return errList.GetErrListAsOne()
}
func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
return "", errors.New("美团外卖不支持此操作")
}
func (p *PurchaseHandler) onStoreStatusChanged(msg *mtwmapi.CallbackMsg) (response *mtwmapi.CallbackResponse) {
var err error
vendorStoreID := msg.FormData.Get("app_poi_code")
storeStatus := 0
if msg.Cmd == mtwmapi.MsgTypeStoreStatusChanged {
poiStatus := int(utils.Str2Int64(msg.FormData.Get("poi_status")))
if poiStatus == mtwmapi.MsgPoiStatusOpened {
storeStatus = model.StoreStatusOpened
} else if poiStatus == mtwmapi.MsgPoiStatusClosed {
storeStatus = model.StoreStatusClosed
} else if poiStatus == mtwmapi.MsgPoiStatusOffline {
storeStatus = model.StoreStatusDisabled
} else {
storeStatus, err = p.GetStoreStatus(jxcontext.AdminCtx, "", 0, vendorStoreID)
}
} else if msg.Cmd == mtwmapi.MsgTypeStoreAuditStatusChanged {
auditDetails := []map[string]interface{}{}
auditDetail := msg.FormData.Get("audit_detail")
openFlag := false
openCount := 0
closeFlag := false
if err = json.Unmarshal([]byte(auditDetail), &auditDetails); err == nil {
for _, v := range auditDetails {
if v["module_status"].(string) == "3" || v["module_status"].(string) == "5" || v["module_status"].(string) == "7" {
closeFlag = true
break
}
if v["module_status"].(string) == "6" {
openCount++
}
}
if openCount == len(auditDetails) {
openFlag = true
}
if closeFlag {
storeStatus = model.StoreStatusDisabled
} else if openFlag {
storeStatus = model.StoreStatusOpened
} else {
storeStatus = model.StoreStatusClosed
}
}
}
if err == nil {
err = partner.CurStoreManager.OnStoreStatusChanged(vendorStoreID, model.VendorIDMTWM, storeStatus)
}
response = mtwmapi.Err2CallbackResponse(err, "")
// 操作日志(美团外卖)
ctx := jxcontext.AdminCtx
store := fmt.Sprintf("美团外卖回调门店改变回调(营业状态/审核状态):门店id:%s,美团门店状态:%d.[121营业,120休息,18上线,19下线],本地修改后状态[%d]", vendorStoreID, int(utils.Str2Int64(msg.FormData.Get("poi_status"))), storeStatus)
event.AddOperateEvent(ctx, ctx.GetTrackInfo(), store, "", "", 10, "UpdateStore")
return response
}
func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error) {
result, err := getAPI(vendorOrgCode, storeID, "").PoiGet(vendorStoreID)
if err == nil {
return bizStatusMtwm2JX(result.OpenLevel, result.IsOnline), nil
}
return 0, err
}
func (p *PurchaseHandler) EnableAutoAcceptOrder(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, isSetEnable bool) (err error) {
return err
}
func (c *PurchaseHandler) UpdateStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, status int) (err error) {
openLevel, isOnline := bizStatusJX2Mtwm(status)
if globals.EnableMtwmStoreWrite {
if isOnline != mtwmapi.PoiStatusOnline {
err = getAPI(vendorOrgCode, storeID, vendorStoreID).PoiOffline(vendorStoreID)
} else {
if err = getAPI(vendorOrgCode, storeID, vendorStoreID).PoiOnline(vendorStoreID); err == nil { // 这个函数成功返回也并不表示上线成功。。。
remoteStoreInfo, err2 := getAPI(vendorOrgCode, storeID, vendorStoreID).PoiGet(vendorStoreID)
if err = err2; err != nil {
return err
}
if remoteStoreInfo.IsOnline == mtwmapi.PoiStatusOnline {
if openLevel == mtwmapi.PoiOpenLevelHaveRest {
err = getAPI(vendorOrgCode, storeID, vendorStoreID).PoiClose(vendorStoreID)
} else {
err = getAPI(vendorOrgCode, storeID, vendorStoreID).PoiOpen(vendorStoreID)
}
} else {
err = errors.New("门店还未上线,不能修改营业状态")
}
store := fmt.Sprintf("美团外卖回调门店改变回调(营业状态/审核状态):门店id:%s,美团门店状态:%d.[121营业,120休息,18上线,19下线],本地修改后状态[%d]", vendorStoreID, remoteStoreInfo.OpenLevel, openLevel)
event.AddOperateEvent(ctx, ctx.GetTrackInfo(), store, "", "", 10, "UpdateStore")
}
}
}
return err
}
func errOpStr2Int16(str string) []int16 {
list := strings.Split(str, "~")
if len(list) >= 2 {
return []int16{jxutils.StrTime2JxOperationTime(list[0]+":00", 0), jxutils.StrTime2JxOperationTime(list[1]+":00", 2359)}
}
return nil
}
func getOpTimeListFromErr(err error) (opTimeList []int16) {
if errExt, ok := err.(*utils.ErrorWithCode); ok && errExt.IntCode() == mtwmapi.ErrCodeOpFailed {
if result := opTimeErrReg.FindStringSubmatch(errExt.ErrMsg()); len(result) >= 2 {
timeStrList := strings.Split(result[1], ",")
for _, v := range timeStrList {
v = utils.TrimBlankChar(v)
if len(v) == len("00:00~02:00") {
opTimeList = append(opTimeList, errOpStr2Int16(v)...)
}
}
}
}
return opTimeList
}
// 此函数只是简单实现,不支持区间切分,只做单一区间限制
func constrainOpTimeList(opTimeList, validOpTimeList []int16) (newOpTimeList []int16) {
for k := 0; k < len(opTimeList); k += 2 {
beginTime := opTimeList[k]
endTime := opTimeList[k+1]
for k2 := 0; k2 < len(validOpTimeList); k2 += 2 {
beginTime2 := validOpTimeList[k2]
endTime2 := validOpTimeList[k2+1]
if beginTime >= beginTime2 && beginTime <= endTime2 {
newOpTimeList = append(newOpTimeList, beginTime)
newOpTimeList = append(newOpTimeList, int16(math.Min(float64(endTime), float64(endTime2))))
} else if beginTime2 >= beginTime && beginTime2 <= endTime {
newOpTimeList = append(newOpTimeList, beginTime2)
newOpTimeList = append(newOpTimeList, int16(math.Min(float64(endTime), float64(endTime2))))
}
}
}
return newOpTimeList
}
func (c *PurchaseHandler) UpdateStoreOpTime(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, opTimeList []int16) (err error) {
shippingTime := openTimeJX2Mtwm(opTimeList)
if globals.EnableMtwmStoreWrite {
err = getAPI(vendorOrgCode, storeID, vendorStoreID).PoiShipTimeUpdate(vendorStoreID, shippingTime)
if err != nil {
shippingTime = ""
if validOpTimeList := getOpTimeListFromErr(err); len(validOpTimeList) > 0 {
shippingTime = openTimeJX2Mtwm(constrainOpTimeList(opTimeList, validOpTimeList))
}
if shippingTime != "" {
err = getAPI(vendorOrgCode, storeID, vendorStoreID).PoiShipTimeUpdate(vendorStoreID, shippingTime)
}
}
}
return err
}
func (c *PurchaseHandler) GetAllStoresVendorID(ctx *jxcontext.Context, vendorOrgCode string) (vendorStoreIDs []string, err error) {
vendorStoreIDs, err = getAPIWithoutToken(vendorOrgCode).PoiGetIDs()
return vendorStoreIDs, err
}
func (c *PurchaseHandler) UpdateStoreCustomID(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string, storeID int64) (err error) {
return err
}
func (c *PurchaseHandler) UpdateStoreBoxFee(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (err error) {
boxFee, err := dao.GetSysConfigAsInt64(dao.GetDB(), model.ConfigSysMtwmBoxFee)
if err == nil {
if globals.EnableMtwmStoreWrite && globals.IsProductEnv() {
err = getAPI(vendorOrgCode, storeID, vendorStoreID).PackagePriceUpdate(vendorStoreID, 1, int(boxFee))
}
}
return err
}
func (c *PurchaseHandler) UpdateStoreLineStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, lineStatus int) (err error) {
mtwmApi := getAPI(vendorOrgCode, storeID, vendorStoreID)
switch lineStatus {
case model.StoreStatusOpened: // 先上线在开店
if err = mtwmApi.PoiOnline(vendorStoreID); err == nil {
err = mtwmApi.PoiOpen(vendorStoreID)
}
default: // 先关店,在下线
globals.SugarLogger.Debugf("===========err1 := %s", vendorStoreID)
err = mtwmApi.PoiClose(vendorStoreID)
if err != nil {
globals.SugarLogger.Debugf("===========err1 := %v", err)
}
if err == nil {
err = mtwmApi.PoiOffline(vendorStoreID)
if err != nil {
globals.SugarLogger.Debugf("===========err1 := %v", err)
}
}
}
return err
}