@@ -6,7 +6,8 @@ from account import views as account_views  | 
            ||
| 6 | 6 | 
                from account import tourguide_views  | 
            
| 7 | 7 | 
                from geo import views as geo_views  | 
            
| 8 | 8 | 
                from group import views as group_views  | 
            
| 9 | 
                -from group import groupuser_views, lensman_views, tourguidegroup_views, tourguidegroupuser_views  | 
            |
| 9 | 
                +from group import (groupuser_views, lensman_views, tourguidegroup_views, tourguidegroupadmin_views,  | 
            |
| 10 | 
                + tourguidegroupuser_views)  | 
            |
| 10 | 11 | 
                from message import views as message_views  | 
            
| 11 | 12 | 
                from miniapp import views as mini_views  | 
            
| 12 | 13 | 
                from operation import views as op_views  | 
            
                @@ -79,6 +80,10 @@ urlpatterns += [  | 
            ||
| 79 | 80 | 
                # url(r'^tg/gather/end$', tourguidegroup_views.tg_group_gather_end_api, name='tg_group_gather_end_api'), # 旅行团集合结束,清理数据  | 
            
| 80 | 81 | 
                url(r'^tg/token$', tourguidegroup_views.tg_group_token_api, name='tg_group_token_api'), # 旅行团权限管理票据  | 
            
| 81 | 82 | 
                url(r'^tg/transfer$', tourguidegroup_views.tg_group_transfer_api, name='tg_group_transfer_api'), # 旅行团权限管理转移  | 
            
| 83 | 
                +  | 
            |
| 84 | 
                + url(r'^tg/admin/list$', tourguidegroupadmin_views.tg_group_admin_list_api, name='tg_group_admin_list_api'), # 旅行团管理员列表  | 
            |
| 85 | 
                + url(r'^tg/admin/recovery$', tourguidegroupadmin_views.tg_group_admin_recovery_api, name='tg_group_admin_recovery_api'), # 旅行团管理员权限回收,管理员主动,团成员被动  | 
            |
| 86 | 
                + url(r'^tg/admin/waiver$', tourguidegroupadmin_views.tg_group_admin_waiver_api, name='tg_group_admin_waiver_api'), # 旅行团管理员权限放弃  | 
            |
| 82 | 87 | 
                ]  | 
            
| 83 | 88 | 
                 | 
            
| 84 | 89 | 
                # 旅行团成员相关  | 
            
                @@ -88,9 +88,13 @@ def group_user_remove_api(request):  | 
            ||
| 88 | 88 | 
                return response(GroupStatusCode.GROUP_NOT_FOUND)  | 
            
| 89 | 89 | 
                 | 
            
| 90 | 90 | 
                # 权限校验  | 
            
| 91 | 
                - if group.admin_id != admin_id or group.admin_id == user_id: # 管理员也不允许将自己移除  | 
            |
| 91 | 
                + if group.admin_id != admin_id:  | 
            |
| 92 | 92 | 
                return response(GroupStatusCode.NO_REMOVE_PERMISSION)  | 
            
| 93 | 93 | 
                 | 
            
| 94 | 
                + # 管理员也不允许将自己移除  | 
            |
| 95 | 
                + if group.admin_id == user_id:  | 
            |
| 96 | 
                + return response(GroupStatusCode.ADMIN_CANNOT_HANDLE_SELF)  | 
            |
| 97 | 
                +  | 
            |
| 94 | 98 | 
                # 群组用户校验  | 
            
| 95 | 99 | 
                try:  | 
            
| 96 | 100 | 
                group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, status=True)  | 
            
                @@ -177,6 +177,22 @@ class GroupUserInfo(CreateUpdateMixin):  | 
            ||
| 177 | 177 | 
                'remark': self.remark,  | 
            
| 178 | 178 | 
                }  | 
            
| 179 | 179 | 
                 | 
            
| 180 | 
                + @property  | 
            |
| 181 | 
                + def admin_info(self):  | 
            |
| 182 | 
                +        return {
               | 
            |
| 183 | 
                + 'user_id': self.user_id,  | 
            |
| 184 | 
                + 'nickname': self.nickname,  | 
            |
| 185 | 
                + 'avatar': self.avatar,  | 
            |
| 186 | 
                + 'admin': self.admin,  | 
            |
| 187 | 
                + 'subadmin': self.subadmin,  | 
            |
| 188 | 
                + 'name': self.name,  | 
            |
| 189 | 
                + 'phone': self.phone,  | 
            |
| 190 | 
                + 'relative_persons': self.relative_persons,  | 
            |
| 191 | 
                + 'authority': self.authority,  | 
            |
| 192 | 
                + 'remark': self.remark,  | 
            |
| 193 | 
                + 'status': self.status,  | 
            |
| 194 | 
                + }  | 
            |
