jiaweiqi 3 years ago
parent
commit
1a0aa73806

+ 1 - 11
apps/api/urls.py

@@ -2,18 +2,8 @@
 
 
 from django.conf.urls import url
 from django.conf.urls import url
 from .views import *
 from .views import *
-urlpatterns = [
-    url(r'^callback_authorize/$', CallbackAuthorize.as_view()),
-    url(r'^redirect_authorize/(?P<pk>[0-9]+)/$', RedirectAuthorize.as_view()),
-    url('^(?P<appid>.+)/callback_event/$', CallbackEvent.as_view()),
 
 
+urlpatterns = [
     url(r'^wechat_notify/(?P<appid>.+)/$', WechatNotifyView.as_view()),
     url(r'^wechat_notify/(?P<appid>.+)/$', WechatNotifyView.as_view()),
-
-    url(r'^xgj/get_comppany/$', GetCompany.as_view()),
-    url(r'^xgj/get_member_card/$', GetMemberCard.as_view()),
-    url(r'^xgj/get_member_info/$', GetMemberInfo.as_view()),
-    url(r'^xgj/get_member_points/$', GetMemberPoints.as_view()),
-    url(r'^xgj/get_member_record/$', GetMemberRecord.as_view()),
-    url(r'^xgj/get_member_balance/$', GetMemberBalance.as_view()),
 ]
 ]
 
 

+ 18 - 177
apps/api/views.py

@@ -2,10 +2,10 @@
 
 
 import json
 import json
 import xmltodict
 import xmltodict
+import traceback
 
 
 from django.db import transaction
 from django.db import transaction
 from django.http import HttpResponse
 from django.http import HttpResponse
-from apps.customer import customer_log
 from rest_framework.views import APIView
 from rest_framework.views import APIView
 
 
 from utils.wx.WXBizMsgCrypt import WXBizMsgCrypt
 from utils.wx.WXBizMsgCrypt import WXBizMsgCrypt
@@ -14,94 +14,17 @@ from utils import response_ok, response_error
 from utils.wechatpay import WechatPayNotify
 from utils.wechatpay import WechatPayNotify
 
 
 from apps.log.models import BizLog
 from apps.log.models import BizLog
-from apps.WechatTp.models import WechatTp
 from apps.WechatApplet.models import WechatApplet
 from apps.WechatApplet.models import WechatApplet
-from apps.tenant.models import Tenant
-from apps.pay.models import Pay
-from apps.tenant.biz import TenantBiz
-from utils.xgj.xgj import XGJ
-from utils.permission import IsCustomerUser
+from apps.order.models import Pay
+from apps.rebate.bussiness import CustomerRebate
 
 
 
 
-class CallbackAuthorize(APIView):
-    '''验证票据(component_verify_ticket)在第三方平台创建审核通过后,微信服务器会向其 ”授权事件接收URL”
-    每隔 10 分钟以 POST 的方式推送 component_verify_ticket 接收 POST 请求后,只需直接返回字符串 success。
-    为了加强安全性,postdata 中的 xml 将使用服务申请时的加解密 key 来进行加密'''
-
-    def post(self, request):
-        sMsgSignature = request.GET.get('msg_signature')
-        sTimeStamp = request.GET.get('timestamp')
-        sNonce = request.GET.get('nonce')
-        sPostData = request.body.decode('utf-8')
-
-        try:
-            component = WechatTp.getDefault()
-            if component:
-                appid = component.getAppid()
-                msg_crypt = WXBizMsgCrypt(component.getToken(), component.getEncodeKey(), appid)
-                ret, decryp_xml = msg_crypt.DecryptMsg(sPostData, sMsgSignature, sTimeStamp, sNonce)
-                data = json.loads(json.dumps(xmltodict.parse(decryp_xml)))['xml']
-                if data['AppId'] == appid:
-                    if data['InfoType'] == 'component_verify_ticket':
-                        component.refreshVerifyTicket(data['ComponentVerifyTicket'])
-                    elif data['InfoType'] == 'unauthorized':
-                        authorizer_appid = data['AuthorizerAppid']
-                        authorizer = WechatApplet.getByAppidAndComponentAppid(authorizer_appid, appid)
-                        if authorizer:
-                            authorizer.revoke()
-        except:
-            pass
-
-        return HttpResponse('success')
-
-
-class RedirectAuthorize(APIView):
-    '''小程序绑定授权回调'''
-
-    def get(self, request, pk):
-        try:
-            with transaction.atomic():
-                tenant = Tenant.objects.select_for_update().filter(id=pk).first()
-                app = TenantBiz.bindWechatApplet(tenant, request.GET.get('auth_code'))
-                BizLog.objects.addnew(None, None, BizLog.INSERT, u'租户绑定小程序, id=%d' % app.id)
-        except Exception as e:
-            return response_error(str(e))
-        return response_ok()
-
-
-class CallbackEvent(APIView):
-    '''消息与事件接收'''
-
-    def post(self, request, appid):
-        appid = appid
-        sMsgSignature = request.GET.get('msg_signature')
-        sTimeStamp = request.GET.get('timestamp')
-        sNonce = request.GET.get('nonce')
-        sPostData = request.body.decode('utf-8')
-
-        try:
-            tp = WechatTp.getDefault()
-            msg_crypt = WXBizMsgCrypt(tp.getToken(), tp.getEncodeKey(), tp.getAppid())
-            ret, decryp_xml = msg_crypt.DecryptMsg(sPostData, sMsgSignature, sTimeStamp, sNonce)
-            data = json.loads(json.dumps(xmltodict.parse(decryp_xml)))['xml']
-            if data['MsgType'] == 'event':
-                app = WechatApplet.getByAppid(appid)
-                if data['Event'] == 'weapp_audit_success':  # 代码审核通过
-                    app.weapp_audit_success()
-                elif data['Event'] == 'weapp_audit_fail':  # 代码审核不通过
-                    app.weapp_audit_fail(data['Reason'])
-                elif data['Event'] == 'weapp_audit_delay':  # 代码审核延后
-                    app.weapp_audit_delay(data['Reason'])
-        except:
-            pass
-        return HttpResponse('success')
-
 class WechatNotifyView(APIView):
 class WechatNotifyView(APIView):
 
 
     def dispatch(self, request, *args, **kwargs):
     def dispatch(self, request, *args, **kwargs):
         appid = kwargs['appid']
         appid = kwargs['appid']
         applet = WechatApplet.getByAppid(appid)
         applet = WechatApplet.getByAppid(appid)
-        param = request.body.decode('utf-8')
+        param = request.body
         notify = WechatPayNotify(param, applet.tenant_key)
         notify = WechatPayNotify(param, applet.tenant_key)
 
 
         try:
         try:
@@ -114,104 +37,22 @@ class WechatNotifyView(APIView):
                 raise CustomError(u'错误的请求!')
                 raise CustomError(u'错误的请求!')
 
 
             no = data['out_trade_no']
             no = data['out_trade_no']
-            amount = int(data['total_fee']) * 100
+            amount = int(data['total_fee'])
+            transaction_id = data['transaction_id']
 
 
             with transaction.atomic():
             with transaction.atomic():
                 pay = Pay.getByNo(no)
                 pay = Pay.getByNo(no)
-                pay.payConfirm(amount)
-                customer_log(pay.customer, BizLog.INSERT, u'支付成功,no=%s' % no, param)
-        except:
+                pay.payConfirm(amount, transaction_id)
+                BizLog.objects.addnew(pay.customer.user, BizLog.INSERT, u'微信支付成功,pay_no=%s' % no, param)
+            # 计算返利
+            # 在这现金返利发红包(不要在同一个事务里边 防止出错导致 订单状态不能正确改变)
+            try:
+                with transaction.atomic():  # 因为在计算 返利的时候使用了select_for_update 这个必须在事务里边
+                    instance = CustomerRebate(pay)
+                    instance.calcul_rebate()
+            except Exception as e:
+                traceback.print_exc()
+        except Exception as e:
+            traceback.print_exc()
             return HttpResponse(WechatPayNotify.response_fail())
             return HttpResponse(WechatPayNotify.response_fail())
         return HttpResponse(WechatPayNotify.response_ok())
         return HttpResponse(WechatPayNotify.response_ok())
