package cms import ( "errors" "fmt" "sort" "strings" "sync" "time" "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) // auth2.RemoveUserInfo(mobileAuth.Token) // if newAuthInfo, err := auth2.BindUser(mobileAuth, user); err == nil { // globals.SugarLogger.Debugf("testRegisterUserWithMobile", utils.Format4Output(mobileAuth, false), utils.Format4Output(newAuthInfo, false)) // return nil, jsonerr.New(newAuthInfo, model.ErrCodeJsonUserAlreadyExist) // } else { // return nil, err // } } } 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 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 = 1 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"}, "", "", "wx4b5930c13f8b1170") 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 { } dao.Commit(db) return num, err } func DeleteUserInfo(ctx *jxcontext.Context, userID string) (err error) { db := dao.GetDB() sql := ` UPDATE user SET status = ? WHERE user_id = ? ` sqlParams := []interface{}{ model.NO, userID, } _, err = dao.ExecuteSQL(db, sql, sqlParams) /* 删除离职人员门店市场人员 */ sql2 := ` UPDATE store t1 LEFT JOIN user t2 ON t2.mobile = t1.market_man_phone AND t2.status <> 0 SET t1.market_man_phone = '' WHERE t2.id IS NULL ` _, err = dao.ExecuteSQL(db, sql2, nil) /* 删除离职人员门店运营人员 */ sql3 := ` UPDATE store t1 LEFT JOIN user t2 ON t2.mobile = t1.operator_phone AND t2.status <> 0 SET t1.operator_phone = '' WHERE t2.id IS NULL ` _, err = dao.ExecuteSQL(db, sql3, nil) /* 删除离职人员门店运营人员 */ sql4 := ` UPDATE store t1 LEFT JOIN user t2 ON t2.mobile = t1.operator_phone2 AND t2.status <> 0 SET t1.operator_phone2 = '' WHERE t2.id IS NULL ` _, err = dao.ExecuteSQL(db, sql4, nil) /*删除离职人员的角色信息*/ sql5 := ` DELETE t1 FROM casbin_rule t1 LEFT JOIN user t2 ON t2.user_id = t1.v0 AND t2.status <> 0 WHERE t2.id IS NULL ` _, err = dao.ExecuteSQL(db, sql5, nil) //删除token tokens, err := api.Cacher.Keys("TOKEN.V2." + userID + "*") for _, v := range tokens { err = api.Cacher.Del(v) } return err } func GetMyJxStoreList(ctx *jxcontext.Context, mobile string) (storesInfo interface{}, err error) { db := dao.GetDB() user, err := dao.GetUserByID(db, "mobile", mobile) if err != nil { return nil, err } userID := user.UserID var storeList []*dao.StoreWithCityName if storeList, err = GetStoreList4User(ctx, mobile, 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 CreateUserAgreement(ctx *jxcontext.Context, userAgrs []*model.UserAgreement) (err error) { var ( db = dao.GetDB() ) for _, v := range userAgrs { dao.WrapAddIDCULDEntity(v, ctx.GetUserName()) } err = dao.CreateMultiEntities(db, userAgrs) return err } func GetUserAgreement(ctx *jxcontext.Context, name, idNumber, bankNumber, mobile string) (userAgrs []*model.UserAgreement, err error) { var ( db = dao.GetDB() ) userAgrs, err = dao.GetUserAgreement(db, name, idNumber, bankNumber, mobile) return userAgrs, err } func CleanUserOrderSMSMark(ctx *jxcontext.Context) (err error) { var ( db = dao.GetDB() ) if time.Now().Day() == 1 { sql := ` UPDATE user_order_sms SET sms_mark = ? ` sqlParams := []interface{}{model.NO} _, err = dao.ExecuteSQL(db, sql, sqlParams) } return err }