| @@ -0,0 +1,20 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | +# Generated by Django 1.11.9 on 2018-03-08 06:40 | |
| 3 | +from __future__ import unicode_literals | |
| 4 | + | |
| 5 | +from django.db import migrations, models | |
| 6 | + | |
| 7 | + | |
| 8 | +class Migration(migrations.Migration): | |
| 9 | + | |
| 10 | + dependencies = [ | |
| 11 | +        ('account', '0027_franchiserinfo_saleclerkinfo'), | |
| 12 | + ] | |
| 13 | + | |
| 14 | + operations = [ | |
| 15 | + migrations.AddField( | |
| 16 | + model_name='saleclerkinfo', | |
| 17 | + name='total_integral', | |
| 18 | + field=models.IntegerField(default=0, help_text='\u5168\u90e8\u79ef\u5206', verbose_name='total_integral'), | |
| 19 | + ), | |
| 20 | + ] | 
| @@ -475,6 +475,7 @@ class SaleclerkInfo(BaseModelMixin, SexModelMixin): | ||
| 475 | 475 | unionid = models.CharField(_(u'unionid'), max_length=32, blank=True, null=True, help_text=u'微信 UnionID', db_index=True, unique=True) | 
| 476 | 476 |  | 
| 477 | 477 | integral = models.IntegerField(_(u'integral'), default=0, help_text=u'积分') | 
| 478 | + total_integral = models.IntegerField(_(u'total_integral'), default=0, help_text=u'全部积分') | |
| 478 | 479 |  | 
| 479 | 480 | user_status = models.IntegerField(_(u'user_status'), choices=USER_STATUS, default=UNVERIFIED, help_text=u'用户状态', db_index=True) | 
| 480 | 481 | refused_reason = models.TextField(_(u'refused_reason'), blank=True, null=True, help_text=u'审核拒绝原因') | 
| @@ -1,15 +1,23 @@ | ||
| 1 | 1 | # -*- coding: utf-8 -*- | 
| 2 | 2 |  | 
| 3 | +from djadmin import ReadOnlyModelAdmin | |
| 3 | 4 | from django.contrib import admin | 
| 4 | 5 |  | 
| 5 | -from integral.models import SaleclerkIntegralIncomeExpensesInfo | |
| 6 | +from integral.models import SaleclerkIntegralIncomeExpensesInfo, SaleclerkSubmitLogInfo | |
| 6 | 7 |  | 
| 7 | 8 |  | 
| 8 | -class SaleclerkIntegralIncomeExpensesInfoAdmin(admin.ModelAdmin): | |
| 9 | -    readonly_fields = ('franchiser_id', 'clerk_id', 'type', 'code', 'integral', 'left_integral') | |
| 9 | +class SaleclerkIntegralIncomeExpensesInfoAdmin(ReadOnlyModelAdmin, admin.ModelAdmin): | |
| 10 | 10 |      list_display = ('franchiser_id', 'clerk_id', 'type', 'code', 'integral', 'left_integral', 'remark', 'status', 'created_at', 'updated_at') | 
| 11 | -    search_fields = ('code', 'remark') | |
| 12 | 11 |      list_filter = ('franchiser_id', 'type', 'status') | 
| 12 | +    readonly_fields = ('franchiser_id', 'clerk_id', 'type', 'code', 'integral', 'left_integral') | |
| 13 | +    search_fields = ('code', 'remark') | |
| 14 | + | |
| 15 | + | |
| 16 | +class SaleclerkSubmitLogInfoAdmin(ReadOnlyModelAdmin, admin.ModelAdmin): | |
| 17 | +    list_display = ('franchiser_id', 'clerk_id', 'code', 'remark', 'status', 'created_at', 'updated_at') | |
| 18 | +    list_filter = ('franchiser_id', 'status') | |
| 19 | +    search_fields = ('code', 'remark') | |
| 13 | 20 |  | 
| 14 | 21 |  | 
| 15 | 22 | admin.site.register(SaleclerkIntegralIncomeExpensesInfo, SaleclerkIntegralIncomeExpensesInfoAdmin) | 
| 23 | +admin.site.register(SaleclerkSubmitLogInfo, SaleclerkSubmitLogInfoAdmin) | 
| @@ -0,0 +1,63 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | +# Generated by Django 1.11.9 on 2018-03-08 06:40 | |
| 3 | +from __future__ import unicode_literals | |
| 4 | + | |
| 5 | +from django.db import migrations, models | |
| 6 | +import models_ext.fileext | |
| 7 | + | |
| 8 | + | |
| 9 | +class Migration(migrations.Migration): | |
| 10 | + | |
| 11 | + dependencies = [ | |
| 12 | +        ('integral', '0001_initial'), | |
| 13 | + ] | |
| 14 | + | |
| 15 | + operations = [ | |
| 16 | + migrations.CreateModel( | |
| 17 | + name='SaleclerkSubmitLogInfo', | |
| 18 | + fields=[ | |
| 19 | +                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |
| 20 | +                ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')), | |
| 21 | +                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), | |
| 22 | +                ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), | |
| 23 | +                ('franchiser_id', models.CharField(blank=True, db_index=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, verbose_name='franchiser_id')), | |
| 24 | +                ('clerk_id', models.CharField(blank=True, db_index=True, help_text='\u5e97\u5458\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, verbose_name='clerk_id')), | |
| 25 | +                ('code', models.CharField(blank=True, db_index=True, help_text='\u673a\u8eab\u7801', max_length=32, null=True, verbose_name='code')), | |
| 26 | +                ('consumer_name', models.CharField(blank=True, help_text='\u6d88\u8d39\u8005\u59d3\u540d', max_length=32, null=True, verbose_name='consumer_name')), | |
| 27 | +                ('consumer_phone', models.CharField(blank=True, help_text='\u6d88\u8d39\u8005\u624b\u673a\u53f7', max_length=32, null=True, verbose_name='consumer_phone')), | |
| 28 | +                ('lat', models.FloatField(default=1.0, help_text='\u7eac\u5ea6', verbose_name='lat')), | |
| 29 | +                ('lon', models.FloatField(default=1.0, help_text='\u7ecf\u5ea6', verbose_name='lon')), | |
| 30 | +                ('image', models.FileField(blank=True, help_text='\u56fe\u7247', null=True, upload_to=models_ext.fileext.upload_path, verbose_name='image')), | |
| 31 | +                ('remark', models.CharField(blank=True, help_text='\u5907\u6ce8', max_length=255, null=True, verbose_name='remark')), | |
| 32 | + ], | |
| 33 | +            options={ | |
| 34 | + 'verbose_name': 'saleclerksubmitloginfo', | |
| 35 | + 'verbose_name_plural': 'saleclerksubmitloginfo', | |
| 36 | + }, | |
| 37 | + ), | |
| 38 | + migrations.AddField( | |
| 39 | + model_name='saleclerkintegralincomeexpensesinfo', | |
| 40 | + name='consumer_name', | |
| 41 | + field=models.CharField(blank=True, help_text='\u6d88\u8d39\u8005\u59d3\u540d', max_length=32, null=True, verbose_name='consumer_name'), | |
| 42 | + ), | |
| 43 | + migrations.AddField( | |
| 44 | + model_name='saleclerkintegralincomeexpensesinfo', | |
| 45 | + name='consumer_phone', | |
| 46 | + field=models.CharField(blank=True, help_text='\u6d88\u8d39\u8005\u624b\u673a\u53f7', max_length=32, null=True, verbose_name='consumer_phone'), | |
| 47 | + ), | |
| 48 | + migrations.AddField( | |
| 49 | + model_name='saleclerkintegralincomeexpensesinfo', | |
| 50 | + name='image', | |
| 51 | + field=models.FileField(blank=True, help_text='\u56fe\u7247', null=True, upload_to=models_ext.fileext.upload_path, verbose_name='image'), | |
| 52 | + ), | |
| 53 | + migrations.AddField( | |
| 54 | + model_name='saleclerkintegralincomeexpensesinfo', | |
| 55 | + name='lat', | |
| 56 | + field=models.FloatField(default=1.0, help_text='\u7eac\u5ea6', verbose_name='lat'), | |
| 57 | + ), | |
| 58 | + migrations.AddField( | |
| 59 | + model_name='saleclerkintegralincomeexpensesinfo', | |
| 60 | + name='lon', | |
| 61 | + field=models.FloatField(default=1.0, help_text='\u7ecf\u5ea6', verbose_name='lon'), | |
| 62 | + ), | |
| 63 | + ] | 
| @@ -2,7 +2,7 @@ | ||
| 2 | 2 |  | 
| 3 | 3 | from django.db import models | 
| 4 | 4 | from django.utils.translation import ugettext_lazy as _ | 
| 5 | -from models_ext import BaseModelMixin | |
| 5 | +from models_ext import BaseModelMixin, upload_path | |
| 6 | 6 |  | 
| 7 | 7 |  | 
| 8 | 8 | class SaleclerkIntegralIncomeExpensesInfo(BaseModelMixin): | 
| @@ -22,6 +22,15 @@ class SaleclerkIntegralIncomeExpensesInfo(BaseModelMixin): | ||
| 22 | 22 | type = models.IntegerField(_(u'type'), choices=TYPE, default=INCOME, help_text=u'收支类别', db_index=True) | 
| 23 | 23 |  | 
| 24 | 24 | code = models.CharField(_(u'code'), max_length=32, blank=True, null=True, help_text=u'机身码', db_index=True) | 
| 25 | + | |
| 26 | + consumer_name = models.CharField(_(u'consumer_name'), max_length=32, blank=True, null=True, help_text=u'消费者姓名') | |
| 27 | + consumer_phone = models.CharField(_(u'consumer_phone'), max_length=32, blank=True, null=True, help_text=u'消费者手机号') | |
| 28 | + | |
| 29 | + lat = models.FloatField(_(u'lat'), default=1.0, help_text=u'纬度') | |
| 30 | + lon = models.FloatField(_(u'lon'), default=1.0, help_text=u'经度') | |
| 31 | + | |
| 32 | + image = models.FileField(_(u'image'), upload_to=upload_path, blank=True, null=True, help_text=u'图片') | |
| 33 | + | |
| 25 | 34 | integral = models.IntegerField(_(u'integral'), default=0, help_text=u'增减积分') | 
| 26 | 35 | left_integral = models.IntegerField(_(u'left_integral'), default=0, help_text=u'积分增减后数量(分)') | 
| 27 | 36 |  | 
| @@ -33,3 +42,27 @@ class SaleclerkIntegralIncomeExpensesInfo(BaseModelMixin): | ||
| 33 | 42 |  | 
| 34 | 43 | def __unicode__(self): | 
| 35 | 44 | return unicode(self.pk) | 
| 45 | + | |
| 46 | + | |
| 47 | +class SaleclerkSubmitLogInfo(BaseModelMixin): | |
| 48 | + franchiser_id = models.CharField(_(u'franchiser_id'), max_length=32, blank=True, null=True, help_text=u'经销商唯一标识', db_index=True) | |
| 49 | + clerk_id = models.CharField(_(u'clerk_id'), max_length=32, blank=True, null=True, help_text=u'店员唯一标识', db_index=True) | |
| 50 | + | |
| 51 | + code = models.CharField(_(u'code'), max_length=32, blank=True, null=True, help_text=u'机身码', db_index=True) | |
| 52 | + | |
| 53 | + consumer_name = models.CharField(_(u'consumer_name'), max_length=32, blank=True, null=True, help_text=u'消费者姓名') | |
| 54 | + consumer_phone = models.CharField(_(u'consumer_phone'), max_length=32, blank=True, null=True, help_text=u'消费者手机号') | |
| 55 | + | |
| 56 | + lat = models.FloatField(_(u'lat'), default=1.0, help_text=u'纬度') | |
| 57 | + lon = models.FloatField(_(u'lon'), default=1.0, help_text=u'经度') | |
| 58 | + | |
| 59 | + image = models.FileField(_(u'image'), upload_to=upload_path, blank=True, null=True, help_text=u'图片') | |
| 60 | + | |
| 61 | + remark = models.CharField(_(u'remark'), max_length=255, blank=True, null=True, help_text=u'备注') | |
| 62 | + | |
| 63 | + class Meta: | |
| 64 | + verbose_name = _(u'saleclerksubmitloginfo') | |
| 65 | + verbose_name_plural = _(u'saleclerksubmitloginfo') | |
| 66 | + | |
| 67 | + def __unicode__(self): | |
| 68 | + return unicode(self.pk) | 
| @@ -9,7 +9,7 @@ from django_response import response | ||
| 9 | 9 | from logit import logit | 
| 10 | 10 |  | 
| 11 | 11 | from account.models import SaleclerkInfo | 
| 12 | -from integral.models import SaleclerkIntegralIncomeExpensesInfo | |
| 12 | +from integral.models import SaleclerkIntegralIncomeExpensesInfo, SaleclerkSubmitLogInfo | |
| 13 | 13 | from product.models import ProductCodeSubmitLogInfo, ProductInfo, ProductModelInfo | 
| 14 | 14 | from utils.error.errno_utils import ProductModelStatusCode, ProductStatusCode, SaleclerkStatusCode | 
| 15 | 15 |  | 
| @@ -47,9 +47,52 @@ def clerk_sale_submit_api(request): | ||
| 47 | 47 |  | 
| 48 | 48 |      file_path = request.POST.get('file_path', '') | 
| 49 | 49 |  | 
| 50 | + try: | |
| 51 | + clerk = SaleclerkInfo.objects.get(user_id=user_id) | |
| 52 | + except SaleclerkInfo.DoesNotExist: | |
| 53 | + return response(SaleclerkStatusCode.CLERK_NOT_FOUND) | |
| 54 | + | |
| 55 | + # 店员提交记录 | |
| 56 | + SaleclerkSubmitLogInfo.objects.create( | |
| 57 | + franchiser_id=clerk.franchiser_id, | |
| 58 | + clerk_id=clerk.clerk_id, | |
| 59 | + code=serialNo, | |
| 60 | + consumer_name=consumer_name, | |
| 61 | + consumer_phone=consumer_phone, | |
| 62 | + lat=lat, | |
| 63 | + lon=lon, | |
| 64 | + image=file_path, | |
| 65 | + ) | |
| 66 | + | |
| 67 | + if SaleclerkIntegralIncomeExpensesInfo.objects.filter(code=serialNo, status=True).exists(): | |
| 68 | + return response(SaleclerkStatusCode.DUPLICATE_SUBMIT) | |
| 69 | + | |
| 70 | + # 店员积分 | |
| 71 | + # TODO: 序列号 vs. 积分 | |
| 72 | + integral = 100 | |
| 73 | + | |
| 74 | + clerk.integral += integral | |
| 75 | + clerk.total_integral += integral | |
| 76 | + clerk.save() | |
| 77 | + | |
| 78 | + # 店员积分记录 | |
| 79 | + SaleclerkIntegralIncomeExpensesInfo.objects.create( | |
| 80 | + franchiser_id=clerk.franchiser_id, | |
| 81 | + clerk_id=clerk.clerk_id, | |
| 82 | + type=SaleclerkIntegralIncomeExpensesInfo.INCOME, | |
| 83 | + code=serialNo, | |
| 84 | + consumer_name=consumer_name, | |
| 85 | + consumer_phone=consumer_phone, | |
| 86 | + lat=lat, | |
| 87 | + lon=lon, | |
| 88 | + image=file_path, | |
| 89 | + integral=integral, | |
| 90 | + left_integral=clerk.total_integral, | |
| 91 | + ) | |
| 92 | + | |
| 50 | 93 |      return response(200, data={ | 
| 51 | - 'integral': 123, | |
| 52 | - 'total_integral': 12345, | |
| 94 | + 'integral': integral, | |
| 95 | + 'total_integral': clerk.integral, | |
| 53 | 96 | }) | 
| 54 | 97 |  | 
| 55 | 98 |  | 
| @@ -16,6 +16,8 @@ class SaleclerkStatusCode(BaseStatusCode): | ||
| 16 | 16 | # 状态 | 
| 17 | 17 | CLERK_ALREADY_NOT_UNVERIFIED = StatusCodeField(500110, 'Clerk Already Not Unverified', description=u'店员帐号已激活') | 
| 18 | 18 | CLERK_NOT_ACTIVATED = StatusCodeField(500115, 'Clerk Not Activated', description=u'店员帐号未激活') | 
| 19 | + # 上传 | |
| 20 | + DUPLICATE_SUBMIT = StatusCodeField(500199, 'Duplicate Submit', description=u'重复提交') | |
| 19 | 21 |  | 
| 20 | 22 |  | 
| 21 | 23 | class ProductModelStatusCode(BaseStatusCode): |