-
-
-class GetCompany(APIView):
-    permission_classes = [IsCustomerUser, ]
-
-    def get(self, request):
-        appid = request.GET.get('appid')
-        try:
-            res = XGJ.get_company(appid)
-        except Exception as e:
-            return response_error(str(e))
-        return response_ok(res)
-
-
-class GetMemberCard(APIView):
-    permission_classes = [IsCustomerUser, ]
-
-    def post(self, request):
-        appid = request.POST.get('appid')
-        company_id = request.POST.get('company_id')
-        tel = request.POST.get('tel')
-        number = request.POST.get('number')
-        try:
-            res = XGJ.get_member_card(appid, company_id, tel, number)
-        except Exception as e:
-            return response_error(str(e))
-        return response_ok(res)
-
-
-class GetMemberInfo(APIView):
-    permission_classes = [IsCustomerUser, ]
-
-    def get(self, request):
-        appid = request.GET.get('appid')
-        customer = request.customer
-        if not customer.member_id:
-            raise CustomError(u'请先绑定会员卡')
-        try:
-            res = XGJ.get_member_info(appid, str(customer.member_id))
-        except Exception as e:
-            return response_error(str(e))
-        return response_ok(res)
-
-
-class GetMemberPoints(APIView):
-    permission_classes = [IsCustomerUser, ]
-
-    def get(self, request):
-        appid = request.GET.get('appid')
-        page = request.GET.get('page')
-        pageSize = request.GET.get('pageSize')
-        customer = request.customer
-        if not customer.member_id:
-            raise CustomError(u'请先绑定会员卡')
-        try:
-            res = XGJ.get_member_points(appid, str(customer.member_id), page, pageSize)
-        except Exception as e:
-            return response_error(str(e))
-        return response_ok(res)
-
-
-class GetMemberRecord(APIView):
-    permission_classes = [IsCustomerUser, ]
-
-    def get(self, request):
-        appid = request.GET.get('appid')
-        page = request.GET.get('page')
-        pageSize = request.GET.get('pageSize')
-        customer = request.customer
-        if not customer.member_id:
-            raise CustomError(u'请先绑定会员卡')
-        try:
-            res = XGJ.get_member_record(appid, str(customer.member_id), page, pageSize)
-        except Exception as e:
-            return response_error(str(e))
-        return response_ok(res)
-
-
-class GetMemberBalance(APIView):
-    permission_classes = [IsCustomerUser, ]
-
-    def get(self, request):
-        appid = request.GET.get('appid')
-        customer = request.customer
-        if not customer.member_id:
-            raise CustomError(u'未绑定会员卡')
-        try:
-            res = XGJ.get_member_balance(appid, str(customer.member_id))
-        except Exception as e:
-            return response_error(str(e))
-        return response_ok(res)
-

+ 36 - 2
apps/config/models.py

@@ -51,7 +51,41 @@ class Config(models.Model):
     @staticmethod
     @staticmethod
     def get_commodity():
     def get_commodity():
         try:
         try:
-            commodity = Config.objects.get(property=Config.KEY_DISTRIBUTOR_COMMODITY).value
+            commodity = int(Config.objects.get(property=Config.KEY_DISTRIBUTOR_COMMODITY).value)
             return commodity
             return commodity
         except:
         except:
-            return ''
+            return 0
+
+    @staticmethod
+    def get_rebate(first):
+        item_list = [Config.KEY_AGAIN_LEVEL1, Config.KEY_AGAIN_LEVEL2, Config.KEY_AGAIN_LEVEL3, Config.KEY_AGAIN_LEVEL4, Config.KEY_AGAIN_LEVEL5,]
+        if first:
+            item_list = [Config.KEY_FIRST_LEVEL1, Config.KEY_FIRST_LEVEL2, Config.KEY_FIRST_LEVEL3, Config.KEY_FIRST_LEVEL4, Config.KEY_FIRST_LEVEL5,]
+
+        rows = Config.objects.filter(property__in=item_list)
+
+        data = {'one_level': 0, 'two_level': 0, 'three_level': 0, 'four_level': 0, 'five_level': 0}
+        for row in rows:
+            if first:
+                if row.property == Config.KEY_FIRST_LEVEL1:
+                    data['one_level'] = row.value and float(row.value) or 0
+                elif row.property == Config.KEY_FIRST_LEVEL2:
+                    data['two_level'] = row.value and float(row.value) or 0
+                elif row.property == Config.KEY_FIRST_LEVEL3:
+                    data['three_level'] = row.value and float(row.value) or 0
+                elif row.property == Config.KEY_FIRST_LEVEL4:
+                    data['four_level'] = row.value and float(row.value) or 0
+                elif row.property == Config.KEY_FIRST_LEVEL5:
+                    data['five_level'] = row.value and float(row.value) or 0
+            else:
+                if row.property == Config.KEY_AGAIN_LEVEL1:
+                    data['one_level'] = row.value and float(row.value) or 0
+                elif row.property == Config.KEY_AGAIN_LEVEL2:
+                    data['two_level'] = row.value and float(row.value) or 0
+                elif row.property == Config.KEY_AGAIN_LEVEL3:
+                    data['three_level'] = row.value and float(row.value) or 0
+                elif row.property == Config.KEY_AGAIN_LEVEL4:
+                    data['four_level'] = row.value and float(row.value) or 0
+                elif row.property == Config.KEY_AGAIN_LEVEL5:
+                    data['five_level'] = row.value and float(row.value) or 0
+        return data

+ 3 - 1
apps/customer/collection/views.py

@@ -1,5 +1,7 @@
 # coding=utf-8
 # coding=utf-8
 
 
+from django.conf import settings
+
 from rest_framework import generics
 from rest_framework import generics
 from rest_framework.exceptions import NotFound
 from rest_framework.exceptions import NotFound
 
 
@@ -12,7 +14,7 @@ from .serializers import CollectionSerializer
 
 
 class CollectionListViewSet(generics.ListAPIView):
 class CollectionListViewSet(generics.ListAPIView):
     permission_classes = [IsCustomer, ]
     permission_classes = [IsCustomer, ]
-    queryset = Collection.objects.filter(delete=False)
+    queryset = Collection.objects.filter(delete=False, commodity__delete=False, commodity__status=settings.ONLINE)
     serializer_class = CollectionSerializer
     serializer_class = CollectionSerializer
 
 
     def filter_queryset(self, queryset):
     def filter_queryset(self, queryset):

+ 15 - 2
apps/customer/commodity/serializers.py

@@ -43,7 +43,6 @@ class CommodityDetailSerializer(serializers.ModelSerializer):
     price = serializers.SerializerMethodField()
     price = serializers.SerializerMethodField()
     vip_price = serializers.SerializerMethodField()
     vip_price = serializers.SerializerMethodField()
     show_image = serializers.SerializerMethodField()
     show_image = serializers.SerializerMethodField()
-    # 评论
 
 
     def get_sale_count(self, obj):
     def get_sale_count(self, obj):
         count = (obj.total_sales or 0) + (obj.initial_sale_count or 0)
         count = (obj.total_sales or 0) + (obj.initial_sale_count or 0)
@@ -87,7 +86,7 @@ class CommodityDetailSerializer(serializers.ModelSerializer):
     class Meta:
     class Meta:
         model = Commodity
         model = Commodity
         fields = (
         fields = (
-            'id', 'name', 'price', 'vip_price', 'point_price', 'sale_count', 'is_collection', 'carousel_urls', 'details_urls', 'show_image',
+            'id', 'name', 'price', 'vip_price', 'point_price', 'sale_count', 'is_collection', 'carousel_urls', 'details_urls', 'show_image', 'type',
         )
         )
 
 
 
 
@@ -97,3 +96,17 @@ class CommodityCategorySerializer(serializers.ModelSerializer):
     class Meta:
     class Meta:
         model = Option
         model = Option
         fields = ('id', 'label', )
         fields = ('id', 'label', )
+
+
+class HomeOptionSerializer(serializers.ModelSerializer):
+    commodity_list = serializers.SerializerMethodField()
+
+    class Meta:
+        model = Option
+        fields = ('id', 'name', 'commodity_list', )
+
+    def get_commodity_list(self, obj):
+        rows = Commodity.objects.filter(category=obj, delete=False, status=settings.ONLINE)
+        serializer = CommoditySerializer(rows, many=True)
+        data = serializer.data
+        return data

+ 1 - 0
apps/customer/commodity/urls.py

@@ -9,6 +9,7 @@ urlpatterns = [
     url(r'^category/$', CommodityCategoryListView.as_view()),
     url(r'^category/$', CommodityCategoryListView.as_view()),
     url(r'^list/$', CommodityListView.as_view()),
     url(r'^list/$', CommodityListView.as_view()),
     url(r'^detail/(?P<pk>[0-9]+)/$', CommodityDetailView.as_view()),
     url(r'^detail/(?P<pk>[0-9]+)/$', CommodityDetailView.as_view()),
+    url(r'^home/$', HomeCommodityListView.as_view()),
 ]
 ]
 
 
 router = SimpleRouter()
 router = SimpleRouter()

