예제 #1
0
class CLogistic:
    def __init__(self):
        self.strade = STrade()

    def list_company(self):

        common = LogisticsCompnay.query.filter_by({'LCisCommon': True}).all()
        logistics = LogisticsCompnay.query.filter_by_().order_by(
            LogisticsCompnay.LCfirstCharater).all()
        return Success(data={'common': common, 'all': logistics})

    @token_required
    def send(self):
        """发货"""
        data = parameter_required(('omid', 'olcompany', 'olexpressno'))
        omid = data.get('omid')
        olcompany = data.get('olcompany')
        olexpressno = data.get('olexpressno')
        with self.strade.auto_commit() as s:
            s_list = []
            order_main_instance = s.query(OrderMain).filter_by_({
                'OMid': omid,
            }).first_('订单不存在')
            # if order_main_instance.OMstatus != OrderMainStatus.wait_send.value:
            #     raise StatusError('订单状态不正确')
            if order_main_instance.OMinRefund is True:
                raise StatusError('商品在售后状态')
            s.query(LogisticsCompnay).filter_by_({
                'LCcode': olcompany
            }).first_('快递公司不存在')
            # 之前物流记录判断
            order_logistics_instance_old = OrderLogistics.query.filter(
                OrderLogistics.OMid == omid,
                OrderLogistics.isdelete == False,
            ).first()
            if order_logistics_instance_old:
                order_logistics_instance_old.isdelete = True

            # 添加物流记录
            order_logistics_instance = OrderLogistics.create({
                'OLid':
                str(uuid.uuid4()),
                'OMid':
                omid,
                'OLcompany':
                olcompany,
                'OLexpressNo':
                olexpressno,
            })
            s_list.append(order_logistics_instance)
            # 更改主单状态
            order_main_instance.OMstatus = OrderMainStatus.wait_recv.value
            s_list.append(order_main_instance)
            s.add_all(s_list)
        return Success('发货成功')

    #
    # def update(self):
    #     data = parameter_required(('omid', 'olcompany', 'olexpressno'))
    #     omid = data.get('omid')
    #     olcompany = data.get('olcompany')
    #     olexpressno = data.get('olexpressno')
    #     with self.strade.auto_commit() as s:
    #         s_list = []
    #         order_main_instance = s.query(OrderMain).filter_by_({
    #             'OMid': omid,
    #         }).first_('订单不存在')
    #         if order_main_instance.OMstatus != OrderMainStatus.wait_recv.value:
    #             raise StatusError('订单状态不正确')
    #         if order_main_instance.OMinRefund is True:
    #             raise StatusError('商品在售后状态')
    #         s.query(LogisticsCompnay).filter_by_({
    #             'LCcode': olcompany
    #         }).first_('快递公司不存在')
    #         # 之前物流记录判断
    #         order_logistics_instance_old = OrderLogistics.query.filter(
    #             OrderLogistics.OMid == omid,
    #             OrderLogistics.isdelete == False,
    #         ).first()
    #         if order_logistics_instance_old:
    #             order_logistics_instance_old.isdelete = True
    #
    #         # 添加物流记录
    #         order_logistics_instance = OrderLogistics.create({
    #             'OLid': str(uuid.uuid4()),
    #             'OMid': omid,
    #             'OLcompany': olcompany,
    #             'OLexpressNo': olexpressno,
    #         })
    #         s_list.append(order_logistics_instance)
    #         # 更改主单状态
    #         order_main_instance.OMstatus = OrderMainStatus.wait_recv.value
    #         s_list.append(order_main_instance)
    #         s.add_all(s_list)
    #     return Success('发货成功')

    def get(self):
        """获取主单物流"""
        data = parameter_required(('omid', ))
        omid = data.get('omid')
        with db.auto_commit():
            order_logistics = OrderLogistics.query.filter_by_({
                'OMid': omid
            }).first_('未获得物流信息')
            time_now = datetime.now()
            if order_logistics.OLdata:
                oldata = json.loads(order_logistics.OLdata)
                if not oldata:
                    oldata_status = False
                else:
                    oldata_status = oldata.get('status')
                    if str(oldata_status) == "205":
                        oldata_status = False
                    else:
                        oldata_status = True
            else:
                oldata_status = False

            # 没有data信息或超过6小时 并且状态不是已签收
            if ((not oldata_status or
                 (time_now - order_logistics.updatetime).total_seconds() >
                 6 * 3600) and order_logistics.OLsignStatus !=
                    LogisticsSignStatus.already_signed.value):
                order_logistics = self._get_logistics(order_logistics)
            logistics_company = LogisticsCompnay.query.filter_by_({
                'LCcode':
                order_logistics.OLcompany
            }).first()
            order_logistics.fill(
                'OLsignStatus_en',
                LogisticsSignStatus(order_logistics.OLsignStatus).name)
            order_logistics.fill(
                'OLsignStatus_zh',
                LogisticsSignStatus(order_logistics.OLsignStatus).zh_value)
            order_logistics.fill('logistics_company', logistics_company)
        order_logistics.OLdata = json.loads(order_logistics.OLdata)
        order_logistics.OLlastresult = json.loads(order_logistics.OLlastresult)
        return Success(data=order_logistics)

    def _get_logistics(self, order_logistics):
        # http查询
        l = Logistics()
        response = l.get_logistic(order_logistics.OLexpressNo,
                                  order_logistics.OLcompany)
        current_app.logger.info("物流记录OLid--> {} ;快递response --> {}".format(
            order_logistics.OLid, response))
        if response:
            # 插入数据库
            code = response.get('status')
            if code == '0':
                result = response.get('result')
                OrderLogisticsDict = {
                    'OLsignStatus': int(result.get('deliverystatus')),
                    'OLdata': json.dumps(result),  # 快递结果原字符串
                    'OLlastresult': json.dumps(result.get('list')[0])  # 最新物流
                }
                #
            elif code == '205':  # 205 暂时没有信息,可能在揽件过程中
                OrderLogisticsDict = {
                    'OLsignStatus':
                    0,  # 签收状态 0:快递收件(揽件) 1.在途中 2.正在派件 3.已签收 4.派送失败 -1 异常数据'
                    'OLdata': json.dumps(response),  # 整体结果原字符串
                    'OLlastresult': '{}'
                }
            else:
                OrderLogisticsDict = {
                    'OLsignStatus': -1,
                    'OLdata': json.dumps(response),  # 结果原字符串
                    'OLlastresult': '{}'
                }
                order_main = OrderMain.query.filter(
                    OrderMain.OMid == order_logistics.OMid,
                    OrderMain.isdelete == False).first()
                order_main.update(
                    {'OMstatus': OrderMainStatus.wait_send.value})
                db.session.add(order_main)

            # s_list.append(order_logistics)
        else:
            # 无信息 todo
            OrderLogisticsDict = {
                'OLsignStatus': -1,
                'OLdata': "[]",  # 结果原字符串
                'OLlastresult': '{}'
            }
            order_main = OrderMain.query.filter(
                OrderMain.OMid == order_logistics.OMid,
                OrderMain.isdelete == False).first()
            order_main.update({'OMstatus': OrderMainStatus.wait_send.value})
            db.session.add(order_main)
            gennerc_log('物流信息出错')
        order_logistics.update(OrderLogisticsDict)
        db.session.add(order_logistics)
        return order_logistics

    def subcribe_callback(self):
        with open('callback', 'w') as f:
            json.dump(request.detail, f)
        return 'ok'

    def _insert_to_orderlogistics(
        self,
        response,
    ):
        pass
예제 #2
0
 def __init__(self):
     self.strade = STrade()
예제 #3
0
class CCart(object):
    def __init__(self):
        self.scart = STrade()
        self.sproduct = SProducts()

    @token_required
    def add(self):
        """添加购物车"""
        data = parameter_required(('skuid', ))
        skuid = data.get('skuid')
        try:
            num = int(data.get('canums', 1))
        except TypeError as e:
            raise ParamsError('num参数类型错误')
        usid = request.user.id
        is_exists = self.scart.get_card_one({'USid': usid, 'SKUid': skuid})
        if is_exists:
            # 已存在
            caid = is_exists.CAid
            with self.scart.auto_commit() as session:
                new_nums = is_exists.CAnums
                if new_nums <= 0:
                    # 数目过小则为删除
                    session.query(Carts).filter_by_({'CAid': caid}).update({
                        'isdelete': True
                    })
                    msg = '删除购物车成功'
                else:
                    # 更新数据
                    session.query(Carts).filter_by_({'CAid': caid}).update({
                        'CAnums': Carts.CAnums + num
                    })
                    msg = '更新购物车成功'
        else:
            # 不存在
            with self.scart.auto_commit() as session:
                sku = session.query(ProductSku).filter_by_({'SKUid': skuid}).first_('sku不存在')
                prid = sku.PRid
                product = session.query(Products).filter_by_({'PRid': prid}).first_('商品不存在')
                pbid = product.PBid
                if num <= 0:
                    raise ParamsError('num参数错误')
                cart = Carts.create({
                    'CAid': str(uuid.uuid4()),
                    'USid': usid,
                    'SKUid': skuid,
                    'CAnums': num,
                    'PBid': pbid,
                    'PRid': prid
                })
                msg = '添加购物车成功'
                session.add(cart)
        return Success(msg)

    @token_required
    def update(self):
        """更新购物车"""
        data = parameter_required(('caid', ))
        caid = data.get('caid')
        usid = request.user.id
        card = self.scart.get_card_one({'CAid': caid, 'USid': usid}, error='购物车不存在')  # card就是cart.
        # 默认的sku和数量
        skuid = data.get('skuid') or card.SKUid
        try:
            num = int(data.get('canums', card.CAnums))
            if num < 0:
                raise TypeError()
        except TypeError as e:
            raise ParamsError('num类型错误')
        msg = '更新成功'
        with self.scart.auto_commit() as session:
            # 数量为0执行删除
            if num == 0:
                session.query(Carts).filter_by({'CAid': caid}).delete_()
                msg = '删除成功'
            else:
                session.query(ProductSku).filter_by_({'SKUid': skuid}).first_('商品sku不存在')
                session.query(Carts).filter_by({'CAid': caid}).update({
                    'SKUid': skuid,
                    'CAnums': num
                })
        return Success(msg)

    @token_required
    def list(self):
        """个人购物车列表"""
        usid = request.user.id
        my_carts = self.scart.get_card_list({'USid': usid})
        pb_list = []
        new_cart_list = []
        product_num = 0
        for cart in my_carts:
            pbid = cart.PBid
            product = self.sproduct.get_product_by_prid(cart.PRid)  # 商品
            if not product:
                continue
            product.PRattribute = json.loads(product.PRattribute)
            pb = self.sproduct.get_product_brand_one({'PBid': pbid})
            if not pb:
                continue
            cart_sku = self.sproduct.get_sku_one({'SKUid': cart.SKUid})   # 购物车的sku
            if not cart_sku:
                continue
            cart_sku.SKUattriteDetail = json.loads(cart_sku.SKUattriteDetail)
            # skuvalue = self.sproduct.get_sku_value({'PRid': cart.PRid})   # 商品的skuvalue
            # 填充商品
            product.hide('PRdesc')
            product.fill('PRstatus_en', ProductStatus(product.PRstatus).name)
            # 商品sku
            skus = self.sproduct.get_sku({'PRid': product.PRid})
            sku_value_item = []
            for sku in skus:
                sku.SKUattriteDetail = json.loads(sku.SKUattriteDetail)
                sku_value_item.append(sku.SKUattriteDetail)
            product.fill('skus', skus)
            # 商品sku value
            sku_value_item_reverse = []
            for index, name in enumerate(product.PRattribute):
                value = list(set([attribute[index] for attribute in sku_value_item]))
                value = sorted(value)
                temp = {
                    'name': name,
                    'value': value
                }
                sku_value_item_reverse.append(temp)
            product.fill('SkuValue', sku_value_item_reverse)

            # 填充购物车
            cart.fill('sku', cart_sku)
            cart.fill('product', product)
            # 小计
            # cart.subtotal =
            # 数量
            product_num += 1
            # 店铺分组
            if pbid not in pb_list:
                new_cart_list.append({'cart': [cart], 'pb': pb})
                pb_list.append(pbid)
            else:
                index = pb_list.index(pbid)
                new_cart_list[index]['cart'].append(cart)
        return Success(data=new_cart_list).get_body(product_num=product_num)

    @token_required
    def destroy(self):
        """批量个人购物车"""
        data = parameter_required()
        usid = request.user.id
        caids = data.get('caids')
        if isinstance(caids, list) and len(caids) == 0:
            raise ParamsError('caids 为空')
        if not caids:
            caids = []
        if not isinstance(caids, list):
            raise ParamsError('caids 参数错误')
        # 删除
        with self.scart.auto_commit() as session:
            session.query(Carts).filter_(
                Carts.CAid.in_(caids),
                Carts.USid == usid
            ).delete_(synchronize_session=False)
        return Success('删除成功')
예제 #4
0
 def __init__(self):
     self.scart = STrade()
     self.sproduct = SProducts()
