coupons

huangqimin 5 年之前
父节点
当前提交
608f25d6bc
共有 6 个文件被更改,包括 180 次插入15 次删除
  1. 6 1
      api/mch_views.py
  2. 26 6
      api/member_views.py
  3. 2 0
      api/urls.py
  4. 52 0
      member/migrations/0007_auto_20191212_0952.py
  5. 93 7
      member/models.py
  6. 1 1
      requirements.txt

+ 6 - 1
api/mch_views.py

@@ -398,7 +398,12 @@ def consumer_info_api(request):
398 398
         log.has_scan = True
399 399
         log.save()
400 400
 
401
-    # TODO: 发放会员权益
401
+    if not dupload:
402
+        user.shots_num += 1
403
+        if user.level < UserInfo.MEMBER_BLACK_GOLD:
404
+            user.level += 1
405
+        user.save()
406
+        # TODO: 发放会员权益
402 407
 
403 408
     return response(200, 'Submit Consumer Info Success', u'提交消费者信息成功')
404 409
 

+ 26 - 6
api/member_views.py

@@ -6,9 +6,10 @@ from django.conf import settings
6 6
 from django.db import transaction
7 7
 from django_logit import logit
8 8
 from django_response import response
9
+from paginator import pagination
9 10
 
10 11
 from account.models import UserInfo