+ 41 - 1
apps/customer/commodity/views.py

@@ -1,5 +1,7 @@
 # coding=utf-8
 # coding=utf-8
 
 
+import json
+
 from django.db import transaction
 from django.db import transaction
 from django.db.models import F
 from django.db.models import F
 from django.conf import settings
 from django.conf import settings
@@ -23,7 +25,7 @@ from apps.collection.models import Collection
 from apps.option.filters import OptionFilter
 from apps.option.filters import OptionFilter
 from apps.option.models import Option
 from apps.option.models import Option
 
 
-from .serializers import CommodityCategorySerializer, CommoditySerializer, CommodityDetailSerializer
+from .serializers import CommodityCategorySerializer, CommoditySerializer, CommodityDetailSerializer, HomeOptionSerializer
 
 
 
 
 class CollectionViewSet(GenericViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin):
 class CollectionViewSet(GenericViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin):
@@ -45,6 +47,22 @@ class CollectionViewSet(GenericViewSet, mixins.ListModelMixin, mixins.RetrieveMo
             Collection.addnew(customer, instance)
             Collection.addnew(customer, instance)
         return response_ok()
         return response_ok()
 
 
+    @action(methods=['post'], detail=False)
+    def batch_collection(self, request):
+        ids = json.loads(request.data.get('ids'))
+        commoditys = self.queryset.filter(id__in=ids)
+
+        with transaction.atomic():
+            for item in commoditys:
+                ct = Collection.objects.filter(customer=request.customer, commodity=item).first()
+                if not ct:
+                    Collection.objects.create(customer=request.customer, commodity=item, create_time=timezone.now())
+                if ct and ct.delete:
+                    ct.delete = False
+                    ct.create_time = timezone.now()
+                    ct.save()
+        return response_ok()
+
     @action(methods=['get'], detail=True)
     @action(methods=['get'], detail=True)
     def uncollection(self, request, pk):
     def uncollection(self, request, pk):
         instance = self.get_object()
         instance = self.get_object()
@@ -101,3 +119,25 @@ class CommodityDetailView(generics.RetrieveAPIView):
             raise CustomError(u'未找到相应的商品!')
             raise CustomError(u'未找到相应的商品!')
         serializer = self.get_serializer(instance)
         serializer = self.get_serializer(instance)
         return response_ok(serializer.data)
         return response_ok(serializer.data)
+
+
+class HomeCommodityListView(generics.ListAPIView):
+    queryset = Option.objects.filter(type=Option.COMMODITY_CATEGORY, delete=False, enable=True)
+    serializer_class = HomeOptionSerializer
+
+    def filter_queryset(self, queryset):
+        queryset = queryset.filter()
+        f = OptionFilter(self.request.GET, queryset=queryset)
+        return f.qs
+
+    def list(self, request, *args, **kwargs):
+        '''
+        首页商品列表  不分页  每类商品加载6条商品
+        :param request:
+        :param args:
+        :param kwargs:
+        :return:
+        '''
+        queryset = self.filter_queryset(self.get_queryset())
+        serializer = self.get_serializer(queryset, many=True)
+        return response_ok(serializer.data)

+ 2 - 1
apps/customer/distributor/serializers.py

@@ -12,10 +12,11 @@ class DistributorSerializer(serializers.ModelSerializer):
     name = serializers.CharField(source='customer.name', read_only=True)
     name = serializers.CharField(source='customer.name', read_only=True)
     total_count = serializers.CharField(source='customer.success_count', read_only=True)
     total_count = serializers.CharField(source='customer.success_count', read_only=True)
     total_amount = serializers.SerializerMethodField()
     total_amount = serializers.SerializerMethodField()
+    total_point = serializers.CharField(source='customer.total_point', read_only=True)
 
 
     class Meta:
     class Meta:
         model = SuperiorDistributor
         model = SuperiorDistributor
-        fields = ('name', 'total_count', 'total_amount', )
+        fields = ('name', 'total_count', 'total_amount', 'total_point', )
 
 
     def get_total_amount(self, obj):
     def get_total_amount(self, obj):
         return Formater.formatValueShow(obj.customer.total_amount)
         return Formater.formatValueShow(obj.customer.total_amount)

+ 3 - 2
apps/customer/distributor/views.py

@@ -55,12 +55,13 @@ class DistributorView(generics.ListAPIView):
 
 
     def list(self, request, *args, **kwargs):
     def list(self, request, *args, **kwargs):
         queryset = self.filter_queryset(self.get_queryset())
         queryset = self.filter_queryset(self.get_queryset())
-        sum_rows = queryset.aggregate(sum_count=Sum('customer__success_count'), sum_amount=Sum('customer__total_amount'))
+        sum_rows = queryset.aggregate(sum_count=Sum('customer__success_count'), sum_amount=Sum('customer__total_amount'), sum_point=Sum('customer__total_point'))
         sum_cash = CashRebate.objects.filter(customer=request.customer).aggregate(sum_amount=Sum('amount'))['sum_amount'] or 0
         sum_cash = CashRebate.objects.filter(customer=request.customer).aggregate(sum_amount=Sum('amount'))['sum_amount'] or 0
         sum_point = PointRebate.objects.filter(customer=request.customer).aggregate(sum_amount=Sum('amount'))['sum_amount'] or 0
         sum_point = PointRebate.objects.filter(customer=request.customer).aggregate(sum_amount=Sum('amount'))['sum_amount'] or 0
         footer = {
         footer = {
             'sum_count': sum_rows['sum_count'] or 0,
             'sum_count': sum_rows['sum_count'] or 0,
-            'sum_amount': Formater.formatValueShow(sum_rows['sum_amount']),
+            'sum_amount': Formater.formatValueShow(sum_rows['sum_amount'] or 0),
+            'total_point': sum_rows['sum_point'] or 0,
             'sum_cash': Formater.formatValueShow(sum_cash),
             'sum_cash': Formater.formatValueShow(sum_cash),
             'sum_point': sum_point,
             'sum_point': sum_point,
         }
         }

+ 59 - 1
apps/customer/order/serializers.py

@@ -6,7 +6,7 @@ from rest_framework import serializers
 
 
 from utils.exceptions import CustomError
 from utils.exceptions import CustomError
 
 
-from apps.order.models import ShoppingCart
+from apps.order.models import ShoppingCart, Order, OrderDetails
 from apps.base import Formater
 from apps.base import Formater
 
 
 
 
@@ -53,3 +53,61 @@ class ShoppingCartSerializer(serializers.ModelSerializer):
         else:
         else:
             instance = super(ShoppingCartSerializer, self).create(validated_data)
             instance = super(ShoppingCartSerializer, self).create(validated_data)
         return instance
         return instance
+
+
+class OderSerializer(serializers.ModelSerializer):
+
+    class Meta:
+        model = Order
+        fields = '__all__'
+
+    def create(self, validated_data):
+        validated_data['customer'] = self.context['request'].customer
+        instance = super(OderSerializer, self).create(validated_data)
+        return instance
+
+
+class OderSimpleSerializer(serializers.ModelSerializer):
+    total_amount = serializers.SerializerMethodField()
+    total_point = serializers.SerializerMethodField()
+    status_text = serializers.CharField(source='get_status_display', read_only=True)
+    details = serializers.SerializerMethodField()
+
+    class Meta:
+        model = Order
+        fields = ('no', 'total_amount', 'total_point', 'status_text', 'details', 'id', 'name', 'tel', 'user_address', )
+
+    def get_total_amount(self, obj):
+        return Formater.formatValueShow(obj.total_amount)
+
+    def get_total_point(self, obj):
+        return '%.2f' % obj.total_point
+
+    def get_details(self, obj):
+        rows = OrderDetails.objects.filter(order=obj)
+        serializer = OderDetailSimpleSerializer(rows, many=True)
+        return serializer.data
+
+
+class OderDetailSimpleSerializer(serializers.ModelSerializer):
+    name = serializers.CharField(source='commodity.name', read_only=True)
+    show_image = serializers.SerializerMethodField()
+    amount = serializers.SerializerMethodField()
+    point_amount = serializers.SerializerMethodField()
+    type = serializers.CharField(source='commodity.type', read_only=True)
+    commodity_id = serializers.CharField(source='commodity.id', read_only=True)
+
+    class Meta:
+        model = OrderDetails
+        fields = ('name', 'show_image', 'amount', 'point_amount', 'count', 'type', 'commodity_id', )
+
+    def get_show_image(self, obj):
+        if obj.commodity and obj.commodity.show_image:
+            return obj.commodity.show_image.get_path()
+        return ''
+
+    def get_amount(self, obj):
+        return Formater.formatValueShow(obj.amount)
+
+    def get_point_amount(self, obj):
+        return '%.2f' % obj.point_amount

+ 2 - 8
apps/customer/order/urls.py

@@ -6,16 +6,10 @@ from rest_framework.routers import SimpleRouter
 from .views import *
 from .views import *
 
 
 urlpatterns = [
 urlpatterns = [
-    # url(r'^code2Session/$', WxLoginView.as_view()),
-    # url(r'^wxbind/$', WxBindView.as_view()),
-    # url(r'^setUserInfo/$', SetUserInfoView.as_view()),
-    # url(r'^token/refresh/$', CustomerRefreshTokenView),
-    # url(r'^token/verify/$', CustomerVerifyTokenView),
-    #
-    # url(r'^commodity/', include('apps.customer.commodity.urls'))
+    url(r'^list/$', OrderListView.as_view()),
 ]
 ]
 
 
 router = SimpleRouter()
 router = SimpleRouter()
 router.register(r'cart', ShoppingCartViewSet)
 router.register(r'cart', ShoppingCartViewSet)
-# router.register(r'', CustomerViewSet)
+router.register(r'', OrderViewSet)
 urlpatterns += router.urls
 urlpatterns += router.urls

+ 89 - 4
apps/customer/order/views.py

@@ -1,15 +1,23 @@
 # coding=utf-8
 # coding=utf-8
 
 
+import json
+
 from django.db import transaction
 from django.db import transaction
+from django.db.models import Q
+
 from rest_framework.decorators import action
 from rest_framework.decorators import action
+from rest_framework import generics
 
 
 from utils import response_ok, response_error
 from utils import response_ok, response_error
 from utils.exceptions import CustomError
 from utils.exceptions import CustomError
 from utils.permission import IsCustomer
 from utils.permission import IsCustomer
 from utils.custom_modelviewset import CustomModelViewSet
 from utils.custom_modelviewset import CustomModelViewSet
-from apps.order.models import ShoppingCart
-from apps.order.filters import ShoppingCartFilter
-from apps.customer.order.serializers import ShoppingCartSerializer
+from utils.wechatpay import WeChatResponse
+from apps.order.models import ShoppingCart, Order, Pay
+from apps.order.filters import ShoppingCartFilter, OrderFilter
+from apps.customer.order.serializers import ShoppingCartSerializer, OderSerializer, OderSimpleSerializer
+from apps.customer.models import Customer
+from apps.rebate.models import PointLogOrder
 from apps.log.models import BizLog
 from apps.log.models import BizLog
 
 
 
 
@@ -44,7 +52,84 @@ class ShoppingCartViewSet(CustomModelViewSet):
 
 
     @action(methods=['post'], detail=False)
     @action(methods=['post'], detail=False)
     def del_cart(self, request):
     def del_cart(self, request):
-        car_ids = request.POST.get('ids').split(',')
+        car_ids = json.loads(request.data.get('ids'))
         with transaction.atomic():
         with transaction.atomic():
             ShoppingCart.objects.filter(id__in=car_ids, customer=request.customer).delete()
             ShoppingCart.objects.filter(id__in=car_ids, customer=request.customer).delete()
         return response_ok()
         return response_ok()
+
+
+class OrderListView(generics.ListAPIView):
+    permission_classes = [IsCustomer, ]
+    queryset = Order.objects.filter()
+    serializer_class = OderSimpleSerializer
+
+    def filter_queryset(self, queryset):
+        queryset = queryset.filter(customer=self.request.customer)
+        f = OrderFilter(self.request.GET, queryset=queryset)
+        return f.qs
+
+
+class OrderViewSet(CustomModelViewSet):
+    permission_classes = [IsCustomer, ]
+    queryset = Order.objects.filter()
+    serializer_class = OderSerializer
+
+    def create(self, request, *args, **kwargs):
+        '''
+        创建订单
+        :param request:
+        :param args:
+        :param kwargs:
+        :return:
+        '''
+        openid = request.POST.get('openid')
+        appid = request.POST.get('appid')
+        address_id = request.POST.get('address_id', None)
+        details = json.loads(request.POST.get('details'))
+        if not address_id:
+            raise CustomError(u'请选择收货地址!')
+        with transaction.atomic():
+            serializer = self.get_serializer(data=request.data)
+            serializer.is_valid(raise_exception=True)
+            serializer.save()
+            order = serializer.instance
+            order.generateNo()
+            # 用户收货地址
+            order.set_order_adderss(address_id)
+            # 订单详细
+            order.set_order_detail(details)
+            # 订单支付
+            data = ''
+            if order.total_amount <= 0 and order.total_point <= 0:
+                raise CustomError(u'无效的付款金额')
+            # 下单时如果有积分,直接扣掉积分。如果没有支付或支付失败 取消订单还原积分
+            if order.total_point > 0:
+                PointLogOrder.addnew(order)
+            if order.total_amount > 0:
+                pay, data = Pay.wechatPay(order.total_amount, self.request.customer, appid, openid)
+                order.pay = pay
+            # 没有支付现金的积分也扣过了  直接修改订单状态  如果有现金支付的 通过微信支付回调修改订单状态
+            if not order.pay:
+                order.pointConfirm()
+            order.save()
+            BizLog.objects.addnew(self.request.user, BizLog.INSERT, u'添加订单[%s],id=%d' % (order.no, order.id), request.data)
+        return response_ok(data)
+
+    @action(methods=['post'], detail=True)
+    def pay_order(self, request, pk):
+        '''
+        待支付订单支付  在订单管理 待支付 订单直接支付(由于积分商品在下单的时候积分都已经扣过了  在这就不在扣除积分了)
+        :param request:
+        :param pk:
+        :return:
+        '''
+        openid = request.POST.get('openid')
+        appid = request.POST.get('appid')
+
+        order = self.get_object()
+        print(order.id)
+        if not openid or not appid:
+            raise CustomError(u'参数错误!')
+        with transaction.atomic():
+            data = order.orderPay(openid, appid)
+        return response_ok(data)

+ 2 - 0
apps/customer/urls.py

@@ -12,6 +12,8 @@ urlpatterns = [
     url(r'^token/refresh/$', CustomerRefreshTokenView),
     url(r'^token/refresh/$', CustomerRefreshTokenView),
     url(r'^token/verify/$', CustomerVerifyTokenView),
     url(r'^token/verify/$', CustomerVerifyTokenView),
 
 
+    url(r'^home/$', CustomerHomeView.as_view()),
+
     url(r'^address/', include('apps.customer.address.urls')),
     url(r'^address/', include('apps.customer.address.urls')),
     url(r'^commodity/', include('apps.customer.commodity.urls')),
     url(r'^commodity/', include('apps.customer.commodity.urls')),
     url(r'^collection/', include('apps.customer.collection.urls')),
     url(r'^collection/', include('apps.customer.collection.urls')),

+ 19 - 0
apps/customer/views.py

@@ -15,6 +15,7 @@ from utils.custom_modelviewset import CustomModelViewSet
 from apps.customer.serializers import WechatLoginSerializer, WechatBindSerializer, CustomerSerializer
 from apps.customer.serializers import WechatLoginSerializer, WechatBindSerializer, CustomerSerializer
 from apps.customer.models import Customer
 from apps.customer.models import Customer
 from apps.customer.filters import CustomerFilter
 from apps.customer.filters import CustomerFilter
+from apps.order.models import Order
 from apps.log.models import BizLog
 from apps.log.models import BizLog
 from apps.base import Formater
 from apps.base import Formater
 
 
@@ -55,6 +56,24 @@ class SetUserInfoView(APIView):
         return response_ok({'face': face, 'name': name})
         return response_ok({'face': face, 'name': name})
 
 
 
 
+class CustomerHomeView(APIView):
+    permission_classes = [IsCustomer, ]
+
+    def get(self, request):
+        customer = self.request.customer
+        rows = Order.objects.filter(customer=customer)
+
+        item = {
+            'point': '%.2f' % customer.points,
+            'balance': Formater.formatValueShow(customer.balance),
+            'wait_pay': rows.filter(status=Order.WAIT_PAY).count(),
+            'wait_dispatch': rows.filter(status=Order.WAIT_DISPATCH).count(),
+            'dispatch': rows.filter(status=Order.CONFIRM_DISPATCH).count(),
+        }
+
+        return response_ok(item)
+
+
 class CustomerRefreshTokenView(RefreshJSONWebToken):
 class CustomerRefreshTokenView(RefreshJSONWebToken):
     def post(self, request, *args, **kwargs):
     def post(self, request, *args, **kwargs):
         try:
         try:

+ 205 - 7
apps/order/models.py

@@ -3,9 +3,14 @@
 from django.db import models
 from django.db import models
 from django.conf import settings
 from django.conf import settings
 from django.utils import timezone
 from django.utils import timezone
+from django.db.models import F
+
 from apps.option.models import Option
 from apps.option.models import Option
+from apps.config.models import Config
 from apps.commodity.models import Commodity
 from apps.commodity.models import Commodity
-from apps.customer.models import Customer, CustomerAddress
+from apps.customer.models import Customer, CustomerAddress, SuperiorDistributor
+from utils.exceptions import CustomError
+from utils.wechatpay import WechatPay, WeChatResponse
 
 
 
 
 class Pay(models.Model):
 class Pay(models.Model):
@@ -39,6 +44,50 @@ class Pay(models.Model):
         )
         )
         default_permissions = ()
         default_permissions = ()
 
 