예제 #5
0
class CCoupon(object):
    def __init__(self):
        self.strade = STrade()

    def list(self):
        """获取优惠券列表"""
        form = CouponListForm().valid_data()
        itid = form.itid.data
        coupons = Coupon.query.filter(Coupon.isdelete == False)
        usid = suid = adid = None
        if is_supplizer():
            suid = request.user.id
        elif is_admin():
            adid = request.user.id
        elif not is_tourist():
            usid = request.user.id
        if itid:
            coupons = coupons.join(CouponItem,
                                   CouponItem.COid == Coupon.COid).filter(
                                       CouponItem.ITid == itid,
                                       CouponItem.isdelete == False)
        if suid:
            coupons = coupons.filter(Coupon.SUid == suid)
        coupons = coupons.order_by(Coupon.createtime.desc(),
                                   Coupon.COid).all_with_page()
        for coupon in coupons:
            # 标签
            self._coupon(coupon, usid=usid)
        return Success(data=coupons)

    def get(self):
        data = parameter_required(('coid', ))
        coid = data.get('coid')
        coupon = Coupon.query.filter(
            Coupon.COid == coid,
            Coupon.isdelete == False,
        ).first()
        self._coupon(coupon)
        return Success(data=coupon)

    def _coupon(self, coupon, **kwargs):
        items = Items.query.join(CouponItem,
                                 CouponItem.ITid == Items.ITid).filter(
                                     CouponItem.COid == coupon.COid).all()
        if not is_admin() and not is_supplizer():
            coupon.COcanCollect = self._can_collect(coupon)
        # 优惠券使用对象
        coupon.fill('items', items)
        coupon.fill('title_subtitle', self._title_subtitle(coupon))
        usid = kwargs.get('usid')
        if usid:
            coupon_user = CouponUser.query.filter_by({
                'USid': usid,
                'COid': coupon.COid
            }).first()
            coupon.fill('ready_collected', bool(coupon_user))

    @token_required
    def list_user_coupon(self):
        """获取用户优惠券"""
        form = CouponUserListForm().valid_data()
        usid = form.usid.data
        itid = form.itid.data
        can_use = dict(form.canuse.choices).get(form.canuse.data)  # 是否可用
        ucalreadyuse = dict(form.ucalreadyuse.choices).get(
            form.ucalreadyuse.data)  # 是否已经使用
        user_coupon = CouponUser.query.filter(
            CouponUser.USid == usid, CouponUser.UCalreadyUse == ucalreadyuse,
            CouponUser.isdelete == False)
        # 过滤标签
        if itid:
            user_coupon = user_coupon.join(
                CouponItem, CouponItem.COid == CouponUser.COid).filter(
                    CouponItem.ITid == itid, CouponItem.isdelete == False)
        # 过滤是否可用
        user_coupon = user_coupon.join(
            Coupon,
            Coupon.COid == CouponUser.COid).filter(Coupon.isdelete == False)
        time_now = datetime.now()
        if can_use:
            user_coupons = user_coupon.filter_(
                or_(Coupon.COvalidEndTime > time_now,
                    Coupon.COvalidEndTime.is_(None)),
                # or_(Coupon.COvalidStartTime < time_now, Coupon.COvalidStartTime.is_(None)),
                Coupon.COisAvailable == True,  # 可用
                # CouponUser.UCalreadyUse == False,  # 未用
            ).order_by(CouponUser.createtime.desc()).all_with_page()
        elif can_use is False:
            user_coupons = user_coupon.filter(
                or_(
                    Coupon.COisAvailable == False,
                    # CouponUser.UCalreadyUse == True,
                    Coupon.COvalidEndTime < time_now,  # 已经结束
                    # Coupon.COvalidStartTime > time_now ,  # 未开始
                ), ).order_by(CouponUser.createtime.desc()).all_with_page()
        else:
            user_coupons = user_coupon.order_by(
                CouponUser.createtime.desc()).all_with_page()
        for user_coupon in user_coupons:
            if is_admin():
                # 填用户
                user = User.query.filter(User.USid == user_coupon.USid).first()
                if user:
                    user.fields = ['USheader', 'USname', 'USid']
                user_coupon.fill('user', user)
            # 优惠券
            coupon = Coupon.query.filter(
                Coupon.COid == user_coupon.COid).first()  # 待优化
            coupon.title_subtitle = self._title_subtitle(coupon)
            # coupon.fields = ['title_subtitle', 'COname', 'COisAvailable', 'COdiscount', 'COdownLine', 'COsubtration']
            coupon.add('title_subtitle')
            user_coupon.fill('coupon', coupon)
            user_coupon.fill('can_use', self._isavalible(coupon, user_coupon))
            # 标签
            item = Items.query.join(
                CouponItem, CouponItem.ITid == Items.ITid).filter(
                    CouponItem.COid == user_coupon.COid).all()
            user_coupon.fill('item', item)
        return Success(data=user_coupons)

    @token_required
    def create(self):
        form = CouponCreateForm().valid_data()
        pbids = form.pbids.data
        prids = form.prids.data
        adid = suid = None
        if is_admin():
            adid = request.user.id
        elif is_supplizer():
            suid = request.user.id
            """如果是供应商暂时取消发布折扣优惠券权限"""
            if form.codiscount.data != 10:
                raise ParamsError('暂不提供供应商发放折扣优惠券,请联系平台后台发放')
            if not form.colimitnum:
                raise ParamsError('需要指定发放数量')
            if not (pbids or prids):
                raise ParamsError('不能发放全平台优惠券')

        else:
            raise AuthorityError()
        with self.strade.auto_commit() as s:
            s_list = []
            coid = str(uuid.uuid1())
            itids = form.itids.data
            coupon_instance = Coupon.create({
                'COid':
                coid,
                'COname':
                form.coname.data,
                'COisAvailable':
                form.coisavailable.data,
                'COcanCollect':
                form.coiscancollect.data,
                'COlimitNum':
                form.colimitnum.data,
                'COcollectNum':
                form.cocollectnum.data,
                'COsendStarttime':
                form.cosendstarttime.data,
                'COsendEndtime':
                form.cosendendtime.data,
                'COvalidStartTime':
                form.covalidstarttime.data,
                'COvalidEndTime':
                form.covalidendtime.data,
                'COdiscount':
                form.codiscount.data,
                'COdownLine':
                form.codownline.data,
                'COsubtration':
                form.cosubtration.data,
                'COdesc':
                form.codesc.data,
                'COuseNum':
                form.cousenum.data,
                'ADid':
                adid,
                'SUid':
                suid
            })
            s_list.append(coupon_instance)
            for itid in itids:
                s.query(Items).filter_by_({
                    'ITid': itid,
                    'ITtype': ItemType.coupon.value
                }).first_('指定标签不存在')
                # 优惠券标签中间表
                couponitem_instance = CouponItem.create({
                    'CIid':
                    str(uuid.uuid4()),
                    'COid':
                    coid,
                    'ITid':
                    itid
                })
                s_list.append(couponitem_instance)
            # 优惠券和应用对象的中间表
            for pbid in pbids:
                # 限制使用品牌
                pb = ProductBrand.query.filter(
                    ProductBrand.isdelete == False, ProductBrand.PBid == pbid,
                    ProductBrand.SUid == suid).first_('品牌不存在')
                coupon_for = CouponFor.create({
                    'CFid': str(uuid.uuid1()),
                    'PBid': pbid,
                    'COid': coupon_instance.COid,
                })
                s_list.append(coupon_for)
            for prid in prids:
                # 限制使用商品
                product = Products.query.filter(
                    Products.isdelete == False, Products.PRid == prid,
                    Products.CreaterId == suid).first_('不能指定其他供应商商品')

                coupon_for = CouponFor.create({
                    'CFid': str(uuid.uuid1()),
                    'PRid': prid,
                    'COid': coupon_instance.COid,
                })
                s_list.append(coupon_for)

            if is_supplizer():
                # 供应商发放优惠券 押金扣除
                su = Supplizer.query.filter(
                    Supplizer.isdelete == False,
                    Supplizer.SUid == request.user.id).first()
                co_total = Decimal(
                    str(coupon_instance.COlimitNum *
                        coupon_instance.COsubtration))
                if su.SUdeposit < co_total:
                    raise ParamsError('供应商押金不足。当前账户剩余押金 {} 发放优惠券需要 {}'.format(
                        su.SUdeposit, co_total))
                after_deposit = su.SUdeposit - co_total
                sdl = SupplizerDepositLog.create({
                    'SDLid': str(uuid.uuid1()),
                    'SUid': su.SUid,
                    'SDLnum': co_total,
                    # 'SDLtype': SupplizerDepositLogType.account_out.value,
                    'SDafter': after_deposit,
                    'SDbefore': su.SUdeposit,
                    'SDLacid': su.SUid
                })
                current_app.logger.info(
                    '供应商 {} 押金 {} 发放优惠券 {} 变更后 押金剩余 {} '.format(
                        su.SUname, su.SUdeposit, co_total, after_deposit))
                su.SUdeposit = after_deposit
                s_list.append(sdl)

            # todo 优惠券历史创建
            s.add_all(s_list)
        return Success('添加成功', data=coid)

    @admin_required
    def update(self):
        form = CouponUpdateForm().valid_data()
        itids = form.itids.data
        coid = form.coid.data
        pbids = form.pbids.data
        prids = form.prids.data
        with db.auto_commit():
            coupon = Coupon.query.filter(
                Coupon.COid == coid, Coupon.isdelete == False).first_('优惠券不存在')
            # 已经可以使用的不可以修改
            if coupon.COsendStarttime is None or coupon.COsendStarttime < datetime.now(
            ):
                raise StatusError('已经开放领取不可修改')
            coupon_dict = {
                'COname': form.coname.data,
                'COisAvailable': form.coisavailable.data,
                'COcanCollect': form.coiscancollect.data,
                'COlimitNum': form.colimitnum.data,
                'COcollectNum': form.cocollectnum.data,
                'COsendStarttime': form.cosendstarttime.data,
                'COsendEndtime': form.cosendendtime.data,
                'COvalidStartTime': form.covalidstarttime.data,
                'COvalidEndTime': form.covalidendtime.data,
                'COdiscount': form.codiscount.data,
                'COdownLine': form.codownline.data,
                'COsubtration': form.cosubtration.data,
                'COdesc': form.codesc.data,
                'COuseNum': form.cousenum.data,
            }
            if form.colimitnum.data:
                coupon_dict.setdefault('COremainNum', form.colimitnum.data)
            coupon.update(coupon_dict, 'dont ignore')
            if coupon.SUid:
                # todo 如果修改的是供应商的优惠券。需要涉及押金的修改 目前不做校验
                pass

            db.session.add(coupon)
            for itid in itids:
                Items.query.filter_by_({
                    'ITid': itid,
                    'ITtype': ItemType.coupon.value
                }).first_('指定标签不存在')
                coupon_items = CouponItem.query.filter(
                    CouponItem.ITid == itid, CouponItem.isdelete == False,
                    CouponItem.COid == coid).first()
                if not coupon_items:
                    # 优惠券标签中间表
                    couponitem_instance = CouponItem.create({
                        'CIid':
                        str(uuid.uuid4()),
                        'COid':
                        coupon.COid,
                        'ITid':
                        itid
                    })
                    db.session.add(couponitem_instance)
            # 删除原有的标签
            CouponItem.query.filter(
                CouponItem.isdelete == False, CouponItem.ITid.notin_(itids),
                CouponItem.COid == coid).delete_(synchronize_session=False)
            # todo 修改此句
            CouponFor.query.filter(
                CouponFor.COid == coid,
                CouponFor.isdelete == False).delete_(synchronize_session=False)
            # 优惠券和应用对象的中间表
            for pbid in pbids:
                coupon_for = CouponFor.create({
                    'CFid': str(uuid.uuid1()),
                    'PBid': pbid,
                    'COid': coid
                })
                db.session.add(coupon_for)
            for prid in prids:
                coupon_for = CouponFor.create({
                    'CFid': str(uuid.uuid1()),
                    'PRid': prid,
                    'COid': coid
                })
                db.session.add(coupon_for)
            # 删除无用的
            #
            # CouponFor.query.filter(
            #     CouponFor.isdelete == False,
            #     CouponFor.COid == coid,
            #     or_(CouponFor.PBid.notin_(pbids),
            #          CouponFor.PRid.notin_(prids))
            # ).delete_(synchronize_session=False)
        return Success('修改成功')

    @admin_required
    def delete(self):
        data = parameter_required(('coid', ))
        coid = data.get('coid')
        with db.auto_commit():
            coupon = Coupon.query.filter(
                Coupon.isdelete == False,
                Coupon.COid == coid,
            ).first_('优惠券不存在')
            coupon.isdelete = True
            db.session.add(coupon)
            # 删除用户的优惠券
            coupon_user = CouponUser.query.filter(
                CouponUser.isdelete == False,
                CouponUser.COid == coid).delete_()
            coupon_for = CouponFor.query.filter(
                CouponFor.isdelete == False, CouponFor.COid == coid).delete_()
            current_app.logger.info(
                '删除优惠券的同时 将{}个用户拥有的优惠券也删除'.format(coupon_user))
        return Success('删除成功')

    @token_required
    def fetch(self):
        """领取优惠券"""
        form = CouponFetchForm().valid_data()
        coid = form.coid.data
        usid = request.user.id
        with self.strade.auto_commit() as s:
            s_list = []
            # 优惠券状态是否可领取
            coupon = s.query(Coupon).filter_by_({
                'COid': coid,
                'COcanCollect': True
            }).first_('优惠券不存在或不可领取')
            coupon_user_count = s.query(CouponUser).filter_by_({
                'COid': coid,
                'USid': usid
            }).count()
            # 领取过多
            if coupon.COcollectNum and coupon_user_count > coupon.COcollectNum:
                raise StatusError('已经领取过')
            # 发放完毕或抢空
            if coupon.COlimitNum:
                # 共领取的数量
                if not coupon.COremainNum:
                    raise StatusError('已发放完毕')
                coupon.COremainNum = coupon.COremainNum - 1  # 剩余数量减1
                s_list.append(coupon)
            if coupon.COsendStarttime and coupon.COsendStarttime > datetime.now(
            ):
                raise StatusError('未开抢')
            if coupon.COsendEndtime and coupon.COsendEndtime < datetime.now():
                raise StatusError('来晚了')
            # 写入couponuser
            coupon_user_dict = {
                'UCid': str(uuid.uuid4()),
                'COid': coid,
                'USid': usid,
            }
            coupon_user_instance = CouponUser.create(coupon_user_dict)
            # 优惠券减1
            s_list.append(coupon_user_instance)
            s.add_all(s_list)
        return Success('领取成功')

    @staticmethod
    def _title_subtitle(coupon):
        # 使用对象限制
        coupon_fors = CouponFor.query.filter_by_({'COid': coupon.COid}).all()
        if len(coupon_fors) == 1:
            if coupon_fors[0].PCid:
                category = ProductCategory.query.filter_by_({
                    'PCid':
                    coupon_fors[0].PCid
                }).first()
                title = '{}类专用'.format(category.PCname)
                left_logo = category['PCpic']
                left_text = category.PCname
            elif coupon_fors[0].PBid:
                brand = ProductBrand.query.filter_by_({
                    'PBid':
                    coupon_fors[0].PBid
                }).first()
                title = '{}品牌专用'.format(brand.PBname)
                left_logo = brand['PBlogo']
                left_text = brand.PBname
                coupon.fill('brands', [brand])
            elif coupon_fors[0].PRid:
                product = Products.query.filter(
                    Products.PRid == coupon_fors[0].PRid).first()
                brand = ProductBrand.query.filter(
                    ProductBrand.PBid == product.PBid).first()
                product.fill('brand', brand)
                title = '单品专用'.format(product.PRtitle)
                left_logo = product['PRmainpic']
                left_text = product.PRtitle
                coupon.fill('products', [product])
        elif coupon_fors:
            # 多品牌
            cfg = ConfigSettings()
            pbids = [x.PBid for x in coupon_fors if x.PBid]
            left_logo = cfg.get_item('planet', 'logo')
            if pbids:
                title = '多品牌专用'
                for_brand = []
                brands = []
                for pbid in pbids:
                    brand = ProductBrand.query.filter(
                        ProductBrand.PBid == pbid).first()
                    if brand:
                        brands.append(brand)
                        for_brand.append(brand.PBname)
                left_text = '{}通用'.format('/'.join(for_brand))
                coupon.fill('brands', brands)
            # 多商品
            else:
                prids = [x.PRid for x in coupon_fors if x.PRid]
                left_logo = cfg.get_item('planet', 'logo')
                title = '多商品专用'
                for_product = []
                products = []
                for prid in prids:
                    product = Products.query.filter(
                        Products.PRid == prid).first()
                    brand = ProductBrand.query.filter(
                        ProductBrand.PBid == product.PBid).first()
                    product.fill('brand', brand)
                    if product:
                        products.append(product)
                        for_product.append(product.PRtitle)
                left_text = '{}通用'.format('/'.join(for_product))
                coupon.fill('products', products)
            # 多类目 暂时没有多类目优惠券
            pass
        else:
            title = '全场通用'
            cfg = ConfigSettings()
            left_logo = cfg.get_item('planet', 'logo')
            left_text = cfg.get_item('planet', 'title')
        # 使用下限
        if coupon.COdownLine:
            subtitle = '满{:g}元'.format(coupon.COdownLine)
        else:
            subtitle = '无限制'
        # 叠加方式
        if coupon.COuseNum:
            subtitle += '可用'
        else:
            subtitle += '可叠加'
        return {
            'title': title,
            'subtitle': subtitle,
            'left_logo': left_logo,
            'left_text': left_text
        }

    def _can_collect(self, coupon):
        # 发放完毕或抢空
        can_not_collect = (not coupon.COcanCollect) or (
            coupon.COlimitNum and not coupon.COremainNum) or (
                coupon.COsendStarttime and coupon.COsendStarttime >
                datetime.now()) or (coupon.COsendEndtime
                                    and coupon.COsendEndtime < datetime.now())
        return not can_not_collect

    def _isavalible(self, coupon, user_coupon=None):
        # 判断是否可用
        time_now = datetime.now()
        ended = (  # 已结束
            coupon.COvalidEndTime < time_now
            if coupon.COvalidEndTime else False)
        not_start = (  # 未开始
            coupon.COvalidStartTime > time_now
            if coupon.COvalidStartTime else False)

        if user_coupon:
            avalible = not ended and not not_start and coupon.COisAvailable and not user_coupon.UCalreadyUse

        else:
            avalible = not (ended or not_start or not coupon.COisAvailable)
        return avalible
