Files
jx-callback/business/jxstore/cms/user2.go

1066 lines
33 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package cms
import (
"errors"
"fmt"
"sort"
"strings"
"sync"
"time"
"git.rosy.net.cn/baseapi/platformapi/wxpayapi"
"git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
"git.rosy.net.cn/jx-callback/globals/api/apimanager"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/jx-callback/business/jxutils/excel"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/baseapi/utils/errlist"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/dingding"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin"
"git.rosy.net.cn/jx-callback/business/authz"
"git.rosy.net.cn/jx-callback/business/authz/autils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jsonerr"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/jx-callback/globals/api2"
)
var (
ErrUserIDAndNameMustGiven = errors.New("用户ID2和用户名必须不为空")
)
var (
userProvider = &UserProvider{}
authTypeFieldMap = map[string]string{
auth2.UserIDID: "user_id",
auth2.UserIDID2: "user_id2",
auth2.UserIDMobile: "mobile",
auth2.UserIDEmail: "email",
}
jdUsersStruct GetJdUsersStruct
titleListJdUser = []string{
"用户名",
"关联门店",
"所属角色",
"状态",
}
)
type GetJdUsersStruct struct {
locker sync.RWMutex
userMap []JdUserStruct
}
type JdUserStruct struct {
UserName string `json:"用户名"`
StoreIDs string `json:"关联门店"`
RoleName string `json:"所属角色"`
Status string `json:"状态"`
}
type UserProvider struct {
}
func (*UserProvider) GetUser(authID, authIDType string) (user auth2.IUser) {
globals.SugarLogger.Debugf("GetUser, authID:%s, authIDType:%s", authID, authIDType)
fieldName := authTypeFieldMap[authIDType]
if fieldName != "" {
user2, err := dao.GetUserByID(dao.GetDB(), fieldName, authID)
if err == nil {
user = user2 // 这样写的原因是golang nil的比较问题
}
}
return user
}
func (*UserProvider) UpdateUserMobile(userID string, mobile string) (err error) {
_, err = dao.UpdateEntityLogically(dao.GetDB(), &model.User{}, map[string]interface{}{
"Mobile": mobile,
}, userID, map[string]interface{}{
"UserID": userID,
})
return err
}
func (*UserProvider) UpdateUserEmail(userID string, email string) (err error) {
_, err = dao.UpdateEntityLogically(dao.GetDB(), &model.User{}, map[string]interface{}{
"Email": email,
}, userID, map[string]interface{}{
"UserID": userID,
})
return err
}
func (*UserProvider) UpdateUserType(userID string, userTypeMask int8, updateType int) (err error) {
db := dao.GetDB()
user := &model.User{
UserID: userID,
}
if err = dao.GetEntity(db, user, "UserID"); err == nil {
if updateType == auth2.UpdateUserTypeAdd {
user.Type |= userTypeMask
} else if updateType == auth2.UpdateUserTypeDelete {
user.Type &= ^userTypeMask
} else {
user.Type = userTypeMask
}
dao.WrapUpdateULEntity(user, userID)
_, err = dao.UpdateEntity(db, user, "Type", model.FieldUpdatedAt, model.FieldLastOperator)
}
return err
}
func (*UserProvider) UpdateLastLogin(userID string, lastLoginType, fromIP string) (err error) {
_, err = dao.UpdateEntityLogically(dao.GetDB(), &model.User{}, map[string]interface{}{
"LastLoginAt": utils.Time2Pointer(time.Now()),
"LastLoginType": lastLoginType,
"LastLoginIP": fromIP,
}, userID, map[string]interface{}{
"UserID": userID,
})
return err
}
// func (*UserProvider) CreateUser(userID2, mobile, email, name string) (user auth2.IUser, err error) {
// realUser := &model.User{
// UserID2: userID2,
// Mobile: mobile,
// Email: email,
// Name: name,
// }
// return realUser, CreateUser(realUser)
// }
func init() {
auth2.Init(userProvider)
}
func RegisterUserWithMobile(ctx *jxcontext.Context, user *model.User, mobileVerifyCode string, inAuthInfo, manTokenInfo *auth2.AuthInfo) (outAuthInfo *auth2.AuthInfo, err error) {
var mobileAuth *auth2.AuthInfo
fakeMobile := false
user.Type = model.UserTypeConsumer | model.UserTypeStoreBoss // 先不区分商户与消息者
createName := ctx.GetRealRemoteIP()
authType := auth2.AuthTypeMobile
if manTokenInfo != nil && mobileVerifyCode == "" {
manUser, err2 := dao.GetUserByID(dao.GetDB(), "user_id", manTokenInfo.GetID())
if err = err2; err != nil {
return nil, err
}
if manUser.Type&(model.UserTypeOperator|model.UserTypeBoss) == 0 {
return nil, fmt.Errorf("管理员才能添加商户")
}
if utils.Pointer2String(user.Mobile) == "" {
return nil, fmt.Errorf("管理员添加必须指定用户手机号")
}
mobileVerifyCode = auth2.InternalAuthSecret
fakeMobile = true
user.Type |= model.UserTypeStoreBoss
createName = manTokenInfo.GetName()
}
if mobileVerifyCode != "" {
if fakeMobile {
mobileAuth, err = auth2.LoginInternal(ctx.Context, auth2.AuthTypeMobile, user.GetMobile(), auth2.UserIDMobile, mobileVerifyCode)
} else {
mobileAuth, err = auth2.Login(ctx.Context, auth2.AuthTypeMobile, user.GetMobile(), auth2.UserIDMobile, mobileVerifyCode)
}
if err != nil {
return nil, err
}
if mobileAuth != nil && !mobileAuth.IsUserEmpty() {
return nil, jsonerr.New(mobileAuth, model.ErrCodeJsonUserAlreadyExist)
}
} else if inAuthInfo != nil {
user.Mobile = nil
} else {
return nil, fmt.Errorf("短信验证码与其它认证方式至少要指定一种")
}
if inAuthInfo != nil {
if inAuthInfo.AuthBindInfo.Type == dingding.AuthTypeStaff {
user.Type |= model.UserTypeOperator
} else if user.Mobile != nil {
user.Type |= model.UserTypeStoreBoss
}
createName += "," + inAuthInfo.GetAuthID()
authType = inAuthInfo.GetAuthType()
if user.Avatar == "" {
user.Avatar = inAuthInfo.GetAvatar()
}
}
//注册时默认商城用户就加入分账接收方
if strings.Contains(ctx.GetRequest().Referer(), "wx4b5930c13f8b1170") {
param := &wxpayapi.ProfitSharingReceiverParam{
Receiver: wxpayapi.CData(`{
"type":"` + wxpayapi.AccountTypeOpen + `",
"account":"` + inAuthInfo.GetAuthID() + `",
"relation_type":" ` + wxpayapi.Relation + `"
}`),
}
_, err = api.WxpayAPI.AddProfitSharingReceiver(param)
}
if err = CreateUser(user, utils.LimitUTF8StringLen(createName, 32)); err == nil {
userProvider.UpdateLastLogin(user.GetID(), authType, ctx.GetRealRemoteIP())
TryAddStoreBossRole4User(ctx, user)
if mobileAuth != nil {
if outAuthInfo, err = auth2.BindUser(mobileAuth, user); err == nil && inAuthInfo != nil {
err = auth2.AddAuthBind(&outAuthInfo.UserBasic, inAuthInfo)
}
} else {
outAuthInfo, err = auth2.BindUser(inAuthInfo, user)
}
} else if dao.IsDuplicateError(err) {
err = auth2.ErrUserID2AlreadyExist
}
return outAuthInfo, err
}
func TryAddStoreBossRole4User(ctx *jxcontext.Context, user *model.User) (err error) {
if user.Type&model.UserTypeStoreBoss != 0 {
userMobile := user.GetMobile()
if userMobile != "" {
if storeList, err := dao.GetStoreList(dao.GetDB(), nil, nil, nil, []string{userMobile}, ""); err == nil && len(storeList) > 0 {
roleList := make([]*authz.RoleInfo, len(storeList))
for k, v := range storeList {
roleList[k] = autils.NewStoreBossRole(v.ID)
}
err = AddRoles4User(ctx, user.GetID(), roleList)
}
}
}
return err
}
func TryAddStoreBossRole4StoreByMobile(ctx *jxcontext.Context, storeID int, mobileList []string) (err error) {
if storeID > 0 {
var userIDs []string
for _, v := range mobileList {
if v != "" {
if userList, _, err := dao.GetUsers(dao.GetDB(), model.UserTypeStoreBoss, "", nil, nil, []string{v}, 0, -1); err == nil && len(userList) > 0 {
userIDs = append(userIDs, userList[0].GetID())
}
}
}
if len(userIDs) > 0 {
role := autils.NewStoreBossRole(storeID)
err = AddUsers4Role(ctx, role, userIDs)
}
}
return err
}
func HandleOrder4Consignee(order *model.GoodsOrder) (err error) {
var user *model.User
mobileNumber := jxutils.GetRealMobile4Order(order)
if mobileNumber == "" && order.VendorUserID == "" {
return fmt.Errorf("订单:%s手机号与平台用户标识都是空", order.VendorOrderID)
}
authType := dao.GetAuthType4Vendor(order.VendorID)
if authType == "" {
msg := fmt.Sprintf("平台ID:%d当前不被支持请联系开发", order.VendorID)
globals.SugarLogger.Warn(msg)
return fmt.Errorf(msg)
}
oeratorName := order.VendorOrderID
db := dao.GetDB()
if mobileNumber != "" {
userList, _, err2 := dao.GetUsers(db, 0, "", nil, nil, []string{mobileNumber}, 0, 0)
if err = err2; err != nil {
return err
}
if len(userList) > 0 {
user = userList[0]
}
}
vendorUserID := order.VendorUserID
if vendorUserID != "" {
authInfo, err2 := dao.GetAuthBind(db, model.AuthBindTypeID, authType, vendorUserID)
if err = err2; err != nil && !dao.IsNoRowsError(err) {
return err
}
if err == nil {
vendorUserID = ""
if user == nil {
if user, err = dao.GetUserByID(db, "user_id", authInfo.UserID); err != nil {
return err
}
}
} else {
err = nil
}
}
const Remark = "fromOrder"
if user == nil {
user = &model.User{
UserID2: mobileNumber,
Name: order.ConsigneeName,
Mobile: &mobileNumber,
Type: model.UserTypeConsumer,
Address: order.ConsigneeAddress,
Remark: Remark,
}
setUserAddress(db, user, order)
if user.GetID2() == "" {
user.UserID2 = order.VendorUserID
}
if user.GetID2() == "" {
user.UserID2 = order.VendorOrderID
}
user.Type = model.UserTypeConsumer
err = CreateUser(user, oeratorName)
} else {
if user.GetMobile() == "" && mobileNumber != "" {
user.Mobile = &mobileNumber
dao.UpdateEntity(db, user, "Mobile")
}
}
if err == nil {
order.UserID = user.GetID()
if vendorUserID != "" {
authBind := &model.AuthBind{
UserID: user.GetID(),
BindType: model.AuthBindTypeID,
AuthID: vendorUserID,
Type: authType,
Remark: Remark,
}
dao.WrapAddIDCULDEntity(authBind, oeratorName)
authBind.Status = model.AuthBindStatusNormal
err = dao.CreateEntity(nil, authBind)
}
}
return err
}
func setUserAddress(db *dao.DaoDB, user *model.User, order *model.GoodsOrder) {
user.Address = order.ConsigneeAddress
store := &model.Store{}
store.ID = jxutils.GetSaleStoreIDFromOrder(order)
if err := dao.GetEntity(db, store); err == nil {
user.CityCode = store.CityCode
user.DistrictCode = store.DistrictCode
} else if dao.IsNoRowsError(err) {
if order.ConsigneeLng != 0 && order.ConsigneeLat != 0 {
if user.DistrictCode = api.AutonaviAPI.GetCoordinateDistrictCode(jxutils.IntCoordinate2Standard(order.ConsigneeLng), jxutils.IntCoordinate2Standard(order.ConsigneeLat)); user.DistrictCode > 0 {
if placeInfo, err := dao.GetPlaceByCode(db, user.DistrictCode); err == nil {
user.CityCode = placeInfo.ParentCode
}
}
}
}
}
func GetUserBindAuthInfo(ctx *jxcontext.Context) (authList []*model.AuthBind, err error) {
authInfo, err := ctx.GetV2AuthInfo()
if err == nil {
return auth2.GetUserBindAuthInfo(authInfo.GetID())
}
return nil, err
}
func CreateUser(user *model.User, creatorName string) (err error) {
globals.SugarLogger.Debugf("CreateUser user:%s, creatorName:%s", utils.Format4Output(user, true), creatorName)
if user == nil || user.UserID2 == "" || user.Name == "" {
return ErrUserIDAndNameMustGiven
}
if user.GetMobile() == "" {
user.Mobile = nil
}
if user.GetEmail() == "" {
user.Email = nil
}
dao.WrapAddIDCULDEntity(user, creatorName)
user.UserID = utils.GetUUID()
user.Status = model.UserStatusNormal
user.DividePercentage = 5
return dao.CreateEntity(nil, user)
}
func DisableUser(ctx *jxcontext.Context, userID string) (err error) {
userName := ctx.GetUserName()
if _, err = dao.UpdateEntityLogically(dao.GetDB(), &model.User{}, map[string]interface{}{
"Status": model.UserStatusDisabled,
}, userName, map[string]interface{}{
"UserID": userID,
}); err == nil {
auth2.DisableUser(userID, userName)
}
return err
}
func OnDingDingMsg(msg map[string]interface{}) (callbackResponse *dingdingapi.CallbackResponse) {
eventType := utils.Interface2String(msg[dingdingapi.KeyEventType])
if eventType == dingdingapi.CBTagUserLeaveOrg {
var (
authBind *model.AuthBind
err error
)
db := dao.GetDB()
for _, userID := range msg[dingdingapi.KeyUserID].([]interface{}) {
userIDStr := utils.Interface2String(userID)
globals.SugarLogger.Debugf("OnDingDingMsg dingding user:%s left company", userIDStr)
if authBind, err = dao.GetAuthBind(db, model.AuthBindTypeAuth, dingding.AuthTypeStaff, userIDStr); err == nil { // 直接找到了
globals.SugarLogger.Debugf("OnDingDingMsg dingding user:%s, userID:%s left company", userIDStr, authBind.UserID)
if err = DisableUser(jxcontext.AdminCtx, authBind.UserID); err != nil {
globals.SugarLogger.Errorf("OnDingDingMsg failed with error:%v", err)
}
}
}
}
return api.DingDingAPI.Err2CallbackResponse(nil)
}
func GetUsers(ctx *jxcontext.Context, userType int, keyword string, userIDs []string, userID2, mobile string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
userList, totalCount, err := dao.GetUsers(dao.GetDB(), userType, keyword, userIDs, jxutils.BatchString2Slice(userID2), jxutils.BatchString2Slice(mobile), offset, pageSize)
if err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: totalCount,
Data: userList,
}
}
return pagedInfo, err
}
func GetStoreList4User(ctx *jxcontext.Context, mobileNum, userID string) (storeList []*dao.StoreWithCityName, err error) {
roleList, err := api2.RoleMan.GetUserRoleList(userID)
if err != nil {
return nil, err
}
var (
storeIDs []int
shortRoleNameList []string
)
for _, v := range roleList {
if v.StoreID == 0 {
shortRoleNameList = append(shortRoleNameList, v.Name)
} else {
storeIDs = append(storeIDs, v.StoreID)
}
}
storeList, err = dao.GetStoreListByMobileOrStoreIDs(dao.GetDB(), mobileNum, shortRoleNameList, storeIDs)
return storeList, err
}
func GetMyStoreListNew(ctx *jxcontext.Context) (storesInfo interface{}, errCode string, err error) {
if !auth2.IsV2Token(ctx.GetToken()) {
return nil, model.ErrCodeTokenIsInvalid, model.ErrTokenIsInvalid
}
mobileNum, userID := ctx.GetMobileAndUserID()
if mobileNum == "" {
return nil, "", fmt.Errorf("不能得到用户手机号")
}
var storeList []*dao.StoreWithCityName
if storeList, err = GetStoreList4User(ctx, mobileNum, userID); err == nil && len(storeList) > 0 {
// todo应该用通用方法
mapDataList := make([]map[string]interface{}, len(storeList))
for k, v := range storeList {
mapDataList[k] = map[string]interface{}{
"id": v.ID,
"address": v.Address,
"cityName": v.CityName,
"name": v.Name,
"tel1": v.Tel1,
"tel2": v.Tel2,
"payeeName": v.PayeeName,
"status": v.Status,
}
}
storesInfo = mapDataList
}
return storesInfo, "", err
}
func GetStoreRoleList(ctx *jxcontext.Context) (roleList []*authz.RoleInfo, err error) {
return authz.StoreRoleList, nil
}
func GetUserRoleList(ctx *jxcontext.Context, userID string) (roleList []*authz.RoleInfo, err error) {
return api2.RoleMan.GetUserRoleList(userID)
}
func GetRoleUserList(ctx *jxcontext.Context, r *authz.RoleInfo) (userIDList []string, err error) {
return api2.RoleMan.GetRoleUserList(r)
}
func GetRolesUserList(ctx *jxcontext.Context, rList []*authz.RoleInfo) (userIDMap map[string][]string, err error) {
userIDMap = make(map[string][]string)
for _, r := range rList {
userIDList, err2 := api2.RoleMan.GetRoleUserList(r)
if err = err2; err == nil {
userIDMap[r.GetFullName()] = userIDList
} else {
break
}
}
return userIDMap, err
}
func checkUserType(userID string, userType int8) (err error) {
userList, _, err := dao.GetUsers(dao.GetDB(), 0, "", []string{userID}, nil, nil, 0, 0)
if err != nil {
return err
}
if len(userList) == 0 {
return fmt.Errorf("找不到用户:%s", userID)
}
if userList[0].Type&userType == 0 {
return fmt.Errorf("用户:%s不能用于当前操作", userID)
}
return nil
}
func AddRoles4User(ctx *jxcontext.Context, userID string, rList []*authz.RoleInfo) (err error) {
errList := errlist.New()
if err = checkUserType(userID, model.UserTypeNonConsumer); err != nil {
return err
}
for _, v := range rList {
if err = autils.ValidateRole(v.Name, v.StoreID); err == nil {
if err = api2.RoleMan.AddRole4User(userID, v); err != nil {
errList.AddErr(err)
} else if v.StoreID > 0 {
HandleUserWXRemark(dao.GetDB(), userID, true)
}
} else {
errList.AddErr(err)
}
}
return errList.GetErrListAsOne()
}
func DeleteRoles4User(ctx *jxcontext.Context, userID string, rList []*authz.RoleInfo) (err error) {
errList := errlist.New()
for _, v := range rList {
if err = api2.RoleMan.DeleteRole4User(userID, v); err != nil {
errList.AddErr(err)
} else if v.StoreID > 0 {
HandleUserWXRemark(dao.GetDB(), userID, true)
}
}
return errList.GetErrListAsOne()
}
func AddUsers4Role(ctx *jxcontext.Context, r *authz.RoleInfo, userIDList []string) (err error) {
if err = autils.ValidateRole(r.Name, r.StoreID); err != nil {
return err
}
errList := errlist.New()
for _, v := range userIDList {
if err = checkUserType(v, model.UserTypeNonConsumer); err != nil {
return err
}
if err = api2.RoleMan.AddRole4User(v, r); err != nil {
errList.AddErr(err)
} else if r.StoreID > 0 {
HandleUserWXRemark(dao.GetDB(), v, true)
}
}
return errList.GetErrListAsOne()
}
func DeleteUsers4Role(ctx *jxcontext.Context, r *authz.RoleInfo, userIDList []string) (err error) {
errList := errlist.New()
for _, v := range userIDList {
if err = api2.RoleMan.DeleteRole4User(v, r); err != nil {
errList.AddErr(err)
} else if r.StoreID > 0 {
HandleUserWXRemark(dao.GetDB(), v, true)
}
}
return errList.GetErrListAsOne()
}
func getAddressInfoFromCoord(db *dao.DaoDB, lng, lat float64) (formattedAddress string, districtCode, cityCode int, err error) {
regeoInfo, err := api.AutonaviAPI.GeoCodeRegeoSingle(lng, lat, 0, false, nil, 0, 0)
if err == nil {
formattedAddress = regeoInfo.FormattedAddress
districtCode = int(utils.Str2Int64WithDefault(regeoInfo.AddressComponent.Adcode, 0))
if districtCode == 0 {
err = fmt.Errorf("坐标lng:%f,lat:%f找不到位置信息", lng, lat)
} else if districtInfo, err2 := dao.GetPlaceByCode(db, districtCode); err2 == nil {
cityCode = districtInfo.ParentCode
}
}
return formattedAddress, districtCode, cityCode, err
}
func AddUserDeliveryAddress(ctx *jxcontext.Context, address *model.UserDeliveryAddress) (outAddress *model.UserDeliveryAddress, err error) {
globals.SugarLogger.Debugf("AddUserDeliveryAddress1 address:%s", utils.Format4Output(address, true))
if address.UserID == "" {
return nil, fmt.Errorf("操作用户配送地址时必须指定UserID")
}
db := dao.GetDB()
lng := address.Lng
lat := address.Lat
address.AutoAddress, address.DistrictCode, address.CityCode, err = getAddressInfoFromCoord(db, lng, lat)
if err == nil {
globals.SugarLogger.Debugf("AddUserDeliveryAddress2 address:%s", utils.Format4Output(address, true))
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
dao.WrapAddIDCULDEntity(address, ctx.GetUserName())
if address.IsDefault == 1 {
if err = dao.ClearUserDeliveryAddressDefault(db, address.UserID, 0); err != nil {
dao.Rollback(db)
return nil, err
}
}
if err = dao.CreateEntity(db, address); err == nil {
dao.Commit(db)
outAddress = address
} else {
dao.Rollback(db)
}
}
globals.SugarLogger.Debugf("AddUserDeliveryAddress3 address:%s", utils.Format4Output(address, true))
return outAddress, err
}
func AddMyDeliveryAddress(ctx *jxcontext.Context, address *model.UserDeliveryAddress) (outAddress *model.UserDeliveryAddress, err error) {
globals.SugarLogger.Debugf("AddMyDeliveryAddress address:%s", utils.Format4Output(address, true))
_, address.UserID = ctx.GetMobileAndUserID()
outAddress, err = AddUserDeliveryAddress(ctx, address)
globals.SugarLogger.Debugf("AddMyDeliveryAddress2 address:%s, err:%v", utils.Format4Output(address, true), err)
return outAddress, err
}
func DeleteUserDeliveryAddress(ctx *jxcontext.Context, userID string, addressID int) (err error) {
num, err := dao.DeleteEntityLogically(dao.GetDB(), &model.UserDeliveryAddress{}, nil, ctx.GetUserName(), map[string]interface{}{
model.FieldID: addressID,
"UserID": userID,
})
if err == nil {
if num == 0 {
err = fmt.Errorf("地址ID:%d不存在", addressID)
}
}
return err
}
func DeleteMyDeliveryAddress(ctx *jxcontext.Context, addressID int) (err error) {
_, userID := ctx.GetMobileAndUserID()
return DeleteUserDeliveryAddress(ctx, userID, addressID)
}
func UpdateUserDeliveryAddress(ctx *jxcontext.Context, userID string, addressID int, payload map[string]interface{}) (err error) {
if userID == "" {
return fmt.Errorf("操作用户配送地址时必须指定UserID")
}
address := &model.UserDeliveryAddress{
UserID: userID,
}
address.ID = addressID
db := dao.GetDB()
if err = dao.GetEntity(db, address, model.FieldID, "UserID"); err == nil {
var outAddress *model.UserDeliveryAddress
valid := dao.StrictMakeMapByStructObject2(payload, address, &outAddress, ctx.GetUserName())
delete(valid, "autoAddress")
delete(valid, "districtCode")
delete(valid, "cityCode")
if len(valid) > 0 {
if valid["lng"] != nil || valid["lat"] != nil {
valid["autoAddress"], valid["districtCode"], valid["cityCode"], err = getAddressInfoFromCoord(db, outAddress.Lng, outAddress.Lat)
if err != nil {
return err
}
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if utils.ForceInterface2Int64(valid["isDefault"]) == 1 {
if err = dao.ClearUserDeliveryAddressDefault(db, userID, 0); err != nil {
dao.Rollback(db)
return err
}
}
if _, err = dao.UpdateEntityLogically(db, address, valid, ctx.GetUserName(), nil); err == nil {
dao.Commit(db)
} else {
dao.Rollback(db)
}
}
}
return err
}
func UpdateMyDeliveryAddress(ctx *jxcontext.Context, addressID int, payload map[string]interface{}) (err error) {
_, userID := ctx.GetMobileAndUserID()
return UpdateUserDeliveryAddress(ctx, userID, addressID, payload)
}
func QueryUserDeliveryAddress(ctx *jxcontext.Context, userIDs []string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
addressList, totalCount, err := dao.QueryUserDeliveryAddress(dao.GetDB(), 0, userIDs, offset, pageSize)
if err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: totalCount,
Data: addressList,
}
}
return pagedInfo, err
}
func QueryMyDeliveryAddress(ctx *jxcontext.Context) (addressList []*dao.UserDeliveryAddressEx, err error) {
_, userID := ctx.GetMobileAndUserID()
addressList, _, err = dao.QueryUserDeliveryAddress(dao.GetDB(), 0, []string{userID}, 0, model.UnlimitedPageSize)
return addressList, err
}
func SaveUserCart(ctx *jxcontext.Context, userID string, storeID int, cartItems []*model.UserCartItem) (err error) {
if userID == "" || storeID == 0 {
return fmt.Errorf("用户与门店必须要指定")
}
for _, v := range cartItems {
v.UserID = userID
v.StoreID = storeID
dao.WrapAddIDCULEntity(v, userID)
}
db := dao.GetDB()
dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db)
if r != nil {
panic(r)
}
}
}()
_, err = dao.ExecuteSQL(db, `
DELETE t1
FROM user_cart_item t1
WHERE t1.user_id = ? AND t1.store_id = ?
`, userID, storeID)
if err != nil {
return err
}
if len(cartItems) > 0 {
err = dao.CreateMultiEntities(db, cartItems)
}
if err == nil {
dao.Commit(db)
}
return err
}
func LoadUserCart(ctx *jxcontext.Context, userID string, storeIDs []int) (cartItems []*model.UserCartItem, err error) {
if userID == "" || len(storeIDs) == 0 {
return nil, fmt.Errorf("用户与门店必须要指定")
}
sql := `
SELECT t1.*
FROM user_cart_item t1
WHERE t1.user_id = ? AND t1.store_id IN (` + dao.GenQuestionMarks(len(storeIDs)) + `)
ORDER BY t1.sku_id
`
err = dao.GetRows(dao.GetDB(), &cartItems, sql, userID, storeIDs)
return cartItems, err
}
func GetSelfInfo(ctx *jxcontext.Context) (user *model.User, err error) {
tokenInfo, err := auth2.GetTokenInfo(ctx.GetToken())
if err == nil {
user, err = dao.GetUserByID(dao.GetDB(), "user_id", tokenInfo.GetID())
}
return user, err
}
func HandleUserWXRemark(db *dao.DaoDB, mobile string, mobileIsUerID bool) (err error) {
if db == nil {
db = dao.GetDB()
}
openIDs := []string{}
storeID := 0
remark := ""
// if !globals.DisableWXAuth1 {
// wxinfo, err := dao.GetUserStoreInfo(db, "tel", mobile)
// if err == nil {
// openIDs = []string{wxinfo.OpenID}
// storeID = wxinfo.JxStoreID
// }
// }
if globals.EnableWXAuth2 {
userID := ""
if mobileIsUerID {
userID = mobile
} else {
userList, _, err2 := dao.GetUsers(db, model.UserTypeStoreBoss, "", nil, nil, []string{mobile}, 0, -1)
if err = err2; len(userList) > 0 {
userID = userList[0].GetID()
}
}
if userID != "" {
authBindList, err2 := dao.GetUserBindAuthInfo(db, userID, model.AuthBindTypeAuth, []string{weixin.AuthTypeMP}, "", "")
if err = err2; err == nil {
for _, v := range authBindList {
openIDs = append(openIDs, v.AuthID)
}
}
roleList, err2 := api2.RoleMan.GetUserRoleList(userID)
if err = err2; err == nil && len(roleList) > 0 {
storeID = roleList[0].StoreID
}
}
}
if len(openIDs) > 0 {
if storeID > 0 {
store := &model.Store{}
store.ID = storeID
if err = dao.GetEntity(db, store); err == nil {
city := &model.Place{
Code: store.CityCode,
}
if err = dao.GetEntity(db, city, "Code"); err == nil {
remark = city.Name + "-" + store.Name
}
}
}
if err == nil {
if globals.EnableStoreWrite {
for _, openID := range openIDs {
err = api.WeixinAPI.CBUpdateRemark(openID, remark)
}
}
}
}
return err
}
func GetJdUsers(ctx *jxcontext.Context, isAsync, isContinueWhenError bool) (hint string, err error) {
var (
jxVendorIDsMap = make(map[string]string)
pageNoList []int
storeUserList []interface{}
disabledIdList []interface{}
)
db := dao.GetDB()
jdUsersStruct.userMap = jdUsersStruct.userMap[0:0]
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
//获取京东商城所有用户
apiList := apimanager.CurAPIManager.GetAppOrgCodeList(model.VendorIDJD)
for _, v := range apiList {
_, _, toatlPage, _ := jd.GetAPI(v).PrivilegeSearchUser(1)
for i := 1; i <= toatlPage; i++ {
pageNoList = append(pageNoList, i)
}
storeMapList, _ := dao.GetStoreMapsListWithoutDisabled(db, []int{model.VendorIDJD}, model.StoreStatusDisabled)
for _, v := range storeMapList {
jxVendorIDsMap[v.VendorStoreID] = utils.Int64ToStr(int64(v.StoreID))
}
taskFunc1 := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
pageNo := batchItemList[0].(int)
storeUserLists, _, _, err := jd.GetAPI(v).PrivilegeSearchUser(pageNo)
retVal = storeUserLists
return retVal, err
}
taskParallel1 := tasksch.NewParallelTask("获取京东商城所有用户列表", tasksch.NewParallelConfig(), ctx, taskFunc1, pageNoList)
tasksch.HandleTask(taskParallel1, task, true).Run()
storeUserList, err = taskParallel1.GetResult(0)
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vv := batchItemList[0].(*jdapi.StoreUserInfo)
vendorStoreIDs, err := jd.GetAPI(v).GetJdUserBindStoreIDs(vv.ID)
var vendorStoreIDsMap = make(map[string]string, len(vendorStoreIDs))
var vendorStoreIDsResult []string
var roleNameStr string
for _, v := range vendorStoreIDs {
if jxVendorIDsMap[v] == "" {
continue
}
vendorStoreIDsMap[v] = jxVendorIDsMap[v]
}
if vv.RoleNameStr != "" {
roleNameStr = strings.ReplaceAll(vv.RoleNameStr, " ", "")
if roleNameStr != jdapi.JdUserRoleJHYName && roleNameStr != jdapi.JdUserRolesName && roleNameStr != jdapi.JdUserNoRole {
jd.GetAPI(v).UpdateJdUserRoles(int64(vv.ID), []string{jdapi.JdUserRoleJHYId})
}
}
if len(vendorStoreIDsMap) == 0 {
isManager, _ := jd.GetAPI(v).IsJdManagerUser(int64(vv.ID))
if isManager {
jdStruct := JdUserStruct{vv.LoginName, "商家管理员", vv.RoleNameStr, vv.LockStatus}
jdUsersStruct.AppendData(jdStruct)
} else {
retVal = []int64{int64(vv.ID)}
}
} else {
for _, m := range vendorStoreIDsMap {
vendorStoreIDsResult = append(vendorStoreIDsResult, m)
}
sort.Strings(vendorStoreIDsResult[:])
jdStruct := JdUserStruct{vv.LoginName, strings.Join(vendorStoreIDsResult, ","), vv.RoleNameStr, vv.LockStatus}
jdUsersStruct.AppendData(jdStruct)
}
return retVal, err
}
taskParallel := tasksch.NewParallelTask("获取京东商城用户关联门店列表", tasksch.NewParallelConfig(), ctx, taskFunc, storeUserList)
tasksch.HandleTask(taskParallel, task, true).Run()
disabledIdList, err = taskParallel.GetResult(0)
taskFunc2 := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
id := batchItemList[0].(int64)
jd.GetAPI(v).PrivilegeUpdateJdUserStatus(id, jdapi.JdUserStatusDisable)
return retVal, err
}
taskParallel2 := tasksch.NewParallelTask("禁用未关联活跃门店用户", tasksch.NewParallelConfig(), ctx, taskFunc2, disabledIdList)
tasksch.HandleTask(taskParallel2, task, true).Run()
_, err = taskParallel2.GetResult(0)
}
case 1:
WriteToExcelJd(task, jdUsersStruct.userMap)
}
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 (d *GetJdUsersStruct) AppendData(jd JdUserStruct) {
d.locker.RLock()
defer d.locker.RUnlock()
d.userMap = append(d.userMap, jd)
}
func WriteToExcelJd(task *tasksch.SeqTask, jd []JdUserStruct) (err error) {
var sheetList []*excel.Obj2ExcelSheetConfig
var downloadURL, fileName string
excelConf := &excel.Obj2ExcelSheetConfig{
Title: "京东用户列表",
Data: jd,
CaptionList: titleListJdUser,
}
sheetList = append(sheetList, excelConf)
if excelConf != nil {
downloadURL, fileName, err = jxutils.UploadExeclAndPushMsg(sheetList, "京东用户列表")
} else {
baseapi.SugarLogger.Debug("WriteToExcel: JdUserStruct is nil!")
}
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 UpdateUserWxNoAndPercent(user *model.User, isReceiver bool) (num int64, err error) {
db := dao.GetDB()
user2, err := dao.GetUserByID(db, "user_id", user.UserID)
auth, err := dao.GetUserBindAuthInfo(db, user.UserID, model.AuthBindTypeAuth, []string{"weixinmini"}, "", "")
if len(auth) == 0 {
return 0, fmt.Errorf("未找到此用户的微信验证方式用户ID[%v]\n", user.UserID)
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db)
if r != nil {
panic(r)
}
}
}()
user2.DividePercentage = user.DividePercentage
num2, err := dao.UpdateEntity(db, user2, "DividePercentage")
num += num2
if err != nil {
dao.Rollback(db)
}
if isReceiver {
param := &wxpayapi.ProfitSharingReceiverParam{
Receiver: wxpayapi.CData(`{
"type":"` + wxpayapi.AccountTypeOpen + `",
"account":"` + auth[0].AuthID + `",
"relation_type":" ` + wxpayapi.Relation + `"
}`),
}
_, err := api.WxpayAPI.AddProfitSharingReceiver(param)
if err != nil {
return 0, err
} else {
user2.IsReceiver = 1
num3, err := dao.UpdateEntity(db, user2, "IsReceiver")
num += num3
if err != nil {
dao.Rollback(db)
}
}
}
dao.Commit(db)
return num, err
}
func DeleteProfitSharingReceiver(ctx *jxcontext.Context, userID string) (err error) {
db := dao.GetDB()
auth, err := dao.GetUserBindAuthInfo(db, userID, model.AuthBindTypeAuth, []string{"weixinmini"}, "", "")
if len(auth) == 0 {
return fmt.Errorf("未找到此用户的微信验证方式用户ID[%v]\n", userID)
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db)
if r != nil {
panic(r)
}
}
}()
param := &wxpayapi.ProfitSharingReceiverParam{
Receiver: wxpayapi.CData(`{
"type":"` + wxpayapi.AccountTypeOpen + `",
"account":"` + auth[0].AuthID + `"
}`),
}
_, err = api.WxpayAPI.DeleteProfitSharingReceiver(param)
if err != nil {
return err
} else {
user2, err := dao.GetUserByID(db, "user_id", userID)
user2.IsReceiver = 0
_, err = dao.UpdateEntity(db, user2, "IsReceiver")
if err != nil {
dao.Rollback(db)
}
}
dao.Commit(db)
return err
}