@@ -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 |
|
@@ -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 |
}) |
@@ -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'), |
@@ -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 |
+ ] |
@@ -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,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 |