| 195 | 
                +  | 
            |
| 180 | 196 | 
                 | 
            
| 181 | 197 | 
                class GroupPhotoInfo(CreateUpdateMixin):  | 
            
| 182 | 198 | 
                APP_GROUP = 0  | 
            
                @@ -13,6 +13,7 @@ from TimeConvert import TimeConvert as tc  | 
            ||
| 13 | 13 | 
                 | 
            
| 14 | 14 | 
                from account.models import UserInfo  | 
            
| 15 | 15 | 
                from group.models import GroupInfo, GroupUserInfo  | 
            
| 16 | 
                +from utils.admin_utils import is_group_admin, is_group_subadmin  | 
            |
| 16 | 17 | 
                from utils.error.errno_utils import GroupStatusCode, GroupUserStatusCode, TokenStatusCode, UserStatusCode  | 
            
| 17 | 18 | 
                from utils.error.response_utils import response  | 
            
| 18 | 19 | 
                from utils.redis.connect import r  | 
            
                @@ -263,8 +264,8 @@ def tg_group_gather_start_api(request):  | 
            ||
| 263 | 264 | 
                return response(GroupStatusCode.GROUP_NOT_FOUND)  | 
            
| 264 | 265 | 
                 | 
            
| 265 | 266 | 
                # 权限校验  | 
            
| 266 | 
                - if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists():  | 
            |
| 267 | 
                - return response(GroupStatusCode.NO_UPDATE_PERMISSION)  | 
            |
| 267 | 
                + if not is_group_subadmin(group_id, admin_id):  | 
            |
| 268 | 
                + return response(GroupStatusCode.NOT_GROUP_SUBADMIN)  | 
            |
| 268 | 269 | 
                 | 
            
| 269 | 270 | 
                # 集合信息设置  | 
            
| 270 | 271 | 
                group.gather_at = gather_at  | 
            
                @@ -331,8 +332,8 @@ def tg_group_transfer_api(request):  | 
            ||
| 331 | 332 | 
                return response(GroupStatusCode.GROUP_NOT_FOUND)  | 
            
| 332 | 333 | 
                 | 
            
| 333 | 334 | 
                # 权限校验  | 
            
| 334 | 
                - if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, admin=True, status=True).exists():  | 
            |
| 335 | 
                - return response(GroupStatusCode.NO_TRANSFER_PERMISSION)  | 
            |
| 335 | 
                + if not is_group_admin(group_id, admin_id):  | 
            |
| 336 | 
                + return response(GroupStatusCode.NOT_GROUP_ADMIN)  | 
            |
| 336 | 337 | 
                 | 
            
| 337 | 338 | 
                # 群组用户记录创建,若记录不存在,则创建,若记录已存在,则更新  | 
            
