2872 lines
104 KiB
Go
2872 lines
104 KiB
Go
package cms
|
||
|
||
import (
|
||
"bytes"
|
||
"errors"
|
||
"fmt"
|
||
"io"
|
||
"math"
|
||
"mime/multipart"
|
||
"sort"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
"unicode/utf8"
|
||
|
||
"git.rosy.net.cn/jx-callback/globals/refutil"
|
||
|
||
"github.com/360EntSecGroup-Skylar/excelize"
|
||
|
||
"git.rosy.net.cn/baseapi"
|
||
"git.rosy.net.cn/jx-callback/business/authz/autils"
|
||
"git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||
|
||
"git.rosy.net.cn/baseapi/platformapi/autonavi"
|
||
"git.rosy.net.cn/baseapi/platformapi/baidunavi"
|
||
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
|
||
"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/jxutils"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/excel"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/msg"
|
||
"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/model/legacymodel"
|
||
"git.rosy.net.cn/jx-callback/business/partner"
|
||
"git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||
"git.rosy.net.cn/jx-callback/globals"
|
||
"git.rosy.net.cn/jx-callback/globals/api"
|
||
)
|
||
|
||
const (
|
||
GET_BAD_COMMENTS_TYPE = 0 //获取差评的标志
|
||
GET_ALL_COMMENTS_TYPE = 1 //获取所有评论的标志
|
||
GET_FIXED_COMMENTS_TYPE = 2 //获取已解决评论的标志
|
||
)
|
||
|
||
type StoreExt struct {
|
||
model.Store
|
||
|
||
MarketManName string `orm:"size(8)" json:"marketManName"` // 市场负责人姓名
|
||
OperatorName string `orm:"size(8)" json:"operatorName"` // 京东运营人姓名
|
||
OperatorName2 string `orm:"size(8)" json:"operatorName2"` // 美团运营人姓名
|
||
OperatorName3 string `orm:"size(8)" json:"operatorName3"` // 饿百运营人姓名
|
||
|
||
FloatLng float64 `json:"lng"`
|
||
FloatLat float64 `json:"lat"`
|
||
|
||
ProvinceCode int `json:"provinceCode"`
|
||
ProvinceName string `json:"provinceName"`
|
||
CityName string `json:"cityName"`
|
||
DistrictName string `json:"districtName"`
|
||
StoreMapStr string `json:"-"`
|
||
CourierMapStr string `json:"-"`
|
||
PayeeBankName string `json:"payeeBankName"` // 开户行名称
|
||
LinkStoreCount int `json:"linkStoreCount"`
|
||
// StoreMaps []map[string]interface{} `orm:"-"`
|
||
// CourierMaps []map[string]interface{} `orm:"-"`
|
||
StoreMaps []*model.StoreMap `json:"StoreMaps"`
|
||
CourierMaps []*model.StoreCourierMap `json:"CourierMaps"`
|
||
|
||
OrderCount int `json:"orderCount"`
|
||
}
|
||
|
||
type Store4User struct {
|
||
model.ModelIDCULD
|
||
|
||
OriginalName string `orm:"-" json:"originalName"`
|
||
Name string `orm:"size(255)" json:"name"`
|
||
OpenTime1 int16 `json:"openTime1"` // 930就表示9点半,用两个的原因是为了支持中午休息,1与2的时间段不能交叉,为0表示没有
|
||
CloseTime1 int16 `json:"closeTime1"` // 格式同上
|
||
OpenTime2 int16 `json:"openTime2"` // 格式同上
|
||
CloseTime2 int16 `json:"closeTime2"` // 格式同上
|
||
Status int `json:"status"`
|
||
CityCode int `orm:"default(0);null" json:"cityCode"` // todo ?
|
||
DistrictCode int `orm:"default(0);null" json:"districtCode"` // todo ?
|
||
Address string `orm:"size(255)" json:"address"`
|
||
Tel1 string `orm:"size(32);index" json:"tel1"`
|
||
Tel2 string `orm:"size(32);index" json:"tel2"`
|
||
Lng int `json:"-"` // 乘了10的6次方
|
||
Lat int `json:"-"` // 乘了10的6次方
|
||
DeliveryRangeType int8 `json:"-"` // 参见相关常量定义
|
||
DeliveryRange string `orm:"type(text)" json:"-"` // 如果DeliveryRangeType为DeliveryRangeTypePolygon,则为逗号分隔坐标,分号分隔的坐标点(坐标与Lng和Lat一样,都是整数),比如 121361504,31189308;121420555,31150238。否则为半径,单位为米
|
||
|
||
FloatLng float64 `json:"lng"`
|
||
FloatLat float64 `json:"lat"`
|
||
CityName string `json:"cityName"`
|
||
DistrictName string `json:"districtName"`
|
||
|
||
Distance int `json:"distance"`
|
||
WalkDistance int `json:"walkDistance"`
|
||
}
|
||
|
||
type Store4UserList []*Store4User
|
||
|
||
func (x Store4UserList) Len() int {
|
||
return len(x)
|
||
}
|
||
|
||
func (x Store4UserList) Less(i, j int) bool {
|
||
if x[i].Status != x[j].Status {
|
||
return x[i].Status > x[j].Status
|
||
}
|
||
if x[i].WalkDistance != x[j].WalkDistance {
|
||
return x[i].WalkDistance < x[j].WalkDistance
|
||
}
|
||
return x[i].Distance < x[j].Distance
|
||
}
|
||
|
||
func (x Store4UserList) Swap(i, j int) {
|
||
x[i], x[j] = x[j], x[i]
|
||
}
|
||
|
||
type StoresInfo struct {
|
||
TotalCount int `json:"totalCount"`
|
||
MapCenterLng float64 `json:"mapCenterLng"`
|
||
MapCenterLat float64 `json:"mapCenterLat"`
|
||
Stores []*StoreExt `json:"stores"`
|
||
}
|
||
|
||
type JxBadCommentsExt struct {
|
||
legacymodel.JxBadComments
|
||
StoreName string `json:"storeName"`
|
||
CityName string `json:"cityName"`
|
||
|
||
VendorOrderID2 string `orm:"column(vendor_order_id2);size(48);index" json:"vendorOrderID2"`
|
||
}
|
||
|
||
type VendorStoreExcel struct {
|
||
StoreID int `json:"门店ID"`
|
||
VendorStoreName string `json:"门店名"`
|
||
Status string `json:"营业状态"`
|
||
Tel1 string `json:"电话1"`
|
||
Tel2 string `json:"电话2"`
|
||
CityName string `json:"城市名"`
|
||
Address string `json:"地址"`
|
||
MarketManName string `json:"市场负责人"`
|
||
OperatorName string `json:"运营负责人"`
|
||
OperatorName2 string `json:"运营负责人2"`
|
||
OperatorName3 string `json:"运营负责人3"`
|
||
}
|
||
|
||
type JdStoreLevelExt struct {
|
||
Level string `json:"level`
|
||
PageNo int `json:"pageNo"`
|
||
}
|
||
|
||
var (
|
||
ErrMissingInput = errors.New("没有有效的输入参数")
|
||
ErrCanNotFindVendor = errors.New("vendorID参数不合法")
|
||
)
|
||
|
||
var (
|
||
storeKeyPropertyMap = map[string]int{
|
||
"name": 1,
|
||
"cityCode": 1,
|
||
"districtCode": 1,
|
||
"address": 1,
|
||
"tel1": 1,
|
||
"tel2": 1,
|
||
"openTime1": 1,
|
||
"closeTime1": 1,
|
||
"openTime2": 1,
|
||
"closeTime2": 1,
|
||
"lng": 1,
|
||
"lat": 1,
|
||
"deliveryRangeType": 1,
|
||
"deliveryRange": 1,
|
||
"status": 1,
|
||
"promoteInfo": 1,
|
||
}
|
||
|
||
storeMapKeyPropertyMap = map[string]int{
|
||
"status": 1,
|
||
"freightDeductionPack": 1,
|
||
"vendorStoreName": 1,
|
||
"boxFee": 1,
|
||
}
|
||
|
||
WatchVendorStoreTimeList = []string{
|
||
"8:00:00",
|
||
"10:00:00",
|
||
"11:00:00",
|
||
"15:00:00",
|
||
"20:00:00",
|
||
}
|
||
titleListStore = []string{
|
||
"门店ID",
|
||
"门店名",
|
||
"营业状态",
|
||
"电话1",
|
||
"电话2",
|
||
"城市名",
|
||
"地址",
|
||
"市场负责人",
|
||
"运营负责人",
|
||
"运营负责人2",
|
||
}
|
||
roleMap = map[string]string{
|
||
// "marketManPhone": "市场负责人电话",
|
||
// "marketManRole": "市场负责人组(角色,单人)",
|
||
"jxBrandFeeFactor": "京西品牌费因子",
|
||
"marketAddFeeFactor": "市场附加费因子",
|
||
"payeeName": "收款人姓名",
|
||
"payeeAccountNo": "收款账号",
|
||
"payeeBankBranchName": "开户支行",
|
||
"payeeBankCode": "开户行代码",
|
||
"payPercentage": "支付比例",
|
||
}
|
||
roleMoblieMap = map[string]string{
|
||
"17380734342": "17380734342", //漆云的手机 ,用于判断updatestore的权限
|
||
"18328080405": "18328080405", //肖娜娜的手机
|
||
"13350726500": "13350726500", //谭翔心
|
||
"15928865396": "15928865396", //何佳梦
|
||
"18048531223": "18048531223", //石老板
|
||
"18982250714": "18982250714", //赵敏夫
|
||
}
|
||
)
|
||
|
||
func getStoresSql(ctx *jxcontext.Context, keyword string, params map[string]interface{}, orderTimeFrom, orderTimeTo time.Time) (sql string, sqlParams []interface{}, sqlFrom string, sqlFromParams []interface{}, err error) {
|
||
sqlFrom = `
|
||
FROM store t1
|
||
LEFT JOIN new_config bank ON bank.deleted_at = ? AND bank.type = ? AND bank.key = t1.payee_bank_code
|
||
LEFT JOIN place city ON t1.city_code = city.code AND city.level = 2
|
||
LEFT JOIN place province ON province.code = city.parent_code AND province.level = 1
|
||
LEFT JOIN place district ON t1.district_code = district.code AND district.level = 3
|
||
/*
|
||
LEFT JOIN store_map m1 ON t1.id = m1.store_id AND m1.deleted_at = ?
|
||
LEFT JOIN store_courier_map m2 ON t1.id = m2.store_id AND m2.deleted_at = ?
|
||
*/
|
||
LEFT JOIN user mm ON mm.mobile <> '' AND mm.mobile = t1.market_man_phone AND mm.deleted_at = ?
|
||
LEFT JOIN user om ON om.mobile <> '' AND om.mobile = t1.operator_phone AND om.deleted_at = ?
|
||
LEFT JOIN user om2 ON om2.mobile <> '' AND om2.mobile = t1.operator_phone2 AND om2.deleted_at = ?
|
||
LEFT JOIN user om3 ON om3.mobile <> '' AND om3.mobile = t1.operator_phone3 AND om3.deleted_at = ?
|
||
`
|
||
sqlFromParams = []interface{}{
|
||
utils.DefaultTimeValue,
|
||
model.ConfigTypeBank,
|
||
// utils.DefaultTimeValue,
|
||
// utils.DefaultTimeValue,
|
||
utils.DefaultTimeValue,
|
||
utils.DefaultTimeValue,
|
||
utils.DefaultTimeValue,
|
||
utils.DefaultTimeValue,
|
||
}
|
||
sqlWhere := `
|
||
WHERE t1.deleted_at = ?
|
||
`
|
||
sqlWhereParams := []interface{}{
|
||
utils.DefaultTimeValue,
|
||
}
|
||
for mapCondKey, tableName := range map[string]string{
|
||
"vendorStoreCond": "store_map",
|
||
"courierStoreCond": "store_courier_map",
|
||
} {
|
||
if mapCond := strings.ToUpper(utils.Interface2String(params[mapCondKey])); mapCond == "AND" || mapCond == "OR" {
|
||
mapCondsStr := utils.Interface2String(params[mapCondKey+"s"])
|
||
if mapCondsStr != "" {
|
||
var vendorStoreConds map[string]interface{}
|
||
if err = utils.UnmarshalUseNumber([]byte(mapCondsStr), &vendorStoreConds); err != nil {
|
||
return "", nil, "", nil, err
|
||
}
|
||
sqlVendorStoreCond := ""
|
||
for vendor, cond2 := range vendorStoreConds {
|
||
var cond string
|
||
if condStr, ok := cond2.(string); !ok {
|
||
cond = utils.Int64ToStr(utils.ForceInterface2Int64(cond2))
|
||
} else {
|
||
cond = condStr
|
||
}
|
||
|
||
tableAlias := tableName + vendor
|
||
if cond != "0" && cond != "" {
|
||
if sqlVendorStoreCond == "" {
|
||
if mapCond == "AND" {
|
||
sqlVendorStoreCond += " AND ( 1 = 1"
|
||
} else {
|
||
sqlVendorStoreCond += " AND ( 1 = 0"
|
||
}
|
||
}
|
||
sqlFrom += "\nLEFT JOIN " + tableName + " " + tableAlias + " ON " + tableAlias + ".vendor_id = ? AND " +
|
||
tableAlias + ".store_id = t1.id AND " + tableAlias + ".deleted_at = ? AND " +
|
||
tableAlias + ".is_sync <> 0 "
|
||
sqlFromParams = append(sqlFromParams, vendor, utils.DefaultTimeValue)
|
||
if cond == "1" {
|
||
sqlVendorStoreCond += " " + mapCond + " " + tableAlias + ".id IS NOT NULL"
|
||
} else if cond == "-1" {
|
||
sqlVendorStoreCond += " " + mapCond + " " + tableAlias + ".id IS NULL"
|
||
} else {
|
||
sqlFrom += " AND " + tableAlias + ".vendor_org_code = ?"
|
||
sqlFromParams = append(sqlFromParams, cond)
|
||
sqlVendorStoreCond += " " + mapCond + " " + tableAlias + ".id IS NOT NULL"
|
||
}
|
||
}
|
||
}
|
||
if sqlVendorStoreCond != "" {
|
||
sqlWhere += sqlVendorStoreCond + ")"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if keyword != "" {
|
||
keywordLike := "%" + keyword + "%"
|
||
sqlWhere += ` AND (t1.name LIKE ? OR t1.tel1 LIKE ? OR t1.tel2 LIKE ? OR t1.operator_phone LIKE ? OR t1.operator_phone2 LIKE ? OR t1.operator_phone3 LIKE ? OR t1.market_man_phone LIKE ?
|
||
OR t1.last_operator LIKE ? OR city.name LIKE ? OR t1.address LIKE ? OR t1.printer_sn LIKE ? OR t1.licence_code LIKE ? OR t1.id_code LIKE ?`
|
||
sqlWhereParams = append(sqlWhereParams, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike,
|
||
keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike)
|
||
|
||
if keywordInt64, err2 := strconv.ParseInt(keyword, 10, 64); err2 == nil {
|
||
if true { // jxutils.IsLegalMobileNumber(keywordInt64) {
|
||
sqlWhere += ` OR (
|
||
SELECT COUNT(*)
|
||
FROM casbin_rule t11
|
||
JOIN user t12 ON t12.user_id = t11.v0 AND t12.mobile LIKE ?
|
||
WHERE t11.v1 <> '' AND (t11.v1 = CONCAT(?, t1.id) OR t11.v1 = CONCAT(?, t1.market_man_role) OR t11.v1 = CONCAT(?, t1.operator_role) OR t11.v1 = CONCAT(?, t1.operator_role2) OR t11.v1 = CONCAT(?, t1.operator_role3))
|
||
) > 0`
|
||
prefix := autils.NewRole("", 0).GetFullName()
|
||
sqlWhereParams = append(sqlWhereParams, keyword+"%", autils.NewStoreBossRole(-1).GetFullName(), prefix, prefix, prefix, prefix) // 必须要前缀,不然不能用过些会很慢
|
||
}
|
||
sqlWhere += " OR t1.id = ? OR t1.city_code = ? OR t1.district_code = ? OR t1.link_store_id = ?"
|
||
sqlWhereParams = append(sqlWhereParams, keywordInt64, keywordInt64, keywordInt64, keywordInt64)
|
||
if jxutils.GuessVendorIDFromVendorStoreID(keywordInt64) != model.VendorIDUnknown {
|
||
sqlWhere += `
|
||
OR (SELECT COUNT(*) FROM store_map tsm WHERE t1.id = tsm.store_id AND tsm.deleted_at = ? AND tsm.vendor_store_id = ?) > 0
|
||
OR (SELECT COUNT(*) FROM store_courier_map tsm WHERE t1.id = tsm.store_id AND tsm.deleted_at = ? AND tsm.vendor_store_id = ?) > 0
|
||
`
|
||
sqlWhereParams = append(sqlWhereParams, utils.DefaultTimeValue, keyword, utils.DefaultTimeValue, keyword)
|
||
}
|
||
}
|
||
sqlWhere += ")"
|
||
}
|
||
|
||
if params["storeID"] != nil || params["storeIDs"] != nil {
|
||
var storeIDs []int
|
||
if params["storeIDs"] != nil {
|
||
if err = jxutils.Strings2Objs(utils.Interface2String(params["storeIDs"]), &storeIDs); err != nil {
|
||
return "", nil, "", nil, err
|
||
}
|
||
}
|
||
if params["storeID"] != nil {
|
||
storeIDs = append(storeIDs, params["storeID"].(int))
|
||
}
|
||
if len(storeIDs) > 0 {
|
||
sqlWhere += " AND t1.id IN (" + dao.GenQuestionMarks(len(storeIDs)) + ")"
|
||
sqlWhereParams = append(sqlWhereParams, storeIDs)
|
||
}
|
||
}
|
||
if params["startStoreID"] != nil {
|
||
sqlWhere += " AND t1.id >= ?"
|
||
sqlWhereParams = append(sqlWhereParams, params["startStoreID"])
|
||
}
|
||
if params["name"] != nil {
|
||
sqlWhere += " AND t1.name LIKE ?"
|
||
sqlWhereParams = append(sqlWhereParams, "%"+params["name"].(string)+"%")
|
||
}
|
||
if params["placeID"] != nil {
|
||
level := 2
|
||
if params["placeLevel"] != nil {
|
||
level = params["placeLevel"].(int)
|
||
}
|
||
if level == 2 {
|
||
sqlWhere += " AND t1.city_code = ?"
|
||
} else {
|
||
sqlWhere += " AND t1.district_code = ?"
|
||
}
|
||
sqlWhereParams = append(sqlWhereParams, params["placeID"].(int))
|
||
}
|
||
if params["address"] != nil {
|
||
sqlWhere += " AND t1.address LIKE ?"
|
||
sqlWhereParams = append(sqlWhereParams, "%"+params["address"].(string)+"%")
|
||
}
|
||
if params["tel"] != nil {
|
||
sqlWhere += " AND (t1.tel1 LIKE ? OR t1.tel2 LIKE ?)"
|
||
sqlWhereParams = append(sqlWhereParams, "%"+params["tel"].(string)+"%")
|
||
sqlWhereParams = append(sqlWhereParams, "%"+params["tel"].(string)+"%")
|
||
}
|
||
|
||
if params["statuss"] != nil {
|
||
var statuss []int
|
||
if err = utils.UnmarshalUseNumber([]byte(params["statuss"].(string)), &statuss); err != nil {
|
||
return "", nil, "", nil, err
|
||
}
|
||
if len(statuss) > 0 {
|
||
sqlWhere += " AND t1.status IN (" + dao.GenQuestionMarks(len(statuss)) + ")"
|
||
sqlWhereParams = append(sqlWhereParams, statuss)
|
||
}
|
||
}
|
||
|
||
sql = sqlFrom + sqlWhere
|
||
sqlParams = append(sqlParams, sqlFromParams...)
|
||
sqlParams = append(sqlParams, sqlWhereParams...)
|
||
return sql, sqlParams, sqlFrom, sqlFromParams, nil
|
||
}
|
||
|
||
func setStoreMapInfo(ctx *jxcontext.Context, db *dao.DaoDB, storesInfo *StoresInfo, storeIDs []int, briefLevel int) (err error) {
|
||
storeMapList, err := dao.GetStoresMapList(db, nil, storeIDs, nil, model.StoreStatusAll, model.StoreIsSyncAll, "")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
storeCourierList, err := dao.GetStoreCourierList(db, storeIDs, model.StoreStatusAll, model.StoreAuditStatusAll)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
storeMapMap := dao.StoreMapList2Map(storeMapList)
|
||
storeCourierMap := dao.StoreCourierList2Map(storeCourierList)
|
||
|
||
for _, v := range storesInfo.Stores {
|
||
if briefLevel > 0 {
|
||
v.DeliveryRange = ""
|
||
v.IDCardFront = ""
|
||
v.IDCardBack = ""
|
||
v.IDCardHand = ""
|
||
v.Licence = ""
|
||
v.Licence2Image = ""
|
||
}
|
||
for _, v2 := range storeMapMap[v.ID] {
|
||
v.StoreMaps = append(v.StoreMaps, v2)
|
||
}
|
||
for _, v2 := range storeCourierMap[v.ID] {
|
||
v.CourierMaps = append(v.CourierMaps, v2)
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// todo 门店绑定信息可以考虑以数组形式返回,而不是现在这样
|
||
func GetStores(ctx *jxcontext.Context, keyword string, params map[string]interface{}, offset, pageSize int, orderTimeFrom, orderTimeTo time.Time, orderCountFrom, orderCountTo int) (retVal *StoresInfo, err error) {
|
||
briefLevel := int(utils.ForceInterface2Int64(params["briefLevel"]))
|
||
sql, sqlParams, _, _, err := getStoresSql(ctx, keyword, params, orderTimeFrom, orderTimeTo)
|
||
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
sql = `
|
||
SELECT
|
||
DISTINCT t1.*,
|
||
CAST(t1.lng AS DECIMAL(15,6))/1000000 float_lng,
|
||
CAST(t1.lat AS DECIMAL(15,6))/1000000 float_lat,
|
||
IF(mm.name <> '', mm.name, mm.user_id2) market_man_name,
|
||
bank.value payee_bank_name,
|
||
IF(om.name <> '', om.name, om.user_id2) operator_name,
|
||
IF(om2.name <> '', om2.name, om2.user_id2) operator_name2,
|
||
IF(om3.name <> '', om3.name, om3.user_id2) operator_name3,
|
||
province.code province_code,
|
||
province.name province_name,
|
||
city.name city_name,
|
||
district.name district_name,
|
||
(SELECT COUNT(*) FROM store t11 WHERE t11.link_store_id = t1.id) link_store_count
|
||
` + sql + `
|
||
ORDER BY t1.id DESC
|
||
`
|
||
db := dao.GetDB()
|
||
retVal = &StoresInfo{}
|
||
|
||
var storeIDs []int
|
||
var storeList []*StoreExt
|
||
offset = jxutils.FormalizePageOffset(offset)
|
||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||
mapLimit := false
|
||
// globals.SugarLogger.Debug(sql)
|
||
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
|
||
|
||
if err = dao.GetRows(db, &storeList, sql, sqlParams...); err == nil {
|
||
// 地图区域限制过滤
|
||
if mapLongitude2, ok := params["mapLongitude"].(string); ok {
|
||
var (
|
||
mapLatitude, mapLongitude float64
|
||
mapRadius int
|
||
)
|
||
mapLimit = true
|
||
mapLongitude = utils.Str2Float64(mapLongitude2)
|
||
mapLatitude = utils.Str2Float64(params["mapLatitude"].(string))
|
||
mapRadius = params["mapRadius"].(int)
|
||
for _, v := range storeList {
|
||
valid := !mapLimit
|
||
if mapLimit {
|
||
valid = jxutils.EarthDistance(mapLongitude, mapLatitude, v.FloatLng, v.FloatLat)*1000 <= float64(mapRadius)
|
||
}
|
||
if valid {
|
||
retVal.Stores = append(retVal.Stores, v)
|
||
}
|
||
}
|
||
} else {
|
||
retVal.Stores = storeList
|
||
}
|
||
|
||
// 订单情况过滤
|
||
storeList, err = filterStoreByOrderInfo(db, retVal.Stores, orderTimeFrom, orderTimeTo, orderCountFrom, orderCountTo)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 分页
|
||
retVal.TotalCount = len(storeList)
|
||
retVal.Stores = nil
|
||
for i := offset; i < offset+pageSize && i < len(storeList); i++ {
|
||
storeIDs = append(storeIDs, storeList[i].ID)
|
||
retVal.Stores = append(retVal.Stores, storeList[i])
|
||
}
|
||
if len(storeIDs) == 0 {
|
||
return retVal, nil
|
||
}
|
||
|
||
// 导出门店地图标信息时,可能会需要转换门店坐标
|
||
needConver2Baidu := int(utils.Interface2Int64WithDefault(params["coordinateType"], 0)) == model.CoordinateTypeBaiDu
|
||
if needConver2Baidu {
|
||
task := tasksch.NewParallelTask("坐标转换", tasksch.NewParallelConfig().SetParallelCount(4).SetBatchSize(autonavi.MaxConvertCount), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
var coords []*baidunavi.Coordinate
|
||
for _, v := range batchItemList {
|
||
store := v.(*StoreExt)
|
||
coords = append(coords, &baidunavi.Coordinate{
|
||
Lng: store.FloatLng,
|
||
Lat: store.FloatLat,
|
||
})
|
||
}
|
||
coords, err = api.BaiDuNaviAPI.BatchCoordinateConvert(coords, baidunavi.CoordSysGCJ02, baidunavi.CoordSysBaiDu)
|
||
if err == nil {
|
||
for k, v := range batchItemList {
|
||
store := v.(*StoreExt)
|
||
coord := coords[k]
|
||
store.FloatLng = coord.Lng
|
||
store.FloatLat = coord.Lat
|
||
}
|
||
}
|
||
return retVal, err
|
||
}, retVal.Stores)
|
||
task.Run()
|
||
task.GetResult(0)
|
||
}
|
||
} else {
|
||
return nil, err
|
||
}
|
||
|
||
if len(retVal.Stores) > 0 {
|
||
setStoreMapInfo(ctx, db, retVal, storeIDs, briefLevel)
|
||
retVal.MapCenterLng, retVal.MapCenterLat = getMapCenter(retVal.Stores)
|
||
}
|
||
return retVal, err
|
||
}
|
||
|
||
func filterStoreByOrderInfo(db *dao.DaoDB, inStores []*StoreExt, orderTimeFrom, orderTimeTo time.Time, orderCountFrom, orderCountTo int) (outStores []*StoreExt, err error) {
|
||
if len(inStores) > 0 && !utils.IsTimeZero(orderTimeFrom) {
|
||
storeIDs := make([]int, len(inStores))
|
||
for k, v := range inStores {
|
||
storeIDs[k] = v.ID
|
||
}
|
||
orderSaleList, err2 := dao.GetStoresOrderSaleInfo(dao.GetDB(), storeIDs, orderTimeFrom, orderTimeTo, []int{model.OrderStatusFinished})
|
||
if err = err2; err != nil {
|
||
return nil, err
|
||
}
|
||
storeOrderCountMap := make(map[int]int)
|
||
for _, v := range orderSaleList {
|
||
storeOrderCountMap[v.StoreID] += v.Count
|
||
}
|
||
|
||
for _, v := range inStores {
|
||
orderCount := storeOrderCountMap[v.ID]
|
||
if orderCount >= orderCountFrom && orderCount <= orderCountTo {
|
||
v.OrderCount = orderCount
|
||
outStores = append(outStores, v)
|
||
}
|
||
}
|
||
} else {
|
||
outStores = inStores
|
||
}
|
||
return outStores, err
|
||
}
|
||
|
||
func getMapCenter(storeList []*StoreExt) (lng, lat float64) {
|
||
globals.SugarLogger.Debugf("getMapCenter len(storeList):%d", len(storeList))
|
||
if len(storeList) == 0 {
|
||
return 0, 0
|
||
}
|
||
|
||
lngAvg := float64(0)
|
||
latAvg := float64(0)
|
||
storeListLenFloat := float64(len(storeList))
|
||
for _, store := range storeList {
|
||
lngAvg += store.FloatLng
|
||
latAvg += store.FloatLat
|
||
}
|
||
lngAvg = lngAvg / storeListLenFloat
|
||
latAvg = latAvg / storeListLenFloat
|
||
|
||
distAvg := float64(0)
|
||
for _, store := range storeList {
|
||
distAvg += math.Sqrt((store.FloatLng-lngAvg)*(store.FloatLng-lngAvg) + (store.FloatLat-latAvg)*(store.FloatLat-latAvg))
|
||
}
|
||
distAvg = (distAvg / storeListLenFloat)
|
||
maxDist := distAvg * 5
|
||
newStoreList := []*StoreExt{}
|
||
for _, store := range storeList {
|
||
dist := math.Sqrt((store.FloatLng-lngAvg)*(store.FloatLng-lngAvg) + (store.FloatLat-latAvg)*(store.FloatLat-latAvg))
|
||
if dist <= maxDist {
|
||
lng += store.FloatLng
|
||
lat += store.FloatLat
|
||
newStoreList = append(newStoreList, store)
|
||
}
|
||
}
|
||
if len(newStoreList) == len(storeList) {
|
||
lng = lng / float64(len(newStoreList))
|
||
lat = lat / float64(len(newStoreList))
|
||
// for _, store := range storeList {
|
||
// globals.SugarLogger.Debugf("store:%s, lng:%f, lat:%f", store.Name, store.FloatLng, store.FloatLat)
|
||
// }
|
||
// globals.SugarLogger.Debugf("lng:%f, lat:%f", lng, lat)
|
||
return lng, lat
|
||
}
|
||
return getMapCenter(newStoreList)
|
||
}
|
||
|
||
func GetVendorStore(ctx *jxcontext.Context, vendorID int, vendorOrgCode, vendorStoreID string) (retVal *StoreExt, err error) {
|
||
if handler := CurVendorSync.GetStoreHandler(vendorID); handler != nil {
|
||
result, err2 := handler.ReadStore(ctx, vendorOrgCode, vendorStoreID)
|
||
if err = err2; err == nil {
|
||
retVal = &StoreExt{
|
||
Store: result.Store,
|
||
FloatLng: jxutils.IntCoordinate2Standard(result.Lng),
|
||
FloatLat: jxutils.IntCoordinate2Standard(result.Lat),
|
||
}
|
||
db := dao.GetDB()
|
||
if city, err2 := dao.GetPlaceByCode(db, result.CityCode); err2 == nil {
|
||
retVal.CityName = city.Name
|
||
}
|
||
if district, err2 := dao.GetPlaceByCode(db, result.DistrictCode); err2 == nil {
|
||
retVal.DistrictName = district.Name
|
||
}
|
||
if !jxutils.IsLegalStoreID(retVal.ID) {
|
||
retVal.ID = 0
|
||
}
|
||
return retVal, nil
|
||
}
|
||
return nil, err
|
||
}
|
||
return nil, ErrCanNotFindVendor
|
||
}
|
||
|
||
func isUpdateStoreNeedSync(valid map[string]interface{}) bool {
|
||
for k := range valid {
|
||
if storeKeyPropertyMap[k] == 1 {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
func checkBankBranch(payeeBankBranchName string) (err error) {
|
||
if payeeBankBranchName != "" {
|
||
if strings.Index(payeeBankBranchName, "支行") == -1 && strings.Index(payeeBankBranchName, "分行") == -1 {
|
||
err = fmt.Errorf("支行信息异常,你可能没有在使用最新的版本,请强制刷新浏览器或联系开发")
|
||
}
|
||
}
|
||
return err
|
||
}
|
||
|
||
func checkCreateStore(store *model.Store) (err error) {
|
||
if store.Lng == 0 || store.Lat == 0 || store.Address == "" {
|
||
err = fmt.Errorf("必须设置地址信息")
|
||
}
|
||
return err
|
||
}
|
||
|
||
func checkStoreDeliveryRange(deliveryRange string) (err error) {
|
||
if deliveryRange != "" {
|
||
points := jxutils.CoordinateStr2Points(deliveryRange)
|
||
for _, point := range points {
|
||
for _, coord := range point {
|
||
if coord == 0 || math.IsNaN(coord) {
|
||
return fmt.Errorf("坐标点数据非法:%s", deliveryRange)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return err
|
||
}
|
||
|
||
func UpdateStore(ctx *jxcontext.Context, storeID int, payload map[string]interface{}, userName string) (num int64, err error) {
|
||
globals.SugarLogger.Debugf("UpdateStore storeID:%d, payload:%s", storeID, utils.Format4Output(payload, true))
|
||
if err = checkBankBranch(utils.Interface2String(payload["payeeBankBranchName"])); err != nil {
|
||
return 0, err
|
||
}
|
||
db := dao.GetDB()
|
||
store := &model.Store{}
|
||
store.ID = storeID
|
||
if err = dao.GetEntity(db, store); err != nil {
|
||
return 0, err
|
||
}
|
||
var outStore *model.Store
|
||
var beforStore = *store
|
||
if payload["autoEnableAt"] != nil {
|
||
payload["autoEnableAt"] = utils.Time2Date(utils.Str2Time(utils.Interface2String(payload["autoEnableAt"])))
|
||
}
|
||
valid := dao.StrictMakeMapByStructObject2(payload, store, &outStore, userName)
|
||
if err = checkStoreDeliveryRange(utils.Interface2String(valid["deliveryRange"])); err != nil {
|
||
return 0, err
|
||
}
|
||
if globals.EnableWXAuth2 {
|
||
if err = dao.ValidateRoles(db, utils.Interface2String(valid["marketManRole"]), utils.Interface2String(valid["operatorRole"]), utils.Interface2String(valid["operatorRole2"])); err != nil {
|
||
return 0, err
|
||
}
|
||
}
|
||
if payload["lng"] != nil || payload["lat"] != nil {
|
||
intLng := jxutils.StandardCoordinate2Int(utils.Interface2Float64WithDefault(payload["lng"], 0.0))
|
||
intLat := jxutils.StandardCoordinate2Int(utils.Interface2Float64WithDefault(payload["lat"], 0.0))
|
||
if intLng != 0 && intLng != store.Lng {
|
||
valid["lng"] = intLng
|
||
}
|
||
if intLat != 0 && intLat != store.Lng {
|
||
valid["lat"] = intLat
|
||
}
|
||
}
|
||
|
||
if valid["originalName"] != nil {
|
||
delete(valid, "originalName")
|
||
}
|
||
if valid["printerBindInfo"] != nil {
|
||
delete(valid, "printerBindInfo")
|
||
}
|
||
syncStatus := model.SyncFlagModifiedMask
|
||
if valid["name"] != nil {
|
||
valid["name"] = jxutils.FormalizeName(valid["name"].(string))
|
||
store.Name = valid["name"].(string)
|
||
syncStatus |= model.SyncFlagStoreName
|
||
}
|
||
// globals.SugarLogger.Debug(utils.Format4Output(valid, false))
|
||
printerVendorID := int(utils.Interface2Int64WithDefault(valid["printerVendorID"], 0))
|
||
if printerVendorID == 0 {
|
||
printerVendorID = store.PrinterVendorID
|
||
}
|
||
if printerVendorID == model.VendorIDXiaoWM {
|
||
delete(valid, "printerKey")
|
||
}
|
||
// 网络打印机处理
|
||
if valid["printerVendorID"] != nil || valid["printerSN"] != nil || valid["printerKey"] != nil {
|
||
if valid["printerVendorID"] == nil {
|
||
valid["printerVendorID"] = store.PrinterVendorID
|
||
}
|
||
if printerVendorID := int(utils.Interface2Int64WithDefault(valid["printerVendorID"], 0)); printerVendorID > 0 {
|
||
handler := partner.GetPrinterPlatformFromVendorID(printerVendorID)
|
||
if handler == nil {
|
||
return 0, fmt.Errorf("不支持的打印机厂商ID:%d", printerVendorID)
|
||
}
|
||
if valid["printerSN"] == nil {
|
||
valid["printerSN"] = store.PrinterSN
|
||
}
|
||
if valid["printerKey"] == nil {
|
||
valid["printerKey"] = store.PrinterKey
|
||
}
|
||
newID1, newID2, err2 := handler.RegisterPrinter(ctx, valid["printerSN"].(string), valid["printerKey"].(string), store.Name)
|
||
if err = err2; err != nil {
|
||
return 0, err
|
||
}
|
||
handler.EmptyPrintList(ctx, newID1, newID2)
|
||
if newID1 != "" {
|
||
valid["printerSN"] = newID1
|
||
}
|
||
if newID2 != "" {
|
||
valid["printerKey"] = newID2
|
||
}
|
||
} else {
|
||
valid["printerVendorID"] = 0
|
||
valid["printerSN"] = ""
|
||
valid["printerKey"] = ""
|
||
}
|
||
valid["printerBindInfo"] = ""
|
||
if handler := partner.GetPrinterPlatformFromVendorID(store.PrinterVendorID); handler != nil {
|
||
handler.UnregisterPrinter(ctx, store.PrinterSN, store.PrinterKey)
|
||
}
|
||
}
|
||
if valid["linkStoreID"] != nil {
|
||
linkStoreID := int(utils.Interface2Int64WithDefault(valid["linkStoreID"], 0))
|
||
linkStoreID, err = dao.GetRealLinkStoreID(db, linkStoreID)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
if err = checkStoreHaveLinkedStore(storeID, linkStoreID); err != nil {
|
||
return 0, err
|
||
}
|
||
valid["linkStoreID"] = linkStoreID
|
||
// globals.SugarLogger.Debug(linkStoreID)
|
||
}
|
||
|
||
// globals.SugarLogger.Debug(utils.Format4Output(valid, false))
|
||
for _, v := range []string{
|
||
"lng",
|
||
"lat",
|
||
"cityCode",
|
||
"address",
|
||
"deliveryRange",
|
||
} {
|
||
if valid[v] != nil {
|
||
syncStatus |= model.SyncFlagStoreAddress
|
||
break
|
||
}
|
||
}
|
||
status := 0
|
||
if valid["status"] != nil || valid["autoEnableAt"] != nil {
|
||
if valid["status"] != nil {
|
||
syncStatus |= model.SyncFlagStoreStatus
|
||
status = int(utils.Interface2Int64WithDefault(valid["status"], 0))
|
||
if status == model.StoreStatusDisabled {
|
||
valid["deliveryRangeType"] = model.DeliveryRangeTypeRadius
|
||
valid["deliveryRange"] = "1"
|
||
}
|
||
} else {
|
||
status = store.Status
|
||
}
|
||
|
||
if status != model.StoreStatusClosed && status != model.StoreStatusHaveRest {
|
||
valid["autoEnableAt"] = nil
|
||
} else {
|
||
if valid["autoEnableAt"] != nil {
|
||
status = model.StoreStatusHaveRest
|
||
} else {
|
||
status = model.StoreStatusClosed
|
||
valid["autoEnableAt"] = nil
|
||
}
|
||
valid["status"] = status
|
||
}
|
||
}
|
||
|
||
if valid["deliveryRange"] != nil {
|
||
valid["deliveryRange"] = strings.Trim(valid["deliveryRange"].(string), ";")
|
||
}
|
||
|
||
//时间校验
|
||
if outStore != nil {
|
||
if outStore.OpenTime1 != 0 && outStore.CloseTime1 != 0 {
|
||
if err := ValidateStructPartial(outStore, "OpenTime1", "CloseTime1"); err != nil {
|
||
return 0, errors.New(fmt.Sprintf("门店营业时间1设置不合法!时间范围1 :[%v] 至 [%v]", outStore.OpenTime1, outStore.CloseTime1))
|
||
}
|
||
}
|
||
if (outStore.OpenTime1 == 0 && outStore.CloseTime1 != 0) || (outStore.OpenTime1 != 0 && outStore.CloseTime1 == 0) {
|
||
return 0, errors.New(fmt.Sprintf("门店营业时间1设置不合法!时间范围1 :[%v] 至 [%v]", outStore.OpenTime1, outStore.CloseTime1))
|
||
}
|
||
if outStore.OpenTime2 != 0 && outStore.CloseTime2 != 0 {
|
||
if err := ValidateStructPartial(outStore, "OpenTime2", "CloseTime2"); err != nil {
|
||
return 0, errors.New(fmt.Sprintf("门店营业时间2设置不合法!时间范围2 :[%v] 至 [%v]", outStore.OpenTime2, outStore.CloseTime2))
|
||
}
|
||
}
|
||
if (outStore.OpenTime2 == 0 && outStore.CloseTime2 != 0) || (outStore.OpenTime2 != 0 && outStore.CloseTime2 == 0) {
|
||
return 0, errors.New(fmt.Sprintf("门店营业时间2设置不合法!时间范围2 :[%v] 至 [%v]", outStore.OpenTime1, outStore.CloseTime1))
|
||
}
|
||
if outStore.OpenTime1 != 0 && outStore.CloseTime1 != 0 && outStore.OpenTime2 != 0 && outStore.CloseTime2 != 0 {
|
||
if outStore.OpenTime2 < outStore.CloseTime1 {
|
||
return 0, errors.New(fmt.Sprintf("门店营业时间设置不合法!第二段营业时间应该在第一段营业时间之后!"))
|
||
}
|
||
}
|
||
if beginAt, endAt := GetTimeMixByInt(outStore.OpenTime1, outStore.CloseTime1, outStore.OpenTime2, outStore.CloseTime2); beginAt != 0 && endAt != 0 {
|
||
return 0, errors.New(fmt.Sprintf("两段门店营业时间不可交叉!时间范围1 :[%v] 至 [%v], 时间范围2 :[%v] 至 [%v]", outStore.OpenTime1, outStore.CloseTime1, outStore.OpenTime2, outStore.CloseTime2))
|
||
}
|
||
}
|
||
|
||
if valid["promoteInfo"] != nil {
|
||
valid["promoteInfo"] = strings.ReplaceAll(valid["promoteInfo"].(string), "{phone}", store.Tel1)
|
||
}
|
||
|
||
for k, _ := range valid {
|
||
if roleMap[k] != "" {
|
||
if authInfo, err := ctx.GetV2AuthInfo(); err == nil {
|
||
if roleMoblieMap[authInfo.Mobile] == "" {
|
||
return 0, errors.New(fmt.Sprintf("当前用户 [%v] 无权限修改 [%v] 字段!", authInfo.Name, roleMap[k]))
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// districtCode := 0
|
||
// if valid["districtCode"] != nil {
|
||
// districtCode = int(utils.MustInterface2Int64(valid["districtCode"]))
|
||
// }
|
||
// if districtCode == 0 && store.DistrictCode == 0 {
|
||
// if lng == 0 {
|
||
// lng = jxutils.IntCoordinate2Standard(store.Lng)
|
||
// lat = jxutils.IntCoordinate2Standard(store.Lat)
|
||
// }
|
||
// valid["districtCode"] = api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat)
|
||
// }
|
||
globals.SugarLogger.Debugf("UpdateStore track:%s, storeID:%d, valid:%s", ctx.GetTrackInfo(), storeID, utils.Format4Output(valid, true))
|
||
if len(valid) > 0 {
|
||
if globals.IsAddEvent {
|
||
mapBefore := refutil.FindMapAndStructMixed(valid, beforStore)
|
||
err = AddEventDetail(db, ctx, model.OperateUpdate, storeID, model.ThingTypeStore, storeID, BuildDiffData(mapBefore), BuildDiffData(valid))
|
||
}
|
||
dao.Begin(db)
|
||
defer func() {
|
||
dao.Rollback(db)
|
||
}()
|
||
if num, err = dao.UpdateEntityLogically(db, store, valid, userName, nil); err == nil && num == 1 {
|
||
if isUpdateStoreNeedSync(valid) {
|
||
dummy := &model.StoreMap{}
|
||
kv := make(map[string]interface{})
|
||
if valid["status"] != nil {
|
||
if syncStatus&model.SyncFlagStoreStatus != 0 && status == model.StoreStatusOpened {
|
||
kv[model.FieldStatus] = status
|
||
}
|
||
}
|
||
_, err2 := dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, dummy, kv, userName, map[string]interface{}{
|
||
model.FieldStoreID: store.ID,
|
||
}, model.FieldSyncStatus, syncStatus)
|
||
if err = err2; err == nil {
|
||
dao.Commit(db)
|
||
globals.SugarLogger.Debugf("UpdateStore track:%s, before call SyncStore", ctx.GetTrackInfo())
|
||
_, err = CurVendorSync.SyncStore(ctx, db, -1, store.ID, false, userName)
|
||
if valid["tel1"] != nil || valid["tel2"] != nil {
|
||
TryAddStoreBossRole4StoreByMobile(ctx, store.ID, []string{utils.Interface2String(valid["tel1"]), utils.Interface2String(valid["tel2"])})
|
||
}
|
||
if syncStatus&model.SyncFlagStoreAddress != 0 || valid["tel1"] != nil || valid["payeeName"] != nil {
|
||
updateCourierStores(ctx, storeID)
|
||
}
|
||
}
|
||
} else {
|
||
dao.Commit(db)
|
||
}
|
||
notifyStoreOperatorChanged(store.ID, "京东运营", store.OperatorPhone, valid["operatorPhone"])
|
||
notifyStoreOperatorChanged(store.ID, "美团运营", store.OperatorPhone2, valid["operatorPhone2"])
|
||
notifyStoreOperatorChanged(store.ID, "饿百运营", store.OperatorPhone3, valid["operatorPhone3"])
|
||
notifyStoreOperatorChanged(store.ID, "市场", store.MarketManPhone, valid["marketManPhone"])
|
||
if err == nil {
|
||
if valid["openTime1"] != 0 || valid["closeTime1"] != 0 || valid["openTime2"] != 0 || valid["closeTime2"] != 0 {
|
||
err = CurVendorSync.ChangeStoreSkuSaleStatus(ctx, storeID, true, true)
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
globals.SugarLogger.Debugf("UpdateStore track:%s, store:%s", ctx.GetTrackInfo(), utils.Format4Output(store, true))
|
||
}
|
||
return num, err
|
||
}
|
||
|
||
func notifyStoreOperatorChanged(storeID int, operatorRoleName, phone string, newPhone interface{}) {
|
||
if phone != "" && newPhone != nil {
|
||
db := dao.GetDB()
|
||
if user, err := dao.GetUserByID(db, "mobile", phone); err == nil {
|
||
curUserName := ""
|
||
if newOperator := utils.Interface2String(newPhone); newOperator != "" {
|
||
if curUser, err := dao.GetUserByID(db, "mobile", newOperator); err == nil {
|
||
curUserName = curUser.GetName()
|
||
}
|
||
}
|
||
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.GetID(), fmt.Sprintf("门店%s变更", operatorRoleName), fmt.Sprintf("门店:%d,原%s:%s,变更为:%s", storeID, operatorRoleName, user.GetName(), curUserName))
|
||
}
|
||
}
|
||
}
|
||
|
||
func SetStoreStatus(ctx *jxcontext.Context, storeID, status int) (err error) {
|
||
payload := map[string]interface{}{
|
||
"status": status,
|
||
}
|
||
_, err = UpdateStore(ctx, storeID, payload, ctx.GetUserName())
|
||
return err
|
||
}
|
||
|
||
func EnableHaveRestStores(ctx *jxcontext.Context, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||
storeInfo, err := GetStores(ctx, "", map[string]interface{}{
|
||
"statuss": string(utils.MustMarshal([]int{model.StoreStatusHaveRest})),
|
||
}, 0, model.UnlimitedPageSize, utils.DefaultTimeValue, utils.DefaultTimeValue, 0, 0)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
if len(storeInfo.Stores) == 0 {
|
||
return "0", nil
|
||
}
|
||
|
||
task := tasksch.NewParallelTask("EnableHaveRestStores", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
store := batchItemList[0].(*StoreExt)
|
||
var autoEnableAt time.Time
|
||
if store.AutoEnableAt != nil {
|
||
autoEnableAt = *store.AutoEnableAt
|
||
} else {
|
||
autoEnableAt = utils.Time2Date(time.Now().Add(12 * time.Hour)) // 临时休息,但没有设置恢复营业时间,缺省是第二天
|
||
}
|
||
if time.Now().Sub(autoEnableAt) >= -2*time.Hour {
|
||
err = SetStoreStatus(ctx, store.ID, model.StoreStatusOpened)
|
||
}
|
||
return nil, err
|
||
}, storeInfo.Stores)
|
||
tasksch.ManageTask(task).Run()
|
||
if !isAsync {
|
||
if _, err = task.GetResult(0); err == nil {
|
||
hint = utils.Int2Str(len(storeInfo.Stores))
|
||
}
|
||
} else {
|
||
hint = task.GetID()
|
||
}
|
||
return hint, err
|
||
}
|
||
|
||
func checkStoreHaveLinkedStore(storeID, linkStoreID int) (err error) {
|
||
if linkStoreID != 0 {
|
||
if storeID == linkStoreID {
|
||
err = fmt.Errorf("不能自我关联")
|
||
} else {
|
||
storeList, err2 := dao.GetStoreLinkStores(dao.GetDB(), storeID)
|
||
if err = err2; err == nil {
|
||
if len(storeList) > 0 {
|
||
var storeInfo []string
|
||
for _, v := range storeList {
|
||
storeInfo = append(storeInfo, utils.Int2Str(v.ID))
|
||
}
|
||
err = fmt.Errorf("门店%d已经被其它门店(%s)关联,不能再关联至其它门店", storeID, strings.Join(storeInfo, ","))
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return err
|
||
}
|
||
|
||
func CreateStore(ctx *jxcontext.Context, storeExt *StoreExt, userName string) (id int, err error) {
|
||
globals.SugarLogger.Debugf("CreateStore storeExt:%s", utils.Format4Output(storeExt, false))
|
||
if err = checkBankBranch(storeExt.PayeeBankBranchName); err != nil {
|
||
return 0, err
|
||
}
|
||
store := &storeExt.Store
|
||
if store.ID != 0 && !jxutils.IsLegalStoreID(store.ID) {
|
||
return 0, fmt.Errorf("ID:%d不是合法的京西门店编号", store.ID)
|
||
}
|
||
db := dao.GetDB()
|
||
if globals.EnableWXAuth2 {
|
||
if err = dao.ValidateRoles(db, store.MarketManRole, store.OperatorRole, store.OperatorRole2, store.OperatorRole3); err != nil {
|
||
return 0, err
|
||
}
|
||
}
|
||
realLinkStoreID, err := dao.GetRealLinkStoreID(db, storeExt.LinkStoreID)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
if err = checkStoreHaveLinkedStore(storeExt.ID, realLinkStoreID); err != nil {
|
||
return 0, err
|
||
}
|
||
storeExt.LinkStoreID = realLinkStoreID
|
||
|
||
existingID := store.ID
|
||
store.Lng = jxutils.StandardCoordinate2Int(storeExt.FloatLng)
|
||
store.Lat = jxutils.StandardCoordinate2Int(storeExt.FloatLat)
|
||
if err = checkCreateStore(&storeExt.Store); err != nil {
|
||
return 0, err
|
||
}
|
||
store.Name = jxutils.FormalizeName(store.Name)
|
||
store.DeliveryRange = strings.Trim(store.DeliveryRange, ";")
|
||
if store.PrinterSN != "" {
|
||
handler := partner.GetPrinterPlatformFromVendorID(store.PrinterVendorID)
|
||
if handler == nil {
|
||
return 0, fmt.Errorf("不支持的打印机厂商ID:%d", store.PrinterVendorID)
|
||
}
|
||
newID1, newID2, err2 := handler.RegisterPrinter(ctx, store.PrinterSN, store.PrinterKey, store.Name)
|
||
if err = err2; err != nil {
|
||
return 0, err
|
||
}
|
||
handler.EmptyPrintList(ctx, newID1, newID2)
|
||
if newID1 != "" {
|
||
store.PrinterSN = newID1
|
||
}
|
||
if newID2 != "" {
|
||
store.PrinterKey = newID2
|
||
}
|
||
}
|
||
dao.WrapAddIDCULDEntity(store, userName)
|
||
store.ID = existingID
|
||
if err = dao.CreateEntity(db, store); err == nil {
|
||
if globals.IsAddEvent {
|
||
err = AddEventDetail(db, ctx, model.OperateAdd, store.ID, model.ThingTypeStore, store.ID, "", "")
|
||
}
|
||
UpdateOrCreateCourierStores(ctx, store.ID, false, false, false)
|
||
TryAddStoreBossRole4StoreByMobile(ctx, storeExt.ID, []string{storeExt.Tel1, storeExt.Tel2})
|
||
return store.ID, err
|
||
}
|
||
return 0, err
|
||
}
|
||
|
||
func GetStoreVendorMaps(ctx *jxcontext.Context, db *dao.DaoDB, storeID int, vendorID int) (storeMaps []*model.StoreMap, err error) {
|
||
cond := map[string]interface{}{
|
||
model.FieldStoreID: storeID,
|
||
}
|
||
if vendorID != -1 {
|
||
cond[model.FieldVendorID] = vendorID
|
||
}
|
||
return storeMaps, dao.GetEntitiesByKV(db, &storeMaps, cond, false)
|
||
}
|
||
|
||
// todo 需要对字段做有效性检查
|
||
func AddStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, vendorID int, vendorOrgCode string, storeID int, storeMap *model.StoreMap) (outStoreMap *model.StoreMap, err error) {
|
||
if storeID == 0 {
|
||
return nil, fmt.Errorf("storeID不能为0")
|
||
}
|
||
if vendorID != model.VendorIDJD && (storeMap.AutoPickup == 0) {
|
||
return nil, fmt.Errorf("非京东平台要求必须自动拣货")
|
||
}
|
||
userName := ctx.GetUserName()
|
||
storeMap.StoreID = storeID
|
||
storeMap.VendorID = vendorID
|
||
storeMap.VendorOrgCode = vendorOrgCode
|
||
storeMap.Status = model.StoreStatusOpened
|
||
storeMap.DeliveryType = model.StoreDeliveryTypeByStore
|
||
storeMap.SyncStatus = 0
|
||
if vendorID != model.VendorIDJX {
|
||
if storeMap.VendorOrgCode == "" {
|
||
return nil, fmt.Errorf("必须指定平台分账号信息")
|
||
}
|
||
if handler := CurVendorSync.GetStoreHandler(vendorID); handler != nil {
|
||
store, err2 := handler.ReadStore(ctx, vendorOrgCode, storeMap.VendorStoreID)
|
||
if err = err2; err == nil || storeMap.IsSync == 0 {
|
||
if store != nil {
|
||
storeMap.DeliveryType = store.DeliveryType
|
||
storeMap.Status = store.Status
|
||
}
|
||
err = nil
|
||
storeMap.SyncStatus = model.SyncFlagModifiedMask | model.SyncFlagStoreName | model.SyncFlagStoreAddress // 新增绑定门店是修改的概念
|
||
}
|
||
} else {
|
||
err = ErrCanNotFindVendor
|
||
}
|
||
} else {
|
||
ReCalculateJxPriceLight(db, ctx, storeID)
|
||
}
|
||
if err == nil {
|
||
dao.WrapAddIDCULDEntity(storeMap, userName)
|
||
if db == nil {
|
||
db = dao.GetDB()
|
||
}
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
dao.Rollback(db)
|
||
panic(r)
|
||
}
|
||
}()
|
||
if err = dao.CreateEntity(db, storeMap); err == nil {
|
||
if globals.IsAddEvent {
|
||
err = AddEventDetail(db, ctx, model.OperateAdd, vendorID, model.ThingTypeStore, storeID, "", `{"VendorID":`+utils.Int2Str(vendorID)+`}`)
|
||
}
|
||
dao.Commit(db)
|
||
outStoreMap = storeMap
|
||
_, err = CurVendorSync.SyncStore(ctx, db, storeMap.VendorID, storeID, false, userName)
|
||
} else {
|
||
dao.Rollback(db)
|
||
}
|
||
}
|
||
return outStoreMap, err
|
||
}
|
||
|
||
func DeleteStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, userName string) (num int64, err error) {
|
||
if db == nil {
|
||
db = dao.GetDB()
|
||
}
|
||
storeMap := &model.StoreMap{
|
||
StoreID: storeID,
|
||
VendorID: vendorID,
|
||
}
|
||
storeMap.DeletedAt = utils.DefaultTimeValue
|
||
if err = dao.GetEntity(db, storeMap, model.FieldStoreID, model.FieldVendorID, model.FieldDeletedAt); err == nil {
|
||
if handler := partner.GetPurchasePlatformFromVendorID(vendorID); handler != nil {
|
||
handler.UpdateStoreCustomID(ctx, storeMap.VendorOrgCode, storeMap.VendorStoreID, utils.Str2Int64WithDefault(storeMap.VendorStoreID, 0))
|
||
}
|
||
num, err = dao.DeleteEntityLogically(db, storeMap, map[string]interface{}{
|
||
model.FieldStatus: model.StoreStatusDisabled,
|
||
}, userName, nil)
|
||
if globals.IsAddEvent {
|
||
err = AddEventDetail(db, ctx, model.OperateDelete, vendorID, model.ThingTypeStore, storeID, "", `{"VendorID":`+utils.Int2Str(vendorID)+`}`)
|
||
}
|
||
}
|
||
return num, err
|
||
}
|
||
|
||
func isStoreMapNeedSync(vendorID int, valid map[string]interface{}) bool {
|
||
if vendorID != model.VendorIDJX {
|
||
for k := range valid {
|
||
if storeMapKeyPropertyMap[k] == 1 {
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
func UpdateStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, payload map[string]interface{}, userName string) (num int64, err error) {
|
||
if vendorID != model.VendorIDJD {
|
||
if autoPickup, ok := payload["autoPickup"]; ok && autoPickup == 0 {
|
||
return 0, fmt.Errorf("非京东平台要求必须自动拣货")
|
||
}
|
||
}
|
||
var storeHandler partner.IPurchasePlatformHandler
|
||
if vendorID != model.VendorIDJX {
|
||
storeHandler = CurVendorSync.GetStoreHandler(vendorID)
|
||
if storeHandler == nil {
|
||
return 0, ErrCanNotFindVendor
|
||
}
|
||
}
|
||
// 暂时不开放isSync
|
||
if isSync, ok := payload["isSync"].(int); ok && isSync == 0 {
|
||
delete(payload, "isSync")
|
||
}
|
||
if db == nil {
|
||
db = dao.GetDB()
|
||
}
|
||
storeMap := &model.StoreMap{
|
||
StoreID: storeID,
|
||
VendorID: vendorID,
|
||
}
|
||
storeMap.DeletedAt = utils.DefaultTimeValue
|
||
if err = dao.GetEntity(db, storeMap, model.FieldStoreID, model.FieldVendorID, model.FieldDeletedAt); err != nil {
|
||
return 0, err
|
||
}
|
||
var beforeStoreMap = *storeMap
|
||
syncStatus := model.SyncFlagModifiedMask
|
||
valid := dao.StrictMakeMapByStructObject(payload, storeMap, userName)
|
||
if valid["status"] != nil {
|
||
syncStatus |= model.SyncFlagStoreStatus
|
||
}
|
||
if vendorStoreName, ok := valid["vendorStoreName"].(string); ok {
|
||
if utf8.RuneCountInString(vendorStoreName) > jdapi.MaxStoreNameLen && vendorID == model.VendorIDJD {
|
||
return 0, fmt.Errorf("门店名称不允许超过13位!")
|
||
}
|
||
syncStatus |= model.SyncFlagStoreName
|
||
}
|
||
for _, v := range [][]string{
|
||
[]string{
|
||
"pricePercentagePack",
|
||
model.ConfigTypePricePack,
|
||
},
|
||
[]string{
|
||
"freightDeductionPack",
|
||
model.ConfigTypeFreightPack,
|
||
},
|
||
} {
|
||
if valid[v[0]] != nil {
|
||
if value := utils.Interface2String(valid[v[0]]); value != "" {
|
||
_, err2 := dao.QueryConfigs(db, value, v[1], "")
|
||
if err = err2; err != nil {
|
||
return 0, err
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if vendorID != model.VendorIDJX {
|
||
if vendorStoreID := utils.Interface2String(valid["vendorStoreID"]); vendorStoreID != "" {
|
||
vendorStoreInfo, err2 := storeHandler.ReadStore(ctx, storeMap.VendorOrgCode, vendorStoreID)
|
||
if err = err2; err == nil {
|
||
valid["deliveryType"] = vendorStoreInfo.DeliveryType
|
||
}
|
||
err = nil // todo 忽略读不到DeliveryType的错误
|
||
}
|
||
}
|
||
|
||
if err == nil {
|
||
// globals.SugarLogger.Debug(utils.Format4Output(valid, false))
|
||
if len(valid) > 0 {
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
dao.Rollback(db)
|
||
panic(r)
|
||
}
|
||
}()
|
||
if isStoreMapNeedSync(vendorID, valid) { // 对于store vendor map,只有Status改变才需要同步到厂商
|
||
num, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, storeMap, valid, userName, map[string]interface{}{
|
||
model.FieldStoreID: storeID,
|
||
model.FieldVendorID: vendorID,
|
||
}, model.FieldSyncStatus, syncStatus)
|
||
} else {
|
||
num, err = dao.UpdateEntityLogically(db, storeMap, valid, userName, map[string]interface{}{
|
||
model.FieldStoreID: storeID,
|
||
model.FieldVendorID: vendorID,
|
||
})
|
||
}
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return 0, err
|
||
}
|
||
if num > 0 {
|
||
if globals.IsAddEvent {
|
||
mapBefore := refutil.FindMapAndStructMixed(valid, beforeStoreMap)
|
||
err = AddEventDetail(db, ctx, model.OperateUpdate, vendorID, model.ThingTypeStore, storeID, BuildDiffData(mapBefore), BuildDiffData(valid))
|
||
}
|
||
if vendorID != model.VendorIDJX {
|
||
if valid["pricePercentage"] != nil || valid["pricePercentagePack"] != nil {
|
||
storeSkuBind := &model.StoreSkuBind{}
|
||
if num, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, storeSkuBind, nil, userName, map[string]interface{}{
|
||
model.FieldStoreID: storeID,
|
||
}, dao.GetSyncStatusStructField(model.VendorNames[vendorID]), model.SyncFlagPriceMask); err != nil {
|
||
dao.Rollback(db)
|
||
return 0, err
|
||
}
|
||
}
|
||
} else {
|
||
if valid["pricePercentage"] != nil || valid["pricePercentagePack"] != nil {
|
||
ReCalculateJxPriceLight(db, ctx, storeID)
|
||
}
|
||
}
|
||
}
|
||
dao.Commit(db)
|
||
if isStoreMapNeedSync(vendorID, valid) {
|
||
_, err = CurVendorSync.SyncStore(ctx, db, vendorID, storeID, false, userName)
|
||
}
|
||
}
|
||
}
|
||
return num, err
|
||
}
|
||
|
||
func DeleteStore(ctx *jxcontext.Context, storeID int) (num int64, err error) {
|
||
db := dao.GetDB()
|
||
|
||
store := &model.Store{}
|
||
store.ID = storeID
|
||
if err = dao.GetEntity(db, store); err != nil {
|
||
return 0, err
|
||
}
|
||
if store.Status == model.StoreStatusOpened {
|
||
return 0, fmt.Errorf("删除京西门店前必须将所有门店解绑且门店处于关店状态")
|
||
}
|
||
|
||
sql := `
|
||
SELECT (SELECT COUNT(*) FROM store_map t1 WHERE t1.store_id = ? AND t1.deleted_at = ?)
|
||
+ (SELECT COUNT(*) FROM store_courier_map t1 WHERE t1.store_id = ? AND t1.deleted_at = ?) ct
|
||
`
|
||
ct := 0
|
||
if err = dao.GetRow(db, &ct, sql, storeID, utils.DefaultTimeValue, storeID, utils.DefaultTimeValue); err != nil {
|
||
return 0, err
|
||
}
|
||
globals.SugarLogger.Debugf("DeleteStore storeID:%d, ct=%d", storeID, ct)
|
||
if ct > 0 {
|
||
return 0, fmt.Errorf("删除京西门店前必须将所有门店解绑且门店处于关店状态")
|
||
}
|
||
|
||
dao.Begin(db)
|
||
defer dao.Rollback(db)
|
||
now := time.Now()
|
||
|
||
for _, tableName := range []string{"store_sku_bind", "store_sku_category_map", "store_op_request"} {
|
||
sql = fmt.Sprintf(`
|
||
UPDATE %s t1
|
||
SET t1.deleted_at = ?,
|
||
t1.updated_at = ?,
|
||
t1.last_operator = ?
|
||
WHERE t1.store_id = ? AND t1.deleted_at = ?
|
||
`, tableName)
|
||
if _, err = dao.ExecuteSQL(db, sql, now, now, ctx.GetUserName(), storeID, utils.DefaultTimeValue); err != nil {
|
||
return 0, err
|
||
}
|
||
}
|
||
|
||
if num, err = dao.DeleteEntityLogically(db, store, nil, ctx.GetUserName(), nil); err != nil {
|
||
return 0, err
|
||
}
|
||
if globals.IsAddEvent {
|
||
err = AddEventDetail(db, ctx, model.OperateDelete, storeID, model.ThingTypeStore, storeID, "", "")
|
||
}
|
||
dao.Commit(db)
|
||
return num, err
|
||
// return 0, errors.New("暂不支持删除京西门店")
|
||
}
|
||
|
||
// 状态是未解决,且初始是2星以下
|
||
func TmpGetJxBadCommentsNo(ctx *jxcontext.Context, storeID int) (count int, err error) {
|
||
db := dao.GetDB()
|
||
var ctInfo struct {
|
||
Ct int
|
||
}
|
||
if err = dao.GetRow(db, &ctInfo, `
|
||
SELECT COUNT(*) ct
|
||
FROM jx_bad_comments
|
||
WHERE status = ? AND jxstoreid = ? AND score <= ?
|
||
`, orderman.COMMENT_NOT_RESOLVED, utils.Int2Str(storeID), orderman.JX_BAD_COMMENTS_MAX_LEVEL); err == nil {
|
||
count = ctInfo.Ct
|
||
}
|
||
return count, err
|
||
}
|
||
|
||
func TmpGetJxBadCommentsByStoreId(ctx *jxcontext.Context, keyword string, storeIDs []int, offset, pageSize, commentType int, fromTime, toTime time.Time) (retVal map[string]interface{}, err error) {
|
||
db := dao.GetDB()
|
||
sql := `
|
||
SELECT SQL_CALC_FOUND_ROWS
|
||
t1.*, t2.name store_name, t3.name city_name,
|
||
t4.vendor_order_id2
|
||
FROM jx_bad_comments t1
|
||
LEFT JOIN store t2 ON t2.id = t1.jxstoreid
|
||
LEFT JOIN place t3 ON t3.code = t2.city_code
|
||
LEFT JOIN goods_order t4 ON t4.vendor_order_id = t1.order_id AND t4.vendor_id = t1.order_flag
|
||
WHERE 1 = 1
|
||
`
|
||
sqlParams := []interface{}{}
|
||
if keyword != "" {
|
||
keywordLike := "%" + keyword + "%"
|
||
sql += `
|
||
AND (t1.order_id LIKE ? OR t1.jxstoreid LIKE ? OR t1.userphone LIKE ? OR t1.scorecontent LIKE ? OR t1.vendertags LIKE ? OR t1.updated_scorecontent LIKE ?
|
||
OR t1.updated_vendertags LIKE ? OR t2.name LIKE ?)`
|
||
sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike)
|
||
}
|
||
if len(storeIDs) > 0 {
|
||
sql += " AND t1.jxstoreid IN (" + dao.GenQuestionMarks(len(storeIDs)) + ")"
|
||
sqlParams = append(sqlParams, storeIDs)
|
||
}
|
||
if commentType != GET_ALL_COMMENTS_TYPE {
|
||
sql += " AND t1.status = ?"
|
||
if commentType == GET_BAD_COMMENTS_TYPE {
|
||
sql += " AND t1.score <= ?"
|
||
sqlParams = append(sqlParams, orderman.COMMENT_NOT_RESOLVED, orderman.JX_BAD_COMMENTS_MAX_LEVEL)
|
||
} else {
|
||
sqlParams = append(sqlParams, orderman.COMMENT_RESOLVED)
|
||
}
|
||
}
|
||
if !utils.IsTimeZero(fromTime) {
|
||
sql += " AND t1.createtime >= ?"
|
||
sqlParams = append(sqlParams, fromTime)
|
||
}
|
||
if !utils.IsTimeZero(toTime) {
|
||
sql += " AND t1.createtime < ?"
|
||
sqlParams = append(sqlParams, toTime)
|
||
}
|
||
sql += " ORDER BY t1.createtime DESC"
|
||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||
offset = jxutils.FormalizePageOffset(offset)
|
||
sql += " LIMIT ? OFFSET ?"
|
||
sqlParams = append(sqlParams, pageSize, offset)
|
||
var commentList []*JxBadCommentsExt
|
||
dao.Begin(db)
|
||
defer func() {
|
||
dao.Rollback(db)
|
||
}()
|
||
// globals.SugarLogger.Debug(sql)
|
||
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
|
||
if err = dao.GetRows(db, &commentList, sql, sqlParams...); err == nil {
|
||
retVal = map[string]interface{}{
|
||
"total": dao.GetLastTotalRowCount(db),
|
||
"list": commentList,
|
||
}
|
||
dao.Commit(db)
|
||
}
|
||
return retVal, err
|
||
}
|
||
|
||
func GetStoreCourierMaps(ctx *jxcontext.Context, db *dao.DaoDB, storeID int, vendorID int) (storeCourierMaps []*model.StoreCourierMap, err error) {
|
||
cond := map[string]interface{}{
|
||
model.FieldStoreID: storeID,
|
||
}
|
||
if vendorID != -1 {
|
||
cond[model.FieldVendorID] = vendorID
|
||
}
|
||
return storeCourierMaps, dao.GetEntitiesByKV(db, &storeCourierMaps, cond, false)
|
||
}
|
||
|
||
func AddStoreCourierMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, storeCourierMap *model.StoreCourierMap) (outStoreCourierMap *model.StoreCourierMap, err error) {
|
||
return addStoreCourierMap(ctx, db, storeID, vendorID, storeCourierMap, true)
|
||
}
|
||
|
||
func addStoreCourierMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, storeCourierMap *model.StoreCourierMap, isNeedUpdateRemote bool) (outStoreCourierMap *model.StoreCourierMap, err error) {
|
||
storeCourierMap.StoreID = storeID
|
||
storeCourierMap.VendorID = vendorID
|
||
globals.SugarLogger.Debugf("addStoreCourierMap %s, storeCourierMap:%s, isNeedUpdateRemote:%t", model.VendorChineseNames[vendorID], utils.Format4Output(storeCourierMap, true), isNeedUpdateRemote)
|
||
|
||
if handler := partner.GetDeliveryPlatformFromVendorID(vendorID); handler != nil {
|
||
if db == nil {
|
||
db = dao.GetDB()
|
||
}
|
||
if isNeedUpdateRemote {
|
||
storeDetail, err2 := dao.GetStoreDetail2(db, storeID, "", vendorID)
|
||
if err = err2; err != nil {
|
||
return nil, err
|
||
}
|
||
if storeDetail.VendorStoreID != "" {
|
||
return nil, fmt.Errorf("门店已经绑定了%s, ID:%s, 如需重新绑定, 请先解绑", model.VendorChineseNames[vendorID], storeDetail.VendorStoreID)
|
||
}
|
||
storeDetail.VendorID = vendorID
|
||
storeDetail.VendorStoreID = storeCourierMap.VendorStoreID
|
||
if err = updateCourierStore(ctx, storeDetail); err != nil {
|
||
if vendorID != model.VendorIDMTPS {
|
||
return nil, err
|
||
}
|
||
// 如果是美团配送,强制忽略更新错
|
||
globals.SugarLogger.Infof("addStoreCourierMap storeID:%d, vendorID:%d failed with err:%v", storeID, vendorID, err)
|
||
err = nil
|
||
}
|
||
}
|
||
dao.WrapAddIDCULDEntity(storeCourierMap, ctx.GetUserName())
|
||
if err = dao.CreateEntity(db, storeCourierMap); err != nil {
|
||
return nil, err
|
||
}
|
||
if globals.IsAddEvent {
|
||
err = AddEventDetail(db, ctx, model.OperateAdd, vendorID, model.ThingTypeStore, storeID, "", `{"VendorID":`+utils.Int2Str(vendorID)+`}`)
|
||
}
|
||
outStoreCourierMap = storeCourierMap
|
||
} else {
|
||
err = ErrCanNotFindVendor
|
||
}
|
||
return outStoreCourierMap, err
|
||
}
|
||
|
||
func DeleteStoreCourierMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, userName string) (num int64, err error) {
|
||
if db == nil {
|
||
db = dao.GetDB()
|
||
}
|
||
storeCourierMap := &model.StoreCourierMap{}
|
||
num, err = dao.DeleteEntityLogically(db, storeCourierMap, map[string]interface{}{
|
||
model.FieldStatus: model.StoreStatusDisabled,
|
||
}, userName, map[string]interface{}{
|
||
model.FieldStoreID: storeID,
|
||
model.FieldVendorID: vendorID,
|
||
})
|
||
if globals.IsAddEvent {
|
||
err = AddEventDetail(db, ctx, model.OperateDelete, vendorID, model.ThingTypeStore, storeID, "", `{"VendorID":`+utils.Int2Str(vendorID)+`}`)
|
||
}
|
||
return num, err
|
||
}
|
||
|
||
func UpdateStoreCourierMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, payload map[string]interface{}, userName string) (num int64, err error) {
|
||
if db == nil {
|
||
db = dao.GetDB()
|
||
}
|
||
storeCourier := &model.StoreCourierMap{
|
||
StoreID: storeID,
|
||
VendorID: vendorID,
|
||
}
|
||
storeCourier.DeletedAt = utils.DefaultTimeValue
|
||
if err = dao.GetEntity(db, storeCourier, model.FieldStoreID, model.FieldVendorID, model.FieldDeletedAt); err != nil {
|
||
return 0, err
|
||
}
|
||
var beforeStoreCourier = *storeCourier
|
||
delete(payload, "auditStatus") // 不允许直接修改auditStatus的值
|
||
valid := dao.NormalMakeMapByStructObject(payload, storeCourier, userName)
|
||
if len(valid) > 0 {
|
||
if storeCourier.AuditStatus != model.StoreAuditStatusOnline {
|
||
if status := utils.Interface2Int64WithDefault(valid["status"], 0); status == model.StoreStatusOpened {
|
||
// 没有通过审核的禁止改状态为正常
|
||
return 0, fmt.Errorf("此快递门店还没有通过审核,不启用")
|
||
}
|
||
}
|
||
num, err = dao.UpdateEntityLogically(db, storeCourier, valid, userName, nil)
|
||
if globals.IsAddEvent {
|
||
mapBefore := refutil.FindMapAndStructMixed(valid, beforeStoreCourier)
|
||
err = AddEventDetail(db, ctx, model.OperateUpdate, vendorID, model.ThingTypeStore, storeID, BuildDiffData(mapBefore), BuildDiffData(valid))
|
||
}
|
||
}
|
||
return num, err
|
||
}
|
||
|
||
func updateCourierStore(ctx *jxcontext.Context, storeDetail *dao.StoreDetail2) (err error) {
|
||
globals.SugarLogger.Debugf("updateCourierStore %s, storeID:%d, vendorStoreID:%s", model.VendorChineseNames[storeDetail.VendorID], storeDetail.ID, storeDetail.VendorStoreID)
|
||
|
||
if handlerInfo := partner.GetDeliveryPlatformFromVendorID(storeDetail.VendorID); handlerInfo != nil && handlerInfo.Use4CreateWaybill {
|
||
if updateHandler, ok := handlerInfo.Handler.(partner.IDeliveryUpdateStoreHandler); ok {
|
||
err = updateHandler.UpdateStore(ctx, formalizeStore4Courier(storeDetail))
|
||
}
|
||
} else {
|
||
err = fmt.Errorf("配送平台:%s不被支持", model.VendorChineseNames[storeDetail.VendorID])
|
||
}
|
||
return err
|
||
}
|
||
|
||
func updateCourierStores(ctx *jxcontext.Context, storeID int) (err error) {
|
||
globals.SugarLogger.Debugf("updateCourierStores storeID:%d", storeID)
|
||
|
||
db := dao.GetDB()
|
||
errList := errlist.New()
|
||
for k, v := range partner.DeliveryPlatformHandlers {
|
||
if v.Use4CreateWaybill {
|
||
if _, ok := v.Handler.(partner.IDeliveryUpdateStoreHandler); ok {
|
||
storeDetail, err2 := dao.GetStoreDetail2(db, storeID, "", k)
|
||
if err = err2; err2 == nil {
|
||
if storeDetail.VendorStoreID != "" && storeDetail.AuditStatus == model.StoreAuditStatusOnline {
|
||
err = updateCourierStore(ctx, storeDetail)
|
||
}
|
||
}
|
||
errList.AddErr(err)
|
||
}
|
||
}
|
||
}
|
||
return errList.GetErrListAsOne()
|
||
}
|
||
|
||
func updateOrCreateCourierStore(ctx *jxcontext.Context, storeDetail *dao.StoreDetail2) (isCreated bool, err error) {
|
||
globals.SugarLogger.Debugf("updateOrCreateCourierStore %s, storeID:%d, vendorStoreID:%s", model.VendorChineseNames[storeDetail.VendorID], storeDetail.ID, storeDetail.VendorStoreID)
|
||
|
||
if handlerInfo := partner.GetDeliveryPlatformFromVendorID(storeDetail.VendorID); handlerInfo != nil && handlerInfo.Use4CreateWaybill {
|
||
if storeDetail.DistrictName == "" {
|
||
return false, fmt.Errorf("门店的区码有问题,请检查")
|
||
}
|
||
if storeDetail.CityName == "" {
|
||
return false, fmt.Errorf("门店的城市码有问题,请检查")
|
||
}
|
||
formalizeStore4Courier(storeDetail)
|
||
needUpdate := false
|
||
remoteStoreDetail, err2 := handlerInfo.Handler.GetStore(ctx, 0, storeDetail.VendorStoreID)
|
||
if err = err2; err != nil {
|
||
if handlerInfo.Handler.IsErrStoreNotExist(err) {
|
||
storeDetail.VendorStoreID, storeDetail.AuditStatus, err = handlerInfo.Handler.CreateStore(ctx, storeDetail)
|
||
if err == nil {
|
||
isCreated = true
|
||
} else if handlerInfo.Handler.IsErrStoreExist(err) {
|
||
storeDetail.AuditStatus = model.StoreAuditStatusCreated
|
||
err = nil
|
||
}
|
||
}
|
||
} else {
|
||
storeDetail.CourierStatus = remoteStoreDetail.CourierStatus
|
||
storeDetail.AuditStatus = remoteStoreDetail.AuditStatus
|
||
needUpdate = true
|
||
}
|
||
if err == nil && needUpdate {
|
||
if updateHandler, _ := handlerInfo.Handler.(partner.IDeliveryUpdateStoreHandler); updateHandler != nil {
|
||
err = updateHandler.UpdateStore(ctx, storeDetail)
|
||
} else {
|
||
// err = fmt.Errorf("快递平台%s不支持更新门店信息,请手动处理", model.VendorChineseNames[storeDetail.VendorID])
|
||
}
|
||
}
|
||
if err != nil {
|
||
err = fmt.Errorf("门店ID:%d,门店名:%s,错误描述:%s", storeDetail.Store.ID, storeDetail.Name, err.Error())
|
||
globals.SugarLogger.Debugf("updateOrCreateCourierStore storeID:%d failed with error:%v", storeDetail.ID, err)
|
||
}
|
||
}
|
||
return isCreated, err
|
||
}
|
||
|
||
func UpdateOrCreateCourierStores(ctx *jxcontext.Context, storeID int, isForceUpdate, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||
globals.SugarLogger.Debugf("UpdateOrCreateCourierStores storeID:%d", storeID)
|
||
|
||
var storeIDs []int
|
||
if storeID != 0 {
|
||
storeIDs = []int{storeID}
|
||
} else {
|
||
storesInfo, err2 := GetStores(ctx, "", map[string]interface{}{}, 0, -1, utils.DefaultTimeValue, utils.DefaultTimeValue, 0, 0)
|
||
if err = err2; err != nil {
|
||
return "", err
|
||
}
|
||
for _, v := range storesInfo.Stores {
|
||
storeIDs = append(storeIDs, v.ID)
|
||
}
|
||
}
|
||
|
||
task := tasksch.NewParallelTask("UpdateOrCreateCourierStores", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
var resultList []interface{}
|
||
storeID := batchItemList[0].(int)
|
||
errList := errlist.New()
|
||
db := dao.GetDB()
|
||
for vendorID, v := range partner.DeliveryPlatformHandlers {
|
||
if v.Use4CreateWaybill {
|
||
if _, ok := v.Handler.(partner.IDeliveryUpdateStoreHandler); ok {
|
||
storeDetail, err2 := dao.GetStoreDetail2(db, storeID, "", vendorID)
|
||
if err = err2; err2 == nil {
|
||
isNeedAdd := storeDetail.VendorStoreID == ""
|
||
if isForceUpdate || isNeedAdd {
|
||
if isNeedAdd {
|
||
storeDetail.VendorID = vendorID
|
||
storeDetail.VendorStoreID = utils.Int2Str(storeDetail.ID)
|
||
}
|
||
if _, err = updateOrCreateCourierStore(ctx, storeDetail); err == nil && isNeedAdd {
|
||
storeCourier := &model.StoreCourierMap{
|
||
VendorStoreID: storeDetail.VendorStoreID,
|
||
Status: model.StoreStatusOpened,
|
||
AuditStatus: storeDetail.AuditStatus,
|
||
}
|
||
if storeDetail.AuditStatus != model.StoreAuditStatusOnline {
|
||
storeCourier.Status = model.StoreStatusDisabled
|
||
}
|
||
if _, err = addStoreCourierMap(ctx, db, storeDetail.ID, storeDetail.VendorID, storeCourier, false); err == nil {
|
||
resultList = append(resultList, 1)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
errList.AddErr(err)
|
||
}
|
||
}
|
||
}
|
||
return resultList, errList.GetErrListAsOne()
|
||
}, storeIDs)
|
||
tasksch.HandleTask(task, nil, len(storeIDs) > 1).Run()
|
||
if !isAsync {
|
||
resultList, err2 := task.GetResult(0)
|
||
if err = err2; err == nil {
|
||
hint = utils.Int2Str(len(resultList))
|
||
}
|
||
} else {
|
||
hint = task.ID
|
||
}
|
||
return hint, err
|
||
}
|
||
|
||
func formalizeStore4Courier(storeDetail *dao.StoreDetail2) *dao.StoreDetail2 {
|
||
storeDetail.Name = fmt.Sprintf("%s-%s-%s", model.ShopChineseNames[model.VendorIDJD], storeDetail.CityName, storeDetail.Name)
|
||
if storeDetail.PayeeName == "" {
|
||
storeDetail.PayeeName = "店主"
|
||
}
|
||
return storeDetail
|
||
}
|
||
|
||
func ExportShopsHealthInfo(ctx *jxcontext.Context, vendorIDs, storeIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||
db := dao.GetDB()
|
||
vendorID := model.VendorIDEBAI
|
||
storeMapList, err := dao.GetStoresMapList(db, []int{vendorID}, storeIDs, nil, model.StoreStatusAll, model.StoreIsSyncYes, "")
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
storeMap2 := make(map[string]*model.StoreMap)
|
||
for _, v := range storeMapList {
|
||
storeMap2[v.VendorStoreID] = v
|
||
}
|
||
if len(storeMapList) > 0 {
|
||
var healthInfoList []interface{}
|
||
var excelBin []byte
|
||
var excelURL string
|
||
task := tasksch.NewSeqTask(fmt.Sprintf("ExportShopHealthInfo[%s]", model.VendorChineseNames[vendorID]), ctx,
|
||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||
switch step {
|
||
case 0:
|
||
subTask := tasksch.NewParallelTask(fmt.Sprintf("ExportShopHealthInfo2[%s]", model.VendorChineseNames[vendorID]), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
storeMap := batchItemList[0].(*model.StoreMap)
|
||
healthInfo, err := ebai.CurPurchaseHandler.GetShopHealthInfo(storeMap.VendorStoreID)
|
||
if err == nil {
|
||
retVal = []map[string]interface{}{healthInfo}
|
||
}
|
||
return retVal, err
|
||
}, storeMapList)
|
||
tasksch.AddChild(task, subTask).Run()
|
||
healthInfoList, err = subTask.GetResult(0)
|
||
if isContinueWhenError && err != nil && len(healthInfoList) > 0 {
|
||
err = nil
|
||
}
|
||
case 1:
|
||
var healthInfoList2 []map[string]interface{}
|
||
for _, v := range healthInfoList {
|
||
mapInfo := v.(map[string]interface{})
|
||
mapInfo["real_shop_id"] = storeMap2[utils.Interface2String(mapInfo["merchant_id"])].StoreID
|
||
healthInfoList2 = append(healthInfoList2, mapInfo)
|
||
}
|
||
excelConf := &excel.Obj2ExcelSheetConfig{
|
||
Title: "饿百门店情况导出",
|
||
Data: healthInfoList2,
|
||
CaptionList: []string{
|
||
"real_shop_id",
|
||
"merchant_id",
|
||
"merchant_name",
|
||
"hours",
|
||
"sku_num",
|
||
"target_jiedan",
|
||
"is_healthy",
|
||
"bad_order_rate",
|
||
},
|
||
}
|
||
excelBin = excel.Obj2Excel([]*excel.Obj2ExcelSheetConfig{excelConf})
|
||
case 2:
|
||
keyPart := []string{
|
||
ctx.GetUserName(),
|
||
"饿百门店情况",
|
||
}
|
||
keyPart = append(keyPart, time.Now().Format("20060102T150405")+".xlsx")
|
||
key := "export/" + strings.Join(keyPart, "_")
|
||
excelURL, err = jxutils.UploadExportContent(excelBin, key)
|
||
if err == nil {
|
||
task.SetNoticeMsg(excelURL)
|
||
}
|
||
globals.SugarLogger.Debugf("导出饿百门店情况excelURL:%s, err:%v", excelURL, err)
|
||
}
|
||
return nil, err
|
||
}, 3)
|
||
tasksch.HandleTask(task, nil, true).Run()
|
||
if !isAsync {
|
||
_, err = task.GetResult(0)
|
||
if err == nil {
|
||
hint = excelURL
|
||
}
|
||
} else {
|
||
hint = task.GetID()
|
||
}
|
||
}
|
||
return hint, err
|
||
}
|
||
|
||
func GetCorporationInfo(ctx *jxcontext.Context, licenceCode string) (corporationInfo *jdapi.CorporationInfo, err error) {
|
||
// 门店ID随便一个合法的京东门店ID就可以
|
||
corporationInfo, err = api.JdAPI.GetCorporationInfo("11734851", licenceCode)
|
||
return corporationInfo, err
|
||
}
|
||
|
||
func GetStoresVendorSnapshot(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorIDs, storeIDs []int) (vendorStoreSnapshotList []*model.VendorStoreSnapshot, err error) {
|
||
db := dao.GetDB()
|
||
storeMapList, err := dao.GetStoresMapList(db, vendorIDs, storeIDs, nil, model.StoreStatusAll, model.StoreIsSyncYes, "")
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
task := tasksch.NewParallelTask("GetStoresVendorSnapshot", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
storeMap := batchItemList[0].(*model.StoreMap)
|
||
if model.IsVendorRemote(storeMap.VendorID) {
|
||
if handler := partner.GetPurchasePlatformFromVendorID(storeMap.VendorID); handler != nil {
|
||
store, err2 := handler.ReadStore(ctx, storeMap.VendorOrgCode, storeMap.VendorStoreID)
|
||
if err = err2; err == nil {
|
||
retVal = []interface{}{&model.VendorStoreSnapshot{
|
||
StoreID: storeMap.StoreID,
|
||
VendorID: storeMap.VendorID,
|
||
VendorStoreID: storeMap.VendorStoreID,
|
||
|
||
Status: store.Status,
|
||
OpenTime1: store.OpenTime1,
|
||
CloseTime1: store.CloseTime1,
|
||
OpenTime2: store.OpenTime2,
|
||
CloseTime2: store.CloseTime2,
|
||
|
||
DeliveryType: store.DeliveryType,
|
||
StoreName: store.OriginalName,
|
||
IsAutoOrder: store.IsAutoOrder,
|
||
}}
|
||
}
|
||
}
|
||
}
|
||
return retVal, err
|
||
}, storeMapList)
|
||
tasksch.HandleTask(task, parentTask, true).Run()
|
||
resultList, err := task.GetResult(0)
|
||
if len(resultList) > 0 {
|
||
for _, v := range resultList {
|
||
dao.WrapAddIDCULDEntity(v, ctx.GetUserName())
|
||
vendorStoreSnapshotList = append(vendorStoreSnapshotList, v.(*model.VendorStoreSnapshot))
|
||
}
|
||
}
|
||
return vendorStoreSnapshotList, err
|
||
}
|
||
|
||
func getCurrentSnapshotAt(now time.Time) (snapshotAt time.Time) {
|
||
return jxutils.GetLastTimeFromList(now, WatchVendorStoreTimeList)
|
||
}
|
||
|
||
func updateVendorStoreStatusBySnapshot(db *dao.DaoDB, curSnapshotList []*model.VendorStoreSnapshot) (err error) {
|
||
storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncAll, "")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
snapshotMap := make(map[int64]*model.VendorStoreSnapshot)
|
||
for _, v := range curSnapshotList {
|
||
snapshotMap[jxutils.Combine2Int(v.StoreID, v.VendorID)] = v
|
||
}
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil || err != nil {
|
||
dao.Rollback(db)
|
||
if r != nil {
|
||
panic(r)
|
||
}
|
||
}
|
||
}()
|
||
for _, v := range storeMapList {
|
||
if snapshot := snapshotMap[jxutils.Combine2Int(v.StoreID, v.VendorID)]; snapshot != nil &&
|
||
(v.Status != snapshot.Status || v.DeliveryType != snapshot.DeliveryType || v.StoreName != snapshot.StoreName) {
|
||
v.Status = snapshot.Status
|
||
v.DeliveryType = snapshot.DeliveryType
|
||
v.StoreName = snapshot.StoreName
|
||
if _, err = dao.UpdateEntity(db, v, model.FieldStatus, "DeliveryType", "StoreName"); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
}
|
||
dao.Commit(db)
|
||
|
||
utils.CallFuncAsync(func() {
|
||
for _, v := range storeMapList {
|
||
if snapshot := snapshotMap[jxutils.Combine2Int(v.StoreID, v.VendorID)]; snapshot != nil {
|
||
if snapshot.IsAutoOrder == 1 {
|
||
if handler, ok := partner.GetPurchasePlatformFromVendorID(snapshot.VendorID).(partner.IStoreHandler); ok {
|
||
handler.EnableAutoAcceptOrder(jxcontext.AdminCtx, v.VendorOrgCode, v.StoreID, v.VendorStoreID, false)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
})
|
||
return err
|
||
}
|
||
|
||
func SaveStoresVendorSnapshot(db *dao.DaoDB, snapshotAt time.Time, curSnapshotList []*model.VendorStoreSnapshot) (err error) {
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil || err != nil {
|
||
dao.Rollback(db)
|
||
if r != nil {
|
||
panic(r)
|
||
}
|
||
}
|
||
}()
|
||
if err = dao.DeleteVendorStoreSnapshot(db, snapshotAt.Add(-48*time.Hour)); err != nil {
|
||
return err
|
||
}
|
||
for _, v := range curSnapshotList {
|
||
v.SnapshotAt = snapshotAt
|
||
|
||
dao.DeleteEntity(db, v, "VendorStoreID", "VendorID", "SnapshotAt")
|
||
if err = dao.CreateEntity(db, v); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
dao.Commit(db)
|
||
return err
|
||
}
|
||
|
||
func isVendorStoresStatusNotOk(storeMapList []*model.VendorStoreSnapshot) bool {
|
||
statusMap := make(map[int]int)
|
||
maxStatus := model.StoreStatusClosed
|
||
for _, v := range storeMapList {
|
||
statusMap[v.Status] = 1
|
||
if v.Status > maxStatus {
|
||
maxStatus = v.Status
|
||
}
|
||
}
|
||
return len(statusMap) > 1 && maxStatus == model.StoreStatusOpened
|
||
}
|
||
|
||
func getAllUsers4Store(ctx *jxcontext.Context, db *dao.DaoDB, store *model.Store) (userList []*model.User) {
|
||
storeID := store.ID
|
||
var userIDs []string
|
||
userMap := make(map[string]int)
|
||
|
||
// 门店老板
|
||
if roleUserIDList, err := GetRoleUserList(ctx, autils.NewStoreBossRole(storeID)); err == nil && len(roleUserIDList) > 0 {
|
||
userIDs = append(userIDs, roleUserIDList...)
|
||
}
|
||
|
||
// 全局相关角色(市场或运营)
|
||
for _, v := range []string{store.MarketManRole, store.OperatorRole, store.OperatorRole2, store.OperatorRole3} {
|
||
if v != "" {
|
||
if roleUserIDList, err := GetRoleUserList(ctx, autils.NewRole(v, 0)); err == nil && len(roleUserIDList) > 0 {
|
||
userIDs = append(userIDs, roleUserIDList...)
|
||
}
|
||
}
|
||
}
|
||
|
||
if len(userIDs) > 0 {
|
||
userList, _, _ = dao.GetUsers(db, 0, "", userIDs, nil, nil, 0, -1)
|
||
for _, v := range userList {
|
||
userMap[v.GetID()] = 1
|
||
}
|
||
}
|
||
|
||
// 直接电话信息相关人员
|
||
for _, mobile := range []string{store.Tel1, store.Tel2, store.MarketManPhone, store.OperatorPhone, store.OperatorPhone2, store.OperatorPhone3} {
|
||
if mobile != "" {
|
||
if user, err2 := dao.GetUserByID(db, "mobile", mobile); err2 == nil {
|
||
if userMap[user.GetID()] == 0 {
|
||
userMap[user.GetID()] = 1
|
||
userList = append(userList, user)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return userList
|
||
}
|
||
|
||
type tStoreIDList struct {
|
||
StoreIDList []int
|
||
StoreMap map[int]*model.Store
|
||
}
|
||
|
||
func (l *tStoreIDList) Len() int {
|
||
return len(l.StoreIDList)
|
||
}
|
||
|
||
func (l *tStoreIDList) Less(i, j int) bool {
|
||
storei := l.StoreMap[l.StoreIDList[i]]
|
||
storej := l.StoreMap[l.StoreIDList[j]]
|
||
if storei.CityCode == storej.CityCode {
|
||
return storei.ID < storej.ID
|
||
}
|
||
return storei.CityCode < storej.CityCode
|
||
}
|
||
|
||
func (l *tStoreIDList) Swap(i, j int) {
|
||
l.StoreIDList[i], l.StoreIDList[j] = l.StoreIDList[j], l.StoreIDList[i]
|
||
}
|
||
|
||
func SendAlarmVendorSnapshot(ctx *jxcontext.Context, parentTask tasksch.ITask, prevSnapshotList, curSnapshotList []*model.VendorStoreSnapshot) (err error) {
|
||
if len(prevSnapshotList) == 0 {
|
||
return nil
|
||
}
|
||
|
||
prevSnapshotMap := make(map[string]*model.VendorStoreSnapshot)
|
||
prevSnapshotMap2 := make(map[int]map[int]*model.VendorStoreSnapshot)
|
||
for _, v := range prevSnapshotList {
|
||
prevSnapshotMap[v.GenMapKey()] = v
|
||
if prevSnapshotMap2[v.StoreID] == nil {
|
||
prevSnapshotMap2[v.StoreID] = make(map[int]*model.VendorStoreSnapshot)
|
||
}
|
||
prevSnapshotMap2[v.StoreID][v.VendorID] = v
|
||
}
|
||
curSnapshotMap := make(map[string]*model.VendorStoreSnapshot)
|
||
curSnapshotMap2 := make(map[int]map[int]*model.VendorStoreSnapshot)
|
||
curSnapshotGroupMap := make(map[int][]*model.VendorStoreSnapshot)
|
||
|
||
alarmSnapshotMap := make(map[int][]*model.VendorStoreSnapshot)
|
||
txtAlarmSnapshotMap := make(map[int][]*model.VendorStoreSnapshot)
|
||
// 之前是开店当前是关店的,或营业时间缩短的
|
||
for _, v := range curSnapshotList {
|
||
curSnapshotGroupMap[v.StoreID] = append(curSnapshotGroupMap[v.StoreID], v)
|
||
if curSnapshotMap2[v.StoreID] == nil {
|
||
curSnapshotMap2[v.StoreID] = make(map[int]*model.VendorStoreSnapshot)
|
||
}
|
||
curSnapshotMap2[v.StoreID][v.VendorID] = v
|
||
|
||
curSnapshotMap[v.GenMapKey()] = v
|
||
prevSnapshot := prevSnapshotMap[v.GenMapKey()]
|
||
if prevSnapshot != nil {
|
||
if (prevSnapshot.Status == model.StoreStatusOpened && v.Status != model.StoreStatusOpened) ||
|
||
v.CompareOperationTime(prevSnapshot) < 0 {
|
||
alarmSnapshotMap[v.StoreID] = append(alarmSnapshotMap[v.StoreID], v)
|
||
|
||
txtAlarmSnapshotMap[prevSnapshot.StoreID] = append(txtAlarmSnapshotMap[prevSnapshot.StoreID], prevSnapshot)
|
||
}
|
||
}
|
||
}
|
||
|
||
//当前门店,不同平台门店状态不一致的
|
||
for storeID, list := range curSnapshotGroupMap {
|
||
if isVendorStoresStatusNotOk(list) {
|
||
alarmSnapshotMap[storeID] = list
|
||
}
|
||
}
|
||
|
||
// 之前有店(且是开店状态),当前无店的
|
||
for _, v := range prevSnapshotList {
|
||
if v.Status == model.StoreStatusOpened && curSnapshotMap[v.GenMapKey()] == nil {
|
||
alarmSnapshotMap[v.StoreID] = append(alarmSnapshotMap[v.StoreID], v)
|
||
|
||
txtAlarmSnapshotMap[v.StoreID] = append(txtAlarmSnapshotMap[v.StoreID], v)
|
||
}
|
||
}
|
||
|
||
db := dao.GetDB()
|
||
storeDetailMap := make(map[int]*dao.StoreDetail)
|
||
userMap2 := make(map[string]*model.User)
|
||
userMap := make(map[string]map[int]int)
|
||
userMapTxt := make(map[string][]*model.VendorStoreSnapshot)
|
||
for storeID, list := range alarmSnapshotMap {
|
||
storeDetail, _ := dao.GetStoreDetail(db, storeID, list[0].VendorID)
|
||
if storeDetail != nil {
|
||
storeDetailMap[storeID] = storeDetail
|
||
userList := getAllUsers4Store(ctx, db, &storeDetail.Store)
|
||
for _, user := range userList {
|
||
userID := user.GetID()
|
||
if userMap[userID] == nil {
|
||
userMap[userID] = make(map[int]int)
|
||
userMap2[userID] = user
|
||
}
|
||
userMap[userID][storeID] = 1
|
||
if txtAlarmSnapshotMap[storeID] != nil {
|
||
userMapTxt[userID] = append(userMapTxt[userID], txtAlarmSnapshotMap[storeID]...)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
var userList []*model.User
|
||
for _, user := range userMap2 {
|
||
userList = append(userList, user)
|
||
}
|
||
|
||
if len(userList) > 0 {
|
||
allStores, err := dao.GetStoreList(db, nil, nil, nil, nil, "")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
allStoreMap := make(map[int]*model.Store)
|
||
for _, v := range allStores {
|
||
allStoreMap[v.ID] = v
|
||
}
|
||
|
||
const fixTitle = "门店状态变化"
|
||
title := fmt.Sprintf("%s:%s-->%s", fixTitle, utils.Time2Str(prevSnapshotList[0].SnapshotAt), utils.Time2Str(curSnapshotList[0].SnapshotAt))
|
||
task := tasksch.NewParallelTask("SendAlarmVendorSnapshot", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
user := batchItemList[0].(*model.User)
|
||
var excelURL string
|
||
if user.Type&model.UserTypeOperator != 0 {
|
||
var dataList []map[string]interface{}
|
||
captionList := []string{"京西门店ID", "门店名", "城市"}
|
||
isFirstRow := true
|
||
|
||
storeIDList := &tStoreIDList{
|
||
StoreMap: allStoreMap,
|
||
}
|
||
for storeID := range userMap[user.GetID()] {
|
||
storeIDList.StoreIDList = append(storeIDList.StoreIDList, storeID)
|
||
}
|
||
sort.Sort(storeIDList)
|
||
for _, storeID := range storeIDList.StoreIDList {
|
||
prevAlarmMap := prevSnapshotMap2[storeID]
|
||
curAlarmMap := curSnapshotMap2[storeID]
|
||
data := map[string]interface{}{
|
||
"京西门店ID": storeID,
|
||
"门店名": storeDetailMap[storeID].Store.Name,
|
||
"城市": storeDetailMap[storeID].CityName,
|
||
}
|
||
for _, vendorID := range []int{model.VendorIDJD, model.VendorIDEBAI, model.VendorIDMTWM} {
|
||
if isFirstRow {
|
||
captionList = append(captionList, model.VendorChineseNames[vendorID]+"ID",
|
||
model.VendorChineseNames[vendorID]+"之前状态", model.VendorChineseNames[vendorID]+"当前状态",
|
||
model.VendorChineseNames[vendorID]+"之前营业时间", model.VendorChineseNames[vendorID]+"当前营业时间")
|
||
}
|
||
if prevAlarmMap != nil {
|
||
data[model.VendorChineseNames[vendorID]+"当前状态"] = ""
|
||
data[model.VendorChineseNames[vendorID]+"当前营业时间"] = ""
|
||
if prevSnapshot := prevAlarmMap[vendorID]; prevSnapshot != nil {
|
||
data[model.VendorChineseNames[vendorID]+"ID"] = prevSnapshot.VendorStoreID
|
||
data[model.VendorChineseNames[vendorID]+"之前状态"] = model.StoreStatusName[prevSnapshot.Status]
|
||
data[model.VendorChineseNames[vendorID]+"之前营业时间"] = jxutils.OperationTimeStr4VendorStore(prevSnapshot)
|
||
if snapshot := curSnapshotMap[prevSnapshot.GenMapKey()]; snapshot != nil {
|
||
data[model.VendorChineseNames[vendorID]+"当前状态"] = model.StoreStatusName[snapshot.Status]
|
||
data[model.VendorChineseNames[vendorID]+"当前营业时间"] = jxutils.OperationTimeStr4VendorStore(snapshot)
|
||
}
|
||
} else {
|
||
data[model.VendorChineseNames[vendorID]+"ID"] = ""
|
||
data[model.VendorChineseNames[vendorID]+"之前状态"] = ""
|
||
data[model.VendorChineseNames[vendorID]+"之前营业时间"] = ""
|
||
}
|
||
} else if curAlarmMap != nil {
|
||
data[model.VendorChineseNames[vendorID]+"之前状态"] = ""
|
||
data[model.VendorChineseNames[vendorID]+"之前营业时间"] = ""
|
||
if curSnapshot := curAlarmMap[vendorID]; curSnapshot != nil {
|
||
data[model.VendorChineseNames[vendorID]+"ID"] = curSnapshot.VendorStoreID
|
||
data[model.VendorChineseNames[vendorID]+"当前状态"] = model.StoreStatusName[curSnapshot.Status]
|
||
data[model.VendorChineseNames[vendorID]+"当前营业时间"] = jxutils.OperationTimeStr4VendorStore(curSnapshot)
|
||
} else {
|
||
data[model.VendorChineseNames[vendorID]+"ID"] = ""
|
||
data[model.VendorChineseNames[vendorID]+"当前状态"] = ""
|
||
data[model.VendorChineseNames[vendorID]+"当前营业时间"] = ""
|
||
}
|
||
}
|
||
}
|
||
dataList = append(dataList, data)
|
||
|
||
isFirstRow = false
|
||
}
|
||
excelConf := &excel.Obj2ExcelSheetConfig{
|
||
Title: fixTitle,
|
||
Data: dataList,
|
||
CaptionList: captionList,
|
||
}
|
||
excelBin := excel.Obj2Excel([]*excel.Obj2ExcelSheetConfig{excelConf})
|
||
keyPart := []string{
|
||
"store_status",
|
||
user.GetMobile(),
|
||
time.Now().Format("20060102T150405") + ".xlsx",
|
||
}
|
||
key := "export/" + strings.Join(keyPart, "_")
|
||
excelURL, err = jxutils.UploadExportContent(excelBin, key)
|
||
if err != nil {
|
||
globals.SugarLogger.Warnf("SendAlarmVendorSnapshot, %s upload %s failed with error:%v", user.GetName(), key, err)
|
||
}
|
||
var txtAlarm []string
|
||
|
||
for _, v := range userMapTxt[user.GetID()] {
|
||
curSnapshot := curSnapshotMap[v.GenMapKey()]
|
||
storeDetail := storeDetailMap[v.StoreID]
|
||
curStoreStatus := "无店"
|
||
curOpTimeStr := "无店"
|
||
if curSnapshot != nil {
|
||
curStoreStatus = model.StoreStatusName[curSnapshot.Status]
|
||
curOpTimeStr = jxutils.OperationTimeStr4VendorStore(curSnapshot)
|
||
}
|
||
txtAlarm = append(txtAlarm, fmt.Sprintf(`## 门店: %s(%d)
|
||
- 城市: %s
|
||
- 平台: %s
|
||
- 平台ID: %s
|
||
- 之前状态: %s
|
||
- 当前状态: %s
|
||
- 之前营业时间: %s
|
||
- 当前营业时间: %s
|
||
`, storeDetail.Store.Name, v.StoreID, storeDetail.CityName, model.VendorChineseNames[v.VendorID], v.VendorStoreID, model.StoreStatusName[v.Status], curStoreStatus, jxutils.OperationTimeStr4VendorStore(v), curOpTimeStr))
|
||
}
|
||
alarmTextStr := "# " + title + " \n" + fmt.Sprintf("[详情点我](%s/billshow/?normal=true&path=%s) \n", globals.BackstageHost, excelURL) + strings.Join(txtAlarm, " \n")
|
||
sendStoreStatusInfo2Mobile(user, dingdingapi.MsgTypeMarkdown, title, alarmTextStr)
|
||
} else if len(userMapTxt[user.GetID()]) > 0 {
|
||
var txtAlarm []string
|
||
for _, v := range userMapTxt[user.GetID()] {
|
||
curSnapshot := curSnapshotMap[v.GenMapKey()]
|
||
// storeDetail := storeDetailMap[v.StoreID]
|
||
curStoreStatus := "下线"
|
||
if curSnapshot != nil {
|
||
curStoreStatus = model.StoreStatusName[curSnapshot.Status]
|
||
}
|
||
txtAlarm = append(txtAlarm, fmt.Sprintf("您的门店:%s,平台:%s,%s了", v.StoreName, model.VendorChineseNames[v.VendorID], curStoreStatus))
|
||
}
|
||
alarmTextStr := strings.Join(txtAlarm, ",\n")
|
||
sendStoreStatusInfo2Mobile(user, dingdingapi.MsgTyeText, title, alarmTextStr)
|
||
}
|
||
return nil, nil
|
||
}, userList)
|
||
tasksch.HandleTask(task, parentTask, true).Run()
|
||
_, err = task.GetResult(0)
|
||
}
|
||
return err
|
||
}
|
||
|
||
func sendStoreStatusInfo2Mobile(user *model.User, msgType, title, txtAlarm string) {
|
||
msg.SendUserMessage(msgType, user, title, txtAlarm)
|
||
}
|
||
|
||
func SaveAndSendAlarmVendorSnapshot(ctx *jxcontext.Context, vendorIDs, storeIDs []int, isAsync bool) (err error) {
|
||
curSnapshotAt := getCurrentSnapshotAt(time.Now())
|
||
prevSnapshotAt := getCurrentSnapshotAt(curSnapshotAt.Add(-1 * time.Second))
|
||
db := dao.GetDB()
|
||
var curSnapshotList, prevSnapshotList []*model.VendorStoreSnapshot
|
||
task := tasksch.NewParallelTask("SaveAndSendAlarmVendorSnapshot", tasksch.NewParallelConfig().SetIsContinueWhenError(true).SetParallelCount(1), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
step := batchItemList[0].(int)
|
||
switch step {
|
||
case 0:
|
||
curSnapshotList, err = GetStoresVendorSnapshot(ctx, task, vendorIDs, storeIDs)
|
||
if len(curSnapshotList) == 0 {
|
||
task.Cancel()
|
||
} else {
|
||
updateVendorStoreStatusBySnapshot(db, curSnapshotList)
|
||
}
|
||
case 1:
|
||
err = SaveStoresVendorSnapshot(db, curSnapshotAt, curSnapshotList)
|
||
case 2:
|
||
prevSnapshotList, err = dao.GetVendorStoreSnapshot(db, prevSnapshotAt)
|
||
case 3:
|
||
err = SendAlarmVendorSnapshot(ctx, task, prevSnapshotList, curSnapshotList)
|
||
}
|
||
return nil, err
|
||
}, []int{0, 1, 2, 3})
|
||
tasksch.ManageTask(task).Run()
|
||
if !isAsync {
|
||
_, err = task.GetResult(0)
|
||
}
|
||
return err
|
||
}
|
||
|
||
func SyncStoresCourierInfo(ctx *jxcontext.Context, storeIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||
db := dao.GetDB()
|
||
storeList2, err := dao.GetStoreList(db, storeIDs, nil, nil, nil, "")
|
||
var storeList []*model.Store
|
||
for _, v := range storeList2 {
|
||
if v.Status != model.StoreStatusDisabled {
|
||
storeList = append(storeList, v)
|
||
}
|
||
}
|
||
if err == nil && len(storeList) > 0 {
|
||
task := tasksch.NewParallelTask(fmt.Sprintf("同步门店快递信息1:%v", storeIDs),
|
||
tasksch.NewParallelConfig().SetParallelCount(2).SetIsContinueWhenError(isContinueWhenError), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
store := batchItemList[0].(*model.Store)
|
||
subTask := tasksch.NewParallelTask(fmt.Sprintf("同步门店快递信息2:%d", store.ID),
|
||
tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
vendorID := batchItemList[0].(int)
|
||
storeDetail2, err := dao.GetStoreDetail2(db, store.ID, "", vendorID)
|
||
if err == nil && storeDetail2.VendorStoreID != "" /*&& storeDetail2.CourierStatus != model.StoreStatusDisabled*/ {
|
||
if handler := partner.GetDeliveryPlatformFromVendorID(vendorID); handler != nil {
|
||
if updateHandler, ok := handler.Handler.(partner.IDeliveryUpdateStoreHandler); ok {
|
||
updateHandler.UpdateStore(ctx, storeDetail2)
|
||
}
|
||
storeCourier, err2 := handler.Handler.GetStore(ctx, store.ID, storeDetail2.VendorStoreID)
|
||
if err = err2; err == nil {
|
||
if storeDetail2.AuditStatus == model.StoreAuditStatusCreated { // 如果已经通过审核,更新本地状态
|
||
partner.CurStoreManager.OnCourierStoreStatusChanged(ctx, storeCourier.VendorStoreID, vendorID, storeCourier.AuditStatus)
|
||
}
|
||
|
||
distance := jxutils.EarthDistance(jxutils.IntCoordinate2Standard(store.Lng), jxutils.IntCoordinate2Standard(store.Lat), jxutils.IntCoordinate2Standard(storeCourier.Lng), jxutils.IntCoordinate2Standard(storeCourier.Lat))
|
||
params := map[string]interface{}{
|
||
"Lng": storeCourier.Lng,
|
||
"Lat": storeCourier.Lat,
|
||
"Remark": fmt.Sprintf("%d", int(distance*1000)),
|
||
}
|
||
_, err = dao.UpdateEntityLogically(dao.GetDB(), &model.StoreCourierMap{}, params, ctx.GetUserName(), map[string]interface{}{
|
||
"StoreID": store.ID,
|
||
"VendorID": vendorID,
|
||
})
|
||
if distance > 0.2 {
|
||
globals.SugarLogger.Infof("SyncStoresCourierInfo [运营2]门店:%s-%d的%s配送门店坐标不一致,京西:%d,%d,平台:%d,%d,距离:%f公里", store.Name, store.ID, model.VendorChineseNames[vendorID], store.Lng, store.Lat, storeCourier.Lng, storeCourier.Lat, distance)
|
||
retVal = [][]interface{}{
|
||
[]interface{}{
|
||
store,
|
||
storeDetail2,
|
||
},
|
||
}
|
||
}
|
||
} else if handler.Handler.IsErrStoreNotExist(err) {
|
||
if storeDetail2.AuditStatus == model.StoreAuditStatusCreated {
|
||
err = nil
|
||
} else {
|
||
globals.SugarLogger.Infof("SyncStoresCourierInfo [运营2]门店:%s-%d的%s配送门店%s获取出错:%v", store.Name, store.ID, model.VendorChineseNames[vendorID], storeDetail2.VendorStoreID, err)
|
||
}
|
||
}
|
||
}
|
||
} else if dao.IsNoRowsError(err) {
|
||
err = nil
|
||
}
|
||
return retVal, err
|
||
}, partner.UseableDeliveryVendorIDs)
|
||
tasksch.HandleTask(subTask, task, true).Run()
|
||
retVal, err = subTask.GetResult(0)
|
||
return retVal, err
|
||
}, storeList)
|
||
tasksch.HandleTask(task, nil, true).Run()
|
||
if isAsync {
|
||
hint = task.GetID()
|
||
} else {
|
||
resultList, err2 := task.GetResult(0)
|
||
if err = err2; err == nil {
|
||
hint = utils.Int2Str(len(resultList))
|
||
}
|
||
}
|
||
}
|
||
return hint, err
|
||
}
|
||
|
||
func SyncStoresQualify(ctx *jxcontext.Context, storeIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||
if len(storeIDs) > 0 {
|
||
db := dao.GetDB()
|
||
task := tasksch.NewParallelTask(fmt.Sprintf("上传门店资质:%v", storeIDs), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
vendorID := model.VendorIDJD
|
||
if handler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IStoreSyncQualifyHandler); handler != nil {
|
||
storeID := batchItemList[0].(int)
|
||
storeDetail, err2 := dao.GetStoreDetail(db, storeID, vendorID)
|
||
if err = err2; err == nil {
|
||
if err = handler.SyncQualify(ctx, storeDetail); err == nil {
|
||
retVal = []int{1}
|
||
}
|
||
}
|
||
} else {
|
||
err = fmt.Errorf("平台%s不支持此操作", model.VendorChineseNames[vendorID])
|
||
}
|
||
return retVal, err
|
||
}, storeIDs)
|
||
tasksch.HandleTask(task, nil, true).Run()
|
||
if isAsync {
|
||
hint = task.GetID()
|
||
} else {
|
||
resultList, err2 := task.GetResult(0)
|
||
if err = err2; err == nil {
|
||
hint = utils.Int2Str(len(resultList))
|
||
}
|
||
}
|
||
}
|
||
return hint, err
|
||
}
|
||
|
||
func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, needWalkDistance bool) (storeList []*Store4User, err error) {
|
||
const (
|
||
maxRadius = 5000
|
||
maxStoreCount4User = 5
|
||
)
|
||
|
||
lng2, _ := jxutils.ConvertDistanceToLogLat(lng, lat, float64(maxRadius), 90)
|
||
_, lat2 := jxutils.ConvertDistanceToLogLat(lng, lat, float64(maxRadius), 0)
|
||
lng1 := lng - (lng2 - lng)
|
||
lat1 := lat - (lat2 - lat)
|
||
// globals.SugarLogger.Debugf("%f,%f,%f,%f\n", lng1, lng2, lat1, lat2)
|
||
sql := `
|
||
SELECT t1.*,
|
||
city.name city_name
|
||
FROM store t1
|
||
JOIN place city ON city.code = t1.city_code
|
||
JOIN store_map sm ON sm.store_id = t1.id AND sm.vendor_id = ? AND sm.deleted_at = ? AND sm.status <> ?
|
||
WHERE t1.deleted_at = ? AND t1.status <> ? AND t1.lng > ? AND t1.lng < ? AND t1.lat > ? AND t1.lat < ?
|
||
AND sm.is_order <> ?
|
||
ORDER BY t1.id
|
||
`
|
||
sqlParams := []interface{}{
|
||
model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
|
||
utils.DefaultTimeValue, model.StoreStatusDisabled, jxutils.StandardCoordinate2Int(lng1), jxutils.StandardCoordinate2Int(lng2), jxutils.StandardCoordinate2Int(lat1), jxutils.StandardCoordinate2Int(lat2),
|
||
model.YES,
|
||
}
|
||
|
||
var storeList1 []*Store4User
|
||
if err = dao.GetRows(dao.GetDB(), &storeList1, sql, sqlParams...); err == nil {
|
||
var storeList2 []*Store4User
|
||
for _, v := range storeList1 {
|
||
distance := jxutils.Point2StoreDistance(lng, lat, v.Lng, v.Lat, v.DeliveryRangeType, v.DeliveryRange)
|
||
if distance > 0 || (lng == jxutils.IntCoordinate2Standard(v.Lng) && lat == jxutils.IntCoordinate2Standard(v.Lat)) {
|
||
v.Distance = distance
|
||
storeList2 = append(storeList2, v)
|
||
}
|
||
}
|
||
|
||
// 为了审核用
|
||
if len(storeList2) == 0 {
|
||
sqlParams2 := []interface{}{
|
||
model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
|
||
utils.DefaultTimeValue,
|
||
model.StoreStatusDisabled,
|
||
jxutils.StandardCoordinate2Int(0),
|
||
jxutils.StandardCoordinate2Int(10000),
|
||
jxutils.StandardCoordinate2Int(0),
|
||
jxutils.StandardCoordinate2Int(10000),
|
||
}
|
||
dao.GetRows(dao.GetDB(), &storeList2, sql, sqlParams2...)
|
||
if len(storeList2) > 1 {
|
||
storeList2 = storeList2[:1]
|
||
}
|
||
}
|
||
|
||
// 如果要求以步行距离来算
|
||
if needWalkDistance {
|
||
var coordList []*autonavi.Coordinate
|
||
for _, v := range storeList2 {
|
||
coordList = append(coordList, &autonavi.Coordinate{
|
||
Lng: v.FloatLng,
|
||
Lat: v.FloatLat,
|
||
})
|
||
}
|
||
if distanceList, err2 := api.AutonaviAPI.BatchWalkingDistance(lng, lat, coordList); err2 == nil {
|
||
for k, v := range storeList2 {
|
||
v.WalkDistance = int(distanceList[k])
|
||
}
|
||
} else {
|
||
return nil, err2
|
||
}
|
||
}
|
||
|
||
sort.Sort(Store4UserList(storeList2))
|
||
storeList = storeList2
|
||
if len(storeList) > maxStoreCount4User {
|
||
storeList = storeList[:maxStoreCount4User]
|
||
}
|
||
}
|
||
return storeList, err
|
||
}
|
||
|
||
func JdStoreInfoCoordinateRecover(ctx *jxcontext.Context, vendorOrgCode string, files []*multipart.FileHeader) (err error) {
|
||
if len(files) == 0 {
|
||
return errors.New("没有文件上传!")
|
||
}
|
||
fileHeader := files[0]
|
||
file1, err := fileHeader.Open()
|
||
defer file1.Close()
|
||
|
||
db := dao.GetDB()
|
||
storeList, err := dao.GetStoresMapList(db, []int{model.VendorIDJD}, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "")
|
||
if err == nil {
|
||
var validStoreList []*dao.StoreDetail
|
||
for _, v := range storeList {
|
||
if v.Status != model.StoreStatusDisabled && v.CreatedAt.Sub(utils.Str2Time("2019-10-01")) > 0 {
|
||
storeInfo, err := jd.GetAPI(vendorOrgCode).GetStoreInfoByStationNo2(v.VendorStoreID)
|
||
if err == nil && storeInfo.CreateTime.GoTime().Sub(utils.Str2Time("2019-10-25")) > 0 {
|
||
if storeDetail, err := dao.GetStoreDetail(db, v.StoreID, v.VendorID); err == nil {
|
||
validStoreList = append(validStoreList, storeDetail)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
getStoreList := func(lng, lat, lng2, lat2 int) (vendorStoreIDs []string) {
|
||
for _, v := range validStoreList {
|
||
if v.Lng >= lng && v.Lng <= lng2 && v.Lat >= lat && v.Lat <= lat2 {
|
||
vendorStoreIDs = append(vendorStoreIDs, v.VendorStoreID)
|
||
}
|
||
}
|
||
return vendorStoreIDs
|
||
}
|
||
sheetName := "老格明细"
|
||
file, err2 := excelize.OpenReader(file1)
|
||
if err = err2; err == nil {
|
||
rows, err2 := file.GetRows(sheetName)
|
||
if err = err2; err == nil {
|
||
str2Coords := func(str string) (lng, lat int) {
|
||
list := strings.Split(str, ",")
|
||
if len(list) >= 2 {
|
||
lng, lat = jxutils.StandardCoordinate2Int(utils.Str2Float64WithDefault(list[1], 0)), jxutils.StandardCoordinate2Int(utils.Str2Float64WithDefault(list[0], 0))
|
||
}
|
||
return lng, lat
|
||
}
|
||
for i := 1; i < len(rows); i++ {
|
||
lng, lat := str2Coords(rows[i][8])
|
||
lng2, lat2 := str2Coords(rows[i][7])
|
||
vendorStoreIDs := getStoreList(lng, lat, lng2, lat2)
|
||
countInfo := fmt.Sprintf("京西已拓%d", len(vendorStoreIDs))
|
||
axis, _ := excelize.CoordinatesToCellName(5, i+1)
|
||
file.SetCellStr(sheetName, axis, countInfo)
|
||
axis2, _ := excelize.CoordinatesToCellName(6, i+1)
|
||
file.SetCellStr(sheetName, axis2, strings.Join(vendorStoreIDs, ","))
|
||
}
|
||
filename := ExecuteFileName(fileHeader.Filename)
|
||
buf := bytes.NewBuffer(nil)
|
||
if _, err = io.Copy(buf, file1); err != nil {
|
||
return err
|
||
}
|
||
baseapi.SugarLogger.Debugf("WriteToExcel:save %s success", filename)
|
||
downloadURL, err := jxutils.UploadExportContent(buf.Bytes(), filename)
|
||
if err != nil {
|
||
baseapi.SugarLogger.Errorf("WriteToExcel:upload %s, failed error:%v", filename, err)
|
||
} else {
|
||
if authInfo, err := ctx.GetV2AuthInfo(); err == nil {
|
||
noticeMsg := fmt.Sprintf("path=%s\n", downloadURL)
|
||
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, authInfo.UserID, "导出老格恢复拓店进度成功", noticeMsg)
|
||
}
|
||
baseapi.SugarLogger.Debugf("WriteToExcel:upload %s success, downloadURL:%s", filename, downloadURL)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return err
|
||
}
|
||
|
||
func ExecuteFileName(filename string) (name string) {
|
||
filePrefix := filename[strings.LastIndex(filename, "."):len(filename)]
|
||
fileRealName := filename[0:strings.LastIndex(filename, ".")]
|
||
name = fileRealName + utils.Int64ToStr(time.Now().Unix()) + filePrefix
|
||
return name
|
||
}
|
||
|
||
func GetVendorStoreInfo(ctx *jxcontext.Context, vendorIDList []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||
var (
|
||
storeListJD []VendorStoreExcel
|
||
storeListMT []VendorStoreExcel
|
||
storeListEB []VendorStoreExcel
|
||
storeIDs []string
|
||
)
|
||
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||
switch step {
|
||
case 0:
|
||
for _, vendorID := range vendorIDList {
|
||
iStoreHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IStoreHandler)
|
||
if vendorID == model.VendorIDEBAI {
|
||
storeIDs, err = ebai.CurPurchaseHandler.GetShopIDsByPage()
|
||
} else {
|
||
storeIDs, err = iStoreHandler.GetAllStoresVendorID(ctx, "")
|
||
}
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
var storeDetail *dao.StoreDetail
|
||
storeID := batchItemList[0].(string)
|
||
if partner.IsMultiStore(vendorID) {
|
||
multiHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler)
|
||
storeDetail, err = multiHandler.ReadStore(ctx, "", storeID)
|
||
if err != nil {
|
||
return retVal, err
|
||
}
|
||
} else {
|
||
singleHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreHandler)
|
||
storeDetail, err = singleHandler.ReadStore(ctx, "", storeID)
|
||
if err != nil {
|
||
return retVal, err
|
||
}
|
||
}
|
||
db := dao.GetDB()
|
||
storeDetail2, err := dao.GetStoreDetailByVendorStoreID(db, storeDetail.VendorStoreID, vendorID)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
if storeDetail.Status != model.StoreStatusOpened {
|
||
if storeDetail2 != nil {
|
||
var storeExcel = VendorStoreExcel{
|
||
StoreID: storeDetail2.ID,
|
||
VendorStoreName: storeDetail.Name,
|
||
Tel1: storeDetail.Tel1,
|
||
Tel2: storeDetail.Tel2,
|
||
Address: storeDetail.Address,
|
||
Status: StoreStatus2Chinese(storeDetail.Status),
|
||
CityName: storeDetail.CityName,
|
||
MarketManName: storeDetail2.MarketManName,
|
||
OperatorName: storeDetail2.OperatorName,
|
||
OperatorName2: storeDetail2.OperatorName2,
|
||
OperatorName3: storeDetail2.OperatorName3,
|
||
}
|
||
retVal = []VendorStoreExcel{storeExcel}
|
||
}
|
||
}
|
||
return retVal, err
|
||
}
|
||
taskParallel := tasksch.NewParallelTask("获取各平台未营业门店", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, taskFunc, storeIDs)
|
||
tasksch.HandleTask(taskParallel, task, true).Run()
|
||
storeList, _ := taskParallel.GetResult(0)
|
||
for _, v := range storeList {
|
||
if vendorID == model.VendorIDJD {
|
||
storeListJD = append(storeListJD, v.(VendorStoreExcel))
|
||
}
|
||
if vendorID == model.VendorIDEBAI {
|
||
storeListEB = append(storeListEB, v.(VendorStoreExcel))
|
||
}
|
||
if vendorID == model.VendorIDMTWM {
|
||
storeListMT = append(storeListMT, v.(VendorStoreExcel))
|
||
}
|
||
}
|
||
}
|
||
case 1:
|
||
WriteToExcelStore(task, storeListJD, storeListMT, storeListEB)
|
||
}
|
||
return result, err
|
||
}
|
||
taskSeq := tasksch.NewSeqTask2("导出各平台未营业门店-序列任务", ctx, isContinueWhenError, taskSeqFunc, 2)
|
||
tasksch.HandleTask(taskSeq, nil, true).Run()
|
||
if !isAsync {
|
||
_, err = taskSeq.GetResult(0)
|
||
hint = "1"
|
||
} else {
|
||
hint = taskSeq.GetID()
|
||
}
|
||
return hint, err
|
||
}
|
||
|
||
func WriteToExcelStore(task *tasksch.SeqTask, storeListJD, storeListMT, storeListEB []VendorStoreExcel) (err error) {
|
||
var sheetList []*excel.Obj2ExcelSheetConfig
|
||
var downloadURL, fileName string
|
||
if len(storeListJD) > 0 {
|
||
excelConf := &excel.Obj2ExcelSheetConfig{
|
||
Title: "京东平台",
|
||
Data: storeListJD,
|
||
CaptionList: titleListStore,
|
||
}
|
||
sheetList = append(sheetList, excelConf)
|
||
}
|
||
if len(storeListMT) > 0 {
|
||
excelConf := &excel.Obj2ExcelSheetConfig{
|
||
Title: "美团平台",
|
||
Data: storeListMT,
|
||
CaptionList: titleListStore,
|
||
}
|
||
sheetList = append(sheetList, excelConf)
|
||
}
|
||
if len(storeListEB) > 0 {
|
||
excelConf := &excel.Obj2ExcelSheetConfig{
|
||
Title: "饿百平台",
|
||
Data: storeListEB,
|
||
CaptionList: titleListStore,
|
||
}
|
||
sheetList = append(sheetList, excelConf)
|
||
}
|
||
if len(sheetList) == 0 {
|
||
return errors.New("所选平台没有未营业的门店!")
|
||
} else {
|
||
downloadURL, fileName, err = jxutils.UploadExeclAndPushMsg(sheetList, "各平台未营业门店统计")
|
||
if err != nil {
|
||
baseapi.SugarLogger.Errorf("WriteToExcel:upload %s failed error:%v", fileName, err)
|
||
} else {
|
||
noticeMsg := fmt.Sprintf("[详情点我]path=%s \n", downloadURL)
|
||
task.SetNoticeMsg(noticeMsg)
|
||
baseapi.SugarLogger.Debugf("WriteToExcel:upload %s success, downloadURL:%s", fileName, downloadURL)
|
||
}
|
||
}
|
||
return err
|
||
}
|
||
|
||
func StoreStatus2Chinese(status int) (str string) {
|
||
if status == model.StoreStatusOpened {
|
||
return "正常营业"
|
||
} else if status == model.StoreStatusDisabled {
|
||
return "暂停营业"
|
||
} else if status == model.StoreStatusClosed {
|
||
return "休息中"
|
||
} else {
|
||
return "未知的营业状态"
|
||
}
|
||
}
|
||
|
||
func GetStorePriceScore(ctx *jxcontext.Context, storeIDs, vendorIDs []int, fromScore, toScore, sort int, snapDate string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
|
||
var snapDateParam time.Time
|
||
db := dao.GetDB()
|
||
if snapDate != "" {
|
||
snapDateParam = utils.Str2Time(snapDate)
|
||
}
|
||
storePriceScore, totalCount, err := dao.GetStorePriceScore(db, storeIDs, vendorIDs, fromScore, toScore, sort, snapDateParam, offset, pageSize)
|
||
pagedInfo = &model.PagedInfo{
|
||
Data: storePriceScore,
|
||
TotalCount: totalCount,
|
||
}
|
||
return pagedInfo, err
|
||
}
|
||
|
||
func CreateStorePriceScore(ctx *jxcontext.Context) (err error) {
|
||
db := dao.GetDB()
|
||
var snapshotAt time.Time
|
||
snapshotAt = utils.Time2Date(time.Now().AddDate(0, 0, -1))
|
||
storePriceScoreSnapshot, err := dao.GetStorePriceScoreSnapshot(db, snapshotAt)
|
||
if len(storePriceScoreSnapshot) > 0 {
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil || err != nil {
|
||
dao.Rollback(db)
|
||
if r != nil {
|
||
panic(r)
|
||
}
|
||
}
|
||
}()
|
||
priceReferSnapshotDeleteHis := &model.StorePriceScoreSnapshot{SnapshotAt: snapshotAt.AddDate(0, 0, -7)}
|
||
priceReferSnapshotDelete := &model.StorePriceScoreSnapshot{SnapshotAt: snapshotAt}
|
||
dao.DeleteEntity(db, priceReferSnapshotDeleteHis, "SnapshotAt")
|
||
dao.DeleteEntity(db, priceReferSnapshotDelete, "SnapshotAt")
|
||
for _, v := range storePriceScoreSnapshot {
|
||
dao.WrapAddIDCULDEntity(v, ctx.GetUserName())
|
||
v.SnapshotAt = snapshotAt
|
||
if err = dao.CreateEntity(db, v); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
dao.Commit(db)
|
||
globals.SugarLogger.Debugf("CreateStorePriceScore")
|
||
}
|
||
return err
|
||
}
|
||
|
||
func RefreshJdLevel(ctx *jxcontext.Context) (err error) {
|
||
db := dao.GetDB()
|
||
storeMapList, err := dao.GetStoresMapList(db, []int{model.VendorIDJD}, nil, nil, model.StoreStatusOpened, -1, "")
|
||
if len(storeMapList) > 0 {
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil || err != nil {
|
||
dao.Rollback(db)
|
||
if r != nil {
|
||
panic(r)
|
||
}
|
||
}
|
||
}()
|
||
task := tasksch.NewParallelTask("更新京东门店等级", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
v := batchItemList[0].(*model.StoreMap)
|
||
var (
|
||
pageLimit = 5
|
||
pageNo = 1
|
||
level string
|
||
)
|
||
for ; pageNo < pageLimit+1; pageNo++ {
|
||
level, err = jd.GetAPI(v.VendorOrgCode).GetJdStoreLevel(v.VendorOrgCode, v.VendorStoreID, pageNo)
|
||
if err != nil {
|
||
return retVal, err
|
||
}
|
||
if level != "" {
|
||
break
|
||
}
|
||
if pageNo == pageLimit {
|
||
level = ""
|
||
}
|
||
}
|
||
v.JdStoreLevel = level
|
||
_, err = dao.UpdateEntity(db, v, "JdStoreLevel")
|
||
return retVal, err
|
||
}, storeMapList)
|
||
tasksch.HandleTask(task, nil, true).Run()
|
||
_, err = task.GetResult(0)
|
||
dao.Commit(db)
|
||
}
|
||
return err
|
||
}
|
||
|
||
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
|
||
}
|
||
|
||
func UpdateJdStoreNameAll(ctx *jxcontext.Context) (err error) {
|
||
storeMap := map[int]int{
|
||
100345: 100345,
|
||
100347: 100347,
|
||
100852: 100852,
|
||
101689: 101689,
|
||
102654: 102654,
|
||
102381: 102381,
|
||
102500: 102500,
|
||
102810: 102810,
|
||
}
|
||
db := dao.GetDB()
|
||
userName := ctx.GetUserName()
|
||
for _, v := range storeMap {
|
||
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 = ?
|
||
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, v); err == nil {
|
||
for _, store := range stores {
|
||
a := jd.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
|
||
}
|
||
}
|
||
// 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 = jd.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))
|
||
}
|
||
err = errList.GetErrListAsOne()
|
||
}
|
||
}
|
||
}
|
||
return err
|
||
}
|
||
|
||
func DeletePrinterSeq(ctx *jxcontext.Context, storeIDs []int) (err error) {
|
||
db := dao.GetDB()
|
||
for _, v := range storeIDs {
|
||
stores, err := dao.GetStoreList(db, []int{v}, nil, nil, nil, "")
|
||
if err != nil || len(stores) == 0 {
|
||
return err
|
||
}
|
||
vendorID := stores[0].PrinterVendorID
|
||
if vendorID == model.NO {
|
||
return fmt.Errorf("该门店没有绑定打印机,ID:[%v],名字:[%v]", stores[0].ID, stores[0].Name)
|
||
}
|
||
if vendorID == model.VendorIDXiaoWM {
|
||
return fmt.Errorf("暂不支持该打印机品牌清空打印队列,[%v]", model.VendorChineseNames[model.VendorIDXiaoWM])
|
||
}
|
||
handler := partner.GetPrinterPlatformFromVendorID(vendorID)
|
||
err = handler.EmptyPrintList(ctx, stores[0].PrinterSN, stores[0].PrinterKey)
|
||
}
|
||
return err
|
||
}
|