+    @staticmethod
+    def wechatPay(amount, customer, appid, openid):
+        instance = Pay._addnew(amount, customer)
+        return instance, instance._wechatUnifiedOrder(appid, openid)
+
+    @staticmethod
+    def _addnew(amount, customer):
+        if amount <= 0:
+            raise CustomError(u'无效的付款金额!')
+        pay_no = '{}{}'.format(timezone.now().strftime('%y%m%d%H%M%S'), str(customer.id))
+        pay = Pay.objects.create(no=pay_no, status=Pay.WAIT, precreate_amount=amount, customer=customer)
+        return pay
+
+    def _wechatUnifiedOrder(self, appid, openid):
+        wechatpay = WechatPay(appid)
+        wechatpay.unifiedOrder(self.no, self.precreate_amount, openid)
+        data = wechatpay.getAppString()
+        return data
+
+    @staticmethod
+    def getByNo(no):
+        instance = Pay.objects.filter(no=no).first()
+        if not instance:
+            raise CustomError(u'未找到相应的支付单!')
+        return instance
+
+    def payClosed(self):
+        if self.status != Pay.WAIT:
+            return
+        self.status = Pay.UNDO
+        self.save()
+
+    def payConfirm(self, amount, transaction_id):
+        if self.status != Pay.WAIT:
+            return
+
+        self.status = Pay.PAY
+        self.amount = amount
+        self.transaction_id = transaction_id
+        self.save()
+        order = Order.objects.filter(pay=self).first()
+        if order:
+            order.orderPayConfirm()
+
 
 
 class ShoppingCart(models.Model):
 class ShoppingCart(models.Model):
     commodity_details = models.ForeignKey(Commodity, verbose_name=u'产品明细', on_delete=models.PROTECT)
     commodity_details = models.ForeignKey(Commodity, verbose_name=u'产品明细', on_delete=models.PROTECT)
