493 lines
16 KiB
Go
493 lines
16 KiB
Go
package cms
|
||
|
||
import (
|
||
"fmt"
|
||
"reflect"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
|
||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||
|
||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||
|
||
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
|
||
|
||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/mobile"
|
||
"git.rosy.net.cn/jx-callback/business/authz/autils"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||
"git.rosy.net.cn/jx-callback/business/partner"
|
||
|
||
"git.rosy.net.cn/baseapi/utils"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||
"git.rosy.net.cn/jx-callback/business/model"
|
||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||
"git.rosy.net.cn/jx-callback/globals/api"
|
||
)
|
||
|
||
const (
|
||
SendMsgTypeOpenStoreRequest = "openStoreRequest"
|
||
SendMsgTypeSuggestRequest = "suggestRequest"
|
||
)
|
||
|
||
type SysConfigLimit struct {
|
||
ValueType reflect.Kind
|
||
MinValue int64
|
||
MaxValue int64
|
||
AfterChanged func() error
|
||
}
|
||
|
||
var (
|
||
serviceInfo map[string]interface{}
|
||
allowUpdatePlaceFieldsMap = map[string]bool{
|
||
"name": true,
|
||
"enabled": true,
|
||
"mtpsPrice": true,
|
||
}
|
||
|
||
receiveMsgUsersMap = map[string][]string{
|
||
SendMsgTypeOpenStoreRequest: []string{
|
||
"石锋",
|
||
// "x",
|
||
// "周扬",
|
||
},
|
||
SendMsgTypeSuggestRequest: []string{
|
||
"石锋",
|
||
// "x",
|
||
// "周扬",
|
||
},
|
||
}
|
||
needConfirmRequestMap = map[string]int{
|
||
SendMsgTypeOpenStoreRequest: 1,
|
||
}
|
||
|
||
SysConfigLimitMap = map[string]*SysConfigLimit{
|
||
model.ConfigSysEbaiBoxFee: &SysConfigLimit{
|
||
ValueType: reflect.Int,
|
||
MinValue: 0,
|
||
MaxValue: 500,
|
||
AfterChanged: func() (err error) {
|
||
_, err = dao.SetStoreMapSyncStatus(dao.GetDB(), []int{model.VendorIDEBAI}, nil, model.SyncFlagModifiedMask)
|
||
return err
|
||
},
|
||
},
|
||
model.ConfigSysMtwmBoxFee: &SysConfigLimit{
|
||
ValueType: reflect.Int,
|
||
MinValue: 0,
|
||
MaxValue: 500,
|
||
AfterChanged: func() (err error) {
|
||
_, err = dao.SetStoreMapSyncStatus(dao.GetDB(), []int{model.VendorIDMTWM}, nil, model.SyncFlagModifiedMask)
|
||
return err
|
||
},
|
||
},
|
||
model.ConfigSysMtwmSkuBoxFee: &SysConfigLimit{
|
||
ValueType: reflect.Int,
|
||
MinValue: 0,
|
||
MaxValue: 50,
|
||
AfterChanged: func() (err error) {
|
||
_, err = dao.SetStoreSkuSyncStatus(dao.GetDB(), model.VendorIDMTWM, nil, nil, model.SyncFlagModifiedMask)
|
||
return err
|
||
},
|
||
},
|
||
}
|
||
)
|
||
|
||
func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
|
||
buildTimeStr := ""
|
||
if !utils.IsTimeZero(buildTime) {
|
||
buildTimeStr = utils.Time2Str(buildTime)
|
||
}
|
||
serviceInfo = map[string]interface{}{
|
||
"startupTime": utils.Time2Str(time.Now()),
|
||
"version": version,
|
||
"buildTime": buildTimeStr,
|
||
"gitCommit": gitCommit,
|
||
"metaData": map[string]interface{}{
|
||
"skuNamePrefix": model.SkuNamePrefixNames,
|
||
"skuNameUnit": model.UnitNames,
|
||
"skuSpecUnit": model.SpecUnitNames,
|
||
"skuStatus": model.SkuStatusName,
|
||
"storeDeliveryRangeType": model.DeliveryRangeTypeName,
|
||
"storeDeliveryType": model.DeliveryTypeName,
|
||
"storeStatus": model.StoreStatusName,
|
||
"categoryType": model.CategoryTypeName,
|
||
"vendorTypeName": model.VendorTypeName,
|
||
"vendorName": model.VendorChineseNames,
|
||
"orderStatus": model.OrderStatusName,
|
||
"waybillStatus": model.WaybillStatusName,
|
||
"orderTypeName": model.OrderTypeName,
|
||
"taskStatusName": tasksch.TaskStatusName,
|
||
"opRequestTypeName": model.RequestTypeName,
|
||
"opRequestStatusName": model.RequestStatusName,
|
||
"storeMsgSendStatusName": model.StoreMsgSendStatusName,
|
||
"shopChineseNames": model.ShopChineseNames,
|
||
"printerVendorInfo": model.PrinterVendorInfo,
|
||
"printerStatusName": partner.PrinterStatusName,
|
||
"purchaseVendorInfo": model.PurchaseVendorInfo,
|
||
"afsReasonTypeName": model.AfsReasonTypeName,
|
||
"afsAppealTypeName": model.AfsAppealTypeName,
|
||
"actTypeName": model.ActTypeName,
|
||
"actStatusName": model.ActStatusName,
|
||
"actCreateTypeName": model.ActCreateTypeName,
|
||
"storeAuditStatusName": model.StoreAuditStatusName,
|
||
"configTypeName": model.ConfigTypeName,
|
||
"autoSaleAt": AutoSaleAtStr,
|
||
"userTypeName": model.UserTypeName,
|
||
"storePriceTypeName": model.StorePriceTypeName,
|
||
"payStatusName": model.PayStatusName,
|
||
"refundStatusName": model.RefundStatusName,
|
||
"autoReplyTypeName": model.AutoReplyTypeName,
|
||
"complaintReasons": model.ComplaintReasons,
|
||
"supplementType": model.SupplementTypeName,
|
||
"operateType": model.OperateTypeName,
|
||
"thingType": model.ThingTypeName,
|
||
"apiFunctionName": model.ApiFunctionName,
|
||
},
|
||
}
|
||
}
|
||
|
||
func GetServiceInfo(ctx *jxcontext.Context) map[string]interface{} {
|
||
return serviceInfo
|
||
}
|
||
|
||
func GetPlaces(ctx *jxcontext.Context, keyword string, includeDisabled bool, params map[string]interface{}) ([]*model.Place, error) {
|
||
sql := `
|
||
SELECT *
|
||
FROM place t1
|
||
WHERE 1 = 1
|
||
`
|
||
if !includeDisabled {
|
||
sql += " AND enabled = 1"
|
||
}
|
||
sqlParams := make([]interface{}, 0)
|
||
if keyword != "" {
|
||
sql += " AND (t1.name LIKE ?"
|
||
sqlParams = append(sqlParams, "%"+keyword+"%")
|
||
if keywordInt64, err2 := strconv.ParseInt(keyword, 10, 64); err2 == nil {
|
||
sql += " OR t1.code = ?"
|
||
sqlParams = append(sqlParams, keywordInt64)
|
||
}
|
||
sql += ")"
|
||
}
|
||
if params["parentCode"] != nil {
|
||
sql += " AND t1.parent_code = ?"
|
||
sqlParams = append(sqlParams, params["parentCode"])
|
||
}
|
||
if params["level"] != nil {
|
||
sql += " AND t1.level = ?"
|
||
sqlParams = append(sqlParams, params["level"])
|
||
}
|
||
sql += " ORDER BY t1.level, t1.name"
|
||
// globals.SugarLogger.Debug(sql)
|
||
places := []*model.Place{}
|
||
return places, dao.GetRows(nil, &places, sql, sqlParams)
|
||
}
|
||
|
||
func UpdatePlaces(ctx *jxcontext.Context, places []map[string]interface{}, userName string) (num int64, err error) {
|
||
if len(places) == 0 {
|
||
return 0, ErrMissingInput
|
||
}
|
||
updateFields := []string{}
|
||
for k := range places[0] {
|
||
if allowUpdatePlaceFieldsMap[k] {
|
||
updateFields = append(updateFields, k)
|
||
}
|
||
}
|
||
for _, place := range places {
|
||
if place["code"] == nil {
|
||
return 0, ErrMissingInput
|
||
}
|
||
placeid := &model.Place{}
|
||
valid := dao.NormalMakeMapByFieldList(place, updateFields, userName)
|
||
if num, err = dao.UpdateEntityLogically(nil, placeid, valid, userName, utils.Params2Map("Code", place["code"])); err != nil {
|
||
return num, err
|
||
}
|
||
}
|
||
return num, err
|
||
}
|
||
|
||
func UpdatePlace(ctx *jxcontext.Context, placeCode int, payload map[string]interface{}, userName string) (num int64, err error) {
|
||
payload["code"] = placeCode
|
||
return UpdatePlaces(ctx, []map[string]interface{}{payload}, userName)
|
||
}
|
||
|
||
func GetCoordinateDistrictCode(ctx *jxcontext.Context, lng, lat float64) (code int, err error) {
|
||
return api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat), nil
|
||
}
|
||
|
||
func SendMsg2Somebody(ctx *jxcontext.Context, mobileNum, verifyCode, msgType, msgContent string) (err error) {
|
||
if needConfirmRequestMap[msgType] == 1 {
|
||
if _, err = mobile.AutherObj.VerifySecret(mobileNum, verifyCode); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
db := dao.GetDB()
|
||
for _, v := range receiveMsgUsersMap[msgType] {
|
||
user, err2 := dao.GetUserByID(db, "name", v)
|
||
if err2 == nil {
|
||
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.GetID(), msgType, msgContent)
|
||
} else if err == nil {
|
||
err = err2
|
||
}
|
||
}
|
||
return err
|
||
}
|
||
|
||
func checkSysConfig(key, value string) (err error) {
|
||
if limit := SysConfigLimitMap[key]; limit != nil {
|
||
if limit.ValueType == reflect.Int {
|
||
int64Value, err2 := strconv.ParseInt(value, 10, 64)
|
||
if err = err2; err == nil {
|
||
if int64Value < limit.MinValue || int64Value > limit.MaxValue {
|
||
err = fmt.Errorf("配置%s,值%s超范围[%d,%d]", key, value, limit.MinValue, limit.MaxValue)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return err
|
||
}
|
||
|
||
func onSysConfigChanged(key, value string) (err error) {
|
||
if limit := SysConfigLimitMap[key]; limit != nil && limit.AfterChanged != nil {
|
||
err = limit.AfterChanged()
|
||
}
|
||
return err
|
||
}
|
||
|
||
func checkConfig(opFlag int, configType, key, value string) (err error) {
|
||
switch configType {
|
||
case model.ConfigTypePricePack:
|
||
if value != "" {
|
||
pricePack := dao.PricePercentagePack2Obj(value)
|
||
if pricePack == nil {
|
||
err = fmt.Errorf("配置:%s不合法", value)
|
||
}
|
||
}
|
||
case model.ConfigTypeFreightPack:
|
||
if value != "" {
|
||
freightPack := dao.FreightDeductionPack2Obj(value)
|
||
if freightPack == nil {
|
||
err = fmt.Errorf("配置:%s不合法", value)
|
||
} else {
|
||
var lastStage *model.FreightDeductionItem
|
||
for _, v := range freightPack.FreightDeductionList {
|
||
if lastStage != nil && lastStage.DeductFreight > v.DeductFreight {
|
||
err = fmt.Errorf("免运设置不合理:门槛:%s,免运金额:%s,门槛:%s,免运金额:%s",
|
||
jxutils.IntPrice2StandardString(int64(lastStage.BeginPrice)), jxutils.IntPrice2StandardString(int64(lastStage.DeductFreight)),
|
||
jxutils.IntPrice2StandardString(int64(v.BeginPrice)), jxutils.IntPrice2StandardString(int64(v.DeductFreight)))
|
||
return err
|
||
}
|
||
lastStage = v
|
||
}
|
||
}
|
||
}
|
||
case model.ConfigTypeBank:
|
||
if value != "" {
|
||
if model.BankName[key] == "" {
|
||
err = fmt.Errorf("此银行代码:%s不支持,请联系开发", value)
|
||
}
|
||
}
|
||
case model.ConfigTypeRole:
|
||
case model.ConfigTypeSys:
|
||
if opFlag&( /*model.SyncFlagNewMask|*/ model.SyncFlagDeletedMask) != 0 {
|
||
err = fmt.Errorf("系统参数只支持修改或添加,不支持删除")
|
||
} else {
|
||
err = checkSysConfig(key, value)
|
||
}
|
||
case model.ConfigTypeJxStore:
|
||
case model.ConfigTypeCookie:
|
||
default:
|
||
err = fmt.Errorf("当前只支持配置:%s, 传入的配置类型:%s", utils.Format4Output(model.ConfigTypeName, true), configType)
|
||
}
|
||
return err
|
||
}
|
||
|
||
func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error) {
|
||
if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
|
||
return err
|
||
}
|
||
|
||
db := dao.GetDB()
|
||
conf := &model.NewConfig{
|
||
Key: key,
|
||
Type: configType,
|
||
Value: value,
|
||
}
|
||
dao.WrapAddIDCULDEntity(conf, ctx.GetUserName())
|
||
err = dao.CreateEntity(db, conf)
|
||
if configType == model.ConfigTypeSys && err == nil {
|
||
err = onSysConfigChanged(key, value)
|
||
}
|
||
return err
|
||
}
|
||
|
||
func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
|
||
if err = checkConfig(model.SyncFlagDeletedMask, configType, key, ""); err != nil {
|
||
return err
|
||
}
|
||
db := dao.GetDB()
|
||
switch configType {
|
||
case model.ConfigTypePricePack:
|
||
storeMapList, err2 := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, key)
|
||
if err = err2; err == nil {
|
||
var storeInfo []string
|
||
for _, v := range storeMapList {
|
||
storeInfo = append(storeInfo, fmt.Sprintf("门店:%d, 平台:%s", v.StoreID, model.VendorChineseNames[v.VendorID]))
|
||
}
|
||
if len(storeInfo) > 0 {
|
||
err = fmt.Errorf("还有门店在使用价格包:%s,门店信息:%s", key, strings.Join(storeInfo, ","))
|
||
}
|
||
}
|
||
case model.ConfigTypeFreightPack:
|
||
storeMapList, err2 := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "")
|
||
if err = err2; err == nil {
|
||
var storeInfo []string
|
||
for _, v := range storeMapList {
|
||
if v.FreightDeductionPack == key {
|
||
storeInfo = append(storeInfo, fmt.Sprintf("门店:%d, 平台:%s", v.StoreID, model.VendorChineseNames[v.VendorID]))
|
||
}
|
||
}
|
||
if len(storeInfo) > 0 {
|
||
err = fmt.Errorf("还有门店在使用价格包:%s,门店信息:%s", key, strings.Join(storeInfo, ","))
|
||
}
|
||
}
|
||
case model.ConfigTypeBank:
|
||
//todo
|
||
return fmt.Errorf("暂不支持删除银行")
|
||
case model.ConfigTypeRole:
|
||
errList := errlist.New()
|
||
userIDs, err2 := api2.RoleMan.GetRoleUserList(autils.NewRole(key, 0))
|
||
if err = err2; err == nil && len(userIDs) > 0 {
|
||
userList, totalCount, err2 := dao.GetUsers(dao.GetDB(), 0, "", userIDs, nil, nil, 0, -1)
|
||
if err = err2; err == nil && totalCount > 0 {
|
||
// todo
|
||
// err = fmt.Errorf("还有人员在使用角色:%s,人员信息:%s", key, utils.MustMarshal(utils.Struct2Map(userList, "compact")))
|
||
err = fmt.Errorf("还有人员在使用角色:%s,人员信息:%s", key, utils.Format4Output(userList, false))
|
||
}
|
||
}
|
||
errList.AddErr(err)
|
||
storeList, err2 := dao.GetStoreList(db, nil, nil, nil, nil, key)
|
||
if err = err2; err == nil && len(storeList) > 0 {
|
||
storeIDs := make([]int, len(storeList))
|
||
for k, v := range storeList {
|
||
storeIDs[k] = v.ID
|
||
}
|
||
err = fmt.Errorf("还有门店在使用角色:%s,门店信息:%s", key, utils.MustMarshal(storeIDs))
|
||
}
|
||
errList.AddErr(err)
|
||
err = errList.GetErrListAsOne()
|
||
}
|
||
if err == nil {
|
||
_, err = dao.DeleteEntityLogically(db, &model.NewConfig{}, nil, ctx.GetUserName(), map[string]interface{}{
|
||
"Key": key,
|
||
"Type": configType,
|
||
})
|
||
}
|
||
if configType == model.ConfigTypeSys && err == nil {
|
||
err = onSysConfigChanged(key, "")
|
||
}
|
||
return err
|
||
}
|
||
|
||
func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint string, err error) {
|
||
if key == "" {
|
||
return "", fmt.Errorf("修改配置必须给定key")
|
||
}
|
||
if err = checkConfig(model.SyncFlagModifiedMask, configType, key, value); err != nil {
|
||
return "", err
|
||
}
|
||
hint = "1"
|
||
|
||
db := dao.GetDB()
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
dao.Rollback(db)
|
||
panic(r)
|
||
}
|
||
}()
|
||
configList, err := dao.QueryConfigs(db, key, configType, "")
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return "", err
|
||
}
|
||
if _, err = dao.UpdateEntityLogically(db, configList[0], map[string]interface{}{
|
||
"Value": value,
|
||
}, ctx.GetUserName(), nil); err != nil {
|
||
dao.Rollback(db)
|
||
return "", err
|
||
}
|
||
switch configType {
|
||
case model.ConfigTypePricePack:
|
||
storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, key)
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return "", err
|
||
}
|
||
dao.Commit(db)
|
||
vendorStoreMap := make(map[int][]int)
|
||
for _, v := range storeMapList {
|
||
vendorStoreMap[v.VendorID] = append(vendorStoreMap[v.VendorID], v.StoreID)
|
||
}
|
||
for vendorID, storeIDs := range vendorStoreMap {
|
||
if vendorID != model.VendorIDJX {
|
||
dao.SetStoreSkuSyncStatus(db, vendorID, storeIDs, nil, model.SyncFlagPriceMask)
|
||
} else {
|
||
hint, err = ReCalculateJxPrice(db, ctx, storeIDs)
|
||
}
|
||
}
|
||
case model.ConfigTypeFreightPack:
|
||
dao.Commit(db)
|
||
storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "")
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
for _, v := range storeMapList {
|
||
var storeMapList2 []*model.StoreMap
|
||
if v.FreightDeductionPack == key {
|
||
storeMapList2 = append(storeMapList2, v)
|
||
}
|
||
if len(storeMapList2) > 0 {
|
||
task := tasksch.NewParallelTask("同步门店配送免运", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
storeMap := batchItemList[0].(*model.StoreMap)
|
||
_, err = CurVendorSync.SyncStore(ctx, db, storeMap.VendorID, storeMap.StoreID, false, ctx.GetUserName())
|
||
return retVal, err
|
||
}, storeMapList2)
|
||
tasksch.HandleTask(task, nil, true).Run()
|
||
if len(storeMapList2) < 5 {
|
||
_, err = task.GetResult(0)
|
||
} else {
|
||
hint = task.GetID()
|
||
}
|
||
}
|
||
}
|
||
default:
|
||
dao.Commit(db)
|
||
}
|
||
if configType == model.ConfigTypeSys && err == nil {
|
||
err = onSysConfigChanged(key, value)
|
||
}
|
||
return hint, err
|
||
}
|
||
|
||
func QueryConfigs(key, configType, keyword string) (configList []*model.NewConfig, err error) {
|
||
return dao.QueryConfigs(dao.GetDB(), key, configType, keyword)
|
||
}
|
||
|
||
func GetCityBankBranches(ctx *jxcontext.Context, cityCode int, bankCode string) (info map[int]map[string][]string, err error) {
|
||
list, err := dao.GetCityBankBranches(dao.GetDB(), cityCode, bankCode)
|
||
if err == nil && len(list) > 0 {
|
||
info = make(map[int]map[string][]string)
|
||
for _, v := range list {
|
||
if info[v.CityCode] == nil {
|
||
info[v.CityCode] = make(map[string][]string)
|
||
}
|
||
info[v.CityCode][v.PayeeBankCode] = append(info[v.CityCode][v.PayeeBankCode], v.PayeeBankBranchName)
|
||
}
|
||
}
|
||
return info, err
|
||
}
|