No Description

mch_views.py 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. # -*- coding: utf-8 -*-
  2. from __future__ import division
  3. from django.conf import settings
  4. from django.contrib.auth.hashers import check_password
  5. from django.db import transaction
  6. from django_logit import logit
  7. from django_response import response
  8. from pywe_miniapp import get_phone_number
  9. from pywe_storage import RedisStorage
  10. from TimeConvert import TimeConvert as tc
  11. from account.models import UserInfo
  12. from integral.models import SaleclerkSubmitLogInfo
  13. from mch.models import (ActivityInfo, AdministratorInfo, BrandInfo, ConsumeInfoSubmitLogInfo, DistributorInfo,
  14. LatestAppInfo, LatestAppScreenInfo, ModelInfo, OperatorInfo)
  15. from statistic.models import ConsumeModelSaleStatisticInfo, ConsumeSaleStatisticInfo, ConsumeUserStatisticInfo
  16. from utils.error.errno_utils import (AdministratorStatusCode, OperatorStatusCode, ProductBrandStatusCode,
  17. ProductModelStatusCode, UserStatusCode)
  18. from utils.redis.connect import r
  19. from utils.redis.rkeys import MEMBER_SEND_COUPON_LIST, MINI_PROGRAM_GIS_LIST, MEMBER_UPGRADE_INFO
  20. WECHAT = settings.WECHAT
  21. @logit
  22. def optor_login_api(request):
  23. brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
  24. if brand_id != settings.KODO_DEFAULT_BRAND_ID:
  25. return response(ProductBrandStatusCode.BRAND_NOT_MATCH)
  26. phone = request.POST.get('phone', '')
  27. password = request.POST.get('password', '')
  28. try:
  29. operator = OperatorInfo.objects.get(phone=phone, status=True)
  30. except OperatorInfo.DoesNotExist:
  31. return response(OperatorStatusCode.OPERATOR_NOT_FOUND)
  32. if operator.user_status == OperatorInfo.DISABLED:
  33. return response(OperatorStatusCode.OPERATOR_NOT_ACTIVATED)
  34. elif operator.user_status == OperatorInfo.DELETED:
  35. return response(OperatorStatusCode.OPERATOR_HAS_DELETED)
  36. if not check_password(password, operator.encryption):
  37. return response(OperatorStatusCode.OPERATOR_PASSWORD_ERROR)
  38. return response(200, 'Optor Login Success', u'操作员登录成功', data=operator.kododata)
  39. @logit
  40. def admin_login_api(request):
  41. brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
  42. if brand_id != settings.KODO_DEFAULT_BRAND_ID:
  43. return response(ProductBrandStatusCode.BRAND_NOT_MATCH)
  44. phone = request.POST.get('phone', '')
  45. password = request.POST.get('password', '')
  46. try:
  47. administrator = AdministratorInfo.objects.get(phone=phone, status=True)
  48. except AdministratorInfo.DoesNotExist:
  49. return response(AdministratorStatusCode.ADMINISTRATOR_NOT_FOUND)
  50. if administrator.user_status == AdministratorInfo.DISABLED:
  51. return response(AdministratorStatusCode.ADMINISTRATOR_NOT_ACTIVATED)
  52. elif administrator.user_status == AdministratorInfo.DELETED:
  53. return response(AdministratorStatusCode.ADMINISTRATOR_HAS_DELETED)
  54. if not check_password(password, administrator.encryption):
  55. return response(AdministratorStatusCode.ADMINISTRATOR_PASSWORD_ERROR)
  56. request.session['admin_id'] = administrator.admin_id
  57. return response(200, 'Admin Login Success', u'管理员登录成功', data={
  58. 'admin_id': administrator.admin_id,
  59. 'admin_type': administrator.admin_type,
  60. 'qrurl': settings.KODO_CLERK_AUTH_URL.format(administrator.brand_id),
  61. })
  62. @logit
  63. def bmd_infos(request):
  64. optor_id = request.POST.get('optor_id', '')
  65. try:
  66. operator = OperatorInfo.objects.get(operator_id=optor_id, status=True)
  67. except OperatorInfo.DoesNotExist:
  68. return response(OperatorStatusCode.OPERATOR_NOT_FOUND)
  69. if operator.user_status == OperatorInfo.DISABLED:
  70. return response(OperatorStatusCode.OPERATOR_NOT_ACTIVATED)
  71. brands = BrandInfo.objects.filter(brand_id=operator.brand_id, status=True).order_by('position')
  72. brands = [brand.data for brand in brands]
  73. tmpmodels = ModelInfo.objects.filter(brand_id=operator.brand_id, display=True, status=True).order_by('position')
  74. models = [model.data for model in tmpmodels]
  75. # jancodes = {model.jancode: model.data for model in tmpmodels}
  76. distributors = DistributorInfo.objects.filter(brand_id=operator.brand_id, status=True).order_by('position')
  77. distributors = [distributor.data for distributor in distributors]
  78. return response(200, data={
  79. 'optor_id': operator.operator_id,
  80. 'brands': brands,
  81. 'models': models,
  82. # 'jancodes': jancodes,
  83. 'distributors': distributors,
  84. })
  85. @logit
  86. def brands_list(request):
  87. brands = BrandInfo.objects.filter(status=True).order_by('position')
  88. brands = [brand.data for brand in brands]
  89. return response(200, data={
  90. 'brands': brands,
  91. })
  92. @logit
  93. def models_list(request):
  94. models = ModelInfo.objects.filter(status=True).order_by('position')
  95. models = [model.data for model in models]
  96. return response(200, data={
  97. 'models': models,
  98. })
  99. @logit
  100. def distributors_list(request):
  101. distributors = DistributorInfo.objects.filter(status=True).order_by('position')
  102. distributors = [distributor.data for distributor in distributors]
  103. return response(200, data={
  104. 'distributors': distributors,
  105. })
  106. @logit
  107. def upgrade_api(request):
  108. """ APP 升级 """
  109. src = request.POST.get('src', '')
  110. if src == 'datascreen':
  111. latestappmodel = LatestAppScreenInfo
  112. else:
  113. latestappmodel = LatestAppInfo
  114. try:
  115. appinfo = latestappmodel.objects.filter(status=True)[0].adr
  116. except IndexError:
  117. appinfo = {
  118. 'latest_version_code': '',
  119. 'latest_version_name': '',
  120. 'latest_url': '',
  121. }
  122. return response(200, 'Get Latest App Success', u'获取最新版信息成功', {
  123. 'appinfo': appinfo,
  124. })
  125. def getPhoneNumber(request):
  126. user_id = request.POST.get('user_id', '')
  127. wxcfg = WECHAT.get('MINIAPP', {})
  128. appid = wxcfg.get('appID')
  129. # Just for compatible because of store session_key has changed
  130. session_key = None if user_id else RedisStorage(r).get('{0}:{1}:sessionKey'.format(appid, ''))
  131. wxcfg = WECHAT.get('MINIAPP', {})
  132. appid = wxcfg.get('appID')
  133. secret = wxcfg.get('appsecret')
  134. iv = request.POST.get('iv', '')
  135. encryptedData = request.POST.get('encryptedData', '')
  136. # {
  137. # "phoneNumber": "13580006666",
  138. # "purePhoneNumber": "13580006666",
  139. # "countryCode": "86",
  140. # "watermark":
  141. # {
  142. # "appid": "APPID",
  143. # "timestamp": TIMESTAMP
  144. # }
  145. # }
  146. phone_number = get_phone_number(appid=appid, secret=secret, unid=user_id, session_key=session_key, encryptedData=encryptedData, iv=iv, storage=RedisStorage(r))
  147. return phone_number.get('purePhoneNumber', '')
  148. @logit(res=True)
  149. def consumer_phone_api(request):
  150. return response(200, 'Get Consumer Phone Success', u'获取消费者手机号成功', {
  151. 'purePhoneNumber': getPhoneNumber(request),
  152. })
  153. @logit(res=True)
  154. @transaction.atomic
  155. def consumer_info_api(request):
  156. user_id = request.POST.get('user_id', '')
  157. iv = request.POST.get('iv', '')
  158. encryptedData = request.POST.get('encryptedData', '')
  159. lat = request.POST.get('lat', .0)
  160. lon = request.POST.get('lon', .0)
  161. brandID = request.POST.get('brand_id', '') or request.POST.get('BrandID', '')
  162. modelID = request.POST.get('ModelID', '')
  163. distributorID = request.POST.get('DistributorID', '')
  164. serialNo = request.POST.get('SerialNo', '')
  165. verifyResult = request.POST.get('verifyResult', '')
  166. purePhoneNumber = request.POST.get('purePhoneNumber', '')
  167. if lat == 'undefined':
  168. lat = .0
  169. if lon == 'undefined':
  170. lon = .0
  171. purePhoneNumber = purePhoneNumber or getPhoneNumber(request)
  172. # 校验用户是否存在
  173. try:
  174. user = UserInfo.objects.get(user_id=user_id)
  175. except UserInfo.DoesNotExist:
  176. return response(UserStatusCode.USER_NOT_FOUND)
  177. # 更新用户手机号
  178. user.phone = purePhoneNumber
  179. user.save()
  180. try:
  181. brand = BrandInfo.objects.get(brand_id=brandID)
  182. except BrandInfo.DoesNotExist:
  183. brand = None
  184. if not brand:
  185. try:
  186. brand = BrandInfo.objects.get(pk=brandID)
  187. except BrandInfo.DoesNotExist:
  188. return response(ProductBrandStatusCode.BRAND_NOT_FOUND)
  189. except ValueError:
  190. return response(ProductBrandStatusCode.BRAND_NOT_FOUND)
  191. try:
  192. model = ModelInfo.objects.get(pk=modelID)
  193. except ModelInfo.DoesNotExist:
  194. return response(ProductModelStatusCode.MODEL_NOT_FOUND)
  195. except ValueError:
  196. return response(ProductModelStatusCode.MODEL_NOT_FOUND)
  197. # try:
  198. # distributor = DistributorInfo.objects.get(pk=distributorID)
  199. # except DistributorInfo.DoesNotExist:
  200. # return response(ProductDistributorStatusCode.DISTRIBUTOR_NOT_FOUND)
  201. # except ValueError:
  202. # return response(ProductDistributorStatusCode.DISTRIBUTOR_NOT_FOUND)
  203. dupload = ConsumeInfoSubmitLogInfo.objects.filter(
  204. brand_id=brand.brand_id,
  205. model_id=model.model_id,
  206. # distributor_id=distributor.distributor_id,
  207. distributor_id='',
  208. serialNo=serialNo,
  209. verifyResult=1,
  210. test_user=False,
  211. ).exists()
  212. if dupload:
  213. act = None
  214. during_activity = False
  215. else:
  216. act = ActivityInfo.objects.filter(status=True).order_by('-pk').first()
  217. during_activity = True if act and act.has_unexpired_activity(model.model_uni_name) else False
  218. # 记录用户信息提交记录
  219. log = ConsumeInfoSubmitLogInfo.objects.create(
  220. user_id=user_id,
  221. phone=purePhoneNumber,
  222. iv=iv,
  223. encryptedData=encryptedData,
  224. lat=lat,
  225. lon=lon,
  226. brand_id=brand.brand_id,
  227. brand_name=brand.brand_name,
  228. model_id=model.model_id,
  229. model_name=model.model_name,
  230. # distributor_id=distributor.distributor_id,
  231. # distributor_name=distributor.distributor_name,
  232. distributor_id='',
  233. distributor_name='',
  234. serialNo=serialNo,
  235. verifyResult=verifyResult,
  236. dupload=dupload,
  237. submit_during_activity=during_activity,
  238. activity_id=act.pk if during_activity else 0,
  239. coupon_expire_at=act.coupon_expire_at if during_activity else None,
  240. coupon_value=act.coupon_value if during_activity else 0,
  241. test_user=user.test_user,
  242. )
  243. if not user.test_user and not dupload:
  244. # TODO: Make statistic async
  245. ymd = tc.local_string(format='%Y%m%d')
  246. cusi, _ = ConsumeUserStatisticInfo.objects.get_or_create(
  247. brand_id=brand.brand_id,
  248. ymd=ymd,
  249. )
  250. cusi.users = list(set(cusi.users + [log.user_id]))
  251. cusi.num = len(cusi.users)
  252. cusi.save()
  253. cusi, _ = ConsumeUserStatisticInfo.objects.get_or_create(
  254. brand_id=brand.brand_id,
  255. ymd=ymd[:6],
  256. )
  257. cusi.users = list(set(cusi.users + [log.user_id]))
  258. cusi.num = len(cusi.users)
  259. cusi.save()
  260. cusi, _ = ConsumeUserStatisticInfo.objects.get_or_create(
  261. brand_id=brand.brand_id,
  262. ymd=ymd[:4],
  263. )
  264. cusi.users = list(set(cusi.users + [log.user_id]))
  265. cusi.num = len(cusi.users)
  266. cusi.save()
  267. # 日销量统计
  268. cssi, _ = ConsumeSaleStatisticInfo.objects.select_for_update().get_or_create(
  269. brand_id=brand.brand_id,
  270. ymd=ymd,
  271. )
  272. cssi.num += 1
  273. cssi.save()
  274. # 月销量统计
  275. cssi, _ = ConsumeSaleStatisticInfo.objects.select_for_update().get_or_create(
  276. brand_id=brand.brand_id,
  277. ymd=ymd[:6],
  278. )
  279. cssi.num += 1
  280. cssi.save()
  281. # 年销量统计
  282. cssi, _ = ConsumeSaleStatisticInfo.objects.select_for_update().get_or_create(
  283. brand_id=brand.brand_id,
  284. ymd=ymd[:4],
  285. )
  286. cssi.num += 1
  287. cssi.save()
  288. # 日型号销量统计
  289. cmssi, _ = ConsumeModelSaleStatisticInfo.objects.select_for_update().get_or_create(
  290. brand_id=brand.brand_id,
  291. model_name=model.model_uni_name,
  292. ymd=ymd,
  293. )
  294. cmssi.users = list(set(cmssi.users + [user_id]))
  295. cmssi.num = len(cmssi.users)
  296. cmssi.save()
  297. # 月型号销量统计
  298. cmssi, _ = ConsumeModelSaleStatisticInfo.objects.select_for_update().get_or_create(
  299. brand_id=brand.brand_id,
  300. model_name=model.model_uni_name,
  301. ymd=ymd[:6],
  302. )
  303. cmssi.users = list(set(cmssi.users + [user_id]))
  304. cmssi.num = len(cmssi.users)
  305. cmssi.save()
  306. # 年型号销量统计
  307. cmssi, _ = ConsumeModelSaleStatisticInfo.objects.select_for_update().get_or_create(
  308. brand_id=brand.brand_id,
  309. model_name=model.model_uni_name,
  310. ymd=ymd[:4],
  311. )
  312. cmssi.users = list(set(cmssi.users + [user_id]))
  313. cmssi.num = len(cmssi.users)
  314. cmssi.save()
  315. r.rpushjson(MINI_PROGRAM_GIS_LIST, {
  316. 'brand_id': log.brand_id,
  317. 'user_id': log.user_id,
  318. 'lat': log.lat,
  319. 'lon': log.lon,
  320. 'phone': log.phone,
  321. 'ymd': ymd,
  322. })
  323. # 更新销售员提交的表
  324. logs = SaleclerkSubmitLogInfo.objects.filter(code=serialNo, model_pk=model.pk)
  325. for log in logs:
  326. log.has_scan = True
  327. log.save()
  328. if not dupload:
  329. user.shots_num += 1
  330. if user.level < UserInfo.MEMBER_BLACK_GOLD:
  331. user.level += 1
  332. user.integral += model.shot_member_integral
  333. # 发放会员权益
  334. r.rpushjson(MEMBER_SEND_COUPON_LIST, {
  335. 'brand_id': brand.brand_id,
  336. 'user_id': user_id,
  337. })
  338. # 会员升级提示
  339. r.set(MEMBER_UPGRADE_INFO % (brand.brand_id, user_id), 1)
  340. user.save()
  341. return response(200, 'Submit Consumer Info Success', u'提交消费者信息成功')
  342. @logit(res=True)
  343. @transaction.atomic
  344. def consumer_snlist_api(request):
  345. user_id = request.POST.get('user_id', '')
  346. # 校验用户是否存在
  347. try:
  348. user = UserInfo.objects.get(user_id=user_id)
  349. except UserInfo.DoesNotExist:
  350. return response(UserStatusCode.USER_NOT_FOUND)
  351. # 用户信息提交列表
  352. logs = ConsumeInfoSubmitLogInfo.objects.filter(user_id=user_id, status=True).distinct()
  353. seen = set()
  354. seen_add = seen.add
  355. logs = [log.data for log in logs if not (log.serialNo in seen or seen_add(log.serialNo))]
  356. return response(200, 'Get Consumer Submit List Success', u'获取消费者提交列表成功', {
  357. 'logs': logs,
  358. })