@@ -56,18 +105,16 @@ class ShoppingCart(models.Model):
 class Order(models.Model):
 class Order(models.Model):
     WAIT_PAY = 0
     WAIT_PAY = 0
     WAIT_DISPATCH = 1
     WAIT_DISPATCH = 1
-    WAIT_EVALUATE = 2
-    EVALUATED = 3
-    CANCEL = 4
+    CONFIRM_DISPATCH = 2
+    CANCEL = 3
     STATUS_CHOICES = (
     STATUS_CHOICES = (
         (WAIT_PAY, u'待付款'),
         (WAIT_PAY, u'待付款'),
         (WAIT_DISPATCH, u'待发货'),
         (WAIT_DISPATCH, u'待发货'),
-        (WAIT_EVALUATE, u'待评价'),
-        (EVALUATED, u'已评价'),
+        (CONFIRM_DISPATCH, u'已发货'),
         (CANCEL, u'已取消'),
         (CANCEL, u'已取消'),
     )
     )
 
 
-    no = models.CharField(max_length=50, verbose_name=u'订单号', editable=False)
+    no = models.CharField(max_length=50, verbose_name=u'订单号', editable=False, null=True, blank=True)
     pay = models.ForeignKey(Pay, verbose_name=u'支付信息', on_delete=models.PROTECT, null=True, editable=False)
     pay = models.ForeignKey(Pay, verbose_name=u'支付信息', on_delete=models.PROTECT, null=True, editable=False)
 
 
     total_count = models.IntegerField(verbose_name=u'总数量', default=0, editable=False)
     total_count = models.IntegerField(verbose_name=u'总数量', default=0, editable=False)
@@ -96,9 +143,160 @@ class Order(models.Model):
         db_table = "order"
         db_table = "order"
         verbose_name = u"客户订单"
         verbose_name = u"客户订单"
         ordering = ('-id',)
         ordering = ('-id',)
+        index_together = ('status', 'create_time', 'no', )
         default_permissions = ()
         default_permissions = ()
         permissions = []
         permissions = []
 
 
+    def generateNo(self):
+        '''
+        生成订单的订单号(注意:该函数最后没有 save 要在调用该函数后save )
+        :return:
+        '''
+        no = '{}{}{:0>4}'.format('XCX', timezone.now().strftime('%Y%m%d'), self.id)
+        self.no = no
+
+    def set_order_adderss(self, address_id):
+        '''
+        下单时保存用户选择的收货地址(注意:该函数最后没有 save 要在调用该函数后save )
+        :param address_id: 收货地址id
+        :return:
+        '''
+        address = CustomerAddress.objects.filter(id=address_id).first()
+        if not address:
+            raise CustomError(u'请选择正确的收货地址!')
+        if address.delete:
+            raise CustomError(u'该收货地址已删除,请选择重新选择收货地址!')
+        self.address = address
+        self.name = address.name
+        self.tel = address.tel
+        self.user_address = address.get_address()
+
+    def set_order_detail(self, details):
+        '''
+        下单时保存选择的商品明细(注意:该函数最后没有 save 要在调用该函数后save )
+        :param details: 商品明细
+        :return:
+        '''
+        total_count = total_amount = total_point = 0
+        create_data = []
+        for item in details:
+            commodity = Commodity.objects.filter(id=item['id']).first()
+            if not commodity:
+                raise CustomError(u'您选择的商品不存在,请刷新后重新选择!')
+            if commodity.delete:
+                raise CustomError(u'商品【{}】已下架!'.format(commodity.name))
+            if commodity.status != settings.ONLINE:
+                raise CustomError(u'商品【{}】已下架!'.format(commodity.name))
+
+            try:
+                count = int(item['count'])
+            except:
+                raise CustomError(u'商品数量错误,请重新选择!')
+            if count <= 0:
+                raise CustomError(u'商品数量错误,请重新选择!')
+
+            amount = point_amount = 0
+            if commodity.type == Commodity.POINT:
+                point_amount = commodity.point_price * count
+            elif commodity.type == Commodity.CASH:
+                amount = commodity.price * count
+            else:
+                continue
+
+            d = OrderDetails(
+                order=self,
+                commodity=commodity,
+                price=commodity.price,
+                point=commodity.point_price,
+                count=count,
+                amount=amount,
+                point_amount=point_amount
+            )
+
+            create_data.append(d)
+
+            total_point += point_amount
+            total_amount += amount
+            total_count += count
+
+        OrderDetails.objects.bulk_create(create_data)
+        self.total_count = total_count
+        self.total_amount = total_amount
+        self.total_point = total_point
+
+    def pointConfirm(self):
+        '''
+        积分兑换 确认兑换成功  当只购买了积分商品的时候 使用本函数确认  有现金商品的时候使用pay下边的确认函数确认
+        注意 order最后没有save()  在调用该函数后order要save()
+        :return:
+        '''
+        if self.status != Order.WAIT_PAY:
+            return
+        self.status = Order.WAIT_DISPATCH
+        commodity_id = Config.get_commodity()
+        # 这一点儿不能用这个  不然 数据customer数据重新保存了 积分那一块儿的就不行了
+        customer = Customer.objects.filter(id=self.customer.id).first()
+
+        detail = OrderDetails.objects.filter(order=self)
+        for item in detail:
+            commodity = item.commodity
+            commodity.total_sales += item.count
+            commodity.save()
+
+            if not commodity_id:
+                continue
+            if commodity.id != commodity_id:
+                continue
+
+            if customer.is_distributor:
+                continue
+            customer.is_distributor = True
+        customer.total_point += self.total_point
+        customer.success_count += 1
+        customer.save()
+
+    def orderPay(self, openid, appid):
+        if self.status != Order.WAIT_PAY:
+            raise CustomError(u'订单费待付款状态,禁止付款!')
+        if self.pay:
+            pay_no = self.pay.no
+            # 先查询订单状态
+            checkRexponse = WeChatResponse(appid)
+            total_fee = checkRexponse.OrderQuery(pay_no)
+            if int(total_fee) == int(self.total_amount):
+                wechatpay = WechatPay(appid)
+                wechatpay.unifiedOrder(pay_no, self.total_amount, openid)
+                data = wechatpay.getAppString()
+                return data
+            self.pay.payClosed()
+
+    def orderPayConfirm(self):
+        self.status = Order.WAIT_DISPATCH
+        self.save()
+
+        # 购买指定的商品 成为分销商
+        commodity_id = Config.get_commodity()
+        point_rule = Config.get_value(Config.KEY_POINT_RULE)
+        customer = Customer.objects.filter(id=self.customer.id).first()
+
+        detail = OrderDetails.objects.filter(order=self)
+        for item in detail:
+            commodity = item.commodity
+            commodity.total_sales += item.count
+            commodity.save()
+
+            if not commodity_id:
+                continue
+            if commodity.id != commodity_id:
+                continue
+            if customer.is_distributor:
+                continue
+            customer.is_distributor = True
+        customer.success_count += 1
+        customer.total_amount += self.total_amount
+        customer.total_point += self.total_point
+        customer.save()
+
 
 
 class OrderDetails(models.Model):
 class OrderDetails(models.Model):
 
 