예제 #6
0
class CCart(object):
    def __init__(self):
        self.scart = STrade()
        self.sproduct = SProducts()

    @token_required
    def add(self):
        """添加购物车"""
        data = parameter_required(('skuid', ))
        try:
            cafrom = CartFrom(data.get('cafrom')).value
            current_app.logger.info('获取到了cafrom value = {}'.format(cafrom))
        except:
            current_app.logger.info('cafrom 参数异常')
            cafrom = 10
        contentid = data.get('contentid')
        # todo 前端目前只会在限时活动传该参数
        if cafrom == CartFrom.time_limited.value and not contentid:
            current_app.logger.info('miss content  cafrom {}'.format(cafrom))
            raise ParamsError('非活动商品加入购物车参数异常')

        skuid = data.get('skuid')
        try:
            num = int(data.get('canums', 1))
        except TypeError as e:
            raise ParamsError('num参数类型错误')
        usid = request.user.id
        is_exists = self.scart.get_card_one({
            'USid': usid,
            'SKUid': skuid,
            'CAfrom': cafrom
        })
        if is_exists:
            # 已存在
            caid = is_exists.CAid
            with self.scart.auto_commit() as session:
                new_nums = is_exists.CAnums
                if new_nums <= 0:
                    # 数目过小则为删除
                    session.query(Carts).filter_by_({
                        'CAid': caid
                    }).update({'isdelete': True})
                    msg = '删除购物车成功'
                else:
                    # 更新数据
                    session.query(Carts).filter_by_({
                        'CAid': caid
                    }).update({'CAnums': Carts.CAnums + num})
                    msg = '更新购物车成功'
        else:
            # 不存在
            with self.scart.auto_commit() as session:
                sku = session.query(ProductSku).filter_by_({
                    'SKUid': skuid
                }).first_('sku不存在')
                prid = sku.PRid
                product = session.query(Products).filter_by_({
                    'PRid': prid
                }).first_('商品不存在')
                pbid = product.PBid
                if num <= 0:
                    raise ParamsError('num参数错误')
                cart = Carts.create({
                    'CAid': str(uuid.uuid4()),
                    'USid': usid,
                    'SKUid': skuid,
                    'CAnums': num,
                    'PBid': pbid,
                    'PRid': prid,
                    'Contentid': contentid,
                    'CAfrom': cafrom
                })
                msg = '添加购物车成功'
                session.add(cart)
        return Success(msg)

    @token_required
    def update(self):
        """更新购物车"""
        data = parameter_required(('caid', ))
        caid = data.get('caid')
        usid = request.user.id
        card = self.scart.get_card_one({
            'CAid': caid,
            'USid': usid
        },
                                       error='购物车不存在')  # card就是cart.
        # 默认的sku和数量
        skuid = data.get('skuid') or card.SKUid
        try:
            num = int(data.get('canums', card.CAnums))
            if num < 0:
                raise TypeError()
        except TypeError as e:
            raise ParamsError('num类型错误')
        msg = '更新成功'
        with self.scart.auto_commit() as session:
            # 数量为0执行删除
            if num == 0:
                session.query(Carts).filter_by({'CAid': caid}).delete_()
                msg = '删除成功'
            else:
                session.query(ProductSku).filter_by_({
                    'SKUid': skuid
                }).first_('商品sku不存在')
                session.query(Carts).filter_by({
                    'CAid': caid
                }).update({
                    'SKUid': skuid,
                    'CAnums': num
                })
        return Success(msg)

    @token_required
    def list(self):
        """个人购物车列表"""
        usid = request.user.id
        my_carts = self.scart.get_card_list({'USid': usid})
        pb_list = []
        new_cart_list = []
        product_num = 0
        for cart in my_carts:
            pbid = cart.PBid
            car_from = cart.CAfrom
            product = self.sproduct.get_product_by_prid(cart.PRid)  # 商品
            if not product:
                continue

            product.PRattribute = json.loads(product.PRattribute)
            pb = self.sproduct.get_product_brand_one({'PBid': pbid})
            if not pb:
                continue
            cart_sku = self.sproduct.get_sku_one({'SKUid':
                                                  cart.SKUid})  # 购物车的sku
            if not cart_sku:
                continue
            cart_sku.SKUattriteDetail = json.loads(cart_sku.SKUattriteDetail)
            # skuvalue = self.sproduct.get_sku_value({'PRid': cart.PRid})   # 商品的skuvalue
            # 填充商品
            product.hide('PRdesc')
            product.fill('PRstatus_en', ProductStatus(product.PRstatus).name)
            # 商品sku
            skus = self.sproduct.get_sku({'PRid': product.PRid})
            sku_value_item = []
            for sku in skus:
                sku.SKUattriteDetail = json.loads(sku.SKUattriteDetail)
                sku_value_item.append(sku.SKUattriteDetail)
            product.fill('skus', skus)
            # 商品sku value
            sku_value_item_reverse = []
            for index, name in enumerate(product.PRattribute):
                value = list(
                    set([attribute[index] for attribute in sku_value_item]))
                value = sorted(value)
                temp = {'name': name, 'value': value}
                sku_value_item_reverse.append(temp)
            product.fill('SkuValue', sku_value_item_reverse)
            # 填充活动商品信息

            # 填充购物车
            cart.fill('sku', cart_sku)
            cart.fill('product', product)
            if car_from == CartFrom.time_limited.value:
                self._fill_tlp(cart)
            # 小计
            # cart.subtotal =
            # 数量
            product_num += 1
            # 店铺分组
            if pbid not in pb_list:
                new_cart_list.append({'cart': [cart], 'pb': pb})
                pb_list.append(pbid)
            else:
                index = pb_list.index(pbid)
                new_cart_list[index]['cart'].append(cart)
        return Success(data=new_cart_list).get_body(product_num=product_num)

    @token_required
    def destroy(self):
        """批量个人购物车"""
        data = parameter_required()
        usid = request.user.id
        caids = data.get('caids')
        if isinstance(caids, list) and len(caids) == 0:
            raise ParamsError('caids 为空')
        if not caids:
            caids = []
        if not isinstance(caids, list):
            raise ParamsError('caids 参数错误')
        # 删除
        with self.scart.auto_commit() as session:
            session.query(Carts).filter_(
                Carts.CAid.in_(caids),
                Carts.USid == usid).delete_(synchronize_session=False)
        return Success('删除成功')

    def _fill_tlp(self, cart):

        tlp = TimeLimitedProduct.query.filter_by(
            TLPid=cart.Contentid,
            isdelete=False,
            TLAstatus=ApplyStatus.agree.value).first()
        if not tlp:
            current_app.logger.info('当前活动商品尚未通过审批')
            return
        tla = TimeLimitedActivity.query.filter_by(TLAid=tlp.TLAid,
                                                  isdelete=False).first()
        if not tla and tla.TLAstatus not in [
                TimeLimitedStatus.starting.value,
                TimeLimitedStatus.waiting.value
        ]:
            current_app.logger.info('当前活动已结束或者已中止 tla = {}'.format(tlp.TLAid))
            return
        tls = TimeLimitedSku.query.filter_by(TLPid=tlp.TLPid,
                                             isdelete=False,
                                             SKUid=cart.sku.SKUid).first()
        if tls:
            cart.sku.fill('tlsprice', tls.SKUprice)
            cart.sku.fill('tlsstock', tls.TLSstock)

        cart.product.fill('tlpprice', tlp.PRprice)
        cart.product.fill('tlastatus', tla.TLAstatus)
예제 #7
0
 def __init__(self):
     self.strade = STrade()
     self.suser = SUser()
     self.alipay = alipay
     self.wx_pay = wx_pay
