Files
jx-callback/business/partner/purchase/jd/store.go

500 lines
18 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 jd
import (
"fmt"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"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/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/errlist"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals/api"
)
type tJdStoreInfo struct {
model.Store
VendorOrgCode string `orm:"size(32)" json:"vendorOrgCode"` // 同一平台下不同的商户代码,如果只有一个,可以为空
FreightDeductionPack string `orm:"size(32)" json:"freightDeductionPack"` //
JdCityCode int
JdDistrictCode int
JdStoreStatus int
VendorStoreID string `orm:"column(vendor_store_id)"`
RealLastOperator string
SyncStatus int
VendorStoreName string
}
var (
specialDistrictMap = map[int]int{
13989: 310032,
}
)
func (p *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string) (*dao.StoreDetail, error) {
a := getAPI(vendorOrgCode)
result, err := a.GetStoreInfoByStationNo2(vendorStoreID)
if err == nil {
retVal := &dao.StoreDetail{
Store: model.Store{
Address: result.StationAddress,
OpenTime1: JdOperationTime2JxOperationTime(result.ServiceTimeStart1),
CloseTime1: JdOperationTime2JxOperationTime(result.ServiceTimeEnd1),
OpenTime2: JdOperationTime2JxOperationTime(result.ServiceTimeStart2),
CloseTime2: JdOperationTime2JxOperationTime(result.ServiceTimeEnd2),
Status: JdStoreStatus2JxStatus(int(result.Yn), result.CloseStatus),
Tel1: result.Phone,
},
}
if result.IsAutoOrder == 0 {
retVal.IsAutoOrder = 1
} else {
retVal.IsAutoOrder = -1
}
retVal.OriginalName = result.StationName
_, retVal.Name = jxutils.SplitStoreName(retVal.OriginalName, partner.StoreNameSeparator, globals.StoreName)
retVal.DeliveryType = JdDeliveryType2Jx(result.CarrierNo)
tel2 := result.Mobile
if tel2 != "" && tel2 != retVal.Tel1 {
retVal.Tel2 = tel2
}
lng := result.Lng
lat := result.Lat
retVal.Lng = jxutils.StandardCoordinate2Int(lng)
retVal.Lat = jxutils.StandardCoordinate2Int(lat)
db := dao.GetDB()
cityCode := result.City
if cityCode != 0 {
if place, err2 := dao.GetPlaceByJdCode(db, cityCode); err2 == nil {
if place.Level == model.PlaceLevelCity {
retVal.CityCode = place.Code
retVal.CityName = utils.Interface2String(result.CityName)
districtName := result.CountyName // 京东的市区号码与通用数据完全无法关联,只有通过名字来关联
if retVal.CityCode != 0 && districtName != "" {
if district, err2 := dao.GetPlaceByName(db, districtName, 3, place.Code); err2 == nil {
retVal.DistrictCode = district.Code
}
}
} else if place.Level == model.PlaceLevelDistrict {
retVal.CityCode = place.ParentCode
retVal.DistrictCode = place.Code
} else {
globals.SugarLogger.Warnf("门店:%s的城市码:%d异常", vendorStoreID, cityCode)
}
}
}
if retVal.DistrictCode == 0 {
retVal.DistrictCode = api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat)
if retVal.CityCode == 0 {
if district, err := dao.GetPlaceByCode(db, retVal.DistrictCode); err == nil {
retVal.CityCode = district.ParentCode
}
}
}
retVal.VendorStoreID = vendorStoreID
retVal.ID = int(utils.Str2Int64WithDefault(result.OutSystemID, 0))
deliveryRange, err2 := a.GetDeliveryRangeByStationNo2(vendorStoreID)
if err = err2; err == nil {
retVal.DeliveryRangeType = int8(deliveryRange.DeliveryRangeType)
if retVal.DeliveryRangeType == model.DeliveryRangeTypePolygon {
retVal.DeliveryRange = strings.Trim(deliveryRange.DeliveryRange, ";")
} else {
retVal.DeliveryRange = utils.Int2Str(deliveryRange.DeliveryRangeRadius)
}
return retVal, nil
}
}
return nil, err
}
// stoerIDs为nil表示所有
func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error) {
var stores []*tJdStoreInfo
sql := `
SELECT
t1.*, city.jd_code jd_city_code, district.jd_code jd_district_code,
t2.status jd_store_status, t2.vendor_store_id, IF(t1.updated_at > t2.updated_at, t1.last_operator,
t2.last_operator) real_last_operator,
t2.sync_status, t2.freight_deduction_pack, t2.vendor_org_code, t2.vendor_store_name
FROM store t1
JOIN store_map t2 ON t1.id = t2.store_id AND t2.vendor_id = ? AND (t2.deleted_at = ?)
LEFT JOIN place city ON t1.city_code = city.code
LEFT JOIN place district ON t1.district_code = district.code
WHERE t1.id = ?
ORDER BY t2.updated_at
`
if err = dao.GetRows(db, &stores, sql, model.VendorIDJD, utils.DefaultTimeValue, storeID); err == nil {
for _, store := range stores {
a := getAPI(store.VendorOrgCode)
storeParams := &jdapi.OpStoreParams{
StationNo: store.VendorStoreID,
Operator: userName,
Phone: store.Tel1,
Mobile: store.Tel2,
}
if store.SyncStatus&model.SyncFlagDeletedMask == 0 {
storeParams.OutSystemID = utils.Int2Str(int(store.ID))
} else {
storeParams.OutSystemID = store.VendorStoreID
}
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreName) != 0 {
if store.VendorStoreName != "" {
storeParams.StationName = store.VendorStoreName
} else {
storeParams.StationName = jxutils.ComposeStoreName(store.Name, model.VendorIDJD)
}
storeParams.StationName = utils.LimitUTF8StringLen(storeParams.StationName, jdapi.MaxStoreNameLen)
}
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreAddress) != 0 {
storeParams.StationAddress = store.Address
storeParams.CoordinateType = jdapi.CoordinateTypeAutonavi // 一直用高德
storeParams.Lng = jxutils.IntCoordinate2Standard(store.Lng)
storeParams.Lat = jxutils.IntCoordinate2Standard(store.Lat)
if store.JdCityCode != 0 {
storeParams.City = store.JdCityCode
}
if store.JdDistrictCode != 0 {
storeParams.County = store.JdDistrictCode
}
// storeParams.DeliveryRangeType = store.DeliveryRangeType
// if store.DeliveryRangeType == model.DeliveryRangeTypePolygon {
// storeParams.CoordinatePoints = store.DeliveryRange
// } else {
// storeParams.DeliveryRangeRadius = int(utils.Str2Int64WithDefault(store.DeliveryRange, 0))
// }
}
if specialDistrictMap[storeParams.County] != 0 {
storeParams.City = storeParams.County
storeParams.County = specialDistrictMap[storeParams.County]
}
storeParams.StoreNotice = store.PromoteInfo
modifyCloseStatus := false
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagDeletedMask|model.SyncFlagStoreStatus) != 0 {
modifyCloseStatus = true
_, storeParams.CloseStatus = JxStoreStatus2JdStatus(jxutils.MergeStoreStatus(store.Status, store.JdStoreStatus))
}
fillOpTimeParams(storeParams, store.GetOpTimeList())
// globals.SugarLogger.Debug(utils.Format4Output(storeParams, false))
errList := errlist.New()
if globals.EnableJdStoreWrite {
errList.AddErr(a.UpdateStoreInfo4Open2(storeParams, modifyCloseStatus))
}
if store.FreightDeductionPack != "" {
storeDetail, err2 := dao.GetStoreDetail(db, store.ID, model.VendorIDJD)
if err2 == nil {
if storeDetail.FreightDeductionPackObj != nil {
freightParams := &jdapi.UpdateStoreFreightParam{
StationNo: store.VendorStoreID,
UserPin: userName,
OpenDistanceFreight: true,
StartCharge: int64(storeDetail.FreightDeductionPackObj.StartPrice),
}
if len(storeDetail.FreightDeductionPackObj.FreightDeductionList) > 0 {
for _, v := range storeDetail.FreightDeductionPackObj.FreightDeductionList {
if v.DeductFreight > 0 {
freightParams.FreeFreightInfoList = append(freightParams.FreeFreightInfoList, &jdapi.FreeFreightInfo{
FullFreeMoney: int64(v.BeginPrice),
FreeType: jdapi.FreightFreeTypePartBase,
FreeMoney: int64(v.DeductFreight),
FreeFreightTimes: []*jdapi.FreeFreightTime{
&jdapi.FreeFreightTime{
FreeBeginTime: utils.Time2Str(time.Now()),
FreeEndTime: utils.Time2Str(time.Now().Add(24 * time.Hour * 365 * 2)),
},
},
})
break // 京东只能设置一个满减,之前理解有误
}
}
}
freightParams.IsFullFree = len(freightParams.FreeFreightInfoList) > 0
// globals.SugarLogger.Debug(utils.Format4Output(freightParams, false))
if globals.EnableJdStoreWrite {
errList.AddErr(a.UpdateStoreFreightConfigNew(freightParams))
}
}
}
}
err = errList.GetErrListAsOne()
}
}
return err
}
func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
globals.SugarLogger.Debugf("jd RefreshAllStoresID")
const stepCount = 3
var stores []*tJdStoreInfo
db := dao.GetDB()
rootTask := tasksch.NewSeqTask("jd RefreshAllStoresID", ctx,
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
err = dao.GetRows(db, &stores, `
SELECT t1.*, t2.vendor_store_id
FROM store t1
JOIN store_map t2 ON t1.id = t2.store_id AND t2.deleted_at = ? AND t2.vendor_id = ?
WHERE t1.deleted_at = ?
`, utils.DefaultTimeValue, model.VendorIDJD, utils.DefaultTimeValue)
default:
taskName := "jd RefreshAllStoresID update outSystemId"
if step != stepCount-1 {
taskName = "jd RefreshAllStoresID update to uuid"
}
task1 := tasksch.NewParallelTask(taskName, nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
store := batchItemList[0].(*tJdStoreInfo)
storeParams := &jdapi.OpStoreParams{
StationNo: store.VendorStoreID,
Operator: ctx.GetUserName(),
OutSystemID: utils.Int2Str(int(store.ID)),
}
if step != stepCount-1 {
storeParams.OutSystemID = store.VendorStoreID
}
if globals.EnableJdStoreWrite {
err = getAPI(store.VendorOrgCode).UpdateStoreInfo4Open2(storeParams, false)
}
return nil, err
}, stores)
task.AddChild(task1).Run()
_, err = task1.GetResult(0)
}
return nil, err
}, stepCount)
tasksch.HandleTask(rootTask, parentTask, false).Run()
if !isAsync {
_, err = rootTask.GetResult(0)
}
return rootTask.ID, err
}
func JdDeliveryType2Jx(deliveryType int) int8 {
if deliveryType == jdapi.CarrierNoSelfDelivery {
return scheduler.StoreDeliveryTypeByStore
} else if deliveryType == jdapi.CarrierNoCrowdSourcing {
return scheduler.StoreDeliveryTypeCrowdSourcing
}
return scheduler.StoreDeliveryTypeByPlatform
}
func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error) {
result, err := getAPI(vendorOrgCode).GetStoreInfoByStationNo2(vendorStoreID)
if err == nil {
storeStatus = JdStoreStatus2JxStatus(int(result.Yn), result.CloseStatus)
}
return storeStatus, err
}
// 当前京东的storeCrud消息不会在门店状态改变时发送所以意义不大先放在这里
func (c *PurchaseHandler) OnStoreMsg(vendorOrgCode string, msg *jdapi.CallbackOrderMsg) (response *jdapi.CallbackResponse) {
var err error
// if msg.StatusID == jdapi.StatusIDUpdateStore {
// var storeStatus int
// vendorStoreID := msg.BillID
// if storeStatus, err = c.GetStoreStatus(jxcontext.AdminCtx, vendorStoreID); err == nil {
// err = partner.CurStoreManager.OnStoreStatusChanged(vendorStoreID, model.VendorIDJD, storeStatus)
// } else {
// // 可能在门店删除的情况下会出查不到门店的错误
// if errExt, ok := err.(*utils.ErrorWithCode); ok && errExt.IntCode() == 4 {
// err = nil
// }
// }
// }
return jdapi.Err2CallbackResponse(err, "")
}
func (p *PurchaseHandler) EnableAutoAcceptOrder(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, isSetEnable bool) (err error) {
_, err = getAPI(vendorOrgCode).UpdateStoreConfig4Open(vendorStoreID, isSetEnable)
return err
}
func (c *PurchaseHandler) UpdateStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, status int) (err error) {
_, closeStatus := JxStoreStatus2JdStatus(status)
if globals.EnableJdStoreWrite {
err = getAPI(vendorOrgCode).UpdateStoreInfo4Open2(&jdapi.OpStoreParams{
StationNo: vendorStoreID,
Operator: ctx.GetUserName(),
CloseStatus: closeStatus,
}, true)
}
return err
}
func fillOpTimeParams(params *jdapi.OpStoreParams, opTimeList []int16) {
index := 1
opTimeListLen := len(opTimeList)
if opTimeListLen > 4 {
opTimeListLen = 4
}
opTimeListLen = opTimeListLen / 2 * 2
for k := 0; k < len(opTimeList); k += 2 {
if opTimeList[k] != 0 {
if index == 1 {
params.ServiceTimeStart1 = int(JxOperationTime2JdOperationTime(int16(opTimeList[k])))
params.ServiceTimeEnd1 = int(JxOperationTime2JdOperationTime(int16(opTimeList[k+1])))
} else {
params.ServiceTimeStart2 = int(JxOperationTime2JdOperationTime(int16(opTimeList[k])))
params.ServiceTimeEnd2 = int(JxOperationTime2JdOperationTime(int16(opTimeList[k+1])))
}
} else {
break
}
index++
}
}
func (c *PurchaseHandler) UpdateStoreOpTime(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, opTimeList []int16) (err error) {
params := &jdapi.OpStoreParams{
StationNo: vendorStoreID,
Operator: ctx.GetUserName(),
}
fillOpTimeParams(params, opTimeList)
if globals.EnableJdStoreWrite {
err = getAPI(vendorOrgCode).UpdateStoreInfo4Open2(params, false)
}
return err
}
func (c *PurchaseHandler) GetAllStoresVendorID(ctx *jxcontext.Context, vendorOrgCode string) (vendorStoreIDs []string, err error) {
vendorStoreIDs, err = getAPI(vendorOrgCode).GetStationsByVenderId()
return vendorStoreIDs, err
}
func (c *PurchaseHandler) storeUploadImgByURL(vendorOrgCode, inImgURL string) (imgURL string, err error) {
if globals.EnableJdStoreWrite {
if vendorOrgCode == globals.JdOrgCode {
imgURL, err = api.JdPageAPI.StoreUploadImgByURL(inImgURL)
} else {
imgURL, err = getAPI(vendorOrgCode).StoreUploadImgByURL(inImgURL)
}
} else {
imgURL = utils.GetUUID()
}
return imgURL, err
}
func addStoreInfo2Err(err error, storeID int) error {
if err != nil {
errExt, _ := err.(*utils.ErrorWithCode)
if errExt == nil {
errExt = utils.NewErrorCode(err.Error(), "999")
}
errExt.AddPrefixMsg(fmt.Sprintf("门店%d", storeID))
err = errExt
}
return err
}
func (c *PurchaseHandler) SyncQualify(ctx *jxcontext.Context, storeDetail *dao.StoreDetail) (err error) {
if storeDetail.LicenceCode == "" || storeDetail.Licence == "" {
return addStoreInfo2Err(fmt.Errorf("营业执照信息不全"), storeDetail.ID)
}
if storeDetail.IDCode == "" || storeDetail.IDCardFront == "" || storeDetail.IDCardBack == "" || storeDetail.IDValid == "" {
return addStoreInfo2Err(fmt.Errorf("个人信息不全"), storeDetail.ID)
}
var qualifyList []*jdapi.QualifyItem
licenceDetail, err := api.JdPageAPI.GetCorporationInfo(storeDetail.VendorStoreID, storeDetail.LicenceCode)
if err != nil {
return addStoreInfo2Err(err, storeDetail.ID)
}
licenceURL, err := c.storeUploadImgByURL(storeDetail.VendorOrgCode, storeDetail.Licence)
if err != nil {
return addStoreInfo2Err(err, storeDetail.ID)
}
expireStart, err := utils.TryStr2Time(licenceDetail.StartDate)
if err != nil {
return addStoreInfo2Err(fmt.Errorf("执照有效开始时间:%s非法请手动处理", licenceDetail.StartDate), storeDetail.ID)
}
qualifyList = append(qualifyList, &jdapi.QualifyItem{
QualifyType: jdapi.QualifyTypeCompany,
QualifyURL: licenceURL,
QualifyExpireStart: utils.Time2Str(expireStart),
QualifyExpireForever: 0,
QualifyName: licenceDetail.OperName,
LicenceType: "-1",
QualifyNumber: storeDetail.LicenceCode,
QualifyAddress: licenceDetail.Address,
LicenceName: licenceDetail.Name,
EconKind: licenceDetail.EconKind,
Scope: licenceDetail.Scope,
})
idFrondURL, err := c.storeUploadImgByURL(storeDetail.VendorOrgCode, storeDetail.IDCardFront)
if err != nil {
return addStoreInfo2Err(err, storeDetail.ID)
}
// 个体经营,个体工商户
if storeDetail.LicenceType == 0 { // 个人
personQualify := &jdapi.QualifyItem{
QualifyType: jdapi.QualifyTypePerson,
QualifyURL: idFrondURL,
QualifyExpireStart: utils.Time2Str(utils.Str2Time(storeDetail.IDValid)),
QualifyExpireForever: 0,
QualifyNumber: storeDetail.IDCode,
QualifyOwner: storeDetail.LicenceOwnerName,
}
if storeDetail.IDExpire != "" {
personQualify.QualifyExpireForever = 1
personQualify.QualifyExpireEnd = utils.Time2Str(utils.Str2Time(storeDetail.IDExpire))
}
qualifyList = append(qualifyList, personQualify)
} else {
addInfo := &jdapi.QualifyItem{
QualifyType: jdapi.QualifyTypeAddInfo,
QualifyURL: idFrondURL,
QualifyExpireStart: utils.Time2Str(utils.Str2Time(storeDetail.IDValid)),
QualifyExpireForever: 0,
}
if storeDetail.IDExpire != "" {
addInfo.QualifyExpireForever = 1
addInfo.QualifyExpireEnd = utils.Time2Str(utils.Str2Time(storeDetail.IDExpire))
}
qualifyList = append(qualifyList, addInfo)
}
if storeDetail.IDExpire == "" {
idBackURL, err := c.storeUploadImgByURL(storeDetail.VendorOrgCode, storeDetail.IDCardBack)
if err != nil {
return addStoreInfo2Err(err, storeDetail.ID)
}
qualifyList = append(qualifyList, &jdapi.QualifyItem{
QualifyType: jdapi.QualifyTypeAddInfo,
QualifyURL: idBackURL,
QualifyExpireStart: utils.Time2Str(utils.Str2Time(storeDetail.IDValid)),
QualifyExpireForever: 0,
})
}
globals.SugarLogger.Debug(utils.Format4Output(qualifyList, false))
if globals.EnableJdStoreWrite {
err = api.JdPageAPI.SaveQualify(storeDetail.VendorStoreID, jdapi.SaveQualifyActionTypeCommit, qualifyList)
// err = api.JdPageAPI.SaveQualify(storeDetail.VendorStoreID, jdapi.SaveQualifyActionTypeSave, qualifyList)
}
return addStoreInfo2Err(err, storeDetail.ID)
}
func (c *PurchaseHandler) UpdateStoreCustomID(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string, storeID int64) (err error) {
if globals.EnableJdStoreWrite {
err = getAPI(vendorOrgCode).UpdateStoreInfo4Open2(
&jdapi.OpStoreParams{
StationNo: vendorStoreID,
Operator: ctx.GetUserName(),
OutSystemID: utils.Int2Str(int(storeID)),
}, false)
}
return err
}