+ 1 - 1
apps/order/views.py

@@ -79,7 +79,7 @@ class OrderViewSet(CustomModelViewSet):
         if express_company.delete:
         if express_company.delete:
             raise CustomError(u'该快递公司已被删除!')
             raise CustomError(u'该快递公司已被删除!')
         with transaction.atomic():
         with transaction.atomic():
-            order.status = Order.WAIT_EVALUATE
+            order.status = Order.CONFIRM_DISPATCH
             order.dispatch_time = timezone.now()
             order.dispatch_time = timezone.now()
             order.dispatch_user = request.user
             order.dispatch_user = request.user
             order.express_no = express_no
             order.express_no = express_no

+ 118 - 0
apps/rebate/bussiness.py

@@ -0,0 +1,118 @@
+# coding=utf-8
+
+from django.utils import timezone
+
+from apps.rebate.models import CashRebate, PointRebate, CashRebateLog, PointRebateLog, PointGive, PointGiveLog
+from apps.customer.models import SuperiorDistributor
+from apps.order.models import Order
+from apps.config.models import Config
+
+
+class CustomerRebate(object):
+
+    def __init__(self, pay):
+        self.pay = pay
+        self.order = Order.objects.filter(pay=self.pay).first()
+
+    def cash_rebate(self, ratio, amount, customer):
+        '''
+        计算现金返利  1、2、3级分销商 返现金
+        :param ratio:
+        :param amount:
+        :param customer:
+        :return:
+        '''
+        rebate = CashRebate.objects.create(
+            order=self.order,
+            ratio=ratio,
+            amount=amount,
+            customer=customer,
+            create_time=timezone.now()
+        )
+        CashRebateLog.addnew(rebate)
+
+    def point_rebate(self, ratio, amount, customer):
+        '''
+        计算积分返利  4、5级分销商 返积分
+        :param ratio:
+        :param amount:
+        :param customer:
+        :return:
+        '''
+        rebate = PointRebate.objects.create(
+            order=self.order,
+            ratio=ratio,
+            amount=amount,
+            customer=customer,
+            create_time=timezone.now()
+        )
+        PointRebateLog.addnew(rebate)
+
+    def point_give(self, ratio, amount, customer):
+        '''
+        计算购买商品赠送的积分  购买商品时根据后台设置的比例赠送相应的积分给购买者
+        :param ratio:
+        :param amount:
+        :param customer:
+        :return:
+        '''
+        give = PointGive.objects.create(
+            order=self.order,
+            ratio=ratio,
+            amount=amount,
+            customer=customer,
+            create_time=timezone.now()
+        )
+        PointGiveLog.addnew(give)
+
+    def calcul_rebate(self):
+        '''
+        计算返利并保存log
+        :return:
+        '''
+        if not self.order:
+            return
+        if self.order.total_amount <= 0:
+            return
+        if self.order.status == Order.WAIT_PAY or self.order.status == Order.CANCEL:
+            return
+
+        customer = self.order.customer
+        sd = SuperiorDistributor.objects.filter(customer=customer).first()
+        if not sd:
+            return
+        # 判断是首次购买还是再次购买  首次购买与再次购买返利的比例不同
+        count = Order.objects.filter(customer=customer, status__in=[Order.WAIT_DISPATCH, Order.CONFIRM_DISPATCH]).count()
+        rebate_dic = {}
+        if count > 1:
+            rebate_dic = Config.get_rebate(False)
+        elif count == 1:
+            rebate_dic = Config.get_rebate(True)
+        # 现金保留两位小数, 积分整数
+        total_amount = float(self.order.total_amount or 0)
+
+        if sd.one_level and sd.one_level.is_distributor and rebate_dic['one_level'] > 0:
+            amount = int(round(total_amount * rebate_dic['one_level'] / 100.0, 0))
+            self.cash_rebate(rebate_dic['one_level'], amount, sd.one_level)
+
+        if sd.two_level and sd.two_level.is_distributor and rebate_dic['two_level'] > 0:
+            amount = int(round(total_amount * rebate_dic['two_level']/ 100.0, 0))
+            self.cash_rebate(rebate_dic['two_level'], amount, sd.two_level)
+
+        if sd.three_level and sd.three_level.is_distributor and rebate_dic['three_level'] > 0:
+            amount = int(round(total_amount * rebate_dic['three_level'] / 100.0, 0))
+            self.cash_rebate(rebate_dic['three_level'], amount, sd.three_level)
+
+        if sd.four_level and sd.four_level.is_distributor and rebate_dic['four_level'] > 0:
+            amount = int(round((total_amount / 100.0) * (rebate_dic['four_level'] / 100.0), 0))
+            self.point_rebate(rebate_dic['four_level'], amount, sd.four_level)
+
+        if sd.five_level and sd.five_level.is_distributor and rebate_dic['five_level'] > 0:
+            amount = int(round((total_amount / 100.0) * (rebate_dic['five_level'] / 100.0), 0))
+            self.point_rebate(rebate_dic['five_level'], amount, sd.five_level)
+
+        # 计算购买商品 赠送积分
+        rule = Config.get_value(Config.KEY_POINT_RULE)
+        if rule > 0:
+            amount = int(round((total_amount / 100.0) * (rule / 100.0), 0))
+            self.point_give(rule, amount, customer)

+ 99 - 5
apps/rebate/models.py

@@ -7,6 +7,9 @@ from django.utils import timezone
 
 
 from apps.customer.models import Customer
 from apps.customer.models import Customer
 from apps.order.models import Order
 from apps.order.models import Order
+from apps.customer.models import SuperiorDistributor
+
+from utils.exceptions import CustomError
 
 
 '''
 '''
 现金返利及现金变动记录
 现金返利及现金变动记录
@@ -28,11 +31,28 @@ class CashLog(models.Model):
     class Meta:
     class Meta:
         db_table = "cash_log"
         db_table = "cash_log"
         verbose_name = u'现金日志'
         verbose_name = u'现金日志'
-        ordering = []
-        index_together = ()
+        ordering = ['-happen_time',]
+        index_together = (
+            'happen_time',
+        )
         default_permissions = ()
         default_permissions = ()
         permissions = []
         permissions = []
 
 
+    @staticmethod
+    def addnew(customer, type, amount):
+        customer.balance += amount
+        if customer.balance < 0:
+            raise CustomError(u'用户余额不足!')
+        customer.save()
+        instance = CashLog.objects.create(
+            customer=customer,
+            type=type,
+            happen_time=timezone.now(),
+            amount=amount,
+            balance=customer.balance
+        )
+        return instance
+
 
 
 class CashRebate(models.Model):
 class CashRebate(models.Model):
 
 
@@ -63,6 +83,13 @@ class CashRebateLog(models.Model):
         default_permissions = ()
         default_permissions = ()
         permissions = []
         permissions = []
 
 
+    @staticmethod
+    def addnew(rebate):
+        customer = Customer.objects.select_for_update().filter(id=rebate.customer.id).first()
+        log = CashLog.addnew(customer, CashLog.CASH_REBATE, rebate.amount)
+        instance = CashRebateLog.objects.create(rebate=rebate, log=log)
+        return instance
+
 '''
 '''
 积分返利及积分变动记录
 积分返利及积分变动记录
 '''
 '''
@@ -72,9 +99,11 @@ class PointLog(models.Model):
 
 
     POINT_REBATE = 1
     POINT_REBATE = 1
     POINT_ORDER = 2
     POINT_ORDER = 2
