@@ -64,3 +64,6 @@ collect_static/  | 
            ||
| 64 | 64 | 
                 | 
            
| 65 | 65 | 
                # Special File  | 
            
| 66 | 66 | 
                *download.html  | 
            
| 67 | 
                +  | 
            |
| 68 | 
                +# Qiniu  | 
            |
| 69 | 
                +.qiniu_pythonsdk_hostscache.json  | 
            
                @@ -398,6 +398,8 @@ def consumer_info_api(request):  | 
            ||
| 398 | 398 | 
                log.has_scan = True  | 
            
| 399 | 399 | 
                log.save()  | 
            
| 400 | 400 | 
                 | 
            
| 401 | 
                + # TODO: 发放会员权益  | 
            |
| 402 | 
                +  | 
            |
| 401 | 403 | 
                return response(200, 'Submit Consumer Info Success', u'提交消费者信息成功')  | 
            
| 402 | 404 | 
                 | 
            
| 403 | 405 | 
                 | 
            
                @@ -3,13 +3,13 @@  | 
            ||
| 3 | 3 | 
                from __future__ import division  | 
            
| 4 | 4 | 
                 | 
            
| 5 | 5 | 
                from django.conf import settings  | 
            
| 6 | 
                +from django.db import transaction  | 
            |
| 6 | 7 | 
                from django_logit import logit  | 
            
| 7 | 8 | 
                from django_response import response  | 
            
| 8 | 
                -from paginator import pagination  | 
            |
| 9 | 9 | 
                 | 
            
| 10 | 10 | 
                from account.models import UserInfo  | 
            
| 11 | 
                -from member.models import GoodsInfo, MemberActivityInfo, RightInfo  | 
            |
| 12 | 
                -from utils.error.errno_utils import UserStatusCode  | 
            |
| 11 | 
                +from member.models import GoodsInfo, GoodsOrderInfo, MemberActivityInfo, MemberActivitySigninInfo, MemberActivitySignupInfo, RightInfo  | 
            |
| 12 | 
                +from utils.error.errno_utils import MemberActivityStatusCode, MemberGoodStatusCode, MemberRightStatusCode, UserStatusCode  | 
            |
| 13 | 13 | 
                from utils.redis.rshot import get_shot_member_data  | 
            
| 14 | 14 | 
                 | 
            
| 15 | 15 | 
                 | 
            
                @@ -79,7 +79,7 @@ def right_detail(request):  | 
            ||
| 79 | 79 | 
                try:  | 
            
| 80 | 80 | 
                right = RightInfo.objects.get(right_id=right_id)  | 
            
| 81 | 81 | 
                except RightInfo.DoesNotExist:  | 
            
| 82 | 
                - return response()  | 
            |
| 82 | 
                + return response(MemberRightStatusCode.RIGHT_NOT_FOUND)  | 
            |
| 83 | 83 | 
                 | 
            
