No Description

views.py 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. # -*- coding: utf-8 -*-
  2. from django.conf import settings
  3. from django.db import transaction
  4. from django.db.models import Sum
  5. from django_logit import logit
  6. from django_models_ext.provincemodels import ProvinceShortModelMixin
  7. from django_query import get_query_value
  8. from django_response import response
  9. from TimeConvert import TimeConvert as tc
  10. from mch.models import BrandInfo, DistributorInfo, ModelInfo, SaleclerkInfo
  11. from statistic.models import (ConsumeDistributorSaleStatisticInfo, ConsumeModelSaleStatisticInfo,
  12. ConsumeProvinceSaleStatisticInfo, ConsumeSaleStatisticInfo, ConsumeUserStatisticInfo,
  13. DistributorSaleStatisticInfo, ModelSaleStatisticInfo, ProvinceSaleStatisticInfo,
  14. RegisterStatisticInfo, SaleclerkSaleStatisticInfo, SaleStatisticInfo)
  15. from utils.rdm_utils import randnum
  16. @logit
  17. def tj_distributor(request):
  18. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  19. ymd = int(tc.local_string(format='%Y%m%d'))
  20. # 注册用户统计 & 今日注册用户
  21. try:
  22. register_num = RegisterStatisticInfo.objects.get(brand_id=brand_id, ymd=ymd).num
  23. except RegisterStatisticInfo.DoesNotExist:
  24. register_num = 0
  25. # # 注册用户数趋势
  26. # register_trends = RegisterStatisticInfo.objects.filter(status=True).order_by('-ymd')
  27. # register_trends = [r.data for r in register_trends]
  28. # 销量统计 & 今日销量
  29. try:
  30. sale_num = SaleStatisticInfo.objects.get(brand_id=brand_id, ymd=ymd).num
  31. except SaleStatisticInfo.DoesNotExist:
  32. sale_num = 0
  33. # # 商品销量趋势
  34. # sale_trends = SaleStatisticInfo.objects.filter(status=True).order_by('-ymd')
  35. # sale_trends = [s.data for s in sale_trends]
  36. # 型号销量统计 & 热销商品榜
  37. model_sales = ModelSaleStatisticInfo.objects.filter(brand_id=brand_id, ymd=ymd, status=True).order_by('-num')
  38. model_sales = [m.data for m in model_sales]
  39. # 经销商销量统计 & 经销商榜
  40. distributor_sales = DistributorSaleStatisticInfo.objects.filter(brand_id=brand_id, ymd=ymd, status=True).order_by('-num')
  41. distributor_sales = [d.data for d in distributor_sales]
  42. # 各地区实时销量
  43. province_sales = ProvinceSaleStatisticInfo.objects.filter(brand_id=brand_id, ymd=ymd, status=True).order_by('position')
  44. province_sales = [p.data for p in province_sales]
  45. # TOADD: ROI
  46. rois = ModelSaleStatisticInfo.objects.filter(brand_id=brand_id, ymd=ymd, status=True)
  47. rois = [m.roi for m in rois]
  48. return response(200, 'Get TJ Data Success', u'获取统计数据成功', {
  49. 'register_num': randnum() if settings.DEBUG_STATISTIC_DATA_FLAG else register_num, # 注册用户统计 & 今日注册用户
  50. # 'register_trends': register_trends, # 注册用户数趋势
  51. 'sale_num': randnum() if settings.DEBUG_STATISTIC_DATA_FLAG else sale_num, # 销量统计 & 今日销量
  52. # 'sale_trends': sale_trends, # 商品销量趋势
  53. 'model_sales': model_sales, # 型号销量统计 & 热销商品榜
  54. 'distributor_sales': distributor_sales, # 经销商销量统计 & 经销商榜
  55. 'province_sales': province_sales, # 各地区实时销量
  56. 'rois': rois, # ROI
  57. })
  58. @logit
  59. def tj_consumer(request):
  60. brand_id = request.POST.get('brand_id') or settings.KODO_DEFAULT_BRAND_ID
  61. ymd = int(tc.local_string(format='%Y%m%d'))
  62. # 注册用户统计 & 今日注册用户
  63. try:
  64. register_num = RegisterStatisticInfo.objects.get(brand_id=brand_id, ymd=ymd).num
  65. except RegisterStatisticInfo.DoesNotExist:
  66. register_num = 0
  67. # 注册用户数趋势
  68. register_trends = RegisterStatisticInfo.objects.filter(brand_id=brand_id, status=True).order_by('-ymd')[:30]
  69. register_trends = [r.data for r in register_trends][::-1]
  70. # 销量统计 & 今日销量
  71. try:
  72. sale_num = ConsumeSaleStatisticInfo.objects.get(brand_id=brand_id, ymd=ymd).num
  73. except ConsumeSaleStatisticInfo.DoesNotExist:
  74. sale_num = 0
  75. # 商品销量趋势
  76. sale_trends = ConsumeSaleStatisticInfo.objects.filter(brand_id=brand_id, status=True).order_by('-ymd')[:30]
  77. sale_trends = [s.data for s in sale_trends][::-1]
  78. # 型号销量统计 & 热销商品榜
  79. model_sales = ConsumeModelSaleStatisticInfo.objects.filter(brand_id=brand_id, ymd=ymd, status=True).order_by('-num')
  80. model_sales = [m.data for m in model_sales]
  81. # 经销商销量统计 & 经销商榜
  82. distributor_sales = ConsumeDistributorSaleStatisticInfo.objects.filter(brand_id=brand_id, ymd=ymd, status=True).order_by('-num')
  83. distributor_sales = [d.data for d in distributor_sales]
  84. # 各地区实时销量
  85. province_sales = ConsumeProvinceSaleStatisticInfo.objects.filter(brand_id=brand_id, ymd=ymd, status=True).order_by('position')
  86. province_sales = [p.data for p in province_sales]
  87. return response(200, 'Get TJ Data Success', u'获取统计数据成功', {
  88. 'register_num': randnum() if settings.DEBUG_STATISTIC_DATA_FLAG else register_num, # 注册用户统计 & 今日注册用户
  89. 'register_trends': register_trends, # 注册用户数趋势
  90. 'sale_num': randnum() if settings.DEBUG_STATISTIC_DATA_FLAG else sale_num, # 销量统计 & 今日销量
  91. 'sale_trends': sale_trends, # 商品销量趋势
  92. 'model_sales': model_sales, # 型号销量统计 & 热销商品榜
  93. 'distributor_sales': distributor_sales, # 经销商销量统计 & 经销商榜
  94. 'province_sales': province_sales, # 各地区实时销量
  95. })
  96. @logit
  97. @transaction.atomic
  98. def tj_generate(request):
  99. # 1 0 * * * curl http://kodo.xfoto.com.cn/api/tj/generate
  100. __tj_generate(ymd=None)
  101. return response()
  102. @transaction.atomic
  103. def __tj_generate(ymd=None):
  104. ymd = ymd or int(tc.local_string(format='%Y%m%d'))
  105. brands = BrandInfo.objects.filter(status=True)
  106. for brand in brands:
  107. for pcode, pname in ProvinceShortModelMixin.PROVINCE_CODE_NAME_DICT.items():
  108. pssi, created = ProvinceSaleStatisticInfo.objects.get_or_create(
  109. brand_id=brand.brand_id,
  110. province_code=pcode,
  111. ymd=ymd,
  112. )
  113. pssi.province_name = pname
  114. pssi.save()
  115. cpssi, created = ConsumeProvinceSaleStatisticInfo.objects.get_or_create(
  116. brand_id=brand.brand_id,
  117. province_code=pcode,
  118. ymd=ymd,
  119. )
  120. cpssi.province_name = pname
  121. cpssi.save()
  122. models = ModelInfo.objects.filter(brand_id=brand.brand_id, status=True)
  123. for mdl in models:
  124. mssi, created = ModelSaleStatisticInfo.objects.get_or_create(
  125. brand_id=brand.brand_id,
  126. model_id=mdl.model_id,
  127. ymd=ymd,
  128. )
  129. mssi.model_name = mdl.model_name
  130. mssi.save()
  131. cmssi, created = ConsumeModelSaleStatisticInfo.objects.get_or_create(
  132. brand_id=brand.brand_id,
  133. model_name=mdl.model_uni_name,
  134. ymd=ymd,
  135. )
  136. cmssi.save()
  137. distributors = DistributorInfo.objects.filter(brand_id=brand.brand_id, status=True)
  138. for dtbt in distributors:
  139. dssi, created = DistributorSaleStatisticInfo.objects.get_or_create(
  140. brand_id=brand.brand_id,
  141. distributor_id=dtbt.distributor_id,
  142. ymd=ymd,
  143. )
  144. dssi.distributor_name = dtbt.distributor_name
  145. dssi.save()
  146. cdssi, created = ConsumeDistributorSaleStatisticInfo.objects.get_or_create(
  147. brand_id=brand.brand_id,
  148. distributor_id=dtbt.distributor_id,
  149. ymd=ymd,
  150. )
  151. cdssi.distributor_name = dtbt.distributor_name
  152. cdssi.save()
  153. RegisterStatisticInfo.objects.select_for_update().get_or_create(
  154. brand_id=brand.brand_id,
  155. ymd=ymd,
  156. )
  157. SaleStatisticInfo.objects.select_for_update().get_or_create(
  158. brand_id=brand.brand_id,
  159. ymd=ymd,
  160. )
  161. ConsumeSaleStatisticInfo.objects.select_for_update().get_or_create(
  162. brand_id=brand.brand_id,
  163. ymd=ymd,
  164. )
  165. def ytj(brand_id):
  166. # [消费者维度] 周期内扫描用户人数
  167. cusis = ConsumeUserStatisticInfo.objects.filter(brand_id=brand_id, ymd__lt=9999)
  168. users = []
  169. for cusi in cusis:
  170. users += cusi.users
  171. scan_user_count = len(set(users))
  172. # [消费者维度] 周期内镜头销售支数
  173. sell_volume_count = ConsumeSaleStatisticInfo.objects.filter(brand_id=brand_id, ymd__lt=9999).aggregate(Sum('num')).get('num__sum', 0) or 0
  174. startd = tc.local_string(months=-12, format='%Y%m%d')
  175. endd = tc.local_string(format='%Y%m%d')
  176. # [消费者维度] 统计周期内型号扫描排行数据,请按顺序返回
  177. models = ConsumeModelSaleStatisticInfo.objects.filter(
  178. brand_id=brand_id,
  179. ymd__gt=startd,
  180. ymd__lte=endd,
  181. status=True
  182. ).order_by(
  183. 'model_name'
  184. ).values(
  185. 'model_id', 'model_name'
  186. ).annotate(
  187. num=Sum('num')
  188. ).order_by(
  189. '-num'
  190. )[:20]
  191. # [经销商维度] 统计周期内销售员排行数据,请按顺序返回
  192. salesmen = SaleclerkSaleStatisticInfo.objects.filter(
  193. brand_id=brand_id,
  194. ymd__gt=startd,
  195. ymd__lte=endd,
  196. status=True
  197. ).order_by(
  198. 'clerk_id'
  199. ).values(
  200. 'clerk_id'
  201. ).annotate(
  202. num=Sum('num')
  203. ).order_by(
  204. '-num'
  205. )[:20]
  206. clerks = SaleclerkInfo.objects.filter(brand_id=brand_id, status=True)
  207. clerks = {clerk.clerk_id: {'distributor_id': clerk.distributor_id, 'distributor_name': clerk.distributor_name, 'clerk_name': clerk.clerk_name, 'salesman_id': clerk.clerk_id, 'salesman_name': clerk.clerk_name} for clerk in clerks}
  208. salesmen = [dict(sm, **clerks.get(sm.get('clerk_id', ''), {})) for sm in salesmen]
  209. # [收费者维度] 统计周期内省份销量排行数据,请按顺序返回
  210. provinces = ConsumeProvinceSaleStatisticInfo.objects.filter(
  211. brand_id=brand_id,
  212. ymd__gt=startd,
  213. ymd__lte=endd,
  214. status=True
  215. )
  216. # ).order_by(
  217. # 'province_code'
  218. # ).values(
  219. # 'province_code'
  220. # ).annotate(
  221. # num=Sum('num')
  222. # ).order_by(
  223. # '-num'
  224. # )
  225. provinces_users = {}
  226. for province in provinces:
  227. if provinces_users.get(province.province_code):
  228. provinces_users[province.province_code] += province.users
  229. else:
  230. provinces_users[province.province_code] = province.users
  231. provinces = [{'province_code': province_code, 'num': len(set(users))} for province_code, users in provinces_users.items()]
  232. provinces = sorted(provinces, key=lambda p: p['num'], reverse=True)
  233. return {
  234. 'scan_user_count': scan_user_count,
  235. 'sell_volume_count': sell_volume_count,
  236. 'user_count_increase_pct': -1, # 与上个统计周期数据的用户人数比例
  237. 'volume_count_increase_pct': -1, # 与上个统计周期数据的销售支数比例
  238. 'models': list(models),
  239. 'salesmen': salesmen,
  240. 'provinces': provinces,
  241. }
  242. def ymdtj(brand_id, ymd, lastymd):
  243. # [消费者维度] 周期内扫描用户人数
  244. try:
  245. scan_user_count = ConsumeUserStatisticInfo.objects.get(brand_id=brand_id, ymd=ymd).num
  246. except ConsumeUserStatisticInfo.DoesNotExist:
  247. scan_user_count = 0
  248. try:
  249. last_scan_user_count = ConsumeUserStatisticInfo.objects.get(brand_id=brand_id, ymd=lastymd).num
  250. except ConsumeUserStatisticInfo.DoesNotExist:
  251. last_scan_user_count = 0
  252. # [消费者维度] 周期内镜头销售支数
  253. try:
  254. sell_volume_count = ConsumeSaleStatisticInfo.objects.get(brand_id=brand_id, ymd=ymd).num
  255. except ConsumeSaleStatisticInfo.DoesNotExist:
  256. sell_volume_count = 0
  257. try:
  258. last_sell_volume_count = ConsumeSaleStatisticInfo.objects.get(brand_id=brand_id, ymd=lastymd).num
  259. except ConsumeSaleStatisticInfo.DoesNotExist:
  260. last_sell_volume_count = 0
  261. # 与上个统计周期数据的销售支数比例
  262. volume_count_increase_pct = '%.2f' % (sell_volume_count * 100.0 / last_sell_volume_count) if last_sell_volume_count != 0 else -1
  263. # 与上个统计周期数据的用户人数比例
  264. user_count_increase_pct = '%.2f' % (scan_user_count * 100.0 / last_scan_user_count) if last_scan_user_count != 0 else -1
  265. # [消费者维度] 统计周期内型号扫描排行数据,请按顺序返回
  266. current_models = ConsumeModelSaleStatisticInfo.objects.filter(brand_id=brand_id, ymd=ymd, status=True).order_by('-num')
  267. models = [m.data for m in current_models[:20]]
  268. # [经销商维度] 统计周期内销售员排行数据,请按顺序返回
  269. salesmen = SaleclerkSaleStatisticInfo.objects.filter(brand_id=brand_id, ymd=ymd, status=True).order_by('-num')
  270. salesmen = [s.data for s in salesmen[:20]]
  271. # [收费者维度] 统计周期内省份销量排行数据,请按顺序返回
  272. provinces = ConsumeProvinceSaleStatisticInfo.objects.filter(brand_id=brand_id, ymd=ymd, status=True).order_by('-num')
  273. provinces = [p.data for p in provinces]
  274. return {
  275. 'scan_user_count': scan_user_count,
  276. 'sell_volume_count': sell_volume_count,
  277. 'user_count_increase_pct': user_count_increase_pct,
  278. 'volume_count_increase_pct': volume_count_increase_pct,
  279. 'models': models,
  280. 'salesmen': salesmen,
  281. 'provinces': provinces,
  282. }
  283. @logit
  284. def v2_tj_distributor(request):
  285. brand_id = get_query_value(request, 'brand_id', settings.KODO_DEFAULT_BRAND_ID)
  286. # year = tc.local_string(format='%Y')
  287. month = tc.local_string(format='%Y%m')
  288. day = tc.local_string(format='%Y%m%d')
  289. # lastyear = tc.local_string(years=-1, format='%Y')
  290. lastmonth = tc.local_string(months=-1, format='%Y%m')
  291. lastday = tc.local_string(days=-1, format='%Y%m%d')
  292. year_data = ytj(brand_id)
  293. month_data = ymdtj(brand_id, month, lastmonth)
  294. day_data = ymdtj(brand_id, day, lastday)
  295. return response(200, 'Get TJ Data Success', u'获取统计数据成功', data={
  296. 'year_data': year_data,
  297. 'month_data': month_data,
  298. 'day_data': day_data,
  299. })