+    POINT_GIVE = 3
     TYPE_CHOICES = (
     TYPE_CHOICES = (
         (POINT_REBATE, u'积分返利'),
         (POINT_REBATE, u'积分返利'),
         (POINT_ORDER, u'积分兑换'),
         (POINT_ORDER, u'积分兑换'),
+        (POINT_GIVE, u'赠送积分'),  # 购买商品赠送的积分
     )
     )
 
 
     customer = models.ForeignKey(Customer, verbose_name=u'客户', on_delete=models.PROTECT)
     customer = models.ForeignKey(Customer, verbose_name=u'客户', on_delete=models.PROTECT)
@@ -86,11 +115,28 @@ class PointLog(models.Model):
     class Meta:
     class Meta:
         db_table = "point_log"
         db_table = "point_log"
         verbose_name = u'积分日志'
         verbose_name = u'积分日志'
-        ordering = []
-        index_together = ()
+        ordering = ['-happen_time',]
+        index_together = (
+            'happen_time',
+        )
         default_permissions = ()
         default_permissions = ()
         permissions = []
         permissions = []
 
 
+    @staticmethod
+    def addnew(customer, type, point):
+        customer.points += point
+        if customer.points < 0:
+            raise CustomError(u'用户积分不足!')
+        customer.save()
+        instance = PointLog.objects.create(
+            customer=customer,
+            type=type,
+            happen_time=timezone.now(),
+            amount=point,
+            balance=customer.points
+        )
+        return instance
+
 
 
 class PointRebate(models.Model):
 class PointRebate(models.Model):
 
 
@@ -109,6 +155,23 @@ class PointRebate(models.Model):
         permissions = []
         permissions = []
 
 
 
 
+class PointGive(models.Model):
+
+    order = models.ForeignKey(Order, verbose_name=u'订单', related_name='point_give_order', editable=False, on_delete=models.PROTECT)
+    ratio = models.FloatField(verbose_name=u'赠送比例', default=0)
+    amount = models.IntegerField(verbose_name=u'赠送积分', default=0)
+    customer = models.ForeignKey(Customer, verbose_name=u'客户', editable=False, on_delete=models.PROTECT)
+    create_time = models.DateTimeField(verbose_name=u"创建时间", default=timezone.now, editable=False)
+
+    class Meta:
+        db_table = "point_give"
+        verbose_name = u'积分返利'
+        ordering = []
+        index_together = ()
+        default_permissions = ()
+        permissions = []
+
+
 class PointLogOrder(models.Model):
 class PointLogOrder(models.Model):
 
 
     order = models.OneToOneField(Order, verbose_name=u'订单', related_name='order', editable=False, on_delete=models.PROTECT)
     order = models.OneToOneField(Order, verbose_name=u'订单', related_name='order', editable=False, on_delete=models.PROTECT)
@@ -122,8 +185,15 @@ class PointLogOrder(models.Model):
         default_permissions = ()
         default_permissions = ()
         permissions = []
         permissions = []
 
 
+    @staticmethod
+    def addnew(order):
+        customer = Customer.objects.select_for_update().filter(id=order.customer.id).first()
+        log = PointLog.addnew(customer, PointLog.POINT_ORDER, -order.total_point)
+        instance = PointLogOrder.objects.create(order=order, log=log)
+        return instance
+
 
 
-class PointLogRebate(models.Model):
+class PointRebateLog(models.Model):
     rebate = models.OneToOneField(PointRebate, verbose_name=u'积分返利', related_name='rebate', editable=False, on_delete=models.PROTECT)
     rebate = models.OneToOneField(PointRebate, verbose_name=u'积分返利', related_name='rebate', editable=False, on_delete=models.PROTECT)
     log = models.OneToOneField(PointLog, verbose_name=u'日志', related_name='rebate_log', editable=False, on_delete=models.PROTECT)
     log = models.OneToOneField(PointLog, verbose_name=u'日志', related_name='rebate_log', editable=False, on_delete=models.PROTECT)
 
 
@@ -135,5 +205,29 @@ class PointLogRebate(models.Model):
         default_permissions = ()
         default_permissions = ()
         permissions = []
         permissions = []
 
 
+    @staticmethod
+    def addnew(rebate):
+        customer = Customer.objects.select_for_update().filter(id=rebate.customer.id).first()
+        log = PointLog.addnew(customer, PointLog.POINT_REBATE, rebate.amount)
+        instance = PointRebateLog.objects.create(rebate=rebate, log=log)
+        return instance
 
 
 
 
+class PointGiveLog(models.Model):
+    give = models.OneToOneField(PointGive, verbose_name=u'赠送积分', related_name='give', editable=False, on_delete=models.PROTECT)
+    log = models.OneToOneField(PointLog, verbose_name=u'日志', related_name='give_log', editable=False, on_delete=models.PROTECT)
+
+    class Meta:
+        db_table = "point_log_give"
+        verbose_name = u'赠送积分日志'
+        ordering = []
+        index_together = ()
+        default_permissions = ()
+        permissions = []
+
+    @staticmethod
+    def addnew(give):
+        customer = Customer.objects.select_for_update().filter(id=give.customer.id).first()
+        log = PointLog.addnew(customer, PointLog.POINT_GIVE, give.amount)
+        instance = PointGiveLog.objects.create(give=give, log=log)
+        return instance

+ 2 - 1
cosmetics_shop/settings.py