예제 #8
0
class CPay():
    def __init__(self):
        self.strade = STrade()
        self.suser = SUser()
        self.alipay = alipay
        self.wx_pay = wx_pay

    @token_required
    def pay(self):
        """订单发起支付"""
        data = parameter_required(('omid', ))
        omid = data.get('omid')
        usid = request.user.id
        try:
            omclient = int(data.get('omclient',
                                    Client.wechat.value))  # 客户端(app或者微信)
            Client(omclient)
            opaytype = int(data.get('opaytype',
                                    PayType.wechat_pay.value))  # 付款方式
            PayType(opaytype)
        except ValueError as e:
            raise e
        except Exception as e:
            raise ParamsError('客户端或支付方式类型错误')
        from planet.control.CUser import CUser
        cuser = CUser()
        if opaytype == PayType.integralpay.value:
            return self._integralpay(data, usid)
        with db.auto_commit():
            opayno = self.wx_pay.nonce_str
            order_main = OrderMain.query.filter_by_({
                'OMid':
                omid,
                'USid':
                usid,
                'OMstatus':
                OrderMainStatus.wait_pay.value
            }).first_('不存在的订单')
            # 原支付流水删除
            OrderPay.query.filter_by({'OPayno': order_main.OPayno}).delete_()
            # 更改订单支付编号
            order_main.OPayno = opayno
            # 判断订单是否是开店大礼包
            # 是否是开店大礼包
            if order_main.OMlogisticType == OMlogisticTypeEnum.online.value:
                cuser = CUser()
                cuser._check_gift_order('重复购买开店大礼包')
            db.session.add(order_main)
            pay_price = order_main.OMtrueMount

            # 魔术礼盒订单
            if order_main.OMfrom == OrderFrom.magic_box.value:
                magic_box_join = MagicBoxJoin.query.filter(
                    MagicBoxJoin.isdelete == False,
                    MagicBoxJoin.OMid == order_main.OMid,
                    MagicBoxJoin.MBJstatus ==
                    MagicBoxJoinStatus.pending.value).first()
                pay_price = float(order_main.OMtrueMount) - float(
                    magic_box_join.MBJcurrentPrice)
                if pay_price <= 0:
                    pay_price = 0.01
            # 新建支付流水
            if order_main.OMintegralpayed and order_main.OMintegralpayed > 0:
                db.session.add(
                    OrderPay.create({
                        'OPayid': str(uuid.uuid1()),
                        'OPayno': opayno,
                        'OPayType': PayType.mixedpay.value,
                        'OPayMount': order_main.OMintegralpayed
                    }))
            order_pay_instance = OrderPay.create({
                'OPayid': str(uuid.uuid1()),
                'OPayno': opayno,
                'OPayType': opaytype,
                'OPayMount': pay_price,
            })
            # 付款时候的body信息
            order_parts = OrderPart.query.filter_by_({'OMid': omid}).all()
            body = ''.join([getattr(x, 'PRtitle', '') for x in order_parts])
            db.session.add(order_pay_instance)
        user = User.query.filter(User.USid == order_main.USid).first()
        pay_args = self._pay_detail(omclient,
                                    opaytype,
                                    opayno,
                                    float(pay_price),
                                    body,
                                    openid=user.USopenid2)
        response = {
            'pay_type': PayType(opaytype).name,
            'opaytype': opaytype,
            'args': pay_args
        }
        return Success('生成付款参数成功', response)

    def alipay_notify(self):
        """异步通知, 文档 https://docs.open.alipay.com/203/105286/"""
        # 待测试
        data = request.form.to_dict()
        signature = data.pop("sign")
        success = self.alipay.verify(data, signature)
        if not (success and data["trade_status"]
                in ("TRADE_SUCCESS", "TRADE_FINISHED")):
            return
        print("trade succeed")
        out_trade_no = data.get('out_trade_no')
        # 交易成功
        with self.strade.auto_commit() as s:
            # 更改付款流水
            order_pay_instance = OrderPay.query.filter_by_({
                'OPayno':
                out_trade_no
            }).first_()
            order_pay_instance.OPaytime = data.get('gmt_payment')
            order_pay_instance.OPaysn = data.get('trade_no')  # 支付宝交易凭证号
            order_pay_instance.OPayJson = json.dumps(data)
            # 更改主单
            order_mains = OrderMain.query.filter_by_({
                'OPayno': out_trade_no
            }).all()
            for order_main in order_mains:
                order_main.update(
                    {'OMstatus': OrderMainStatus.wait_send.value})
                db.session.add(order_main)
                # 添加佣金记录
                current_app.logger.info('支付宝付款成功')
                self._insert_usercommision(order_main)
        return 'success'

    def wechat_notify(self):
        """微信支付回调"""
        data = self.wx_pay.to_dict(request.data)
        if not self.wx_pay.check(data):
            return self.wx_pay.reply(u"签名验证失败", False)
        out_trade_no = data.get('out_trade_no')
        current_app.logger.info(
            "This is wechat_notify, opayno is {}".format(out_trade_no))
        with db.auto_commit():
            # 更改付款流水
            order_pay_instance = OrderPay.query.filter_by_({
                'OPayno':
                out_trade_no,
                'OPayType':
                PayType.wechat_pay.value
            }).first_()
            order_pay_instance.OPaytime = data.get('time_end')
            order_pay_instance.OPaysn = data.get('transaction_id')  # 微信支付订单号
            order_pay_instance.OPayJson = json.dumps(data)

            # 魔术礼盒押金 创建盒子
            deposit = ActivityDeposit.query.filter_by_(
                OPayno=out_trade_no,
                ACtype=ActivityType.magic_box.value,
                ACDstatus=ActivityDepositStatus.failed.value).first()
            if deposit:
                current_app.logger.info(
                    'magic_box deposit found, ACDid: {}'.format(deposit.ACDid))
                self._create_magic_box(deposit)

            # 更改主单
            order_mains = OrderMain.query.filter_by_({
                'OPayno': out_trade_no
            }).all()
            for order_main in order_mains:
                user = User.query.filter_by_({'USid': order_main.USid}).first()
                order_main.update(
                    {'OMstatus': OrderMainStatus.wait_send.value})
                if order_main.OMfrom == OrderFrom.magic_box.value:
                    current_app.logger.info('find a magic_box order')
                    self._change_box_status(order_main)  # 魔盒订单
                # 添加佣金记录
                current_app.logger.info('微信支付成功')
                self._insert_usercommision(order_main)
                if user:
                    self._notify_payed_integral(order_main, user,
                                                out_trade_no)  # 组合支付的类型,扣除相应星币
                    self._trade_add_integral(order_main, user)  # 购物加星币

        return self.wx_pay.reply("OK", True).decode()

    @staticmethod
    def _change_box_status(ordermain):
        """付款成功后更改魔盒相应状态"""
        current_app.logger.info('change magic box status, omid {}'.format(
            ordermain.OMid))
        order_part = OrderPart.query.filter_by_(OMid=ordermain.OMid).first()
        mbj = MagicBoxJoin.query.filter(
            MagicBoxJoin.MBAid == order_part.PRid,
            MagicBoxJoin.MBSid == order_part.SKUid,
            MagicBoxJoin.USid == ordermain.USid,
            MagicBoxJoin.isdelete == False,
            MagicBoxJoin.OMid == ordermain.OMid, MagicBoxJoin.MBJstatus ==
            MagicBoxJoinStatus.pending.value).first()
        current_app.logger.info('find a magic_box_join, MBJid:{}'.format(
            [mbj.MBJid if mbj else None]))
        # 完成盒子
        mbj.update({'MBJstatus': MagicBoxJoinStatus.completed.value})
        db.session.add(mbj)
        # 扣除押金
        deposit = ActivityDeposit.query.filter_by_(
            ACDid=mbj.ACDid,
            ACDstatus=ActivityDepositStatus.valid.value).first()
        current_app.logger.info('deduct a magic box deposit, ACDid:{}'.format(
            [deposit.ACDid if deposit else None]))
        deposit.update({'ACDstatus': ActivityDepositStatus.deduct.value})
        db.session.add(deposit)

    @staticmethod
    def _create_magic_box(deposit):
        """创建魔盒"""
        # 押金状态生效
        current_app.logger.info('change deposit status')
        deposit.update({'ACDstatus': ActivityDepositStatus.valid.value})
        db.session.add(deposit)
        mbaid, mbsid = deposit.ACDcontentId, deposit.SKUid
        mba = MagicBoxApply.query.filter_by_(MBAid=mbaid).first()
        mbs = MagicBoxApplySku.query.filter_by_(MBSid=mbsid).first()
        product = Products.query.filter_by_(PRid=mba.PRid).first()
        current_app.logger.info('wechat_notify, create box')

        day = datetime.now().date() + timedelta(days=1)
        while MagicBoxApply.query.filter(
                MagicBoxApply.isdelete == False,
                MagicBoxApply.PRid == mba.PRid,
                MagicBoxApply.MBAstatus == ApplyStatus.agree.value,
                MagicBoxApply.MBAday == day).first():
            day = day + timedelta(days=1)
        endtime = day - timedelta(days=1)

        magic_box = MagicBoxJoin.create({
            'MBJid':
            str(uuid.uuid1()),
            'USid':
            deposit.USid,
            'MBAid':
            mbaid,
            'MBSid':
            mbsid,
            'PRtitle':
            product.PRtitle,
            'PRmainpic':
            product.PRmainpic,
            'MBJstatus':
            MagicBoxJoinStatus.pending.value,
            'MBJprice':
            mbs.SKUprice,
            'MBJcurrentPrice':
            mbs.SKUprice,
            'HighestPrice':
            mbs.HighestPrice,
            'LowestPrice':
            mbs.LowestPrice,
            'MBSendtime':
            endtime,
            'ACDid':
            deposit.ACDid
        })
        db.session.add(magic_box)

    def _notify_payed_integral(self, om, user, opayno):
        """扣除组合支付时的星币"""
        if om.OMintegralpayed and om.OMintegralpayed > 0:
            current_app.logger.info("wechat_notify, reduce integral")
            ui = UserIntegral.create({
                'UIid':
                str(uuid.uuid1()),
                'USid':
                user.USid,
                'UIintegral':
                om.OMintegralpayed,
                'UIaction':
                UserIntegralAction.consumption.value,
                'UItype':
                UserIntegralType.expenditure.value,
                'OPayno':
                opayno
            })
            db.session.add(ui)
            user.update(
                {'USintegral': user.USintegral - int(om.OMintegralpayed)})
            db.session.add(user)

    def _trade_add_integral(self, order_main, user):
        """购物加星币"""
        #  购物加积分
        # percent = 0.2
        current_app.logger.info("wechat_notify, trade add integral")
        percent = ConfigSettings().get_item('integralbase', 'trade_percent')
        if not (0 < int(percent) <= 100):
            return
        intergral = int(
            Decimal(int(percent) / 100) * Decimal(order_main.OMtrueMount))
        ui = UserIntegral.create({
            'UIid': str(uuid.uuid1()),
            'USid': user.USid,
            'UIintegral': intergral,
            'UIaction': UserIntegralAction.trade.value,
            'UItype': UserIntegralType.income.value
        })
        db.session.add(ui)
        user.update({'USintegral': user.USintegral + int(intergral)})
        db.session.add(user)

    def _insert_usercommision(self, order_main):
        """写入佣金流水表"""
        omid = order_main.OMid
        user = User.query.filter_by_({'USid': order_main.USid}).first()  # 订单用户
        try:
            current_app.logger.info('当前付款人: {}, 状态: {}  '.format(
                user.USname,
                UserIdentityStatus(user.USlevel).zh_value))
        except Exception:
            pass
        commision = Commision.query.filter(Commision.isdelete == False).first()
        order_parts = OrderPart.query.filter_by_({'OMid': omid}).all()
        UCstatus = None
        UCendTime = None
        is_trial_commodity = order_main.OMfrom == OrderFrom.trial_commodity.value
        opid = None
        for order_part in order_parts:
            # 是否是新人大礼包
            prid = order_part.PRid
            opid = order_part.OPid
            if order_main.OMfrom == OrderFrom.fresh_man.value:
                current_app.logger.info('新人首单不参与分佣')
                continue
            if self._check_upgrade_gift((prid, )):
                current_app.logger.info('开店礼包不需要佣金')
                # user.USlevel = UserIdentityStatus.toapply.value
                # continue
            if is_trial_commodity:
                trialcommodity = TrialCommodity.query.filter_by(
                    TCid=order_parts[0]['PRid']).first()
                user_commision_dict = {
                    'UCid':
                    str(uuid.uuid1()),
                    'OMid':
                    omid,
                    'OPid':
                    order_part.OPid,
                    'UCcommission':
                    order_main.OMtrueMount,
                    'USid':
                    user.USid,
                    'CommisionFor':
                    ApplyFrom.user.value,
                    'UCtype':
                    UserCommissionType.deposit.value,  # 类型是押金
                    'PRtitle':
                    order_part.PRtitle,
                    'SKUpic':
                    order_part.SKUpic,
                    'UCendTime':
                    order_main.createtime +
                    timedelta(days=trialcommodity.TCdeadline),
                    'UCstatus':
                    UserCommissionStatus.preview.value,
                    'FromUsid':
                    order_main.USid
                }
                db.session.add(UserCommission.create(user_commision_dict))
                continue
            up1 = order_part.UPperid
            up2 = order_part.UPperid2
            up3 = order_part.UPperid3
            # 如果付款用户是代理商
            if UserIdentityStatus.agent.value == user.USlevel:
                up1, up2, up3 = user.USid, up1, up2  # 代理商自己也会有一部分佣金
            up1_user = User.query.filter(User.isdelete == False,
                                         User.USid == up1).first()
            up2_user = User.query.filter(User.isdelete == False,
                                         User.USid == up2).first()
            up3_user = User.query.filter(User.isdelete == False,
                                         User.USid == up3).first()
            self._caculate_commsion(
                user,
                up1_user,
                up2_user,
                up3_user,
                commision,
                order_part,
                is_act=bool(
                    order_main.OMfrom == OrderFrom.trial_commodity.value))

        # 新人活动订单
        if order_main.OMfrom == OrderFrom.fresh_man.value:
            if not opid:
                current_app.logger.info('新人首单没有分单id  请检查数据库')
                return
            first = 20
            second = 30
            third = 50

            fresh_man_join_flow = FreshManJoinFlow.query.filter(
                FreshManJoinFlow.isdelete == False,
                FreshManJoinFlow.OMid == order_main.OMid,
            ).first()
            if fresh_man_join_flow and fresh_man_join_flow.UPid:
                fresh_man_join_count = FreshManJoinFlow.query.filter(
                    FreshManJoinFlow.isdelete == False,
                    FreshManJoinFlow.UPid == fresh_man_join_flow.UPid,
                    FreshManJoinFlow.OMid == OrderMain.OMid,
                    OrderMain.OMstatus >= OrderMainStatus.wait_send.value,
                    OrderMain.OMinRefund == False,
                    OrderMain.isdelete == False).count()
                current_app.logger.info(
                    "当前邀请人 邀请了总共 {} ".format(fresh_man_join_count))
                # 邀请人的新人首单
                up_order_main = OrderMain.query.filter(
                    OrderMain.isdelete == False,
                    OrderMain.USid == fresh_man_join_flow.UPid,
                    OrderMain.OMfrom == OrderFrom.fresh_man.value,
                    OrderMain.OMstatus > OrderMainStatus.wait_pay.value,
                ).first()
                # 邀请人的新人首单佣金列表
                up_order_fresh_commissions = UserCommission.query.filter(
                    UserCommission.isdelete == False,
                    # OrderMain.OMinRefund == False,
                    UserCommission.USid == up_order_main.USid,
                    UserCommission.UCstatus >=
                    UserCommissionStatus.preview.value,
                    UserCommission.UCtype ==
                    UserCommissionType.fresh_man.value,
                ).order_by(UserCommission.createtime.asc()).limit(3)
                # 邀请人的新人首单佣金
                commissions = 0
                for commission in up_order_fresh_commissions:
                    commissions += commission.UCcommission
                if up_order_main:
                    up_fresh_order_price = up_order_main.OMtrueMount
                    # 邀请人新品佣金小于这次新人返现并且这次新人在前三个返现的人之内
                    if commissions < up_fresh_order_price and fresh_man_join_count <= 3:
                        reward = fresh_man_join_flow.OMprice
                        if fresh_man_join_count == 0:
                            reward = reward * (first / 100)
                        elif fresh_man_join_count == 1:
                            reward = reward * (second / 100)
                        elif fresh_man_join_count == 2:
                            reward = reward * (third / 100)
                        else:
                            reward = 0
                        if reward + commissions > up_fresh_order_price:
                            reward = up_fresh_order_price - commissions
                        current_app.logger.info(
                            '本次订单可以获取的佣金是 {}'.format(reward))
                        if reward:
                            user_commision_dict = {
                                'UCid': str(uuid.uuid1()),
                                'OMid': omid,
                                'UCcommission': reward,
                                'USid': fresh_man_join_flow.UPid,
                                'UCtype': UserCommissionType.fresh_man.value,
                                'UCendTime': UCendTime,
                                'OPid': opid
                            }
                            db.session.add(
                                UserCommission.create(user_commision_dict))
        # 线上发货
        if order_main.OMlogisticType == OMlogisticTypeEnum.online.value:
            order_main.OMstatus = OrderMainStatus.ready.value
            db.session.add(order_main)
            # 发货表
            orderlogistics = OrderLogistics.create({
                'OLid':
                str(uuid.uuid1()),
                'OMid':
                omid,
                'OLcompany':
                'auto',
                'OLexpressNo':
                self._generic_omno(),
                'OLsignStatus':
                LogisticsSignStatus.already_signed.value,
                'OLdata':
                '[]',
                'OLlastresult':
                '{}'
            })
            db.session.add(orderlogistics)

    def _caculate_commsion(self,
                           user,
                           up1,
                           up2,
                           up3,
                           commision,
                           order_part,
                           is_act=False):
        """计算各级佣金"""
        # 活动佣金即时到账
        suid = order_part.PRcreateId
        if is_act:
            current_app.logger.info('活动订单和押金即时到账')
            UCstatus = UserCommissionStatus.in_account.value
        else:
            UCstatus = None
        default_level1commision, default_level2commision, default_level3commision, default_planetcommision = json.loads(
            commision.Levelcommision)
        reduce_ratio = json.loads(commision.ReduceRatio)
        increase_ratio = json.loads(commision.IncreaseRatio)
        # 基础佣金比
        user_level1commision = Decimal(
            str(
                self._current_commission(
                    getattr(order_part, 'USCommission1', ''),
                    default_level1commision)))
        user_level2commision = Decimal(
            str(
                self._current_commission(
                    getattr(order_part, 'USCommission2', ''),
                    default_level2commision)))
        user_level3commision = Decimal(
            str(
                self._current_commission(
                    getattr(order_part, 'USCommission3', ''),
                    default_level3commision)))
        # 平台 + 用户 抽成: 获取成功比例, 依次查找订单--> sku --> 系统默认
        planet_and_user_rate = Decimal(str(order_part.SkudevideRate or 0))

        if not planet_and_user_rate:
            sku = ProductSku.query.filter(
                ProductSku.SKUid == OrderPart.SKUid).first()
            if sku:
                planet_and_user_rate = Decimal(str(sku.SkudevideRate or 0))
        if not planet_and_user_rate:
            planet_and_user_rate = default_planetcommision
        planet_and_user_rate = Decimal(planet_and_user_rate) / 100
        # 平台固定抽成
        planet_rate = Decimal(default_planetcommision) / 100
        planet_commision = order_part.OPsubTotal * planet_rate  # 平台获得, 是总价的的百分比
        user_commision = order_part.OPsubTotal * planet_and_user_rate - planet_commision  # 用户获得, 是总价 - 平台获得
        # user_rate = planet_and_user_rate - planet_rate  # 用户的的比例
        # 用户佣金
        commision_for_supplizer = order_part.OPsubTotal * (
            Decimal('1') - planet_and_user_rate)  #  给供应商的钱   总价 * ( 1 - 让利 )
        commision_for_supplizer = self.get_two_float(commision_for_supplizer)

        desposit = 0
        # 正常应该获得佣金
        up1_base = up2_base = up3_base = 0
        if up1 and up1.USlevel > 1:
            user_level1commision = self._current_commission(
                up1.USCommission1, user_level1commision) / 100  # 个人佣金比
            up1_base = user_commision * user_level1commision
            if up2 and up2.USlevel > 1:
                user_level2commision = self._current_commission(
                    up2.USCommission2, user_level2commision) / 100  # 个人佣金比
                up2_base = user_commision * user_level2commision
                # 偏移
                up1_up2 = up1.CommisionLevel - up2.CommisionLevel
                up1_base, up2_base = self._caculate_offset(
                    up1_up2, up1_base, up2_base, reduce_ratio, increase_ratio)
                if up3 and up3.USlevel > 1:
                    user_level3commision = self._current_commission(
                        up3.USCommission3, user_level3commision) / 100  # 个人佣金比
                    up3_base = user_commision * user_level3commision
                    up2_up3 = Decimal(up2.CommisionLevel) - Decimal(
                        up3.CommisionLevel)
                    up2_base, up3_base = self._caculate_offset(
                        up2_up3, up2_base, up3_base, reduce_ratio,
                        increase_ratio)
        if up1_base:
            up1_base = self.get_two_float(up1_base)
            user_commision -= up1_base
            current_app.logger.info('一级获得佣金: {}'.format(up1_base))
            commision_account = UserCommission.create({
                'UCid': str(uuid.uuid1()),
                'OMid': order_part.OMid,
                'OPid': order_part.OPid,
                'UCcommission': up1_base,
                'USid': up1.USid,
                'PRtitle': order_part.PRtitle,
                'SKUpic': order_part.SKUpic,
                'UCstatus': UCstatus,
                'FromUsid': user.USid
            })
            db.session.add(commision_account)
        if up2_base:
            up2_base = self.get_two_float(up2_base)
            user_commision -= up2_base
            current_app.logger.info('二级获得佣金: {}'.format(up2_base))
            commision_account = UserCommission.create({
                'UCid': str(uuid.uuid1()),
                'OMid': order_part.OMid,
                'OPid': order_part.OPid,
                'UCcommission': up2_base,
                'USid': up2.USid,
                'PRtitle': order_part.PRtitle,
                'SKUpic': order_part.SKUpic,
                'UCstatus': UCstatus,
                'FromUsid': user.USid
            })
            db.session.add(commision_account)
        if up3_base:
            up3_base = self.get_two_float(up3_base)
            user_commision -= up3_base
            current_app.logger.info('三级获得佣金: {}'.format(up3_base))
            commision_account = UserCommission.create({
                'UCid': str(uuid.uuid1()),
                'OMid': order_part.OMid,
                'OPid': order_part.OPid,
                'UCcommission': up3_base,
                'USid': up3.USid,
                'PRtitle': order_part.PRtitle,
                'SKUpic': order_part.SKUpic,
                'UCstatus': UCstatus,
                'FromUsid': user.USid
            })
            db.session.add(commision_account)
        planet_remain = user_commision + planet_commision
        # 优惠券计算
        order_coupon = order_part.order_coupon
        if order_coupon:
            if order_coupon.SUid:
                # commision_for_supplizer -= (Decimal(order_part.OPsubTotal) - Decimal(order_part.OPsubTrueTotal))
                current_app.logger.info(
                    'get commision_for_supplizer {} '.format(
                        commision_for_supplizer))

                commision_sub = (Decimal(order_part.OPsubTotal) -
                                 Decimal(order_part.OPsubTrueTotal))
                current_app.logger.info(
                    'get commision_sub {}'.format(commision_sub))
                if commision_for_supplizer >= commision_sub:
                    desposit = commision_sub
                    commision_for_supplizer -= commision_sub
                else:
                    desposit = commision_for_supplizer
                    commision_for_supplizer = 0
            else:
                planet_remain -= (Decimal(order_part.OPsubTotal) -
                                  Decimal(order_part.OPsubTrueTotal))

        # 供应商获取佣金
        if suid:
            su = Supplizer.query.filter(Supplizer.isdelete == False,
                                        Supplizer.SUid == suid).first()
            current_app.logger.info('get supplizer {}'.format(su))
            if su:
                if desposit:
                    current_app.logger.info('get change {}'.format(desposit))
                    desposit = Decimal(str(desposit))
                    sudeposit = Decimal(str(su.SUdeposit or 0))
                    after_deposit = sudeposit + desposit
                    current_app.logger.info(
                        'start add supplizer deposit before {} change {} after {}'
                        .format(sudeposit, desposit, after_deposit))

                    sdl = SupplizerDepositLog.create({
                        'SDLid':
                        str(uuid.uuid1()),
                        'SUid':
                        su.SUid,
                        'SDLnum':
                        desposit,
                        'SDafter':
                        after_deposit,
                        'SDbefore':
                        sudeposit,
                        'SDLacid':
                        'system',
                        'SDLcontentid':
                        order_part.OPid,
                    })
                    su.SUdeposit = after_deposit
                    db.session.add(sdl)

                commision_account = UserCommission.create({
                    'UCid':
                    str(uuid.uuid1()),
                    'OMid':
                    order_part.OMid,
                    'OPid':
                    order_part.OPid,
                    'UCcommission':
                    commision_for_supplizer,
                    'USid':
                    suid,
                    'CommisionFor':
                    ApplyFrom.supplizer.value,
                    'PRtitle':
                    order_part.PRtitle,
                    'SKUpic':
                    order_part.SKUpic,
                    'UCstatus':
                    UCstatus,
                    'FromUsid':
                    user.USid
                })
                db.session.add(commision_account)
                current_app.logger.info('供应商获取佣金: {}'.format(
                    commision_account.UCcommission))
        else:
            planet_remain += commision_for_supplizer
        # 平台剩余佣金
        commision_account = UserCommission.create({
            'UCid':
            str(uuid.uuid1()),
            'OMid':
            order_part.OMid,
            'OPid':
            order_part.OPid,
            'UCcommission':
            planet_remain,
            'USid':
            '0',
            'CommisionFor':
            ApplyFrom.platform.value,
            'PRtitle':
            order_part.PRtitle,
            'SKUpic':
            order_part.SKUpic,
            'UCstatus':
            UCstatus,
            'FromUsid':
            user.USid
        })
        db.session.add(commision_account)
        current_app.logger.info('平台获取: {}'.format(planet_remain))

    @token_required
    def get_preview_commision(self):
        # 活动佣金即时到账
        usid = request.user.id
        user = User.query.filter(User.isdelete == False,
                                 User.USid == usid).first()
        commision = Commision.query.filter(
            Commision.isdelete == False, ).order_by(
                Commision.createtime.desc()).first()
        level_commision = list(
            map(Decimal, json.loads(commision.Levelcommision)))
        ReduceRatio = list(map(Decimal, json.loads(commision.ReduceRatio)))
        IncreaseRatio = list(map(Decimal, json.loads(commision.IncreaseRatio)))
        level1_commision = self._current_commission(user.USCommission1,
                                                    level_commision[0])
        default_planetcommision = level_commision[-1]
        up1, up2 = user, User.query.filter(
            User.isdelete == False, User.USid == user.USsupper1).first()
        order_price = Decimal()  # 订单实际价格
        info = parameter_required((
            'pbid',
            'skus',
        ))
        pbid = info.get('pbid')
        skus = info.get('skus')
        brand = ProductBrand.query.filter(ProductBrand.PBid == pbid).first()
        supplizer = Supplizer.query.filter(
            Supplizer.SUid == brand.SUid).first()
        up1_bases = Decimal(0)
        for sku in skus:
            # 订单副单
            skuid = sku.get('skuid')
            opnum = int(sku.get('nums', 1))
            assert opnum > 0
            sku_instance = ProductSku.query.filter_by_({
                'SKUid': skuid
            }).first_('skuid: {}不存在'.format(skuid))
            small_total = Decimal(str(sku_instance.SKUprice)) * opnum
            # 订单价格计算
            order_price += small_total
            planet_and_user_rate = self._current_commission(
                sku_instance.SkudevideRate,
                getattr(supplizer, 'SUbaseRate', ''), default_planetcommision)
            planet_and_user_rate = Decimal(planet_and_user_rate) / 100
            # 平台固定抽成
            planet_rate = Decimal(default_planetcommision) / 100
            planet_commision = order_price * planet_rate  # 平台获得, 是总价的的百分比
            user_commision = order_price * planet_and_user_rate - planet_commision  # 用户获得, 是总价 - 平台获得
            # 正常应该获得佣金
            up1_base = up2_base = 0
            if up1 and up1.USlevel > 1:
                user_level1commision = self._current_commission(
                    up1.USCommission1, level1_commision) / 100  # 个人佣金比
                up1_base = user_commision * user_level1commision
                if up2 and up2.USlevel > 1:
                    user_level2commision = self._current_commission(
                        up2.USCommission2, level1_commision) / 100  # 个人佣金比
                    up2_base = user_commision * user_level2commision
                    # 偏移
                    up1_up2 = up1.CommisionLevel - up2.CommisionLevel
                    up1_base, up2_base = self._caculate_offset(
                        up1_up2, up1_base, up2_base, ReduceRatio,
                        IncreaseRatio)
            up1_bases += up1_base
        return Success(data='%.2f' % up1_bases)

    def _caculate_offset(self, low_high, user_low_base, user_hign_base,
                         reduce_ratio, increase_ratio):
        """计算偏移后的佣金"""
        if low_high <= 0:
            return user_low_base, user_hign_base
        low_ratio = Decimal()
        hign_ratio = Decimal('1')
        hign_comm_base_temp = user_hign_base
        # 不限等级。限制偏移上限
        if low_high > 4:
            low_high = 4
        for index in range(low_high):
            hign_comm_base_temp *= hign_ratio  # 本级的基础佣金比
            hign_ratio *= (1 - Decimal(reduce_ratio[index]) / 100)
            low_ratio += (hign_comm_base_temp *
                          Decimal(increase_ratio[index]) / 100)
        return low_ratio + user_low_base, hign_ratio * user_hign_base

    def _pay_detail(self,
                    omclient,
                    opaytype,
                    opayno,
                    mount_price,
                    body,
                    openid='openid'):
        opaytype = int(opaytype)
        omclient = int(omclient)
        body = re.sub("[\s+\.\!\/_,$%^*(+\"\'\-_]+|[+——!,。?、~@#¥%……&*()]+", '',
                      body)
        mount_price = 0.01 if API_HOST != 'https://www.bigxingxing.com' else mount_price
        current_app.logger.info('openid is {}, out_trade_no is {} '.format(
            openid, opayno))
        # 微信支付的单位是'分', 支付宝使用的单位是'元'
        if opaytype == PayType.wechat_pay.value:
            try:
                body = body[:16] + '...'
                current_app.logger.info('body is {}, wechatpay'.format(body))
                wechat_pay_dict = {
                    'body': body,
                    'out_trade_no': opayno,
                    'total_fee': int(mount_price * 100),
                    'attach': 'attach',
                    'spbill_create_ip': request.remote_addr
                }

                if omclient == Client.wechat.value:  # 微信客户端
                    if not openid:
                        raise StatusError('用户未使用微信登录')
                    # wechat_pay_dict.update(dict(trade_type="JSAPI", openid=openid))
                    wechat_pay_dict.update({
                        'trade_type': 'JSAPI',
                        'openid': openid
                    })
                    raw = self.wx_pay.jsapi(**wechat_pay_dict)
                else:
                    wechat_pay_dict.update({'trade_type': "APP"})
                    raw = self.wx_pay.unified_order(**wechat_pay_dict)
            except WeixinPayError as e:
                raise SystemError('微信支付异常: {}'.format('.'.join(e.args)))

        elif opaytype == PayType.alipay.value:
            current_app.logger.info('body is {}, alipay'.format(body))
            if omclient == Client.wechat.value:
                raise SystemError('请选用其他支付方式')
            else:
                try:
                    raw = self.alipay.api_alipay_trade_app_pay(
                        out_trade_no=opayno,
                        total_amount=mount_price,
                        subject=body[:66] + '...',
                    )
                except Exception:
                    raise SystemError('支付宝参数异常')
        elif opaytype == PayType.test_pay.value:
            raw = self.alipay.api_alipay_trade_page_pay(
                out_trade_no=opayno,
                total_amount=mount_price,
                subject=body[10],
            )
            raw = 'https://openapi.alipaydev.com/gateway.do?' + raw
        else:
            raise SystemError('请选用其他支付方式')
        current_app.logger.info('pay response is {}'.format(raw))
        return raw

    def _integralpay(self, data, usid):
        """星币支付"""
        with db.auto_commit():
            model_bean = list()
            omid, omtruemount = data.get('omid'), data.get('omtruemount')
            uspaycode = data.get('uspaycode')
            order_main = OrderMain.query.filter_by_({
                'OMid':
                omid,
                'USid':
                usid,
                'OMstatus':
                OrderMainStatus.wait_pay.value,
                'OMfrom':
                OrderFrom.integral_store.value,
                'OMtrueMount':
                omtruemount
            }).first_('订单信息错误')
            user = User.query.filter(User.USid == usid,
                                     User.isdelete == False).first_("请重新登录")
            if not user.USpaycode:
                raise ParamsError('请在 “我的 - 安全中心” 设置支付密码后重试')
            if not (uspaycode
                    and check_password_hash(user.USpaycode, uspaycode)):
                raise ParamsError('请输入正确的支付密码')
            # 增加星币消费记录
            userintegral_dict = UserIntegral.create({
                'UIid':
                str(uuid.uuid1()),
                'USid':
                user.USid,
                'UIintegral':
                order_main.OMtrueMount,
                'UIaction':
                UserIntegralAction.consumption.value,
                'UItype':
                UserIntegralType.expenditure.value,
                'OPayno':
                order_main.OPayno
            })
            model_bean.append(userintegral_dict)
            # 扣除用户积分
            if user.USintegral < omtruemount:
                raise PoorScore('用户星币余额不足')
            user.update({
                'USintegral':
                int(user.USintegral) - int(order_main.OMtrueMount)
            })
            model_bean.append(user)
            # 更改订单状态
            order_main.update({'OMstatus': OrderMainStatus.wait_send.value})
            model_bean.append(order_main)
            db.session.add_all(model_bean)
        return Success('支付成功', dict(omid=omid))

    def _pay_to_user(self, cn):
        """
        付款到用户微信零钱
        :return:
        """
        user = User.query.filter_by_(USid=cn.USid).first_("提现用户状态异常,请检查后重试")
        try:
            result = self.wx_pay.pay_individual(
                partner_trade_no=self.wx_pay.nonce_str,
                openid=user.USopenid2,
                amount=int(
                    Decimal(cn.CNcashNum).quantize(Decimal('0.00')) * 100),
                desc="大行星零钱转出",
                spbill_create_ip=self.wx_pay.remote_addr)
            current_app.logger.info('微信提现到零钱, response: {}'.format(request))
        except Exception as e:
            current_app.logger.error('微信提现返回错误:{}'.format(e))
            raise StatusError('微信商户平台: {}'.format(e))
        return result

    def _pay_to_bankcard(self, cn):
        """
        付款到银行卡号
        :param cn:
        :return:
        """
        try:
            enc_bank_no = self._to_encrypt(cn.CNcardNo)
            enc_true_name = self._to_encrypt(cn.CNcardName)
            bank_code = WexinBankCode(cn.CNbankName).zh_value
        except Exception as e:
            current_app.logger.error('提现到银行卡,参数加密出错:{}'.format(e))
            raise ParamsError('服务器繁忙,请稍后再试')

        try:
            result = self.wx_pay.pay_individual_to_card(
                partner_trade_no=self.wx_pay.nonce_str,
                enc_bank_no=enc_bank_no,
                enc_true_name=enc_true_name,
                bank_code=bank_code,
                amount=int(
                    Decimal(cn.CNcashNum).quantize(Decimal('0.00')) * 100))
            current_app.logger.info('微信提现到银行卡, response: {}'.format(request))
        except Exception as e:
            current_app.logger.error('微信提现返回错误:{}'.format(e))
            raise StatusError('微信商户平台: {}'.format(e))
        return result

    def _to_encrypt(self, message):
        """银行卡信息加密"""
        from planet.config.secret import apiclient_public
        import base64
        from Cryptodome.PublicKey import RSA
        from Cryptodome.Cipher import PKCS1_OAEP

        with open(apiclient_public, 'r') as f:
            # pubkey = rsa.PublicKey.load_pkcs1(f.read().encode())
            pubkey = f.read()
            rsa_key = RSA.importKey(pubkey)
            # crypto = rsa.encrypt(message.encode(), pubkey)
            cipher = PKCS1_OAEP.new(rsa_key)
            crypto = cipher.encrypt(message.encode())
        return base64.b64encode(crypto).decode()

    @staticmethod
    def _generic_omno():
        """生成订单号"""
        return str(time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))) + \
               str(time.time()).replace('.', '')[-7:] + str(random.randint(1000, 9999))

    @staticmethod
    def _current_commission(*args):
        for comm in args:
            if comm is not None:
                return comm
        return 0

    def _check_upgrade_gift(self, prid_list):
        return Items.query.join(ProductItems,
                                Items.ITid == ProductItems.ITid).filter(
                                    Items.isdelete == False,
                                    ProductItems.isdelete == False,
                                    Items.ITid == 'upgrade_product',
                                    ProductItems.PRid.in_(prid_list),
                                ).first()

    @staticmethod
    def get_two_float(f_str, n=2):
        f_str = str(f_str)
        a, b, c = f_str.partition('.')
        c = (c + "0" * n)[:n]
        return Decimal(".".join([a, c]))
