暂无描述

member_views.py 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. # -*- coding: utf-8 -*-
  2. from __future__ import division
  3. from django.conf import settings
  4. from django.db import transaction
  5. from django.db.models import Sum
  6. from django_logit import logit
  7. from django_query import get_query_value
  8. from django_response import response
  9. from paginator import pagination
  10. from pywe_miniapp import get_shareinfo
  11. from pywe_storage import RedisStorage
  12. from TimeConvert import TimeConvert as tc
  13. from account.models import UserInfo, UserIntegralIncomeExpensesInfo
  14. from coupon.models import UserCouponInfo
  15. from member.models import (GoodsInfo, GoodsOrderInfo, MemberActivityContributionInfo,
  16. MemberActivityContributionWelfareUnlockingInfo, MemberActivityGroupShareInfo,
  17. MemberActivityInfo, MemberActivitySigninInfo, MemberActivitySignupInfo, RightInfo)
  18. from utils.error.errno_utils import (MemberActivityContributionStatusCode,
  19. MemberActivityContributionWelfareUnblockingStatusCode, MemberActivityStatusCode,
  20. MemberCouponStatusCode, MemberGoodStatusCode, MemberRightStatusCode,
  21. PermissionStatusCode, UserStatusCode)
  22. from utils.redis.connect import r
  23. from utils.redis.rkeys import MEMBER_SEND_COUPON_LIST, MEMBER_UPGRADE_INFO
  24. from utils.redis.rshot import get_member_shot_data
  25. WECHAT = settings.WECHAT
  26. @logit
  27. def member(request):
  28. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  29. user_id = request.POST.get('user_id', '')
  30. # 校验用户是否存在
  31. try:
  32. user = UserInfo.objects.get(user_id=user_id)
  33. except UserInfo.DoesNotExist:
  34. return response(UserStatusCode.USER_NOT_FOUND)
  35. rights = RightInfo.objects.filter(status=True).order_by('position')
  36. rights = [right.data for right in rights]
  37. goods = GoodsInfo.objects.filter(only_for_member=False, left_num__gt=0, status=True).order_by('position')
  38. goods = [good.data(user_id) for good in goods][:2]
  39. member_goods = GoodsInfo.objects.filter(only_for_member=True, left_num__gt=0, minlevel__lte=user.level, status=True).order_by('position')
  40. member_goods = [good.data(user_id) for good in member_goods]
  41. member_goods = [good for good in member_goods if not good['has_member_exchange']]
  42. upgrade_info, _ = r.getdel(MEMBER_UPGRADE_INFO % (brand_id, user_id))
  43. return response(data={
  44. 'nickname': user.final_nickname,
  45. 'avatar': user.final_avatar,
  46. 'integral': user.integral,
  47. 'freeze_integral': user.freeze_integral,
  48. 'final_integral': user.final_integral,
  49. 'shots_num': user.shots_num,
  50. 'level': user.level,
  51. 'rights': rights,
  52. 'goods': goods,
  53. 'has_membercard': user.has_membercard,
  54. 'membercardid': user.membercardid,
  55. 'memberusercardcode': user.memberusercardcode,
  56. 'member_goods': member_goods,
  57. 'has_upgrade': bool(upgrade_info),
  58. })
  59. @logit
  60. def rights(request):
  61. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  62. user_id = request.POST.get('user_id', '')
  63. level = request.POST.get('level', '')
  64. # 校验用户是否存在
  65. try:
  66. user = UserInfo.objects.get(user_id=user_id)
  67. except UserInfo.DoesNotExist:
  68. return response(UserStatusCode.USER_NOT_FOUND)
  69. rights = RightInfo.objects.filter(status=True).order_by('position')
  70. rights = [right.data for right in rights]
  71. return response(data={
  72. 'nickname': user.final_nickname,
  73. 'avatar': user.final_avatar,
  74. 'integral': user.integral,
  75. 'freeze_integral': user.freeze_integral,
  76. 'final_integral': user.final_integral,
  77. 'shots_num': user.shots_num,
  78. 'level': user.level,
  79. 'rights': rights,
  80. })
  81. @logit
  82. def right_detail(request):
  83. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  84. user_id = request.POST.get('user_id', '')
  85. right_id = request.POST.get('right_id', '')
  86. try:
  87. right = RightInfo.objects.get(right_id=right_id)
  88. except RightInfo.DoesNotExist:
  89. return response(MemberRightStatusCode.RIGHT_NOT_FOUND)
  90. return response(data={
  91. 'right': right.data,
  92. })
  93. @logit
  94. def goods(request):
  95. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  96. user_id = request.POST.get('user_id', '')
  97. # 校验用户是否存在
  98. try:
  99. user = UserInfo.objects.get(user_id=user_id)
  100. except UserInfo.DoesNotExist:
  101. return response(UserStatusCode.USER_NOT_FOUND)
  102. raw_goods = GoodsInfo.objects.filter(only_for_member=False, left_num__gt=0, good_state=GoodsInfo.SHELVES, status=True).order_by('position', '-pk')
  103. banners = goods = []
  104. for good in raw_goods:
  105. if good.is_slider:
  106. banners.append(good.data(user_id))
  107. else:
  108. goods.append(good.data(user_id))
  109. return response(data={
  110. 'nickname': user.final_nickname,
  111. 'avatar': user.final_avatar,
  112. 'integral': user.integral,
  113. 'freeze_integral': user.freeze_integral,
  114. 'final_integral': user.final_integral,
  115. 'shots_num': user.shots_num,
  116. 'level': user.level,
  117. 'banners': banners,
  118. 'goods': goods,
  119. })
  120. @logit
  121. def good_detail(request):
  122. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  123. user_id = request.POST.get('user_id', '')
  124. good_id = request.POST.get('good_id', '')
  125. # 校验用户是否存在
  126. try:
  127. user = UserInfo.objects.get(user_id=user_id)
  128. except UserInfo.DoesNotExist:
  129. return response(UserStatusCode.USER_NOT_FOUND)
  130. try:
  131. good = GoodsInfo.objects.get(good_id=good_id)
  132. except GoodsInfo.DoesNotExist:
  133. return response(MemberGoodStatusCode.GOOD_NOT_FOUND)
  134. return response(data={
  135. 'nickname': user.final_nickname,
  136. 'avatar': user.final_avatar,
  137. 'integral': user.integral,
  138. 'freeze_integral': user.freeze_integral,
  139. 'final_integral': user.final_integral,
  140. 'shots_num': user.shots_num,
  141. 'level': user.level,
  142. 'good': good.details(user_id),
  143. })
  144. @logit
  145. @transaction.atomic
  146. def good_exchange(request):
  147. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  148. user_id = request.POST.get('user_id', '')
  149. good_id = request.POST.get('good_id', '')
  150. good_ids = get_query_value(request, 'good_ids', val_cast_type='listjson')
  151. name = request.POST.get('name', '')
  152. phone = request.POST.get('phone', '')
  153. address = request.POST.get('address', '')
  154. # 校验用户是否存在
  155. try:
  156. user = UserInfo.objects.select_for_update().get(user_id=user_id)
  157. except UserInfo.DoesNotExist:
  158. return response(UserStatusCode.USER_NOT_FOUND)
  159. if good_id:
  160. good_ids.append(good_id)
  161. goods = []
  162. for good_id in good_ids:
  163. try:
  164. good = GoodsInfo.objects.select_for_update().get(good_id=good_id)
  165. except GoodsInfo.DoesNotExist:
  166. return response(MemberGoodStatusCode.GOOD_NOT_FOUND)
  167. if good.left_num <= 0:
  168. return response(MemberGoodStatusCode.GOOD_STOCK_NOT_ENOUGH)
  169. if user.level < good.minlevel:
  170. return response(MemberGoodStatusCode.GOOD_NO_EXCHANGE_PERMISSION)
  171. if user.integral < good.integral:
  172. return response(MemberGoodStatusCode.GOOD_INTEGRAL_NOT_ENOUGH)
  173. # 校验重复兑换
  174. if good.only_once and GoodsOrderInfo.objects.filter(user_id=user_id, good_id=good_id, status=True).exists():
  175. return response(MemberGoodStatusCode.GOOD_EXCHANGE_ONLY_ONCE)
  176. if good.good_type == GoodsInfo.PHYSICAL and address == '':
  177. return response(MemberGoodStatusCode.GOOD_NO_ADDRESS)
  178. user.integral -= good.integral
  179. user.save()
  180. good.left_num -= 1
  181. good.save()
  182. GoodsOrderInfo.objects.create(
  183. user_id=user_id,
  184. good_id=good_id,
  185. good_type=good.good_type,
  186. title=good.title,
  187. relate_good_title=good.relate_good_title,
  188. name=name,
  189. phone=phone,
  190. address=address,
  191. integral=good.integral,
  192. )
  193. if good.good_type == GoodsInfo.PHYSICAL:
  194. # TODO: 通知客服发快递
  195. pass
  196. else:
  197. # TODO: 发放虚拟商品
  198. if good.coupon_id:
  199. # 发放券
  200. r.rpushjson(MEMBER_SEND_COUPON_LIST, {
  201. 'brand_id': brand_id,
  202. 'user_id': user_id,
  203. 'coupon_id': good.coupon_id,
  204. })
  205. else:
  206. pass
  207. goods.append(good.data(user_id))
  208. return response(data={
  209. 'nickname': user.final_nickname,
  210. 'avatar': user.final_avatar,
  211. 'integral': user.integral,
  212. 'freeze_integral': user.freeze_integral,
  213. 'final_integral': user.final_integral,
  214. 'shots_num': user.shots_num,
  215. 'level': user.level,
  216. 'goods': goods,
  217. })
  218. @logit
  219. def coupons(request):
  220. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  221. user_id = request.POST.get('user_id', '')
  222. page = request.POST.get('page', 1)
  223. num = request.POST.get('num', 20)
  224. coupons = UserCouponInfo.objects.filter(user_id=user_id, status=True).order_by('-pk')
  225. coupons, left = pagination(coupons, page, num)
  226. coupons = [coupon.data for coupon in coupons]
  227. return response(data={
  228. 'coupons': coupons,
  229. 'left': left,
  230. })
  231. @logit
  232. def user_coupon_detail(request):
  233. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  234. user_coupon_id = request.POST.get('user_coupon_id', '')
  235. try:
  236. coupon = UserCouponInfo.objects.get(user_coupon_id=user_coupon_id, status=True)
  237. except UserCouponInfo.DoesNotExist:
  238. return response(MemberCouponStatusCode.USER_COUPON_NOT_FOUND)
  239. return response(data=coupon.data)
  240. @logit
  241. @transaction.atomic
  242. def user_coupon_use(request):
  243. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  244. admin_id = request.POST.get('admin_id', '')
  245. user_coupon_id = request.POST.get('user_coupon_id', '')
  246. try:
  247. coupon = UserCouponInfo.objects.select_for_update().get(user_coupon_id=user_coupon_id, status=True)
  248. except UserCouponInfo.DoesNotExist:
  249. return response(MemberCouponStatusCode.USER_COUPON_NOT_FOUND)
  250. if not coupon.has_actived:
  251. return response(MemberCouponStatusCode.USER_COUPON_NOT_ACTIVED)
  252. if coupon.has_expired:
  253. return response(MemberCouponStatusCode.USER_COUPON_HAS_EXPIRED)
  254. if coupon.has_used:
  255. return response(MemberCouponStatusCode.USER_COUPON_HAS_USED)
  256. coupon.has_used = True
  257. coupon.admin_id = admin_id
  258. coupon.used_at = tc.utc_datetime()
  259. coupon.save()
  260. return response(data=coupon.data)
  261. @logit
  262. def integrals(request):
  263. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  264. return response(data={
  265. 'shots_types': get_member_shot_data(),
  266. 'enable_photo_upvote_integral': True,
  267. 'mp_url': 'https://mp.weixin.qq.com/s/2K6PAnf3KrxtrP40-DBuww',
  268. 'photo_upvote_integrals': {
  269. 'headers': [u'排名', u'日', u'周', u'月'],
  270. 'ranks': [
  271. [u'第1名', '10', '20', '30'],
  272. [u'第2名', '5', '10', '15'],
  273. [u'第3名', '3', '6', '9'],
  274. [u'第4-10名', '1', '2', '3'],
  275. ]
  276. },
  277. 'enable_activity_integral': True,
  278. })
  279. def get_group_share_info_integral(activity_id, share_user_id, open_gid, group_share_integral, group_share_max_integral):
  280. # 校验该分享人是否已领取该群积分
  281. if open_gid:
  282. has_integral = MemberActivityGroupShareInfo.objects.filter(activity_id=activity_id, share_user_id=share_user_id, open_gid=open_gid, is_integral=True).exists()
  283. else:
  284. has_integral = MemberActivityGroupShareInfo.objects.filter(activity_id=activity_id, share_user_id=share_user_id, is_integral=True).exists()
  285. if has_integral:
  286. return False, 0
  287. # 校验该分享人是否已领取该活动积分上限
  288. total_integral = MemberActivityGroupShareInfo.objects.filter(activity_id=activity_id, share_user_id=share_user_id).aggregate(Sum('integral')).get('integral__sum', 0) or 0
  289. if total_integral + group_share_integral > group_share_max_integral:
  290. return False, 0
  291. return True, group_share_integral
  292. @logit
  293. @transaction.atomic
  294. def activity_group_share(request):
  295. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  296. share_user_id = request.POST.get('share_user_id', '')
  297. click_user_id = request.POST.get('click_user_id', '')
  298. activity_id = request.POST.get('activity_id', '')
  299. iv = request.POST.get('iv', '')
  300. encryptedData = request.POST.get('encryptedData', '')
  301. open_gid = None
  302. if iv and encryptedData:
  303. wxcfg = WECHAT.get('MINIAPP', {})
  304. appid = wxcfg.get('appID')
  305. secret = wxcfg.get('appsecret')
  306. # {
  307. # "openGId": "OPENGID"
  308. # }
  309. shareinfo = get_shareinfo(appid=appid, secret=secret, unid=click_user_id, session_key=None, encryptedData=encryptedData, iv=iv, storage=RedisStorage(r))
  310. open_gid = shareinfo.get('openGId')
  311. if not open_gid:
  312. return response()
  313. try:
  314. user = UserInfo.objects.select_for_update().get(user_id=share_user_id, status=True)
  315. except UserInfo.DoesNotExist:
  316. return response(UserStatusCode.USER_NOT_FOUND)
  317. try:
  318. act = MemberActivityInfo.objects.select_for_update().get(activity_id=activity_id, status=True)
  319. except MemberActivityInfo.DoesNotExist:
  320. return response(MemberActivityStatusCode.ACTIVITY_NOT_FOUND)
  321. isOffline = act.activity_state != 1 or act.final_state == '已结束'
  322. # 判断是否给积分 & 给多少积分
  323. is_integral, integral = get_group_share_info_integral(act.activity_id, share_user_id, open_gid, act.group_share_integral, act.group_share_max_integral)
  324. # 活动未结束,则给用户加积分
  325. if is_integral:
  326. MemberActivityGroupShareInfo.objects.create(**{
  327. 'brand_id': act.brand_id,
  328. 'brand_name': act.brand_name,
  329. 'share_user_id': share_user_id,
  330. 'click_user_id': click_user_id,
  331. 'open_gid': open_gid,
  332. 'activity_id': activity_id,
  333. 'title': act.title,
  334. 'is_integral': is_integral,
  335. 'integral': 0 if isOffline else integral,
  336. })
  337. if not isOffline:
  338. user.integral += integral
  339. user.save()
  340. if isOffline:
  341. return response(400002, 'Activity has been offline', '会员活动已下线')
  342. return response()
  343. @logit
  344. def activity_contribute_welfare_unlocking_list(request):
  345. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  346. user_id = request.POST.get('user_id', '')
  347. page = request.POST.get('page', 1)
  348. num = request.POST.get('num', 20)
  349. unlockings = MemberActivityContributionWelfareUnlockingInfo.objects.filter(user_id=user_id, is_handled=False, status=True).order_by('-pk')
  350. unlockings, left = pagination(unlockings, page, num)
  351. unlockings = [unlocking.data for unlocking in unlockings]
  352. return response(data={
  353. 'unlockings': unlockings,
  354. 'left': left,
  355. })
  356. @logit
  357. def activity_contribute_welfare_unlocking_detail(request):
  358. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  359. unlocking_id = request.POST.get('unlocking_id', '')
  360. user_id = request.POST.get('user_id', '')
  361. try:
  362. unlocking = MemberActivityContributionWelfareUnlockingInfo.objects.get(unlocking_id=unlocking_id, status=True)
  363. except MemberActivityContributionWelfareUnlockingInfo.DoesNotExist:
  364. return response(MemberActivityContributionWelfareUnblockingStatusCode.ACTIVITY_CONTRIBUTION_WELFARE_UNBLOCKING_NOT_FOUND)
  365. if user_id != unlocking.user_id:
  366. return response(PermissionStatusCode.PERMISSION_DENIED)
  367. return response(data=unlocking.data)
  368. @logit
  369. @transaction.atomic
  370. def activity_contribute_welfare_unlocking_update(request):
  371. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  372. unlocking_id = request.POST.get('unlocking_id', '')
  373. user_id = request.POST.get('user_id', '')
  374. name = request.POST.get('name', '')
  375. phone = request.POST.get('phone', '')
  376. address = request.POST.get('address', '')
  377. try:
  378. unlocking = MemberActivityContributionWelfareUnlockingInfo.objects.select_for_update().get(unlocking_id=unlocking_id, status=True)
  379. except MemberActivityContributionWelfareUnlockingInfo.DoesNotExist:
  380. return response(MemberActivityContributionWelfareUnblockingStatusCode.ACTIVITY_CONTRIBUTION_WELFARE_UNBLOCKING_NOT_FOUND)
  381. if user_id != unlocking.user_id:
  382. return response(PermissionStatusCode.PERMISSION_DENIED)
  383. if name:
  384. unlocking.name = name
  385. if phone:
  386. unlocking.phone = phone
  387. if address:
  388. unlocking.address = address
  389. unlocking.is_handled = True
  390. unlocking.save()
  391. return response(200, 'Update Member Activity Contribute Welfare Unblocking Success', u'更新会员活动投稿福利解锁成功')
  392. @logit
  393. @transaction.atomic
  394. def activity_contribute_welfare_unlocking_handled(request):
  395. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  396. unlocking_id = request.POST.get('unlocking_id', '')
  397. user_id = request.POST.get('user_id', '')
  398. try:
  399. unlocking = MemberActivityContributionWelfareUnlockingInfo.objects.select_for_update().get(unlocking_id=unlocking_id, status=True)
  400. except MemberActivityContributionWelfareUnlockingInfo.DoesNotExist:
  401. return response(MemberActivityContributionWelfareUnblockingStatusCode.ACTIVITY_CONTRIBUTION_WELFARE_UNBLOCKING_NOT_FOUND)
  402. if unlocking.is_handled:
  403. return response(MemberActivityContributionWelfareUnblockingStatusCode.ACTIVITY_CONTRIBUTION_WELFARE_UNBLOCKING_HAS_HANDLED)
  404. if user_id != unlocking.user_id:
  405. return response(PermissionStatusCode.PERMISSION_DENIED)
  406. unlocking.is_handled = True
  407. unlocking.save()
  408. if unlocking.welfare_type == MemberActivityContributionWelfareUnlockingInfo.WELFARE_INTEGRAL:
  409. try:
  410. user = UserInfo.objects.select_for_update().get(user_id=user_id, status=True)
  411. except UserInfo.DoesNotExist:
  412. return response(UserStatusCode.USER_NOT_FOUND)
  413. user.integral += unlocking.welfare_value
  414. user.save()
  415. UserIntegralIncomeExpensesInfo.objects.create(
  416. brand_id=brand_id,
  417. user_id=user_id,
  418. integral_from=UserIntegralIncomeExpensesInfo.MEMBER_ACTIVITY_CONTRIBUTION_WELFARE,
  419. integral=unlocking.welfare_value,
  420. final_integral=user.integral,
  421. remark=unlocking.id,
  422. )
  423. return response(200, 'Update Member Activity Contribute Welfare Unblocking Success', u'处理会员活动投稿福利解锁成功')