@@ -45,6 +45,7 @@ INSTALLED_APPS = [
     'django_filters',
     'django_filters',
 
 
     'apps.account',
     'apps.account',
+    'apps.api',
     'apps.collection',
     'apps.collection',
     'apps.commodity',
     'apps.commodity',
     'apps.config',
     'apps.config',
@@ -222,7 +223,7 @@ REST_FRAMEWORK = {
 
 
 # 导入本地设置
 # 导入本地设置
 try:
 try:
-    from markwin.local_settings import *
+    from cosmetics_shop.local_settings import *
 except ImportError:
 except ImportError:
     pass
     pass
 
 

+ 1 - 0
cosmetics_shop/urls.py

@@ -27,6 +27,7 @@ urlpatterns = [
     url(r'^commodity/', include('apps.commodity.urls')),
     url(r'^commodity/', include('apps.commodity.urls')),
     url(r'^option/', include('apps.option.urls')),
     url(r'^option/', include('apps.option.urls')),
     url(r'^order/', include('apps.order.urls')),
     url(r'^order/', include('apps.order.urls')),
+    url(r'^api/', include('apps.api.urls')),
 ]
 ]
 
 
 urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
 urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

+ 4 - 4
uis/views/commodity/edit.html

@@ -54,28 +54,28 @@
                         <div class="layui-form-item" id="price_item">
                         <div class="layui-form-item" id="price_item">
                             <label class="layui-form-label"><font color='red' size="4">*</font>销售价格:</label>
                             <label class="layui-form-label"><font color='red' size="4">*</font>销售价格:</label>
                             <div class="layui-input-block">
                             <div class="layui-input-block">
-                                <input type="text" id="id_price" name="price" lay-verify="numberGtZ|required" placeholder="请输入销售价" autocomplete="off" class="layui-input">
+                                <input type="text" id="id_price" name="price" lay-verify="numberGtZ|required" placeholder="请输入销售价" autocomplete="off" class="layui-input">
                             </div>
                             </div>
                         </div>
                         </div>
 
 
                         <div class="layui-form-item" id="vip_price_item">
                         <div class="layui-form-item" id="vip_price_item">
                             <label class="layui-form-label"><font color='red' size="4">*</font>会员价格:</label>
                             <label class="layui-form-label"><font color='red' size="4">*</font>会员价格:</label>
                             <div class="layui-input-block">
                             <div class="layui-input-block">
-                                <input type="text" id="id_vip_price" name="vip_price" lay-verify="numberGtZ|required" placeholder="请输入销售限价折扣" autocomplete="off" class="layui-input">
+                                <input type="text" id="id_vip_price" name="vip_price" lay-verify="numberGtZ|required" placeholder="请输入会员价格" autocomplete="off" class="layui-input">
                             </div>
                             </div>
                         </div>
                         </div>
 
 
                         <div class="layui-form-item" id="point_price_item" hidden>
                         <div class="layui-form-item" id="point_price_item" hidden>
                             <label class="layui-form-label"><font color='red' size="4">*</font>积分价格:</label>
                             <label class="layui-form-label"><font color='red' size="4">*</font>积分价格:</label>
                             <div class="layui-input-block">
                             <div class="layui-input-block">
-                                <input type="text" id="id_point_price" name="point_price" lay-verify="intGtz" placeholder="请输入销售限价折扣" autocomplete="off" class="layui-input">
+                                <input type="text" id="id_point_price" name="point_price" lay-verify="intGtz" placeholder="请输入积分价格" autocomplete="off" class="layui-input">
                             </div>
                             </div>
                         </div>
                         </div>
 
 
                         <div class="layui-form-item">
                         <div class="layui-form-item">
                             <label class="layui-form-label">起始销量:</label>
                             <label class="layui-form-label">起始销量:</label>
                             <div class="layui-input-block">
                             <div class="layui-input-block">
-                                <input type="text" name="initial_sale_count" lay-verify="intGtz|required" placeholder="请输入" value="0" class="layui-input">
+                                <input type="text" name="initial_sale_count" lay-verify="intGtz|required" placeholder="请输入起始销量" value="0" class="layui-input">
                             </div>
                             </div>
                         </div>
                         </div>
 
 

+ 1 - 1
uis/views/customer/index.html

@@ -86,7 +86,7 @@
       ,cols: [[
       ,cols: [[
         {field:'name', title:'名称',width: 120}
         {field:'name', title:'名称',width: 120}
        ,{field:'tel', title:'电话',width: 150}
        ,{field:'tel', title:'电话',width: 150}
-       ,{field:'gender_text', title:'性别',width: 80}
+      // ,{field:'gender_text', title:'性别',width: 80}
        ,{field:'is_distributor_text', title:'分销商',width: 80}
        ,{field:'is_distributor_text', title:'分销商',width: 80}
        ,{field:'balance', align: 'right', title:'余额',width: 120}
        ,{field:'balance', align: 'right', title:'余额',width: 120}
        ,{field:'points', align:'right', title:'积分', width:120}
        ,{field:'points', align:'right', title:'积分', width:120}

+ 3 - 4
uis/views/order/index.html

@@ -47,9 +47,8 @@
                                 <option value="">订单状态</option>
                                 <option value="">订单状态</option>
                                 <option value="0">待付款</option>
                                 <option value="0">待付款</option>
                                 <option value="1">待发货</option>
                                 <option value="1">待发货</option>
-                                <option value="2">待评价</option>
-                                <option value="3">已评价</option>
-                                <option value="4">已取消</option>
+                                <option value="2">已发货</option>
+                                <option value="3">已取消</option>
                             </select>
                             </select>
                         </div>
                         </div>
                         <div class="seach_items">
                         <div class="seach_items">
@@ -121,7 +120,7 @@
        ,{field:'cancel_reason', title:'取消订单原因',width: 150}
        ,{field:'cancel_reason', title:'取消订单原因',width: 150}
        ,{field:'cancel_user_text', title:'取消人',width: 80}
        ,{field:'cancel_user_text', title:'取消人',width: 80}
        ,{field:'cancel_time', title:'取消时间',width: 150}
        ,{field:'cancel_time', title:'取消时间',width: 150}
-       ,{field:'notes', title:'备注',width: 150}
+       ,{field:'notes', title:'买家留言',width: 150}
         ,{width:150, align:'center', fixed: 'right', toolbar: '#datagrid-operate-bar'}
         ,{width:150, align:'center', fixed: 'right', toolbar: '#datagrid-operate-bar'}
       ]]
       ]]
       ,totalRow:false
       ,totalRow:false

+ 56 - 7
utils/wechatpay.py

@@ -9,6 +9,7 @@ from hashlib import md5
 from django.conf import settings
 from django.conf import settings
 
 
 from utils.exceptions import CustomError
 from utils.exceptions import CustomError
+from apps.WechatApplet.models import WechatApplet
 
 
 # 微信支付sign_type
 # 微信支付sign_type
 WEIXIN_SIGN_TYPE = 'MD5'
 WEIXIN_SIGN_TYPE = 'MD5'
@@ -21,25 +22,34 @@ WEIXIN_UNIFIED_ORDER_URL = 'https://api.mch.weixin.qq.com/pay/unifiedorder'
 # 微信查询订单URL
 # 微信查询订单URL
 WEIXIN_QUERY_ORDER_URL = 'https://api.mch.weixin.qq.com/pay/orderquery'
 WEIXIN_QUERY_ORDER_URL = 'https://api.mch.weixin.qq.com/pay/orderquery'
 # 微信支付回调API
 # 微信支付回调API
-WEIXIN_CALLBACK_API = 'https://xapp.aiche360.cn/api/wechat_notify/'
+# WEIXIN_CALLBACK_API = 'https://xapp.aiche360.cn/api/wechat_notify/'
+
+
+def getApp(appid):
+    wxapp = WechatApplet.objects.filter(authorizer_appid=appid).first()
+    if not wxapp:
+        raise CustomError(u'小程序appid认证失败!')
+    return wxapp
+
 
 
 class WechatPay():
 class WechatPay():
 
 
-    def __init__(self, appid, mch_id, merchant_key):
+    def __init__(self, appid):
+        wxapp = getApp(appid)
         self.params = {
         self.params = {
             'appid': appid,
             'appid': appid,
-            'mch_id': mch_id,
+            'mch_id': wxapp.agent_num,
             'nonce_str': '',
             'nonce_str': '',
             'sign_type': WEIXIN_SIGN_TYPE,
             'sign_type': WEIXIN_SIGN_TYPE,
             'body': WEIXIN_BODY,
             'body': WEIXIN_BODY,
             'out_trade_no': '',
             'out_trade_no': '',
             'total_fee': '',
             'total_fee': '',
             'spbill_create_ip': WEIXIN_SPBILL_CREATE_IP,
             'spbill_create_ip': WEIXIN_SPBILL_CREATE_IP,
-            'notify_url': WEIXIN_CALLBACK_API + appid + '/',
+            'notify_url': wxapp.callback_api + appid + '/',
             'trade_type': 'JSAPI'
             'trade_type': 'JSAPI'
         }
         }
         self.prepay_id = None
         self.prepay_id = None
-        self.merchant_key = merchant_key
+        self.merchant_key = wxapp.agent_key
 
 
     def getAppString(self):
     def getAppString(self):
         data = {
         data = {
@@ -53,9 +63,9 @@ class WechatPay():
         data.pop('appId')
         data.pop('appId')
         return data
         return data
 
 
-    def unifiedOrder(self,out_trade_no,total_fee, openid):
+    def unifiedOrder(self, out_trade_no, total_fee, openid):
         self.params['out_trade_no'] = out_trade_no
         self.params['out_trade_no'] = out_trade_no
-        self.params['total_fee'] = int(round(total_fee / 100,0))
+        self.params['total_fee'] = int(round(total_fee, 0))
         self.params['openid'] = openid
         self.params['openid'] = openid
         self.params['nonce_str'] = generate_nonce_str()
         self.params['nonce_str'] = generate_nonce_str()
         self.params['sign'] = generate_sign(self.params, self.merchant_key)
         self.params['sign'] = generate_sign(self.params, self.merchant_key)
@@ -77,6 +87,45 @@ class WechatPay():
 
 
         return result['xml']
         return result['xml']
 
 
+
+class WeChatResponse():
+    def __init__(self, appid):
+        wxapp = getApp(appid)
+        self.params = {
+            'appid': appid,
+            'mch_id': wxapp.agent_num,
+            'nonce_str': '',
+            'sign_type': WEIXIN_SIGN_TYPE,
+            'sign': '',
+            'out_trade_no': '',
+        }
+        self.prepay_id = None
+        self.merchant_key = wxapp.agent_key
+
+    def OrderQuery(self, out_trade_no):
+        '''
+        查询订单
+        :param out_trade_no:
+        :return:
+        '''
+        self.params['out_trade_no'] = out_trade_no
+        self.params['nonce_str'] = generate_nonce_str()
+        self.params['sign'] = generate_sign(self.params, self.merchant_key)
+        data = xmltodict.unparse({'xml': self.params}, pretty=True, full_document=False).encode('utf-8')
+        headers = {'Content-Type': 'application/xml'}
+        res = requests.post(WEIXIN_QUERY_ORDER_URL, data=data, headers=headers)
+        if res.status_code != 200:
+            raise CustomError(u'微信请求失败!')
+        result = json.loads(json.dumps(xmltodict.parse(res.content)))
+
+        if result['xml']['return_code'] != 'SUCCESS':
+            raise CustomError(u'微信通信失败![%s]' % result['xml']['return_msg'])
+        print(u'微信交易状态![%s]' % (result['xml']['trade_state_desc']))
+        if result['xml']['trade_state'] == 'NOTPAY':
+            return result['xml']['total_fee']
+        return 0
+
+
 class WechatPayNotify():
 class WechatPayNotify():
     def __init__(self,params, merchant_key):
     def __init__(self,params, merchant_key):
         self.params = params
         self.params = params