:art: member/user/coupon/detail & member/user/coupon/use

huangqimin 5 anni fa
parent
commit
211ab99a32

+ 50 - 5
api/member_views.py

@@ -8,12 +8,13 @@ from django_logit import logit
8 8
 from django_query import get_query_value
9 9
 from django_response import response
10 10
 from paginator import pagination
11
+from TimeConvert import TimeConvert as tc
11 12
 
12 13
 from account.models import UserInfo
13 14
 from coupon.models import UserCouponInfo
14 15
 from member.models import (GoodsInfo, GoodsOrderInfo, MemberActivityInfo, MemberActivitySigninInfo,
15 16
                            MemberActivitySignupInfo, RightInfo)
16
-from utils.error.errno_utils import (MemberActivityStatusCode, MemberGoodStatusCode, MemberRightStatusCode,
17
+from utils.error.errno_utils import (MemberActivityStatusCode, MemberCouponStatusCode, MemberGoodStatusCode, MemberRightStatusCode,
17 18
                                      UserStatusCode)
18 19
 from utils.redis.connect import r
19 20
 from utils.redis.rkeys import MEMBER_SEND_COUPON_LIST, MEMBER_UPGRADE_INFO
@@ -112,7 +113,7 @@ def goods(request):
112 113
     except UserInfo.DoesNotExist:
113 114
         return response(UserStatusCode.USER_NOT_FOUND)
114 115
 
115
-    raw_goods = GoodsInfo.objects.filter(only_for_member=False, left_num__gt=0, status=True).order_by('position')
116
+    raw_goods = GoodsInfo.objects.filter(only_for_member=False, left_num__gt=0, status=True).order_by('position', '-pk')
116 117
     banners = goods = []
117 118
     for good in raw_goods:
118 119
         if good.is_slider:
@@ -190,6 +191,9 @@ def good_exchange(request):
190 191
         except GoodsInfo.DoesNotExist:
191 192
             return response(MemberGoodStatusCode.GOOD_NOT_FOUND)
192 193
 
194
+        if good.left_num <= 0:
195
+            return response(MemberGoodStatusCode.GOOD_STOCK_NOT_ENOUGH)
196
+
193 197
         if user.level < good.minlevel:
194 198
             return response(MemberGoodStatusCode.GOOD_NO_EXCHANGE_PERMISSION)
195 199
 
@@ -199,9 +203,6 @@ def good_exchange(request):
199 203
         user.integral -= good.integral
200 204
         user.save()
201 205
 
202
-        if good.left_num <= 0:
203
-            return response(MemberGoodStatusCode.GOOD_STOCK_NOT_ENOUGH)
204
-
205 206
         good.left_num -= 1
206 207
         good.save()
207 208
 
@@ -261,6 +262,50 @@ def coupons(request):
261 262
 
262 263
 
263 264
 @logit
265
+def user_coupon_detail(request):
266
+    brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
267
+    user_id = request.POST.get('user_id', '')
268
+    user_coupon_id = request.POST.get('user_coupon_id', '')
269
+
270
+    try:
271
+        coupon = UserCouponInfo.objects.get(user_coupon_id=user_coupon_id, user_id=user_id, status=True)
272
+    except UserCouponInfo.DoesNotExist:
273
+        return response(MemberCouponStatusCode.USER_COUPON_NOT_FOUND)
274
+
275
+    return response(200, data=coupon.data)
276
+
277
+
278
+@logit
279
+@transaction.atomic
280
+def user_coupon_use(request):
281
+    brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
282
+    admin_id = request.POST.get('admin_id', '')
283
+    user_id = request.POST.get('user_id', '')
284
+    user_coupon_id = request.POST.get('user_coupon_id', '')
285
+
286
+    try:
287
+        coupon = UserCouponInfo.objects.select_for_update().get(user_coupon_id=user_coupon_id, user_id=user_id, status=True)
288
+    except UserCouponInfo.DoesNotExist:
289
+        return response(MemberCouponStatusCode.USER_COUPON_NOT_FOUND)
290
+
291
+    if not coupon.has_actived:
292
+        return response(MemberCouponStatusCode.USER_COUPON_NOT_ACTIVED)
293
+
294
+    if coupon.has_expired:
295
+        return response(MemberCouponStatusCode.USER_COUPON_HAS_EXPIRED)
296
+
297
+    if coupon.has_used:
298
+        return response(MemberCouponStatusCode.USER_COUPON_HAS_USED)
299
+
300
+    coupon.has_used = True
301
+    coupon.admin_id = admin_id
302
+    coupon.used_at = tc.utc_datetime()
303
+    coupon.save()
304
+
305
+    return response(200, data=coupon.data)
306
+
307
+
308
+@logit
264 309
 def integrals(request):
265 310
     brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
266 311
 

+ 2 - 0
api/urls.py

@@ -310,6 +310,8 @@ urlpatterns += [
310 310
     url(r'^member/good/exchange$', member_views.good_exchange, name='member_good_exchange'),
311 311
 
312 312
     url(r'^member/coupons$', member_views.coupons, name='member_coupons'),
313
+    url(r'^member/user/coupon/detail$', member_views.user_coupon_detail, name='user_coupon_detail'),
314
+    url(r'^member/user/coupon/use$', member_views.user_coupon_use, name='user_coupon_use'),
313 315
 
314 316
     url(r'^member/integrals$', member_views.integrals, name='member_integrals'),
315 317
 

+ 2 - 2
commands/management/commands/cpon.py

@@ -64,7 +64,7 @@ class Command(CompatibilityBaseCommand):
64 64
                             active_at=tc.utc_datetime(),
65 65
                             expire_at=tc.utc_datetime(days=365),
66 66
                             coupon_valid_period=coupon.coupon_valid_period,
67
-                            coupon_limit_brand_ids=coupon.coupon_limit_brand_ids,
67
+                            coupon_limit_model_ids=coupon.coupon_limit_model_ids,
68 68
                         )
69 69
 
70 70
                     else:
@@ -105,7 +105,7 @@ class Command(CompatibilityBaseCommand):
105 105
                                     active_at=tc.utc_datetime(),
106 106
                                     expire_at=tc.utc_datetime(days=365),
107 107
                                     coupon_valid_period=coupon.coupon_valid_period,
108
-                                    coupon_limit_brand_ids=coupon.coupon_limit_brand_ids,
108
+                                    coupon_limit_model_ids=coupon.coupon_limit_model_ids,
109 109
                                 )