| 338 | 339 | 
                group_user, created = GroupUserInfo.objects.get_or_create(  | 
            
                @@ -0,0 +1,89 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from __future__ import division  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +import json  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +from django.conf import settings  | 
            |
| 8 | 
                +from django.db import transaction  | 
            |
| 9 | 
                +from logit import logit  | 
            |
| 10 | 
                +from TimeConvert import TimeConvert as tc  | 
            |
| 11 | 
                +  | 
            |
| 12 | 
                +from account.models import UserInfo  | 
            |
| 13 | 
                +from group.models import GroupInfo, GroupUserInfo  | 
            |
| 14 | 
                +from utils.admin_utils import is_group_admin, is_group_subadmin  | 
            |
| 15 | 
                +from utils.error.errno_utils import GroupStatusCode, GroupUserStatusCode, UserStatusCode  | 
            |
| 16 | 
                +from utils.error.response_utils import response  | 
            |
| 17 | 
                +from utils.group_photo_utils import get_current_photos  | 
            |
| 18 | 
                +from utils.redis.connect import r  | 
            |
| 19 | 
                +from utils.redis.rgroup import get_group_info, get_group_users_info, get_group_users_kv_info, set_group_users_info  | 
            |
| 20 | 
                +from utils.redis.rkeys import (GROUP_LAST_PHOTO_PK, GROUP_USERS_DELETED_SET, GROUP_USERS_PASSED_SET,  | 
            |
| 21 | 
                + GROUP_USERS_QUIT_SET, GROUP_USERS_REFUSED_SET, TOUR_GUIDE_GROUP_CUR_GATHER_INFO,  | 
            |
| 22 | 
                + TOUR_GUIDE_GROUP_CUR_SESSION, TOUR_GUIDE_GROUP_GEO_INFO, TOUR_GUIDE_GROUP_GEO_SUBMIT_DT,  | 
            |
| 23 | 
                + TOUR_GUIDE_GROUP_USER_GEO_LIST)  | 
            |
| 24 | 
                +from utils.redis.rtourguide import get_tour_guide_own_group  | 
            |
| 25 | 
                +from utils.redis.rtouruser import set_tour_user_belong_group  | 
            |
| 26 | 
                +  | 
            |
| 27 | 
                +  | 
            |
| 28 | 
                +@logit  | 
            |
| 29 | 
                +def tg_group_admin_list_api(request):  | 
            |
| 30 | 
                + """ 旅行团管理员列表 """  | 
            |
| 31 | 
                +    group_id = request.POST.get('group_id', '')
               | 
            |
| 32 | 
                +    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识
               | 
            |
| 33 | 
                +  | 
            |
| 34 | 
                + # 权限校验  | 
            |
| 35 | 
                + if not is_group_admin(group_id, admin_id):  | 
            |
| 36 | 
                + return response(GroupStatusCode.NOT_GROUP_ADMIN)  | 
            |
| 37 | 
                +  | 
            |
| 38 | 
                + admins = GroupUserInfo.objects.filter(group_id=group_id, subadmin=True)  | 
            |
| 39 | 
                + admins = [admin.admin_info for admin in admins]  | 
            |
| 40 | 
                +  | 
            |
| 41 | 
                +    return response(200, 'Get Tour Guide Group Admin List Success', u'获取旅行团管理员列表成功', {
               | 
            |
| 42 | 
                + 'group_id': group_id,  | 
            |
| 43 | 
                + 'admins': admins,  | 
            |
| 44 | 
                + })  | 
            |
| 45 | 
                +  | 
            |
| 46 | 
                +  | 
            |
| 47 | 
                +@logit  | 
            |
| 48 | 
                +def tg_group_admin_recovery_api(request):  | 
            |
| 49 | 
                + """ 旅行团管理员权限回收,管理员主动,团成员被动 """  | 
            |
| 50 | 
                +    group_id = request.POST.get('group_id', '')
               | 
            |
| 51 | 
                +    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识
               | 
            |
| 52 | 
                +    user_id = request.POST.get('user_id', '')
               | 
            |
| 53 | 
                +  | 
            |
| 54 | 
                + # 权限校验  | 
            |
| 55 | 
                + if not is_group_admin(group_id, admin_id):  | 
            |
| 56 | 
                + return response(GroupStatusCode.NOT_GROUP_ADMIN)  | 
            |
| 57 | 
                +  | 
            |
| 58 | 
                + # 管理员也不允许将自己移除  | 
            |
| 59 | 
                + if admin_id == user_id:  | 
            |
| 60 | 
                + return response(GroupStatusCode.ADMIN_CANNOT_HANDLE_SELF)  | 
            |
| 61 | 
                +  | 
            |
| 62 | 
                + try:  | 
            |
| 63 | 
                + subadmin = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, subadmin=True)  | 
            |
| 64 | 
                + except GroupUserInfo.DoesNotExist:  | 
            |
| 65 | 
                + return response(GroupStatusCode.NOT_GROUP_SUBADMIN)  | 
            |
| 66 | 
                +  | 
            |
| 67 | 
                + # 权限回收  | 
            |
| 68 | 
                + subadmin.status = False  | 
            |
| 69 | 
                + subadmin.save()  | 
            |
| 70 | 
                +  | 
            |
| 71 | 
                + return response(200, 'Tour Guide Group Admin Right Recovery Success', u'旅行团管理员权限回收成功')  | 
            |
| 72 | 
                +  | 
            |
| 73 | 
                +  | 
            |
| 74 | 
                +@logit  | 
            |
| 75 | 
                +def tg_group_admin_waiver_api(request):  | 
            |
| 76 | 
                + """ 旅行团管理员权限放弃 """  | 
            |
| 77 | 
                +    group_id = request.POST.get('group_id', '')
               | 
            |
| 78 | 
                +    user_id = request.POST.get('user_id', '')
               | 
            |
| 79 | 
                +  | 
            |