11
-from member.models import (GoodsInfo, GoodsOrderInfo, MemberActivityInfo, MemberActivitySigninInfo,
12
+from member.models import (CouponInfo, GoodsInfo, GoodsOrderInfo, MemberActivityInfo, MemberActivitySigninInfo,
12 13
                            MemberActivitySignupInfo, RightInfo)
13 14
 from utils.error.errno_utils import (MemberActivityStatusCode, MemberGoodStatusCode, MemberRightStatusCode,
14 15
                                      UserStatusCode)
@@ -208,6 +209,23 @@ def good_exchange(request):
208 209
 
209 210
 
210 211
 @logit
212
+def coupons(request):
213
+    brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
214
+    user_id = request.POST.get('user_id', '')
215
+    page = request.POST.get('page', 1)
216
+    num = request.POST.get('num', 20)
217
+
218
+    coupons = CouponInfo.objects.filter(user_id=user_id, status=True).order_by('-pk')
219
+    coupons, left = pagination(coupons, page, num)
220
+    coupons = [coupon.data for coupon in coupons]
221
+
222
+    return response(200, data={
223
+        'coupons': coupons,
224
+        'left': left,
225
+    })
226
+
227
+
228
+@logit
211 229
 def integrals(request):
212 230
     brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
213 231
 
@@ -230,15 +248,16 @@ def integrals(request):
230 248
 @logit
231 249
 def activity_list(request):
232 250
     brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
251
+    user_id = request.POST.get('user_id', '')
233 252
 
234 253
     raw_activitys = MemberActivityInfo.objects.filter(status=True).order_by('position')
235 254
     banners = []
236 255
     activitys = []
237 256
     for act in raw_activitys:
238 257
         if act.is_slider:
239
-            banners.append(act.data)
258
+            banners.append(act.data(user_id))
240 259
         else:
241
-            activitys.append(act.data)
260
+            activitys.append(act.data(user_id))
242 261
 
243 262
     return response(200, data={
244 263
         'banners': banners,
@@ -249,6 +268,7 @@ def activity_list(request):
249 268
 @logit
250 269
 def activity_detail(request):
251 270
     brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
271
+    user_id = request.POST.get('user_id', '')
252 272
     activity_id = request.POST.get('activity_id')
253 273
 
254 274
     try:
@@ -257,7 +277,7 @@ def activity_detail(request):
257 277
         return response(MemberActivityStatusCode.ACTIVITY_NOT_FOUND)
258 278
 
259 279
     return response(200, data={
260
-        'activity': act.data,
280
+        'activity': act.data(user_id),
261 281
     })
262 282
 
263 283
 
@@ -284,7 +304,7 @@ def activity_signup(request):
284 304
     # TODO: 延迟(活动当天)推送模版消息(时间,地点)
285 305
 
286 306
     return response(200, data={
287
-        'activity': act.data,
307
+        'activity': act.data(user_id),
288 308
     })
289 309
 
290 310
 
@@ -316,5 +336,5 @@ def activity_signin(request):
316 336
     # TODO: 立即推送模版消息(感谢您参加活动,获得的积分)
317 337
 
318 338
     return response(200, data={
319
-        'activity': act.data,
339
+        'activity': act.data(user_id),
320 340
     })

+ 2 - 0
api/urls.py

@@ -309,6 +309,8 @@ urlpatterns += [
309 309
     url(r'^member/good/detail$', member_views.good_detail, name='member_good_detail'),
310 310
     url(r'^member/good/exchange$', member_views.good_exchange, name='member_good_exchange'),
311 311
 
312
+    url(r'^member/coupons$', member_views.coupons, name='member_coupons'),
313
+
312 314
     url(r'^member/integrals$', member_views.integrals, name='member_integrals'),
313 315
 
314 316
     url(r'^member/activity/list$', member_views.activity_list, name='member_activity_list'),

+ 52 - 0
member/migrations/0007_auto_20191212_0952.py

@@ -0,0 +1,52 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 1.11.26 on 2019-12-12 01:52
3
+from __future__ import unicode_literals
4
+
5
+from django.db import migrations, models
6
+import django_models_ext.fileext
7
+import shortuuidfield.fields
8
+import simditor.fields
9
+
10
+
11
+class Migration(migrations.Migration):
12
+
13
+    dependencies = [
14
+        ('member', '0006_auto_20191201_2110'),
15
+    ]
16
+
17
+    operations = [
18
+        migrations.CreateModel(
19
+            name='CouponInfo',
20
+            fields=[
21
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
22
+                ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')),
23
+                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')),
24
+                ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')),
25
+                ('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)),
26
+                ('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')),
27
+                ('active_at', models.DateTimeField(blank=True, help_text='\u751f\u6548\u65f6\u95f4', null=True, verbose_name='active_at')),
28
+                ('expire_at', models.DateTimeField(blank=True, help_text='\u8fc7\u671f\u65f6\u95f4', null=True, verbose_name='expire_at')),
29
+                ('right_id', models.CharField(blank=True, db_index=True, help_text='\u6743\u76ca\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, verbose_name='right_id')),
30
+                ('right_type', models.IntegerField(choices=[(0, '\u5b9e\u7269'), (1, '\u865a\u62df'), (2, '\u4f18\u60e0\u5238')], db_index=True, default=1, help_text='\u6743\u76ca\u7c7b\u578b', verbose_name='right_type')),
31
+                ('icon', models.ImageField(blank=True, help_text='\u6743\u76ca\u56fe\u6807', null=True, upload_to=django_models_ext.fileext.upload_path, verbose_name='icon')),
32
+                ('title', models.CharField(blank=True, help_text='\u6743\u76ca\u540d\u79f0', max_length=255, null=True, verbose_name='title')),
33
+                ('subtitle', models.CharField(blank=True, help_text='\u6743\u76ca\u4e8c\u7ea7\u540d\u79f0', max_length=255, null=True, verbose_name='subtitle')),
34
+                ('detail', simditor.fields.RichTextField(blank=True, help_text='\u6743\u76ca\u8be6\u60c5', null=True, verbose_name='detail')),
35
+                ('level1', models.CharField(blank=True, help_text='level1', max_length=255, null=True, verbose_name='level1')),
36
+                ('level2', models.CharField(blank=True, help_text='level2', max_length=255, null=True, verbose_name='level2')),
37
+                ('level3', models.CharField(blank=True, help_text='level3', max_length=255, null=True, verbose_name='level3')),
38
+                ('level4', models.CharField(blank=True, help_text='level4', max_length=255, null=True, verbose_name='level4')),
39
+                ('level5', models.CharField(blank=True, help_text='level5', max_length=255, null=True, verbose_name='level5')),
40
+                ('minlevel', models.IntegerField(default=0, help_text='\u6743\u76ca\u6700\u4f4e\u4f1a\u5458\u7ea7\u522b', verbose_name='minlevel')),
41
+                ('position', models.IntegerField(db_index=True, default=1, help_text='\u6392\u5e8f', verbose_name='position')),
42
+            ],
43
+            options={
44
+                'verbose_name': '\u4f1a\u5458\u5238\u4fe1\u606f',
45
+                'verbose_name_plural': '\u4f1a\u5458\u5238\u4fe1\u606f',
46
+            },
47
+        ),
48
+        migrations.AlterModelOptions(
49
+            name='membercouponinfo',
50
+            options={'verbose_name': '\u4f1a\u5458\u5238\u4fe1\u606f', 'verbose_name_plural': '\u4f1a\u5458\u5238\u4fe1\u606f'},
51
+        ),
52
+    ]

+ 93 - 7
member/models.py

@@ -169,9 +169,83 @@ class RightInfo(BaseModelMixin):
169 169
             'level4': self.level4,
170 170
             'level5': self.level5,
171 171
             'minlevel': self.minlevel,
172
-            "able": True,
173
-            "left_num": 3,
174
-            "left_tip": 3,
172
+            'able': True,
173
+            'left_num': 3,
174
+            'left_tip': 3,
175
+        }
176
+
177
+
178
+class CouponInfo(BaseModelMixin):
179
+    PHYSICAL = 0
180
+    VIRTUAL = 1
181
+    COUPON = 2
182
+
183
+    RIGHT_TYPE_TUPLE = (
184
+        (PHYSICAL, u'实物'),
185
+        (VIRTUAL, u'虚拟'),
186
+        (COUPON, u'优惠券'),
187
+    )
188
+
189
+    coupon_id = ShortUUIDField(_(u'coupon_id'), max_length=32, blank=True, null=True, help_text=u'券唯一标识', db_index=True, unique=True)
190
+    user_id = models.CharField(_(u'user_id'), max_length=32, blank=True, null=True, help_text=u'用户唯一标识', db_index=True)
191
+
192
+    active_at = models.DateTimeField(_(u'active_at'), blank=True, null=True, help_text=_(u'生效时间'))
193
+    expire_at = models.DateTimeField(_(u'expire_at'), blank=True, null=True, help_text=_(u'过期时间'))
194
+
195
+    right_id = models.CharField(_(u'right_id'), max_length=32, blank=True, null=True, help_text=u'权益唯一标识', db_index=True)
196
+    right_type = models.IntegerField(_(u'right_type'), choices=RIGHT_TYPE_TUPLE, default=VIRTUAL, help_text=u'权益类型', db_index=True)
197
+
198
+    icon = models.ImageField(_(u'icon'), upload_to=upload_path, blank=True, null=True, help_text=u'权益图标')
199
+    title = models.CharField(_(u'title'), max_length=255, blank=True, null=True, help_text=u'权益名称')
200
+    subtitle = models.CharField(_(u'subtitle'), max_length=255, blank=True, null=True, help_text=u'权益二级名称')
201
+    detail = RichTextField(_(u'detail'), blank=True, null=True, help_text=u'权益详情')
202
+
203
+    level1 = models.CharField(_(u'level1'), max_length=255, blank=True, null=True, help_text=u'level1')
204
+    level2 = models.CharField(_(u'level2'), max_length=255, blank=True, null=True, help_text=u'level2')
205
+    level3 = models.CharField(_(u'level3'), max_length=255, blank=True, null=True, help_text=u'level3')
206
+    level4 = models.CharField(_(u'level4'), max_length=255, blank=True, null=True, help_text=u'level4')
207
+    level5 = models.CharField(_(u'level5'), max_length=255, blank=True, null=True, help_text=u'level5')
208
+
209
+    minlevel = models.IntegerField(_(u'minlevel'), default=0, help_text=u'权益最低会员级别')
210
+
211
+    position = models.IntegerField(_(u'position'), default=1, help_text=u'排序', db_index=True)
212
+
213
+    class Meta:
214
+        verbose_name = _(u'会员券信息')
215
+        verbose_name_plural = _(u'会员券信息')
216
+
217
+    def __unicode__(self):
218
+        return unicode(self.pk)
219
+
220
+    @property
221
+    def icon_path(self):
222
+        return upload_file_path(self.icon)
223
+
224
+    @property
225
+    def icon_url(self):
226
+        return upload_file_url(self.icon)
227
+
228
+    @property
229
+    def data(self):
230
+        return {
231
+            'coupon_id': self.coupon_id,
232
+            'active_at': tc.local_string(self.active_at, format='%Y%m%d'),
233
+            'expire_at': tc.local_string(self.expire_at, format='%Y%m%d'),
234
+            'right_id': self.right_id,
235
+            'right_type': self.right_type,
236
+            'icon': self.icon_url,
237
+            'title': self.title,
238
+            'subtitle': self.subtitle,
239
+            'detail': self.detail,
240
+            'level1': self.level1,
241
+            'level2': self.level2,
242
+            'level3': self.level3,
243
+            'level4': self.level4,
244
+            'level5': self.level5,
245
+            'minlevel': self.minlevel,
246
+            'able': True,
247
+            'left_num': 3,
248
+            'left_tip': 3,
175 249
         }
176 250
 
177 251
 
@@ -262,13 +336,25 @@ class MemberActivityInfo(BaseModelMixin):
262 336
         return upload_file_url(self.slider_image)
263 337
 
264 338
     @property
265
-    def data(self):
339
+    def final_state(self):
340
+        tdate = tc.local_date()
341
+        if tdate < self.date:
342
+            return u'报名中'
343
+        if tdate == self.date:
344
+            return u'活动中'
345
+        return u'已结束'
346
+
347
+    def is_signed(self, user_id):
348
+        # 是否已报名
349
+        return MemberActivitySignupInfo.objects.filter(user_id=user_id, activity_id=self.activity_id, status=True).exists()
350
+
351
+    def data(self, user_id):
266 352
         return {
267 353
             'id': self.activity_id,
268 354
             'activity_id': self.activity_id,
269 355
             'title': self.title,
270 356
             'subtitle': self.subtitle,
271
-            'date': tc.local_string(self.date, '%Y-%m-%d'),
357
+            'date': tc.local_string(self.date, format='%Y-%m-%d'),
272 358
             'city': self.city,
273 359
             'location': self.location,
274 360
             'lat': self.lat,
@@ -279,8 +365,8 @@ class MemberActivityInfo(BaseModelMixin):
279 365
             'share_img_link': self.share_img_link,
280 366
             'share_h5_link': self.share_h5_link,
281 367
             'slider_image': self.slider_image_url,
282
-            'state': 0,
283
-            'is_signed': 0,
368
+            'state': self.final_state,
369
+            'is_signed': self.is_signed(user_id),
284 370
         }
285 371
 
286 372
 

+ 1 - 1
requirements.txt

@@ -1,7 +1,7 @@
1 1
 CodeConvert==2.0.5
2 2
 Pillow==5.0.0
3 3
 StatusCode==1.0.0
4
-TimeConvert==1.5.0
4
+TimeConvert==1.5.1
5 5
 furl==2.1.0
6 6
 isoweek==1.3.3
7 7
 jsonfield==2.0.2