110 110
 
111 111
                 close_old_connections()

+ 1 - 1
coupon/admin.py

@@ -11,7 +11,7 @@ class CouponInfoAdmin(admin.ModelAdmin):
11 11
 
12 12
 
13 13
 class UserCouponInfoAdmin(admin.ModelAdmin):
14
-    list_display = ('brand_id', 'brand_name', 'user_coupon_id', 'coupon_id', 'user_id', 'coupon_title', 'coupon_value', 'active_at', 'expire_at', 'coupon_valid_period', 'coupon_limit_brand_ids', 'has_used', 'admin_id', 'used_at', 'status', 'created_at', 'updated_at')
14
+    list_display = ('brand_id', 'brand_name', 'user_coupon_id', 'coupon_id', 'user_id', 'coupon_title', 'coupon_value', 'active_at', 'expire_at', 'coupon_valid_period', 'coupon_limit_model_ids', 'has_used', 'admin_id', 'used_at', 'status', 'created_at', 'updated_at')
15 15
     list_filter = ('brand_id', 'has_used', 'status')
16 16
 
17 17
 

+ 34 - 0
coupon/migrations/0007_auto_20191230_1605.py

@@ -0,0 +1,34 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 1.11.26 on 2019-12-30 08:05
3
+from __future__ import unicode_literals
4
+
5
+from django.db import migrations
6
+import jsonfield.fields
7
+
8
+
9
+class Migration(migrations.Migration):
10
+
11
+    dependencies = [
12
+        ('coupon', '0006_auto_20191230_1516'),
13
+    ]
14
+
15
+    operations = [
16
+        migrations.RemoveField(
17
+            model_name='couponinfo',
18
+            name='coupon_limit_brand_ids',
19
+        ),
20
+        migrations.RemoveField(
21
+            model_name='usercouponinfo',
22
+            name='coupon_limit_brand_ids',
23
+        ),
24
+        migrations.AddField(
25
+            model_name='couponinfo',
26
+            name='coupon_limit_model_ids',
27
+            field=jsonfield.fields.JSONField(blank=True, help_text='\u5238\u9650\u5236\u4f7f\u7528 model_ids', null=True, verbose_name='coupon_limit_model_ids'),
28
+        ),
29
+        migrations.AddField(
30
+            model_name='usercouponinfo',
31
+            name='coupon_limit_model_ids',
32
+            field=jsonfield.fields.JSONField(blank=True, help_text='\u5238\u9650\u5236\u4f7f\u7528 model_ids', null=True, verbose_name='coupon_limit_model_ids'),
33
+        ),
34
+    ]

+ 17 - 3
coupon/models.py

@@ -33,7 +33,7 @@ class CouponInfo(BaseModelMixin):
33 33
     coupon_valid_period = models.IntegerField(_(u'coupon_valid_period'), default=0, help_text=_(u'维修券有效时间(单位:天)'))
34 34
     coupon_expire_at = models.DateTimeField(_(u'coupon_expire_at'), blank=True, null=True, help_text=_(u'维修券过期时间'))
35 35
 