| 80 | 
                + try:  | 
            |
| 81 | 
                + subadmin = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, subadmin=True)  | 
            |
| 82 | 
                + except GroupUserInfo.DoesNotExist:  | 
            |
| 83 | 
                + return response(GroupStatusCode.NOT_GROUP_SUBADMIN)  | 
            |
| 84 | 
                +  | 
            |
| 85 | 
                + # 权限回收  | 
            |
| 86 | 
                + subadmin.status = False  | 
            |
| 87 | 
                + subadmin.save()  | 
            |
| 88 | 
                +  | 
            |
| 89 | 
                + return response(200, 'Tour Guide Group Admin Right Waiver Success', u'旅行团管理员权限放弃成功')  | 
            
                @@ -11,6 +11,7 @@ from TimeConvert import TimeConvert as tc  | 
            ||
| 11 | 11 | 
                 | 
            
| 12 | 12 | 
                from account.models import UserInfo  | 
            
| 13 | 13 | 
                from group.models import GroupInfo, GroupUserInfo  | 
            
| 14 | 
                +from utils.admin_utils import is_group_subadmin  | 
            |
| 14 | 15 | 
                from utils.error.errno_utils import GroupStatusCode, GroupUserStatusCode, UserStatusCode  | 
            
| 15 | 16 | 
                from utils.error.response_utils import response  | 
            
| 16 | 17 | 
                from utils.group_photo_utils import get_current_photos  | 
            
                @@ -127,8 +128,12 @@ def tgu_group_user_remove_api(request):  | 
            ||
| 127 | 128 | 
                return response(GroupStatusCode.GROUP_NOT_FOUND)  | 
            
| 128 | 129 | 
                 | 
            
| 129 | 130 | 
                # 权限校验  | 
            
| 130 | 
                - if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists() or admin_id == user_id: # 管理员也不允许将自己移除  | 
            |
| 131 | 
                - return response(GroupStatusCode.NO_UPDATE_PERMISSION)  | 
            |
| 131 | 
                + if not is_group_subadmin(group_id, admin_id):  | 
            |
| 132 | 
                + return response(GroupStatusCode.NOT_GROUP_SUBADMIN)  | 
            |
| 133 | 
                +  | 
            |
| 134 | 
                + # 管理员也不允许将自己移除  | 
            |
| 135 | 
                + if admin_id == user_id:  | 
            |
| 136 | 
                + return response(GroupStatusCode.ADMIN_CANNOT_HANDLE_SELF)  | 
            |
| 132 | 137 | 
                 | 
            
| 133 | 138 | 
                # 群组用户校验  | 
            
| 134 | 139 | 
                try:  | 
            
                @@ -179,8 +184,8 @@ def tgu_group_user_update_api(request):  | 
            ||
| 179 | 184 | 
                 | 
            
| 180 | 185 | 
                # 权限校验  | 
            
| 181 | 186 | 
                if admin_id:  | 
            
| 182 | 
                - if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists():  | 
            |
| 183 | 
                - return response(GroupStatusCode.NO_UPDATE_PERMISSION)  | 
            |
| 187 | 
                + if not is_group_subadmin(group_id, admin_id):  | 
            |
| 188 | 
                + return response(GroupStatusCode.NOT_GROUP_SUBADMIN)  | 
            |
| 184 | 189 | 
                else:  | 
            
| 185 | 190 | 
                if not GroupUserInfo.objects.filter(group_id=group_id, user_id=user_id, status=True).exists():  | 
            
| 186 | 191 | 
                return response(GroupStatusCode.NO_UPDATE_PERMISSION)  | 
            
                @@ -237,8 +242,8 @@ def tgu_group_user_locations_api(request):  | 
            ||
| 237 | 242 | 
                     admin_id = request.POST.get('admin_id', '')  # 导游唯一标识
               | 
            
| 238 | 243 | 
                 | 
            
| 239 | 244 | 
                # 权限校验  | 
            
| 240 | 
                - if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists():  | 
            |
| 241 | 
                - return response(GroupStatusCode.NO_LOCATION_PERMISSION)  | 
            |
| 245 | 
                + if not is_group_subadmin(group_id, admin_id):  | 
            |
| 246 | 
                + return response(GroupStatusCode.NOT_GROUP_SUBADMIN)  | 
            |
| 242 | 247 | 
                 | 
            
| 243 | 248 | 
                # 获取集合经纬度  | 
            