예제 #9
0
class CRefund(object):
    def __init__(self):
        self.strade = STrade()

    @token_required
    def create(self):
        data = parameter_required(('orareason', 'oraproductstatus'))
        opid = data.get('opid')
        omid = data.get('omid')
        if opid and omid:
            raise ParamsError('omid,opid只能存在一个')
        usid = request.user.id
        if opid:
            # 单个商品售后
            self._order_part_refund(opid, usid, data)
        elif omid:
            # 主单售后
            self._order_main_refund(omid, usid, data)
        else:
            raise ParamsError('须指定主单或副单')
        return Success('申请成功, 等待答复')

    @token_required
    def cancle(self):
        """撤销"""
        data = parameter_required(('oraid', ))
        oraid = data.get('oraid')
        with db.auto_commit():
            order_refund_apply = OrderRefundApply.query.filter_by({
                'isdelete':
                False,
                'ORAid':
                oraid,
                "USid":
                request.user.id,
                'ORAstatus':
                ApplyStatus.wait_check.value
            }).first_('售后已处理')

            order_refund_apply.update({'ORAstatus': ApplyStatus.cancle.value})
            db.session.add(order_refund_apply)
            # 修改主单或副单售后状态
            if order_refund_apply.OPid:
                OrderPart.query.filter_by({
                    'OPid': order_refund_apply.OPid
                }).update({'OPisinORA': False})
            if order_refund_apply.OMid:
                OrderMain.query.filter_by({
                    'OMid': order_refund_apply.OMid
                }).update({"OMinRefund": False})
            # 对应退货流水表改为已取消
            OrderRefund.query.filter(OrderRefund.ORAid == oraid,
                                     OrderRefund.isdelete == False).update({
                                         'ORstatus':
                                         OrderRefundOrstatus.cancle.value
                                     })
        return Success('撤销成功')

    @token_required
    def create_dispute_type(self):
        """添加内置纠纷类型"""
        data = parameter_required(('diname', 'ditype', 'disort'))
        diname = data.get('diname')
        ditype = data.get('ditype')
        try:
            DisputeTypeType(ditype)
            disort = int(data.get('disort'))
        except Exception as e:
            raise ParamsError('ditype错误')
        with self.strade.auto_commit() as s:
            diid = str(uuid.uuid1())
            dispute_type_dict = {
                'DIid': diid,
                'DIname': diname,
                'DItype': ditype,
                'DIsort': disort
            }
            dispute_type_instance = DisputeType.create(dispute_type_dict)
            s.add(dispute_type_instance)
        return Success('创建成功', data={'diid': diid})

    def list_dispute_type(self):
        """获取纠纷类型"""
        data = parameter_required()
        ditype = data.get('type') or None
        order_refund_types = DisputeType.query.filter_by_({
            'DItype': ditype
        }).order_by(DisputeType.DIsort).all()
        return Success(data=order_refund_types)

    @token_required
    def agree_apply(self):
        """同意退款"""
        data = parameter_required(('oraid', 'agree'))
        oraid = data.get('oraid')
        agree = data.get('agree')
        with self.strade.auto_commit() as s:
            s_list = []
            refund_apply_instance = s.query(OrderRefundApply).filter_by_({
                'ORAid':
                oraid,
                'ORAstatus':
                ApplyStatus.wait_check.value
            }).first_('申请已处理或不存在')
            refund_apply_instance.ORAcheckTime = datetime.now()
            # 获取订单
            if refund_apply_instance.OMid:
                order_main_instance = s.query(OrderMain).filter_by({
                    'OMid':
                    refund_apply_instance.OMid
                }).first()
            else:
                order_part_instance = s.query(OrderPart).filter(
                    OrderPart.OPid == refund_apply_instance.OPid).first()
                order_main_instance = s.query(OrderMain).filter_by({
                    'OMid':
                    order_part_instance.OMid
                }).first()
            if agree is True:
                refund_apply_instance.ORAstatus = ApplyStatus.agree.value
                if refund_apply_instance.ORAstate == OrderRefundORAstate.only_money.value:  # 仅退款
                    # 退款流水表
                    order_pay_instance = s.query(OrderPay).filter(
                        OrderPay.isdelete == False,
                        OrderPay.OPayno == order_main_instance.OPayno).first()
                    refund_flow_instance = OrderRefundFlow.create({
                        'ORFid':
                        str(uuid.uuid1()),
                        'ORAid':
                        oraid,
                        'ORAmount':
                        refund_apply_instance.ORAmount,
                        'OPayno':
                        order_main_instance.OPayno,
                        'OPayType':
                        order_pay_instance.OPayType,
                    })
                    s_list.append(refund_flow_instance)
                    mount = refund_apply_instance.ORAmount  # todo 退款金额需要改正
                    old_total_fee = order_pay_instance.OPayMount
                    if API_HOST == 'https://test.bigxingxing.com':
                        mount = 0.01
                        old_total_fee = 0.01
                    current_app.logger.info('正在退款中 {} '.format(
                        refund_apply_instance.ORAmount))

                    self._refund_to_user(  # 执行退款, 待测试
                        out_trade_no=order_main_instance.OPayno,
                        out_request_no=oraid,
                        mount=mount,
                        opaytype=order_pay_instance.OPayType,
                        old_total_fee=old_total_fee)
                    msg = '已同意, 正在退款'
                    # 佣金退
                    if refund_apply_instance.OPid:
                        self._cancle_commision(order_part=order_part_instance)
                    if refund_apply_instance.OMid:
                        self._cancle_commision(order_main=order_main_instance)

                    # 减少商品相应销量
                    refund_order_parts = OrderPart.query.filter(
                        OrderPart.OMid == order_main_instance.OMid,
                        OrderPart.isdelete == False).all()
                    current_app.logger.info('退款的副单数有{}个'.format(
                        len(refund_order_parts)))
                    for reop in refund_order_parts:
                        res = Products.query.filter_by(PRid=reop.PRid).update({
                            'PRsalesValue':
                            Products.PRsalesValue - reop.OPnum
                        })
                        if res:
                            current_app.logger.info('退货商品id{} 销量减少{}'.format(
                                reop.PRid, reop.OPnum))
                        # 月销量更新
                        ProductMonthSaleValue.query.filter(
                            ProductMonthSaleValue.PRid == reop.PRid,
                            ProductMonthSaleValue.isdelete == False,
                            extract('year', ProductMonthSaleValue.createtime)
                            == reop.createtime.year,
                            extract('month', ProductMonthSaleValue.createtime)
                            == reop.createtime.month,
                        ).update(
                            {
                                'PMSVnum':
                                ProductMonthSaleValue.PMSVnum - reop.OPnum,
                            },
                            synchronize_session=False)

                if refund_apply_instance.ORAstate == OrderRefundORAstate.goods_money.value:  # 退货退款
                    # 取消原来的退货表, (主要是因为因为可能因撤销为未完全删除)
                    old_order_refund = OrderRefund.query.filter(
                        OrderRefund.isdelete == False,
                        OrderRefund.ORAid == oraid).update(
                            {'ORstatus': OrderRefundOrstatus.cancle.value})
                    # 写入退换货表
                    orrecvname = data.get('orrecvname')
                    orrecvphone = validate_arg('^1\d{10}$',
                                               data.get('orrecvphone', ''),
                                               '输入合法的手机号码')
                    orrecvaddress = data.get('orrecvaddress')
                    try:
                        assert orrecvname and orrecvphone and orrecvaddress
                    except Exception as e:
                        raise ParamsError('请填写必要的收货信息')

                    order_refund_dict = {
                        'ORid': str(uuid.uuid1()),
                        'OMid': refund_apply_instance.OMid,
                        'OPid': refund_apply_instance.OPid,
                        'ORAid': oraid,
                        'ORrecvname': orrecvname,
                        'ORrecvphone': orrecvphone,
                        'ORrecvaddress': orrecvaddress,
                    }
                    order_refund_instance = OrderRefund.create(
                        order_refund_dict)
                    s_list.append(order_refund_instance)
                    msg = '已同意, 等待买家发货'
                refund_apply_instance.ORAstatus = ApplyStatus.agree.value
            else:
                refund_apply_instance.ORAstatus = ApplyStatus.reject.value
                if refund_apply_instance.OMid:
                    order_main_instance.OMinRefund = False
                    db.session.add(order_main_instance)
                    db.session.add(
                        OrderRefundNotes.create({
                            'ORNid':
                            str(uuid.uuid1()),
                            'OMid':
                            refund_apply_instance.OMid,
                            'UserName':
                            request.user.username,
                            'USid':
                            request.user.id,
                            'ORNaction':
                            -1,  # 拒绝
                            'ORNabo':
                            data.get('oracheckreason')
                        }))
                else:
                    order_part_instance.OPisinORA = False
                    db.session.add(order_part_instance)
                    db.session.add(
                        OrderRefundNotes.create({
                            'ORNid':
                            str(uuid.uuid1()),
                            'OPid':
                            order_part_instance.OPid,
                            'UserName':
                            request.user.username,
                            'USid':
                            request.user.id,
                            'ORNaction':
                            -1,  # 拒绝
                            'ORNabo':
                            data.get('oracheckreason')
                        }))
                msg = '拒绝成功'
            refund_apply_instance.ORAcheckReason = data.get('oracheckreason')
            refund_apply_instance.ORAcheckTime = datetime.now()
            refund_apply_instance.ORAcheckUser = request.user.id
            s_list.append(refund_apply_instance)
            s.add_all(s_list)
        return Success(msg)

    @token_required
    def back_confirm_refund(self):
        """执行退款退款中的最后一步, 退款"""
        form = RefundConfirmForm().valid_data()
        oraid = form.oraid.data
        agree = form.agree.data
        with db.auto_commit():
            refund_apply_instance = OrderRefundApply.query.filter(
                OrderRefundApply.isdelete == False,
                OrderRefundApply.ORAid == oraid,
                OrderRefundApply.ORAstatus == ApplyStatus.agree.value,
                OrderRefundApply.ORAstate ==
                OrderRefundORAstate.goods_money.value).first_('对应的退货申请不存在或未同意')

            if refund_apply_instance.OMid:
                order_main_instance = OrderMain.query.filter_by({
                    'OMid':
                    refund_apply_instance.OMid
                }).first()
            else:
                order_part_instance = OrderPart.query.filter(
                    OrderPart.OPid == refund_apply_instance.OPid).first()
                order_main_instance = OrderMain.query.filter_by({
                    'OMid':
                    order_part_instance.OMid
                }).first()
            order_refund = OrderRefund.query.filter(
                OrderRefund.isdelete == False,
                OrderRefund.ORstatus ==
                OrderRefundOrstatus.ready_recv.value,  # 确认收货后执行退款
                OrderRefund.ORAid == oraid).first_('请确认收货后退款')
            if agree is True:
                order_pay_instance = OrderPay.query.filter(
                    OrderPay.isdelete == False,
                    OrderPay.OPayno == order_main_instance.OPayno).first()
                order_refund.ORstatus = OrderRefundOrstatus.ready_refund.value
                db.session.add(order_refund)
                # TODO 执行退款
                mount = refund_apply_instance.ORAmount  # todo 退款金额需要改正
                old_total_fee = order_pay_instance.OPayMount
                refund_flow_instance = OrderRefundFlow.create({
                    'ORFid':
                    str(uuid.uuid1()),
                    'ORAid':
                    oraid,
                    'ORAmount':
                    refund_apply_instance.ORAmount,
                    'OPayno':
                    order_main_instance.OPayno,
                    'OPayType':
                    order_pay_instance.OPayType,
                })
                db.session.add(refund_flow_instance)
                if API_HOST == 'https://test.bigxingxing.com':
                    mount = 0.01
                    old_total_fee = 0.01
                self._refund_to_user(  # 执行退款, 待测试
                    out_trade_no=order_main_instance.OPayno,
                    out_request_no=oraid,
                    mount=mount,
                    opaytype=order_pay_instance.OPayType,
                    old_total_fee=old_total_fee)
                msg = '已同意, 正在退款'

                # 减去对应商品的销量
                refund_order_parts = OrderPart.query.filter(
                    OrderPart.OMid == order_main_instance.OMid,
                    OrderPart.isdelete == False).all()
                current_app.logger.info('退货退款的副单数有{}个'.format(
                    len(refund_order_parts)))
                for reop in refund_order_parts:
                    res = Products.query.filter_by(PRid=reop.PRid).update(
                        {'PRsalesValue': Products.PRsalesValue - reop.OPnum})
                    if res:
                        current_app.logger.info('退货商品id{} 销量减少{}'.format(
                            reop.PRid, reop.OPnum))
                    # 月销量更新
                    ProductMonthSaleValue.query.filter(
                        ProductMonthSaleValue.PRid == reop.PRid,
                        ProductMonthSaleValue.isdelete == False,
                        extract('year', ProductMonthSaleValue.createtime) ==
                        reop.createtime.year,
                        extract('month', ProductMonthSaleValue.createtime) ==
                        reop.createtime.month,
                    ).update(
                        {
                            'PMSVnum':
                            ProductMonthSaleValue.PMSVnum - reop.OPnum,
                        },
                        synchronize_session=False)

            elif agree is False:
                order_refund.ORstatus = OrderRefundOrstatus.reject.value
                db.session.add(order_refund)
                msg = '已拒绝'
            else:
                raise ParamsError('agree 参数错误')
        return Success(msg)

    @token_required
    def back_confirm_recv(self):
        """后台确认收货"""
        form = RefundConfirmRecvForm().valid_data()
        oraid = form.oraid.data
        with db.auto_commit():
            OrderRefundApply.query.filter(
                OrderRefundApply.isdelete == False,
                OrderRefundApply.ORAid == oraid,
                OrderRefundApply.ORAstatus == ApplyStatus.agree.value,
                OrderRefundApply.ORAstate ==
                OrderRefundORAstate.goods_money.value).first_('对应的退货申请不存在或未同意')
            order_refund = OrderRefund.query.filter(
                OrderRefund.isdelete == False,
                OrderRefund.ORstatus >=
                OrderRefundOrstatus.wait_recv.value,  # 确认收货后执行退款
                OrderRefund.ORAid == oraid).first_('未发货')
            order_refund.ORstatus = OrderRefundOrstatus.ready_recv.value
            db.session.add(order_refund)
            msg = '已收货'
        return Success(msg)

    @token_required
    def send(self):
        """买家发货"""
        form = RefundSendForm().valid_data()
        oraid = form.oraid.data
        orlogisticcompany = form.orlogisticcompany.data
        orlogisticsn = form.orlogisticsn.data
        with self.strade.auto_commit() as s:
            # 判断
            s.query(LogisticsCompnay).filter_by_({
                'LCcode': orlogisticcompany
            }).first_('物流公司不存在')
            order_refund_instance = s.query(OrderRefund).filter_by_({
                'ORAid':
                oraid
            }).first_('申请未同意或不存在')
            if order_refund_instance.ORstatus > OrderRefundOrstatus.wait_send.value:
                raise StatusError('重复发货')
            # 写入退货表
            order_refund_instance.update({
                'ORlogisticCompany':
                orlogisticcompany,
                'ORlogisticsn':
                orlogisticsn,
                'ORstatus':
                OrderRefundOrstatus.wait_recv.value,
            })
            s.add(order_refund_instance)
        return Success('发货成功')

    @token_required
    def refund_query(self):
        """查询退款结果"""
        # todo 查询退款结果

    @staticmethod
    def _generic_no():
        """生成退款号"""
        return str(time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))) + \
               str(time.time()).replace('.', '')[-7:] + str(random.randint(1000, 9999))

    def _order_part_refund(self, opid, usid, data):
        with self.strade.auto_commit() as s:
            s_list = []
            # 副单
            order_part = s.query(OrderPart).filter(
                OrderPart.OPid == opid,
                OrderPart.isdelete == False).first_('不存在的订单详情')
            # 删除原来的
            OrderRefundNotes.query.filter(
                OrderRefundNotes.isdelete == False,
                OrderRefundNotes.OPid == order_part.OPid).delete_()
            # 所在主单的副单个数
            order_part_count = OrderPart.query.filter_by_({
                'OMid':
                order_part.OMid
            }).count()
            current_app.logger.info(
                '当前副单所在主单有 {} 个商品'.format(order_part_count))
            if order_part_count == 1:
                # 如果只有一个副单, 则改为申请主单售后
                current_app.logger.info('改为主单售后')
                return self._order_main_refund(order_part.OMid, usid, data)

            # 副单售后
            if order_part.OPisinORA is True:
                cancled_apply = OrderRefundApply.query.filter_by_({
                    'ORAstatus':
                    ApplyStatus.cancle.value,
                    'OPid':
                    opid
                }).first()
                if not cancled_apply:
                    raise DumpliError('重复申请')
                # 删除之前已经撤销的售后
                cancled_apply.isdelete = True
                s_list.append(cancled_apply)
            # 主单售后状态
            omid = order_part.OMid
            order_main = s.query(OrderMain).filter_(
                OrderMain.OMid == omid,
                OrderMain.OMstatus.notin_([
                    OrderMainStatus.wait_pay.value,
                    OrderMainStatus.cancle.value,
                    OrderMainStatus.ready.value,
                ]), OrderMain.USid == usid).first_('不存在的订单')
            if order_main.OMinRefund == True:
                raise DumpliError('主订单已在售后中, 请勿重复申请')
            apply = OrderRefundApply.query.filter(
                OrderRefundApply.OPid == opid,
                OrderRefundApply.isdelete == False, OrderRefundApply.ORAstatus
                != ApplyStatus.reject.value).first()
            if apply and apply.ORAstatus != ApplyStatus.cancle.value:
                raise DumpliError('订单已在售后中, 请勿重复申请')
            elif apply:
                current_app.logger.info('删除原来副单售后申请')
                apply.isdelete = True
                s_list.append(apply)
            # 不改变主单的状态
            # order_main.OMinRefund = True  # 主单状态
            # s_list.append(order_main)

            order_part.OPisinORA = True  # 附单状态
            s_list.append(order_part)
            # 申请参数校验
            oraproductstatus = data.get('oraproductstatus')
            ORAproductStatus(oraproductstatus)
            oramount = data.get('oramount')
            if oramount:
                oramount = Decimal(str((oramount)))
            if not oramount or oramount > order_part.OPsubTrueTotal:
                raise ParamsError('退款金额不正确')
            oraddtionvoucher = data.get('oraddtionvoucher')
            if oraddtionvoucher and isinstance(oraddtionvoucher, list):
                oraddtionvoucher = oraddtionvoucher
            else:
                oraddtionvoucher = None
            oraaddtion = data.get('oraaddtion')
            orastate = data.get('orastate',
                                OrderRefundORAstate.goods_money.value)
            try:
                OrderRefundORAstate(orastate)
            except Exception as e:
                raise ParamsError('orastate参数错误')
            # 添加申请表
            order_refund_apply_dict = {
                'ORAid': str(uuid.uuid1()),
                # 'OMid': omid,
                'ORAsn': self._generic_no(),
                'OPid': opid,
                'USid': usid,
                'ORAmount': oramount,
                'ORaddtionVoucher': oraddtionvoucher,
                'ORAaddtion': oraaddtion,
                'ORAreason': data.get('orareason'),
                'ORAproductStatus': oraproductstatus,
                'ORAstate': orastate,
            }
            order_refund_apply_instance = OrderRefundApply.create(
                order_refund_apply_dict)
            s_list.append(order_refund_apply_instance)
            s.add_all(s_list)
            current_app.logger.info(
                'the order_part refund apply id(oraid) is {}'.format(
                    order_refund_apply_dict['ORAid']))

    def _order_main_refund(self, omid, usid, data):
        with self.strade.auto_commit() as s:
            s_list = []
            OrderRefundNotes.query.filter(
                OrderRefundNotes.isdelete == False,
                OrderRefundNotes.OMid == omid).delete_()
            order_main = s.query(OrderMain).filter_(
                OrderMain.OMid == omid,
                OrderMain.OMstatus.notin_([
                    OrderMainStatus.wait_pay.value,
                    OrderMainStatus.cancle.value,
                    OrderMainStatus.ready.value,
                ]), OrderMain.USid == usid).first_('不存在的订单')
            if order_main.OMinRefund is True:
                raise DumpliError('已经在售后中')
            # 之前的申请
            apply = OrderRefundApply.query.filter(
                OrderRefundApply.isdelete == False,
                OrderRefundApply.OMid == order_main.OMid,
                OrderRefundApply.ORAstatus.notin_([
                    ApplyStatus.reject.value,
                    ApplyStatus.cancle.value,
                ]),
            ).first()
            if apply:
                raise DumpliError('订单已在售后中, 请勿重复申请')
            if apply:
                apply.isdelete = True
                s_list.append(apply)
            # 申请主单售后, 所有的副单不可以有在未撤销的售后状态或未被拒绝
            order_parts_in_refund = OrderPart.query.filter_by_({
                'OMid':
                omid,
                'OPisinORA':
                True
            }).all()
            for order_part in order_parts_in_refund:
                part_apply = OrderRefundApply.query.filter_by_({
                    'OPid':
                    order_part.OPid
                }).first()
                # if not cancled_apply:
                #     raise DumpliError('订单中有商品已在售后中, 请勿重复申请')
                if part_apply and part_apply.ORAstatus != ApplyStatus.cancle.value:
                    raise DumpliError('订单中有商品已在售后中, 请勿重复申请')
                elif part_apply:
                    part_apply.isdelete = True
                    s_list.append(part_apply)
            order_main.OMinRefund = True  # 主单状态
            s_list.append(order_main)
            # 申请参数校验
            oraproductstatus = int(data.get('oraproductstatus'))  # 是否已经收到货
            ORAproductStatus(oraproductstatus)

            orastate = int(
                data.get('orastate', OrderRefundORAstate.goods_money.value))
            try:
                OrderRefundORAstate(orastate)
            except Exception as e:
                raise ParamsError('orastate参数错误')
            oramount = data.get('oramount')
            if oramount:
                oramount = Decimal(str(oramount))
            if not oramount or oramount > order_main.OMtrueMount:
                raise ParamsError('oramount退款金额不正确')
            # 不改变副单的状态
            # order_parts = s.query(OrderPart).filter_by_({'OMid': omid}).all()
            # for order_part in order_parts:
            #     order_part.OPisinORA = True  # 附单状态
            #     s_list.append(order_part)
            # 添加申请表
            oraddtionvoucher = data.get('oraddtionvoucher')
            oraaddtion = data.get('oraaddtion')
            order_refund_apply_dict = {
                'ORAid': str(uuid.uuid1()),
                'OMid': omid,
                'ORAsn': self._generic_no(),
                'USid': usid,
                'ORAmount': oramount,
                'ORaddtionVoucher': oraddtionvoucher,
                'ORAaddtion': oraaddtion,
                'ORAreason': data.get('orareason'),
                'ORAproductStatus': oraproductstatus,
                'ORAstate': orastate,
            }
            order_refund_apply_instance = OrderRefundApply.create(
                order_refund_apply_dict)
            s_list.append(order_refund_apply_instance)
            s.add_all(s_list)
            current_app.logger.info(
                'the order_main refund apply id(oraid) is {}'.format(
                    order_refund_apply_dict['ORAid']))

    def _refund_to_user(self,
                        out_trade_no,
                        out_request_no,
                        mount,
                        opaytype,
                        old_total_fee=None):
        """
        执行退款
        mount 单位元
        old_total_fee 单位元
        out_request_no
        :return:
        """
        if opaytype == PayType.wechat_pay.value:  # 微信
            mount = int(mount * 100)
            old_total_fee = int(Decimal(str(old_total_fee)) * 100)
            current_app.logger.info(
                'the total fee to refund cent is {}'.format(mount))
            result = wx_pay.refund(
                out_trade_no=out_trade_no,
                out_refund_no=out_request_no,
                total_fee=old_total_fee,  # 原支付的金额
                refund_fee=mount  # 退款的金额
            )

        else:  # 支付宝
            result = alipay.api_alipay_trade_refund(
                out_trade_no=out_trade_no,
                out_request_no=out_request_no,
                refund_amount=mount)
            if result["code"] != "10000":
                raise ApiError('退款错误')
        return result

    def _cancle_commision(self, *args, **kwargs):
        order_main = kwargs.get('order_main')
        order_part = kwargs.get('order_part')
        if order_main:
            if order_main.OMfrom == OrderFrom.fresh_man.value:
                user_commision = UserCommission.query.filter(
                    UserCommission.OMid == order_main.OMid,
                    UserCommission.isdelete == False).first()
                if user_commision:
                    current_app.logger.info(
                        '检测到有新人首单退货。订单id是 {}, 用户id是 {}'.format(
                            order_main.OMid, user_commision.USid))
                    fresh_man_join_count = FreshManJoinFlow.query.filter(
                        FreshManJoinFlow.isdelete == False,
                        FreshManJoinFlow.UPid == user_commision.USid,
                        FreshManJoinFlow.OMid == OrderMain.OMid,
                        OrderMain.OMstatus >= OrderMainStatus.wait_send.value,
                        OrderMain.OMinRefund == False,
                        OrderMain.isdelete == False).count()

                    current_app.logger.info(
                        '当前用户已分享的有效新人首单商品订单有 {}'.format(fresh_man_join_count))
                    # 获取其前三个有效的新人首单
                    fresh_man_join_all = FreshManJoinFlow.query.filter(
                        FreshManJoinFlow.isdelete == False,
                        FreshManJoinFlow.UPid == user_commision.USid,
                        FreshManJoinFlow.OMid == OrderMain.OMid,
                        OrderMain.OMstatus >= OrderMainStatus.wait_send.value,
                        OrderMain.OMinRefund == False,
                        OrderMain.isdelete == False).order_by(
                            FreshManJoinFlow.createtime.asc()).limit(3)

                    # 邀请人新品佣金修改
                    user_order_main = OrderMain.query.filter(
                        OrderMain.isdelete == False,
                        OrderMain.USid == user_commision.USid,
                        OrderMain.OMfrom == OrderFrom.fresh_man.value,
                        OrderMain.OMstatus > OrderMainStatus.wait_pay.value,
                    ).first()
                    user_fresh_order_price = user_order_main.OMtrueMount
                    first = 20
                    second = 30
                    third = 50
                    commissions = 0

                    if fresh_man_join_all:
                        for fresh_man_count, fresh_man in enumerate(
                                fresh_man_join_all, start=1):
                            fresh_man = fresh_man.to_dict()
                            if commissions < user_fresh_order_price:
                                reward = fresh_man['OMprice']
                                if fresh_man_count == 1:
                                    reward = reward * (first / 100)
                                elif fresh_man_count == 2:
                                    reward = reward * (second / 100)
                                elif fresh_man_count == 3:
                                    reward = reward * (third / 100)
                                else:
                                    break
                                if reward + commissions > user_fresh_order_price:
                                    reward = user_fresh_order_price - commissions
                                if reward:
                                    if fresh_man_count <= 2:
                                        UserCommission.query.filter(
                                            UserCommission.isdelete == False,
                                            UserCommission.USid ==
                                            fresh_man['UPid'],
                                            UserCommission.OMid ==
                                            fresh_man['OMid'],
                                            UserCommission.UCstatus ==
                                            UserCommissionStatus.preview.value
                                        ).update({'UCcommission': reward})
                                    else:
                                        user_main_order = OrderMain.query.filter(
                                            OrderMain.isdelete == False,
                                            OrderMain.OMid ==
                                            fresh_man['OMid'],
                                        ).first()
                                        user_main_order = user_main_order.to_dict(
                                        )
                                        user_order_status = user_main_order[
                                            'OMstatus']
                                        if user_order_status == OrderMainStatus.ready.value:
                                            status = UserCommissionStatus.in_account.value
                                        else:
                                            status = UserCommissionStatus.preview.value
                                        user_commision_dict = {
                                            'UCid':
                                            str(uuid.uuid1()),
                                            'OMid':
                                            user_main_order['OMid'],
                                            'UCcommission':
                                            reward,
                                            'USid':
                                            user_main_order['USid'],
                                            'UCtype':
                                            UserCommissionType.fresh_man.value,
                                            'UCstatus':
                                            status
                                        }
                                        db.session.add(
                                            UserCommission.create(
                                                user_commision_dict))
                UserCommission.query.filter(
                    UserCommission.isdelete == False,
                    UserCommission.USid == order_main.USid,
                    UserCommission.UCtype ==
                    UserCommissionType.fresh_man.value, UserCommission.UCstatus
                    == UserCommissionStatus.preview).update({
                        'UCcommission': 0,
                        'isdelete': True
                    })
                return

            order_parts = OrderPart.query.filter(
                OrderPart.isdelete == False,
                OrderPart.OMid == order_main.OMid).all()
            for order_part in order_parts:
                self._cancle_commision(order_part=order_part)

        # 如果是分享者
        elif order_part:
            user_commision = UserCommission.query.filter(
                UserCommission.isdelete == False,
                UserCommission.OPid == order_part.OPid, UserCommission.UCstatus
                == UserCommissionStatus.preview.value).update(
                    {'UCstatus': UserCommissionStatus.error.value})
            current_app.logger.info(
                '失效了{}个佣金到账(包括供应商到账, 平台到账)'.format(user_commision))