36
-    coupon_limit_brand_ids = JSONField(_(u'coupon_limit_brand_ids'), blank=True, null=True, help_text=u'券限制使用 brand_ids')
36
+    coupon_limit_model_ids = JSONField(_(u'coupon_limit_model_ids'), blank=True, null=True, help_text=u'券限制使用 model_ids')
37 37
 
38 38
     class Meta:
39 39
         verbose_name = _(u'券信息')
@@ -60,7 +60,7 @@ class UserCouponInfo(BaseModelMixin):
60 60
     expire_at = models.DateTimeField(_(u'expire_at'), blank=True, null=True, help_text=_(u'过期时间'))
61 61
     coupon_valid_period = models.IntegerField(_(u'coupon_valid_period'), default=0, help_text=_(u'券有效时间(单位:天)'))
62 62
 
63
-    coupon_limit_brand_ids = JSONField(_(u'coupon_limit_brand_ids'), blank=True, null=True, help_text=u'券限制使用 brand_ids')
63
+    coupon_limit_model_ids = JSONField(_(u'coupon_limit_model_ids'), blank=True, null=True, help_text=u'券限制使用 model_ids')
64 64
 
65 65
     has_used = models.BooleanField(_(u'has_used'), default=False, help_text=u'是否已核销', db_index=True)
66 66
     admin_id = models.CharField(_(u'admin_id'), max_length=32, blank=True, null=True, help_text=u'核销员唯一标识', db_index=True)
@@ -82,6 +82,18 @@ class UserCouponInfo(BaseModelMixin):
82 82
         return upload_file_url(self.coupon_image)
83 83
 
84 84
     @property
85
+    def has_actived(self):
86
+        if not self.active_at:
87
+            return True
88
+        return tc.utc_datetime() > self.active_at
89
+
90
+    @property
91
+    def has_expired(self):
92
+        if not self.expire_at:
93
+            return False
94
+        return tc.utc_datetime() > self.expire_at
95
+
96
+    @property
85 97
     def data(self):
86 98
         return {
87 99
             'user_coupon_id': self.user_coupon_id,
@@ -94,7 +106,9 @@ class UserCouponInfo(BaseModelMixin):
94 106
             'active_at': tc.local_string(self.active_at, format='%Y%m%d'),
95 107
             'expire_at': tc.local_string(self.expire_at, format='%Y-%m-%d'),
96 108
             'coupon_valid_period': self.coupon_valid_period,
97
-            'coupon_limit_brand_ids': self.coupon_limit_brand_ids,
109
+            'coupon_limit_model_ids': self.coupon_limit_model_ids,
110
+            'has_actived': self.has_actived,
111
+            'has_expired': self.has_expired,
98 112
             'has_used': self.has_used,
99 113
             'admin_id': self.admin_id,
100 114
             'used_at': self.used_at,

+ 9 - 0
utils/error/errno_utils.py

@@ -81,6 +81,15 @@ class MemberActivityStatusCode(BaseStatusCode):
81 81
     ACTIVITY_NOT_FOUND = StatusCodeField(503701, 'Activity Not Found', description=u'活动不存在')
82 82
 
83 83
 
84
+class MemberCouponStatusCode(BaseStatusCode):
85
+    """ 会员优惠券相关错误码 5040xx """
86
+    USER_COUPON_NOT_FOUND = StatusCodeField(504001, 'User Coupon Not Found', description=u'用户优惠券不存在')
87
+
88
+    USER_COUPON_HAS_USED = StatusCodeField(504010, 'User Coupon Has Used', description=u'用户优惠券已使用')
89
+    USER_COUPON_NOT_ACTIVED = StatusCodeField(504011, 'User Coupon Not Actived', description=u'用户优惠券未生效')
90
+    USER_COUPON_HAS_EXPIRED = StatusCodeField(504012, 'User Coupon Has Expired', description=u'用户优惠券已过期')
91
+
92
+
84 93
 class LensmanStatusCode(BaseStatusCode):
85 94
     """ 摄影师相关错误码 4000xx """
86 95
     LENSMAN_NOT_FOUND = StatusCodeField(400001, 'Lensman Not Found', description=u'摄影师不存在')

+ 1 - 1
utils/redis/rshot.py

@@ -6,7 +6,7 @@ from utils.redis.rkeys import MEMBER_SHOT_DATA
6 6
 
7 7
 def update_member_shot_data():
8 8
     from member.models import ShotTypeInfo
9
-    shots_types = ShotTypeInfo.objects.filter(status=True).order_by('position')
9
+    shots_types = ShotTypeInfo.objects.filter(status=True).order_by('position', '-pk')
10 10
     shots_types = [st.data for st in shots_types]
11 11
     r.setjson(MEMBER_SHOT_DATA, shots_types)
12 12
     return shots_types