| 244 | 249 | 
                     gather_info = json.loads(r.get(TOUR_GUIDE_GROUP_CUR_GATHER_INFO % group_id) or '{}')
               | 
            
                @@ -272,8 +277,8 @@ def tgu_group_user_location_api(request):  | 
            ||
| 272 | 277 | 
                     user_id = request.POST.get('user_id', '')
               | 
            
| 273 | 278 | 
                 | 
            
| 274 | 279 | 
                # 权限校验  | 
            
| 275 | 
                - if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists():  | 
            |
| 276 | 
                - return response(GroupStatusCode.NO_LOCATION_PERMISSION)  | 
            |
| 280 | 
                + if not is_group_subadmin(group_id, admin_id):  | 
            |
| 281 | 
                + return response(GroupStatusCode.NOT_GROUP_SUBADMIN)  | 
            |
| 277 | 282 | 
                 | 
            
| 278 | 283 | 
                session_id = r.get(TOUR_GUIDE_GROUP_CUR_SESSION % group_id)  | 
            
| 279 | 284 | 
                locations = r.lrange(TOUR_GUIDE_GROUP_USER_GEO_LIST % (group_id, session_id, user_id), 0, -1)  | 
            
                @@ -0,0 +1,11 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +from group.models import GroupUserInfo  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +def is_group_admin(group_id, admin_id):  | 
            |
| 7 | 
                + return GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, admin=True, status=True).exists()  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                +def is_group_subadmin(group_id, admin_id):  | 
            |
| 11 | 
                + return GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists()  | 
            
                @@ -57,24 +57,27 @@ class GroupStatusCode(BaseStatusCode):  | 
            ||
| 57 | 57 | 
                """ 群组/团相关错误码 4020xx """  | 
            
| 58 | 58 | 
                GROUP_NOT_FOUND = StatusCodeField(402001, 'Group Not Found', description=u'群组不存在')  | 
            
| 59 | 59 | 
                GROUP_HAS_LOCKED = StatusCodeField(402002, 'Group Has Locked', description=u'群组已锁定')  | 
            
| 60 | 
                - NOT_GROUP_ADMIN = StatusCodeField(402003, 'Not Group Admin', description=u'非群组管理员')  | 
            |
| 60 | 
                + # 管理员  | 
            |
| 61 | 
                + NOT_GROUP_ADMIN = StatusCodeField(402010, 'Not Group Admin', description=u'非群组管理员')  | 
            |
| 62 | 
                + NOT_GROUP_SUBADMIN = StatusCodeField(402011, 'Not Group Sub Admin', description=u'非群组协同管理员')  | 
            |
| 63 | 
                + ADMIN_CANNOT_HANDLE_SELF = StatusCodeField(402012, 'Admin Cannot Handle Self', description=u'群组管理员无法操作自身')  | 
            |
| 61 | 64 | 
                # 权限  | 
            
| 62 | 
                - NO_UPDATE_PERMISSION = StatusCodeField(402010, 'No Update Permission', description=u'没有更新权限')  | 
            |
| 63 | 
                - NO_LOCK_PERMISSION = StatusCodeField(402011, 'No Lock Permission', description=u'没有锁定权限')  | 
            |
| 64 | 
                - NO_UNLOCK_PERMISSION = StatusCodeField(402012, 'No Unlock Permission', description=u'没有解锁权限')  | 
            |
| 65 | 
                - NO_REMOVE_PERMISSION = StatusCodeField(402013, 'No Remove Permission', description=u'没有移除权限')  | 
            |
| 66 | 
                - NO_QUIT_PERMISSION = StatusCodeField(402014, 'No Quit Permission', description=u'没有退出权限')  | 
            |
| 67 | 
                - NO_PASS_PERMISSION = StatusCodeField(402015, 'No Pass Permission', description=u'没有通过权限')  | 
            |
| 68 | 
                - NO_REFUSE_PERMISSION = StatusCodeField(402016, 'No Refuse Permission', description=u'没有拒绝权限')  | 
            |
| 69 | 
                - NO_CLOSE_PERMISSION = StatusCodeField(402017, 'No Close Permission', description=u'没有关闭权限')  | 
            |
| 70 | 
                - NO_TRANSFER_PERMISSION = StatusCodeField(402018, 'No Transfer Permission', description=u'没有转移权限')  | 
            |
| 71 | 
                - NO_LOCATION_PERMISSION = StatusCodeField(402019, 'No Location Permission', description=u'没有地理位置权限')  | 
            |