| 84 | 84 | 
                     return response(200, data={
               | 
            
| 85 | 85 | 
                'right': right.data,  | 
            
                @@ -133,7 +133,65 @@ def good_detail(request):  | 
            ||
| 133 | 133 | 
                try:  | 
            
| 134 | 134 | 
                good = GoodsInfo.objects.get(good_id=good_id)  | 
            
| 135 | 135 | 
                except GoodsInfo.DoesNotExist:  | 
            
| 136 | 
                - return response()  | 
            |
| 136 | 
                + return response(MemberGoodStatusCode.GOOD_NOT_FOUND)  | 
            |
| 137 | 
                +  | 
            |
| 138 | 
                +    return response(200, data={
               | 
            |
| 139 | 
                + 'nickname': user.final_nickname,  | 
            |
| 140 | 
                + 'avatar': user.avatar,  | 
            |
| 141 | 
                + 'integral': user.integral,  | 
            |
| 142 | 
                + 'freeze_integral': user.freeze_integral,  | 
            |
| 143 | 
                + 'final_integral': user.final_integral,  | 
            |
| 144 | 
                + 'shots_num': user.shots_num,  | 
            |
| 145 | 
                + 'level': user.level,  | 
            |
| 146 | 
                + 'good': good.data,  | 
            |
| 147 | 
                + })  | 
            |
| 148 | 
                +  | 
            |
| 149 | 
                +  | 
            |
| 150 | 
                +@logit  | 
            |
| 151 | 
                +@transaction.atomic  | 
            |
| 152 | 
                +def good_exchange(request):  | 
            |
| 153 | 
                +    brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
               | 
            |
| 154 | 
                +    user_id = request.POST.get('user_id', '')
               | 
            |
| 155 | 
                +    good_id = request.POST.get('good_id', '')
               | 
            |
| 156 | 
                +    name = request.POST.get('name', '')
               | 
            |
| 157 | 
                +    phone = request.POST.get('phone', '')
               | 
            |
| 158 | 
                +    address = request.POST.get('address', '')
               | 
            |
| 159 | 
                +  | 
            |
| 160 | 
                + # 校验用户是否存在  | 
            |
| 161 | 
                + try:  | 
            |
| 162 | 
                + user = UserInfo.objects.select_for_update().get(user_id=user_id)  | 
            |
| 163 | 
                + except UserInfo.DoesNotExist:  | 
            |
| 164 | 
                + return response(UserStatusCode.USER_NOT_FOUND)  | 
            |
| 165 | 
                +  | 
            |
| 166 | 
                + try:  | 
            |
| 167 | 
                + good = GoodsInfo.objects.get(good_id=good_id)  | 
            |
| 168 | 
                + except GoodsInfo.DoesNotExist:  | 
            |
| 169 | 
                + return response(MemberGoodStatusCode.GOOD_NOT_FOUND)  | 
            |
| 170 | 
                +  | 
            |
| 171 | 
                + if user.level < good.minlevel:  | 
            |
| 172 | 
                + return response(MemberGoodStatusCode.GOOD_NO_EXCHANGE_PERMISSION)  | 
            |
| 173 | 
                +  | 
            |
| 174 | 
                + if user.integral < good.integral:  | 
            |
| 175 | 
                + return response(MemberGoodStatusCode.GOOD_INTEGRAL_NOT_ENOUGH)  | 
            |
| 176 | 
                +  | 
            |
| 177 | 
                + user.integral -= good.integral  | 
            |
| 178 | 
                + user.save()  | 
            |
| 179 | 
                +  | 
            |
| 180 | 
                + GoodsOrderInfo.objects.create(  | 
            |
| 181 | 
                + user_id=user_id,  | 
            |
| 182 | 
                + good_id=good_id,  | 
            |
| 183 | 
                + good_type=good.good_type,  | 
            |
| 184 | 
                + name=name,  | 
            |
| 185 | 
                + phone=phone,  | 
            |
| 186 | 
                + address=address,  | 
            |
| 187 | 
                + )  | 
            |
| 188 | 
                +  | 
            |
| 189 | 
                + if good.good_type == GoodsInfo.PHYSICAL:  | 
            |
| 190 | 
                + # TODO: 通知客服发快递  | 
            |
| 191 | 
                + pass  | 
            |
| 192 | 
                + else:  | 
            |
| 193 | 
                + # TODO: 发放虚拟商品  | 
            |
| 194 | 
                + pass  | 
            |
| 137 | 195 | 
                 | 
            
| 138 | 196 | 
                     return response(200, data={
               | 
            
| 139 | 197 | 
                'nickname': user.final_nickname,  | 
            
                @@ -192,9 +250,68 @@ def activity_detail(request):  | 
            ||
| 192 | 250 | 
                     activity_id = request.POST.get('activity_id')
               | 
            
| 193 | 251 | 
                 | 
            
| 194 | 252 | 
                try:  | 
            
| 195 | 
                - act = MemberActivityInfo.objects.get(pk=activity_id, status=True)  | 
            |
| 253 | 
                + act = MemberActivityInfo.objects.get(activity_id=activity_id, status=True)  | 
            |
| 196 | 254 | 
                except MemberActivityInfo.DoesNotExist:  | 
            
| 197 | 
                - return response()  | 
            |
| 255 | 
                + return response(MemberActivityStatusCode.ACTIVITY_NOT_FOUND)  | 
            |
| 256 | 
                +  | 
            |
| 257 | 
                +    return response(200, data={
               | 
            |
| 258 | 
                + 'activity': act.data,  | 
            |
| 259 | 
                + })  | 
            |
| 260 | 
                +  | 
            |
| 261 | 
                +  | 
            |
| 262 | 
                +@logit  | 
            |
| 263 | 
                +def activity_signup(request):  | 
            |
| 264 | 
                +    brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
               | 
            |
| 265 | 
                +    user_id = request.POST.get('user_id', '')
               | 
            |
| 266 | 
                +    activity_id = request.POST.get('activity_id')
               | 
            |
| 267 | 
                +    name = request.POST.get('name', '')
               | 
            |
| 268 | 
                +    phone = request.POST.get('phone', '')
               | 
            |
| 269 | 
                +  | 
            |
| 270 | 
                + try:  | 
            |
| 271 | 
                + act = MemberActivityInfo.objects.get(activity_id=activity_id, status=True)  | 
            |
| 272 | 
                + except MemberActivityInfo.DoesNotExist:  | 
            |
| 273 | 
                + return response(MemberActivityStatusCode.ACTIVITY_NOT_FOUND)  | 
            |
| 274 | 
                +  | 
            |
| 275 | 
                +    MemberActivitySignupInfo.objects.update_or_create(user_id=user_id, activity_id=activity_id, defaults={
               | 
            |
| 276 | 
                + 'title': act.title,  | 
            |
| 277 | 
                + 'name': name,  | 
            |
| 278 | 
                + 'phone': phone,  | 
            |
| 279 | 
                + })  | 
            |
| 280 | 
                +  | 
            |
| 281 | 
                + # TODO: 立即推送模版消息(报名成功,时间,地点)  | 
            |
| 282 | 
                + # TODO: 延迟(活动当天)推送模版消息(时间,地点)  | 
            |
| 283 | 
                +  | 
            |
| 284 | 
                +    return response(200, data={
               | 
            |
| 285 | 
                + 'activity': act.data,  | 
            |
| 286 | 
                + })  | 
            |
| 287 | 
                +  | 
            |
| 288 | 
                +  | 
            |
| 289 | 
                +@logit  | 
            |
| 290 | 
                +@transaction.atomic  | 
            |
| 291 | 
                +def activity_signin(request):  | 
            |
| 292 | 
                +    brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
               | 
            |
| 293 | 
                +    user_id = request.POST.get('user_id', '')
               | 
            |
| 294 | 
                +    activity_id = request.POST.get('activity_id')
               | 
            |
| 295 | 
                +  | 
            |
| 296 | 
                + # 校验用户是否存在  | 
            |
| 297 | 
                + try:  | 
            |
| 298 | 
                + user = UserInfo.objects.select_for_update().get(user_id=user_id)  | 
            |
| 299 | 
                + except UserInfo.DoesNotExist:  | 
            |
| 300 | 
                + return response(UserStatusCode.USER_NOT_FOUND)  | 
            |
| 301 | 
                +  | 
            |
| 302 | 
                + try:  | 
            |
| 303 | 
                + act = MemberActivityInfo.objects.get(activity_id=activity_id, status=True)  | 
            |
| 304 | 
                + except MemberActivityInfo.DoesNotExist:  | 
            |
| 305 | 
                + return response(MemberActivityStatusCode.ACTIVITY_NOT_FOUND)  | 
            |
| 306 | 
                +  | 
            |
| 307 | 
                +    MemberActivitySigninInfo.objects.update_or_create(user_id=user_id, activity_id=activity_id, defaults={
               | 
            |
| 308 | 
                + 'title': act.title,  | 
            |
| 309 | 
                + })  | 
            |
| 310 | 
                +  | 
            |
| 311 | 
                + user.integral += act.integral  | 
            |
| 312 | 
                + user.save()  | 
            |
| 313 | 
                +  | 
            |
| 314 | 
                + # TODO: 立即推送模版消息(感谢您参加活动,获得的积分)  | 
            |
| 198 | 315 | 
                 | 
            
| 199 | 316 | 
                     return response(200, data={
               | 
            
| 200 | 317 | 
                'activity': act.data,  | 
            
                @@ -304,12 +304,17 @@ urlpatterns += [  | 
            ||
| 304 | 304 | 
                 | 
            
| 305 | 305 | 
                url(r'^member/rights$', member_views.rights, name='member_rights'),  | 
            
| 306 | 306 | 
                url(r'^member/right/detail$', member_views.right_detail, name='member_right_detail'),  | 
            
| 307 | 
                +  | 
            |
| 307 | 308 | 
                url(r'^member/goods$', member_views.goods, name='member_goods'),  | 
            
| 308 | 309 | 
                url(r'^member/good/detail$', member_views.good_detail, name='member_good_detail'),  | 
            
| 310 | 
                + url(r'^member/good/exchange$', member_views.good_exchange, name='member_good_exchange'),  | 
            |
| 311 | 
                +  | 
            |
| 309 | 312 | 
                url(r'^member/integrals$', member_views.integrals, name='member_integrals'),  | 
            
| 310 | 313 | 
                 | 
            
| 311 | 314 | 
                url(r'^member/activity/list$', member_views.activity_list, name='member_activity_list'),  | 
            
| 312 | 315 | 
                url(r'^member/activity/detail$', member_views.activity_detail, name='member_activity_detail'),  | 
            
| 316 | 
                + url(r'^member/activity/signup$', member_views.activity_signup, name='member_activity_signup'),  | 
            |
| 317 | 
                + url(r'^member/activity/signin$', member_views.activity_signin, name='member_activity_signin'),  | 
            |
| 313 | 318 | 
                 | 
            
| 314 | 319 | 
                url(r'^rights$', member_views.rights, name='rights'),  | 
            
| 315 | 320 | 
                url(r'^right/detail$', member_views.right_detail, name='right_detail'),  | 
            
                @@ -246,12 +246,12 @@ QINIU = {
               | 
            ||
| 246 | 246 | 
                'secret_key': '05sCekniLCgM6-d_PxrH8sFjvEOsx3ev-FgS7R-k',  | 
            
| 247 | 247 | 
                'bucket_default': 'photo',  | 
            
| 248 | 248 | 
                     'buckets': {
               | 
            
| 249 | 
                - 'original': 'http://orf3sfb8s.bkt.clouddn.com',  | 
            |
| 250 | 
                - 'photo': 'http://orf3lnlmb.bkt.clouddn.com',  | 
            |
| 251 | 
                - 'prettify': 'http://orzfu8zxw.bkt.clouddn.com',  | 
            |
| 252 | 
                - 'thumbnail': 'http://orf3ahvt6.bkt.clouddn.com',  | 
            |
| 253 | 
                - 'thumbnail2': 'http://orf3muf5n.bkt.clouddn.com',  | 
            |
| 254 | 
                - 'watermark': 'http://orf3qne9f.bkt.clouddn.com',  | 
            |
| 249 | 
                + 'original': 'http://original.img.pai.ai',  | 
            |
| 250 | 
                + 'photo': 'http://photo.img.pai.ai',  | 
            |
| 251 | 
                + 'prettify': 'http://prettify.img.pai.ai',  | 
            |
| 252 | 
                + 'thumbnail': 'http://thumbnail.img.pai.ai',  | 
            |
| 253 | 
                + 'thumbnail2': 'http://thumbnail2.img.pai.ai',  | 
            |
| 254 | 
                + 'watermark': 'http://watermark.img.pai.ai',  | 
            |
| 255 | 255 | 
                }  | 
            
| 256 | 256 | 
                }  | 
            
| 257 | 257 | 
                 | 
            
                @@ -99,7 +99,13 @@ urlpatterns += [  | 
            ||
| 99 | 99 | 
                     url(r'^page/', include('page.urls', namespace='page')),
               | 
            
| 100 | 100 | 
                ]  | 
            
| 101 | 101 | 
                 | 
            
| 102 | 
                -urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)  | 
            |
| 103 | 
                -urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)  | 
            |
| 102 | 
                +# Simditor编辑器  | 
            |
| 103 | 
                +urlpatterns += [  | 
            |
| 104 | 
                +    url(r'^simditor/', include('simditor.urls'))
               | 
            |
| 105 | 
                +]  | 
            |
| 106 | 
                +  | 
            |
| 107 | 
                +if settings.DEBUG:  | 
            |
| 108 | 
                + urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)  | 
            |
| 109 | 
                + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)  | 
            |
| 104 | 110 | 
                 | 
            
| 105 | 111 | 
                 admin.site.site_header = u'[盈多]{}后台管理系统'.format(settings.KODO_BRAND_NAME)
               | 
            
                @@ -0,0 +1,20 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +# Generated by Django 1.11.26 on 2019-12-01 13:10  | 
            |
| 3 | 
                +from __future__ import unicode_literals  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +from django.db import migrations, models  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +class Migration(migrations.Migration):  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                + dependencies = [  | 
            |
| 11 | 
                +        ('mch', '0039_auto_20191119_1348'),
               | 
            |
| 12 | 
                + ]  | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                + operations = [  | 
            |
| 15 | 
                + migrations.AddField(  | 
            |
| 16 | 
                + model_name='modelinfo',  | 
            |
| 17 | 
                + name='shot_member_name',  | 
            |
| 18 | 
                + field=models.CharField(blank=True, help_text='\u578b\u53f7\u5168\u540d\u79f0', max_length=255, null=True, verbose_name='shot_member_name'),  | 
            |
| 19 | 
                + ),  | 
            |
| 20 | 
                + ]  | 
            
                @@ -2,7 +2,7 @@  | 
            ||
| 2 | 2 | 
                 | 
            
| 3 | 3 | 
                from django.contrib import admin  | 
            
| 4 | 4 | 
                 | 
            
| 5 | 
                -from member.models import GoodsInfo, MemberActivityInfo, ShotTypeInfo, RightInfo  | 
            |
| 5 | 
                +from member.models import GoodsInfo, GoodsOrderInfo, MemberActivityInfo, MemberActivitySigninInfo, MemberActivitySignupInfo, MemberCouponInfo, ShotTypeInfo, RightInfo  | 
            |
| 6 | 6 | 
                from utils.redis.rshot import update_shot_member_data  | 
            
| 7 | 7 | 
                 | 
            
| 8 | 8 | 
                 | 
            
                @@ -11,6 +11,20 @@ class GoodsInfoAdmin(admin.ModelAdmin):  | 
            ||
| 11 | 11 | 
                     list_filter = ('is_slider', 'status')
               | 
            
| 12 | 12 | 
                 | 
            
| 13 | 13 | 
                 | 
            
| 14 | 
                +class GoodsOrderInfoAdmin(admin.ModelAdmin):  | 
            |
| 15 | 
                +    list_display = ('order_id', 'user_id', 'good_id', 'good_type', 'title', 'name', 'phone', 'address', 'tracking_number', 'has_send_template_message', 'status', 'created_at', 'updated_at')
               | 
            |
| 16 | 
                +  | 
            |
| 17 | 
                + def save_model(self, request, obj, form, change):  | 
            |
| 18 | 
                + obj.save()  | 
            |
| 19 | 
                +  | 
            |
| 20 | 
                + if obj.has_send_template_message:  | 
            |
| 21 | 
                + return  | 
            |
| 22 | 
                +  | 
            |
| 23 | 
                + if obj.good_type == GoodsInfo.PHYSICAL:  | 
            |
| 24 | 
                + # TODO: 立即推送模版消息,兑换成功,快递已发送(商品,快递单号,扣除的积分)  | 
            |
| 25 | 
                + pass  | 
            |
| 26 | 
                +  | 
            |
| 27 | 
                +  | 
            |
| 14 | 28 | 
                class RightInfoAdmin(admin.ModelAdmin):  | 
            
| 15 | 29 | 
                     list_display = ('right_id', 'right_type', 'icon', 'title', 'subtitle', 'detail', 'level1', 'level2', 'level3', 'level4', 'level5',  'minlevel', 'position', 'status', 'created_at', 'updated_at')
               | 
            
| 16 | 30 | 
                     list_filter = ('right_type', 'status')
               | 
            
                @@ -29,11 +43,31 @@ class ShotTypeInfoAdmin(admin.ModelAdmin):  | 
            ||
| 29 | 43 | 
                 | 
            
| 30 | 44 | 
                 | 
            
| 31 | 45 | 
                class MemberActivityInfoAdmin(admin.ModelAdmin):  | 
            
| 32 | 
                -    list_display = ('title', 'subtitle', 'date', 'city', 'location', 'lat', 'lon', 'image', 'is_slider', 'slider_image', 'position', 'status', 'created_at', 'updated_at')
               | 
            |
| 46 | 
                +    list_display = ('activity_id', 'title', 'subtitle', 'date', 'city', 'location', 'lat', 'lon', 'image', 'is_slider', 'slider_image', 'position', 'status', 'created_at', 'updated_at')
               | 
            |
| 33 | 47 | 
                     list_filter = ('is_slider', 'status')
               | 
            
| 34 | 48 | 
                 | 
            
| 35 | 49 | 
                 | 
            
| 50 | 
                +class MemberActivitySignupInfoAdmin(admin.ModelAdmin):  | 
            |
| 51 | 
                +    list_display = ('signup_id', 'activity_id', 'title', 'name', 'phone', 'status', 'created_at', 'updated_at')
               | 
            |
| 52 | 
                +  | 
            |
| 53 | 
                +  | 
            |
| 54 | 
                +class MemberActivitySignupInfoAdmin(admin.ModelAdmin):  | 
            |
| 55 | 
                +    list_display = ('signup_id', 'user_id', 'activity_id', 'title', 'name', 'phone', 'status', 'created_at', 'updated_at')
               | 
            |
| 56 | 
                +  | 
            |
| 57 | 
                +  | 
            |
| 58 | 
                +class MemberActivitySigninInfoAdmin(admin.ModelAdmin):  | 
            |
| 59 | 
                +    list_display = ('signin_id', 'user_id', 'activity_id', 'title', 'status', 'created_at', 'updated_at')
               | 
            |
| 60 | 
                +  | 
            |
| 61 | 
                +  | 
            |
| 62 | 
                +class MemberCouponInfoAdmin(admin.ModelAdmin):  | 
            |
| 63 | 
                +    list_display = ('coupon_id', 'user_id', 'coupon_type', 'coupon_start_at', 'coupon_expire_at', 'coupon_value', 'has_used', 'admin_id', 'used_at', 'status', 'created_at', 'updated_at')
               | 
            |
| 64 | 
                +  | 
            |
| 65 | 
                +  | 
            |
| 36 | 66 | 
                admin.site.register(GoodsInfo, GoodsInfoAdmin)  | 
            
| 67 | 
                +admin.site.register(GoodsOrderInfo, GoodsOrderInfoAdmin)  | 
            |
| 37 | 68 | 
                admin.site.register(RightInfo, RightInfoAdmin)  | 
            
| 38 | 69 | 
                admin.site.register(ShotTypeInfo, ShotTypeInfoAdmin)  | 
            
| 39 | 70 | 
                admin.site.register(MemberActivityInfo, MemberActivityInfoAdmin)  | 
            
| 71 | 
                +admin.site.register(MemberActivitySignupInfo, MemberActivitySignupInfoAdmin)  | 
            |
| 72 | 
                +admin.site.register(MemberActivitySigninInfo, MemberActivitySigninInfoAdmin)  | 
            |
| 73 | 
                +admin.site.register(MemberCouponInfo, MemberCouponInfoAdmin)  | 
            
                @@ -0,0 +1,110 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +# Generated by Django 1.11.26 on 2019-12-01 13:10  | 
            |
| 3 | 
                +from __future__ import unicode_literals  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +from django.db import migrations, models  | 
            |
| 6 | 
                +import shortuuidfield.fields  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                +class Migration(migrations.Migration):  | 
            |
| 10 | 
                +  | 
            |
| 11 | 
                + dependencies = [  | 
            |
| 12 | 
                +        ('member', '0005_memberactivityinfo_city'),
               | 
            |
| 13 | 
                + ]  | 
            |
| 14 | 
                +  | 
            |
| 15 | 
                + operations = [  | 
            |
| 16 | 
                + migrations.CreateModel(  | 
            |
| 17 | 
                + name='GoodsOrderInfo',  | 
            |
| 18 | 
                + fields=[  | 
            |
| 19 | 
                +                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
               | 
            |
| 20 | 
                +                ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')),
               | 
            |
| 21 | 
                +                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')),
               | 
            |
| 22 | 
                +                ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')),
               | 
            |
| 23 | 
                +                ('order_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='\u8ba2\u5355\u552f\u4e00\u6807\u8bc6', max_length=22, null=True, unique=True)),
               | 
            |
| 24 | 
                +                ('user_id', models.CharField(blank=True, db_index=True, help_text='\u7528\u6237\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, verbose_name='user_id')),
               | 
            |
| 25 | 
                +                ('good_id', models.CharField(blank=True, db_index=True, help_text='\u5546\u54c1\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, verbose_name='good_id')),
               | 
            |
| 26 | 
                +                ('good_type', models.IntegerField(choices=[(0, '\u5b9e\u7269'), (1, '\u865a\u62df')], db_index=True, default=1, help_text='\u5546\u54c1\u7c7b\u578b', verbose_name='good_type')),
               | 
            |
| 27 | 
                +                ('title', models.CharField(blank=True, help_text='\u5546\u54c1\u540d\u79f0', max_length=255, null=True, verbose_name='title')),
               | 
            |
| 28 | 
                +                ('name', models.CharField(blank=True, help_text='\u59d3\u540d', max_length=255, null=True, verbose_name='name')),
               | 
            |
| 29 | 
                +                ('phone', models.CharField(blank=True, help_text='\u7535\u8bdd', max_length=255, null=True, verbose_name='phone')),
               | 
            |
| 30 | 
                +                ('address', models.CharField(blank=True, help_text='\u5730\u5740', max_length=255, null=True, verbose_name='address')),
               | 
            |
| 31 | 
                +                ('tracking_number', models.CharField(blank=True, help_text='\u5feb\u9012\u5355\u53f7', max_length=255, null=True, verbose_name='tracking_number')),
               | 
            |
| 32 | 
                +                ('has_send_template_message', models.BooleanField(db_index=True, default=True, help_text='\u662f\u5426\u5df2\u53d1\u9001\u6a21\u7248\u6d88\u606f', verbose_name='has_send_template_message')),
               | 
            |
| 33 | 
                + ],  | 
            |
| 34 | 
                +            options={
               | 
            |
| 35 | 
                + 'verbose_name': '\u4f1a\u5458\u5546\u54c1\u8ba2\u5355\u4fe1\u606f',  | 
            |
| 36 | 
                + 'verbose_name_plural': '\u4f1a\u5458\u5546\u54c1\u8ba2\u5355\u4fe1\u606f',  | 
            |
| 37 | 
                + },  | 
            |
| 38 | 
                + ),  | 
            |
| 39 | 
                + migrations.CreateModel(  | 
            |
| 40 | 
                + name='MemberActivitySigninInfo',  | 
            |
| 41 | 
                + fields=[  | 
            |
| 42 | 
                +                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
               | 
            |
| 43 | 
                +                ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')),
               | 
            |
| 44 | 
                +                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')),
               | 
            |
| 45 | 
                +                ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')),
               | 
            |
| 46 | 
                +                ('signin_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='\u6d3b\u52a8\u7b7e\u5230\u552f\u4e00\u6807\u8bc6', max_length=22, null=True, unique=True)),
               | 
            |
| 47 | 
                +                ('user_id', models.CharField(blank=True, db_index=True, help_text='\u7528\u6237\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, verbose_name='user_id')),
               | 
            |
| 48 | 
                +                ('activity_id', models.CharField(blank=True, db_index=True, help_text='\u6d3b\u52a8\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, verbose_name='activity_id')),
               | 
            |
| 49 | 
                +                ('title', models.CharField(blank=True, help_text='\u6d3b\u52a8\u540d\u79f0', max_length=255, null=True, verbose_name='title')),
               | 
            |
| 50 | 
                + ],  | 
            |
| 51 | 
                +            options={
               | 
            |
| 52 | 
                + 'verbose_name': '\u4f1a\u5458\u6d3b\u52a8\u7b7e\u5230\u4fe1\u606f',  | 
            |
| 53 | 
                + 'verbose_name_plural': '\u4f1a\u5458\u6d3b\u52a8\u7b7e\u5230\u4fe1\u606f',  | 
            |
| 54 | 
                + },  | 
            |
| 55 | 
                + ),  | 
            |
| 56 | 
                + migrations.CreateModel(  | 
            |
| 57 | 
                + name='MemberActivitySignupInfo',  | 
            |
| 58 | 
                + fields=[  | 
            |
| 59 | 
                +                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
               | 
            |
| 60 | 
                +                ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')),
               | 
            |
| 61 | 
                +                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')),
               | 
            |
| 62 | 
                +                ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')),
               | 
            |
| 63 | 
                +                ('signup_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='\u6d3b\u52a8\u62a5\u540d\u552f\u4e00\u6807\u8bc6', max_length=22, null=True, unique=True)),
               | 
            |
| 64 | 
                +                ('user_id', models.CharField(blank=True, db_index=True, help_text='\u7528\u6237\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, verbose_name='user_id')),
               | 
            |
| 65 | 
                +                ('activity_id', models.CharField(blank=True, db_index=True, help_text='\u6d3b\u52a8\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, verbose_name='activity_id')),
               | 
            |
| 66 | 
                +                ('title', models.CharField(blank=True, help_text='\u6d3b\u52a8\u540d\u79f0', max_length=255, null=True, verbose_name='title')),
               | 
            |
| 67 | 
                +                ('name', models.CharField(blank=True, help_text='\u59d3\u540d', max_length=255, null=True, verbose_name='name')),
               | 
            |
| 68 | 
                +                ('phone', models.CharField(blank=True, help_text='\u7535\u8bdd', max_length=255, null=True, verbose_name='phone')),
               | 
            |
| 69 | 
                + ],  | 
            |
| 70 | 
                +            options={
               | 
            |
| 71 | 
                + 'verbose_name': '\u4f1a\u5458\u6d3b\u52a8\u62a5\u540d\u4fe1\u606f',  | 
            |
| 72 | 
                + 'verbose_name_plural': '\u4f1a\u5458\u6d3b\u52a8\u62a5\u540d\u4fe1\u606f',  | 
            |
| 73 | 
                + },  | 
            |
| 74 | 
                + ),  | 
            |
| 75 | 
                + migrations.CreateModel(  | 
            |
| 76 | 
                + name='MemberCouponInfo',  | 
            |
| 77 | 
                + fields=[  | 
            |
| 78 | 
                +                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
               | 
            |
| 79 | 
                +                ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')),
               | 
            |
| 80 | 
                +                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')),
               | 
            |
| 81 | 
                +                ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')),
               | 
            |
| 82 | 
                +                ('coupon_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='\u5238\u552f\u4e00\u6807\u8bc6', max_length=22, null=True, unique=True)),
               | 
            |
| 83 | 
                +                ('user_id', models.CharField(blank=True, db_index=True, help_text='\u7528\u6237\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, verbose_name='user_id')),
               | 
            |
| 84 | 
                +                ('coupon_type', models.IntegerField(choices=[(0, '\u6df1\u5ea6\u6e05\u6d01'), (1, '\u514d\u8d39\u8c03\u7126'), (2, '\u5916\u89c2\u6e05\u6d01'), (3, '\u610f\u5916\u7ef4\u4fee'), (4, '\u7ef4\u4fee\u4eba\u5de5')], db_index=True, default=0, help_text='\u5238\u7c7b\u578b', verbose_name='coupon_type')),
               | 
            |
| 85 | 
                +                ('coupon_start_at', models.DateTimeField(blank=True, help_text='\u5238\u751f\u6548\u65f6\u95f4', null=True, verbose_name='coupon_start_at')),
               | 
            |
| 86 | 
                +                ('coupon_expire_at', models.DateTimeField(blank=True, help_text='\u5238\u8fc7\u671f\u65f6\u95f4', null=True, verbose_name='coupon_expire_at')),
               | 
            |
| 87 | 
                +                ('coupon_value', models.IntegerField(default=0, help_text='\u5238\u91d1\u989d\uff08\u5355\u4f4d\uff1a\u5206\uff09', verbose_name='coupon_value')),
               | 
            |
| 88 | 
                +                ('has_used', models.BooleanField(db_index=True, default=False, help_text='\u662f\u5426\u5df2\u6838\u9500', verbose_name='has_used')),
               | 
            |
| 89 | 
                +                ('admin_id', models.CharField(blank=True, db_index=True, help_text='\u6838\u9500\u5458\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, verbose_name='admin_id')),
               | 
            |
| 90 | 
                +                ('used_at', models.DateTimeField(blank=True, help_text='\u7ef4\u4fee\u5238\u6838\u9500\u65f6\u95f4', null=True, verbose_name='used_at')),
               | 
            |
| 91 | 
                + ],  | 
            |
| 92 | 
                +            options={
               | 
            |
| 93 | 
                + 'verbose_name': '\u4f1a\u5458\u6d3b\u52a8\u7b7e\u5230\u4fe1\u606f',  | 
            |
| 94 | 
                + 'verbose_name_plural': '\u4f1a\u5458\u6d3b\u52a8\u7b7e\u5230\u4fe1\u606f',  | 
            |
| 95 | 
                + },  | 
            |
| 96 | 
                + ),  | 
            |
| 97 | 
                + migrations.AddField(  | 
            |
| 98 | 
                + model_name='memberactivityinfo',  | 
            |
| 99 | 
                + name='activity_id',  | 
            |
| 100 | 
                + field=shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='\u6d3b\u52a8\u552f\u4e00\u6807\u8bc6', max_length=22, null=True, unique=True),  | 
            |
| 101 | 
                + ),  | 
            |
| 102 | 
                + migrations.AlterUniqueTogether(  | 
            |
| 103 | 
                + name='memberactivitysignupinfo',  | 
            |
| 104 | 
                +            unique_together=set([('user_id', 'activity_id')]),
               | 
            |
| 105 | 
                + ),  | 
            |
| 106 | 
                + migrations.AlterUniqueTogether(  | 
            |
| 107 | 
                + name='memberactivitysignininfo',  | 
            |
| 108 | 
                +            unique_together=set([('user_id', 'activity_id')]),
               | 
            |
| 109 | 
                + ),  | 
            |
| 110 | 
                + ]  | 
            
                @@ -27,7 +27,7 @@ class GoodsInfo(BaseModelMixin):  | 
            ||
| 27 | 27 | 
                 | 
            
| 28 | 28 | 
                image = models.ImageField(_(u'image'), upload_to=upload_path, blank=True, null=True, help_text=u'商品图片')  | 
            
| 29 | 29 | 
                 | 
            
| 30 | 
                - is_slider = models.BooleanField(_(u'is_slider'), default=True, help_text=_(u'是否为轮播商品'), db_index=True)  | 
            |
| 30 | 
                + is_slider = models.BooleanField(_(u'is_slider'), default=True, help_text=u'是否为轮播商品', db_index=True)  | 
            |
| 31 | 31 | 
                slider_image = models.ImageField(_(u'slider_image'), upload_to=upload_path, blank=True, null=True, help_text=u'商品轮播图片')  | 
            
| 32 | 32 | 
                 | 
            
| 33 | 33 | 
                integral = models.IntegerField(_(u'integral'), default=99999, help_text=u'兑换所需积分')  | 
            
                @@ -76,6 +76,40 @@ class GoodsInfo(BaseModelMixin):  | 
            ||
| 76 | 76 | 
                }  | 
            
| 77 | 77 | 
                 | 
            
| 78 | 78 | 
                 | 
            
| 79 | 
                +class GoodsOrderInfo(BaseModelMixin):  | 
            |
| 80 | 
                + PHYSICAL = 0  | 
            |
| 81 | 
                + VIRTUAL = 1  | 
            |
| 82 | 
                +  | 
            |
| 83 | 
                + GOOD_TYPE_TUPLE = (  | 
            |
| 84 | 
                + (PHYSICAL, u'实物'),  | 
            |
| 85 | 
                + (VIRTUAL, u'虚拟'),  | 
            |
| 86 | 
                + )  | 
            |
| 87 | 
                +  | 
            |
| 88 | 
                + order_id = ShortUUIDField(_(u'order_id'), max_length=32, blank=True, null=True, help_text=u'订单唯一标识', db_index=True, unique=True)  | 
            |
| 89 | 
                +  | 
            |
| 90 | 
                + user_id = models.CharField(_(u'user_id'), max_length=32, blank=True, null=True, help_text=u'用户唯一标识', db_index=True)  | 
            |
| 91 | 
                +  | 
            |
| 92 | 
                + good_id = models.CharField(_(u'good_id'), max_length=32, blank=True, null=True, help_text=u'商品唯一标识', db_index=True)  | 
            |
| 93 | 
                + good_type = models.IntegerField(_(u'good_type'), choices=GOOD_TYPE_TUPLE, default=VIRTUAL, help_text=u'商品类型', db_index=True)  | 
            |
| 94 | 
                +  | 
            |
| 95 | 
                + title = models.CharField(_(u'title'), max_length=255, blank=True, null=True, help_text=u'商品名称')  | 
            |
| 96 | 
                +  | 
            |
| 97 | 
                + name = models.CharField(_(u'name'), max_length=255, blank=True, null=True, help_text=u'姓名')  | 
            |
| 98 | 
                + phone = models.CharField(_(u'phone'), max_length=255, blank=True, null=True, help_text=u'电话')  | 
            |
| 99 | 
                + address = models.CharField(_(u'address'), max_length=255, blank=True, null=True, help_text=u'地址')  | 
            |
| 100 | 
                +  | 
            |
| 101 | 
                + tracking_number = models.CharField(_(u'tracking_number'), max_length=255, blank=True, null=True, help_text=u'快递单号')  | 
            |
| 102 | 
                +  | 
            |
| 103 | 
                + has_send_template_message = models.BooleanField(_(u'has_send_template_message'), default=True, help_text=u'是否已发送模版消息', db_index=True)  | 
            |
| 104 | 
                +  | 
            |
| 105 | 
                + class Meta:  | 
            |
| 106 | 
                + verbose_name = _(u'会员商品订单信息')  | 
            |
| 107 | 
                + verbose_name_plural = _(u'会员商品订单信息')  | 
            |
| 108 | 
                +  | 
            |
| 109 | 
                + def __unicode__(self):  | 
            |
| 110 | 
                + return unicode(self.pk)  | 
            |
| 111 | 
                +  | 
            |
| 112 | 
                +  | 
            |
| 79 | 113 | 
                class RightInfo(BaseModelMixin):  | 
            
| 80 | 114 | 
                PHYSICAL = 0  | 
            
| 81 | 115 | 
                VIRTUAL = 1  | 
            
                @@ -169,6 +203,8 @@ class ShotTypeInfo(BaseModelMixin):  | 
            ||
| 169 | 203 | 
                 | 
            
| 170 | 204 | 
                 | 
            
| 171 | 205 | 
                class MemberActivityInfo(BaseModelMixin):  | 
            
| 206 | 
                + activity_id = ShortUUIDField(_(u'activity_id'), max_length=32, blank=True, null=True, help_text=u'活动唯一标识', db_index=True, unique=True)  | 
            |
| 207 | 
                +  | 
            |
| 172 | 208 | 
                title = models.CharField(_(u'title'), max_length=255, blank=True, null=True, help_text=u'活动名称')  | 
            
| 173 | 209 | 
                subtitle = models.CharField(_(u'subtitle'), max_length=255, blank=True, null=True, help_text=u'活动二级名称')  | 
            
| 174 | 210 | 
                 | 
            
                @@ -184,7 +220,7 @@ class MemberActivityInfo(BaseModelMixin):  | 
            ||
| 184 | 220 | 
                 | 
            
| 185 | 221 | 
                cover = models.ImageField(_(u'cover'), upload_to=upload_path, blank=True, null=True, help_text=u'活动列表图片')  | 
            
| 186 | 222 | 
                 | 
            
| 187 | 
                - is_slider = models.BooleanField(_(u'is_slider'), default=True, help_text=_(u'是否为轮播活动'), db_index=True)  | 
            |
| 223 | 
                + is_slider = models.BooleanField(_(u'is_slider'), default=True, help_text=u'是否为轮播活动', db_index=True)  | 
            |
| 188 | 224 | 
                slider_image = models.ImageField(_(u'slider_image'), upload_to=upload_path, blank=True, null=True, help_text=u'活动轮播图片')  | 
            
| 189 | 225 | 
                 | 
            
| 190 | 226 | 
                content_rich_text = RichTextField(_(u'content_rich_text'), blank=True, null=True, help_text=u'活动描述')  | 
            
                @@ -228,7 +264,8 @@ class MemberActivityInfo(BaseModelMixin):  | 
            ||
| 228 | 264 | 
                @property  | 
            
| 229 | 265 | 
                def data(self):  | 
            
| 230 | 266 | 
                         return {
               | 
            
| 231 | 
                - 'id': self.pk,  | 
            |
| 267 | 
                + 'id': self.activity_id,  | 
            |
| 268 | 
                + 'activity_id': self.activity_id,  | 
            |
| 232 | 269 | 
                'title': self.title,  | 
            
| 233 | 270 | 
                'subtitle': self.subtitle,  | 
            
| 234 | 271 | 
                'date': tc.local_string(self.date, '%Y-%m-%d'),  | 
            
                @@ -245,3 +282,97 @@ class MemberActivityInfo(BaseModelMixin):  | 
            ||
| 245 | 282 | 
                'state': 0,  | 
            
| 246 | 283 | 
                'is_signed': 0,  | 
            
| 247 | 284 | 
                }  | 
            
| 285 | 
                +  | 
            |
| 286 | 
                +  | 
            |
| 287 | 
                +class MemberActivitySignupInfo(BaseModelMixin):  | 
            |
| 288 | 
                + signup_id = ShortUUIDField(_(u'signup_id'), max_length=32, blank=True, null=True, help_text=u'活动报名唯一标识', db_index=True, unique=True)  | 
            |
| 289 | 
                +  | 
            |
| 290 | 
                + user_id = models.CharField(_(u'user_id'), max_length=32, blank=True, null=True, help_text=u'用户唯一标识', db_index=True)  | 
            |
| 291 | 
                +  | 
            |
| 292 | 
                + activity_id = models.CharField(_(u'activity_id'), max_length=32, blank=True, null=True, help_text=u'活动唯一标识', db_index=True)  | 
            |
| 293 | 
                +  | 
            |
| 294 | 
                + title = models.CharField(_(u'title'), max_length=255, blank=True, null=True, help_text=u'活动名称')  | 
            |
| 295 | 
                +  | 
            |
| 296 | 
                + name = models.CharField(_(u'name'), max_length=255, blank=True, null=True, help_text=u'姓名')  | 
            |
| 297 | 
                + phone = models.CharField(_(u'phone'), max_length=255, blank=True, null=True, help_text=u'电话')  | 
            |
| 298 | 
                +  | 
            |
| 299 | 
                + class Meta:  | 
            |
| 300 | 
                + verbose_name = _(u'会员活动报名信息')  | 
            |
| 301 | 
                + verbose_name_plural = _(u'会员活动报名信息')  | 
            |
| 302 | 
                +  | 
            |
| 303 | 
                + unique_together = (  | 
            |
| 304 | 
                +            ('user_id', 'activity_id'),
               | 
            |
| 305 | 
                + )  | 
            |
| 306 | 
                +  | 
            |
| 307 | 
                + def __unicode__(self):  | 
            |
| 308 | 
                + return unicode(self.pk)  | 
            |
| 309 | 
                +  | 
            |
| 310 | 
                +  | 
            |
| 311 | 
                +class MemberActivitySigninInfo(BaseModelMixin):  | 
            |
| 312 | 
                + signin_id = ShortUUIDField(_(u'signin_id'), max_length=32, blank=True, null=True, help_text=u'活动签到唯一标识', db_index=True, unique=True)  | 
            |
| 313 | 
                +  | 
            |
| 314 | 
                + user_id = models.CharField(_(u'user_id'), max_length=32, blank=True, null=True, help_text=u'用户唯一标识', db_index=True)  | 
            |
| 315 | 
                +  | 
            |
| 316 | 
                + activity_id = models.CharField(_(u'activity_id'), max_length=32, blank=True, null=True, help_text=u'活动唯一标识', db_index=True)  | 
            |
| 317 | 
                +  | 
            |
| 318 | 
                + title = models.CharField(_(u'title'), max_length=255, blank=True, null=True, help_text=u'活动名称')  | 
            |
| 319 | 
                +  | 
            |
| 320 | 
                + class Meta:  | 
            |
| 321 | 
                + verbose_name = _(u'会员活动签到信息')  | 
            |
| 322 | 
                + verbose_name_plural = _(u'会员活动签到信息')  | 
            |
| 323 | 
                +  | 
            |
| 324 | 
                + unique_together = (  | 
            |
| 325 | 
                +            ('user_id', 'activity_id'),
               | 
            |
| 326 | 
                + )  | 
            |
| 327 | 
                +  | 
            |
| 328 | 
                + def __unicode__(self):  | 
            |
| 329 | 
                + return unicode(self.pk)  | 
            |
| 330 | 
                +  | 
            |
| 331 | 
                +  | 
            |
| 332 | 
                +class MemberCouponInfo(BaseModelMixin):  | 
            |
| 333 | 
                + DEEP_CLEANING = 0  | 
            |
| 334 | 
                + FREE_FOCUS = 1  | 
            |
| 335 | 
                + CLEAN_APPEARANCE = 2  | 
            |
| 336 | 
                + ACCIDENTAL_MAINTENANCE = 3  | 
            |
| 337 | 
                + MAINTENANCE_MANPOWER = 4  | 
            |
| 338 | 
                +  | 
            |
| 339 | 
                + COUPON_TYPE_TUPLE = (  | 
            |
| 340 | 
                + (DEEP_CLEANING, u'深度清洁'),  | 
            |
| 341 | 
                + (FREE_FOCUS, u'免费调焦'),  | 
            |
| 342 | 
                + (CLEAN_APPEARANCE, u'外观清洁'),  | 
            |
| 343 | 
                + (ACCIDENTAL_MAINTENANCE, u'意外维修'),  | 
            |
| 344 | 
                + (MAINTENANCE_MANPOWER, u'维修人工')  | 
            |
| 345 | 
                + )  | 
            |
| 346 | 
                +  | 
            |
| 347 | 
                + coupon_id = ShortUUIDField(_(u'coupon_id'), max_length=32, blank=True, null=True, help_text=u'券唯一标识', db_index=True, unique=True)  | 
            |
| 348 | 
                +  | 
            |
| 349 | 
                + user_id = models.CharField(_(u'user_id'), max_length=32, blank=True, null=True, help_text=u'用户唯一标识', db_index=True)  | 
            |
| 350 | 
                +  | 
            |
| 351 | 
                + coupon_type = models.IntegerField(_(u'coupon_type'), choices=COUPON_TYPE_TUPLE, default=DEEP_CLEANING, help_text=u'券类型', db_index=True)  | 
            |
| 352 | 
                + coupon_start_at = models.DateTimeField(_(u'coupon_start_at'), blank=True, null=True, help_text=u'券生效时间')  | 
            |
| 353 | 
                + coupon_expire_at = models.DateTimeField(_(u'coupon_expire_at'), blank=True, null=True, help_text=u'券过期时间')  | 
            |
| 354 | 
                + coupon_value = models.IntegerField(_(u'coupon_value'), default=0, help_text=u'券金额(单位:分)')  | 
            |
| 355 | 
                +  | 
            |
| 356 | 
                + has_used = models.BooleanField(_(u'has_used'), default=False, help_text=u'是否已核销', db_index=True)  | 
            |
| 357 | 
                + admin_id = models.CharField(_(u'admin_id'), max_length=32, blank=True, null=True, help_text=u'核销员唯一标识', db_index=True)  | 
            |
| 358 | 
                + used_at = models.DateTimeField(_(u'used_at'), blank=True, null=True, help_text=u'维修券核销时间')  | 
            |
| 359 | 
                +  | 
            |
| 360 | 
                + class Meta:  | 
            |
| 361 | 
                + verbose_name = _(u'会员券信息')  | 
            |
| 362 | 
                + verbose_name_plural = _(u'会员券信息')  | 
            |
| 363 | 
                +  | 
            |
| 364 | 
                + def __unicode__(self):  | 
            |
| 365 | 
                + return unicode(self.pk)  | 
            |
| 366 | 
                +  | 
            |
| 367 | 
                + @property  | 
            |
| 368 | 
                + def data(self):  | 
            |
| 369 | 
                +        return {
               | 
            |
| 370 | 
                + 'coupon_id': self.coupon_id,  | 
            |
| 371 | 
                + 'coupon_type': self.coupon_type,  | 
            |
| 372 | 
                + 'coupon_start_at': tc.local_string(self.coupon_start_at, format='%Y%m%d'),  | 
            |
| 373 | 
                + 'coupon_expire_at': tc.local_string(self.coupon_expire_at, format='%Y%m%d'),  | 
            |
| 374 | 
                + 'coupon_value': self.coupon_value,  | 
            |
| 375 | 
                + 'has_used': self.has_used,  | 
            |
| 376 | 
                + 'admin_id': self.admin_id,  | 
            |
| 377 | 
                + 'used_at': tc.local_string(self.used_at, format='%Y%m%d'),  | 
            |
| 378 | 
                + }  | 
            
                @@ -59,7 +59,7 @@ def upload_handler(request):  | 
            ||
| 59 | 59 | 
                'msg': '图片格式错误!'}  | 
            
| 60 | 60 | 
                return JsonResponse(retdata)  | 
            
| 61 | 61 | 
                 | 
            
| 62 | 
                -    key = upload(uploaded_file.read()).get('key', '')
               | 
            |
| 62 | 
                + key = upload(uploaded_file.read())  | 
            |
| 63 | 63 | 
                if not key:  | 
            
| 64 | 64 | 
                         retdata = {'file_path': key, 'success': False, 'msg': '上传失败,请重试!'}
               | 
            
| 65 | 65 | 
                else:  | 
            
                @@ -62,6 +62,24 @@ class ProductStatusCode(BaseStatusCode):  | 
            ||
| 62 | 62 | 
                PRODUCT_NOT_USED = StatusCodeField(502012, 'Product Not Used', description=u'产品未使用')  | 
            
| 63 | 63 | 
                 | 
            
| 64 | 64 | 
                 | 
            
| 65 | 
                +class MemberGoodStatusCode(BaseStatusCode):  | 
            |
| 66 | 
                + """ 会员商品相关错误码 5035xx """  | 
            |
| 67 | 
                + GOOD_NOT_FOUND = StatusCodeField(503501, 'Good Not Found', description=u'商品不存在')  | 
            |
| 68 | 
                +  | 
            |
| 69 | 
                + GOOD_NO_EXCHANGE_PERMISSION = StatusCodeField(503502, 'Good No Exchange Permission', description=u'商品无兑换权限')  | 
            |
| 70 | 
                + GOOD_INTEGRAL_NOT_ENOUGH = StatusCodeField(503503, 'Good Integral Not Enough', description=u'商品兑换积分不足')  | 
            |
| 71 | 
                +  | 
            |
| 72 | 
                +  | 
            |
| 73 | 
                +class MemberRightStatusCode(BaseStatusCode):  | 
            |
| 74 | 
                + """ 会员商品相关错误码 5036xx """  | 
            |
| 75 | 
                + RIGHT_NOT_FOUND = StatusCodeField(503601, 'Right Not Found', description=u'权益不存在')  | 
            |
| 76 | 
                +  | 
            |
| 77 | 
                +  | 
            |
| 78 | 
                +class MemberActivityStatusCode(BaseStatusCode):  | 
            |
| 79 | 
                + """ 会员活动相关错误码 5037xx """  | 
            |
| 80 | 
                + ACTIVITY_NOT_FOUND = StatusCodeField(503701, 'Activity Not Found', description=u'活动不存在')  | 
            |
| 81 | 
                +  | 
            |
| 82 | 
                +  | 
            |
| 65 | 83 | 
                class LensmanStatusCode(BaseStatusCode):  | 
            
| 66 | 84 | 
                """ 摄影师相关错误码 4000xx """  | 
            
| 67 | 85 | 
                LENSMAN_NOT_FOUND = StatusCodeField(400001, 'Lensman Not Found', description=u'摄影师不存在')  | 
            
                @@ -39,7 +39,7 @@ def upload_file_path(path, key=None, mime_type='application/octet-stream', bucke  | 
            ||
| 39 | 39 | 
                     return ret.get('key')
               | 
            
| 40 | 40 | 
                 | 
            
| 41 | 41 | 
                 | 
            
| 42 | 
                -def qiniu_file_url(key, bucket):  | 
            |
| 42 | 
                +def qiniu_file_url(key, bucket=QINIU['bucket_default']):  | 
            |
| 43 | 43 | 
                if not key:  | 
            
| 44 | 44 | 
                return ''  | 
            
| 45 | 45 | 
                     return '{}/{}'.format(QINIU['buckets'][bucket], key)
               |