# todo 售后物流
예제 #10
0
class CPay():
    def __init__(self):
        self.strade = STrade()
        self.suser = SUser()
        self.alipay = alipay
        self.wx_pay = wx_pay

    @token_required
    def pay(self):
        """订单发起支付"""
        data = parameter_required(('omid', ))
        omid = data.get('omid')
        usid = request.user.id
        try:
            omclient = int(data.get('omclient',
                                    Client.wechat.value))  # 客户端(app或者微信)
            Client(omclient)
            opaytype = int(data.get('opaytype',
                                    PayType.wechat_pay.value))  # 付款方式
            PayType(opaytype)
        except ValueError as e:
            raise e
        except Exception as e:
            raise ParamsError('客户端或支付方式类型错误')
        from planet.control.CUser import CUser
        cuser = CUser()
        with db.auto_commit():
            opayno = self.wx_pay.nonce_str
            order_main = OrderMain.query.filter_by_({
                'OMid':
                omid,
                'USid':
                usid,
                'OMstatus':
                OrderMainStatus.wait_pay.value
            }).first_('不存在的订单')
            # 原支付流水删除
            OrderPay.query.filter_by({'OPayno': order_main.OPayno}).delete_()
            # 更改订单支付编号
            order_main.OPayno = opayno
            # 判断订单是否是开店大礼包
            # 是否是开店大礼包
            if order_main.OMlogisticType == OMlogisticTypeEnum.online.value:
                cuser = CUser()
                cuser._check_gift_order('重复购买开店大礼包')
            db.session.add(order_main)
            # 新建支付流水
            order_pay_instance = OrderPay.create({
                'OPayid':
                str(uuid.uuid1()),
                'OPayno':
                opayno,
                'OPayType':
                opaytype,
                'OPayMount':
                order_main.OMtrueMount
            })
            # 付款时候的body信息
            order_parts = OrderPart.query.filter_by_({'OMid': omid}).all()
            body = ''.join([getattr(x, 'PRtitle', '') for x in order_parts])
            db.session.add(order_pay_instance)
        user = User.query.filter(User.USid == order_main.USid).first()
        pay_args = self._pay_detail(omclient,
                                    opaytype,
                                    opayno,
                                    float(order_main.OMtrueMount),
                                    body,
                                    openid=user.USopenid1 or user.USopenid2)
        response = {
            'pay_type': PayType(opaytype).name,
            'opaytype': opaytype,
            'args': pay_args
        }
        return Success('生成付款参数成功', response)

    def alipay_notify(self):
        """异步通知, 文档 https://docs.open.alipay.com/203/105286/"""
        # 待测试
        data = request.form.to_dict()
        signature = data.pop("sign")
        success = self.alipay.verify(data, signature)
        if not (success and data["trade_status"]
                in ("TRADE_SUCCESS", "TRADE_FINISHED")):
            return
        print("trade succeed")
        out_trade_no = data.get('out_trade_no')
        # 交易成功
        with self.strade.auto_commit() as s:
            # 更改付款流水
            order_pay_instance = OrderPay.query.filter_by_({
                'OPayno':
                out_trade_no
            }).first_()
            order_pay_instance.OPaytime = data.get('gmt_payment')
            order_pay_instance.OPaysn = data.get('trade_no')  # 支付宝交易凭证号
            order_pay_instance.OPayJson = json.dumps(data)
            # 更改主单
            order_mains = OrderMain.query.filter_by_({
                'OPayno': out_trade_no
            }).all()
            for order_main in order_mains:
                order_main.update(
                    {'OMstatus': OrderMainStatus.wait_send.value})
                db.session.add(order_main)
                # 添加佣金记录
                current_app.logger.info('支付宝付款成功')
                self._insert_usercommision(order_main)
        return 'success'

    def wechat_notify(self):
        """微信支付回调"""
        data = self.wx_pay.to_dict(request.data)
        if not self.wx_pay.check(data):
            return self.wx_pay.reply(u"签名验证失败", False)
        out_trade_no = data.get('out_trade_no')
        with db.auto_commit():
            # 更改付款流水
            order_pay_instance = OrderPay.query.filter_by_({
                'OPayno':
                out_trade_no
            }).first_()
            order_pay_instance.OPaytime = data.get('time_end')
            order_pay_instance.OPaysn = data.get('transaction_id')  # 微信支付订单号
            order_pay_instance.OPayJson = json.dumps(data)
            # 更改主单
            order_mains = OrderMain.query.filter_by_({
                'OPayno': out_trade_no
            }).all()
            for order_main in order_mains:
                order_main.update(
                    {'OMstatus': OrderMainStatus.wait_send.value})
                # 添加佣金记录
                current_app.logger.info('微信支付成功')
                self._insert_usercommision(order_main)
        return self.wx_pay.reply("OK", True).decode()

    def _insert_usercommision(self, order_main):
        """写入佣金流水表"""
        omid = order_main.OMid
        user = User.query.filter_by_({'USid': order_main.USid}).first()  # 订单用户
        try:
            current_app.logger.info('当前付款人: {}, 状态: {}  '.format(
                user.USname,
                UserIdentityStatus(user.USlevel).zh_value))
        except Exception:
            pass
        commision = Commision.query.filter(Commision.isdelete == False).first()
        order_parts = OrderPart.query.filter_by_({'OMid': omid}).all()
        UCstatus = None
        UCendTime = None
        is_trial_commodity = order_main.OMfrom == OrderFrom.trial_commodity.value
        for order_part in order_parts:
            # 是否是新人大礼包
            prid = order_part.PRid
            if order_main.OMfrom == OrderFrom.fresh_man.value:
                current_app.logger.info('新人首单不参与分佣')
                continue
            if self._check_upgrade_gift((prid, )):
                current_app.logger.info('开店礼包不需要佣金')
                user.USlevel = UserIdentityStatus.toapply.value
                # continue
            if is_trial_commodity:
                trialcommodity = TrialCommodity.query.filter_by(
                    TCid=order_parts[0]['PRid']).first()
                user_commision_dict = {
                    'UCid':
                    str(uuid.uuid1()),
                    'OMid':
                    omid,
                    'OPid':
                    order_part.OPid,
                    'UCcommission':
                    order_main.OMtrueMount,
                    'USid':
                    user.USid,
                    'CommisionFor':
                    ApplyFrom.user.value,
                    'UCtype':
                    UserCommissionType.deposit.value,  # 类型是押金
                    'PRtitle':
                    order_part.PRtitle,
                    'SKUpic':
                    order_part.SKUpic,
                    'UCendTime':
                    order_main.createtime +
                    timedelta(days=trialcommodity.TCdeadline),
                    'UCstatus':
                    UserCommissionStatus.preview.value,
                    'FromUsid':
                    order_main.USid
                }
                db.session.add(UserCommission.create(user_commision_dict))
                continue
            up1 = order_part.UPperid
            up2 = order_part.UPperid2
            up3 = order_part.UPperid3
            # 如果付款用户是代理商
            if UserIdentityStatus.agent.value == user.USlevel:
                up1, up2, up3 = user.USid, up1, up2  # 代理商自己也会有一部分佣金
            up1_user = User.query.filter(User.isdelete == False,
                                         User.USid == up1).first()
            up2_user = User.query.filter(User.isdelete == False,
                                         User.USid == up2).first()
            up3_user = User.query.filter(User.isdelete == False,
                                         User.USid == up3).first()
            self._caculate_commsion(
                user,
                up1_user,
                up2_user,
                up3_user,
                commision,
                order_part,
                is_act=bool(order_main.OMfrom > OrderFrom.product_info.value))

        # 新人活动订单
        if order_main.OMfrom == OrderFrom.fresh_man.value:
            first = 20
            second = 30
            third = 50

            fresh_man_join_flow = FreshManJoinFlow.query.filter(
                FreshManJoinFlow.isdelete == False,
                FreshManJoinFlow.OMid == order_main.OMid,
            ).first()
            if fresh_man_join_flow and fresh_man_join_flow.UPid:
                fresh_man_join_count = FreshManJoinFlow.query.filter(
                    FreshManJoinFlow.isdelete == False,
                    FreshManJoinFlow.UPid == fresh_man_join_flow.UPid,
                    FreshManJoinFlow.OMid == OrderMain.OMid,
                    OrderMain.OMstatus >= OrderMainStatus.wait_send.value,
                    OrderMain.OMinRefund == False,
                    OrderMain.isdelete == False).count()
                current_app.logger.info(
                    "当前邀请人 邀请了总共 {} ".format(fresh_man_join_count))
                # 邀请人的新人首单
                up_order_main = OrderMain.query.filter(
                    OrderMain.isdelete == False,
                    OrderMain.USid == fresh_man_join_flow.UPid,
                    OrderMain.OMfrom == OrderFrom.fresh_man.value,
                    OrderMain.OMstatus > OrderMainStatus.wait_pay.value,
                ).first()
                # 邀请人的新人首单佣金列表
                up_order_fresh_commissions = UserCommission.query.filter(
                    UserCommission.isdelete == False,
                    # OrderMain.OMinRefund == False,
                    UserCommission.USid == up_order_main.USid,
                    UserCommission.UCstatus >=
                    UserCommissionStatus.preview.value,
                    UserCommission.UCtype ==
                    UserCommissionType.fresh_man.value,
                ).order_by(UserCommission.createtime.asc()).limit(3)
                # 邀请人的新人首单佣金
                commissions = 0
                for commission in up_order_fresh_commissions:
                    commission = commission.to_dict()
                    commissions += commission['UCcommission']
                if up_order_main:
                    up_fresh_order_price = up_order_main.OMtrueMount
                    # 邀请人新品佣金小于这次新人返现并且这次新人在前三个返现的人之内
                    if commissions < up_fresh_order_price and fresh_man_join_count <= 3:
                        reward = fresh_man_join_flow.OMprice
                        if fresh_man_join_count == 1:
                            reward = reward * (first / 100)
                        elif fresh_man_join_count == 2:
                            reward = reward * (second / 100)
                        elif fresh_man_join_count == 3:
                            reward = reward * (third / 100)
                        else:
                            reward = 0
                        if reward + commissions > up_fresh_order_price:
                            reward = up_fresh_order_price - commissions
                        if reward:
                            user_commision_dict = {
                                'UCid': str(uuid.uuid1()),
                                'OMid': omid,
                                'UCcommission': reward,
                                'USid': fresh_man_join_flow.UPid,
                                'UCtype': UserCommissionType.fresh_man.value,
                                'UCendTime': UCendTime
                            }
                            db.session.add(
                                UserCommission.create(user_commision_dict))
        # 线上发货
        if order_main.OMlogisticType == OMlogisticTypeEnum.online.value:
            order_main.OMstatus = OrderMainStatus.ready.value
            db.session.add(order_main)
            # 发货表
            orderlogistics = OrderLogistics.create({
                'OLid':
                str(uuid.uuid1()),
                'OMid':
                omid,
                'OLcompany':
                'auto',
                'OLexpressNo':
                self._generic_omno(),
                'OLsignStatus':
                LogisticsSignStatus.already_signed.value,
                'OLdata':
                '[]',
                'OLlastresult':
                '{}'
            })
            db.session.add(orderlogistics)

    def _caculate_commsion(self,
                           user,
                           up1,
                           up2,
                           up3,
                           commision,
                           order_part,
                           is_act=False):
        """计算各级佣金"""
        # 活动佣金即时到账
        suid = order_part.PRcreateId
        if is_act:
            current_app.logger.info('活动订单和押金即时到账')
            UCstatus = UserCommissionStatus.in_account.value
        else:
            UCstatus = None
        default_level1commision, default_level2commision, default_level3commision, default_planetcommision = json.loads(
            commision.Levelcommision)
        reduce_ratio = json.loads(commision.ReduceRatio)
        increase_ratio = json.loads(commision.IncreaseRatio)
        # 基础佣金比
        user_level1commision = Decimal(
            str(
                self._current_commission(
                    getattr(order_part, 'USCommission1', ''),
                    default_level1commision)))
        user_level2commision = Decimal(
            str(
                self._current_commission(
                    getattr(order_part, 'USCommission2', ''),
                    default_level2commision)))
        user_level3commision = Decimal(
            str(
                self._current_commission(
                    getattr(order_part, 'USCommission3', ''),
                    default_level3commision)))
        # 平台 + 用户 抽成: 获取成功比例, 依次查找订单--> sku --> 系统默认
        planet_and_user_rate = Decimal(str(order_part.SkudevideRate or 0))

        if not planet_and_user_rate:
            sku = ProductSku.query.filter(
                ProductSku.SKUid == OrderPart.SKUid).first()
            if sku:
                planet_and_user_rate = Decimal(str(sku.SkudevideRate or 0))
        if not planet_and_user_rate:
            planet_and_user_rate = default_planetcommision
        planet_and_user_rate = Decimal(planet_and_user_rate) / 100
        # 平台固定抽成
        planet_rate = Decimal(default_planetcommision) / 100
        planet_commision = order_part.OPsubTotal * planet_rate  # 平台获得, 是总价的的百分比
        user_commision = order_part.OPsubTotal * planet_and_user_rate - planet_commision  # 用户获得, 是总价 - 平台获得
        # user_rate = planet_and_user_rate - planet_rate  # 用户的的比例
        # 用户佣金
        commision_for_supplizer = order_part.OPsubTotal * (
            Decimal('1') - planet_and_user_rate)  #  给供应商的钱   总价 * ( 1 - 让利 )
        commision_for_supplizer = self.get_two_float(commision_for_supplizer)

        desposit = commision_for_supplizer
        # 正常应该获得佣金
        up1_base = up2_base = up3_base = 0
        if up1 and up1.USlevel > 1:
            user_level1commision = self._current_commission(
                up1.USCommission1, user_level1commision) / 100  # 个人佣金比
            up1_base = user_commision * user_level1commision
            if up2 and up2.USlevel > 1:
                user_level2commision = self._current_commission(
                    up2.USCommission2, user_level2commision) / 100  # 个人佣金比
                up2_base = user_commision * user_level2commision
                # 偏移
                up1_up2 = up1.CommisionLevel - up2.CommisionLevel
                up1_base, up2_base = self._caculate_offset(
                    up1_up2, up1_base, up2_base, reduce_ratio, increase_ratio)
                if up3 and up3.USlevel > 1:
                    user_level3commision = self._current_commission(
                        up3.USCommission3, user_level3commision) / 100  # 个人佣金比
                    up3_base = user_commision * user_level3commision
                    up2_up3 = Decimal(up2.CommisionLevel) - Decimal(
                        up3.CommisionLevel)
                    up2_base, up3_base = self._caculate_offset(
                        up2_up3, up2_base, up3_base, reduce_ratio,
                        increase_ratio)
        if up1_base:
            up1_base = self.get_two_float(up1_base)
            user_commision -= up1_base
            current_app.logger.info('一级获得佣金: {}'.format(up1_base))
            commision_account = UserCommission.create({
                'UCid': str(uuid.uuid1()),
                'OMid': order_part.OMid,
                'OPid': order_part.OPid,
                'UCcommission': up1_base,
                'USid': up1.USid,
                'PRtitle': order_part.PRtitle,
                'SKUpic': order_part.SKUpic,
                'UCstatus': UCstatus,
                'FromUsid': user.USid
            })
            db.session.add(commision_account)
        if up2_base:
            up2_base = self.get_two_float(up2_base)
            user_commision -= up2_base
            current_app.logger.info('二级获得佣金: {}'.format(up2_base))
            commision_account = UserCommission.create({
                'UCid': str(uuid.uuid1()),
                'OMid': order_part.OMid,
                'OPid': order_part.OPid,
                'UCcommission': up2_base,
                'USid': up2.USid,
                'PRtitle': order_part.PRtitle,
                'SKUpic': order_part.SKUpic,
                'UCstatus': UCstatus,
                'FromUsid': user.USid
            })
            db.session.add(commision_account)
        if up3_base:
            up3_base = self.get_two_float(up3_base)
            user_commision -= up3_base
            current_app.logger.info('三级获得佣金: {}'.format(up3_base))
            commision_account = UserCommission.create({
                'UCid': str(uuid.uuid1()),
                'OMid': order_part.OMid,
                'OPid': order_part.OPid,
                'UCcommission': up3_base,
                'USid': up3.USid,
                'PRtitle': order_part.PRtitle,
                'SKUpic': order_part.SKUpic,
                'UCstatus': UCstatus,
                'FromUsid': user.USid
            })
            db.session.add(commision_account)
        planet_remain = user_commision + planet_commision
        # 优惠券计算
        order_coupon = order_part.order_coupon
        if order_coupon:
            if order_coupon.SUid:
                # commision_for_supplizer -= (Decimal(order_part.OPsubTotal) - Decimal(order_part.OPsubTrueTotal))
                current_app.logger.info(
                    'get commision_for_supplizer {} '.format(
                        commision_for_supplizer))

                commision_sub = (Decimal(order_part.OPsubTotal) -
                                 Decimal(order_part.OPsubTrueTotal))
                current_app.logger.info(
                    'get commision_sub {}'.format(commision_sub))
                if commision_for_supplizer >= commision_sub:
                    desposit = commision_sub
                    commision_for_supplizer -= commision_sub
                else:
                    commision_for_supplizer = 0
            else:
                planet_remain -= (Decimal(order_part.OPsubTotal) -
                                  Decimal(order_part.OPsubTrueTotal))

        # 供应商获取佣金
        if suid:
            su = Supplizer.query.filter(Supplizer.isdelete == False,
                                        Supplizer.SUid == suid).first()
            current_app.logger.info('get supplizer {}'.format(su))
            if su:

                current_app.logger.info('get change {}'.format(desposit))
                desposit = Decimal(str(desposit))
                sudeposit = Decimal(str(su.SUdeposit or 0))
                after_deposit = sudeposit + desposit
                current_app.logger.info(
                    'start add supplizer deposit before {} change {} after {}'.
                    format(sudeposit, desposit, after_deposit))
                sdl = SupplizerDepositLog.create({
                    'SDLid': str(uuid.uuid1()),
                    'SUid': su.SUid,
                    'SDLnum': desposit,
                    'SDafter': after_deposit,
                    'SDbefore': sudeposit,
                    'SDLacid': 'system'
                })
                su.SUdeposit = after_deposit
                db.session.add(sdl)
                commision_account = UserCommission.create({
                    'UCid':
                    str(uuid.uuid1()),
                    'OMid':
                    order_part.OMid,
                    'OPid':
                    order_part.OPid,
                    'UCcommission':
                    commision_for_supplizer,
                    'USid':
                    suid,
                    'CommisionFor':
                    ApplyFrom.supplizer.value,
                    'PRtitle':
                    order_part.PRtitle,
                    'SKUpic':
                    order_part.SKUpic,
                    'UCstatus':
                    UCstatus,
                    'FromUsid':
                    user.USid
                })
                db.session.add(commision_account)
                current_app.logger.info('供应商获取佣金: {}'.format(
                    commision_account.UCcommission))
        else:
            planet_remain += commision_for_supplizer
        # 平台剩余佣金
        commision_account = UserCommission.create({
            'UCid':
            str(uuid.uuid1()),
            'OMid':
            order_part.OMid,
            'OPid':
            order_part.OPid,
            'UCcommission':
            planet_remain,
            'USid':
            '0',
            'CommisionFor':
            ApplyFrom.platform.value,
            'PRtitle':
            order_part.PRtitle,
            'SKUpic':
            order_part.SKUpic,
            'UCstatus':
            UCstatus,
            'FromUsid':
            user.USid
        })
        db.session.add(commision_account)
        current_app.logger.info('平台获取: {}'.format(planet_remain))

    @token_required
    def get_preview_commision(self):
        # 活动佣金即时到账
        usid = request.user.id
        user = User.query.filter(User.isdelete == False,
                                 User.USid == usid).first()
        commision = Commision.query.filter(
            Commision.isdelete == False, ).order_by(
                Commision.createtime.desc()).first()
        level_commision = list(
            map(Decimal, json.loads(commision.Levelcommision)))
        ReduceRatio = list(map(Decimal, json.loads(commision.ReduceRatio)))
        IncreaseRatio = list(map(Decimal, json.loads(commision.IncreaseRatio)))
        level1_commision = self._current_commission(user.USCommission1,
                                                    level_commision[0])
        default_planetcommision = level_commision[-1]
        up1, up2 = user, User.query.filter(
            User.isdelete == False, User.USid == user.USsupper1).first()
        order_price = Decimal()  # 订单实际价格
        info = parameter_required((
            'pbid',
            'skus',
        ))
        pbid = info.get('pbid')
        skus = info.get('skus')
        brand = ProductBrand.query.filter(ProductBrand.PBid == pbid).first()
        supplizer = Supplizer.query.filter(
            Supplizer.SUid == brand.SUid).first()
        up1_bases = Decimal(0)
        for sku in skus:
            # 订单副单
            skuid = sku.get('skuid')
            opnum = int(sku.get('nums', 1))
            assert opnum > 0
            sku_instance = ProductSku.query.filter_by_({
                'SKUid': skuid
            }).first_('skuid: {}不存在'.format(skuid))
            small_total = Decimal(str(sku_instance.SKUprice)) * opnum
            # 订单价格计算
            order_price += small_total
            planet_and_user_rate = self._current_commission(
                sku_instance.SkudevideRate,
                getattr(supplizer, 'SUbaseRate', ''), default_planetcommision)
            planet_and_user_rate = Decimal(planet_and_user_rate) / 100
            # 平台固定抽成
            planet_rate = Decimal(default_planetcommision) / 100
            planet_commision = order_price * planet_rate  # 平台获得, 是总价的的百分比
            user_commision = order_price * planet_and_user_rate - planet_commision  # 用户获得, 是总价 - 平台获得
            # 正常应该获得佣金
            up1_base = up2_base = 0
            if up1 and up1.USlevel > 1:
                user_level1commision = self._current_commission(
                    up1.USCommission1, level1_commision) / 100  # 个人佣金比
                up1_base = user_commision * user_level1commision
                if up2 and up2.USlevel > 1:
                    user_level2commision = self._current_commission(
                        up2.USCommission2, level1_commision) / 100  # 个人佣金比
                    up2_base = user_commision * user_level2commision
                    # 偏移
                    up1_up2 = up1.CommisionLevel - up2.CommisionLevel
                    up1_base, up2_base = self._caculate_offset(
                        up1_up2, up1_base, up2_base, ReduceRatio,
                        IncreaseRatio)
            up1_bases += up1_base
        return Success(data='%.2f' % up1_bases)

    def _caculate_offset(self, low_high, user_low_base, user_hign_base,
                         reduce_ratio, increase_ratio):
        """计算偏移后的佣金"""
        if low_high <= 0:
            return user_low_base, user_hign_base
        low_ratio = Decimal()
        hign_ratio = Decimal('1')
        hign_comm_base_temp = user_hign_base
        # 不限等级。限制偏移上限
        if low_high > 4:
            low_high = 4
        for index in range(low_high):
            hign_comm_base_temp *= hign_ratio  # 本级的基础佣金比
            hign_ratio *= (1 - Decimal(reduce_ratio[index]) / 100)
            low_ratio += (hign_comm_base_temp *
                          Decimal(increase_ratio[index]) / 100)
        return low_ratio + user_low_base, hign_ratio * user_hign_base

    def _pay_detail(self,
                    omclient,
                    opaytype,
                    opayno,
                    mount_price,
                    body,
                    openid='openid'):
        opaytype = int(opaytype)
        omclient = int(omclient)
        body = re.sub("[\s+\.\!\/_,$%^*(+\"\'\-_]+|[+——!,。?、~@#¥%……&*()]+", '',
                      body)
        if API_HOST == 'https://test.bigxingxing.com':
            mount_price = 0.01
        current_app.logger.info('openid is {}, out_trade_no is {} '.format(
            openid, opayno))
        # 微信支付的单位是'分', 支付宝使用的单位是'元'
        if opaytype == PayType.wechat_pay.value:
            try:
                body = body[:16] + '...'
                current_app.logger.info('body is {}, wechatpay'.format(body))
                wechat_pay_dict = {
                    'body': body,
                    'out_trade_no': opayno,
                    'total_fee': int(mount_price * 100),
                    'attach': 'attach',
                    'spbill_create_ip': request.remote_addr
                }

                if omclient == Client.wechat.value:  # 微信客户端
                    if not openid:
                        raise StatusError('用户未使用微信登录')
                    # wechat_pay_dict.update(dict(trade_type="JSAPI", openid=openid))
                    wechat_pay_dict.update({
                        'trade_type': 'JSAPI',
                        'openid': openid
                    })
                    raw = self.wx_pay.jsapi(**wechat_pay_dict)
                else:
                    wechat_pay_dict.update({'trade_type': "APP"})
                    raw = self.wx_pay.unified_order(**wechat_pay_dict)
            except WeixinPayError as e:
                raise SystemError('微信支付异常: {}'.format('.'.join(e.args)))

        elif opaytype == PayType.alipay.value:
            current_app.logger.info('body is {}, alipay'.format(body))
            if omclient == Client.wechat.value:
                raise SystemError('请选用其他支付方式')
            else:
                try:
                    raw = self.alipay.api_alipay_trade_app_pay(
                        out_trade_no=opayno,
                        total_amount=mount_price,
                        subject=body[:66] + '...',
                    )
                except Exception:
                    raise SystemError('支付宝参数异常')
        elif opaytype == PayType.test_pay.value:
            raw = self.alipay.api_alipay_trade_page_pay(
                out_trade_no=opayno,
                total_amount=mount_price,
                subject=body[10],
            )
            raw = 'https://openapi.alipaydev.com/gateway.do?' + raw
        else:
            raise SystemError('请选用其他支付方式')
        current_app.logger.info('pay response is {}'.format(raw))
        return raw

    def _pay_to_user(self, opaytype):
        """
        向用户提现
        :return:
        """
        pass

    @staticmethod
    def _generic_omno():
        """生成订单号"""
        return str(time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))) + \
               str(time.time()).replace('.', '')[-7:] + str(random.randint(1000, 9999))

    @staticmethod
    def _current_commission(*args):
        for comm in args:
            if comm is not None:
                return comm
        return 0

    def _check_upgrade_gift(self, prid_list):
        return Items.query.join(ProductItems,
                                Items.ITid == ProductItems.ITid).filter(
                                    Items.isdelete == False,
                                    ProductItems.isdelete == False,
                                    Items.ITid == 'upgrade_product',
                                    ProductItems.PRid.in_(prid_list),
                                ).first()

    @staticmethod
    def get_two_float(f_str, n=2):
        f_str = str(f_str)
        a, b, c = f_str.partition('.')
        c = (c + "0" * n)[:n]
        return Decimal(".".join([a, c]))
예제 #11
0
 def __init__(self):
     self.strade = STrade()
     self.corder = COrder()