| 65 | 
                + NO_UPDATE_PERMISSION = StatusCodeField(402020, 'No Update Permission', description=u'无更新权限')  | 
            |
| 66 | 
                + NO_LOCK_PERMISSION = StatusCodeField(402021, 'No Lock Permission', description=u'无锁定权限')  | 
            |
| 67 | 
                + NO_UNLOCK_PERMISSION = StatusCodeField(402022, 'No Unlock Permission', description=u'无解锁权限')  | 
            |
| 68 | 
                + NO_REMOVE_PERMISSION = StatusCodeField(402023, 'No Remove Permission', description=u'无移除权限')  | 
            |
| 69 | 
                + NO_QUIT_PERMISSION = StatusCodeField(402024, 'No Quit Permission', description=u'无退出权限')  | 
            |
| 70 | 
                + NO_PASS_PERMISSION = StatusCodeField(402025, 'No Pass Permission', description=u'无通过权限')  | 
            |
| 71 | 
                + NO_REFUSE_PERMISSION = StatusCodeField(402026, 'No Refuse Permission', description=u'无拒绝权限')  | 
            |
| 72 | 
                + NO_CLOSE_PERMISSION = StatusCodeField(402027, 'No Close Permission', description=u'无关闭权限')  | 
            |
| 73 | 
                + NO_TRANSFER_PERMISSION = StatusCodeField(402028, 'No Transfer Permission', description=u'无转移权限')  | 
            |
| 74 | 
                + NO_LOCATION_PERMISSION = StatusCodeField(402029, 'No Location Permission', description=u'无地理位置权限')  | 
            |
| 72 | 75 | 
                # 请求  | 
            
| 73 | 
                - DUPLICATE_JOIN_REQUEST = StatusCodeField(402020, 'Duplicate Join Request', description=u'重复加群申请')  | 
            |
| 74 | 
                - JOIN_REQUEST_NOT_FOUND = StatusCodeField(402021, 'Join Request Not Found', description=u'加群申请不存在')  | 
            |
| 76 | 
                + DUPLICATE_JOIN_REQUEST = StatusCodeField(402030, 'Duplicate Join Request', description=u'重复加群申请')  | 
            |
| 77 | 
                + JOIN_REQUEST_NOT_FOUND = StatusCodeField(402031, 'Join Request Not Found', description=u'加群申请不存在')  | 
            |
| 75 | 78 | 
                # 旅行团  | 
            
| 76 | 
                - GROUP_HAS_ENDED = StatusCodeField(402030, 'Group Has Ended', description=u'群组已结束')  | 
            |
| 77 | 
                - COULD_HAVE_ONLY_ONE_ACTIVE_GROUP = StatusCodeField(402031, 'Could Have Only One Active Group', description=u'只能创建一个活跃团')  | 
            |
| 79 | 
                + GROUP_HAS_ENDED = StatusCodeField(402040, 'Group Has Ended', description=u'群组已结束')  | 
            |
| 80 | 
                + COULD_HAVE_ONLY_ONE_ACTIVE_GROUP = StatusCodeField(402041, 'Could Have Only One Active Group', description=u'只能创建一个活跃团')  | 
            |
| 78 | 81 | 
                 | 
            
| 79 | 82 | 
                 | 
            
| 80 | 83 | 
                class GroupUserStatusCode(BaseStatusCode):  | 
            
                @@ -104,7 +107,7 @@ class OrderStatusCode(BaseStatusCode):  | 
            ||
| 104 | 107 | 
                WX_ORDER_PAY_FAIL = StatusCodeField(404009, 'WX Order Pay Fail', description=u'微信支付失败')  | 
            
| 105 | 108 | 
                SIGN_CHECK_FAIL = StatusCodeField(404010, 'Sign Check Fail', description=u'签名校验失败')  | 
            
| 106 | 109 | 
                FEE_CHECK_FAIL = StatusCodeField(404011, 'FEE Check Fail', description=u'金额校验失败')  | 
            
| 107 | 
                - NO_DETAIL_PERMISSION = StatusCodeField(404015, 'No Detail Permission', description=u'没有详情权限')  | 
            |
| 110 | 
                + NO_DETAIL_PERMISSION = StatusCodeField(404015, 'No Detail Permission', description=u'无详情权限')  | 
            |
| 108 | 111 | 
                WX_ORDER_PAID_ALREADY_EXISTS = StatusCodeField(404020, 'WX Order Paid Already Exists', description=u'照片已购买')  | 
            
| 109 | 112 | 
                 | 
            
| 110 | 113 | 
                 |